github.com/uchennaokeke444/nomad@v0.11.8/nomad/structs/services_test.go (about)

     1  package structs
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	"github.com/hashicorp/nomad/helper"
     8  	"github.com/stretchr/testify/require"
     9  )
    10  
    11  func TestService_Hash(t *testing.T) {
    12  	t.Parallel()
    13  
    14  	original := &Service{
    15  		Name:      "myService",
    16  		PortLabel: "portLabel",
    17  		// AddressMode: "bridge", // not hashed (used internally by Nomad)
    18  		Tags:       []string{"original", "tags"},
    19  		CanaryTags: []string{"canary", "tags"},
    20  		// Checks:      nil, // not hashed (managed independently)
    21  		Connect: &ConsulConnect{
    22  			// Native: false, // not hashed
    23  			SidecarService: &ConsulSidecarService{
    24  				Tags: []string{"original", "sidecar", "tags"},
    25  				Port: "9000",
    26  				Proxy: &ConsulProxy{
    27  					LocalServiceAddress: "127.0.0.1",
    28  					LocalServicePort:    24000,
    29  					Config:              map[string]interface{}{"foo": "bar"},
    30  					Upstreams: []ConsulUpstream{{
    31  						DestinationName: "upstream1",
    32  						LocalBindPort:   29000,
    33  					}},
    34  				},
    35  			},
    36  			// SidecarTask: nil // not hashed
    37  		}}
    38  
    39  	type svc = Service
    40  	type tweaker = func(service *svc)
    41  
    42  	hash := func(s *svc, canary bool) string {
    43  		return s.Hash("AllocID", "TaskName", canary)
    44  	}
    45  
    46  	t.Run("matching and is canary", func(t *testing.T) {
    47  		require.Equal(t, hash(original, true), hash(original, true))
    48  	})
    49  
    50  	t.Run("matching and is not canary", func(t *testing.T) {
    51  		require.Equal(t, hash(original, false), hash(original, false))
    52  	})
    53  
    54  	t.Run("matching mod canary", func(t *testing.T) {
    55  		require.NotEqual(t, hash(original, true), hash(original, false))
    56  	})
    57  
    58  	try := func(t *testing.T, tweak tweaker) {
    59  		originalHash := hash(original, true)
    60  		modifiable := original.Copy()
    61  		tweak(modifiable)
    62  		tweakedHash := hash(modifiable, true)
    63  		require.NotEqual(t, originalHash, tweakedHash)
    64  	}
    65  
    66  	// these tests use tweaker to modify 1 field and make the false assertion
    67  	// on comparing the resulting hash output
    68  
    69  	t.Run("mod name", func(t *testing.T) {
    70  		try(t, func(s *svc) { s.Name = "newName" })
    71  	})
    72  
    73  	t.Run("mod port label", func(t *testing.T) {
    74  		try(t, func(s *svc) { s.PortLabel = "newPortLabel" })
    75  	})
    76  
    77  	t.Run("mod tags", func(t *testing.T) {
    78  		try(t, func(s *svc) { s.Tags = []string{"new", "tags"} })
    79  	})
    80  
    81  	t.Run("mod canary tags", func(t *testing.T) {
    82  		try(t, func(s *svc) { s.CanaryTags = []string{"new", "tags"} })
    83  	})
    84  
    85  	t.Run("mod enable tag override", func(t *testing.T) {
    86  		try(t, func(s *svc) { s.EnableTagOverride = true })
    87  	})
    88  
    89  	t.Run("mod connect sidecar tags", func(t *testing.T) {
    90  		try(t, func(s *svc) { s.Connect.SidecarService.Tags = []string{"new", "tags"} })
    91  	})
    92  
    93  	t.Run("mod connect sidecar port", func(t *testing.T) {
    94  		try(t, func(s *svc) { s.Connect.SidecarService.Port = "9090" })
    95  	})
    96  
    97  	t.Run("mod connect sidecar proxy local service address", func(t *testing.T) {
    98  		try(t, func(s *svc) { s.Connect.SidecarService.Proxy.LocalServiceAddress = "1.1.1.1" })
    99  	})
   100  
   101  	t.Run("mod connect sidecar proxy local service port", func(t *testing.T) {
   102  		try(t, func(s *svc) { s.Connect.SidecarService.Proxy.LocalServicePort = 9999 })
   103  	})
   104  
   105  	t.Run("mod connect sidecar proxy config", func(t *testing.T) {
   106  		try(t, func(s *svc) { s.Connect.SidecarService.Proxy.Config = map[string]interface{}{"foo": "baz"} })
   107  	})
   108  
   109  	t.Run("mod connect sidecar proxy upstream dest name", func(t *testing.T) {
   110  		try(t, func(s *svc) { s.Connect.SidecarService.Proxy.Upstreams[0].DestinationName = "dest2" })
   111  	})
   112  
   113  	t.Run("mod connect sidecar proxy upstream dest local bind port", func(t *testing.T) {
   114  		try(t, func(s *svc) { s.Connect.SidecarService.Proxy.Upstreams[0].LocalBindPort = 29999 })
   115  	})
   116  }
   117  
   118  func TestConsulConnect_Validate(t *testing.T) {
   119  	t.Parallel()
   120  
   121  	c := &ConsulConnect{}
   122  
   123  	// An empty Connect stanza is invalid
   124  	require.Error(t, c.Validate())
   125  
   126  	// Native=true is valid
   127  	c.Native = true
   128  	require.NoError(t, c.Validate())
   129  
   130  	// Native=true + Sidecar!=nil is invalid
   131  	c.SidecarService = &ConsulSidecarService{}
   132  	require.Error(t, c.Validate())
   133  
   134  	// Native=false + Sidecar!=nil is valid
   135  	c.Native = false
   136  	require.NoError(t, c.Validate())
   137  }
   138  
   139  func TestConsulConnect_CopyEquals(t *testing.T) {
   140  	t.Parallel()
   141  
   142  	c := &ConsulConnect{
   143  		SidecarService: &ConsulSidecarService{
   144  			Tags: []string{"tag1", "tag2"},
   145  			Port: "9001",
   146  			Proxy: &ConsulProxy{
   147  				LocalServiceAddress: "127.0.0.1",
   148  				LocalServicePort:    8080,
   149  				Upstreams: []ConsulUpstream{
   150  					{
   151  						DestinationName: "up1",
   152  						LocalBindPort:   9002,
   153  					},
   154  					{
   155  						DestinationName: "up2",
   156  						LocalBindPort:   9003,
   157  					},
   158  				},
   159  				Config: map[string]interface{}{
   160  					"foo": 1,
   161  				},
   162  			},
   163  		},
   164  	}
   165  
   166  	require.NoError(t, c.Validate())
   167  
   168  	// Copies should be equivalent
   169  	o := c.Copy()
   170  	require.True(t, c.Equals(o))
   171  
   172  	o.SidecarService.Proxy.Upstreams = nil
   173  	require.False(t, c.Equals(o))
   174  }
   175  
   176  func TestSidecarTask_MergeIntoTask(t *testing.T) {
   177  	t.Parallel()
   178  
   179  	task := MockJob().TaskGroups[0].Tasks[0]
   180  	sTask := &SidecarTask{
   181  		Name:   "sidecar",
   182  		Driver: "sidecar",
   183  		User:   "test",
   184  		Config: map[string]interface{}{
   185  			"foo": "bar",
   186  		},
   187  		Resources: &Resources{
   188  			CPU:      10000,
   189  			MemoryMB: 10000,
   190  		},
   191  		Env: map[string]string{
   192  			"sidecar": "proxy",
   193  		},
   194  		Meta: map[string]string{
   195  			"abc": "123",
   196  		},
   197  		KillTimeout: helper.TimeToPtr(15 * time.Second),
   198  		LogConfig: &LogConfig{
   199  			MaxFiles: 3,
   200  		},
   201  		ShutdownDelay: helper.TimeToPtr(5 * time.Second),
   202  		KillSignal:    "SIGABRT",
   203  	}
   204  
   205  	expected := task.Copy()
   206  	expected.Name = "sidecar"
   207  	expected.Driver = "sidecar"
   208  	expected.User = "test"
   209  	expected.Config = map[string]interface{}{
   210  		"foo": "bar",
   211  	}
   212  	expected.Resources.CPU = 10000
   213  	expected.Resources.MemoryMB = 10000
   214  	expected.Env["sidecar"] = "proxy"
   215  	expected.Meta["abc"] = "123"
   216  	expected.KillTimeout = 15 * time.Second
   217  	expected.LogConfig.MaxFiles = 3
   218  	expected.ShutdownDelay = 5 * time.Second
   219  	expected.KillSignal = "SIGABRT"
   220  
   221  	sTask.MergeIntoTask(task)
   222  	require.Exactly(t, expected, task)
   223  
   224  	// Check that changing just driver config doesn't replace map
   225  	sTask.Config["abc"] = 123
   226  	expected.Config["abc"] = 123
   227  
   228  	sTask.MergeIntoTask(task)
   229  	require.Exactly(t, expected, task)
   230  }
   231  
   232  func TestConsulUpstream_upstreamEquals(t *testing.T) {
   233  	t.Parallel()
   234  
   235  	up := func(name string, port int) ConsulUpstream {
   236  		return ConsulUpstream{
   237  			DestinationName: name,
   238  			LocalBindPort:   port,
   239  		}
   240  	}
   241  
   242  	t.Run("size mismatch", func(t *testing.T) {
   243  		a := []ConsulUpstream{up("foo", 8000)}
   244  		b := []ConsulUpstream{up("foo", 8000), up("bar", 9000)}
   245  		require.False(t, upstreamsEquals(a, b))
   246  	})
   247  
   248  	t.Run("different", func(t *testing.T) {
   249  		a := []ConsulUpstream{up("bar", 9000)}
   250  		b := []ConsulUpstream{up("foo", 8000)}
   251  		require.False(t, upstreamsEquals(a, b))
   252  	})
   253  
   254  	t.Run("identical", func(t *testing.T) {
   255  		a := []ConsulUpstream{up("foo", 8000), up("bar", 9000)}
   256  		b := []ConsulUpstream{up("foo", 8000), up("bar", 9000)}
   257  		require.True(t, upstreamsEquals(a, b))
   258  	})
   259  
   260  	t.Run("unsorted", func(t *testing.T) {
   261  		a := []ConsulUpstream{up("foo", 8000), up("bar", 9000)}
   262  		b := []ConsulUpstream{up("bar", 9000), up("foo", 8000)}
   263  		require.True(t, upstreamsEquals(a, b))
   264  	})
   265  }
   266  
   267  func TestConsulExposePath_exposePathsEqual(t *testing.T) {
   268  	t.Parallel()
   269  
   270  	expose := func(path, protocol, listen string, local int) ConsulExposePath {
   271  		return ConsulExposePath{
   272  			Path:          path,
   273  			Protocol:      protocol,
   274  			LocalPathPort: local,
   275  			ListenerPort:  listen,
   276  		}
   277  	}
   278  
   279  	t.Run("size mismatch", func(t *testing.T) {
   280  		a := []ConsulExposePath{expose("/1", "http", "myPort", 8000)}
   281  		b := []ConsulExposePath{expose("/1", "http", "myPort", 8000), expose("/2", "http", "myPort", 8000)}
   282  		require.False(t, exposePathsEqual(a, b))
   283  	})
   284  
   285  	t.Run("different", func(t *testing.T) {
   286  		a := []ConsulExposePath{expose("/1", "http", "myPort", 8000)}
   287  		b := []ConsulExposePath{expose("/2", "http", "myPort", 8000)}
   288  		require.False(t, exposePathsEqual(a, b))
   289  	})
   290  
   291  	t.Run("identical", func(t *testing.T) {
   292  		a := []ConsulExposePath{expose("/1", "http", "myPort", 8000)}
   293  		b := []ConsulExposePath{expose("/1", "http", "myPort", 8000)}
   294  		require.True(t, exposePathsEqual(a, b))
   295  	})
   296  
   297  	t.Run("unsorted", func(t *testing.T) {
   298  		a := []ConsulExposePath{expose("/2", "http", "myPort", 8000), expose("/1", "http", "myPort", 8000)}
   299  		b := []ConsulExposePath{expose("/1", "http", "myPort", 8000), expose("/2", "http", "myPort", 8000)}
   300  		require.True(t, exposePathsEqual(a, b))
   301  	})
   302  }
   303  
   304  func TestConsulExposeConfig_Copy(t *testing.T) {
   305  	t.Parallel()
   306  
   307  	require.Nil(t, (*ConsulExposeConfig)(nil).Copy())
   308  	require.Equal(t, &ConsulExposeConfig{
   309  		Paths: []ConsulExposePath{{
   310  			Path: "/health",
   311  		}},
   312  	}, (&ConsulExposeConfig{
   313  		Paths: []ConsulExposePath{{
   314  			Path: "/health",
   315  		}},
   316  	}).Copy())
   317  }
   318  
   319  func TestConsulExposeConfig_Equals(t *testing.T) {
   320  	t.Parallel()
   321  
   322  	require.True(t, (*ConsulExposeConfig)(nil).Equals(nil))
   323  	require.True(t, (&ConsulExposeConfig{
   324  		Paths: []ConsulExposePath{{
   325  			Path: "/health",
   326  		}},
   327  	}).Equals(&ConsulExposeConfig{
   328  		Paths: []ConsulExposePath{{
   329  			Path: "/health",
   330  		}},
   331  	}))
   332  }
   333  
   334  func TestConsulSidecarService_Copy(t *testing.T) {
   335  	t.Parallel()
   336  
   337  	t.Run("nil", func(t *testing.T) {
   338  		s := (*ConsulSidecarService)(nil)
   339  		result := s.Copy()
   340  		require.Nil(t, result)
   341  	})
   342  
   343  	t.Run("not nil", func(t *testing.T) {
   344  		s := &ConsulSidecarService{
   345  			Tags:  []string{"foo", "bar"},
   346  			Port:  "port1",
   347  			Proxy: &ConsulProxy{LocalServiceAddress: "10.0.0.1"},
   348  		}
   349  		result := s.Copy()
   350  		require.Equal(t, &ConsulSidecarService{
   351  			Tags:  []string{"foo", "bar"},
   352  			Port:  "port1",
   353  			Proxy: &ConsulProxy{LocalServiceAddress: "10.0.0.1"},
   354  		}, result)
   355  	})
   356  }