package structs import ( "reflect" "testing" "github.com/hashicorp/nomad/helper/uuid" ) func testNode() *Node { return &Node{ ID: uuid.Generate(), Datacenter: "dc1", Name: "foobar", Attributes: map[string]string{ "kernel.name": "linux", "arch": "x86", "version": "0.1.0", "driver.exec": "1", }, Resources: &Resources{ CPU: 4000, MemoryMB: 8192, DiskMB: 100 * 1024, IOPS: 150, Networks: []*NetworkResource{ { Device: "eth0", CIDR: "192.168.0.100/32", MBits: 1000, }, }, }, Links: map[string]string{ "consul": "foobar.dc1", }, Meta: map[string]string{ "pci-dss": "true", }, NodeClass: "linux-medium-pci", Status: NodeStatusReady, } } func TestNode_ComputedClass(t *testing.T) { // Create a node and gets it computed class n := testNode() if err := n.ComputeClass(); err != nil { t.Fatalf("ComputeClass() failed: %v", err) } if n.ComputedClass == "" { t.Fatal("ComputeClass() didn't set computed class") } old := n.ComputedClass // Compute again to ensure determinism if err := n.ComputeClass(); err != nil { t.Fatalf("ComputeClass() failed: %v", err) } if old != n.ComputedClass { t.Fatalf("ComputeClass() should have returned same class; got %v; want %v", n.ComputedClass, old) } // Modify a field and compute the class again. n.Datacenter = "New DC" if err := n.ComputeClass(); err != nil { t.Fatalf("ComputeClass() failed: %v", err) } if n.ComputedClass == "" { t.Fatal("ComputeClass() didn't set computed class") } if old == n.ComputedClass { t.Fatal("ComputeClass() returned same computed class") } } func TestNode_ComputedClass_Ignore(t *testing.T) { // Create a node and gets it computed class n := testNode() if err := n.ComputeClass(); err != nil { t.Fatalf("ComputeClass() failed: %v", err) } if n.ComputedClass == "" { t.Fatal("ComputeClass() didn't set computed class") } old := n.ComputedClass // Modify an ignored field and compute the class again. n.ID = "New ID" if err := n.ComputeClass(); err != nil { t.Fatalf("ComputeClass() failed: %v", err) } if n.ComputedClass == "" { t.Fatal("ComputeClass() didn't set computed class") } if old != n.ComputedClass { t.Fatal("ComputeClass() should have ignored field") } } func TestNode_ComputedClass_Attr(t *testing.T) { // Create a node and gets it computed class n := testNode() if err := n.ComputeClass(); err != nil { t.Fatalf("ComputeClass() failed: %v", err) } if n.ComputedClass == "" { t.Fatal("ComputeClass() didn't set computed class") } old := n.ComputedClass // Add a unique addr and compute the class again n.Attributes["unique.foo"] = "bar" if err := n.ComputeClass(); err != nil { t.Fatalf("ComputeClass() failed: %v", err) } if old != n.ComputedClass { t.Fatal("ComputeClass() didn't ignore unique attr suffix") } // Modify an attribute and compute the class again. n.Attributes["version"] = "New Version" if err := n.ComputeClass(); err != nil { t.Fatalf("ComputeClass() failed: %v", err) } if n.ComputedClass == "" { t.Fatal("ComputeClass() didn't set computed class") } if old == n.ComputedClass { t.Fatal("ComputeClass() ignored attribute change") } // Remove and attribute and compute the class again. old = n.ComputedClass delete(n.Attributes, "driver.exec") if err := n.ComputeClass(); err != nil { t.Fatalf("ComputedClass() failed: %v", err) } if n.ComputedClass == "" { t.Fatal("ComputeClass() didn't set computed class") } if old == n.ComputedClass { t.Fatalf("ComputedClass() ignored removal of attribute key") } } func TestNode_ComputedClass_Meta(t *testing.T) { // Create a node and gets it computed class n := testNode() if err := n.ComputeClass(); err != nil { t.Fatalf("ComputeClass() failed: %v", err) } if n.ComputedClass == "" { t.Fatal("ComputeClass() didn't set computed class") } old := n.ComputedClass // Modify a meta key and compute the class again. n.Meta["pci-dss"] = "false" if err := n.ComputeClass(); err != nil { t.Fatalf("ComputeClass() failed: %v", err) } if n.ComputedClass == "" { t.Fatal("ComputeClass() didn't set computed class") } if old == n.ComputedClass { t.Fatal("ComputeClass() ignored meta change") } old = n.ComputedClass // Add a unique meta key and compute the class again. n.Meta["unique.foo"] = "ignore" if err := n.ComputeClass(); err != nil { t.Fatalf("ComputeClass() failed: %v", err) } if n.ComputedClass == "" { t.Fatal("ComputeClass() didn't set computed class") } if old != n.ComputedClass { t.Fatal("ComputeClass() didn't ignore unique meta key") } } func TestNode_EscapedConstraints(t *testing.T) { // Non-escaped constraints ne1 := &Constraint{ LTarget: "${attr.kernel.name}", RTarget: "linux", Operand: "=", } ne2 := &Constraint{ LTarget: "${meta.key_foo}", RTarget: "linux", Operand: "<", } ne3 := &Constraint{ LTarget: "${node.dc}", RTarget: "test", Operand: "!=", } // Escaped constraints e1 := &Constraint{ LTarget: "${attr.unique.kernel.name}", RTarget: "linux", Operand: "=", } e2 := &Constraint{ LTarget: "${meta.unique.key_foo}", RTarget: "linux", Operand: "<", } e3 := &Constraint{ LTarget: "${unique.node.id}", RTarget: "test", Operand: "!=", } constraints := []*Constraint{ne1, ne2, ne3, e1, e2, e3} expected := []*Constraint{ne1, ne2, ne3} if act := EscapedConstraints(constraints); reflect.DeepEqual(act, expected) { t.Fatalf("EscapedConstraints(%v) returned %v; want %v", constraints, act, expected) } }