From 8c1940445503fd6678d0961600f2be81622793a2 Mon Sep 17 00:00:00 2001 From: Max Nanis Date: Tue, 24 Feb 2026 17:26:15 -0500 Subject: Extensive use of type checking. Movement of pytest conf towards handling managers (for db agnostic unittest). Starting to organize pytests. --- tests/__init__.py | 2 +- tests/amt/test_models.py | 36 ++++--- tests/conftest.py | 228 +++++++++++++++++++++++++++++++-------- tests/flow/test_tasks.py | 15 +-- tests/http/test_basic.py | 11 -- tests/http/test_notifications.py | 16 +-- tests/http/test_preview.py | 41 +++++++ tests/http/test_report.py | 0 tests/http/test_status.py | 78 -------------- tests/http/test_statuses.py | 102 ------------------ tests/http/test_work.py | 38 +++---- tests/managers/amt.py | 9 +- tests/managers/hit.py | 19 ++-- 13 files changed, 296 insertions(+), 299 deletions(-) create mode 100644 tests/http/test_preview.py create mode 100644 tests/http/test_report.py delete mode 100644 tests/http/test_status.py delete mode 100644 tests/http/test_statuses.py (limited to 'tests') diff --git a/tests/__init__.py b/tests/__init__.py index 469eda2..f37e785 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -2,6 +2,6 @@ import random import string -def generate_amt_id(length=30): +def generate_amt_id(length=30) -> str: chars = string.ascii_uppercase + string.digits return "".join(random.choices(chars, k=length)) diff --git a/tests/amt/test_models.py b/tests/amt/test_models.py index c2a61b5..cecd948 100644 --- a/tests/amt/test_models.py +++ b/tests/amt/test_models.py @@ -22,20 +22,26 @@ def get_assignment_response_bad_tsid( ) return res -def test_get_assignment(get_assignment_response): - assignment = Assignment.from_amt_get_assignment( - get_assignment_response["Assignment"] - ) - assert assignment.tsid is not None -def test_get_assignment_no_tsid(get_assignment_response_no_tsid): - assignment = Assignment.from_amt_get_assignment( - get_assignment_response_no_tsid["Assignment"] - ) - assert assignment.tsid is None +class TestAssignment: -def test_get_assignment_bad_tsid(get_assignment_response_bad_tsid): - assignment = Assignment.from_amt_get_assignment( - get_assignment_response_bad_tsid["Assignment"] - ) - assert assignment.tsid is None \ No newline at end of file + @pytest.mark.anyio + def test_get_assignment(get_assignment_response): + assignment = Assignment.from_amt_get_assignment( + get_assignment_response["Assignment"] + ) + assert assignment.tsid is not None + + @pytest.mark.anyio + def test_get_assignment_no_tsid(get_assignment_response_no_tsid): + assignment = Assignment.from_amt_get_assignment( + get_assignment_response_no_tsid["Assignment"] + ) + assert assignment.tsid is None + + @pytest.mark.anyio + def test_get_assignment_bad_tsid(get_assignment_response_bad_tsid): + assignment = Assignment.from_amt_get_assignment( + get_assignment_response_bad_tsid["Assignment"] + ) + assert assignment.tsid is None diff --git a/tests/conftest.py b/tests/conftest.py index 985c9dc..3318f1c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,8 +1,9 @@ import copy from datetime import datetime, timezone, timedelta +import os from typing import Optional from uuid import uuid4 - +from dotenv import load_dotenv import pytest from dateutil.tz import tzlocal from mypy_boto3_mturk.type_defs import ( @@ -11,62 +12,179 @@ from mypy_boto3_mturk.type_defs import ( CreateHITWithHITTypeResponseTypeDef, GetAssignmentResponseTypeDef, ) - -from jb.decorators import HQM, HTM, HM, AM +from jb.managers import Permission +from generalresearchutils.pg_helper import PostgresConfig from jb.managers.amt import AMTManager, APPROVAL_MESSAGE, NO_WORK_APPROVAL_MESSAGE from jb.models.assignment import AssignmentStub, Assignment -from jb.models.currency import USDCent +from generalresearchutils.currency import USDCent from jb.models.definitions import HitStatus, HitReviewStatus, AssignmentStatus from jb.models.hit import HitType, HitQuestion, Hit from tests import generate_amt_id @pytest.fixture -def amt_hit_type_id(): - return generate_amt_id() - - -@pytest.fixture -def amt_hit_id(): +def amt_hit_type_id() -> str: return generate_amt_id() @pytest.fixture -def amt_assignment_id(): +def amt_assignment_id() -> str: return generate_amt_id() @pytest.fixture -def amt_worker_id(): +def amt_worker_id() -> str: return generate_amt_id(length=21) @pytest.fixture -def amt_group_id(): +def amt_group_id() -> str: return generate_amt_id() @pytest.fixture -def tsid(): +def tsid() -> str: return uuid4().hex @pytest.fixture -def tsid1(): +def tsid1() -> str: return uuid4().hex @pytest.fixture -def tsid2(): +def tsid2() -> str: return uuid4().hex @pytest.fixture -def pe_id(): +def pe_id() -> str: # payout event / cashout request UUID return uuid4().hex +# --- Settings --- + + +@pytest.fixture(scope="session") +def env_file_path(pytestconfig): + root_path = pytestconfig.rootpath + env_path = os.path.join(root_path, ".env.test") + + if os.path.exists(env_path): + load_dotenv(dotenv_path=env_path, override=True) + + return env_path + + +@pytest.fixture(scope="session") +def settings(env_file_path) -> "Settings": + from jb.settings import Settings as JBSettings + + s = JBSettings(_env_file=env_file_path) + + return s + + +# --- Database Connectors --- + + +@pytest.fixture(scope="session") +def redis(settings): + from generalresearchutils.redis_helper import RedisConfig + + redis_config = RedisConfig( + dsn=settings.redis, + decode_responses=True, + socket_timeout=settings.redis_timeout, + socket_connect_timeout=settings.redis_timeout, + ) + return redis_config.create_redis_client() + + +@pytest.fixture(scope="session") +def pg_config(settings) -> PostgresConfig: + return PostgresConfig( + dsn=settings.amt_jb_db, + connect_timeout=1, + statement_timeout=1, + ) + + +# --- Managers --- + + +@pytest.fixture(scope="session") +def hqm(pg_config) -> "HitQuestionManager": + assert "/unittest-" in pg_config.dsn.path + + from jb.managers.hit import HitQuestionManager + + return HitQuestionManager( + pg_config=pg_config, permissions=[Permission.READ, Permission.CREATE] + ) + + +@pytest.fixture(scope="session") +def htm(pg_config) -> "HitTypeManager": + assert "/unittest-" in pg_config.dsn.path + + from jb.managers.hit import HitTypeManager + + return HitTypeManager( + pg_config=pg_config, permissions=[Permission.READ, Permission.CREATE] + ) + + +@pytest.fixture(scope="session") +def hm(pg_config) -> "HitManager": + assert "/unittest-" in pg_config.dsn.path + + from jb.managers.hit import HitManager + + return HitManager( + pg_config=pg_config, permissions=[Permission.READ, Permission.CREATE] + ) + + +@pytest.fixture(scope="session") +def am(pg_config) -> "AssignmentManager": + assert "/unittest-" in pg_config.dsn.path + + from jb.managers.assignment import AssignmentManager + + return AssignmentManager( + pg_config=pg_config, permissions=[Permission.READ, Permission.CREATE] + ) + + +@pytest.fixture(scope="session") +def bm(pg_config) -> "BonusManager": + assert "/unittest-" in pg_config.dsn.path + + from jb.managers.bonus import BonusManager + + return BonusManager( + pg_config=pg_config, permissions=[Permission.READ, Permission.CREATE] + ) + + +# --- Question --- + + +@pytest.fixture +def question() -> HitQuestion: + return HitQuestion(url="https://jamesbillings67.com/work/", height=1200) + + +@pytest.fixture +def question_record(hqm, question) -> HitQuestion: + return hqm.get_or_create(question) + + +# --- HITType --- + + @pytest.fixture def hit_type() -> HitType: return HitType( @@ -78,42 +196,38 @@ def hit_type() -> HitType: ) -from jb.models.hit import HitType +@pytest.fixture +def hit_type_record(htm, hit_type) -> HitType: + hit_type.amt_hit_type_id = generate_amt_id() + + return htm.get_or_create(hit_type) @pytest.fixture -def hit_type_with_amt_id(hit_type: HitType) -> HitType: +def hit_type_with_amt_id(htm, hit_type: HitType) -> HitType: # This is a real hit type I've previously registered with amt (sandbox). # It will always exist hit_type.amt_hit_type_id = "3217B3DC4P5YW9DRV9R3X8O56V041J" # Get or create our db - HTM.get_or_create(hit_type) + htm.get_or_create(hit_type) # this call adds the pk int id ---^ return hit_type -@pytest.fixture -def question(): - return HitQuestion(url="https://jamesbillings67.com/work/", height=1200) +# --- HIT --- @pytest.fixture -def hit_in_amt(hit_type_with_amt_id: HitType, question: HitQuestion) -> Hit: - # Actually create a new HIT in amt (sandbox) - question = HQM.get_or_create(question) - hit = AMTManager.create_hit_with_hit_type( - hit_type=hit_type_with_amt_id, question=question - ) - # Create it in the DB - HM.create(hit) - return hit +def amt_hit_id() -> str: + return generate_amt_id() @pytest.fixture -def hit(amt_hit_id, amt_hit_type_id, amt_group_id, question): +def hit(amt_hit_id, amt_hit_type_id, amt_group_id, question) -> Hit: now = datetime.now(tz=timezone.utc) + return Hit.model_validate( dict( amt_hit_id=amt_hit_id, @@ -140,24 +254,41 @@ def hit(amt_hit_id, amt_hit_type_id, amt_group_id, question): @pytest.fixture -def hit_in_db( - hit_type: HitType, amt_hit_type_id, amt_hit_id, question: HitQuestion, hit: Hit +def hit_record( + hm, + question_record, + hit_type_record, + hit, + amt_hit_id, ) -> Hit: """ Returns a hit that exists in our db, but does not in amazon (the amt ids are random). The mtwerk_hittype and mtwerk_question records will also exist (in the db) """ - question = HQM.get_or_create(question) - hit_type.amt_hit_type_id = amt_hit_type_id - HTM.create(hit_type) - hit.hit_type_id = hit_type.id + + hit.hit_type_id = hit_type_record.id hit.amt_hit_id = amt_hit_id - hit.question_id = question.id - HM.create(hit) + hit.question_id = question_record.id + + hm.create(hit) + return hit + + +@pytest.fixture +def hit_in_amt(hm, question_record, hit_type_with_amt_id: HitType) -> Hit: + # Actually create a new HIT in amt (sandbox) + hit = AMTManager.create_hit_with_hit_type( + hit_type=hit_type_with_amt_id, question=question_record + ) + # Create it in the DB + hm.create(hit) return hit +# --- Assignment --- + + @pytest.fixture def assignment_stub(hit: Hit, amt_assignment_id, amt_worker_id): now = datetime.now(tz=timezone.utc) @@ -193,28 +324,31 @@ def assignment_factory(hit: Hit): @pytest.fixture -def assignment_in_db_factory(assignment_factory): +def assignment_in_db_factory(am, assignment_factory): def inner(hit_id: int, amt_worker_id: Optional[str] = None): a = assignment_factory(amt_worker_id=amt_worker_id) a.hit_id = hit_id - AM.create_stub(a) - AM.update_answer(a) + am.create_stub(a) + am.update_answer(a) return a return inner @pytest.fixture -def assignment_stub_in_db(hit_in_db, assignment_stub) -> AssignmentStub: +def assignment_stub_in_db(am, hit_record, assignment_stub) -> AssignmentStub: """ Returns an AssignmentStub that exists in our db, but does not in amazon (the amt ids are random). The mtwerk_hit, mtwerk_hittype, and mtwerk_question records will also exist (in the db) """ - assignment_stub.hit_id = hit_in_db.id - AM.create_stub(assignment_stub) + assignment_stub.hit_id = hit_record.id + am.create_stub(assignment_stub) return assignment_stub +# --- HIT --- + + @pytest.fixture def amt_response_metadata(): req_id = str(uuid4()) diff --git a/tests/flow/test_tasks.py b/tests/flow/test_tasks.py index 37391d1..b708cf9 100644 --- a/tests/flow/test_tasks.py +++ b/tests/flow/test_tasks.py @@ -26,8 +26,9 @@ from jb.managers.amt import ( BONUS_MESSAGE, NO_WORK_APPROVAL_MESSAGE, ) -from jb.models.currency import USDCent -from jb.models.definitions import AssignmentStatus, PayoutStatus +from generalresearchutils.currency import USDCent +from jb.models.definitions import AssignmentStatus +from generalresearchutils.models.thl.definitions import PayoutStatus from jb.models.event import MTurkEvent @@ -336,7 +337,7 @@ class TestProcessAssignmentSubmitted: amt_assignment_id, get_assignment_response: Dict, caplog, - hit_in_db, + hit_record, rejected_assignment_stubs, ): # An assignment is submitted. The hit exists in the DB. The amt assignment id is valid, @@ -442,7 +443,7 @@ class TestProcessAssignmentSubmitted: get_assignment_response_rejected_no_tsid, get_assignment_response_no_tsid, assignment_in_db_factory, - hit_in_db, + hit_record, amt_worker_id, ): # An assignment is submitted. The hit and assignment stub exist in the DB. @@ -451,9 +452,9 @@ class TestProcessAssignmentSubmitted: # Going to create and submit 3 assignments w no work # (all on the same hit, which we don't do in JB for real, # but doesn't matter here) - a1 = assignment_in_db_factory(hit_id=hit_in_db.id, amt_worker_id=amt_worker_id) - a2 = assignment_in_db_factory(hit_id=hit_in_db.id, amt_worker_id=amt_worker_id) - a3 = assignment_in_db_factory(hit_id=hit_in_db.id, amt_worker_id=amt_worker_id) + a1 = assignment_in_db_factory(hit_id=hit_record.id, amt_worker_id=amt_worker_id) + a2 = assignment_in_db_factory(hit_id=hit_record.id, amt_worker_id=amt_worker_id) + a3 = assignment_in_db_factory(hit_id=hit_record.id, amt_worker_id=amt_worker_id) assert AM.missing_tsid_count(amt_worker_id=amt_worker_id) == 3 # So now, we'll reject, b/c they've already gotten 3 warnings diff --git a/tests/http/test_basic.py b/tests/http/test_basic.py index 7b03a1e..18359da 100644 --- a/tests/http/test_basic.py +++ b/tests/http/test_basic.py @@ -22,14 +22,3 @@ async def test_static_file_alias(httpxclient: AsyncClient): res = await client.get(p) assert res.status_code == 200, p assert res.json() == {} - - -@pytest.mark.anyio -async def test_health(httpxclient: AsyncClient): - client = httpxclient - """ - These are here for site crawlers and stuff.. - """ - res = await client.get("/health/") - assert res.status_code == 200 - assert res.json() == {} diff --git a/tests/http/test_notifications.py b/tests/http/test_notifications.py index 70458b8..6770044 100644 --- a/tests/http/test_notifications.py +++ b/tests/http/test_notifications.py @@ -5,7 +5,6 @@ from httpx import AsyncClient import secrets from jb.config import JB_EVENTS_STREAM, settings -from jb.decorators import REDIS from jb.models.event import MTurkEvent from tests import generate_amt_id @@ -40,16 +39,17 @@ def example_mturk_event_body(amt_hit_id, amt_hit_type_id, amt_assignment_id): @pytest.fixture() -def clean_mturk_events_redis_stream(): - REDIS.xtrim(JB_EVENTS_STREAM, maxlen=0) - assert REDIS.xlen(JB_EVENTS_STREAM) == 0 +def clean_mturk_events_redis_stream(redis): + redis.xtrim(JB_EVENTS_STREAM, maxlen=0) + assert redis.xlen(JB_EVENTS_STREAM) == 0 yield - REDIS.xtrim(JB_EVENTS_STREAM, maxlen=0) - assert REDIS.xlen(JB_EVENTS_STREAM) == 0 + redis.xtrim(JB_EVENTS_STREAM, maxlen=0) + assert redis.xlen(JB_EVENTS_STREAM) == 0 @pytest.mark.anyio async def test_mturk_notifications( + redis, httpxclient: AsyncClient, no_limit, example_mturk_event_body, @@ -61,10 +61,10 @@ async def test_mturk_notifications( res = await client.post(url=f"/{settings.sns_path}/", json=example_mturk_event_body) res.raise_for_status() - msg_res = REDIS.xread(streams={JB_EVENTS_STREAM: 0}, count=1, block=100) + msg_res = redis.xread(streams={JB_EVENTS_STREAM: 0}, count=1, block=100) msg_res = msg_res[0][1][0] msg_id, msg = msg_res - REDIS.xdel(JB_EVENTS_STREAM, msg_id) + redis.xdel(JB_EVENTS_STREAM, msg_id) msg_json = msg["data"] event = MTurkEvent.model_validate_json(msg_json) diff --git a/tests/http/test_preview.py b/tests/http/test_preview.py new file mode 100644 index 0000000..2bdf265 --- /dev/null +++ b/tests/http/test_preview.py @@ -0,0 +1,41 @@ +# There are two types of "preview" - one is where we navigate direclty +# to it and one is where we redirect possibly + +import pytest +from httpx import AsyncClient + +from jb.models.hit import Hit + + +class TestPreview: + + @pytest.mark.anyio + async def test_preview_direct(self, httpxclient: AsyncClient): + client = httpxclient + res = await client.get("/preview/") + + assert res.status_code == 200 + # the response is an html page + + assert res.headers["content-type"] == "text/html; charset=utf-8" + assert res.num_bytes_downloaded == 507 + + assert "James Billings loves you." in res.text + assert "https://cdn.jamesbillings67.com/james-has-style.css" in res.text + assert "https://cdn.jamesbillings67.com/james-billings.js" in res.text + + @pytest.mark.anyio + async def test_preview_redirect_from_work( + self, httpxclient: AsyncClient, amt_hit_id, amt_assignment_id + ): + client = httpxclient + + params = { + "workerId": None, + "assignmentId": amt_assignment_id, + "hitId": amt_hit_id, + } + res = await client.get("/work/", params=params) + + assert res.status_code == 302 + assert "/preview/" in res.headers["location"] diff --git a/tests/http/test_report.py b/tests/http/test_report.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/http/test_status.py b/tests/http/test_status.py deleted file mode 100644 index d88ff65..0000000 --- a/tests/http/test_status.py +++ /dev/null @@ -1,78 +0,0 @@ -from uuid import uuid4 - -import pytest -from httpx import AsyncClient - -from jb.config import settings -from tests import generate_amt_id - - -@pytest.mark.anyio -async def test_get_status_args(httpxclient: AsyncClient, no_limit): - client = httpxclient - - # tsid misformatted - res = await client.get(f"/status/{uuid4().hex[:-1]}/") - assert res.status_code == 422 - assert "String should have at least 32 characters" in res.text - - -@pytest.mark.anyio -async def test_get_status_error(httpxclient: AsyncClient, no_limit): - # Expects settings.fsb_host to point to a functional thl-fsb - client = httpxclient - - # tsid doesn't exist - res = await client.get(f"/status/{uuid4().hex}/") - assert res.status_code == 502 - assert res.json()["detail"] == "Failed to fetch status" - - -@pytest.mark.anyio -async def test_get_status_complete(httpxclient: AsyncClient, no_limit, mock_requests): - client = httpxclient - - tsid = uuid4().hex - url = f"{settings.fsb_host}{settings.product_id}/status/{tsid}/" - - mock_response = { - "tsid": tsid, - "product_id": settings.product_id, - "bpuid": generate_amt_id(length=21), - "started": "2022-06-29T23:43:48.247777Z", - "finished": "2022-06-29T23:56:57.632634Z", - "status": 3, - "payout": 81, - "user_payout": 77, - "payout_format": "${payout/100:.2f}", - "user_payout_string": "$0.77", - "kwargs": {}, - } - mock_requests.get(url, json=mock_response, status_code=200) - res = await client.get(f"/status/{tsid}/") - assert res.status_code == 200 - assert res.json() == {"status": 3, "payout": "$0.77"} - - -@pytest.mark.anyio -async def test_get_status_failure(httpxclient: AsyncClient, no_limit, mock_requests): - client = httpxclient - - tsid = uuid4().hex - url = f"{settings.fsb_host}{settings.product_id}/status/{tsid}/" - - mock_response = { - "tsid": tsid, - "product_id": settings.product_id, - "bpuid": "123ABC", - "status": 2, - "payout": 0, - "user_payout": 0, - "payout_format": "${payout/100:.2f}", - "user_payout_string": None, - "kwargs": {}, - } - mock_requests.get(url, json=mock_response, status_code=200) - res = await client.get(f"/status/{tsid}/") - assert res.status_code == 200 - assert res.json() == {"status": 2, "payout": None} diff --git a/tests/http/test_statuses.py b/tests/http/test_statuses.py deleted file mode 100644 index ffc98fd..0000000 --- a/tests/http/test_statuses.py +++ /dev/null @@ -1,102 +0,0 @@ -from datetime import datetime, timezone, timedelta -from urllib.parse import urlencode - -import pytest -from uuid import uuid4 -from httpx import AsyncClient - -from jb.config import settings - - -@pytest.mark.anyio -async def test_get_statuses(httpxclient: AsyncClient, no_limit, amt_worker_id): - # Expects settings.fsb_host to point to a functional thl-fsb - client = httpxclient - now = datetime.now(tz=timezone.utc) - - params = {"worker_id": amt_worker_id} - res = await client.get(f"/statuses/", params=params) - assert res.status_code == 200 - assert res.json() == [] - - params = {"worker_id": amt_worker_id, "started_after": now.isoformat()} - res = await client.get(f"/statuses/", params=params) - assert res.status_code == 422 - assert "Input should be a valid integer" in res.text - - -@pytest.fixture -def fsb_get_statuses_example_response(amt_worker_id, tsid1, tsid2): - return { - "tasks_status": [ - { - "tsid": tsid1, - "product_id": settings.product_id, - "bpuid": amt_worker_id, - "started": "2025-06-12T03:27:24.902280Z", - "finished": "2025-06-12T03:29:37.626481Z", - "status": 2, - "payout": 0, - "user_payout": None, - "payout_format": None, - "user_payout_string": None, - "kwargs": {}, - "status_code_1": "SESSION_START_QUALITY_FAIL", - "status_code_2": "ENTRY_URL_MODIFICATION", - }, - { - "tsid": tsid2, - "product_id": settings.product_id, - "bpuid": amt_worker_id, - "started": "2025-06-12T03:30:18.176826Z", - "finished": "2025-06-12T03:36:58.789059Z", - "status": 2, - "payout": 0, - "user_payout": None, - "payout_format": None, - "user_payout_string": None, - "kwargs": {}, - "status_code_1": "BUYER_QUALITY_FAIL", - "status_code_2": None, - }, - ] - } - - -@pytest.mark.anyio -async def test_get_statuses_mock( - httpxclient: AsyncClient, - no_limit, - amt_worker_id, - mock_requests, - fsb_get_statuses_example_response, - tsid1, - tsid2, -): - client = httpxclient - now = datetime.now(tz=timezone.utc) - started_after = now - timedelta(minutes=5) - - # The fsb call we are mocking ------v - params = { - "bpuid": amt_worker_id, - "started_after": round(started_after.timestamp()), - "started_before": round(now.timestamp()), - } - url = f"{settings.fsb_host}{settings.product_id}/status/" + "?" + urlencode(params) - mock_requests.get(url, json=fsb_get_statuses_example_response, status_code=200) - # ---- end mock - - params = { - "worker_id": amt_worker_id, - "started_after": round(started_after.timestamp()), - "started_before": round(now.timestamp()), - } - result = await client.get(f"/statuses/", params=params) - assert result.status_code == 200 - res = result.json() - assert len(res) == 2 - assert res == [ - {"status": 2, "tsid": tsid1}, - {"status": 2, "tsid": tsid2}, - ] diff --git a/tests/http/test_work.py b/tests/http/test_work.py index 59b8830..c69118b 100644 --- a/tests/http/test_work.py +++ b/tests/http/test_work.py @@ -1,24 +1,24 @@ import pytest from httpx import AsyncClient -from jb.models.hit import Hit +class TestWork: -@pytest.mark.skip(reason="hits live api, need to look at this") -async def test_work( - httpxclient: AsyncClient, - no_limit, - amt_worker_id, - amt_assignment_id, - hit_in_amt: Hit, -): - client = httpxclient - params = { - "workerId": amt_worker_id, - "assignmentId": amt_assignment_id, - "hitId": hit_in_amt.amt_hit_id, - } - res = await client.get(f"/work/", params=params) - assert res.status_code == 200 - # the response is an html page - assert res.headers["content-type"] == "text/html; charset=utf-8" + @pytest.mark.anyio + async def test_work( + self, + httpxclient: AsyncClient, + hit_record, + amt_assignment_id, + amt_worker_id, + ): + client = httpxclient + + params = { + "workerId": amt_worker_id, + "assignmentId": amt_assignment_id, + "hitId": hit_record.amt_hit_id, + } + res = await client.get("/work/", params=params) + + assert res.status_code == 200 diff --git a/tests/managers/amt.py b/tests/managers/amt.py index 0b2e501..a847582 100644 --- a/tests/managers/amt.py +++ b/tests/managers/amt.py @@ -1,4 +1,3 @@ -from jb.decorators import HTM, HM, HQM from jb.managers.amt import AMTManager @@ -8,16 +7,16 @@ def test_create_hit_type(hit_type): assert hit_type.amt_hit_type_id is not None -def test_create_hit_with_hit_type(hit_type_with_amt_id, question): - question = HQM.get_or_create(question) +def test_create_hit_with_hit_type(hqm, htm, hm, hit_type_with_amt_id, question): + question = hqm.get_or_create(question) hit_type = hit_type_with_amt_id hit_type = [ - x for x in HTM.filter_active() if x.amt_hit_type_id == hit_type.amt_hit_type_id + x for x in htm.filter_active() if x.amt_hit_type_id == hit_type.amt_hit_type_id ][0] hit = AMTManager.create_hit_with_hit_type(hit_type=hit_type, question=question) assert hit.amt_hit_id is not None assert hit.id is None - HM.create(hit) + hm.create(hit) assert hit.id is not None diff --git a/tests/managers/hit.py b/tests/managers/hit.py index 8fcd673..cb2b35a 100644 --- a/tests/managers/hit.py +++ b/tests/managers/hit.py @@ -1,18 +1,25 @@ -from jb.decorators import HTM +from jb.models import Question + + +class TestHitQuestionManager: + + def test_base(self, question_record): + assert isinstance(question_record, Question) + assert question_record.id is None class TestHitTypeManager: - def test_create(self, hit_type_with_amt_id): + def test_create(self, htm, hit_type_with_amt_id): assert hit_type_with_amt_id.id is None - HTM.create(hit_type_with_amt_id) + htm.create(hit_type_with_amt_id) assert hit_type_with_amt_id.id is not None - res = HTM.filter_active() + res = htm.filter_active() assert len(res) == 1 hit_type_with_amt_id.min_active = 0 - HTM.set_min_active(hit_type_with_amt_id) + htm.set_min_active(hit_type_with_amt_id) - res = HTM.filter_active() + res = htm.filter_active() assert len(res) == 0 -- cgit v1.2.3