open-nomad/nomad/structs/structs_test.go

491 lines
10 KiB
Go
Raw Normal View History

2015-06-05 22:21:17 +00:00
package structs
import (
"github.com/hashicorp/go-multierror"
2015-06-05 22:21:17 +00:00
"reflect"
2015-09-15 18:23:03 +00:00
"strings"
2015-06-05 22:21:17 +00:00
"testing"
"time"
2015-06-05 22:21:17 +00:00
)
2015-09-15 18:23:03 +00:00
func TestJob_Validate(t *testing.T) {
j := &Job{}
err := j.Validate()
mErr := err.(*multierror.Error)
if !strings.Contains(mErr.Errors[0].Error(), "job region") {
t.Fatalf("err: %s", err)
}
if !strings.Contains(mErr.Errors[1].Error(), "job ID") {
t.Fatalf("err: %s", err)
}
if !strings.Contains(mErr.Errors[2].Error(), "job name") {
t.Fatalf("err: %s", err)
}
if !strings.Contains(mErr.Errors[3].Error(), "job type") {
t.Fatalf("err: %s", err)
}
if !strings.Contains(mErr.Errors[4].Error(), "priority") {
t.Fatalf("err: %s", err)
}
if !strings.Contains(mErr.Errors[5].Error(), "datacenters") {
t.Fatalf("err: %s", err)
}
if !strings.Contains(mErr.Errors[6].Error(), "task groups") {
t.Fatalf("err: %s", err)
}
j = &Job{
Region: "global",
ID: GenerateUUID(),
Name: "my-job",
Type: JobTypeService,
Priority: 50,
Datacenters: []string{"dc1"},
TaskGroups: []*TaskGroup{
&TaskGroup{
Name: "web",
RestartPolicy: &RestartPolicy{
Interval: 5 * time.Minute,
Delay: 10 * time.Second,
Attempts: 10,
},
2015-09-15 18:23:03 +00:00
},
&TaskGroup{
Name: "web",
RestartPolicy: &RestartPolicy{
Interval: 5 * time.Minute,
Delay: 10 * time.Second,
Attempts: 10,
},
},
&TaskGroup{
RestartPolicy: &RestartPolicy{
Interval: 5 * time.Minute,
Delay: 10 * time.Second,
Attempts: 10,
},
2015-09-15 18:23:03 +00:00
},
},
}
err = j.Validate()
mErr = err.(*multierror.Error)
if !strings.Contains(mErr.Errors[0].Error(), "2 redefines 'web' from group 1") {
t.Fatalf("err: %s", err)
}
if !strings.Contains(mErr.Errors[1].Error(), "group 3 missing name") {
t.Fatalf("err: %s", err)
}
if !strings.Contains(mErr.Errors[2].Error(), "Task group 1 validation failed") {
t.Fatalf("err: %s", err)
}
}
func TestTaskGroup_Validate(t *testing.T) {
tg := &TaskGroup{
RestartPolicy: &RestartPolicy{
Interval: 5 * time.Minute,
Delay: 10 * time.Second,
Attempts: 10,
},
}
2015-09-15 18:23:03 +00:00
err := tg.Validate()
mErr := err.(*multierror.Error)
if !strings.Contains(mErr.Errors[0].Error(), "group name") {
t.Fatalf("err: %s", err)
}
if !strings.Contains(mErr.Errors[1].Error(), "count must be positive") {
t.Fatalf("err: %s", err)
}
if !strings.Contains(mErr.Errors[2].Error(), "Missing tasks") {
t.Fatalf("err: %s", err)
}
tg = &TaskGroup{
Name: "web",
Count: 1,
Tasks: []*Task{
&Task{Name: "web"},
&Task{Name: "web"},
&Task{},
},
RestartPolicy: &RestartPolicy{
Interval: 5 * time.Minute,
Delay: 10 * time.Second,
Attempts: 10,
},
2015-09-15 18:23:03 +00:00
}
err = tg.Validate()
mErr = err.(*multierror.Error)
if !strings.Contains(mErr.Errors[0].Error(), "2 redefines 'web' from task 1") {
t.Fatalf("err: %s", err)
}
if !strings.Contains(mErr.Errors[1].Error(), "Task 3 missing name") {
t.Fatalf("err: %s", err)
}
if !strings.Contains(mErr.Errors[2].Error(), "Task 1 validation failed") {
t.Fatalf("err: %s", err)
}
}
func TestTask_Validate(t *testing.T) {
task := &Task{}
err := task.Validate()
mErr := err.(*multierror.Error)
if !strings.Contains(mErr.Errors[0].Error(), "task name") {
t.Fatalf("err: %s", err)
}
if !strings.Contains(mErr.Errors[1].Error(), "task driver") {
t.Fatalf("err: %s", err)
}
if !strings.Contains(mErr.Errors[2].Error(), "task resources") {
t.Fatalf("err: %s", err)
}
task = &Task{
Name: "web",
Driver: "docker",
Resources: &Resources{},
}
err = task.Validate()
if err != nil {
t.Fatalf("err: %s", err)
}
}
func TestConstraint_Validate(t *testing.T) {
c := &Constraint{}
err := c.Validate()
mErr := err.(*multierror.Error)
if !strings.Contains(mErr.Errors[0].Error(), "Missing constraint operand") {
t.Fatalf("err: %s", err)
}
c = &Constraint{
LTarget: "$attr.kernel.name",
RTarget: "linux",
Operand: "=",
}
err = c.Validate()
if err != nil {
t.Fatalf("err: %v", err)
}
// Perform additional regexp validation
c.Operand = ConstraintRegex
c.RTarget = "(foo"
err = c.Validate()
mErr = err.(*multierror.Error)
if !strings.Contains(mErr.Errors[0].Error(), "missing closing") {
t.Fatalf("err: %s", err)
}
// Perform version validation
c.Operand = ConstraintVersion
c.RTarget = "~> foo"
err = c.Validate()
mErr = err.(*multierror.Error)
if !strings.Contains(mErr.Errors[0].Error(), "Malformed constraint") {
t.Fatalf("err: %s", err)
}
}
func TestResource_NetIndex(t *testing.T) {
2015-08-05 00:23:42 +00:00
r := &Resources{
Networks: []*NetworkResource{
&NetworkResource{Device: "eth0"},
&NetworkResource{Device: "lo0"},
&NetworkResource{Device: ""},
2015-08-05 00:23:42 +00:00
},
}
if idx := r.NetIndex(&NetworkResource{Device: "eth0"}); idx != 0 {
2015-08-05 00:23:42 +00:00
t.Fatalf("Bad: %d", idx)
}
if idx := r.NetIndex(&NetworkResource{Device: "lo0"}); idx != 1 {
2015-08-05 00:23:42 +00:00
t.Fatalf("Bad: %d", idx)
}
if idx := r.NetIndex(&NetworkResource{Device: "eth1"}); idx != -1 {
2015-09-12 23:21:57 +00:00
t.Fatalf("Bad: %d", idx)
}
}
2015-08-05 00:32:57 +00:00
func TestResource_Superset(t *testing.T) {
r1 := &Resources{
2015-09-23 18:14:32 +00:00
CPU: 2000,
2015-08-05 00:32:57 +00:00
MemoryMB: 2048,
DiskMB: 10000,
IOPS: 100,
}
r2 := &Resources{
2015-09-23 18:14:32 +00:00
CPU: 2000,
2015-08-05 00:32:57 +00:00
MemoryMB: 1024,
DiskMB: 5000,
IOPS: 50,
}
if s, _ := r1.Superset(r1); !s {
2015-08-05 00:32:57 +00:00
t.Fatalf("bad")
}
if s, _ := r1.Superset(r2); !s {
2015-08-05 00:32:57 +00:00
t.Fatalf("bad")
}
if s, _ := r2.Superset(r1); s {
2015-08-05 00:32:57 +00:00
t.Fatalf("bad")
}
if s, _ := r2.Superset(r2); !s {
2015-08-05 00:32:57 +00:00
t.Fatalf("bad")
}
}
2015-08-05 00:41:02 +00:00
func TestResource_Add(t *testing.T) {
r1 := &Resources{
2015-09-23 18:14:32 +00:00
CPU: 2000,
2015-08-05 00:41:02 +00:00
MemoryMB: 2048,
DiskMB: 10000,
IOPS: 100,
Networks: []*NetworkResource{
&NetworkResource{
CIDR: "10.0.0.0/8",
MBits: 100,
2015-11-15 09:56:21 +00:00
ReservedPorts: []Port{{"ssh", 22}},
2015-08-05 00:41:02 +00:00
},
},
}
r2 := &Resources{
2015-09-23 18:14:32 +00:00
CPU: 2000,
2015-08-05 00:41:02 +00:00
MemoryMB: 1024,
DiskMB: 5000,
IOPS: 50,
Networks: []*NetworkResource{
&NetworkResource{
IP: "10.0.0.1",
2015-08-05 00:41:02 +00:00
MBits: 50,
2015-11-15 09:56:21 +00:00
ReservedPorts: []Port{{"web", 80}},
2015-08-05 00:41:02 +00:00
},
},
}
err := r1.Add(r2)
if err != nil {
t.Fatalf("Err: %v", err)
}
expect := &Resources{
2015-09-23 18:14:32 +00:00
CPU: 3000,
2015-08-05 00:41:02 +00:00
MemoryMB: 3072,
DiskMB: 15000,
IOPS: 150,
Networks: []*NetworkResource{
&NetworkResource{
CIDR: "10.0.0.0/8",
MBits: 150,
2015-11-15 09:56:21 +00:00
ReservedPorts: []Port{{"ssh", 22}, {"web", 80}},
2015-08-05 00:41:02 +00:00
},
},
}
if !reflect.DeepEqual(expect.Networks, r1.Networks) {
t.Fatalf("bad: %#v %#v", expect, r1)
}
}
func TestResource_Add_Network(t *testing.T) {
r1 := &Resources{}
r2 := &Resources{
Networks: []*NetworkResource{
&NetworkResource{
MBits: 50,
2015-11-15 09:56:21 +00:00
DynamicPorts: []Port{{"http", 0}, {"https", 0}},
},
},
}
r3 := &Resources{
Networks: []*NetworkResource{
&NetworkResource{
MBits: 25,
2015-11-15 09:56:21 +00:00
DynamicPorts: []Port{{"admin", 0}},
},
},
}
err := r1.Add(r2)
if err != nil {
t.Fatalf("Err: %v", err)
}
err = r1.Add(r3)
if err != nil {
t.Fatalf("Err: %v", err)
}
expect := &Resources{
Networks: []*NetworkResource{
&NetworkResource{
MBits: 75,
2015-11-15 09:56:21 +00:00
DynamicPorts: []Port{{"http", 0}, {"https", 0}, {"admin", 0}},
},
},
}
if !reflect.DeepEqual(expect.Networks, r1.Networks) {
t.Fatalf("bad: %#v %#v", expect.Networks[0], r1.Networks[0])
}
}
2015-06-05 22:21:17 +00:00
func TestEncodeDecode(t *testing.T) {
type FooRequest struct {
Foo string
Bar int
Baz bool
}
arg := &FooRequest{
Foo: "test",
Bar: 42,
Baz: true,
}
buf, err := Encode(1, arg)
if err != nil {
t.Fatalf("err: %v", err)
}
var out FooRequest
err = Decode(buf[1:], &out)
if err != nil {
t.Fatalf("err: %v", err)
}
if !reflect.DeepEqual(arg, &out) {
t.Fatalf("bad: %#v %#v", arg, out)
}
}
2015-11-17 21:36:59 +00:00
func TestInvalidServiceCheck(t *testing.T) {
s := Service{
Id: "service-id",
Name: "service-name",
PortLabel: "bar",
2015-11-26 20:40:42 +00:00
Checks: []*ServiceCheck{
2015-11-17 21:36:59 +00:00
{
Id: "check-id",
Name: "check-name",
Type: "lol",
},
},
}
if err := s.Validate(); err == nil {
t.Fatalf("Service should be invalid")
}
}
2015-11-21 20:34:01 +00:00
func TestDistinctCheckId(t *testing.T) {
c1 := ServiceCheck{
Name: "web-health",
Type: "http",
Path: "/health",
Interval: 2 * time.Second,
Timeout: 3 * time.Second,
}
c2 := ServiceCheck{
Name: "web-health",
Type: "http",
Path: "/health1",
Interval: 2 * time.Second,
Timeout: 3 * time.Second,
}
c3 := ServiceCheck{
Name: "web-health",
Type: "http",
Path: "/health",
Interval: 4 * time.Second,
Timeout: 3 * time.Second,
}
2015-11-26 20:40:42 +00:00
serviceId := "123"
2015-11-26 21:47:02 +00:00
c1Hash := c1.Hash(serviceId)
c2Hash := c2.Hash(serviceId)
c3Hash := c3.Hash(serviceId)
2015-11-21 20:34:01 +00:00
2015-11-26 21:47:02 +00:00
if c1Hash == c2Hash || c1Hash == c3Hash || c3Hash == c2Hash {
t.Fatalf("Checks need to be uniq c1: %s, c2: %s, c3: %s", c1Hash, c2Hash, c3Hash)
2015-11-21 20:34:01 +00:00
}
}
func TestService_Expand_Name(t *testing.T) {
job := "example"
taskGroup := "cache"
task := "redis"
s := Service{
Name: "${TASK}-db",
}
s.ExpandName(job, taskGroup, task)
if s.Name != "redis-db" {
t.Fatalf("Expected name: %v, Actual: %v", "redis-db", s.Name)
}
s.Name = "db"
s.ExpandName(job, taskGroup, task)
if s.Name != "db" {
t.Fatalf("Expected name: %v, Actual: %v", "redis-db", s.Name)
}
s.Name = "${JOB}-${TASKGROUP}-${TASK}-db"
s.ExpandName(job, taskGroup, task)
if s.Name != "example-cache-redis-db" {
t.Fatalf("Expected name: %v, Actual: %v", "expample-cache-redis-db", s.Name)
}
s.Name = "${BASE}-db"
s.ExpandName(job, taskGroup, task)
if s.Name != "example-cache-redis-db" {
t.Fatalf("Expected name: %v, Actual: %v", "expample-cache-redis-db", s.Name)
}
}
func TestJob_ExpandServiceNames(t *testing.T) {
j := &Job{
Name: "my-job",
TaskGroups: []*TaskGroup{
&TaskGroup{
Name: "web",
Tasks: []*Task{
{
Name: "frontend",
Services: []*Service{
{
Name: "${BASE}-default",
},
{
Name: "jmx",
},
},
},
},
},
&TaskGroup{
Name: "admin",
Tasks: []*Task{
{
Name: "admin-web",
},
},
},
},
}
j.ExpandAllServiceNames()
service1Name := j.TaskGroups[0].Tasks[0].Services[0].Name
if service1Name != "my-job-web-frontend-default" {
t.Fatalf("Expected Service Name: %s, Actual: %s", "my-job-web-frontend-default", service1Name)
}
service2Name := j.TaskGroups[0].Tasks[0].Services[1].Name
if service2Name != "jmx" {
t.Fatalf("Expected Service Name: %s, Actual: %s", "jmx", service2Name)
}
}