Skip to content

Commit 7337b81

Browse files
authored
Fix flaky chunk tests by being explicit about now (#656)
* Fix flaky chunk tests by being explicit about `now` `dummyChunkFor` was consulting the system clock itself. This meant that tests like `TestChunkStore_Get` would intermittently fail, because _sometimes_ the created chunks would have timestamps outside the window chosen within `TestChunkStore_Get` (which itself consults the system clock). This fixes the tests by making `now` a parameter of `dummyChunkFor`, which makes the created chunks deterministic. It also adds a `now` parameter to `dummyChunk`, which isn't strictly necessary, but I believe is less error prone. * Review feedback - Be even more deterministic by sharing `now` values - Be even more deterministic by making benchmark chunk factory accept a `now` value
1 parent 8c9b975 commit 7337b81

File tree

6 files changed

+31
-29
lines changed

6 files changed

+31
-29
lines changed

pkg/chunk/aws_storage_client_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,7 @@ func testStorageClientChunks(t *testing.T, client StorageClient) {
531531
for i := 0; i < 50; i++ {
532532
chunks := []Chunk{}
533533
for j := 0; j < batchSize; j++ {
534-
chunk := dummyChunkFor(model.Metric{
534+
chunk := dummyChunkFor(model.Now(), model.Metric{
535535
model.MetricNameLabel: "foo",
536536
"index": model.LabelValue(strconv.Itoa(i*batchSize + j)),
537537
})

pkg/chunk/by_key_test.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ func TestNWayIntersect(t *testing.T) {
102102
}
103103

104104
func BenchmarkByKeyLess(b *testing.B) {
105-
a := ByKey{dummyChunk(), dummyChunk()}
105+
now := model.Now()
106+
a := ByKey{dummyChunk(now), dummyChunk(now)}
106107

107108
b.ResetTimer()
108109

@@ -118,10 +119,7 @@ func BenchmarkByKeySort10000(b *testing.B) { benchmarkByKeySort(b, 10000) }
118119
func benchmarkByKeySort(b *testing.B, batchSize int) {
119120
chunks := []Chunk{}
120121
for i := 0; i < batchSize; i++ {
121-
chunk := dummyChunk()
122-
// Tweak the dummy data slightly so the chunks are more likely to be different
123-
// this makes the checksum wrong but we don't look at it
124-
chunk.From += model.Time(rand.Intn(batchSize))
122+
chunk := dummyChunk(model.Now() + model.Time(rand.Intn(batchSize)))
125123
chunks = append(chunks, chunk)
126124
}
127125

pkg/chunk/chunk_store_test.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,11 @@ func TestChunkStore_Get(t *testing.T) {
8686
"toms": "code",
8787
}
8888

89-
fooChunk1 := dummyChunkFor(fooMetric1)
90-
fooChunk2 := dummyChunkFor(fooMetric2)
89+
fooChunk1 := dummyChunkFor(now, fooMetric1)
90+
fooChunk2 := dummyChunkFor(now, fooMetric2)
9191

92-
barChunk1 := dummyChunkFor(barMetric1)
93-
barChunk2 := dummyChunkFor(barMetric2)
92+
barChunk1 := dummyChunkFor(now, barMetric1)
93+
barChunk2 := dummyChunkFor(now, barMetric2)
9494

9595
fooSampleStream1, err := createSampleStreamFrom(fooChunk1)
9696
require.NoError(t, err)
@@ -222,6 +222,8 @@ func TestChunkStore_Get(t *testing.T) {
222222

223223
sort.Sort(ByFingerprint(matrix1))
224224
if !reflect.DeepEqual(tc.expect, matrix1) {
225+
t.Fatalf("jml\nstart = %#v\nnow = %#v\nfooChunk1 = %#v\nfooChunk2 = %#v\nbarChunk1 = %#v\nbarChunk2 = %#v\n",
226+
now.Add(-time.Hour), now, fooChunk1, fooChunk2, barChunk1, barChunk2)
225227
t.Fatalf("%s: wrong chunks - %s", tc.query, test.Diff(tc.expect, matrix1))
226228
}
227229

@@ -251,13 +253,13 @@ func TestChunkStore_getMetricNameChunks(t *testing.T) {
251253
ctx := user.InjectOrgID(context.Background(), userID)
252254
now := model.Now()
253255
metricName := "foo"
254-
chunk1 := dummyChunkFor(model.Metric{
256+
chunk1 := dummyChunkFor(now, model.Metric{
255257
model.MetricNameLabel: "foo",
256258
"bar": "baz",
257259
"toms": "code",
258260
"flip": "flop",
259261
})
260-
chunk2 := dummyChunkFor(model.Metric{
262+
chunk2 := dummyChunkFor(now, model.Metric{
261263
model.MetricNameLabel: "foo",
262264
"bar": "beep",
263265
"toms": "code",

pkg/chunk/chunk_test.go

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,15 @@ import (
1616

1717
const userID = "userID"
1818

19-
func dummyChunk() Chunk {
20-
return dummyChunkFor(model.Metric{
19+
func dummyChunk(now model.Time) Chunk {
20+
return dummyChunkFor(now, model.Metric{
2121
model.MetricNameLabel: "foo",
2222
"bar": "baz",
2323
"toms": "code",
2424
})
2525
}
2626

27-
func dummyChunkFor(metric model.Metric) Chunk {
28-
now := model.Now()
27+
func dummyChunkFor(now model.Time, metric model.Metric) Chunk {
2928
cs, _ := chunk.New().Add(model.SamplePair{Timestamp: now, Value: 0})
3029
chunk := NewChunk(
3130
userID,
@@ -44,39 +43,40 @@ func dummyChunkFor(metric model.Metric) Chunk {
4443
}
4544

4645
func TestChunkCodec(t *testing.T) {
46+
dummy := dummyChunk(model.Now())
4747
decodeContext := NewDecodeContext()
4848
for i, c := range []struct {
4949
chunk Chunk
5050
err error
5151
f func(*Chunk, []byte)
5252
}{
5353
// Basic round trip
54-
{chunk: dummyChunk()},
54+
{chunk: dummy},
5555

5656
// Checksum should fail
5757
{
58-
chunk: dummyChunk(),
58+
chunk: dummy,
5959
err: ErrInvalidChecksum,
6060
f: func(_ *Chunk, buf []byte) { buf[4]++ },
6161
},
6262

6363
// Checksum should fail
6464
{
65-
chunk: dummyChunk(),
65+
chunk: dummy,
6666
err: ErrInvalidChecksum,
6767
f: func(c *Chunk, _ []byte) { c.Checksum = 123 },
6868
},
6969

7070
// Metadata test should fail
7171
{
72-
chunk: dummyChunk(),
72+
chunk: dummy,
7373
err: ErrWrongMetadata,
7474
f: func(c *Chunk, _ []byte) { c.Fingerprint++ },
7575
},
7676

7777
// Metadata test should fail
7878
{
79-
chunk: dummyChunk(),
79+
chunk: dummy,
8080
err: ErrWrongMetadata,
8181
f: func(c *Chunk, _ []byte) { c.UserID = "foo" },
8282
},
@@ -139,10 +139,11 @@ func TestChunksToMatrix(t *testing.T) {
139139
"bar": "baz",
140140
"toms": "code",
141141
}
142-
chunk1 := dummyChunkFor(metric)
142+
now := model.Now()
143+
chunk1 := dummyChunkFor(now, metric)
143144
chunk1Samples, err := chunk1.Samples(chunk1.From, chunk1.Through)
144145
require.NoError(t, err)
145-
chunk2 := dummyChunkFor(metric)
146+
chunk2 := dummyChunkFor(now, metric)
146147
chunk2Samples, err := chunk2.Samples(chunk2.From, chunk2.Through)
147148
require.NoError(t, err)
148149

@@ -157,7 +158,7 @@ func TestChunksToMatrix(t *testing.T) {
157158
"bar": "baz",
158159
"toms": "code",
159160
}
160-
chunk3 := dummyChunkFor(otherMetric)
161+
chunk3 := dummyChunkFor(now, otherMetric)
161162
chunk3Samples, err := chunk3.Samples(chunk3.From, chunk3.Through)
162163
require.NoError(t, err)
163164

@@ -194,9 +195,9 @@ func TestChunksToMatrix(t *testing.T) {
194195
}
195196
}
196197

197-
func benchmarkChunk() Chunk {
198+
func benchmarkChunk(now model.Time) Chunk {
198199
// This is a real example from Kubernetes' embedded cAdvisor metrics, lightly obfuscated
199-
return dummyChunkFor(model.Metric{
200+
return dummyChunkFor(now, model.Metric{
200201
model.MetricNameLabel: "container_cpu_usage_seconds_total",
201202
"beta_kubernetes_io_arch": "amd64",
202203
"beta_kubernetes_io_instance_type": "c3.somesize",
@@ -218,7 +219,7 @@ func benchmarkChunk() Chunk {
218219
}
219220

220221
func BenchmarkEncode(b *testing.B) {
221-
chunk := dummyChunk()
222+
chunk := dummyChunk(model.Now())
222223

223224
b.ResetTimer()
224225

@@ -232,7 +233,7 @@ func BenchmarkDecode100(b *testing.B) { benchmarkDecode(b, 100) }
232233
func BenchmarkDecode10000(b *testing.B) { benchmarkDecode(b, 10000) }
233234

234235
func benchmarkDecode(b *testing.B, batchSize int) {
235-
chunk := benchmarkChunk()
236+
chunk := benchmarkChunk(model.Now())
236237
buf, err := chunk.Encode()
237238
require.NoError(b, err)
238239

pkg/ingester/ingester_lifecycle.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ loop:
155155
for {
156156
select {
157157
case <-autoJoinAfter:
158+
level.Debug(util.Logger).Log("msg", "JoinAfter expired")
158159
// Will only fire once, after auto join timeout. If we haven't entered "JOINING" state,
159160
// then pick some tokens and enter ACTIVE state.
160161
if i.state == ring.PENDING {

pkg/ingester/ingester_lifecycle_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ func TestIngesterTransfer(t *testing.T) {
142142
Labels: util.ToLabelPairs(m),
143143
Samples: []client.Sample{
144144
{
145-
Value: 456.,
145+
Value: 456,
146146
TimestampMs: 123000,
147147
},
148148
},

0 commit comments

Comments
 (0)