github.com/zoomfoo/nomad@v0.8.5-0.20180907175415-f28fd3a1a056/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 TestScoreFit(t *testing.T) { 220 node := &Node{} 221 node.Resources = &Resources{ 222 CPU: 4096, 223 MemoryMB: 8192, 224 } 225 node.Reserved = &Resources{ 226 CPU: 2048, 227 MemoryMB: 4096, 228 } 229 230 // Test a perfect fit 231 util := &Resources{ 232 CPU: 2048, 233 MemoryMB: 4096, 234 } 235 score := ScoreFit(node, util) 236 if score != 18.0 { 237 t.Fatalf("bad: %v", score) 238 } 239 240 // Test the worst fit 241 util = &Resources{ 242 CPU: 0, 243 MemoryMB: 0, 244 } 245 score = ScoreFit(node, util) 246 if score != 0.0 { 247 t.Fatalf("bad: %v", score) 248 } 249 250 // Test a mid-case scenario 251 util = &Resources{ 252 CPU: 1024, 253 MemoryMB: 2048, 254 } 255 score = ScoreFit(node, util) 256 if score < 10.0 || score > 16.0 { 257 t.Fatalf("bad: %v", score) 258 } 259 } 260 261 func TestACLPolicyListHash(t *testing.T) { 262 h1 := ACLPolicyListHash(nil) 263 assert.NotEqual(t, "", h1) 264 265 p1 := &ACLPolicy{ 266 Name: fmt.Sprintf("policy-%s", uuid.Generate()), 267 Description: "Super cool policy!", 268 Rules: ` 269 namespace "default" { 270 policy = "write" 271 } 272 node { 273 policy = "read" 274 } 275 agent { 276 policy = "read" 277 } 278 `, 279 CreateIndex: 10, 280 ModifyIndex: 20, 281 } 282 283 h2 := ACLPolicyListHash([]*ACLPolicy{p1}) 284 assert.NotEqual(t, "", h2) 285 assert.NotEqual(t, h1, h2) 286 287 // Create P2 as copy of P1 with new name 288 p2 := &ACLPolicy{} 289 *p2 = *p1 290 p2.Name = fmt.Sprintf("policy-%s", uuid.Generate()) 291 292 h3 := ACLPolicyListHash([]*ACLPolicy{p1, p2}) 293 assert.NotEqual(t, "", h3) 294 assert.NotEqual(t, h2, h3) 295 296 h4 := ACLPolicyListHash([]*ACLPolicy{p2}) 297 assert.NotEqual(t, "", h4) 298 assert.NotEqual(t, h3, h4) 299 300 // ModifyIndex should change the hash 301 p2.ModifyIndex++ 302 h5 := ACLPolicyListHash([]*ACLPolicy{p2}) 303 assert.NotEqual(t, "", h5) 304 assert.NotEqual(t, h4, h5) 305 } 306 307 func TestCompileACLObject(t *testing.T) { 308 p1 := &ACLPolicy{ 309 Name: fmt.Sprintf("policy-%s", uuid.Generate()), 310 Description: "Super cool policy!", 311 Rules: ` 312 namespace "default" { 313 policy = "write" 314 } 315 node { 316 policy = "read" 317 } 318 agent { 319 policy = "read" 320 } 321 `, 322 CreateIndex: 10, 323 ModifyIndex: 20, 324 } 325 326 // Create P2 as copy of P1 with new name 327 p2 := &ACLPolicy{} 328 *p2 = *p1 329 p2.Name = fmt.Sprintf("policy-%s", uuid.Generate()) 330 331 // Create a small cache 332 cache, err := lru.New2Q(16) 333 assert.Nil(t, err) 334 335 // Test compilation 336 aclObj, err := CompileACLObject(cache, []*ACLPolicy{p1}) 337 assert.Nil(t, err) 338 assert.NotNil(t, aclObj) 339 340 // Should get the same object 341 aclObj2, err := CompileACLObject(cache, []*ACLPolicy{p1}) 342 assert.Nil(t, err) 343 if aclObj != aclObj2 { 344 t.Fatalf("expected the same object") 345 } 346 347 // Should get another object 348 aclObj3, err := CompileACLObject(cache, []*ACLPolicy{p1, p2}) 349 assert.Nil(t, err) 350 assert.NotNil(t, aclObj3) 351 if aclObj == aclObj3 { 352 t.Fatalf("unexpected same object") 353 } 354 355 // Should be order independent 356 aclObj4, err := CompileACLObject(cache, []*ACLPolicy{p2, p1}) 357 assert.Nil(t, err) 358 assert.NotNil(t, aclObj4) 359 if aclObj3 != aclObj4 { 360 t.Fatalf("expected same object") 361 } 362 } 363 364 // TestGenerateMigrateToken asserts the migrate token is valid for use in HTTP 365 // headers and CompareMigrateToken works as expected. 366 func TestGenerateMigrateToken(t *testing.T) { 367 assert := assert.New(t) 368 allocID := uuid.Generate() 369 nodeSecret := uuid.Generate() 370 token, err := GenerateMigrateToken(allocID, nodeSecret) 371 assert.Nil(err) 372 _, err = base64.URLEncoding.DecodeString(token) 373 assert.Nil(err) 374 375 assert.True(CompareMigrateToken(allocID, nodeSecret, token)) 376 assert.False(CompareMigrateToken("x", nodeSecret, token)) 377 assert.False(CompareMigrateToken(allocID, "x", token)) 378 assert.False(CompareMigrateToken(allocID, nodeSecret, "x")) 379 380 token2, err := GenerateMigrateToken("x", nodeSecret) 381 assert.Nil(err) 382 assert.False(CompareMigrateToken(allocID, nodeSecret, token2)) 383 assert.True(CompareMigrateToken("x", nodeSecret, token2)) 384 }