package store import ( "testing" ) func TestJetStreamConfigNamespace(t *testing.T) { t.Run("default config has empty namespace", func(t *testing.T) { config := DefaultJetStreamConfig() if config.Namespace != "" { t.Errorf("expected empty namespace in default config, got %q", config.Namespace) } }) t.Run("namespace can be set in config", func(t *testing.T) { config := JetStreamConfig{ Namespace: "tenant-abc", } if config.Namespace != "tenant-abc" { t.Errorf("expected namespace tenant-abc, got %q", config.Namespace) } }) } func TestNamespacedStreamName(t *testing.T) { tests := []struct { name string baseStreamName string namespace string expectedStreamName string }{ { name: "no namespace - stream name unchanged", baseStreamName: "events", namespace: "", expectedStreamName: "events", }, { name: "with namespace - prefixed stream name", baseStreamName: "events", namespace: "tenant-abc", expectedStreamName: "tenant-abc_events", }, { name: "namespace with dots - sanitized", baseStreamName: "events", namespace: "tenant.abc", expectedStreamName: "tenant_abc_events", }, { name: "namespace with spaces - sanitized", baseStreamName: "events", namespace: "tenant abc", expectedStreamName: "tenant_abc_events", }, { name: "namespace with special chars - sanitized", baseStreamName: "events", namespace: "tenant*abc>def", expectedStreamName: "tenant_abc_def_events", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // We can't create a real JetStreamEventStore without NATS, // but we can test the stream name logic by examining the expected format effectiveStreamName := tt.baseStreamName if tt.namespace != "" { effectiveStreamName = sanitizeSubject(tt.namespace) + "_" + tt.baseStreamName } if effectiveStreamName != tt.expectedStreamName { t.Errorf("expected stream name %q, got %q", tt.expectedStreamName, effectiveStreamName) } }) } } func TestSanitizeSubject(t *testing.T) { tests := []struct { input string expected string }{ {"simple", "simple"}, {"with spaces", "with_spaces"}, {"with.dots", "with_dots"}, {"with*stars", "with_stars"}, {"with>greater", "with_greater"}, {"complex.name with*special>chars", "complex_name_with_special_chars"}, } for _, tt := range tests { t.Run(tt.input, func(t *testing.T) { result := sanitizeSubject(tt.input) if result != tt.expected { t.Errorf("sanitizeSubject(%q) = %q, want %q", tt.input, result, tt.expected) } }) } } func TestExtractActorType(t *testing.T) { tests := []struct { actorID string expectedType string }{ {"order-123", "order"}, {"user-abc-def", "user"}, {"nodelimiter", "unknown"}, {"", "unknown"}, {"-leadingdash", "unknown"}, {"a-b", "a"}, } for _, tt := range tests { t.Run(tt.actorID, func(t *testing.T) { result := extractActorType(tt.actorID) if result != tt.expectedType { t.Errorf("extractActorType(%q) = %q, want %q", tt.actorID, result, tt.expectedType) } }) } }