github.com/ecodeclub/eorm@v0.0.2-0.20231001112437-dae71da914d0/internal/datasource/transaction/single_transaction_test.go (about)

     1  // Copyright 2021 ecodeclub
     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 transaction_test
    16  
    17  import (
    18  	"context"
    19  	"database/sql"
    20  	"errors"
    21  	"regexp"
    22  	"strings"
    23  	"testing"
    24  
    25  	"github.com/DATA-DOG/go-sqlmock"
    26  	"github.com/ecodeclub/eorm"
    27  	"github.com/ecodeclub/eorm/internal/datasource/masterslave"
    28  	"github.com/ecodeclub/eorm/internal/datasource/transaction"
    29  	"github.com/ecodeclub/eorm/internal/errs"
    30  	"github.com/ecodeclub/eorm/internal/test"
    31  	"github.com/stretchr/testify/assert"
    32  	"github.com/stretchr/testify/require"
    33  	"github.com/stretchr/testify/suite"
    34  )
    35  
    36  type TestSingleTxTestSuite struct {
    37  	ShardingTransactionSuite
    38  }
    39  
    40  func (s *TestSingleTxTestSuite) TestExecute_Commit_Or_Rollback() {
    41  	t := s.T()
    42  	testCases := []struct {
    43  		name         string
    44  		wantAffected int64
    45  		wantErr      error
    46  		shardingVal  int
    47  		values       []*test.OrderDetail
    48  		querySet     []*test.OrderDetail
    49  		tx           *eorm.Tx
    50  		mockOrder    func(mock1, mock2 sqlmock.Sqlmock)
    51  		afterFunc    func(t *testing.T, tx *eorm.Tx, values []*test.OrderDetail)
    52  	}{
    53  		{
    54  			name:         "select insert commit",
    55  			wantAffected: 1,
    56  			shardingVal:  234,
    57  			values: []*test.OrderDetail{
    58  				{OrderId: 288, ItemId: 101, UsingCol1: "Jimmy", UsingCol2: "Butler"},
    59  			},
    60  			querySet: []*test.OrderDetail{
    61  				{OrderId: 234, ItemId: 12, UsingCol1: "Kevin", UsingCol2: "Durant"},
    62  			},
    63  			mockOrder: func(mock1, mock2 sqlmock.Sqlmock) {
    64  				mock1.MatchExpectationsInOrder(false)
    65  				mock1.ExpectBegin()
    66  
    67  				mock1.ExpectQuery(regexp.QuoteMeta("SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_0`.`order_detail_tab_0` WHERE `order_id`=?;")).
    68  					WithArgs(234).
    69  					WillReturnRows(mock1.NewRows([]string{"order_id", "item_id", "using_col1", "using_col2"}).AddRow(234, 12, "Kevin", "Durant"))
    70  
    71  				mock1.ExpectExec(regexp.QuoteMeta("INSERT INTO `order_detail_db_0`.`order_detail_tab_0`(`order_id`,`item_id`,`using_col1`,`using_col2`) VALUES(?,?,?,?);")).
    72  					WithArgs(288, 101, "Jimmy", "Butler").WillReturnResult(sqlmock.NewResult(1, 1))
    73  
    74  				mock1.ExpectCommit()
    75  			},
    76  			tx: func() *eorm.Tx {
    77  				tx, er := s.shardingDB.BeginTx(
    78  					transaction.UsingTxType(context.Background(), transaction.Single), &sql.TxOptions{})
    79  				require.NoError(t, er)
    80  				return tx
    81  			}(),
    82  			afterFunc: func(t *testing.T, tx *eorm.Tx, values []*test.OrderDetail) {
    83  				err := tx.Commit()
    84  				require.NoError(t, err)
    85  
    86  				s.mockMaster.MatchExpectationsInOrder(false)
    87  
    88  				s.mockMaster.ExpectQuery(regexp.QuoteMeta("SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_0`.`order_detail_tab_0` WHERE `order_id`=?;")).
    89  					WithArgs(288).WillReturnRows(s.mockMaster.NewRows([]string{"order_id", "item_id", "using_col1", "using_col2"}).AddRow(288, 101, "Jimmy", "Butler"))
    90  
    91  				queryVal := s.findTgt(t, values)
    92  				assert.ElementsMatch(t, values, queryVal)
    93  			},
    94  		},
    95  		{
    96  			name:         "select insert rollback",
    97  			wantAffected: 1,
    98  			shardingVal:  253,
    99  			values: []*test.OrderDetail{
   100  				{OrderId: 199, ItemId: 100, UsingCol1: "Jason", UsingCol2: "Tatum"},
   101  			},
   102  			querySet: []*test.OrderDetail{
   103  				{OrderId: 253, ItemId: 8, UsingCol1: "Stephen", UsingCol2: "Curry"},
   104  			},
   105  			mockOrder: func(mock1, mock2 sqlmock.Sqlmock) {
   106  				mock2.MatchExpectationsInOrder(false)
   107  				mock2.ExpectBegin()
   108  
   109  				mock2.ExpectQuery(regexp.QuoteMeta("SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_1`.`order_detail_tab_1` WHERE `order_id`=?;")).
   110  					WithArgs(253).
   111  					WillReturnRows(mock1.NewRows([]string{"order_id", "item_id", "using_col1", "using_col2"}).AddRow(253, 8, "Stephen", "Curry"))
   112  
   113  				mock2.ExpectExec(regexp.QuoteMeta("INSERT INTO `order_detail_db_1`.`order_detail_tab_1`(`order_id`,`item_id`,`using_col1`,`using_col2`) VALUES(?,?,?,?);")).
   114  					WithArgs(199, 100, "Jason", "Tatum").WillReturnResult(sqlmock.NewResult(1, 1))
   115  
   116  				mock2.ExpectRollback()
   117  			},
   118  			tx: func() *eorm.Tx {
   119  				tx, er := s.shardingDB.BeginTx(
   120  					transaction.UsingTxType(context.Background(), transaction.Single), &sql.TxOptions{})
   121  				require.NoError(t, er)
   122  				return tx
   123  			}(),
   124  			afterFunc: func(t *testing.T, tx *eorm.Tx, values []*test.OrderDetail) {
   125  				err := tx.Rollback()
   126  				require.NoError(t, err)
   127  
   128  				s.mockMaster2.MatchExpectationsInOrder(false)
   129  				s.mockMaster2.ExpectQuery(regexp.QuoteMeta("SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_1`.`order_detail_tab_1` WHERE `order_id`=?;")).
   130  					WithArgs(199).WillReturnRows(s.mockMaster2.NewRows([]string{"order_id", "item_id", "using_col1", "using_col2"}))
   131  
   132  				queryVal := s.findTgt(t, values)
   133  				var wantOds []*test.OrderDetail
   134  				assert.ElementsMatch(t, wantOds, queryVal)
   135  			},
   136  		},
   137  		{
   138  			name:         "insert use multi db err",
   139  			wantAffected: 2,
   140  			shardingVal:  234,
   141  			wantErr:      errs.NewErrDBNotEqual("order_detail_db_0", "order_detail_db_1"),
   142  			values: []*test.OrderDetail{
   143  				{OrderId: 288, ItemId: 101, UsingCol1: "Jimmy", UsingCol2: "Butler"},
   144  				{OrderId: 33, ItemId: 100, UsingCol1: "Nikolai", UsingCol2: "Jokic"},
   145  			},
   146  			querySet: []*test.OrderDetail{
   147  				{OrderId: 234, ItemId: 12, UsingCol1: "Kevin", UsingCol2: "Durant"},
   148  			},
   149  			mockOrder: func(mock1, mock2 sqlmock.Sqlmock) {
   150  				mock1.MatchExpectationsInOrder(false)
   151  				mock2.MatchExpectationsInOrder(false)
   152  				mock1.ExpectBegin()
   153  				mock2.ExpectBegin()
   154  
   155  				mock1.ExpectQuery(regexp.QuoteMeta("SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_0`.`order_detail_tab_0` WHERE `order_id`=?;")).
   156  					WithArgs(234).
   157  					WillReturnRows(mock1.NewRows([]string{"order_id", "item_id", "using_col1", "using_col2"}).AddRow(234, 12, "Kevin", "Durant"))
   158  
   159  				mock1.ExpectExec(regexp.QuoteMeta("INSERT INTO `order_detail_db_0`.`order_detail_tab_0`(`order_id`,`item_id`,`using_col1`,`using_col2`) VALUES(?,?,?,?);")).
   160  					WithArgs(288, 101, "Jimmy", "Butler").WillReturnResult(sqlmock.NewResult(1, 1))
   161  				mock2.ExpectExec(regexp.QuoteMeta("INSERT INTO `order_detail_db_1`.`order_detail_tab_0`(`order_id`,`item_id`,`using_col1`,`using_col2`) VALUES(?,?,?,?);")).
   162  					WithArgs(33, 100, "Nikolai", "Jokic").WillReturnResult(sqlmock.NewResult(1, 1))
   163  
   164  				commitErr := errors.New("commit fail")
   165  				mock1.ExpectCommit().WillReturnError(commitErr)
   166  				mock2.ExpectCommit().WillReturnError(commitErr)
   167  			},
   168  			tx: func() *eorm.Tx {
   169  				tx, er := s.shardingDB.BeginTx(
   170  					transaction.UsingTxType(context.Background(), transaction.Single), &sql.TxOptions{})
   171  				require.NoError(t, er)
   172  				return tx
   173  			}(),
   174  			afterFunc: func(t *testing.T, tx *eorm.Tx, values []*test.OrderDetail) {
   175  				err := tx.Commit()
   176  				newErr := errors.New("commit fail")
   177  				errSlice := strings.Split(err.Error(), "; ")
   178  				wantErrSlice := []string{
   179  					newMockCommitErr("order_detail_db_0", newErr).Error(),
   180  					newMockCommitErr("order_detail_db_1", newErr).Error()}
   181  				assert.ElementsMatch(t, wantErrSlice, errSlice)
   182  
   183  				s.mockMaster.MatchExpectationsInOrder(false)
   184  				s.mockMaster2.MatchExpectationsInOrder(false)
   185  
   186  				//row1 := s.mockMaster.NewRows([]string{"order_id", "item_id", "using_col1", "using_col2"})
   187  				//row2 := s.mockMaster.NewRows([]string{"order_id", "item_id", "using_col1", "using_col2"})
   188  				//s.mockMaster.ExpectQuery(regexp.QuoteMeta("SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_0`.`order_detail_tab_0` WHERE (`order_id`=?) OR (`order_id`=?);SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_0`.`order_detail_tab_1` WHERE (`order_id`=?) OR (`order_id`=?);SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_0`.`order_detail_tab_2` WHERE (`order_id`=?) OR (`order_id`=?);")).
   189  				//	WithArgs(288, 33, 288, 33, 288, 33).WillReturnRows(row1)
   190  				//
   191  				//s.mockMaster2.ExpectQuery(regexp.QuoteMeta("SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_1`.`order_detail_tab_0` WHERE (`order_id`=?) OR (`order_id`=?);SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_1`.`order_detail_tab_1` WHERE (`order_id`=?) OR (`order_id`=?);SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_1`.`order_detail_tab_2` WHERE (`order_id`=?) OR (`order_id`=?);")).
   192  				//	WithArgs(288, 33, 288, 33, 288, 33).WillReturnRows(row2)
   193  
   194  				row1 := s.mockMaster.NewRows([]string{"order_id", "item_id", "using_col1", "using_col2"})
   195  				row2 := s.mockMaster.NewRows([]string{"order_id", "item_id", "using_col1", "using_col2"})
   196  				s.mockMaster.ExpectQuery(regexp.QuoteMeta("SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_0`.`order_detail_tab_0` WHERE (`order_id`=?) OR (`order_id`=?);")).
   197  					WithArgs(288, 33).WillReturnRows(row1)
   198  
   199  				s.mockMaster2.ExpectQuery(regexp.QuoteMeta("SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_1`.`order_detail_tab_0` WHERE (`order_id`=?) OR (`order_id`=?);")).
   200  					WithArgs(288, 33).WillReturnRows(row2)
   201  
   202  				queryVal := s.findTgt(t, values)
   203  				var wantOds []*test.OrderDetail
   204  				assert.ElementsMatch(t, wantOds, queryVal)
   205  			},
   206  		},
   207  		{
   208  			name:         "select and insert use multi db err",
   209  			wantAffected: 2,
   210  			shardingVal:  234,
   211  			wantErr:      errs.NewErrDBNotEqual("order_detail_db_0", "order_detail_db_1"),
   212  			values: []*test.OrderDetail{
   213  				{OrderId: 33, ItemId: 100, UsingCol1: "Nikolai", UsingCol2: "Jokic"},
   214  			},
   215  			querySet: []*test.OrderDetail{
   216  				{OrderId: 234, ItemId: 12, UsingCol1: "Kevin", UsingCol2: "Durant"},
   217  			},
   218  			mockOrder: func(mock1, mock2 sqlmock.Sqlmock) {
   219  				mock1.MatchExpectationsInOrder(false)
   220  				mock1.ExpectBegin()
   221  
   222  				mock1.ExpectQuery(regexp.QuoteMeta("SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_0`.`order_detail_tab_0` WHERE `order_id`=?;")).
   223  					WithArgs(234).
   224  					WillReturnRows(mock1.NewRows([]string{"order_id", "item_id", "using_col1", "using_col2"}).AddRow(234, 12, "Kevin", "Durant"))
   225  
   226  				mock1.ExpectExec(regexp.QuoteMeta("INSERT INTO `order_detail_db_1`.`order_detail_tab_0`(`order_id`,`item_id`,`using_col1`,`using_col2`) VALUES(?,?,?,?);")).
   227  					WithArgs(33, 100, "Nikolai", "Jokic").WillReturnResult(sqlmock.NewResult(1, 1))
   228  
   229  				mock1.ExpectCommit()
   230  			},
   231  			tx: func() *eorm.Tx {
   232  				tx, er := s.shardingDB.BeginTx(
   233  					transaction.UsingTxType(context.Background(), transaction.Single), &sql.TxOptions{})
   234  				require.NoError(t, er)
   235  				return tx
   236  			}(),
   237  			afterFunc: func(t *testing.T, tx *eorm.Tx, values []*test.OrderDetail) {
   238  				err := tx.Commit()
   239  				newErr := errors.New("commit fail")
   240  				errSlice := strings.Split(err.Error(), "; ")
   241  				wantErrSlice := []string{
   242  					newMockCommitErr("order_detail_db_0", newErr).Error(),
   243  					newMockCommitErr("order_detail_db_1", newErr).Error()}
   244  				assert.ElementsMatch(t, wantErrSlice, errSlice)
   245  
   246  				s.mockMaster.MatchExpectationsInOrder(false)
   247  				s.mockMaster2.MatchExpectationsInOrder(false)
   248  
   249  				row1 := s.mockMaster.NewRows([]string{"order_id", "item_id", "using_col1", "using_col2"})
   250  				row2 := s.mockMaster.NewRows([]string{"order_id", "item_id", "using_col1", "using_col2"})
   251  				//s.mockMaster.ExpectQuery(regexp.QuoteMeta("SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_0`.`order_detail_tab_0` WHERE (`order_id`=?) OR (`order_id`=?);SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_0`.`order_detail_tab_1` WHERE (`order_id`=?) OR (`order_id`=?);SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_0`.`order_detail_tab_2` WHERE (`order_id`=?) OR (`order_id`=?);")).
   252  				//	WithArgs(288, 33, 288, 33, 288, 33).WillReturnRows(row1)
   253  				//
   254  				//s.mockMaster2.ExpectQuery(regexp.QuoteMeta("SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_1`.`order_detail_tab_0` WHERE (`order_id`=?) OR (`order_id`=?);SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_1`.`order_detail_tab_1` WHERE (`order_id`=?) OR (`order_id`=?);SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_1`.`order_detail_tab_2` WHERE (`order_id`=?) OR (`order_id`=?);")).
   255  				//	WithArgs(288, 33, 288, 33, 288, 33).WillReturnRows(row2)
   256  
   257  				s.mockMaster.ExpectQuery(regexp.QuoteMeta("SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_0`.`order_detail_tab_0` WHERE `order_id`=?;")).
   258  					WithArgs(33).WillReturnRows(row1)
   259  
   260  				s.mockMaster2.ExpectQuery(regexp.QuoteMeta("SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_1`.`order_detail_tab_0` WHERE `order_id`=?;")).
   261  					WithArgs(33).WillReturnRows(row2)
   262  
   263  				queryVal := s.findTgt(t, values)
   264  				var wantOds []*test.OrderDetail
   265  				assert.ElementsMatch(t, wantOds, queryVal)
   266  			},
   267  		},
   268  		{
   269  			name:         "select insert commit err",
   270  			wantAffected: 1,
   271  			shardingVal:  234,
   272  			values: []*test.OrderDetail{
   273  				{OrderId: 288, ItemId: 101, UsingCol1: "Jimmy", UsingCol2: "Butler"},
   274  			},
   275  			querySet: []*test.OrderDetail{
   276  				{OrderId: 234, ItemId: 12, UsingCol1: "Kevin", UsingCol2: "Durant"},
   277  			},
   278  			mockOrder: func(mock1, mock2 sqlmock.Sqlmock) {
   279  				mock1.MatchExpectationsInOrder(false)
   280  				mock1.ExpectBegin()
   281  
   282  				mock1.ExpectQuery(regexp.QuoteMeta("SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_0`.`order_detail_tab_0` WHERE `order_id`=?;")).
   283  					WithArgs(234).
   284  					WillReturnRows(mock1.NewRows([]string{"order_id", "item_id", "using_col1", "using_col2"}).AddRow(234, 12, "Kevin", "Durant"))
   285  
   286  				mock1.ExpectExec(regexp.QuoteMeta("INSERT INTO `order_detail_db_0`.`order_detail_tab_0`(`order_id`,`item_id`,`using_col1`,`using_col2`) VALUES(?,?,?,?);")).
   287  					WithArgs(288, 101, "Jimmy", "Butler").WillReturnResult(sqlmock.NewResult(1, 1))
   288  
   289  				mock1.ExpectCommit().WillReturnError(errors.New("commit fail"))
   290  			},
   291  			tx: func() *eorm.Tx {
   292  				tx, er := s.shardingDB.BeginTx(
   293  					transaction.UsingTxType(context.Background(), transaction.Single), &sql.TxOptions{})
   294  				require.NoError(t, er)
   295  				return tx
   296  			}(),
   297  			afterFunc: func(t *testing.T, tx *eorm.Tx, values []*test.OrderDetail) {
   298  				err := tx.Commit()
   299  				wantErr := errors.New("commit fail")
   300  				assert.Equal(t, wantErr, err)
   301  
   302  				s.mockMaster.MatchExpectationsInOrder(false)
   303  				s.mockMaster.ExpectQuery(regexp.QuoteMeta("SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_0`.`order_detail_tab_0` WHERE `order_id`=?;")).
   304  					WithArgs(288).WillReturnRows(s.mockMaster.NewRows([]string{"order_id", "item_id", "using_col1", "using_col2"}))
   305  
   306  				queryVal := s.findTgt(t, values)
   307  				var wantOds []*test.OrderDetail
   308  				assert.ElementsMatch(t, wantOds, queryVal)
   309  			},
   310  		},
   311  		{
   312  			name:         "select insert rollback err",
   313  			wantAffected: 1,
   314  			shardingVal:  253,
   315  			values: []*test.OrderDetail{
   316  				{OrderId: 33, ItemId: 100, UsingCol1: "Nikolai", UsingCol2: "Jokic"},
   317  			},
   318  			querySet: []*test.OrderDetail{
   319  				{OrderId: 253, ItemId: 8, UsingCol1: "Stephen", UsingCol2: "Curry"},
   320  			},
   321  			mockOrder: func(mock1, mock2 sqlmock.Sqlmock) {
   322  				mock2.MatchExpectationsInOrder(false)
   323  				mock2.ExpectBegin()
   324  
   325  				mock2.ExpectQuery(regexp.QuoteMeta("SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_1`.`order_detail_tab_1` WHERE `order_id`=?;")).
   326  					WithArgs(253).
   327  					WillReturnRows(mock1.NewRows([]string{"order_id", "item_id", "using_col1", "using_col2"}).AddRow(253, 8, "Stephen", "Curry"))
   328  
   329  				mock2.ExpectExec(regexp.QuoteMeta("INSERT INTO `order_detail_db_1`.`order_detail_tab_0`(`order_id`,`item_id`,`using_col1`,`using_col2`) VALUES(?,?,?,?);")).
   330  					WithArgs(33, 100, "Nikolai", "Jokic").WillReturnResult(sqlmock.NewResult(1, 1))
   331  
   332  				mock2.ExpectRollback().WillReturnError(errors.New("rollback fail"))
   333  			},
   334  			tx: func() *eorm.Tx {
   335  				tx, er := s.shardingDB.BeginTx(
   336  					transaction.UsingTxType(context.Background(), transaction.Single), &sql.TxOptions{})
   337  				require.NoError(t, er)
   338  				return tx
   339  			}(),
   340  			afterFunc: func(t *testing.T, tx *eorm.Tx, values []*test.OrderDetail) {
   341  				err := tx.Rollback()
   342  				wantErr := errors.New("rollback fail")
   343  				assert.Equal(t, wantErr, err)
   344  
   345  				s.mockMaster2.MatchExpectationsInOrder(false)
   346  
   347  				s.mockMaster2.ExpectQuery(regexp.QuoteMeta("SELECT `order_id`,`item_id`,`using_col1`,`using_col2` FROM `order_detail_db_1`.`order_detail_tab_0` WHERE `order_id`=?")).
   348  					WithArgs(33).WillReturnRows(s.mockMaster2.NewRows([]string{"order_id", "item_id", "using_col1", "using_col2"}))
   349  
   350  				queryVal := s.findTgt(t, values)
   351  				var wantOds []*test.OrderDetail
   352  				assert.ElementsMatch(t, wantOds, queryVal)
   353  			},
   354  		},
   355  	}
   356  	for _, tc := range testCases {
   357  		t.Run(tc.name, func(t *testing.T) {
   358  			tc.mockOrder(s.mockMaster, s.mockMaster2)
   359  			tx := tc.tx
   360  			querySet, err := eorm.NewShardingSelector[test.OrderDetail](tx).
   361  				Where(eorm.C("OrderId").EQ(tc.shardingVal)).
   362  				GetMulti(masterslave.UseMaster(context.Background()))
   363  			require.NoError(t, err)
   364  			assert.ElementsMatch(t, tc.querySet, querySet)
   365  
   366  			values := tc.values
   367  			res := eorm.NewShardingInsert[test.OrderDetail](tx).
   368  				Values(values).Exec(context.Background())
   369  			affected, err := res.RowsAffected()
   370  			assert.Equal(t, tc.wantErr, err)
   371  			if err != nil {
   372  				return
   373  			}
   374  			assert.Equal(t, tc.wantAffected, affected)
   375  			tc.afterFunc(t, tx, values)
   376  		})
   377  	}
   378  }
   379  
   380  func TestSingleTransactionSuite(t *testing.T) {
   381  	suite.Run(t, &TestSingleTxTestSuite{
   382  		ShardingTransactionSuite: newShardingTransactionSuite(),
   383  	})
   384  }