github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/go/lockedfile/transform_test.go (about) 1 // Copyright 2019 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // js and wasip1 do not support inter-process file locking. 6 // 7 //go:build !js && !wasip1 8 9 package lockedfile_test 10 11 import ( 12 "bytes" 13 "encoding/binary" 14 "math/rand" 15 "path/filepath" 16 "testing" 17 "time" 18 19 "github.com/go-asm/go/cmd/go/lockedfile" 20 ) 21 22 func isPowerOf2(x int) bool { 23 return x > 0 && x&(x-1) == 0 24 } 25 26 func roundDownToPowerOf2(x int) int { 27 if x <= 0 { 28 panic("nonpositive x") 29 } 30 bit := 1 31 for x != bit { 32 x = x &^ bit 33 bit <<= 1 34 } 35 return x 36 } 37 38 func TestTransform(t *testing.T) { 39 dir, remove := mustTempDir(t) 40 defer remove() 41 path := filepath.Join(dir, "blob.bin") 42 43 const maxChunkWords = 8 << 10 44 buf := make([]byte, 2*maxChunkWords*8) 45 for i := uint64(0); i < 2*maxChunkWords; i++ { 46 binary.LittleEndian.PutUint64(buf[i*8:], i) 47 } 48 if err := lockedfile.Write(path, bytes.NewReader(buf[:8]), 0666); err != nil { 49 t.Fatal(err) 50 } 51 52 var attempts int64 = 128 53 if !testing.Short() { 54 attempts *= 16 55 } 56 const parallel = 32 57 58 var sem = make(chan bool, parallel) 59 60 for n := attempts; n > 0; n-- { 61 sem <- true 62 go func() { 63 defer func() { <-sem }() 64 65 time.Sleep(time.Duration(rand.Intn(100)) * time.Microsecond) 66 chunkWords := roundDownToPowerOf2(rand.Intn(maxChunkWords) + 1) 67 offset := rand.Intn(chunkWords) 68 69 err := lockedfile.Transform(path, func(data []byte) (chunk []byte, err error) { 70 chunk = buf[offset*8 : (offset+chunkWords)*8] 71 72 if len(data)&^7 != len(data) { 73 t.Errorf("read %d bytes, but each write is an integer multiple of 8 bytes", len(data)) 74 return chunk, nil 75 } 76 77 words := len(data) / 8 78 if !isPowerOf2(words) { 79 t.Errorf("read %d 8-byte words, but each write is a power-of-2 number of words", words) 80 return chunk, nil 81 } 82 83 u := binary.LittleEndian.Uint64(data) 84 for i := 1; i < words; i++ { 85 next := binary.LittleEndian.Uint64(data[i*8:]) 86 if next != u+1 { 87 t.Errorf("wrote sequential integers, but read integer out of sequence at offset %d", i) 88 return chunk, nil 89 } 90 u = next 91 } 92 93 return chunk, nil 94 }) 95 96 if err != nil { 97 t.Errorf("unexpected error from Transform: %v", err) 98 } 99 }() 100 } 101 102 for n := parallel; n > 0; n-- { 103 sem <- true 104 } 105 }