go.temporal.io/server@v1.23.0/common/archiver/filestore/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 filestore 26 27 import ( 28 "context" 29 "errors" 30 "os" 31 "path" 32 "testing" 33 "time" 34 35 "github.com/golang/mock/gomock" 36 "github.com/stretchr/testify/require" 37 "github.com/stretchr/testify/suite" 38 commonpb "go.temporal.io/api/common/v1" 39 enumspb "go.temporal.io/api/enums/v1" 40 "go.temporal.io/api/serviceerror" 41 workflowpb "go.temporal.io/api/workflow/v1" 42 "google.golang.org/protobuf/types/known/timestamppb" 43 44 "go.temporal.io/server/common/searchattribute" 45 46 archiverspb "go.temporal.io/server/api/archiver/v1" 47 "go.temporal.io/server/common/archiver" 48 "go.temporal.io/server/common/codec" 49 "go.temporal.io/server/common/config" 50 "go.temporal.io/server/common/convert" 51 "go.temporal.io/server/common/log" 52 "go.temporal.io/server/common/payload" 53 "go.temporal.io/server/common/primitives/timestamp" 54 "go.temporal.io/server/tests/testutils" 55 ) 56 57 const ( 58 testWorkflowTypeName = "test-workflow-type" 59 ) 60 61 type visibilityArchiverSuite struct { 62 *require.Assertions 63 suite.Suite 64 65 container *archiver.VisibilityBootstrapContainer 66 testArchivalURI archiver.URI 67 testQueryDirectory string 68 visibilityRecords []*archiverspb.VisibilityRecord 69 70 controller *gomock.Controller 71 } 72 73 func TestVisibilityArchiverSuite(t *testing.T) { 74 suite.Run(t, new(visibilityArchiverSuite)) 75 } 76 77 func (s *visibilityArchiverSuite) SetupSuite() { 78 var err error 79 s.testQueryDirectory, err = os.MkdirTemp("", "TestQuery") 80 s.Require().NoError(err) 81 s.setupVisibilityDirectory() 82 s.testArchivalURI, err = archiver.NewURI("file:///a/b/c") 83 s.Require().NoError(err) 84 } 85 86 func (s *visibilityArchiverSuite) TearDownSuite() { 87 if err := os.RemoveAll(s.testQueryDirectory); err != nil { 88 s.Fail("Failed to remove test query directory %v: %v", s.testQueryDirectory, err) 89 } 90 } 91 92 func (s *visibilityArchiverSuite) SetupTest() { 93 s.Assertions = require.New(s.T()) 94 s.container = &archiver.VisibilityBootstrapContainer{ 95 Logger: log.NewNoopLogger(), 96 } 97 s.controller = gomock.NewController(s.T()) 98 } 99 100 func (s *visibilityArchiverSuite) TearDownTest() { 101 s.controller.Finish() 102 } 103 104 func (s *visibilityArchiverSuite) TestValidateURI() { 105 testCases := []struct { 106 URI string 107 expectedErr error 108 }{ 109 { 110 URI: "wrongscheme:///a/b/c", 111 expectedErr: archiver.ErrURISchemeMismatch, 112 }, 113 { 114 URI: "file://", 115 expectedErr: errEmptyDirectoryPath, 116 }, 117 { 118 URI: "file:///a/b/c", 119 expectedErr: nil, 120 }, 121 } 122 123 visibilityArchiver := s.newTestVisibilityArchiver() 124 for _, tc := range testCases { 125 URI, err := archiver.NewURI(tc.URI) 126 s.NoError(err) 127 s.Equal(tc.expectedErr, visibilityArchiver.ValidateURI(URI)) 128 } 129 } 130 131 func (s *visibilityArchiverSuite) TestArchive_Fail_InvalidURI() { 132 visibilityArchiver := s.newTestVisibilityArchiver() 133 URI, err := archiver.NewURI("wrongscheme://") 134 s.NoError(err) 135 request := &archiverspb.VisibilityRecord{ 136 Namespace: testNamespace, 137 NamespaceId: testNamespaceID, 138 WorkflowId: testWorkflowID, 139 RunId: testRunID, 140 WorkflowTypeName: testWorkflowTypeName, 141 StartTime: timestamp.TimeNowPtrUtc(), 142 ExecutionTime: nil, // workflow without backoff 143 CloseTime: timestamp.TimeNowPtrUtc(), 144 Status: enumspb.WORKFLOW_EXECUTION_STATUS_FAILED, 145 HistoryLength: int64(101), 146 } 147 err = visibilityArchiver.Archive(context.Background(), URI, request) 148 s.Error(err) 149 } 150 151 func (s *visibilityArchiverSuite) TestArchive_Fail_InvalidRequest() { 152 visibilityArchiver := s.newTestVisibilityArchiver() 153 err := visibilityArchiver.Archive(context.Background(), s.testArchivalURI, &archiverspb.VisibilityRecord{}) 154 s.Error(err) 155 } 156 157 func (s *visibilityArchiverSuite) TestArchive_Fail_NonRetryableErrorOption() { 158 visibilityArchiver := s.newTestVisibilityArchiver() 159 nonRetryableErr := errors.New("some non-retryable error") 160 err := visibilityArchiver.Archive( 161 context.Background(), 162 s.testArchivalURI, 163 &archiverspb.VisibilityRecord{}, 164 archiver.GetNonRetryableErrorOption(nonRetryableErr), 165 ) 166 s.Equal(nonRetryableErr, err) 167 } 168 169 func (s *visibilityArchiverSuite) TestArchive_Success() { 170 dir := testutils.MkdirTemp(s.T(), "", "TestVisibilityArchive") 171 172 visibilityArchiver := s.newTestVisibilityArchiver() 173 closeTimestamp := timestamp.TimeNowPtrUtc() 174 request := &archiverspb.VisibilityRecord{ 175 NamespaceId: testNamespaceID, 176 Namespace: testNamespace, 177 WorkflowId: testWorkflowID, 178 RunId: testRunID, 179 WorkflowTypeName: testWorkflowTypeName, 180 StartTime: timestamppb.New(closeTimestamp.AsTime().Add(-time.Hour)), 181 ExecutionTime: nil, // workflow without backoff 182 CloseTime: closeTimestamp, 183 Status: enumspb.WORKFLOW_EXECUTION_STATUS_FAILED, 184 HistoryLength: int64(101), 185 Memo: &commonpb.Memo{ 186 Fields: map[string]*commonpb.Payload{ 187 "testFields": payload.EncodeBytes([]byte{1, 2, 3}), 188 }, 189 }, 190 SearchAttributes: map[string]string{ 191 "testAttribute": "456", 192 }, 193 } 194 URI, err := archiver.NewURI("file://" + dir) 195 s.NoError(err) 196 err = visibilityArchiver.Archive(context.Background(), URI, request) 197 s.NoError(err) 198 199 expectedFilename := constructVisibilityFilename(closeTimestamp.AsTime(), testRunID) 200 filepath := path.Join(dir, testNamespaceID, expectedFilename) 201 s.assertFileExists(filepath) 202 203 data, err := readFile(filepath) 204 s.NoError(err) 205 206 archivedRecord := &archiverspb.VisibilityRecord{} 207 encoder := codec.NewJSONPBEncoder() 208 err = encoder.Decode(data, archivedRecord) 209 s.NoError(err) 210 s.Equal(request, archivedRecord) 211 } 212 213 func (s *visibilityArchiverSuite) TestMatchQuery() { 214 testCases := []struct { 215 query *parsedQuery 216 record *archiverspb.VisibilityRecord 217 shouldMatch bool 218 }{ 219 { 220 query: &parsedQuery{ 221 earliestCloseTime: time.Unix(0, 1000), 222 latestCloseTime: time.Unix(0, 12345), 223 }, 224 record: &archiverspb.VisibilityRecord{ 225 CloseTime: timestamp.UnixOrZeroTimePtr(1999), 226 }, 227 shouldMatch: true, 228 }, 229 { 230 query: &parsedQuery{ 231 earliestCloseTime: time.Unix(0, 1000), 232 latestCloseTime: time.Unix(0, 12345), 233 }, 234 record: &archiverspb.VisibilityRecord{ 235 CloseTime: timestamp.UnixOrZeroTimePtr(999), 236 }, 237 shouldMatch: false, 238 }, 239 { 240 query: &parsedQuery{ 241 earliestCloseTime: time.Unix(0, 1000), 242 latestCloseTime: time.Unix(0, 12345), 243 workflowID: convert.StringPtr("random workflowID"), 244 }, 245 record: &archiverspb.VisibilityRecord{ 246 CloseTime: timestamp.UnixOrZeroTimePtr(2000), 247 }, 248 shouldMatch: false, 249 }, 250 { 251 query: &parsedQuery{ 252 earliestCloseTime: time.Unix(0, 1000), 253 latestCloseTime: time.Unix(0, 12345), 254 workflowID: convert.StringPtr("random workflowID"), 255 runID: convert.StringPtr("random runID"), 256 }, 257 record: &archiverspb.VisibilityRecord{ 258 CloseTime: timestamp.UnixOrZeroTimePtr(12345), 259 WorkflowId: "random workflowID", 260 RunId: "random runID", 261 WorkflowTypeName: "random type name", 262 }, 263 shouldMatch: true, 264 }, 265 { 266 query: &parsedQuery{ 267 earliestCloseTime: time.Unix(0, 1000), 268 latestCloseTime: time.Unix(0, 12345), 269 workflowTypeName: convert.StringPtr("some random type name"), 270 }, 271 record: &archiverspb.VisibilityRecord{ 272 CloseTime: timestamp.UnixOrZeroTimePtr(12345), 273 }, 274 shouldMatch: false, 275 }, 276 { 277 query: &parsedQuery{ 278 earliestCloseTime: time.Unix(0, 1000), 279 latestCloseTime: time.Unix(0, 12345), 280 workflowTypeName: convert.StringPtr("some random type name"), 281 status: toWorkflowExecutionStatusPtr(enumspb.WORKFLOW_EXECUTION_STATUS_CONTINUED_AS_NEW), 282 }, 283 record: &archiverspb.VisibilityRecord{ 284 CloseTime: timestamp.UnixOrZeroTimePtr(12345), 285 Status: enumspb.WORKFLOW_EXECUTION_STATUS_CONTINUED_AS_NEW, 286 WorkflowTypeName: "some random type name", 287 }, 288 shouldMatch: true, 289 }, 290 } 291 292 for _, tc := range testCases { 293 s.Equal(tc.shouldMatch, matchQuery(tc.record, tc.query)) 294 } 295 } 296 297 func (s *visibilityArchiverSuite) TestSortAndFilterFiles() { 298 testCases := []struct { 299 filenames []string 300 token *queryVisibilityToken 301 expectedResult []string 302 }{ 303 { 304 filenames: []string{"9_12345.vis", "5_0.vis", "9_54321.vis", "1000_654.vis", "1000_78.vis"}, 305 expectedResult: []string{"1000_78.vis", "1000_654.vis", "9_54321.vis", "9_12345.vis", "5_0.vis"}, 306 }, 307 { 308 filenames: []string{"9_12345.vis", "5_0.vis", "9_54321.vis", "1000_654.vis", "1000_78.vis"}, 309 token: &queryVisibilityToken{ 310 LastCloseTime: time.Unix(0, 3), 311 }, 312 expectedResult: []string{}, 313 }, 314 { 315 filenames: []string{"9_12345.vis", "5_0.vis", "9_54321.vis", "1000_654.vis", "1000_78.vis"}, 316 token: &queryVisibilityToken{ 317 LastCloseTime: time.Unix(0, 999), 318 }, 319 expectedResult: []string{"9_54321.vis", "9_12345.vis", "5_0.vis"}, 320 }, 321 { 322 filenames: []string{"9_12345.vis", "5_0.vis", "9_54321.vis", "1000_654.vis", "1000_78.vis"}, 323 token: &queryVisibilityToken{ 324 LastCloseTime: time.Unix(0, 5).UTC(), 325 }, 326 expectedResult: []string{"5_0.vis"}, 327 }, 328 } 329 330 for i, tc := range testCases { 331 result, err := sortAndFilterFiles(tc.filenames, tc.token) 332 s.NoError(err, "case %d", i) 333 s.Equal(tc.expectedResult, result, "case %d", i) 334 } 335 } 336 337 func (s *visibilityArchiverSuite) TestQuery_Fail_InvalidURI() { 338 visibilityArchiver := s.newTestVisibilityArchiver() 339 URI, err := archiver.NewURI("wrongscheme://") 340 s.NoError(err) 341 request := &archiver.QueryVisibilityRequest{ 342 NamespaceID: testNamespaceID, 343 PageSize: 1, 344 } 345 response, err := visibilityArchiver.Query(context.Background(), URI, request, searchattribute.TestNameTypeMap) 346 s.Error(err) 347 s.Nil(response) 348 } 349 350 func (s *visibilityArchiverSuite) TestQuery_Fail_InvalidRequest() { 351 visibilityArchiver := s.newTestVisibilityArchiver() 352 response, err := visibilityArchiver.Query(context.Background(), s.testArchivalURI, &archiver.QueryVisibilityRequest{}, searchattribute.TestNameTypeMap) 353 s.Error(err) 354 s.Nil(response) 355 } 356 357 func (s *visibilityArchiverSuite) TestQuery_Fail_InvalidQuery() { 358 visibilityArchiver := s.newTestVisibilityArchiver() 359 mockParser := NewMockQueryParser(s.controller) 360 mockParser.EXPECT().Parse(gomock.Any()).Return(nil, errors.New("invalid query")) 361 visibilityArchiver.queryParser = mockParser 362 response, err := visibilityArchiver.Query(context.Background(), s.testArchivalURI, &archiver.QueryVisibilityRequest{ 363 NamespaceID: "some random namespaceID", 364 PageSize: 10, 365 Query: "some invalid query", 366 }, searchattribute.TestNameTypeMap) 367 s.Error(err) 368 s.Nil(response) 369 } 370 371 func (s *visibilityArchiverSuite) TestQuery_Success_DirectoryNotExist() { 372 visibilityArchiver := s.newTestVisibilityArchiver() 373 mockParser := NewMockQueryParser(s.controller) 374 mockParser.EXPECT().Parse(gomock.Any()).Return(&parsedQuery{ 375 earliestCloseTime: time.Unix(0, 1), 376 latestCloseTime: time.Unix(0, 101), 377 }, nil) 378 visibilityArchiver.queryParser = mockParser 379 request := &archiver.QueryVisibilityRequest{ 380 NamespaceID: testNamespaceID, 381 Query: "parsed by mockParser", 382 PageSize: 1, 383 } 384 response, err := visibilityArchiver.Query(context.Background(), s.testArchivalURI, request, searchattribute.TestNameTypeMap) 385 s.NoError(err) 386 s.NotNil(response) 387 s.Empty(response.Executions) 388 s.Empty(response.NextPageToken) 389 } 390 391 func (s *visibilityArchiverSuite) TestQuery_Fail_InvalidToken() { 392 visibilityArchiver := s.newTestVisibilityArchiver() 393 mockParser := NewMockQueryParser(s.controller) 394 mockParser.EXPECT().Parse(gomock.Any()).Return(&parsedQuery{ 395 earliestCloseTime: time.Unix(0, 1), 396 latestCloseTime: time.Unix(0, 101), 397 }, nil) 398 visibilityArchiver.queryParser = mockParser 399 request := &archiver.QueryVisibilityRequest{ 400 NamespaceID: testNamespaceID, 401 Query: "parsed by mockParser", 402 PageSize: 1, 403 NextPageToken: []byte{1, 2, 3}, 404 } 405 response, err := visibilityArchiver.Query(context.Background(), s.testArchivalURI, request, searchattribute.TestNameTypeMap) 406 s.Error(err) 407 s.Nil(response) 408 } 409 410 func (s *visibilityArchiverSuite) TestQuery_Success_NoNextPageToken() { 411 visibilityArchiver := s.newTestVisibilityArchiver() 412 mockParser := NewMockQueryParser(s.controller) 413 mockParser.EXPECT().Parse(gomock.Any()).Return(&parsedQuery{ 414 earliestCloseTime: time.Unix(0, 1), 415 latestCloseTime: time.Unix(0, 10001), 416 workflowID: convert.StringPtr(testWorkflowID), 417 }, nil) 418 visibilityArchiver.queryParser = mockParser 419 request := &archiver.QueryVisibilityRequest{ 420 NamespaceID: testNamespaceID, 421 PageSize: 10, 422 Query: "parsed by mockParser", 423 } 424 URI, err := archiver.NewURI("file://" + s.testQueryDirectory) 425 s.NoError(err) 426 response, err := visibilityArchiver.Query(context.Background(), URI, request, searchattribute.TestNameTypeMap) 427 s.NoError(err) 428 s.NotNil(response) 429 s.Nil(response.NextPageToken) 430 s.Len(response.Executions, 1) 431 ei, err := convertToExecutionInfo(s.visibilityRecords[0], searchattribute.TestNameTypeMap) 432 s.NoError(err) 433 s.Equal(ei, response.Executions[0]) 434 } 435 436 func (s *visibilityArchiverSuite) TestQuery_Success_SmallPageSize() { 437 visibilityArchiver := s.newTestVisibilityArchiver() 438 mockParser := NewMockQueryParser(s.controller) 439 mockParser.EXPECT().Parse(gomock.Any()).Return(&parsedQuery{ 440 earliestCloseTime: time.Unix(0, 1), 441 latestCloseTime: time.Unix(0, 10001), 442 status: toWorkflowExecutionStatusPtr(enumspb.WORKFLOW_EXECUTION_STATUS_FAILED), 443 }, nil).AnyTimes() 444 visibilityArchiver.queryParser = mockParser 445 request := &archiver.QueryVisibilityRequest{ 446 NamespaceID: testNamespaceID, 447 PageSize: 2, 448 Query: "parsed by mockParser", 449 } 450 URI, err := archiver.NewURI("file://" + s.testQueryDirectory) 451 s.NoError(err) 452 response, err := visibilityArchiver.Query(context.Background(), URI, request, searchattribute.TestNameTypeMap) 453 s.NoError(err) 454 s.NotNil(response) 455 s.NotNil(response.NextPageToken) 456 s.Len(response.Executions, 2) 457 ei, err := convertToExecutionInfo(s.visibilityRecords[0], searchattribute.TestNameTypeMap) 458 s.NoError(err) 459 s.Equal(ei, response.Executions[0]) 460 ei, err = convertToExecutionInfo(s.visibilityRecords[1], searchattribute.TestNameTypeMap) 461 s.NoError(err) 462 s.Equal(ei, response.Executions[1]) 463 464 request.NextPageToken = response.NextPageToken 465 response, err = visibilityArchiver.Query(context.Background(), URI, request, searchattribute.TestNameTypeMap) 466 s.NoError(err) 467 s.NotNil(response) 468 s.Nil(response.NextPageToken) 469 s.Len(response.Executions, 1) 470 ei, err = convertToExecutionInfo(s.visibilityRecords[3], searchattribute.TestNameTypeMap) 471 s.NoError(err) 472 s.Equal(ei, response.Executions[0]) 473 } 474 475 func (s *visibilityArchiverSuite) TestArchiveAndQuery() { 476 dir := testutils.MkdirTemp(s.T(), "", "TestArchiveAndQuery") 477 478 visibilityArchiver := s.newTestVisibilityArchiver() 479 mockParser := NewMockQueryParser(s.controller) 480 mockParser.EXPECT().Parse(gomock.Any()).Return(&parsedQuery{ 481 earliestCloseTime: time.Unix(0, 10), 482 latestCloseTime: time.Unix(0, 10001), 483 status: toWorkflowExecutionStatusPtr(enumspb.WORKFLOW_EXECUTION_STATUS_FAILED), 484 }, nil).AnyTimes() 485 visibilityArchiver.queryParser = mockParser 486 URI, err := archiver.NewURI("file://" + dir) 487 s.NoError(err) 488 for _, record := range s.visibilityRecords { 489 err := visibilityArchiver.Archive(context.Background(), URI, (*archiverspb.VisibilityRecord)(record)) 490 s.NoError(err) 491 } 492 493 request := &archiver.QueryVisibilityRequest{ 494 NamespaceID: testNamespaceID, 495 PageSize: 1, 496 Query: "parsed by mockParser", 497 } 498 executions := []*workflowpb.WorkflowExecutionInfo{} 499 for len(executions) == 0 || request.NextPageToken != nil { 500 response, err := visibilityArchiver.Query(context.Background(), URI, request, searchattribute.TestNameTypeMap) 501 s.NoError(err) 502 s.NotNil(response) 503 executions = append(executions, response.Executions...) 504 request.NextPageToken = response.NextPageToken 505 } 506 s.Len(executions, 2) 507 ei, err := convertToExecutionInfo(s.visibilityRecords[0], searchattribute.TestNameTypeMap) 508 s.NoError(err) 509 s.Equal(ei, executions[0]) 510 ei, err = convertToExecutionInfo(s.visibilityRecords[1], searchattribute.TestNameTypeMap) 511 s.NoError(err) 512 s.Equal(ei, executions[1]) 513 } 514 515 func (s *visibilityArchiverSuite) TestQuery_EmptyQuery_InvalidNamespace() { 516 URI := s.testArchivalURI 517 518 visibilityArchiver := s.newTestVisibilityArchiver() 519 mockParser := NewMockQueryParser(s.controller) 520 mockParser.EXPECT().Parse(gomock.Any()).Return(&parsedQuery{ 521 earliestCloseTime: time.Unix(0, 10), 522 latestCloseTime: time.Unix(0, 10001), 523 status: toWorkflowExecutionStatusPtr(enumspb.WORKFLOW_EXECUTION_STATUS_FAILED), 524 }, nil).AnyTimes() 525 visibilityArchiver.queryParser = mockParser 526 req := &archiver.QueryVisibilityRequest{ 527 NamespaceID: "", 528 PageSize: 1, 529 NextPageToken: nil, 530 Query: "", 531 } 532 _, err := visibilityArchiver.Query(context.Background(), URI, req, searchattribute.TestNameTypeMap) 533 534 var svcErr *serviceerror.InvalidArgument 535 536 s.ErrorAs(err, &svcErr) 537 } 538 539 func (s *visibilityArchiverSuite) TestQuery_EmptyQuery_ZeroPageSize() { 540 visibilityArchiver := s.newTestVisibilityArchiver() 541 542 req := &archiver.QueryVisibilityRequest{ 543 NamespaceID: testNamespaceID, 544 PageSize: 0, 545 NextPageToken: nil, 546 Query: "", 547 } 548 _, err := visibilityArchiver.Query(context.Background(), s.testArchivalURI, req, searchattribute.TestNameTypeMap) 549 550 var svcErr *serviceerror.InvalidArgument 551 552 s.ErrorAs(err, &svcErr) 553 } 554 555 func (s *visibilityArchiverSuite) TestQuery_EmptyQuery_Pagination() { 556 dir := testutils.MkdirTemp(s.T(), "", "TestQuery_EmptyQuery_Pagination") 557 558 visibilityArchiver := s.newTestVisibilityArchiver() 559 URI, err := archiver.NewURI("file://" + dir) 560 s.NoError(err) 561 for _, record := range s.visibilityRecords { 562 err := visibilityArchiver.Archive(context.Background(), URI, record) 563 s.NoError(err) 564 } 565 566 request := &archiver.QueryVisibilityRequest{ 567 NamespaceID: testNamespaceID, 568 PageSize: 1, 569 Query: "", 570 } 571 var executions []*workflowpb.WorkflowExecutionInfo 572 for len(executions) == 0 || request.NextPageToken != nil { 573 response, err := visibilityArchiver.Query(context.Background(), URI, request, searchattribute.TestNameTypeMap) 574 s.NoError(err) 575 s.NotNil(response) 576 executions = append(executions, response.Executions...) 577 request.NextPageToken = response.NextPageToken 578 } 579 s.Len(executions, 4) 580 } 581 582 func (s *visibilityArchiverSuite) newTestVisibilityArchiver() *visibilityArchiver { 583 config := &config.FilestoreArchiver{ 584 FileMode: testFileModeStr, 585 DirMode: testDirModeStr, 586 } 587 archiver, err := NewVisibilityArchiver(s.container, config) 588 s.NoError(err) 589 return archiver.(*visibilityArchiver) 590 } 591 592 func (s *visibilityArchiverSuite) setupVisibilityDirectory() { 593 s.visibilityRecords = []*archiverspb.VisibilityRecord{ 594 { 595 NamespaceId: testNamespaceID, 596 Namespace: testNamespace, 597 WorkflowId: testWorkflowID, 598 RunId: testRunID, 599 WorkflowTypeName: testWorkflowTypeName, 600 StartTime: timestamp.UnixOrZeroTimePtr(1), 601 CloseTime: timestamp.UnixOrZeroTimePtr(10000), 602 Status: enumspb.WORKFLOW_EXECUTION_STATUS_FAILED, 603 HistoryLength: 101, 604 }, 605 { 606 NamespaceId: testNamespaceID, 607 Namespace: testNamespace, 608 WorkflowId: "some random workflow ID", 609 RunId: "some random run ID", 610 WorkflowTypeName: testWorkflowTypeName, 611 StartTime: timestamp.UnixOrZeroTimePtr(2), 612 ExecutionTime: nil, 613 CloseTime: timestamp.UnixOrZeroTimePtr(1000), 614 Status: enumspb.WORKFLOW_EXECUTION_STATUS_FAILED, 615 HistoryLength: 123, 616 }, 617 { 618 NamespaceId: testNamespaceID, 619 Namespace: testNamespace, 620 WorkflowId: "another workflow ID", 621 RunId: "another run ID", 622 WorkflowTypeName: testWorkflowTypeName, 623 StartTime: timestamp.UnixOrZeroTimePtr(3), 624 ExecutionTime: nil, 625 CloseTime: timestamp.UnixOrZeroTimePtr(10), 626 Status: enumspb.WORKFLOW_EXECUTION_STATUS_CONTINUED_AS_NEW, 627 HistoryLength: 456, 628 }, 629 { 630 NamespaceId: testNamespaceID, 631 Namespace: testNamespace, 632 WorkflowId: "and another workflow ID", 633 RunId: "and another run ID", 634 WorkflowTypeName: testWorkflowTypeName, 635 StartTime: timestamp.UnixOrZeroTimePtr(3), 636 ExecutionTime: nil, 637 CloseTime: timestamp.UnixOrZeroTimePtr(5), 638 Status: enumspb.WORKFLOW_EXECUTION_STATUS_FAILED, 639 HistoryLength: 456, 640 }, 641 { 642 NamespaceId: "some random namespace ID", 643 Namespace: "some random namespace name", 644 WorkflowId: "another workflow ID", 645 RunId: "another run ID", 646 WorkflowTypeName: testWorkflowTypeName, 647 StartTime: timestamp.UnixOrZeroTimePtr(3), 648 ExecutionTime: nil, 649 CloseTime: timestamp.UnixOrZeroTimePtr(10000), 650 Status: enumspb.WORKFLOW_EXECUTION_STATUS_CONTINUED_AS_NEW, 651 HistoryLength: 456, 652 }, 653 } 654 655 for _, record := range s.visibilityRecords { 656 s.writeVisibilityRecordForQueryTest(record) 657 } 658 } 659 660 func (s *visibilityArchiverSuite) writeVisibilityRecordForQueryTest(record *archiverspb.VisibilityRecord) { 661 data, err := encode(record) 662 s.Require().NoError(err) 663 filename := constructVisibilityFilename(record.CloseTime.AsTime(), record.GetRunId()) 664 s.Require().NoError(os.MkdirAll(path.Join(s.testQueryDirectory, record.GetNamespaceId()), testDirMode)) 665 err = writeFile(path.Join(s.testQueryDirectory, record.GetNamespaceId(), filename), data, testFileMode) 666 s.Require().NoError(err) 667 } 668 669 func (s *visibilityArchiverSuite) assertFileExists(filepath string) { 670 exists, err := fileExists(filepath) 671 s.NoError(err) 672 s.True(exists) 673 }