Esempio n. 1
0
    def test_algorithm_no_permission(self):
        alg = AlgorithmFactory()

        form = SubmissionForm(
            user=UserFactory(),
            algorithm_submission=True,
            data={"algorithm": alg.pk},
        )

        assert form.errors["algorithm"] == [
            "Select a valid choice. That choice is not one of the available choices."
        ]
def test_algorithm_groups_permissions_are_assigned():
    alg = AlgorithmFactory()

    editors_perms = get_group_perms(alg.editors_group, alg)
    assert "view_algorithm" in editors_perms
    assert "change_algorithm" in editors_perms
    assert "execute_algorithm" in editors_perms

    users_perms = get_group_perms(alg.users_group, alg)
    assert "view_algorithm" in users_perms
    assert "change_algorithm" not in users_perms
    assert "execute_algorithm" in users_perms
Esempio n. 3
0
    def test_algorithm_with_permission(self):
        user = UserFactory()
        alg = AlgorithmFactory()
        alg.add_editor(user=user)
        alg.inputs.clear()
        alg.outputs.clear()

        ai = AlgorithmImageFactory(ready=True, algorithm=alg)
        AlgorithmJobFactory(algorithm_image=ai, status=4)

        p = PhaseFactory(submission_kind=Phase.SubmissionKind.ALGORITHM)

        form = SubmissionForm(
            user=user,
            phase=p,
            data={"algorithm": alg.pk, "creator": user, "phase": p},
        )

        assert form.errors == {}
        assert "algorithm" not in form.errors
        assert form.is_valid()
Esempio n. 4
0
    def test_algorithm_no_permission(self):
        alg = AlgorithmFactory()

        form = SubmissionForm(
            user=UserFactory(),
            phase=PhaseFactory(submission_kind=Phase.SubmissionKind.ALGORITHM),
            data={"algorithm": alg.pk},
        )

        assert form.errors["algorithm"] == [
            "Select a valid choice. That choice is not one of the available choices."
        ]
def test_algorithm_permission_request_notification_for_admins_only(client):
    base_object = AlgorithmFactory()
    editor = UserFactory()
    user = UserFactory()
    participant = UserFactory()
    base_object.add_editor(editor)
    base_object.add_user(participant)

    # create an algorithm job follow for participant
    follow(user=participant, obj=base_object, flag="job-active")

    permission_create_url = reverse(
        "algorithms:permission-request-create",
        kwargs={"slug": base_object.slug},
    )

    # Create the permission request
    _ = get_view_for_user(
        client=client,
        user=user,
        url=permission_create_url,
        method=client.post,
    )

    assert Notification.objects.count() == 1
    assert Notification.objects.get().user == editor
Esempio n. 6
0
def test_algorithm_image_create_link_view(client):
    alg = AlgorithmFactory()
    expected_url = reverse(
        "algorithms:image-create", kwargs={"slug": alg.slug}
    )
    user = UserFactory()

    alg.add_user(user)

    response = get_view_for_user(
        viewname="algorithms:detail",
        reverse_kwargs={"slug": alg.slug},
        client=client,
        user=user,
    )
    assert response.status_code == 200
    assert expected_url not in response.rendered_content

    alg.add_editor(user)

    response = get_view_for_user(
        viewname="algorithms:detail",
        reverse_kwargs={"slug": alg.slug},
        client=client,
        user=user,
    )
    assert response.status_code == 200
    assert expected_url in response.rendered_content
Esempio n. 7
0
def test_algorithm_job_update_status():
    alg = AlgorithmFactory()
    user = UserFactory()
    editor = UserFactory()

    alg.add_user(user)
    alg.add_editor(editor)

    ai = AlgorithmImageFactory(algorithm=alg)
    job = AlgorithmJobFactory(algorithm_image=ai, creator=user)

    for status, _ in Job.STATUS_CHOICES:
        job.update_status(status=status)
        job.refresh_from_db()
        assert job.status == status

    remaining_recipients = {user.email, editor.email}
    for email in mail.outbox:
        remaining_recipients -= set(email.to)
        assert (
            email.subject ==
            f"[{Site.objects.get_current().domain.lower()}] [{alg.title.lower()}] Job Failed"
        )
        assert (
            f"Unfortunately your job for algorithm '{alg.title}' failed with an error"
            in email.body)
    assert remaining_recipients == set()
