internal product index
Build and Publish / BuildAndDeployArm64 (push) Failing after 6s
Build and Publish / BuildAndDeployAmd64 (push) Failing after 10s

This commit is contained in:
2026-06-28 18:40:58 +02:00
parent aa8b2bdedc
commit 63b0112cc7
4 changed files with 135 additions and 9 deletions
+39
View File
@@ -146,6 +146,45 @@ func TestProjectionCache_BusRaceSafe(t *testing.T) {
}
}
// TestApply_MixedUpsertDelete verifies the realistic per-batch sequence a
// publisher emits: a single Apply call interleaves upserts and deletes, and
// the per-batch counters report the right split. Without this the cache could
// drift on count semantics across batched events.
func TestApply_MixedUpsertDelete(t *testing.T) {
c := newCatalogProjectionCache()
// Order matters: prior in-cache state for A is upserted twice (latest wins),
// B is tombstoned, C cold-upserted, D cold-tombstoned.
updates := []catalog.ProjectionUpdate{
{Projection: catalog.Projection{SKU: "A", PriceIncVat: money.Cents(50_00)}},
{Projection: catalog.Projection{SKU: "B"}, Deleted: true},
{Projection: catalog.Projection{SKU: "C", PriceIncVat: money.Cents(75_00)}},
{Projection: catalog.Projection{SKU: "A", PriceIncVat: money.Cents(60_00)}}, // later wins
{Projection: catalog.Projection{SKU: "D"}, Deleted: true},
}
upserts, deletes := c.Apply(updates)
if upserts != 3 || deletes != 2 {
t.Fatalf("counts: upserts=%d deletes=%d, want 3/2 (A,C live-upserts; B,D tombstones)", upserts, deletes)
}
if got, ok := c.Get("A"); !ok || got.PriceIncVat != money.Cents(60_00) {
t.Fatalf("A latest-wins: got %+v ok=%v, want 6000", got, ok)
}
if _, ok := c.Get("B"); ok {
t.Fatalf("B: tombstoned but Get returned a value")
}
if !c.IsDeleted("B") {
t.Fatalf("B: IsDeleted not true")
}
if got, ok := c.Get("C"); !ok || got.PriceIncVat != money.Cents(75_00) {
t.Fatalf("C cold-upsert: got %+v ok=%v, want 7500", got, ok)
}
if !c.IsDeleted("D") {
t.Fatalf("D: IsDeleted not true")
}
if c.Len() != 4 {
t.Fatalf("Len() after mixed batch: %d, want 4 (A live + B tombstone + C live + D tombstone)", c.Len())
}
}
// TestTaxResolveBp covers the static TaxClass→bp mapping used by
// ApplyProjectionOverlay. Adds a regression net for the common Nordic rates.
func TestTaxResolveBp(t *testing.T) {