package management import ( "context" "testing" "github.com/rs/zerolog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // No listening sessions will not write to the channel func TestLoggerWrite_NoSessions(t *testing.T) { logger := NewLogger() zlog := zerolog.New(logger).With().Timestamp().Logger().Level(zerolog.InfoLevel) zlog.Info().Msg("hello") } // Validate that the session receives the event func TestLoggerWrite_OneSession(t *testing.T) { logger := NewLogger() zlog := zerolog.New(logger).With().Timestamp().Logger().Level(zerolog.InfoLevel) _, cancel := context.WithCancel(context.Background()) defer cancel() session := newSession(logWindow, actor{ID: actorID}, cancel) logger.Listen(session) defer logger.Remove(session) assert.Equal(t, 1, logger.ActiveSessions()) assert.Equal(t, session, logger.ActiveSession(actor{ID: actorID})) zlog.Info().Int(EventTypeKey, int(HTTP)).Msg("hello") select { case event := <-session.listener: assert.NotEmpty(t, event.Time) assert.Equal(t, "hello", event.Message) assert.Equal(t, Info, event.Level) assert.Equal(t, HTTP, event.Event) default: assert.Fail(t, "expected an event to be in the listener") } } // Validate all sessions receive the same event func TestLoggerWrite_MultipleSessions(t *testing.T) { logger := NewLogger() zlog := zerolog.New(logger).With().Timestamp().Logger().Level(zerolog.InfoLevel) _, cancel := context.WithCancel(context.Background()) defer cancel() session1 := newSession(logWindow, actor{}, cancel) logger.Listen(session1) defer logger.Remove(session1) assert.Equal(t, 1, logger.ActiveSessions()) session2 := newSession(logWindow, actor{}, cancel) logger.Listen(session2) assert.Equal(t, 2, logger.ActiveSessions()) zlog.Info().Int(EventTypeKey, int(HTTP)).Msg("hello") for _, session := range []*session{session1, session2} { select { case event := <-session.listener: assert.NotEmpty(t, event.Time) assert.Equal(t, "hello", event.Message) assert.Equal(t, Info, event.Level) assert.Equal(t, HTTP, event.Event) default: assert.Fail(t, "expected an event to be in the listener") } } // Close session2 and make sure session1 still receives events logger.Remove(session2) zlog.Info().Int(EventTypeKey, int(HTTP)).Msg("hello2") select { case event := <-session1.listener: assert.NotEmpty(t, event.Time) assert.Equal(t, "hello2", event.Message) assert.Equal(t, Info, event.Level) assert.Equal(t, HTTP, event.Event) default: assert.Fail(t, "expected an event to be in the listener") } // Make sure a held reference to session2 doesn't receive events after being closed select { case <-session2.listener: assert.Fail(t, "An event was not expected to be in the session listener") default: // pass } } type mockWriter struct { event *Log err error } func (m *mockWriter) Write(p []byte) (int, error) { m.event, m.err = parseZerologEvent(p) return len(p), nil } // Validate all event types are set properly func TestParseZerologEvent_EventTypes(t *testing.T) { writer := mockWriter{} zlog := zerolog.New(&writer).With().Timestamp().Logger().Level(zerolog.InfoLevel) for _, test := range []LogEventType{ Cloudflared, HTTP, TCP, UDP, } { t.Run(test.String(), func(t *testing.T) { defer func() { writer.err = nil }() zlog.Info().Int(EventTypeKey, int(test)).Msg("test") require.NoError(t, writer.err) require.Equal(t, test, writer.event.Event) }) } // Invalid defaults to Cloudflared LogEventType t.Run("invalid", func(t *testing.T) { defer func() { writer.err = nil }() zlog.Info().Str(EventTypeKey, "unknown").Msg("test") require.NoError(t, writer.err) require.Equal(t, Cloudflared, writer.event.Event) }) } // Validate top-level keys are removed from Fields func TestParseZerologEvent_Fields(t *testing.T) { writer := mockWriter{} zlog := zerolog.New(&writer).With().Timestamp().Logger().Level(zerolog.InfoLevel) zlog.Info().Int(EventTypeKey, int(Cloudflared)).Str("test", "test").Msg("test message") require.NoError(t, writer.err) event := writer.event require.NotEmpty(t, event.Time) require.Equal(t, Cloudflared, event.Event) require.Equal(t, Info, event.Level) require.Equal(t, "test message", event.Message) // Make sure Fields doesn't have other set keys used in the Log struct require.NotEmpty(t, event.Fields) require.Equal(t, "test", event.Fields["test"]) require.NotContains(t, event.Fields, EventTypeKey) require.NotContains(t, event.Fields, LevelKey) require.NotContains(t, event.Fields, MessageKey) require.NotContains(t, event.Fields, TimeKey) }