func TestPlanApply_EvalPlan_Simple(t *testing.T) { state := testStateStore(t) node := mock.Node() state.UpsertNode(1000, node) snap, _ := state.Snapshot() alloc := mock.Alloc() allocFail := mock.Alloc() plan := &structs.Plan{ NodeAllocation: map[string][]*structs.Allocation{ node.ID: []*structs.Allocation{alloc}, }, FailedAllocs: []*structs.Allocation{allocFail}, } pool := NewEvaluatePool(workerPoolSize, workerPoolBufferSize) defer pool.Shutdown() result, err := evaluatePlan(pool, snap, plan) if err != nil { t.Fatalf("err: %v", err) } if result == nil { t.Fatalf("missing result") } if !reflect.DeepEqual(result.FailedAllocs, plan.FailedAllocs) { t.Fatalf("missing failed allocs") } }
func TestPlanApply_EvalNodePlan_NodeFull(t *testing.T) { alloc := mock.Alloc() state := testStateStore(t) node := mock.Node() alloc.NodeID = node.ID node.Resources = alloc.Resources node.Reserved = nil state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID)) state.UpsertNode(1000, node) state.UpsertAllocs(1001, []*structs.Allocation{alloc}) alloc2 := mock.Alloc() alloc2.NodeID = node.ID state.UpsertJobSummary(1200, mock.JobSummary(alloc2.JobID)) snap, _ := state.Snapshot() plan := &structs.Plan{ NodeAllocation: map[string][]*structs.Allocation{ node.ID: []*structs.Allocation{alloc2}, }, } fit, err := evaluateNodePlan(snap, plan, node.ID) if err != nil { t.Fatalf("err: %v", err) } if fit { t.Fatalf("bad") } }
func TestUtil_AdjustQueuedAllocations(t *testing.T) { logger := log.New(os.Stderr, "", log.LstdFlags) alloc1 := mock.Alloc() alloc2 := mock.Alloc() alloc2.CreateIndex = 4 alloc3 := mock.Alloc() alloc3.CreateIndex = 3 alloc4 := mock.Alloc() alloc4.CreateIndex = 6 planResult := structs.PlanResult{ NodeUpdate: map[string][]*structs.Allocation{ "node-1": []*structs.Allocation{alloc1}, }, NodeAllocation: map[string][]*structs.Allocation{ "node-1": []*structs.Allocation{ alloc2, }, "node-2": []*structs.Allocation{ alloc3, alloc4, }, }, RefreshIndex: 3, AllocIndex: 4, } queuedAllocs := map[string]int{"web": 2} adjustQueuedAllocations(logger, &planResult, queuedAllocs) if queuedAllocs["web"] != 1 { t.Fatalf("expected: %v, actual: %v", 1, queuedAllocs["web"]) } }
func TestFSM_SnapshotRestore_Allocs_NoSharedResources(t *testing.T) { // Add some state fsm := testFSM(t) state := fsm.State() alloc1 := mock.Alloc() alloc2 := mock.Alloc() alloc1.SharedResources = nil alloc2.SharedResources = nil state.UpsertJobSummary(998, mock.JobSummary(alloc1.JobID)) state.UpsertJobSummary(999, mock.JobSummary(alloc2.JobID)) state.UpsertAllocs(1000, []*structs.Allocation{alloc1}) state.UpsertAllocs(1001, []*structs.Allocation{alloc2}) // Verify the contents fsm2 := testSnapshotRestore(t, fsm) state2 := fsm2.State() out1, _ := state2.AllocByID(alloc1.ID) out2, _ := state2.AllocByID(alloc2.ID) alloc1.SharedResources = &structs.Resources{DiskMB: 150} alloc2.SharedResources = &structs.Resources{DiskMB: 150} if !reflect.DeepEqual(alloc1, out1) { t.Fatalf("bad: \n%#v\n%#v", out1, alloc1) } if !reflect.DeepEqual(alloc2, out2) { t.Fatalf("bad: \n%#v\n%#v", out2, alloc2) } }
func TestPlanApply_EvalPlan_Partial(t *testing.T) { state := testStateStore(t) node := mock.Node() state.UpsertNode(1000, node) node2 := mock.Node() state.UpsertNode(1001, node2) snap, _ := state.Snapshot() alloc := mock.Alloc() alloc2 := mock.Alloc() // Ensure alloc2 does not fit alloc2.Resources = node2.Resources plan := &structs.Plan{ NodeAllocation: map[string][]*structs.Allocation{ node.ID: []*structs.Allocation{alloc}, node2.ID: []*structs.Allocation{alloc2}, }, } result, err := evaluatePlan(snap, plan) if err != nil { t.Fatalf("err: %v", err) } if result == nil { t.Fatalf("missing result") } if _, ok := result.NodeAllocation[node.ID]; !ok { t.Fatalf("should allow alloc") } if _, ok := result.NodeAllocation[node2.ID]; ok { t.Fatalf("should not allow alloc2") } }
func TestPlanApply_EvalPlan_Partial_AllAtOnce(t *testing.T) { state := testStateStore(t) node := mock.Node() state.UpsertNode(1000, node) node2 := mock.Node() state.UpsertNode(1001, node2) snap, _ := state.Snapshot() alloc := mock.Alloc() alloc2 := mock.Alloc() // Ensure alloc2 does not fit alloc2.Resources = node2.Resources plan := &structs.Plan{ AllAtOnce: true, // Require all to make progress NodeAllocation: map[string][]*structs.Allocation{ node.ID: []*structs.Allocation{alloc}, node2.ID: []*structs.Allocation{alloc2}, }, } result, err := evaluatePlan(snap, plan) if err != nil { t.Fatalf("err: %v", err) } if result == nil { t.Fatalf("missing result") } if len(result.NodeAllocation) != 0 { t.Fatalf("should not alloc: %v", result.NodeAllocation) } }
func testTaskRunner(restarts bool) (*MockTaskStateUpdater, *TaskRunner) { logger := testLogger() conf := DefaultConfig() conf.StateDir = os.TempDir() conf.AllocDir = os.TempDir() upd := &MockTaskStateUpdater{} alloc := mock.Alloc() task := alloc.Job.TaskGroups[0].Tasks[0] consulClient, _ := NewConsulService(&consulServiceConfig{logger, "127.0.0.1:8500", "", "", false, false, &structs.Node{}}) // Initialize the port listing. This should be done by the offer process but // we have a mock so that doesn't happen. task.Resources.Networks[0].ReservedPorts = []structs.Port{{"", 80}} allocDir := allocdir.NewAllocDir(filepath.Join(conf.AllocDir, alloc.ID)) allocDir.Build([]*structs.Task{task}) ctx := driver.NewExecContext(allocDir, alloc.ID) rp := structs.NewRestartPolicy(structs.JobTypeService) restartTracker := newRestartTracker(rp) if !restarts { restartTracker = noRestartsTracker() } state := alloc.TaskStates[task.Name] tr := NewTaskRunner(logger, conf, upd.Update, ctx, mock.Alloc(), task, state, restartTracker, consulClient) return upd, tr }
func TestJobEndpoint_Allocations(t *testing.T) { s1 := testServer(t, nil) defer s1.Shutdown() codec := rpcClient(t, s1) testutil.WaitForLeader(t, s1.RPC) // Create the register request alloc1 := mock.Alloc() alloc2 := mock.Alloc() alloc2.JobID = alloc1.JobID state := s1.fsm.State() err := state.UpsertAllocs(1000, []*structs.Allocation{alloc1, alloc2}) if err != nil { t.Fatalf("err: %v", err) } // Lookup the jobs get := &structs.JobSpecificRequest{ JobID: alloc1.JobID, QueryOptions: structs.QueryOptions{Region: "global"}, } var resp2 structs.JobAllocationsResponse if err := msgpackrpc.CallWithCodec(codec, "Job.Allocations", get, &resp2); err != nil { t.Fatalf("err: %v", err) } if resp2.Index != 1000 { t.Fatalf("Bad index: %d %d", resp2.Index, 1000) } if len(resp2.Allocations) != 2 { t.Fatalf("bad: %#v", resp2.Allocations) } }
func TestPlanApply_EvalNodePlan_NodeFull_AllocEvict(t *testing.T) { alloc := mock.Alloc() state := testStateStore(t) node := mock.Node() alloc.NodeID = node.ID alloc.DesiredStatus = structs.AllocDesiredStatusEvict node.Resources = alloc.Resources node.Reserved = nil state.UpsertNode(1000, node) state.UpsertAllocs(1001, []*structs.Allocation{alloc}) snap, _ := state.Snapshot() alloc2 := mock.Alloc() plan := &structs.Plan{ NodeAllocation: map[string][]*structs.Allocation{ node.ID: []*structs.Allocation{alloc2}, }, } fit, err := evaluateNodePlan(snap, plan, node.ID) if err != nil { t.Fatalf("err: %v", err) } if !fit { t.Fatalf("bad") } }
func TestHTTP_AllocsPrefixList(t *testing.T) { httpTest(t, nil, func(s *TestServer) { // Directly manipulate the state state := s.Agent.server.State() alloc1 := mock.Alloc() alloc1.ID = "aaaaaaaa-e8f7-fd38-c855-ab94ceb89706" alloc2 := mock.Alloc() alloc2.ID = "aaabbbbb-e8f7-fd38-c855-ab94ceb89706" summary1 := mock.JobSummary(alloc1.JobID) summary2 := mock.JobSummary(alloc2.JobID) if err := state.UpsertJobSummary(998, summary1); err != nil { t.Fatal(err) } if err := state.UpsertJobSummary(999, summary2); err != nil { t.Fatal(err) } if err := state.UpsertAllocs(1000, []*structs.Allocation{alloc1, alloc2}); err != nil { t.Fatalf("err: %v", err) } // Make the HTTP request req, err := http.NewRequest("GET", "/v1/allocations?prefix=aaab", nil) if err != nil { t.Fatalf("err: %v", err) } respW := httptest.NewRecorder() // Make the request obj, err := s.Server.AllocsRequest(respW, req) if err != nil { t.Fatalf("err: %v", err) } // Check for the index if respW.HeaderMap.Get("X-Nomad-Index") == "" { t.Fatalf("missing index") } if respW.HeaderMap.Get("X-Nomad-KnownLeader") != "true" { t.Fatalf("missing known leader") } if respW.HeaderMap.Get("X-Nomad-LastContact") == "" { t.Fatalf("missing last contact") } // Check the alloc n := obj.([]*structs.AllocListStub) if len(n) != 1 { t.Fatalf("bad: %#v", n) } // Check the identifier if n[0].ID != alloc2.ID { t.Fatalf("expected alloc ID: %v, Actual: %v", alloc2.ID, n[0].ID) } }) }
func TestJobEndpoint_Allocations_Blocking(t *testing.T) { s1 := testServer(t, nil) defer s1.Shutdown() codec := rpcClient(t, s1) testutil.WaitForLeader(t, s1.RPC) // Create the register request alloc1 := mock.Alloc() alloc2 := mock.Alloc() alloc2.JobID = "job1" state := s1.fsm.State() // First upsert an unrelated alloc time.AfterFunc(100*time.Millisecond, func() { state.UpsertJobSummary(99, mock.JobSummary(alloc1.JobID)) err := state.UpsertAllocs(100, []*structs.Allocation{alloc1}) if err != nil { t.Fatalf("err: %v", err) } }) // Upsert an alloc for the job we are interested in later time.AfterFunc(200*time.Millisecond, func() { state.UpsertJobSummary(199, mock.JobSummary(alloc2.JobID)) err := state.UpsertAllocs(200, []*structs.Allocation{alloc2}) if err != nil { t.Fatalf("err: %v", err) } }) // Lookup the jobs get := &structs.JobSpecificRequest{ JobID: "job1", QueryOptions: structs.QueryOptions{ Region: "global", MinQueryIndex: 50, }, } var resp structs.JobAllocationsResponse start := time.Now() if err := msgpackrpc.CallWithCodec(codec, "Job.Allocations", get, &resp); err != nil { t.Fatalf("err: %v", err) } if elapsed := time.Since(start); elapsed < 200*time.Millisecond { t.Fatalf("should block (returned in %s) %#v", elapsed, resp) } if resp.Index != 200 { t.Fatalf("Bad index: %d %d", resp.Index, 200) } if len(resp.Allocations) != 1 || resp.Allocations[0].JobID != "job1" { t.Fatalf("bad: %#v", resp.Allocations) } }
func TestAllocEndpoint_GetAlloc_Blocking(t *testing.T) { s1 := testServer(t, nil) defer s1.Shutdown() state := s1.fsm.State() codec := rpcClient(t, s1) testutil.WaitForLeader(t, s1.RPC) // Create the allocs alloc1 := mock.Alloc() alloc2 := mock.Alloc() // First create an unrelated alloc time.AfterFunc(100*time.Millisecond, func() { state.UpsertJobSummary(99, mock.JobSummary(alloc1.JobID)) err := state.UpsertAllocs(100, []*structs.Allocation{alloc1}) if err != nil { t.Fatalf("err: %v", err) } }) // Create the alloc we are watching later time.AfterFunc(200*time.Millisecond, func() { state.UpsertJobSummary(999, mock.JobSummary(alloc2.JobID)) err := state.UpsertAllocs(200, []*structs.Allocation{alloc2}) if err != nil { t.Fatalf("err: %v", err) } }) // Lookup the allocs get := &structs.AllocSpecificRequest{ AllocID: alloc2.ID, QueryOptions: structs.QueryOptions{ Region: "global", MinQueryIndex: 50, }, } var resp structs.SingleAllocResponse start := time.Now() if err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp); err != nil { t.Fatalf("err: %v", err) } if elapsed := time.Since(start); elapsed < 200*time.Millisecond { t.Fatalf("should block (returned in %s) %#v", elapsed, resp) } if resp.Index != 200 { t.Fatalf("Bad index: %d %d", resp.Index, 200) } if resp.Alloc == nil || resp.Alloc.ID != alloc2.ID { t.Fatalf("bad: %#v", resp.Alloc) } }
func TestStateStore_UpdateAlloc_Alloc(t *testing.T) { state := testStateStore(t) alloc := mock.Alloc() err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) if err != nil { t.Fatalf("err: %v", err) } alloc2 := mock.Alloc() alloc2.ID = alloc.ID alloc2.NodeID = alloc.NodeID + ".new" notify := setupNotifyTest( state, watch.Item{Table: "allocs"}, watch.Item{Alloc: alloc2.ID}, watch.Item{AllocEval: alloc2.EvalID}, watch.Item{AllocJob: alloc2.JobID}, watch.Item{AllocNode: alloc2.NodeID}) err = state.UpsertAllocs(1001, []*structs.Allocation{alloc2}) if err != nil { t.Fatalf("err: %v", err) } out, err := state.AllocByID(alloc.ID) if err != nil { t.Fatalf("err: %v", err) } if !reflect.DeepEqual(alloc2, out) { t.Fatalf("bad: %#v %#v", alloc2, out) } if out.CreateIndex != 1000 { t.Fatalf("bad: %#v", out) } if out.ModifyIndex != 1001 { t.Fatalf("bad: %#v", out) } index, err := state.Index("allocs") if err != nil { t.Fatalf("err: %v", err) } if index != 1001 { t.Fatalf("bad: %d", index) } notify.verify(t) }
func TestEvalEndpoint_Allocations_Blocking(t *testing.T) { s1 := testServer(t, nil) defer s1.Shutdown() state := s1.fsm.State() codec := rpcClient(t, s1) testutil.WaitForLeader(t, s1.RPC) // Create the allocs alloc1 := mock.Alloc() alloc2 := mock.Alloc() // Upsert an unrelated alloc first time.AfterFunc(100*time.Millisecond, func() { err := state.UpsertAllocs(100, []*structs.Allocation{alloc1}) if err != nil { t.Fatalf("err: %v", err) } }) // Upsert an alloc which will trigger the watch later time.AfterFunc(200*time.Millisecond, func() { err := state.UpsertAllocs(200, []*structs.Allocation{alloc2}) if err != nil { t.Fatalf("err: %v", err) } }) // Lookup the eval get := &structs.EvalSpecificRequest{ EvalID: alloc2.EvalID, QueryOptions: structs.QueryOptions{ Region: "global", MinQueryIndex: 50, }, } var resp structs.EvalAllocationsResponse start := time.Now() if err := msgpackrpc.CallWithCodec(codec, "Eval.Allocations", get, &resp); err != nil { t.Fatalf("err: %v", err) } if elapsed := time.Since(start); elapsed < 200*time.Millisecond { t.Fatalf("should block (returned in %s) %#v", elapsed, resp) } if resp.Index != 200 { t.Fatalf("Bad index: %d %d", resp.Index, 200) } if len(resp.Allocations) != 1 || resp.Allocations[0].ID != alloc2.ID { t.Fatalf("bad: %#v", resp.Allocations) } }
func TestAllocEndpoint_GetAlloc(t *testing.T) { s1 := testServer(t, nil) defer s1.Shutdown() codec := rpcClient(t, s1) testutil.WaitForLeader(t, s1.RPC) // Create the register request alloc := mock.Alloc() state := s1.fsm.State() err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) if err != nil { t.Fatalf("err: %v", err) } // Lookup the jobs get := &structs.AllocSpecificRequest{ AllocID: alloc.ID, QueryOptions: structs.QueryOptions{Region: "global"}, } var resp structs.SingleAllocResponse if err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp); err != nil { t.Fatalf("err: %v", err) } if resp.Index != 1000 { t.Fatalf("Bad index: %d %d", resp.Index, 1000) } if !reflect.DeepEqual(alloc, resp.Alloc) { t.Fatalf("bad: %#v", resp.Alloc) } }
func TestClient_UpdateAllocStatus(t *testing.T) { s1, _ := testServer(t, nil) defer s1.Shutdown() testutil.WaitForLeader(t, s1.RPC) c1 := testClient(t, func(c *config.Config) { c.RPCHandler = s1 }) defer c1.Shutdown() alloc := mock.Alloc() alloc.NodeID = c1.Node().ID state := s1.State() state.UpsertAllocs(100, []*structs.Allocation{alloc}) newAlloc := new(structs.Allocation) *newAlloc = *alloc newAlloc.ClientStatus = structs.AllocClientStatusRunning err := c1.updateAllocStatus(newAlloc) if err != nil { t.Fatalf("err: %v", err) } out, err := state.AllocByID(alloc.ID) if err != nil { t.Fatalf("err: %v", err) } if out == nil || out.ClientStatus != structs.AllocClientStatusRunning { t.Fatalf("bad: %#v", out) } }
func TestAllocEndpoint_List(t *testing.T) { s1 := testServer(t, nil) defer s1.Shutdown() codec := rpcClient(t, s1) testutil.WaitForLeader(t, s1.RPC) // Create the register request alloc := mock.Alloc() state := s1.fsm.State() err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) if err != nil { t.Fatalf("err: %v", err) } // Lookup the jobs get := &structs.AllocListRequest{ QueryOptions: structs.QueryOptions{Region: "global"}, } var resp structs.AllocListResponse if err := msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp); err != nil { t.Fatalf("err: %v", err) } if resp.Index != 1000 { t.Fatalf("Bad index: %d %d", resp.Index, 1000) } if len(resp.Allocations) != 1 { t.Fatalf("bad: %#v", resp.Allocations) } if resp.Allocations[0].ID != alloc.ID { t.Fatalf("bad: %#v", resp.Allocations[0]) } }
func TestWorker_SubmitPlan(t *testing.T) { s1 := testServer(t, func(c *Config) { c.NumSchedulers = 0 c.EnabledSchedulers = []string{structs.JobTypeService} }) defer s1.Shutdown() testutil.WaitForLeader(t, s1.RPC) // Register node node := mock.Node() testRegisterNode(t, s1, node) eval1 := mock.Eval() s1.fsm.State().UpsertJobSummary(1000, mock.JobSummary(eval1.JobID)) // Create the register request s1.evalBroker.Enqueue(eval1) evalOut, token, err := s1.evalBroker.Dequeue([]string{eval1.Type}, time.Second) if err != nil { t.Fatalf("err: %v", err) } if evalOut != eval1 { t.Fatalf("Bad eval") } // Create an allocation plan alloc := mock.Alloc() s1.fsm.State().UpsertJobSummary(1200, mock.JobSummary(alloc.JobID)) plan := &structs.Plan{ EvalID: eval1.ID, NodeAllocation: map[string][]*structs.Allocation{ node.ID: []*structs.Allocation{alloc}, }, } // Attempt to submit a plan w := &Worker{srv: s1, logger: s1.logger, evalToken: token} result, state, err := w.SubmitPlan(plan) if err != nil { t.Fatalf("err: %v", err) } // Should have no update if state != nil { t.Fatalf("unexpected state update") } // Result should have allocated if result == nil { t.Fatalf("missing result") } if result.AllocIndex == 0 { t.Fatalf("Bad: %#v", result) } if len(result.NodeAllocation) != 1 { t.Fatalf("Bad: %#v", result) } }
func BenchmarkHTTPRequests(b *testing.B) { s := makeHTTPServerNoLogs(b, func(c *Config) { c.Client.Enabled = false }) defer s.Cleanup() job := mock.Job() var allocs []*structs.Allocation count := 1000 for i := 0; i < count; i++ { alloc := mock.Alloc() alloc.Job = job alloc.JobID = job.ID alloc.Name = fmt.Sprintf("my-job.web[%d]", i) allocs = append(allocs, alloc) } handler := func(resp http.ResponseWriter, req *http.Request) (interface{}, error) { return allocs[:count], nil } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { resp := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/v1/kv/key", nil) s.Server.wrap(handler)(resp, req) } }) }
func TestEvaluatePool(t *testing.T) { state := testStateStore(t) node := mock.Node() state.UpsertNode(1000, node) snap, _ := state.Snapshot() alloc := mock.Alloc() plan := &structs.Plan{ NodeAllocation: map[string][]*structs.Allocation{ node.ID: []*structs.Allocation{alloc}, }, } pool := NewEvaluatePool(1, 4) defer pool.Shutdown() // Push a request req := pool.RequestCh() req <- evaluateRequest{snap, plan, node.ID} // Get the response res := <-pool.ResultCh() // Verify response if res.err != nil { t.Fatalf("err: %v", res.err) } if !res.fit { t.Fatalf("bad") } }
func TestClientEndpoint_GetClientAllocs(t *testing.T) { s1 := testServer(t, nil) defer s1.Shutdown() codec := rpcClient(t, s1) testutil.WaitForLeader(t, s1.RPC) // Create the register request node := mock.Node() reg := &structs.NodeRegisterRequest{ Node: node, WriteRequest: structs.WriteRequest{Region: "global"}, } // Fetch the response var resp structs.GenericResponse if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { t.Fatalf("err: %v", err) } node.CreateIndex = resp.Index node.ModifyIndex = resp.Index // Inject fake evaluations alloc := mock.Alloc() alloc.NodeID = node.ID state := s1.fsm.State() err := state.UpsertAllocs(100, []*structs.Allocation{alloc}) if err != nil { t.Fatalf("err: %v", err) } // Lookup the allocs get := &structs.NodeSpecificRequest{ NodeID: node.ID, QueryOptions: structs.QueryOptions{Region: "global"}, } var resp2 structs.NodeClientAllocsResponse if err := msgpackrpc.CallWithCodec(codec, "Node.GetClientAllocs", get, &resp2); err != nil { t.Fatalf("err: %v", err) } if resp2.Index != 100 { t.Fatalf("Bad index: %d %d", resp2.Index, 100) } if len(resp2.Allocs) != 1 || resp2.Allocs[alloc.ID] != 100 { t.Fatalf("bad: %#v", resp2.Allocs) } // Lookup non-existing node get.NodeID = "foobarbaz" var resp3 structs.NodeClientAllocsResponse if err := msgpackrpc.CallWithCodec(codec, "Node.GetClientAllocs", get, &resp3); err != nil { t.Fatalf("err: %v", err) } if resp3.Index != 100 { t.Fatalf("Bad index: %d %d", resp3.Index, 100) } if len(resp3.Allocs) != 0 { t.Fatalf("unexpected node %#v", resp3.Allocs) } }
func TestClient_UpdateAllocStatus(t *testing.T) { s1, _ := testServer(t, nil) defer s1.Shutdown() testutil.WaitForLeader(t, s1.RPC) c1 := testClient(t, func(c *config.Config) { c.RPCHandler = s1 }) defer c1.Shutdown() alloc := mock.Alloc() alloc.NodeID = c1.Node().ID originalStatus := "foo" alloc.ClientStatus = originalStatus state := s1.State() state.UpsertAllocs(100, []*structs.Allocation{alloc}) testutil.WaitForResult(func() (bool, error) { out, err := state.AllocByID(alloc.ID) if err != nil { return false, err } if out == nil { return false, fmt.Errorf("no such alloc") } if out.ClientStatus == originalStatus { return false, fmt.Errorf("Alloc client status not updated; got %v", out.ClientStatus) } return true, nil }, func(err error) { t.Fatalf("err: %v", err) }) }
func TestStateStore_GetJobStatus_DeadEvalsAndAllocs(t *testing.T) { state := testStateStore(t) job := mock.Job() // Create a mock alloc that is dead. alloc := mock.Alloc() alloc.JobID = job.ID alloc.DesiredStatus = structs.AllocDesiredStatusFailed if err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}); err != nil { t.Fatalf("err: %v", err) } // Create a mock eval that is complete eval := mock.Eval() eval.JobID = job.ID eval.Status = structs.EvalStatusComplete if err := state.UpsertEvals(1001, []*structs.Evaluation{eval}); err != nil { t.Fatalf("err: %v", err) } txn := state.db.Txn(false) status, err := state.getJobStatus(txn, job, false) if err != nil { t.Fatalf("getJobStatus() failed: %v", err) } if status != structs.JobStatusDead { t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusDead) } }
func TestFSM_UpdateAllocFromClient(t *testing.T) { fsm := testFSM(t) state := fsm.State() alloc := mock.Alloc() state.UpsertAllocs(1, []*structs.Allocation{alloc}) clientAlloc := new(structs.Allocation) *clientAlloc = *alloc clientAlloc.ClientStatus = structs.AllocClientStatusFailed req := structs.AllocUpdateRequest{ Alloc: []*structs.Allocation{clientAlloc}, } buf, err := structs.Encode(structs.AllocClientUpdateRequestType, 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 out, err := fsm.State().AllocByID(alloc.ID) if err != nil { t.Fatalf("err: %v", err) } clientAlloc.CreateIndex = out.CreateIndex clientAlloc.ModifyIndex = out.ModifyIndex if !reflect.DeepEqual(clientAlloc, out) { t.Fatalf("bad: %#v %#v", clientAlloc, out) } }
func TestStateStore_AllocsByJob(t *testing.T) { state := testStateStore(t) var allocs []*structs.Allocation for i := 0; i < 10; i++ { alloc := mock.Alloc() alloc.JobID = "foo" allocs = append(allocs, alloc) } err := state.UpsertAllocs(1000, allocs) if err != nil { t.Fatalf("err: %v", err) } out, err := state.AllocsByJob("foo") if err != nil { t.Fatalf("err: %v", err) } sort.Sort(AllocIDSort(allocs)) sort.Sort(AllocIDSort(out)) if !reflect.DeepEqual(allocs, out) { t.Fatalf("bad: %#v %#v", allocs, out) } }
func TestStateStore_EvictAlloc_Alloc(t *testing.T) { state := testStateStore(t) alloc := mock.Alloc() err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) if err != nil { t.Fatalf("err: %v", err) } alloc2 := new(structs.Allocation) *alloc2 = *alloc alloc2.DesiredStatus = structs.AllocDesiredStatusEvict err = state.UpsertAllocs(1001, []*structs.Allocation{alloc2}) if err != nil { t.Fatalf("err: %v", err) } out, err := state.AllocByID(alloc.ID) if err != nil { t.Fatalf("err: %v", err) } if out.DesiredStatus != structs.AllocDesiredStatusEvict { t.Fatalf("bad: %#v %#v", alloc, out) } index, err := state.Index("allocs") if err != nil { t.Fatalf("err: %v", err) } if index != 1001 { t.Fatalf("bad: %d", index) } }
func TestStateStore_Allocs(t *testing.T) { state := testStateStore(t) var allocs []*structs.Allocation for i := 0; i < 10; i++ { alloc := mock.Alloc() allocs = append(allocs, alloc) } err := state.UpsertAllocs(1000, allocs) if err != nil { t.Fatalf("err: %v", err) } iter, err := state.Allocs() if err != nil { t.Fatalf("err: %v", err) } var out []*structs.Allocation for { raw := iter.Next() if raw == nil { break } out = append(out, raw.(*structs.Allocation)) } sort.Sort(AllocIDSort(allocs)) sort.Sort(AllocIDSort(out)) if !reflect.DeepEqual(allocs, out) { t.Fatalf("bad: %#v %#v", allocs, out) } }
func TestVaultClient_CreateToken_Prestart(t *testing.T) { v := testutil.NewTestVault(t) defer v.Stop() logger := log.New(os.Stderr, "", log.LstdFlags) client, err := NewVaultClient(v.Config, logger, nil) if err != nil { t.Fatalf("failed to build vault client: %v", err) } client.SetActive(true) defer client.Stop() // Create an allocation that requires a Vault policy a := mock.Alloc() task := a.Job.TaskGroups[0].Tasks[0] task.Vault = &structs.Vault{Policies: []string{"default"}} _, err = client.CreateToken(context.Background(), a, task.Name) if err == nil { t.Fatalf("CreateToken should have failed: %v", err) } if rerr, ok := err.(*structs.RecoverableError); !ok { t.Fatalf("Err should have been type recoverable error") } else if ok && !rerr.Recoverable { t.Fatalf("Err should have been recoverable") } }
func TestPlanApply_EvalNodePlan_NodeDown_EvictOnly(t *testing.T) { alloc := mock.Alloc() state := testStateStore(t) node := mock.Node() alloc.NodeID = node.ID node.Resources = alloc.Resources node.Reserved = nil node.Status = structs.NodeStatusDown state.UpsertNode(1000, node) state.UpsertAllocs(1001, []*structs.Allocation{alloc}) snap, _ := state.Snapshot() allocEvict := new(structs.Allocation) *allocEvict = *alloc allocEvict.DesiredStatus = structs.AllocDesiredStatusEvict plan := &structs.Plan{ NodeUpdate: map[string][]*structs.Allocation{ node.ID: []*structs.Allocation{allocEvict}, }, } fit, err := evaluateNodePlan(snap, plan, node.ID) if err != nil { t.Fatalf("err: %v", err) } if !fit { t.Fatalf("bad") } }
func TestStateStore_RestoreAlloc(t *testing.T) { state := testStateStore(t) alloc := mock.Alloc() notify := setupNotifyTest( state, watch.Item{Table: "allocs"}, watch.Item{Alloc: alloc.ID}, watch.Item{AllocEval: alloc.EvalID}, watch.Item{AllocJob: alloc.JobID}, watch.Item{AllocNode: alloc.NodeID}) restore, err := state.Restore() if err != nil { t.Fatalf("err: %v", err) } err = restore.AllocRestore(alloc) if err != nil { t.Fatalf("err: %v", err) } restore.Commit() out, err := state.AllocByID(alloc.ID) if err != nil { t.Fatalf("err: %v", err) } if !reflect.DeepEqual(out, alloc) { t.Fatalf("Bad: %#v %#v", out, alloc) } notify.verify(t) }