package importer import ( "context" "errors" "strings" "testing" "evobgp/internal/store" ) type importBackend struct { store.Backend created int onCreate func() } func (s *importBackend) GetModule(string, string) (*store.Module, error) { return &store.Module{Type: "AS_PREFIXES"}, nil } func (s *importBackend) ListCommunities(string) ([]*store.Community, error) { return nil, nil } func (s *importBackend) CreateASEntry(_, _ string, e *store.ASEntry) (*store.ASEntry, error) { s.created++ if s.onCreate != nil { s.onCreate() } return e, nil } func TestCSVByteLimitRejectsValidTruncatedPrefix(t *testing.T) { header := "asn,community\n" for _, extra := range []int{0, 1} { s := &importBackend{} body := header + strings.Repeat("\n", MaxCSVBytes-len(header)) + strings.Repeat("\n", extra) _, err := ImportModuleEntriesCSV(context.Background(), s, "tenant", "module", strings.NewReader(body)) if extra == 0 && err != nil { t.Fatalf("exact limit: %v", err) } if extra == 1 && !errors.Is(err, ErrCSVTooLarge) { t.Fatalf("limit+1: %v", err) } if s.created != 0 { t.Fatal("oversized import created entries") } } } func TestCSVRowLimitCheckedBeforeWrites(t *testing.T) { for _, header := range []string{"", "asn,community\n"} { for _, extra := range []int{0, 1} { s := &importBackend{} _, err := ImportModuleEntriesCSV(context.Background(), s, "tenant", "module", strings.NewReader(header+strings.Repeat("64512,\n", MaxCSVRows+extra))) if extra == 0 && (err != nil || s.created != MaxCSVRows) { t.Fatalf("exact rows: created=%d err=%v", s.created, err) } if extra == 1 && (!errors.Is(err, ErrCSVTooLarge) || s.created != 0) { t.Fatalf("rows+1: created=%d err=%v", s.created, err) } } } } func TestCSVCancellationStopsFurtherWrites(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() s := &importBackend{onCreate: cancel} _, err := ImportModuleEntriesCSV(ctx, s, "tenant", "module", strings.NewReader("asn,community\n64512,\n64513,\n")) if !errors.Is(err, context.Canceled) || s.created != 1 { t.Fatalf("created=%d err=%v", s.created, err) } } func TestCSVFieldLimitAndQuotedFields(t *testing.T) { for _, tc := range []struct { name, input string oversized bool }{ {"exact", "64512," + strings.Repeat(",", MaxCSVFields-2) + "\n", false}, {"over", "64512," + strings.Repeat(",", MaxCSVFields-1) + "\n", true}, {"many_fields", strings.Repeat(",", 1<<20) + "\n", true}, {"quoted_extra", "64512,,\"" + strings.Repeat(",", 128) + "\nquoted \"\"text\"\"\"\n", false}, } { t.Run(tc.name, func(t *testing.T) { s := &importBackend{} _, err := ImportModuleEntriesCSV(context.Background(), s, "tenant", "module", strings.NewReader(tc.input)) if tc.oversized { if !errors.Is(err, ErrCSVTooLarge) || s.created != 0 { t.Fatalf("created=%d err=%v", s.created, err) } } else if err != nil || s.created != 1 { t.Fatalf("created=%d err=%v", s.created, err) } }) } }