github.com/pingcap/tidb-lightning@v5.0.0-rc.0.20210428090220-84b649866577+incompatible/lightning/backend/importer_test.go (about)

     1  // Copyright 2019 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package backend_test
    15  
    16  import (
    17  	"context"
    18  	"sync"
    19  	"testing"
    20  
    21  	"github.com/golang/mock/gomock"
    22  	"github.com/google/uuid"
    23  	. "github.com/pingcap/check"
    24  	"github.com/pingcap/errors"
    25  	"github.com/pingcap/kvproto/pkg/import_kvpb"
    26  
    27  	kvpb "github.com/pingcap/kvproto/pkg/import_kvpb"
    28  
    29  	kv "github.com/pingcap/tidb-lightning/lightning/backend"
    30  	"github.com/pingcap/tidb-lightning/lightning/common"
    31  	"github.com/pingcap/tidb-lightning/mock"
    32  )
    33  
    34  type importerSuite struct {
    35  	controller *gomock.Controller
    36  	mockClient *mock.MockImportKVClient
    37  	mockWriter *mock.MockImportKV_WriteEngineClient
    38  	ctx        context.Context
    39  	engineUUID []byte
    40  	engine     *kv.OpenedEngine
    41  	kvPairs    kv.Rows
    42  }
    43  
    44  var _ = Suite(&importerSuite{})
    45  
    46  const testPDAddr = "pd-addr:2379"
    47  
    48  // FIXME: Cannot use the real SetUpTest/TearDownTest to set up the mock
    49  // otherwise the mock error will be ignored.
    50  
    51  func (s *importerSuite) setUpTest(c *C) {
    52  	s.controller = gomock.NewController(c)
    53  	s.mockClient = mock.NewMockImportKVClient(s.controller)
    54  	s.mockWriter = mock.NewMockImportKV_WriteEngineClient(s.controller)
    55  	importer := kv.NewMockImporter(s.mockClient, testPDAddr)
    56  
    57  	s.ctx = context.Background()
    58  	engineUUID := uuid.MustParse("7e3f3a3c-67ce-506d-af34-417ec138fbcb")
    59  	s.engineUUID = engineUUID[:]
    60  	s.kvPairs = kv.MakeRowsFromKvPairs([]common.KvPair{
    61  		{
    62  			Key: []byte("k1"),
    63  			Val: []byte("v1"),
    64  		},
    65  		{
    66  			Key: []byte("k2"),
    67  			Val: []byte("v2"),
    68  		},
    69  	})
    70  
    71  	s.mockClient.EXPECT().
    72  		OpenEngine(s.ctx, &import_kvpb.OpenEngineRequest{Uuid: s.engineUUID}).
    73  		Return(nil, nil)
    74  
    75  	var err error
    76  	s.engine, err = importer.OpenEngine(s.ctx, "`db`.`table`", -1)
    77  	c.Assert(err, IsNil)
    78  }
    79  
    80  func (s *importerSuite) tearDownTest() {
    81  	s.controller.Finish()
    82  }
    83  
    84  func (s *importerSuite) TestWriteRows(c *C) {
    85  	s.setUpTest(c)
    86  	defer s.tearDownTest()
    87  
    88  	s.mockClient.EXPECT().WriteEngine(s.ctx).Return(s.mockWriter, nil)
    89  
    90  	headSendCall := s.mockWriter.EXPECT().
    91  		Send(&import_kvpb.WriteEngineRequest{
    92  			Chunk: &import_kvpb.WriteEngineRequest_Head{
    93  				Head: &import_kvpb.WriteHead{Uuid: s.engineUUID},
    94  			},
    95  		}).
    96  		Return(nil)
    97  	batchSendCall := s.mockWriter.EXPECT().
    98  		Send(gomock.Any()).
    99  		DoAndReturn(func(x *import_kvpb.WriteEngineRequest) error {
   100  			c.Assert(x.GetBatch().GetMutations(), DeepEquals, []*import_kvpb.Mutation{
   101  				{Op: import_kvpb.Mutation_Put, Key: []byte("k1"), Value: []byte("v1")},
   102  				{Op: import_kvpb.Mutation_Put, Key: []byte("k2"), Value: []byte("v2")},
   103  			})
   104  			return nil
   105  		}).
   106  		After(headSendCall)
   107  	s.mockWriter.EXPECT().
   108  		CloseAndRecv().
   109  		Return(nil, nil).
   110  		After(batchSendCall)
   111  
   112  	err := s.engine.WriteRows(s.ctx, nil, s.kvPairs)
   113  	c.Assert(err, IsNil)
   114  }
   115  
   116  func (s *importerSuite) TestWriteHeadSendFailed(c *C) {
   117  	s.setUpTest(c)
   118  	defer s.tearDownTest()
   119  
   120  	s.mockClient.EXPECT().WriteEngine(s.ctx).Return(s.mockWriter, nil)
   121  
   122  	headSendCall := s.mockWriter.EXPECT().
   123  		Send(gomock.Any()).
   124  		DoAndReturn(func(x *import_kvpb.WriteEngineRequest) error {
   125  			c.Assert(x.GetHead(), NotNil)
   126  			return errors.Annotate(context.Canceled, "fake unrecoverable write head error")
   127  		})
   128  	s.mockWriter.EXPECT().
   129  		CloseAndRecv().
   130  		Return(nil, errors.Annotate(context.Canceled, "fake unrecoverable close stream error")).
   131  		After(headSendCall)
   132  
   133  	err := s.engine.WriteRows(s.ctx, nil, s.kvPairs)
   134  	c.Assert(err, ErrorMatches, "fake unrecoverable write head error.*")
   135  }
   136  
   137  func (s *importerSuite) TestWriteBatchSendFailed(c *C) {
   138  	s.setUpTest(c)
   139  	defer s.tearDownTest()
   140  
   141  	s.mockClient.EXPECT().WriteEngine(s.ctx).Return(s.mockWriter, nil)
   142  
   143  	headSendCall := s.mockWriter.EXPECT().
   144  		Send(gomock.Any()).
   145  		DoAndReturn(func(x *import_kvpb.WriteEngineRequest) error {
   146  			c.Assert(x.GetHead(), NotNil)
   147  			return nil
   148  		})
   149  	batchSendCall := s.mockWriter.EXPECT().
   150  		Send(gomock.Any()).
   151  		DoAndReturn(func(x *import_kvpb.WriteEngineRequest) error {
   152  			c.Assert(x.GetBatch(), NotNil)
   153  			return errors.Annotate(context.Canceled, "fake unrecoverable write batch error")
   154  		}).
   155  		After(headSendCall)
   156  	s.mockWriter.EXPECT().
   157  		CloseAndRecv().
   158  		Return(nil, errors.Annotate(context.Canceled, "fake unrecoverable close stream error")).
   159  		After(batchSendCall)
   160  
   161  	err := s.engine.WriteRows(s.ctx, nil, s.kvPairs)
   162  	c.Assert(err, ErrorMatches, "fake unrecoverable write batch error.*")
   163  }
   164  
   165  func (s *importerSuite) TestWriteCloseFailed(c *C) {
   166  	s.setUpTest(c)
   167  	defer s.tearDownTest()
   168  
   169  	s.mockClient.EXPECT().WriteEngine(s.ctx).Return(s.mockWriter, nil)
   170  
   171  	headSendCall := s.mockWriter.EXPECT().
   172  		Send(gomock.Any()).
   173  		DoAndReturn(func(x *import_kvpb.WriteEngineRequest) error {
   174  			c.Assert(x.GetHead(), NotNil)
   175  			return nil
   176  		})
   177  	batchSendCall := s.mockWriter.EXPECT().
   178  		Send(gomock.Any()).
   179  		DoAndReturn(func(x *import_kvpb.WriteEngineRequest) error {
   180  			c.Assert(x.GetBatch(), NotNil)
   181  			return nil
   182  		}).
   183  		After(headSendCall)
   184  	s.mockWriter.EXPECT().
   185  		CloseAndRecv().
   186  		Return(nil, errors.Annotate(context.Canceled, "fake unrecoverable close stream error")).
   187  		After(batchSendCall)
   188  
   189  	err := s.engine.WriteRows(s.ctx, nil, s.kvPairs)
   190  	c.Assert(err, ErrorMatches, "fake unrecoverable close stream error.*")
   191  }
   192  
   193  func (s *importerSuite) TestCloseImportCleanupEngine(c *C) {
   194  	s.setUpTest(c)
   195  	defer s.tearDownTest()
   196  
   197  	s.mockClient.EXPECT().
   198  		CloseEngine(s.ctx, &import_kvpb.CloseEngineRequest{Uuid: s.engineUUID}).
   199  		Return(nil, nil)
   200  	s.mockClient.EXPECT().
   201  		ImportEngine(s.ctx, &import_kvpb.ImportEngineRequest{Uuid: s.engineUUID, PdAddr: testPDAddr}).
   202  		Return(nil, nil)
   203  	s.mockClient.EXPECT().
   204  		CleanupEngine(s.ctx, &import_kvpb.CleanupEngineRequest{Uuid: s.engineUUID}).
   205  		Return(nil, nil)
   206  
   207  	engine, err := s.engine.Close(s.ctx)
   208  	c.Assert(err, IsNil)
   209  	err = engine.Import(s.ctx)
   210  	c.Assert(err, IsNil)
   211  	err = engine.Cleanup(s.ctx)
   212  	c.Assert(err, IsNil)
   213  }
   214  
   215  func BenchmarkMutationAlloc(b *testing.B) {
   216  	var g *kvpb.Mutation
   217  	for i := 0; i < b.N; i++ {
   218  		m := &kvpb.Mutation{
   219  			Op:    kvpb.Mutation_Put,
   220  			Key:   nil,
   221  			Value: nil,
   222  		}
   223  		g = m
   224  	}
   225  
   226  	var _ = g
   227  }
   228  
   229  func BenchmarkMutationPool(b *testing.B) {
   230  	p := sync.Pool{
   231  		New: func() interface{} {
   232  			return &kvpb.Mutation{}
   233  		},
   234  	}
   235  	var g *kvpb.Mutation
   236  
   237  	for i := 0; i < b.N; i++ {
   238  		m := p.Get().(*kvpb.Mutation)
   239  		m.Op = kvpb.Mutation_Put
   240  		m.Key = nil
   241  		m.Value = nil
   242  
   243  		g = m
   244  
   245  		p.Put(m)
   246  	}
   247  
   248  	var _ = g
   249  }