github.com/ecodeclub/eorm@v0.0.2-0.20231001112437-dae71da914d0/internal/datasource/transaction/transaction_suite_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  	"fmt"
    21  	"testing"
    22  
    23  	"github.com/DATA-DOG/go-sqlmock"
    24  	"github.com/ecodeclub/eorm"
    25  	"github.com/ecodeclub/eorm/internal/datasource"
    26  	"github.com/ecodeclub/eorm/internal/datasource/cluster"
    27  	"github.com/ecodeclub/eorm/internal/datasource/masterslave"
    28  	"github.com/ecodeclub/eorm/internal/datasource/masterslave/slaves"
    29  	"github.com/ecodeclub/eorm/internal/datasource/masterslave/slaves/roundrobin"
    30  	"github.com/ecodeclub/eorm/internal/datasource/shardingsource"
    31  	"github.com/ecodeclub/eorm/internal/model"
    32  	"github.com/ecodeclub/eorm/internal/sharding"
    33  	"github.com/ecodeclub/eorm/internal/sharding/hash"
    34  	"github.com/ecodeclub/eorm/internal/test"
    35  	"github.com/stretchr/testify/require"
    36  	"github.com/stretchr/testify/suite"
    37  )
    38  
    39  type ShardingTransactionSuite struct {
    40  	shardingKey string
    41  	shardingDB  *eorm.DB
    42  	algorithm   sharding.Algorithm
    43  
    44  	suite.Suite
    45  	datasource.DataSource
    46  	clusterDB     datasource.DataSource
    47  	mockMaster1DB *sql.DB
    48  	mockMaster    sqlmock.Sqlmock
    49  
    50  	mockSlave1DB *sql.DB
    51  	mockSlave1   sqlmock.Sqlmock
    52  
    53  	mockSlave2DB *sql.DB
    54  	mockSlave2   sqlmock.Sqlmock
    55  
    56  	mockSlave3DB *sql.DB
    57  	mockSlave3   sqlmock.Sqlmock
    58  
    59  	mockMaster2DB *sql.DB
    60  	mockMaster2   sqlmock.Sqlmock
    61  
    62  	mockSlave4DB *sql.DB
    63  	mockSlave4   sqlmock.Sqlmock
    64  
    65  	mockSlave5DB *sql.DB
    66  	mockSlave5   sqlmock.Sqlmock
    67  
    68  	mockSlave6DB *sql.DB
    69  	mockSlave6   sqlmock.Sqlmock
    70  }
    71  
    72  func (s *ShardingTransactionSuite) SetupTest() {
    73  	t := s.T()
    74  	s.initMock(t)
    75  }
    76  
    77  func (s *ShardingTransactionSuite) initMock(t *testing.T) {
    78  	var err error
    79  	s.mockMaster1DB, s.mockMaster, err = sqlmock.New()
    80  	if err != nil {
    81  		t.Fatal(err)
    82  	}
    83  	s.mockSlave1DB, s.mockSlave1, err = sqlmock.New()
    84  	if err != nil {
    85  		t.Fatal(err)
    86  	}
    87  	s.mockSlave2DB, s.mockSlave2, err = sqlmock.New()
    88  	if err != nil {
    89  		t.Fatal(err)
    90  	}
    91  	s.mockSlave3DB, s.mockSlave3, err = sqlmock.New()
    92  	if err != nil {
    93  		t.Fatal(err)
    94  	}
    95  
    96  	s.mockMaster2DB, s.mockMaster2, err = sqlmock.New()
    97  	if err != nil {
    98  		t.Fatal(err)
    99  	}
   100  	s.mockSlave4DB, s.mockSlave4, err = sqlmock.New()
   101  	if err != nil {
   102  		t.Fatal(err)
   103  	}
   104  	s.mockSlave5DB, s.mockSlave5, err = sqlmock.New()
   105  	if err != nil {
   106  		t.Fatal(err)
   107  	}
   108  	s.mockSlave6DB, s.mockSlave6, err = sqlmock.New()
   109  	if err != nil {
   110  		t.Fatal(err)
   111  	}
   112  
   113  	db1 := masterslave.NewMasterSlavesDB(s.mockMaster1DB, masterslave.MasterSlavesWithSlaves(
   114  		newSlaves(t, s.mockSlave1DB, s.mockSlave2DB, s.mockSlave3DB)))
   115  
   116  	db2 := masterslave.NewMasterSlavesDB(s.mockMaster2DB, masterslave.MasterSlavesWithSlaves(
   117  		newSlaves(t, s.mockSlave4DB, s.mockSlave5DB, s.mockSlave6DB)))
   118  
   119  	s.clusterDB = cluster.NewClusterDB(map[string]*masterslave.MasterSlavesDB{
   120  		"order_detail_db_0": db1,
   121  		"order_detail_db_1": db2,
   122  	})
   123  
   124  	s.DataSource = shardingsource.NewShardingDataSource(map[string]datasource.DataSource{
   125  		"0.db.cluster.company.com:3306": s.clusterDB,
   126  	})
   127  
   128  	r := model.NewMetaRegistry()
   129  	sk := "OrderId"
   130  	s.algorithm = &hash.Hash{
   131  		ShardingKey:  sk,
   132  		DBPattern:    &hash.Pattern{Name: "order_detail_db_%d", Base: 2},
   133  		TablePattern: &hash.Pattern{Name: "order_detail_tab_%d", Base: 3},
   134  		DsPattern:    &hash.Pattern{Name: "0.db.cluster.company.com:3306", NotSharding: true},
   135  	}
   136  	s.shardingKey = sk
   137  	_, err = r.Register(&test.OrderDetail{},
   138  		model.WithTableShardingAlgorithm(s.algorithm))
   139  	require.NoError(t, err)
   140  	db, err := eorm.OpenDS("mysql", s.DataSource, eorm.DBWithMetaRegistry(r))
   141  	require.NoError(t, err)
   142  	s.shardingDB = db
   143  }
   144  
   145  func (s *ShardingTransactionSuite) TearDownTest() {
   146  	_ = s.mockMaster1DB.Close()
   147  	_ = s.mockSlave1DB.Close()
   148  	_ = s.mockSlave2DB.Close()
   149  	_ = s.mockSlave3DB.Close()
   150  
   151  	_ = s.mockMaster2DB.Close()
   152  	_ = s.mockSlave4DB.Close()
   153  	_ = s.mockSlave5DB.Close()
   154  	_ = s.mockSlave6DB.Close()
   155  }
   156  
   157  func (s *ShardingTransactionSuite) findTgt(t *testing.T, values []*test.OrderDetail) []*test.OrderDetail {
   158  	od := values[0]
   159  	pre := eorm.C(s.shardingKey).EQ(od.OrderId)
   160  	for i := 1; i < len(values); i++ {
   161  		od = values[i]
   162  		pre = pre.Or(eorm.C(s.shardingKey).EQ(od.OrderId))
   163  	}
   164  	querySet, err := eorm.NewShardingSelector[test.OrderDetail](s.shardingDB).
   165  		Where(pre).GetMulti(masterslave.UseMaster(context.Background()))
   166  	require.NoError(t, err)
   167  	return querySet
   168  }
   169  
   170  func newShardingTransactionSuite() ShardingTransactionSuite {
   171  	return ShardingTransactionSuite{}
   172  }
   173  
   174  func newSlaves(t *testing.T, dbs ...*sql.DB) slaves.Slaves {
   175  	res, err := roundrobin.NewSlaves(dbs...)
   176  	require.NoError(t, err)
   177  	return res
   178  }
   179  
   180  func newMockCommitErr(dbName string, err error) error {
   181  	return fmt.Errorf("masterslave DB name [%s] Commit error: %w", dbName, err)
   182  }
   183  
   184  func newMockRollbackErr(dbName string, err error) error {
   185  	return fmt.Errorf("masterslave DB name [%s] Rollback error: %w", dbName, err)
   186  }