github.com/huiliang/nomad@v0.2.1-0.20151124023127-7a8b664699ff/nomad/structs/structs_test.go (about) 1 package structs 2 3 import ( 4 "github.com/hashicorp/go-multierror" 5 "reflect" 6 "strings" 7 "testing" 8 "time" 9 ) 10 11 func TestJob_Validate(t *testing.T) { 12 j := &Job{} 13 err := j.Validate() 14 mErr := err.(*multierror.Error) 15 if !strings.Contains(mErr.Errors[0].Error(), "job region") { 16 t.Fatalf("err: %s", err) 17 } 18 if !strings.Contains(mErr.Errors[1].Error(), "job ID") { 19 t.Fatalf("err: %s", err) 20 } 21 if !strings.Contains(mErr.Errors[2].Error(), "job name") { 22 t.Fatalf("err: %s", err) 23 } 24 if !strings.Contains(mErr.Errors[3].Error(), "job type") { 25 t.Fatalf("err: %s", err) 26 } 27 if !strings.Contains(mErr.Errors[4].Error(), "priority") { 28 t.Fatalf("err: %s", err) 29 } 30 if !strings.Contains(mErr.Errors[5].Error(), "datacenters") { 31 t.Fatalf("err: %s", err) 32 } 33 if !strings.Contains(mErr.Errors[6].Error(), "task groups") { 34 t.Fatalf("err: %s", err) 35 } 36 37 j = &Job{ 38 Region: "global", 39 ID: GenerateUUID(), 40 Name: "my-job", 41 Type: JobTypeService, 42 Priority: 50, 43 Datacenters: []string{"dc1"}, 44 TaskGroups: []*TaskGroup{ 45 &TaskGroup{ 46 Name: "web", 47 RestartPolicy: &RestartPolicy{ 48 Interval: 5 * time.Minute, 49 Delay: 10 * time.Second, 50 Attempts: 10, 51 }, 52 }, 53 &TaskGroup{ 54 Name: "web", 55 RestartPolicy: &RestartPolicy{ 56 Interval: 5 * time.Minute, 57 Delay: 10 * time.Second, 58 Attempts: 10, 59 }, 60 }, 61 &TaskGroup{ 62 RestartPolicy: &RestartPolicy{ 63 Interval: 5 * time.Minute, 64 Delay: 10 * time.Second, 65 Attempts: 10, 66 }, 67 }, 68 }, 69 } 70 err = j.Validate() 71 mErr = err.(*multierror.Error) 72 if !strings.Contains(mErr.Errors[0].Error(), "2 redefines 'web' from group 1") { 73 t.Fatalf("err: %s", err) 74 } 75 if !strings.Contains(mErr.Errors[1].Error(), "group 3 missing name") { 76 t.Fatalf("err: %s", err) 77 } 78 if !strings.Contains(mErr.Errors[2].Error(), "Task group 1 validation failed") { 79 t.Fatalf("err: %s", err) 80 } 81 } 82 83 func TestTaskGroup_Validate(t *testing.T) { 84 tg := &TaskGroup{ 85 RestartPolicy: &RestartPolicy{ 86 Interval: 5 * time.Minute, 87 Delay: 10 * time.Second, 88 Attempts: 10, 89 }, 90 } 91 err := tg.Validate() 92 mErr := err.(*multierror.Error) 93 if !strings.Contains(mErr.Errors[0].Error(), "group name") { 94 t.Fatalf("err: %s", err) 95 } 96 if !strings.Contains(mErr.Errors[1].Error(), "count must be positive") { 97 t.Fatalf("err: %s", err) 98 } 99 if !strings.Contains(mErr.Errors[2].Error(), "Missing tasks") { 100 t.Fatalf("err: %s", err) 101 } 102 103 tg = &TaskGroup{ 104 Name: "web", 105 Count: 1, 106 Tasks: []*Task{ 107 &Task{Name: "web"}, 108 &Task{Name: "web"}, 109 &Task{}, 110 }, 111 RestartPolicy: &RestartPolicy{ 112 Interval: 5 * time.Minute, 113 Delay: 10 * time.Second, 114 Attempts: 10, 115 }, 116 } 117 err = tg.Validate() 118 mErr = err.(*multierror.Error) 119 if !strings.Contains(mErr.Errors[0].Error(), "2 redefines 'web' from task 1") { 120 t.Fatalf("err: %s", err) 121 } 122 if !strings.Contains(mErr.Errors[1].Error(), "Task 3 missing name") { 123 t.Fatalf("err: %s", err) 124 } 125 if !strings.Contains(mErr.Errors[2].Error(), "Task 1 validation failed") { 126 t.Fatalf("err: %s", err) 127 } 128 } 129 130 func TestTask_Validate(t *testing.T) { 131 task := &Task{} 132 err := task.Validate() 133 mErr := err.(*multierror.Error) 134 if !strings.Contains(mErr.Errors[0].Error(), "task name") { 135 t.Fatalf("err: %s", err) 136 } 137 if !strings.Contains(mErr.Errors[1].Error(), "task driver") { 138 t.Fatalf("err: %s", err) 139 } 140 if !strings.Contains(mErr.Errors[2].Error(), "task resources") { 141 t.Fatalf("err: %s", err) 142 } 143 144 task = &Task{ 145 Name: "web", 146 Driver: "docker", 147 Resources: &Resources{}, 148 } 149 err = task.Validate() 150 if err != nil { 151 t.Fatalf("err: %s", err) 152 } 153 } 154 155 func TestConstraint_Validate(t *testing.T) { 156 c := &Constraint{} 157 err := c.Validate() 158 mErr := err.(*multierror.Error) 159 if !strings.Contains(mErr.Errors[0].Error(), "Missing constraint operand") { 160 t.Fatalf("err: %s", err) 161 } 162 163 c = &Constraint{ 164 LTarget: "$attr.kernel.name", 165 RTarget: "linux", 166 Operand: "=", 167 } 168 err = c.Validate() 169 if err != nil { 170 t.Fatalf("err: %v", err) 171 } 172 173 // Perform additional regexp validation 174 c.Operand = ConstraintRegex 175 c.RTarget = "(foo" 176 err = c.Validate() 177 mErr = err.(*multierror.Error) 178 if !strings.Contains(mErr.Errors[0].Error(), "missing closing") { 179 t.Fatalf("err: %s", err) 180 } 181 182 // Perform version validation 183 c.Operand = ConstraintVersion 184 c.RTarget = "~> foo" 185 err = c.Validate() 186 mErr = err.(*multierror.Error) 187 if !strings.Contains(mErr.Errors[0].Error(), "Malformed constraint") { 188 t.Fatalf("err: %s", err) 189 } 190 } 191 192 func TestResource_NetIndex(t *testing.T) { 193 r := &Resources{ 194 Networks: []*NetworkResource{ 195 &NetworkResource{Device: "eth0"}, 196 &NetworkResource{Device: "lo0"}, 197 &NetworkResource{Device: ""}, 198 }, 199 } 200 if idx := r.NetIndex(&NetworkResource{Device: "eth0"}); idx != 0 { 201 t.Fatalf("Bad: %d", idx) 202 } 203 if idx := r.NetIndex(&NetworkResource{Device: "lo0"}); idx != 1 { 204 t.Fatalf("Bad: %d", idx) 205 } 206 if idx := r.NetIndex(&NetworkResource{Device: "eth1"}); idx != -1 { 207 t.Fatalf("Bad: %d", idx) 208 } 209 } 210 211 func TestResource_Superset(t *testing.T) { 212 r1 := &Resources{ 213 CPU: 2000, 214 MemoryMB: 2048, 215 DiskMB: 10000, 216 IOPS: 100, 217 } 218 r2 := &Resources{ 219 CPU: 2000, 220 MemoryMB: 1024, 221 DiskMB: 5000, 222 IOPS: 50, 223 } 224 225 if s, _ := r1.Superset(r1); !s { 226 t.Fatalf("bad") 227 } 228 if s, _ := r1.Superset(r2); !s { 229 t.Fatalf("bad") 230 } 231 if s, _ := r2.Superset(r1); s { 232 t.Fatalf("bad") 233 } 234 if s, _ := r2.Superset(r2); !s { 235 t.Fatalf("bad") 236 } 237 } 238 239 func TestResource_Add(t *testing.T) { 240 r1 := &Resources{ 241 CPU: 2000, 242 MemoryMB: 2048, 243 DiskMB: 10000, 244 IOPS: 100, 245 Networks: []*NetworkResource{ 246 &NetworkResource{ 247 CIDR: "10.0.0.0/8", 248 MBits: 100, 249 ReservedPorts: []Port{{"ssh", 22}}, 250 }, 251 }, 252 } 253 r2 := &Resources{ 254 CPU: 2000, 255 MemoryMB: 1024, 256 DiskMB: 5000, 257 IOPS: 50, 258 Networks: []*NetworkResource{ 259 &NetworkResource{ 260 IP: "10.0.0.1", 261 MBits: 50, 262 ReservedPorts: []Port{{"web", 80}}, 263 }, 264 }, 265 } 266 267 err := r1.Add(r2) 268 if err != nil { 269 t.Fatalf("Err: %v", err) 270 } 271 272 expect := &Resources{ 273 CPU: 3000, 274 MemoryMB: 3072, 275 DiskMB: 15000, 276 IOPS: 150, 277 Networks: []*NetworkResource{ 278 &NetworkResource{ 279 CIDR: "10.0.0.0/8", 280 MBits: 150, 281 ReservedPorts: []Port{{"ssh", 22}, {"web", 80}}, 282 }, 283 }, 284 } 285 286 if !reflect.DeepEqual(expect.Networks, r1.Networks) { 287 t.Fatalf("bad: %#v %#v", expect, r1) 288 } 289 } 290 291 func TestResource_Add_Network(t *testing.T) { 292 r1 := &Resources{} 293 r2 := &Resources{ 294 Networks: []*NetworkResource{ 295 &NetworkResource{ 296 MBits: 50, 297 DynamicPorts: []Port{{"http", 0}, {"https", 0}}, 298 }, 299 }, 300 } 301 r3 := &Resources{ 302 Networks: []*NetworkResource{ 303 &NetworkResource{ 304 MBits: 25, 305 DynamicPorts: []Port{{"admin", 0}}, 306 }, 307 }, 308 } 309 310 err := r1.Add(r2) 311 if err != nil { 312 t.Fatalf("Err: %v", err) 313 } 314 err = r1.Add(r3) 315 if err != nil { 316 t.Fatalf("Err: %v", err) 317 } 318 319 expect := &Resources{ 320 Networks: []*NetworkResource{ 321 &NetworkResource{ 322 MBits: 75, 323 DynamicPorts: []Port{{"http", 0}, {"https", 0}, {"admin", 0}}, 324 }, 325 }, 326 } 327 328 if !reflect.DeepEqual(expect.Networks, r1.Networks) { 329 t.Fatalf("bad: %#v %#v", expect.Networks[0], r1.Networks[0]) 330 } 331 } 332 333 func TestEncodeDecode(t *testing.T) { 334 type FooRequest struct { 335 Foo string 336 Bar int 337 Baz bool 338 } 339 arg := &FooRequest{ 340 Foo: "test", 341 Bar: 42, 342 Baz: true, 343 } 344 buf, err := Encode(1, arg) 345 if err != nil { 346 t.Fatalf("err: %v", err) 347 } 348 349 var out FooRequest 350 err = Decode(buf[1:], &out) 351 if err != nil { 352 t.Fatalf("err: %v", err) 353 } 354 355 if !reflect.DeepEqual(arg, &out) { 356 t.Fatalf("bad: %#v %#v", arg, out) 357 } 358 } 359 360 func TestInvalidServiceCheck(t *testing.T) { 361 s := Service{ 362 Id: "service-id", 363 Name: "service-name", 364 PortLabel: "bar", 365 Checks: []ServiceCheck{ 366 { 367 368 Id: "check-id", 369 Name: "check-name", 370 Type: "lol", 371 }, 372 }, 373 } 374 if err := s.Validate(); err == nil { 375 t.Fatalf("Service should be invalid") 376 } 377 }