aboutsummaryrefslogtreecommitdiff
path: root/tests/fixtures/models.py
diff options
context:
space:
mode:
authorMax Nanis2026-02-26 15:51:49 -0500
committerMax Nanis2026-02-26 15:51:49 -0500
commit0bf32fadd85d5938ae29d489efdd82e2cd137300 (patch)
tree814e8128947fb604dc7cc3509e72260d95757590 /tests/fixtures/models.py
parent04aee0dc7e908ce020d2d2c3f8ffb4a96424b883 (diff)
downloadamt-jb-0bf32fadd85d5938ae29d489efdd82e2cd137300.tar.gz
amt-jb-0bf32fadd85d5938ae29d489efdd82e2cd137300.zip
Passing Managers into flow tasks for better pytest usage. Conftests broken out into seperate fixture files. Extensive type hinting.
Diffstat (limited to 'tests/fixtures/models.py')
-rw-r--r--tests/fixtures/models.py279
1 files changed, 279 insertions, 0 deletions
diff --git a/tests/fixtures/models.py b/tests/fixtures/models.py
new file mode 100644
index 0000000..03bd8a2
--- /dev/null
+++ b/tests/fixtures/models.py
@@ -0,0 +1,279 @@
+from datetime import timezone, datetime
+
+import pytest
+
+from jb.models.event import MTurkEvent
+from generalresearchutils.pg_helper import PostgresConfig
+
+from datetime import datetime, timezone, timedelta
+from typing import Optional, TYPE_CHECKING, Callable, Generator
+from jb.managers.amt import AMTManager
+from jb.models.assignment import AssignmentStub, Assignment
+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
+
+if TYPE_CHECKING:
+ from jb.managers.hit import HitQuestionManager, HitTypeManager, HitManager
+ from jb.managers.assignment import AssignmentManager
+
+
+# --- MTurk Event ---
+
+
+@pytest.fixture
+def mturk_event(
+ amt_assignment_id: str, amt_hit_id: str, amt_hit_type_id: str
+) -> MTurkEvent:
+ now = datetime.now(tz=timezone.utc)
+ return MTurkEvent(
+ event_type="AssignmentSubmitted",
+ event_timestamp=now,
+ amt_assignment_id=amt_assignment_id,
+ amt_hit_type_id=amt_hit_type_id,
+ amt_hit_id=amt_hit_id,
+ )
+
+
+# --- Question ---
+
+
+@pytest.fixture
+def question() -> HitQuestion:
+ return HitQuestion(url="https://jamesbillings67.com/work/", height=1200)
+
+
+@pytest.fixture
+def question_record(hqm: "HitQuestionManager", question: HitQuestion) -> HitQuestion:
+ return hqm.get_or_create(question)
+
+
+# --- HITType ---
+
+
+@pytest.fixture
+def hit_type() -> HitType:
+ return HitType(
+ title="Awesome Surveys!",
+ description="Give us your opinion",
+ reward=USDCent(5),
+ keywords="market,research,amazing",
+ min_active=10,
+ )
+
+
+@pytest.fixture
+def hit_type_record(
+ pg_config: PostgresConfig, htm: "HitTypeManager", hit_type: HitType
+) -> Generator[HitType, None, None]:
+
+ hit_type.amt_hit_type_id = generate_amt_id()
+
+ ht = htm.get_or_create(hit_type)
+
+ yield ht
+
+ with pg_config.make_connection() as conn:
+ with conn.cursor() as c:
+ c.execute("DELETE FROM mtwerk_hittype WHERE id=%s", (ht.id,))
+ conn.commit()
+
+
+@pytest.fixture
+def hit_type_record_with_amt_id(
+ pg_config: PostgresConfig, htm: "HitTypeManager", hit_type: HitType
+) -> Generator[HitType, None, None]:
+ # 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
+ ht = htm.get_or_create(hit_type)
+
+ yield ht
+
+ with pg_config.make_connection() as conn:
+ with conn.cursor() as c:
+ c.execute("DELETE FROM mtwerk_hittype WHERE id=%s", (ht.id,))
+ conn.commit()
+
+
+# --- HIT ---
+
+
+@pytest.fixture
+def hit(
+ amt_hit_id: str, amt_hit_type_id: str, amt_group_id: str, question: HitQuestion
+) -> Hit:
+ now = datetime.now(tz=timezone.utc)
+
+ return Hit.model_validate(
+ dict(
+ amt_hit_id=amt_hit_id,
+ amt_hit_type_id=amt_hit_type_id,
+ amt_group_id=amt_group_id,
+ status=HitStatus.Assignable,
+ review_status=HitReviewStatus.NotReviewed,
+ creation_time=now,
+ expiration=now + timedelta(days=3),
+ hit_question_xml=question.xml,
+ qualification_requirements=[],
+ max_assignments=1,
+ assignment_pending_count=0,
+ assignment_available_count=1,
+ assignment_completed_count=0,
+ description="Description",
+ keywords="Keywords",
+ reward=USDCent(5),
+ title="Title",
+ question_id=question.id,
+ hit_type_id=None,
+ )
+ )
+
+
+@pytest.fixture
+def hit_record(
+ pg_config: PostgresConfig,
+ hm: "HitManager",
+ question_record: HitQuestion,
+ hit_type_record: HitType,
+ hit: Hit,
+ amt_hit_id: str,
+) -> Generator[Hit, None, None]:
+ """
+ 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)
+ """
+
+ hit.hit_type_id = hit_type_record.id
+ hit.amt_hit_id = amt_hit_id
+ hit.question_id = question_record.id
+
+ hm.create(hit)
+
+ yield hit
+
+ with pg_config.make_connection() as conn:
+ with conn.cursor() as c:
+ c.execute("DELETE FROM mtwerk_hit WHERE id=%s", (hit.id,))
+ conn.commit()
+
+
+@pytest.fixture
+def hit_in_amt(
+ hm: "HitManager", question_record: HitQuestion, hit_type_record_with_amt_id: HitType
+) -> Hit:
+ # Actually create a new HIT in amt (sandbox)
+ hit = AMTManager.create_hit_with_hit_type(
+ hit_type=hit_type_record_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: str, amt_worker_id: str
+) -> AssignmentStub:
+ now = datetime.now(tz=timezone.utc)
+ return AssignmentStub(
+ amt_assignment_id=amt_assignment_id,
+ amt_hit_id=hit.amt_hit_id,
+ amt_worker_id=amt_worker_id,
+ status=AssignmentStatus.Submitted,
+ modified_at=now,
+ created_at=now,
+ )
+
+
+@pytest.fixture
+def assignment_stub_record(
+ pg_config: PostgresConfig,
+ am: "AssignmentManager",
+ hit_record: Hit,
+ assignment_stub: AssignmentStub,
+) -> Generator[AssignmentStub, None, None]:
+ """
+ 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_record.id
+ am.create_stub(stub=assignment_stub)
+
+ yield assignment_stub
+
+ with pg_config.make_connection() as conn:
+ with conn.cursor() as c:
+ c.execute(
+ "DELETE FROM mtwerk_assignment WHERE id=%s", (assignment_stub.id,)
+ )
+ conn.commit()
+
+
+@pytest.fixture
+def assignment(assignment_factory: Callable[..., Assignment]) -> Assignment:
+ return assignment_factory()
+
+
+@pytest.fixture
+def assignment_record(
+ pg_config: PostgresConfig,
+ hit_record: Hit,
+ assignment_record_factory: Callable[..., Assignment],
+) -> Generator[Assignment, None, None]:
+ assignment = assignment_record_factory(hit_id=hit_record.id)
+
+ yield assignment
+
+ with pg_config.make_connection() as conn:
+ with conn.cursor() as c:
+ c.execute(
+ "DELETE FROM mtwerk_assignment WHERE id=%s", (assignment_stub.id,)
+ )
+ conn.commit()
+
+
+@pytest.fixture
+def assignment_factory(hit: Hit) -> Callable[[Optional[str]], Assignment]:
+
+ def _inner(amt_worker_id: Optional[str] = None) -> Assignment:
+ now = datetime.now(tz=timezone.utc)
+ amt_assignment_id = generate_amt_id()
+ amt_worker_id = amt_worker_id or generate_amt_id()
+
+ return Assignment(
+ amt_assignment_id=amt_assignment_id,
+ amt_hit_id=hit.amt_hit_id,
+ amt_worker_id=amt_worker_id,
+ status=AssignmentStatus.Submitted,
+ modified_at=now,
+ created_at=now,
+ accept_time=now,
+ auto_approval_time=now,
+ submit_time=now,
+ )
+
+ return _inner
+
+
+@pytest.fixture
+def assignment_record_factory(
+ am: "AssignmentManager", assignment_factory: Callable[..., Assignment]
+) -> Callable[..., Assignment]:
+
+ def _inner(hit_id: int, amt_worker_id: Optional[str] = None) -> Assignment:
+ a = assignment_factory(amt_worker_id=amt_worker_id)
+ a.hit_id = hit_id
+ am.create_stub(a)
+ am.update_answer(a)
+ return a
+
+ return _inner