state: use go-cmp for comparison

The output of the previous assertions made it impossible to debug the tests without code changes.

With go-cmp comparing the entire slice we can see the full diffs making it easier to debug failures.
This commit is contained in:
Daniel Nephin 2020-10-28 15:19:24 -04:00
parent c106d94742
commit 8ef4c0fcc5
1 changed files with 30 additions and 50 deletions

View File

@ -4,12 +4,15 @@ import (
"fmt"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/stretchr/testify/require"
"github.com/hashicorp/consul/agent/consul/stream"
"github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/api"
"github.com/hashicorp/consul/proto/pbsubscribe"
"github.com/hashicorp/consul/types"
"github.com/stretchr/testify/require"
)
func TestServiceHealthEventsFromChanges(t *testing.T) {
@ -884,17 +887,36 @@ func TestServiceHealthEventsFromChanges(t *testing.T) {
}
require.NoError(t, err)
// Make sure we have the right events, only taking ordering into account
// where it matters to account for non-determinism.
requireEventsInCorrectPartialOrder(t, tc.WantEvents, got, func(e stream.Event) string {
// We need events affecting unique registrations to be ordered, within a topic
csn := getPayloadCheckServiceNode(e.Payload)
return fmt.Sprintf("%s/%s/%s", e.Topic, csn.Node.Node, csn.Service.Service)
})
assertDeepEqual(t, tc.WantEvents, got, cmpPartialOrderEvents)
})
}
}
func assertDeepEqual(t *testing.T, x, y interface{}, opts ...cmp.Option) {
t.Helper()
if diff := cmp.Diff(x, y, opts...); diff != "" {
t.Fatalf("assertion failed: values are not equal\n--- expected\n+++ actual\n%v", diff)
}
}
// cmpPartialOrderEvents returns a compare option which sorts events so that
// all events for a particular node/service are grouped together. The sort is
// stable so events with the same node/service retain their relative order.
var cmpPartialOrderEvents = cmp.Options{
cmpopts.SortSlices(func(i, j stream.Event) bool {
key := func(e stream.Event) string {
csn := getPayloadCheckServiceNode(e.Payload)
return fmt.Sprintf("%s/%s/%s", e.Topic, csn.Node.Node, csn.Service.Service)
}
return key(i) < key(j)
}),
cmpEvents,
}
var cmpEvents = cmp.Options{
cmp.AllowUnexported(EventPayloadCheckServiceNode{}),
}
type regOption func(req *structs.RegisterRequest) error
func testNodeRegistration(t *testing.T, opts ...regOption) *structs.RegisterRequest {
@ -1337,48 +1359,6 @@ func evServiceCheckDelete(e *stream.Event) error {
return nil
}
// requireEventsInCorrectPartialOrder compares that the expected set of events
// was emitted. It allows for _independent_ events to be emitted in any order -
// this can be important because even though the transaction processing is all
// strictly ordered up until the processing func, grouping multiple updates that
// affect the same logical entity may be necessary and may impose random
// ordering changes on the eventual events if a map is used. We only care that
// events _affecting the same topic and key_ are ordered correctly with respect
// to the "expected" set of events so this helper asserts that.
//
// The caller provides a func that can return a partition key for the given
// event types and we assert that all events with the same partition key are
// deliveries in the same order. Note that this is not necessarily the same as
// topic/key since for example in Catalog only events about a specific service
// _instance_ need to be ordered while topic and key are more general.
func requireEventsInCorrectPartialOrder(t *testing.T, want, got []stream.Event,
partKey func(stream.Event) string) {
t.Helper()
// Partion both arrays by topic/key
wantParts := make(map[string][]stream.Event)
gotParts := make(map[string][]stream.Event)
for _, e := range want {
k := partKey(e)
wantParts[k] = append(wantParts[k], e)
}
for _, e := range got {
k := partKey(e)
gotParts[k] = append(gotParts[k], e)
}
for k, want := range wantParts {
require.Equal(t, want, gotParts[k], "got incorrect events for partition: %s", k)
}
for k, got := range gotParts {
if _, ok := wantParts[k]; !ok {
require.Equal(t, nil, got, "got unwanted events for partition: %s", k)
}
}
}
// newTestEventServiceHealthRegister returns a realistically populated service
// health registration event. The nodeNum is a
// logical node and is used to create the node name ("node%d") but also change