From 1418565a6b28a91f2f15d5b957d7fd31392a47a1 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Thu, 8 Jun 2023 15:50:05 +0200 Subject: 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 --- tests/cluster/poc_test.go | 81 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) (limited to 'tests') 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() +} -- cgit v1.2.3