Skip to content

Commit 124b711

Browse files
committed
test coverage: ensure that multi insert preserves job args
1 parent f27a3bb commit 124b711

File tree

5 files changed

+77
-12
lines changed

5 files changed

+77
-12
lines changed

.github/workflows/ci.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ jobs:
4040
uses: actions/checkout@v4
4141

4242
- name: Install Rye
43-
uses: eifinger/setup-rye@v3
43+
uses: eifinger/setup-rye@v4
4444

4545
# Needed for River's CLI. There is a version of Go on Actions' base image,
4646
# but it's old and can't read modern `go.mod` annotations correctly.
@@ -89,7 +89,7 @@ jobs:
8989
uses: actions/checkout@v4
9090

9191
- name: Install Rye
92-
uses: eifinger/setup-rye@v3
92+
uses: eifinger/setup-rye@v4
9393

9494
# Needed for River's CLI. There is a version of Go on Actions' base image,
9595
# but it's old and can't read modern `go.mod` annotations correctly.
@@ -122,7 +122,7 @@ jobs:
122122
uses: actions/checkout@v4
123123

124124
- name: Install Rye
125-
uses: eifinger/setup-rye@v3
125+
uses: eifinger/setup-rye@v4
126126

127127
- name: Rye sync
128128
run: rye sync

src/riverqueue/client.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -703,9 +703,9 @@ def unique_bitmask_to_states(mask: str) -> list[JobState]:
703703

704704
def _validate_tags(tags: list[str]) -> list[str]:
705705
for tag in tags:
706-
assert (
707-
len(tag) <= 255 and tag_re.match(tag)
708-
), f"tags should be less than 255 characters in length and match regex {tag_re.pattern}"
706+
assert len(tag) <= 255 and tag_re.match(tag), (
707+
f"tags should be less than 255 characters in length and match regex {tag_re.pattern}"
708+
)
709709
return tags
710710

711711

tests/client_test.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,6 @@ def test_unique_bitmask_from_states(description, input_states, postgres_bitstrin
507507
input_states = []
508508

509509
result = unique_bitmask_from_states(input_states)
510-
assert (
511-
result == postgres_bitstring
512-
), f"{description} For states {input_states}, expected {postgres_bitstring}, got {result}"
510+
assert result == postgres_bitstring, (
511+
f"{description} For states {input_states}, expected {postgres_bitstring}, got {result}"
512+
)

tests/conftest.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,6 @@ def check_leftover_jobs(engine) -> Iterator[None]:
9898

9999
with engine.begin() as conn_tx:
100100
jobs = river_job.Querier(conn_tx).job_get_all()
101-
assert (
102-
list(jobs) == []
103-
), "test case should not have persisted any jobs after run"
101+
assert list(jobs) == [], (
102+
"test case should not have persisted any jobs after run"
103+
)

tests/driver/riversqlalchemy/sqlalchemy_driver_test.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,39 @@ async def test_insert_many_tx(self, client, simple_args, test_tx):
305305
assert results[0].unique_skipped_as_duplicated is False
306306
assert results[0].job.id > 0
307307

308+
@pytest.mark.asyncio
309+
async def test_insert_many_preserves_distinct_args(self, client):
310+
# Insert mixed types and ensure each row retains its own args and kind
311+
from dataclasses import dataclass
312+
313+
@dataclass
314+
class TypeA:
315+
n: int
316+
kind: str = "simple_a"
317+
318+
def to_json(self) -> str:
319+
return json.dumps({"a": self.n})
320+
321+
@dataclass
322+
class TypeB:
323+
s: str
324+
kind: str = "simple_b"
325+
326+
def to_json(self) -> str:
327+
return json.dumps({"b": self.s})
328+
329+
batch = [TypeA(1), TypeB("x"), TypeA(2), TypeB("y")]
330+
results = await client.insert_many(batch)
331+
332+
assert len(results) == 4
333+
for res, arg in zip(results, batch):
334+
if isinstance(arg, TypeA):
335+
assert res.job.kind == "simple_a"
336+
assert res.job.args == {"a": arg.n}
337+
else:
338+
assert res.job.kind == "simple_b"
339+
assert res.job.args == {"b": arg.s}
340+
308341

309342
class TestSyncClient:
310343
#
@@ -502,3 +535,35 @@ def test_insert_many_tx(self, client, simple_args, test_tx):
502535
assert len(results) == 1
503536
assert results[0].unique_skipped_as_duplicated is False
504537
assert results[0].job.id > 0
538+
539+
def test_insert_many_preserves_distinct_args(self, client):
540+
# Insert mixed types and ensure each row retains its own args and kind
541+
from dataclasses import dataclass
542+
543+
@dataclass
544+
class TypeA:
545+
n: int
546+
kind: str = "simple_a"
547+
548+
def to_json(self) -> str:
549+
return json.dumps({"a": self.n})
550+
551+
@dataclass
552+
class TypeB:
553+
s: str
554+
kind: str = "simple_b"
555+
556+
def to_json(self) -> str:
557+
return json.dumps({"b": self.s})
558+
559+
batch = [TypeA(1), TypeB("x"), TypeA(2), TypeB("y")]
560+
results = client.insert_many(batch)
561+
562+
assert len(results) == 4
563+
for res, arg in zip(results, batch):
564+
if isinstance(arg, TypeA):
565+
assert res.job.kind == "simple_a"
566+
assert res.job.args == {"a": arg.n}
567+
else:
568+
assert res.job.kind == "simple_b"
569+
assert res.job.args == {"b": arg.s}

0 commit comments

Comments
 (0)