github.com/benz9527/xboot@v0.0.0-20240504061247-c23f15593274/xlog/gorm_test.go (about)

     1  package xlog
     2  
     3  import (
     4  	"context"
     5  	"database/sql"
     6  	"database/sql/driver"
     7  	"errors"
     8  	"testing"
     9  	"time"
    10  
    11  	mock "github.com/DATA-DOG/go-sqlmock"
    12  	"github.com/glebarez/sqlite"
    13  	"github.com/stretchr/testify/require"
    14  	"go.uber.org/zap"
    15  	"go.uber.org/zap/zapcore"
    16  	"gorm.io/gorm"
    17  	glogger "gorm.io/gorm/logger"
    18  )
    19  
    20  func genDBMock(logger glogger.Interface) (*gorm.DB, mock.Sqlmock, error) {
    21  	db, mock, err := mock.New()
    22  	if err != nil {
    23  		return nil, nil, err
    24  	}
    25  	// Mock SQLite3 DB connection, the sqlite version query is essential for go-sqlite driver.
    26  	mock.ExpectQuery(`select sqlite_version()`).
    27  		WithArgs().
    28  		WillReturnRows(mock.NewRows([]string{"sqlite_version()"}).
    29  			AddRow("3.38.0"))
    30  	gdb, err := gorm.Open(sqlite.Dialector{
    31  		DriverName: sqlite.DriverName,
    32  		Conn:       db, // DSN is free. IP, port, username and password is free too.
    33  	}, &gorm.Config{
    34  		Logger: logger,
    35  	})
    36  	if err != nil {
    37  		return nil, nil, err
    38  	}
    39  	// gdb is gorm db connection to the sql mock.
    40  	return gdb, mock, nil
    41  }
    42  
    43  func TestGormXLogger_Sqlite3(t *testing.T) {
    44  	var (
    45  		parentLogger XLogger      = nil
    46  		logger       *GormXLogger = nil
    47  	)
    48  	opts := []XLoggerOption{
    49  		WithXLoggerLevel(LogLevelDebug),
    50  		WithXLoggerEncoder(JSON),
    51  		WithXLoggerTimeEncoder(zapcore.ISO8601TimeEncoder),
    52  		WithXLoggerLevelEncoder(zapcore.CapitalLevelEncoder),
    53  	}
    54  	parentLogger = NewXLogger(opts...)
    55  	logger = NewGormXLogger(parentLogger,
    56  		WithGormXLoggerIgnoreRecord404Err(),
    57  		WithGormXLoggerLogLevel(glogger.Info),
    58  		WithGormXLoggerSlowThreshold(200*time.Millisecond),
    59  	)
    60  
    61  	db, mock, err := genDBMock(logger)
    62  	require.NoError(t, err)
    63  
    64  	type fields struct {
    65  		client *gorm.DB
    66  	}
    67  	type args struct {
    68  	}
    69  	testcases := []struct {
    70  		name   string
    71  		fields fields
    72  		args   args
    73  		invoke func(args)
    74  		exec   func(*testing.T, args, *gorm.DB)
    75  	}{
    76  		{
    77  			name: "create tbl",
    78  			fields: fields{
    79  				client: db,
    80  			},
    81  			args: args{},
    82  			invoke: func(args args) {
    83  				// Mock the SQL by pattern string with dynamic value to match gorm SQL request to be executed really.
    84  				// Mock the db transaction start.
    85  				mock.ExpectBegin().WillReturnError(nil)
    86  				mock.ExpectExec(`SAVEPOINT create-obj`).WithArgs().WillReturnResult(driver.ResultNoRows)
    87  				// Mock the db transaction commit without error.
    88  				mock.ExpectCommit().WillReturnError(nil)
    89  			},
    90  			exec: func(tt *testing.T, args args, client *gorm.DB) {
    91  				sp := "create-obj"
    92  				tx := client.Begin(&sql.TxOptions{
    93  					Isolation: sql.LevelDefault,
    94  					ReadOnly:  false,
    95  				}).SavePoint(sp)
    96  				err := tx.Commit().Error
    97  				require.NoError(tt, err)
    98  			},
    99  		},
   100  	}
   101  	for _, tc := range testcases {
   102  		t.Run(tc.name, func(tt *testing.T) {
   103  			tc.invoke(tc.args)
   104  			tc.exec(tt, tc.args, tc.fields.client)
   105  		})
   106  	}
   107  	_ = parentLogger.Sync()
   108  }
   109  
   110  func TestGormXLogger_AllAPIs(t *testing.T) {
   111  	var (
   112  		parentLogger XLogger      = nil
   113  		logger       *GormXLogger = nil
   114  	)
   115  	opts := []XLoggerOption{
   116  		WithXLoggerLevel(LogLevelDebug),
   117  		WithXLoggerEncoder(JSON),
   118  		WithXLoggerTimeEncoder(zapcore.ISO8601TimeEncoder),
   119  		WithXLoggerLevelEncoder(zapcore.CapitalLevelEncoder),
   120  	}
   121  	parentLogger = NewXLogger(opts...)
   122  	logger = NewGormXLogger(parentLogger,
   123  		WithGormXLoggerIgnoreRecord404Err(),
   124  		WithGormXLoggerLogLevel(glogger.Info),
   125  		WithGormXLoggerParameterizedQueries(),
   126  	)
   127  
   128  	require.Equal(t, zap.ErrorLevel, getLogLevelOrDefaultForGorm(glogger.Error))
   129  	require.Equal(t, zap.WarnLevel, getLogLevelOrDefaultForGorm(glogger.Warn))
   130  	require.Equal(t, zap.InfoLevel, getLogLevelOrDefaultForGorm(glogger.Info))
   131  	require.Equal(t, zap.DebugLevel, getLogLevelOrDefaultForGorm(glogger.Silent))
   132  
   133  	logger.Info(context.TODO(), "sql %s", "insert into abc values(1,2,3)")
   134  	logger.Warn(context.TODO(), "sql %s", "insert into abc values(1,2,3)")
   135  	logger.Error(context.TODO(), "sql %s", "insert into abc values(1,2,3)")
   136  	logger.Trace(context.TODO(), time.Now(), func() (string, int64) {
   137  		return "insert into abc values(1,2,3)", -1
   138  	}, nil)
   139  	logger.Trace(context.TODO(), time.Now(), func() (string, int64) {
   140  		return "insert into abc values(1,2,3)", 1
   141  	}, nil)
   142  	logger.Trace(context.TODO(), time.Now(), func() (string, int64) {
   143  		return "insert into abc values(1,2,3)", -1
   144  	}, errors.New("insert error"))
   145  	logger.Trace(context.TODO(), time.Now(), func() (string, int64) {
   146  		return "insert into abc values(1,2,3)", 1
   147  	}, errors.New("insert error"))
   148  	logger.Trace(context.TODO(), time.Now().Add(-600*time.Millisecond), func() (string, int64) {
   149  		return "insert into abc values(1,2,3)", -1
   150  	}, nil)
   151  	logger.Trace(context.TODO(), time.Now().Add(-550*time.Millisecond), func() (string, int64) {
   152  		return "insert into abc values(1,2,3)", 1
   153  	}, nil)
   154  	_ = parentLogger.Sync()
   155  	logger.LogMode(glogger.Silent).Trace(context.TODO(), time.Now().Add(-500*time.Millisecond), func() (string, int64) {
   156  		return "insert into abc values(1,2,3)", 1
   157  	}, nil)
   158  	_ = parentLogger.Sync()
   159  }