2023-03-28 19:12:30 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
2023-08-11 13:12:13 +00:00
|
|
|
// SPDX-License-Identifier: BUSL-1.1
|
2023-03-28 19:12:30 +00:00
|
|
|
|
2018-02-19 21:53:10 +00:00
|
|
|
package monitor
|
|
|
|
|
|
|
|
import (
|
2021-06-07 16:08:48 +00:00
|
|
|
"encoding/json"
|
|
|
|
"strings"
|
2018-02-19 21:53:10 +00:00
|
|
|
"sync"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/hashicorp/consul/agent"
|
|
|
|
"github.com/mitchellh/cli"
|
|
|
|
)
|
|
|
|
|
2018-03-19 16:56:00 +00:00
|
|
|
func TestMonitorCommand_exitsOnSignalBeforeLinesArrive(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-02-19 21:53:10 +00:00
|
|
|
t.Parallel()
|
2020-03-31 20:24:39 +00:00
|
|
|
a := agent.StartTestAgent(t, agent.TestAgent{})
|
2018-02-19 21:53:10 +00:00
|
|
|
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
|
2020-01-28 23:50:41 +00:00
|
|
|
// 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")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMonitorCommand_LogJSONValidFlag(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2020-01-28 23:50:41 +00:00
|
|
|
t.Parallel()
|
2020-03-31 20:24:39 +00:00
|
|
|
a := agent.StartTestAgent(t, agent.TestAgent{})
|
2020-01-28 23:50:41 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
|
|
|
|
shutdownCh := make(chan struct{})
|
|
|
|
|
|
|
|
ui := cli.NewMockUi()
|
|
|
|
c := New(ui, shutdownCh)
|
|
|
|
args := []string{"-http-addr=" + a.HTTPAddr(), "-log-json"}
|
|
|
|
|
|
|
|
// 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
|
2018-02-19 21:53:10 +00:00
|
|
|
// 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")
|
|
|
|
}
|
|
|
|
}
|
2021-06-07 16:08:48 +00:00
|
|
|
|
|
|
|
func TestMonitorCommand_LogJSONValidFormat(t *testing.T) {
|
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Parallel()
|
|
|
|
a := agent.StartTestAgent(t, agent.TestAgent{})
|
|
|
|
defer a.Shutdown()
|
|
|
|
|
|
|
|
shutdownCh := make(chan struct{})
|
|
|
|
|
|
|
|
ui := cli.NewMockUi()
|
|
|
|
c := New(ui, shutdownCh)
|
|
|
|
args := []string{"-http-addr=" + a.HTTPAddr(), "-log-json"}
|
|
|
|
|
|
|
|
// 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()
|
|
|
|
|
|
|
|
// Read the logs and try to json marshall it
|
|
|
|
go func() {
|
|
|
|
time.Sleep(1 * time.Second)
|
|
|
|
outputs := ui.OutputWriter.String()
|
|
|
|
for count, output := range strings.Split(outputs, "\n") {
|
|
|
|
if output != "" && count > 0 {
|
|
|
|
jsonLog := new(map[string]interface{})
|
|
|
|
err := json.Unmarshal([]byte(output), jsonLog)
|
|
|
|
if err != nil {
|
|
|
|
exitCode <- -1
|
|
|
|
}
|
|
|
|
if len(*jsonLog) <= 0 {
|
|
|
|
exitCode <- 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
shutdownCh <- struct{}{}
|
|
|
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
select {
|
|
|
|
case ret := <-exitCode:
|
|
|
|
if ret != 0 {
|
|
|
|
t.Fatal("command returned with non-zero code")
|
|
|
|
}
|
|
|
|
// OK!
|
|
|
|
case <-time.After(5 * time.Second):
|
|
|
|
t.Fatal("timed out waiting for exit")
|
|
|
|
}
|
|
|
|
}
|