github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/nomad/state/events_test.go (about)

     1  package state
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	memdb "github.com/hashicorp/go-memdb"
     8  	"github.com/hashicorp/nomad/ci"
     9  	"github.com/hashicorp/nomad/helper/pointer"
    10  	"github.com/hashicorp/nomad/helper/uuid"
    11  	"github.com/hashicorp/nomad/nomad/mock"
    12  	"github.com/hashicorp/nomad/nomad/structs"
    13  	"github.com/shoenig/test/must"
    14  	"github.com/stretchr/testify/require"
    15  )
    16  
    17  // TestEventFromChange_SingleEventPerTable ensures that only a single event is
    18  // created per table per memdb.Change
    19  func TestEventFromChange_SingleEventPerTable(t *testing.T) {
    20  	ci.Parallel(t)
    21  	s := TestStateStoreCfg(t, TestStateStorePublisher(t))
    22  	defer s.StopEventBroker()
    23  
    24  	changes := Changes{
    25  		Index:   100,
    26  		MsgType: structs.JobRegisterRequestType,
    27  		Changes: memdb.Changes{
    28  			{
    29  				Table:  "job_version",
    30  				Before: mock.Job(),
    31  				After:  mock.Job(),
    32  			},
    33  			{
    34  				Table:  "jobs",
    35  				Before: mock.Job(),
    36  				After:  mock.Job(),
    37  			},
    38  		},
    39  	}
    40  
    41  	out := eventsFromChanges(s.db.ReadTxn(), changes)
    42  	require.Len(t, out.Events, 1)
    43  	require.Equal(t, out.Events[0].Type, structs.TypeJobRegistered)
    44  }
    45  
    46  func TestEventFromChange_ACLTokenSecretID(t *testing.T) {
    47  	ci.Parallel(t)
    48  	s := TestStateStoreCfg(t, TestStateStorePublisher(t))
    49  	defer s.StopEventBroker()
    50  
    51  	token := mock.ACLToken()
    52  	require.NotEmpty(t, token.SecretID)
    53  
    54  	// Create
    55  	changes := Changes{
    56  		Index:   100,
    57  		MsgType: structs.NodeRegisterRequestType,
    58  		Changes: memdb.Changes{
    59  			{
    60  				Table:  "acl_token",
    61  				Before: nil,
    62  				After:  token,
    63  			},
    64  		},
    65  	}
    66  
    67  	out := eventsFromChanges(s.db.ReadTxn(), changes)
    68  	require.Len(t, out.Events, 1)
    69  	// Ensure original value not altered
    70  	require.NotEmpty(t, token.SecretID)
    71  
    72  	aclTokenEvent, ok := out.Events[0].Payload.(*structs.ACLTokenEvent)
    73  	require.True(t, ok)
    74  	require.Empty(t, aclTokenEvent.ACLToken.SecretID)
    75  
    76  	require.Equal(t, token.SecretID, aclTokenEvent.SecretID())
    77  
    78  	// Delete
    79  	changes = Changes{
    80  		Index:   100,
    81  		MsgType: structs.NodeDeregisterRequestType,
    82  		Changes: memdb.Changes{
    83  			{
    84  				Table:  "acl_token",
    85  				Before: token,
    86  				After:  nil,
    87  			},
    88  		},
    89  	}
    90  
    91  	out2 := eventsFromChanges(s.db.ReadTxn(), changes)
    92  	require.Len(t, out2.Events, 1)
    93  
    94  	tokenEvent2, ok := out2.Events[0].Payload.(*structs.ACLTokenEvent)
    95  	require.True(t, ok)
    96  	require.Empty(t, tokenEvent2.ACLToken.SecretID)
    97  }
    98  
    99  func TestEventsFromChanges_DeploymentUpdate(t *testing.T) {
   100  	ci.Parallel(t)
   101  	s := TestStateStoreCfg(t, TestStateStorePublisher(t))
   102  	defer s.StopEventBroker()
   103  
   104  	// setup
   105  	setupTx := s.db.WriteTxn(10)
   106  
   107  	j := mock.Job()
   108  	e := mock.Eval()
   109  	e.JobID = j.ID
   110  
   111  	d := mock.Deployment()
   112  	d.JobID = j.ID
   113  
   114  	require.NoError(t, s.upsertJobImpl(10, j, false, setupTx))
   115  	require.NoError(t, s.upsertDeploymentImpl(10, d, setupTx))
   116  
   117  	setupTx.Txn.Commit()
   118  
   119  	msgType := structs.DeploymentStatusUpdateRequestType
   120  
   121  	req := &structs.DeploymentStatusUpdateRequest{
   122  		DeploymentUpdate: &structs.DeploymentStatusUpdate{
   123  			DeploymentID:      d.ID,
   124  			Status:            structs.DeploymentStatusPaused,
   125  			StatusDescription: structs.DeploymentStatusDescriptionPaused,
   126  		},
   127  		Eval: e,
   128  		// Exlude Job and assert its added
   129  	}
   130  
   131  	require.NoError(t, s.UpdateDeploymentStatus(msgType, 100, req))
   132  
   133  	events := WaitForEvents(t, s, 100, 1, 1*time.Second)
   134  	require.Len(t, events, 2)
   135  
   136  	got := events[0]
   137  	require.Equal(t, uint64(100), got.Index)
   138  	require.Equal(t, d.ID, got.Key)
   139  
   140  	de := got.Payload.(*structs.DeploymentEvent)
   141  	require.Equal(t, structs.DeploymentStatusPaused, de.Deployment.Status)
   142  	require.Contains(t, got.FilterKeys, j.ID)
   143  }
   144  
   145  func TestEventsFromChanges_DeploymentPromotion(t *testing.T) {
   146  	ci.Parallel(t)
   147  	s := TestStateStoreCfg(t, TestStateStorePublisher(t))
   148  	defer s.StopEventBroker()
   149  
   150  	// setup
   151  	setupTx := s.db.WriteTxn(10)
   152  
   153  	j := mock.Job()
   154  	tg1 := j.TaskGroups[0]
   155  	tg2 := tg1.Copy()
   156  	tg2.Name = "foo"
   157  	j.TaskGroups = append(j.TaskGroups, tg2)
   158  	require.NoError(t, s.upsertJobImpl(10, j, false, setupTx))
   159  
   160  	d := mock.Deployment()
   161  	d.StatusDescription = structs.DeploymentStatusDescriptionRunningNeedsPromotion
   162  	d.JobID = j.ID
   163  	d.TaskGroups = map[string]*structs.DeploymentState{
   164  		"web": {
   165  			DesiredTotal:    10,
   166  			DesiredCanaries: 1,
   167  		},
   168  		"foo": {
   169  			DesiredTotal:    10,
   170  			DesiredCanaries: 1,
   171  		},
   172  	}
   173  	require.NoError(t, s.upsertDeploymentImpl(10, d, setupTx))
   174  
   175  	// create set of allocs
   176  	c1 := mock.Alloc()
   177  	c1.JobID = j.ID
   178  	c1.DeploymentID = d.ID
   179  	d.TaskGroups[c1.TaskGroup].PlacedCanaries = append(d.TaskGroups[c1.TaskGroup].PlacedCanaries, c1.ID)
   180  	c1.DeploymentStatus = &structs.AllocDeploymentStatus{
   181  		Healthy: pointer.Of(true),
   182  	}
   183  	c2 := mock.Alloc()
   184  	c2.JobID = j.ID
   185  	c2.DeploymentID = d.ID
   186  	d.TaskGroups[c2.TaskGroup].PlacedCanaries = append(d.TaskGroups[c2.TaskGroup].PlacedCanaries, c2.ID)
   187  	c2.TaskGroup = tg2.Name
   188  	c2.DeploymentStatus = &structs.AllocDeploymentStatus{
   189  		Healthy: pointer.Of(true),
   190  	}
   191  
   192  	require.NoError(t, s.upsertAllocsImpl(10, []*structs.Allocation{c1, c2}, setupTx))
   193  
   194  	// commit setup transaction
   195  	setupTx.Txn.Commit()
   196  
   197  	e := mock.Eval()
   198  	// Request to promote canaries
   199  	msgType := structs.DeploymentPromoteRequestType
   200  	req := &structs.ApplyDeploymentPromoteRequest{
   201  		DeploymentPromoteRequest: structs.DeploymentPromoteRequest{
   202  			DeploymentID: d.ID,
   203  			All:          true,
   204  		},
   205  		Eval: e,
   206  	}
   207  
   208  	require.NoError(t, s.UpdateDeploymentPromotion(msgType, 100, req))
   209  
   210  	events := WaitForEvents(t, s, 100, 1, 1*time.Second)
   211  	require.Len(t, events, 4)
   212  
   213  	got := events[0]
   214  	require.Equal(t, uint64(100), got.Index)
   215  	require.Equal(t, d.ID, got.Key)
   216  
   217  	de := got.Payload.(*structs.DeploymentEvent)
   218  	require.Equal(t, structs.DeploymentStatusRunning, de.Deployment.Status)
   219  	require.Equal(t, structs.TypeDeploymentPromotion, got.Type)
   220  }
   221  
   222  func TestEventsFromChanges_DeploymentAllocHealthRequestType(t *testing.T) {
   223  	ci.Parallel(t)
   224  	s := TestStateStoreCfg(t, TestStateStorePublisher(t))
   225  	defer s.StopEventBroker()
   226  
   227  	// setup
   228  	setupTx := s.db.WriteTxn(10)
   229  
   230  	j := mock.Job()
   231  	tg1 := j.TaskGroups[0]
   232  	tg2 := tg1.Copy()
   233  	tg2.Name = "foo"
   234  	j.TaskGroups = append(j.TaskGroups, tg2)
   235  	require.NoError(t, s.upsertJobImpl(10, j, false, setupTx))
   236  
   237  	d := mock.Deployment()
   238  	d.StatusDescription = structs.DeploymentStatusDescriptionRunningNeedsPromotion
   239  	d.JobID = j.ID
   240  	d.TaskGroups = map[string]*structs.DeploymentState{
   241  		"web": {
   242  			DesiredTotal:    10,
   243  			DesiredCanaries: 1,
   244  		},
   245  		"foo": {
   246  			DesiredTotal:    10,
   247  			DesiredCanaries: 1,
   248  		},
   249  	}
   250  	require.NoError(t, s.upsertDeploymentImpl(10, d, setupTx))
   251  
   252  	// create set of allocs
   253  	c1 := mock.Alloc()
   254  	c1.JobID = j.ID
   255  	c1.DeploymentID = d.ID
   256  	d.TaskGroups[c1.TaskGroup].PlacedCanaries = append(d.TaskGroups[c1.TaskGroup].PlacedCanaries, c1.ID)
   257  	c1.DeploymentStatus = &structs.AllocDeploymentStatus{
   258  		Healthy: pointer.Of(true),
   259  	}
   260  	c2 := mock.Alloc()
   261  	c2.JobID = j.ID
   262  	c2.DeploymentID = d.ID
   263  	d.TaskGroups[c2.TaskGroup].PlacedCanaries = append(d.TaskGroups[c2.TaskGroup].PlacedCanaries, c2.ID)
   264  	c2.TaskGroup = tg2.Name
   265  	c2.DeploymentStatus = &structs.AllocDeploymentStatus{
   266  		Healthy: pointer.Of(true),
   267  	}
   268  
   269  	require.NoError(t, s.upsertAllocsImpl(10, []*structs.Allocation{c1, c2}, setupTx))
   270  
   271  	// Commit setup
   272  	setupTx.Commit()
   273  
   274  	msgType := structs.DeploymentAllocHealthRequestType
   275  
   276  	req := &structs.ApplyDeploymentAllocHealthRequest{
   277  		DeploymentAllocHealthRequest: structs.DeploymentAllocHealthRequest{
   278  			DeploymentID:           d.ID,
   279  			HealthyAllocationIDs:   []string{c1.ID},
   280  			UnhealthyAllocationIDs: []string{c2.ID},
   281  		},
   282  		DeploymentUpdate: &structs.DeploymentStatusUpdate{
   283  			DeploymentID: d.ID,
   284  		},
   285  	}
   286  
   287  	require.NoError(t, s.UpdateDeploymentAllocHealth(msgType, 100, req))
   288  
   289  	events := WaitForEvents(t, s, 100, 1, 1*time.Second)
   290  	require.Len(t, events, 3)
   291  
   292  	var allocEvents []structs.Event
   293  	var deploymentEvent []structs.Event
   294  	for _, e := range events {
   295  		if e.Topic == structs.TopicAllocation {
   296  			allocEvents = append(allocEvents, e)
   297  		} else if e.Topic == structs.TopicDeployment {
   298  			deploymentEvent = append(deploymentEvent, e)
   299  		}
   300  	}
   301  
   302  	require.Len(t, allocEvents, 2)
   303  	for _, e := range allocEvents {
   304  		require.Equal(t, 100, int(e.Index))
   305  		require.Equal(t, structs.TypeDeploymentAllocHealth, e.Type)
   306  		require.Equal(t, structs.TopicAllocation, e.Topic)
   307  	}
   308  
   309  	require.Len(t, deploymentEvent, 1)
   310  	for _, e := range deploymentEvent {
   311  		require.Equal(t, 100, int(e.Index))
   312  		require.Equal(t, structs.TypeDeploymentAllocHealth, e.Type)
   313  		require.Equal(t, structs.TopicDeployment, e.Topic)
   314  		require.Equal(t, d.ID, e.Key)
   315  	}
   316  }
   317  
   318  func TestEventsFromChanges_UpsertNodeEventsType(t *testing.T) {
   319  	ci.Parallel(t)
   320  	s := TestStateStoreCfg(t, TestStateStorePublisher(t))
   321  	defer s.StopEventBroker()
   322  
   323  	// setup
   324  	n1 := mock.Node()
   325  	n2 := mock.Node()
   326  
   327  	require.NoError(t, s.UpsertNode(structs.MsgTypeTestSetup, 10, n1))
   328  	require.NoError(t, s.UpsertNode(structs.MsgTypeTestSetup, 12, n2))
   329  
   330  	msgType := structs.UpsertNodeEventsType
   331  	req := &structs.EmitNodeEventsRequest{
   332  		NodeEvents: map[string][]*structs.NodeEvent{
   333  			n1.ID: {
   334  				{
   335  					Message: "update",
   336  				},
   337  			},
   338  			n2.ID: {
   339  				{
   340  					Message: "update",
   341  				},
   342  			},
   343  		},
   344  	}
   345  
   346  	require.NoError(t, s.UpsertNodeEvents(msgType, 100, req.NodeEvents))
   347  	events := WaitForEvents(t, s, 100, 1, 1*time.Second)
   348  	require.Len(t, events, 2)
   349  
   350  	for _, e := range events {
   351  		require.Equal(t, structs.TopicNode, e.Topic)
   352  		require.Equal(t, structs.TypeNodeEvent, e.Type)
   353  		event := e.Payload.(*structs.NodeStreamEvent)
   354  		require.Equal(t, "update", event.Node.Events[len(event.Node.Events)-1].Message)
   355  	}
   356  
   357  }
   358  
   359  func TestEventsFromChanges_NodeUpdateStatusRequest(t *testing.T) {
   360  	ci.Parallel(t)
   361  	s := TestStateStoreCfg(t, TestStateStorePublisher(t))
   362  	defer s.StopEventBroker()
   363  
   364  	// setup
   365  	n1 := mock.Node()
   366  
   367  	require.NoError(t, s.UpsertNode(structs.MsgTypeTestSetup, 10, n1))
   368  
   369  	updated := time.Now()
   370  	msgType := structs.NodeUpdateStatusRequestType
   371  	req := &structs.NodeUpdateStatusRequest{
   372  		NodeID:    n1.ID,
   373  		Status:    structs.NodeStatusDown,
   374  		UpdatedAt: updated.UnixNano(),
   375  		NodeEvent: &structs.NodeEvent{Message: "down"},
   376  	}
   377  
   378  	require.NoError(t, s.UpdateNodeStatus(msgType, 100, req.NodeID, req.Status, req.UpdatedAt, req.NodeEvent))
   379  	events := WaitForEvents(t, s, 100, 1, 1*time.Second)
   380  	require.Len(t, events, 1)
   381  
   382  	e := events[0]
   383  	require.Equal(t, structs.TopicNode, e.Topic)
   384  	require.Equal(t, structs.TypeNodeEvent, e.Type)
   385  	event := e.Payload.(*structs.NodeStreamEvent)
   386  	require.Equal(t, "down", event.Node.Events[len(event.Node.Events)-1].Message)
   387  	require.Equal(t, structs.NodeStatusDown, event.Node.Status)
   388  }
   389  
   390  func TestEventsFromChanges_EvalUpdateRequestType(t *testing.T) {
   391  	ci.Parallel(t)
   392  	s := TestStateStoreCfg(t, TestStateStorePublisher(t))
   393  	defer s.StopEventBroker()
   394  
   395  	// setup
   396  	e1 := mock.Eval()
   397  
   398  	require.NoError(t, s.UpsertEvals(structs.MsgTypeTestSetup, 10, []*structs.Evaluation{e1}))
   399  
   400  	e2 := mock.Eval()
   401  	e2.ID = e1.ID
   402  	e2.JobID = e1.JobID
   403  	e2.Status = structs.EvalStatusBlocked
   404  
   405  	msgType := structs.EvalUpdateRequestType
   406  	req := &structs.EvalUpdateRequest{
   407  		Evals: []*structs.Evaluation{e2},
   408  	}
   409  
   410  	require.NoError(t, s.UpsertEvals(msgType, 100, req.Evals))
   411  
   412  	events := WaitForEvents(t, s, 100, 1, 1*time.Second)
   413  	require.Len(t, events, 1)
   414  
   415  	e := events[0]
   416  	require.Equal(t, structs.TopicEvaluation, e.Topic)
   417  	require.Equal(t, structs.TypeEvalUpdated, e.Type)
   418  	require.Contains(t, e.FilterKeys, e2.JobID)
   419  	require.Contains(t, e.FilterKeys, e2.DeploymentID)
   420  	event := e.Payload.(*structs.EvaluationEvent)
   421  	require.Equal(t, "blocked", event.Evaluation.Status)
   422  }
   423  
   424  func TestEventsFromChanges_ApplyPlanResultsRequestType(t *testing.T) {
   425  	ci.Parallel(t)
   426  	s := TestStateStoreCfg(t, TestStateStorePublisher(t))
   427  	defer s.StopEventBroker()
   428  
   429  	// setup
   430  	alloc := mock.Alloc()
   431  	alloc2 := mock.Alloc()
   432  	job := alloc.Job
   433  	alloc.Job = nil
   434  	alloc2.Job = nil
   435  
   436  	d := mock.Deployment()
   437  	alloc.DeploymentID = d.ID
   438  	alloc2.DeploymentID = d.ID
   439  
   440  	require.NoError(t, s.UpsertJob(structs.MsgTypeTestSetup, 9, job))
   441  
   442  	eval := mock.Eval()
   443  	eval.JobID = job.ID
   444  
   445  	// Create an eval
   446  	require.NoError(t, s.UpsertEvals(structs.MsgTypeTestSetup, 10, []*structs.Evaluation{eval}))
   447  
   448  	msgType := structs.ApplyPlanResultsRequestType
   449  	req := &structs.ApplyPlanResultsRequest{
   450  		AllocUpdateRequest: structs.AllocUpdateRequest{
   451  			Alloc: []*structs.Allocation{alloc, alloc2},
   452  			Job:   job,
   453  		},
   454  		Deployment: d,
   455  		EvalID:     eval.ID,
   456  	}
   457  
   458  	require.NoError(t, s.UpsertPlanResults(msgType, 100, req))
   459  
   460  	events := WaitForEvents(t, s, 100, 1, 1*time.Second)
   461  	require.Len(t, events, 5)
   462  
   463  	var allocs []structs.Event
   464  	var evals []structs.Event
   465  	var jobs []structs.Event
   466  	var deploys []structs.Event
   467  	for _, e := range events {
   468  		if e.Topic == structs.TopicAllocation {
   469  			allocs = append(allocs, e)
   470  		} else if e.Topic == structs.TopicEvaluation {
   471  			evals = append(evals, e)
   472  		} else if e.Topic == structs.TopicJob {
   473  			jobs = append(jobs, e)
   474  		} else if e.Topic == structs.TopicDeployment {
   475  			deploys = append(deploys, e)
   476  		}
   477  		require.Equal(t, structs.TypePlanResult, e.Type)
   478  	}
   479  	require.Len(t, allocs, 2)
   480  	require.Len(t, evals, 1)
   481  	require.Len(t, jobs, 1)
   482  	require.Len(t, deploys, 1)
   483  }
   484  
   485  func TestEventsFromChanges_BatchNodeUpdateDrainRequestType(t *testing.T) {
   486  	ci.Parallel(t)
   487  	s := TestStateStoreCfg(t, TestStateStorePublisher(t))
   488  	defer s.StopEventBroker()
   489  
   490  	// setup
   491  	n1 := mock.Node()
   492  	n2 := mock.Node()
   493  
   494  	require.NoError(t, s.UpsertNode(structs.MsgTypeTestSetup, 10, n1))
   495  	require.NoError(t, s.UpsertNode(structs.MsgTypeTestSetup, 11, n2))
   496  
   497  	updated := time.Now()
   498  	msgType := structs.BatchNodeUpdateDrainRequestType
   499  
   500  	expectedDrain := &structs.DrainStrategy{
   501  		DrainSpec: structs.DrainSpec{
   502  			Deadline: -1 * time.Second,
   503  		},
   504  	}
   505  	event := &structs.NodeEvent{
   506  		Message:   "Drain strategy enabled",
   507  		Subsystem: structs.NodeEventSubsystemDrain,
   508  		Timestamp: time.Now(),
   509  	}
   510  	req := structs.BatchNodeUpdateDrainRequest{
   511  		Updates: map[string]*structs.DrainUpdate{
   512  			n1.ID: {
   513  				DrainStrategy: expectedDrain,
   514  			},
   515  			n2.ID: {
   516  				DrainStrategy: expectedDrain,
   517  			},
   518  		},
   519  		NodeEvents: map[string]*structs.NodeEvent{
   520  			n1.ID: event,
   521  			n2.ID: event,
   522  		},
   523  		UpdatedAt: updated.UnixNano(),
   524  	}
   525  
   526  	require.NoError(t, s.BatchUpdateNodeDrain(msgType, 100, req.UpdatedAt, req.Updates, req.NodeEvents))
   527  
   528  	events := WaitForEvents(t, s, 100, 1, 1*time.Second)
   529  	require.Len(t, events, 2)
   530  
   531  	for _, e := range events {
   532  		require.Equal(t, 100, int(e.Index))
   533  		require.Equal(t, structs.TypeNodeDrain, e.Type)
   534  		require.Equal(t, structs.TopicNode, e.Topic)
   535  		ne := e.Payload.(*structs.NodeStreamEvent)
   536  		require.Equal(t, event.Message, ne.Node.Events[len(ne.Node.Events)-1].Message)
   537  	}
   538  }
   539  
   540  func TestEventsFromChanges_NodeUpdateEligibilityRequestType(t *testing.T) {
   541  	ci.Parallel(t)
   542  	s := TestStateStoreCfg(t, TestStateStorePublisher(t))
   543  	defer s.StopEventBroker()
   544  
   545  	// setup
   546  	n1 := mock.Node()
   547  
   548  	require.NoError(t, s.UpsertNode(structs.MsgTypeTestSetup, 10, n1))
   549  
   550  	msgType := structs.NodeUpdateEligibilityRequestType
   551  
   552  	event := &structs.NodeEvent{
   553  		Message:   "Node marked as ineligible",
   554  		Subsystem: structs.NodeEventSubsystemCluster,
   555  		Timestamp: time.Now(),
   556  	}
   557  
   558  	req := structs.NodeUpdateEligibilityRequest{
   559  		NodeID:      n1.ID,
   560  		NodeEvent:   event,
   561  		Eligibility: structs.NodeSchedulingIneligible,
   562  		UpdatedAt:   time.Now().UnixNano(),
   563  	}
   564  
   565  	require.NoError(t, s.UpdateNodeEligibility(msgType, 100, req.NodeID, req.Eligibility, req.UpdatedAt, req.NodeEvent))
   566  
   567  	events := WaitForEvents(t, s, 100, 1, 1*time.Second)
   568  	require.Len(t, events, 1)
   569  
   570  	for _, e := range events {
   571  		require.Equal(t, 100, int(e.Index))
   572  		require.Equal(t, structs.TypeNodeDrain, e.Type)
   573  		require.Equal(t, structs.TopicNode, e.Topic)
   574  		ne := e.Payload.(*structs.NodeStreamEvent)
   575  		require.Equal(t, event.Message, ne.Node.Events[len(ne.Node.Events)-1].Message)
   576  		require.Equal(t, structs.NodeSchedulingIneligible, ne.Node.SchedulingEligibility)
   577  	}
   578  }
   579  
   580  func TestEventsFromChanges_AllocUpdateDesiredTransitionRequestType(t *testing.T) {
   581  	ci.Parallel(t)
   582  	s := TestStateStoreCfg(t, TestStateStorePublisher(t))
   583  	defer s.StopEventBroker()
   584  
   585  	alloc := mock.Alloc()
   586  
   587  	require.Nil(t, s.UpsertJob(structs.MsgTypeTestSetup, 10, alloc.Job))
   588  	require.Nil(t, s.UpsertAllocs(structs.MsgTypeTestSetup, 11, []*structs.Allocation{alloc}))
   589  
   590  	msgType := structs.AllocUpdateDesiredTransitionRequestType
   591  
   592  	eval := &structs.Evaluation{
   593  		ID:             uuid.Generate(),
   594  		Namespace:      alloc.Namespace,
   595  		Priority:       alloc.Job.Priority,
   596  		Type:           alloc.Job.Type,
   597  		TriggeredBy:    structs.EvalTriggerNodeDrain,
   598  		JobID:          alloc.Job.ID,
   599  		JobModifyIndex: alloc.Job.ModifyIndex,
   600  		Status:         structs.EvalStatusPending,
   601  	}
   602  	evals := []*structs.Evaluation{eval}
   603  
   604  	req := &structs.AllocUpdateDesiredTransitionRequest{
   605  		Allocs: map[string]*structs.DesiredTransition{
   606  			alloc.ID: {Migrate: pointer.Of(true)},
   607  		},
   608  		Evals: evals,
   609  	}
   610  
   611  	require.NoError(t, s.UpdateAllocsDesiredTransitions(msgType, 100, req.Allocs, req.Evals))
   612  
   613  	events := WaitForEvents(t, s, 100, 1, 1*time.Second)
   614  	require.Len(t, events, 2)
   615  
   616  	var allocs []structs.Event
   617  	var evalEvents []structs.Event
   618  	for _, e := range events {
   619  		if e.Topic == structs.TopicEvaluation {
   620  			evalEvents = append(evalEvents, e)
   621  		} else if e.Topic == structs.TopicAllocation {
   622  			allocs = append(allocs, e)
   623  		} else {
   624  			require.Fail(t, "unexpected event type")
   625  		}
   626  
   627  		require.Equal(t, structs.TypeAllocationUpdateDesiredStatus, e.Type)
   628  	}
   629  
   630  	require.Len(t, allocs, 1)
   631  	require.Len(t, evalEvents, 1)
   632  }
   633  
   634  func TestEventsFromChanges_JobBatchDeregisterRequestType(t *testing.T) {
   635  	// TODO Job batch deregister logic mostly occurs in the FSM
   636  	t.SkipNow()
   637  
   638  }
   639  func TestEventsFromChanges_AllocClientUpdateRequestType(t *testing.T) {
   640  	t.SkipNow()
   641  }
   642  
   643  func TestEventsFromChanges_JobDeregisterRequestType(t *testing.T) {
   644  	t.SkipNow()
   645  }
   646  
   647  func TestEventsFromChanges_WithDeletion(t *testing.T) {
   648  	ci.Parallel(t)
   649  
   650  	changes := Changes{
   651  		Index: uint64(1),
   652  		Changes: memdb.Changes{
   653  			{
   654  				Table:  "jobs",
   655  				Before: &structs.Job{},
   656  				After:  &structs.Job{},
   657  			},
   658  			{
   659  				Table:  "jobs",
   660  				Before: &structs.Job{},
   661  				After:  nil, // deleted
   662  			},
   663  		},
   664  		MsgType: structs.JobDeregisterRequestType,
   665  	}
   666  
   667  	event := eventsFromChanges(nil, changes)
   668  	require.NotNil(t, event)
   669  
   670  	require.Len(t, event.Events, 1)
   671  }
   672  
   673  func TestEventsFromChanges_WithNodeDeregistration(t *testing.T) {
   674  	ci.Parallel(t)
   675  
   676  	before := &structs.Node{
   677  		ID:         "some-id",
   678  		Datacenter: "some-datacenter",
   679  	}
   680  
   681  	changes := Changes{
   682  		Index: uint64(1),
   683  		Changes: memdb.Changes{
   684  			{
   685  				Table:  "nodes",
   686  				Before: before,
   687  				After:  nil, // deleted
   688  			},
   689  		},
   690  		MsgType: structs.NodeDeregisterRequestType,
   691  	}
   692  
   693  	actual := eventsFromChanges(nil, changes)
   694  	require.NotNil(t, actual)
   695  
   696  	require.Len(t, actual.Events, 1)
   697  
   698  	event := actual.Events[0]
   699  
   700  	require.Equal(t, structs.TypeNodeDeregistration, event.Type)
   701  	require.Equal(t, uint64(1), event.Index)
   702  	require.Equal(t, structs.TopicNode, event.Topic)
   703  	require.Equal(t, "some-id", event.Key)
   704  
   705  	require.Len(t, event.FilterKeys, 0)
   706  
   707  	nodeEvent, ok := event.Payload.(*structs.NodeStreamEvent)
   708  	require.True(t, ok)
   709  	require.Equal(t, *before, *nodeEvent.Node)
   710  }
   711  
   712  func TestNodeEventsFromChanges(t *testing.T) {
   713  	ci.Parallel(t)
   714  
   715  	cases := []struct {
   716  		Name       string
   717  		MsgType    structs.MessageType
   718  		Setup      func(s *StateStore, tx *txn) error
   719  		Mutate     func(s *StateStore, tx *txn) error
   720  		WantEvents []structs.Event
   721  		WantTopic  structs.Topic
   722  	}{
   723  		{
   724  			MsgType:   structs.NodeRegisterRequestType,
   725  			WantTopic: structs.TopicNode,
   726  			Name:      "node registered",
   727  			Mutate: func(s *StateStore, tx *txn) error {
   728  				return upsertNodeTxn(tx, tx.Index, testNode())
   729  			},
   730  			WantEvents: []structs.Event{{
   731  				Topic: structs.TopicNode,
   732  				Type:  structs.TypeNodeRegistration,
   733  				Key:   testNodeID(),
   734  				Index: 100,
   735  				Payload: &structs.NodeStreamEvent{
   736  					Node: testNode(),
   737  				},
   738  			}},
   739  		},
   740  		{
   741  			MsgType:   structs.NodeRegisterRequestType,
   742  			WantTopic: structs.TopicNode,
   743  			Name:      "node registered initializing",
   744  			Mutate: func(s *StateStore, tx *txn) error {
   745  				return upsertNodeTxn(tx, tx.Index, testNode(nodeNotReady))
   746  			},
   747  			WantEvents: []structs.Event{{
   748  				Topic: structs.TopicNode,
   749  				Type:  structs.TypeNodeRegistration,
   750  				Key:   testNodeID(),
   751  				Index: 100,
   752  				Payload: &structs.NodeStreamEvent{
   753  					Node: testNode(nodeNotReady),
   754  				},
   755  			}},
   756  		},
   757  		{
   758  			MsgType:   structs.NodeDeregisterRequestType,
   759  			WantTopic: structs.TopicNode,
   760  			Name:      "node deregistered",
   761  			Setup: func(s *StateStore, tx *txn) error {
   762  				return upsertNodeTxn(tx, tx.Index, testNode())
   763  			},
   764  			Mutate: func(s *StateStore, tx *txn) error {
   765  				return deleteNodeTxn(tx, tx.Index, []string{testNodeID()})
   766  			},
   767  			WantEvents: []structs.Event{{
   768  				Topic: structs.TopicNode,
   769  				Type:  structs.TypeNodeDeregistration,
   770  				Key:   testNodeID(),
   771  				Index: 100,
   772  				Payload: &structs.NodeStreamEvent{
   773  					Node: testNode(),
   774  				},
   775  			}},
   776  		},
   777  		{
   778  			MsgType:   structs.NodeDeregisterRequestType,
   779  			WantTopic: structs.TopicNode,
   780  			Name:      "batch node deregistered",
   781  			Setup: func(s *StateStore, tx *txn) error {
   782  				require.NoError(t, upsertNodeTxn(tx, tx.Index, testNode()))
   783  				return upsertNodeTxn(tx, tx.Index, testNode(nodeIDTwo))
   784  			},
   785  			Mutate: func(s *StateStore, tx *txn) error {
   786  				return deleteNodeTxn(tx, tx.Index, []string{testNodeID(), testNodeIDTwo()})
   787  			},
   788  			WantEvents: []structs.Event{
   789  				{
   790  					Topic: structs.TopicNode,
   791  					Type:  structs.TypeNodeDeregistration,
   792  					Key:   testNodeID(),
   793  					Index: 100,
   794  					Payload: &structs.NodeStreamEvent{
   795  						Node: testNode(),
   796  					},
   797  				},
   798  				{
   799  					Topic: structs.TopicNode,
   800  					Type:  structs.TypeNodeDeregistration,
   801  					Key:   testNodeIDTwo(),
   802  					Index: 100,
   803  					Payload: &structs.NodeStreamEvent{
   804  						Node: testNode(nodeIDTwo),
   805  					},
   806  				},
   807  			},
   808  		},
   809  		{
   810  			MsgType:   structs.UpsertNodeEventsType,
   811  			WantTopic: structs.TopicNode,
   812  			Name:      "batch node events upserted",
   813  			Setup: func(s *StateStore, tx *txn) error {
   814  				require.NoError(t, upsertNodeTxn(tx, tx.Index, testNode()))
   815  				return upsertNodeTxn(tx, tx.Index, testNode(nodeIDTwo))
   816  			},
   817  			Mutate: func(s *StateStore, tx *txn) error {
   818  				eventFn := func(id string) []*structs.NodeEvent {
   819  					return []*structs.NodeEvent{
   820  						{
   821  							Message:   "test event one",
   822  							Subsystem: "Cluster",
   823  							Details: map[string]string{
   824  								"NodeID": id,
   825  							},
   826  						},
   827  						{
   828  							Message:   "test event two",
   829  							Subsystem: "Cluster",
   830  							Details: map[string]string{
   831  								"NodeID": id,
   832  							},
   833  						},
   834  					}
   835  				}
   836  				require.NoError(t, s.upsertNodeEvents(tx.Index, testNodeID(), eventFn(testNodeID()), tx))
   837  				return s.upsertNodeEvents(tx.Index, testNodeIDTwo(), eventFn(testNodeIDTwo()), tx)
   838  			},
   839  			WantEvents: []structs.Event{
   840  				{
   841  					Topic: structs.TopicNode,
   842  					Type:  structs.TypeNodeEvent,
   843  					Key:   testNodeID(),
   844  					Index: 100,
   845  					Payload: &structs.NodeStreamEvent{
   846  						Node: testNode(),
   847  					},
   848  				},
   849  				{
   850  					Topic: structs.TopicNode,
   851  					Type:  structs.TypeNodeEvent,
   852  					Key:   testNodeIDTwo(),
   853  					Index: 100,
   854  					Payload: &structs.NodeStreamEvent{
   855  						Node: testNode(nodeIDTwo),
   856  					},
   857  				},
   858  			},
   859  		},
   860  	}
   861  
   862  	for _, tc := range cases {
   863  		t.Run(tc.Name, func(t *testing.T) {
   864  			s := TestStateStoreCfg(t, TestStateStorePublisher(t))
   865  			defer s.StopEventBroker()
   866  
   867  			if tc.Setup != nil {
   868  				// Bypass publish mechanism for setup
   869  				setupTx := s.db.WriteTxn(10)
   870  				require.NoError(t, tc.Setup(s, setupTx))
   871  				setupTx.Txn.Commit()
   872  			}
   873  
   874  			tx := s.db.WriteTxnMsgT(tc.MsgType, 100)
   875  			require.NoError(t, tc.Mutate(s, tx))
   876  
   877  			changes := Changes{Changes: tx.Changes(), Index: 100, MsgType: tc.MsgType}
   878  			got := eventsFromChanges(tx, changes)
   879  
   880  			require.NotNil(t, got)
   881  
   882  			require.Equal(t, len(tc.WantEvents), len(got.Events))
   883  			for idx, g := range got.Events {
   884  				// assert equality of shared fields
   885  
   886  				want := tc.WantEvents[idx]
   887  				require.Equal(t, want.Index, g.Index)
   888  				require.Equal(t, want.Key, g.Key)
   889  				require.Equal(t, want.Topic, g.Topic)
   890  
   891  				switch tc.MsgType {
   892  				case structs.NodeRegisterRequestType:
   893  					requireNodeRegistrationEventEqual(t, tc.WantEvents[idx], g)
   894  				case structs.NodeDeregisterRequestType:
   895  					requireNodeDeregistrationEventEqual(t, tc.WantEvents[idx], g)
   896  				case structs.UpsertNodeEventsType:
   897  					requireNodeEventEqual(t, tc.WantEvents[idx], g)
   898  				default:
   899  					require.Fail(t, "unhandled message type")
   900  				}
   901  			}
   902  		})
   903  	}
   904  }
   905  
   906  func TestNodeDrainEventFromChanges(t *testing.T) {
   907  	ci.Parallel(t)
   908  	s := TestStateStoreCfg(t, TestStateStorePublisher(t))
   909  	defer s.StopEventBroker()
   910  
   911  	// setup
   912  	setupTx := s.db.WriteTxn(10)
   913  
   914  	node := mock.Node()
   915  	alloc1 := mock.Alloc()
   916  	alloc2 := mock.Alloc()
   917  	alloc1.NodeID = node.ID
   918  	alloc2.NodeID = node.ID
   919  
   920  	require.NoError(t, upsertNodeTxn(setupTx, 10, node))
   921  	require.NoError(t, s.upsertAllocsImpl(100, []*structs.Allocation{alloc1, alloc2}, setupTx))
   922  	setupTx.Txn.Commit()
   923  
   924  	// changes
   925  	tx := s.db.WriteTxn(100)
   926  
   927  	strat := &structs.DrainStrategy{
   928  		DrainSpec: structs.DrainSpec{
   929  			Deadline:         10 * time.Minute,
   930  			IgnoreSystemJobs: false,
   931  		},
   932  		StartedAt: time.Now(),
   933  	}
   934  	markEligible := false
   935  	updatedAt := time.Now()
   936  	event := &structs.NodeEvent{}
   937  
   938  	require.NoError(t, s.updateNodeDrainImpl(tx, 100, node.ID, strat, markEligible, updatedAt.UnixNano(), event, nil, "", false))
   939  	changes := Changes{Changes: tx.Changes(), Index: 100, MsgType: structs.NodeUpdateDrainRequestType}
   940  	got := eventsFromChanges(tx, changes)
   941  
   942  	require.Len(t, got.Events, 1)
   943  
   944  	require.Equal(t, structs.TopicNode, got.Events[0].Topic)
   945  	require.Equal(t, structs.TypeNodeDrain, got.Events[0].Type)
   946  	require.Equal(t, uint64(100), got.Events[0].Index)
   947  
   948  	nodeEvent, ok := got.Events[0].Payload.(*structs.NodeStreamEvent)
   949  	require.True(t, ok)
   950  
   951  	require.Equal(t, structs.NodeSchedulingIneligible, nodeEvent.Node.SchedulingEligibility)
   952  	require.Equal(t, strat, nodeEvent.Node.DrainStrategy)
   953  }
   954  
   955  func Test_eventsFromChanges_ServiceRegistration(t *testing.T) {
   956  	ci.Parallel(t)
   957  	testState := TestStateStoreCfg(t, TestStateStorePublisher(t))
   958  	defer testState.StopEventBroker()
   959  
   960  	// Generate test service registration.
   961  	service := mock.ServiceRegistrations()[0]
   962  
   963  	// Upsert a service registration.
   964  	writeTxn := testState.db.WriteTxn(10)
   965  	updated, err := testState.upsertServiceRegistrationTxn(10, writeTxn, service)
   966  	require.True(t, updated)
   967  	require.NoError(t, err)
   968  	writeTxn.Txn.Commit()
   969  
   970  	// Pull the events from the stream.
   971  	registerChange := Changes{Changes: writeTxn.Changes(), Index: 10, MsgType: structs.ServiceRegistrationUpsertRequestType}
   972  	receivedChange := eventsFromChanges(writeTxn, registerChange)
   973  
   974  	// Check the event, and it's payload are what we are expecting.
   975  	require.Len(t, receivedChange.Events, 1)
   976  	require.Equal(t, structs.TopicService, receivedChange.Events[0].Topic)
   977  	require.Equal(t, structs.TypeServiceRegistration, receivedChange.Events[0].Type)
   978  	require.Equal(t, uint64(10), receivedChange.Events[0].Index)
   979  
   980  	eventPayload := receivedChange.Events[0].Payload.(*structs.ServiceRegistrationStreamEvent)
   981  	require.Equal(t, service, eventPayload.Service)
   982  
   983  	// Delete the previously upserted service registration.
   984  	deleteTxn := testState.db.WriteTxn(20)
   985  	require.NoError(t, testState.deleteServiceRegistrationByIDTxn(uint64(20), deleteTxn, service.Namespace, service.ID))
   986  	writeTxn.Txn.Commit()
   987  
   988  	// Pull the events from the stream.
   989  	deregisterChange := Changes{Changes: deleteTxn.Changes(), Index: 20, MsgType: structs.ServiceRegistrationDeleteByIDRequestType}
   990  	receivedDeleteChange := eventsFromChanges(deleteTxn, deregisterChange)
   991  
   992  	// Check the event, and it's payload are what we are expecting.
   993  	require.Len(t, receivedDeleteChange.Events, 1)
   994  	require.Equal(t, structs.TopicService, receivedDeleteChange.Events[0].Topic)
   995  	require.Equal(t, structs.TypeServiceDeregistration, receivedDeleteChange.Events[0].Type)
   996  	require.Equal(t, uint64(20), receivedDeleteChange.Events[0].Index)
   997  
   998  	eventPayload = receivedChange.Events[0].Payload.(*structs.ServiceRegistrationStreamEvent)
   999  	require.Equal(t, service, eventPayload.Service)
  1000  }
  1001  
  1002  func Test_eventsFromChanges_ACLRole(t *testing.T) {
  1003  	ci.Parallel(t)
  1004  	testState := TestStateStoreCfg(t, TestStateStorePublisher(t))
  1005  	defer testState.StopEventBroker()
  1006  
  1007  	// Generate a test ACL role.
  1008  	aclRole := mock.ACLRole()
  1009  
  1010  	// Upsert the role into state, skipping the checks perform to ensure the
  1011  	// linked policies exist.
  1012  	writeTxn := testState.db.WriteTxn(10)
  1013  	updated, err := testState.upsertACLRoleTxn(10, writeTxn, aclRole, true)
  1014  	require.True(t, updated)
  1015  	require.NoError(t, err)
  1016  	writeTxn.Txn.Commit()
  1017  
  1018  	// Pull the events from the stream.
  1019  	upsertChange := Changes{Changes: writeTxn.Changes(), Index: 10, MsgType: structs.ACLRolesUpsertRequestType}
  1020  	receivedChange := eventsFromChanges(writeTxn, upsertChange)
  1021  
  1022  	// Check the event, and it's payload are what we are expecting.
  1023  	require.Len(t, receivedChange.Events, 1)
  1024  	require.Equal(t, structs.TopicACLRole, receivedChange.Events[0].Topic)
  1025  	require.Equal(t, aclRole.ID, receivedChange.Events[0].Key)
  1026  	require.Equal(t, aclRole.Name, receivedChange.Events[0].FilterKeys[0])
  1027  	require.Equal(t, structs.TypeACLRoleUpserted, receivedChange.Events[0].Type)
  1028  	require.Equal(t, uint64(10), receivedChange.Events[0].Index)
  1029  
  1030  	eventPayload := receivedChange.Events[0].Payload.(*structs.ACLRoleStreamEvent)
  1031  	require.Equal(t, aclRole, eventPayload.ACLRole)
  1032  
  1033  	// Delete the previously upserted ACL role.
  1034  	deleteTxn := testState.db.WriteTxn(20)
  1035  	require.NoError(t, testState.deleteACLRoleByIDTxn(deleteTxn, aclRole.ID))
  1036  	require.NoError(t, deleteTxn.Insert(tableIndex, &IndexEntry{TableACLRoles, 20}))
  1037  	deleteTxn.Txn.Commit()
  1038  
  1039  	// Pull the events from the stream.
  1040  	deleteChange := Changes{Changes: deleteTxn.Changes(), Index: 20, MsgType: structs.ACLRolesDeleteByIDRequestType}
  1041  	receivedDeleteChange := eventsFromChanges(deleteTxn, deleteChange)
  1042  
  1043  	// Check the event, and it's payload are what we are expecting.
  1044  	require.Len(t, receivedDeleteChange.Events, 1)
  1045  	require.Equal(t, structs.TopicACLRole, receivedDeleteChange.Events[0].Topic)
  1046  	require.Equal(t, aclRole.ID, receivedDeleteChange.Events[0].Key)
  1047  	require.Equal(t, aclRole.Name, receivedDeleteChange.Events[0].FilterKeys[0])
  1048  	require.Equal(t, structs.TypeACLRoleDeleted, receivedDeleteChange.Events[0].Type)
  1049  	require.Equal(t, uint64(20), receivedDeleteChange.Events[0].Index)
  1050  
  1051  	eventPayload = receivedChange.Events[0].Payload.(*structs.ACLRoleStreamEvent)
  1052  	require.Equal(t, aclRole, eventPayload.ACLRole)
  1053  }
  1054  
  1055  func Test_eventsFromChanges_ACLAuthMethod(t *testing.T) {
  1056  	ci.Parallel(t)
  1057  	testState := TestStateStoreCfg(t, TestStateStorePublisher(t))
  1058  	defer testState.StopEventBroker()
  1059  
  1060  	// Generate a test ACL auth method
  1061  	authMethod := mock.ACLAuthMethod()
  1062  
  1063  	// Upsert the auth method straight into state
  1064  	writeTxn := testState.db.WriteTxn(10)
  1065  	updated, err := testState.upsertACLAuthMethodTxn(10, writeTxn, authMethod)
  1066  	must.True(t, updated)
  1067  	must.NoError(t, err)
  1068  	writeTxn.Txn.Commit()
  1069  
  1070  	// Pull the events from the stream.
  1071  	upsertChange := Changes{Changes: writeTxn.Changes(), Index: 10, MsgType: structs.ACLAuthMethodsUpsertRequestType}
  1072  	receivedChange := eventsFromChanges(writeTxn, upsertChange)
  1073  	must.NotNil(t, receivedChange)
  1074  
  1075  	// Check the event, and its payload are what we are expecting.
  1076  	must.Len(t, 1, receivedChange.Events)
  1077  	must.Eq(t, structs.TopicACLAuthMethod, receivedChange.Events[0].Topic)
  1078  	must.Eq(t, authMethod.Name, receivedChange.Events[0].Key)
  1079  	must.Eq(t, structs.TypeACLAuthMethodUpserted, receivedChange.Events[0].Type)
  1080  	must.Eq(t, uint64(10), receivedChange.Events[0].Index)
  1081  
  1082  	eventPayload := receivedChange.Events[0].Payload.(*structs.ACLAuthMethodEvent)
  1083  	must.Eq(t, authMethod, eventPayload.AuthMethod)
  1084  
  1085  	// Delete the previously upserted auth method
  1086  	deleteTxn := testState.db.WriteTxn(20)
  1087  	must.NoError(t, testState.deleteACLAuthMethodTxn(deleteTxn, authMethod.Name))
  1088  	must.NoError(t, deleteTxn.Insert(tableIndex, &IndexEntry{TableACLAuthMethods, 20}))
  1089  	deleteTxn.Txn.Commit()
  1090  
  1091  	// Pull the events from the stream.
  1092  	deleteChange := Changes{Changes: deleteTxn.Changes(), Index: 20, MsgType: structs.ACLAuthMethodsDeleteRequestType}
  1093  	receivedDeleteChange := eventsFromChanges(deleteTxn, deleteChange)
  1094  	must.NotNil(t, receivedDeleteChange)
  1095  
  1096  	// Check the event, and its payload are what we are expecting.
  1097  	must.Len(t, 1, receivedDeleteChange.Events)
  1098  	must.Eq(t, structs.TopicACLAuthMethod, receivedDeleteChange.Events[0].Topic)
  1099  	must.Eq(t, authMethod.Name, receivedDeleteChange.Events[0].Key)
  1100  	must.Eq(t, structs.TypeACLAuthMethodDeleted, receivedDeleteChange.Events[0].Type)
  1101  	must.Eq(t, uint64(20), receivedDeleteChange.Events[0].Index)
  1102  
  1103  	eventPayload = receivedChange.Events[0].Payload.(*structs.ACLAuthMethodEvent)
  1104  	must.Eq(t, authMethod, eventPayload.AuthMethod)
  1105  }
  1106  
  1107  func Test_eventsFromChanges_ACLBindingRule(t *testing.T) {
  1108  	ci.Parallel(t)
  1109  	testState := TestStateStoreCfg(t, TestStateStorePublisher(t))
  1110  	defer testState.StopEventBroker()
  1111  
  1112  	// Generate a test ACL binding rule.
  1113  	bindingRule := mock.ACLBindingRule()
  1114  
  1115  	// Upsert the binding rule straight into state.
  1116  	writeTxn := testState.db.WriteTxn(10)
  1117  	updated, err := testState.upsertACLBindingRuleTxn(10, writeTxn, bindingRule, true)
  1118  	must.True(t, updated)
  1119  	must.NoError(t, err)
  1120  	writeTxn.Txn.Commit()
  1121  
  1122  	// Pull the events from the stream.
  1123  	upsertChange := Changes{Changes: writeTxn.Changes(), Index: 10, MsgType: structs.ACLBindingRulesUpsertRequestType}
  1124  	receivedChange := eventsFromChanges(writeTxn, upsertChange)
  1125  	must.NotNil(t, receivedChange)
  1126  
  1127  	// Check the event, and its payload are what we are expecting.
  1128  	must.Len(t, 1, receivedChange.Events)
  1129  	must.Eq(t, structs.TopicACLBindingRule, receivedChange.Events[0].Topic)
  1130  	must.Eq(t, bindingRule.ID, receivedChange.Events[0].Key)
  1131  	must.SliceContainsAll(t, []string{bindingRule.AuthMethod}, receivedChange.Events[0].FilterKeys)
  1132  	must.Eq(t, structs.TypeACLBindingRuleUpserted, receivedChange.Events[0].Type)
  1133  	must.Eq(t, 10, receivedChange.Events[0].Index)
  1134  
  1135  	must.Eq(t, bindingRule, receivedChange.Events[0].Payload.(*structs.ACLBindingRuleEvent).ACLBindingRule)
  1136  
  1137  	// Delete the previously upserted binding rule.
  1138  	deleteTxn := testState.db.WriteTxn(20)
  1139  	must.NoError(t, testState.deleteACLBindingRuleTxn(deleteTxn, bindingRule.ID))
  1140  	must.NoError(t, deleteTxn.Insert(tableIndex, &IndexEntry{TableACLBindingRules, 20}))
  1141  	deleteTxn.Txn.Commit()
  1142  
  1143  	// Pull the events from the stream.
  1144  	deleteChange := Changes{Changes: deleteTxn.Changes(), Index: 20, MsgType: structs.ACLBindingRulesDeleteRequestType}
  1145  	receivedDeleteChange := eventsFromChanges(deleteTxn, deleteChange)
  1146  	must.NotNil(t, receivedDeleteChange)
  1147  
  1148  	// Check the event, and its payload are what we are expecting.
  1149  	must.Len(t, 1, receivedDeleteChange.Events)
  1150  	must.Eq(t, structs.TopicACLBindingRule, receivedDeleteChange.Events[0].Topic)
  1151  	must.Eq(t, bindingRule.ID, receivedDeleteChange.Events[0].Key)
  1152  	must.SliceContainsAll(t, []string{bindingRule.AuthMethod}, receivedDeleteChange.Events[0].FilterKeys)
  1153  	must.Eq(t, structs.TypeACLBindingRuleDeleted, receivedDeleteChange.Events[0].Type)
  1154  	must.Eq(t, uint64(20), receivedDeleteChange.Events[0].Index)
  1155  
  1156  	must.Eq(t, bindingRule, receivedDeleteChange.Events[0].Payload.(*structs.ACLBindingRuleEvent).ACLBindingRule)
  1157  }
  1158  
  1159  func requireNodeRegistrationEventEqual(t *testing.T, want, got structs.Event) {
  1160  	t.Helper()
  1161  
  1162  	wantPayload := want.Payload.(*structs.NodeStreamEvent)
  1163  	gotPayload := got.Payload.(*structs.NodeStreamEvent)
  1164  
  1165  	// Check payload equality for the fields that we can easily control
  1166  	require.Equal(t, wantPayload.Node.Status, gotPayload.Node.Status)
  1167  	require.Equal(t, wantPayload.Node.ID, gotPayload.Node.ID)
  1168  	require.NotEqual(t, wantPayload.Node.Events, gotPayload.Node.Events)
  1169  }
  1170  
  1171  func requireNodeDeregistrationEventEqual(t *testing.T, want, got structs.Event) {
  1172  	t.Helper()
  1173  
  1174  	wantPayload := want.Payload.(*structs.NodeStreamEvent)
  1175  	gotPayload := got.Payload.(*structs.NodeStreamEvent)
  1176  
  1177  	require.Equal(t, wantPayload.Node.ID, gotPayload.Node.ID)
  1178  	require.NotEqual(t, wantPayload.Node.Events, gotPayload.Node.Events)
  1179  }
  1180  
  1181  func requireNodeEventEqual(t *testing.T, want, got structs.Event) {
  1182  	gotPayload := got.Payload.(*structs.NodeStreamEvent)
  1183  
  1184  	require.Len(t, gotPayload.Node.Events, 3)
  1185  }
  1186  
  1187  type nodeOpts func(n *structs.Node)
  1188  
  1189  func nodeNotReady(n *structs.Node) {
  1190  	n.Status = structs.NodeStatusInit
  1191  }
  1192  
  1193  func nodeIDTwo(n *structs.Node) {
  1194  	n.ID = testNodeIDTwo()
  1195  }
  1196  
  1197  func testNode(opts ...nodeOpts) *structs.Node {
  1198  	n := mock.Node()
  1199  	n.ID = testNodeID()
  1200  
  1201  	n.SecretID = "ab9812d3-6a21-40d3-973d-d9d2174a23ee"
  1202  
  1203  	for _, opt := range opts {
  1204  		opt(n)
  1205  	}
  1206  	return n
  1207  }
  1208  
  1209  func testNodeID() string {
  1210  	return "9d5741c1-3899-498a-98dd-eb3c05665863"
  1211  }
  1212  
  1213  func testNodeIDTwo() string {
  1214  	return "694ff31d-8c59-4030-ac83-e15692560c8d"
  1215  }