github.com/alibaba/ilogtail/pkg@v0.0.0-20250526110833-c53b480d046c/helper/containercenter/cri_runtime_api_interface_test.go (about) 1 // Copyright 2025 iLogtail Authors 2 // Licensed under Apache License, Version 2.0 (the "License") 3 4 package containercenter 5 6 import ( 7 "context" 8 "fmt" 9 "net" 10 "sync" 11 "testing" 12 "time" 13 14 "github.com/stretchr/testify/assert" 15 "google.golang.org/grpc" 16 "google.golang.org/grpc/test/bufconn" 17 "google.golang.org/protobuf/runtime/protoimpl" 18 ) 19 20 // 测试服务端实现 21 type testRuntimeServiceServer struct { 22 mu sync.Mutex 23 24 // 控制返回值 25 versionResp *CriVersionResponse 26 } 27 28 func (s *testRuntimeServiceServer) Version(ctx context.Context) (*CriVersionResponse, error) { 29 s.mu.Lock() 30 defer s.mu.Unlock() 31 if s.versionResp.RuntimeAPIVersion == "v1" { 32 return s.versionResp, nil 33 } else if s.versionResp.RuntimeAPIVersion == "v1alpha2" { 34 return s.versionResp, nil 35 } 36 return nil, fmt.Errorf("failed to initialize RuntimeServiceClient") 37 } 38 39 func (s *testRuntimeServiceServer) ListContainers(ctx context.Context) (*CriListContainersResponse, error) { 40 return nil, nil 41 } 42 43 func (s *testRuntimeServiceServer) ContainerStatus(ctx context.Context, containerID string, verbose bool) (*CriContainerStatusResponse, error) { 44 return nil, nil 45 } 46 47 func (s *testRuntimeServiceServer) ListPodSandbox(ctx context.Context) (*CriListPodSandboxResponse, error) { 48 return nil, nil 49 } 50 51 func (s *testRuntimeServiceServer) PodSandboxStatus(ctx context.Context, sandboxID string, verbose bool) (*CriPodSandboxStatusResponse, error) { 52 return nil, nil 53 } 54 55 func (m *CriVersionResponse) Descriptor() ([]byte, []int) { 56 return protoimpl.X.CompressGZIP([]byte{ 57 0x0a, 0x0a, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x74, 0x65, 58 0x73, 0x74, 0x22, 0xa6, 0x01, 0x0a, 0x12, 0x43, 0x72, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 59 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x56, 0x65, 0x72, 60 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x56, 0x65, 0x72, 0x73, 61 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x4e, 0x61, 62 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 63 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 64 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x52, 65 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 66 0x11, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x41, 0x50, 0x49, 0x56, 0x65, 0x72, 0x73, 0x69, 67 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 68 0x65, 0x41, 0x50, 0x49, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x08, 0x5a, 0x06, 0x2e, 69 0x2f, 0x74, 0x65, 0x73, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 70 }), []int{0} 71 } 72 73 func (m *CriVersionResponse) Reset() { 74 *m = CriVersionResponse{} 75 } 76 77 func (m *CriVersionResponse) String() string { 78 return fmt.Sprintf("{Version: %s, RuntimeName: %s, RuntimeVersion: %s, RuntimeAPIVersion: %s}", 79 m.Version, m.RuntimeName, m.RuntimeVersion, m.RuntimeAPIVersion) 80 } 81 82 func (m *CriVersionResponse) ProtoMessage() {} 83 84 // 创建测试服务端 85 func createTestServer(t *testing.T, serviceName string) (*testRuntimeServiceServer, *bufconn.Listener) { 86 listener := bufconn.Listen(1024 * 1024) 87 server := grpc.NewServer() 88 89 testServer := &testRuntimeServiceServer{} 90 serviceDesc := grpc.ServiceDesc{ 91 ServiceName: serviceName, 92 HandlerType: (*RuntimeService)(nil), 93 Methods: []grpc.MethodDesc{ 94 { 95 MethodName: "Version", 96 Handler: func(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 97 return srv.(*testRuntimeServiceServer).Version(ctx) 98 }, 99 }, 100 { 101 MethodName: "ListContainers", 102 Handler: func(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 103 return srv.(*testRuntimeServiceServer).ListContainers(ctx) 104 }, 105 }, 106 { 107 MethodName: "ContainerStatus", 108 Handler: func(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 109 return srv.(*testRuntimeServiceServer).ContainerStatus(ctx, "", false) 110 }, 111 }, 112 { 113 MethodName: "ListPodSandbox", 114 Handler: func(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 115 return srv.(*testRuntimeServiceServer).ListPodSandbox(ctx) 116 }, 117 }, 118 { 119 MethodName: "PodSandboxStatus", 120 Handler: func(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 121 return srv.(*testRuntimeServiceServer).PodSandboxStatus(ctx, "", false) 122 }, 123 }, 124 }, 125 Streams: []grpc.StreamDesc{}, 126 Metadata: "manual", 127 } 128 129 server.RegisterService(&serviceDesc, testServer) 130 131 go func() { 132 if err := server.Serve(listener); err != nil { 133 t.Errorf("Server serve error: %v", err) 134 } 135 }() 136 137 t.Cleanup(func() { 138 server.Stop() 139 }) 140 141 return testServer, listener 142 } 143 144 func TestNewRuntimeServiceClient(t *testing.T) { 145 // 准备测试数据 146 v1Resp := &CriVersionResponse{ 147 Version: "0.1.0", 148 RuntimeName: "containerd", 149 RuntimeVersion: "v2.0.5", 150 RuntimeAPIVersion: "v1", 151 } 152 153 v1alpha2Resp := &CriVersionResponse{ 154 Version: "0.1.0", 155 RuntimeName: "containerd", 156 RuntimeVersion: "v1.6.0", 157 RuntimeAPIVersion: "v1alpha2", 158 } 159 160 invalidResp := &CriVersionResponse{ 161 Version: "0.1.0", 162 RuntimeName: "containerd", 163 RuntimeVersion: "v0.0.0", 164 RuntimeAPIVersion: "invalid", 165 } 166 167 tests := []struct { 168 name string 169 serviceName string 170 expectError bool 171 expectedVersion string 172 setupServer func(*testRuntimeServiceServer) // 自定义服务端配置 173 }{ 174 { 175 name: "V1_Success", 176 serviceName: "runtime.v1.RuntimeService", 177 expectError: false, 178 expectedVersion: "v1", 179 setupServer: func(s *testRuntimeServiceServer) { 180 s.versionResp = v1Resp 181 }, 182 }, 183 { 184 name: "V1Alpha2_Success", 185 serviceName: "runtime.v1alpha2.RuntimeService", 186 expectError: false, 187 expectedVersion: "v1alpha2", 188 setupServer: func(s *testRuntimeServiceServer) { 189 s.versionResp = v1alpha2Resp 190 }, 191 }, 192 { 193 name: "Both_Failed", 194 serviceName: "invalid.service.name", 195 expectError: true, 196 expectedVersion: "invalid", 197 setupServer: func(s *testRuntimeServiceServer) { 198 s.versionResp = invalidResp 199 }, 200 }, 201 } 202 203 for _, tt := range tests { 204 t.Run(tt.name, func(t *testing.T) { 205 // 创建测试服务端 206 testServer, listener := createTestServer(t, tt.serviceName) 207 208 // 应用自定义配置 209 if tt.setupServer != nil { 210 tt.setupServer(testServer) 211 } 212 213 // 替换地址解析函数 214 getAddressAndDialer = func(socket string) (string, func(string, time.Duration) (net.Conn, error), error) { 215 return "bufnet", func(addr string, timeout time.Duration) (net.Conn, error) { 216 return listener.Dial() 217 }, nil 218 } 219 220 // 替换拨号函数 221 grpcDialContext = func(ctx context.Context, addr string, opts ...grpc.DialOption) (*grpc.ClientConn, error) { 222 return grpc.DialContext(ctx, "bufnet", opts...) 223 } 224 225 // 执行测试 226 client, err := NewRuntimeServiceClient(time.Second, 1024*1024) 227 228 // 验证结果 229 if tt.expectError { 230 assert.Error(t, err) 231 assert.Nil(t, client) 232 } else { 233 assert.NoError(t, err) 234 assert.NotNil(t, client) 235 assert.Equal(t, tt.expectedVersion, client.info.RuntimeAPIVersion) 236 } 237 238 // 清理 239 if client != nil { 240 client.Close() 241 } 242 }) 243 } 244 }