Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion log/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,34 @@ func (c *Client) matchesNamespace(namespace string) bool {
return false
}

func normalizeClientNamespaces(namespaces []string) []string {
if len(namespaces) == 0 {
return nil
}

normalized := make([]string, 0, len(namespaces))
seen := make(map[string]struct{}, len(namespaces))
for _, namespace := range namespaces {
namespace = strings.TrimSpace(namespace)
if namespace == "" {
continue
}
if _, ok := seen[namespace]; ok {
continue
}
seen[namespace] = struct{}{}
normalized = append(normalized, namespace)
}
if len(normalized) == 0 {
return nil
}
return normalized
}

func CreateClient(namespaces ...string) *Client {
var client Client
client.initialized = true
client.Namespaces = namespaces
client.Namespaces = normalizeClientNamespaces(namespaces)
client.writer = make(LogWriter, 1000)
sliceTex.Lock()
clients = append(clients, &client)
Expand Down
41 changes: 41 additions & 0 deletions log/log_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,47 @@ func TestMatchesNamespace(t *testing.T) {
c2.Destroy()
}

func TestCreateClientNormalizesNamespaces(t *testing.T) {
c := CreateClient(" api ", "", "auth", "api", "\t")
defer c.Destroy()

want := []string{"api", "auth"}
if len(c.Namespaces) != len(want) {
t.Fatalf("namespaces length = %d, want %d: %#v", len(c.Namespaces), len(want), c.Namespaces)
}
for i := range want {
if c.Namespaces[i] != want[i] {
t.Fatalf("namespaces[%d] = %q, want %q", i, c.Namespaces[i], want[i])
}
}
}

func TestCreateClientBlankNamespacesMatchAll(t *testing.T) {
c := CreateClient("", " ")
defer c.Destroy()

if len(c.Namespaces) != 0 {
t.Fatalf("blank namespaces should normalize to all namespaces, got %#v", c.Namespaces)
}
if !c.matchesNamespace("api") {
t.Error("blank-only namespace filters should match all namespaces")
}
}

func TestCreateClientCopiesNamespaceFilters(t *testing.T) {
namespaces := []string{"api"}
c := CreateClient(namespaces...)
defer c.Destroy()

namespaces[0] = "auth"
if !c.matchesNamespace("api") {
t.Error("client namespace filters should not change when caller mutates input slice")
}
if c.matchesNamespace("auth") {
t.Error("client should not match mutated caller namespace")
}
}

// TestGetContext verifies context cancellation stops blocking Get.
func TestGetContext(t *testing.T) {
c := CreateClient(DefaultNamespace)
Expand Down
46 changes: 35 additions & 11 deletions ws/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,22 +183,46 @@ func TestLogSocketHandler_NamespaceFilter_TrimsWhitespace(t *testing.T) {
defer conn.Close()

filteredLogger := logger.NewLogger("filtered-ns")
filteredLogger.Info("trimmed namespace should arrive")

conn.SetReadDeadline(time.Now().Add(2 * time.Second))
_, message, err := conn.ReadMessage()
if err != nil {
t.Fatalf("failed to read message: %v", err)
}
done := make(chan struct{})
defer close(done)
go func() {
ticker := time.NewTicker(10 * time.Millisecond)
defer ticker.Stop()
for i := 0; ; i++ {
select {
case <-done:
return
case <-ticker.C:
filteredLogger.Infof("trimmed namespace should arrive %d", i)
}
}
}()

var entry logger.Entry
if err := json.Unmarshal(message, &entry); err != nil {
t.Fatalf("failed to unmarshal entry: %v", err)
}
entry := waitForWebSocketEntryWithDeadline(t, conn, 2*time.Second, func(entry logger.Entry) bool {
return entry.Namespace == "filtered-ns"
})
if entry.Namespace != "filtered-ns" {
t.Fatalf("namespace = %q, want filtered-ns", entry.Namespace)
}
if !strings.Contains(entry.Output, "trimmed namespace should arrive") {
t.Fatalf("output = %q, want trimmed namespace message", entry.Output)
}
}

func waitForWebSocketEntryWithDeadline(t *testing.T, conn *websocket.Conn, timeout time.Duration, match func(logger.Entry) bool) logger.Entry {
t.Helper()
conn.SetReadDeadline(time.Now().Add(timeout))
for {
_, message, err := conn.ReadMessage()
if err != nil {
t.Fatalf("failed to read message: %v", err)
}
var entry logger.Entry
if err := json.Unmarshal(message, &entry); err != nil {
t.Fatalf("failed to unmarshal entry: %v", err)
}
if match(entry) {
return entry
}
}
}
Loading