Esempio n. 1
0
def test_valid_schema_ok():
    i = ComponentInterfaceFactory(
        schema={"type": "object"},
        relative_path="test.json",
        kind=InterfaceKindChoices.ANY,
    )
    i.full_clean()
Esempio n. 2
0
def test_input_prefixes(tmp_path, settings):
    interfaces = [
        ComponentInterfaceFactory(
            kind=InterfaceKindChoices.BOOL, relative_path="test/bool.json"
        ),
        ComponentInterfaceFactory(
            kind=InterfaceKindChoices.IMAGE, relative_path="images/test-image"
        ),
        ComponentInterfaceFactory(
            kind=InterfaceKindChoices.CSV, relative_path="test.csv"
        ),
    ]
    civs = [
        ComponentInterfaceValueFactory(interface=interfaces[0], value=True),
        ComponentInterfaceValueFactory(
            interface=interfaces[1],
            image=ImageFileFactory(
                file__from_path=Path(__file__).parent.parent
                / "algorithms_tests"
                / "resources"
                / "input_file.tif"
            ).image,
        ),
        ComponentInterfaceValueFactory(interface=interfaces[2]),
    ]
    settings.COMPONENTS_AMAZON_ECS_NFS_MOUNT_POINT = tmp_path

    executor = AmazonECSExecutorStub(
        job_id="algorithms-job-00000000-0000-0000-0000-000000000000",
        exec_image_sha256="",
        exec_image_repo_tag="",
        memory_limit=4,
        time_limit=60,
        requires_gpu=False,
    )
    executor.provision(
        input_civs=civs,
        input_prefixes={
            str(civs[0].pk): "first/output/",
            str(civs[1].pk): "second/output",
        },
    )

    assert {str(f.relative_to(tmp_path)) for f in tmp_path.glob("**/*")} == {
        "algorithms",
        "algorithms/job",
        "algorithms/job/00000000-0000-0000-0000-000000000000",
        "algorithms/job/00000000-0000-0000-0000-000000000000/input",
        "algorithms/job/00000000-0000-0000-0000-000000000000/input/test.csv",
        "algorithms/job/00000000-0000-0000-0000-000000000000/input/first",
        "algorithms/job/00000000-0000-0000-0000-000000000000/input/first/output",
        "algorithms/job/00000000-0000-0000-0000-000000000000/input/first/output/test",
        "algorithms/job/00000000-0000-0000-0000-000000000000/input/first/output/test/bool.json",
        "algorithms/job/00000000-0000-0000-0000-000000000000/input/second",
        "algorithms/job/00000000-0000-0000-0000-000000000000/input/second/output",
        "algorithms/job/00000000-0000-0000-0000-000000000000/input/second/output/images",
        "algorithms/job/00000000-0000-0000-0000-000000000000/input/second/output/images/test-image",
        "algorithms/job/00000000-0000-0000-0000-000000000000/input/second/output/images/test-image/input_file.tif",
        "algorithms/job/00000000-0000-0000-0000-000000000000/output",
    }
Esempio n. 3
0
def test_invalid_schema_raises_error():
    i = ComponentInterfaceFactory(schema={"type": "whatevs"})
    with pytest.raises(ValidationError) as e:
        i.full_clean()
    assert str(e.value).startswith(
        "{'schema': [\"Invalid schema: 'whatevs' is not valid under any of the given schemas"
    )
Esempio n. 4
0
    def test_unmatched_interface_filter(self):
        ai = AlgorithmImageFactory()
        cis = ComponentInterfaceFactory.create_batch(2)
        ai.algorithm.inputs.set(cis)

        civ_sets = [
            {},  # No interfaces
            {ComponentInterfaceValueFactory(interface=cis[0])
             },  # Missing interface
            {
                # OK
                ComponentInterfaceValueFactory(interface=cis[0]),
                ComponentInterfaceValueFactory(interface=cis[1]),
            },
            {
                # Unmatched interface
                ComponentInterfaceValueFactory(interface=cis[0]),
                ComponentInterfaceValueFactory(
                    interface=ComponentInterfaceFactory()),
            },
        ]

        filtered_civ_sets = filter_civs_for_algorithm(civ_sets=civ_sets,
                                                      algorithm_image=ai)

        assert filtered_civ_sets == [civ_sets[2]]
