github.com/tschmi5/nomad@v0.11.8/helper/funcs_test.go (about)

     1  package helper
     2  
     3  import (
     4  	"fmt"
     5  	"path/filepath"
     6  	"reflect"
     7  	"sort"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/require"
    11  )
    12  
    13  func TestSliceStringIsSubset(t *testing.T) {
    14  	l := []string{"a", "b", "c"}
    15  	s := []string{"d"}
    16  
    17  	sub, offending := SliceStringIsSubset(l, l[:1])
    18  	if !sub || len(offending) != 0 {
    19  		t.Fatalf("bad %v %v", sub, offending)
    20  	}
    21  
    22  	sub, offending = SliceStringIsSubset(l, s)
    23  	if sub || len(offending) == 0 || offending[0] != "d" {
    24  		t.Fatalf("bad %v %v", sub, offending)
    25  	}
    26  }
    27  
    28  func TestCompareSliceSetString(t *testing.T) {
    29  	cases := []struct {
    30  		A      []string
    31  		B      []string
    32  		Result bool
    33  	}{
    34  		{
    35  			A:      []string{},
    36  			B:      []string{},
    37  			Result: true,
    38  		},
    39  		{
    40  			A:      []string{},
    41  			B:      []string{"a"},
    42  			Result: false,
    43  		},
    44  		{
    45  			A:      []string{"a"},
    46  			B:      []string{"a"},
    47  			Result: true,
    48  		},
    49  		{
    50  			A:      []string{"a"},
    51  			B:      []string{"b"},
    52  			Result: false,
    53  		},
    54  		{
    55  			A:      []string{"a", "b"},
    56  			B:      []string{"b"},
    57  			Result: false,
    58  		},
    59  		{
    60  			A:      []string{"a", "b"},
    61  			B:      []string{"a"},
    62  			Result: false,
    63  		},
    64  		{
    65  			A:      []string{"a", "b"},
    66  			B:      []string{"a", "b"},
    67  			Result: true,
    68  		},
    69  		{
    70  			A:      []string{"a", "b"},
    71  			B:      []string{"b", "a"},
    72  			Result: true,
    73  		},
    74  	}
    75  
    76  	for i, tc := range cases {
    77  		tc := tc
    78  		t.Run(fmt.Sprintf("case-%da", i), func(t *testing.T) {
    79  			if res := CompareSliceSetString(tc.A, tc.B); res != tc.Result {
    80  				t.Fatalf("expected %t but CompareSliceSetString(%v, %v) -> %t",
    81  					tc.Result, tc.A, tc.B, res,
    82  				)
    83  			}
    84  		})
    85  
    86  		// Function is commutative so compare B and A
    87  		t.Run(fmt.Sprintf("case-%db", i), func(t *testing.T) {
    88  			if res := CompareSliceSetString(tc.B, tc.A); res != tc.Result {
    89  				t.Fatalf("expected %t but CompareSliceSetString(%v, %v) -> %t",
    90  					tc.Result, tc.B, tc.A, res,
    91  				)
    92  			}
    93  		})
    94  	}
    95  }
    96  
    97  func TestMapStringStringSliceValueSet(t *testing.T) {
    98  	m := map[string][]string{
    99  		"foo": {"1", "2"},
   100  		"bar": {"3"},
   101  		"baz": nil,
   102  	}
   103  
   104  	act := MapStringStringSliceValueSet(m)
   105  	exp := []string{"1", "2", "3"}
   106  	sort.Strings(act)
   107  	if !reflect.DeepEqual(act, exp) {
   108  		t.Fatalf("Bad; got %v; want %v", act, exp)
   109  	}
   110  }
   111  
   112  func TestCopyMapStringSliceString(t *testing.T) {
   113  	m := map[string][]string{
   114  		"x": {"a", "b", "c"},
   115  		"y": {"1", "2", "3"},
   116  		"z": nil,
   117  	}
   118  
   119  	c := CopyMapStringSliceString(m)
   120  	if !reflect.DeepEqual(c, m) {
   121  		t.Fatalf("%#v != %#v", m, c)
   122  	}
   123  
   124  	c["x"][1] = "---"
   125  	if reflect.DeepEqual(c, m) {
   126  		t.Fatalf("Shared slices: %#v == %#v", m["x"], c["x"])
   127  	}
   128  }
   129  
   130  func TestClearEnvVar(t *testing.T) {
   131  	type testCase struct {
   132  		input    string
   133  		expected string
   134  	}
   135  	cases := []testCase{
   136  		{"asdf", "asdf"},
   137  		{"ASDF", "ASDF"},
   138  		{"0sdf", "_sdf"},
   139  		{"asd0", "asd0"},
   140  		{"_asd", "_asd"},
   141  		{"-asd", "_asd"},
   142  		{"asd.fgh", "asd.fgh"},
   143  		{"A~!@#$%^&*()_+-={}[]|\\;:'\"<,>?/Z", "A______________________________Z"},
   144  		{"A\U0001f4a9Z", "A____Z"},
   145  	}
   146  	for _, c := range cases {
   147  		if output := CleanEnvVar(c.input, '_'); output != c.expected {
   148  			t.Errorf("CleanEnvVar(%q, '_') -> %q != %q", c.input, output, c.expected)
   149  		}
   150  	}
   151  }
   152  
   153  func BenchmarkCleanEnvVar(b *testing.B) {
   154  	in := "NOMAD_ADDR_redis-cache"
   155  	replacement := byte('_')
   156  	b.SetBytes(int64(len(in)))
   157  	b.ReportAllocs()
   158  	b.ResetTimer()
   159  	for i := 0; i < b.N; i++ {
   160  		CleanEnvVar(in, replacement)
   161  	}
   162  }
   163  
   164  func TestPathEscapesSandbox(t *testing.T) {
   165  	cases := []struct {
   166  		name     string
   167  		path     string
   168  		dir      string
   169  		expected bool
   170  	}{
   171  		{
   172  			// this is the ${NOMAD_SECRETS_DIR} case
   173  			name:     "ok joined absolute path inside sandbox",
   174  			path:     filepath.Join("/alloc", "/secrets"),
   175  			dir:      "/alloc",
   176  			expected: false,
   177  		},
   178  		{
   179  			name:     "fail unjoined absolute path outside sandbox",
   180  			path:     "/secrets",
   181  			dir:      "/alloc",
   182  			expected: true,
   183  		},
   184  		{
   185  			name:     "ok joined relative path inside sandbox",
   186  			path:     filepath.Join("/alloc", "./safe"),
   187  			dir:      "/alloc",
   188  			expected: false,
   189  		},
   190  		{
   191  			name:     "fail unjoined relative path outside sandbox",
   192  			path:     "./safe",
   193  			dir:      "/alloc",
   194  			expected: true,
   195  		},
   196  		{
   197  			name:     "ok relative path traversal constrained to sandbox",
   198  			path:     filepath.Join("/alloc", "../../alloc/safe"),
   199  			dir:      "/alloc",
   200  			expected: false,
   201  		},
   202  		{
   203  			name:     "ok unjoined absolute path traversal constrained to sandbox",
   204  			path:     filepath.Join("/alloc", "/../alloc/safe"),
   205  			dir:      "/alloc",
   206  			expected: false,
   207  		},
   208  		{
   209  			name:     "ok unjoined absolute path traversal constrained to sandbox",
   210  			path:     "/../alloc/safe",
   211  			dir:      "/alloc",
   212  			expected: false,
   213  		},
   214  		{
   215  			name:     "fail joined relative path traverses outside sandbox",
   216  			path:     filepath.Join("/alloc", "../../../unsafe"),
   217  			dir:      "/alloc",
   218  			expected: true,
   219  		},
   220  		{
   221  			name:     "fail unjoined relative path traverses outside sandbox",
   222  			path:     "../../../unsafe",
   223  			dir:      "/alloc",
   224  			expected: true,
   225  		},
   226  		{
   227  			name:     "fail joined absolute path tries to transverse outside sandbox",
   228  			path:     filepath.Join("/alloc", "/alloc/../../unsafe"),
   229  			dir:      "/alloc",
   230  			expected: true,
   231  		},
   232  		{
   233  			name:     "fail unjoined absolute path tries to transverse outside sandbox",
   234  			path:     "/alloc/../../unsafe",
   235  			dir:      "/alloc",
   236  			expected: true,
   237  		},
   238  	}
   239  
   240  	for _, tc := range cases {
   241  		t.Run(tc.name, func(t *testing.T) {
   242  			caseMsg := fmt.Sprintf("path: %v\ndir: %v", tc.path, tc.dir)
   243  			escapes := PathEscapesSandbox(tc.dir, tc.path)
   244  			require.Equal(t, tc.expected, escapes, caseMsg)
   245  		})
   246  	}
   247  }