forked from rogpeppe/go-internal
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtransform_test.go
105 lines (86 loc) · 2.26 KB
/
transform_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// 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.
//
//go:build !js
package lockedfile_test
import (
"bytes"
"encoding/binary"
"math/rand"
"path/filepath"
"testing"
"time"
"github.com/rogpeppe/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
}
}