@@ -21,6 +21,15 @@ import (
2121 "github.com/crowdsecurity/crowdsec/pkg/pipeline"
2222)
2323
24+ // readTimeout is only ever reached when a line never arrives: it's generous on
25+ // purpose, so that a slow machine doesn't turn into a test failure.
26+ const readTimeout = 10 * time .Second
27+
28+ // quietPeriod is how long we wait to confirm that no extra line shows up. Kept
29+ // short on purpose: a line slower than this is missed, which is better than
30+ // failing at random on a loaded machine.
31+ const quietPeriod = 100 * time .Millisecond
32+
2433func TestConfigureDSN (t * testing.T ) {
2534 cstest .SkipOnWindows (t )
2635
@@ -147,33 +156,53 @@ journalctl_filter:
147156 }
148157 for idx , ts := range tests {
149158 t .Run (strconv .Itoa (idx ), func (t * testing.T ) {
150- ctx , cancel := context .WithCancel (ctx )
159+ // not shadowing ctx: the zombie check at the end needs a context that
160+ // is still alive after the stream has been stopped
161+ streamCtx , cancel := context .WithCancel (ctx )
151162 out := make (chan pipeline.Event )
152163 j := Source {}
153164
154165 logger , _ := logtest .NewNullLogger ()
155166
156- err := j .Configure (ctx , []byte (ts .config ), logrus .NewEntry (logger ), metrics .AcquisitionMetricsLevelNone )
167+ err := j .Configure (streamCtx , []byte (ts .config ), logrus .NewEntry (logger ), metrics .AcquisitionMetricsLevelNone )
157168 require .NoError (t , err )
158169
159- gotLines := 0
160- var wg sync.WaitGroup
170+ var (
171+ wg sync.WaitGroup
172+ extraLines int
173+ )
161174
162175 if ts .wantLines != 0 {
163176 wg .Go (func () {
177+ // whatever happens below, the stream has to be stopped or
178+ // j.Stream() would never return
179+ defer cancel ()
180+
181+ // consuming every line lets journalctl exit on its own
182+ for i := range ts .wantLines {
183+ select {
184+ case <- out :
185+ case <- time .After (readTimeout ):
186+ t .Errorf ("timed out waiting for line %d/%d" , i + 1 , ts .wantLines )
187+ return
188+ }
189+ }
190+
191+ // keep draining for a moment: it catches extra lines, and it keeps a
192+ // source that sends too many from deadlocking on the unbuffered
193+ // channel instead of failing the test
164194 for {
165195 select {
166196 case <- out :
167- gotLines ++
168- case <- time .After (1 * time .Second ):
169- cancel ()
197+ extraLines ++
198+ case <- time .After (quietPeriod ):
170199 return
171200 }
172201 }
173202 })
174203 }
175204
176- err = j .Stream (ctx , out )
205+ err = j .Stream (streamCtx , out )
177206 cstest .RequireErrorContains (t , err , ts .wantErr )
178207
179208 if ts .wantErr != "" {
@@ -183,11 +212,13 @@ journalctl_filter:
183212
184213 if ts .wantLines != 0 {
185214 wg .Wait ()
186- assert .Equal (t , ts . wantLines , gotLines )
215+ assert .Zero (t , extraLines , "source emitted more lines than expected" )
187216 }
188217
189218 cancel ()
190219
220+ // streamCtx is canceled by now, and running pgrep with it would make
221+ // it return nothing and the check below always pass
191222 output , _ := exec .CommandContext (ctx , "pgrep" , "-x" , "journalctl" ).CombinedOutput ()
192223 assert .Empty (t , output , "zombie journalctl process detected!" )
193224 })
0 commit comments