github.com/maier/nomad@v0.4.1-0.20161110003312-a9e3d0b8549d/nomad/alloc_endpoint_test.go (about) 1 package nomad 2 3 import ( 4 "reflect" 5 "testing" 6 "time" 7 8 "github.com/hashicorp/net-rpc-msgpackrpc" 9 "github.com/hashicorp/nomad/nomad/mock" 10 "github.com/hashicorp/nomad/nomad/structs" 11 "github.com/hashicorp/nomad/testutil" 12 ) 13 14 func TestAllocEndpoint_List(t *testing.T) { 15 s1 := testServer(t, nil) 16 defer s1.Shutdown() 17 codec := rpcClient(t, s1) 18 testutil.WaitForLeader(t, s1.RPC) 19 20 // Create the register request 21 alloc := mock.Alloc() 22 summary := mock.JobSummary(alloc.JobID) 23 state := s1.fsm.State() 24 25 if err := state.UpsertJobSummary(999, summary); err != nil { 26 t.Fatalf("err: %v", err) 27 } 28 if err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}); err != nil { 29 t.Fatalf("err: %v", err) 30 } 31 32 // Lookup the allocations 33 get := &structs.AllocListRequest{ 34 QueryOptions: structs.QueryOptions{Region: "global"}, 35 } 36 var resp structs.AllocListResponse 37 if err := msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp); err != nil { 38 t.Fatalf("err: %v", err) 39 } 40 if resp.Index != 1000 { 41 t.Fatalf("Bad index: %d %d", resp.Index, 1000) 42 } 43 44 if len(resp.Allocations) != 1 { 45 t.Fatalf("bad: %#v", resp.Allocations) 46 } 47 if resp.Allocations[0].ID != alloc.ID { 48 t.Fatalf("bad: %#v", resp.Allocations[0]) 49 } 50 51 // Lookup the allocations by prefix 52 get = &structs.AllocListRequest{ 53 QueryOptions: structs.QueryOptions{Region: "global", Prefix: alloc.ID[:4]}, 54 } 55 56 var resp2 structs.AllocListResponse 57 if err := msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp2); err != nil { 58 t.Fatalf("err: %v", err) 59 } 60 if resp2.Index != 1000 { 61 t.Fatalf("Bad index: %d %d", resp2.Index, 1000) 62 } 63 64 if len(resp2.Allocations) != 1 { 65 t.Fatalf("bad: %#v", resp2.Allocations) 66 } 67 if resp2.Allocations[0].ID != alloc.ID { 68 t.Fatalf("bad: %#v", resp2.Allocations[0]) 69 } 70 } 71 72 func TestAllocEndpoint_List_Blocking(t *testing.T) { 73 s1 := testServer(t, nil) 74 defer s1.Shutdown() 75 state := s1.fsm.State() 76 codec := rpcClient(t, s1) 77 testutil.WaitForLeader(t, s1.RPC) 78 79 // Create the alloc 80 alloc := mock.Alloc() 81 82 summary := mock.JobSummary(alloc.JobID) 83 if err := state.UpsertJobSummary(1, summary); err != nil { 84 t.Fatalf("err: %v", err) 85 } 86 // Upsert alloc triggers watches 87 time.AfterFunc(100*time.Millisecond, func() { 88 if err := state.UpsertAllocs(2, []*structs.Allocation{alloc}); err != nil { 89 t.Fatalf("err: %v", err) 90 } 91 }) 92 93 req := &structs.AllocListRequest{ 94 QueryOptions: structs.QueryOptions{ 95 Region: "global", 96 MinQueryIndex: 1, 97 }, 98 } 99 start := time.Now() 100 var resp structs.AllocListResponse 101 if err := msgpackrpc.CallWithCodec(codec, "Alloc.List", req, &resp); err != nil { 102 t.Fatalf("err: %v", err) 103 } 104 105 if elapsed := time.Since(start); elapsed < 100*time.Millisecond { 106 t.Fatalf("should block (returned in %s) %#v", elapsed, resp) 107 } 108 if resp.Index != 2 { 109 t.Fatalf("Bad index: %d %d", resp.Index, 2) 110 } 111 if len(resp.Allocations) != 1 || resp.Allocations[0].ID != alloc.ID { 112 t.Fatalf("bad: %#v", resp.Allocations) 113 } 114 115 // Client updates trigger watches 116 alloc2 := mock.Alloc() 117 alloc2.ID = alloc.ID 118 alloc2.ClientStatus = structs.AllocClientStatusRunning 119 time.AfterFunc(100*time.Millisecond, func() { 120 state.UpsertJobSummary(3, mock.JobSummary(alloc2.JobID)) 121 if err := state.UpdateAllocsFromClient(4, []*structs.Allocation{alloc2}); err != nil { 122 t.Fatalf("err: %v", err) 123 } 124 }) 125 126 req.MinQueryIndex = 3 127 start = time.Now() 128 var resp2 structs.AllocListResponse 129 if err := msgpackrpc.CallWithCodec(codec, "Alloc.List", req, &resp2); err != nil { 130 t.Fatalf("err: %v", err) 131 } 132 133 if elapsed := time.Since(start); elapsed < 100*time.Millisecond { 134 t.Fatalf("should block (returned in %s) %#v", elapsed, resp2) 135 } 136 if resp2.Index != 4 { 137 t.Fatalf("Bad index: %d %d", resp2.Index, 4) 138 } 139 if len(resp2.Allocations) != 1 || resp.Allocations[0].ID != alloc.ID || 140 resp2.Allocations[0].ClientStatus != structs.AllocClientStatusRunning { 141 t.Fatalf("bad: %#v", resp2.Allocations) 142 } 143 } 144 145 func TestAllocEndpoint_GetAlloc(t *testing.T) { 146 s1 := testServer(t, nil) 147 defer s1.Shutdown() 148 codec := rpcClient(t, s1) 149 testutil.WaitForLeader(t, s1.RPC) 150 151 // Create the register request 152 alloc := mock.Alloc() 153 state := s1.fsm.State() 154 state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID)) 155 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 156 if err != nil { 157 t.Fatalf("err: %v", err) 158 } 159 160 // Lookup the jobs 161 get := &structs.AllocSpecificRequest{ 162 AllocID: alloc.ID, 163 QueryOptions: structs.QueryOptions{Region: "global"}, 164 } 165 var resp structs.SingleAllocResponse 166 if err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp); err != nil { 167 t.Fatalf("err: %v", err) 168 } 169 if resp.Index != 1000 { 170 t.Fatalf("Bad index: %d %d", resp.Index, 1000) 171 } 172 173 if !reflect.DeepEqual(alloc, resp.Alloc) { 174 t.Fatalf("bad: %#v", resp.Alloc) 175 } 176 } 177 178 func TestAllocEndpoint_GetAlloc_Blocking(t *testing.T) { 179 s1 := testServer(t, nil) 180 defer s1.Shutdown() 181 state := s1.fsm.State() 182 codec := rpcClient(t, s1) 183 testutil.WaitForLeader(t, s1.RPC) 184 185 // Create the allocs 186 alloc1 := mock.Alloc() 187 alloc2 := mock.Alloc() 188 189 // First create an unrelated alloc 190 time.AfterFunc(100*time.Millisecond, func() { 191 state.UpsertJobSummary(99, mock.JobSummary(alloc1.JobID)) 192 err := state.UpsertAllocs(100, []*structs.Allocation{alloc1}) 193 if err != nil { 194 t.Fatalf("err: %v", err) 195 } 196 }) 197 198 // Create the alloc we are watching later 199 time.AfterFunc(200*time.Millisecond, func() { 200 state.UpsertJobSummary(999, mock.JobSummary(alloc2.JobID)) 201 err := state.UpsertAllocs(200, []*structs.Allocation{alloc2}) 202 if err != nil { 203 t.Fatalf("err: %v", err) 204 } 205 }) 206 207 // Lookup the allocs 208 get := &structs.AllocSpecificRequest{ 209 AllocID: alloc2.ID, 210 QueryOptions: structs.QueryOptions{ 211 Region: "global", 212 MinQueryIndex: 50, 213 }, 214 } 215 var resp structs.SingleAllocResponse 216 start := time.Now() 217 if err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp); err != nil { 218 t.Fatalf("err: %v", err) 219 } 220 221 if elapsed := time.Since(start); elapsed < 200*time.Millisecond { 222 t.Fatalf("should block (returned in %s) %#v", elapsed, resp) 223 } 224 if resp.Index != 200 { 225 t.Fatalf("Bad index: %d %d", resp.Index, 200) 226 } 227 if resp.Alloc == nil || resp.Alloc.ID != alloc2.ID { 228 t.Fatalf("bad: %#v", resp.Alloc) 229 } 230 } 231 232 func TestAllocEndpoint_GetAllocs(t *testing.T) { 233 s1 := testServer(t, nil) 234 defer s1.Shutdown() 235 codec := rpcClient(t, s1) 236 testutil.WaitForLeader(t, s1.RPC) 237 238 // Create the register request 239 alloc := mock.Alloc() 240 alloc2 := mock.Alloc() 241 state := s1.fsm.State() 242 state.UpsertJobSummary(998, mock.JobSummary(alloc.JobID)) 243 state.UpsertJobSummary(999, mock.JobSummary(alloc2.JobID)) 244 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc, alloc2}) 245 if err != nil { 246 t.Fatalf("err: %v", err) 247 } 248 249 // Lookup the allocs 250 get := &structs.AllocsGetRequest{ 251 AllocIDs: []string{alloc.ID, alloc2.ID}, 252 QueryOptions: structs.QueryOptions{Region: "global"}, 253 } 254 var resp structs.AllocsGetResponse 255 if err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAllocs", get, &resp); err != nil { 256 t.Fatalf("err: %v", err) 257 } 258 if resp.Index != 1000 { 259 t.Fatalf("Bad index: %d %d", resp.Index, 1000) 260 } 261 262 if len(resp.Allocs) != 2 { 263 t.Fatalf("bad: %#v", resp.Allocs) 264 } 265 266 // Lookup non-existent allocs. 267 get = &structs.AllocsGetRequest{ 268 AllocIDs: []string{"foo"}, 269 QueryOptions: structs.QueryOptions{Region: "global"}, 270 } 271 if err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAllocs", get, &resp); err == nil { 272 t.Fatalf("expect error") 273 } 274 }