github.com/pingcap/br@v5.3.0-alpha.0.20220125034240-ec59c7b6ce30+incompatible/pkg/lightning/backend/importer/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 importer
    15  
    16  import (
    17  	"context"
    18  	"encoding/json"
    19  	"net/http"
    20  	"net/http/httptest"
    21  	"sync"
    22  	"testing"
    23  
    24  	"github.com/golang/mock/gomock"
    25  	"github.com/google/uuid"
    26  	. "github.com/pingcap/check"
    27  	"github.com/pingcap/errors"
    28  	kvpb "github.com/pingcap/kvproto/pkg/import_kvpb"
    29  
    30  	"github.com/pingcap/br/pkg/lightning/backend"
    31  	"github.com/pingcap/br/pkg/lightning/backend/kv"
    32  	"github.com/pingcap/br/pkg/lightning/common"
    33  	"github.com/pingcap/br/pkg/mock"
    34  )
    35  
    36  type importerSuite struct {
    37  	controller *gomock.Controller
    38  	mockClient *mock.MockImportKVClient
    39  	mockWriter *mock.MockImportKV_WriteEngineClient
    40  	ctx        context.Context
    41  	engineUUID []byte
    42  	engine     *backend.OpenedEngine
    43  	kvPairs    kv.Rows
    44  }
    45  
    46  var _ = Suite(&importerSuite{})
    47  
    48  const testPDAddr = "pd-addr:2379"
    49  
    50  // FIXME: Cannot use the real SetUpTest/TearDownTest to set up the mock
    51  // otherwise the mock error will be ignored.
    52  
    53  func (s *importerSuite) setUpTest(c *C) {
    54  	s.controller = gomock.NewController(c)
    55  	s.mockClient = mock.NewMockImportKVClient(s.controller)
    56  	s.mockWriter = mock.NewMockImportKV_WriteEngineClient(s.controller)
    57  	importer := NewMockImporter(s.mockClient, testPDAddr)
    58  
    59  	s.ctx = context.Background()
    60  	engineUUID := uuid.MustParse("7e3f3a3c-67ce-506d-af34-417ec138fbcb")
    61  	s.engineUUID = engineUUID[:]
    62  	s.kvPairs = kv.MakeRowsFromKvPairs([]common.KvPair{
    63  		{
    64  			Key: []byte("k1"),
    65  			Val: []byte("v1"),
    66  		},
    67  		{
    68  			Key: []byte("k2"),
    69  			Val: []byte("v2"),
    70  		},
    71  	})
    72  
    73  	s.mockClient.EXPECT().
    74  		OpenEngine(s.ctx, &kvpb.OpenEngineRequest{Uuid: s.engineUUID}).
    75  		Return(nil, nil)
    76  
    77  	var err error
    78  	s.engine, err = importer.OpenEngine(s.ctx, &backend.EngineConfig{}, "`db`.`table`", -1)
    79  	c.Assert(err, IsNil)
    80  }
    81  
    82  func (s *importerSuite) tearDownTest() {
    83  	s.controller.Finish()
    84  }
    85  
    86  func (s *importerSuite) TestWriteRows(c *C) {
    87  	s.setUpTest(c)
    88  	defer s.tearDownTest()
    89  
    90  	s.mockClient.EXPECT().WriteEngine(s.ctx).Return(s.mockWriter, nil)
    91  
    92  	headSendCall := s.mockWriter.EXPECT().
    93  		Send(&kvpb.WriteEngineRequest{
    94  			Chunk: &kvpb.WriteEngineRequest_Head{
    95  				Head: &kvpb.WriteHead{Uuid: s.engineUUID},
    96  			},
    97  		}).
    98  		Return(nil)
    99  	batchSendCall := s.mockWriter.EXPECT().
   100  		Send(gomock.Any()).
   101  		DoAndReturn(func(x *kvpb.WriteEngineRequest) error {
   102  			c.Assert(x.GetBatch().GetMutations(), DeepEquals, []*kvpb.Mutation{
   103  				{Op: kvpb.Mutation_Put, Key: []byte("k1"), Value: []byte("v1")},
   104  				{Op: kvpb.Mutation_Put, Key: []byte("k2"), Value: []byte("v2")},
   105  			})
   106  			return nil
   107  		}).
   108  		After(headSendCall)
   109  	s.mockWriter.EXPECT().
   110  		CloseAndRecv().
   111  		Return(nil, nil).
   112  		After(batchSendCall)
   113  
   114  	writer, err := s.engine.LocalWriter(s.ctx, nil)
   115  	c.Assert(err, IsNil)
   116  	err = writer.WriteRows(s.ctx, nil, s.kvPairs)
   117  	c.Assert(err, IsNil)
   118  	st, err := writer.Close(s.ctx)
   119  	c.Assert(err, IsNil)
   120  	c.Assert(st, IsNil)
   121  }
   122  
   123  func (s *importerSuite) TestWriteHeadSendFailed(c *C) {
   124  	s.setUpTest(c)
   125  	defer s.tearDownTest()
   126  
   127  	s.mockClient.EXPECT().WriteEngine(s.ctx).Return(s.mockWriter, nil)
   128  
   129  	headSendCall := s.mockWriter.EXPECT().
   130  		Send(gomock.Any()).
   131  		DoAndReturn(func(x *kvpb.WriteEngineRequest) error {
   132  			c.Assert(x.GetHead(), NotNil)
   133  			return errors.Annotate(context.Canceled, "fake unrecoverable write head error")
   134  		})
   135  	s.mockWriter.EXPECT().
   136  		CloseAndRecv().
   137  		Return(nil, errors.Annotate(context.Canceled, "fake unrecoverable close stream error")).
   138  		After(headSendCall)
   139  
   140  	writer, err := s.engine.LocalWriter(s.ctx, nil)
   141  	c.Assert(err, IsNil)
   142  	err = writer.WriteRows(s.ctx, nil, s.kvPairs)
   143  	c.Assert(err, ErrorMatches, "fake unrecoverable write head error.*")
   144  }
   145  
   146  func (s *importerSuite) TestWriteBatchSendFailed(c *C) {
   147  	s.setUpTest(c)
   148  	defer s.tearDownTest()
   149  
   150  	s.mockClient.EXPECT().WriteEngine(s.ctx).Return(s.mockWriter, nil)
   151  
   152  	headSendCall := s.mockWriter.EXPECT().
   153  		Send(gomock.Any()).
   154  		DoAndReturn(func(x *kvpb.WriteEngineRequest) error {
   155  			c.Assert(x.GetHead(), NotNil)
   156  			return nil
   157  		})
   158  	batchSendCall := s.mockWriter.EXPECT().
   159  		Send(gomock.Any()).
   160  		DoAndReturn(func(x *kvpb.WriteEngineRequest) error {
   161  			c.Assert(x.GetBatch(), NotNil)
   162  			return errors.Annotate(context.Canceled, "fake unrecoverable write batch error")
   163  		}).
   164  		After(headSendCall)
   165  	s.mockWriter.EXPECT().
   166  		CloseAndRecv().
   167  		Return(nil, errors.Annotate(context.Canceled, "fake unrecoverable close stream error")).
   168  		After(batchSendCall)
   169  
   170  	writer, err := s.engine.LocalWriter(s.ctx, nil)
   171  	c.Assert(err, IsNil)
   172  	err = writer.WriteRows(s.ctx, nil, s.kvPairs)
   173  	c.Assert(err, ErrorMatches, "fake unrecoverable write batch error.*")
   174  }
   175  
   176  func (s *importerSuite) TestWriteCloseFailed(c *C) {
   177  	s.setUpTest(c)
   178  	defer s.tearDownTest()
   179  
   180  	s.mockClient.EXPECT().WriteEngine(s.ctx).Return(s.mockWriter, nil)
   181  
   182  	headSendCall := s.mockWriter.EXPECT().
   183  		Send(gomock.Any()).
   184  		DoAndReturn(func(x *kvpb.WriteEngineRequest) error {
   185  			c.Assert(x.GetHead(), NotNil)
   186  			return nil
   187  		})
   188  	batchSendCall := s.mockWriter.EXPECT().
   189  		Send(gomock.Any()).
   190  		DoAndReturn(func(x *kvpb.WriteEngineRequest) error {
   191  			c.Assert(x.GetBatch(), NotNil)
   192  			return nil
   193  		}).
   194  		After(headSendCall)
   195  	s.mockWriter.EXPECT().
   196  		CloseAndRecv().
   197  		Return(nil, errors.Annotate(context.Canceled, "fake unrecoverable close stream error")).
   198  		After(batchSendCall)
   199  
   200  	writer, err := s.engine.LocalWriter(s.ctx, nil)
   201  	c.Assert(err, IsNil)
   202  	err = writer.WriteRows(s.ctx, nil, s.kvPairs)
   203  	c.Assert(err, ErrorMatches, "fake unrecoverable close stream error.*")
   204  }
   205  
   206  func (s *importerSuite) TestCloseImportCleanupEngine(c *C) {
   207  	s.setUpTest(c)
   208  	defer s.tearDownTest()
   209  
   210  	s.mockClient.EXPECT().
   211  		CloseEngine(s.ctx, &kvpb.CloseEngineRequest{Uuid: s.engineUUID}).
   212  		Return(nil, nil)
   213  	s.mockClient.EXPECT().
   214  		ImportEngine(s.ctx, &kvpb.ImportEngineRequest{Uuid: s.engineUUID, PdAddr: testPDAddr}).
   215  		Return(nil, nil)
   216  	s.mockClient.EXPECT().
   217  		CleanupEngine(s.ctx, &kvpb.CleanupEngineRequest{Uuid: s.engineUUID}).
   218  		Return(nil, nil)
   219  
   220  	engine, err := s.engine.Close(s.ctx, nil)
   221  	c.Assert(err, IsNil)
   222  	err = engine.Import(s.ctx)
   223  	c.Assert(err, IsNil)
   224  	err = engine.Cleanup(s.ctx)
   225  	c.Assert(err, IsNil)
   226  }
   227  
   228  func BenchmarkMutationAlloc(b *testing.B) {
   229  	var g *kvpb.Mutation
   230  	for i := 0; i < b.N; i++ {
   231  		m := &kvpb.Mutation{
   232  			Op:    kvpb.Mutation_Put,
   233  			Key:   nil,
   234  			Value: nil,
   235  		}
   236  		g = m
   237  	}
   238  
   239  	_ = g
   240  }
   241  
   242  func BenchmarkMutationPool(b *testing.B) {
   243  	p := sync.Pool{
   244  		New: func() interface{} {
   245  			return &kvpb.Mutation{}
   246  		},
   247  	}
   248  	var g *kvpb.Mutation
   249  
   250  	for i := 0; i < b.N; i++ {
   251  		m := p.Get().(*kvpb.Mutation)
   252  		m.Op = kvpb.Mutation_Put
   253  		m.Key = nil
   254  		m.Value = nil
   255  
   256  		g = m
   257  
   258  		p.Put(m)
   259  	}
   260  
   261  	_ = g
   262  }
   263  
   264  func (s *importerSuite) TestCheckTiDBVersion(c *C) {
   265  	var version string
   266  	ctx := context.Background()
   267  
   268  	mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
   269  		c.Assert(req.URL.Path, Equals, "/status")
   270  		w.WriteHeader(http.StatusOK)
   271  		err := json.NewEncoder(w).Encode(map[string]interface{}{
   272  			"version": version,
   273  		})
   274  		c.Assert(err, IsNil)
   275  	}))
   276  
   277  	tls := common.NewTLSFromMockServer(mockServer)
   278  
   279  	version = "5.7.25-TiDB-v4.0.0"
   280  	c.Assert(checkTiDBVersionByTLS(ctx, tls, requiredMinTiDBVersion, requiredMaxTiDBVersion), IsNil)
   281  
   282  	version = "5.7.25-TiDB-v9999.0.0"
   283  	c.Assert(checkTiDBVersionByTLS(ctx, tls, requiredMinTiDBVersion, requiredMaxTiDBVersion), ErrorMatches, "TiDB version too new.*")
   284  
   285  	version = "5.7.25-TiDB-v6.0.0"
   286  	c.Assert(checkTiDBVersionByTLS(ctx, tls, requiredMinTiDBVersion, requiredMaxTiDBVersion), ErrorMatches, "TiDB version too new.*")
   287  
   288  	version = "5.7.25-TiDB-v6.0.0-beta"
   289  	c.Assert(checkTiDBVersionByTLS(ctx, tls, requiredMinTiDBVersion, requiredMaxTiDBVersion), ErrorMatches, "TiDB version too new.*")
   290  
   291  	version = "5.7.25-TiDB-v1.0.0"
   292  	c.Assert(checkTiDBVersionByTLS(ctx, tls, requiredMinTiDBVersion, requiredMaxTiDBVersion), ErrorMatches, "TiDB version too old.*")
   293  }