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  }