def test_session_create(client): user = UserFactory() ws = WorkstationFactory() ws.add_user(user=user) # Create some workstations and pretend that they're ready WorkstationImageFactory(workstation=ws, ready=True) # Old WSI wsi_new = WorkstationImageFactory(workstation=ws, ready=True) WorkstationImageFactory(workstation=ws) # WSI not ready WorkstationImageFactory(ready=True) # Image for some other ws assert Session.objects.count() == 0 response = get_view_for_user( client=client, method=client.post, viewname="workstations:workstation-session-create", reverse_kwargs={"slug": ws.slug}, user=user, data={"region": "eu-central-1"}, ) assert response.status_code == 302 sessions = Session.objects.all() assert len(sessions) == 1 # Should select the most recent workstation assert sessions[0].workstation_image == wsi_new assert sessions[0].creator == user
def test_workstation_changes(client, group): # Ensure that read permissions are kept up to date if the workstation # changes ws1, ws2 = WorkstationFactory(), WorkstationFactory() user = UserFactory() alg = AlgorithmFactory(workstation=ws1) assert "view_workstation" not in get_perms(user, ws1) assert "view_workstation" not in get_perms(user, ws2) getattr(alg, f"add_{group}")(user=user) assert "view_workstation" in get_perms(user, ws1) assert "view_workstation" not in get_perms(user, ws2) alg.workstation = ws2 alg.save() assert "view_workstation" not in get_perms(user, ws1) assert "view_workstation" in get_perms(user, ws2) # Test permission cleanup assign_perm("view_workstation", getattr(alg, f"{group}s_group"), ws1) assert "view_workstation" in get_perms(user, ws1) assert "view_workstation" in get_perms(user, ws2) alg.save() assert "view_workstation" not in get_perms(user, ws1) assert "view_workstation" in get_perms(user, ws2)
def test_algorithm_create(client): # The algorithm creator should automatically get added to the editors group creator = get_algorithm_creator() ws = WorkstationFactory() def try_create_algorithm(): return get_view_for_user( viewname="algorithms:create", client=client, method=client.post, data={ "title": "foo bar", "logo": get_temporary_image(), "workstation": ws.pk, }, follow=True, user=creator, ) response = try_create_algorithm() assert "error_1_id_workstation" in response.rendered_content # The editor must have view permissions for the workstation to add it ws.add_user(user=creator) response = try_create_algorithm() assert "error_1_id_workstation" not in response.rendered_content assert response.status_code == 200 alg = Algorithm.objects.get(title="foo bar") assert alg.slug == "foo-bar" assert alg.is_editor(user=creator) assert not alg.is_user(user=creator)
def test_social_image_meta_tag(client, uploaded_image): creator = UserFactory() add_archive_perm = Permission.objects.get( codename=f"add_{Archive._meta.model_name}" ) creator.user_permissions.add(add_archive_perm) ws = WorkstationFactory() ws.add_user(user=creator) def create_archive(): return get_view_for_user( viewname="archives:create", client=client, method=client.post, data={ "title": "foo bar", "logo": uploaded_image(), "social_image": uploaded_image(), "workstation": ws.pk, }, follow=True, user=creator, ) response = create_archive() assert response.status_code == 200 archive = Archive.objects.get(title="foo bar") assert str(archive.social_image.x20.url) in response.content.decode()
def test_get_workstation_image_or_404(): # No default workstation with pytest.raises(Http404): get_workstation_image_or_404() default_workstation = Workstation.objects.get( slug=settings.DEFAULT_WORKSTATION_SLUG ) default_wsi = WorkstationImageFactory( workstation=default_workstation, ready=True ) wsi = WorkstationImageFactory(ready=True) found_wsi = get_workstation_image_or_404() assert found_wsi == default_wsi found_wsi = get_workstation_image_or_404(slug=wsi.workstation.slug) assert found_wsi == wsi found_wsi = get_workstation_image_or_404(pk=wsi.pk) assert found_wsi == wsi # No images for workstation with pytest.raises(Http404): get_workstation_image_or_404(slug=WorkstationFactory().slug) # Incorrect pk with pytest.raises(Http404): get_workstation_image_or_404(pk=WorkstationFactory().pk)
def test_workstation_changes(client): # Ensure that read permissions are kept up to date if the workstation # changes ws1, ws2 = WorkstationFactory(), WorkstationFactory() reader = UserFactory() rs = ReaderStudyFactory(workstation=ws1) assert "view_workstation" not in get_perms(reader, ws1) assert "view_workstation" not in get_perms(reader, ws2) rs.add_reader(user=reader) assert "view_workstation" in get_perms(reader, ws1) assert "view_workstation" not in get_perms(reader, ws2) rs.workstation = ws2 rs.save() assert "view_workstation" not in get_perms(reader, ws1) assert "view_workstation" in get_perms(reader, ws2) # Test permission cleanup assign_perm("view_workstation", rs.readers_group, ws1) assert "view_workstation" in get_perms(reader, ws1) assert "view_workstation" in get_perms(reader, ws2) rs.save() assert "view_workstation" not in get_perms(reader, ws1) assert "view_workstation" in get_perms(reader, ws2)
def test_workstation_update_view(client): w = WorkstationFactory() user = UserFactory(is_staff=True) title = "my Workstation" description = "my AWESOME workstation" assert w.title != title assert w.description is None response = get_view_for_user( client=client, method=client.post, viewname="workstations:update", reverse_kwargs={"slug": w.slug}, user=user, data={ "title": title, "description": description }, ) w.refresh_from_db() assert response.status_code == 302 assert w.title == title assert w.description == description
def test_workstation_list_view(client): w1, w2 = WorkstationFactory(), WorkstationFactory() user = UserFactory() response = get_view_for_user(viewname="workstations:list", client=client, user=user) assert w1.get_absolute_url() not in response.rendered_content assert w2.get_absolute_url() not in response.rendered_content w2.add_editor(user=user) response = get_view_for_user(viewname="workstations:list", client=client, user=user) assert w1.get_absolute_url() not in response.rendered_content assert w2.get_absolute_url() in response.rendered_content w1u = UserFactory() w1.add_user(user=w1u) response = get_view_for_user(viewname="workstations:list", client=client, user=w1u) assert w1.get_absolute_url() in response.rendered_content assert w2.get_absolute_url() not in response.rendered_content
def test_reader_study_create(client, uploaded_image): # The study creator should automatically get added to the editors group creator = get_rs_creator() ws = WorkstationFactory() def try_create_rs(allow_case_navigation): return get_view_for_user( viewname="reader-studies:create", client=client, method=client.post, data={ "title": "foo bar", "logo": uploaded_image(), "workstation": ws.pk, "allow_answer_modification": True, "allow_case_navigation": allow_case_navigation, }, follow=True, user=creator, ) response = try_create_rs(False) assert "error_1_id_workstation" in response.rendered_content # The editor must have view permissions for the workstation to add it ws.add_user(user=creator) response = try_create_rs(False) assert "error_1_id_workstation" not in response.rendered_content assert ( "`allow_case_navigation` must be checked if `allow_answer_modification` is" in response.rendered_content ) response = try_create_rs(True) assert "error_1_id_workstation" not in response.rendered_content assert ( "`allow_case_navigation` must be checked if `allow_answer_modification` is" not in response.rendered_content ) assert response.status_code == 200 rs = ReaderStudy.objects.get(title="foo bar") assert rs.slug == "foo-bar" assert rs.is_editor(user=creator) assert not rs.is_reader(user=creator) assert is_following(user=creator, obj=rs)
def test_session_create(client): user = UserFactory(is_staff=True) ws = WorkstationFactory() # Create some workstations and pretend that they're ready wsi_old = WorkstationImageFactory(workstation=ws, ready=True) wsi_new = WorkstationImageFactory(workstation=ws, ready=True) wsi_not_ready = WorkstationImageFactory(workstation=ws) wsi_other_ws = WorkstationImageFactory(ready=True) assert Session.objects.count() == 0 response = get_view_for_user( client=client, method=client.post, viewname="workstations:session-create", reverse_kwargs={"slug": ws.slug}, user=user, ) assert response.status_code == 302 sessions = Session.objects.all() assert len(sessions) == 1 # Should select the most recent workstation assert sessions[0].workstation_image == wsi_new assert sessions[0].creator == user
def test_workstations_staff_views(client, view): if view in [ "workstations:update", "workstations:detail", "workstations:image-create", "workstations:session-create", ]: reverse_kwargs = {"slug": WorkstationFactory().slug} elif view in ["workstations:image-detail", "workstations:image-update"]: wsi = WorkstationImageFactory() reverse_kwargs = {"slug": wsi.workstation.slug, "pk": wsi.pk} elif view in [ "workstations:session-detail", "workstations:session-update", ]: session = SessionFactory() reverse_kwargs = { "slug": session.workstation_image.workstation.slug, "pk": session.pk, } else: reverse_kwargs = {} validate_staff_only_view( client=client, viewname=view, reverse_kwargs=reverse_kwargs )
def test_algorithm_create(client, uploaded_image): # The algorithm creator should automatically get added to the editors group creator = get_algorithm_creator() VerificationFactory(user=creator, is_verified=True) ws = WorkstationFactory() ci = ComponentInterface.objects.get(slug="generic-medical-image") def try_create_algorithm(): return get_view_for_user( viewname="algorithms:create", client=client, method=client.post, data={ "title": "foo bar", "logo": uploaded_image(), "workstation": ws.pk, "credits_per_job": 1, "image_requires_gpu": False, "image_requires_memory_gb": 4, "inputs": [ci.pk], "outputs": [ComponentInterfaceFactory().pk], "contact_email": creator.email, "display_editors": True, "access_request_handling": AccessRequestHandlingOptions.MANUAL_REVIEW, "view_content": "{}", }, follow=True, user=creator, ) response = try_create_algorithm() assert "error_1_id_workstation" in response.rendered_content # The editor must have view permissions for the workstation to add it ws.add_user(user=creator) response = try_create_algorithm() assert "error_1_id_workstation" not in response.rendered_content assert response.status_code == 200 alg = Algorithm.objects.get(title="foo bar") assert alg.slug == "foo-bar" assert alg.is_editor(user=creator) assert not alg.is_user(user=creator) assert is_following(user=creator, obj=alg)
def workstation_set(): ws = WorkstationFactory() wsi = WorkstationImageFactory(workstation=ws) e, u, u1 = UserFactory(), UserFactory(), UserFactory() wss = WorkstationSet(workstation=ws, editor=e, user=u, user1=u1, image=wsi) wss.workstation.add_editor(user=e) wss.workstation.add_user(user=u) return wss
def test_workstationimage_create(client): u2 = UserFactory() VerificationFactory(user=u2, is_verified=True) w1 = WorkstationFactory() w2 = WorkstationFactory() w2.add_editor(user=u2) user_upload = UserUploadFactory(filename="test_image.tar.gz", creator=u2) user_upload.status = user_upload.StatusChoices.COMPLETED user_upload.save() assert w1.workstationimage_set.count() == 0 assert w2.workstationimage_set.count() == 0 response = get_view_for_user( client=client, method=client.post, viewname="workstations:image-create", reverse_kwargs={"slug": w2.slug}, user=u2, data={ "user_upload": user_upload.pk, "creator": u2.pk, "workstation": w2.pk, "initial_path": "a", "websocket_port": 1337, "http_port": 1234, }, ) assert response.status_code == 302 w1.refresh_from_db() w2.refresh_from_db() assert w1.workstationimage_set.count() == 0 w2_images = w2.workstationimage_set.all() assert len(w2_images) == 1 assert w2_images[0].creator == u2 assert w2_images[0].websocket_port == 1337 assert w2_images[0].http_port == 1234 assert w2_images[0].user_upload == user_upload assert w2_images[0].initial_path == "a"
def test_group_deletion_reverse(group): ws = WorkstationFactory() users_group = ws.users_group editors_group = ws.editors_group assert users_group assert editors_group getattr(ws, group).delete() with pytest.raises(ObjectDoesNotExist): users_group.refresh_from_db() with pytest.raises(ObjectDoesNotExist): editors_group.refresh_from_db() with pytest.raises(ObjectDoesNotExist): ws.refresh_from_db()
def test_workstation_list_view(client): w1, w2 = WorkstationFactory(), WorkstationFactory() user = UserFactory(is_staff=True) response = get_view_for_user( viewname="workstations:list", client=client, user=user ) assert w1.get_absolute_url() in response.rendered_content assert w2.get_absolute_url() in response.rendered_content w1.delete() response = get_view_for_user( viewname="workstations:list", client=client, user=user ) assert w1.get_absolute_url() not in response.rendered_content assert w2.get_absolute_url() in response.rendered_content
def test_group_deletion_reverse(group): ws = WorkstationFactory() users_group = ws.users_group editors_group = ws.editors_group assert users_group assert editors_group with pytest.raises(ProtectedError): getattr(ws, group).delete()
def test_archive_create(client, uploaded_image): # The archive creator should automatically get added to the editors group creator = UserFactory() add_archive_perm = Permission.objects.get( codename=f"add_{Archive._meta.model_name}" ) creator.user_permissions.add(add_archive_perm) ws = WorkstationFactory() def try_create_archive(): return get_view_for_user( viewname="archives:create", client=client, method=client.post, data={ "title": "foo bar", "logo": uploaded_image(), "workstation": ws.pk, "access_request_handling": AccessRequestHandlingOptions.MANUAL_REVIEW, "view_content": "{}", }, follow=True, user=creator, ) response = try_create_archive() assert "error_1_id_workstation" in response.rendered_content # The editor must have view permissions for the workstation to add it ws.add_user(user=creator) response = try_create_archive() assert "error_1_id_workstation" not in response.rendered_content assert response.status_code == 200 archive = Archive.objects.get(title="foo bar") assert archive.slug == "foo-bar" assert archive.is_editor(user=creator) assert not archive.is_user(user=creator) assert is_following(user=creator, obj=archive)
def workstation_set(): ws = WorkstationFactory() wsi = WorkstationImageFactory(workstation=ws) e, u, u1 = UserFactory(), UserFactory(), UserFactory() for user in [e, u, u1]: VerificationFactory(user=user, is_verified=True) wss = WorkstationSet(workstation=ws, editor=e, user=u, user1=u1, image=wsi) wss.workstation.add_editor(user=e) wss.workstation.add_user(user=u) return wss
def test_workstationimage_create(client): u2 = UserFactory() w1 = WorkstationFactory() w2 = WorkstationFactory() w2.add_editor(user=u2) staged_file = StagedFileFactory(file__filename="example.tar.gz") assert w1.workstationimage_set.count() == 0 assert w2.workstationimage_set.count() == 0 response = get_view_for_user( client=client, method=client.post, viewname="workstations:image-create", reverse_kwargs={"slug": w2.slug}, user=u2, data={ "chunked_upload": staged_file.file_id, "initial_path": "a", "websocket_port": 1337, "http_port": 1234, }, ) assert response.status_code == 302 w1.refresh_from_db() w2.refresh_from_db() assert w1.workstationimage_set.count() == 0 w2_images = w2.workstationimage_set.all() assert len(w2_images) == 1 assert w2_images[0].creator == u2 assert w2_images[0].websocket_port == 1337 assert w2_images[0].http_port == 1234 assert w2_images[0].staged_image_uuid == staged_file.file_id assert w2_images[0].initial_path == "a"
def test_workstation_update_view(client): w = WorkstationFactory() user = UserFactory(is_staff=True) title = "my Workstation" description = "my AWESOME workstation" assert w.title != title assert w.description is None response = get_view_for_user( client=client, method=client.post, viewname="workstations:update", reverse_kwargs={"slug": w.slug}, user=user, data={"title": title, "description": description}, ) w.refresh_from_db() assert response.status_code == 302 assert w.title == title assert w.description == description
def test_workstationimage_detail(client): user = UserFactory() ws = WorkstationFactory() wsi1, wsi2 = ( WorkstationImageFactory(workstation=ws), WorkstationImageFactory(workstation=ws), ) ws.add_editor(user=user) response = get_view_for_user( viewname="workstations:image-detail", reverse_kwargs={ "slug": ws.slug, "pk": wsi1.pk }, client=client, user=user, ) assert response.status_code == 200 assert str(wsi1.pk) in response.rendered_content assert str(wsi2.pk) not in response.rendered_content
def test_group_deletion(): ws = WorkstationFactory() users_group = ws.users_group editors_group = ws.editors_group assert users_group assert editors_group Workstation.objects.filter(pk__in=[ws.pk]).delete() with pytest.raises(ObjectDoesNotExist): users_group.refresh_from_db() with pytest.raises(ObjectDoesNotExist): editors_group.refresh_from_db()
def test_public_group_permissions(): g_reg_anon = Group.objects.get( name=settings.REGISTERED_AND_ANON_USERS_GROUP_NAME) g_reg = Group.objects.get(name=settings.REGISTERED_USERS_GROUP_NAME) workstation = WorkstationFactory() assert "view_workstation" not in get_perms(g_reg, workstation) assert "view_workstation" not in get_perms(g_reg_anon, workstation) workstation.public = True workstation.save() assert "view_workstation" in get_perms(g_reg, workstation) assert "view_workstation" not in get_perms(g_reg_anon, workstation) workstation.public = False workstation.save() assert "view_workstation" not in get_perms(g_reg, workstation) assert "view_workstation" not in get_perms(g_reg_anon, workstation)
def test_workstationimage_create(client): UserFactory() u2 = UserFactory(is_staff=True) w1 = WorkstationFactory() w2 = WorkstationFactory() staged_file = StagedFileFactory(file__filename="example.tar.gz") assert w1.workstationimage_set.count() == 0 assert w2.workstationimage_set.count() == 0 response = get_view_for_user( client=client, method=client.post, viewname="workstations:image-create", reverse_kwargs={"slug": w2.slug}, user=u2, data={ "chunked_upload": staged_file.file_id, "initial_path": "", "websocket_port": 1337, "http_port": 1234, }, ) assert response.status_code == 302 w1.refresh_from_db() w2.refresh_from_db() assert w1.workstationimage_set.count() == 0 w2_images = w2.workstationimage_set.all() assert len(w2_images) == 1 assert w2_images[0].creator == u2 assert w2_images[0].websocket_port == 1337 assert w2_images[0].http_port == 1234 assert w2_images[0].staged_image_uuid == staged_file.file_id assert w2_images[0].initial_path == ""
def test_reader_study_create(client, uploaded_image): # The study creator should automatically get added to the editors group creator = get_rs_creator() ws = WorkstationFactory() def try_create_rs( allow_case_navigation=False, shuffle_hanging_list=False, roll_over_answers_for_n_cases=0, ): return get_view_for_user( viewname="reader-studies:create", client=client, method=client.post, data={ "title": "foo bar", "logo": uploaded_image(), "workstation": ws.pk, "allow_answer_modification": True, "shuffle_hanging_list": shuffle_hanging_list, "allow_case_navigation": allow_case_navigation, "access_request_handling": AccessRequestHandlingOptions.MANUAL_REVIEW, "roll_over_answers_for_n_cases": roll_over_answers_for_n_cases, }, follow=True, user=creator, ) response = try_create_rs() assert "error_1_id_workstation" in response.rendered_content # The editor must have view permissions for the workstation to add it ws.add_user(user=creator) roll_over_error = "Rolling over answers should not be used together with case navigation or shuffling of the hanging list" for navigation, shuffle in [(True, True), (True, False), (False, True)]: response = try_create_rs( allow_case_navigation=navigation, shuffle_hanging_list=shuffle, roll_over_answers_for_n_cases=1, ) assert "error_1_id_workstation" not in response.rendered_content assert roll_over_error in response.rendered_content response = try_create_rs(roll_over_answers_for_n_cases=1) assert "error_1_id_workstation" not in response.rendered_content assert roll_over_error not in response.rendered_content assert response.status_code == 200 case_navigation_error = ( "Case navigation is required when answer modification is allowed" ) response = try_create_rs(allow_case_navigation=False) assert "error_1_id_workstation" not in response.rendered_content assert case_navigation_error in response.rendered_content response = try_create_rs(allow_case_navigation=True) assert "error_1_id_workstation" not in response.rendered_content assert case_navigation_error not in response.rendered_content assert response.status_code == 200 rs = ReaderStudy.objects.get(title="foo bar") assert rs.slug == "foo-bar" assert rs.is_editor(user=creator) assert not rs.is_reader(user=creator) assert is_following(user=creator, obj=rs)