def test_changing_archive_updates_permissions():
    ai = ArchiveItemFactory()
    im = ImageFactory()
    civ = ComponentInterfaceValueFactory(image=im)

    with capture_on_commit_callbacks(execute=True):
        ai.values.set([civ])

    assert get_groups_with_set_perms(im) == {
        ai.archive.editors_group: {"view_image"},
        ai.archive.uploaders_group: {"view_image"},
        ai.archive.users_group: {"view_image"},
    }

    a2 = ArchiveFactory()

    ai.archive = a2

    with capture_on_commit_callbacks(execute=True):
        ai.save()

    assert get_groups_with_set_perms(im) == {
        a2.editors_group: {"view_image"},
        a2.uploaders_group: {"view_image"},
        a2.users_group: {"view_image"},
    }
示例#2
0
def test_api_archive_item_interface_type_update(client, settings):
    # Override the celery settings
    settings.task_eager_propagates = (True, )
    settings.task_always_eager = (True, )

    archive = ArchiveFactory()
    editor = UserFactory()
    archive.add_editor(editor)
    item = ArchiveItemFactory(archive=archive)

    session, _ = create_raw_upload_image_session(images=["image10x10x10.mha"],
                                                 user=editor)
    session.refresh_from_db()
    im = session.image_set.get()
    ci = ComponentInterfaceFactory(
        kind=InterfaceKind.InterfaceKindChoices.IMAGE)
    civ = ComponentInterfaceValueFactory(interface=ci, image=im)
    item.values.add(civ)
    civ.image.update_viewer_groups_permissions()
    assert item.values.count() == 1

    # change interface type from generic medical image to generic overlay
    # for the already uploaded image
    with capture_on_commit_callbacks(execute=True):
        response = get_view_for_user(
            viewname="api:archives-item-detail",
            reverse_kwargs={"pk": item.pk},
            data={
                "values": [{
                    "interface": "generic-overlay",
                    "image": im.api_url
                }]
            },
            user=editor,
            client=client,
            method=client.patch,
            content_type="application/json",
            HTTP_X_FORWARDED_PROTO="https",
        )
    assert response.status_code == 200
    assert response.json()["pk"] == str(item.pk)
    item.refresh_from_db()
    # check that the old item was removed and a new one was added with the same
    # image but the new interface type
    assert item.values.count() == 1
    new_civ = item.values.get()
    assert new_civ.interface.slug == "generic-overlay"
    assert new_civ.image == im
    assert new_civ != civ
示例#3
0
def test_api_archive_item_update_permissions(client, settings, add_to_group,
                                             status):
    # Override the celery settings
    settings.task_eager_propagates = (True, )
    settings.task_always_eager = (True, )

    archive = ArchiveFactory()
    user = UserFactory()
    item = ArchiveItemFactory(archive=archive)

    if add_to_group:
        add_to_group(archive, user)

    ci = ComponentInterfaceFactory(
        kind=InterfaceKind.InterfaceKindChoices.BOOL)

    with capture_on_commit_callbacks(execute=True):
        response = get_view_for_user(
            viewname="api:archives-item-detail",
            reverse_kwargs={"pk": item.pk},
            data={"values": [{
                "interface": ci.slug,
                "value": True
            }]},
            user=user,
            client=client,
            method=client.patch,
            content_type="application/json",
            HTTP_X_FORWARDED_PROTO="https",
        )
    assert response.status_code == status
示例#4
0
def test_user_upload_to_archive_item_without_interface(client, settings):
    # Override the celery settings
    settings.task_eager_propagates = (True, )
    settings.task_always_eager = (True, )

    user = UserFactory()
    archive = ArchiveFactory()
    archive.add_editor(user=user)
    ci = ComponentInterface.objects.filter(slug="generic-overlay").get()
    civ = ComponentInterfaceValueFactory(interface=ci)
    item = ArchiveItemFactory(archive=archive)
    item.values.add(civ)
    assert item.values.count() == 1

    upload = create_upload_from_file(
        file_path=Path(__file__).parent / "resources" / "image10x10x10.mha",
        creator=user,
    )
    with capture_on_commit_callbacks(execute=True):
        response = get_view_for_user(
            viewname="api:upload-session-list",
            user=user,
            client=client,
            method=client.post,
            content_type="application/json",
            data={
                "uploads": [upload.api_url],
                "archive_item": item.pk
            },
            HTTP_X_FORWARDED_PROTO="https",
        )

    assert response.status_code == 400
    assert ("An interface needs to be defined to upload to an archive item."
            in response.json()["non_field_errors"])
    def test_job_permissions_for_challenge(self):
        ai = AlgorithmImageFactory(ready=True)
        archive = ArchiveFactory()
        evaluation = EvaluationFactory(submission__phase__archive=archive,
                                       submission__algorithm_image=ai)

        # Fake an image upload via a session
        u = UserFactory()
        s = UploadSessionFactory(creator=u)
        im = ImageFactory()
        s.image_set.set([im])

        civ = ComponentInterfaceValueFactory(image=im)
        archive_item = ArchiveItemFactory(archive=archive)
        with capture_on_commit_callbacks(execute=True):
            archive_item.values.add(civ)

        create_algorithm_jobs_for_evaluation(evaluation_pk=evaluation.pk)

        job = Job.objects.get()

        # Only the challenge admins and job viewers should be able to view the
        # job. NOTE: NOT THE ALGORITHM EDITORS, they are the participants
        # to the challenge and should not be able to see the test data
        assert get_groups_with_set_perms(job) == {
            evaluation.submission.phase.challenge.admins_group: {"view_job"},
            job.viewers: {"view_job"},
        }
        # No-one should be able to change the job
        assert (get_users_with_perms(job,
                                     attach_perms=True,
                                     with_group_users=False) == {})
        # No-one should be in the viewers group
        assert {*job.viewers.user_set.all()} == set()