Esempio n. 5
0
def test_no_uuid_validation():
    # For multi job inputs we add uuid prefixes, so check that the relative
    # path does not contain a UUID
    i = ComponentInterfaceFactory(
        relative_path=f"{uuid.uuid4()}/whatever.json",
        kind=InterfaceKindChoices.ANY,
    )
    with pytest.raises(ValidationError) as e:
        i.full_clean()
    assert str(e.value) == "{'relative_path': ['Enter a valid value.']}"
def test_save_in_object_store(kind, object_store_required):
    ci = ComponentInterfaceFactory(kind=kind, store_in_database=True)

    if object_store_required:
        assert ci.save_in_object_store is True
        ci.store_in_database = False
        assert ci.save_in_object_store is True
    else:
        assert ci.save_in_object_store is False
        ci.store_in_database = False
        assert ci.save_in_object_store is True
def test_algorithm_job_post_serializer_validations(
    title,
    add_user,
    image_ready,
    algorithm_interface_titles,
    job_interface_slugs,
    error_message,
    rf,
):
    # setup
    user = UserFactory()
    interfaces = {
        "TestInterface 1":
        ComponentInterfaceFactory(kind=ComponentInterface.Kind.STRING,
                                  title="TestInterface 1"),
        "TestInterface 2":
        ComponentInterfaceFactory(kind=ComponentInterface.Kind.STRING,
                                  title="TestInterface 2"),
    }
    algorithm_image = AlgorithmImageFactory(ready=image_ready)
    algorithm_image.algorithm.title = title
    algorithm_image.algorithm.inputs.set(
        [interfaces[title] for title in algorithm_interface_titles])
    if add_user:
        algorithm_image.algorithm.add_editor(user)

    algorithm_image.algorithm.save()

    job = {
        "algorithm":
        algorithm_image.algorithm.api_url,
        "inputs": [{
            "interface": interface,
            "value": "dummy"
        } for interface in job_interface_slugs],
    }

    # test
    request = rf.get("/foo")
    request.user = user
    serializer = JobPostSerializer(data=job, context={"request": request})

    # verify
    assert serializer.is_valid() == (error_message is None)
    if error_message:
        assert error_message in str(serializer.errors)
    else:
        assert len(Job.objects.all()) == 0
        serializer.create(serializer.validated_data)
        assert len(Job.objects.all()) == 1
        job = Job.objects.first()
        assert job.status == job.PENDING
        assert len(job.inputs.all()) == 2
def test_algorithm_job_post_serializer_create(rf):
    # setup
    user = UserFactory()
    upload, upload_2 = (
        RawImageUploadSessionFactory(creator=user),
        RawImageUploadSessionFactory(creator=user),
    )
    image = ImageFactory()
    upload_2.image_set.set([image])
    assign_perm("view_image", user, image)
    assert user.has_perm("view_image", image)
    algorithm_image = AlgorithmImageFactory(ready=True)
    interfaces = {
        ComponentInterfaceFactory(
            kind=ComponentInterface.Kind.STRING,
            title="TestInterface 1",
            default_value="default",
        ),
        ComponentInterfaceFactory(kind=ComponentInterface.Kind.IMAGE,
                                  title="TestInterface 2"),
        ComponentInterfaceFactory(kind=ComponentInterface.Kind.IMAGE,
                                  title="TestInterface 3"),
    }
    algorithm_image.algorithm.inputs.set(interfaces)
    algorithm_image.algorithm.add_editor(user)

    algorithm_image.algorithm.save()

    job = {"algorithm": algorithm_image.algorithm.api_url, "inputs": []}
    job["inputs"].append({
        "interface": "testinterface-2",
        "upload_session": upload.api_url
    })
    job["inputs"].append({
        "interface": "testinterface-3",
        "image": image.api_url
    })

    # test
    request = rf.get("/foo")
    request.user = user
    serializer = JobPostSerializer(data=job, context={"request": request})

    # verify
    assert serializer.is_valid()
    serializer.create(serializer.validated_data)
    assert len(Job.objects.all()) == 1
    job = Job.objects.first()
    assert job.creator == user
    assert len(job.inputs.all()) == 3
