2020-10-01 18:43:28 +00:00
|
|
|
package state
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/hashicorp/nomad/nomad/mock"
|
|
|
|
"github.com/hashicorp/nomad/nomad/stream"
|
|
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestDeploymentEventFromChanges(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
s := TestStateStoreCfg(t, TestStateStorePublisher(t))
|
2020-10-08 18:27:52 +00:00
|
|
|
defer s.StopEventBroker()
|
2020-10-01 18:43:28 +00:00
|
|
|
|
|
|
|
// setup
|
|
|
|
setupTx := s.db.WriteTxn(10)
|
|
|
|
|
|
|
|
j := mock.Job()
|
|
|
|
e := mock.Eval()
|
|
|
|
e.JobID = j.ID
|
|
|
|
|
|
|
|
d := mock.Deployment()
|
|
|
|
d.JobID = j.ID
|
|
|
|
|
|
|
|
require.NoError(t, s.upsertJobImpl(10, j, false, setupTx))
|
|
|
|
require.NoError(t, s.upsertDeploymentImpl(10, d, setupTx))
|
|
|
|
|
|
|
|
setupTx.Txn.Commit()
|
|
|
|
|
2020-10-02 20:13:49 +00:00
|
|
|
msgType := structs.DeploymentStatusUpdateRequestType
|
2020-10-01 18:43:28 +00:00
|
|
|
|
|
|
|
req := &structs.DeploymentStatusUpdateRequest{
|
|
|
|
DeploymentUpdate: &structs.DeploymentStatusUpdate{
|
|
|
|
DeploymentID: d.ID,
|
|
|
|
Status: structs.DeploymentStatusPaused,
|
|
|
|
StatusDescription: structs.DeploymentStatusDescriptionPaused,
|
|
|
|
},
|
|
|
|
Eval: e,
|
|
|
|
// Exlude Job and assert its added
|
|
|
|
}
|
|
|
|
|
2020-10-02 20:13:49 +00:00
|
|
|
require.NoError(t, s.UpdateDeploymentStatus(msgType, 100, req))
|
2020-10-01 18:43:28 +00:00
|
|
|
|
|
|
|
events := WaitForEvents(t, s, 100, 1, 1*time.Second)
|
|
|
|
require.Len(t, events, 2)
|
|
|
|
|
|
|
|
got := events[0]
|
|
|
|
require.Equal(t, uint64(100), got.Index)
|
|
|
|
require.Equal(t, d.ID, got.Key)
|
|
|
|
|
|
|
|
de := got.Payload.(*DeploymentEvent)
|
|
|
|
require.Equal(t, structs.DeploymentStatusPaused, de.Deployment.Status)
|
|
|
|
require.Contains(t, got.FilterKeys, j.ID)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-10-04 19:12:35 +00:00
|
|
|
func WaitForEvents(t *testing.T, s *StateStore, index uint64, minEvents int, timeout time.Duration) []structs.Event {
|
2020-10-01 18:43:28 +00:00
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return
|
|
|
|
case <-time.After(timeout):
|
|
|
|
require.Fail(t, "timeout waiting for events")
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
maxAttempts := 10
|
|
|
|
for {
|
|
|
|
got := EventsForIndex(t, s, index)
|
|
|
|
if len(got) >= minEvents {
|
|
|
|
return got
|
|
|
|
}
|
|
|
|
maxAttempts--
|
|
|
|
if maxAttempts == 0 {
|
2020-10-19 13:30:15 +00:00
|
|
|
require.Failf(t, "reached max attempts waiting for desired event count", "count %d", len(got))
|
2020-10-01 18:43:28 +00:00
|
|
|
}
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-04 19:12:35 +00:00
|
|
|
func EventsForIndex(t *testing.T, s *StateStore, index uint64) []structs.Event {
|
2020-10-08 18:27:52 +00:00
|
|
|
pub, err := s.EventBroker()
|
2020-10-01 18:43:28 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
sub, err := pub.Subscribe(&stream.SubscribeRequest{
|
2020-10-04 19:12:35 +00:00
|
|
|
Topics: map[structs.Topic][]string{
|
2020-10-08 18:27:52 +00:00
|
|
|
"*": {"*"},
|
2020-10-01 18:43:28 +00:00
|
|
|
},
|
2020-10-08 18:27:52 +00:00
|
|
|
Index: index,
|
|
|
|
StartExactlyAtIndex: true,
|
2020-10-01 18:43:28 +00:00
|
|
|
})
|
2020-10-08 18:27:52 +00:00
|
|
|
if err != nil {
|
|
|
|
return []structs.Event{}
|
|
|
|
}
|
2020-10-01 18:43:28 +00:00
|
|
|
defer sub.Unsubscribe()
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-10-04 19:12:35 +00:00
|
|
|
var events []structs.Event
|
2020-10-01 18:43:28 +00:00
|
|
|
for {
|
|
|
|
e, err := sub.NextNoBlock()
|
|
|
|
require.NoError(t, err)
|
|
|
|
if e == nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
events = append(events, e...)
|
|
|
|
}
|
|
|
|
return events
|
|
|
|
}
|