2025-12-22 13:37:57 +08:00
|
|
|
|
package queryclient_test
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"context"
|
|
|
|
|
|
"testing"
|
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/go-logr/logr"
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
|
"google.golang.org/grpc"
|
|
|
|
|
|
"google.golang.org/grpc/test/bufconn"
|
|
|
|
|
|
"google.golang.org/protobuf/types/known/timestamppb"
|
|
|
|
|
|
|
2025-12-24 15:31:11 +08:00
|
|
|
|
"go.yandata.net/iod/iod/go-trustlog/api/grpc/pb"
|
|
|
|
|
|
"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/queryclient"
|
2025-12-22 13:37:57 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
const bufSize = 1024 * 1024
|
|
|
|
|
|
|
|
|
|
|
|
//nolint:gochecknoglobals // 测试文件中的全局变量是可接受的
|
|
|
|
|
|
var testLogger = logger.NewLogger(logr.Discard())
|
|
|
|
|
|
|
|
|
|
|
|
// mockOperationServer 模拟操作验证服务.
|
|
|
|
|
|
type mockOperationServer struct {
|
|
|
|
|
|
pb.UnimplementedOperationValidationServiceServer
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *mockOperationServer) ListOperations(
|
|
|
|
|
|
_ context.Context,
|
|
|
|
|
|
_ *pb.ListOperationReq,
|
|
|
|
|
|
) (*pb.ListOperationRes, error) {
|
|
|
|
|
|
return &pb.ListOperationRes{
|
|
|
|
|
|
Count: 2,
|
|
|
|
|
|
Data: []*pb.OperationData{
|
|
|
|
|
|
{
|
|
|
|
|
|
OpId: "op-1",
|
|
|
|
|
|
Timestamp: timestamppb.Now(),
|
|
|
|
|
|
OpSource: "test",
|
|
|
|
|
|
OpType: "create",
|
|
|
|
|
|
DoPrefix: "test",
|
|
|
|
|
|
DoRepository: "repo",
|
|
|
|
|
|
Doid: "test/repo/123",
|
|
|
|
|
|
ProducerId: "producer-1",
|
|
|
|
|
|
OpActor: "tester",
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
OpId: "op-2",
|
|
|
|
|
|
Timestamp: timestamppb.Now(),
|
|
|
|
|
|
OpSource: "test",
|
|
|
|
|
|
OpType: "update",
|
|
|
|
|
|
DoPrefix: "test",
|
|
|
|
|
|
DoRepository: "repo",
|
|
|
|
|
|
Doid: "test/repo/456",
|
|
|
|
|
|
ProducerId: "producer-1",
|
|
|
|
|
|
OpActor: "tester",
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
}, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *mockOperationServer) ValidateOperation(
|
|
|
|
|
|
req *pb.ValidationReq,
|
|
|
|
|
|
stream pb.OperationValidationService_ValidateOperationServer,
|
|
|
|
|
|
) error {
|
|
|
|
|
|
// 发送进度消息
|
|
|
|
|
|
_ = stream.Send(&pb.ValidationStreamRes{
|
|
|
|
|
|
Code: 100,
|
|
|
|
|
|
Msg: "Processing",
|
|
|
|
|
|
Progress: "50%",
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 发送完成消息
|
|
|
|
|
|
_ = stream.Send(&pb.ValidationStreamRes{
|
|
|
|
|
|
Code: 200,
|
|
|
|
|
|
Msg: "Completed",
|
|
|
|
|
|
Progress: "100%",
|
|
|
|
|
|
Data: &pb.OperationData{
|
|
|
|
|
|
OpId: req.GetOpId(),
|
|
|
|
|
|
Timestamp: req.GetTime(),
|
|
|
|
|
|
OpSource: "test",
|
|
|
|
|
|
OpType: req.GetOpType(),
|
|
|
|
|
|
DoPrefix: "test",
|
|
|
|
|
|
DoRepository: req.GetDoRepository(),
|
|
|
|
|
|
Doid: "test/repo/123",
|
|
|
|
|
|
ProducerId: "producer-1",
|
|
|
|
|
|
OpActor: "tester",
|
|
|
|
|
|
},
|
|
|
|
|
|
Proof: &pb.Proof{
|
|
|
|
|
|
ColItems: []*pb.MerkleTreeProofItem{
|
|
|
|
|
|
{Floor: 1, Hash: "hash1", Left: true},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// mockRecordServer 模拟记录验证服务.
|
|
|
|
|
|
type mockRecordServer struct {
|
|
|
|
|
|
pb.UnimplementedRecordValidationServiceServer
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *mockRecordServer) ListRecords(
|
|
|
|
|
|
_ context.Context,
|
|
|
|
|
|
_ *pb.ListRecordReq,
|
|
|
|
|
|
) (*pb.ListRecordRes, error) {
|
|
|
|
|
|
return &pb.ListRecordRes{
|
|
|
|
|
|
Count: 2,
|
|
|
|
|
|
Data: []*pb.RecordData{
|
|
|
|
|
|
{
|
|
|
|
|
|
Id: "rec-1",
|
|
|
|
|
|
DoPrefix: "test",
|
|
|
|
|
|
ProducerId: "producer-1",
|
|
|
|
|
|
Timestamp: timestamppb.Now(),
|
|
|
|
|
|
Operator: "tester",
|
|
|
|
|
|
RcType: "log",
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
Id: "rec-2",
|
|
|
|
|
|
DoPrefix: "test",
|
|
|
|
|
|
ProducerId: "producer-1",
|
|
|
|
|
|
Timestamp: timestamppb.Now(),
|
|
|
|
|
|
Operator: "tester",
|
|
|
|
|
|
RcType: "log",
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
}, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *mockRecordServer) ValidateRecord(
|
|
|
|
|
|
req *pb.RecordValidationReq,
|
|
|
|
|
|
stream pb.RecordValidationService_ValidateRecordServer,
|
|
|
|
|
|
) error {
|
|
|
|
|
|
// 发送进度消息
|
|
|
|
|
|
_ = stream.Send(&pb.RecordValidationStreamRes{
|
|
|
|
|
|
Code: 100,
|
|
|
|
|
|
Msg: "Processing",
|
|
|
|
|
|
Progress: "50%",
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 发送完成消息
|
|
|
|
|
|
_ = stream.Send(&pb.RecordValidationStreamRes{
|
|
|
|
|
|
Code: 200,
|
|
|
|
|
|
Msg: "Completed",
|
|
|
|
|
|
Progress: "100%",
|
|
|
|
|
|
Result: &pb.RecordData{
|
|
|
|
|
|
Id: req.GetRecordId(),
|
|
|
|
|
|
DoPrefix: req.GetDoPrefix(),
|
|
|
|
|
|
ProducerId: "producer-1",
|
|
|
|
|
|
Timestamp: req.GetTimestamp(),
|
|
|
|
|
|
Operator: "tester",
|
|
|
|
|
|
RcType: req.GetRcType(),
|
|
|
|
|
|
},
|
|
|
|
|
|
Proof: &pb.Proof{
|
|
|
|
|
|
ColItems: []*pb.MerkleTreeProofItem{
|
|
|
|
|
|
{Floor: 1, Hash: "hash1", Left: true},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// setupTestServer 创建测试用的 gRPC server.
|
|
|
|
|
|
func setupTestServer(t *testing.T) (*grpc.Server, *bufconn.Listener) {
|
|
|
|
|
|
lis := bufconn.Listen(bufSize)
|
|
|
|
|
|
s := grpc.NewServer()
|
|
|
|
|
|
pb.RegisterOperationValidationServiceServer(s, &mockOperationServer{})
|
|
|
|
|
|
pb.RegisterRecordValidationServiceServer(s, &mockRecordServer{})
|
|
|
|
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
|
|
if err := s.Serve(lis); err != nil {
|
|
|
|
|
|
t.Logf("Server exited with error: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
|
|
return s, lis
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// createTestClient 创建用于测试的客户端.
|
|
|
|
|
|
//
|
|
|
|
|
|
//nolint:unparam // 集成测试暂时跳过,返回值始终为 nil
|
|
|
|
|
|
func createTestClient(t *testing.T, _ *bufconn.Listener) *queryclient.Client {
|
|
|
|
|
|
// 使用 bufconn 的特殊方式创建客户端
|
|
|
|
|
|
// 由于我们不能直接注入连接,需要通过地址的方式
|
|
|
|
|
|
// 这里我们使用一个变通的方法:直接构建客户端结构(不推荐生产使用)
|
|
|
|
|
|
// 更好的方法是提供一个可注入连接的构造函数
|
|
|
|
|
|
|
|
|
|
|
|
// 暂时使用真实的地址测试配置验证
|
|
|
|
|
|
client, err := queryclient.NewClient(queryclient.ClientConfig{
|
|
|
|
|
|
ServerAddr: "bufnet",
|
|
|
|
|
|
}, testLogger)
|
|
|
|
|
|
|
|
|
|
|
|
// 对于这个测试,我们关闭它并使用 mock 方式
|
|
|
|
|
|
if client != nil {
|
|
|
|
|
|
_ = client.Close()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查 err 避免未使用的警告
|
|
|
|
|
|
_ = err
|
|
|
|
|
|
|
|
|
|
|
|
// 返回 nil,让调用者知道需要用其他方式测试
|
|
|
|
|
|
t.Skip("Skipping integration test - requires real gRPC server setup")
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func TestNewClient(t *testing.T) {
|
|
|
|
|
|
tests := []struct {
|
|
|
|
|
|
name string
|
|
|
|
|
|
config queryclient.ClientConfig
|
|
|
|
|
|
wantErr bool
|
|
|
|
|
|
errMsg string
|
|
|
|
|
|
}{
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "使用ServerAddr成功创建客户端",
|
|
|
|
|
|
config: queryclient.ClientConfig{
|
|
|
|
|
|
ServerAddr: "localhost:9090",
|
|
|
|
|
|
},
|
|
|
|
|
|
wantErr: false,
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "使用ServerAddrs成功创建客户端",
|
|
|
|
|
|
config: queryclient.ClientConfig{
|
|
|
|
|
|
ServerAddrs: []string{"localhost:9090", "localhost:9091"},
|
|
|
|
|
|
},
|
|
|
|
|
|
wantErr: false,
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "没有提供地址应该失败",
|
|
|
|
|
|
config: queryclient.ClientConfig{},
|
|
|
|
|
|
wantErr: true,
|
|
|
|
|
|
errMsg: "at least one server address is required",
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
|
client, err := queryclient.NewClient(tt.config, testLogger)
|
|
|
|
|
|
|
|
|
|
|
|
if tt.wantErr {
|
|
|
|
|
|
require.Error(t, err)
|
|
|
|
|
|
if tt.errMsg != "" {
|
|
|
|
|
|
assert.Contains(t, err.Error(), tt.errMsg)
|
|
|
|
|
|
}
|
|
|
|
|
|
assert.Nil(t, client)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
require.NotNil(t, client)
|
|
|
|
|
|
// 清理
|
|
|
|
|
|
if client != nil {
|
|
|
|
|
|
_ = client.Close()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func TestClientConfig_GetAddrs(t *testing.T) {
|
|
|
|
|
|
tests := []struct {
|
|
|
|
|
|
name string
|
|
|
|
|
|
config queryclient.ClientConfig
|
|
|
|
|
|
wantAddrs []string
|
|
|
|
|
|
wantErr bool
|
|
|
|
|
|
}{
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "ServerAddrs优先",
|
|
|
|
|
|
config: queryclient.ClientConfig{
|
|
|
|
|
|
ServerAddrs: []string{"addr1:9090", "addr2:9090"},
|
|
|
|
|
|
ServerAddr: "addr3:9090",
|
|
|
|
|
|
},
|
|
|
|
|
|
wantAddrs: []string{"addr1:9090", "addr2:9090"},
|
|
|
|
|
|
wantErr: false,
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "使用ServerAddr作为后备",
|
|
|
|
|
|
config: queryclient.ClientConfig{
|
|
|
|
|
|
ServerAddr: "addr1:9090",
|
|
|
|
|
|
},
|
|
|
|
|
|
wantAddrs: []string{"addr1:9090"},
|
|
|
|
|
|
wantErr: false,
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "没有地址应该返回错误",
|
|
|
|
|
|
config: queryclient.ClientConfig{},
|
|
|
|
|
|
wantAddrs: nil,
|
|
|
|
|
|
wantErr: true,
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
|
addrs, err := tt.config.GetAddrs()
|
|
|
|
|
|
|
|
|
|
|
|
if tt.wantErr {
|
|
|
|
|
|
require.Error(t, err)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
assert.Equal(t, tt.wantAddrs, addrs)
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func TestListOperationsRequest(t *testing.T) {
|
|
|
|
|
|
// 测试请求结构的创建
|
|
|
|
|
|
now := time.Now()
|
|
|
|
|
|
req := queryclient.ListOperationsRequest{
|
|
|
|
|
|
PageSize: 10,
|
|
|
|
|
|
PreTime: now,
|
|
|
|
|
|
Timestamp: &now,
|
|
|
|
|
|
OpSource: model.Source("test"),
|
2025-12-24 16:48:00 +08:00
|
|
|
|
OpType: "create",
|
2025-12-22 13:37:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
assert.Equal(t, uint64(10), req.PageSize)
|
|
|
|
|
|
assert.Equal(t, now, req.PreTime)
|
|
|
|
|
|
assert.NotNil(t, req.Timestamp)
|
|
|
|
|
|
assert.Equal(t, "test", string(req.OpSource))
|
|
|
|
|
|
assert.Equal(t, "create", string(req.OpType))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func TestValidationRequest(t *testing.T) {
|
|
|
|
|
|
// 测试验证请求结构
|
|
|
|
|
|
now := time.Now()
|
|
|
|
|
|
req := queryclient.ValidationRequest{
|
|
|
|
|
|
Time: now,
|
|
|
|
|
|
OpID: "op-123",
|
|
|
|
|
|
OpType: "create",
|
|
|
|
|
|
DoRepository: "repo",
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
assert.Equal(t, now, req.Time)
|
|
|
|
|
|
assert.Equal(t, "op-123", req.OpID)
|
|
|
|
|
|
assert.Equal(t, "create", req.OpType)
|
|
|
|
|
|
assert.Equal(t, "repo", req.DoRepository)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func TestListRecordsRequest(t *testing.T) {
|
|
|
|
|
|
// 测试记录列表请求结构
|
|
|
|
|
|
now := time.Now()
|
|
|
|
|
|
|
|
|
|
|
|
req := queryclient.ListRecordsRequest{
|
|
|
|
|
|
PageSize: 20,
|
|
|
|
|
|
PreTime: now,
|
|
|
|
|
|
DoPrefix: "test",
|
|
|
|
|
|
RCType: "log",
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
assert.Equal(t, uint64(20), req.PageSize)
|
|
|
|
|
|
assert.Equal(t, now, req.PreTime)
|
|
|
|
|
|
assert.Equal(t, "test", req.DoPrefix)
|
|
|
|
|
|
assert.Equal(t, "log", req.RCType)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func TestRecordValidationRequest(t *testing.T) {
|
|
|
|
|
|
// 测试记录验证请求结构
|
|
|
|
|
|
now := time.Now()
|
|
|
|
|
|
req := queryclient.RecordValidationRequest{
|
|
|
|
|
|
Timestamp: now,
|
|
|
|
|
|
RecordID: "rec-123",
|
|
|
|
|
|
DoPrefix: "test",
|
|
|
|
|
|
RCType: "log",
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
assert.Equal(t, now, req.Timestamp)
|
|
|
|
|
|
assert.Equal(t, "rec-123", req.RecordID)
|
|
|
|
|
|
assert.Equal(t, "test", req.DoPrefix)
|
|
|
|
|
|
assert.Equal(t, "log", req.RCType)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 集成测试部分(需要真实的 gRPC server).
|
|
|
|
|
|
func TestIntegration_ListOperations(t *testing.T) {
|
|
|
|
|
|
if testing.Short() {
|
|
|
|
|
|
t.Skip("Skipping integration test in short mode")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
server, lis := setupTestServer(t)
|
|
|
|
|
|
defer server.Stop()
|
|
|
|
|
|
|
|
|
|
|
|
client := createTestClient(t, lis)
|
|
|
|
|
|
if client == nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
defer client.Close()
|
|
|
|
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
|
|
|
|
resp, err := client.ListOperations(ctx, queryclient.ListOperationsRequest{
|
|
|
|
|
|
PageSize: 10,
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
require.NotNil(t, resp)
|
|
|
|
|
|
assert.Equal(t, int64(2), resp.Count)
|
|
|
|
|
|
assert.Len(t, resp.Data, 2)
|
|
|
|
|
|
assert.Equal(t, "op-1", resp.Data[0].OpID)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func TestIntegration_ValidateOperation(t *testing.T) { //nolint:dupl // 测试代码中的重复模式是合理的
|
|
|
|
|
|
if testing.Short() {
|
|
|
|
|
|
t.Skip("Skipping integration test in short mode")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
server, lis := setupTestServer(t)
|
|
|
|
|
|
defer server.Stop()
|
|
|
|
|
|
|
|
|
|
|
|
client := createTestClient(t, lis)
|
|
|
|
|
|
if client == nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
defer client.Close()
|
|
|
|
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
|
|
|
|
resultChan, err := client.ValidateOperation(ctx, queryclient.ValidationRequest{
|
|
|
|
|
|
Time: time.Now(),
|
|
|
|
|
|
OpID: "op-test",
|
|
|
|
|
|
OpType: "create",
|
|
|
|
|
|
DoRepository: "repo",
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
require.NotNil(t, resultChan)
|
|
|
|
|
|
|
|
|
|
|
|
results := []int32{}
|
|
|
|
|
|
for result := range resultChan {
|
|
|
|
|
|
results = append(results, result.Code)
|
|
|
|
|
|
if result.IsCompleted() {
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
assert.Contains(t, results, int32(100)) // Processing
|
|
|
|
|
|
assert.Contains(t, results, int32(200)) // Completed
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func TestIntegration_ValidateOperationSync(t *testing.T) {
|
|
|
|
|
|
if testing.Short() {
|
|
|
|
|
|
t.Skip("Skipping integration test in short mode")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
server, lis := setupTestServer(t)
|
|
|
|
|
|
defer server.Stop()
|
|
|
|
|
|
|
|
|
|
|
|
client := createTestClient(t, lis)
|
|
|
|
|
|
if client == nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
defer client.Close()
|
|
|
|
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
|
|
|
|
progressCount := 0
|
|
|
|
|
|
result, err := client.ValidateOperationSync(
|
|
|
|
|
|
ctx,
|
|
|
|
|
|
queryclient.ValidationRequest{
|
|
|
|
|
|
Time: time.Now(),
|
|
|
|
|
|
OpID: "op-test",
|
|
|
|
|
|
OpType: "create",
|
|
|
|
|
|
DoRepository: "repo",
|
|
|
|
|
|
},
|
|
|
|
|
|
func(r *model.ValidationResult) {
|
|
|
|
|
|
progressCount++
|
|
|
|
|
|
assert.Equal(t, int32(100), r.Code)
|
|
|
|
|
|
},
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
require.NotNil(t, result)
|
|
|
|
|
|
assert.Equal(t, int32(200), result.Code)
|
|
|
|
|
|
assert.True(t, result.IsCompleted())
|
|
|
|
|
|
assert.Positive(t, progressCount)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func TestIntegration_ListRecords(t *testing.T) {
|
|
|
|
|
|
if testing.Short() {
|
|
|
|
|
|
t.Skip("Skipping integration test in short mode")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
server, lis := setupTestServer(t)
|
|
|
|
|
|
defer server.Stop()
|
|
|
|
|
|
|
|
|
|
|
|
client := createTestClient(t, lis)
|
|
|
|
|
|
if client == nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
defer client.Close()
|
|
|
|
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
|
|
|
|
resp, err := client.ListRecords(ctx, queryclient.ListRecordsRequest{
|
|
|
|
|
|
PageSize: 10,
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
require.NotNil(t, resp)
|
|
|
|
|
|
assert.Equal(t, int64(2), resp.Count)
|
|
|
|
|
|
assert.Len(t, resp.Data, 2)
|
|
|
|
|
|
assert.Equal(t, "rec-1", resp.Data[0].ID)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func TestIntegration_ValidateRecord(t *testing.T) { //nolint:dupl // 测试代码中的重复模式是合理的
|
|
|
|
|
|
if testing.Short() {
|
|
|
|
|
|
t.Skip("Skipping integration test in short mode")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
server, lis := setupTestServer(t)
|
|
|
|
|
|
defer server.Stop()
|
|
|
|
|
|
|
|
|
|
|
|
client := createTestClient(t, lis)
|
|
|
|
|
|
if client == nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
defer client.Close()
|
|
|
|
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
|
|
|
|
resultChan, err := client.ValidateRecord(ctx, queryclient.RecordValidationRequest{
|
|
|
|
|
|
Timestamp: time.Now(),
|
|
|
|
|
|
RecordID: "rec-test",
|
|
|
|
|
|
DoPrefix: "test",
|
|
|
|
|
|
RCType: "log",
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
require.NotNil(t, resultChan)
|
|
|
|
|
|
|
|
|
|
|
|
results := []int32{}
|
|
|
|
|
|
for result := range resultChan {
|
|
|
|
|
|
results = append(results, result.Code)
|
|
|
|
|
|
if result.IsCompleted() {
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
assert.Contains(t, results, int32(100)) // Processing
|
|
|
|
|
|
assert.Contains(t, results, int32(200)) // Completed
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func TestIntegration_ValidateRecordSync(t *testing.T) {
|
|
|
|
|
|
if testing.Short() {
|
|
|
|
|
|
t.Skip("Skipping integration test in short mode")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
server, lis := setupTestServer(t)
|
|
|
|
|
|
defer server.Stop()
|
|
|
|
|
|
|
|
|
|
|
|
client := createTestClient(t, lis)
|
|
|
|
|
|
if client == nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
defer client.Close()
|
|
|
|
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
|
|
|
|
progressCount := 0
|
|
|
|
|
|
result, err := client.ValidateRecordSync(
|
|
|
|
|
|
ctx,
|
|
|
|
|
|
queryclient.RecordValidationRequest{
|
|
|
|
|
|
Timestamp: time.Now(),
|
|
|
|
|
|
RecordID: "rec-test",
|
|
|
|
|
|
DoPrefix: "test",
|
|
|
|
|
|
RCType: "log",
|
|
|
|
|
|
},
|
|
|
|
|
|
func(r *model.RecordValidationResult) {
|
|
|
|
|
|
progressCount++
|
|
|
|
|
|
assert.Equal(t, int32(100), r.Code)
|
|
|
|
|
|
},
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
require.NotNil(t, result)
|
|
|
|
|
|
assert.Equal(t, int32(200), result.Code)
|
|
|
|
|
|
assert.True(t, result.IsCompleted())
|
|
|
|
|
|
assert.Positive(t, progressCount)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func TestClient_GetLowLevelClients(t *testing.T) {
|
|
|
|
|
|
if testing.Short() {
|
|
|
|
|
|
t.Skip("Skipping integration test in short mode")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
server, lis := setupTestServer(t)
|
|
|
|
|
|
defer server.Stop()
|
|
|
|
|
|
|
|
|
|
|
|
client := createTestClient(t, lis)
|
|
|
|
|
|
if client == nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
defer client.Close()
|
|
|
|
|
|
|
|
|
|
|
|
opClient := client.GetLowLevelOperationClient()
|
|
|
|
|
|
assert.NotNil(t, opClient)
|
|
|
|
|
|
|
|
|
|
|
|
recClient := client.GetLowLevelRecordClient()
|
|
|
|
|
|
assert.NotNil(t, recClient)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func TestClient_Close(t *testing.T) {
|
|
|
|
|
|
if testing.Short() {
|
|
|
|
|
|
t.Skip("Skipping integration test in short mode")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
server, lis := setupTestServer(t)
|
|
|
|
|
|
defer server.Stop()
|
|
|
|
|
|
|
|
|
|
|
|
client := createTestClient(t, lis)
|
|
|
|
|
|
if client == nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
err := client.Close()
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
|
|
// 再次关闭应该不会报错
|
|
|
|
|
|
err = client.Close()
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
}
|