github.com/anuvu/nomad@v0.8.7-atom1/nomad/structs/funcs_test.go (about) 1 package structs 2 3 import ( 4 "encoding/base64" 5 "fmt" 6 "testing" 7 8 lru "github.com/hashicorp/golang-lru" 9 "github.com/hashicorp/nomad/helper/uuid" 10 "github.com/stretchr/testify/assert" 11 ) 12 13 func TestRemoveAllocs(t *testing.T) { 14 l := []*Allocation{ 15 {ID: "foo"}, 16 {ID: "bar"}, 17 {ID: "baz"}, 18 {ID: "zip"}, 19 } 20 21 out := RemoveAllocs(l, []*Allocation{l[1], l[3]}) 22 if len(out) != 2 { 23 t.Fatalf("bad: %#v", out) 24 } 25 if out[0].ID != "foo" && out[1].ID != "baz" { 26 t.Fatalf("bad: %#v", out) 27 } 28 } 29 30 func TestFilterTerminalAllocs(t *testing.T) { 31 l := []*Allocation{ 32 { 33 ID: "bar", 34 Name: "myname1", 35 DesiredStatus: AllocDesiredStatusEvict, 36 }, 37 {ID: "baz", DesiredStatus: AllocDesiredStatusStop}, 38 { 39 ID: "foo", 40 DesiredStatus: AllocDesiredStatusRun, 41 ClientStatus: AllocClientStatusPending, 42 }, 43 { 44 ID: "bam", 45 Name: "myname", 46 DesiredStatus: AllocDesiredStatusRun, 47 ClientStatus: AllocClientStatusComplete, 48 CreateIndex: 5, 49 }, 50 { 51 ID: "lol", 52 Name: "myname", 53 DesiredStatus: AllocDesiredStatusRun, 54 ClientStatus: AllocClientStatusComplete, 55 CreateIndex: 2, 56 }, 57 } 58 59 out, terminalAllocs := FilterTerminalAllocs(l) 60 if len(out) != 1 { 61 t.Fatalf("bad: %#v", out) 62 } 63 if out[0].ID != "foo" { 64 t.Fatalf("bad: %#v", out) 65 } 66 67 if len(terminalAllocs) != 3 { 68 for _, o := range terminalAllocs { 69 fmt.Printf("%#v \n", o) 70 } 71 72 t.Fatalf("bad: %#v", terminalAllocs) 73 } 74 75 if terminalAllocs["myname"].ID != "bam" { 76 t.Fatalf("bad: %#v", terminalAllocs["myname"]) 77 } 78 } 79 80 func TestAllocsFit_PortsOvercommitted(t *testing.T) { 81 n := &Node{ 82 Resources: &Resources{ 83 Networks: []*NetworkResource{ 84 { 85 Device: "eth0", 86 CIDR: "10.0.0.0/8", 87 MBits: 100, 88 }, 89 }, 90 }, 91 } 92 93 a1 := &Allocation{ 94 Job: &Job{ 95 TaskGroups: []*TaskGroup{ 96 { 97 Name: "web", 98 EphemeralDisk: DefaultEphemeralDisk(), 99 }, 100 }, 101 }, 102 TaskResources: map[string]*Resources{ 103 "web": { 104 Networks: []*NetworkResource{ 105 { 106 Device: "eth0", 107 IP: "10.0.0.1", 108 MBits: 50, 109 ReservedPorts: []Port{{"main", 8000}}, 110 }, 111 }, 112 }, 113 }, 114 } 115 116 // Should fit one allocation 117 fit, dim, _, err := AllocsFit(n, []*Allocation{a1}, nil) 118 if err != nil { 119 t.Fatalf("err: %v", err) 120 } 121 if !fit { 122 t.Fatalf("Bad: %s", dim) 123 } 124 125 // Should not fit second allocation 126 fit, _, _, err = AllocsFit(n, []*Allocation{a1, a1}, nil) 127 if err != nil { 128 t.Fatalf("err: %v", err) 129 } 130 if fit { 131 t.Fatalf("Bad") 132 } 133 } 134 135 func TestAllocsFit(t *testing.T) { 136 n := &Node{ 137 Resources: &Resources{ 138 CPU: 2000, 139 MemoryMB: 2048, 140 DiskMB: 10000, 141 IOPS: 100, 142 Networks: []*NetworkResource{ 143 { 144 Device: "eth0", 145 CIDR: "10.0.0.0/8", 146 MBits: 100, 147 }, 148 }, 149 }, 150 Reserved: &Resources{ 151 CPU: 1000, 152 MemoryMB: 1024, 153 DiskMB: 5000, 154 IOPS: 50, 155 Networks: []*NetworkResource{ 156 { 157 Device: "eth0", 158 IP: "10.0.0.1", 159 MBits: 50, 160 ReservedPorts: []Port{{"main", 80}}, 161 }, 162 }, 163 }, 164 } 165 166 a1 := &Allocation{ 167 Resources: &Resources{ 168 CPU: 1000, 169 MemoryMB: 1024, 170 DiskMB: 5000, 171 IOPS: 50, 172 Networks: []*NetworkResource{ 173 { 174 Device: "eth0", 175 IP: "10.0.0.1", 176 MBits: 50, 177 ReservedPorts: []Port{{"main", 8000}}, 178 }, 179 }, 180 }, 181 } 182 183 // Should fit one allocation 184 fit, _, used, err := AllocsFit(n, []*Allocation{a1}, nil) 185 if err != nil { 186 t.Fatalf("err: %v", err) 187 } 188 if !fit { 189 t.Fatalf("Bad") 190 } 191 192 // Sanity check the used resources 193 if used.CPU != 2000 { 194 t.Fatalf("bad: %#v", used) 195 } 196 if used.MemoryMB != 2048 { 197 t.Fatalf("bad: %#v", used) 198 } 199 200 // Should not fit second allocation 201 fit, _, used, err = AllocsFit(n, []*Allocation{a1, a1}, nil) 202 if err != nil { 203 t.Fatalf("err: %v", err) 204 } 205 if fit { 206 t.Fatalf("Bad") 207 } 208 209 // Sanity check the used resources 210 if used.CPU != 3000 { 211 t.Fatalf("bad: %#v", used) 212 } 213 if used.MemoryMB != 3072 { 214 t.Fatalf("bad: %#v", used) 215 } 216 217 } 218 219 func TestAllocsFit_TerminalAlloc(t *testing.T) { 220 n := &Node{ 221 Resources: &Resources{ 222 CPU: 2000, 223 MemoryMB: 2048, 224 DiskMB: 10000, 225 IOPS: 100, 226 Networks: []*NetworkResource{ 227 { 228 Device: "eth0", 229 CIDR: "10.0.0.0/8", 230 MBits: 100, 231 }, 232 }, 233 }, 234 Reserved: &Resources{ 235 CPU: 1000, 236 MemoryMB: 1024, 237 DiskMB: 5000, 238 IOPS: 50, 239 Networks: []*NetworkResource{ 240 { 241 Device: "eth0", 242 IP: "10.0.0.1", 243 MBits: 50, 244 ReservedPorts: []Port{{"main", 80}}, 245 }, 246 }, 247 }, 248 } 249 250 a1 := &Allocation{ 251 Resources: &Resources{ 252 CPU: 1000, 253 MemoryMB: 1024, 254 DiskMB: 5000, 255 IOPS: 50, 256 Networks: []*NetworkResource{ 257 { 258 Device: "eth0", 259 IP: "10.0.0.1", 260 MBits: 50, 261 ReservedPorts: []Port{{"main", 8000}}, 262 }, 263 }, 264 }, 265 } 266 267 // Should fit one allocation 268 fit, _, used, err := AllocsFit(n, []*Allocation{a1}, nil) 269 if err != nil { 270 t.Fatalf("err: %v", err) 271 } 272 if !fit { 273 t.Fatalf("Bad") 274 } 275 276 // Sanity check the used resources 277 if used.CPU != 2000 { 278 t.Fatalf("bad: %#v", used) 279 } 280 if used.MemoryMB != 2048 { 281 t.Fatalf("bad: %#v", used) 282 } 283 284 // Should fit second allocation since it is terminal 285 a2 := a1.Copy() 286 a2.DesiredStatus = AllocDesiredStatusStop 287 fit, _, used, err = AllocsFit(n, []*Allocation{a1, a2}, nil) 288 if err != nil { 289 t.Fatalf("err: %v", err) 290 } 291 if !fit { 292 t.Fatalf("Bad") 293 } 294 295 // Sanity check the used resources 296 if used.CPU != 2000 { 297 t.Fatalf("bad: %#v", used) 298 } 299 if used.MemoryMB != 2048 { 300 t.Fatalf("bad: %#v", used) 301 } 302 } 303 304 func TestScoreFit(t *testing.T) { 305 node := &Node{} 306 node.Resources = &Resources{ 307 CPU: 4096, 308 MemoryMB: 8192, 309 } 310 node.Reserved = &Resources{ 311 CPU: 2048, 312 MemoryMB: 4096, 313 } 314 315 // Test a perfect fit 316 util := &Resources{ 317 CPU: 2048, 318 MemoryMB: 4096, 319 } 320 score := ScoreFit(node, util) 321 if score != 18.0 { 322 t.Fatalf("bad: %v", score) 323 } 324 325 // Test the worst fit 326 util = &Resources{ 327 CPU: 0, 328 MemoryMB: 0, 329 } 330 score = ScoreFit(node, util) 331 if score != 0.0 { 332 t.Fatalf("bad: %v", score) 333 } 334 335 // Test a mid-case scenario 336 util = &Resources{ 337 CPU: 1024, 338 MemoryMB: 2048, 339 } 340 score = ScoreFit(node, util) 341 if score < 10.0 || score > 16.0 { 342 t.Fatalf("bad: %v", score) 343 } 344 } 345 346 func TestACLPolicyListHash(t *testing.T) { 347 h1 := ACLPolicyListHash(nil) 348 assert.NotEqual(t, "", h1) 349 350 p1 := &ACLPolicy{ 351 Name: fmt.Sprintf("policy-%s", uuid.Generate()), 352 Description: "Super cool policy!", 353 Rules: ` 354 namespace "default" { 355 policy = "write" 356 } 357 node { 358 policy = "read" 359 } 360 agent { 361 policy = "read" 362 } 363 `, 364 CreateIndex: 10, 365 ModifyIndex: 20, 366 } 367 368 h2 := ACLPolicyListHash([]*ACLPolicy{p1}) 369 assert.NotEqual(t, "", h2) 370 assert.NotEqual(t, h1, h2) 371 372 // Create P2 as copy of P1 with new name 373 p2 := &ACLPolicy{} 374 *p2 = *p1 375 p2.Name = fmt.Sprintf("policy-%s", uuid.Generate()) 376 377 h3 := ACLPolicyListHash([]*ACLPolicy{p1, p2}) 378 assert.NotEqual(t, "", h3) 379 assert.NotEqual(t, h2, h3) 380 381 h4 := ACLPolicyListHash([]*ACLPolicy{p2}) 382 assert.NotEqual(t, "", h4) 383 assert.NotEqual(t, h3, h4) 384 385 // ModifyIndex should change the hash 386 p2.ModifyIndex++ 387 h5 := ACLPolicyListHash([]*ACLPolicy{p2}) 388 assert.NotEqual(t, "", h5) 389 assert.NotEqual(t, h4, h5) 390 } 391 392 func TestCompileACLObject(t *testing.T) { 393 p1 := &ACLPolicy{ 394 Name: fmt.Sprintf("policy-%s", uuid.Generate()), 395 Description: "Super cool policy!", 396 Rules: ` 397 namespace "default" { 398 policy = "write" 399 } 400 node { 401 policy = "read" 402 } 403 agent { 404 policy = "read" 405 } 406 `, 407 CreateIndex: 10, 408 ModifyIndex: 20, 409 } 410 411 // Create P2 as copy of P1 with new name 412 p2 := &ACLPolicy{} 413 *p2 = *p1 414 p2.Name = fmt.Sprintf("policy-%s", uuid.Generate()) 415 416 // Create a small cache 417 cache, err := lru.New2Q(16) 418 assert.Nil(t, err) 419 420 // Test compilation 421 aclObj, err := CompileACLObject(cache, []*ACLPolicy{p1}) 422 assert.Nil(t, err) 423 assert.NotNil(t, aclObj) 424 425 // Should get the same object 426 aclObj2, err := CompileACLObject(cache, []*ACLPolicy{p1}) 427 assert.Nil(t, err) 428 if aclObj != aclObj2 { 429 t.Fatalf("expected the same object") 430 } 431 432 // Should get another object 433 aclObj3, err := CompileACLObject(cache, []*ACLPolicy{p1, p2}) 434 assert.Nil(t, err) 435 assert.NotNil(t, aclObj3) 436 if aclObj == aclObj3 { 437 t.Fatalf("unexpected same object") 438 } 439 440 // Should be order independent 441 aclObj4, err := CompileACLObject(cache, []*ACLPolicy{p2, p1}) 442 assert.Nil(t, err) 443 assert.NotNil(t, aclObj4) 444 if aclObj3 != aclObj4 { 445 t.Fatalf("expected same object") 446 } 447 } 448 449 // TestGenerateMigrateToken asserts the migrate token is valid for use in HTTP 450 // headers and CompareMigrateToken works as expected. 451 func TestGenerateMigrateToken(t *testing.T) { 452 assert := assert.New(t) 453 allocID := uuid.Generate() 454 nodeSecret := uuid.Generate() 455 token, err := GenerateMigrateToken(allocID, nodeSecret) 456 assert.Nil(err) 457 _, err = base64.URLEncoding.DecodeString(token) 458 assert.Nil(err) 459 460 assert.True(CompareMigrateToken(allocID, nodeSecret, token)) 461 assert.False(CompareMigrateToken("x", nodeSecret, token)) 462 assert.False(CompareMigrateToken(allocID, "x", token)) 463 assert.False(CompareMigrateToken(allocID, nodeSecret, "x")) 464 465 token2, err := GenerateMigrateToken("x", nodeSecret) 466 assert.Nil(err) 467 assert.False(CompareMigrateToken(allocID, nodeSecret, token2)) 468 assert.True(CompareMigrateToken("x", nodeSecret, token2)) 469 }