e2e: add task events tests
This commit is contained in:
parent
324e989327
commit
2cf49f9121
|
@ -7,6 +7,7 @@ import (
|
||||||
_ "github.com/hashicorp/nomad/e2e/consultemplate"
|
_ "github.com/hashicorp/nomad/e2e/consultemplate"
|
||||||
_ "github.com/hashicorp/nomad/e2e/example"
|
_ "github.com/hashicorp/nomad/e2e/example"
|
||||||
_ "github.com/hashicorp/nomad/e2e/spread"
|
_ "github.com/hashicorp/nomad/e2e/spread"
|
||||||
|
_ "github.com/hashicorp/nomad/e2e/taskevents"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestE2E(t *testing.T) {
|
func TestE2E(t *testing.T) {
|
||||||
|
|
28
e2e/taskevents/input/completed_leader.nomad
Normal file
28
e2e/taskevents/input/completed_leader.nomad
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
job "completed_leader" {
|
||||||
|
type = "batch"
|
||||||
|
datacenters = ["dc1"]
|
||||||
|
|
||||||
|
group "completed_leader" {
|
||||||
|
restart {
|
||||||
|
attempts = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Only the task named the same as the job has its events tested.
|
||||||
|
task "completed_leader" {
|
||||||
|
driver = "raw_exec"
|
||||||
|
config {
|
||||||
|
command = "sleep"
|
||||||
|
args = ["1000"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task "leader" {
|
||||||
|
leader = true
|
||||||
|
driver = "raw_exec"
|
||||||
|
config {
|
||||||
|
command = "sleep"
|
||||||
|
args = ["1"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
e2e/taskevents/input/failed_batch.nomad
Normal file
17
e2e/taskevents/input/failed_batch.nomad
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
job "failed_batch" {
|
||||||
|
type = "batch"
|
||||||
|
datacenters = ["dc1"]
|
||||||
|
|
||||||
|
group "failed_batch" {
|
||||||
|
restart {
|
||||||
|
attempts = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
task "failed_batch" {
|
||||||
|
driver = "raw_exec"
|
||||||
|
config {
|
||||||
|
command = "SomeInvalidCommand"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
e2e/taskevents/input/simple_batch.nomad
Normal file
12
e2e/taskevents/input/simple_batch.nomad
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
job "simple_batch" {
|
||||||
|
type = "batch"
|
||||||
|
datacenters = ["dc1"]
|
||||||
|
|
||||||
|
task "simple_batch" {
|
||||||
|
driver = "raw_exec"
|
||||||
|
config {
|
||||||
|
command = "sleep"
|
||||||
|
args = ["1"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
167
e2e/taskevents/taskevents.go
Normal file
167
e2e/taskevents/taskevents.go
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
package taskevents
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/nomad/api"
|
||||||
|
"github.com/hashicorp/nomad/e2e/framework"
|
||||||
|
"github.com/hashicorp/nomad/testutil"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/hashicorp/nomad/e2e/e2eutil"
|
||||||
|
"github.com/hashicorp/nomad/helper/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TaskEventsTest struct {
|
||||||
|
framework.TC
|
||||||
|
jobIds []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
framework.AddSuites(&framework.TestSuite{
|
||||||
|
Component: "TaskEvents",
|
||||||
|
CanRunLocal: true,
|
||||||
|
Cases: []framework.TestCase{
|
||||||
|
new(TaskEventsTest),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tc *TaskEventsTest) BeforeAll(f *framework.F) {
|
||||||
|
e2eutil.WaitForLeader(f.T(), tc.Nomad())
|
||||||
|
e2eutil.WaitForNodesReady(f.T(), tc.Nomad(), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tc *TaskEventsTest) AfterEach(f *framework.F) {
|
||||||
|
nomadClient := tc.Nomad()
|
||||||
|
jobs := nomadClient.Jobs()
|
||||||
|
// Stop all jobs in test
|
||||||
|
for _, id := range tc.jobIds {
|
||||||
|
jobs.Deregister(id, true, nil)
|
||||||
|
}
|
||||||
|
// Garbage collect
|
||||||
|
nomadClient.System().GarbageCollect()
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatEvents(events []*api.TaskEvent) string {
|
||||||
|
estrs := make([]string, len(events))
|
||||||
|
for i, e := range events {
|
||||||
|
estrs[i] = fmt.Sprintf("%2d %-20s fail=%t msg=> %s", i, e.Type, e.FailsTask, e.DisplayMessage)
|
||||||
|
}
|
||||||
|
return strings.Join(estrs, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// waitUntilEvents submits a job and then waits until the expected number of
|
||||||
|
// events exist.
|
||||||
|
//
|
||||||
|
// The job name is used to load the job file from "input/${job}.nomad", and
|
||||||
|
// events are only inspected for tasks named the same as the job.
|
||||||
|
func (tc *TaskEventsTest) waitUntilEvents(f *framework.F, jobName string, numEvents int) *api.TaskState {
|
||||||
|
t := f.T()
|
||||||
|
nomadClient := tc.Nomad()
|
||||||
|
uuid := uuid.Generate()
|
||||||
|
uniqJobId := jobName + uuid[0:8]
|
||||||
|
tc.jobIds = append(tc.jobIds, uniqJobId)
|
||||||
|
|
||||||
|
jobFile := fmt.Sprintf("taskevents/input/%s.nomad", jobName)
|
||||||
|
allocs := e2eutil.RegisterAndWaitForAllocs(f, nomadClient, jobFile, uniqJobId)
|
||||||
|
|
||||||
|
require.Len(t, allocs, 1)
|
||||||
|
alloc := allocs[0]
|
||||||
|
qo := &api.QueryOptions{
|
||||||
|
WaitTime: time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Capture state outside of wait to ease assertions once expected
|
||||||
|
// number of events have been received.
|
||||||
|
var taskState *api.TaskState
|
||||||
|
|
||||||
|
testutil.WaitForResultRetries(10, func() (bool, error) {
|
||||||
|
a, meta, err := nomadClient.Allocations().Info(alloc.ID, qo)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
qo.WaitIndex = meta.LastIndex
|
||||||
|
|
||||||
|
// Capture task state
|
||||||
|
taskState = a.TaskStates[jobName]
|
||||||
|
if taskState == nil {
|
||||||
|
return false, fmt.Errorf("task state not found for %s", jobName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assert expected number of task events
|
||||||
|
if len(taskState.Events) != numEvents {
|
||||||
|
return false, fmt.Errorf("expected %d task events but found %d\n%s",
|
||||||
|
numEvents, len(taskState.Events), formatEvents(taskState.Events),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}, func(err error) {
|
||||||
|
t.Fatalf("task events error: %v", err)
|
||||||
|
})
|
||||||
|
|
||||||
|
return taskState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tc *TaskEventsTest) TestTaskEvents_SimpleBatch(f *framework.F) {
|
||||||
|
t := f.T()
|
||||||
|
taskState := tc.waitUntilEvents(f, "simple_batch", 4)
|
||||||
|
events := taskState.Events
|
||||||
|
|
||||||
|
// Assert task did not fail
|
||||||
|
require.Falsef(t, taskState.Failed, "task unexpectedly failed after %d events\n%s",
|
||||||
|
len(events), formatEvents(events),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert the expected type of events were emitted in a specific order
|
||||||
|
// (based on v0.8.6)
|
||||||
|
require.Equal(t, api.TaskReceived, events[0].Type)
|
||||||
|
require.Equal(t, api.TaskSetup, events[1].Type)
|
||||||
|
require.Equal(t, api.TaskStarted, events[2].Type)
|
||||||
|
require.Equal(t, api.TaskTerminated, events[3].Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tc *TaskEventsTest) TestTaskEvents_FailedBatch(f *framework.F) {
|
||||||
|
t := f.T()
|
||||||
|
taskState := tc.waitUntilEvents(f, "failed_batch", 4)
|
||||||
|
events := taskState.Events
|
||||||
|
|
||||||
|
// Assert task did fail
|
||||||
|
require.Truef(t, taskState.Failed, "task unexpectedly succeeded after %d events\n%s",
|
||||||
|
len(events), formatEvents(events),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert the expected type of events were emitted in a specific order
|
||||||
|
// (based on v0.8.6)
|
||||||
|
require.Equal(t, api.TaskReceived, events[0].Type)
|
||||||
|
require.Equal(t, api.TaskSetup, events[1].Type)
|
||||||
|
require.Equal(t, api.TaskDriverFailure, events[2].Type)
|
||||||
|
require.Equal(t, api.TaskNotRestarting, events[3].Type)
|
||||||
|
require.True(t, events[3].FailsTask)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestTaskEvents_CompletedLeader asserts the proper events are emitted for a
|
||||||
|
// non-leader task when its leader task completes.
|
||||||
|
func (tc *TaskEventsTest) TestTaskEvents_CompletedLeader(f *framework.F) {
|
||||||
|
t := f.T()
|
||||||
|
taskState := tc.waitUntilEvents(f, "completed_leader", 7)
|
||||||
|
events := taskState.Events
|
||||||
|
|
||||||
|
// Assert task did not fail
|
||||||
|
require.Falsef(t, taskState.Failed, "task unexpectedly failed after %d events\n%s",
|
||||||
|
len(events), formatEvents(events),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert the expected type of events were emitted in a specific order
|
||||||
|
require.Equal(t, api.TaskReceived, events[0].Type)
|
||||||
|
require.Equal(t, api.TaskSetup, events[1].Type)
|
||||||
|
require.Equal(t, api.TaskStarted, events[2].Type)
|
||||||
|
require.Equal(t, api.TaskLeaderDead, events[3].Type)
|
||||||
|
require.Equal(t, api.TaskKilling, events[4].Type)
|
||||||
|
require.Equal(t, api.TaskTerminated, events[5].Type)
|
||||||
|
require.Equal(t, api.TaskKilled, events[6].Type)
|
||||||
|
}
|
Loading…
Reference in a new issue