github.com/outbrain/consul@v1.4.5/agent/structs/service_definition_test.go (about)

     1  package structs
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"strings"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/pascaldekloe/goe/verify"
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  func TestAgentStructs_CheckTypes(t *testing.T) {
    15  	t.Parallel()
    16  	svc := new(ServiceDefinition)
    17  
    18  	// Singular Check field works
    19  	svc.Check = CheckType{
    20  		ScriptArgs: []string{"/foo/bar"},
    21  		Interval:   10 * time.Second,
    22  	}
    23  
    24  	// Returns HTTP checks
    25  	svc.Checks = append(svc.Checks, &CheckType{
    26  		HTTP:     "http://foo/bar",
    27  		Interval: 10 * time.Second,
    28  	})
    29  
    30  	// Returns Script checks
    31  	svc.Checks = append(svc.Checks, &CheckType{
    32  		ScriptArgs: []string{"/foo/bar"},
    33  		Interval:   10 * time.Second,
    34  	})
    35  
    36  	// Returns TTL checks
    37  	svc.Checks = append(svc.Checks, &CheckType{
    38  		TTL: 10 * time.Second,
    39  	})
    40  
    41  	// Validate checks
    42  	cases := []struct {
    43  		in   *CheckType
    44  		err  error
    45  		desc string
    46  	}{
    47  		{&CheckType{HTTP: "http://foo/baz"}, fmt.Errorf("Interval must be > 0 for Script, HTTP, or TCP checks"), "Missing interval"},
    48  		{&CheckType{TTL: -1}, fmt.Errorf("TTL must be > 0 for TTL checks"), "Negative TTL"},
    49  		{&CheckType{TTL: 20 * time.Second, Interval: 10 * time.Second}, fmt.Errorf("Interval and TTL cannot both be specified"), "Interval and TTL both set"},
    50  	}
    51  	for _, tc := range cases {
    52  		svc.Check = *tc.in
    53  		checks, err := svc.CheckTypes()
    54  		verify.Values(t, tc.desc, err.Error(), tc.err.Error())
    55  		if len(checks) != 0 {
    56  			t.Fatalf("bad: %#v", svc)
    57  		}
    58  	}
    59  }
    60  
    61  func TestServiceDefinitionValidate(t *testing.T) {
    62  	cases := []struct {
    63  		Name   string
    64  		Modify func(*ServiceDefinition)
    65  		Err    string
    66  	}{
    67  		{
    68  			"valid",
    69  			func(x *ServiceDefinition) {},
    70  			"",
    71  		},
    72  
    73  		{
    74  			"managed proxy with a port set",
    75  			func(x *ServiceDefinition) {
    76  				x.Port = 8080
    77  				x.Connect = &ServiceConnect{
    78  					Proxy: &ServiceDefinitionConnectProxy{},
    79  				}
    80  			},
    81  			"",
    82  		},
    83  
    84  		{
    85  			"managed proxy with no port set",
    86  			func(x *ServiceDefinition) {
    87  				x.Port = 0 // Explicitly unset this as the test default sets it sanely
    88  				x.Connect = &ServiceConnect{
    89  					Proxy: &ServiceDefinitionConnectProxy{},
    90  				}
    91  			},
    92  			"must have a port",
    93  		},
    94  
    95  		{
    96  			"managed proxy with native set",
    97  			func(x *ServiceDefinition) {
    98  				x.Port = 8080
    99  				x.Connect = &ServiceConnect{
   100  					Native: true,
   101  					Proxy:  &ServiceDefinitionConnectProxy{},
   102  				}
   103  			},
   104  			"may not have a proxy",
   105  		},
   106  	}
   107  
   108  	for _, tc := range cases {
   109  		t.Run(tc.Name, func(t *testing.T) {
   110  			require := require.New(t)
   111  			service := TestServiceDefinition(t)
   112  			tc.Modify(service)
   113  
   114  			err := service.Validate()
   115  			if tc.Err == "" {
   116  				require.NoError(err)
   117  			} else {
   118  				require.Error(err)
   119  				require.Contains(strings.ToLower(err.Error()), strings.ToLower(tc.Err))
   120  			}
   121  		})
   122  	}
   123  }
   124  
   125  func TestServiceDefinitionConnectProxy_json(t *testing.T) {
   126  	cases := []struct {
   127  		Name     string
   128  		Input    *ServiceDefinitionConnectProxy
   129  		Expected string
   130  		Err      string
   131  	}{
   132  		{
   133  			"no config",
   134  			&ServiceDefinitionConnectProxy{
   135  				Command:  []string{"foo"},
   136  				ExecMode: "bar",
   137  			},
   138  			`
   139  {
   140  	"Command": [
   141  		"foo"
   142  	],
   143  	"ExecMode": "bar"
   144  }
   145  			`,
   146  			"",
   147  		},
   148  
   149  		{
   150  			"basic config",
   151  			&ServiceDefinitionConnectProxy{
   152  				Config: map[string]interface{}{
   153  					"foo": "bar",
   154  				},
   155  			},
   156  			`
   157  {
   158  	"Config": {
   159  		"foo": "bar"
   160  	}
   161  }
   162  			`,
   163  			"",
   164  		},
   165  
   166  		{
   167  			"config with upstreams",
   168  			&ServiceDefinitionConnectProxy{
   169  				Config: map[string]interface{}{
   170  					"upstreams": []interface{}{
   171  						map[interface{}]interface{}{
   172  							"key": []byte("value"),
   173  						},
   174  					},
   175  				},
   176  			},
   177  			`
   178  {
   179  	"Config": {
   180  		"upstreams": [
   181  			{
   182  				"key": "value"
   183  			}
   184  		]
   185  	}
   186  }
   187  			`,
   188  			"",
   189  		},
   190  	}
   191  
   192  	for _, tc := range cases {
   193  		t.Run(tc.Name, func(t *testing.T) {
   194  			require := require.New(t)
   195  			result, err := json.MarshalIndent(tc.Input, "", "\t")
   196  			t.Logf("error: %s", err)
   197  			require.Equal(err != nil, tc.Err != "")
   198  			if err != nil {
   199  				require.Contains(strings.ToLower(err.Error()), strings.ToLower(tc.Err))
   200  				return
   201  			}
   202  
   203  			require.Equal(strings.TrimSpace(tc.Expected), strings.TrimSpace(string(result)))
   204  		})
   205  	}
   206  }