示例#6
0
def test_view_permission_when_reused(in_archive, in_rs, in_job):
    """When an image is reused it should have view_image set correctly"""
    im = ImageFactory()

    job = AlgorithmJobFactory()
    rs = ReaderStudyFactory(use_display_sets=False)
    archive = ArchiveFactory()

    if in_archive:
        civ = ComponentInterfaceValueFactory(image=im)
        ai = ArchiveItemFactory(archive=archive)
        with capture_on_commit_callbacks(execute=True):
            ai.values.add(civ)
    if in_rs:
        rs.images.add(im)
    if in_job:
        civ = ComponentInterfaceValueFactory(image=im)
        job.inputs.add(civ)

    assert ("view_image" in get_perms(archive.editors_group, im)) is in_archive
    assert ("view_image" in get_perms(archive.uploaders_group,
                                      im)) is in_archive
    assert ("view_image" in get_perms(archive.users_group, im)) is in_archive

    assert ("view_image" in get_perms(rs.editors_group, im)) is in_rs
    assert ("view_image" in get_perms(rs.readers_group, im)) is in_rs

    for g in job.viewer_groups.all():
        assert ("view_image" in get_perms(g, im)) is in_job
示例#7
0
def test_civ_file_download(client):
    """Only viewers of the job should be allowed to download result files."""
    detection_interface = ComponentInterface(
        store_in_database=False,
        relative_path="detection_results.json",
        slug="detection-results",
        title="Detection Results",
        kind=ComponentInterface.Kind.ANY,
    )
    detection_interface.save()
    output_civ = ComponentInterfaceValue.objects.create(
        interface=detection_interface)
    detection = {
        "detected points": [{
            "type": "Point",
            "start": [0, 1, 2],
            "end": [3, 4, 5]
        }]
    }
    output_civ.file.save(
        "detection_results.json",
        ContentFile(
            bytes(json.dumps(detection, ensure_ascii=True, indent=2),
                  "utf-8")),
    )
    user1, user2 = UserFactory(), UserFactory()

    def has_correct_access(user_allowed, user_denied, url):
        tests = [(403, None), (302, user_allowed), (403, user_denied)]

        for test in tests:
            response = get_view_for_user(url=url, client=client, user=test[1])
            assert response.status_code == test[0]

    # test algorithm
    job = AlgorithmJobFactory(creator=user1)
    job.algorithm_image.algorithm.outputs.add(detection_interface)
    job.outputs.add(output_civ)

    has_correct_access(user1, user2, job.outputs.first().file.url)
    job.outputs.remove(output_civ)

    # test evaluation
    evaluation = EvaluationFactory()
    evaluation.output_interfaces.add(detection_interface)
    evaluation.outputs.add(output_civ)
    assign_perm("view_evaluation", user1, evaluation)
    has_correct_access(user1, user2, evaluation.outputs.first().file.url)
    evaluation.outputs.remove(output_civ)

    # test archive
    archive = ArchiveFactory()
    archive_item = ArchiveItemFactory(archive=archive)
    archive_item.values.add(output_civ)
    archive.add_editor(user1)
    has_correct_access(user1, user2, archive_item.values.first().file.url)
    archive.remove_editor(user1)
    archive.add_user(user1)
    has_correct_access(user1, user2, archive_item.values.first().file.url)
    archive.remove_user(user1)
