go.uber.org/cadence@v1.2.9/internal/common/isolationgroup/service_wrapper_test.go (about) 1 // Copyright (c) 2021 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package isolationgroup 22 23 import ( 24 "context" 25 "testing" 26 "time" 27 28 "github.com/golang/mock/gomock" 29 "github.com/stretchr/testify/assert" 30 "github.com/stretchr/testify/suite" 31 "github.com/uber/tchannel-go/thrift" 32 33 "go.uber.org/cadence/.gen/go/cadence/workflowserviceclient" 34 "go.uber.org/cadence/.gen/go/cadence/workflowservicetest" 35 "go.uber.org/cadence/.gen/go/shared" 36 ) 37 38 type ( 39 serviceWrapperSuite struct { 40 suite.Suite 41 Service *workflowservicetest.MockClient 42 controller *gomock.Controller 43 } 44 ) 45 46 func TestAPICalls(t *testing.T) { 47 48 tests := map[string]struct { 49 action func(ctx context.Context, p workflowserviceclient.Interface) (interface{}, error) 50 affordance func(m *workflowservicetest.MockClient) 51 expectedResponse interface{} 52 expectedErr error 53 }{ 54 "DeprecateDomain": { 55 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 56 return nil, sw.DeprecateDomain(ctx, &shared.DeprecateDomainRequest{}) 57 }, 58 affordance: func(m *workflowservicetest.MockClient) { 59 m.EXPECT().DeprecateDomain(gomock.Any(), gomock.Any(), gomock.Any()).Times(1) 60 }, 61 }, 62 "ListDomains": { 63 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 64 return sw.ListDomains(ctx, &shared.ListDomainsRequest{}) 65 }, 66 affordance: func(m *workflowservicetest.MockClient) { 67 m.EXPECT().ListDomains(gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(&shared.ListDomainsResponse{}, nil) 68 }, 69 expectedResponse: &shared.ListDomainsResponse{}, 70 }, 71 "DescribeDomain": { 72 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 73 return sw.DescribeDomain(ctx, &shared.DescribeDomainRequest{}) 74 }, 75 affordance: func(m *workflowservicetest.MockClient) { 76 m.EXPECT().DescribeDomain(gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(&shared.DescribeDomainResponse{}, nil) 77 }, 78 expectedResponse: &shared.DescribeDomainResponse{}, 79 }, 80 "DescribeWorkflowExecution": { 81 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 82 return sw.DescribeWorkflowExecution(ctx, &shared.DescribeWorkflowExecutionRequest{}) 83 }, 84 affordance: func(m *workflowservicetest.MockClient) { 85 m.EXPECT().DescribeWorkflowExecution(gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(&shared.DescribeWorkflowExecutionResponse{}, nil) 86 }, 87 expectedResponse: &shared.DescribeWorkflowExecutionResponse{}, 88 }, 89 "ListOpenWorkflowExecutions": { 90 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 91 return sw.ListOpenWorkflowExecutions(ctx, &shared.ListOpenWorkflowExecutionsRequest{}) 92 }, 93 affordance: func(m *workflowservicetest.MockClient) { 94 m.EXPECT().ListOpenWorkflowExecutions(gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(&shared.ListOpenWorkflowExecutionsResponse{}, nil) 95 }, 96 expectedResponse: &shared.ListOpenWorkflowExecutionsResponse{}, 97 }, 98 "ListClosedWorkflowExecutions": { 99 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 100 return sw.ListClosedWorkflowExecutions(ctx, &shared.ListClosedWorkflowExecutionsRequest{}) 101 }, 102 affordance: func(m *workflowservicetest.MockClient) { 103 m.EXPECT().ListClosedWorkflowExecutions(gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(&shared.ListClosedWorkflowExecutionsResponse{}, nil) 104 }, 105 expectedResponse: &shared.ListClosedWorkflowExecutionsResponse{}, 106 }, 107 "ListWorkflowExecutions": { 108 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 109 return sw.ListWorkflowExecutions(ctx, &shared.ListWorkflowExecutionsRequest{}) 110 }, 111 affordance: func(m *workflowservicetest.MockClient) { 112 m.EXPECT().ListWorkflowExecutions(gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(&shared.ListWorkflowExecutionsResponse{}, nil) 113 }, 114 expectedResponse: &shared.ListWorkflowExecutionsResponse{}, 115 }, 116 "ListArchivedWorkflowExecutions": { 117 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 118 return sw.ListArchivedWorkflowExecutions(ctx, &shared.ListArchivedWorkflowExecutionsRequest{}) 119 }, 120 affordance: func(m *workflowservicetest.MockClient) { 121 m.EXPECT().ListArchivedWorkflowExecutions(gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(&shared.ListArchivedWorkflowExecutionsResponse{}, nil) 122 }, 123 expectedResponse: &shared.ListArchivedWorkflowExecutionsResponse{}, 124 }, 125 "ScanWorkflowExecutions": { 126 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 127 return sw.ScanWorkflowExecutions(ctx, &shared.ListWorkflowExecutionsRequest{}) 128 }, 129 affordance: func(m *workflowservicetest.MockClient) { 130 m.EXPECT().ScanWorkflowExecutions(gomock.Any(), &shared.ListWorkflowExecutionsRequest{}, gomock.Any()).Times(1).Return(&shared.ListWorkflowExecutionsResponse{}, nil) 131 }, 132 expectedResponse: &shared.ListWorkflowExecutionsResponse{}, 133 }, 134 "CountWorkflowExecutions": { 135 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 136 return sw.CountWorkflowExecutions(ctx, &shared.CountWorkflowExecutionsRequest{}) 137 }, 138 affordance: func(m *workflowservicetest.MockClient) { 139 m.EXPECT().CountWorkflowExecutions(gomock.Any(), &shared.CountWorkflowExecutionsRequest{}, gomock.Any()).Times(1).Return(&shared.CountWorkflowExecutionsResponse{}, nil) 140 }, 141 expectedResponse: &shared.CountWorkflowExecutionsResponse{}, 142 }, 143 "PollForActivityTask": { 144 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 145 return sw.PollForActivityTask(ctx, &shared.PollForActivityTaskRequest{}) 146 }, 147 affordance: func(m *workflowservicetest.MockClient) { 148 m.EXPECT().PollForActivityTask(gomock.Any(), &shared.PollForActivityTaskRequest{}, gomock.Any()).Times(1).Return(&shared.PollForActivityTaskResponse{}, nil) 149 }, 150 expectedResponse: &shared.PollForActivityTaskResponse{}, 151 }, 152 "PollForDecisionTask": { 153 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 154 return sw.PollForDecisionTask(ctx, &shared.PollForDecisionTaskRequest{}) 155 }, 156 affordance: func(m *workflowservicetest.MockClient) { 157 m.EXPECT().PollForDecisionTask(gomock.Any(), &shared.PollForDecisionTaskRequest{}, gomock.Any()).Times(1).Return(&shared.PollForDecisionTaskResponse{}, nil) 158 }, 159 expectedResponse: &shared.PollForDecisionTaskResponse{}, 160 }, 161 "PollForRecordHeartbeatTask": { 162 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 163 return sw.RecordActivityTaskHeartbeat(ctx, &shared.RecordActivityTaskHeartbeatRequest{}) 164 }, 165 affordance: func(m *workflowservicetest.MockClient) { 166 m.EXPECT().RecordActivityTaskHeartbeat(gomock.Any(), &shared.RecordActivityTaskHeartbeatRequest{}, gomock.Any()).Times(1).Return(&shared.RecordActivityTaskHeartbeatResponse{}, nil) 167 }, 168 expectedResponse: &shared.RecordActivityTaskHeartbeatResponse{}, 169 }, 170 "PollForRecordHeartbeatTaskByID": { 171 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 172 return sw.RecordActivityTaskHeartbeatByID(ctx, &shared.RecordActivityTaskHeartbeatByIDRequest{}) 173 }, 174 affordance: func(m *workflowservicetest.MockClient) { 175 m.EXPECT().RecordActivityTaskHeartbeatByID(gomock.Any(), &shared.RecordActivityTaskHeartbeatByIDRequest{}, gomock.Any()).Times(1).Return(&shared.RecordActivityTaskHeartbeatResponse{}, nil) 176 }, 177 expectedResponse: &shared.RecordActivityTaskHeartbeatResponse{}, 178 }, 179 "RegisterDomain": { 180 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 181 return nil, sw.RegisterDomain(ctx, &shared.RegisterDomainRequest{}) 182 }, 183 affordance: func(m *workflowservicetest.MockClient) { 184 m.EXPECT().RegisterDomain(gomock.Any(), &shared.RegisterDomainRequest{}, gomock.Any()).Times(1).Return(nil) 185 }, 186 }, 187 "RequestCancelWorkflowExecution": { 188 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 189 return nil, sw.RequestCancelWorkflowExecution(ctx, &shared.RequestCancelWorkflowExecutionRequest{}) 190 }, 191 affordance: func(m *workflowservicetest.MockClient) { 192 m.EXPECT().RequestCancelWorkflowExecution(gomock.Any(), &shared.RequestCancelWorkflowExecutionRequest{}, gomock.Any()).Times(1).Return(nil) 193 }, 194 }, 195 "RespondActivityTaskCanceled": { 196 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 197 return nil, sw.RespondActivityTaskCanceled(ctx, &shared.RespondActivityTaskCanceledRequest{}) 198 }, 199 affordance: func(m *workflowservicetest.MockClient) { 200 m.EXPECT().RespondActivityTaskCanceled(gomock.Any(), &shared.RespondActivityTaskCanceledRequest{}, gomock.Any()).Times(1).Return(nil) 201 }, 202 }, 203 204 "RespondActivityTaskCompleted": { 205 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 206 return nil, sw.RespondActivityTaskCompleted(ctx, &shared.RespondActivityTaskCompletedRequest{}) 207 }, 208 affordance: func(m *workflowservicetest.MockClient) { 209 m.EXPECT().RespondActivityTaskCompleted(gomock.Any(), &shared.RespondActivityTaskCompletedRequest{}, gomock.Any()).Times(1).Return(nil) 210 }, 211 }, 212 213 "RespondActivityTaskFailed": { 214 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 215 return nil, sw.RespondActivityTaskFailed(ctx, &shared.RespondActivityTaskFailedRequest{}) 216 }, 217 affordance: func(m *workflowservicetest.MockClient) { 218 m.EXPECT().RespondActivityTaskFailed(gomock.Any(), &shared.RespondActivityTaskFailedRequest{}, gomock.Any()).Times(1).Return(nil) 219 }, 220 }, 221 222 "RespondActivityTaskCompletedByID": { 223 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 224 return nil, sw.RespondActivityTaskCompletedByID(ctx, &shared.RespondActivityTaskCompletedByIDRequest{}) 225 }, 226 affordance: func(m *workflowservicetest.MockClient) { 227 m.EXPECT().RespondActivityTaskCompletedByID(gomock.Any(), &shared.RespondActivityTaskCompletedByIDRequest{}, gomock.Any()).Times(1).Return(nil) 228 }, 229 }, 230 231 "RespondActivityTaskCanceledByID": { 232 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 233 return nil, sw.RespondActivityTaskCanceledByID(ctx, &shared.RespondActivityTaskCanceledByIDRequest{}) 234 }, 235 affordance: func(m *workflowservicetest.MockClient) { 236 m.EXPECT().RespondActivityTaskCanceledByID(gomock.Any(), &shared.RespondActivityTaskCanceledByIDRequest{}, gomock.Any()).Times(1).Return(nil) 237 }, 238 }, 239 240 "RespondActivityTaskFailedByID": { 241 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 242 return nil, sw.RespondActivityTaskFailedByID(ctx, &shared.RespondActivityTaskFailedByIDRequest{}) 243 }, 244 affordance: func(m *workflowservicetest.MockClient) { 245 m.EXPECT().RespondActivityTaskFailedByID(gomock.Any(), &shared.RespondActivityTaskFailedByIDRequest{}, gomock.Any()).Times(1).Return(nil) 246 }, 247 }, 248 249 "RespondDecisionTaskCompleted": { 250 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 251 return sw.RespondDecisionTaskCompleted(ctx, &shared.RespondDecisionTaskCompletedRequest{}) 252 }, 253 affordance: func(m *workflowservicetest.MockClient) { 254 m.EXPECT().RespondDecisionTaskCompleted(gomock.Any(), &shared.RespondDecisionTaskCompletedRequest{}, gomock.Any()).Times(1).Return(&shared.RespondDecisionTaskCompletedResponse{}, nil) 255 }, 256 expectedResponse: &shared.RespondDecisionTaskCompletedResponse{}, 257 }, 258 259 "RespondDecisionTaskFailed": { 260 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 261 return nil, sw.RespondDecisionTaskFailed(ctx, &shared.RespondDecisionTaskFailedRequest{}) 262 }, 263 affordance: func(m *workflowservicetest.MockClient) { 264 m.EXPECT().RespondDecisionTaskFailed(gomock.Any(), &shared.RespondDecisionTaskFailedRequest{}, gomock.Any()).Times(1).Return(nil) 265 }, 266 }, 267 "SignalWorkflowExecution": { 268 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 269 return nil, sw.SignalWorkflowExecution(ctx, &shared.SignalWorkflowExecutionRequest{}) 270 }, 271 affordance: func(m *workflowservicetest.MockClient) { 272 m.EXPECT().SignalWorkflowExecution(gomock.Any(), &shared.SignalWorkflowExecutionRequest{}, gomock.Any()).Times(1).Return(nil) 273 }, 274 }, 275 276 "SignalWithStartWorkflowExecution": { 277 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 278 return sw.SignalWithStartWorkflowExecution(ctx, &shared.SignalWithStartWorkflowExecutionRequest{}) 279 }, 280 affordance: func(m *workflowservicetest.MockClient) { 281 m.EXPECT().SignalWithStartWorkflowExecution(gomock.Any(), &shared.SignalWithStartWorkflowExecutionRequest{}, gomock.Any()).Times(1).Return(&shared.StartWorkflowExecutionResponse{}, nil) 282 }, 283 expectedResponse: &shared.StartWorkflowExecutionResponse{}, 284 }, 285 286 "StartWorkflowExecution": { 287 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 288 return sw.StartWorkflowExecution(ctx, &shared.StartWorkflowExecutionRequest{}) 289 }, 290 affordance: func(m *workflowservicetest.MockClient) { 291 m.EXPECT().StartWorkflowExecution(gomock.Any(), &shared.StartWorkflowExecutionRequest{}, gomock.Any()).Times(1).Return(&shared.StartWorkflowExecutionResponse{}, nil) 292 }, 293 expectedResponse: &shared.StartWorkflowExecutionResponse{}, 294 }, 295 296 "TerminateWorkflowExecution": { 297 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 298 return nil, sw.TerminateWorkflowExecution(ctx, &shared.TerminateWorkflowExecutionRequest{}) 299 }, 300 affordance: func(m *workflowservicetest.MockClient) { 301 m.EXPECT().TerminateWorkflowExecution(gomock.Any(), &shared.TerminateWorkflowExecutionRequest{}, gomock.Any()).Times(1).Return(nil) 302 }, 303 }, 304 305 "ResetWorkflowExecution": { 306 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 307 return sw.ResetWorkflowExecution(ctx, &shared.ResetWorkflowExecutionRequest{}) 308 }, 309 affordance: func(m *workflowservicetest.MockClient) { 310 m.EXPECT().ResetWorkflowExecution(gomock.Any(), &shared.ResetWorkflowExecutionRequest{}, gomock.Any()).Times(1).Return(&shared.ResetWorkflowExecutionResponse{}, nil) 311 }, 312 expectedResponse: &shared.ResetWorkflowExecutionResponse{}, 313 }, 314 "UpdateDomain": { 315 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 316 return sw.UpdateDomain(ctx, &shared.UpdateDomainRequest{}) 317 }, 318 affordance: func(m *workflowservicetest.MockClient) { 319 m.EXPECT().UpdateDomain(gomock.Any(), &shared.UpdateDomainRequest{}, gomock.Any()).Times(1).Return(&shared.UpdateDomainResponse{}, nil) 320 }, 321 expectedResponse: &shared.UpdateDomainResponse{}, 322 }, 323 324 "QueryWorkflow": { 325 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 326 return sw.QueryWorkflow(ctx, &shared.QueryWorkflowRequest{}) 327 }, 328 affordance: func(m *workflowservicetest.MockClient) { 329 m.EXPECT().QueryWorkflow(gomock.Any(), &shared.QueryWorkflowRequest{}, gomock.Any()).Times(1).Return(&shared.QueryWorkflowResponse{}, nil) 330 }, 331 expectedResponse: &shared.QueryWorkflowResponse{}, 332 }, 333 "ResetStickyTaskList": { 334 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 335 return sw.ResetStickyTaskList(ctx, &shared.ResetStickyTaskListRequest{}) 336 }, 337 affordance: func(m *workflowservicetest.MockClient) { 338 m.EXPECT().ResetStickyTaskList(gomock.Any(), &shared.ResetStickyTaskListRequest{}, gomock.Any()).Times(1).Return(&shared.ResetStickyTaskListResponse{}, nil) 339 }, 340 expectedResponse: &shared.ResetStickyTaskListResponse{}, 341 }, 342 343 "DescribeTaskList": { 344 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 345 return sw.DescribeTaskList(ctx, &shared.DescribeTaskListRequest{}) 346 }, 347 affordance: func(m *workflowservicetest.MockClient) { 348 m.EXPECT().DescribeTaskList(gomock.Any(), &shared.DescribeTaskListRequest{}, gomock.Any()).Times(1).Return(&shared.DescribeTaskListResponse{}, nil) 349 }, 350 expectedResponse: &shared.DescribeTaskListResponse{}, 351 }, 352 353 "RespondQueryTaskCompleted": { 354 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 355 return nil, sw.RespondQueryTaskCompleted(ctx, &shared.RespondQueryTaskCompletedRequest{}) 356 }, 357 affordance: func(m *workflowservicetest.MockClient) { 358 m.EXPECT().RespondQueryTaskCompleted(gomock.Any(), &shared.RespondQueryTaskCompletedRequest{}, gomock.Any()).Times(1).Return(nil) 359 }, 360 }, 361 362 "GetSearchAttributes": { 363 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 364 return sw.GetSearchAttributes(ctx) 365 }, 366 affordance: func(m *workflowservicetest.MockClient) { 367 m.EXPECT().GetSearchAttributes(gomock.Any(), gomock.Any()).Times(1).Return(&shared.GetSearchAttributesResponse{}, nil) 368 }, 369 expectedResponse: &shared.GetSearchAttributesResponse{}, 370 }, 371 372 "ListTaskListPartitions": { 373 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 374 return sw.ListTaskListPartitions(ctx, &shared.ListTaskListPartitionsRequest{}) 375 }, 376 affordance: func(m *workflowservicetest.MockClient) { 377 m.EXPECT().ListTaskListPartitions(gomock.Any(), &shared.ListTaskListPartitionsRequest{}, gomock.Any()).Times(1).Return(&shared.ListTaskListPartitionsResponse{}, nil) 378 }, 379 expectedResponse: &shared.ListTaskListPartitionsResponse{}, 380 }, 381 382 "GetClusterInfo": { 383 action: func(ctx context.Context, sw workflowserviceclient.Interface) (interface{}, error) { 384 return sw.GetClusterInfo(ctx) 385 }, 386 affordance: func(m *workflowservicetest.MockClient) { 387 m.EXPECT().GetClusterInfo(gomock.Any(), gomock.Any()).Times(1).Return(&shared.ClusterInfo{}, nil) 388 }, 389 expectedResponse: &shared.ClusterInfo{}, 390 }, 391 } 392 393 for name, td := range tests { 394 t.Run(name, func(t *testing.T) { 395 ctrl := gomock.NewController(t) 396 mockClient := workflowservicetest.NewMockClient(ctrl) 397 td.affordance(mockClient) 398 sw := NewWorkflowServiceWrapper(mockClient, "zone-1") 399 ctx, _ := thrift.NewContext(time.Minute) 400 res, err := td.action(ctx, sw) 401 assert.Equal(t, td.expectedResponse, res) 402 assert.Equal(t, td.expectedErr, err) 403 }) 404 } 405 }