// Copyright 2021 TiKV Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // NOTE: The code in this file is based on code from the // TiDB project, licensed under the Apache License v 2.0 // // https://github.com/pingcap/tidb/tree/cc5e161ac06827589c4966674597c137cc9e809c/store/tikv/tests/rawkv_test.go // // Copyright 2016 PingCAP, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package raw_tikv_test import ( "bytes" "context" "fmt" "testing" "github.com/stretchr/testify/suite" "github.com/tikv/client-go/v2/rawkv" "github.com/tikv/client-go/v2/testutils" "github.com/tikv/client-go/v2/tikv" ) func TestRawKV(t *testing.T) { suite.Run(t, new(testRawKVSuite)) } type testRawKVSuite struct { suite.Suite cluster testutils.Cluster client rawkv.ClientProbe bo *tikv.Backoffer } func (s *testRawKVSuite) SetupTest() { client, cluster, pdClient, err := testutils.NewMockTiKV("", nil) s.Require().NoError(err) s.Require().Nil(err) testutils.BootstrapWithSingleStore(cluster) s.cluster = cluster s.client = rawkv.ClientProbe{Client: &rawkv.Client{}} s.client.SetPDClient(pdClient) s.client.SetRegionCache(tikv.NewRegionCache(pdClient)) s.client.SetRPCClient(client) s.bo = tikv.NewBackofferWithVars(context.Background(), 5000, nil) } func (s *testRawKVSuite) TearDownTest() { s.client.Close() } func (s *testRawKVSuite) mustNotExist(key []byte) { v, err := s.client.Get(context.Background(), key) s.Nil(err) s.Nil(v) } func (s *testRawKVSuite) mustBatchNotExist(keys [][]byte) { values, err := s.client.BatchGet(context.Background(), keys) s.Nil(err) s.NotNil(values) s.Equal(len(keys), len(values)) for _, value := range values { s.Len(value, 0) } } func (s *testRawKVSuite) mustGet(key, value []byte) { v, err := s.client.Get(context.Background(), key) s.Nil(err) s.NotNil(v) s.Equal(v, value) } func (s *testRawKVSuite) mustBatchGet(keys, values [][]byte) { checkValues, err := s.client.BatchGet(context.Background(), keys) s.Nil(err) s.NotNil(checkValues) s.Equal(len(keys), len(checkValues)) for i := range keys { s.Equal(values[i], checkValues[i]) } } func (s *testRawKVSuite) mustPut(key, value []byte) { err := s.client.Put(context.Background(), key, value) s.Nil(err) } func (s *testRawKVSuite) mustBatchPut(keys, values [][]byte) { err := s.client.BatchPut(context.Background(), keys, values) s.Nil(err) } func (s *testRawKVSuite) mustDelete(key []byte) { err := s.client.Delete(context.Background(), key) s.Nil(err) } func (s *testRawKVSuite) mustBatchDelete(keys [][]byte) { err := s.client.BatchDelete(context.Background(), keys) s.Nil(err) } func (s *testRawKVSuite) mustScan(startKey string, limit int, expect ...string) { keys, values, err := s.client.Scan(context.Background(), []byte(startKey), nil, limit) s.Nil(err) s.Equal(len(keys)*2, len(expect)) for i := range keys { s.Equal(string(keys[i]), expect[i*2]) s.Equal(string(values[i]), expect[i*2+1]) } } func (s *testRawKVSuite) mustScanRange(startKey string, endKey string, limit int, expect ...string) { keys, values, err := s.client.Scan(context.Background(), []byte(startKey), []byte(endKey), limit) s.Nil(err) s.Equal(len(keys)*2, len(expect)) for i := range keys { s.Equal(string(keys[i]), expect[i*2]) s.Equal(string(values[i]), expect[i*2+1]) } } func (s *testRawKVSuite) mustReverseScan(startKey []byte, limit int, expect ...string) { keys, values, err := s.client.ReverseScan(context.Background(), startKey, nil, limit) s.Nil(err) s.Equal(len(keys)*2, len(expect)) for i := range keys { s.Equal(string(keys[i]), expect[i*2]) s.Equal(string(values[i]), expect[i*2+1]) } } func (s *testRawKVSuite) mustReverseScanRange(startKey, endKey []byte, limit int, expect ...string) { keys, values, err := s.client.ReverseScan(context.Background(), startKey, endKey, limit) s.Nil(err) s.Equal(len(keys)*2, len(expect)) for i := range keys { s.Equal(string(keys[i]), expect[i*2]) s.Equal(string(values[i]), expect[i*2+1]) } } func (s *testRawKVSuite) mustDeleteRange(startKey, endKey []byte, expected map[string]string) { err := s.client.DeleteRange(context.Background(), startKey, endKey) s.Nil(err) for keyStr := range expected { key := []byte(keyStr) if bytes.Compare(startKey, key) <= 0 && bytes.Compare(key, endKey) < 0 { delete(expected, keyStr) } } s.checkData(expected) } func (s *testRawKVSuite) checkData(expected map[string]string) { keys, values, err := s.client.Scan(context.Background(), []byte(""), nil, len(expected)+1) s.Nil(err) s.Equal(len(expected), len(keys)) for i, key := range keys { s.Equal(expected[string(key)], string(values[i])) } } func (s *testRawKVSuite) split(regionKey, splitKey string) error { loc, err := s.client.GetRegionCache().LocateKey(s.bo, []byte(regionKey)) if err != nil { return err } newRegionID, peerID := s.cluster.AllocID(), s.cluster.AllocID() s.cluster.SplitRaw(loc.Region.GetID(), newRegionID, []byte(splitKey), []uint64{peerID}, peerID) return nil } func (s *testRawKVSuite) TestSimple() { s.mustNotExist([]byte("key")) s.mustPut([]byte("key"), []byte("value")) s.mustGet([]byte("key"), []byte("value")) s.mustDelete([]byte("key")) s.mustNotExist([]byte("key")) err := s.client.Put(context.Background(), []byte("key"), []byte("")) s.Nil(err) // empty value is legal } func (s *testRawKVSuite) TestRawBatch() { testNum := 0 size := 0 var testKeys [][]byte var testValues [][]byte for i := 0; size/(rawkv.ConfigProbe{}.GetRawBatchPutSize()) < 4; i++ { key := fmt.Sprint("key", i) size += len(key) testKeys = append(testKeys, []byte(key)) value := fmt.Sprint("value", i) size += len(value) testValues = append(testValues, []byte(value)) s.mustNotExist([]byte(key)) testNum = i } err := s.split("", fmt.Sprint("key", testNum/2)) s.Nil(err) s.mustBatchPut(testKeys, testValues) s.mustBatchGet(testKeys, testValues) s.mustBatchDelete(testKeys) s.mustBatchNotExist(testKeys) } func (s *testRawKVSuite) TestSplit() { s.mustPut([]byte("k1"), []byte("v1")) s.mustPut([]byte("k3"), []byte("v3")) err := s.split("k", "k2") s.Nil(err) s.mustGet([]byte("k1"), []byte("v1")) s.mustGet([]byte("k3"), []byte("v3")) } func (s *testRawKVSuite) TestScan() { s.mustPut([]byte("k1"), []byte("v1")) s.mustPut([]byte("k3"), []byte("v3")) s.mustPut([]byte("k5"), []byte("v5")) s.mustPut([]byte("k7"), []byte("v7")) check := func() { s.mustScan("", 1, "k1", "v1") s.mustScan("k1", 2, "k1", "v1", "k3", "v3") s.mustScan("", 10, "k1", "v1", "k3", "v3", "k5", "v5", "k7", "v7") s.mustScan("k2", 2, "k3", "v3", "k5", "v5") s.mustScan("k2", 3, "k3", "v3", "k5", "v5", "k7", "v7") s.mustScanRange("", "k1", 1) s.mustScanRange("k1", "k3", 2, "k1", "v1") s.mustScanRange("k1", "k5", 10, "k1", "v1", "k3", "v3") s.mustScanRange("k1", "k5\x00", 10, "k1", "v1", "k3", "v3", "k5", "v5") s.mustScanRange("k5\x00", "k5\x00\x00", 10) } check() err := s.split("k", "k2") s.Nil(err) check() err = s.split("k2", "k5") s.Nil(err) check() } func (s *testRawKVSuite) TestReverseScan() { s.mustPut([]byte("k1"), []byte("v1")) s.mustPut([]byte("k3"), []byte("v3")) s.mustPut([]byte("k5"), []byte("v5")) s.mustPut([]byte("k7"), []byte("v7")) s.checkReverseScan() err := s.split("k", "k2") s.Nil(err) s.checkReverseScan() err = s.split("k2", "k5") s.Nil(err) s.checkReverseScan() } func (s *testRawKVSuite) checkReverseScan() { s.mustReverseScan([]byte(""), 10) s.mustReverseScan([]byte("z"), 1, "k7", "v7") s.mustReverseScan([]byte("z"), 2, "k7", "v7", "k5", "v5") s.mustReverseScan([]byte("z"), 10, "k7", "v7", "k5", "v5", "k3", "v3", "k1", "v1") s.mustReverseScan([]byte("k2"), 10, "k1", "v1") s.mustReverseScan([]byte("k6"), 2, "k5", "v5", "k3", "v3") s.mustReverseScan([]byte("k5"), 1, "k3", "v3") s.mustReverseScan(append([]byte("k5"), 0), 1, "k5", "v5") s.mustReverseScan([]byte("k6"), 3, "k5", "v5", "k3", "v3", "k1", "v1") s.mustReverseScanRange([]byte("z"), []byte("k3"), 10, "k7", "v7", "k5", "v5", "k3", "v3") s.mustReverseScanRange([]byte("k7"), append([]byte("k3"), 0), 10, "k5", "v5") } func (s *testRawKVSuite) TestDeleteRange() { // Init data testData := map[string]string{} for _, i := range []byte("abcd") { for j := byte('0'); j <= byte('9'); j++ { key := []byte{i, j} value := []byte{'v', i, j} s.mustPut(key, value) testData[string(key)] = string(value) } } err := s.split("b", "b") s.Nil(err) err = s.split("c", "c") s.Nil(err) err = s.split("d", "d") s.Nil(err) s.checkData(testData) s.mustDeleteRange([]byte("b"), []byte("c0"), testData) s.mustDeleteRange([]byte("c11"), []byte("c12"), testData) s.mustDeleteRange([]byte("d0"), []byte("d0"), testData) s.mustDeleteRange([]byte("c5"), []byte("d5"), testData) s.mustDeleteRange([]byte("a"), []byte("z"), testData) }