def test_environmentbuildlist_post_with_error1(client, project, monkeypatch): monkeypatch.setattr(namespace_environment_builds, "make_celery", raise_exception_function()) data = client.post("/api/environment-builds/", json=create_env_build_request(project.uuid, 1)).get_json() assert len(data["failed_requests"]) == 1
def test_environmentbuildlist_post_revert(client, project, monkeypatch): monkeypatch.setattr(namespace_environment_builds, "make_celery", raise_exception_function()) client.post("/api/environment-builds/", json=create_env_build_request(project.uuid, 1)) data = client.get("/api/environment-builds/").get_json() data = data["environment_builds"][0] assert data["status"] == "FAILURE"
def test_runlist_post_revert(client, celery, pipeline, monkeypatch): monkeypatch.setattr(namespace_runs, "lock_environment_images_for_run", raise_exception_function()) resp = client.post( "/api/runs/", json=create_pipeline_run_spec(pipeline.project.uuid, pipeline.uuid), ) assert resp.status_code == 500 data = client.get("/api/runs/").get_json()["runs"] assert data[0]["status"] == "FAILURE"
def test_environmentbuildlist_post_with_error2(client, project, monkeypatch): celery = CeleryMock() # Make it so that only the first request will go through. monkeypatch.setattr( namespace_environment_builds, "make_celery", raise_exception_function(should_trigger=lambda: bool(celery.tasks), return_value=celery), ) data = client.post("/api/environment-builds/", json=create_env_build_request(project.uuid, 3)).get_json() assert len(data["environment_builds"]) == 3 assert len(data["failed_requests"]) == 2
def test_job_put_revert(client, pipeline, monkeypatch): job_spec = create_job_spec(pipeline.project.uuid, pipeline.uuid) job_uuid = client.post("/api/jobs/", json=job_spec).get_json()["uuid"] # Cause an exception so that running the job fails. monkeypatch.setattr(namespace_jobs, "lock_environment_images_for_run", raise_exception_function()) resp = client.put(f"/api/jobs/{job_uuid}", json={"confirm_draft": True}) assert resp.status_code == 500 job = client.get(f"/api/jobs/{job_uuid}").get_json() assert job["status"] == "FAILURE" pipeline_runs = job["pipeline_runs"] for run in pipeline_runs: assert run["status"] == "FAILURE"
def test_session_delete_revert(client, pipeline, monkeypatch_interactive_session, monkeypatch): pipeline_spec = { "project_uuid": pipeline.project.uuid, "pipeline_uuid": pipeline.uuid, "pipeline_path": "pip_path", "project_dir": "project_dir", "host_userdir": "host_userdir", } client.post("/api/sessions/", json=pipeline_spec) monkeypatch.setattr(InteractiveSession, "from_container_IDs", raise_exception_function()) resp1 = client.delete( f"/api/sessions/{pipeline.project.uuid}/{pipeline.uuid}") resp2 = client.get( f"/api/sessions/{pipeline.project.uuid}/{pipeline.uuid}") assert resp1.status_code == 500 assert resp2.status_code == 404
def test_environment_build( image_in_local_environment, abort, build_events, monkeypatch, ): def mock_cleanup_docker_artifacts(filters): docker_cleanup_uuid_request.append(filters["label"][1].split("=")[1]) def mock_put_request(self, url, json=None, *args, **kwargs): put_requests.append(json["status"]) return MockRequestReponse() def mock_delete_request(self, url, *args, **kwargs): proj_uuid, env_uuid = url.split("/")[-2:] delete_requests.append((proj_uuid, env_uuid)) return MockRequestReponse() def mock_write_environment_dockerfile(*args, **kwargs): pass def mock_prepare_build_context(task_uuid, project_uuid, environment_uuid, project_path): return {"snapshot_path": None, "base_image": None} # To keep track if requests are properly made. monkeypatch.setattr(requests.sessions.Session, "put", mock_put_request) monkeypatch.setattr(requests.sessions.Session, "delete", mock_delete_request) # Not much use to write the dockerfile since we are monkeypatching # docker. monkeypatch.setattr( app.core.environment_builds, "write_environment_dockerfile", mock_write_environment_dockerfile, ) # Not much use to prepare the build context since we are # monkeypatching docker. monkeypatch.setattr(app.core.environment_builds, "prepare_build_context", mock_prepare_build_context) # Logs will be written here. monkeypatch.setattr( app.core.environment_builds, "__ENV_BUILD_FULL_LOGS_DIRECTORY", "/tmp/output_environment_build", ) # To make sure the correct cleanup request is issued. monkeypatch.setattr( app.core.environment_builds, "cleanup_docker_artifacts", mock_cleanup_docker_artifacts, ) # To be able to fake the cancellation of an env build. monkeypatch.setattr( app.core.environment_builds, "AbortableAsyncResult", mocked_abortable_async_result(abort), ) # To mock getting an image and building an image. MockedDockerClient = mocked_docker_client(_NOT_TO_BE_LOGGED, build_events) # Patch docker get if not image_in_local_environment: monkeypatch.setattr( MockedDockerClient, "get", raise_exception_function(docker.errors.ImageNotFound("error")), ) monkeypatch.setattr(app.core.docker_utils, "docker_client", MockedDockerClient()) socketio_data = { "output_logs": [], "has_connected": False, "has_disconnected": False, } # Capture build logs sent to socketio. monkeypatch.setattr(socketio, "Client", mocked_socketio_class(socketio_data)) put_requests = [] delete_requests = [] docker_cleanup_uuid_request = [] # Inputs of the function to be tested. task_uuid = "task_uuid" # This way the name of the log file can easily be matched with the # actual test. project_uuid = "".join([ "events:", str(build_events), "-abort:", str(abort), "-image_in_local_environment:", str(image_in_local_environment), ]) environment_uuid = "environment_uuid" project_path = "project_path" app.core.environment_builds.build_environment_task( task_uuid, project_uuid, environment_uuid, project_path, ) assert len(put_requests) == 2 assert put_requests[0] == "STARTED" if abort: assert put_requests[1] == "ABORTED" elif any([event is None for event in build_events]): assert put_requests[1] == "FAILURE" else: assert put_requests[1] == "SUCCESS" assert len(delete_requests) == 1 assert delete_requests[0] == (project_uuid, environment_uuid) assert len(docker_cleanup_uuid_request) == 1 assert docker_cleanup_uuid_request[0] == task_uuid assert socketio_data["has_connected"] assert socketio_data["has_disconnected"] if not abort: if not image_in_local_environment: assert "Pulling image" in socketio_data["output_logs"][0] # We cannot rely on different messages being different elements # in the list, since the parent process will try to read # everything that is in the buffer every time, so multiple log # messages can be emitted togheter. logged_events = "".join(socketio_data["output_logs"]) assert _NOT_TO_BE_LOGGED not in logged_events expected_events = [] for event in build_events: if event is None: break expected_events.append(event) expected_events = "\n".join(expected_events) assert expected_events in logged_events # Successful tests can remove their log file. os.remove( os.path.join( app.core.environment_builds.__ENV_BUILD_FULL_LOGS_DIRECTORY, f"orchest-env-{project_uuid}-{environment_uuid}", ))