1 package log
2
3 import (
4 "context"
5 "sync"
6 "testing"
7 "testing/synctest"
8 "time"
9
10 "github.com/sirupsen/logrus"
11 "github.com/stretchr/testify/assert"
12 )
13
14 type errorFormatter struct{}
15
16 func (f *errorFormatter) Format(*logrus.Entry) ([]byte, error) {
17 return nil, assert.AnError
18 }
19
20 func TestFormatterError(t *testing.T) {
21 hook := NewBrokerHook(t.Context(), "info")
22 hook.SetBrokerFormatter(&errorFormatter{})
23 entry := logrus.NewEntry(logrus.New())
24 entry.Message = "hello broker"
25 entry.Level = logrus.InfoLevel
26 assert.Error(t, hook.Fire(entry))
27 }
28
29 func TestRemoveSubscriber(t *testing.T) {
30 hook := NewBrokerHook(t.Context(), "info")
31 msgChan1 := make(MessageChanType)
32 msgChan2 := make(MessageChanType)
33 hook.AddSubscriber(msgChan1)
34 hook.AddSubscriber(msgChan2)
35 assert.Equal(t, 2, len(hook.subscribers))
36
37
38 hook.RemoveSubscriber(msgChan1)
39 assert.Equal(t, 1, len(hook.subscribers))
40
41
42 hook.RemoveSubscriber(msgChan2)
43 assert.Equal(t, 0, len(hook.subscribers))
44 }
45
46 func TestFire_CancelledContext(t *testing.T) {
47 ctx, cancel := context.WithCancel(t.Context())
48 cancel()
49 hook := NewBrokerHook(ctx, "info")
50 err := hook.Fire(logrus.NewEntry(logrus.New()))
51 assert.NoError(t, err)
52 }
53
54 func TestFire_DeliverToSubscriber(t *testing.T) {
55 synctest.Test(t, func(t *testing.T) {
56 ctx, cancel := context.WithCancel(t.Context())
57 hook := NewBrokerHook(ctx, "info")
58 msgChan := make(MessageChanType, 1)
59 hook.AddSubscriber(msgChan)
60
61 entry := logrus.NewEntry(logrus.New())
62 entry.Message = "hello broker"
63 entry.Level = logrus.InfoLevel
64 assert.NoError(t, hook.Fire(entry))
65
66
67 synctest.Wait()
68
69 select {
70 case msg := <-msgChan:
71 assert.Contains(t, string(msg), "hello broker")
72 default:
73 t.Fatal("message not delivered")
74 }
75
76 cancel()
77 synctest.Wait()
78 })
79 }
80
81 func TestFire_HighLoad(t *testing.T) {
82 synctest.Test(t, func(t *testing.T) {
83
84 hook := &BrokerHook{
85 highLoadTimeout: time.Millisecond,
86 input: make(chan MessageType, 1),
87 ctx: t.Context(),
88 level: "info",
89 mu: &sync.Mutex{},
90 formatter: defaultFormatter,
91 }
92 hook.input <- "fill"
93
94 entry := logrus.NewEntry(logrus.New())
95 entry.Message = "to be dropped"
96
97
98 assert.NoError(t, hook.Fire(entry))
99 })
100 }
101
102 func TestSend_NoSubscribersIsNoop(t *testing.T) {
103 hook := NewBrokerHook(t.Context(), "info")
104
105 hook.send("msg")
106 }
107
108 func TestSend_FullSubscriberDrops(t *testing.T) {
109 hook := NewBrokerHook(t.Context(), "info")
110
111 msgChan := make(MessageChanType)
112 hook.AddSubscriber(msgChan)
113 hook.send("dropped")
114 }
115
116 func TestSetBrokerFormatter_NilResetsDefault(t *testing.T) {
117 hook := NewBrokerHook(t.Context(), "info")
118 hook.SetBrokerFormatter(&logrus.JSONFormatter{})
119 hook.SetBrokerFormatter(nil)
120 assert.Equal(t, defaultFormatter, hook.formatter)
121 }
122
123 func TestLevels(t *testing.T) {
124 cases := []struct {
125 level string
126 expected []logrus.Level
127 }{
128 {"none", []logrus.Level{}},
129 {"debug", logrus.AllLevels},
130 {"info", []logrus.Level{logrus.PanicLevel, logrus.FatalLevel, logrus.ErrorLevel, logrus.WarnLevel, logrus.InfoLevel}},
131 {"error", []logrus.Level{logrus.PanicLevel, logrus.FatalLevel, logrus.ErrorLevel}},
132 }
133 for _, tc := range cases {
134 hook := NewBrokerHook(t.Context(), tc.level)
135 assert.Equal(t, tc.expected, hook.Levels(), "level=%s", tc.level)
136 }
137 }
138