aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorJakob Unterwurzacher2023-06-08 15:50:05 +0200
committerJakob Unterwurzacher2023-06-09 07:29:54 +0200
commit1418565a6b28a91f2f15d5b957d7fd31392a47a1 (patch)
tree8fea28e07476968c96294e569e6d3c144acc868b /tests
parent2b416942b0366c41672bf6bab69b2f1a1ceb5f5d (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
Diffstat (limited to 'tests')
-rw-r--r--tests/cluster/poc_test.go81
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()
+}