go.temporal.io/server@v1.23.0/common/testing/event_generator.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 testing 26 27 import ( 28 "math/rand" 29 ) 30 31 const ( 32 emptyCandidateIndex = -1 33 defaultVersion = int64(100) 34 ) 35 36 var ( 37 defaultBatchFunc = func(batch []Vertex, history []Vertex) bool { 38 return len(batch) == 0 39 } 40 ) 41 42 type ( 43 // HistoryEventVertex represents one type of history event 44 HistoryEventVertex struct { 45 name string 46 isStrictOnNextVertex bool 47 maxNextGeneration int 48 dataFunc func(...interface{}) interface{} 49 data interface{} 50 } 51 52 // HistoryEventModel is a graph represents relationships among history event types 53 HistoryEventModel struct { 54 edges []Edge 55 } 56 57 // EventGenerator is a history event generator 58 // The event generator will generate next history event 59 // based on the history event transition graph defined in the model 60 EventGenerator struct { 61 connections map[string][]Edge 62 previousVertices []Vertex 63 leafVertices []Vertex 64 entryVertices []Vertex 65 exitVertices map[string]bool 66 randomEntryVertices []Vertex 67 dice *rand.Rand 68 seed int64 69 canDoBatch func([]Vertex, []Vertex) bool 70 version int64 71 } 72 73 // HistoryEventEdge is the directional edge of two history events 74 HistoryEventEdge struct { 75 startVertex Vertex 76 endVertex Vertex 77 condition func(...interface{}) bool 78 action func() 79 } 80 81 // RevokeFunc is the condition inside edge 82 // The function used to check if the edge is accessible at a certain state 83 RevokeFunc struct { 84 } 85 ) 86 87 // NewEventGenerator initials the event generator 88 func NewEventGenerator( 89 seed int64, 90 ) Generator { 91 92 return &EventGenerator{ 93 connections: make(map[string][]Edge), 94 previousVertices: make([]Vertex, 0), 95 leafVertices: make([]Vertex, 0), 96 entryVertices: make([]Vertex, 0), 97 exitVertices: make(map[string]bool), 98 randomEntryVertices: make([]Vertex, 0), 99 dice: rand.New(rand.NewSource(seed)), 100 seed: seed, 101 canDoBatch: defaultBatchFunc, 102 version: defaultVersion, 103 } 104 } 105 106 // AddInitialEntryVertex adds the initial history event vertices 107 // Generator will only start from one of the entry vertex 108 func (g *EventGenerator) AddInitialEntryVertex( 109 entry ...Vertex, 110 ) { 111 112 g.entryVertices = append( 113 g.entryVertices, 114 entry...) 115 } 116 117 // AddExitVertex adds the terminate history event vertex 118 func (g *EventGenerator) AddExitVertex( 119 exit ...Vertex, 120 ) { 121 122 for _, v := range exit { 123 g.exitVertices[v.GetName()] = true 124 } 125 } 126 127 // AddRandomEntryVertex adds the random history event vertex 128 func (g *EventGenerator) AddRandomEntryVertex( 129 exit ...Vertex, 130 ) { 131 132 g.randomEntryVertices = append(g.randomEntryVertices, exit...) 133 } 134 135 // AddModel adds a history event model 136 func (g *EventGenerator) AddModel( 137 model Model, 138 ) { 139 140 for _, e := range model.ListEdges() { 141 if _, ok := g.connections[e.GetStartVertex().GetName()]; !ok { 142 g.connections[e.GetStartVertex().GetName()] = make([]Edge, 0) 143 } 144 g.connections[e.GetStartVertex().GetName()] = append(g.connections[e.GetStartVertex().GetName()], e) 145 } 146 } 147 148 // ListGeneratedVertices returns all the generated history events 149 func (g EventGenerator) ListGeneratedVertices() []Vertex { 150 151 return g.previousVertices 152 } 153 154 // HasNextVertex checks if there is accessible history event vertex 155 func (g *EventGenerator) HasNextVertex() bool { 156 157 for _, prev := range g.previousVertices { 158 if _, ok := g.exitVertices[prev.GetName()]; ok { 159 return false 160 } 161 } 162 return len(g.leafVertices) > 0 || (len(g.previousVertices) == 0 && len(g.entryVertices) > 0) 163 } 164 165 // GetNextVertices generates a batch of history events happened in the same transaction 166 func (g *EventGenerator) GetNextVertices() []Vertex { 167 168 if !g.HasNextVertex() { 169 panic("Generator reached to a terminate state.") 170 } 171 172 batch := make([]Vertex, 0) 173 for g.HasNextVertex() && g.canDoBatch(batch, g.previousVertices) { 174 res := g.generateNextEventBatch() 175 g.updateContext(res) 176 batch = append(batch, res...) 177 } 178 return batch 179 } 180 181 // Reset reset the generator to the initial state 182 func (g *EventGenerator) Reset() { 183 184 g.leafVertices = make([]Vertex, 0) 185 g.previousVertices = make([]Vertex, 0) 186 g.version = defaultVersion 187 } 188 189 // DeepCopy copy a new instance of generator 190 func (g *EventGenerator) DeepCopy() Generator { 191 192 return &EventGenerator{ 193 connections: copyConnections(g.connections), 194 previousVertices: copyVertex(g.previousVertices), 195 leafVertices: copyVertex(g.leafVertices), 196 entryVertices: copyVertex(g.entryVertices), 197 exitVertices: copyExitVertices(g.exitVertices), 198 randomEntryVertices: copyVertex(g.randomEntryVertices), 199 dice: rand.New(rand.NewSource(g.seed)), 200 seed: g.seed, 201 canDoBatch: g.canDoBatch, 202 version: g.version, 203 } 204 } 205 206 // SetBatchGenerationRule sets a function to determine next generated batch of history events 207 func (g *EventGenerator) SetBatchGenerationRule( 208 canDoBatchFunc func([]Vertex, []Vertex) bool, 209 ) { 210 211 g.canDoBatch = canDoBatchFunc 212 } 213 214 // SetVersion sets the event version 215 func (g *EventGenerator) SetVersion(version int64) { 216 217 g.version = version 218 } 219 220 // GetVersion returns event version 221 func (g *EventGenerator) GetVersion() int64 { 222 223 return g.version 224 } 225 226 func (g *EventGenerator) generateNextEventBatch() []Vertex { 227 228 batch := make([]Vertex, 0) 229 switch { 230 case len(g.previousVertices) == 0: 231 // Generate for the first time, get the event candidates from entry vertex group 232 batch = append(batch, g.getEntryVertex()) 233 case len(g.randomEntryVertices) > 0 && g.dice.Intn(len(g.connections)) == 0: 234 // Get the event candidate from random vertex group 235 batch = append(batch, g.getRandomVertex()) 236 default: 237 // Get the event candidates based on context 238 idx := g.getVertexCandidate() 239 batch = append(batch, g.randomNextVertex(idx)...) 240 g.leafVertices = append(g.leafVertices[:idx], g.leafVertices[idx+1:]...) 241 } 242 return batch 243 } 244 245 func (g *EventGenerator) updateContext( 246 batch []Vertex, 247 ) { 248 249 g.leafVertices = append(g.leafVertices, batch...) 250 g.previousVertices = append(g.previousVertices, batch...) 251 } 252 253 func (g *EventGenerator) getEntryVertex() Vertex { 254 255 if len(g.entryVertices) == 0 { 256 panic("No possible start vertex to go to next step") 257 } 258 nextRange := len(g.entryVertices) 259 nextIdx := g.dice.Intn(nextRange) 260 vertex := g.entryVertices[nextIdx].DeepCopy() 261 vertex.GenerateData(nil) 262 return vertex 263 } 264 265 func (g *EventGenerator) getRandomVertex() Vertex { 266 267 if len(g.randomEntryVertices) == 0 { 268 panic("No possible vertex to go to next step") 269 } 270 nextRange := len(g.randomEntryVertices) 271 nextIdx := g.dice.Intn(nextRange) 272 vertex := g.randomEntryVertices[nextIdx].DeepCopy() 273 parentEvent := g.previousVertices[len(g.previousVertices)-1] 274 275 vertex.GenerateData(parentEvent.GetData(), parentEvent.GetData(), g.version) 276 return vertex 277 } 278 279 func (g *EventGenerator) getVertexCandidate() int { 280 281 if len(g.leafVertices) == 0 { 282 panic("No possible vertex to go to next step") 283 } 284 nextRange := len(g.leafVertices) 285 notAvailable := make(map[int]bool) 286 var nextVertexIdx int 287 for len(notAvailable) < nextRange { 288 nextVertexIdx = g.dice.Intn(nextRange) 289 // If the vertex is not accessible at this state, skip it 290 if _, ok := notAvailable[nextVertexIdx]; ok { 291 continue 292 } 293 isAccessible, nextVertexIdx := g.findAccessibleVertex(nextVertexIdx) 294 if isAccessible { 295 return nextVertexIdx 296 } 297 notAvailable[nextVertexIdx] = true 298 } 299 // If all history event cannot be accessible, which means the model is incorrect 300 panic("cannot find available history event to proceed. please check your model") 301 } 302 303 func (g *EventGenerator) findAccessibleVertex( 304 vertexIndex int, 305 ) (bool, int) { 306 307 candidate := g.leafVertices[vertexIndex] 308 if g.leafVertices[len(g.leafVertices)-1].IsStrictOnNextVertex() { 309 vertexIndex = len(g.leafVertices) - 1 310 candidate = g.leafVertices[vertexIndex] 311 } 312 neighbors := g.connections[candidate.GetName()] 313 for _, nextV := range neighbors { 314 if nextV.GetCondition() == nil || nextV.GetCondition()(g.previousVertices) { 315 return true, vertexIndex 316 } 317 } 318 return false, emptyCandidateIndex 319 } 320 321 func (g *EventGenerator) randomNextVertex( 322 nextVertexIdx int, 323 ) []Vertex { 324 325 nextVertex := g.leafVertices[nextVertexIdx] 326 327 count := g.dice.Intn(nextVertex.GetMaxNextVertex()) + 1 328 res := make([]Vertex, 0) 329 latestVertex := g.previousVertices[len(g.previousVertices)-1] 330 for i := 0; i < count; i++ { 331 endVertex := g.pickRandomVertex(nextVertex) 332 endVertex.GenerateData(nextVertex.GetData(), latestVertex.GetData(), g.version) 333 latestVertex = endVertex 334 res = append(res, endVertex) 335 if _, ok := g.exitVertices[endVertex.GetName()]; ok { 336 res = []Vertex{endVertex} 337 return res 338 } 339 } 340 return res 341 } 342 343 func (g *EventGenerator) pickRandomVertex( 344 nextVertex Vertex, 345 ) Vertex { 346 347 neighbors := g.connections[nextVertex.GetName()] 348 neighborsRange := len(neighbors) 349 nextIdx := g.dice.Intn(neighborsRange) 350 for neighbors[nextIdx].GetCondition() != nil && !neighbors[nextIdx].GetCondition()(g.previousVertices) { 351 nextIdx = g.dice.Intn(neighborsRange) 352 } 353 newConnection := neighbors[nextIdx] 354 endVertex := newConnection.GetEndVertex() 355 if newConnection.GetAction() != nil { 356 newConnection.GetAction()() 357 } 358 return endVertex.DeepCopy() 359 } 360 361 // NewHistoryEventEdge initials a new edge between two HistoryEventVertexes 362 func NewHistoryEventEdge( 363 start Vertex, 364 end Vertex, 365 ) Edge { 366 367 return &HistoryEventEdge{ 368 startVertex: start, 369 endVertex: end, 370 } 371 } 372 373 // SetStartVertex sets the start vertex 374 func (c *HistoryEventEdge) SetStartVertex( 375 start Vertex, 376 ) { 377 378 c.startVertex = start 379 } 380 381 // GetStartVertex returns the start vertex 382 func (c HistoryEventEdge) GetStartVertex() Vertex { 383 384 return c.startVertex 385 } 386 387 // SetEndVertex sets the end vertex 388 func (c *HistoryEventEdge) SetEndVertex(end Vertex) { 389 390 c.endVertex = end 391 } 392 393 // GetEndVertex returns the end vertex 394 func (c HistoryEventEdge) GetEndVertex() Vertex { 395 396 return c.endVertex 397 } 398 399 // SetCondition sets the condition to access this edge 400 func (c *HistoryEventEdge) SetCondition( 401 condition func(...interface{}) bool, 402 ) { 403 404 c.condition = condition 405 } 406 407 // GetCondition returns the condition 408 func (c HistoryEventEdge) GetCondition() func(...interface{}) bool { 409 410 return c.condition 411 } 412 413 // SetAction sets an action to perform when the end vertex hits 414 func (c *HistoryEventEdge) SetAction(action func()) { 415 416 c.action = action 417 } 418 419 // GetAction returns the action 420 func (c HistoryEventEdge) GetAction() func() { 421 422 return c.action 423 } 424 425 // DeepCopy copies a new edge 426 func (c *HistoryEventEdge) DeepCopy() Edge { 427 428 return &HistoryEventEdge{ 429 startVertex: c.startVertex.DeepCopy(), 430 endVertex: c.endVertex.DeepCopy(), 431 condition: c.condition, 432 action: c.action, 433 } 434 } 435 436 // NewHistoryEventVertex initials a history event vertex 437 func NewHistoryEventVertex( 438 name string, 439 ) Vertex { 440 441 return &HistoryEventVertex{ 442 name: name, 443 isStrictOnNextVertex: false, 444 maxNextGeneration: 1, 445 } 446 } 447 448 // GetName returns the name 449 func (he HistoryEventVertex) GetName() string { 450 451 return he.name 452 } 453 454 // SetName sets the name 455 func (he *HistoryEventVertex) SetName( 456 name string, 457 ) { 458 459 he.name = name 460 } 461 462 // Equals compares two vertex 463 // func (he *HistoryEventVertex) Equals( 464 // v Vertex, 465 // ) bool { 466 // 467 // return strings.EqualFold(he.name, v.GetName()) && he.data == v.GetData() 468 // } 469 470 // SetIsStrictOnNextVertex sets if a vertex can be added between the current vertex and its child Vertices 471 func (he *HistoryEventVertex) SetIsStrictOnNextVertex( 472 isStrict bool, 473 ) { 474 475 he.isStrictOnNextVertex = isStrict 476 } 477 478 // IsStrictOnNextVertex returns the isStrict flag 479 func (he HistoryEventVertex) IsStrictOnNextVertex() bool { 480 481 return he.isStrictOnNextVertex 482 } 483 484 // SetMaxNextVertex sets the max concurrent path can be generated from this vertex 485 func (he *HistoryEventVertex) SetMaxNextVertex( 486 maxNextGeneration int, 487 ) { 488 489 if maxNextGeneration < 1 { 490 panic("max next vertex number cannot less than 1") 491 } 492 he.maxNextGeneration = maxNextGeneration 493 } 494 495 // GetMaxNextVertex returns the max concurrent path 496 func (he HistoryEventVertex) GetMaxNextVertex() int { 497 498 return he.maxNextGeneration 499 } 500 501 // SetDataFunc sets the data generation function 502 func (he *HistoryEventVertex) SetDataFunc( 503 dataFunc func(...interface{}) interface{}, 504 ) { 505 506 he.dataFunc = dataFunc 507 } 508 509 // GetDataFunc returns the data generation function 510 func (he HistoryEventVertex) GetDataFunc() func(...interface{}) interface{} { 511 512 return he.dataFunc 513 } 514 515 // GenerateData generates the data and return 516 func (he *HistoryEventVertex) GenerateData( 517 input ...interface{}, 518 ) interface{} { 519 520 if he.dataFunc == nil { 521 return nil 522 } 523 524 he.data = he.dataFunc(input...) 525 return he.data 526 } 527 528 // GetData returns the vertex data 529 func (he HistoryEventVertex) GetData() interface{} { 530 531 return he.data 532 } 533 534 // DeepCopy returns the a deep copy of vertex 535 func (he HistoryEventVertex) DeepCopy() Vertex { 536 537 return &HistoryEventVertex{ 538 name: he.GetName(), 539 isStrictOnNextVertex: he.IsStrictOnNextVertex(), 540 maxNextGeneration: he.GetMaxNextVertex(), 541 dataFunc: he.GetDataFunc(), 542 data: he.GetData(), 543 } 544 } 545 546 // NewHistoryEventModel initials new history event model 547 func NewHistoryEventModel() Model { 548 549 return &HistoryEventModel{ 550 edges: make([]Edge, 0), 551 } 552 } 553 554 // AddEdge adds an edge to the model 555 func (m *HistoryEventModel) AddEdge( 556 edge ...Edge, 557 ) { 558 559 m.edges = append(m.edges, edge...) 560 } 561 562 // ListEdges returns all added edges 563 func (m HistoryEventModel) ListEdges() []Edge { 564 565 return m.edges 566 }