Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions chk/chk.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,50 @@ func HasResult(t testing.TB, res []*client.OpResult, want *client.OpResult, opt
}
}

// HasResultsCache implements an efficient mechanism to call HasResults across
// a large set of operations results. HasResultsCache checks whether each result
// in wants is present in res, using the options specified.
func HasResultsCache(t testing.TB, res []*client.OpResult, wants []*client.OpResult, opt ...resultOpt) {
t.Helper()

byOpID := map[uint64]*client.OpResult{}
byNHID := map[uint64]*client.OpResult{}
byNHGID := map[uint64]*client.OpResult{}
byIPv4Prefix := map[string]*client.OpResult{}

for _, r := range res {
byOpID[r.OperationID] = r
if r.Details != nil {
switch {
case r.Details.NextHopGroupID != 0:
byNHGID[r.Details.NextHopGroupID] = r
case r.Details.NextHopIndex != 0:
byNHID[r.Details.NextHopIndex] = r
case r.Details.IPv4Prefix != "":
byIPv4Prefix[r.Details.IPv4Prefix] = r
}
}
}

if !hasIgnoreOperationID(opt) {
for _, want := range wants {
HasResult(t, []*client.OpResult{byOpID[want.OperationID]}, want, opt...)
}
return
}

for _, want := range wants {
switch {
case want.Details.NextHopGroupID != 0:
HasResult(t, []*client.OpResult{byNHGID[want.Details.NextHopGroupID]}, want, opt...)
case want.Details.NextHopIndex != 0:
HasResult(t, []*client.OpResult{byNHID[want.Details.NextHopIndex]}, want, opt...)
case want.Details.IPv4Prefix != "":
HasResult(t, []*client.OpResult{byIPv4Prefix[want.Details.IPv4Prefix]}, want, opt...)
}
}
}

// clientError converts the given error into a client ClientErr.
func clientError(t testing.TB, err error) *client.ClientErr {
t.Helper()
Expand Down
167 changes: 167 additions & 0 deletions chk/chk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,170 @@ func TestHasMessage(t *testing.T) {
})
}
}