Esempio n. 9
0
def test_view_content_mixin():
    form = DummyForm()
    form.cleaned_data["view_content"] = {"main": ["test"]}
    form.clean_view_content()
    assert "Unkown slugs in view_content: test" in form.errors["view_content"]

    form.errors = {"view_content": []}
    form.cleaned_data["hanging_protocol"] = HangingProtocolFactory(
        json=[{
            "viewport_name": "main"
        }])
    form.cleaned_data["view_content"] = {"secondary": ["test"]}
    form.clean_view_content()

    assert (
        "Image ports in view_content do not match those in the selected hanging protocol."
        in form.errors["view_content"])
    assert "Unkown slugs in view_content: test" in form.errors["view_content"]

    ComponentInterfaceFactory(title="Test")
    form.errors = {"view_content": []}
    form.cleaned_data["hanging_protocol"] = HangingProtocolFactory(
        json=[{
            "viewport_name": "main"
        }])
    form.cleaned_data["view_content"] = {"main": ["test"]}
    form.clean_view_content()

    assert form.errors["view_content"] == []
Esempio n. 10
0
def test_disjoint_interfaces():
    i = ComponentInterfaceFactory()
    form = AlgorithmForm(
        user=UserFactory(), data={"inputs": [i.pk], "outputs": [i.pk]}
    )
    assert form.is_valid() is False
    assert "The sets of Inputs and Outputs must be unique" in str(form.errors)
Esempio n. 11
0
def test_assert_modification_allowed():
    rs = ReaderStudyFactory(use_display_sets=False)
    ci = ComponentInterfaceFactory(
        kind=InterfaceKind.InterfaceKindChoices.BOOL)
    civ = ComponentInterfaceValueFactory(interface=ci, value=True)
    ds = DisplaySetFactory(reader_study=rs)
    ds.values.add(civ)

    del ds.is_editable

    civ2 = ComponentInterfaceValueFactory(interface=ci, value=True)
    ds.values.remove(civ)
    ds.values.add(civ2)

    assert ds.values.count() == 1
    assert ds.values.first() == civ2

    q = QuestionFactory(reader_study=rs)
    AnswerFactory(question=q, display_set=ds)

    del ds.is_editable

    with pytest.raises(ValidationError):
        with transaction.atomic():
            ds.values.remove(civ2)

    assert ds.values.count() == 1
    assert ds.values.first() == civ2
Esempio n. 12
0
def test_ecs_unzip(tmp_path, settings, submission_file):
    interface = ComponentInterfaceFactory(
        kind=InterfaceKindChoices.ZIP, relative_path="preds.zip"
    )
    civ = ComponentInterfaceValueFactory(interface=interface)

    with open(submission_file, "rb") as f:
        civ.file.save("my_submission.zip", File(f))

    settings.COMPONENTS_AMAZON_ECS_NFS_MOUNT_POINT = tmp_path

    executor = AmazonECSExecutorStub(
        job_id="algorithms-job-00000000-0000-0000-0000-000000000000",
        exec_image_sha256="",
        exec_image_repo_tag="",
        memory_limit=4,
        time_limit=60,
        requires_gpu=False,
    )
    executor.provision(input_civs=[civ], input_prefixes={})

    assert {str(f.relative_to(tmp_path)) for f in tmp_path.glob("**/*")} == {
        "algorithms",
        "algorithms/job",
        "algorithms/job/00000000-0000-0000-0000-000000000000",
        "algorithms/job/00000000-0000-0000-0000-000000000000/input",
        "algorithms/job/00000000-0000-0000-0000-000000000000/input/submission.csv",
        "algorithms/job/00000000-0000-0000-0000-000000000000/input/images",
        "algorithms/job/00000000-0000-0000-0000-000000000000/input/images/image10x10x10.mhd",
        "algorithms/job/00000000-0000-0000-0000-000000000000/input/images/image10x10x10.zraw",
        "algorithms/job/00000000-0000-0000-0000-000000000000/output",
    }
