...

Source file src/github.com/linkerd/linkerd2/cli/cmd/check_extensions_test.go

Documentation: github.com/linkerd/linkerd2/cli/cmd

     1  package cmd
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"path/filepath"
     7  	"reflect"
     8  	"testing"
     9  
    10  	"k8s.io/utils/exec"
    11  	fakeexec "k8s.io/utils/exec/testing"
    12  )
    13  
    14  func TestFindExtensions(t *testing.T) {
    15  	fakeGlob := func(path string) ([]string, error) {
    16  		dir, _ := filepath.Split(path)
    17  		return []string{
    18  			filepath.Join(dir, "linkerd-bar"),
    19  			filepath.Join(dir, "linkerd-baz"),
    20  			filepath.Join(dir, "linkerd-foo"),
    21  		}, nil
    22  	}
    23  
    24  	fcmd := fakeexec.FakeCmd{
    25  		RunScript: []fakeexec.FakeAction{
    26  			func() ([]byte, []byte, error) {
    27  				return []byte(`{"name":"linkerd-baz","checks":"always"}`), nil, nil
    28  			},
    29  			func() ([]byte, []byte, error) {
    30  				return []byte(`{"name":"linkerd-foo-no-match","checks":"always"}`), nil, nil
    31  			},
    32  			func() ([]byte, []byte, error) { return []byte(`{"name":"linkerd-bar","checks":"always"}`), nil, nil },
    33  		},
    34  	}
    35  
    36  	lookPathSuccess := false
    37  
    38  	fexec := &fakeexec.FakeExec{
    39  		CommandScript: []fakeexec.FakeCommandAction{
    40  			func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
    41  			func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
    42  			func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
    43  		},
    44  		LookPathFunc: func(cmd string) (string, error) {
    45  			if lookPathSuccess {
    46  				return cmd, nil
    47  			}
    48  			lookPathSuccess = true
    49  			return "", errors.New("fake-error")
    50  		},
    51  	}
    52  
    53  	extensions, missing := findExtensions("/path1:/this/is/a/fake/path2", fakeGlob, fexec, []string{"foo", "missing-cli"})
    54  
    55  	expExtensions := []extension{
    56  		{path: "/this/is/a/fake/path2/linkerd-bar"},
    57  		{path: "/path1/linkerd-baz"},
    58  		{path: "/path1/linkerd-foo"},
    59  	}
    60  	expMissing := []string{"linkerd-missing-cli"}
    61  
    62  	if !reflect.DeepEqual(expExtensions, extensions) {
    63  		t.Errorf("Expected [%+v] Got [%+v]", expExtensions, extensions)
    64  	}
    65  	if !reflect.DeepEqual(expMissing, missing) {
    66  		t.Errorf("Expected [%+v] Got [%+v]", expMissing, missing)
    67  	}
    68  }
    69  
    70  func TestRunExtensionsChecks(t *testing.T) {
    71  	successJSON := `
    72  	{
    73  		"success": true,
    74  		"categories": [
    75  			{
    76  				"categoryName": "success check name",
    77  				"checks": [
    78  					{
    79  						"description": "success check desc",
    80  						"result": "success"
    81  					}
    82  				]
    83  			}
    84  		]
    85  	}
    86  	`
    87  
    88  	warningJSON := `
    89  	{
    90  		"success": true,
    91  		"categories": [
    92  			{
    93  				"categoryName": "warning check name",
    94  				"checks": [
    95  					{
    96  						"description": "warning check desc",
    97  						"hint": "https://example.com/warning",
    98  						"error": "this is the warning message",
    99  						"result": "warning"
   100  					}
   101  				]
   102  			}
   103  		]
   104  	}
   105  	`
   106  
   107  	errorJSON := `
   108  	{
   109  		"success": false,
   110  		"categories": [
   111  			{
   112  				"categoryName": "error check name",
   113  				"checks": [
   114  					{
   115  						"description": "error check desc",
   116  						"hint": "https://example.com/error",
   117  						"error": "this is the error message",
   118  						"result": "error"
   119  					}
   120  				]
   121  			}
   122  		]
   123  	}
   124  	`
   125  
   126  	multiJSON := `
   127  	{
   128  		"success": true,
   129  		"categories": [
   130  			{
   131  				"categoryName": "multi check name",
   132  				"checks": [
   133  					{
   134  						"description": "multi check desc success",
   135  						"result": "success"
   136  					},
   137  					{
   138  						"description": "multi check desc warning",
   139  						"hint": "https://example.com/multi",
   140  						"error": "this is the multi warning message",
   141  						"result": "warning"
   142  					}
   143  				]
   144  			}
   145  		]
   146  	}
   147  	`
   148  
   149  	testCases := []struct {
   150  		name        string
   151  		extensions  []extension
   152  		missing     []string
   153  		fakeActions []fakeexec.FakeAction
   154  		expSuccess  bool
   155  		expWarning  bool
   156  		expOutput   string
   157  	}{
   158  		{
   159  			"no checks",
   160  			nil,
   161  			nil,
   162  			[]fakeexec.FakeAction{
   163  				func() ([]byte, []byte, error) {
   164  					return nil, nil, nil
   165  				},
   166  			},
   167  			true,
   168  			false,
   169  			"",
   170  		},
   171  		{
   172  			"invalid JSON",
   173  			[]extension{{path: "/path/linkerd-invalid"}},
   174  			nil,
   175  			[]fakeexec.FakeAction{
   176  				func() ([]byte, []byte, error) {
   177  					return []byte("bad json"), nil, nil
   178  				},
   179  			},
   180  			false,
   181  			false,
   182  			`linkerd-invalid
   183  ---------------
   184  × Running: /path/linkerd-invalid check
   185      invalid extension check output from "/path/linkerd-invalid check" (JSON object expected):
   186  bad json
   187  [invalid character 'b' looking for beginning of value]
   188      see https://linkerd.io/2/checks/#extensions for hints
   189  
   190  `,
   191  		},
   192  		{
   193  			"one successful check",
   194  			[]extension{{path: "/path/linkerd-success"}},
   195  			nil,
   196  			[]fakeexec.FakeAction{
   197  				func() ([]byte, []byte, error) {
   198  					return []byte(successJSON), nil, nil
   199  				},
   200  			},
   201  			true,
   202  			false,
   203  			`success check name
   204  ------------------
   205  √ success check desc
   206  
   207  `,
   208  		},
   209  		{
   210  			"one warning check",
   211  			[]extension{{path: "/path/linkerd-warning"}},
   212  			nil,
   213  			[]fakeexec.FakeAction{
   214  				func() ([]byte, []byte, error) {
   215  					return []byte(warningJSON), nil, nil
   216  				},
   217  			},
   218  			true,
   219  			true,
   220  			`warning check name
   221  ------------------
   222  ‼ warning check desc
   223      this is the warning message
   224      see https://example.com/warning for hints
   225  
   226  `,
   227  		},
   228  		{
   229  			"one error check",
   230  			[]extension{{path: "/path/linkerd-error"}},
   231  			nil,
   232  			[]fakeexec.FakeAction{
   233  				func() ([]byte, []byte, error) {
   234  					return []byte(errorJSON), nil, nil
   235  				},
   236  			},
   237  			false,
   238  			false,
   239  			`error check name
   240  ----------------
   241  × error check desc
   242      this is the error message
   243      see https://example.com/error for hints
   244  
   245  `,
   246  		},
   247  		{
   248  			"one missing check",
   249  			nil,
   250  			[]string{"missing"},
   251  			nil,
   252  			true,
   253  			true,
   254  			`missing
   255  -------
   256  ‼ Linkerd extension command missing exists
   257      exec: "missing": executable file not found in $PATH
   258      see https://linkerd.io/2/checks/#extensions for hints
   259  
   260  `,
   261  		},
   262  		{
   263  			"multiple checks with success, warnings, errors, and missing",
   264  			[]extension{{path: "/path/linkerd-success"}, {path: "/path/linkerd-warning"}, {path: "/path/linkerd-error"}, {path: "/path/linkerd-multi"}},
   265  			[]string{"missing1", "missing2"},
   266  			[]fakeexec.FakeAction{
   267  				func() ([]byte, []byte, error) {
   268  					return []byte(successJSON), nil, nil
   269  				},
   270  				func() ([]byte, []byte, error) {
   271  					return []byte(warningJSON), nil, nil
   272  				},
   273  				func() ([]byte, []byte, error) {
   274  					return []byte(errorJSON), nil, nil
   275  				},
   276  				func() ([]byte, []byte, error) {
   277  					return []byte(multiJSON), nil, nil
   278  				},
   279  			},
   280  			false,
   281  			true,
   282  			`success check name
   283  ------------------
   284  √ success check desc
   285  
   286  warning check name
   287  ------------------
   288  ‼ warning check desc
   289      this is the warning message
   290      see https://example.com/warning for hints
   291  
   292  error check name
   293  ----------------
   294  × error check desc
   295      this is the error message
   296      see https://example.com/error for hints
   297  
   298  multi check name
   299  ----------------
   300  √ multi check desc success
   301  ‼ multi check desc warning
   302      this is the multi warning message
   303      see https://example.com/multi for hints
   304  
   305  missing1
   306  --------
   307  ‼ Linkerd extension command missing1 exists
   308      exec: "missing1": executable file not found in $PATH
   309      see https://linkerd.io/2/checks/#extensions for hints
   310  
   311  missing2
   312  --------
   313  ‼ Linkerd extension command missing2 exists
   314      exec: "missing2": executable file not found in $PATH
   315      see https://linkerd.io/2/checks/#extensions for hints
   316  
   317  `,
   318  		},
   319  	}
   320  
   321  	for _, tc := range testCases {
   322  		tc := tc // pin
   323  		t.Run(tc.name, func(t *testing.T) {
   324  			fcmd := fakeexec.FakeCmd{
   325  				RunScript: tc.fakeActions,
   326  			}
   327  
   328  			fakeCommandActions := make([]fakeexec.FakeCommandAction, len(tc.fakeActions))
   329  			for i := 0; i < len(tc.fakeActions); i++ {
   330  				fakeCommandActions[i] = func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) }
   331  			}
   332  			fexec := &fakeexec.FakeExec{
   333  				CommandScript: fakeCommandActions,
   334  			}
   335  
   336  			var stdout, stderr bytes.Buffer
   337  			success, warning := runExtensionsChecks(&stdout, &stderr, tc.extensions, tc.missing, fexec, nil, "")
   338  			if tc.expSuccess != success {
   339  				t.Errorf("Expected success to be %t, got %t", tc.expSuccess, success)
   340  			}
   341  			if tc.expWarning != warning {
   342  				t.Errorf("Expected warning to be %t, got %t", tc.expWarning, warning)
   343  			}
   344  			output := stdout.String()
   345  			if tc.expOutput != output {
   346  				t.Errorf("Expected output to be:\n%s\nGot:\n%s", tc.expOutput, output)
   347  			}
   348  		})
   349  	}
   350  }
   351  
   352  func TestSuffix(t *testing.T) {
   353  	testCases := []*struct {
   354  		testName string
   355  		input    string
   356  		exp      string
   357  	}{
   358  		{
   359  			"empty",
   360  			"",
   361  			"",
   362  		},
   363  		{
   364  			"no path",
   365  			"linkerd-foo",
   366  			"foo",
   367  		},
   368  		{
   369  			"extra dash",
   370  			"linkerd-foo-bar",
   371  			"foo-bar",
   372  		},
   373  		{
   374  			"with path",
   375  			"/tmp/linkerd-foo",
   376  			"foo",
   377  		},
   378  	}
   379  	for _, tc := range testCases {
   380  		tc := tc // pin
   381  		t.Run(tc.testName, func(t *testing.T) {
   382  			result := suffix(tc.input)
   383  			if !reflect.DeepEqual(tc.exp, result) {
   384  				t.Fatalf("Expected [%s] Got [%s]", tc.exp, result)
   385  			}
   386  		})
   387  	}
   388  }
   389  

View as plain text