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