Compare commits
1
Commits
next
...
3f1524020d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f1524020d |
+31
-24
@@ -10,6 +10,7 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -425,36 +426,42 @@ func TestGPGTimeoutKillsGPG(t *testing.T) {
|
||||
assert.Contains(t, err.Error(), "gpg sign failed: gpg timed out")
|
||||
}
|
||||
|
||||
// TestGPGTimeoutWhenChildHoldsOutput uses a fake gpg that runs sleep as a
|
||||
// TestGPGCancelWhenChildHoldsOutput uses a fake gpg that runs sleep as a
|
||||
// child instead of exec-ing it, the way a wrapper script around the real
|
||||
// gpg might. Killing the fake gpg leaves sleep holding its stdout and
|
||||
// stderr open; the call must still return shortly after the deadline
|
||||
// instead of waiting for sleep to exit. The fake gpg writes the process ID
|
||||
// of sleep to a file so that the test can kill it before returning.
|
||||
func TestGPGTimeoutWhenChildHoldsOutput(t *testing.T) {
|
||||
pidFile := filepath.Join(t.TempDir(), "sleep.pid")
|
||||
// stderr open; the call must still return once ctx ends instead of waiting
|
||||
// for sleep to exit. The fake gpg writes the process ID of sleep to a named
|
||||
// pipe; the test ends ctx only after reading it, so sleep is running by
|
||||
// then, and kills sleep before returning.
|
||||
func TestGPGCancelWhenChildHoldsOutput(t *testing.T) {
|
||||
pidPipe := filepath.Join(t.TempDir(), "sleep.pid")
|
||||
require.NoError(t, syscall.Mkfifo(pidPipe, 0o600))
|
||||
// sleep outlasts the 30 s test timeout, so a call that waits for it fails.
|
||||
t.Setenv("PATH", fakeGPGPath(t,
|
||||
"#!/bin/sh\nsleep 3 &\necho $! >'"+pidFile+"'\nwait\n"))
|
||||
t.Cleanup(func() {
|
||||
pid, err := os.ReadFile(pidFile) //nolint:gosec // G304: path inside t.TempDir()
|
||||
require.NoError(t, err)
|
||||
"#!/bin/sh\nsleep 60 &\necho $! >'"+pidPipe+"'\nwait\n"))
|
||||
|
||||
n, err := strconv.Atoi(strings.TrimSpace(string(pid)))
|
||||
require.NoError(t, err)
|
||||
|
||||
sleep, err := os.FindProcess(n)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, sleep.Kill())
|
||||
})
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
start := time.Now()
|
||||
_, err := gpgSign(ctx, []byte("data"), GPGKeyID("any"))
|
||||
require.ErrorIs(t, err, context.DeadlineExceeded)
|
||||
assert.Less(t, time.Since(start), 3*time.Second,
|
||||
"the call waited for the child holding gpg's output to exit")
|
||||
signErr := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
_, err := gpgSign(ctx, []byte("data"), GPGKeyID("any"))
|
||||
signErr <- err
|
||||
}()
|
||||
|
||||
pid, err := os.ReadFile(pidPipe) //nolint:gosec // G304: path inside t.TempDir()
|
||||
require.NoError(t, err)
|
||||
|
||||
n, err := strconv.Atoi(strings.TrimSpace(string(pid)))
|
||||
require.NoError(t, err)
|
||||
|
||||
sleep, err := os.FindProcess(n)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { require.NoError(t, sleep.Kill()) })
|
||||
|
||||
cancel()
|
||||
require.ErrorIs(t, <-signErr, context.Canceled)
|
||||
}
|
||||
|
||||
// TestBuildPassesContextToSigning checks that a caller can cancel the gpg
|
||||
|
||||
+4
-31
@@ -304,46 +304,19 @@ func TestScannerEnumerateFS(t *testing.T) {
|
||||
func TestSendEnumerateStatusNonBlocking(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Channel with no buffer - send should not block
|
||||
// Nobody receives, so a blocking send would hang the test into its timeout.
|
||||
ch := make(chan EnumerateStatus)
|
||||
|
||||
// This should not block
|
||||
done := make(chan bool)
|
||||
|
||||
go func() {
|
||||
sendEnumerateStatus(ch, EnumerateStatus{FilesFound: 1})
|
||||
|
||||
done <- true
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
// Success - did not block
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
t.Fatal("sendEnumerateStatus blocked on full channel")
|
||||
}
|
||||
sendEnumerateStatus(ch, EnumerateStatus{FilesFound: 1})
|
||||
}
|
||||
|
||||
func TestSendScanStatusNonBlocking(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Channel with no buffer - send should not block
|
||||
// Nobody receives, so a blocking send would hang the test into its timeout.
|
||||
ch := make(chan ScanStatus)
|
||||
|
||||
done := make(chan bool)
|
||||
|
||||
go func() {
|
||||
sendScanStatus(ch, ScanStatus{ScannedFiles: 1})
|
||||
|
||||
done <- true
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
// Success - did not block
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
t.Fatal("sendScanStatus blocked on full channel")
|
||||
}
|
||||
sendScanStatus(ch, ScanStatus{ScannedFiles: 1})
|
||||
}
|
||||
|
||||
func TestSendStatusNilChannel(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user