示例#8
0
def test_api_archive_item_retrieve_permissions(client):
    archive = ArchiveFactory()
    editor, user = UserFactory(), UserFactory()
    archive.add_editor(editor)
    i1 = ArchiveItemFactory(archive=archive)

    # editor can retrieve archive item
    response = get_view_for_user(
        viewname="api:archives-item-detail",
        reverse_kwargs={"pk": i1.pk},
        user=editor,
        client=client,
    )
    assert response.status_code == 200
    assert response.json()["pk"] == str(i1.pk)

    # user cannot retrieve archive item
    response = get_view_for_user(
        viewname="api:archives-item-detail",
        reverse_kwargs={"pk": i1.pk},
        user=user,
        client=client,
    )
    assert response.status_code == 404

    # add user to archive
    archive.add_user(user)
    response = get_view_for_user(
        viewname="api:archives-item-detail",
        reverse_kwargs={"pk": i1.pk},
        user=user,
        client=client,
    )
    assert response.status_code == 200
    assert response.json()["pk"] == str(i1.pk)
def test_deleting_archive_item_removes_permissions():
    ai1, ai2 = ArchiveItemFactory.create_batch(2)
    im = ImageFactory()
    civ = ComponentInterfaceValueFactory(image=im)

    with capture_on_commit_callbacks(execute=True):
        ai1.values.set([civ])
        ai2.values.set([civ])

    assert get_groups_with_set_perms(im) == {
        ai1.archive.editors_group: {"view_image"},
        ai1.archive.uploaders_group: {"view_image"},
        ai1.archive.users_group: {"view_image"},
        ai2.archive.editors_group: {"view_image"},
        ai2.archive.uploaders_group: {"view_image"},
        ai2.archive.users_group: {"view_image"},
    }

    with capture_on_commit_callbacks(execute=True):
        ai1.delete()

    assert get_groups_with_set_perms(im) == {
        ai2.archive.editors_group: {"view_image"},
        ai2.archive.uploaders_group: {"view_image"},
        ai2.archive.users_group: {"view_image"},
    }
示例#10
0
    def setUp(self):
        interface = ComponentInterface.objects.get(
            slug="generic-medical-image")

        archive = ArchiveFactory()
        ais = ArchiveItemFactory.create_batch(2)
        archive.items.set(ais)

        input_civs = ComponentInterfaceValueFactory.create_batch(
            2, interface=interface)
        output_civs = ComponentInterfaceValueFactory.create_batch(
            2, interface=interface)

        for ai, civ in zip(ais, input_civs):
            ai.values.set([civ])

        alg = AlgorithmImageFactory()
        submission = SubmissionFactory(algorithm_image=alg)
        submission.phase.archive = archive
        submission.phase.save()
        submission.phase.algorithm_inputs.set([interface])

        jobs = []
        for inpt, output in zip(input_civs, output_civs):
            j = AlgorithmJobFactory(status=Job.SUCCESS, algorithm_image=alg)
            j.inputs.set([inpt])
            j.outputs.set([output])
            jobs.append(j)

        self.evaluation = EvaluationFactory(
            submission=submission, status=Evaluation.EXECUTING_PREREQUISITES)
        self.jobs = jobs
        self.output_civs = output_civs
示例#11
0
def test_user_upload_to_archive_item_with_new_interface(client, settings):
    # Override the celery settings
    settings.task_eager_propagates = (True, )
    settings.task_always_eager = (True, )

    user = UserFactory()
    archive = ArchiveFactory()
    archive.add_editor(user=user)
    ci = ComponentInterfaceFactory(kind=ComponentInterface.Kind.STRING,
                                   title="Test")
    civ = ComponentInterfaceValueFactory(interface=ci)
    item = ArchiveItemFactory(archive=archive)
    item.values.add(civ)
    assert item.values.count() == 1

    upload = create_upload_from_file(
        file_path=Path(__file__).parent / "resources" / "image10x10x10.mha",
        creator=user,
    )

    with capture_on_commit_callbacks(execute=True):
        response = get_view_for_user(
            viewname="api:upload-session-list",
            user=user,
            client=client,
            method=client.post,
            content_type="application/json",
            data={
                "uploads": [upload.api_url],
                "archive_item": item.pk,
                "interface": "generic-overlay",
            },
            HTTP_X_FORWARDED_PROTO="https",
        )

    assert response.status_code == 201
    upload_session = response.json()
    assert upload_session["uploads"] == [upload.api_url]
    item.refresh_from_db()
    assert item.values.count() == 2
    assert "generic-overlay" in [
        item.interface.slug for item in item.values.all()
    ]