def test_editor_update_form(client):
    alg, _ = AlgorithmFactory(), AlgorithmFactory()

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

    assert alg.editors_group.user_set.count() == 1

    new_editor = UserFactory()
    assert not alg.is_editor(user=new_editor)
    response = get_view_for_user(
        viewname="algorithms:editors-update",
        client=client,
        method=client.post,
        data={"user": new_editor.pk, "action": "ADD"},
        reverse_kwargs={"slug": alg.slug},
        follow=True,
        user=editor,
    )
    assert response.status_code == 200

    alg.refresh_from_db()
    assert alg.editors_group.user_set.count() == 2
    assert alg.is_editor(user=new_editor)

    response = get_view_for_user(
        viewname="algorithms:editors-update",
        client=client,
        method=client.post,
        data={"user": new_editor.pk, "action": "REMOVE"},
        reverse_kwargs={"slug": alg.slug},
        follow=True,
        user=editor,
    )
    assert response.status_code == 200

    alg.refresh_from_db()
    assert alg.editors_group.user_set.count() == 1
    assert not alg.is_editor(user=new_editor)
def test_algorithm_image_create_detail(client):
    user = UserFactory()
    algorithm = AlgorithmFactory()
    algorithm.add_editor(user)

    algorithm_image = StagedFileFactory(file__filename="test_image.tar.gz")
    response = get_view_for_user(
        client=client,
        viewname="algorithms:image-create",
        reverse_kwargs={"slug": algorithm.slug},
        user=user,
    )
    assert response.status_code == 200

    assert AlgorithmImage.objects.all().count() == 0

    response = get_view_for_user(
        client=client,
        method=client.post,
        viewname="algorithms:image-create",
        reverse_kwargs={"slug": algorithm.slug},
        user=user,
        data={
            "chunked_upload": algorithm_image.file_id,
            "requires_memory_gb": 24,
        },
    )
    assert response.status_code == 302

    images = AlgorithmImage.objects.all()
    assert len(images) == 1
    assert images[0].algorithm == algorithm
    assert response.url == reverse(
        "algorithms:image-detail",
        kwargs={
            "slug": algorithm.slug,
            "pk": images[0].pk
        },
    )
Esempio n. 10
0
def test_visible_to_public_group_permissions():
    g_reg_anon = Group.objects.get(
        name=settings.REGISTERED_AND_ANON_USERS_GROUP_NAME)
    algorithm = AlgorithmFactory()

    assert "view_algorithm" not in get_perms(g_reg_anon, algorithm)

    algorithm.public = True
    algorithm.save()

    assert "view_algorithm" in get_perms(g_reg_anon, algorithm)

    algorithm.public = False
    algorithm.save()

    assert "view_algorithm" not in get_perms(g_reg_anon, algorithm)
Esempio n. 11
0
def test_group_deletion():
    algorithm = AlgorithmFactory()
    users_group = algorithm.users_group
    editors_group = algorithm.editors_group

    assert users_group
    assert editors_group

    Algorithm.objects.filter(pk__in=[algorithm.pk]).delete()

    with pytest.raises(ObjectDoesNotExist):
        users_group.refresh_from_db()

    with pytest.raises(ObjectDoesNotExist):
        editors_group.refresh_from_db()
Esempio n. 12
0
def test_algorithm_list_view(client):
    alg1, alg2 = AlgorithmFactory(), AlgorithmFactory()
    user = UserFactory()

    alg1.add_user(user)
    alg2.add_user(user)

    response = get_view_for_user(
        viewname="algorithms:list", client=client, user=user
    )

    assert alg1.get_absolute_url() in response.rendered_content
    assert alg2.get_absolute_url() in response.rendered_content

    alg1.remove_user(user)

    response = get_view_for_user(
        viewname="algorithms:list", client=client, user=user
    )

    assert alg1.get_absolute_url() not in response.rendered_content
    assert alg2.get_absolute_url() in response.rendered_content