Esempio n. 13
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
Esempio n. 14
0
    def test_existing_jobs(self):
        ai = AlgorithmImageFactory()
        cis = ComponentInterfaceFactory.create_batch(2)
        ai.algorithm.inputs.set(cis)

        civs = [ComponentInterfaceValueFactory(interface=c) for c in cis]

        j = AlgorithmJobFactory(algorithm_image=ai)
        j.inputs.set(civs)

        civ_sets = [
            civs,  # Job already exists
            {
                # New values
                ComponentInterfaceValueFactory(interface=cis[0]),
                ComponentInterfaceValueFactory(interface=cis[1]),
            },
            {
                # Changed values
                civs[0],
                ComponentInterfaceValueFactory(interface=cis[1]),
            },
        ]

        filtered_civ_sets = filter_civs_for_algorithm(civ_sets=civ_sets,
                                                      algorithm_image=ai)

        assert filtered_civ_sets == civ_sets[1:]
Esempio n. 15
0
def test_algorithm_with_invalid_output(client, algorithm_image, settings):
    # Override the celery settings
    settings.task_eager_propagates = (True, )
    settings.task_always_eager = (True, )

    assert Job.objects.count() == 0

    # Create the algorithm image
    algorithm_container, sha256 = algorithm_image
    alg = AlgorithmImageFactory(image__from_path=algorithm_container,
                                image_sha256=sha256,
                                ready=True)

    # Make sure the job fails when trying to upload an invalid file
    detection_interface = ComponentInterfaceFactory(
        store_in_database=False,
        relative_path="some_text.txt",
        slug="detection-json-file",
        kind=ComponentInterface.Kind.JSON,
    )
    alg.algorithm.outputs.add(detection_interface)
    alg.save()
    image_file = ImageFileFactory(file__from_path=Path(__file__).parent /
                                  "resources" / "input_file.tif")

    with capture_on_commit_callbacks(execute=True):
        execute_jobs(algorithm_image=alg, images=[image_file.image])

    jobs = Job.objects.filter(algorithm_image=alg,
                              inputs__image=image_file.image,
                              status=Job.FAILURE).all()
    assert len(jobs) == 1
    assert jobs.first().error_message == "Invalid filetype."
    assert len(jobs[0].outputs.all()) == 2
Esempio n. 16
0
def test_disjoint_interfaces():
    i = ComponentInterfaceFactory()
    form = PhaseAdmin.form(data={
        "algorithm_inputs": [i.pk],
        "algorithm_outputs": [i.pk]
    })
    assert form.is_valid() is False
    assert ("The sets of Algorithm Inputs and Algorithm Outputs must be unique"
            in str(form.errors))
Esempio n. 17
0
    def test_unmatched_interface_filter_subset(self):
        ai = AlgorithmImageFactory()
        cis = ComponentInterfaceFactory.create_batch(2)
        ai.algorithm.inputs.set(cis)

        civ_sets = [{
            # Extra interface
            ComponentInterfaceValueFactory(interface=cis[0]),
            ComponentInterfaceValueFactory(interface=cis[1]),
            ComponentInterfaceValueFactory(
                interface=ComponentInterfaceFactory()),
        }]

        filtered_civ_sets = filter_civs_for_algorithm(civ_sets=civ_sets,
                                                      algorithm_image=ai)

        assert len(filtered_civ_sets) == 1
        assert {civ.interface for civ in filtered_civ_sets[0]} == {*cis}
Esempio n. 18
0
def test_extra_schema_validation(kind, value, invalidation_schema, use_file):
    i = ComponentInterfaceFactory(kind=kind, store_in_database=not use_file)

    if use_file:
        kwargs = {
            "file": ContentFile(
                json.dumps(value).encode("utf-8"), name="test.json"
            )
        }
    else:
        kwargs = {"value": value}

    v = ComponentInterfaceValue(interface=i, **kwargs)
    v.full_clean()

    i.schema = invalidation_schema

    with pytest.raises(ValidationError):
        v.full_clean()