示例#12
0
def test_user_upload_to_archive_item_with_existing_interface(client, settings):
    # Override the celery settings
    settings.task_eager_propagates = (True, )
    settings.task_always_eager = (True, )

    user = UserFactory()
    archive = ArchiveFactory()
    archive.add_editor(user=user)
    ci = ComponentInterface.objects.filter(slug="generic-overlay").get()
    civ = ComponentInterfaceValueFactory(interface=ci)
    item = ArchiveItemFactory(archive=archive)
    item.values.add(civ)
    assert item.values.count() == 1

    # upload another generic-overlay to the same item
    upload = create_upload_from_file(
        file_path=Path(__file__).parent / "resources" / "image10x10x10.mha",
        creator=user,
    )
    with capture_on_commit_callbacks(execute=True):
        response = get_view_for_user(
            viewname="api:upload-session-list",
            user=user,
            client=client,
            method=client.post,
            content_type="application/json",
            data={
                "uploads": [upload.api_url],
                "archive_item": item.pk,
                "interface": "generic-overlay",
            },
            HTTP_X_FORWARDED_PROTO="https",
        )
    assert response.status_code == 201
    item.refresh_from_db()
    # check that there is only one civ with the generic-overlay interface
    assert item.values.filter(interface__slug="generic-overlay").count() == 1
    # and that the previously added one is no longer associated with the item
    assert civ not in item.values.all()
示例#13
0
def test_api_archive_item_list_is_filtered(client):
    a1, a2 = ArchiveFactory(), ArchiveFactory()
    a1_editor, user = UserFactory(), UserFactory()
    a1.add_editor(a1_editor)
    _, _ = (ArchiveItemFactory(archive=a1), ArchiveItemFactory(archive=a1))
    i3 = ArchiveItemFactory(archive=a2)

    # user does not see any archive items
    response = get_view_for_user(viewname="api:archives-item-list",
                                 user=user,
                                 client=client)
    assert response.status_code == 200
    assert response.json()["count"] == 0

    # editor of archive 1 sees the items from archive 1, but not from archive 2
    response = get_view_for_user(viewname="api:archives-item-list",
                                 user=a1_editor,
                                 client=client)
    assert response.status_code == 200
    assert response.json()["count"] == 2
    assert i3.id not in (
        response.json()["results"][0]["pk"],
        response.json()["results"][1]["pk"],
    )
示例#14
0
    def setUp(self) -> None:
        self.method = MethodFactory(ready=True,
                                    phase__archive=ArchiveFactory())
        self.algorithm_image = AlgorithmImageFactory()

        interface = ComponentInterfaceFactory()
        self.algorithm_image.algorithm.inputs.set([interface])

        self.images = ImageFactory.create_batch(3)

        for image in self.images[:2]:
            civ = ComponentInterfaceValueFactory(image=image,
                                                 interface=interface)
            ai = ArchiveItemFactory(archive=self.method.phase.archive)
            ai.values.add(civ)
def test_archive_item_permissions_signal(client, reverse):  # noqa: C901
    ai1, ai2 = ArchiveItemFactory.create_batch(2)
    im1, im2, im3, im4 = ImageFactory.create_batch(4)

    civ1, civ2, civ3, civ4 = (
        ComponentInterfaceValueFactory(image=im1),
        ComponentInterfaceValueFactory(image=im2),
        ComponentInterfaceValueFactory(image=im3),
        ComponentInterfaceValueFactory(image=im4),
    )

    with capture_on_commit_callbacks(execute=True):
        if reverse:
            for civ in [civ1, civ2, civ3, civ4]:
                civ.archive_items.add(ai1, ai2)
            for civ in [civ3, civ4]:
                civ.archive_items.remove(ai1, ai2)
            for civ in [civ1, civ2]:
                civ.archive_items.remove(ai2)
        else:
            # Test that adding images works
            ai1.values.add(civ1, civ2, civ3, civ4)
            # Test that removing images works
            ai1.values.remove(civ3, civ4)

    assert get_groups_with_set_perms(im1) == {
        ai1.archive.editors_group: {"view_image"},
        ai1.archive.uploaders_group: {"view_image"},
        ai1.archive.users_group: {"view_image"},
    }
    assert get_groups_with_set_perms(im2) == {
        ai1.archive.editors_group: {"view_image"},
        ai1.archive.uploaders_group: {"view_image"},
        ai1.archive.users_group: {"view_image"},
    }
    assert get_groups_with_set_perms(im3) == {}
    assert get_groups_with_set_perms(im4) == {}

    # Test clearing
    with capture_on_commit_callbacks(execute=True):
        if reverse:
            civ1.archive_items.clear()
            civ2.archive_items.clear()
        else:
            ai1.values.clear()

    assert get_groups_with_set_perms(im1) == {}
    assert get_groups_with_set_perms(im2) == {}
