diff options
author | Jakob Unterwurzacher | 2023-06-08 15:50:05 +0200 |
---|---|---|
committer | Jakob Unterwurzacher | 2023-06-09 07:29:54 +0200 |
commit | 1418565a6b28a91f2f15d5b957d7fd31392a47a1 (patch) | |
tree | 8fea28e07476968c96294e569e6d3c144acc868b | |
parent | 2b416942b0366c41672bf6bab69b2f1a1ceb5f5d (diff) |
tests/cluster: add TestPoCTornWrite
Scary. But explains why TestConcurrentCreate fails.
gocryptfs/tests/cluster$ go test -run TestPoCTornWrite
--- FAIL: TestPoCTornWrite (0.00s)
poc_test.go:210: iteration 214: inconsistent block: d6d6d6d6d6d6d6d6d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1
FAIL
-rw-r--r-- | tests/cluster/poc_test.go | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/tests/cluster/poc_test.go b/tests/cluster/poc_test.go index 6f74ba2..6719663 100644 --- a/tests/cluster/poc_test.go +++ b/tests/cluster/poc_test.go @@ -139,3 +139,84 @@ func TestPoCHeaderCreation(t *testing.T) { t.Logf("readEmpty=%d readOk=%d writes=%d", stats.readEmpty, stats.readOk, stats.writes) } + +// TestPoCTornWrite simulates what TestConcurrentCreate does. +func TestPoCTornWrite(t *testing.T) { + path := test_helpers.TmpDir + "/" + t.Name() + var wg sync.WaitGroup + const loops = 10000 + + writerThread := func() { + defer wg.Done() + for i := 0; i < loops; i++ { + if t.Failed() { + return + } + f, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, 0600) + if err != nil { + t.Errorf("BUG: this should not happen: open err=%v", err) + return + } + + // Write dummy header unless it is already there + lk := unix.Flock_t{ + Type: unix.F_WRLCK, + Whence: unix.SEEK_SET, + Start: 0, + Len: 0, + } + if err := unix.FcntlFlock(uintptr(f.Fd()), syscallcompat.F_OFD_SETLKW, &lk); err != nil { + t.Error(err) + return + } + + hdr := make([]byte, contentenc.HeaderLen) + if _, err := f.ReadAt(hdr, 0); err == io.EOF { + hdr = bytes.Repeat([]byte{byte(i)}, contentenc.HeaderLen) + if _, err := f.WriteAt(hdr, 0); err != nil { + t.Errorf("header write failed: %v", err) + return + } + } else if err != nil { + t.Error(err) + return + } + lk.Type = unix.F_UNLCK + if err := unix.FcntlFlock(uintptr(f.Fd()), syscallcompat.F_OFD_SETLKW, &lk); err != nil { + t.Error(err) + return + } + + // Write dummy data + blockData := bytes.Repeat([]byte{byte(i)}, 42) + if _, err = f.WriteAt(blockData, contentenc.HeaderLen); err != nil { + t.Errorf("iteration %d: WriteAt: %v", i, err) + return + } + + readBuf := make([]byte, 100) + if n, err := f.ReadAt(readBuf, contentenc.HeaderLen); err == io.EOF { + readBuf = readBuf[:n] + } else if err != nil { + t.Error(err) + return + } + if len(readBuf) != len(blockData) { + t.Error("wrong length") + return + } + for _, v := range readBuf { + if v != readBuf[0] { + t.Errorf("iteration %d: inconsistent block: %x", i, readBuf) + return + } + } + f.Close() + } + } + + wg.Add(2) + go writerThread() + go writerThread() + wg.Wait() +} |