Esempio n. 19
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_civ_post_image_or_upload_required_validation(kind):
    # setup
    interface = ComponentInterfaceFactory(kind=kind)

    civ = {"interface": interface.slug}

    # test
    serializer = ComponentInterfaceValuePostSerializer(data=civ)

    # verify
    assert not serializer.is_valid()
    assert (f"upload_session or image are required for interface kind {kind}"
            in serializer.errors["non_field_errors"])
def test_civ_post_value_required(kind):
    # setup
    interface = ComponentInterfaceFactory(kind=kind)

    civ = {"interface": interface.slug}

    # test
    serializer = ComponentInterfaceValuePostSerializer(data=civ)

    # verify
    assert not serializer.is_valid()
    assert "JSON does not fulfill schema: None is not of type" in str(
        serializer.errors["__all__"][0])
Esempio n. 22
0
def test_multi_value_fails(kind, image, file, value):
    if image:
        image = ImageFactory()

    if file:
        file = ContentFile(json.dumps(True).encode("utf-8"), name="test.csv")

    i = ComponentInterfaceFactory(kind=kind)
    v = ComponentInterfaceValue(
        interface=i, image=image, file=file, value=value
    )

    with pytest.raises(ValidationError):
        v.full_clean()
Esempio n. 23
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
Esempio n. 24
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)
Esempio n. 25
0
def test_default_validation(kind, value, expectation, use_file):
    i = ComponentInterfaceFactory(kind=kind, store_in_database=not use_file)

    if use_file:
        kwargs = {
            "file": ContentFile(
                json.dumps(value).encode("utf-8"), name="test.json"
            )
        }
    else:
        kwargs = {"value": value}

    v = ComponentInterfaceValue(interface=i, **kwargs)

    with expectation:
        v.full_clean()
def test_civ_post_image_valid(kind, rf):
    # setup
    user = UserFactory()
    upload = UploadSessionFactory(status=RawImageUploadSession.PENDING,
                                  creator=user)
    interface = ComponentInterfaceFactory(kind=kind)

    civ = {"interface": interface.slug, "upload_session": upload.api_url}

    # test
    request = rf.get("/foo")
    request.user = user
    serializer = ComponentInterfaceValuePostSerializer(
        data=civ, context={"request": request})

    # verify
    assert serializer.is_valid()
Esempio n. 27
0
def test_relative_path_file_ending(kind):
    if kind in InterfaceKind.interface_type_json():
        good_suffix = "json"
    else:
        good_suffix = kind.lower()

    i = ComponentInterfaceFactory(
        kind=kind,
        relative_path=f"foo/bar.{good_suffix}",
        store_in_database=False,
    )
    i.full_clean()

    i.relative_path = "foo/bar"
    with pytest.raises(ValidationError):
        i.full_clean()
def test_civ_post_value_validation(kind):
    # setup
    interface = ComponentInterfaceFactory(kind=kind)

    for test in TEST_DATA:
        civ = {"interface": interface.slug, "value": TEST_DATA[test]}

        # test
        serializer = ComponentInterfaceValuePostSerializer(data=civ)

        # verify
        assert serializer.is_valid() == (
            kind == test or (
                # Ints are valid for float types
                kind == "FLT" and test == "INT"))
        if not serializer.is_valid():
            assert "JSON does not fulfill schema: " in str(
                serializer.errors["__all__"][0])
def test_civ_post_upload_permission_validation(kind, rf):
    # setup
    user = UserFactory()
    upload = UploadSessionFactory()
    interface = ComponentInterfaceFactory(kind=kind)

    civ = {"interface": interface.slug, "upload_session": upload.api_url}

    # test
    request = rf.get("/foo")
    request.user = user
    serializer = ComponentInterfaceValuePostSerializer(
        data=civ, context={"request": request})

    # verify
    assert not serializer.is_valid()
    assert ("Invalid hyperlink - Object does not exist"
            in serializer.errors["upload_session"][0])
Esempio n. 30
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()
    ]