-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3900 from hashicorp/fix-monitor-sigint-3891
Fixes #3891: agent monitor no longer unresponsive before logs stream.
- Loading branch information
Showing
2 changed files
with
76 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package monitor | ||
|
||
import ( | ||
"io" | ||
"os" | ||
"sync" | ||
"testing" | ||
"time" | ||
|
||
"github.com/hashicorp/consul/agent" | ||
"github.com/hashicorp/consul/logger" | ||
"github.com/mitchellh/cli" | ||
) | ||
|
||
func TestMonitorCommand_exitssOnSignalBeforeLinesArrive(t *testing.T) { | ||
t.Parallel() | ||
logWriter := logger.NewLogWriter(512) | ||
a := &agent.TestAgent{ | ||
Name: t.Name(), | ||
LogWriter: logWriter, | ||
LogOutput: io.MultiWriter(os.Stderr, logWriter), | ||
} | ||
a.Start() | ||
defer a.Shutdown() | ||
|
||
shutdownCh := make(chan struct{}) | ||
|
||
ui := cli.NewMockUi() | ||
c := New(ui, shutdownCh) | ||
// Only wait for ERR which shouldn't happen so should leave logs empty for a | ||
// while | ||
args := []string{"-http-addr=" + a.HTTPAddr(), "-log-level=ERR"} | ||
|
||
// Buffer it so we don't deadlock when blocking send on shutdownCh triggers | ||
// Run to return before we can select on it. | ||
exitCode := make(chan int, 1) | ||
|
||
// Run the monitor in another go routine. If this doesn't exit on our "signal" | ||
// then the whole test will hang and we'll panic (to not blow up if people run | ||
// the suite without -timeout) | ||
var wg sync.WaitGroup | ||
wg.Add(1) | ||
go func() { | ||
wg.Done() // Signal that this goroutine is at least running now | ||
exitCode <- c.Run(args) | ||
}() | ||
|
||
// Wait for that routine to at least be running | ||
wg.Wait() | ||
|
||
// Simulate signal in a few milliseconds without blocking this thread | ||
go func() { | ||
time.Sleep(5 * time.Millisecond) | ||
shutdownCh <- struct{}{} | ||
}() | ||
|
||
// Wait for a second - shouldn't take long to handle the signal before we | ||
// panic. We simulate inside the select since the other goroutine might | ||
// already have exited if there was some error and we'd block forever trying | ||
// to write to unbuffered shutdownCh. We don't just buffer it because then it | ||
// doesn't model the real shutdownCh we use for signal watching and could mask | ||
// bugs in the handling. | ||
select { | ||
case ret := <-exitCode: | ||
if ret != 0 { | ||
t.Fatal("command returned with non-zero code") | ||
} | ||
// OK! | ||
case <-time.After(1 * time.Second): | ||
t.Fatal("timed out waiting for exit") | ||
} | ||
} |