示例#16
0
def test_api_archive_item_add_and_update_value(client, settings):
    # Override the celery settings
    settings.task_eager_propagates = (True, )
    settings.task_always_eager = (True, )

    archive = ArchiveFactory()
    editor = UserFactory()
    archive.add_editor(editor)
    item = ArchiveItemFactory(archive=archive)
    ci = ComponentInterfaceFactory(
        kind=InterfaceKind.InterfaceKindChoices.BOOL)
    # add civ
    with capture_on_commit_callbacks(execute=True):
        response = get_view_for_user(
            viewname="api:archives-item-detail",
            reverse_kwargs={"pk": item.pk},
            data={"values": [{
                "interface": ci.slug,
                "value": True
            }]},
            user=editor,
            client=client,
            method=client.patch,
            content_type="application/json",
            HTTP_X_FORWARDED_PROTO="https",
        )
    assert response.status_code == 200
    assert response.json()["pk"] == str(item.pk)
    item.refresh_from_db()
    assert item.values.count() == 1
    civ = item.values.get()
    assert civ.interface.slug == ci.slug
    assert civ.value
    #  update civ
    with capture_on_commit_callbacks(execute=True):
        response = get_view_for_user(
            viewname="api:archives-item-detail",
            reverse_kwargs={"pk": item.pk},
            data={"values": [{
                "interface": ci.slug,
                "value": False
            }]},
            user=editor,
            client=client,
            method=client.patch,
            content_type="application/json",
            HTTP_X_FORWARDED_PROTO="https",
        )
    assert response.status_code == 200
    assert response.json()["pk"] == str(item.pk)
    item.refresh_from_db()
    assert item.values.count() == 1
    new_civ = item.values.get()
    assert new_civ.interface.slug == ci.slug
    assert new_civ != civ
    def test_job_permissions_for_archive(self):
        ai = AlgorithmImageFactory(ready=True)
        archive = ArchiveFactory()

        # Fake an image upload via a session
        u = UserFactory()
        s = UploadSessionFactory(creator=u)
        im = ImageFactory()
        s.image_set.set([im])

        civ = ComponentInterfaceValueFactory(
            image=im, interface=ai.algorithm.inputs.get())
        archive_item = ArchiveItemFactory(archive=archive)
        with capture_on_commit_callbacks(execute=True):
            archive_item.values.add(civ)

        archive.algorithms.set([ai.algorithm])

        create_algorithm_jobs_for_archive(archive_pks=[archive.pk])

        job = Job.objects.get()

        # The archive editors, users and uploaders and job
        # viewers should be able to view the job.
        # NOTE: NOT THE ALGORITHM EDITORS, if they need
        # access the job can be shared with them.
        assert get_groups_with_set_perms(job) == {
            archive.editors_group: {"view_job"},
            archive.users_group: {"view_job"},
            archive.uploaders_group: {"view_job"},
            job.viewers: {"view_job"},
        }
        # No-one should be able to change the job
        assert (get_users_with_perms(job,
                                     attach_perms=True,
                                     with_group_users=False) == {})
        # No-one should be in the viewers group
        assert {*job.viewers.user_set.all()} == set()
