def test_creation_without_api_key(client: Client) -> None: """Test whether creation without sending the API key whilst logged in is forbidden.""" client, headers, _ = setup_user_client(client, is_staff=False, is_grafeas_staff=False) result = client.get(reverse("volunteer-list"), USER_CREATION_DATA) assert result.status_code == status.HTTP_403_FORBIDDEN
def test_create_no_coc(self, client: Client) -> None: """Test that no transcription can be created without accepting the CoC.""" client, headers, user = setup_user_client(client) user.accepted_coc = False user.save() submission = create_submission() data = { "submission_id": submission.id, "username": user.username, "original_id": "ABC", "source": submission.source.name, "url": "https://example.com", "text": "test content", } result = client.post( reverse("transcription-list"), json.dumps(data), content_type="application/json", **headers, ) assert result.status_code == status.HTTP_403_FORBIDDEN assert Transcription.objects.count() == 0
def test_with_blacklisted_user(self, client: Client) -> None: """Test whether a creation with a blacklisted user is rejected.""" client, headers, user = setup_user_client(client) user.blacklisted = True user.save() submission = create_submission() data = { "submission_id": submission.id, "username": user.username, "original_id": "ABC", "source": submission.source.name, "url": "https://example.com", "text": "test content", } result = client.post( reverse("transcription-list"), json.dumps(data), content_type="application/json", **headers, ) assert result.status_code == status.HTTP_423_LOCKED assert Transcription.objects.count() == 0
def test_time_frames( self, client: Client, time_frame: str, dates: List[datetime], results: List[Dict[str, Union[str, int]]], ) -> None: """Verify that the time_frame parameter properly changes the response.""" client, headers, user = setup_user_client(client, id=123456) for date in dates: create_transcription( create_submission(completed_by=user, complete_time=date), user, create_time=make_aware(date), ) result = client.get( reverse("submission-rate") + f"?time_frame={time_frame}&completed_by=123456", content_type="application/json", **headers, ) assert result.status_code == status.HTTP_200_OK response = result.json() assert response["results"] == results
def test_report_not_removed(self, client: Client) -> None: """Verify that reporting sends a message to Slack.""" mock = MagicMock() slack_client.chat_postMessage = mock client, headers, user = setup_user_client(client) submission = create_submission(id=3) assert not submission.removed_from_queue assert not submission.report_reason assert not submission.report_slack_channel_id assert not submission.report_slack_message_ts data = {"reason": "Violation of ALL the rules"} result = client.patch(reverse("submission-report", args=[submission.id]), json.dumps(data), content_type="application/json", **headers) submission.refresh_from_db() assert result.status_code == status.HTTP_201_CREATED assert not submission.removed_from_queue assert submission.report_reason == "Violation of ALL the rules"
def test_ocr_on_create_with_cannot_ocr_flag( self, client: Client, settings: SettingsWrapper) -> None: """Verify the OCR process exits early if the cannot_ocr flag is already set.""" settings.ENABLE_OCR = True settings.IMAGE_DOMAINS = ["example.com"] assert Transcription.objects.count() == 0 client, headers, _ = setup_user_client(client) source = get_default_test_source() data = { "original_id": "spaaaaace", "source": source.pk, "content_url": "http://example.com/a.jpg", "cannot_ocr": "True", } with patch("api.models.process_image", return_value={"text": "AAA"}) as mock: # mock it anyway just in case this fails -- we don't want to actually # call OCR result = client.post( reverse("submission-list"), data, content_type="application/json", **headers, ) mock.assert_not_called() assert result.status_code == status.HTTP_201_CREATED assert Transcription.objects.count() == 0
def test_submission_create_with_full_args(self, client: Client) -> None: """Test whether creation with all arguments is successful.""" client, headers, _ = setup_user_client(client) source = get_default_test_source() data = { "original_id": "spaaaaace", "source": source.pk, "url": "http://example.com", "tor_url": "http://example.com/tor", "content_url": "http://a.com", "title": "This is a Submission", "nsfw": False, } result = client.post( reverse("submission-list"), data, content_type="application/json", **headers, ) assert result.status_code == status.HTTP_201_CREATED submission = Submission.objects.get(id=result.json()["id"]) assert submission.original_id == data["original_id"] assert submission.source == source assert submission.url == data["url"] assert submission.tor_url == data["tor_url"] assert submission.content_url == data["content_url"] assert submission.nsfw == data["nsfw"] assert submission.title == data["title"]
def test_post_errors(self, client: Client, error: int, expected_redirect: str) -> None: """Verify that errors from the API translate correctly to responses.""" client, _, user = setup_user_client(client) add_social_auth_to_user(user) submission = create_submission( original_id=int(random.random() * 1000), content_url="http://imgur.com", title="a", claimed_by=user, ) class Response: ... response = Response() response.status_code = error with patch("api.views.submission.SubmissionViewSet.done", lambda a, b, c: response): response = client.post( reverse("transcribe_submission", kwargs={"submission_id": submission.id}), data={"transcription": "AAA"}, ) assert reverse(expected_redirect) in response.url
def test_claim_already_claimed_other_user(self, client: Client) -> None: """Test a claim on a Submission already claimed by another user. This should be prevented and return an error. """ BlossomUser.objects.all().delete() client, headers, user = setup_user_client(client, id=1, username="******") other_user = create_user(id=2, username="******") submission = create_submission(claimed_by=other_user) data = {"username": user.username} result = client.patch( reverse("submission-claim", args=[submission.id]), json.dumps(data), content_type="application/json", **headers, ) assert result.status_code == status.HTTP_409_CONFLICT claimed_by = result.json() assert claimed_by["id"] == 2 assert claimed_by["username"] == "user_2" submission.refresh_from_db() assert submission.claimed_by == other_user
def test_summary_blacklisted_user(self, client: Client) -> None: """Test that a blacklisted user is reported as having 0 gamma.""" client, headers, user = setup_user_client(client) user.blacklisted = True user.save() for _ in range(3): create_submission(completed_by=user) assert Submission.objects.filter(completed_by=user).count() == 3 result = client.get( reverse("volunteer-summary") + f"?username={user.username}", **headers) assert result.status_code == status.HTTP_200_OK assert result.json().get("username") == user.username assert result.json()["gamma"] == 0 user.blacklisted = False user.save() result = client.get( reverse("volunteer-summary") + f"?username={user.username}", **headers) assert result.json()["gamma"] == 3
def test_check_reddit_for_missing_information( self, client: Client, settings: SettingsWrapper) -> None: """Verify that if information is missing we will check Reddit for it.""" client, _, user = setup_user_client(client) add_social_auth_to_user(user) settings.ENABLE_REDDIT = True class RedditSubmission: class Response: over_18 = True title = "AAA" def submission(self, **kwargs: Any) -> Response: """Return a mocked response from Reddit.""" return self.Response() with patch("app.middleware.configure_reddit", lambda a: RedditSubmission()): submission = create_submission( original_id=int(random.random() * 1000), content_url="http://imgur.com", ) client.get(reverse("choose_transcription")) submission.refresh_from_db() assert submission.title == "AAA" assert submission.nsfw is True
def test_is_returning_transcriber( self, client: Client, recent_gamma: int, total_gamma: int, expected: bool, ) -> None: """Test whether returning transcribers are determined correctly.""" # Mock both the total gamma with patch( "authentication.models.BlossomUser.gamma", new_callable=PropertyMock, return_value=total_gamma, ): # Mock the Slack client to catch the sent messages by the function under test. client, headers, user = setup_user_client(client) now = datetime.datetime.now(tz=pytz.UTC) # Create the recent transcriptions for i in range(0, recent_gamma): submission = create_submission( id=i + 100, claimed_by=user, completed_by=user, complete_time=now, ) create_transcription(submission, user, id=i + 100, create_time=now) assert _is_returning_transcriber(user) == expected
def test_list_with_null_filters( self, client: Client, filter_str: str, result_count: int ) -> None: """Verify that attributes can be filtered by null.""" client, headers, user = setup_user_client(client, id=123) today = timezone.now() create_submission( id=1, claimed_by=user, completed_by=user, claim_time=today, complete_time=today, title="Test Submission", url="https://example.org", tor_url="https://example.org", content_url="https://example.org", redis_id="abc", ) create_submission(id=2) result = client.get( reverse("submission-list") + f"?{filter_str}", content_type="application/json", **headers, ) assert result.status_code == status.HTTP_200_OK assert len(result.json()["results"]) == result_count
def test_creation_with_normal_user(client: Client) -> None: """Test whether creation is not allowed to a user which is not a staff member.""" client, headers, _ = setup_user_client(client, is_grafeas_staff=False, is_staff=False) result = client.post(reverse("volunteer-list"), USER_CREATION_DATA) assert result.status_code == status.HTTP_403_FORBIDDEN
def test_random_none_available(self, client: Client) -> None: """Test that no transcription is returned when there is none available.""" client, headers, user = setup_user_client(client) result = client.get(reverse("transcription-review-random"), **headers) assert not result.content assert result.status_code == status.HTTP_200_OK
def test_list_with_contains_filters(self, client: Client, filter_str: str, result_count: int) -> None: """Test whether the transcription text can be searched.""" client, headers, user = setup_user_client(client, id=123) submission = create_submission(id=1) create_transcription( submission, user, id=2, text="This is a very interesting text and such.", ) create_transcription( submission, user, id=3, text="A text is a form of literature.", ) create_transcription( submission, user, id=4, text="Bla bla bla bla.", ) result = client.get( reverse("transcription-list") + f"?{filter_str}", content_type="application/json", **headers, ) assert result.status_code == status.HTTP_200_OK assert len(result.json()["results"]) == result_count
def test_list_with_null_filters(self, client: Client, filter_str: str, result_count: int) -> None: """Verify that filtering for null works correctly.""" client, headers, user = setup_user_client(client, id=123) submission = create_submission(id=1) create_transcription( submission, user, id=2, original_id="abc", url="https://example.org", text="Test Transcription", ) create_transcription(submission, user, id=3, original_id=None, url=None, text=None) result = client.get( reverse("transcription-list") + f"?{filter_str}", content_type="application/json", **headers, ) assert result.status_code == status.HTTP_200_OK assert len(result.json()["results"]) == result_count
def test_list_with_time_filters(self, client: Client) -> None: """Verify that the transcriptions can be filtered by time.""" client, headers, user = setup_user_client(client) dates = [ datetime(2021, 1, 1), datetime(2021, 2, 1), datetime(2021, 2, 3), datetime(2021, 5, 10), ] for date in dates: create_transcription(create_submission(), user, create_time=make_aware(date)) result = client.get( reverse("transcription-list") + "?create_time__gte=2021-02-01T00:00:00Z" + "&create_time__lte=2021-04-01T00:00:00Z", content_type="application/json", **headers, ) assert result.status_code == status.HTTP_200_OK assert len(result.json()["results"]) == 2
def test_failed_ocr_on_create(self, client: Client, settings: SettingsWrapper) -> None: """Verify that a new submission completes the OCR process.""" settings.ENABLE_OCR = True settings.IMAGE_DOMAINS = ["example.com"] assert Transcription.objects.count() == 0 client, headers, _ = setup_user_client(client) source = get_default_test_source() data = { "original_id": "spaaaaace", "source": source.pk, "content_url": "http://example.com/a.jpg", } with patch("api.models.process_image", return_value=None) as mock: result = client.post( reverse("submission-list"), data, content_type="application/json", **headers, ) mock.assert_called_once() assert result.status_code == status.HTTP_201_CREATED assert Transcription.objects.count() == 0 assert result.json().get("cannot_ocr") is True
def test_create(self, client: Client) -> None: """Test whether the creation functions correctly when invoked correctly.""" client, headers, user = setup_user_client(client) submission = create_submission() data = { "submission_id": submission.id, "username": user.username, "original_id": "ABC", "source": submission.source.name, "url": "https://example.com", "text": "test content", } result = client.post( reverse("transcription-list"), json.dumps(data), content_type="application/json", **headers, ) assert result.status_code == status.HTTP_201_CREATED transcription = Transcription.objects.get(id=result.json()["id"]) assert transcription.submission == submission assert transcription.source == submission.source assert transcription.author == user assert transcription.original_id == data["original_id"] assert transcription.url == data["url"] assert transcription.text == data["text"]
def test_rate_count_aggregation( self, client: Client, data: List[Dict[str, Union[str, int]]], url_additions: str, different_result: List[Dict], ) -> None: """Test if the number of transcriptions per day is aggregated correctly.""" client, headers, user = setup_user_client(client, id=123456) for obj in data: date = make_aware( datetime.strptime(obj.get("date"), "%Y-%m-%dT%H:%M:%SZ")) for _ in range(obj.get("count")): create_transcription( create_submission(completed_by=user, complete_time=date), user, create_time=date, ) if not url_additions: url_additions = "?completed_by=123456" else: url_additions += "&completed_by=123456" result = client.get( reverse("submission-rate") + url_additions, content_type="application/json", **headers, ) assert result.status_code == status.HTTP_200_OK rates = result.json()["results"] if different_result: assert rates == different_result else: assert rates == data
def test_create_with_tz_aware_timestamp(self, client: Client) -> None: """Test whether the creation functions correctly when invoked correctly.""" # TODO: Remove me when we remove the ability to create with create_time variable client, headers, user = setup_user_client(client) submission = create_submission() timestamp = "2021-11-28T13:00:05.985314+00:00" data = { "submission_id": submission.id, "username": user.username, "original_id": "ABC", "create_time": timestamp, "source": submission.source.name, "url": "https://example.com", "text": "test content", } result = client.post( reverse("transcription-list"), json.dumps(data), content_type="application/json", **headers, ) assert result.status_code == status.HTTP_201_CREATED transcription = Transcription.objects.get(id=result.json()["id"]) assert transcription.create_time.isoformat() == timestamp
def test_filtered_leaderboard(self, client: Client,) -> None: """Test if the submissions for the rate is calculated on are filtered.""" BlossomUser.objects.all().delete() date_joined = datetime(2021, 11, 3, tzinfo=pytz.UTC) client, headers, user = setup_user_client( client, id=1, username="******", date_joined=date_joined, is_volunteer=True ) # Submissions before filter for _ in range(4): create_submission( completed_by=user, complete_time=make_aware(datetime(2021, 11, 3)) ) # Submissions after filter for _ in range(7): create_submission( completed_by=user, complete_time=make_aware(datetime(2021, 11, 5)) ) results = client.get( reverse("submission-leaderboard") + "?user_id=1&complete_time__gte=2021-11-04T00:00:00Z", content_type="application/json", **headers, ) assert results.status_code == status.HTTP_200_OK results = results.json() assert results["user"] == { "id": 1, "username": "******", "gamma": 7, "rank": 1, "date_joined": "2021-11-03T00:00:00Z", }
def test_search_with_ordering_filter( self, client: Client, ordering: str, create_times: List[datetime], expected_times: List[datetime], ) -> None: """Verify that listing items with specified orderings works correctly.""" client, headers, user = setup_user_client(client) for time in create_times: create_transcription(create_time=make_aware(time), submission=create_submission(), user=user) result = client.get( reverse("transcription-list") + f"?ordering={ordering}", content_type="application/json", **headers, ) assert result.status_code == status.HTTP_200_OK result_times = [ datetime.strptime(obj.get("create_time"), "%Y-%m-%dT%H:%M:%SZ") for obj in result.json()["results"] ] assert result_times == expected_times
def test_list_with_filters(self, client: Client) -> None: """Verify that listing all submissions works correctly.""" Source.objects.all().delete() # clear out system ones for test client, headers, _ = setup_user_client(client) Source.objects.get_or_create(name="AAA") Source.objects.get_or_create(name="BBB") Source.objects.get_or_create(name="CCC") result = client.get(reverse("source-list"), content_type="application/json", **headers) assert result.status_code == status.HTTP_200_OK assert len(result.json()["results"]) == 3 result = client.get( reverse("source-list") + "?name=AAA", content_type="application/json", **headers, ) assert result.status_code == status.HTTP_200_OK assert len(result.json()["results"]) == 1 assert result.json()["results"][0]["name"] == "AAA"
def test_in_progress_custom_time(self, client: Client) -> None: """Verify that passing a different time changes the returned submissions.""" client, headers, user = setup_user_client(client) reddit, _ = Source.objects.get_or_create(name="reddit") submission = create_submission( claimed_by=user, claim_time=timezone.now() - timezone.timedelta(hours=2), source=reddit, ) # will default to four hours, should return nothing result = client.get( reverse("submission-in-progress") + "?source=reddit", content_type="application/json", **headers, ) assert result.status_code == status.HTTP_200_OK assert len(result.json()) == 0 # we'll set a custom hour and now we should get the submission result = client.get( reverse("submission-in-progress") + "?source=reddit&hours=1", content_type="application/json", **headers, ) assert result.status_code == status.HTTP_200_OK assert len(result.json()) == 1 assert result.json()[0]["id"] == submission.id
def test_find_in_progress(client: Client, url: str, expected: bool) -> None: """Verify that an in-progress posts can be found by its URLs.""" client, headers, user = setup_user_client(client, id=123, username="******") submission = create_submission( claimed_by=user, url="https://reddit.com/r/antiwork/comments/q1tlcf/work_is_work/", tor_url= "https://reddit.com/r/TranscribersOfReddit/comments/q1tnhc/antiwork_image_work_is_work/", content_url="https://i.redd.it/upwchc4bqhr71.jpg", title="Work is work", ) result = client.get( reverse("find") + f"?url={url}", content_type="application/json", **headers, ) if expected: assert result.status_code == status.HTTP_200_OK actual = result.json() assert actual["submission"]["id"] == submission.id assert actual["author"]["id"] == user.id else: assert result.status_code == status.HTTP_404_NOT_FOUND
def test_transcribot_limit_param(self, client: Client) -> None: """Verify that adding the `limit` QSP modifies the results.""" client, headers, _ = setup_user_client(client) user_model = get_user_model() transcribot = user_model.objects.get(username="******") submission1 = create_submission(source="reddit", original_id="A") submission2 = create_submission(source="reddit", original_id="B") submission3 = create_submission(source="reddit", original_id="C") create_transcription(submission1, transcribot, original_id=None) create_transcription(submission2, transcribot, original_id=None) create_transcription(submission3, transcribot, original_id=None) result = client.get( reverse("submission-get-transcribot-queue") + "?source=reddit&limit=none", content_type="application/json", **headers, ).json() assert len(result["data"]) == 3 result = client.get( reverse("submission-get-transcribot-queue") + "?source=reddit&limit=1", content_type="application/json", **headers, ).json() assert len(result["data"]) == 1 assert result["data"][0]["id"] == submission1.id
def test_get_transcribot_queue(self, client: Client) -> None: """Test that the OCR queue endpoint returns the correct data.""" client, headers, _ = setup_user_client(client) user_model = get_user_model() transcribot = user_model.objects.get(username="******") result = client.get( reverse("submission-get-transcribot-queue") + "?source=reddit", content_type="application/json", **headers, ).json() assert len(result["data"]) == 0 # there are no posts to work on submission = create_submission(source="reddit") result = client.get( reverse("submission-get-transcribot-queue") + "?source=reddit", content_type="application/json", **headers, ).json() # now there's a submission without a transcribot transcription assert len(result["data"]) == 0 create_transcription(submission, transcribot, original_id=None) result = client.get( reverse("submission-get-transcribot-queue") + "?source=reddit", content_type="application/json", **headers, ).json() # now the submission has a transcribot entry assert len(result["data"]) == 1
def test_yeet_with_no_user(self, client: Client) -> None: """Verify that yeeting without a count only deletes one.""" client, headers, user = setup_user_client(client) response = client.post(reverse("submission-yeet"), content_type="application/json", **headers) assert response.status_code == 400