Esempio n. 13
0
def test_algorithm_permission_request_create(client):
    user = UserFactory()
    alg = AlgorithmFactory(public=False)

    response = get_view_for_user(
        viewname="algorithms:detail",
        reverse_kwargs={"slug": slugify(alg.slug)},
        client=client,
        user=user,
        follow=True,
    )

    assert response.status_code == 200
    assert "Request access" in response.rendered_content

    response = get_view_for_user(
        viewname="algorithms:permission-request-create",
        reverse_kwargs={"slug": slugify(alg.slug)},
        client=client,
        user=user,
        method=client.post,
        follow=True,
    )

    assert AlgorithmPermissionRequest.objects.count() == 1
    assert response.status_code == 200
    pr = AlgorithmPermissionRequest.objects.get(user=user)
    assert "Request access" in response.rendered_content
    assert pr.status_to_string() in response.rendered_content
    assert pr.status == AlgorithmPermissionRequest.PENDING

    # Calling create again should not create a new permission request object
    response = get_view_for_user(
        viewname="algorithms:permission-request-create",
        reverse_kwargs={"slug": slugify(alg.slug)},
        client=client,
        user=user,
        method=client.post,
        follow=True,
    )

    assert AlgorithmPermissionRequest.objects.count() == 1
Esempio n. 14
0
def test_notification_list_view_num_queries(client, django_assert_num_queries):
    user1 = UserFactory()
    _ = NotificationFactory(
        user=user1,
        message="requested access to",
        target=AlgorithmFactory(),
        type=Notification.Type.ACCESS_REQUEST,
    )

    notifications = Notification.objects.select_related(
        "actor_content_type",
        "target_content_type",
        "action_object_content_type",
        "user",
    ).all()

    notifications_with_prefetched_fks = prefetch_generic_foreign_key_objects(
        Notification.objects.select_related(
            "actor_content_type",
            "target_content_type",
            "action_object_content_type",
            "user",
        ).all())
    # double check that there is an action target for the test below to be meaningful
    assert notifications[0].target

    try:
        settings.DEBUG = True
        notifications[0].target
        # when the generic foreign keys have not been prefetched, accessing the
        # action target, result in two db calls
        assert len(connection.queries) == 2
        reset_queries()
        notifications_with_prefetched_fks[0].target
        # when gfks have been prefetched, accessing the action target
        # no longer requires any db calls
        assert len(connection.queries) == 0
    finally:
        settings.DEBUG = False
        reset_queries()
Esempio n. 15
0
def test_algorithm_detail_flexible_inputs(client):
    editor = UserFactory()

    alg = AlgorithmFactory(use_flexible_inputs=False)
    alg.add_editor(editor)
    AlgorithmImageFactory(algorithm=alg, ready=True)

    flexi_input_url = reverse(
        viewname="algorithms:execution-session-create-new",
        kwargs={"slug": alg.slug},
    )

    response = get_view_for_user(
        viewname="algorithms:detail",
        reverse_kwargs={"slug": slugify(alg.slug)},
        client=client,
        user=editor,
        method=client.get,
        follow=True,
        **{"HTTP_X_REQUESTED_WITH": "XMLHttpRequest"},
    )

    assert response.status_code == 200
    assert flexi_input_url not in response.rendered_content

    alg.use_flexible_inputs = True
    alg.save()

    response = get_view_for_user(
        viewname="algorithms:detail",
        reverse_kwargs={"slug": slugify(alg.slug)},
        client=client,
        user=editor,
        method=client.get,
        follow=True,
        **{"HTTP_X_REQUESTED_WITH": "XMLHttpRequest"},
    )

    assert response.status_code == 200
    assert flexi_input_url in response.rendered_content
Esempio n. 16
0
def test_follows_deleted_when_base_obj_deleted(client):
    base_object = AlgorithmFactory(
        access_request_handling=AccessRequestHandlingOptions.MANUAL_REVIEW)
    editor = UserFactory()
    base_object.add_editor(editor)
    permission_create_url = reverse(
        "algorithms:permission-request-create",
        kwargs={"slug": base_object.slug},
    )
    user = UserFactory()
    _ = get_view_for_user(client=client,
                          user=user,
                          url=permission_create_url,
                          method=client.post)
    pr = AlgorithmPermissionRequest.objects.get()
    assert is_following(user, pr)

    base_object.delete()
    assert not Follow.objects.filter(object_id=base_object.pk)
Esempio n. 17
0
def test_publication_object_visibilty(client, mocker):
    user1 = UserFactory()
    user2 = UserFactory()

    alg = AlgorithmFactory()
    alg.add_user(user1)
    assert user1.has_perm("view_algorithm", alg)
    assert not user2.has_perm("view_algorithm", alg)

    mocker.patch("grandchallenge.publications.utils.get_doi_csl",
                 return_value=TEST_CSL)

    # create publication
    _ = get_view_for_user(
        viewname="publications:create",
        client=client,
        method=client.post,
        data={"identifier": TEST_DOI},
        user=user1,
    )
    # add publication to algorithm
    alg.publications.add(Publication.objects.get())
    alg.save()

    response = get_view_for_user(
        viewname="publications:list",
        client=client,
        method=client.get,
        user=user1,
    )

    assert response.status_code == 200
    assert alg.title in response.rendered_content

    response = get_view_for_user(
        viewname="publications:list",
        client=client,
        method=client.get,
        user=user2,
    )

    assert response.status_code == 200
    assert alg.title not in response.rendered_content
