bastion 0.53.2
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
package main
|
||||
|
||||
// Gate: a push whose file stops answering (a network mount that died while
|
||||
// the job reads it) does not stay pending: a read of the file that does not
|
||||
// return within the bound fails the job with a sentence, whether it is stuck
|
||||
// checking the digest or sending.
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// deadMountReads makes every read of a pushed file block until the test ends,
|
||||
// then fail, as a read of a mount that went away does.
|
||||
func deadMountReads(t *testing.T) {
|
||||
t.Helper()
|
||||
gate := make(chan struct{})
|
||||
var once sync.Once
|
||||
backupPushHookMu.Lock()
|
||||
prev := backupPushRead
|
||||
backupPushRead = func(f *os.File, p []byte) (int, error) {
|
||||
<-gate
|
||||
return 0, errors.New("the mount went away")
|
||||
}
|
||||
backupPushHookMu.Unlock()
|
||||
t.Cleanup(func() {
|
||||
once.Do(func() { close(gate) })
|
||||
backupPushHookMu.Lock()
|
||||
backupPushRead = prev
|
||||
backupPushHookMu.Unlock()
|
||||
})
|
||||
}
|
||||
|
||||
func TestAPushFromAFolderThatStopsAnsweringFails(t *testing.T) {
|
||||
allowLoopbackFetch(t)
|
||||
backupPushHookMu.Lock()
|
||||
prevStall := backupPushFileStall
|
||||
backupPushFileStall = 200 * time.Millisecond
|
||||
backupPushHookMu.Unlock()
|
||||
t.Cleanup(func() { backupPushHookMu.Lock(); backupPushFileStall = prevStall; backupPushHookMu.Unlock() })
|
||||
|
||||
for _, phase := range []string{"checking the digest", "sending"} {
|
||||
t.Run(phase, func(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
_, sum := pushFixture(t, root, []byte(strings.Repeat("a backup ", 1000)))
|
||||
abs := filepath.Join(root, fixtureData)
|
||||
if phase == "sending" {
|
||||
// The digest is known, so the first read is the upload's.
|
||||
fi, err := os.Lstat(abs)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
noteHash(abs, fi, sum)
|
||||
}
|
||||
srv, _, _ := uploadServer(t, 200)
|
||||
deadMountReads(t)
|
||||
job := pushJob(root, sum)
|
||||
done := make(chan struct{})
|
||||
go func() { runBackupPush(job, srv.URL+"/put", abs); close(done) }()
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatal("a push whose file stopped answering is still running")
|
||||
}
|
||||
backupJobsMu.Lock()
|
||||
state, msg := job.State, job.Error
|
||||
backupJobsMu.Unlock()
|
||||
if state != "failed" || !strings.Contains(msg, "stopped answering") {
|
||||
t.Fatalf("the job reads %s %q", state, msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user