open-nomad/nomad/fsm_test.go

409 lines
7.9 KiB
Go
Raw Normal View History

2015-07-04 01:41:36 +00:00
package nomad
import (
"bytes"
2015-07-04 01:41:36 +00:00
"os"
"reflect"
2015-07-04 01:41:36 +00:00
"testing"
"github.com/hashicorp/nomad/nomad/structs"
"github.com/hashicorp/raft"
)
type MockSink struct {
*bytes.Buffer
cancel bool
}
func (m *MockSink) ID() string {
return "Mock"
}
func (m *MockSink) Cancel() error {
m.cancel = true
return nil
}
func (m *MockSink) Close() error {
return nil
}
2015-07-04 01:41:36 +00:00
func testFSM(t *testing.T) *nomadFSM {
fsm, err := NewFSM(testBroker(t, 0), os.Stderr)
2015-07-04 01:41:36 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
if fsm == nil {
t.Fatalf("missing fsm")
}
return fsm
}
func makeLog(buf []byte) *raft.Log {
return &raft.Log{
Index: 1,
Term: 1,
Type: raft.LogCommand,
Data: buf,
}
}
func TestFSM_RegisterNode(t *testing.T) {
fsm := testFSM(t)
req := structs.NodeRegisterRequest{
2015-07-04 01:41:36 +00:00
Node: mockNode(),
}
buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
2015-07-04 01:41:36 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
resp := fsm.Apply(makeLog(buf))
if resp != nil {
t.Fatalf("resp: %v", resp)
}
// Verify we are registered
node, err := fsm.State().GetNodeByID(req.Node.ID)
if err != nil {
t.Fatalf("err: %v", err)
}
if node == nil {
t.Fatalf("not found!")
}
if node.CreateIndex != 1 {
t.Fatalf("bad index: %d", node.CreateIndex)
}
}
func TestFSM_DeregisterNode(t *testing.T) {
fsm := testFSM(t)
node := mockNode()
req := structs.NodeRegisterRequest{
2015-07-04 01:41:36 +00:00
Node: node,
}
buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
2015-07-04 01:41:36 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
resp := fsm.Apply(makeLog(buf))
if resp != nil {
t.Fatalf("resp: %v", resp)
}
req2 := structs.NodeDeregisterRequest{
2015-07-04 01:41:36 +00:00
NodeID: node.ID,
}
buf, err = structs.Encode(structs.NodeDeregisterRequestType, req2)
2015-07-04 01:41:36 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
resp = fsm.Apply(makeLog(buf))
if resp != nil {
t.Fatalf("resp: %v", resp)
}
// Verify we are NOT registered
node, err = fsm.State().GetNodeByID(req.Node.ID)
if err != nil {
t.Fatalf("err: %v", err)
}
if node != nil {
t.Fatalf("node found!")
}
}
func TestFSM_UpdateNodeStatus(t *testing.T) {
fsm := testFSM(t)
node := mockNode()
req := structs.NodeRegisterRequest{
2015-07-04 01:41:36 +00:00
Node: node,
}
buf, err := structs.Encode(structs.NodeRegisterRequestType, req)
2015-07-04 01:41:36 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
resp := fsm.Apply(makeLog(buf))
if resp != nil {
t.Fatalf("resp: %v", resp)
}
req2 := structs.NodeUpdateStatusRequest{
2015-07-04 01:41:36 +00:00
NodeID: node.ID,
Status: structs.NodeStatusReady,
}
buf, err = structs.Encode(structs.NodeUpdateStatusRequestType, req2)
if err != nil {
t.Fatalf("err: %v", err)
}
resp = fsm.Apply(makeLog(buf))
if resp != nil {
t.Fatalf("resp: %v", resp)
}
// Verify we are NOT registered
node, err = fsm.State().GetNodeByID(req.Node.ID)
if err != nil {
t.Fatalf("err: %v", err)
}
if node.Status != structs.NodeStatusReady {
t.Fatalf("bad node: %#v", node)
}
}
2015-07-07 16:55:47 +00:00
func TestFSM_RegisterJob(t *testing.T) {
fsm := testFSM(t)
req := structs.JobRegisterRequest{
Job: mockJob(),
}
buf, err := structs.Encode(structs.JobRegisterRequestType, req)
if err != nil {
t.Fatalf("err: %v", err)
}
resp := fsm.Apply(makeLog(buf))
if resp != nil {
t.Fatalf("resp: %v", resp)
}
// Verify we are registered
job, err := fsm.State().GetJobByID(req.Job.ID)
2015-07-07 16:55:47 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
if job == nil {
t.Fatalf("not found!")
}
if job.CreateIndex != 1 {
t.Fatalf("bad index: %d", job.CreateIndex)
}
}
func TestFSM_DeregisterJob(t *testing.T) {
fsm := testFSM(t)
job := mockJob()
req := structs.JobRegisterRequest{
Job: job,
}
buf, err := structs.Encode(structs.JobRegisterRequestType, req)
if err != nil {
t.Fatalf("err: %v", err)
}
resp := fsm.Apply(makeLog(buf))
if resp != nil {
t.Fatalf("resp: %v", resp)
}
req2 := structs.JobDeregisterRequest{
JobID: job.ID,
2015-07-07 16:55:47 +00:00
}
buf, err = structs.Encode(structs.JobDeregisterRequestType, req2)
if err != nil {
t.Fatalf("err: %v", err)
}
resp = fsm.Apply(makeLog(buf))
if resp != nil {
t.Fatalf("resp: %v", resp)
}
// Verify we are NOT registered
job, err = fsm.State().GetJobByID(req.Job.ID)
2015-07-07 16:55:47 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
if job != nil {
t.Fatalf("job found!")
}
}
func TestFSM_UpdateEval(t *testing.T) {
fsm := testFSM(t)
req := structs.EvalUpdateRequest{
Eval: mockEval(),
}
buf, err := structs.Encode(structs.EvalUpdateRequestType, req)
if err != nil {
t.Fatalf("err: %v", err)
}
resp := fsm.Apply(makeLog(buf))
if resp != nil {
t.Fatalf("resp: %v", resp)
}
// Verify we are registered
eval, err := fsm.State().GetEvalByID(req.Eval.ID)
if err != nil {
t.Fatalf("err: %v", err)
}
if eval == nil {
t.Fatalf("not found!")
}
if eval.CreateIndex != 1 {
t.Fatalf("bad index: %d", eval.CreateIndex)
}
}
func TestFSM_DeleteEval(t *testing.T) {
fsm := testFSM(t)
eval := mockEval()
req := structs.EvalUpdateRequest{
Eval: eval,
}
buf, err := structs.Encode(structs.EvalUpdateRequestType, req)
if err != nil {
t.Fatalf("err: %v", err)
}
resp := fsm.Apply(makeLog(buf))
if resp != nil {
t.Fatalf("resp: %v", resp)
}
req2 := structs.EvalDeleteRequest{
EvalID: eval.ID,
}
buf, err = structs.Encode(structs.EvalDeleteRequestType, req2)
if err != nil {
t.Fatalf("err: %v", err)
}
resp = fsm.Apply(makeLog(buf))
if resp != nil {
t.Fatalf("resp: %v", resp)
}
// Verify we are NOT registered
eval, err = fsm.State().GetEvalByID(req.Eval.ID)
if err != nil {
t.Fatalf("err: %v", err)
}
if eval != nil {
t.Fatalf("eval found!")
}
}
func testSnapshotRestore(t *testing.T, fsm *nomadFSM) *nomadFSM {
// Snapshot
snap, err := fsm.Snapshot()
if err != nil {
t.Fatalf("err: %v", err)
}
defer snap.Release()
// Persist
buf := bytes.NewBuffer(nil)
sink := &MockSink{buf, false}
if err := snap.Persist(sink); err != nil {
t.Fatalf("err: %v", err)
}
// Try to restore on a new FSM
fsm2 := testFSM(t)
// Do a restore
if err := fsm2.Restore(sink); err != nil {
t.Fatalf("err: %v", err)
}
return fsm2
}
func TestFSM_SnapshotRestore_Nodes(t *testing.T) {
// Add some state
fsm := testFSM(t)
state := fsm.State()
node1 := mockNode()
state.RegisterNode(1000, node1)
node2 := mockNode()
state.RegisterNode(1001, node2)
// Verify the contents
fsm2 := testSnapshotRestore(t, fsm)
state2 := fsm2.State()
out1, _ := state2.GetNodeByID(node1.ID)
out2, _ := state2.GetNodeByID(node2.ID)
if !reflect.DeepEqual(node1, out1) {
t.Fatalf("bad: \n%#v\n%#v", out1, node1)
}
if !reflect.DeepEqual(node2, out2) {
t.Fatalf("bad: \n%#v\n%#v", out2, node2)
}
}
2015-07-07 16:55:47 +00:00
func TestFSM_SnapshotRestore_Jobs(t *testing.T) {
// Add some state
fsm := testFSM(t)
state := fsm.State()
job1 := mockJob()
state.RegisterJob(1000, job1)
job2 := mockJob()
state.RegisterJob(1001, job2)
// Verify the contents
fsm2 := testSnapshotRestore(t, fsm)
state2 := fsm2.State()
out1, _ := state2.GetJobByID(job1.ID)
out2, _ := state2.GetJobByID(job2.ID)
2015-07-07 16:55:47 +00:00
if !reflect.DeepEqual(job1, out1) {
t.Fatalf("bad: \n%#v\n%#v", out1, job1)
}
if !reflect.DeepEqual(job2, out2) {
t.Fatalf("bad: \n%#v\n%#v", out2, job2)
}
}
func TestFSM_SnapshotRestore_Evals(t *testing.T) {
// Add some state
fsm := testFSM(t)
state := fsm.State()
eval1 := mockEval()
state.UpsertEval(1000, eval1)
eval2 := mockEval()
state.UpsertEval(1001, eval2)
// Verify the contents
fsm2 := testSnapshotRestore(t, fsm)
state2 := fsm2.State()
out1, _ := state2.GetEvalByID(eval1.ID)
out2, _ := state2.GetEvalByID(eval2.ID)
if !reflect.DeepEqual(eval1, out1) {
t.Fatalf("bad: \n%#v\n%#v", out1, eval1)
}
if !reflect.DeepEqual(eval2, out2) {
t.Fatalf("bad: \n%#v\n%#v", out2, eval2)
}
}
func TestFSM_SnapshotRestore_Indexes(t *testing.T) {
// Add some state
fsm := testFSM(t)
state := fsm.State()
node1 := mockNode()
state.RegisterNode(1000, node1)
// Verify the contents
fsm2 := testSnapshotRestore(t, fsm)
state2 := fsm2.State()
index, err := state2.GetIndex("nodes")
if err != nil {
t.Fatalf("err: %v", err)
}
if index != 1000 {
t.Fatalf("bad: %d", index)
}
}