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.
This commit is contained in:
Daniel Nephin 2020-07-22 16:26:49 -04:00
parent a6a1a0e3d6
commit 0402dd7ac5

View File

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