-
Notifications
You must be signed in to change notification settings - Fork 17.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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>
- Loading branch information
Bryan C. Mills
committed
Nov 8, 2019
1 parent
c5fac1e
commit a84ac18
Showing
1 changed file
with
104 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} | ||
} |