github.com/Iqoqo/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  }