go.temporal.io/server@v1.23.0/common/persistence/tests/visibility_persistence_suite.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 tests 26 27 import ( 28 "context" 29 "fmt" 30 "time" 31 32 "github.com/golang/mock/gomock" 33 "github.com/pborman/uuid" 34 "github.com/stretchr/testify/require" 35 commonpb "go.temporal.io/api/common/v1" 36 enumspb "go.temporal.io/api/enums/v1" 37 workflowpb "go.temporal.io/api/workflow/v1" 38 "go.temporal.io/api/workflowservice/v1" 39 40 "go.temporal.io/server/common/debug" 41 "go.temporal.io/server/common/dynamicconfig" 42 "go.temporal.io/server/common/log/tag" 43 "go.temporal.io/server/common/metrics" 44 "go.temporal.io/server/common/namespace" 45 "go.temporal.io/server/common/payload" 46 "go.temporal.io/server/common/persistence" 47 persistencetests "go.temporal.io/server/common/persistence/persistence-tests" 48 "go.temporal.io/server/common/persistence/sql/sqlplugin/mysql" 49 "go.temporal.io/server/common/persistence/sql/sqlplugin/postgresql" 50 "go.temporal.io/server/common/persistence/visibility" 51 "go.temporal.io/server/common/persistence/visibility/manager" 52 "go.temporal.io/server/common/persistence/visibility/store/standard/cassandra" 53 "go.temporal.io/server/common/primitives/timestamp" 54 "go.temporal.io/server/common/resolver" 55 "go.temporal.io/server/common/searchattribute" 56 ) 57 58 type ( 59 // VisibilityPersistenceSuite tests visibility persistence 60 VisibilityPersistenceSuite struct { 61 // override suite.Suite.Assertions with require.Assertions; this means that s.NotNil(nil) will stop the test, 62 // not merely log an error 63 *require.Assertions 64 controller *gomock.Controller 65 66 *persistencetests.TestBase 67 VisibilityMgr manager.VisibilityManager 68 SearchAttributesProvider searchattribute.Provider 69 SearchAttributesMapperProvider searchattribute.MapperProvider 70 CustomVisibilityStoreFactory visibility.VisibilityStoreFactory 71 72 ctx context.Context 73 cancel context.CancelFunc 74 } 75 ) 76 77 // SetupSuite implementation 78 func (s *VisibilityPersistenceSuite) SetupSuite() { 79 s.DefaultTestCluster.SetupTestDatabase() 80 cfg := s.DefaultTestCluster.Config() 81 82 var err error 83 s.controller = gomock.NewController(s.T()) 84 s.SearchAttributesProvider = searchattribute.NewTestProvider() 85 s.SearchAttributesMapperProvider = searchattribute.NewTestMapperProvider(nil) 86 s.VisibilityMgr, err = visibility.NewManager( 87 cfg, 88 resolver.NewNoopResolver(), 89 s.CustomVisibilityStoreFactory, 90 nil, 91 nil, 92 s.SearchAttributesProvider, 93 s.SearchAttributesMapperProvider, 94 dynamicconfig.GetIntPropertyFn(1000), 95 dynamicconfig.GetIntPropertyFn(1000), 96 dynamicconfig.GetFloatPropertyFn(0.2), 97 dynamicconfig.GetBoolPropertyFnFilteredByNamespace(false), 98 dynamicconfig.GetStringPropertyFn(visibility.SecondaryVisibilityWritingModeOff), 99 dynamicconfig.GetBoolPropertyFnFilteredByNamespace(false), 100 dynamicconfig.GetBoolPropertyFnFilteredByNamespace(true), 101 metrics.NoopMetricsHandler, 102 s.Logger, 103 ) 104 105 if err != nil { 106 // s.NoError doesn't work here. 107 s.Logger.Fatal("Unable to create visibility manager", tag.Error(err)) 108 } 109 } 110 111 // SetupTest implementation 112 func (s *VisibilityPersistenceSuite) SetupTest() { 113 // Have to define our overridden assertions in the test setup. If we did it earlier, s.T() will return nil 114 s.Assertions = require.New(s.T()) 115 s.ctx, s.cancel = context.WithTimeout(context.Background(), 30*time.Second*debug.TimeoutMultiplier) 116 } 117 118 func (s *VisibilityPersistenceSuite) TearDownTest() { 119 s.cancel() 120 } 121 122 // TearDownSuite implementation 123 func (s *VisibilityPersistenceSuite) TearDownSuite() { 124 s.VisibilityMgr.Close() 125 s.DefaultTestCluster.TearDownTestDatabase() 126 } 127 128 // TestBasicVisibility test 129 func (s *VisibilityPersistenceSuite) TestBasicVisibility() { 130 testNamespaceUUID := namespace.ID(uuid.New()) 131 startTime := time.Now().UTC().Add(time.Second * -5) 132 startReq := s.createOpenWorkflowRecord(testNamespaceUUID, "visibility-workflow-test", "visibility-workflow", startTime, "test-queue") 133 134 resp, err1 := s.VisibilityMgr.ListOpenWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequest{ 135 NamespaceID: testNamespaceUUID, 136 PageSize: 1, 137 EarliestStartTime: startTime, 138 LatestStartTime: startTime, 139 }) 140 s.Nil(err1) 141 s.Equal(1, len(resp.Executions)) 142 s.assertOpenExecutionEquals(startReq, resp.Executions[0]) 143 144 closeReq := s.createClosedWorkflowRecord(startReq, time.Now()) 145 146 resp, err3 := s.VisibilityMgr.ListOpenWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequest{ 147 NamespaceID: testNamespaceUUID, 148 PageSize: 1, 149 EarliestStartTime: startTime, 150 LatestStartTime: startTime, 151 }) 152 s.Nil(err3) 153 s.Equal(0, len(resp.Executions)) 154 155 resp, err4 := s.VisibilityMgr.ListClosedWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequest{ 156 NamespaceID: testNamespaceUUID, 157 PageSize: 1, 158 EarliestStartTime: startTime, 159 LatestStartTime: time.Now(), 160 }) 161 s.Nil(err4) 162 s.Equal(1, len(resp.Executions)) 163 s.assertClosedExecutionEquals(closeReq, resp.Executions[0]) 164 } 165 166 // TestBasicVisibilityTimeSkew test 167 func (s *VisibilityPersistenceSuite) TestBasicVisibilityTimeSkew() { 168 testNamespaceUUID := namespace.ID(uuid.New()) 169 170 startTime := time.Now() 171 openRecord := s.createOpenWorkflowRecord(testNamespaceUUID, "visibility-workflow-test-time-skew", "visibility-workflow", startTime, "test-queue") 172 173 resp, err1 := s.VisibilityMgr.ListOpenWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequest{ 174 NamespaceID: testNamespaceUUID, 175 PageSize: 1, 176 EarliestStartTime: startTime, 177 LatestStartTime: startTime, 178 }) 179 s.NoError(err1) 180 s.Equal(1, len(resp.Executions)) 181 s.assertOpenExecutionEquals(openRecord, resp.Executions[0]) 182 183 closedRecord := s.createClosedWorkflowRecord(openRecord, startTime.Add(-10*time.Millisecond)) 184 185 resp, err3 := s.VisibilityMgr.ListOpenWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequest{ 186 NamespaceID: testNamespaceUUID, 187 PageSize: 1, 188 EarliestStartTime: startTime, 189 LatestStartTime: startTime, 190 }) 191 s.NoError(err3) 192 s.Equal(0, len(resp.Executions)) 193 194 resp, err4 := s.VisibilityMgr.ListClosedWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequest{ 195 NamespaceID: testNamespaceUUID, 196 PageSize: 1, 197 EarliestStartTime: startTime.Add(-10 * time.Millisecond), // This is actually close_time 198 LatestStartTime: startTime.Add(-10 * time.Millisecond), 199 }) 200 s.NoError(err4) 201 s.Equal(1, len(resp.Executions)) 202 s.assertClosedExecutionEquals(closedRecord, resp.Executions[0]) 203 } 204 205 func (s *VisibilityPersistenceSuite) TestBasicVisibilityShortWorkflow() { 206 testNamespaceUUID := namespace.ID(uuid.New()) 207 208 startTime := time.Now().UTC() 209 openRecord := s.createOpenWorkflowRecord(testNamespaceUUID, "visibility-workflow-test-short-workflow", "visibility-workflow", startTime, "test-queue") 210 closedRecord := s.createClosedWorkflowRecord(openRecord, startTime.Add(10*time.Millisecond)) 211 212 resp, err3 := s.VisibilityMgr.ListOpenWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequest{ 213 NamespaceID: testNamespaceUUID, 214 PageSize: 1, 215 EarliestStartTime: startTime, 216 LatestStartTime: startTime, 217 }) 218 s.NoError(err3) 219 s.Equal(0, len(resp.Executions)) 220 221 resp, err4 := s.VisibilityMgr.ListClosedWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequest{ 222 NamespaceID: testNamespaceUUID, 223 PageSize: 1, 224 EarliestStartTime: startTime.Add(10 * time.Millisecond), // This is actually close_time 225 LatestStartTime: startTime.Add(10 * time.Millisecond), 226 }) 227 s.NoError(err4) 228 s.Equal(1, len(resp.Executions)) 229 s.assertClosedExecutionEquals(closedRecord, resp.Executions[0]) 230 } 231 232 // TestVisibilityPagination test 233 func (s *VisibilityPersistenceSuite) TestVisibilityPagination() { 234 testNamespaceUUID := namespace.ID(uuid.New()) 235 236 // Create 2 executions 237 startTime1 := time.Now().UTC() 238 openRecord1 := s.createOpenWorkflowRecord(testNamespaceUUID, "visibility-pagination-test1", "visibility-workflow", startTime1, "test-queue") 239 240 startTime2 := startTime1.Add(time.Second) 241 openRecord2 := s.createOpenWorkflowRecord(testNamespaceUUID, "visibility-pagination-test2", "visibility-workflow", startTime2, "test-queue") 242 243 // Get the first one 244 resp, err2 := s.VisibilityMgr.ListOpenWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequest{ 245 NamespaceID: testNamespaceUUID, 246 PageSize: 1, 247 EarliestStartTime: startTime1, 248 LatestStartTime: startTime2, 249 }) 250 s.Nil(err2) 251 s.Equal(1, len(resp.Executions)) 252 s.assertOpenExecutionEquals(openRecord2, resp.Executions[0]) 253 254 // Use token to get the second one 255 resp, err3 := s.VisibilityMgr.ListOpenWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequest{ 256 NamespaceID: testNamespaceUUID, 257 PageSize: 1, 258 EarliestStartTime: startTime1, 259 LatestStartTime: startTime2, 260 NextPageToken: resp.NextPageToken, 261 }) 262 s.Nil(err3) 263 s.Equal(1, len(resp.Executions)) 264 s.assertOpenExecutionEquals(openRecord1, resp.Executions[0]) 265 266 // It is possible to not return non empty token which is going to return empty result 267 if len(resp.NextPageToken) != 0 { 268 // Now should get empty result by using token 269 resp, err4 := s.VisibilityMgr.ListOpenWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequest{ 270 NamespaceID: testNamespaceUUID, 271 PageSize: 1, 272 EarliestStartTime: startTime1, 273 LatestStartTime: startTime2, 274 NextPageToken: resp.NextPageToken, 275 }) 276 s.Nil(err4) 277 s.Equal(0, len(resp.Executions)) 278 } 279 } 280 281 // TestFilteringByStartTime test 282 func (s *VisibilityPersistenceSuite) TestFilteringByStartTime() { 283 testNamespaceUUID := namespace.ID(uuid.New()) 284 startTime := time.Now() 285 286 // Create 2 open workflows, one started 2hrs ago, the other started just now. 287 openRecord1 := s.createOpenWorkflowRecord(testNamespaceUUID, "visibility-filtering-test1", "visibility-workflow-1", startTime.Add(-2*time.Hour), "test-queue") 288 openRecord2 := s.createOpenWorkflowRecord(testNamespaceUUID, "visibility-filtering-test2", "visibility-workflow-2", startTime, "test-queue") 289 290 // List open workflows with start time filter 291 resp, err := s.VisibilityMgr.ListOpenWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequest{ 292 NamespaceID: testNamespaceUUID, 293 PageSize: 2, 294 EarliestStartTime: time.Now().Add(-time.Hour), 295 LatestStartTime: time.Now(), 296 }) 297 s.NoError(err) 298 s.Equal(1, len(resp.Executions)) 299 s.assertOpenExecutionEquals(openRecord2, resp.Executions[0]) 300 301 // List with WorkflowType filter in query string 302 queryStr := fmt.Sprintf(`StartTime BETWEEN "%v" AND "%v"`, time.Now().Add(-time.Hour).Format(time.RFC3339Nano), time.Now().Format(time.RFC3339Nano)) 303 resp, err = s.VisibilityMgr.ListWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequestV2{ 304 NamespaceID: testNamespaceUUID, 305 PageSize: 2, 306 Query: queryStr, 307 }) 308 s.Nil(err) 309 s.Equal(1, len(resp.Executions)) 310 s.assertOpenExecutionEquals(openRecord2, resp.Executions[0]) 311 312 queryStr = fmt.Sprintf(`StartTime BETWEEN "%v" AND "%v"`, time.Now().Add(-3*time.Hour).Format(time.RFC3339Nano), time.Now().Format(time.RFC3339Nano)) 313 resp, err = s.VisibilityMgr.ListWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequestV2{ 314 NamespaceID: testNamespaceUUID, 315 PageSize: 2, 316 Query: queryStr, 317 }) 318 s.Nil(err) 319 s.Equal(2, len(resp.Executions)) 320 321 resp, err = s.VisibilityMgr.ListWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequestV2{ 322 NamespaceID: testNamespaceUUID, 323 PageSize: 2, 324 Query: queryStr + ` AND WorkflowType = "visibility-workflow-1"`, 325 }) 326 s.Nil(err) 327 s.Equal(1, len(resp.Executions)) 328 s.assertOpenExecutionEquals(openRecord1, resp.Executions[0]) 329 } 330 331 // TestFilteringByType test 332 func (s *VisibilityPersistenceSuite) TestFilteringByType() { 333 testNamespaceUUID := namespace.ID(uuid.New()) 334 startTime := time.Now() 335 336 // Create 2 executions 337 openRecord1 := s.createOpenWorkflowRecord(testNamespaceUUID, "visibility-filtering-test1", "visibility-workflow-1", startTime, "test-queue") 338 openRecord2 := s.createOpenWorkflowRecord(testNamespaceUUID, "visibility-filtering-test2", "visibility-workflow-2", startTime, "test-queue") 339 340 // List open with filtering 341 resp, err2 := s.VisibilityMgr.ListOpenWorkflowExecutionsByType(s.ctx, &manager.ListWorkflowExecutionsByTypeRequest{ 342 ListWorkflowExecutionsRequest: &manager.ListWorkflowExecutionsRequest{ 343 NamespaceID: testNamespaceUUID, 344 PageSize: 2, 345 EarliestStartTime: startTime, 346 LatestStartTime: startTime, 347 }, 348 WorkflowTypeName: "visibility-workflow-1", 349 }) 350 s.Nil(err2) 351 s.Equal(1, len(resp.Executions)) 352 s.assertOpenExecutionEquals(openRecord1, resp.Executions[0]) 353 354 // List with WorkflowType filter in query string 355 resp, err := s.VisibilityMgr.ListWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequestV2{ 356 NamespaceID: testNamespaceUUID, 357 PageSize: 2, 358 Query: `WorkflowType = "visibility-workflow-1"`, 359 }) 360 s.Nil(err) 361 s.Equal(1, len(resp.Executions)) 362 s.assertOpenExecutionEquals(openRecord1, resp.Executions[0]) 363 364 // Close both executions 365 s.createClosedWorkflowRecord(openRecord1, time.Now()) 366 closedRecord2 := s.createClosedWorkflowRecord(openRecord2, time.Now()) 367 368 // List closed with filtering 369 resp, err5 := s.VisibilityMgr.ListClosedWorkflowExecutionsByType(s.ctx, &manager.ListWorkflowExecutionsByTypeRequest{ 370 ListWorkflowExecutionsRequest: &manager.ListWorkflowExecutionsRequest{ 371 NamespaceID: testNamespaceUUID, 372 PageSize: 2, 373 EarliestStartTime: startTime, 374 LatestStartTime: time.Now(), 375 }, 376 WorkflowTypeName: "visibility-workflow-2", 377 }) 378 s.Nil(err5) 379 s.Equal(1, len(resp.Executions)) 380 s.assertClosedExecutionEquals(closedRecord2, resp.Executions[0]) 381 382 // List with WorkflowType filter in query string 383 resp, err = s.VisibilityMgr.ListWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequestV2{ 384 NamespaceID: testNamespaceUUID, 385 PageSize: 2, 386 Query: `WorkflowType = "visibility-workflow-2"`, 387 }) 388 s.Nil(err) 389 s.Equal(1, len(resp.Executions)) 390 s.assertClosedExecutionEquals(closedRecord2, resp.Executions[0]) 391 } 392 393 // TestFilteringByWorkflowID test 394 func (s *VisibilityPersistenceSuite) TestFilteringByWorkflowID() { 395 testNamespaceUUID := namespace.ID(uuid.New()) 396 startTime := time.Now() 397 398 // Create 2 executions 399 openRecord1 := s.createOpenWorkflowRecord(testNamespaceUUID, "visibility-filtering-test1", "visibility-workflow", startTime, "test-queue") 400 openRecord2 := s.createOpenWorkflowRecord(testNamespaceUUID, "visibility-filtering-test2", "visibility-workflow", startTime, "test-queue") 401 402 // List open with filtering 403 resp, err2 := s.VisibilityMgr.ListOpenWorkflowExecutionsByWorkflowID(s.ctx, &manager.ListWorkflowExecutionsByWorkflowIDRequest{ 404 ListWorkflowExecutionsRequest: &manager.ListWorkflowExecutionsRequest{ 405 NamespaceID: testNamespaceUUID, 406 PageSize: 2, 407 EarliestStartTime: startTime, 408 LatestStartTime: startTime, 409 }, 410 WorkflowID: "visibility-filtering-test1", 411 }) 412 s.Nil(err2) 413 s.Equal(1, len(resp.Executions)) 414 s.assertOpenExecutionEquals(openRecord1, resp.Executions[0]) 415 416 // List workflow with workflowID filter in query string 417 resp, err := s.VisibilityMgr.ListWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequestV2{ 418 NamespaceID: testNamespaceUUID, 419 PageSize: 2, 420 Query: `WorkflowId = "visibility-filtering-test1"`, 421 }) 422 s.Nil(err) 423 s.Equal(1, len(resp.Executions)) 424 s.assertOpenExecutionEquals(openRecord1, resp.Executions[0]) 425 426 // Close both executions 427 s.createClosedWorkflowRecord(openRecord1, time.Now()) 428 closedRecord2 := s.createClosedWorkflowRecord(openRecord2, time.Now()) 429 430 // List closed with filtering 431 resp, err5 := s.VisibilityMgr.ListClosedWorkflowExecutionsByWorkflowID(s.ctx, &manager.ListWorkflowExecutionsByWorkflowIDRequest{ 432 ListWorkflowExecutionsRequest: &manager.ListWorkflowExecutionsRequest{ 433 NamespaceID: testNamespaceUUID, 434 PageSize: 2, 435 EarliestStartTime: startTime, 436 LatestStartTime: time.Now(), 437 }, 438 WorkflowID: "visibility-filtering-test2", 439 }) 440 s.Nil(err5) 441 s.Equal(1, len(resp.Executions)) 442 s.assertClosedExecutionEquals(closedRecord2, resp.Executions[0]) 443 444 // List workflow with workflowID filter in query string 445 resp, err = s.VisibilityMgr.ListWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequestV2{ 446 NamespaceID: testNamespaceUUID, 447 PageSize: 2, 448 Query: `WorkflowId = "visibility-filtering-test2"`, 449 }) 450 s.Nil(err) 451 s.Equal(1, len(resp.Executions)) 452 s.assertClosedExecutionEquals(closedRecord2, resp.Executions[0]) 453 } 454 455 // TestFilteringByStatus test 456 func (s *VisibilityPersistenceSuite) TestFilteringByStatus() { 457 testNamespaceUUID := namespace.ID(uuid.New()) 458 startTime := time.Now() 459 460 // Create 2 executions 461 workflowExecution1 := commonpb.WorkflowExecution{ 462 WorkflowId: "visibility-filtering-test1", 463 RunId: "fb15e4b5-356f-466d-8c6d-a29223e5c536", 464 } 465 err0 := s.VisibilityMgr.RecordWorkflowExecutionStarted(s.ctx, &manager.RecordWorkflowExecutionStartedRequest{ 466 VisibilityRequestBase: &manager.VisibilityRequestBase{ 467 NamespaceID: testNamespaceUUID, 468 Execution: &workflowExecution1, 469 WorkflowTypeName: "visibility-workflow", 470 StartTime: startTime, 471 Status: enumspb.WORKFLOW_EXECUTION_STATUS_RUNNING, 472 }, 473 }) 474 s.Nil(err0) 475 476 workflowExecution2 := commonpb.WorkflowExecution{ 477 WorkflowId: "visibility-filtering-test2", 478 RunId: "843f6fc7-102a-4c63-a2d4-7c653b01bf52", 479 } 480 err1 := s.VisibilityMgr.RecordWorkflowExecutionStarted(s.ctx, &manager.RecordWorkflowExecutionStartedRequest{ 481 VisibilityRequestBase: &manager.VisibilityRequestBase{ 482 NamespaceID: testNamespaceUUID, 483 Execution: &workflowExecution2, 484 WorkflowTypeName: "visibility-workflow", 485 StartTime: startTime, 486 Status: enumspb.WORKFLOW_EXECUTION_STATUS_RUNNING, 487 }, 488 }) 489 s.Nil(err1) 490 491 // Close both executions with different status 492 err2 := s.VisibilityMgr.RecordWorkflowExecutionClosed(s.ctx, &manager.RecordWorkflowExecutionClosedRequest{ 493 VisibilityRequestBase: &manager.VisibilityRequestBase{ 494 NamespaceID: testNamespaceUUID, 495 Execution: &workflowExecution1, 496 WorkflowTypeName: "visibility-workflow", 497 StartTime: startTime, 498 Status: enumspb.WORKFLOW_EXECUTION_STATUS_COMPLETED, 499 }, 500 CloseTime: time.Now(), 501 }) 502 s.Nil(err2) 503 504 closeReq := &manager.RecordWorkflowExecutionClosedRequest{ 505 VisibilityRequestBase: &manager.VisibilityRequestBase{ 506 NamespaceID: testNamespaceUUID, 507 Execution: &workflowExecution2, 508 WorkflowTypeName: "visibility-workflow", 509 StartTime: startTime, 510 Status: enumspb.WORKFLOW_EXECUTION_STATUS_FAILED, 511 }, 512 CloseTime: time.Now(), 513 HistoryLength: 3, 514 } 515 err3 := s.VisibilityMgr.RecordWorkflowExecutionClosed(s.ctx, closeReq) 516 s.Nil(err3) 517 518 // List closed with filtering 519 resp, err4 := s.VisibilityMgr.ListClosedWorkflowExecutionsByStatus(s.ctx, &manager.ListClosedWorkflowExecutionsByStatusRequest{ 520 ListWorkflowExecutionsRequest: &manager.ListWorkflowExecutionsRequest{ 521 NamespaceID: testNamespaceUUID, 522 PageSize: 2, 523 EarliestStartTime: startTime, 524 LatestStartTime: time.Now(), 525 }, 526 Status: enumspb.WORKFLOW_EXECUTION_STATUS_FAILED, 527 }) 528 s.Nil(err4) 529 s.Equal(1, len(resp.Executions)) 530 s.assertClosedExecutionEquals(closeReq, resp.Executions[0]) 531 532 resp, err := s.VisibilityMgr.ListWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequestV2{ 533 NamespaceID: testNamespaceUUID, 534 PageSize: 5, 535 Query: `ExecutionStatus = "Failed"`, 536 }) 537 s.Nil(err) 538 s.Equal(1, len(resp.Executions)) 539 s.assertClosedExecutionEquals(closeReq, resp.Executions[0]) 540 } 541 542 // TestDelete test 543 func (s *VisibilityPersistenceSuite) TestDeleteWorkflow() { 544 openRows := 10 545 closedRows := 5 546 testNamespaceUUID := namespace.ID(uuid.New()) 547 closeTime := time.Now().UTC() 548 startTime := closeTime.Add(-5 * time.Second) 549 var pendingExecutions []*commonpb.WorkflowExecution 550 for i := 0; i < openRows; i++ { 551 workflowExecution := commonpb.WorkflowExecution{ 552 WorkflowId: uuid.New(), 553 RunId: uuid.New(), 554 } 555 pendingExecutions = append(pendingExecutions, &workflowExecution) 556 err0 := s.VisibilityMgr.RecordWorkflowExecutionStarted(s.ctx, &manager.RecordWorkflowExecutionStartedRequest{ 557 VisibilityRequestBase: &manager.VisibilityRequestBase{ 558 NamespaceID: testNamespaceUUID, 559 Execution: &workflowExecution, 560 WorkflowTypeName: "visibility-workflow", 561 StartTime: startTime, 562 Status: enumspb.WORKFLOW_EXECUTION_STATUS_RUNNING, 563 }, 564 }) 565 s.Nil(err0) 566 } 567 568 for i := 0; i < closedRows; i++ { 569 closeReq := &manager.RecordWorkflowExecutionClosedRequest{ 570 VisibilityRequestBase: &manager.VisibilityRequestBase{ 571 NamespaceID: testNamespaceUUID, 572 Execution: pendingExecutions[i], 573 WorkflowTypeName: "visibility-workflow", 574 StartTime: startTime, 575 Status: enumspb.WORKFLOW_EXECUTION_STATUS_FAILED, 576 }, 577 CloseTime: closeTime, 578 HistoryLength: 3, 579 } 580 err1 := s.VisibilityMgr.RecordWorkflowExecutionClosed(s.ctx, closeReq) 581 s.Nil(err1) 582 } 583 584 resp, err3 := s.VisibilityMgr.ListClosedWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequest{ 585 NamespaceID: testNamespaceUUID, 586 EarliestStartTime: startTime, 587 LatestStartTime: closeTime, 588 PageSize: 10, 589 }) 590 s.Nil(err3) 591 s.Equal(closedRows, len(resp.Executions)) 592 593 // Delete closed workflow 594 for _, row := range resp.Executions { 595 err4 := s.VisibilityMgr.DeleteWorkflowExecution(s.ctx, &manager.VisibilityDeleteWorkflowExecutionRequest{ 596 NamespaceID: testNamespaceUUID, 597 WorkflowID: row.GetExecution().GetWorkflowId(), 598 RunID: row.GetExecution().GetRunId(), 599 CloseTime: closeTime, 600 }) 601 s.Nil(err4) 602 } 603 resp, err5 := s.VisibilityMgr.ListClosedWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequest{ 604 NamespaceID: testNamespaceUUID, 605 EarliestStartTime: startTime, 606 LatestStartTime: closeTime, 607 PageSize: 10, 608 }) 609 s.Nil(err5) 610 s.Equal(0, len(resp.Executions)) 611 612 resp, err6 := s.VisibilityMgr.ListOpenWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequest{ 613 NamespaceID: testNamespaceUUID, 614 EarliestStartTime: startTime, 615 LatestStartTime: closeTime, 616 PageSize: 10, 617 }) 618 s.Nil(err6) 619 s.Equal(openRows-closedRows, len(resp.Executions)) 620 // Delete open workflow 621 for _, row := range resp.Executions { 622 err7 := s.VisibilityMgr.DeleteWorkflowExecution(s.ctx, &manager.VisibilityDeleteWorkflowExecutionRequest{ 623 NamespaceID: testNamespaceUUID, 624 WorkflowID: row.GetExecution().GetWorkflowId(), 625 RunID: row.GetExecution().GetRunId(), 626 StartTime: startTime, 627 }) 628 s.Nil(err7) 629 } 630 resp, err8 := s.VisibilityMgr.ListOpenWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequest{ 631 NamespaceID: testNamespaceUUID, 632 EarliestStartTime: startTime, 633 LatestStartTime: closeTime, 634 PageSize: 10, 635 }) 636 s.Nil(err8) 637 s.Equal(0, len(resp.Executions)) 638 } 639 640 // TestUpsertWorkflowExecution test 641 func (s *VisibilityPersistenceSuite) TestUpsertWorkflowExecution() { 642 temporalChangeVersionPayload, _ := payload.Encode([]string{"dummy"}) 643 tests := []struct { 644 request *manager.UpsertWorkflowExecutionRequest 645 expected error 646 }{ 647 { 648 request: &manager.UpsertWorkflowExecutionRequest{ 649 VisibilityRequestBase: &manager.VisibilityRequestBase{ 650 NamespaceID: "", 651 Namespace: "", 652 Execution: &commonpb.WorkflowExecution{}, 653 WorkflowTypeName: "", 654 StartTime: time.Time{}, 655 ExecutionTime: time.Time{}, 656 TaskID: 0, 657 Memo: nil, 658 SearchAttributes: &commonpb.SearchAttributes{ 659 IndexedFields: map[string]*commonpb.Payload{ 660 searchattribute.TemporalChangeVersion: temporalChangeVersionPayload, 661 }, 662 }, 663 Status: enumspb.WORKFLOW_EXECUTION_STATUS_RUNNING, 664 }, 665 }, 666 expected: nil, 667 }, 668 { 669 request: &manager.UpsertWorkflowExecutionRequest{ 670 VisibilityRequestBase: &manager.VisibilityRequestBase{ 671 NamespaceID: "", 672 Namespace: "", 673 Execution: &commonpb.WorkflowExecution{}, 674 WorkflowTypeName: "", 675 StartTime: time.Time{}, 676 ExecutionTime: time.Time{}, 677 TaskID: 0, 678 Memo: nil, 679 SearchAttributes: nil, 680 Status: enumspb.WORKFLOW_EXECUTION_STATUS_RUNNING, 681 }, 682 }, 683 // To avoid blocking the task queue processors on non-ElasticSearch visibility stores 684 // we simply treat any attempts to perform Upserts as "no-ops" 685 // Attempts to Scan, Count or List will still fail for non-ES stores. 686 expected: nil, 687 }, 688 } 689 690 for _, test := range tests { 691 s.Equal(test.expected, s.VisibilityMgr.UpsertWorkflowExecution(s.ctx, test.request)) 692 } 693 } 694 695 // TestGetWorkflowExecution test 696 func (s *VisibilityPersistenceSuite) TestGetWorkflowExecution() { 697 testNamespaceUUID := namespace.ID(uuid.New()) 698 closeTime := time.Now().UTC() 699 startTime := closeTime.Add(-5 * time.Second) 700 701 var startRequests []*manager.RecordWorkflowExecutionStartedRequest 702 for i := 0; i < 5; i++ { 703 startRequests = append( 704 startRequests, 705 s.createOpenWorkflowRecord( 706 testNamespaceUUID, 707 "visibility-workflow-test", 708 "visibility-workflow", 709 startTime, 710 "test-queue", 711 ), 712 ) 713 } 714 for _, req := range startRequests { 715 resp, err := s.VisibilityMgr.GetWorkflowExecution( 716 s.ctx, 717 &manager.GetWorkflowExecutionRequest{ 718 NamespaceID: testNamespaceUUID, 719 RunID: req.Execution.RunId, 720 StartTime: startTime, 721 }, 722 ) 723 s.NoError(err) 724 s.assertOpenExecutionEquals(req, resp.Execution) 725 } 726 727 var closeRequests []*manager.RecordWorkflowExecutionClosedRequest 728 for _, startReq := range startRequests { 729 closeRequests = append(closeRequests, s.createClosedWorkflowRecord(startReq, closeTime)) 730 } 731 for _, req := range closeRequests { 732 resp, err := s.VisibilityMgr.GetWorkflowExecution( 733 s.ctx, 734 &manager.GetWorkflowExecutionRequest{ 735 NamespaceID: testNamespaceUUID, 736 RunID: req.Execution.RunId, 737 CloseTime: closeTime, 738 }, 739 ) 740 s.NoError(err) 741 s.assertClosedExecutionEquals(req, resp.Execution) 742 } 743 } 744 745 // TestAdvancedVisibilityPagination test 746 func (s *VisibilityPersistenceSuite) TestAdvancedVisibilityPagination() { 747 testNamespaceUUID := namespace.ID(uuid.New()) 748 749 // Generate 5 workflow records, keep 2 open and 3 closed. 750 var startReqs []*manager.RecordWorkflowExecutionStartedRequest 751 var closeReqs []*manager.RecordWorkflowExecutionClosedRequest 752 for i := 0; i < 5; i++ { 753 startReq := s.createOpenWorkflowRecord(testNamespaceUUID, fmt.Sprintf("advanced-visibility-%v", i), "visibility-workflow", time.Now(), "test-queue") 754 if i <= 1 { 755 startReqs = append([]*manager.RecordWorkflowExecutionStartedRequest{startReq}, startReqs...) 756 } else { 757 closeReq := s.createClosedWorkflowRecord(startReq, time.Now()) 758 closeReqs = append([]*manager.RecordWorkflowExecutionClosedRequest{closeReq}, closeReqs...) 759 } 760 } 761 762 for pageSize := 1; pageSize <= 5; pageSize++ { 763 executions := make(map[string]*workflowpb.WorkflowExecutionInfo) 764 for _, e := range s.listWithPagination(testNamespaceUUID, 5) { 765 executions[e.GetExecution().GetWorkflowId()] = e 766 } 767 768 // there is no order guarantee from the list method, so we have to find the right execution 769 for _, r := range startReqs { 770 id := r.Execution.GetWorkflowId() 771 e, ok := executions[id] 772 s.True(ok) 773 s.assertOpenExecutionEquals(r, e) 774 delete(executions, id) 775 } 776 for _, r := range closeReqs { 777 id := r.Execution.GetWorkflowId() 778 e, ok := executions[id] 779 s.True(ok) 780 s.assertClosedExecutionEquals(r, e) 781 delete(executions, id) 782 } 783 s.Empty(executions, "Unexpected executions returned from list method") 784 } 785 } 786 787 func (s *VisibilityPersistenceSuite) TestCountWorkflowExecutions() { 788 switch s.VisibilityMgr.GetStoreNames()[0] { 789 case mysql.PluginName, postgresql.PluginName, postgresql.PluginNamePGX, cassandra.CassandraPersistenceName: 790 s.T().Skip("Not supported by standard visibility") 791 } 792 793 testNamespaceUUID := namespace.ID(uuid.New()) 794 closeTime := time.Now().UTC() 795 startTime := closeTime.Add(-5 * time.Second) 796 797 for i := 0; i < 5; i++ { 798 s.createOpenWorkflowRecord( 799 testNamespaceUUID, 800 "visibility-workflow-test", 801 "visibility-workflow", 802 startTime, 803 "test-queue", 804 ) 805 } 806 807 resp, err := s.VisibilityMgr.CountWorkflowExecutions( 808 s.ctx, 809 &manager.CountWorkflowExecutionsRequest{ 810 NamespaceID: testNamespaceUUID, 811 Query: "", 812 }, 813 ) 814 s.NoError(err) 815 s.Equal(int64(5), resp.Count) 816 s.Nil(resp.Groups) 817 } 818 819 func (s *VisibilityPersistenceSuite) TestCountGroupByWorkflowExecutions() { 820 switch s.VisibilityMgr.GetStoreNames()[0] { 821 case mysql.PluginName, postgresql.PluginName, postgresql.PluginNamePGX, cassandra.CassandraPersistenceName: 822 s.T().Skip("Not supported by standard visibility") 823 } 824 825 testNamespaceUUID := namespace.ID(uuid.New()) 826 closeTime := time.Now().UTC() 827 startTime := closeTime.Add(-5 * time.Second) 828 829 var startRequests []*manager.RecordWorkflowExecutionStartedRequest 830 for i := 0; i < 5; i++ { 831 startRequests = append( 832 startRequests, 833 s.createOpenWorkflowRecord( 834 testNamespaceUUID, 835 "visibility-workflow-test", 836 "visibility-workflow", 837 startTime, 838 "test-queue", 839 ), 840 ) 841 } 842 843 runningStatusPayload, _ := searchattribute.EncodeValue( 844 enumspb.WORKFLOW_EXECUTION_STATUS_RUNNING.String(), 845 enumspb.INDEXED_VALUE_TYPE_KEYWORD, 846 ) 847 resp, err := s.VisibilityMgr.CountWorkflowExecutions( 848 s.ctx, 849 &manager.CountWorkflowExecutionsRequest{ 850 NamespaceID: testNamespaceUUID, 851 Query: "GROUP BY ExecutionStatus", 852 }, 853 ) 854 s.NoError(err) 855 s.Equal(int64(5), resp.Count) 856 s.Equal( 857 []*workflowservice.CountWorkflowExecutionsResponse_AggregationGroup{ 858 { 859 GroupValues: []*commonpb.Payload{runningStatusPayload}, 860 Count: int64(5), 861 }, 862 }, 863 resp.Groups, 864 ) 865 866 for i := 0; i < 2; i++ { 867 s.createClosedWorkflowRecord(startRequests[i], closeTime) 868 } 869 870 resp, err = s.VisibilityMgr.CountWorkflowExecutions( 871 s.ctx, 872 &manager.CountWorkflowExecutionsRequest{ 873 NamespaceID: testNamespaceUUID, 874 Query: "GROUP BY ExecutionStatus", 875 }, 876 ) 877 s.NoError(err) 878 s.Equal(int64(5), resp.Count) 879 } 880 881 func (s *VisibilityPersistenceSuite) listWithPagination(namespaceID namespace.ID, pageSize int) []*workflowpb.WorkflowExecutionInfo { 882 var executions []*workflowpb.WorkflowExecutionInfo 883 resp, err := s.VisibilityMgr.ListWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequestV2{ 884 NamespaceID: namespaceID, 885 PageSize: pageSize, 886 Query: "", 887 }) 888 s.Nil(err) 889 executions = append(executions, resp.Executions...) 890 891 for len(resp.NextPageToken) > 0 { 892 resp, err = s.VisibilityMgr.ListWorkflowExecutions(s.ctx, &manager.ListWorkflowExecutionsRequestV2{ 893 NamespaceID: namespaceID, 894 PageSize: pageSize, 895 Query: "", 896 NextPageToken: resp.NextPageToken, 897 }) 898 s.Nil(err) 899 executions = append(executions, resp.Executions...) 900 } 901 902 return executions 903 } 904 905 func (s *VisibilityPersistenceSuite) createClosedWorkflowRecord( 906 startReq *manager.RecordWorkflowExecutionStartedRequest, 907 closeTime time.Time, 908 ) *manager.RecordWorkflowExecutionClosedRequest { 909 closeReq := &manager.RecordWorkflowExecutionClosedRequest{ 910 VisibilityRequestBase: &manager.VisibilityRequestBase{ 911 NamespaceID: startReq.NamespaceID, 912 Execution: startReq.Execution, 913 WorkflowTypeName: startReq.WorkflowTypeName, 914 StartTime: startReq.StartTime, 915 Status: enumspb.WORKFLOW_EXECUTION_STATUS_COMPLETED, 916 }, 917 CloseTime: closeTime, 918 HistoryLength: 5, 919 } 920 err := s.VisibilityMgr.RecordWorkflowExecutionClosed(s.ctx, closeReq) 921 s.Nil(err) 922 return closeReq 923 } 924 925 func (s *VisibilityPersistenceSuite) createOpenWorkflowRecord( 926 namespaceID namespace.ID, 927 workflowID string, 928 workflowType string, 929 startTime time.Time, 930 taskQueue string, 931 ) *manager.RecordWorkflowExecutionStartedRequest { 932 workflowExecution := commonpb.WorkflowExecution{ 933 WorkflowId: workflowID, 934 RunId: uuid.New(), 935 } 936 startReq := &manager.RecordWorkflowExecutionStartedRequest{ 937 VisibilityRequestBase: &manager.VisibilityRequestBase{ 938 NamespaceID: namespaceID, 939 Execution: &workflowExecution, 940 WorkflowTypeName: workflowType, 941 StartTime: startTime, 942 Status: enumspb.WORKFLOW_EXECUTION_STATUS_RUNNING, 943 TaskQueue: taskQueue, 944 }, 945 } 946 err := s.VisibilityMgr.RecordWorkflowExecutionStarted(s.ctx, startReq) 947 s.Nil(err) 948 return startReq 949 } 950 951 func (s *VisibilityPersistenceSuite) assertClosedExecutionEquals( 952 req *manager.RecordWorkflowExecutionClosedRequest, resp *workflowpb.WorkflowExecutionInfo) { 953 s.Equal(req.Execution.RunId, resp.Execution.RunId) 954 s.Equal(req.Execution.WorkflowId, resp.Execution.WorkflowId) 955 s.Equal(req.WorkflowTypeName, resp.GetType().GetName()) 956 s.Equal(persistence.UnixMilliseconds(req.StartTime), persistence.UnixMilliseconds(timestamp.TimeValue(resp.GetStartTime()))) 957 s.Equal(persistence.UnixMilliseconds(req.CloseTime), persistence.UnixMilliseconds(timestamp.TimeValue(resp.GetCloseTime()))) 958 s.Equal(req.Status, resp.GetStatus()) 959 s.Equal(req.HistoryLength, resp.HistoryLength) 960 } 961 962 func (s *VisibilityPersistenceSuite) assertOpenExecutionEquals( 963 req *manager.RecordWorkflowExecutionStartedRequest, resp *workflowpb.WorkflowExecutionInfo) { 964 s.Equal(req.Execution.GetRunId(), resp.Execution.GetRunId()) 965 s.Equal(req.Execution.WorkflowId, resp.Execution.WorkflowId) 966 s.Equal(req.WorkflowTypeName, resp.GetType().GetName()) 967 s.Equal(persistence.UnixMilliseconds(req.StartTime), persistence.UnixMilliseconds(timestamp.TimeValue(resp.GetStartTime()))) 968 s.Nil(resp.CloseTime) 969 s.Equal(resp.Status, enumspb.WORKFLOW_EXECUTION_STATUS_RUNNING) 970 s.Zero(resp.HistoryLength) 971 }