-
Notifications
You must be signed in to change notification settings - Fork 31
Make SSH integration tests easier to debug #1046
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
78 commits
Select commit
Hold shift + click to select a range
97f1d94
tests: Fix error message
adombeck 580cfd1
Revert "ssh-tests: Avoid building module twice when updating golden f…
adombeck edbaf3e
tests: Continuously print output of build commands
adombeck b9664fe
tests: Continuously print output of VHS
adombeck 5cd8975
tests: Print duration of setup steps
adombeck adcf8e1
tests: Print duration of VHS tape execution
adombeck 4e22136
tests: Improve log messages
adombeck 0755ebc
tests: Make VHS use colors in its output
adombeck ea229d3
tests: Adapt log level of sshd logs
adombeck 1a2b79f
tests: Support overriding the default VHS wait timeout
adombeck fee6fb1
tests: Use consistent log format in sshd_preloader
adombeck 463ecd1
tests: Always daemonize sshd
adombeck bf51fe9
ssh tests: Improve formatting of tape output in error message
adombeck 39248b4
Remove redundant call to slog.SetLogLoggerLevel
adombeck a8828bc
tests: Print output of authd continuously
adombeck 0271cba
log: Use the SimpleHandler by default
adombeck f745e47
tests: Don't print full tape before executing
adombeck d3bdc1e
Use correct capitalization for sshd
adombeck 3548d3f
daemon: Improve log messages when receiving SIGINT/SIGHUP
adombeck 1266200
tests: Add colored log separators
adombeck 23fadf4
tests: Refer to authd as "authd" instead of "daemon"
adombeck 1191559
tests: Run build commands in minimal environment
adombeck b2bde29
nss: Improve log message
adombeck 4f1fe8b
tests: Fix AUTHD_TESTS_ARTIFACTS_ALWAYS_SAVE
adombeck 10bd986
refactor: Rename saveArtifactsForDebugOnCleanup -> maybeSaveFilesAsAr…
adombeck 5f9f83a
refactor: Use variadic argument
adombeck fbeb0c4
refactor: Rename authdArtifactsDirSync -> authdArtifactsDirOnce
adombeck 62856de
refactor: Rename artifactsPath -> artifactsDir
adombeck f17f1f5
refator: Extract createArtifactsDir
adombeck 1c29e3a
refactor: Extract maybeSaveBytesAsArtifactOnCleanup
adombeck 615b4f2
refactor: Extract maybeSaveBufferAsArtifactOnCleanup
adombeck 1f9663c
refactor: Rename ExpectedOutput -> SanitizedOutput
adombeck 8c52299
VHS: Save sanitized output even if the tape execution failed
adombeck bb532dd
tests: Fix artifacts path
adombeck 1584aa3
refactor: Use fileutils.CopyFile
adombeck 7fcb1c3
tests: Avoid VHS suggesting to upload GIF
adombeck 52da12d
refactor: Extract field tapeData.OutputDir
adombeck 114adcf
refactor: Replace tapeData.Outputs with tapeData.OutputFilename
adombeck 2b53cb1
refactor: Move the artifact-saving code out of PrepareTape
adombeck 2743fa1
tests: Run sshd in foreground and without log file
adombeck 810b755
tests: Improve log messages
adombeck cb9e9a4
tests: Make the name of the pam service clearer
adombeck e30eff7
tests: Store sshd output with log level debug3 as test artifact
adombeck 5377b68
ssh tests: Only build test dependencies once when needed
adombeck 78e9b01
tests: Fix log message
adombeck e5c2cfa
tests: Log output via t.Log
adombeck 2a0b757
tests: Make use of the new Output method of testing.T
adombeck bcf14a8
tests: Run gcov with logging
adombeck d0ef0ca
tests: Add log messages when locking/unlocking rust build dir
adombeck 0ad3aa5
tests: Support printing stdout/stderr on error in RunWithTiming
adombeck 34b62b7
refactor: Extract testlog package
adombeck 37eecfa
refactor: Rename buildCModule -> buildSharedLibrary
adombeck a1f2083
tests: Avoid data race when reading/writing sshd output buffer
adombeck 8af4041
refactor: Rename some variables for better clarity
adombeck 6660c92
tests: Bump time waiting for server to quit
adombeck 5a1a621
refactor: Move artifacts-related functions to testutils
adombeck 735708b
tests: Avoid data race when writing authd output
adombeck 928e8ae
tests: Handle "connection reset by peer" when waiting for sshd to start
adombeck 43f9abd
Use correct capitalization for VHS
adombeck 60cbe34
testlog: Drop support for Go versions < 1.25
adombeck 7a4cc60
Address linter issues
adombeck 40e0e6b
Rename default PAM runner service name
adombeck 1b25901
refactor: Rename buildSharedLibrary -> buildSharedModule
adombeck b8751f5
Avoid printing multi-line string in error message
adombeck 7e0e830
refactor: Extract alwaysSaveArtifactsEnvVar
adombeck 2de3445
testlog: Avoid writing output to stderr if -v is not set
adombeck 00d74cf
daemon_test: Use testutils.MultipliedSleepDuration
adombeck 5b57393
testutils: Append "/snap/bin" to MinimalPathEnv
adombeck 0dc52e1
testutils: Simplify SyncBuffer
adombeck 96f381b
testlog: Fix data race when writing to t.Output()
adombeck a3a9174
ssh_test: Fix data races when setting global variables
adombeck aca43ef
tests: Fix error message
adombeck f66a4a3
tests: Use "Teardown:" prefix in log messages more consistently
adombeck b2582a0
tests: Improve error message
adombeck 6eb5068
tests: Avoid data race in RunVHS
adombeck 478905d
tests: Avoid data race with t.Output and shared authd instances
adombeck 40fa113
tests: Print all PAM messages of sshd to stderr in CI
adombeck 44d38b9
refactor: Extract testutils.IsDebianPackageBuild
adombeck File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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,217 @@ | ||
| // Package testlog provides utilities for logging test output. | ||
| package testlog | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "io" | ||
| "os" | ||
| "os/exec" | ||
| "strings" | ||
| "sync" | ||
| "testing" | ||
| "time" | ||
| ) | ||
|
|
||
| var ( | ||
| isVerboseOnce sync.Once | ||
| isVerbose bool | ||
| ) | ||
|
|
||
| type runWithTimingOptions struct { | ||
| doNotSetStdoutAndStderr bool | ||
| onlyPrintStdoutAndStderrOnError bool | ||
| } | ||
|
|
||
| // RunWithTimingOption is a function that configures the RunWithTiming function. | ||
| type RunWithTimingOption func(options *runWithTimingOptions) | ||
|
|
||
| // DoNotSetStdoutAndStderr prevents RunWithTiming from setting the stdout and stderr of the given command. | ||
| // By default, RunWithTiming sets stdout and stderr to the test's output. | ||
| func DoNotSetStdoutAndStderr() RunWithTimingOption { | ||
| return func(options *runWithTimingOptions) { | ||
| options.doNotSetStdoutAndStderr = true | ||
| } | ||
| } | ||
|
|
||
| // OnlyPrintStdoutAndStderrOnError makes RunWithTiming only print the stdout and stderr of the given command if it fails. | ||
| func OnlyPrintStdoutAndStderrOnError() RunWithTimingOption { | ||
| return func(options *runWithTimingOptions) { | ||
| options.onlyPrintStdoutAndStderrOnError = true | ||
| } | ||
| } | ||
|
|
||
| // RunWithTiming runs the given command while logging its duration with the provided message. | ||
| // | ||
| //nolint:thelper // we do call t.Helper() if t is not nil | ||
| func RunWithTiming(t *testing.T, msg string, cmd *exec.Cmd, options ...RunWithTimingOption) error { | ||
| if t != nil { | ||
| t.Helper() | ||
| } | ||
|
|
||
| w := testOutput(t) | ||
|
|
||
| opts := runWithTimingOptions{} | ||
| for _, f := range options { | ||
| f(&opts) | ||
| } | ||
|
|
||
| if opts.doNotSetStdoutAndStderr && opts.onlyPrintStdoutAndStderrOnError { | ||
| panic("onlyPrintStdoutAndStderrOnError and doNotSetStdoutAndStderr cannot be used together") | ||
| } | ||
|
|
||
| if !opts.doNotSetStdoutAndStderr && !opts.onlyPrintStdoutAndStderrOnError { | ||
| cmd.Stdout = w | ||
| cmd.Stderr = w | ||
| } | ||
|
|
||
| LogCommand(t, msg, cmd) | ||
| start := time.Now() | ||
|
|
||
| var err error | ||
| var out []byte | ||
| if opts.onlyPrintStdoutAndStderrOnError { | ||
| out, err = cmd.CombinedOutput() | ||
| if err != nil { | ||
| _, _ = w.Write(out) | ||
| } | ||
| } else { | ||
| err = cmd.Run() | ||
| } | ||
| duration := time.Since(start) | ||
|
|
||
| if err != nil { | ||
| fmt.Fprintln(w, redSeparatorf("%s failed in %.3fs with %v", msg, duration.Seconds(), err)+"\n") | ||
| } else { | ||
| fmt.Fprintln(w, separatorf("%s finished in %.3fs", msg, duration.Seconds())+"\n") | ||
| } | ||
|
|
||
| return err | ||
| } | ||
|
|
||
| // LogCommand logs the given command to stderr. | ||
| // | ||
| //nolint:thelper // we do call t.Helper() if t is not nil | ||
| func LogCommand(t *testing.T, msg string, cmd *exec.Cmd) { | ||
| if t != nil { | ||
| t.Helper() | ||
| } | ||
| w := testOutput(t) | ||
|
|
||
| sep := "----------------------------------------" | ||
| fmt.Fprintf(w, "\n"+separator(msg)+"command: %s\n%s\nenvironment: %s\n%s\n", cmd.String(), sep, cmd.Env, sep) | ||
| } | ||
|
|
||
| // LogStartSeparatorf logs a separator to stderr with the given formatted message. | ||
| // | ||
| //nolint:thelper // we do call t.Helper() if t is not nil | ||
| func LogStartSeparatorf(t *testing.T, s string, args ...any) { | ||
| if t != nil { | ||
| t.Helper() | ||
| } | ||
| w := testOutput(t) | ||
|
|
||
| fmt.Fprintln(w, "\n"+separatorf(s, args...)) | ||
| } | ||
|
|
||
| // LogStartSeparator logs a separator to stderr with the given message. | ||
| // | ||
| //nolint:thelper // we do call t.Helper() if t is not nil | ||
| func LogStartSeparator(t *testing.T, args ...any) { | ||
| if t != nil { | ||
| t.Helper() | ||
| } | ||
| w := testOutput(t) | ||
|
|
||
| fmt.Fprintln(w, "\n"+separator(args...)) | ||
| } | ||
|
|
||
| // LogEndSeparatorf logs a separator to stderr with the given formatted message. | ||
| // | ||
| //nolint:thelper // we do call t.Helper() if t is not nil | ||
| func LogEndSeparatorf(t *testing.T, s string, args ...any) { | ||
| if t != nil { | ||
| t.Helper() | ||
| } | ||
| w := testOutput(t) | ||
|
|
||
| fmt.Fprintln(w, separatorf(s, args...)+"\n") | ||
| } | ||
|
|
||
| // LogEndSeparator logs a separator to stderr with the given message. | ||
| // | ||
| //nolint:thelper // we do call t.Helper() if t is not nil | ||
| func LogEndSeparator(t *testing.T, args ...any) { | ||
| if t != nil { | ||
| t.Helper() | ||
| } | ||
| w := testOutput(t) | ||
|
|
||
| fmt.Fprintln(w, separator(args...)+"\n") | ||
| } | ||
|
|
||
| // separatorf returns a formatted separator string for logging purposes. | ||
| func separatorf(s string, args ...any) string { | ||
| return highCyan("===== " + fmt.Sprintf(s, args...) + " =====\n") | ||
| } | ||
|
|
||
| // separator returns a separator string for logging purposes. | ||
| func separator(args ...any) string { | ||
| return highCyan("===== " + fmt.Sprint(args...) + " =====\n") | ||
| } | ||
|
|
||
| func redSeparatorf(s string, args ...any) string { | ||
| return highRed("===== " + fmt.Sprintf(s, args...) + " =====\n") | ||
| } | ||
|
|
||
| // highCyan returns a string with the given text in high-intensity cyan color for terminal output. | ||
| func highCyan(s string) string { | ||
| return fmt.Sprintf("\033[1;36m%s\033[0m", s) | ||
| } | ||
|
|
||
| // highRed returns a string with the given text in high-intensity red color for terminal output. | ||
| func highRed(s string) string { | ||
| return fmt.Sprintf("\033[1;31m%s\033[0m", s) | ||
| } | ||
|
|
||
| // testOutput returns the appropriate output writer for the test. | ||
| // | ||
| //nolint:thelper // we're not using t in any way that requires the helper annotation | ||
| func testOutput(t *testing.T) io.Writer { | ||
| if t != nil { | ||
| return &syncWriter{w: t.Output()} | ||
| } | ||
| if verbose() { | ||
| return os.Stderr | ||
| } | ||
| return io.Discard | ||
| } | ||
|
|
||
| // verbose returns whether verbose mode is enabled. | ||
| // testing.Verbose() should be used instead when possible, this function is only | ||
| // needed because testing.Verbose() panics when called in a TestMain function. | ||
| func verbose() bool { | ||
| isVerboseOnce.Do(func() { | ||
| for _, arg := range os.Args { | ||
| value, ok := strings.CutPrefix(arg, "-test.v=") | ||
| if !ok { | ||
| continue | ||
| } | ||
| isVerbose = value == "true" | ||
| } | ||
| }) | ||
| return isVerbose | ||
| } | ||
|
|
||
| // syncWriter is a writer that synchronizes writes to its underlying writer. | ||
| type syncWriter struct { | ||
| w io.Writer | ||
| mu sync.Mutex | ||
| } | ||
|
|
||
| // Write writes to the underlying writer while synchronizing access. | ||
| func (s *syncWriter) Write(p []byte) (n int, err error) { | ||
| s.mu.Lock() | ||
| defer s.mu.Unlock() | ||
|
|
||
| return s.w.Write(p) | ||
| } |
This file contains hidden or 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
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.