Files
go-trustlog/api/persistence/example_test.go
ryan fb182adef4 feat: OpType重构为OpCode (int32) - 完整实现
🎯 核心变更:
- OpType (string) → OpCode (int32)
- 20+ OpCode枚举常量 (基于DOIP/IRP标准)
- 类型安全 + 性能优化

📊 影响范围:
- 核心模型: Operation结构体、CBOR序列化
- 数据库: schema.go + SQL DDL (PostgreSQL/MySQL/SQLite)
- 持久化: repository.go查询、cursor_worker.go
- API接口: Protobuf定义 + gRPC客户端
- 测试代码: 60+ 测试文件更新

 测试结果:
- 通过率: 100% (所有87个测试用例)
- 总体覆盖率: 53.7%
- 核心包覆盖率: logger(100%), highclient(95.3%), model(79.1%)

📝 文档:
- 精简README (1056行→489行,减少54%)
- 完整的OpCode枚举说明
- 三种持久化策略示例
- 数据库表结构和架构图

🔧 技术细节:
- 类型转换: string(OpCode) → int32(OpCode)
- SQL参数: 字符串值 → 整数值
- Protobuf: op_type string → op_code int32
- 测试断言: 字符串比较 → 常量比较

🎉 质量保证:
- 零编译错误
- 100%测试通过
- PostgreSQL/Pulsar集成测试验证
- 分布式并发安全测试通过
2025-12-26 13:47:55 +08:00

