package pipeline import ( "context" "net/http" "net/http/httptest" "sync/atomic" "testing" "evobgp/internal/store" ) func TestCDNRefreshSameSetDoesNotRewriteOrRevise(t *testing.T) { t.Setenv("EVOBGP_CDN_ALLOW_PRIVATE", "1") m := store.NewMemory() m.SeedDemo() tenant, _, _, _, _ := m.DemoIDs() disabled := false for _, mod := range m.ListModules(tenant) { if mod == nil { continue } if _, err := m.UpdateModule(tenant, mod.ID, &store.ModulePatch{Enabled: &disabled}); err != nil { t.Fatal(err) } } var body atomic.Value body.Store("203.0.113.0/24\n198.51.100.0/24\n") srv := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte(body.Load().(string))) })) defer srv.Close() mod, err := m.CreateModule(tenant, &store.Module{Type: "CDN_CIDRS", Name: "cdn-order", Enabled: true}) if err != nil { t.Fatal(err) } if _, err := m.CreateCDNSource(tenant, mod.ID, &store.CDNSource{SourceKind: "plain", URL: srv.URL}); err != nil { t.Fatal(err) } ctx := context.Background() if err := RefreshModuleIngest(ctx, m, srv.Client(), tenant, mod.ID); err != nil { t.Fatal(err) } snap1, ok, err := m.GetModulePrefixSnapshot(ctx, tenant, mod.ID) if err != nil || !ok || snap1 == nil { t.Fatalf("snapshot: ok=%v err=%v", ok, err) } gen1, err := m.GetRenderGeneration(ctx, tenant) if err != nil { t.Fatal(err) } if err := RefreshModuleIngest(ctx, m, srv.Client(), tenant, mod.ID); err != nil { t.Fatal(err) } snapSame, ok, err := m.GetModulePrefixSnapshot(ctx, tenant, mod.ID) if err != nil || !ok || snapSame == nil { t.Fatal(err) } genSame, err := m.GetRenderGeneration(ctx, tenant) if err != nil { t.Fatal(err) } if snapSame.Version != snap1.Version || !snapSame.CollectedAt.Equal(snap1.CollectedAt) || genSame != gen1 { t.Fatalf("unchanged CDN rewritten: version %d->%d gen %d->%d", snap1.Version, snapSame.Version, gen1, genSame) } body.Store("198.51.100.0/24\n203.0.113.0/24\n") if err := RefreshModuleIngest(ctx, m, srv.Client(), tenant, mod.ID); err != nil { t.Fatal(err) } snap2, ok, err := m.GetModulePrefixSnapshot(ctx, tenant, mod.ID) if err != nil || !ok || snap2 == nil { t.Fatal(err) } gen2, err := m.GetRenderGeneration(ctx, tenant) if err != nil { t.Fatal(err) } if snap2.Version != snap1.Version || !snap2.CollectedAt.Equal(snap1.CollectedAt) || gen2 != gen1 { t.Fatalf("reordered CDN rewritten: version %d->%d gen %d->%d", snap1.Version, snap2.Version, gen1, gen2) } if len(snap2.Prefixes) != len(snap1.Prefixes) || snap2.Prefixes[0].Prefix != snap1.Prefixes[0].Prefix { t.Fatalf("row order changed without a content change: %+v", snap2.Prefixes) } before, _, _ := m.ListRevisions(tenant, "", "", 50) rev1, err := RenderTenantRevision(ctx, m, srv.Client(), tenant, mod.ID) if err != nil { t.Fatal(err) } rev2, err := RenderTenantRevision(ctx, m, srv.Client(), tenant, mod.ID) if err != nil { t.Fatal(err) } if rev2 != rev1 { t.Fatalf("order-stable inputs created another revision: %s vs %s", rev1, rev2) } mid, _, _ := m.ListRevisions(tenant, "", "", 50) if len(mid) != len(before)+1 { t.Fatalf("revisions after unchanged renders: before=%d after=%d", len(before), len(mid)) } body.Store("203.0.113.0/24\n192.0.2.0/24\n") if err := RefreshModuleIngest(ctx, m, srv.Client(), tenant, mod.ID); err != nil { t.Fatal(err) } rev3, err := RenderTenantRevision(ctx, m, srv.Client(), tenant, mod.ID) if err != nil { t.Fatal(err) } if rev3 == rev1 { t.Fatal("prefix change did not create a revision") } after, _, _ := m.ListRevisions(tenant, "", "", 50) if len(after) != len(mid)+1 { t.Fatalf("prefix change revisions: before=%d after=%d", len(mid), len(after)) } }