mirror of https://github.com/golang/go.git
cmd/go/internal/lockedfile: add a unit-test for Transform
Updates #35425 Change-Id: I9ca2251246ee2fa9bb7a335d5eff94d3c9f1f004 Reviewed-on: https://go-review.googlesource.com/c/go/+/206143 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
c5fac1edc4
commit
a84ac18936
|
|
@ -0,0 +1,104 @@
|
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// js does not support inter-process file locking.
|
||||
// +build !js
|
||||
|
||||
package lockedfile_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"math/rand"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"cmd/go/internal/lockedfile"
|
||||
)
|
||||
|
||||
func isPowerOf2(x int) bool {
|
||||
return x > 0 && x&(x-1) == 0
|
||||
}
|
||||
|
||||
func roundDownToPowerOf2(x int) int {
|
||||
if x <= 0 {
|
||||
panic("nonpositive x")
|
||||
}
|
||||
bit := 1
|
||||
for x != bit {
|
||||
x = x &^ bit
|
||||
bit <<= 1
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func TestTransform(t *testing.T) {
|
||||
dir, remove := mustTempDir(t)
|
||||
defer remove()
|
||||
path := filepath.Join(dir, "blob.bin")
|
||||
|
||||
const maxChunkWords = 8 << 10
|
||||
buf := make([]byte, 2*maxChunkWords*8)
|
||||
for i := uint64(0); i < 2*maxChunkWords; i++ {
|
||||
binary.LittleEndian.PutUint64(buf[i*8:], i)
|
||||
}
|
||||
if err := lockedfile.Write(path, bytes.NewReader(buf[:8]), 0666); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var attempts int64 = 128
|
||||
if !testing.Short() {
|
||||
attempts *= 16
|
||||
}
|
||||
const parallel = 32
|
||||
|
||||
var sem = make(chan bool, parallel)
|
||||
|
||||
for n := attempts; n > 0; n-- {
|
||||
sem <- true
|
||||
go func() {
|
||||
defer func() { <-sem }()
|
||||
|
||||
time.Sleep(time.Duration(rand.Intn(100)) * time.Microsecond)
|
||||
chunkWords := roundDownToPowerOf2(rand.Intn(maxChunkWords) + 1)
|
||||
offset := rand.Intn(chunkWords)
|
||||
|
||||
err := lockedfile.Transform(path, func(data []byte) (chunk []byte, err error) {
|
||||
chunk = buf[offset*8 : (offset+chunkWords)*8]
|
||||
|
||||
if len(data)&^7 != len(data) {
|
||||
t.Errorf("read %d bytes, but each write is an integer multiple of 8 bytes", len(data))
|
||||
return chunk, nil
|
||||
}
|
||||
|
||||
words := len(data) / 8
|
||||
if !isPowerOf2(words) {
|
||||
t.Errorf("read %d 8-byte words, but each write is a power-of-2 number of words", words)
|
||||
return chunk, nil
|
||||
}
|
||||
|
||||
u := binary.LittleEndian.Uint64(data)
|
||||
for i := 1; i < words; i++ {
|
||||
next := binary.LittleEndian.Uint64(data[i*8:])
|
||||
if next != u+1 {
|
||||
t.Errorf("wrote sequential integers, but read integer out of sequence at offset %d", i)
|
||||
return chunk, nil
|
||||
}
|
||||
u = next
|
||||
}
|
||||
|
||||
return chunk, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error from Transform: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
for n := parallel; n > 0; n-- {
|
||||
sem <- true
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue