-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathprogress_test.go
More file actions
140 lines (112 loc) · 3.05 KB
/
Copy pathprogress_test.go
File metadata and controls
140 lines (112 loc) · 3.05 KB
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package dspc
import (
"fmt"
"sync"
"testing"
"time"
)
func TestRead(t *testing.T) {
var progress Progress
// Read from zero value Progress
expectValue(t, progress.Get("any"), 0)
// Returns correct values after Inc
progress.Inc("foo", 5)
expectValue(t, progress.Get("foo"), 5)
// Still returns 0 for non-existent
expectValue(t, progress.Get("nonexistent"), 0)
}
func TestWrite(t *testing.T) {
var progress Progress
progress.Set("foo", 10)
progress.Inc("foo", 5)
progress.Inc("foo", -7)
progress.Inc("bar", 2)
expectValue(t, progress.Get("foo"), 8)
expectValue(t, progress.Get("bar"), 2)
}
func TestIteration(t *testing.T) {
var progress Progress
// Read from zero value Progress
for _, _ = range progress.All() {
t.Fatalf("expected no values")
}
// Should iterate in alphabetical order
progress.Inc("foo4", 1)
progress.Set("foo2", 2)
progress.Inc("foo3", -3)
progress.Inc("foo1", 4)
var actual []entry
for k, v := range progress.All() {
actual = append(actual, entry{k, v})
}
expectSlice(t, actual, []entry{{"foo1", 4}, {"foo2", 2}, {"foo3", -3}, {"foo4", 1}})
}
func TestConcurrency(t *testing.T) {
concurrency := 5
totalKeys := 1000
keysStream := make(chan string, concurrency)
// Start a key producer
// The idea is to create contention by forcing multiple goroutines to
// write to the same key at the same time.
// With the current settings (5 goroutines, 1000 keys), test runs have shown
// about 3.5k failures of the CAS operation.
go func() {
defer close(keysStream)
for k := range totalKeys {
key := fmt.Sprintf("key-%d", k)
for range concurrency {
keysStream <- key
}
// Sleep for a bit to allow goroutines to finish with the current key
time.Sleep(1 * time.Microsecond)
}
}()
// Start the workers
var progress Progress
var wg sync.WaitGroup
for range concurrency {
wg.Add(1)
go func() {
defer wg.Done()
for key := range keysStream {
progress.Inc(key, 1)
}
}()
}
wg.Wait()
// Verify each key got incremented exactly 'concurrency' times
for k := range totalKeys {
key := fmt.Sprintf("key-%d", k)
expectValue(t, progress.Get(key), int64(concurrency))
}
}
func TestPrinting(t *testing.T) {
var progress Progress
progress.Inc("foo", -100)
progress.Inc("bar", 20)
progress.Set("grault", 0)
outParts := make([]string, 0, 5)
enough := make(chan struct{})
var out customWriter
out.WriteFunc = func(p []byte) (n int, err error) {
outParts = append(outParts, string(p))
if len(outParts) == 2 {
enough <- struct{}{} // tell the main goroutine to call stop()
}
return len(p), nil
}
stop := progress.PrettyPrintEvery(&out, 100*time.Millisecond, "Test progress:")
<-enough
stop() // this should also print the final state w/o ansi
const expectedOutput = "\033[J" + `
Test progress:
bar 20
foo -100
grault 0
`
const inPlaceExpectedOutput = expectedOutput + "\033[6A"
expectValue(t, len(outParts), 3)
expectValue(t, outParts[0], inPlaceExpectedOutput)
expectValue(t, outParts[1], inPlaceExpectedOutput)
expectValue(t, outParts[2], expectedOutput)
}