From 93df29e606675ea7a3aa34fb61344d0a109b4de4 Mon Sep 17 00:00:00 2001 From: Noble Mittal <62551163+beingnoble03@users.noreply.github.com> Date: Mon, 20 May 2024 16:25:31 +0530 Subject: [PATCH] test: Add required tests for `vt/key`, `timer` and `cache/theine/bf` (#15976) Signed-off-by: Noble Mittal --- go/cache/theine/bf/bf_test.go | 20 +++ go/timer/timer_test.go | 10 ++ go/vt/key/destination_test.go | 222 ++++++++++++++++++++++++++++++---- go/vt/key/key_test.go | 98 +++++++-------- 4 files changed, 273 insertions(+), 77 deletions(-) diff --git a/go/cache/theine/bf/bf_test.go b/go/cache/theine/bf/bf_test.go index f0e505766e7..135826195ac 100644 --- a/go/cache/theine/bf/bf_test.go +++ b/go/cache/theine/bf/bf_test.go @@ -21,4 +21,24 @@ func TestBloom(t *testing.T) { exist = bf.Exist(456) require.False(t, exist) + + bf = New(0.01) + require.Equal(t, 512, bf.Capacity) + require.Equal(t, 0.01, bf.FalsePositiveRate) + + bf.Insert(123) + exist = bf.Exist(123) + require.True(t, exist) + + bf.Insert(256) + exist = bf.Exist(256) + require.True(t, exist) + + bf.Reset() + + exist = bf.Exist(123) + require.False(t, exist) + + exist = bf.Exist(256) + require.False(t, exist) } diff --git a/go/timer/timer_test.go b/go/timer/timer_test.go index c504a7d0eb2..fe268938db0 100644 --- a/go/timer/timer_test.go +++ b/go/timer/timer_test.go @@ -74,3 +74,13 @@ func TestIndefinite(t *testing.T) { time.Sleep(quarter) assert.Equal(t, int64(1), numcalls.Load()) } + +func TestInterval(t *testing.T) { + timer := NewTimer(100) + in := timer.Interval() + assert.Equal(t, 100*time.Nanosecond, in) + + timer.interval.Store(200) + in = timer.Interval() + assert.Equal(t, 200*time.Nanosecond, in) +} diff --git a/go/vt/key/destination_test.go b/go/vt/key/destination_test.go index 1f51323c715..f348b9ffa25 100644 --- a/go/vt/key/destination_test.go +++ b/go/vt/key/destination_test.go @@ -17,9 +17,12 @@ limitations under the License. package key import ( - "reflect" + "encoding/hex" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + topodatapb "vitess.io/vitess/go/vt/proto/topodata" ) @@ -51,9 +54,7 @@ func initShardArray(t *testing.T, shardingSpec string) []*topodatapb.ShardRefere } shardKrArray, err := ParseShardingSpec(shardingSpec) - if err != nil { - t.Fatalf("ParseShardingSpec failed: %v", err) - } + require.NoError(t, err, "ParseShardingSpec failed") result := make([]*topodatapb.ShardReference, len(shardKrArray)) for i, kr := range shardKrArray { @@ -137,9 +138,7 @@ func TestDestinationExactKeyRange(t *testing.T) { keyRange = &topodatapb.KeyRange{} } else { krArray, err := ParseShardingSpec(testCase.keyRange) - if err != nil { - t.Errorf("Got error while parsing sharding spec %v", err) - } + assert.NoError(t, err, "Got error while parsing sharding spec") keyRange = krArray[0] } dkr := DestinationExactKeyRange{KeyRange: keyRange} @@ -148,12 +147,10 @@ func TestDestinationExactKeyRange(t *testing.T) { gotShards = append(gotShards, shard) return nil }) - if err != nil && err.Error() != testCase.err { - t.Errorf("gotShards: %v, want %s", err, testCase.err) - } - if !reflect.DeepEqual(testCase.shards, gotShards) { - t.Errorf("want \n%#v, got \n%#v", testCase.shards, gotShards) + if testCase.err != "" { + assert.ErrorContains(t, err, testCase.err) } + assert.Equal(t, testCase.shards, gotShards) } } @@ -241,21 +238,202 @@ func TestDestinationKeyRange(t *testing.T) { keyRange = &topodatapb.KeyRange{} } else { krArray, err := ParseShardingSpec(testCase.keyRange) - if err != nil { - t.Errorf("Got error while parsing sharding spec %v", err) - } + assert.NoError(t, err, "Got error while parsing sharding spec") keyRange = krArray[0] } dkr := DestinationKeyRange{KeyRange: keyRange} var gotShards []string - if err := dkr.Resolve(allShards, func(shard string) error { + err := dkr.Resolve(allShards, func(shard string) error { gotShards = append(gotShards, shard) return nil - }); err != nil { - t.Errorf("want nil, got %v", err) - } - if !reflect.DeepEqual(testCase.shards, gotShards) { - t.Errorf("want \n%#v, got \n%#v", testCase.shards, gotShards) - } + }) + assert.NoError(t, err) + assert.Equal(t, testCase.shards, gotShards) + } +} + +func TestDestinationsString(t *testing.T) { + kr2040 := &topodatapb.KeyRange{ + Start: []byte{0x20}, + End: []byte{0x40}, + } + + got := DestinationsString([]Destination{ + DestinationShard("2"), + DestinationShards{"2", "3"}, + DestinationExactKeyRange{KeyRange: kr2040}, + DestinationKeyRange{KeyRange: kr2040}, + DestinationKeyspaceID{1, 2}, + DestinationKeyspaceIDs{ + {1, 2}, + {2, 3}, + }, + DestinationAllShards{}, + DestinationNone{}, + DestinationAnyShard{}, + }) + want := "Destinations:DestinationShard(2),DestinationShards(2,3),DestinationExactKeyRange(20-40),DestinationKeyRange(20-40),DestinationKeyspaceID(0102),DestinationKeyspaceIDs(0102,0203),DestinationAllShards(),DestinationNone(),DestinationAnyShard()" + assert.Equal(t, want, got) +} + +func TestDestinationShardResolve(t *testing.T) { + allShards := initShardArray(t, "") + + ds := DestinationShard("test-destination-shard") + + var calledVar string + err := ds.Resolve(allShards, func(shard string) error { + calledVar = shard + return nil + }) + assert.NoError(t, err) + assert.Equal(t, "test-destination-shard", calledVar) +} + +func TestDestinationShardsResolve(t *testing.T) { + allShards := initShardArray(t, "") + + ds := DestinationShards{"ds1", "ds2"} + + var calledVar []string + err := ds.Resolve(allShards, func(shard string) error { + calledVar = append(calledVar, shard) + return nil + }) + assert.NoError(t, err) + + want := []string{"ds1", "ds2"} + assert.ElementsMatch(t, want, calledVar) +} + +func TestDestinationKeyspaceIDResolve(t *testing.T) { + allShards := initShardArray(t, "60-80-90") + + testCases := []struct { + keyspaceID string + want string + err string + }{ + {"59", "", "KeyspaceId 59 didn't match any shards"}, + // Should include start limit of keyRange + {"60", "60-80", ""}, + {"79", "60-80", ""}, + {"80", "80-90", ""}, + {"89", "80-90", ""}, + // Shouldn't include end limit of keyRange + {"90", "", "KeyspaceId 90 didn't match any shards"}, + } + + for _, tc := range testCases { + t.Run(tc.keyspaceID, func(t *testing.T) { + k, err := hex.DecodeString(tc.keyspaceID) + assert.NoError(t, err) + + ds := DestinationKeyspaceID(k) + + var calledVar string + addShard := func(shard string) error { + calledVar = shard + return nil + } + + err = ds.Resolve(allShards, addShard) + if tc.err != "" { + assert.ErrorContains(t, err, tc.err) + return + } + + assert.Equal(t, tc.want, calledVar) + }) + } + + // Expect error when allShards is empty + ds := DestinationKeyspaceID("80") + err := ds.Resolve([]*topodatapb.ShardReference{}, func(_ string) error { + return nil + }) + assert.ErrorContains(t, err, "no shard in keyspace") +} + +func TestDestinationKeyspaceIDsResolve(t *testing.T) { + allShards := initShardArray(t, "60-80-90") + + k1, err := hex.DecodeString("82") + assert.NoError(t, err) + + k2, err := hex.DecodeString("61") + assert.NoError(t, err) + + k3, err := hex.DecodeString("89") + assert.NoError(t, err) + + ds := DestinationKeyspaceIDs{k1, k2, k3} + + var calledVar []string + addShard := func(shard string) error { + calledVar = append(calledVar, shard) + return nil + } + + err = ds.Resolve(allShards, addShard) + assert.NoError(t, err) + + want := []string{"80-90", "60-80", "80-90"} + assert.Equal(t, want, calledVar) +} + +func TestDestinationAllShardsResolve(t *testing.T) { + allShards := initShardArray(t, "60-80-90") + + ds := DestinationAllShards{} + + var calledVar []string + addShard := func(shard string) error { + calledVar = append(calledVar, shard) + return nil } + + err := ds.Resolve(allShards, addShard) + assert.NoError(t, err) + + want := []string{"60-80", "80-90"} + assert.ElementsMatch(t, want, calledVar) +} + +func TestDestinationNoneResolve(t *testing.T) { + allShards := initShardArray(t, "60-80-90") + + ds := DestinationNone{} + + var called bool + addShard := func(shard string) error { + called = true + return nil + } + + err := ds.Resolve(allShards, addShard) + assert.NoError(t, err) + assert.False(t, called, "addShard shouldn't be called in the case of DestinationNone") +} + +func TestDestinationAnyShardResolve(t *testing.T) { + allShards := initShardArray(t, "custom") + + ds := DestinationAnyShard{} + + var calledVar string + addShard := func(shard string) error { + calledVar = shard + return nil + } + + err := ds.Resolve(allShards, addShard) + assert.NoError(t, err) + + possibleShards := []string{"0", "1"} + assert.Contains(t, possibleShards, calledVar) + + // Expect error when allShards is empty + err = ds.Resolve([]*topodatapb.ShardReference{}, addShard) + assert.ErrorContains(t, err, "no shard in keyspace") } diff --git a/go/vt/key/key_test.go b/go/vt/key/key_test.go index 8db45aa79b9..84d4365ff0e 100644 --- a/go/vt/key/key_test.go +++ b/go/vt/key/key_test.go @@ -333,25 +333,18 @@ func TestEvenShardsKeyRange(t *testing.T) { for _, tc := range testCases { got, err := EvenShardsKeyRange(tc.i, tc.n) - if err != nil { - t.Fatalf("EvenShardsKeyRange(%v, %v) returned unexpected error: %v", tc.i, tc.n, err) - } - if !proto.Equal(got, tc.want) { - t.Errorf("EvenShardsKeyRange(%v, %v) = (%x, %x), want = (%x, %x)", tc.i, tc.n, got.Start, got.End, tc.want.Start, tc.want.End) - } + require.NoError(t, err) + assert.True(t, proto.Equal(got, tc.want), "got=(%x, %x), want=(%x, %x)", got.Start, got.End, tc.want.Start, tc.want.End) // Check if the string representation is equal as well. - if gotStr, want := KeyRangeString(got), tc.wantSpec; gotStr != want { - t.Errorf("EvenShardsKeyRange(%v) = %v, want = %v", got, gotStr, want) - } + gotStr := KeyRangeString(got) + assert.Equal(t, tc.wantSpec, gotStr) // Now verify that ParseKeyRangeParts() produces the same KeyRange object as // we do. parts := strings.Split(tc.wantSpec, "-") kr, _ := ParseKeyRangeParts(parts[0], parts[1]) - if !proto.Equal(got, kr) { - t.Errorf("EvenShardsKeyRange(%v, %v) != ParseKeyRangeParts(%v, %v): (%x, %x) != (%x, %x)", tc.i, tc.n, parts[0], parts[1], got.Start, got.End, kr.Start, kr.End) - } + assert.True(t, proto.Equal(got, kr), "EvenShardsKeyRange(%v, %v) != ParseKeyRangeParts(%v, %v): (%x, %x) != (%x, %x)", tc.i, tc.n, parts[0], parts[1], got.Start, got.End, kr.Start, kr.End) } } @@ -477,9 +470,7 @@ func TestKeyRangeEndEqual(t *testing.T) { first := stringToKeyRange(tcase.first) second := stringToKeyRange(tcase.second) out := KeyRangeEndEqual(first, second) - if out != tcase.out { - t.Fatalf("KeyRangeEndEqual(%q, %q) expected %t, got %t", tcase.first, tcase.second, tcase.out, out) - } + require.Equal(t, tcase.out, out) } } @@ -518,9 +509,7 @@ func TestKeyRangeStartEqual(t *testing.T) { first := stringToKeyRange(tcase.first) second := stringToKeyRange(tcase.second) out := KeyRangeStartEqual(first, second) - if out != tcase.out { - t.Fatalf("KeyRangeStartEqual(%q, %q) expected %t, got %t", tcase.first, tcase.second, tcase.out, out) - } + require.Equal(t, tcase.out, out) } } @@ -555,9 +544,7 @@ func TestKeyRangeEqual(t *testing.T) { first := stringToKeyRange(tcase.first) second := stringToKeyRange(tcase.second) out := KeyRangeEqual(first, second) - if out != tcase.out { - t.Fatalf("KeyRangeEqual(%q, %q) expected %t, got %t", tcase.first, tcase.second, tcase.out, out) - } + require.Equal(t, tcase.out, out) } } @@ -600,9 +587,7 @@ func TestKeyRangeContiguous(t *testing.T) { first := stringToKeyRange(tcase.first) second := stringToKeyRange(tcase.second) out := KeyRangeContiguous(first, second) - if out != tcase.out { - t.Fatalf("KeyRangeContiguous(%q, %q) expected %t, got %t", tcase.first, tcase.second, tcase.out, out) - } + require.Equal(t, tcase.out, out) } } @@ -626,10 +611,8 @@ func TestEvenShardsKeyRange_Error(t *testing.T) { } for _, tc := range testCases { - kr, err := EvenShardsKeyRange(tc.i, tc.n) - if err == nil || !strings.Contains(err.Error(), tc.wantError) { - t.Fatalf("EvenShardsKeyRange(%v, %v) = (%v, %v) want error = %v", tc.i, tc.n, kr, err, tc.wantError) - } + _, err := EvenShardsKeyRange(tc.i, tc.n) + require.ErrorContains(t, err, tc.wantError) } } @@ -653,25 +636,17 @@ func TestParseShardingSpec(t *testing.T) { } for key, wanted := range goodTable { r, err := ParseShardingSpec(key) - if err != nil { - t.Errorf("Unexpected error: %v.", err) - } - if len(r) != len(wanted) { - t.Errorf("Wrong result: wanted %v, got %v", wanted, r) + assert.NoError(t, err) + if !assert.Len(t, r, len(wanted)) { continue } for i, w := range wanted { - if !proto.Equal(r[i], w) { - t.Errorf("Wrong result: wanted %v, got %v", w, r[i]) - break - } + require.Truef(t, proto.Equal(r[i], w), "wanted %v, got %v", w, r[i]) } } for _, bad := range badTable { _, err := ParseShardingSpec(bad) - if err == nil { - t.Errorf("Didn't get expected error for %v.", bad) - } + assert.Error(t, err) } } @@ -1081,27 +1056,19 @@ func TestKeyRangeContains(t *testing.T) { for _, el := range table { s, err := hex.DecodeString(el.start) - if err != nil { - t.Errorf("Unexpected error: %v", err) - } + assert.NoError(t, err) e, err := hex.DecodeString(el.end) - if err != nil { - t.Errorf("Unexpected error: %v", err) - } + assert.NoError(t, err) kr := &topodatapb.KeyRange{ Start: s, End: e, } k, err := hex.DecodeString(el.kid) - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - if c := KeyRangeContains(kr, k); c != el.contained { - t.Errorf("Unexpected result: contains for %v and (%v-%v) yields %v.", el.kid, el.start, el.end, c) - } - if !KeyRangeContains(nil, k) { - t.Errorf("KeyRangeContains(nil, x) should always be true") - } + assert.NoError(t, err) + c := KeyRangeContains(kr, k) + assert.Equal(t, el.contained, c) + + assert.True(t, KeyRangeContains(nil, k), "KeyRangeContains(nil, x) should always be true") } } @@ -1601,3 +1568,24 @@ func stringToKeyRange(spec string) *topodatapb.KeyRange { } return kr } + +func TestKeyRangeIsPartial(t *testing.T) { + testCases := []struct { + name string + keyRange *topodatapb.KeyRange + want bool + }{ + {"nil key range", nil, false}, + {"empty start and end", &topodatapb.KeyRange{}, false}, + {"empty end", &topodatapb.KeyRange{Start: []byte("12")}, true}, + {"empty start", &topodatapb.KeyRange{End: []byte("13")}, true}, + {"non-empty start and end", &topodatapb.KeyRange{Start: []byte("12"), End: []byte("13")}, true}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + isPartial := KeyRangeIsPartial(tc.keyRange) + assert.Equal(t, tc.want, isPartial) + }) + } +}