382 lines
9.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 persistence_test
import (
"context"
"fmt"
"time"
"github.com/go-logr/logr"
"go.yandata.net/iod/iod/go-trustlog/api/adapter"
"go.yandata.net/iod/iod/go-trustlog/api/logger"
"go.yandata.net/iod/iod/go-trustlog/api/model"
"go.yandata.net/iod/iod/go-trustlog/api/persistence"
)
// Example_dbOnly 演示仅落库策略
func Example_dbOnly() {
ctx := context.Background()
// 1. 创建 Logger
myLogger := logger.NewLogger(logr.Discard())
// 2. 创建 Pulsar Publisher
pub, err := adapter.NewPublisher(
adapter.PublisherConfig{
URL: "pulsar://localhost:6650",
},
myLogger,
)
if err != nil {
panic(err)
}
defer pub.Close()
// 3. 准备 SM2 密钥配置
privateKeyHex := []byte("私钥D的十六进制字符串")
publicKeyHex := []byte("04 + x坐标 + y坐标的十六进制字符串")
envelopeConfig := model.NewSM2EnvelopeConfig(privateKeyHex, publicKeyHex)
// 4. 创建支持数据库持久化的客户端(仅落库策略)
client, err := persistence.NewPersistenceClient(ctx, persistence.PersistenceClientConfig{
Publisher: pub,
Logger: myLogger,
EnvelopeConfig: envelopeConfig,
DBConfig: persistence.DefaultDBConfig(
"postgres",
"postgres://postgres:postgres@localhost:5432/trustlog?sslmode=disable",
),
PersistenceConfig: persistence.DefaultPersistenceConfig(persistence.StrategyDBOnly),
EnableRetryWorker: false, // 仅落库不需要重试
})
if err != nil {
panic(err)
}
defer client.Close()
// 5. 构造 Operation包含 IP 信息)
op, err := model.NewFullOperation(
model.OpSourceDOIP,
model.OpCodeCreateID,
"10.1000",
"my-repo",
"10.1000/my-repo/doc001",
"producer-001",
"admin",
[]byte(`{"action":"create"}`),
[]byte(`{"status":"success"}`),
time.Now(),
)
if err != nil {
panic(err)
}
// 设置 IP 信息(仅落库字段,可空)
clientIP := "192.168.1.100"
serverIP := "10.0.0.50"
op.ClientIP = &clientIP
op.ServerIP = &serverIP
// 6. 发布操作(仅落库,不存证)
if err := client.OperationPublish(ctx, op); err != nil {
panic(err)
}
fmt.Printf("Operation saved to database only: %s\n", op.OpID)
}
// Example_dbAndTrustlog 演示既落库又存证策略
func Example_dbAndTrustlog() {
ctx := context.Background()
// 1. 创建 Logger
myLogger := logger.NewLogger(logr.Discard())
// 2. 创建 Pulsar Publisher
pub, err := adapter.NewPublisher(
adapter.PublisherConfig{
URL: "pulsar://localhost:6650",
},
myLogger,
)
if err != nil {
panic(err)
}
defer pub.Close()
// 3. 准备 SM2 密钥配置
privateKeyHex := []byte("私钥D的十六进制字符串")
publicKeyHex := []byte("04 + x坐标 + y坐标的十六进制字符串")
envelopeConfig := model.NewSM2EnvelopeConfig(privateKeyHex, publicKeyHex)
// 4. 创建支持数据库持久化的客户端(既落库又存证策略)
retryConfig := persistence.DefaultRetryWorkerConfig()
retryConfig.MaxRetryCount = 5
retryConfig.RetryInterval = 30 * time.Second
client, err := persistence.NewPersistenceClient(ctx, persistence.PersistenceClientConfig{
Publisher: pub,
Logger: myLogger,
EnvelopeConfig: envelopeConfig,
DBConfig: persistence.DefaultDBConfig(
"postgres",
"postgres://postgres:postgres@localhost:5432/trustlog?sslmode=disable",
),
PersistenceConfig: persistence.PersistenceConfig{
Strategy: persistence.StrategyDBAndTrustlog,
EnableRetry: true,
MaxRetryCount: 5,
RetryBatchSize: 100,
},
RetryWorkerConfig: &retryConfig,
EnableRetryWorker: true, // 启用重试工作器保证最终一致性
})
if err != nil {
panic(err)
}
defer client.Close()
// 5. 构造 Operation
op, err := model.NewFullOperation(
model.OpSourceDOIP,
model.OpCodeCreateID,
"10.1000",
"my-repo",
"10.1000/my-repo/doc002",
"producer-001",
"admin",
[]byte(`{"action":"create"}`),
[]byte(`{"status":"success"}`),
time.Now(),
)
if err != nil {
panic(err)
}
// 设置 IP 信息(可空)
clientIP := "192.168.1.100"
serverIP := "10.0.0.50"
op.ClientIP = &clientIP
op.ServerIP = &serverIP
// 6. 发布操作(既落库又存证,保证最终一致性)
if err := client.OperationPublish(ctx, op); err != nil {
panic(err)
}
fmt.Printf("Operation saved to database and published to trustlog: %s\n", op.OpID)
fmt.Println("If publish fails, retry worker will handle it automatically")
}
// Example_trustlogOnly 演示仅存证策略
func Example_trustlogOnly() {
ctx := context.Background()
// 1. 创建 Logger
myLogger := logger.NewLogger(logr.Discard())
// 2. 创建 Pulsar Publisher
pub, err := adapter.NewPublisher(
adapter.PublisherConfig{
URL: "pulsar://localhost:6650",
},
myLogger,
)
if err != nil {
panic(err)
}
defer pub.Close()
// 3. 准备 SM2 密钥配置
privateKeyHex := []byte("私钥D的十六进制字符串")
publicKeyHex := []byte("04 + x坐标 + y坐标的十六进制字符串")
envelopeConfig := model.NewSM2EnvelopeConfig(privateKeyHex, publicKeyHex)
// 4. 创建支持数据库持久化的客户端(仅存证策略)
client, err := persistence.NewPersistenceClient(ctx, persistence.PersistenceClientConfig{
Publisher: pub,
Logger: myLogger,
EnvelopeConfig: envelopeConfig,
DBConfig: persistence.DefaultDBConfig(
"postgres",
"postgres://postgres:postgres@localhost:5432/trustlog?sslmode=disable",
),
PersistenceConfig: persistence.DefaultPersistenceConfig(persistence.StrategyTrustlogOnly),
EnableRetryWorker: false, // 仅存证不需要重试工作器
})
if err != nil {
panic(err)
}
defer client.Close()
// 5. 构造 Operation
op, err := model.NewFullOperation(
model.OpSourceDOIP,
model.OpCodeCreateID,
"10.1000",
"my-repo",
"10.1000/my-repo/doc003",
"producer-001",
"admin",
[]byte(`{"action":"create"}`),
[]byte(`{"status":"success"}`),
time.Now(),
)
if err != nil {
panic(err)
}
// 6. 发布操作(仅存证,不落库)
if err := client.OperationPublish(ctx, op); err != nil {
panic(err)
}
fmt.Printf("Operation published to trustlog only: %s\n", op.OpID)
}
// Example_mysqlDatabase 演示使用 MySQL 数据库
func Example_mysqlDatabase() {
ctx := context.Background()
// 1. 创建 Logger
myLogger := logger.NewLogger(logr.Discard())
// 2. 创建 Pulsar Publisher
pub, err := adapter.NewPublisher(
adapter.PublisherConfig{
URL: "pulsar://localhost:6650",
},
myLogger,
)
if err != nil {
panic(err)
}
defer pub.Close()
// 3. 准备 SM2 密钥配置
privateKeyHex := []byte("私钥D的十六进制字符串")
publicKeyHex := []byte("04 + x坐标 + y坐标的十六进制字符串")
envelopeConfig := model.NewSM2EnvelopeConfig(privateKeyHex, publicKeyHex)
// 4. 创建支持 MySQL 数据库的客户端
client, err := persistence.NewPersistenceClient(ctx, persistence.PersistenceClientConfig{
Publisher: pub,
Logger: myLogger,
EnvelopeConfig: envelopeConfig,
DBConfig: persistence.DefaultDBConfig(
"mysql",
"user:pass@tcp(localhost:3306)/trustlog?parseTime=true",
),
PersistenceConfig: persistence.DefaultPersistenceConfig(persistence.StrategyDBAndTrustlog),
EnableRetryWorker: true,
})
if err != nil {
panic(err)
}
defer client.Close()
// 5. 构造并发布 Operation
op, err := model.NewFullOperation(
model.OpSourceDOIP,
model.OpCodeCreateID,
"10.1000",
"my-repo",
"10.1000/my-repo/doc004",
"producer-001",
"admin",
[]byte(`{"action":"create"}`),
[]byte(`{"status":"success"}`),
time.Now(),
)
if err != nil {
panic(err)
}
// 设置 IP 信息(可空)
clientIP := "192.168.1.100"
serverIP := "10.0.0.50"
op.ClientIP = &clientIP
op.ServerIP = &serverIP
if err := client.OperationPublish(ctx, op); err != nil {
panic(err)
}
fmt.Printf("Operation saved to MySQL and published: %s\n", op.OpID)
}
// Example_sqliteDatabase 演示使用 SQLite 数据库
func Example_sqliteDatabase() {
ctx := context.Background()
// 1. 创建 Logger
myLogger := logger.NewLogger(logr.Discard())
// 2. 创建 Pulsar Publisher
pub, err := adapter.NewPublisher(
adapter.PublisherConfig{
URL: "pulsar://localhost:6650",
},
myLogger,
)
if err != nil {
panic(err)
}
defer pub.Close()
// 3. 准备 SM2 密钥配置
privateKeyHex := []byte("私钥D的十六进制字符串")
publicKeyHex := []byte("04 + x坐标 + y坐标的十六进制字符串")
envelopeConfig := model.NewSM2EnvelopeConfig(privateKeyHex, publicKeyHex)
// 4. 创建支持 SQLite 数据库的客户端
client, err := persistence.NewPersistenceClient(ctx, persistence.PersistenceClientConfig{
Publisher: pub,
Logger: myLogger,
EnvelopeConfig: envelopeConfig,
DBConfig: persistence.DefaultDBConfig(
"sqlite3",
"./trustlog.db",
),
PersistenceConfig: persistence.DefaultPersistenceConfig(persistence.StrategyDBOnly),
EnableRetryWorker: false,
})
if err != nil {
panic(err)
}
defer client.Close()
// 5. 构造并发布 Operation
op, err := model.NewFullOperation(
model.OpSourceDOIP,
model.OpCodeCreateID,
"10.1000",
"my-repo",
"10.1000/my-repo/doc005",
"producer-001",
"admin",
[]byte(`{"action":"create"}`),
[]byte(`{"status":"success"}`),
time.Now(),
)
if err != nil {
panic(err)
}
// 设置 IP 信息(可空)
clientIP := "192.168.1.100"
serverIP := "10.0.0.50"
op.ClientIP = &clientIP
op.ServerIP = &serverIP
if err := client.OperationPublish(ctx, op); err != nil {
panic(err)
}
fmt.Printf("Operation saved to SQLite: %s\n", op.OpID)
}