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:
parent
c106d94742
commit
8ef4c0fcc5
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue