Repository: hashicorp/nomad
File: command/agent/retry_join_test.go (Go)

Code before:
}

func TestRetryJoin_joinFuncFailure(t *testing.T) {
	testlog.WithLogging("warn", func() {
		// Create an error channel to pass to the retry joiner. When the retry
		// attempts have been exhausted, this channel is closed and our only way
		// to test this apart from inspecting log entries.
		errCh := make(chan struct{})

		// Create an output for logging that can be inspected
		logOutput := bytes.NewBufferString("")

		// Create a timeout to protect against problems within the test blocking
		// for arbitrary long times.
		timeout, timeoutStop := helper.NewSafeTimer(2 * time.Second)
		defer timeoutStop()

		var output []string

		joiner := retryJoiner{
			autoDiscover: autoDiscover{goDiscover: &MockDiscover{}},
			joinCfg:      &ServerJoin{RetryMaxAttempts: 1, RetryJoin: []string{"provider=foo"}},
			joinFunc: func(_ []string) (int, error) {
				return 0, fmt.Errorf("joinFunc testing error")
			},
			logger: testlog.HCLogger(t, testlog.WithOutput(logOutput)),
			errCh:  errCh,
		}

		// Execute the retry join function in a routine, so we can track whether
		// this returns and exits without close the error channel and thus
		// indicating retry failure.
		doneCh := make(chan struct{})

		go func(doneCh chan struct{}) {
			joiner.RetryJoin()
			close(doneCh)
		}(doneCh)

		// The main test; ensure error channel is closed, indicating the retry
		// limit has been reached.
		select {
		case <-errCh:
			must.Len(t, 0, output)
		case <-doneCh:
			t.Fatal("retry join completed without closing error channel")
		case <-timeout.C:
			t.Fatal("timeout reached without error channel close")
		}

		must.StrContains(t, logOutput.String(), "joinFunc testing error")

Review comment (suggestion):
You can set the log level on this logger directly instead of using the env var:

```go
logger := testlog.HCLogger(t)
logger.SetLevel(hclog.Warn)
// ...
  logger: logger,
}
```

You could even use an intercept logger to capture the output at a different level than the default logger. Or even put test assertions right into your SinkAdapter implementation: https://pkg.go.dev/github.com/hashicorp/go-hclog#SinkAdapter

The api isn't the most obvious to use, but here's how we intercept agent logs to allow monitoring agents at a different level than they're logging at: https://github.com/hashicorp/nomad/blob/6563d0ec3ca837eaca5f379f9cb4dabbbb153897/command/agent/monitor/monitor.go#L61-L87

Code after:
	}
}

func TestRetryJoin_joinFuncFailure(t *testing.T) {
	// Create an error channel to pass to the retry joiner. When the retry
	// attempts have been exhausted, this channel is closed and our only way
	// to test this apart from inspecting log entries.
	errCh := make(chan struct{})

	// Create an output for logging that can be inspected
	logOutput := bytes.NewBufferString("")

	// Create a timeout to protect against problems within the test blocking
	// for arbitrary long times.
	timeout, timeoutStop := helper.NewSafeTimer(2 * time.Second)
	defer timeoutStop()

	var output []string

	l := testlog.HCLogger(t)
	s := hclog.NewSinkAdapter(&hclog.LoggerOptions{
		Output: logOutput,
		Level:  hclog.Warn,
	})
	l.RegisterSink(s)

	joiner := retryJoiner{
		autoDiscover: autoDiscover{goDiscover: &MockDiscover{}},
		joinCfg:      &ServerJoin{RetryMaxAttempts: 1, RetryJoin: []string{"provider=foo"}},
		joinFunc: func(_ []string) (int, error) {
			return 0, fmt.Errorf("joinFunc testing error")
		},
		logger: l,
		errCh:  errCh,
	}

	// Execute the retry join function in a routine, so we can track whether
	// this returns and exits without close the error channel and thus
	// indicating retry failure.
	doneCh := make(chan struct{})

	go func(doneCh chan struct{}) {
		joiner.RetryJoin()
		close(doneCh)
	}(doneCh)

	// The main test; ensure error channel is closed, indicating the retry
	// limit has been reached.
	select {
	case <-errCh:
		must.Len(t, 0, output)