示例#18
0
def test_workstation_query(settings):
    image, overlay = ImageFactory(), ImageFactory()
    reader_study = ReaderStudyFactory(
        workstation_config=WorkstationConfigFactory())
    algorithm_job = AlgorithmJobFactory()
    config = WorkstationConfigFactory()
    archive_item = ArchiveItemFactory()

    qs = workstation_query(image=image)
    assert "&" not in qs
    assert f"{settings.WORKSTATIONS_BASE_IMAGE_QUERY_PARAM}={image.pk}" in qs
    assert (f"{settings.WORKSTATIONS_OVERLAY_QUERY_PARAM}={overlay.pk}"
            not in qs)
    assert f"{settings.WORKSTATIONS_CONFIG_QUERY_PARAM}={config.pk}" not in qs

    qs = workstation_query(image=image, overlay=overlay)
    assert "&" in qs
    assert f"{settings.WORKSTATIONS_BASE_IMAGE_QUERY_PARAM}={image.pk}" in qs
    assert f"{settings.WORKSTATIONS_OVERLAY_QUERY_PARAM}={overlay.pk}" in qs
    assert f"{settings.WORKSTATIONS_CONFIG_QUERY_PARAM}={config.pk}" not in qs

    qs = workstation_query(image=image, config=config)
    assert "&" in qs
    assert f"{settings.WORKSTATIONS_BASE_IMAGE_QUERY_PARAM}={image.pk}" in qs
    assert (f"{settings.WORKSTATIONS_OVERLAY_QUERY_PARAM}={overlay.pk}"
            not in qs)
    assert f"{settings.WORKSTATIONS_CONFIG_QUERY_PARAM}={config.pk}" in qs

    qs = workstation_query(reader_study=reader_study)
    assert "&" in qs
    assert (
        f"{settings.WORKSTATIONS_READY_STUDY_QUERY_PARAM}={reader_study.pk}"
        in qs)
    assert (
        f"{settings.WORKSTATIONS_CONFIG_QUERY_PARAM}={reader_study.workstation_config.pk}"
        in qs)
    assert f"{settings.WORKSTATIONS_CONFIG_QUERY_PARAM}={config.pk}" not in qs

    qs = workstation_query(reader_study=reader_study, config=config)
    assert "&" in qs
    assert (
        f"{settings.WORKSTATIONS_READY_STUDY_QUERY_PARAM}={reader_study.pk}"
        in qs)
    assert (
        f"{settings.WORKSTATIONS_CONFIG_QUERY_PARAM}={reader_study.workstation_config.pk}"
        not in qs)
    assert f"{settings.WORKSTATIONS_CONFIG_QUERY_PARAM}={config.pk}" in qs

    reader_study.workstation_config = None

    qs = workstation_query(reader_study=reader_study)
    assert "&" not in qs
    assert (
        f"{settings.WORKSTATIONS_READY_STUDY_QUERY_PARAM}={reader_study.pk}"
        in qs)
    assert f"{settings.WORKSTATIONS_CONFIG_QUERY_PARAM}" not in qs

    qs = workstation_query(algorithm_job=algorithm_job)
    assert "&" not in qs
    assert (
        f"{settings.WORKSTATIONS_ALGORITHM_JOB_QUERY_PARAM}={algorithm_job.pk}"
        in qs)

    qs = workstation_query(algorithm_job=algorithm_job, config=config)
    assert "&" in qs
    assert (
        f"{settings.WORKSTATIONS_ALGORITHM_JOB_QUERY_PARAM}={algorithm_job.pk}"
        in qs)
    assert f"{settings.WORKSTATIONS_CONFIG_QUERY_PARAM}={config.pk}" in qs

    qs = workstation_query(archive_item=archive_item, config=config)
    assert "&" in qs
    assert (
        f"{settings.WORKSTATIONS_ARCHIVE_ITEM_QUERY_PARAM}={archive_item.pk}"
        in qs)
    assert f"{settings.WORKSTATIONS_CONFIG_QUERY_PARAM}={config.pk}" in qs

    qs = workstation_query(archive_item=archive_item)
    assert "&" not in qs
    assert (
        f"{settings.WORKSTATIONS_ARCHIVE_ITEM_QUERY_PARAM}={archive_item.pk}"
        in qs)
    assert f"{settings.WORKSTATIONS_CONFIG_QUERY_PARAM}" not in qs
示例#19
0
def test_archive_items_to_reader_study_update_form(client, settings):
    settings.task_eager_propagates = (True,)
    settings.task_always_eager = (True,)
    archive = ArchiveFactory()
    rs1, rs2 = ReaderStudyFactory(use_display_sets=True), ReaderStudyFactory(
        use_display_sets=False
    )

    editor, reader = UserFactory(), UserFactory()
    archive.editors_group.user_set.add(editor)
    rs1.add_editor(editor)
    rs1.add_reader(reader)

    rs2.add_editor(editor)

    im1, im2, im3, im4 = ImageFactory.create_batch(4)
    overlay = ComponentInterface.objects.get(slug="generic-overlay")
    image = ComponentInterface.objects.get(slug="generic-medical-image")

    civ1, civ2, civ3, civ4 = (
        ComponentInterfaceValueFactory(interface=image, image=im1),
        ComponentInterfaceValueFactory(interface=image, image=im2),
        ComponentInterfaceValueFactory(interface=overlay, image=im3),
        ComponentInterfaceValueFactory(interface=overlay, image=im4),
    )

    ai1 = ArchiveItemFactory(archive=archive)
    ai2 = ArchiveItemFactory(archive=archive)

    ai1.values.add(civ1)
    ai2.values.add(civ2)

    assert rs1.display_sets.count() == 0

    response = get_view_for_user(
        viewname="archives:items-reader-study-update",
        client=client,
        method=client.post,
        data={"items": [ai1.pk, ai2.pk], "reader_study": rs1.pk},
        reverse_kwargs={"slug": archive.slug},
        follow=True,
        user=reader,
    )

    assert response.status_code == 403
    assert rs1.display_sets.count() == 0

    response = get_view_for_user(
        viewname="archives:items-reader-study-update",
        client=client,
        method=client.post,
        data={"items": [ai1.pk, ai2.pk], "reader_study": rs1.pk},
        reverse_kwargs={"slug": archive.slug},
        follow=True,
        user=editor,
    )

    assert response.status_code == 200
    assert rs1.display_sets.count() == 2
    assert sorted(
        list(rs1.display_sets.values_list("values", flat=True))
    ) == sorted([civ1.pk, civ2.pk])

    assert rs2.display_sets.count() == 0
    response = get_view_for_user(
        viewname="archives:items-reader-study-update",
        client=client,
        method=client.post,
        data={"items": [ai1.pk, ai2.pk], "reader_study": rs2.pk},
        reverse_kwargs={"slug": archive.slug},
        follow=True,
        user=editor,
    )

    assert response.status_code == 200
    assert rs2.display_sets.count() == 0

    ai1.values.add(civ3)
    ai2.values.add(civ4)

    response = get_view_for_user(
        viewname="archives:items-reader-study-update",
        client=client,
        method=client.post,
        data={"items": [ai1.pk, ai2.pk], "reader_study": rs1.pk},
        reverse_kwargs={"slug": archive.slug},
        follow=True,
        user=editor,
    )

    assert response.status_code == 200
    assert rs1.display_sets.count() == 4
    assert sorted(
        sorted(list(ds.values.values_list("pk", flat=True)))
        for ds in rs1.display_sets.all()
    ) == sorted([[civ1.pk], [civ2.pk], [civ1.pk, civ3.pk], [civ2.pk, civ4.pk]])
