def test_workspacestatusapi_success(api_rf): request = api_rf.get("/") project1 = ProjectFactory() workspace1 = WorkspaceFactory(project=project1, uses_new_release_flow=True) response = WorkspaceStatusAPI.as_view()(request, workspace_id=workspace1.name) assert response.status_code == 200 assert response.data["uses_new_release_flow"] project2 = ProjectFactory() workspace2 = WorkspaceFactory(project=project2, uses_new_release_flow=False) response = WorkspaceStatusAPI.as_view()(request, workspace_id=workspace2.name) assert response.status_code == 200 assert not response.data["uses_new_release_flow"]
def test_create_release_success(): backend = BackendFactory() workspace = WorkspaceFactory() user = UserFactory() files = {"file1.txt": "hash"} release = releases.create_release(workspace, backend, user, files) assert release.requested_files == files
def test_jobrequestapicreate_success(api_rf, pipeline_config): backend = BackendFactory() workspace = WorkspaceFactory() user = UserFactory() token = user.rotate_token() assert not JobRequest.objects.exists() data = { "workspace": workspace.name, "backend": backend.slug, "sha": "123", "project_definition": pipeline_config, "requested_actions": ["test"], } request = api_rf.post("/", HTTP_AUTHORIZATION=f"{user.username}:{token}", data=data) response = JobRequestAPICreate.as_view()(request) assert response.status_code == 201, response.data assert JobRequest.objects.count() == 1 job_request = JobRequest.objects.first() assert job_request.workspace == workspace
def test_jobapiupdate_notifications_on_with_move_to_completed(api_rf, mocker): workspace = WorkspaceFactory() job_request = JobRequestFactory(workspace=workspace, will_notify=True) job = JobFactory(job_request=job_request, status="running") now = timezone.now() mocked_send = mocker.patch("jobserver.api.jobs.send_finished_notification", autospec=True) data = [ { "identifier": job.identifier, "job_request_id": job_request.identifier, "action": "test", "status": "succeeded", "status_code": "", "status_message": "", "created_at": minutes_ago(now, 2), "started_at": minutes_ago(now, 1), "updated_at": now, "completed_at": seconds_ago(now, 30), }, ] request = api_rf.post( "/", HTTP_AUTHORIZATION=job_request.backend.auth_token, data=data, format="json", ) response = JobAPIUpdate.as_view()(request) mocked_send.assert_called_once() assert response.status_code == 200
def test_releaseworkspaceapi_post_without_backend_token(api_rf): workspace = WorkspaceFactory() request = api_rf.post("/") response = ReleaseWorkspaceAPI.as_view()(request, workspace_name=workspace.name) assert response.status_code == 403
def test_releaseworkspaceapi_get_with_anonymous_user(api_rf): workspace = WorkspaceFactory() request = api_rf.get("/") response = ReleaseWorkspaceAPI.as_view()(request, workspace_name=workspace.name) assert response.status_code == 403
def test_releaseworkspaceapi_get_without_permission(api_rf): workspace = WorkspaceFactory() request = api_rf.get("/") request.user = UserFactory() response = ReleaseWorkspaceAPI.as_view()(request, workspace_name=workspace.name) assert response.status_code == 403
def test_releaseworkspaceapi_post_with_bad_backend_token(api_rf): workspace = WorkspaceFactory() BackendFactory(auth_token="test") request = api_rf.post("/", HTTP_AUTHORIZATION="invalid") response = ReleaseWorkspaceAPI.as_view()(request, workspace_name=workspace.name) assert response.status_code == 403
def test_snapshotcreate_without_permission(api_rf): workspace = WorkspaceFactory() request = api_rf.post("/", data={"file_ids": ["test"]}) request.user = UserFactory() response = SnapshotCreateAPI.as_view()(request, workspace_id=workspace.name) assert response.status_code == 403, response.data
def test_validate_upload_access_unknown_user(rf): backend = BackendFactory() workspace = WorkspaceFactory() BackendMembershipFactory(backend=backend) request = rf.get("/", HTTP_AUTHORIZATION=backend.auth_token, HTTP_OS_USER="******") with pytest.raises(NotAuthenticated): validate_upload_access(request, workspace)
def test_validate_release_access_with_auth_header_success(rf): user = UserFactory() workspace = WorkspaceFactory() token = user.rotate_token() request = rf.get("/", HTTP_AUTHORIZATION=f"{user.username}:{token}") request.user = AnonymousUser() assert validate_release_access(request, workspace) is None
def test_workspacestatusesapi_success(api_rf): workspace = WorkspaceFactory() job_request = JobRequestFactory(workspace=workspace) JobFactory(job_request=job_request, action="run_all", status="failed") request = api_rf.get("/") response = WorkspaceStatusesAPI.as_view()(request, name=workspace.name) assert response.status_code == 200 assert response.data["run_all"] == "failed"
def test_build_hatch_token_and_url_default(): backend = BackendFactory() user = UserFactory() workspace = WorkspaceFactory() releases.build_hatch_token_and_url( backend=backend, workspace=workspace, user=user, )
def test_releaseworkspaceapi_get_with_permission(api_rf, build_release_with_files): workspace = WorkspaceFactory() backend1 = BackendFactory(slug="backend1") backend2 = BackendFactory(slug="backend2") user = UserFactory() ProjectMembershipFactory( user=user, project=workspace.project, roles=[ProjectCollaborator] ) # two release for same filename but different content release1 = build_release_with_files( ["file1.txt"], workspace=workspace, backend=backend1, created_by=user ) rfile1 = release1.files.first() release2 = build_release_with_files( ["file1.txt"], workspace=workspace, backend=backend2, created_by=user ) rfile2 = release2.files.first() request = api_rf.get("/") request.user = user response = ReleaseWorkspaceAPI.as_view()(request, workspace_name=workspace.name) assert response.status_code == 200 assert response.data == { "files": [ { "name": "backend2/file1.txt", "id": rfile2.pk, "url": f"/api/v2/releases/file/{rfile2.id}", "user": rfile2.created_by.username, "date": rfile2.created_at.isoformat(), "size": rfile2.size, "sha256": rfile2.filehash, "is_deleted": False, "backend": release2.backend.name, "metadata": None, "review": None, }, { "name": "backend1/file1.txt", "id": rfile1.pk, "url": f"/api/v2/releases/file/{rfile1.id}", "user": rfile1.created_by.username, "date": rfile1.created_at.isoformat(), "size": rfile1.size, "sha256": rfile1.filehash, "is_deleted": False, "backend": release1.backend.name, "metadata": None, "review": None, }, ], }
def test_validate_release_access_with_auth_header_and_unknown_user(rf): user = UserFactory() workspace = WorkspaceFactory() token = user.rotate_token() request = rf.get("/", HTTP_AUTHORIZATION=f"0:{token}") request.user = AnonymousUser() with pytest.raises(NotAuthenticated): validate_release_access(request, workspace)
def test_build_hatch_token_and_url_with_custom_expires(): backend = BackendFactory() user = UserFactory() workspace = WorkspaceFactory() releases.build_hatch_token_and_url( backend=backend, workspace=workspace, user=user, expiry=timezone.now() + timedelta(minutes=3), )
def test_workspace_files_many_releases(freezer, build_release_with_files): now = timezone.now() backend1 = BackendFactory(slug="backend1") backend2 = BackendFactory(slug="backend2") workspace = WorkspaceFactory() build_release_with_files( ["test1", "test2", "test3"], workspace=workspace, backend=backend1, created_at=minutes_ago(now, 10), ) build_release_with_files( ["test2", "test3"], workspace=workspace, backend=backend1, created_at=minutes_ago(now, 8), ) release3 = build_release_with_files( ["test2"], workspace=workspace, backend=backend1, created_at=minutes_ago(now, 6), ) release4 = build_release_with_files( ["test1", "test3"], workspace=workspace, backend=backend1, created_at=minutes_ago(now, 4), ) release5 = build_release_with_files( ["test1"], workspace=workspace, backend=backend1, created_at=minutes_ago(now, 2), ) # different backend, same file name, more recent release6 = build_release_with_files( ["test1"], workspace=workspace, backend=backend2, created_at=minutes_ago(now, 1), ) output = releases.workspace_files(workspace) assert output == { "backend1/test1": release5.files.get(name="test1"), "backend1/test3": release4.files.get(name="test3"), "backend1/test2": release3.files.get(name="test2"), "backend2/test1": release6.files.get(name="test1"), }
def test_validate_release_access_with_auth_header_and_invalid_token(rf): user = UserFactory() workspace = WorkspaceFactory() # set a token so the user is considered a bot user.rotate_token() request = rf.get("/", HTTP_AUTHORIZATION=f"{user.username}:invalid") request.user = AnonymousUser() with pytest.raises(PermissionDenied): validate_release_access(request, workspace)
def test_snapshotpublishapi_unknown_snapshot(api_rf): workspace = WorkspaceFactory() request = api_rf.post("/") request.user = UserFactory(roles=[OutputPublisher]) response = SnapshotPublishAPI.as_view()( request, workspace_id=workspace.name, snapshot_id=0, ) assert response.status_code == 404
def test_validate_upload_access_not_a_backend_member(rf): backend = BackendFactory() user = UserFactory(roles=[OutputChecker]) workspace = WorkspaceFactory() request = rf.get( "/", HTTP_AUTHORIZATION=backend.auth_token, HTTP_OS_USER=user.username, ) with pytest.raises(NotAuthenticated): validate_upload_access(request, workspace)
def test_snapshotcreate_unknown_files(api_rf): workspace = WorkspaceFactory() user = UserFactory() ProjectMembershipFactory( project=workspace.project, user=user, roles=[ProjectDeveloper] ) request = api_rf.post("/", data={"file_ids": ["test"]}) request.user = user response = SnapshotCreateAPI.as_view()(request, workspace_id=workspace.name) assert response.status_code == 400, response.data assert "Unknown file IDs" in response.data["detail"], response.data
def test_releaseworkspaceapi_post_create_release(api_rf, slack_messages): user = UserFactory(roles=[OutputChecker]) workspace = WorkspaceFactory() ProjectMembershipFactory(user=user, project=workspace.project) backend = BackendFactory(auth_token="test", name="test-backend") BackendMembershipFactory(backend=backend, user=user) assert Release.objects.count() == 0 data = { "files": [ { "name": "file1.txt", "url": "url", "size": 7, "sha256": "hash", "date": timezone.now(), "metadata": {}, "review": None, } ], "metadata": {}, "review": None, } request = api_rf.post( "/", data=data, format="json", HTTP_AUTHORIZATION="test", HTTP_OS_USER=user.username, ) response = ReleaseWorkspaceAPI.as_view()(request, workspace_name=workspace.name) assert response.status_code == 201, response.data assert Release.objects.count() == 1 release = Release.objects.first() assert response["Release-Id"] == str(release.id) assert response["Location"] == f"http://testserver{release.get_api_url()}" assert len(slack_messages) == 1 text, channel = slack_messages[0] assert channel == "opensafely-releases" assert f"{user.get_staff_url()}|{user.name}>" in text assert f"{release.get_absolute_url()}|release>" in text assert f"{workspace.get_absolute_url()}|{workspace.name}>" in text assert backend.name in text
def test_validate_upload_access_no_permission(rf): backend = BackendFactory() user = UserFactory() workspace = WorkspaceFactory() BackendMembershipFactory(backend=backend, user=user) request = rf.get( "/", HTTP_AUTHORIZATION=backend.auth_token, HTTP_OS_USER=user.username, ) with pytest.raises(NotAuthenticated): validate_upload_access(request, workspace)
def test_snapshotcreate_with_existing_snapshot(api_rf, build_release_with_files): workspace = WorkspaceFactory() release = build_release_with_files(["file1.txt"]) snapshot = SnapshotFactory(workspace=workspace) snapshot.files.set(release.files.all()) user = UserFactory() ProjectMembershipFactory( project=workspace.project, user=user, roles=[ProjectDeveloper] ) request = api_rf.post("/", data={"file_ids": [release.files.first().pk]}) request.user = user response = SnapshotCreateAPI.as_view()(request, workspace_id=workspace.name) assert response.status_code == 400, response.data msg = "A release with the current files already exists" assert msg in response.data["detail"], response.data
def test_releaseworkspaceapi_post_with_bad_json(api_rf): user = UserFactory(roles=[OutputChecker]) workspace = WorkspaceFactory() ProjectMembershipFactory(user=user, project=workspace.project) backend = BackendFactory(auth_token="test") BackendMembershipFactory(backend=backend, user=user) request = api_rf.post( "/", content_type="application/json", data=json.dumps({}), HTTP_CONTENT_DISPOSITION="attachment; filename=release.zip", HTTP_AUTHORIZATION="test", HTTP_OS_USER=user.username, ) response = ReleaseWorkspaceAPI.as_view()(request, workspace_name=workspace.name) assert response.status_code == 400
def test_create_release_new_style_success(): backend = BackendFactory() workspace = WorkspaceFactory() user = UserFactory() files = [{ "name": "file1.txt", "path": "path/to/file1.txt", "url": "", "size": 7, "sha256": "hash", "date": "2022-08-17T13:37Z", "metadata": {}, }] release = releases.create_release(workspace, backend, user, files) assert release.requested_files == files assert release.files.count() == 1 rfile = release.files.first() rfile.filehash == "hash" rfile.size == 7
def test_snapshotcreate_with_permission(api_rf, build_release_with_files): workspace = WorkspaceFactory() release = build_release_with_files( [ "file1.txt", "file2.txt", "file3.txt", "file4.txt", "file5.txt", ], workspace=workspace, ) user = UserFactory() ProjectMembershipFactory( project=workspace.project, user=user, roles=[ProjectDeveloper] ) data = { "file_ids": [ release.files.get(name="file1.txt").pk, release.files.get(name="file3.txt").pk, release.files.get(name="file5.txt").pk, ], } request = api_rf.post("/", data) request.user = user response = SnapshotCreateAPI.as_view()(request, workspace_id=workspace.name) assert response.status_code == 201 workspace.refresh_from_db() assert workspace.snapshots.count() == 1 snapshot_file_ids = set_from_qs(workspace.snapshots.first().files.all()) current_file_ids = set_from_qs(workspace.files.all()) assert snapshot_file_ids <= current_file_ids
def test_jobrequestapilist_success(api_rf): workspace = WorkspaceFactory() # all completed job_request1 = JobRequestFactory(workspace=workspace) JobFactory.create_batch(2, job_request=job_request1, completed_at=timezone.now()) # some completed job_request2 = JobRequestFactory(workspace=workspace) JobFactory(job_request=job_request2, completed_at=timezone.now()) JobFactory(job_request=job_request2, completed_at=None) # none completed job_request3 = JobRequestFactory(workspace=workspace) JobFactory.create_batch(2, job_request=job_request3, completed_at=None) # no jobs job_request4 = JobRequestFactory(workspace=workspace) assert JobRequest.objects.count() == 4 request = api_rf.get("/") response = JobRequestAPIList.as_view()(request) assert response.status_code == 200 assert response.data["count"] == 3 assert len(response.data["results"]) == 3 identifiers = {j["identifier"] for j in response.data["results"]} assert identifiers == { job_request2.identifier, job_request3.identifier, job_request4.identifier, }
def test_workspace_files_no_releases(): workspace = WorkspaceFactory() assert releases.workspace_files(workspace) == {}