package usage import ( "context" "sync" "testing" ) // Akzeptanzkriterium 1 + 2 + Pruefung 1: paralleler Schreib-Test (viele // gleichzeitige Uploads) ergibt korrekten Endstand ohne verlorene Updates. func TestReportStorageWrite_ConcurrentUploadsSumCorrectly(t *testing.T) { store, cleanup := setupTest(t) defer cleanup() ctx := context.Background() tenant := newTenantID() sizes := []int64{1024, 2048, 4096, 8192, 512, 256, 1000, 999, 1, 7000} var wg sync.WaitGroup for _, size := range sizes { wg.Add(1) go func(sz int64) { defer wg.Done() if err := store.ReportStorageWrite(ctx, tenant, sz); err != nil { t.Errorf("report write: %v", err) } }(size) } wg.Wait() var expected int64 for _, s := range sizes { expected += s } got, err := store.CurrentStorageUsage(ctx, tenant) if err != nil { t.Fatalf("current usage: %v", err) } if got != expected { t.Fatalf("erwartet %d bytes (unabhaengige kontrollsumme), habe %d — hinweis auf verlorene updates", expected, got) } } // Akzeptanzkriterium 1 + Pruefung 2: Loeschvorgang dekrementiert korrekt. func TestReportStorageDelete_Decrements(t *testing.T) { store, cleanup := setupTest(t) defer cleanup() ctx := context.Background() tenant := newTenantID() if err := store.ReportStorageWrite(ctx, tenant, 10_000); err != nil { t.Fatalf("write: %v", err) } if err := store.ReportStorageDelete(ctx, tenant, 3_000); err != nil { t.Fatalf("delete: %v", err) } got, err := store.CurrentStorageUsage(ctx, tenant) if err != nil { t.Fatalf("current usage: %v", err) } if got != 7_000 { t.Fatalf("erwartet 7000 nach schreiben(10000)+loeschen(3000), habe %d", got) } } // Akzeptanzkriterium 3 + Pruefung 3: Abfrage liefert konsistenten Wert mit // einer unabhaengigen Kontrollzaehlung ueber gemischte Schreib-/Loeschvorgaenge. func TestCurrentStorageUsage_MatchesIndependentTally(t *testing.T) { store, cleanup := setupTest(t) defer cleanup() ctx := context.Background() tenant := newTenantID() type op struct { write bool size int64 } ops := []op{ {true, 5000}, {true, 3000}, {false, 1000}, {true, 2000}, {false, 4000}, {true, 500}, } var tally int64 for _, o := range ops { if o.write { if err := store.ReportStorageWrite(ctx, tenant, o.size); err != nil { t.Fatalf("write: %v", err) } tally += o.size } else { if err := store.ReportStorageDelete(ctx, tenant, o.size); err != nil { t.Fatalf("delete: %v", err) } tally -= o.size } } got, err := store.CurrentStorageUsage(ctx, tenant) if err != nil { t.Fatalf("current usage: %v", err) } if got != tally { t.Fatalf("erwartet %d (unabhaengige kontrollzaehlung), habe %d", tally, got) } } // Akzeptanzkriterium 3: LIC-03s generischer Store.Get liefert denselben Wert // wie CurrentStorageUsage — kein zweiter, abweichender Zaehlmechanismus. func TestCurrentStorageUsage_MatchesGenericStoreGet(t *testing.T) { store, cleanup := setupTest(t) defer cleanup() ctx := context.Background() tenant := newTenantID() if err := store.ReportStorageWrite(ctx, tenant, 42); err != nil { t.Fatalf("write: %v", err) } viaStorage, err := store.CurrentStorageUsage(ctx, tenant) if err != nil { t.Fatalf("current usage: %v", err) } viaGeneric, err := store.Get(ctx, tenant, StorageBytesMetric) if err != nil { t.Fatalf("generic get: %v", err) } if viaStorage != viaGeneric || viaStorage != 42 { t.Fatalf("erwartet beide wege liefern 42, habe storage=%d generic=%d", viaStorage, viaGeneric) } }