state: Use subtests in TestStateStore_ServicesByNodeMeta

These subtests make it much easier to identify the slow part of the test, but they also help enumerate all the different cases which are being tested.
pull/8365/head
Daniel Nephin 2020-07-22 16:26:49 -04:00
parent a6a1a0e3d6
commit 0402dd7ac5
1 changed files with 75 additions and 82 deletions

View File

@ -1611,12 +1611,14 @@ func TestStateStore_Services(t *testing.T) {
func TestStateStore_ServicesByNodeMeta(t *testing.T) { func TestStateStore_ServicesByNodeMeta(t *testing.T) {
s := testStateStore(t) s := testStateStore(t)
// Listing with no results returns nil.
ws := memdb.NewWatchSet() ws := memdb.NewWatchSet()
idx, res, err := s.ServicesByNodeMeta(ws, map[string]string{"somekey": "somevalue"}, nil)
if idx != 0 || len(res) != 0 || err != nil { t.Run("Listing with no results returns nil", func(t *testing.T) {
t.Fatalf("expected (0, nil, nil), got: (%d, %#v, %#v)", idx, res, err) idx, res, err := s.ServicesByNodeMeta(ws, map[string]string{"somekey": "somevalue"}, nil)
} if idx != 0 || len(res) != 0 || err != nil {
t.Fatalf("expected (0, nil, nil), got: (%d, %#v, %#v)", idx, res, err)
}
})
// Create some nodes and services in the state store. // Create some nodes and services in the state store.
node0 := &structs.Node{Node: "node0", Address: "127.0.0.1", Meta: map[string]string{"role": "client", "common": "1"}} node0 := &structs.Node{Node: "node0", Address: "127.0.0.1", Meta: map[string]string{"role": "client", "common": "1"}}
@ -1648,94 +1650,85 @@ func TestStateStore_ServicesByNodeMeta(t *testing.T) {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
if !watchFired(ws) { if !watchFired(ws) {
t.Fatalf("bad") t.Fatalf("expected the watch to be triggered by the queries")
} }
// Filter the services by the first node's meta value.
ws = memdb.NewWatchSet() ws = memdb.NewWatchSet()
_, res, err = s.ServicesByNodeMeta(ws, map[string]string{"role": "client"}, nil)
if err != nil {
t.Fatalf("err: %s", err)
}
expected := structs.Services{
"redis": []string{"master", "prod"},
}
sort.Strings(res["redis"])
if !reflect.DeepEqual(res, expected) {
t.Fatalf("bad: %v %v", res, expected)
}
// Get all services using the common meta value t.Run("Filter the services by the first node's meta value", func(t *testing.T) {
_, res, err = s.ServicesByNodeMeta(ws, map[string]string{"common": "1"}, nil) _, res, err := s.ServicesByNodeMeta(ws, map[string]string{"role": "client"}, nil)
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
expected = structs.Services{ expected := structs.Services{
"redis": []string{"master", "prod", "slave"}, "redis": []string{"master", "prod"},
} }
sort.Strings(res["redis"]) sort.Strings(res["redis"])
if !reflect.DeepEqual(res, expected) { require.Equal(t, expected, res)
t.Fatalf("bad: %v %v", res, expected) })
}
// Get an empty list for an invalid meta value t.Run("Get all services using the common meta value", func(t *testing.T) {
_, res, err = s.ServicesByNodeMeta(ws, map[string]string{"invalid": "nope"}, nil) _, res, err := s.ServicesByNodeMeta(ws, map[string]string{"common": "1"}, nil)
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
expected = structs.Services{} expected := structs.Services{
if !reflect.DeepEqual(res, expected) { "redis": []string{"master", "prod", "slave"},
t.Fatalf("bad: %v %v", res, expected) }
} sort.Strings(res["redis"])
require.Equal(t, expected, res)
})
// Get the first node's service instance using multiple meta filters t.Run("Get an empty list for an invalid meta value", func(t *testing.T) {
_, res, err = s.ServicesByNodeMeta(ws, map[string]string{"role": "client", "common": "1"}, nil) _, res, err := s.ServicesByNodeMeta(ws, map[string]string{"invalid": "nope"}, nil)
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
expected = structs.Services{ expected := structs.Services{}
"redis": []string{"master", "prod"}, require.Equal(t, expected, res)
} })
sort.Strings(res["redis"])
if !reflect.DeepEqual(res, expected) {
t.Fatalf("bad: %v %v", res, expected)
}
// Sanity check the watch before we proceed. t.Run("Get the first node's service instance using multiple meta filters", func(t *testing.T) {
if watchFired(ws) { _, res, err := s.ServicesByNodeMeta(ws, map[string]string{"role": "client", "common": "1"}, nil)
t.Fatalf("bad") if err != nil {
} t.Fatalf("err: %s", err)
}
expected := structs.Services{
"redis": []string{"master", "prod"},
}
sort.Strings(res["redis"])
require.Equal(t, expected, res)
})
// Registering some unrelated node + service should not fire the watch. t.Run("Registering some unrelated node + service should not fire the watch.", func(t *testing.T) {
testRegisterNode(t, s, 4, "nope") testRegisterNode(t, s, 4, "nope")
testRegisterService(t, s, 5, "nope", "nope") testRegisterService(t, s, 5, "nope", "nope")
if watchFired(ws) { if watchFired(ws) {
t.Fatalf("bad") t.Fatalf("expected the watch to timeout and not be triggered")
} }
})
// Overwhelm the service tracking. t.Run("Uses watchLimit to limit the number of watches", func(t *testing.T) {
idx = 6 var idx uint64 = 6
for i := 0; i < 2*watchLimit; i++ { for i := 0; i < 2*watchLimit; i++ {
node := fmt.Sprintf("many%d", i) node := fmt.Sprintf("many%d", i)
testRegisterNodeWithMeta(t, s, idx, node, map[string]string{"common": "1"}) testRegisterNodeWithMeta(t, s, idx, node, map[string]string{"common": "1"})
idx++ idx++
testRegisterService(t, s, idx, node, "nope") testRegisterService(t, s, idx, node, "nope")
idx++ idx++
} }
// Now get a fresh watch, which will be forced to watch the whole // Now get a fresh watch, which will be forced to watch the whole
// service table. // service table.
ws = memdb.NewWatchSet() ws := memdb.NewWatchSet()
_, _, err = s.ServicesByNodeMeta(ws, map[string]string{"common": "1"}, nil) _, _, err := s.ServicesByNodeMeta(ws, map[string]string{"common": "1"}, nil)
if err != nil { require.NoError(t, err)
t.Fatalf("err: %s", err)
}
// Registering some unrelated node + service should not fire the watch. testRegisterService(t, s, idx, "nope", "more-nope")
testRegisterService(t, s, idx, "nope", "more-nope") if !watchFired(ws) {
if !watchFired(ws) { t.Fatalf("expected the watch to timeout and not be triggered")
t.Fatalf("bad") }
} })
} }
func TestStateStore_ServiceNodes(t *testing.T) { func TestStateStore_ServiceNodes(t *testing.T) {