示例#20
0
def add_image_to_archive(image, archive):
    interface = ComponentInterfaceFactory()
    civ = ComponentInterfaceValueFactory(interface=interface, image=image)
    item = ArchiveItemFactory(archive=archive)
    item.values.set([civ])
示例#21
0
def test_archive_items_to_reader_study_update(client, settings):
    settings.task_eager_propagates = (True, )
    settings.task_always_eager = (True, )
    archive = ArchiveFactory()
    rs1 = ReaderStudyFactory(use_display_sets=True)
    rs2 = ReaderStudyFactory(use_display_sets=False)

    editor, user = UserFactory(), UserFactory()
    archive.add_user(user)
    archive.add_editor(editor)
    rs1.add_editor(editor)
    rs2.add_editor(editor)

    im1, im2, im3, im4 = ImageFactory.create_batch(4)
    overlay = ComponentInterface.objects.get(slug="generic-overlay")
    image = ComponentInterface.objects.get(slug="generic-medical-image")

    civ1, civ2, civ3, civ4 = (
        ComponentInterfaceValueFactory(interface=image, image=im1),
        ComponentInterfaceValueFactory(interface=image, image=im2),
        ComponentInterfaceValueFactory(interface=overlay, image=im3),
        ComponentInterfaceValueFactory(interface=overlay, image=im4),
    )

    ai1 = ArchiveItemFactory(archive=archive)
    ai2 = ArchiveItemFactory(archive=archive)

    ai1.values.add(civ1)
    ai2.values.add(civ2)

    response = get_view_for_user(
        viewname="archives:items-reader-study-update",
        client=client,
        reverse_kwargs={"slug": archive.slug},
        user=user,
    )
    assert response.status_code == 200
    assert str(rs1.pk) not in response.rendered_content
    assert str(rs2.pk) not in response.rendered_content

    response = get_view_for_user(
        viewname="archives:items-reader-study-update",
        client=client,
        reverse_kwargs={"slug": archive.slug},
        follow=True,
        user=editor,
    )

    assert response.status_code == 200
    assert str(rs1.pk) in response.rendered_content
    assert str(rs2.pk) not in response.rendered_content

    assert im1.name in response.rendered_content
    assert im2.name in response.rendered_content
    assert im3.name not in response.rendered_content
    assert im4.name not in response.rendered_content

    ai1.values.add(civ3)
    ai2.values.add(civ4)

    response = get_view_for_user(
        viewname="archives:items-reader-study-update",
        client=client,
        reverse_kwargs={"slug": archive.slug},
        follow=True,
        user=editor,
    )

    assert response.status_code == 200

    assert f"{im1.name}, {im3.name}" in response.rendered_content
    assert f"{im2.name}, {im4.name}" in response.rendered_content