Esempio n. 18
0
def test_default_interfaces_created():
    a = AlgorithmFactory()

    assert {i.kind for i in a.inputs.all()} == {InterfaceKindChoices.IMAGE}
    assert {o.kind for o in a.outputs.all()} == {InterfaceKindChoices.JSON}
Esempio n. 19
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
Esempio n. 20
0
def test_algorithm_permission_request_update(client):
    user = UserFactory()
    editor = UserFactory()

    alg = AlgorithmFactory(public=True)
    alg.add_editor(editor)

    pr = AlgorithmPermissionRequestFactory(algorithm=alg, user=user)
    assert pr.status == AlgorithmPermissionRequest.PENDING

    response = get_view_for_user(
        viewname="algorithms:permission-request-update",
        reverse_kwargs={
            "slug": slugify(alg.slug),
            "pk": pr.pk
        },
        client=client,
        user=editor,
        method=client.get,
        follow=True,
    )

    assert "review access request for user" in response.rendered_content
    assert "Request access" not in response.rendered_content

    response = get_view_for_user(
        viewname="algorithms:permission-request-update",
        reverse_kwargs={
            "slug": slugify(alg.slug),
            "pk": pr.pk
        },
        client=client,
        user=editor,
        method=client.post,
        follow=True,
        data={"status": "NONEXISTENT"},
    )

    pr.refresh_from_db()
    assert response.status_code == 200
    assert pr.status == AlgorithmPermissionRequest.PENDING

    response = get_view_for_user(
        viewname="algorithms:permission-request-update",
        reverse_kwargs={
            "slug": slugify(alg.slug),
            "pk": pr.pk
        },
        client=client,
        user=editor,
        method=client.post,
        follow=True,
        data={"status": AlgorithmPermissionRequest.REJECTED},
    )

    pr.refresh_from_db()
    assert response.status_code == 200
    assert pr.status == AlgorithmPermissionRequest.REJECTED

    response = get_view_for_user(
        viewname="algorithms:permission-request-update",
        reverse_kwargs={
            "slug": slugify(alg.slug),
            "pk": pr.pk
        },
        client=client,
        user=user,
        method=client.get,
        follow=True,
    )

    assert response.status_code == 403

    # User should not be able to change the status
    response = get_view_for_user(
        viewname="algorithms:permission-request-update",
        reverse_kwargs={
            "slug": slugify(alg.slug),
            "pk": pr.pk
        },
        client=client,
        user=user,
        method=client.post,
        follow=True,
        data={"status": AlgorithmPermissionRequest.ACCEPTED},
    )

    pr.refresh_from_db()
    assert response.status_code == 403
    assert pr.status == AlgorithmPermissionRequest.REJECTED

    response = get_view_for_user(
        viewname="algorithms:permission-request-update",
        reverse_kwargs={
            "slug": slugify(alg.slug),
            "pk": pr.pk
        },
        client=client,
        user=editor,
        method=client.post,
        follow=True,
        data={"status": AlgorithmPermissionRequest.ACCEPTED},
    )

    pr.refresh_from_db()
    assert response.status_code == 200
    assert pr.status == AlgorithmPermissionRequest.ACCEPTED
