go.temporal.io/server@v1.23.0/common/archiver/s3store/visibility_archiver_test.go (about) 1 // The MIT License 2 // 3 // Copyright (c) 2020 Temporal Technologies Inc. All rights reserved. 4 // 5 // Copyright (c) 2020 Uber Technologies, Inc. 6 // 7 // Permission is hereby granted, free of charge, to any person obtaining a copy 8 // of this software and associated documentation files (the "Software"), to deal 9 // in the Software without restriction, including without limitation the rights 10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 // copies of the Software, and to permit persons to whom the Software is 12 // furnished to do so, subject to the following conditions: 13 // 14 // The above copyright notice and this permission notice shall be included in 15 // all copies or substantial portions of the Software. 16 // 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 // THE SOFTWARE. 24 25 package s3store 26 27 import ( 28 "context" 29 "errors" 30 "fmt" 31 "testing" 32 "time" 33 34 "github.com/aws/aws-sdk-go/aws" 35 "github.com/aws/aws-sdk-go/aws/awserr" 36 "github.com/aws/aws-sdk-go/aws/request" 37 "github.com/aws/aws-sdk-go/service/s3" 38 "github.com/golang/mock/gomock" 39 "github.com/stretchr/testify/require" 40 "github.com/stretchr/testify/suite" 41 enumspb "go.temporal.io/api/enums/v1" 42 "go.temporal.io/api/serviceerror" 43 "google.golang.org/protobuf/types/known/timestamppb" 44 45 "go.temporal.io/server/common/searchattribute" 46 47 archiverspb "go.temporal.io/server/api/archiver/v1" 48 "go.temporal.io/server/common/archiver" 49 "go.temporal.io/server/common/archiver/s3store/mocks" 50 "go.temporal.io/server/common/codec" 51 "go.temporal.io/server/common/convert" 52 "go.temporal.io/server/common/log" 53 "go.temporal.io/server/common/metrics" 54 "go.temporal.io/server/common/payload" 55 "go.temporal.io/server/common/primitives/timestamp" 56 57 commonpb "go.temporal.io/api/common/v1" 58 workflowpb "go.temporal.io/api/workflow/v1" 59 ) 60 61 type visibilityArchiverSuite struct { 62 *require.Assertions 63 suite.Suite 64 s3cli *mocks.MockS3API 65 66 container *archiver.VisibilityBootstrapContainer 67 visibilityRecords []*archiverspb.VisibilityRecord 68 69 controller *gomock.Controller 70 testArchivalURI archiver.URI 71 } 72 73 func TestVisibilityArchiverSuite(t *testing.T) { 74 suite.Run(t, new(visibilityArchiverSuite)) 75 } 76 77 func (s *visibilityArchiverSuite) TestValidateURI() { 78 testCases := []struct { 79 URI string 80 expectedErr error 81 }{ 82 { 83 URI: "wrongscheme:///a/b/c", 84 expectedErr: archiver.ErrURISchemeMismatch, 85 }, 86 { 87 URI: "s3://", 88 expectedErr: errNoBucketSpecified, 89 }, 90 { 91 URI: "s3:///test", 92 expectedErr: errNoBucketSpecified, 93 }, 94 { 95 URI: "s3://bucket/a/b/c", 96 expectedErr: errBucketNotExists, 97 }, 98 { 99 URI: testBucketURI, 100 expectedErr: nil, 101 }, 102 } 103 104 s.s3cli.EXPECT().HeadBucketWithContext(gomock.Any(), gomock.Any()).DoAndReturn( 105 func(ctx aws.Context, input *s3.HeadBucketInput, options ...request.Option) (*s3.HeadBucketOutput, error) { 106 if *input.Bucket != s.testArchivalURI.Hostname() { 107 return nil, awserr.New("NotFound", "", nil) 108 } 109 110 return &s3.HeadBucketOutput{}, nil 111 }).AnyTimes() 112 113 visibilityArchiver := s.newTestVisibilityArchiver() 114 for _, tc := range testCases { 115 URI, err := archiver.NewURI(tc.URI) 116 s.NoError(err) 117 s.Equal(tc.expectedErr, visibilityArchiver.ValidateURI(URI)) 118 } 119 } 120 121 func (s *visibilityArchiverSuite) newTestVisibilityArchiver() *visibilityArchiver { 122 return &visibilityArchiver{ 123 container: s.container, 124 s3cli: s.s3cli, 125 queryParser: NewQueryParser(), 126 } 127 } 128 129 const ( 130 testWorkflowTypeName = "test-workflow-type" 131 ) 132 133 func (s *visibilityArchiverSuite) SetupSuite() { 134 var err error 135 136 s.testArchivalURI, err = archiver.NewURI(testBucketURI) 137 s.Require().NoError(err) 138 s.container = &archiver.VisibilityBootstrapContainer{ 139 Logger: log.NewNoopLogger(), 140 MetricsHandler: metrics.NoopMetricsHandler, 141 } 142 } 143 144 func (s *visibilityArchiverSuite) TearDownSuite() { 145 } 146 147 func (s *visibilityArchiverSuite) SetupTest() { 148 s.Assertions = require.New(s.T()) 149 s.controller = gomock.NewController(s.T()) 150 151 s.s3cli = mocks.NewMockS3API(s.controller) 152 setupFsEmulation(s.s3cli) 153 s.setupVisibilityDirectory() 154 } 155 156 func (s *visibilityArchiverSuite) TearDownTest() { 157 s.controller.Finish() 158 } 159 160 func (s *visibilityArchiverSuite) TestArchive_Fail_InvalidURI() { 161 visibilityArchiver := s.newTestVisibilityArchiver() 162 URI, err := archiver.NewURI("wrongscheme://") 163 s.NoError(err) 164 request := &archiverspb.VisibilityRecord{ 165 Namespace: testNamespace, 166 NamespaceId: testNamespaceID, 167 WorkflowId: testWorkflowID, 168 RunId: testRunID, 169 WorkflowTypeName: testWorkflowTypeName, 170 StartTime: timestamp.TimeNowPtrUtc(), 171 ExecutionTime: nil, // workflow without backoff 172 CloseTime: timestamp.TimeNowPtrUtc(), 173 Status: enumspb.WORKFLOW_EXECUTION_STATUS_FAILED, 174 HistoryLength: int64(101), 175 } 176 err = visibilityArchiver.Archive(context.Background(), URI, request) 177 s.Error(err) 178 } 179 180 func (s *visibilityArchiverSuite) TestArchive_Fail_InvalidRequest() { 181 visibilityArchiver := s.newTestVisibilityArchiver() 182 err := visibilityArchiver.Archive(context.Background(), s.testArchivalURI, &archiverspb.VisibilityRecord{}) 183 s.Error(err) 184 } 185 186 func (s *visibilityArchiverSuite) TestArchive_Fail_NonRetryableErrorOption() { 187 visibilityArchiver := s.newTestVisibilityArchiver() 188 nonRetryableErr := errors.New("some non-retryable error") 189 err := visibilityArchiver.Archive( 190 context.Background(), 191 s.testArchivalURI, 192 &archiverspb.VisibilityRecord{ 193 NamespaceId: testNamespaceID, 194 }, 195 archiver.GetNonRetryableErrorOption(nonRetryableErr), 196 ) 197 s.Equal(nonRetryableErr, err) 198 } 199 200 func (s *visibilityArchiverSuite) TestArchive_Success() { 201 visibilityArchiver := s.newTestVisibilityArchiver() 202 closeTimestamp := timestamp.TimeNowPtrUtc() 203 request := &archiverspb.VisibilityRecord{ 204 NamespaceId: testNamespaceID, 205 Namespace: testNamespace, 206 WorkflowId: testWorkflowID, 207 RunId: testRunID, 208 WorkflowTypeName: testWorkflowTypeName, 209 StartTime: timestamppb.New(closeTimestamp.AsTime().Add(-time.Hour)), 210 ExecutionTime: nil, // workflow without backoff 211 CloseTime: closeTimestamp, 212 Status: enumspb.WORKFLOW_EXECUTION_STATUS_FAILED, 213 HistoryLength: int64(101), 214 Memo: &commonpb.Memo{ 215 Fields: map[string]*commonpb.Payload{ 216 "testFields": payload.EncodeBytes([]byte{1, 2, 3}), 217 }, 218 }, 219 SearchAttributes: map[string]string{ 220 "testAttribute": "456", 221 }, 222 } 223 URI, err := archiver.NewURI(testBucketURI + "/test-archive-success") 224 s.NoError(err) 225 err = visibilityArchiver.Archive(context.Background(), URI, request) 226 s.NoError(err) 227 228 expectedKey := constructTimestampIndex(URI.Path(), testNamespaceID, primaryIndexKeyWorkflowID, testWorkflowID, secondaryIndexKeyCloseTimeout, timestamp.TimeValue(closeTimestamp), testRunID) 229 data, err := Download(context.Background(), visibilityArchiver.s3cli, URI, expectedKey) 230 s.NoError(err, expectedKey) 231 232 archivedRecord := &archiverspb.VisibilityRecord{} 233 encoder := codec.NewJSONPBEncoder() 234 err = encoder.Decode(data, archivedRecord) 235 s.NoError(err) 236 s.Equal(request, archivedRecord) 237 } 238 239 func (s *visibilityArchiverSuite) TestQuery_Fail_InvalidURI() { 240 visibilityArchiver := s.newTestVisibilityArchiver() 241 URI, err := archiver.NewURI("wrongscheme://") 242 s.NoError(err) 243 request := &archiver.QueryVisibilityRequest{ 244 NamespaceID: testNamespaceID, 245 PageSize: 1, 246 } 247 response, err := visibilityArchiver.Query(context.Background(), URI, request, searchattribute.TestNameTypeMap) 248 s.Error(err) 249 s.Nil(response) 250 } 251 252 func (s *visibilityArchiverSuite) TestQuery_Fail_InvalidRequest() { 253 visibilityArchiver := s.newTestVisibilityArchiver() 254 response, err := visibilityArchiver.Query(context.Background(), s.testArchivalURI, &archiver.QueryVisibilityRequest{}, searchattribute.TestNameTypeMap) 255 s.Error(err) 256 s.Nil(response) 257 } 258 259 func (s *visibilityArchiverSuite) TestQuery_Fail_InvalidQuery() { 260 visibilityArchiver := s.newTestVisibilityArchiver() 261 mockParser := NewMockQueryParser(s.controller) 262 mockParser.EXPECT().Parse(gomock.Any()).Return(nil, errors.New("invalid query")) 263 visibilityArchiver.queryParser = mockParser 264 response, err := visibilityArchiver.Query(context.Background(), s.testArchivalURI, &archiver.QueryVisibilityRequest{ 265 NamespaceID: "some random namespaceID", 266 PageSize: 10, 267 Query: "some invalid query", 268 }, searchattribute.TestNameTypeMap) 269 s.Error(err) 270 s.Nil(response) 271 } 272 273 func (s *visibilityArchiverSuite) TestQuery_Success_DirectoryNotExist() { 274 visibilityArchiver := s.newTestVisibilityArchiver() 275 mockParser := NewMockQueryParser(s.controller) 276 mockParser.EXPECT().Parse(gomock.Any()).Return(&parsedQuery{ 277 workflowID: convert.StringPtr(testWorkflowID), 278 closeTime: &time.Time{}, 279 searchPrecision: convert.StringPtr(PrecisionSecond), 280 }, nil) 281 visibilityArchiver.queryParser = mockParser 282 request := &archiver.QueryVisibilityRequest{ 283 NamespaceID: testNamespaceID, 284 Query: "parsed by mockParser", 285 PageSize: 1, 286 } 287 response, err := visibilityArchiver.Query(context.Background(), s.testArchivalURI, request, searchattribute.TestNameTypeMap) 288 s.NoError(err) 289 s.NotNil(response) 290 s.Empty(response.Executions) 291 s.Empty(response.NextPageToken) 292 } 293 294 func (s *visibilityArchiverSuite) TestQuery_Success_NoNextPageToken() { 295 visibilityArchiver := s.newTestVisibilityArchiver() 296 mockParser := NewMockQueryParser(s.controller) 297 mockParser.EXPECT().Parse(gomock.Any()).Return(&parsedQuery{ 298 closeTime: ptr(time.Unix(0, int64(1*time.Hour)).UTC()), 299 searchPrecision: convert.StringPtr(PrecisionHour), 300 workflowID: convert.StringPtr(testWorkflowID), 301 }, nil) 302 visibilityArchiver.queryParser = mockParser 303 request := &archiver.QueryVisibilityRequest{ 304 NamespaceID: testNamespaceID, 305 PageSize: 10, 306 Query: "parsed by mockParser", 307 } 308 URI, err := archiver.NewURI(testBucketURI) 309 s.NoError(err) 310 response, err := visibilityArchiver.Query(context.Background(), URI, request, searchattribute.TestNameTypeMap) 311 s.NoError(err) 312 s.NotNil(response) 313 s.Nil(response.NextPageToken) 314 s.Len(response.Executions, 2) 315 ei, err := convertToExecutionInfo(s.visibilityRecords[0], searchattribute.TestNameTypeMap) 316 s.NoError(err) 317 s.Equal(response.Executions[0], ei) 318 } 319 320 func (s *visibilityArchiverSuite) TestQuery_Success_SmallPageSize() { 321 visibilityArchiver := s.newTestVisibilityArchiver() 322 mockParser := NewMockQueryParser(s.controller) 323 mockParser.EXPECT().Parse(gomock.Any()).Return(&parsedQuery{ 324 closeTime: ptr(time.Unix(0, 0).UTC()), 325 searchPrecision: convert.StringPtr(PrecisionDay), 326 workflowID: convert.StringPtr(testWorkflowID), 327 }, nil).AnyTimes() 328 visibilityArchiver.queryParser = mockParser 329 request := &archiver.QueryVisibilityRequest{ 330 NamespaceID: testNamespaceID, 331 PageSize: 2, 332 Query: "parsed by mockParser", 333 } 334 URI, err := archiver.NewURI(testBucketURI) 335 s.NoError(err) 336 response, err := visibilityArchiver.Query(context.Background(), URI, request, searchattribute.TestNameTypeMap) 337 s.NoError(err) 338 s.NotNil(response) 339 s.NotNil(response.NextPageToken) 340 s.Len(response.Executions, 2) 341 ei, err := convertToExecutionInfo(s.visibilityRecords[0], searchattribute.TestNameTypeMap) 342 s.NoError(err) 343 s.Equal(ei, response.Executions[0]) 344 ei, err = convertToExecutionInfo(s.visibilityRecords[1], searchattribute.TestNameTypeMap) 345 s.NoError(err) 346 s.Equal(ei, response.Executions[1]) 347 348 request.NextPageToken = response.NextPageToken 349 response, err = visibilityArchiver.Query(context.Background(), URI, request, searchattribute.TestNameTypeMap) 350 s.NoError(err) 351 s.NotNil(response) 352 s.Nil(response.NextPageToken) 353 s.Len(response.Executions, 1) 354 ei, err = convertToExecutionInfo(s.visibilityRecords[2], searchattribute.TestNameTypeMap) 355 s.NoError(err) 356 s.Equal(ei, response.Executions[0]) 357 } 358 359 func (s *visibilityArchiverSuite) TestQuery_EmptyQuery_InvalidNamespace() { 360 arc := archiver.VisibilityArchiver(s.newTestVisibilityArchiver()) 361 uri, err := archiver.NewURI(testBucketURI) 362 s.NoError(err) 363 req := &archiver.QueryVisibilityRequest{ 364 NamespaceID: "", 365 PageSize: 1, 366 NextPageToken: nil, 367 Query: "", 368 } 369 _, err = arc.Query(context.Background(), uri, req, searchattribute.TestNameTypeMap) 370 371 var svcErr *serviceerror.InvalidArgument 372 373 s.ErrorAs(err, &svcErr) 374 } 375 376 func (s *visibilityArchiverSuite) TestQuery_EmptyQuery_ZeroPageSize() { 377 arc := archiver.VisibilityArchiver(s.newTestVisibilityArchiver()) 378 379 uri, err := archiver.NewURI(testBucketURI) 380 s.NoError(err) 381 382 req := &archiver.QueryVisibilityRequest{ 383 NamespaceID: testNamespaceID, 384 PageSize: 0, 385 NextPageToken: nil, 386 Query: "", 387 } 388 _, err = arc.Query(context.Background(), uri, req, searchattribute.TestNameTypeMap) 389 390 var svcErr *serviceerror.InvalidArgument 391 392 s.ErrorAs(err, &svcErr) 393 } 394 395 func (s *visibilityArchiverSuite) TestQuery_EmptyQuery_Pagination() { 396 arc := archiver.VisibilityArchiver(s.newTestVisibilityArchiver()) 397 uri, err := archiver.NewURI(testBucketURI) 398 s.NoError(err) 399 400 executions := make(map[string]*workflowpb.WorkflowExecutionInfo, len(s.visibilityRecords)) 401 var nextPageToken []byte 402 403 for { 404 req := &archiver.QueryVisibilityRequest{ 405 NamespaceID: testNamespaceID, 406 PageSize: 1, 407 NextPageToken: nextPageToken, 408 Query: "", 409 } 410 response, err := arc.Query(context.Background(), uri, req, searchattribute.TestNameTypeMap) 411 s.NoError(err) 412 s.NotNil(response) 413 nextPageToken = response.NextPageToken 414 for _, execution := range response.Executions { 415 key := execution.Execution.GetWorkflowId() + 416 "/" + execution.Execution.GetRunId() + 417 "/" + execution.CloseTime.String() 418 if executions[key] != nil { 419 s.Fail("duplicate key", key) 420 } 421 executions[key] = execution 422 } 423 if len(nextPageToken) == 0 { 424 break 425 } 426 } 427 s.Len(executions, len(s.visibilityRecords)) 428 } 429 430 type precisionTest struct { 431 day int 432 hour int 433 minute int 434 second int 435 precision string 436 } 437 438 func (s *visibilityArchiverSuite) TestArchiveAndQueryPrecisions() { 439 precisionTests := []*precisionTest{ 440 { 441 day: 1, 442 hour: 0, 443 minute: 0, 444 second: 0, 445 precision: PrecisionDay, 446 }, 447 { 448 day: 1, 449 hour: 1, 450 minute: 0, 451 second: 0, 452 precision: PrecisionDay, 453 }, 454 { 455 day: 2, 456 hour: 1, 457 minute: 0, 458 second: 0, 459 precision: PrecisionHour, 460 }, 461 { 462 day: 2, 463 hour: 1, 464 minute: 30, 465 second: 0, 466 precision: PrecisionHour, 467 }, 468 { 469 day: 3, 470 hour: 2, 471 minute: 1, 472 second: 0, 473 precision: PrecisionMinute, 474 }, 475 { 476 day: 3, 477 hour: 2, 478 minute: 1, 479 second: 30, 480 precision: PrecisionMinute, 481 }, 482 { 483 day: 4, 484 hour: 3, 485 minute: 2, 486 second: 1, 487 precision: PrecisionSecond, 488 }, 489 { 490 day: 4, 491 hour: 3, 492 minute: 2, 493 second: 1, 494 precision: PrecisionSecond, 495 }, 496 { 497 day: 4, 498 hour: 3, 499 minute: 2, 500 second: 2, 501 precision: PrecisionSecond, 502 }, 503 { 504 day: 4, 505 hour: 3, 506 minute: 2, 507 second: 2, 508 precision: PrecisionSecond, 509 }, 510 } 511 visibilityArchiver := s.newTestVisibilityArchiver() 512 URI, err := archiver.NewURI(testBucketURI + "/archive-and-query-precision") 513 s.NoError(err) 514 515 for i, testData := range precisionTests { 516 record := archiverspb.VisibilityRecord{ 517 NamespaceId: testNamespaceID, 518 Namespace: testNamespace, 519 WorkflowId: testWorkflowID, 520 RunId: fmt.Sprintf("%s-%d", testRunID, i), 521 WorkflowTypeName: testWorkflowTypeName, 522 StartTime: timestamppb.New(time.Date(2000, 1, testData.day, testData.hour, testData.minute, testData.second, 0, time.UTC)), 523 CloseTime: timestamppb.New(time.Date(2000, 1, testData.day, testData.hour, testData.minute, testData.second, 0, time.UTC)), 524 Status: enumspb.WORKFLOW_EXECUTION_STATUS_FAILED, 525 HistoryLength: 101, 526 } 527 err := visibilityArchiver.Archive(context.Background(), URI, &record) 528 s.NoError(err, "case %d", i) 529 } 530 531 request := &archiver.QueryVisibilityRequest{ 532 NamespaceID: testNamespaceID, 533 PageSize: 100, 534 Query: "parsed by mockParser", 535 } 536 537 for i, testData := range precisionTests { 538 mockParser := NewMockQueryParser(s.controller) 539 mockParser.EXPECT().Parse(gomock.Any()).Return(&parsedQuery{ 540 closeTime: ptr(time.Date(2000, 1, testData.day, testData.hour, testData.minute, testData.second, 0, time.UTC)), 541 searchPrecision: convert.StringPtr(testData.precision), 542 workflowID: convert.StringPtr(testWorkflowID), 543 }, nil).AnyTimes() 544 visibilityArchiver.queryParser = mockParser 545 546 response, err := visibilityArchiver.Query(context.Background(), URI, request, searchattribute.TestNameTypeMap) 547 s.NoError(err) 548 s.NotNil(response) 549 s.Len(response.Executions, 2, "Iteration ", i) 550 551 mockParser = NewMockQueryParser(s.controller) 552 mockParser.EXPECT().Parse(gomock.Any()).Return(&parsedQuery{ 553 startTime: ptr(time.Date(2000, 1, testData.day, testData.hour, testData.minute, testData.second, 0, time.UTC)), 554 searchPrecision: convert.StringPtr(testData.precision), 555 workflowID: convert.StringPtr(testWorkflowID), 556 }, nil).AnyTimes() 557 visibilityArchiver.queryParser = mockParser 558 559 response, err = visibilityArchiver.Query(context.Background(), URI, request, searchattribute.TestNameTypeMap) 560 s.NoError(err) 561 s.NotNil(response) 562 s.Len(response.Executions, 2, "Iteration ", i) 563 564 mockParser = NewMockQueryParser(s.controller) 565 mockParser.EXPECT().Parse(gomock.Any()).Return(&parsedQuery{ 566 closeTime: ptr(time.Date(2000, 1, testData.day, testData.hour, testData.minute, testData.second, 0, time.UTC)), 567 searchPrecision: convert.StringPtr(testData.precision), 568 workflowTypeName: convert.StringPtr(testWorkflowTypeName), 569 }, nil).AnyTimes() 570 visibilityArchiver.queryParser = mockParser 571 572 response, err = visibilityArchiver.Query(context.Background(), URI, request, searchattribute.TestNameTypeMap) 573 s.NoError(err) 574 s.NotNil(response) 575 s.Len(response.Executions, 2, "Iteration ", i) 576 577 mockParser = NewMockQueryParser(s.controller) 578 mockParser.EXPECT().Parse(gomock.Any()).Return(&parsedQuery{ 579 startTime: ptr(time.Date(2000, 1, testData.day, testData.hour, testData.minute, testData.second, 0, time.UTC)), 580 searchPrecision: convert.StringPtr(testData.precision), 581 workflowTypeName: convert.StringPtr(testWorkflowTypeName), 582 }, nil).AnyTimes() 583 visibilityArchiver.queryParser = mockParser 584 585 response, err = visibilityArchiver.Query(context.Background(), URI, request, searchattribute.TestNameTypeMap) 586 s.NoError(err) 587 s.NotNil(response) 588 s.Len(response.Executions, 2, "Iteration ", i) 589 } 590 } 591 592 func (s *visibilityArchiverSuite) TestArchiveAndQuery() { 593 visibilityArchiver := s.newTestVisibilityArchiver() 594 URI, err := archiver.NewURI(testBucketURI + "/archive-and-query") 595 s.NoError(err) 596 for _, record := range s.visibilityRecords { 597 err := visibilityArchiver.Archive(context.Background(), URI, (*archiverspb.VisibilityRecord)(record)) 598 s.NoError(err) 599 } 600 601 mockParser := NewMockQueryParser(s.controller) 602 mockParser.EXPECT().Parse(gomock.Any()).Return(&parsedQuery{ 603 workflowID: convert.StringPtr(testWorkflowID), 604 }, nil).AnyTimes() 605 visibilityArchiver.queryParser = mockParser 606 request := &archiver.QueryVisibilityRequest{ 607 NamespaceID: testNamespaceID, 608 PageSize: 1, 609 Query: "parsed by mockParser", 610 } 611 executions := []*workflowpb.WorkflowExecutionInfo{} 612 first := true 613 for first || request.NextPageToken != nil { 614 response, err := visibilityArchiver.Query(context.Background(), URI, request, searchattribute.TestNameTypeMap) 615 s.NoError(err) 616 s.NotNil(response) 617 executions = append(executions, response.Executions...) 618 request.NextPageToken = response.NextPageToken 619 first = false 620 } 621 s.Len(executions, 3) 622 ei, err := convertToExecutionInfo(s.visibilityRecords[0], searchattribute.TestNameTypeMap) 623 s.NoError(err) 624 s.Equal(ei, executions[0]) 625 ei, err = convertToExecutionInfo(s.visibilityRecords[1], searchattribute.TestNameTypeMap) 626 s.NoError(err) 627 s.Equal(ei, executions[1]) 628 ei, err = convertToExecutionInfo(s.visibilityRecords[2], searchattribute.TestNameTypeMap) 629 s.NoError(err) 630 s.Equal(ei, executions[2]) 631 632 mockParser = NewMockQueryParser(s.controller) 633 mockParser.EXPECT().Parse(gomock.Any()).Return(&parsedQuery{ 634 workflowTypeName: convert.StringPtr(testWorkflowTypeName), 635 }, nil).AnyTimes() 636 visibilityArchiver.queryParser = mockParser 637 request = &archiver.QueryVisibilityRequest{ 638 NamespaceID: testNamespaceID, 639 PageSize: 1, 640 Query: "parsed by mockParser", 641 } 642 executions = []*workflowpb.WorkflowExecutionInfo{} 643 first = true 644 for first || request.NextPageToken != nil { 645 response, err := visibilityArchiver.Query(context.Background(), URI, request, searchattribute.TestNameTypeMap) 646 s.NoError(err) 647 s.NotNil(response) 648 executions = append(executions, response.Executions...) 649 request.NextPageToken = response.NextPageToken 650 first = false 651 } 652 s.Len(executions, 3) 653 ei, err = convertToExecutionInfo(s.visibilityRecords[0], searchattribute.TestNameTypeMap) 654 s.NoError(err) 655 s.Equal(ei, executions[0]) 656 ei, err = convertToExecutionInfo(s.visibilityRecords[1], searchattribute.TestNameTypeMap) 657 s.NoError(err) 658 s.Equal(ei, executions[1]) 659 ei, err = convertToExecutionInfo(s.visibilityRecords[2], searchattribute.TestNameTypeMap) 660 s.NoError(err) 661 s.Equal(ei, executions[2]) 662 } 663 664 func (s *visibilityArchiverSuite) setupVisibilityDirectory() { 665 s.visibilityRecords = []*archiverspb.VisibilityRecord{ 666 { 667 NamespaceId: testNamespaceID, 668 Namespace: testNamespace, 669 WorkflowId: testWorkflowID, 670 RunId: testRunID, 671 WorkflowTypeName: testWorkflowTypeName, 672 StartTime: timestamp.UnixOrZeroTimePtr(1), 673 CloseTime: timestamp.UnixOrZeroTimePtr(int64(time.Hour)), 674 Status: enumspb.WORKFLOW_EXECUTION_STATUS_FAILED, 675 HistoryLength: 101, 676 }, 677 { 678 NamespaceId: testNamespaceID, 679 Namespace: testNamespace, 680 WorkflowId: testWorkflowID, 681 RunId: testRunID + "1", 682 WorkflowTypeName: testWorkflowTypeName, 683 StartTime: timestamp.UnixOrZeroTimePtr(1), 684 CloseTime: timestamp.UnixOrZeroTimePtr(int64(time.Hour + 30*time.Minute)), 685 Status: enumspb.WORKFLOW_EXECUTION_STATUS_FAILED, 686 HistoryLength: 101, 687 }, 688 { 689 NamespaceId: testNamespaceID, 690 Namespace: testNamespace, 691 WorkflowId: testWorkflowID, 692 RunId: testRunID + "1", 693 WorkflowTypeName: testWorkflowTypeName, 694 StartTime: timestamp.UnixOrZeroTimePtr(1), 695 CloseTime: timestamp.UnixOrZeroTimePtr(int64(3 * time.Hour)), 696 Status: enumspb.WORKFLOW_EXECUTION_STATUS_FAILED, 697 HistoryLength: 101, 698 }, 699 } 700 visibilityArchiver := s.newTestVisibilityArchiver() 701 for _, record := range s.visibilityRecords { 702 s.writeVisibilityRecordForQueryTest(visibilityArchiver, record) 703 } 704 } 705 706 func (s *visibilityArchiverSuite) writeVisibilityRecordForQueryTest(visibilityArchiver *visibilityArchiver, record *archiverspb.VisibilityRecord) { 707 err := visibilityArchiver.Archive(context.Background(), s.testArchivalURI, record) 708 s.Require().NoError(err) 709 }