def test_adding_images_triggers_task(reverse, mocker):
    mocker.patch(
        "grandchallenge.algorithms.tasks.create_algorithm_jobs_for_archive.apply_async"
    )
    create_algorithm_jobs_for_archive.apply_async.assert_not_called()

    arch_set = TwoArchives()

    with capture_on_commit_callbacks(execute=True):
        ai1, ai2 = (
            ArchiveItemFactory(archive=arch_set.arch1),
            ArchiveItemFactory(archive=arch_set.arch2),
        )
        ai1.values.set([ComponentInterfaceValueFactory()])
        ai2.values.set([ComponentInterfaceValueFactory()])
    create_algorithm_jobs_for_archive.apply_async.assert_has_calls(
        [
            call(
                kwargs={
                    "archive_pks": [arch_set.arch1.pk],
                    "archive_item_pks": [ai1.pk],
                }
            ),
            call(
                kwargs={
                    "archive_pks": [arch_set.arch2.pk],
                    "archive_item_pks": [ai2.pk],
                }
            ),
        ]
    )
    create_algorithm_jobs_for_archive.apply_async.reset_mock()
    ai1, ai2, ai3, ai4 = (
        ArchiveItemFactory(archive=arch_set.arch1),
        ArchiveItemFactory(archive=arch_set.arch1),
        ArchiveItemFactory(archive=arch_set.arch1),
        ArchiveItemFactory(archive=arch_set.arch1),
    )
    civ1, civ2, civ3, civ4 = (
        ComponentInterfaceValueFactory(),
        ComponentInterfaceValueFactory(),
        ComponentInterfaceValueFactory(),
        ComponentInterfaceValueFactory(),
    )

    if not reverse:
        for ai, civ in [(ai1, civ1), (ai2, civ2), (ai3, civ3), (ai4, civ4)]:
            with capture_on_commit_callbacks(execute=True):
                ai.values.set([civ])

            kwargs = create_algorithm_jobs_for_archive.apply_async.call_args.kwargs[
                "kwargs"
            ]
            create_algorithm_jobs_for_archive.apply_async.assert_called_once()
            assert {*kwargs["archive_pks"]} == {arch_set.arch1.pk}
            assert {*kwargs["archive_item_pks"]} == {ai.pk}
            create_algorithm_jobs_for_archive.apply_async.reset_mock()

            with capture_on_commit_callbacks(execute=True):
                ai.values.remove(civ)
                ai.values.clear()

            create_algorithm_jobs_for_archive.apply_async.assert_not_called()
    else:
        for ai in [ai1, ai2, ai3, ai4]:
            with capture_on_commit_callbacks(execute=True):
                civ = ComponentInterfaceValueFactory()
                civ.archive_items.add(ai)

            kwargs = create_algorithm_jobs_for_archive.apply_async.call_args.kwargs[
                "kwargs"
            ]
            create_algorithm_jobs_for_archive.apply_async.assert_called_once()
            assert {*kwargs["archive_pks"]} == {arch_set.arch1.pk}
            assert {*kwargs["archive_item_pks"]} == {ai.pk}
            create_algorithm_jobs_for_archive.apply_async.reset_mock()

        with capture_on_commit_callbacks(execute=True):
            civ3.archive_items.remove(ai3)
            civ1.archive_items.clear()

        create_algorithm_jobs_for_archive.apply_async.assert_not_called()
def create_archive_items_for_images(images, archive):
    for image in images:
        civ = ComponentInterfaceValueFactory(image=image)
        ai = ArchiveItemFactory(archive=archive)
        ai.values.add(civ)
示例#24
0
def test_archive_item_form(client, settings):
    # Override the celery settings
    settings.task_eager_propagates = (True,)
    settings.task_always_eager = (True,)

    archive = ArchiveFactory()

    editor = UserFactory()
    archive.editors_group.user_set.add(editor)

    ci = ComponentInterfaceFactory(
        kind=InterfaceKind.InterfaceKindChoices.BOOL
    )
    civ = ComponentInterfaceValueFactory(
        interface=ci, value=True, file=None, image=None
    )
    ai = ArchiveItemFactory(archive=archive)
    ai.values.add(civ)

    response = get_view_for_user(
        viewname="archives:item-edit",
        client=client,
        method=client.get,
        reverse_kwargs={"slug": archive.slug, "id": ai.pk},
        follow=True,
        user=editor,
    )
    assert response.status_code == 200

    for _ci in ComponentInterface.objects.all():
        assert _ci.slug in response.rendered_content

    assert f'id="id_{ci.slug}" checked' in response.rendered_content

    assert Job.objects.count() == 0

    alg = AlgorithmFactory()
    AlgorithmImageFactory(algorithm=alg, ready=True)
    alg.inputs.set([ci])
    with capture_on_commit_callbacks(execute=True):
        archive.algorithms.add(alg)

    assert Job.objects.count() == 1

    civ_count = ComponentInterfaceValue.objects.count()

    with capture_on_commit_callbacks(execute=True):
        with capture_on_commit_callbacks(execute=True):
            response = get_view_for_user(
                viewname="archives:item-edit",
                client=client,
                method=client.post,
                reverse_kwargs={"slug": archive.slug, "id": ai.pk},
                data={ci.slug: False},
                follow=True,
                user=editor,
            )

    assert ai.values.filter(pk=civ.pk).count() == 0
    # This should created a new CIV as they are immutable
    assert ComponentInterfaceValue.objects.count() == civ_count + 1

    # A new job should have been created, because the value for 'bool'
    # has changed
    assert Job.objects.count() == 2

    with capture_on_commit_callbacks(execute=True):
        with capture_on_commit_callbacks(execute=True):
            response = get_view_for_user(
                viewname="archives:item-edit",
                client=client,
                method=client.post,
                reverse_kwargs={"slug": archive.slug, "id": ai.pk},
                data={ci.slug: True},
                follow=True,
                user=editor,
            )

    # New jobs should be created as there is a new CIV
    assert Job.objects.count() == 3
    assert ComponentInterfaceValue.objects.count() == civ_count + 2