github.com/emate/nomad@v0.8.2-wo-binpacking/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  }