github.com/matrixorigin/matrixone@v1.2.0/pkg/txn/client/testutil.go (about) 1 // Copyright 2023 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 "sync/atomic" 22 23 "github.com/matrixorigin/matrixone/pkg/common/runtime" 24 "github.com/matrixorigin/matrixone/pkg/pb/txn" 25 "github.com/matrixorigin/matrixone/pkg/txn/rpc" 26 ) 27 28 // RunTxnTests runs txn tests. 29 func RunTxnTests(fn func(TxnClient, rpc.TxnSender), opts ...TxnClientCreateOption) { 30 runtime.SetupProcessLevelRuntime(runtime.DefaultRuntime()) 31 ts := newTestTxnSender() 32 c := NewTxnClient(ts, opts...) 33 c.Resume() 34 fn(c, ts) 35 } 36 37 func newTestTxnSender() *testTxnSender { 38 return &testTxnSender{auto: true} 39 } 40 41 type testTxnSender struct { 42 sync.Mutex 43 lastRequests []txn.TxnRequest 44 auto bool 45 manualFunc func(*rpc.SendResult, error) (*rpc.SendResult, error) 46 } 47 48 func (ts *testTxnSender) Close() error { 49 return nil 50 } 51 52 func (ts *testTxnSender) Send(ctx context.Context, requests []txn.TxnRequest) (*rpc.SendResult, error) { 53 ts.Lock() 54 defer ts.Unlock() 55 ts.lastRequests = requests 56 57 responses := make([]txn.TxnResponse, 0, len(requests)) 58 for _, req := range requests { 59 resp := txn.TxnResponse{ 60 Txn: &req.Txn, 61 Method: req.Method, 62 Flag: req.Flag, 63 } 64 switch resp.Method { 65 case txn.TxnMethod_Read: 66 resp.CNOpResponse = &txn.CNOpResponse{Payload: []byte(fmt.Sprintf("r-%d", req.CNRequest.OpCode))} 67 case txn.TxnMethod_Write: 68 resp.CNOpResponse = &txn.CNOpResponse{Payload: []byte(fmt.Sprintf("w-%d", req.CNRequest.OpCode))} 69 case txn.TxnMethod_DEBUG: 70 resp.CNOpResponse = &txn.CNOpResponse{Payload: req.CNRequest.Payload} 71 case txn.TxnMethod_Rollback: 72 resp.Txn.Status = txn.TxnStatus_Aborted 73 case txn.TxnMethod_Commit: 74 resp.Txn.CommitTS = resp.Txn.SnapshotTS.Next() 75 resp.Txn.Status = txn.TxnStatus_Committed 76 } 77 78 responses = append(responses, resp) 79 } 80 81 result := &rpc.SendResult{Responses: responses} 82 if !ts.auto { 83 return ts.manualFunc(result, nil) 84 } 85 return result, nil 86 } 87 88 func (ts *testTxnSender) setManual(manualFunc func(*rpc.SendResult, error) (*rpc.SendResult, error)) { 89 ts.Lock() 90 defer ts.Unlock() 91 ts.manualFunc = manualFunc 92 ts.auto = false 93 } 94 95 func (ts *testTxnSender) getLastRequests() []txn.TxnRequest { 96 ts.Lock() 97 defer ts.Unlock() 98 return ts.lastRequests 99 } 100 101 type counter struct { 102 enter atomic.Uint64 103 exit atomic.Uint64 104 } 105 106 func (count *counter) addEnter() { 107 count.enter.Add(1) 108 } 109 110 func (count *counter) addExit() { 111 count.exit.Add(1) 112 } 113 114 func (count *counter) more() bool { 115 return count.enter.Load() > count.exit.Load() 116 } 117 118 func (count *counter) String() string { 119 return fmt.Sprintf("enter:%d, exit:%d", count.enter.Load(), count.exit.Load()) 120 }