This is an automated email from the ASF dual-hosted git repository.

jimin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-seata-go.git


The following commit(s) were added to refs/heads/master by this push:
     new faa32f07 test: add some test (#979)
faa32f07 is described below

commit faa32f07441b67b82c0b10d2022bd2bdd44ba467
Author: Eric Wang <[email protected]>
AuthorDate: Sat Nov 8 05:33:01 2025 +0300

    test: add some test (#979)
---
 changes/dev.md                                     |    3 +
 .../tcc_fence_config_test.go}                      |   29 +-
 pkg/rm/tcc/fence/fence_driver_conn_test.go         |  562 +++++++++++
 pkg/rm/tcc/fence/fence_test.go                     |  792 +++++++++++++++
 .../handler/tcc_fence_wrapper_handler_test.go      | 1027 ++++++++++++++++++++
 .../fence/store/db/sql/tcc_fence_store_sql_test.go |  409 ++++++++
 6 files changed, 2816 insertions(+), 6 deletions(-)

diff --git a/changes/dev.md b/changes/dev.md
index 46eb7b1c..0c8e5acc 100755
--- a/changes/dev.md
+++ b/changes/dev.md
@@ -37,6 +37,9 @@
 
 ### test:
 
+  - [[#958](https://github.com/apache/incubator-seata-go/issues/958)] improve 
test coverage for pkg/rm/tcc/fence/store/db/sql (100%)
+  - [[#957](https://github.com/apache/incubator-seata-go/issues/957)] improve 
test coverage for pkg/rm/tcc/fence/handler (84.5%)
+  - [[#955](https://github.com/apache/incubator-seata-go/issues/955)] improve 
test coverage for pkg/rm/tcc/fence (95.1%)
   - [[#947](https://github.com/apache/incubator-seata-go/issues/947)] improve 
test coverage for pkg/discovery/mock
   - [[#948](https://github.com/apache/incubator-seata-go/issues/948)] improve 
test coverage for pkg/integration        
 
diff --git a/pkg/rm/tcc/fence/fence_driver_conn_test.go 
b/pkg/rm/tcc/fence/config/tcc_fence_config_test.go
similarity index 53%
copy from pkg/rm/tcc/fence/fence_driver_conn_test.go
copy to pkg/rm/tcc/fence/config/tcc_fence_config_test.go
index 336da282..fa174147 100644
--- a/pkg/rm/tcc/fence/fence_driver_conn_test.go
+++ b/pkg/rm/tcc/fence/config/tcc_fence_config_test.go
@@ -15,16 +15,33 @@
  * limitations under the License.
  */
 
-package fence
+package config
 
 import (
        "testing"
 
-       "github.com/stretchr/testify/assert"
+       "seata.apache.org/seata-go/pkg/util/log"
 )
 
-func TestBegin(t *testing.T) {
-       tx, err := (&FenceConn{}).Begin()
-       assert.NotNil(t, err)
-       assert.Nil(t, tx)
+func TestInitFence(t *testing.T) {
+       log.Init()
+
+       // InitFence is currently empty, just call it to ensure no panic
+       InitFence()
+}
+
+func TestInitCleanTask(t *testing.T) {
+       log.Init()
+
+       // Test with an invalid DSN - should log warning but not panic
+       dsn := "invalid-dsn"
+
+       // Call InitCleanTask which starts a goroutine
+       // Even with invalid DSN, it should handle the error gracefully
+       InitCleanTask(dsn)
+
+       // Note: We don't call Destroy() here because there's a known issue
+       // where Destroy() panics if the logQueue was not initialized
+       // (which happens when the DSN is invalid and sql.Open fails).
+       // This is a limitation of the current handler implementation.
 }
diff --git a/pkg/rm/tcc/fence/fence_driver_conn_test.go 
b/pkg/rm/tcc/fence/fence_driver_conn_test.go
index 336da282..bfae1da1 100644
--- a/pkg/rm/tcc/fence/fence_driver_conn_test.go
+++ b/pkg/rm/tcc/fence/fence_driver_conn_test.go
@@ -18,13 +18,575 @@
 package fence
 
 import (
+       "context"
+       "database/sql"
+       "database/sql/driver"
+       "errors"
        "testing"
 
+       sqlmock "github.com/DATA-DOG/go-sqlmock"
        "github.com/stretchr/testify/assert"
+
+       "seata.apache.org/seata-go/pkg/rm/tcc/fence/enum"
+       "seata.apache.org/seata-go/pkg/tm"
+       "seata.apache.org/seata-go/pkg/util/log"
 )
 
+// Mock connection without BeginTx support
+type mockConnNoBeginTx struct {
+       driver.Conn
+}
+
+func (m *mockConnNoBeginTx) Prepare(query string) (driver.Stmt, error) {
+       return nil, errors.New("not used")
+}
+
+func (m *mockConnNoBeginTx) Close() error {
+       return nil
+}
+
+// mockConnWithBeginTx implements driver.ConnBeginTx
+type mockConnWithBeginTx struct {
+       *mockConn
+       beginTxFunc func(ctx context.Context, opts driver.TxOptions) 
(driver.Tx, error)
+}
+
+func (m *mockConnWithBeginTx) BeginTx(ctx context.Context, opts 
driver.TxOptions) (driver.Tx, error) {
+       if m.beginTxFunc != nil {
+               return m.beginTxFunc(ctx, opts)
+       }
+       return nil, errors.New("not implemented")
+}
+
 func TestBegin(t *testing.T) {
        tx, err := (&FenceConn{}).Begin()
        assert.NotNil(t, err)
        assert.Nil(t, tx)
 }
+
+func TestFenceConn_Prepare(t *testing.T) {
+       mockConn := &mockConn{
+               prepareFunc: func(query string) (driver.Stmt, error) {
+                       return nil, nil
+               },
+       }
+
+       fenceConn := &FenceConn{TargetConn: mockConn}
+       stmt, err := fenceConn.Prepare("SELECT 1")
+       assert.NoError(t, err)
+       assert.Nil(t, stmt)
+}
+
+func TestFenceConn_PrepareContext(t *testing.T) {
+       mockConn := &mockConn{
+               prepareFunc: func(query string) (driver.Stmt, error) {
+                       return nil, nil
+               },
+       }
+
+       fenceConn := &FenceConn{TargetConn: mockConn}
+       stmt, err := fenceConn.PrepareContext(context.Background(), "SELECT 1")
+       assert.NoError(t, err)
+       assert.Nil(t, stmt)
+}
+
+func TestFenceConn_Exec(t *testing.T) {
+       tests := []struct {
+               name    string
+               conn    driver.Conn
+               wantErr bool
+       }{
+               {
+                       name: "exec supported",
+                       conn: &mockConnWithExec{
+                               mockConn: &mockConn{},
+                               execFunc: func(query string, args 
[]driver.Value) (driver.Result, error) {
+                                       return &mockResult{}, nil
+                               },
+                       },
+                       wantErr: false,
+               },
+               {
+                       name:    "exec not supported",
+                       conn:    &mockConn{},
+                       wantErr: true,
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       fenceConn := &FenceConn{TargetConn: tt.conn}
+                       result, err := fenceConn.Exec("INSERT INTO test VALUES 
(?)", []driver.Value{1})
+
+                       if tt.wantErr {
+                               assert.Error(t, err)
+                               assert.Equal(t, driver.ErrSkip, err)
+                       } else {
+                               assert.NoError(t, err)
+                               assert.NotNil(t, result)
+                       }
+               })
+       }
+}
+
+func TestFenceConn_ExecContext(t *testing.T) {
+       tests := []struct {
+               name    string
+               conn    driver.Conn
+               wantErr bool
+               errType error
+       }{
+               {
+                       name: "exec context supported",
+                       conn: &mockConnWithExecContext{
+                               mockConn: &mockConn{},
+                               execContextFunc: func(ctx context.Context, 
query string, args []driver.NamedValue) (driver.Result, error) {
+                                       return &mockResult{}, nil
+                               },
+                       },
+                       wantErr: false,
+               },
+               {
+                       name: "fallback to exec - exec supported",
+                       conn: &mockConnWithExec{
+                               mockConn: &mockConn{},
+                               execFunc: func(query string, args 
[]driver.Value) (driver.Result, error) {
+                                       return &mockResult{}, nil
+                               },
+                       },
+                       wantErr: false,
+               },
+               {
+                       name:    "fallback to exec - exec not supported",
+                       conn:    &mockConn{},
+                       wantErr: true,
+                       errType: driver.ErrSkip,
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       fenceConn := &FenceConn{TargetConn: tt.conn}
+                       args := []driver.NamedValue{{Ordinal: 1, Value: 1}}
+                       result, err := 
fenceConn.ExecContext(context.Background(), "INSERT INTO test VALUES (?)", args)
+
+                       if tt.wantErr {
+                               assert.Error(t, err)
+                               if tt.errType != nil {
+                                       assert.Equal(t, tt.errType, err)
+                               }
+                       } else {
+                               assert.NoError(t, err)
+                               assert.NotNil(t, result)
+                       }
+               })
+       }
+}
+
+func TestFenceConn_Query(t *testing.T) {
+       tests := []struct {
+               name    string
+               conn    driver.Conn
+               wantErr bool
+       }{
+               {
+                       name: "query supported",
+                       conn: &mockConnWithQuery{
+                               mockConn: &mockConn{},
+                               queryFunc: func(query string, args 
[]driver.Value) (driver.Rows, error) {
+                                       return nil, nil
+                               },
+                       },
+                       wantErr: false,
+               },
+               {
+                       name:    "query not supported",
+                       conn:    &mockConn{},
+                       wantErr: true,
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       fenceConn := &FenceConn{TargetConn: tt.conn}
+                       rows, err := fenceConn.Query("SELECT * FROM test", 
[]driver.Value{})
+
+                       if tt.wantErr {
+                               assert.Error(t, err)
+                               assert.Equal(t, driver.ErrSkip, err)
+                       } else {
+                               assert.NoError(t, err)
+                               assert.Nil(t, rows)
+                       }
+               })
+       }
+}
+
+func TestFenceConn_QueryContext(t *testing.T) {
+       tests := []struct {
+               name    string
+               conn    driver.Conn
+               wantErr bool
+               errType error
+       }{
+               {
+                       name: "query context supported",
+                       conn: &mockConnWithQueryContext{
+                               mockConn: &mockConn{},
+                               queryContextFunc: func(ctx context.Context, 
query string, args []driver.NamedValue) (driver.Rows, error) {
+                                       return nil, nil
+                               },
+                       },
+                       wantErr: false,
+               },
+               {
+                       name: "fallback to query - query supported",
+                       conn: &mockConnWithQuery{
+                               mockConn: &mockConn{},
+                               queryFunc: func(query string, args 
[]driver.Value) (driver.Rows, error) {
+                                       return nil, nil
+                               },
+                       },
+                       wantErr: false,
+               },
+               {
+                       name:    "fallback to query - query not supported",
+                       conn:    &mockConn{},
+                       wantErr: true,
+                       errType: driver.ErrSkip,
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       fenceConn := &FenceConn{TargetConn: tt.conn}
+                       args := []driver.NamedValue{{Ordinal: 1, Value: 1}}
+                       rows, err := 
fenceConn.QueryContext(context.Background(), "SELECT * FROM test WHERE id = ?", 
args)
+
+                       if tt.wantErr {
+                               assert.Error(t, err)
+                               if tt.errType != nil {
+                                       assert.Equal(t, tt.errType, err)
+                               }
+                       } else {
+                               assert.NoError(t, err)
+                               assert.Nil(t, rows)
+                       }
+               })
+       }
+}
+
+func TestFenceConn_ResetSession(t *testing.T) {
+       tests := []struct {
+               name    string
+               conn    driver.Conn
+               wantErr bool
+               errType error
+       }{
+               {
+                       name: "reset session supported",
+                       conn: &mockConnWithResetSession{
+                               mockConn: &mockConn{},
+                               resetFunc: func(ctx context.Context) error {
+                                       return nil
+                               },
+                       },
+                       wantErr: false,
+               },
+               {
+                       name:    "reset session not supported",
+                       conn:    &mockConn{},
+                       wantErr: true,
+                       errType: driver.ErrSkip,
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       fenceConn := &FenceConn{TargetConn: tt.conn}
+                       err := fenceConn.ResetSession(context.Background())
+
+                       if tt.wantErr {
+                               assert.Error(t, err)
+                               if tt.errType != nil {
+                                       assert.Equal(t, tt.errType, err)
+                               }
+                       } else {
+                               assert.NoError(t, err)
+                       }
+               })
+       }
+}
+
+func TestFenceConn_Close(t *testing.T) {
+       tests := []struct {
+               name    string
+               conn    *mockConn
+               wantErr bool
+       }{
+               {
+                       name: "close success",
+                       conn: &mockConn{
+                               closeFunc: func() error {
+                                       return nil
+                               },
+                       },
+                       wantErr: false,
+               },
+               {
+                       name: "close with error",
+                       conn: &mockConn{
+                               closeFunc: func() error {
+                                       return errors.New("close error")
+                               },
+                       },
+                       wantErr: true,
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       fenceConn := &FenceConn{TargetConn: tt.conn}
+                       err := fenceConn.Close()
+
+                       if tt.wantErr {
+                               assert.Error(t, err)
+                       } else {
+                               assert.NoError(t, err)
+                       }
+               })
+       }
+}
+
+func TestFenceConn_BeginTx_NotSupported(t *testing.T) {
+       log.Init()
+
+       mockConn := &mockConnNoBeginTx{}
+       fenceConn := &FenceConn{TargetConn: mockConn}
+
+       tx, err := fenceConn.BeginTx(context.Background(), driver.TxOptions{})
+       assert.Error(t, err)
+       assert.Contains(t, err.Error(), "operation unsupported")
+       assert.Nil(t, tx)
+}
+
+func TestFenceConn_BeginTx_NoSeataContext(t *testing.T) {
+       log.Init()
+
+       mockConnWithBegin := &mockConnWithBeginTx{
+               mockConn: &mockConn{},
+               beginTxFunc: func(ctx context.Context, opts driver.TxOptions) 
(driver.Tx, error) {
+                       return &mockTx{}, nil
+               },
+       }
+
+       fenceConn := &FenceConn{
+               TargetConn: mockConnWithBegin,
+               TargetDB:   &sql.DB{},
+       }
+
+       tx, err := fenceConn.BeginTx(context.Background(), driver.TxOptions{})
+       assert.Error(t, err)
+       assert.Contains(t, err.Error(), "there is not seata context")
+       assert.Nil(t, tx)
+}
+
+func TestFenceConn_BeginTx_BeginTxError(t *testing.T) {
+       log.Init()
+
+       expectedErr := errors.New("begin tx failed")
+       mockConnWithBegin := &mockConnWithBeginTx{
+               mockConn: &mockConn{},
+               beginTxFunc: func(ctx context.Context, opts driver.TxOptions) 
(driver.Tx, error) {
+                       return nil, expectedErr
+               },
+       }
+
+       fenceConn := &FenceConn{
+               TargetConn: mockConnWithBegin,
+       }
+
+       tx, err := fenceConn.BeginTx(context.Background(), driver.TxOptions{})
+       assert.Error(t, err)
+       assert.Equal(t, expectedErr, err)
+       assert.Nil(t, tx)
+}
+
+func TestFenceConn_BeginTx_FenceTxAlreadyBegun(t *testing.T) {
+       log.Init()
+
+       mockTx := &mockTx{}
+       mockConnWithBegin := &mockConnWithBeginTx{
+               mockConn: &mockConn{},
+               beginTxFunc: func(ctx context.Context, opts driver.TxOptions) 
(driver.Tx, error) {
+                       return mockTx, nil
+               },
+       }
+
+       fenceConn := &FenceConn{
+               TargetConn: mockConnWithBegin,
+       }
+
+       ctx := context.Background()
+       ctx = tm.InitSeataContext(ctx)
+       tm.SetXID(ctx, "test-xid")
+       tm.SetFenceTxBeginedFlag(ctx, true) // Mark fence tx as already begun
+
+       tx, err := fenceConn.BeginTx(ctx, driver.TxOptions{})
+       assert.NoError(t, err)
+       assert.Equal(t, mockTx, tx) // Should return the original tx directly
+}
+
+func TestFenceConn_BeginTx_TargetDBBeginTxError(t *testing.T) {
+       log.Init()
+
+       mockTx := &mockTx{
+               rollbackFunc: func() error {
+                       return nil
+               },
+       }
+       mockConnWithBegin := &mockConnWithBeginTx{
+               mockConn: &mockConn{},
+               beginTxFunc: func(ctx context.Context, opts driver.TxOptions) 
(driver.Tx, error) {
+                       return mockTx, nil
+               },
+       }
+
+       // Create a closed database to trigger BeginTx error
+       db, _, err := sqlmock.New()
+       assert.NoError(t, err)
+       db.Close() // Close it to cause BeginTx to fail
+
+       fenceConn := &FenceConn{
+               TargetConn: mockConnWithBegin,
+               TargetDB:   db,
+       }
+
+       ctx := context.Background()
+       ctx = tm.InitSeataContext(ctx)
+       tm.SetXID(ctx, "test-xid")
+       tm.SetFenceTxBeginedFlag(ctx, false)
+
+       tx, err := fenceConn.BeginTx(ctx, driver.TxOptions{})
+       assert.Error(t, err)
+       assert.Nil(t, tx)
+}
+
+func TestFenceConn_BeginTx_WithFenceError(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mockTx := &mockTx{
+               rollbackFunc: func() error {
+                       return nil
+               },
+       }
+       mockConnWithBegin := &mockConnWithBeginTx{
+               mockConn: &mockConn{},
+               beginTxFunc: func(ctx context.Context, opts driver.TxOptions) 
(driver.Tx, error) {
+                       return mockTx, nil
+               },
+       }
+
+       // Expect both transactions to begin
+       mock.ExpectBegin()
+
+       fenceConn := &FenceConn{
+               TargetConn: mockConnWithBegin,
+               TargetDB:   db,
+       }
+
+       ctx := context.Background()
+       ctx = tm.InitSeataContext(ctx)
+       tm.SetXID(ctx, "test-xid")
+       tm.SetTxName(ctx, "test-tx")
+       tm.SetFencePhase(ctx, enum.FencePhaseNotExist) // This will cause 
WithFence to fail
+       tm.SetFenceTxBeginedFlag(ctx, false)
+
+       tx, err := fenceConn.BeginTx(ctx, driver.TxOptions{})
+       assert.Error(t, err)
+       assert.Contains(t, err.Error(), "fence phase not exist")
+       assert.Nil(t, tx)
+}
+
+func TestFenceConn_BeginTx_Success(t *testing.T) {
+       log.Init()
+
+       db, mock, err := 
sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mockTx := &mockTx{
+               rollbackFunc: func() error {
+                       return nil
+               },
+       }
+       mockConnWithBegin := &mockConnWithBeginTx{
+               mockConn: &mockConn{},
+               beginTxFunc: func(ctx context.Context, opts driver.TxOptions) 
(driver.Tx, error) {
+                       return mockTx, nil
+               },
+       }
+
+       // Expect fence transaction operations
+       mock.ExpectBegin()
+       mock.ExpectPrepare("insert into  tcc_fence_log  (xid, branch_id, 
action_name, status, gmt_create, gmt_modified) values ( ?,?,?,?,?,?)").
+               ExpectExec().
+               WithArgs(sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), 
sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg()).
+               WillReturnResult(sqlmock.NewResult(1, 1))
+       // Note: No ExpectCommit here - the transaction is kept open in FenceTx
+
+       fenceConn := &FenceConn{
+               TargetConn: mockConnWithBegin,
+               TargetDB:   db,
+       }
+
+       ctx := context.Background()
+       ctx = tm.InitSeataContext(ctx)
+       tm.SetXID(ctx, "test-xid")
+       tm.SetTxName(ctx, "test-tx")
+       tm.SetFencePhase(ctx, enum.FencePhasePrepare)
+       tm.SetFenceTxBeginedFlag(ctx, false)
+
+       bac := &tm.BusinessActionContext{
+               Xid:           "test-xid",
+               BranchId:      1001,
+               ActionName:    "test-action",
+               ActionContext: make(map[string]interface{}),
+       }
+       tm.SetBusinessActionContext(ctx, bac)
+
+       tx, err := fenceConn.BeginTx(ctx, driver.TxOptions{})
+       assert.NoError(t, err)
+       assert.NotNil(t, tx)
+
+       fenceTx, ok := tx.(*FenceTx)
+       assert.True(t, ok)
+       assert.Equal(t, mockTx, fenceTx.TargetTx)
+       assert.NotNil(t, fenceTx.TargetFenceTx)
+       assert.Equal(t, ctx, fenceTx.Ctx)
+
+       // Clean up - the fence tx needs to be rolled back or committed
+       // For this test, we just verify the expectations were met so far
+       // In real usage, the FenceTx would be committed/rolled back by the 
caller
+}
+
+func TestFenceConn_ResetSession_Error(t *testing.T) {
+       log.Init()
+
+       expectedErr := errors.New("reset session failed")
+       mockConnWithReset := &mockConnWithResetSession{
+               mockConn: &mockConn{},
+               resetFunc: func(ctx context.Context) error {
+                       return expectedErr
+               },
+       }
+
+       fenceConn := &FenceConn{TargetConn: mockConnWithReset}
+       err := fenceConn.ResetSession(context.Background())
+       assert.Error(t, err)
+       assert.Equal(t, expectedErr, err)
+}
diff --git a/pkg/rm/tcc/fence/fence_test.go b/pkg/rm/tcc/fence/fence_test.go
new file mode 100644
index 00000000..aed0ebbd
--- /dev/null
+++ b/pkg/rm/tcc/fence/fence_test.go
@@ -0,0 +1,792 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package fence
+
+import (
+       "context"
+       "database/sql"
+       "database/sql/driver"
+       "errors"
+       "flag"
+       "testing"
+       "time"
+
+       sqlmock "github.com/DATA-DOG/go-sqlmock"
+       "github.com/stretchr/testify/assert"
+
+       "seata.apache.org/seata-go/pkg/rm/tcc/fence/enum"
+       "seata.apache.org/seata-go/pkg/tm"
+       "seata.apache.org/seata-go/pkg/util/log"
+)
+
+func TestInitFenceConfig(t *testing.T) {
+       log.Init()
+
+       tests := []struct {
+               name   string
+               config Config
+       }{
+               {
+                       name: "config with enable=false",
+                       config: Config{
+                               Enable:       false,
+                               Url:          "test-url",
+                               LogTableName: "test_table",
+                               CleanPeriod:  10 * time.Minute,
+                       },
+               },
+               {
+                       name: "config with enable=true",
+                       config: Config{
+                               Enable:       true,
+                               Url:          "",
+                               LogTableName: "tcc_fence_log",
+                               CleanPeriod:  5 * time.Minute,
+                       },
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       InitFenceConfig(tt.config)
+                       assert.Equal(t, tt.config, FenceConfig)
+               })
+       }
+}
+
+func TestConfig_RegisterFlagsWithPrefix(t *testing.T) {
+       tests := []struct {
+               name   string
+               prefix string
+       }{
+               {
+                       name:   "register with prefix 'tcc'",
+                       prefix: "tcc",
+               },
+               {
+                       name:   "register with prefix 'fence'",
+                       prefix: "fence",
+               },
+               {
+                       name:   "register with empty prefix",
+                       prefix: "",
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       cfg := &Config{}
+                       fs := flag.NewFlagSet("test", flag.ContinueOnError)
+
+                       cfg.RegisterFlagsWithPrefix(tt.prefix, fs)
+
+                       // Verify flags are registered
+                       assert.NotNil(t, fs.Lookup(tt.prefix+".enable"))
+                       assert.NotNil(t, fs.Lookup(tt.prefix+".url"))
+                       assert.NotNil(t, fs.Lookup(tt.prefix+".log-table-name"))
+                       assert.NotNil(t, fs.Lookup(tt.prefix+".clean-period"))
+               })
+       }
+}
+
+func TestDoFence_AllPhases(t *testing.T) {
+       log.Init()
+
+       tests := []struct {
+               name       string
+               fencePhase enum.FencePhase
+               xid        string
+               txName     string
+               wantErr    bool
+               errMsg     string
+       }{
+               {
+                       name:       "fence phase not exist",
+                       fencePhase: enum.FencePhaseNotExist,
+                       xid:        "test-xid-001",
+                       txName:     "test-tx",
+                       wantErr:    true,
+                       errMsg:     "xid test-xid-001, tx name test-tx, fence 
phase not exist",
+               },
+               {
+                       name:       "illegal fence phase",
+                       fencePhase: enum.FencePhase(99),
+                       xid:        "test-xid-002",
+                       txName:     "test-tx",
+                       wantErr:    true,
+                       errMsg:     "fence phase: 99 illegal",
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       db, mock, err := sqlmock.New()
+                       assert.NoError(t, err)
+                       defer db.Close()
+
+                       mock.ExpectBegin()
+                       tx, err := db.Begin()
+                       assert.NoError(t, err)
+
+                       ctx := context.Background()
+                       ctx = tm.InitSeataContext(ctx)
+                       tm.SetXID(ctx, tt.xid)
+                       tm.SetTxName(ctx, tt.txName)
+                       tm.SetFencePhase(ctx, tt.fencePhase)
+
+                       err = DoFence(ctx, tx)
+
+                       if tt.wantErr {
+                               assert.Error(t, err)
+                               assert.Contains(t, err.Error(), tt.errMsg)
+                       } else {
+                               assert.NoError(t, err)
+                       }
+               })
+       }
+}
+
+func TestWithFence_CallbackError(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mock.ExpectBegin()
+       tx, err := db.Begin()
+       assert.NoError(t, err)
+
+       ctx := context.Background()
+       ctx = tm.InitSeataContext(ctx)
+       tm.SetXID(ctx, "test-xid")
+       tm.SetTxName(ctx, "test-tx")
+       tm.SetFencePhase(ctx, enum.FencePhaseNotExist)
+
+       callbackErr := errors.New("business logic error")
+       callback := func() error {
+               return callbackErr
+       }
+
+       err = WithFence(ctx, tx, callback)
+       assert.Error(t, err)
+}
+
+// Mock implementations for driver interfaces
+type mockConn struct {
+       driver.Conn
+       prepareFunc      func(query string) (driver.Stmt, error)
+       beginTxFunc      func(ctx context.Context, opts driver.TxOptions) 
(driver.Tx, error)
+       closeFunc        func() error
+       resetSessionFunc func(ctx context.Context) error
+}
+
+func (m *mockConn) Prepare(query string) (driver.Stmt, error) {
+       if m.prepareFunc != nil {
+               return m.prepareFunc(query)
+       }
+       return nil, nil
+}
+
+func (m *mockConn) BeginTx(ctx context.Context, opts driver.TxOptions) 
(driver.Tx, error) {
+       if m.beginTxFunc != nil {
+               return m.beginTxFunc(ctx, opts)
+       }
+       return nil, errors.New("not implemented")
+}
+
+func (m *mockConn) Close() error {
+       if m.closeFunc != nil {
+               return m.closeFunc()
+       }
+       return nil
+}
+
+func (m *mockConn) ResetSession(ctx context.Context) error {
+       if m.resetSessionFunc != nil {
+               return m.resetSessionFunc(ctx)
+       }
+       return driver.ErrSkip
+}
+
+// mockConnWithExec implements driver.Execer
+type mockConnWithExec struct {
+       *mockConn
+       execFunc func(query string, args []driver.Value) (driver.Result, error)
+}
+
+func (m *mockConnWithExec) Exec(query string, args []driver.Value) 
(driver.Result, error) {
+       if m.execFunc != nil {
+               return m.execFunc(query, args)
+       }
+       return nil, driver.ErrSkip
+}
+
+// mockConnWithExecContext implements driver.ExecerContext
+type mockConnWithExecContext struct {
+       *mockConn
+       execContextFunc func(ctx context.Context, query string, args 
[]driver.NamedValue) (driver.Result, error)
+}
+
+func (m *mockConnWithExecContext) ExecContext(ctx context.Context, query 
string, args []driver.NamedValue) (driver.Result, error) {
+       if m.execContextFunc != nil {
+               return m.execContextFunc(ctx, query, args)
+       }
+       return nil, driver.ErrSkip
+}
+
+// mockConnWithQuery implements driver.Queryer
+type mockConnWithQuery struct {
+       *mockConn
+       queryFunc func(query string, args []driver.Value) (driver.Rows, error)
+}
+
+func (m *mockConnWithQuery) Query(query string, args []driver.Value) 
(driver.Rows, error) {
+       if m.queryFunc != nil {
+               return m.queryFunc(query, args)
+       }
+       return nil, driver.ErrSkip
+}
+
+// mockConnWithQueryContext implements driver.QueryerContext
+type mockConnWithQueryContext struct {
+       *mockConn
+       queryContextFunc func(ctx context.Context, query string, args 
[]driver.NamedValue) (driver.Rows, error)
+}
+
+func (m *mockConnWithQueryContext) QueryContext(ctx context.Context, query 
string, args []driver.NamedValue) (driver.Rows, error) {
+       if m.queryContextFunc != nil {
+               return m.queryContextFunc(ctx, query, args)
+       }
+       return nil, driver.ErrSkip
+}
+
+// mockConnWithResetSession implements driver.SessionResetter
+type mockConnWithResetSession struct {
+       *mockConn
+       resetFunc func(ctx context.Context) error
+}
+
+func (m *mockConnWithResetSession) ResetSession(ctx context.Context) error {
+       if m.resetFunc != nil {
+               return m.resetFunc(ctx)
+       }
+       return nil
+}
+
+type mockTx struct {
+       driver.Tx
+       commitFunc   func() error
+       rollbackFunc func() error
+}
+
+func (m *mockTx) Commit() error {
+       if m.commitFunc != nil {
+               return m.commitFunc()
+       }
+       return nil
+}
+
+func (m *mockTx) Rollback() error {
+       if m.rollbackFunc != nil {
+               return m.rollbackFunc()
+       }
+       return nil
+}
+
+type mockResult struct {
+       driver.Result
+}
+
+func (m *mockResult) LastInsertId() (int64, error) {
+       return 0, nil
+}
+
+func (m *mockResult) RowsAffected() (int64, error) {
+       return 1, nil
+}
+
+func TestFenceTx_Commit(t *testing.T) {
+       log.Init()
+
+       tests := []struct {
+               name         string
+               targetTx     *mockTx
+               wantErr      bool
+               setupContext func() context.Context
+       }{
+               {
+                       name: "commit success",
+                       targetTx: &mockTx{
+                               commitFunc: func() error {
+                                       return nil
+                               },
+                       },
+                       wantErr: false,
+                       setupContext: func() context.Context {
+                               ctx := context.Background()
+                               ctx = tm.InitSeataContext(ctx)
+                               tm.SetFenceTxBeginedFlag(ctx, true)
+                               return ctx
+                       },
+               },
+               {
+                       name: "commit with target tx error",
+                       targetTx: &mockTx{
+                               commitFunc: func() error {
+                                       return errors.New("commit failed")
+                               },
+                       },
+                       wantErr: true,
+                       setupContext: func() context.Context {
+                               ctx := context.Background()
+                               ctx = tm.InitSeataContext(ctx)
+                               return ctx
+                       },
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       db, mock, err := sqlmock.New()
+                       assert.NoError(t, err)
+                       defer db.Close()
+
+                       mock.ExpectBegin()
+                       fenceTx, err := db.Begin()
+                       assert.NoError(t, err)
+
+                       if !tt.wantErr {
+                               mock.ExpectCommit()
+                       }
+
+                       ctx := tt.setupContext()
+                       tx := &FenceTx{
+                               Ctx:           ctx,
+                               TargetTx:      tt.targetTx,
+                               TargetFenceTx: fenceTx,
+                       }
+
+                       err = tx.Commit()
+
+                       if tt.wantErr {
+                               assert.Error(t, err)
+                       } else {
+                               assert.NoError(t, err)
+                               // Verify fence tx flag is cleared
+                               assert.False(t, tm.IsFenceTxBegin(ctx))
+                       }
+               })
+       }
+}
+
+func TestFenceTx_Rollback(t *testing.T) {
+       log.Init()
+
+       tests := []struct {
+               name         string
+               targetTx     *mockTx
+               wantErr      bool
+               setupContext func() context.Context
+       }{
+               {
+                       name: "rollback success",
+                       targetTx: &mockTx{
+                               rollbackFunc: func() error {
+                                       return nil
+                               },
+                       },
+                       wantErr: false,
+                       setupContext: func() context.Context {
+                               ctx := context.Background()
+                               ctx = tm.InitSeataContext(ctx)
+                               tm.SetFenceTxBeginedFlag(ctx, true)
+                               return ctx
+                       },
+               },
+               {
+                       name: "rollback with target tx error",
+                       targetTx: &mockTx{
+                               rollbackFunc: func() error {
+                                       return errors.New("rollback failed")
+                               },
+                       },
+                       wantErr: true,
+                       setupContext: func() context.Context {
+                               ctx := context.Background()
+                               ctx = tm.InitSeataContext(ctx)
+                               return ctx
+                       },
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       db, mock, err := sqlmock.New()
+                       assert.NoError(t, err)
+                       defer db.Close()
+
+                       mock.ExpectBegin()
+                       fenceTx, err := db.Begin()
+                       assert.NoError(t, err)
+
+                       if !tt.wantErr {
+                               mock.ExpectRollback()
+                       }
+
+                       ctx := tt.setupContext()
+                       tx := &FenceTx{
+                               Ctx:           ctx,
+                               TargetTx:      tt.targetTx,
+                               TargetFenceTx: fenceTx,
+                       }
+
+                       err = tx.Rollback()
+
+                       if tt.wantErr {
+                               assert.Error(t, err)
+                       } else {
+                               assert.NoError(t, err)
+                               // Verify fence tx flag is cleared
+                               assert.False(t, tm.IsFenceTxBegin(ctx))
+                       }
+               })
+       }
+}
+
+func TestSeataFenceConnector_Connect(t *testing.T) {
+       mockConn := &mockConn{}
+       mockConnector := &mockConnector{
+               connectFunc: func(ctx context.Context) (driver.Conn, error) {
+                       return mockConn, nil
+               },
+       }
+
+       connector := &SeataFenceConnector{
+               TargetConnector: mockConnector,
+               TargetDB:        &sql.DB{},
+       }
+
+       conn, err := connector.Connect(context.Background())
+       assert.NoError(t, err)
+       assert.NotNil(t, conn)
+
+       fenceConn, ok := conn.(*FenceConn)
+       assert.True(t, ok)
+       assert.Equal(t, mockConn, fenceConn.TargetConn)
+}
+
+func TestSeataFenceConnector_Driver(t *testing.T) {
+       mockDriver := &FenceDriver{}
+       mockConnector := &mockConnector{
+               driverFunc: func() driver.Driver {
+                       return mockDriver
+               },
+       }
+
+       connector := &SeataFenceConnector{
+               TargetConnector: mockConnector,
+       }
+
+       driver := connector.Driver()
+       assert.Equal(t, mockDriver, driver)
+}
+
+type mockConnector struct {
+       connectFunc func(ctx context.Context) (driver.Conn, error)
+       driverFunc  func() driver.Driver
+}
+
+func (m *mockConnector) Connect(ctx context.Context) (driver.Conn, error) {
+       if m.connectFunc != nil {
+               return m.connectFunc(ctx)
+       }
+       return nil, nil
+}
+
+func (m *mockConnector) Driver() driver.Driver {
+       if m.driverFunc != nil {
+               return m.driverFunc()
+       }
+       return nil
+}
+
+func TestDoFence_PreparePhase(t *testing.T) {
+       log.Init()
+
+       db, mock, err := 
sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mock.ExpectBegin()
+       mock.ExpectPrepare("insert into  tcc_fence_log  (xid, branch_id, 
action_name, status, gmt_create, gmt_modified) values ( ?,?,?,?,?,?)").
+               ExpectExec().
+               WithArgs(sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), 
sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg()).
+               WillReturnResult(sqlmock.NewResult(1, 1))
+       mock.ExpectCommit()
+
+       tx, err := db.BeginTx(context.Background(), &sql.TxOptions{})
+       assert.NoError(t, err)
+
+       ctx := context.Background()
+       ctx = tm.InitSeataContext(ctx)
+       tm.SetXID(ctx, "test-xid-prepare")
+       tm.SetTxName(ctx, "test-tx")
+       tm.SetFencePhase(ctx, enum.FencePhasePrepare)
+       bac := &tm.BusinessActionContext{
+               Xid:        "test-xid-prepare",
+               BranchId:   123,
+               ActionName: "test-action",
+       }
+       tm.SetBusinessActionContext(ctx, bac)
+
+       err = DoFence(ctx, tx)
+       assert.NoError(t, err)
+
+       tx.Commit()
+       assert.NoError(t, mock.ExpectationsWereMet())
+}
+
+func TestDoFence_CommitPhase(t *testing.T) {
+       log.Init()
+
+       db, mock, err := 
sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
+       assert.NoError(t, err)
+       defer db.Close()
+
+       now := time.Now()
+       mock.ExpectBegin()
+       mock.ExpectPrepare("select xid, branch_id, action_name, status, 
gmt_create, gmt_modified from  tcc_fence_log  where xid = ? and branch_id = ? 
for update").
+               ExpectQuery().
+               WithArgs("test-xid-commit", int64(456)).
+               WillReturnRows(sqlmock.NewRows([]string{"xid", "branch_id", 
"action_name", "status", "gmt_create", "gmt_modified"}).
+                       AddRow("test-xid-commit", int64(456), "test-action", 
enum.StatusTried, now, now))
+       mock.ExpectPrepare("update  tcc_fence_log  set status = ?, gmt_modified 
= ? where xid = ? and  branch_id = ? and status = ? ").
+               ExpectExec().
+               WithArgs(sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), 
sqlmock.AnyArg(), sqlmock.AnyArg()).
+               WillReturnResult(sqlmock.NewResult(1, 1))
+       mock.ExpectCommit()
+
+       tx, err := db.BeginTx(context.Background(), &sql.TxOptions{})
+       assert.NoError(t, err)
+
+       ctx := context.Background()
+       ctx = tm.InitSeataContext(ctx)
+       tm.SetXID(ctx, "test-xid-commit")
+       tm.SetTxName(ctx, "test-tx")
+       tm.SetFencePhase(ctx, enum.FencePhaseCommit)
+       bac := &tm.BusinessActionContext{
+               Xid:        "test-xid-commit",
+               BranchId:   456,
+               ActionName: "test-action",
+       }
+       tm.SetBusinessActionContext(ctx, bac)
+
+       err = DoFence(ctx, tx)
+       assert.NoError(t, err)
+
+       tx.Commit()
+       assert.NoError(t, mock.ExpectationsWereMet())
+}
+
+func TestDoFence_RollbackPhase(t *testing.T) {
+       log.Init()
+
+       db, mock, err := 
sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
+       assert.NoError(t, err)
+       defer db.Close()
+
+       now := time.Now()
+       mock.ExpectBegin()
+       mock.ExpectPrepare("select xid, branch_id, action_name, status, 
gmt_create, gmt_modified from  tcc_fence_log  where xid = ? and branch_id = ? 
for update").
+               ExpectQuery().
+               WithArgs("test-xid-rollback", int64(789)).
+               WillReturnRows(sqlmock.NewRows([]string{"xid", "branch_id", 
"action_name", "status", "gmt_create", "gmt_modified"}).
+                       AddRow("test-xid-rollback", int64(789), "test-action", 
enum.StatusTried, now, now))
+       mock.ExpectPrepare("update  tcc_fence_log  set status = ?, gmt_modified 
= ? where xid = ? and  branch_id = ? and status = ? ").
+               ExpectExec().
+               WithArgs(sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), 
sqlmock.AnyArg(), sqlmock.AnyArg()).
+               WillReturnResult(sqlmock.NewResult(1, 1))
+       mock.ExpectCommit()
+
+       tx, err := db.BeginTx(context.Background(), &sql.TxOptions{})
+       assert.NoError(t, err)
+
+       ctx := context.Background()
+       ctx = tm.InitSeataContext(ctx)
+       tm.SetXID(ctx, "test-xid-rollback")
+       tm.SetTxName(ctx, "test-tx")
+       tm.SetFencePhase(ctx, enum.FencePhaseRollback)
+       bac := &tm.BusinessActionContext{
+               Xid:        "test-xid-rollback",
+               BranchId:   789,
+               ActionName: "test-action",
+       }
+       tm.SetBusinessActionContext(ctx, bac)
+
+       err = DoFence(ctx, tx)
+       assert.NoError(t, err)
+
+       tx.Commit()
+       assert.NoError(t, mock.ExpectationsWereMet())
+}
+
+func TestWithFence_CallbackSuccess(t *testing.T) {
+       log.Init()
+
+       db, mock, err := 
sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mock.ExpectBegin()
+       mock.ExpectPrepare("insert into  tcc_fence_log  (xid, branch_id, 
action_name, status, gmt_create, gmt_modified) values ( ?,?,?,?,?,?)").
+               ExpectExec().
+               WithArgs(sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), 
sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg()).
+               WillReturnResult(sqlmock.NewResult(1, 1))
+       mock.ExpectCommit()
+
+       tx, err := db.BeginTx(context.Background(), &sql.TxOptions{})
+       assert.NoError(t, err)
+
+       ctx := context.Background()
+       ctx = tm.InitSeataContext(ctx)
+       tm.SetXID(ctx, "test-xid-success")
+       tm.SetTxName(ctx, "test-tx")
+       tm.SetFencePhase(ctx, enum.FencePhasePrepare)
+       bac := &tm.BusinessActionContext{
+               Xid:        "test-xid-success",
+               BranchId:   999,
+               ActionName: "test-action",
+       }
+       tm.SetBusinessActionContext(ctx, bac)
+
+       callbackExecuted := false
+       callback := func() error {
+               callbackExecuted = true
+               return nil
+       }
+
+       err = WithFence(ctx, tx, callback)
+       assert.NoError(t, err)
+       assert.True(t, callbackExecuted)
+
+       tx.Commit()
+       assert.NoError(t, mock.ExpectationsWereMet())
+}
+
+func TestWithFence_CallbackErrorFormatting(t *testing.T) {
+       log.Init()
+
+       db, mock, err := 
sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mock.ExpectBegin()
+       mock.ExpectPrepare("insert into  tcc_fence_log  (xid, branch_id, 
action_name, status, gmt_create, gmt_modified) values ( ?,?,?,?,?,?)").
+               ExpectExec().
+               WithArgs(sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), 
sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg()).
+               WillReturnResult(sqlmock.NewResult(1, 1))
+       mock.ExpectCommit()
+
+       tx, err := db.BeginTx(context.Background(), &sql.TxOptions{})
+       assert.NoError(t, err)
+
+       ctx := context.Background()
+       ctx = tm.InitSeataContext(ctx)
+       tm.SetXID(ctx, "test-xid")
+       tm.SetTxName(ctx, "test-tx")
+       tm.SetFencePhase(ctx, enum.FencePhasePrepare)
+
+       bac := &tm.BusinessActionContext{
+               Xid:           "test-xid",
+               BranchId:      1001,
+               ActionName:    "test-action",
+               ActionContext: make(map[string]interface{}),
+       }
+       tm.SetBusinessActionContext(ctx, bac)
+
+       expectedCallbackErr := errors.New("specific business error")
+       callback := func() error {
+               return expectedCallbackErr
+       }
+
+       err = WithFence(ctx, tx, callback)
+       assert.Error(t, err)
+       assert.Contains(t, err.Error(), "the business method error msg of:")
+       assert.ErrorIs(t, err, expectedCallbackErr)
+}
+
+// Test OpenConnector with DriverContext.OpenConnector error
+func TestFenceDriver_OpenConnector_DriverContextError(t *testing.T) {
+       log.Init()
+
+       expectedErr := errors.New("open connector failed")
+       mockDriverCtx := &mockDriverContext{
+               openConnectorFunc: func(name string) (driver.Connector, error) {
+                       return nil, expectedErr
+               },
+       }
+
+       fd := &FenceDriver{
+               TargetDriver: mockDriverCtx,
+       }
+
+       connector, err := fd.OpenConnector("test-dsn")
+       assert.Error(t, err)
+       assert.Equal(t, expectedErr, err)
+       assert.Nil(t, connector)
+}
+
+// Test SeataFenceConnector.Connect with error
+func TestSeataFenceConnector_Connect_Error(t *testing.T) {
+       log.Init()
+
+       expectedErr := errors.New("connect failed")
+       mockConnector := &mockConnector{
+               connectFunc: func(ctx context.Context) (driver.Conn, error) {
+                       return nil, expectedErr
+               },
+       }
+
+       connector := &SeataFenceConnector{
+               TargetConnector: mockConnector,
+               TargetDB:        &sql.DB{},
+       }
+
+       conn, err := connector.Connect(context.Background())
+       assert.Error(t, err)
+       assert.Equal(t, expectedErr, err)
+       assert.Nil(t, conn)
+}
+
+// Mock DriverContext for testing
+type mockDriverContext struct {
+       driver.Driver
+       openConnectorFunc func(name string) (driver.Connector, error)
+}
+
+func (m *mockDriverContext) OpenConnector(name string) (driver.Connector, 
error) {
+       if m.openConnectorFunc != nil {
+               return m.openConnectorFunc(name)
+       }
+       return nil, errors.New("not implemented")
+}
+
+func (m *mockDriverContext) Open(name string) (driver.Conn, error) {
+       return nil, errors.New("not used")
+}
diff --git a/pkg/rm/tcc/fence/handler/tcc_fence_wrapper_handler_test.go 
b/pkg/rm/tcc/fence/handler/tcc_fence_wrapper_handler_test.go
new file mode 100644
index 00000000..c7c397a9
--- /dev/null
+++ b/pkg/rm/tcc/fence/handler/tcc_fence_wrapper_handler_test.go
@@ -0,0 +1,1027 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package handler
+
+import (
+       "context"
+       "database/sql"
+       "errors"
+       "sync"
+       "testing"
+       "time"
+
+       sqlmock "github.com/DATA-DOG/go-sqlmock"
+       "github.com/go-sql-driver/mysql"
+       "github.com/stretchr/testify/assert"
+
+       "seata.apache.org/seata-go/pkg/rm/tcc/fence/enum"
+       "seata.apache.org/seata-go/pkg/rm/tcc/fence/store/db/model"
+       "seata.apache.org/seata-go/pkg/tm"
+       "seata.apache.org/seata-go/pkg/util/log"
+)
+
+// mockTCCFenceStore is a mock implementation of TCCFenceStore for testing
+type mockTCCFenceStore struct {
+       mu                               sync.RWMutex
+       insertFunc                       func(tx *sql.Tx, tccFenceDo 
*model.TCCFenceDO) error
+       queryFunc                        func(tx *sql.Tx, xid string, branchId 
int64) (*model.TCCFenceDO, error)
+       updateFunc                       func(tx *sql.Tx, xid string, branchId 
int64, oldStatus enum.FenceStatus, newStatus enum.FenceStatus) error
+       deleteFunc                       func(tx *sql.Tx, xid string, branchId 
int64) error
+       deleteMultipleFunc               func(tx *sql.Tx, identity 
[]model.FenceLogIdentity) error
+       deleteTCCFenceDOByMdfDateFunc    func(tx *sql.Tx, datetime time.Time, 
limit int32) (int64, error)
+       queryTCCFenceLogIdentityByMdDate func(tx *sql.Tx, datetime time.Time) 
([]model.FenceLogIdentity, error)
+}
+
+func (m *mockTCCFenceStore) InsertTCCFenceDO(tx *sql.Tx, tccFenceDo 
*model.TCCFenceDO) error {
+       m.mu.RLock()
+       defer m.mu.RUnlock()
+       if m.insertFunc != nil {
+               return m.insertFunc(tx, tccFenceDo)
+       }
+       return nil
+}
+
+func (m *mockTCCFenceStore) QueryTCCFenceDO(tx *sql.Tx, xid string, branchId 
int64) (*model.TCCFenceDO, error) {
+       m.mu.RLock()
+       defer m.mu.RUnlock()
+       if m.queryFunc != nil {
+               return m.queryFunc(tx, xid, branchId)
+       }
+       return nil, nil
+}
+
+func (m *mockTCCFenceStore) UpdateTCCFenceDO(tx *sql.Tx, xid string, branchId 
int64, oldStatus enum.FenceStatus, newStatus enum.FenceStatus) error {
+       m.mu.RLock()
+       defer m.mu.RUnlock()
+       if m.updateFunc != nil {
+               return m.updateFunc(tx, xid, branchId, oldStatus, newStatus)
+       }
+       return nil
+}
+
+func (m *mockTCCFenceStore) DeleteTCCFenceDO(tx *sql.Tx, xid string, branchId 
int64) error {
+       m.mu.RLock()
+       defer m.mu.RUnlock()
+       if m.deleteFunc != nil {
+               return m.deleteFunc(tx, xid, branchId)
+       }
+       return nil
+}
+
+func (m *mockTCCFenceStore) DeleteMultipleTCCFenceLogIdentity(tx *sql.Tx, 
identity []model.FenceLogIdentity) error {
+       m.mu.RLock()
+       defer m.mu.RUnlock()
+       if m.deleteMultipleFunc != nil {
+               return m.deleteMultipleFunc(tx, identity)
+       }
+       return nil
+}
+
+func (m *mockTCCFenceStore) DeleteTCCFenceDOByMdfDate(tx *sql.Tx, datetime 
time.Time, limit int32) (int64, error) {
+       m.mu.RLock()
+       defer m.mu.RUnlock()
+       if m.deleteTCCFenceDOByMdfDateFunc != nil {
+               return m.deleteTCCFenceDOByMdfDateFunc(tx, datetime, limit)
+       }
+       return 0, nil
+}
+
+func (m *mockTCCFenceStore) QueryTCCFenceLogIdentityByMdDate(tx *sql.Tx, 
datetime time.Time) ([]model.FenceLogIdentity, error) {
+       m.mu.RLock()
+       defer m.mu.RUnlock()
+       if m.queryTCCFenceLogIdentityByMdDate != nil {
+               return m.queryTCCFenceLogIdentityByMdDate(tx, datetime)
+       }
+       return nil, nil
+}
+
+func (m *mockTCCFenceStore) SetLogTableName(logTable string) {
+       // No-op for mock
+}
+
+func createTestContext(xid string, branchId int64, actionName string) 
context.Context {
+       ctx := context.Background()
+       ctx = tm.InitSeataContext(ctx)
+       bac := &tm.BusinessActionContext{
+               Xid:        xid,
+               BranchId:   branchId,
+               ActionName: actionName,
+       }
+       tm.SetBusinessActionContext(ctx, bac)
+       return ctx
+}
+
+func TestGetFenceHandler(t *testing.T) {
+       log.Init()
+
+       handler1 := GetFenceHandler()
+       assert.NotNil(t, handler1)
+
+       handler2 := GetFenceHandler()
+       assert.Equal(t, handler1, handler2, "GetFenceHandler should return the 
same instance")
+}
+
+func TestInitCleanPeriod(t *testing.T) {
+       log.Init()
+
+       handler := GetFenceHandler()
+       testDuration := 10 * time.Minute
+
+       handler.InitCleanPeriod(testDuration)
+       assert.Equal(t, testDuration, cleanInterval)
+
+       // Reset to default for other tests
+       cleanInterval = 5 * time.Minute
+}
+
+func TestPrepareFence_Success(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mock.ExpectBegin()
+       tx, err := db.Begin()
+       assert.NoError(t, err)
+
+       mockDao := &mockTCCFenceStore{
+               insertFunc: func(tx *sql.Tx, tccFenceDo *model.TCCFenceDO) 
error {
+                       assert.Equal(t, "test-xid", tccFenceDo.Xid)
+                       assert.Equal(t, int64(123), tccFenceDo.BranchId)
+                       assert.Equal(t, "test-action", tccFenceDo.ActionName)
+                       assert.Equal(t, enum.StatusTried, tccFenceDo.Status)
+                       return nil
+               },
+       }
+
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: mockDao,
+       }
+
+       ctx := createTestContext("test-xid", 123, "test-action")
+       err = handler.PrepareFence(ctx, tx)
+       assert.NoError(t, err)
+}
+
+func TestPrepareFence_DuplicateEntry(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mock.ExpectBegin()
+       tx, err := db.Begin()
+       assert.NoError(t, err)
+
+       mysqlErr := &mysql.MySQLError{Number: 1062, Message: "Duplicate entry"}
+       mockDao := &mockTCCFenceStore{
+               insertFunc: func(tx *sql.Tx, tccFenceDo *model.TCCFenceDO) 
error {
+                       return mysqlErr
+               },
+       }
+
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: mockDao,
+               logQueue:    make(chan *model.FenceLogIdentity, maxQueueSize),
+       }
+
+       ctx := createTestContext("test-xid", 123, "test-action")
+       err = handler.PrepareFence(ctx, tx)
+       assert.Error(t, err)
+       assert.Contains(t, err.Error(), "insert tcc fence record errors")
+}
+
+func TestPrepareFence_InsertError(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mock.ExpectBegin()
+       tx, err := db.Begin()
+       assert.NoError(t, err)
+
+       mockDao := &mockTCCFenceStore{
+               insertFunc: func(tx *sql.Tx, tccFenceDo *model.TCCFenceDO) 
error {
+                       return errors.New("database error")
+               },
+       }
+
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: mockDao,
+       }
+
+       ctx := createTestContext("test-xid", 123, "test-action")
+       err = handler.PrepareFence(ctx, tx)
+       assert.Error(t, err)
+       assert.Contains(t, err.Error(), "insert tcc fence record errors")
+}
+
+func TestCommitFence_Success(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mock.ExpectBegin()
+       tx, err := db.Begin()
+       assert.NoError(t, err)
+
+       mockDao := &mockTCCFenceStore{
+               queryFunc: func(tx *sql.Tx, xid string, branchId int64) 
(*model.TCCFenceDO, error) {
+                       return &model.TCCFenceDO{
+                               Xid:      xid,
+                               BranchId: branchId,
+                               Status:   enum.StatusTried,
+                       }, nil
+               },
+               updateFunc: func(tx *sql.Tx, xid string, branchId int64, 
oldStatus enum.FenceStatus, newStatus enum.FenceStatus) error {
+                       assert.Equal(t, enum.StatusTried, oldStatus)
+                       assert.Equal(t, enum.StatusCommitted, newStatus)
+                       return nil
+               },
+       }
+
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: mockDao,
+       }
+
+       ctx := createTestContext("test-xid", 123, "test-action")
+       err = handler.CommitFence(ctx, tx)
+       assert.NoError(t, err)
+}
+
+func TestCommitFence_QueryError(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mock.ExpectBegin()
+       tx, err := db.Begin()
+       assert.NoError(t, err)
+
+       mockDao := &mockTCCFenceStore{
+               queryFunc: func(tx *sql.Tx, xid string, branchId int64) 
(*model.TCCFenceDO, error) {
+                       return nil, errors.New("query error")
+               },
+       }
+
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: mockDao,
+       }
+
+       ctx := createTestContext("test-xid", 123, "test-action")
+       err = handler.CommitFence(ctx, tx)
+       assert.Error(t, err)
+       assert.Contains(t, err.Error(), "commit fence method failed")
+}
+
+func TestCommitFence_RecordNotExists(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mock.ExpectBegin()
+       tx, err := db.Begin()
+       assert.NoError(t, err)
+
+       mockDao := &mockTCCFenceStore{
+               queryFunc: func(tx *sql.Tx, xid string, branchId int64) 
(*model.TCCFenceDO, error) {
+                       return nil, nil
+               },
+       }
+
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: mockDao,
+       }
+
+       ctx := createTestContext("test-xid", 123, "test-action")
+       err = handler.CommitFence(ctx, tx)
+       assert.Error(t, err)
+       assert.Contains(t, err.Error(), "tcc fence record not exists")
+}
+
+func TestCommitFence_AlreadyCommitted(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mock.ExpectBegin()
+       tx, err := db.Begin()
+       assert.NoError(t, err)
+
+       mockDao := &mockTCCFenceStore{
+               queryFunc: func(tx *sql.Tx, xid string, branchId int64) 
(*model.TCCFenceDO, error) {
+                       return &model.TCCFenceDO{
+                               Xid:      xid,
+                               BranchId: branchId,
+                               Status:   enum.StatusCommitted,
+                       }, nil
+               },
+       }
+
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: mockDao,
+       }
+
+       ctx := createTestContext("test-xid", 123, "test-action")
+       err = handler.CommitFence(ctx, tx)
+       assert.NoError(t, err)
+}
+
+func TestCommitFence_UnexpectedStatus_Rollbacked(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mock.ExpectBegin()
+       tx, err := db.Begin()
+       assert.NoError(t, err)
+
+       mockDao := &mockTCCFenceStore{
+               queryFunc: func(tx *sql.Tx, xid string, branchId int64) 
(*model.TCCFenceDO, error) {
+                       return &model.TCCFenceDO{
+                               Xid:      xid,
+                               BranchId: branchId,
+                               Status:   enum.StatusRollbacked,
+                       }, nil
+               },
+       }
+
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: mockDao,
+       }
+
+       ctx := createTestContext("test-xid", 123, "test-action")
+       err = handler.CommitFence(ctx, tx)
+       assert.Error(t, err)
+       assert.Contains(t, err.Error(), "branch transaction status is 
unexpected")
+}
+
+func TestCommitFence_UnexpectedStatus_Suspended(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mock.ExpectBegin()
+       tx, err := db.Begin()
+       assert.NoError(t, err)
+
+       mockDao := &mockTCCFenceStore{
+               queryFunc: func(tx *sql.Tx, xid string, branchId int64) 
(*model.TCCFenceDO, error) {
+                       return &model.TCCFenceDO{
+                               Xid:      xid,
+                               BranchId: branchId,
+                               Status:   enum.StatusSuspended,
+                       }, nil
+               },
+       }
+
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: mockDao,
+       }
+
+       ctx := createTestContext("test-xid", 123, "test-action")
+       err = handler.CommitFence(ctx, tx)
+       assert.Error(t, err)
+       assert.Contains(t, err.Error(), "branch transaction status is 
unexpected")
+}
+
+func TestRollbackFence_Success(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mock.ExpectBegin()
+       tx, err := db.Begin()
+       assert.NoError(t, err)
+
+       mockDao := &mockTCCFenceStore{
+               queryFunc: func(tx *sql.Tx, xid string, branchId int64) 
(*model.TCCFenceDO, error) {
+                       return &model.TCCFenceDO{
+                               Xid:      xid,
+                               BranchId: branchId,
+                               Status:   enum.StatusTried,
+                       }, nil
+               },
+               updateFunc: func(tx *sql.Tx, xid string, branchId int64, 
oldStatus enum.FenceStatus, newStatus enum.FenceStatus) error {
+                       assert.Equal(t, enum.StatusTried, oldStatus)
+                       assert.Equal(t, enum.StatusRollbacked, newStatus)
+                       return nil
+               },
+       }
+
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: mockDao,
+       }
+
+       ctx := createTestContext("test-xid", 123, "test-action")
+       err = handler.RollbackFence(ctx, tx)
+       assert.NoError(t, err)
+}
+
+func TestRollbackFence_QueryError(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mock.ExpectBegin()
+       tx, err := db.Begin()
+       assert.NoError(t, err)
+
+       mockDao := &mockTCCFenceStore{
+               queryFunc: func(tx *sql.Tx, xid string, branchId int64) 
(*model.TCCFenceDO, error) {
+                       return nil, errors.New("query error")
+               },
+       }
+
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: mockDao,
+       }
+
+       ctx := createTestContext("test-xid", 123, "test-action")
+       err = handler.RollbackFence(ctx, tx)
+       assert.Error(t, err)
+       assert.Contains(t, err.Error(), "rollback fence method failed")
+}
+
+func TestRollbackFence_RecordNotExists_InsertSuspended(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mock.ExpectBegin()
+       tx, err := db.Begin()
+       assert.NoError(t, err)
+
+       mockDao := &mockTCCFenceStore{
+               queryFunc: func(tx *sql.Tx, xid string, branchId int64) 
(*model.TCCFenceDO, error) {
+                       return nil, nil
+               },
+               insertFunc: func(tx *sql.Tx, tccFenceDo *model.TCCFenceDO) 
error {
+                       assert.Equal(t, enum.StatusSuspended, tccFenceDo.Status)
+                       return nil
+               },
+       }
+
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: mockDao,
+       }
+
+       ctx := createTestContext("test-xid", 123, "test-action")
+       err = handler.RollbackFence(ctx, tx)
+       assert.NoError(t, err)
+}
+
+func TestRollbackFence_RecordNotExists_InsertError(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mock.ExpectBegin()
+       tx, err := db.Begin()
+       assert.NoError(t, err)
+
+       mockDao := &mockTCCFenceStore{
+               queryFunc: func(tx *sql.Tx, xid string, branchId int64) 
(*model.TCCFenceDO, error) {
+                       return nil, nil
+               },
+               insertFunc: func(tx *sql.Tx, tccFenceDo *model.TCCFenceDO) 
error {
+                       return errors.New("insert error")
+               },
+       }
+
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: mockDao,
+       }
+
+       ctx := createTestContext("test-xid", 123, "test-action")
+       err = handler.RollbackFence(ctx, tx)
+       assert.Error(t, err)
+       assert.Contains(t, err.Error(), "insert tcc fence record errors")
+}
+
+func TestRollbackFence_AlreadyRollbacked(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mock.ExpectBegin()
+       tx, err := db.Begin()
+       assert.NoError(t, err)
+
+       mockDao := &mockTCCFenceStore{
+               queryFunc: func(tx *sql.Tx, xid string, branchId int64) 
(*model.TCCFenceDO, error) {
+                       return &model.TCCFenceDO{
+                               Xid:      xid,
+                               BranchId: branchId,
+                               Status:   enum.StatusRollbacked,
+                       }, nil
+               },
+       }
+
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: mockDao,
+       }
+
+       ctx := createTestContext("test-xid", 123, "test-action")
+       err = handler.RollbackFence(ctx, tx)
+       assert.NoError(t, err)
+}
+
+func TestRollbackFence_AlreadySuspended(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mock.ExpectBegin()
+       tx, err := db.Begin()
+       assert.NoError(t, err)
+
+       mockDao := &mockTCCFenceStore{
+               queryFunc: func(tx *sql.Tx, xid string, branchId int64) 
(*model.TCCFenceDO, error) {
+                       return &model.TCCFenceDO{
+                               Xid:      xid,
+                               BranchId: branchId,
+                               Status:   enum.StatusSuspended,
+                       }, nil
+               },
+       }
+
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: mockDao,
+       }
+
+       ctx := createTestContext("test-xid", 123, "test-action")
+       err = handler.RollbackFence(ctx, tx)
+       assert.NoError(t, err)
+}
+
+func TestRollbackFence_UnexpectedStatus_Committed(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mock.ExpectBegin()
+       tx, err := db.Begin()
+       assert.NoError(t, err)
+
+       mockDao := &mockTCCFenceStore{
+               queryFunc: func(tx *sql.Tx, xid string, branchId int64) 
(*model.TCCFenceDO, error) {
+                       return &model.TCCFenceDO{
+                               Xid:      xid,
+                               BranchId: branchId,
+                               Status:   enum.StatusCommitted,
+                       }, nil
+               },
+       }
+
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: mockDao,
+       }
+
+       ctx := createTestContext("test-xid", 123, "test-action")
+       err = handler.RollbackFence(ctx, tx)
+       assert.Error(t, err)
+       assert.Contains(t, err.Error(), "branch transaction status is 
unexpected")
+}
+
+func TestInsertTCCFenceLog(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mock.ExpectBegin()
+       tx, err := db.Begin()
+       assert.NoError(t, err)
+
+       mockDao := &mockTCCFenceStore{
+               insertFunc: func(tx *sql.Tx, tccFenceDo *model.TCCFenceDO) 
error {
+                       assert.Equal(t, "test-xid", tccFenceDo.Xid)
+                       assert.Equal(t, int64(456), tccFenceDo.BranchId)
+                       assert.Equal(t, "test-action", tccFenceDo.ActionName)
+                       assert.Equal(t, enum.StatusTried, tccFenceDo.Status)
+                       return nil
+               },
+       }
+
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: mockDao,
+       }
+
+       err = handler.insertTCCFenceLog(tx, "test-xid", 456, "test-action", 
enum.StatusTried)
+       assert.NoError(t, err)
+}
+
+func TestUpdateFenceStatus(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mock.ExpectBegin()
+       tx, err := db.Begin()
+       assert.NoError(t, err)
+
+       mockDao := &mockTCCFenceStore{
+               updateFunc: func(tx *sql.Tx, xid string, branchId int64, 
oldStatus enum.FenceStatus, newStatus enum.FenceStatus) error {
+                       assert.Equal(t, "test-xid", xid)
+                       assert.Equal(t, int64(789), branchId)
+                       assert.Equal(t, enum.StatusTried, oldStatus)
+                       assert.Equal(t, enum.StatusCommitted, newStatus)
+                       return nil
+               },
+       }
+
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: mockDao,
+       }
+
+       err = handler.updateFenceStatus(tx, "test-xid", 789, 
enum.StatusCommitted)
+       assert.NoError(t, err)
+}
+
+func TestDeleteBatchFence_Success(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mock.ExpectBegin()
+       tx, err := db.Begin()
+       assert.NoError(t, err)
+
+       batch := []model.FenceLogIdentity{
+               {Xid: "xid1", BranchId: 1},
+               {Xid: "xid2", BranchId: 2},
+       }
+
+       mockDao := &mockTCCFenceStore{
+               deleteMultipleFunc: func(tx *sql.Tx, identity 
[]model.FenceLogIdentity) error {
+                       assert.Equal(t, batch, identity)
+                       return nil
+               },
+       }
+
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: mockDao,
+       }
+
+       err = handler.deleteBatchFence(tx, batch)
+       assert.NoError(t, err)
+}
+
+func TestDeleteBatchFence_Error(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       mock.ExpectBegin()
+       tx, err := db.Begin()
+       assert.NoError(t, err)
+
+       batch := []model.FenceLogIdentity{
+               {Xid: "xid1", BranchId: 1},
+       }
+
+       mockDao := &mockTCCFenceStore{
+               deleteMultipleFunc: func(tx *sql.Tx, identity 
[]model.FenceLogIdentity) error {
+                       return errors.New("delete error")
+               },
+       }
+
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: mockDao,
+       }
+
+       err = handler.deleteBatchFence(tx, batch)
+       assert.Error(t, err)
+       assert.Contains(t, err.Error(), "delete batch fence log failed")
+}
+
+func TestPushCleanChannel(t *testing.T) {
+       log.Init()
+
+       handler := &tccFenceWrapperHandler{
+               logQueue: make(chan *model.FenceLogIdentity, maxQueueSize),
+       }
+
+       handler.pushCleanChannel("test-xid", 123)
+
+       select {
+       case fli := <-handler.logQueue:
+               assert.Equal(t, "test-xid", fli.Xid)
+               assert.Equal(t, int64(123), fli.BranchId)
+       case <-time.After(1 * time.Second):
+               t.Fatal("Expected to receive from logQueue")
+       }
+}
+
+func TestPushCleanChannel_FullQueue(t *testing.T) {
+       log.Init()
+
+       handler := &tccFenceWrapperHandler{
+               logQueue: make(chan *model.FenceLogIdentity, 1),
+       }
+
+       // Fill the queue
+       handler.pushCleanChannel("xid1", 1)
+
+       // This should add to cache instead
+       handler.pushCleanChannel("xid2", 2)
+
+       // Verify queue has first item
+       select {
+       case fli := <-handler.logQueue:
+               assert.Equal(t, "xid1", fli.Xid)
+       default:
+               t.Fatal("Expected queue to have item")
+       }
+
+       // Verify cache has second item
+       assert.Equal(t, 1, handler.logCache.Len())
+}
+
+func TestDestroyLogCleanChannel(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+
+       mock.ExpectClose()
+
+       handler := &tccFenceWrapperHandler{
+               logQueue: make(chan *model.FenceLogIdentity, maxQueueSize),
+               db:       db,
+       }
+
+       handler.DestroyLogCleanChannel()
+
+       // Verify channel is closed
+       _, ok := <-handler.logQueue
+       assert.False(t, ok, "logQueue should be closed")
+
+       // Verify db is nil
+       assert.Nil(t, handler.db)
+}
+
+func TestDestroyLogCleanChannel_OnlyOnce(t *testing.T) {
+       log.Init()
+
+       handler := &tccFenceWrapperHandler{
+               logQueue: make(chan *model.FenceLogIdentity, maxQueueSize),
+       }
+
+       // Call multiple times
+       handler.DestroyLogCleanChannel()
+       handler.DestroyLogCleanChannel()
+       handler.DestroyLogCleanChannel()
+
+       // Should only close once without panic
+       assert.Nil(t, handler.db)
+}
+
+func TestTraversalCleanChannel(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       // Expect Begin and Commit for batch delete
+       mock.ExpectBegin()
+       mock.ExpectCommit()
+
+       mockDao := &mockTCCFenceStore{
+               deleteMultipleFunc: func(tx *sql.Tx, identity 
[]model.FenceLogIdentity) error {
+                       // Verify we're deleting the expected batch
+                       assert.Equal(t, channelDelete, len(identity))
+                       return nil
+               },
+       }
+
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: mockDao,
+               logQueue:    make(chan *model.FenceLogIdentity, maxQueueSize),
+       }
+
+       // Start the goroutine
+       go handler.traversalCleanChannel(db)
+
+       // Push exactly channelDelete items to trigger batch delete
+       for i := 0; i < channelDelete; i++ {
+               handler.logQueue <- &model.FenceLogIdentity{
+                       Xid:      "test-xid",
+                       BranchId: int64(i),
+               }
+       }
+
+       // Give it time to process
+       time.Sleep(100 * time.Millisecond)
+
+       // Close the channel to stop the goroutine
+       close(handler.logQueue)
+
+       // Give it time to finish
+       time.Sleep(100 * time.Millisecond)
+
+       // Verify expectations
+       assert.NoError(t, mock.ExpectationsWereMet())
+}
+
+func TestTraversalCleanChannel_RemainingBatch(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       // Expect Begin and Commit for final batch
+       mock.ExpectBegin()
+       mock.ExpectCommit()
+
+       mockDao := &mockTCCFenceStore{
+               deleteMultipleFunc: func(tx *sql.Tx, identity 
[]model.FenceLogIdentity) error {
+                       // Verify we're deleting the remaining items
+                       assert.Equal(t, 3, len(identity))
+                       return nil
+               },
+       }
+
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: mockDao,
+               logQueue:    make(chan *model.FenceLogIdentity, maxQueueSize),
+       }
+
+       // Start the goroutine
+       go handler.traversalCleanChannel(db)
+
+       // Push less than channelDelete items
+       for i := 0; i < 3; i++ {
+               handler.logQueue <- &model.FenceLogIdentity{
+                       Xid:      "test-xid",
+                       BranchId: int64(i),
+               }
+       }
+
+       // Give it time to process
+       time.Sleep(100 * time.Millisecond)
+
+       // Close the channel to stop the goroutine and trigger final batch
+       close(handler.logQueue)
+
+       // Give it time to finish
+       time.Sleep(100 * time.Millisecond)
+
+       // Verify expectations
+       assert.NoError(t, mock.ExpectationsWereMet())
+}
+
+func TestTraversalCleanChannel_DeleteError(t *testing.T) {
+       log.Init()
+
+       db, mock, err := sqlmock.New()
+       assert.NoError(t, err)
+       defer db.Close()
+
+       // Expect Begin but delete will fail
+       mock.ExpectBegin()
+
+       mockDao := &mockTCCFenceStore{
+               deleteMultipleFunc: func(tx *sql.Tx, identity 
[]model.FenceLogIdentity) error {
+                       return errors.New("delete failed")
+               },
+       }
+
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: mockDao,
+               logQueue:    make(chan *model.FenceLogIdentity, maxQueueSize),
+       }
+
+       // Start the goroutine
+       go handler.traversalCleanChannel(db)
+
+       // Push channelDelete items to trigger batch delete
+       for i := 0; i < channelDelete; i++ {
+               handler.logQueue <- &model.FenceLogIdentity{
+                       Xid:      "test-xid",
+                       BranchId: int64(i),
+               }
+       }
+
+       // Give it time to process
+       time.Sleep(100 * time.Millisecond)
+
+       // Close the channel
+       close(handler.logQueue)
+
+       // Give it time to finish
+       time.Sleep(100 * time.Millisecond)
+}
+
+func TestInitLogCleanChannel(t *testing.T) {
+       log.Init()
+
+       // Create a test DSN for sqlmock
+       db, mock, err := sqlmock.New(sqlmock.MonitorPingsOption(true))
+       assert.NoError(t, err)
+       defer db.Close()
+
+       // We can't easily test the actual goroutines, but we can verify
+       // the function doesn't panic and initializes the handler
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: &mockTCCFenceStore{},
+       }
+
+       // Test with invalid DSN (won't connect but won't panic)
+       handler.InitLogCleanChannel("invalid-dsn")
+
+       // Verify db was attempted to be set
+       handler.dbMutex.RLock()
+       dbSet := handler.db != nil
+       handler.dbMutex.RUnlock()
+
+       // With invalid DSN, db should still be nil
+       assert.False(t, dbSet)
+
+       // Clean up
+       if err := mock.ExpectationsWereMet(); err != nil {
+               // It's okay if expectations aren't met with invalid DSN
+               t.Logf("Expected behavior with invalid DSN: %v", err)
+       }
+}
+
+func TestInitLogCleanChannel_EmptyDSN(t *testing.T) {
+       log.Init()
+
+       handler := &tccFenceWrapperHandler{
+               tccFenceDao: &mockTCCFenceStore{},
+       }
+
+       // Test with empty DSN - sql.Open still returns a non-nil DB even with 
empty DSN
+       // but it may not be usable
+       handler.InitLogCleanChannel("")
+
+       // Verify db was attempted to be set (sql.Open returns non-nil DB even 
with empty DSN)
+       handler.dbMutex.RLock()
+       defer handler.dbMutex.RUnlock()
+       // DB object is created but may not be functional
+       assert.NotNil(t, handler.db)
+}
+
+func TestConstants(t *testing.T) {
+       // Verify constants are set as expected
+       assert.Equal(t, 500, maxQueueSize)
+       assert.Equal(t, 5, channelDelete)
+       assert.Equal(t, 24*time.Hour, cleanExpired)
+       assert.Equal(t, 5*time.Minute, cleanInterval)
+}
diff --git a/pkg/rm/tcc/fence/store/db/sql/tcc_fence_store_sql_test.go 
b/pkg/rm/tcc/fence/store/db/sql/tcc_fence_store_sql_test.go
new file mode 100644
index 00000000..8fe0d2cc
--- /dev/null
+++ b/pkg/rm/tcc/fence/store/db/sql/tcc_fence_store_sql_test.go
@@ -0,0 +1,409 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package sql
+
+import (
+       "strconv"
+       "strings"
+       "testing"
+
+       "github.com/stretchr/testify/assert"
+
+       "seata.apache.org/seata-go/pkg/rm/tcc/fence/enum"
+)
+
+func TestGetInsertLocalTCCLogSQL(t *testing.T) {
+       tests := []struct {
+               name           string
+               localTccTable  string
+               expectedResult string
+       }{
+               {
+                       name:           "standard table name",
+                       localTccTable:  "tcc_fence_log",
+                       expectedResult: "insert into  tcc_fence_log  (xid, 
branch_id, action_name, status, gmt_create, gmt_modified) values ( 
?,?,?,?,?,?)",
+               },
+               {
+                       name:           "custom table name",
+                       localTccTable:  "my_custom_tcc_log",
+                       expectedResult: "insert into  my_custom_tcc_log  (xid, 
branch_id, action_name, status, gmt_create, gmt_modified) values ( 
?,?,?,?,?,?)",
+               },
+               {
+                       name:           "table name with schema",
+                       localTccTable:  "schema.tcc_log",
+                       expectedResult: "insert into  schema.tcc_log  (xid, 
branch_id, action_name, status, gmt_create, gmt_modified) values ( 
?,?,?,?,?,?)",
+               },
+               {
+                       name:           "empty table name",
+                       localTccTable:  "",
+                       expectedResult: "insert into    (xid, branch_id, 
action_name, status, gmt_create, gmt_modified) values ( ?,?,?,?,?,?)",
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       result := GetInsertLocalTCCLogSQL(tt.localTccTable)
+                       assert.Equal(t, tt.expectedResult, result)
+                       // Verify the SQL contains the required placeholders
+                       assert.Contains(t, result, "insert into")
+                       assert.Contains(t, result, "xid, branch_id, 
action_name, status, gmt_create, gmt_modified")
+                       assert.Contains(t, result, "?,?,?,?,?,?")
+               })
+       }
+}
+
+func TestGetQuerySQLByBranchIdAndXid(t *testing.T) {
+       tests := []struct {
+               name           string
+               localTccTable  string
+               expectedResult string
+       }{
+               {
+                       name:           "standard table name",
+                       localTccTable:  "tcc_fence_log",
+                       expectedResult: "select xid, branch_id, action_name, 
status, gmt_create, gmt_modified from  tcc_fence_log  where xid = ? and 
branch_id = ? for update",
+               },
+               {
+                       name:           "custom table name",
+                       localTccTable:  "my_tcc_table",
+                       expectedResult: "select xid, branch_id, action_name, 
status, gmt_create, gmt_modified from  my_tcc_table  where xid = ? and 
branch_id = ? for update",
+               },
+               {
+                       name:           "empty table name",
+                       localTccTable:  "",
+                       expectedResult: "select xid, branch_id, action_name, 
status, gmt_create, gmt_modified from    where xid = ? and branch_id = ? for 
update",
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       result := GetQuerySQLByBranchIdAndXid(tt.localTccTable)
+                       assert.Equal(t, tt.expectedResult, result)
+                       // Verify the SQL structure
+                       assert.Contains(t, result, "select")
+                       assert.Contains(t, result, "where xid = ? and branch_id 
= ?")
+                       assert.Contains(t, result, "for update")
+               })
+       }
+}
+
+func TestGetUpdateStatusSQLByBranchIdAndXid(t *testing.T) {
+       tests := []struct {
+               name           string
+               localTccTable  string
+               expectedResult string
+       }{
+               {
+                       name:           "standard table name",
+                       localTccTable:  "tcc_fence_log",
+                       expectedResult: "update  tcc_fence_log  set status = ?, 
gmt_modified = ? where xid = ? and  branch_id = ? and status = ? ",
+               },
+               {
+                       name:           "custom table name",
+                       localTccTable:  "custom_fence",
+                       expectedResult: "update  custom_fence  set status = ?, 
gmt_modified = ? where xid = ? and  branch_id = ? and status = ? ",
+               },
+               {
+                       name:           "empty table name",
+                       localTccTable:  "",
+                       expectedResult: "update    set status = ?, gmt_modified 
= ? where xid = ? and  branch_id = ? and status = ? ",
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       result := 
GetUpdateStatusSQLByBranchIdAndXid(tt.localTccTable)
+                       assert.Equal(t, tt.expectedResult, result)
+                       // Verify the SQL structure
+                       assert.Contains(t, result, "update")
+                       assert.Contains(t, result, "set status = ?, 
gmt_modified = ?")
+                       assert.Contains(t, result, "where xid = ? and  
branch_id = ? and status = ?")
+                       // Verify the correct number of placeholders (5 total)
+                       assert.Equal(t, 5, strings.Count(result, "?"))
+               })
+       }
+}
+
+func TestGetDeleteSQLByBranchIdAndXid(t *testing.T) {
+       tests := []struct {
+               name           string
+               localTccTable  string
+               expectedResult string
+       }{
+               {
+                       name:           "standard table name",
+                       localTccTable:  "tcc_fence_log",
+                       expectedResult: "delete from  tcc_fence_log  where xid 
= ? and  branch_id = ? ",
+               },
+               {
+                       name:           "custom table name",
+                       localTccTable:  "my_table",
+                       expectedResult: "delete from  my_table  where xid = ? 
and  branch_id = ? ",
+               },
+               {
+                       name:           "empty table name",
+                       localTccTable:  "",
+                       expectedResult: "delete from    where xid = ? and  
branch_id = ? ",
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       result := GetDeleteSQLByBranchIdAndXid(tt.localTccTable)
+                       assert.Equal(t, tt.expectedResult, result)
+                       // Verify the SQL structure
+                       assert.Contains(t, result, "delete from")
+                       assert.Contains(t, result, "where xid = ? and  
branch_id = ?")
+                       // Verify the correct number of placeholders (2 total)
+                       assert.Equal(t, 2, strings.Count(result, "?"))
+               })
+       }
+}
+
+func TestGertDeleteSQLByBranchIdsAndXids(t *testing.T) {
+       tests := []struct {
+               name              string
+               localTccTable     string
+               paramsPlaceHolder string
+               expectedResult    string
+       }{
+               {
+                       name:              "single pair of parameters",
+                       localTccTable:     "tcc_fence_log",
+                       paramsPlaceHolder: "(?,?)",
+                       expectedResult:    "delete from  tcc_fence_log  where 
(xid,branch_id) in ((?,?) )",
+               },
+               {
+                       name:              "multiple pairs of parameters",
+                       localTccTable:     "tcc_fence_log",
+                       paramsPlaceHolder: "(?,?),(?,?),(?,?)",
+                       expectedResult:    "delete from  tcc_fence_log  where 
(xid,branch_id) in ((?,?),(?,?),(?,?) )",
+               },
+               {
+                       name:              "custom table with multiple 
parameters",
+                       localTccTable:     "custom_log",
+                       paramsPlaceHolder: "(?,?),(?,?)",
+                       expectedResult:    "delete from  custom_log  where 
(xid,branch_id) in ((?,?),(?,?) )",
+               },
+               {
+                       name:              "empty table name",
+                       localTccTable:     "",
+                       paramsPlaceHolder: "(?,?)",
+                       expectedResult:    "delete from    where 
(xid,branch_id) in ((?,?) )",
+               },
+               {
+                       name:              "empty placeholder",
+                       localTccTable:     "tcc_fence_log",
+                       paramsPlaceHolder: "",
+                       expectedResult:    "delete from  tcc_fence_log  where 
(xid,branch_id) in ( )",
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       result := 
GertDeleteSQLByBranchIdsAndXids(tt.localTccTable, tt.paramsPlaceHolder)
+                       assert.Equal(t, tt.expectedResult, result)
+                       // Verify the SQL structure
+                       assert.Contains(t, result, "delete from")
+                       assert.Contains(t, result, "where (xid,branch_id) in")
+               })
+       }
+}
+
+func TestGetDeleteSQLByMdfDateAndStatus(t *testing.T) {
+       // Pre-calculate the expected status values
+       statusCommitted := strconv.Itoa(int(enum.StatusCommitted))
+       statusRollbacked := strconv.Itoa(int(enum.StatusRollbacked))
+       statusSuspended := strconv.Itoa(int(enum.StatusSuspended))
+
+       tests := []struct {
+               name           string
+               localTccTable  string
+               expectedResult string
+       }{
+               {
+                       name:           "standard table name",
+                       localTccTable:  "tcc_fence_log",
+                       expectedResult: "delete from  tcc_fence_log  where 
gmt_modified < ?  and status in (" + statusCommitted + " , " + statusRollbacked 
+ " , " + statusSuspended + ") limit ?",
+               },
+               {
+                       name:           "custom table name",
+                       localTccTable:  "my_custom_table",
+                       expectedResult: "delete from  my_custom_table  where 
gmt_modified < ?  and status in (" + statusCommitted + " , " + statusRollbacked 
+ " , " + statusSuspended + ") limit ?",
+               },
+               {
+                       name:           "empty table name",
+                       localTccTable:  "",
+                       expectedResult: "delete from    where gmt_modified < ?  
and status in (" + statusCommitted + " , " + statusRollbacked + " , " + 
statusSuspended + ") limit ?",
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       result := 
GetDeleteSQLByMdfDateAndStatus(tt.localTccTable)
+                       assert.Equal(t, tt.expectedResult, result)
+                       // Verify the SQL structure
+                       assert.Contains(t, result, "delete from")
+                       assert.Contains(t, result, "where gmt_modified < ?")
+                       assert.Contains(t, result, "status in")
+                       assert.Contains(t, result, "limit ?")
+                       // Verify it contains the status values
+                       assert.Contains(t, result, statusCommitted)
+                       assert.Contains(t, result, statusRollbacked)
+                       assert.Contains(t, result, statusSuspended)
+                       // Verify the correct number of placeholders (2 total: 
date and limit)
+                       assert.Equal(t, 2, strings.Count(result, "?"))
+               })
+       }
+}
+
+func TestGetQuerySQLByMdDate(t *testing.T) {
+       // Pre-calculate the expected status values
+       statusCommitted := strconv.Itoa(int(enum.StatusCommitted))
+       statusRollbacked := strconv.Itoa(int(enum.StatusRollbacked))
+       statusSuspended := strconv.Itoa(int(enum.StatusSuspended))
+
+       tests := []struct {
+               name           string
+               localTccTable  string
+               expectedResult string
+       }{
+               {
+                       name:           "standard table name",
+                       localTccTable:  "tcc_fence_log",
+                       expectedResult: "select xid, branch_id from  
tcc_fence_log  where gmt_modified < ?  and status in (" + statusCommitted + " , 
" + statusRollbacked + " , " + statusSuspended + ")",
+               },
+               {
+                       name:           "custom table name",
+                       localTccTable:  "my_log_table",
+                       expectedResult: "select xid, branch_id from  
my_log_table  where gmt_modified < ?  and status in (" + statusCommitted + " , 
" + statusRollbacked + " , " + statusSuspended + ")",
+               },
+               {
+                       name:           "empty table name",
+                       localTccTable:  "",
+                       expectedResult: "select xid, branch_id from    where 
gmt_modified < ?  and status in (" + statusCommitted + " , " + statusRollbacked 
+ " , " + statusSuspended + ")",
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       result := GetQuerySQLByMdDate(tt.localTccTable)
+                       assert.Equal(t, tt.expectedResult, result)
+                       // Verify the SQL structure
+                       assert.Contains(t, result, "select xid, branch_id from")
+                       assert.Contains(t, result, "where gmt_modified < ?")
+                       assert.Contains(t, result, "status in")
+                       // Verify it contains the status values
+                       assert.Contains(t, result, statusCommitted)
+                       assert.Contains(t, result, statusRollbacked)
+                       assert.Contains(t, result, statusSuspended)
+                       // Verify the correct number of placeholders (1 total: 
date)
+                       assert.Equal(t, 1, strings.Count(result, "?"))
+               })
+       }
+}
+
+func TestSQLTemplateConsistency(t *testing.T) {
+       // Test that SQL templates properly handle table name substitution
+       tableName := "test_table"
+
+       t.Run("all functions return non-empty strings", func(t *testing.T) {
+               assert.NotEmpty(t, GetInsertLocalTCCLogSQL(tableName))
+               assert.NotEmpty(t, GetQuerySQLByBranchIdAndXid(tableName))
+               assert.NotEmpty(t, 
GetUpdateStatusSQLByBranchIdAndXid(tableName))
+               assert.NotEmpty(t, GetDeleteSQLByBranchIdAndXid(tableName))
+               assert.NotEmpty(t, GertDeleteSQLByBranchIdsAndXids(tableName, 
"(?,?)"))
+               assert.NotEmpty(t, GetDeleteSQLByMdfDateAndStatus(tableName))
+               assert.NotEmpty(t, GetQuerySQLByMdDate(tableName))
+       })
+
+       t.Run("all functions properly inject table name", func(t *testing.T) {
+               assert.Contains(t, GetInsertLocalTCCLogSQL(tableName), 
tableName)
+               assert.Contains(t, GetQuerySQLByBranchIdAndXid(tableName), 
tableName)
+               assert.Contains(t, 
GetUpdateStatusSQLByBranchIdAndXid(tableName), tableName)
+               assert.Contains(t, GetDeleteSQLByBranchIdAndXid(tableName), 
tableName)
+               assert.Contains(t, GertDeleteSQLByBranchIdsAndXids(tableName, 
"(?,?)"), tableName)
+               assert.Contains(t, GetDeleteSQLByMdfDateAndStatus(tableName), 
tableName)
+               assert.Contains(t, GetQuerySQLByMdDate(tableName), tableName)
+       })
+}
+
+func TestStatusEnumValues(t *testing.T) {
+       // Verify that the status enum values used in SQL generation are correct
+       t.Run("status values are as expected", func(t *testing.T) {
+               assert.Equal(t, enum.FenceStatus(1), enum.StatusTried)
+               assert.Equal(t, enum.FenceStatus(2), enum.StatusCommitted)
+               assert.Equal(t, enum.FenceStatus(3), enum.StatusRollbacked)
+               assert.Equal(t, enum.FenceStatus(4), enum.StatusSuspended)
+       })
+
+       t.Run("status values in SQL match enum", func(t *testing.T) {
+               sql := GetDeleteSQLByMdfDateAndStatus("test_table")
+
+               // Verify the SQL contains the correct status values
+               assert.Contains(t, sql, strconv.Itoa(int(enum.StatusCommitted)))
+               assert.Contains(t, sql, 
strconv.Itoa(int(enum.StatusRollbacked)))
+               assert.Contains(t, sql, strconv.Itoa(int(enum.StatusSuspended)))
+
+               // Verify StatusTried is NOT in the cleanup SQL (as it's an 
active status)
+               assert.NotContains(t, sql, strconv.Itoa(int(enum.StatusTried)))
+       })
+}
+
+func TestSQLInjectionProtection(t *testing.T) {
+       // Test that the functions handle potentially malicious input
+       // Note: The actual protection comes from using prepared statements 
with ?
+       // These tests verify the SQL structure remains valid even with unusual 
table names
+
+       tests := []struct {
+               name      string
+               tableName string
+       }{
+               {
+                       name:      "table name with quotes",
+                       tableName: "table'name",
+               },
+               {
+                       name:      "table name with semicolon",
+                       tableName: "table;name",
+               },
+               {
+                       name:      "table name with dashes",
+                       tableName: "table-name-test",
+               },
+               {
+                       name:      "table name with underscores",
+                       tableName: "table_name_test",
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       // All functions should handle these inputs without 
panic
+                       assert.NotPanics(t, func() {
+                               GetInsertLocalTCCLogSQL(tt.tableName)
+                               GetQuerySQLByBranchIdAndXid(tt.tableName)
+                               GetUpdateStatusSQLByBranchIdAndXid(tt.tableName)
+                               GetDeleteSQLByBranchIdAndXid(tt.tableName)
+                               GertDeleteSQLByBranchIdsAndXids(tt.tableName, 
"(?,?)")
+                               GetDeleteSQLByMdfDateAndStatus(tt.tableName)
+                               GetQuerySQLByMdDate(tt.tableName)
+                       })
+               })
+       }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to