github.com/matrixorigin/matrixone@v0.7.0/pkg/txn/client/client_test.go (about)

     1  // Copyright 2022 Matrix Origin
     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  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package client
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"sync"
    21  	"testing"
    22  
    23  	"github.com/matrixorigin/matrixone/pkg/common/runtime"
    24  	"github.com/matrixorigin/matrixone/pkg/logutil"
    25  	"github.com/matrixorigin/matrixone/pkg/pb/metadata"
    26  	"github.com/matrixorigin/matrixone/pkg/pb/timestamp"
    27  	"github.com/matrixorigin/matrixone/pkg/pb/txn"
    28  	"github.com/matrixorigin/matrixone/pkg/txn/clock"
    29  	"github.com/matrixorigin/matrixone/pkg/txn/rpc"
    30  	"github.com/stretchr/testify/assert"
    31  )
    32  
    33  func TestAdjustClient(t *testing.T) {
    34  	c := &txnClient{rt: runtime.DefaultRuntime()}
    35  	c.adjust()
    36  	assert.NotNil(t, c.generator)
    37  	assert.NotNil(t, c.generator)
    38  	assert.NotNil(t, c.rt)
    39  }
    40  
    41  func TestNewTxn(t *testing.T) {
    42  	rt := runtime.NewRuntime(metadata.ServiceType_CN, "",
    43  		logutil.GetPanicLogger(),
    44  		runtime.WithClock(clock.NewHLCClock(func() int64 {
    45  			return 1
    46  		}, 0)))
    47  	c := NewTxnClient(rt, newTestTxnSender())
    48  	tx, err := c.New()
    49  	assert.Nil(t, err)
    50  	txnMeta := tx.(*txnOperator).mu.txn
    51  	assert.Equal(t, timestamp.Timestamp{PhysicalTime: 1}, txnMeta.SnapshotTS)
    52  	assert.NotEmpty(t, txnMeta.ID)
    53  	assert.Equal(t, txn.TxnStatus_Active, txnMeta.Status)
    54  }
    55  
    56  func TestNewTxnWithSnapshotTS(t *testing.T) {
    57  	rt := runtime.NewRuntime(metadata.ServiceType_CN, "",
    58  		logutil.GetPanicLogger(),
    59  		runtime.WithClock(clock.NewHLCClock(func() int64 {
    60  			return 1
    61  		}, 0)))
    62  	c := NewTxnClient(rt, newTestTxnSender())
    63  	tx, err := c.New(WithSnapshotTS(timestamp.Timestamp{PhysicalTime: 10}))
    64  	assert.Nil(t, err)
    65  	txnMeta := tx.(*txnOperator).mu.txn
    66  	assert.Equal(t, timestamp.Timestamp{PhysicalTime: 10}, txnMeta.SnapshotTS)
    67  	assert.NotEmpty(t, txnMeta.ID)
    68  	assert.Equal(t, txn.TxnStatus_Active, txnMeta.Status)
    69  }
    70  
    71  func newTestTxnSender() *testTxnSender {
    72  	return &testTxnSender{auto: true}
    73  }
    74  
    75  type testTxnSender struct {
    76  	sync.Mutex
    77  	lastRequests []txn.TxnRequest
    78  	auto         bool
    79  	manualFunc   func(*rpc.SendResult, error) (*rpc.SendResult, error)
    80  }
    81  
    82  func (ts *testTxnSender) Close() error {
    83  	return nil
    84  }
    85  
    86  func (ts *testTxnSender) Send(ctx context.Context, requests []txn.TxnRequest) (*rpc.SendResult, error) {
    87  	ts.Lock()
    88  	defer ts.Unlock()
    89  	ts.lastRequests = requests
    90  
    91  	responses := make([]txn.TxnResponse, 0, len(requests))
    92  	for _, req := range requests {
    93  		resp := txn.TxnResponse{
    94  			Txn:    &req.Txn,
    95  			Method: req.Method,
    96  			Flag:   req.Flag,
    97  		}
    98  		switch resp.Method {
    99  		case txn.TxnMethod_Read:
   100  			resp.CNOpResponse = &txn.CNOpResponse{Payload: []byte(fmt.Sprintf("r-%d", req.CNRequest.OpCode))}
   101  		case txn.TxnMethod_Write:
   102  			resp.CNOpResponse = &txn.CNOpResponse{Payload: []byte(fmt.Sprintf("w-%d", req.CNRequest.OpCode))}
   103  		case txn.TxnMethod_DEBUG:
   104  			resp.CNOpResponse = &txn.CNOpResponse{Payload: req.CNRequest.Payload}
   105  		case txn.TxnMethod_Rollback:
   106  			resp.Txn.Status = txn.TxnStatus_Aborted
   107  		case txn.TxnMethod_Commit:
   108  			resp.Txn.Status = txn.TxnStatus_Committed
   109  		}
   110  
   111  		responses = append(responses, resp)
   112  	}
   113  
   114  	result := &rpc.SendResult{Responses: responses}
   115  	if !ts.auto {
   116  		return ts.manualFunc(result, nil)
   117  	}
   118  	return result, nil
   119  }
   120  
   121  func (ts *testTxnSender) setManual(manualFunc func(*rpc.SendResult, error) (*rpc.SendResult, error)) {
   122  	ts.Lock()
   123  	defer ts.Unlock()
   124  	ts.manualFunc = manualFunc
   125  	ts.auto = false
   126  }
   127  
   128  func (ts *testTxnSender) getLastRequests() []txn.TxnRequest {
   129  	ts.Lock()
   130  	defer ts.Unlock()
   131  	return ts.lastRequests
   132  }