Skip to content

Commit 1700f84

Browse files
Fix thinSnaps (#1105)
* Fix thinSnaps logic * Guarantee FinalSnapshot matches last snapshot * Add export for thinSnaps for testing * Add explicit test for thinSnaps edge cases
1 parent 04ddb3c commit 1700f84

File tree

3 files changed

+110
-8
lines changed

3 files changed

+110
-8
lines changed

parser/export_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@ var InitParserVersionForTest = initParserVersion
1111
// InitParserGitCommitForTest allows test to rerun initParseGitCommit after initializing
1212
// environement variables.
1313
var InitParserGitCommitForTest = initParserGitCommit
14+
15+
// ThinSnaps allows exhaustive edge case testing of thinSnaps.
16+
var ThinSnaps = thinSnaps

parser/tcpinfo.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,19 @@ func (p *TCPInfoParser) IsParsable(testName string, data []byte) (string, bool)
9696
return "", false
9797
}
9898

99+
// thinSnaps collects every 10th snapshot in orig. thinSnaps guarantees that the last snapshot is preserved.
99100
func thinSnaps(orig []snapshot.Snapshot) []snapshot.Snapshot {
100101
n := len(orig)
102+
if n == 0 {
103+
return orig
104+
}
101105
out := make([]snapshot.Snapshot, 0, 1+n/10)
102-
for i := 0; i < n; i += 10 {
106+
// Take first and every 10th snapshot after (exluding the final snapshot, which is always included).
107+
for i := 0; i < n-1; i += 10 {
103108
out = append(out, orig[i])
104109
}
105-
if n%10 != 0 {
106-
out = append(out, orig[n-1])
107-
}
110+
// Always append final snapshot.
111+
out = append(out, orig[n-1])
108112
return out
109113
}
110114

parser/tcpinfo_test.go

Lines changed: 99 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@ import (
1414
"time"
1515

1616
"cloud.google.com/go/civil"
17+
"github.com/go-test/deep"
1718
"github.com/m-lab/etl/etl"
1819
"github.com/m-lab/etl/parser"
1920
"github.com/m-lab/etl/schema"
2021
"github.com/m-lab/etl/storage"
2122
"github.com/m-lab/etl/task"
23+
"github.com/m-lab/tcp-info/snapshot"
2224
)
2325

2426
func assertTCPInfoParser(in *parser.TCPInfoParser) {
@@ -169,6 +171,10 @@ func TestTCPParser(t *testing.T) {
169171
if row.A.SockID.SrcIP != "195.89.146.242" && row.A.SockID.SrcIP != "2001:5012:100:24::242" {
170172
t.Error("Wrong SrcIP", row.A.SockID.SrcIP)
171173
}
174+
// Guarantee that FinalSnapshot matches the last raw snapshot.
175+
if diff := deep.Equal(row.A.FinalSnapshot, row.Raw.Snapshots[len(row.Raw.Snapshots)-1]); diff != nil {
176+
t.Errorf("TestTCPParser.ParseAndInsert() FinalSnapshot and last snapshot differ: %s", strings.Join(diff, "\n"))
177+
}
172178
}
173179

174180
// This section is just for understanding how big these objects typically are, and what kind of compression
@@ -201,10 +207,6 @@ func TestTCPParser(t *testing.T) {
201207
if duration > 20*time.Second {
202208
t.Error("Incorrect duration calculation", duration)
203209
}
204-
205-
if totalSnaps != 1588 {
206-
t.Error("expected 1588 (thinned) snapshots, got", totalSnaps)
207-
}
208210
}
209211

210212
// This is a subset of TestTCPParser, but simpler, so might be useful.
@@ -295,3 +297,96 @@ func BenchmarkTCPParser(b *testing.B) {
295297
}
296298
}
297299
}
300+
301+
func makeSnaps(n int) []snapshot.Snapshot {
302+
snaps := []snapshot.Snapshot{}
303+
for i := 0; i < n; i++ {
304+
snaps = append(snaps, snapshot.Snapshot{
305+
Observed: uint32(i), // this field is arbitrary. Just make the Snapshot distinct without populating every field.
306+
})
307+
}
308+
return snaps
309+
}
310+
311+
func Test_thinSnaps(t *testing.T) {
312+
tests := []struct {
313+
name string
314+
orig []snapshot.Snapshot
315+
want []snapshot.Snapshot
316+
}{
317+
{
318+
name: "success-nil",
319+
orig: nil,
320+
want: nil,
321+
},
322+
{
323+
name: "success-0",
324+
orig: makeSnaps(0),
325+
want: []snapshot.Snapshot{},
326+
},
327+
{
328+
name: "success-1",
329+
orig: makeSnaps(1),
330+
want: []snapshot.Snapshot{
331+
{Observed: 0},
332+
},
333+
},
334+
{
335+
name: "success-2",
336+
orig: makeSnaps(2),
337+
want: []snapshot.Snapshot{
338+
{Observed: 0},
339+
{Observed: 1},
340+
},
341+
},
342+
{
343+
name: "success-3",
344+
orig: makeSnaps(3),
345+
want: []snapshot.Snapshot{
346+
{Observed: 0},
347+
{Observed: 2},
348+
},
349+
},
350+
{
351+
name: "success-9",
352+
orig: makeSnaps(9),
353+
want: []snapshot.Snapshot{
354+
{Observed: 0},
355+
{Observed: 8},
356+
},
357+
},
358+
{
359+
name: "success-10",
360+
orig: makeSnaps(10),
361+
want: []snapshot.Snapshot{
362+
{Observed: 0},
363+
{Observed: 9},
364+
},
365+
},
366+
{
367+
name: "success-11",
368+
orig: makeSnaps(11),
369+
want: []snapshot.Snapshot{
370+
{Observed: 0},
371+
{Observed: 10},
372+
},
373+
},
374+
{
375+
name: "success-12",
376+
orig: makeSnaps(12),
377+
want: []snapshot.Snapshot{
378+
{Observed: 0},
379+
{Observed: 10},
380+
{Observed: 11},
381+
},
382+
},
383+
}
384+
for _, tt := range tests {
385+
t.Run(tt.name, func(t *testing.T) {
386+
got := parser.ThinSnaps(tt.orig)
387+
if diff := deep.Equal(got, tt.want); diff != nil {
388+
t.Errorf("TestThinSnaps() differ = %s", strings.Join(diff, "\n"))
389+
}
390+
})
391+
}
392+
}

0 commit comments

Comments
 (0)