github.imxd.top/hashicorp/consul@v1.4.5/command/monitor/monitor_test.go (about) 1 package monitor 2 3 import ( 4 "io" 5 "os" 6 "sync" 7 "testing" 8 "time" 9 10 "github.com/hashicorp/consul/agent" 11 "github.com/hashicorp/consul/logger" 12 "github.com/mitchellh/cli" 13 ) 14 15 func TestMonitorCommand_exitsOnSignalBeforeLinesArrive(t *testing.T) { 16 t.Parallel() 17 logWriter := logger.NewLogWriter(512) 18 a := &agent.TestAgent{ 19 Name: t.Name(), 20 LogWriter: logWriter, 21 LogOutput: io.MultiWriter(os.Stderr, logWriter), 22 } 23 a.Start(t) 24 defer a.Shutdown() 25 26 shutdownCh := make(chan struct{}) 27 28 ui := cli.NewMockUi() 29 c := New(ui, shutdownCh) 30 // Only wait for ERR which shouldn't happen so should leave logs empty for a 31 // while 32 args := []string{"-http-addr=" + a.HTTPAddr(), "-log-level=ERR"} 33 34 // Buffer it so we don't deadlock when blocking send on shutdownCh triggers 35 // Run to return before we can select on it. 36 exitCode := make(chan int, 1) 37 38 // Run the monitor in another go routine. If this doesn't exit on our "signal" 39 // then the whole test will hang and we'll panic (to not blow up if people run 40 // the suite without -timeout) 41 var wg sync.WaitGroup 42 wg.Add(1) 43 go func() { 44 wg.Done() // Signal that this goroutine is at least running now 45 exitCode <- c.Run(args) 46 }() 47 48 // Wait for that routine to at least be running 49 wg.Wait() 50 51 // Simulate signal in a few milliseconds without blocking this thread 52 go func() { 53 time.Sleep(5 * time.Millisecond) 54 shutdownCh <- struct{}{} 55 }() 56 57 // Wait for a second - shouldn't take long to handle the signal before we 58 // panic. We simulate inside the select since the other goroutine might 59 // already have exited if there was some error and we'd block forever trying 60 // to write to unbuffered shutdownCh. We don't just buffer it because then it 61 // doesn't model the real shutdownCh we use for signal watching and could mask 62 // bugs in the handling. 63 select { 64 case ret := <-exitCode: 65 if ret != 0 { 66 t.Fatal("command returned with non-zero code") 67 } 68 // OK! 69 case <-time.After(1 * time.Second): 70 t.Fatal("timed out waiting for exit") 71 } 72 }