func TestHasResultsCache(t *testing.T) {
tests := []struct {
desc string
inResults []*client.OpResult
inWants []*client.OpResult
expectFatalMsg string
inOpt []resultOpt
}{{
desc: "single want, single result by operation ID",
inResults: []*client.OpResult{{
OperationID: 42,
}},
inWants: []*client.OpResult{{
OperationID: 42,
}},
}, {
desc: "multiple results, single want by operation ID",
inResults: []*client.OpResult{{
OperationID: 42,
}, {
OperationID: 128,
}},
inWants: []*client.OpResult{{
OperationID: 128,
}},
}, {
desc: "multiple results, multiple want by opeation ID",
inResults: []*client.OpResult{{
OperationID: 42,
}, {
OperationID: 128,
}},
inWants: []*client.OpResult{{
OperationID: 42,
}, {
OperationID: 128,
}},
}, {
desc: "missing result by operation ID",
inResults: []*client.OpResult{{
OperationID: 52,
}, {
OperationID: 124,
}},
inWants: []*client.OpResult{{
OperationID: 42,
}},
expectFatalMsg: "results did not contain a result of value",
}, {
desc: "result by nhg ID - found",
inResults: []*client.OpResult{{
OperationID: 42,
Details: &client.OpDetailsResults{
NextHopGroupID: 242,
},
}, {
OperationID: 44,
Details: &client.OpDetailsResults{
NextHopGroupID: 244,
},
}},
inWants: []*client.OpResult{{
Details: &client.OpDetailsResults{
NextHopGroupID: 242,
},
}, {
Details: &client.OpDetailsResults{
NextHopGroupID: 244,
},
}},
inOpt: []resultOpt{IgnoreOperationID()},
}, {
desc: "result by nhg ID - missing",
inResults: []*client.OpResult{{
OperationID: 42,
Details: &client.OpDetailsResults{
NextHopGroupID: 242,
},
}, {
OperationID: 44,
Details: &client.OpDetailsResults{
NextHopGroupID: 256,
},
}},
inWants: []*client.OpResult{{
Details: &client.OpDetailsResults{
NextHopGroupID: 257,
},
}},
inOpt: []resultOpt{IgnoreOperationID()},
expectFatalMsg: "results did not contain a result",
}, {
desc: "result by NH ID - found",
inResults: []*client.OpResult{{
OperationID: 42,
Details: &client.OpDetailsResults{
NextHopIndex: 420,
},
}},
inWants: []*client.OpResult{{
Details: &client.OpDetailsResults{
NextHopIndex: 420,
},
}},
inOpt: []resultOpt{IgnoreOperationID()},
}, {
desc: "result by NH ID - missing",
inResults: []*client.OpResult{{
OperationID: 42,
Details: &client.OpDetailsResults{
NextHopIndex: 420,
},
}},
inWants: []*client.OpResult{{
Details: &client.OpDetailsResults{
NextHopIndex: 1280,
},
}},
inOpt: []resultOpt{IgnoreOperationID()},
expectFatalMsg: "results did not contain a result",
}, {
desc: "result by IPv4 prefix - found",
inResults: []*client.OpResult{{
OperationID: 42,
Details: &client.OpDetailsResults{
IPv4Prefix: "1.1.1.1/32",
},
}},
inWants: []*client.OpResult{{
Details: &client.OpDetailsResults{
IPv4Prefix: "1.1.1.1/32",
},
}},
inOpt: []resultOpt{IgnoreOperationID()},
}, {
desc: "result by IPv4 prefix - missing",
inResults: []*client.OpResult{{
OperationID: 42,
Details: &client.OpDetailsResults{
IPv4Prefix: "1.1.1.1/32",
},
}},
inWants: []*client.OpResult{{
Details: &client.OpDetailsResults{
IPv4Prefix: "4.4.4.0/24",
},
}},
inOpt: []resultOpt{IgnoreOperationID()},
expectFatalMsg: "results did not contain a result",
}}

for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
if tt.expectFatalMsg != "" {
got := negtest.ExpectFatal(t, func(t testing.TB) {
HasResultsCache(t, tt.inResults, tt.inWants, tt.inOpt...)
})
if !strings.Contains(got, tt.expectFatalMsg) {
t.Fatalf("did not get expected fatal message, but test called Fatal, got: %s, want: %s", got, tt.expectFatalMsg)
}
return
}
HasResultsCache(t, tt.inResults, tt.inWants, tt.inOpt...)
})
}
}
11 changes: 2 additions & 9 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -533,15 +533,8 @@ func (o *OpResult) String() string {
buf.WriteString(fmt.Sprintf(" ElectionID: %s", e))
}

if v := o.OperationID; v != 0 {
typ := "Unknown"
if o.Details != nil {
typ = o.Details.Type.String()
}
buf.WriteString(fmt.Sprintf(" AFTOperation { ID: %d, Type: %s, Status: %s }", v, typ, o.ProgrammingResult))
} else if v := o.ProgrammingResult; v != spb.AFTResult_UNSET {
// Special case for input messages that are just matching on status.
buf.WriteString(fmt.Sprintf(" AFTOperation { Status: %s }", v))
if opID, pr := o.OperationID, o.ProgrammingResult; opID != 0 || pr != spb.AFTResult_UNSET {
buf.WriteString(fmt.Sprintf(" AFTOperation { ID: %d, Details: %s, Status: %s }", opID, o.Details, o.ProgrammingResult))
}

if v := o.SessionParameters; v != nil {
Expand Down
2 changes: 1 addition & 1 deletion client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1125,7 +1125,7 @@ func TestOpResultString(t *testing.T) {
inResult: &OpResult{
OperationID: 42,
},
want: "<0 (0 nsec): AFTOperation { ID: 42, Type: Unknown, Status: UNSET }>",
want: "<0 (0 nsec): AFTOperation { ID: 42, Details: <nil>, Status: UNSET }>",
}}

for _, tt := range tests {
Expand Down