7
7
8
8
"github.com/google/uuid"
9
9
"github.com/stretchr/testify/require"
10
+ protobuf"google.golang.org/protobuf/proto"
10
11
11
12
"cdr.dev/slog"
12
13
"cdr.dev/slog/sloggers/slogtest"
@@ -17,7 +18,7 @@ import (
17
18
"github.com/coder/coder/v2/testutil"
18
19
)
19
20
20
- func TestLogSender (t * testing.T ) {
21
+ func TestLogSender_Mainline (t * testing.T ) {
21
22
t .Parallel ()
22
23
testCtx := testutil .Context (t ,testutil .WaitShort )
23
24
ctx ,cancel := context .WithCancel (testCtx )
@@ -116,6 +117,99 @@ func TestLogSender(t *testing.T) {
116
117
require .NoError (t ,err )
117
118
}
118
119
120
+ func TestLogSender_SkipHugeLog (t * testing.T ) {
121
+ t .Parallel ()
122
+ testCtx := testutil .Context (t ,testutil .WaitShort )
123
+ ctx ,cancel := context .WithCancel (testCtx )
124
+ logger := slogtest .Make (t ,nil ).Leveled (slog .LevelDebug )
125
+ fDest := newFakeLogDest ()
126
+ uut := newLogSender (logger )
127
+
128
+ t0 := dbtime .Now ()
129
+ ls1 := uuid.UUID {0x11 }
130
+ hugeLog := make ([]byte ,logOutputMaxBytes + 1 )
131
+ for i := range hugeLog {
132
+ hugeLog [i ]= 'q'
133
+ }
134
+ err := uut .enqueue (ls1 ,
135
+ agentsdk.Log {
136
+ CreatedAt :t0 ,
137
+ Output :string (hugeLog ),
138
+ Level :codersdk .LogLevelInfo ,
139
+ },
140
+ agentsdk.Log {
141
+ CreatedAt :t0 ,
142
+ Output :"test log 1, src 1" ,
143
+ Level :codersdk .LogLevelInfo ,
144
+ })
145
+ require .NoError (t ,err )
146
+
147
+ loopErr := make (chan error ,1 )
148
+ go func () {
149
+ err := uut .sendLoop (ctx ,fDest )
150
+ loopErr <- err
151
+ }()
152
+
153
+ req := testutil .RequireRecvCtx (ctx ,t ,fDest .reqs )
154
+ require .NotNil (t ,req )
155
+ require .Len (t ,req .Logs ,1 ,"it should skip the huge log" )
156
+ require .Equal (t ,"test log 1, src 1" ,req .Logs [0 ].GetOutput ())
157
+ require .Equal (t ,proto .Log_INFO ,req .Logs [0 ].GetLevel ())
158
+
159
+ cancel ()
160
+ err = testutil .RequireRecvCtx (testCtx ,t ,loopErr )
161
+ require .NoError (t ,err )
162
+ }
163
+
164
+ func TestLogSender_Batch (t * testing.T ) {
165
+ t .Parallel ()
166
+ testCtx := testutil .Context (t ,testutil .WaitShort )
167
+ ctx ,cancel := context .WithCancel (testCtx )
168
+ logger := slogtest .Make (t ,nil ).Leveled (slog .LevelDebug )
169
+ fDest := newFakeLogDest ()
170
+ uut := newLogSender (logger )
171
+
172
+ t0 := dbtime .Now ()
173
+ ls1 := uuid.UUID {0x11 }
174
+ var logs []agentsdk.Log
175
+ for i := 0 ;i < 60000 ;i ++ {
176
+ logs = append (logs , agentsdk.Log {
177
+ CreatedAt :t0 ,
178
+ Output :"r" ,
179
+ Level :codersdk .LogLevelInfo ,
180
+ })
181
+ }
182
+ err := uut .enqueue (ls1 ,logs ... )
183
+ require .NoError (t ,err )
184
+
185
+ loopErr := make (chan error ,1 )
186
+ go func () {
187
+ err := uut .sendLoop (ctx ,fDest )
188
+ loopErr <- err
189
+ }()
190
+
191
+ // with 60k logs, we should split into two updates to avoid going over 1MiB, since each log
192
+ // is about 21 bytes.
193
+ gotLogs := 0
194
+ req := testutil .RequireRecvCtx (ctx ,t ,fDest .reqs )
195
+ require .NotNil (t ,req )
196
+ gotLogs += len (req .Logs )
197
+ wire ,err := protobuf .Marshal (req )
198
+ require .NoError (t ,err )
199
+ require .Less (t ,len (wire ),logOutputMaxBytes ,"wire should not exceed 1MiB" )
200
+ req = testutil .RequireRecvCtx (ctx ,t ,fDest .reqs )
201
+ require .NotNil (t ,req )
202
+ gotLogs += len (req .Logs )
203
+ wire ,err = protobuf .Marshal (req )
204
+ require .NoError (t ,err )
205
+ require .Less (t ,len (wire ),logOutputMaxBytes ,"wire should not exceed 1MiB" )
206
+ require .Equal (t ,60000 ,gotLogs )
207
+
208
+ cancel ()
209
+ err = testutil .RequireRecvCtx (testCtx ,t ,loopErr )
210
+ require .NoError (t ,err )
211
+ }
212
+
119
213
type fakeLogDest struct {
120
214
reqs chan * proto.BatchCreateLogsRequest
121
215
}