github.com/castai/kvisor@v1.7.1-0.20240516114728-b3572a2607b5/cmd/linter/kubebench/util_test.go (about)

     1  // Copyright © 2017 Aqua Security Software Ltd. <info@aquasec.com>
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package kubebench
    16  
    17  import (
    18  	"errors"
    19  	"io/ioutil"
    20  	"os"
    21  	"path/filepath"
    22  	"reflect"
    23  	"sort"
    24  	"strconv"
    25  	"testing"
    26  
    27  	"github.com/castai/kvisor/cmd/linter/kubebench/check"
    28  	"github.com/magiconair/properties/assert"
    29  
    30  	"github.com/spf13/viper"
    31  )
    32  
    33  var (
    34  	g      string
    35  	e      []error
    36  	eIndex int
    37  )
    38  
    39  func fakeps(proc string) string {
    40  	return g
    41  }
    42  
    43  func fakestat(file string) (os.FileInfo, error) {
    44  	err := e[eIndex]
    45  	eIndex++
    46  	return nil, err
    47  }
    48  
    49  func TestVerifyBin(t *testing.T) {
    50  	cases := []struct {
    51  		proc  string
    52  		psOut string
    53  		exp   bool
    54  	}{
    55  		{proc: "single", psOut: "single", exp: true},
    56  		{proc: "single", psOut: "", exp: false},
    57  		{proc: "two words", psOut: "two words", exp: true},
    58  		{proc: "two words", psOut: "", exp: false},
    59  		{proc: "cmd", psOut: "cmd param1 param2", exp: true},
    60  		{proc: "cmd param", psOut: "cmd param1 param2", exp: true},
    61  		{proc: "cmd param", psOut: "cmd", exp: false},
    62  		{proc: "cmd", psOut: "cmd x \ncmd y", exp: true},
    63  		{proc: "cmd y", psOut: "cmd x \ncmd y", exp: true},
    64  		{proc: "cmd", psOut: "/usr/bin/cmd", exp: true},
    65  		{proc: "cmd", psOut: "kube-cmd", exp: false},
    66  		{proc: "cmd", psOut: "/usr/bin/kube-cmd", exp: false},
    67  	}
    68  
    69  	psFunc = fakeps
    70  	for id, c := range cases {
    71  		t.Run(strconv.Itoa(id), func(t *testing.T) {
    72  			g = c.psOut
    73  			v := verifyBin(c.proc)
    74  			if v != c.exp {
    75  				t.Fatalf("Expected %v got %v", c.exp, v)
    76  			}
    77  		})
    78  	}
    79  }
    80  
    81  func TestFindExecutable(t *testing.T) {
    82  	cases := []struct {
    83  		candidates []string // list of executables we'd consider
    84  		psOut      string   // fake output from ps
    85  		exp        string   // the one we expect to find in the (fake) ps output
    86  		expErr     bool
    87  	}{
    88  		{candidates: []string{"one", "two", "three"}, psOut: "two", exp: "two"},
    89  		{candidates: []string{"one", "two", "three"}, psOut: "two three", exp: "two"},
    90  		{candidates: []string{"one double", "two double", "three double"}, psOut: "two double is running", exp: "two double"},
    91  		{candidates: []string{"one", "two", "three"}, psOut: "blah", expErr: true},
    92  		{candidates: []string{"one double", "two double", "three double"}, psOut: "two", expErr: true},
    93  		{candidates: []string{"apiserver", "kube-apiserver"}, psOut: "kube-apiserver", exp: "kube-apiserver"},
    94  		{candidates: []string{"apiserver", "kube-apiserver", "hyperkube-apiserver"}, psOut: "kube-apiserver", exp: "kube-apiserver"},
    95  	}
    96  
    97  	psFunc = fakeps
    98  	for id, c := range cases {
    99  		t.Run(strconv.Itoa(id), func(t *testing.T) {
   100  			g = c.psOut
   101  			e, err := findExecutable(c.candidates)
   102  			if e != c.exp {
   103  				t.Fatalf("Expected %v got %v", c.exp, e)
   104  			}
   105  
   106  			if err == nil && c.expErr {
   107  				t.Fatalf("Expected error")
   108  			}
   109  
   110  			if err != nil && !c.expErr {
   111  				t.Fatalf("Didn't expect error: %v", err)
   112  			}
   113  		})
   114  	}
   115  }
   116  
   117  func TestGetBinaries(t *testing.T) {
   118  	cases := []struct {
   119  		config    map[string]interface{}
   120  		psOut     string
   121  		exp       map[string]string
   122  		expectErr bool
   123  	}{
   124  		{
   125  			config:    map[string]interface{}{"components": []string{"apiserver"}, "apiserver": map[string]interface{}{"bins": []string{"apiserver", "kube-apiserver"}}},
   126  			psOut:     "kube-apiserver",
   127  			exp:       map[string]string{"apiserver": "kube-apiserver"},
   128  			expectErr: false,
   129  		},
   130  		{
   131  			// "thing" is not in the list of components
   132  			config:    map[string]interface{}{"components": []string{"apiserver"}, "apiserver": map[string]interface{}{"bins": []string{"apiserver", "kube-apiserver"}}, "thing": map[string]interface{}{"bins": []string{"something else", "thing"}}},
   133  			psOut:     "kube-apiserver thing",
   134  			exp:       map[string]string{"apiserver": "kube-apiserver"},
   135  			expectErr: false,
   136  		},
   137  		{
   138  			// "anotherthing" in list of components but doesn't have a definition
   139  			config:    map[string]interface{}{"components": []string{"apiserver", "anotherthing"}, "apiserver": map[string]interface{}{"bins": []string{"apiserver", "kube-apiserver"}}, "thing": map[string]interface{}{"bins": []string{"something else", "thing"}}},
   140  			psOut:     "kube-apiserver thing",
   141  			exp:       map[string]string{"apiserver": "kube-apiserver"},
   142  			expectErr: false,
   143  		},
   144  		{
   145  			// more than one component
   146  			config:    map[string]interface{}{"components": []string{"apiserver", "thing"}, "apiserver": map[string]interface{}{"bins": []string{"apiserver", "kube-apiserver"}}, "thing": map[string]interface{}{"bins": []string{"something else", "thing"}}},
   147  			psOut:     "kube-apiserver \nthing",
   148  			exp:       map[string]string{"apiserver": "kube-apiserver", "thing": "thing"},
   149  			expectErr: false,
   150  		},
   151  		{
   152  			// default binary to component name
   153  			config:    map[string]interface{}{"components": []string{"apiserver", "thing"}, "apiserver": map[string]interface{}{"bins": []string{"apiserver", "kube-apiserver"}}, "thing": map[string]interface{}{"bins": []string{"something else", "thing"}, "optional": true}},
   154  			psOut:     "kube-apiserver \notherthing some params",
   155  			exp:       map[string]string{"apiserver": "kube-apiserver", "thing": "thing"},
   156  			expectErr: false,
   157  		},
   158  		{
   159  			// missing mandatory component
   160  			config:    map[string]interface{}{"components": []string{"apiserver", "thing"}, "apiserver": map[string]interface{}{"bins": []string{"apiserver", "kube-apiserver"}}, "thing": map[string]interface{}{"bins": []string{"something else", "thing"}, "optional": true}},
   161  			psOut:     "otherthing some params",
   162  			exp:       map[string]string{"apiserver": "kube-apiserver", "thing": "thing"},
   163  			expectErr: true,
   164  		},
   165  	}
   166  
   167  	v := viper.New()
   168  	psFunc = fakeps
   169  
   170  	for id, c := range cases {
   171  		t.Run(strconv.Itoa(id), func(t *testing.T) {
   172  			g = c.psOut
   173  			for k, val := range c.config {
   174  				v.Set(k, val)
   175  			}
   176  			m, err := getBinaries(v, check.MASTER)
   177  			if c.expectErr {
   178  				if err == nil {
   179  					t.Fatal("Got nil Expected error")
   180  				}
   181  			} else if !reflect.DeepEqual(m, c.exp) {
   182  				t.Fatalf("Got %v\nExpected %v", m, c.exp)
   183  			}
   184  		})
   185  	}
   186  }
   187  
   188  func TestMultiWordReplace(t *testing.T) {
   189  	cases := []struct {
   190  		input   string
   191  		sub     string
   192  		subname string
   193  		output  string
   194  	}{
   195  		{input: "Here's a file with no substitutions", sub: "blah", subname: "blah", output: "Here's a file with no substitutions"},
   196  		{input: "Here's a file with a substitution", sub: "blah", subname: "substitution", output: "Here's a file with a blah"},
   197  		{input: "Here's a file with multi-word substitutions", sub: "multi word", subname: "multi-word", output: "Here's a file with 'multi word' substitutions"},
   198  		{input: "Here's a file with several several substitutions several", sub: "blah", subname: "several", output: "Here's a file with blah blah substitutions blah"},
   199  	}
   200  	for id, c := range cases {
   201  		t.Run(strconv.Itoa(id), func(t *testing.T) {
   202  			s := multiWordReplace(c.input, c.subname, c.sub)
   203  			if s != c.output {
   204  				t.Fatalf("Expected %s got %s", c.output, s)
   205  			}
   206  		})
   207  	}
   208  }
   209  
   210  func Test_getVersionFromKubectlOutput(t *testing.T) {
   211  	ver := getVersionFromKubectlOutput(`{
   212    "serverVersion": {
   213      "major": "1",
   214      "minor": "8",
   215      "gitVersion": "v1.8.0"
   216    }
   217  }`)
   218  	if ver.BaseVersion() != "1.8" {
   219  		t.Fatalf("Expected 1.8 got %s", ver.BaseVersion())
   220  	}
   221  
   222  	ver = getVersionFromKubectlOutput("Something completely different")
   223  	if ver.BaseVersion() != defaultKubeVersion {
   224  		t.Fatalf("Expected %s got %s", defaultKubeVersion, ver.BaseVersion())
   225  	}
   226  }
   227  
   228  func TestFindConfigFile(t *testing.T) {
   229  	cases := []struct {
   230  		input       []string
   231  		statResults []error
   232  		exp         string
   233  	}{
   234  		{input: []string{"myfile"}, statResults: []error{nil}, exp: "myfile"},
   235  		{input: []string{"thisfile", "thatfile"}, statResults: []error{os.ErrNotExist, nil}, exp: "thatfile"},
   236  		{input: []string{"thisfile", "thatfile"}, statResults: []error{os.ErrNotExist, os.ErrNotExist}, exp: ""},
   237  		{input: []string{"thisfile", "/etc/dummy/thatfile"}, statResults: []error{os.ErrNotExist, errors.New("stat /etc/dummy/thatfile: not a directory")}, exp: ""},
   238  	}
   239  
   240  	statFunc = fakestat
   241  	for id, c := range cases {
   242  		t.Run(strconv.Itoa(id), func(t *testing.T) {
   243  			e = c.statResults
   244  			eIndex = 0
   245  			conf := findConfigFile(c.input)
   246  			if conf != c.exp {
   247  				t.Fatalf("Got %s expected %s", conf, c.exp)
   248  			}
   249  		})
   250  	}
   251  }
   252  
   253  func TestGetConfigFiles(t *testing.T) {
   254  	cases := []struct {
   255  		config      map[string]interface{}
   256  		exp         map[string]string
   257  		statResults []error
   258  	}{
   259  		{
   260  			config:      map[string]interface{}{"components": []string{"apiserver"}, "apiserver": map[string]interface{}{"confs": []string{"apiserver", "kube-apiserver"}}},
   261  			statResults: []error{os.ErrNotExist, nil},
   262  			exp:         map[string]string{"apiserver": "kube-apiserver"},
   263  		},
   264  		{
   265  			// Component "thing" isn't included in the list of components
   266  			config: map[string]interface{}{
   267  				"components": []string{"apiserver"},
   268  				"apiserver":  map[string]interface{}{"confs": []string{"apiserver", "kube-apiserver"}},
   269  				"thing":      map[string]interface{}{"confs": []string{"/my/file/thing"}},
   270  			},
   271  			statResults: []error{os.ErrNotExist, nil},
   272  			exp:         map[string]string{"apiserver": "kube-apiserver"},
   273  		},
   274  		{
   275  			// More than one component
   276  			config: map[string]interface{}{
   277  				"components": []string{"apiserver", "thing"},
   278  				"apiserver":  map[string]interface{}{"confs": []string{"apiserver", "kube-apiserver"}},
   279  				"thing":      map[string]interface{}{"confs": []string{"/my/file/thing"}},
   280  			},
   281  			statResults: []error{os.ErrNotExist, nil, nil},
   282  			exp:         map[string]string{"apiserver": "kube-apiserver", "thing": "/my/file/thing"},
   283  		},
   284  		{
   285  			// Default thing to specified default config
   286  			config: map[string]interface{}{
   287  				"components": []string{"apiserver", "thing"},
   288  				"apiserver":  map[string]interface{}{"confs": []string{"apiserver", "kube-apiserver"}},
   289  				"thing":      map[string]interface{}{"confs": []string{"/my/file/thing"}, "defaultconf": "another/thing"},
   290  			},
   291  			statResults: []error{os.ErrNotExist, nil, os.ErrNotExist},
   292  			exp:         map[string]string{"apiserver": "kube-apiserver", "thing": "another/thing"},
   293  		},
   294  		{
   295  			// Default thing to component name
   296  			config: map[string]interface{}{
   297  				"components": []string{"apiserver", "thing"},
   298  				"apiserver":  map[string]interface{}{"confs": []string{"apiserver", "kube-apiserver"}},
   299  				"thing":      map[string]interface{}{"confs": []string{"/my/file/thing"}},
   300  			},
   301  			statResults: []error{os.ErrNotExist, nil, os.ErrNotExist},
   302  			exp:         map[string]string{"apiserver": "kube-apiserver", "thing": "thing"},
   303  		},
   304  	}
   305  
   306  	v := viper.New()
   307  	statFunc = fakestat
   308  
   309  	for id, c := range cases {
   310  		t.Run(strconv.Itoa(id), func(t *testing.T) {
   311  			for k, val := range c.config {
   312  				v.Set(k, val)
   313  			}
   314  			e = c.statResults
   315  			eIndex = 0
   316  
   317  			m := getFiles(v, "config")
   318  			if !reflect.DeepEqual(m, c.exp) {
   319  				t.Fatalf("Got %v\nExpected %v", m, c.exp)
   320  			}
   321  		})
   322  	}
   323  }
   324  
   325  func TestGetServiceFiles(t *testing.T) {
   326  	cases := []struct {
   327  		config      map[string]interface{}
   328  		exp         map[string]string
   329  		statResults []error
   330  	}{
   331  		{
   332  			config: map[string]interface{}{
   333  				"components": []string{"kubelet"},
   334  				"kubelet":    map[string]interface{}{"svc": []string{"kubelet", "10-kubeadm.conf"}},
   335  			},
   336  			statResults: []error{os.ErrNotExist, nil},
   337  			exp:         map[string]string{"kubelet": "10-kubeadm.conf"},
   338  		},
   339  		{
   340  			// Component "thing" isn't included in the list of components
   341  			config: map[string]interface{}{
   342  				"components": []string{"kubelet"},
   343  				"kubelet":    map[string]interface{}{"svc": []string{"kubelet", "10-kubeadm.conf"}},
   344  				"thing":      map[string]interface{}{"svc": []string{"/my/file/thing"}},
   345  			},
   346  			statResults: []error{os.ErrNotExist, nil},
   347  			exp:         map[string]string{"kubelet": "10-kubeadm.conf"},
   348  		},
   349  		{
   350  			// More than one component
   351  			config: map[string]interface{}{
   352  				"components": []string{"kubelet", "thing"},
   353  				"kubelet":    map[string]interface{}{"svc": []string{"kubelet", "10-kubeadm.conf"}},
   354  				"thing":      map[string]interface{}{"svc": []string{"/my/file/thing"}},
   355  			},
   356  			statResults: []error{os.ErrNotExist, nil, nil},
   357  			exp:         map[string]string{"kubelet": "10-kubeadm.conf", "thing": "/my/file/thing"},
   358  		},
   359  		{
   360  			// Default thing to specified default service
   361  			config: map[string]interface{}{
   362  				"components": []string{"kubelet", "thing"},
   363  				"kubelet":    map[string]interface{}{"svc": []string{"kubelet", "10-kubeadm.conf"}},
   364  				"thing":      map[string]interface{}{"svc": []string{"/my/file/thing"}, "defaultsvc": "another/thing"},
   365  			},
   366  			statResults: []error{os.ErrNotExist, nil, os.ErrNotExist},
   367  			exp:         map[string]string{"kubelet": "10-kubeadm.conf", "thing": "another/thing"},
   368  		},
   369  		{
   370  			// Default thing to component name
   371  			config: map[string]interface{}{
   372  				"components": []string{"kubelet", "thing"},
   373  				"kubelet":    map[string]interface{}{"svc": []string{"kubelet", "10-kubeadm.conf"}},
   374  				"thing":      map[string]interface{}{"svc": []string{"/my/file/thing"}},
   375  			},
   376  			statResults: []error{os.ErrNotExist, nil, os.ErrNotExist},
   377  			exp:         map[string]string{"kubelet": "10-kubeadm.conf", "thing": "thing"},
   378  		},
   379  	}
   380  
   381  	v := viper.New()
   382  	statFunc = fakestat
   383  
   384  	for id, c := range cases {
   385  		t.Run(strconv.Itoa(id), func(t *testing.T) {
   386  			for k, val := range c.config {
   387  				v.Set(k, val)
   388  			}
   389  			e = c.statResults
   390  			eIndex = 0
   391  
   392  			m := getFiles(v, "service")
   393  			if !reflect.DeepEqual(m, c.exp) {
   394  				t.Fatalf("Got %v\nExpected %v", m, c.exp)
   395  			}
   396  		})
   397  	}
   398  }
   399  
   400  func TestGetDatadirFiles(t *testing.T) {
   401  	var err error
   402  	datadir, err := ioutil.TempDir("", "kube-bench-test-etcd-data-dir")
   403  	if err != nil {
   404  		t.Fatalf("Failed to create temp directory")
   405  	}
   406  	defer os.RemoveAll(datadir)
   407  
   408  	cases := []struct {
   409  		config      map[string]interface{}
   410  		exp         map[string]string
   411  		statResults []error
   412  	}{
   413  		{
   414  			config: map[string]interface{}{
   415  				"components": []string{"etcd"},
   416  				"etcd": map[string]interface{}{"datadirs": []string{datadir},
   417  					"defaultdatadir": "/var/lib/etcd/default.etcd"},
   418  			},
   419  			statResults: []error{nil},
   420  			exp:         map[string]string{"etcd": datadir},
   421  		},
   422  		// fallback to defaultdatadir
   423  		{
   424  			config: map[string]interface{}{
   425  				"components": []string{"etcd"},
   426  				"etcd": map[string]interface{}{"datadirs": []string{"/path/to/etcd/data.etcd"},
   427  					"defaultdatadir": "/var/lib/etcd/default.etcd"},
   428  			},
   429  			statResults: []error{os.ErrNotExist},
   430  			exp:         map[string]string{"etcd": "/var/lib/etcd/default.etcd"},
   431  		},
   432  	}
   433  
   434  	v := viper.New()
   435  	statFunc = fakestat
   436  
   437  	for id, c := range cases {
   438  		t.Run(strconv.Itoa(id), func(t *testing.T) {
   439  			for k, val := range c.config {
   440  				v.Set(k, val)
   441  			}
   442  			e = c.statResults
   443  			eIndex = 0
   444  			m := getFiles(v, "datadir")
   445  			if !reflect.DeepEqual(m, c.exp) {
   446  				t.Fatalf("Got %v\nExpected %v", m, c.exp)
   447  			}
   448  		})
   449  	}
   450  }
   451  
   452  func TestMakeSubsitutions(t *testing.T) {
   453  	cases := []struct {
   454  		input        string
   455  		subst        map[string]string
   456  		exp          string
   457  		expectedSubs []string
   458  	}{
   459  		{input: "Replace $thisbin", subst: map[string]string{"this": "that"}, exp: "Replace that", expectedSubs: []string{"that"}},
   460  		{input: "Replace $thisbin", subst: map[string]string{"this": "that", "here": "there"}, exp: "Replace that", expectedSubs: []string{"that"}},
   461  		{input: "Replace $thisbin and $herebin", subst: map[string]string{"this": "that", "here": "there"}, exp: "Replace that and there", expectedSubs: []string{"that", "there"}},
   462  	}
   463  	for _, c := range cases {
   464  		t.Run(c.input, func(t *testing.T) {
   465  			s, subs := makeSubstitutions(c.input, "bin", c.subst)
   466  			if s != c.exp {
   467  				t.Fatalf("Got %s expected %s", s, c.exp)
   468  			}
   469  			sort.Strings(subs)
   470  			assert.Equal(t, c.expectedSubs, subs)
   471  		})
   472  	}
   473  }
   474  
   475  func TestGetConfigFilePath(t *testing.T) {
   476  	var err error
   477  	cfgDir, err = ioutil.TempDir("", "kube-bench-test")
   478  	if err != nil {
   479  		t.Fatalf("Failed to create temp directory")
   480  	}
   481  	defer os.RemoveAll(cfgDir)
   482  	d := filepath.Join(cfgDir, "cis-1.4")
   483  	err = os.Mkdir(d, 0766)
   484  	if err != nil {
   485  		t.Fatalf("Failed to create temp dir")
   486  	}
   487  	err = ioutil.WriteFile(filepath.Join(d, "master.yaml"), []byte("hello world"), 0666)
   488  	if err != nil {
   489  		t.Logf("Failed to create temp file")
   490  	}
   491  
   492  	cases := []struct {
   493  		benchmarkVersion string
   494  		succeed          bool
   495  		exp              string
   496  	}{
   497  		{benchmarkVersion: "cis-1.4", succeed: true, exp: d},
   498  		{benchmarkVersion: "cis-1.5", succeed: false, exp: ""},
   499  		{benchmarkVersion: "1.1", succeed: false, exp: ""},
   500  	}
   501  
   502  	for _, c := range cases {
   503  		t.Run(c.benchmarkVersion, func(t *testing.T) {
   504  			path, err := getConfigFilePath(c.benchmarkVersion, "/master.yaml")
   505  			if c.succeed {
   506  				if err != nil {
   507  					t.Fatalf("Error %v", err)
   508  				}
   509  				if path != c.exp {
   510  					t.Fatalf("Got %s expected %s", path, c.exp)
   511  				}
   512  			} else {
   513  				if err == nil {
   514  					t.Fatalf("Expected Error, but none")
   515  				}
   516  			}
   517  		})
   518  	}
   519  }
   520  
   521  func TestDecrementVersion(t *testing.T) {
   522  	cases := []struct {
   523  		kubeVersion string
   524  		succeed     bool
   525  		exp         string
   526  	}{
   527  		{kubeVersion: "1.13", succeed: true, exp: "1.12"},
   528  		{kubeVersion: "1.15", succeed: true, exp: "1.14"},
   529  		{kubeVersion: "1.11", succeed: true, exp: "1.10"},
   530  		{kubeVersion: "1.1", succeed: true, exp: ""},
   531  		{kubeVersion: "invalid", succeed: false, exp: ""},
   532  	}
   533  	for _, c := range cases {
   534  		rv := decrementVersion(c.kubeVersion)
   535  		if c.succeed {
   536  			if c.exp != rv {
   537  				t.Fatalf("decrementVersion(%q) - Got %q expected %s", c.kubeVersion, rv, c.exp)
   538  			}
   539  		} else {
   540  			if len(rv) > 0 {
   541  				t.Fatalf("decrementVersion(%q) - Expected empty string but Got %s", c.kubeVersion, rv)
   542  			}
   543  		}
   544  	}
   545  }
   546  
   547  func TestGetYamlFilesFromDir(t *testing.T) {
   548  	cfgDir, err := ioutil.TempDir("", "kube-bench-test")
   549  	if err != nil {
   550  		t.Fatalf("Failed to create temp directory")
   551  	}
   552  	defer os.RemoveAll(cfgDir)
   553  
   554  	d := filepath.Join(cfgDir, "cis-1.4")
   555  	err = os.Mkdir(d, 0766)
   556  	if err != nil {
   557  		t.Fatalf("Failed to create temp dir")
   558  	}
   559  
   560  	err = ioutil.WriteFile(filepath.Join(d, "something.yaml"), []byte("hello world"), 0666)
   561  	if err != nil {
   562  		t.Fatalf("error writing file %v", err)
   563  	}
   564  	err = ioutil.WriteFile(filepath.Join(d, "config.yaml"), []byte("hello world"), 0666)
   565  	if err != nil {
   566  		t.Fatalf("error writing file %v", err)
   567  	}
   568  
   569  	files, err := getYamlFilesFromDir(d)
   570  	if err != nil {
   571  		t.Fatalf("Unexpected error: %v", err)
   572  	}
   573  	if len(files) != 1 {
   574  		t.Fatalf("Expected to find one file, found %d", len(files))
   575  	}
   576  
   577  	if files[0] != filepath.Join(d, "something.yaml") {
   578  		t.Fatalf("Expected to find something.yaml, found %s", files[0])
   579  	}
   580  }
   581  
   582  func Test_getPlatformNameFromKubectlOutput(t *testing.T) {
   583  	type args struct {
   584  		s string
   585  	}
   586  	tests := []struct {
   587  		name string
   588  		args args
   589  		want Platform
   590  	}{
   591  		{
   592  			name: "eks",
   593  			args: args{s: "v1.17.9-eks-4c6976"},
   594  			want: Platform{Name: "eks", Version: "1.17"},
   595  		},
   596  		{
   597  			name: "gke",
   598  			args: args{s: "v1.17.6-gke.1"},
   599  			want: Platform{Name: "gke", Version: "1.17"},
   600  		},
   601  		{
   602  			name: "ack",
   603  			args: args{s: "v1.18.8-aliyun.1"},
   604  			want: Platform{Name: "aliyun", Version: "1.18"},
   605  		},
   606  		{
   607  			name: "unknown",
   608  			args: args{s: "v1.17.6"},
   609  			want: Platform{},
   610  		},
   611  		{
   612  			name: "empty string",
   613  			args: args{s: ""},
   614  			want: Platform{},
   615  		},
   616  	}
   617  	for _, tt := range tests {
   618  		t.Run(tt.name, func(t *testing.T) {
   619  			got := getPlatformInfoFromVersion(tt.args.s)
   620  			assert.Equal(t, tt.want, got)
   621  		})
   622  	}
   623  }
   624  
   625  func Test_getPlatformBenchmarkVersion(t *testing.T) {
   626  	type args struct {
   627  		platform Platform
   628  	}
   629  	tests := []struct {
   630  		name string
   631  		args args
   632  		want string
   633  	}{
   634  		{
   635  			name: "eks",
   636  			args: args{
   637  				platform: Platform{Name: "eks"},
   638  			},
   639  			want: "eks-1.2.0",
   640  		},
   641  		{
   642  			name: "gke 1.19",
   643  			args: args{
   644  				platform: Platform{Name: "gke", Version: "1.19"},
   645  			},
   646  			want: "gke-1.0",
   647  		},
   648  		{
   649  			name: "gke 1.20",
   650  			args: args{
   651  				platform: Platform{Name: "gke", Version: "1.20"},
   652  			},
   653  			want: "gke-1.2.0",
   654  		},
   655  		{
   656  			name: "gke 1.22",
   657  			args: args{
   658  				platform: Platform{Name: "gke", Version: "1.22"},
   659  			},
   660  			want: "gke-1.2.0",
   661  		},
   662  		{
   663  			name: "aliyun",
   664  			args: args{
   665  				platform: Platform{Name: "aliyun"},
   666  			},
   667  			want: "ack-1.0",
   668  		},
   669  		{
   670  			name: "unknown",
   671  			args: args{
   672  				platform: Platform{Name: "rh"},
   673  			},
   674  			want: "",
   675  		},
   676  		{
   677  			name: "empty",
   678  			args: args{
   679  				platform: Platform{},
   680  			},
   681  			want: "",
   682  		},
   683  		{
   684  			name: "openshift3",
   685  			args: args{
   686  				platform: Platform{Name: "ocp", Version: "3.10"},
   687  			},
   688  			want: "rh-0.7",
   689  		},
   690  		{
   691  			name: "openshift4",
   692  			args: args{
   693  				platform: Platform{Name: "ocp", Version: "4.1"},
   694  			},
   695  			want: "rh-1.0",
   696  		},
   697  	}
   698  	for _, tt := range tests {
   699  		t.Run(tt.name, func(t *testing.T) {
   700  			if got := getPlatformBenchmarkVersion(tt.args.platform); got != tt.want {
   701  				t.Errorf("getPlatformBenchmarkVersion() = %v, want %v", got, tt.want)
   702  			}
   703  		})
   704  	}
   705  }
   706  
   707  func Test_getOcpValidVersion(t *testing.T) {
   708  	cases := []struct {
   709  		openShiftVersion string
   710  		succeed          bool
   711  		exp              string
   712  	}{
   713  		{openShiftVersion: "3.11", succeed: true, exp: "3.10"},
   714  		{openShiftVersion: "3.10", succeed: true, exp: "3.10"},
   715  		{openShiftVersion: "2.9", succeed: false, exp: ""},
   716  		{openShiftVersion: "4.1", succeed: true, exp: "4.1"},
   717  		{openShiftVersion: "4.5", succeed: true, exp: "4.1"},
   718  		{openShiftVersion: "4.6", succeed: true, exp: "4.1"},
   719  		{openShiftVersion: "invalid", succeed: false, exp: ""},
   720  	}
   721  	for _, c := range cases {
   722  		ocpVer, _ := getOcpValidVersion(c.openShiftVersion)
   723  		if c.succeed {
   724  			if c.exp != ocpVer {
   725  				t.Errorf("getOcpValidVersion(%q) - Got %q expected %s", c.openShiftVersion, ocpVer, c.exp)
   726  			}
   727  		} else {
   728  			if len(ocpVer) > 0 {
   729  				t.Errorf("getOcpValidVersion(%q) - Expected empty string but Got %s", c.openShiftVersion, ocpVer)
   730  			}
   731  		}
   732  	}
   733  }