Scert/backend/internal/database/sqlite_deadline_fault_test.go

80 lines
2.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package database
import (
"context"
"database/sql/driver"
"errors"
"strings"
"testing"
"time"
)
type sqliteDeadlineFaultConn struct {
sqliteDriverConn
commands []string
failAt int
err error
}
func (c *sqliteDeadlineFaultConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
c.commands = append(c.commands, query)
if len(c.commands) == c.failAt {
return nil, c.err
}
return driver.RowsAffected(0), nil
}
func (c *sqliteDeadlineFaultConn) IsValid() bool { return true }
func TestSQLiteDeadlineFailureNeverReplaysOperation(t *testing.T) {
for _, name := range []string{"setup_failure", "restore_failure", "operation_failure", "already_canceled"} {
t.Run(name, func(t *testing.T) {
failure := errors.New("注入的隔离测试错误")
raw := &sqliteDeadlineFaultConn{err: failure}
conn := &sqliteDeadlineConn{sqliteDriverConn: raw}
ctx, cancel := context.WithTimeout(t.Context(), time.Second)
defer cancel()
wantRuns := 1
switch name {
case "setup_failure":
raw.failAt = 1
wantRuns = 0
case "restore_failure":
raw.failAt = 2
case "already_canceled":
cancel()
wantRuns = 0
}
runs := 0
_, err := sqliteWithDeadline(conn, ctx, func() (int, error) {
runs++
if name == "operation_failure" {
return 0, failure
}
return 7, nil
})
if err == nil || runs != wantRuns || errors.Is(err, driver.ErrBadConn) {
t.Fatalf("错误处理发生重放或丢失:执行次数=%d,错误=%v", runs, err)
}
if name == "setup_failure" || name == "restore_failure" {
if conn.IsValid() || !errors.Is(conn.ResetSession(t.Context()), driver.ErrBadConn) {
t.Fatal("配置状态不确定的连接仍可被复用")
}
}
if name == "operation_failure" {
if !errors.Is(err, failure) || len(raw.commands) != 2 || raw.commands[1] != "PRAGMA busy_timeout = 5000" || !conn.IsValid() {
t.Fatalf("业务错误后没有保留错误或恢复连接配置:%v", raw.commands)
}
}
if name == "already_canceled" && (len(raw.commands) != 0 || !errors.Is(err, context.Canceled)) {
t.Fatal("已经取消的调用仍然修改了连接")
}
for _, command := range raw.commands {
if !strings.HasPrefix(command, "PRAGMA busy_timeout = ") {
t.Fatalf("执行了额外 SQL:%s", command)
}
}
})
}
}