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