Esempio n. 21
0
def test_algorithm_jobs_list_view(client):
    editor = UserFactory()

    alg = AlgorithmFactory(public=True)
    alg.add_editor(editor)
    im = AlgorithmImageFactory(algorithm=alg)
    for x in range(50):
        created = timezone.now() - datetime.timedelta(days=x + 365)
        job = AlgorithmJobFactory(algorithm_image=im, status=Job.SUCCESS)
        job.created = created
        job.save()
        job.viewer_groups.add(alg.editors_group)

    response = get_view_for_user(
        viewname="algorithms:job-list",
        reverse_kwargs={"slug": slugify(alg.slug)},
        client=client,
        user=editor,
        method=client.get,
        follow=True,
    )

    assert response.status_code == 200

    response = get_view_for_user(
        viewname="algorithms:job-list",
        reverse_kwargs={"slug": slugify(alg.slug)},
        client=client,
        user=editor,
        method=client.get,
        follow=True,
        data={
            "length": 10,
            "draw": 1,
            "order[0][dir]": "desc",
            "order[0][column]": 0,
        },
        **{"HTTP_X_REQUESTED_WITH": "XMLHttpRequest"},
    )

    resp = response.json()
    assert resp["recordsTotal"] == 50
    assert len(resp["data"]) == 10

    response = get_view_for_user(
        viewname="algorithms:job-list",
        reverse_kwargs={"slug": slugify(alg.slug)},
        client=client,
        user=editor,
        method=client.get,
        follow=True,
        data={
            "length": 50,
            "draw": 1,
            "order[0][dir]": "desc",
            "order[0][column]": 0,
        },
        **{"HTTP_X_REQUESTED_WITH": "XMLHttpRequest"},
    )

    resp = response.json()
    assert resp["recordsTotal"] == 50
    assert len(resp["data"]) == 50

    response = get_view_for_user(
        viewname="algorithms:job-list",
        reverse_kwargs={"slug": slugify(alg.slug)},
        client=client,
        user=editor,
        method=client.get,
        follow=True,
        data={
            "length": 50,
            "draw": 1,
            "order[0][dir]": "asc",
            "order[0][column]": 0,
        },
        **{"HTTP_X_REQUESTED_WITH": "XMLHttpRequest"},
    )

    resp_new = response.json()
    assert resp_new["recordsTotal"] == 50
    assert resp_new["data"] == resp["data"][::-1]

    response = get_view_for_user(
        viewname="algorithms:job-list",
        reverse_kwargs={"slug": slugify(alg.slug)},
        client=client,
        user=editor,
        method=client.get,
        follow=True,
        data={
            "length": 50,
            "draw": 1,
            "search[value]": job.creator.username,
            "order[0][column]": 0,
        },
        **{"HTTP_X_REQUESTED_WITH": "XMLHttpRequest"},
    )

    resp = response.json()
    assert resp["recordsTotal"] == 50
    assert resp["recordsFiltered"] == 1
    assert len(resp["data"]) == 1
def test_adding_algorithms_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):
        arch_set.arch1.algorithms.add(AlgorithmFactory())
        arch_set.arch2.algorithms.add(AlgorithmFactory())

    create_algorithm_jobs_for_archive.apply_async.assert_has_calls(
        [
            call(
                kwargs={
                    "archive_pks": [arch_set.arch1.pk],
                    "algorithm_pks": [arch_set.arch1.algorithms.first().pk],
                }
            ),
            call(
                kwargs={
                    "archive_pks": [arch_set.arch2.pk],
                    "algorithm_pks": [arch_set.arch2.algorithms.first().pk],
                }
            ),
        ]
    )
    create_algorithm_jobs_for_archive.apply_async.reset_mock()
    algorithms = (
        AlgorithmFactory(),
        AlgorithmFactory(),
        AlgorithmFactory(),
        AlgorithmFactory(),
    )

    if not reverse:
        with capture_on_commit_callbacks(execute=True):
            arch_set.arch1.algorithms.add(*algorithms)

        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["algorithm_pks"]} == {a.pk for a in algorithms}
        create_algorithm_jobs_for_archive.apply_async.reset_mock()

        with capture_on_commit_callbacks(execute=True):
            arch_set.arch1.algorithms.remove(algorithms[0], algorithms[1])
            arch_set.arch1.algorithms.clear()

        create_algorithm_jobs_for_archive.apply_async.assert_not_called()
    else:
        for alg in algorithms:
            with capture_on_commit_callbacks(execute=True):
                alg.archive_set.add(arch_set.arch1, arch_set.arch2)

            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,
                arch_set.arch2.pk,
            }
            assert {*kwargs["algorithm_pks"]} == {alg.pk}
            create_algorithm_jobs_for_archive.apply_async.reset_mock()

        with capture_on_commit_callbacks(execute=True):
            for im in algorithms[-2:]:
                im.archive_set.remove(arch_set.arch1, arch_set.arch2)
            for im in algorithms[:2]:
                im.archive_set.remove(arch_set.arch2)
            algorithms[0].archive_set.clear()

        create_algorithm_jobs_for_archive.apply_async.assert_not_called()