github.com/kata-containers/runtime@v0.0.0-20210505125100-04f29832a923/cli/kata-check_test.go (about)

     1  // Copyright (c) 2017 Intel Corporation
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  //
     5  
     6  package main
     7  
     8  import (
     9  	"bytes"
    10  	"flag"
    11  	"fmt"
    12  	"html/template"
    13  	"io/ioutil"
    14  	"os"
    15  	"path"
    16  	"path/filepath"
    17  	"strings"
    18  	"testing"
    19  
    20  	ktu "github.com/kata-containers/runtime/pkg/katatestutils"
    21  	"github.com/kata-containers/runtime/pkg/katautils"
    22  	vc "github.com/kata-containers/runtime/virtcontainers"
    23  	"github.com/sirupsen/logrus"
    24  	"github.com/stretchr/testify/assert"
    25  	"github.com/urfave/cli"
    26  )
    27  
    28  type testModuleData struct {
    29  	path     string
    30  	isDir    bool
    31  	contents string
    32  }
    33  
    34  // nolint: structcheck, unused, deadcode
    35  type testCPUData struct {
    36  	vendorID    string
    37  	flags       string
    38  	expectError bool
    39  }
    40  
    41  // nolint: structcheck, unused, deadcode
    42  type testCPUDetail struct {
    43  	contents       string
    44  	expectedVendor string
    45  	expectedModel  string
    46  	expectError    bool
    47  }
    48  
    49  var fakeCPUData = testCPUData{"", "", false}
    50  
    51  func createFile(file, contents string) error {
    52  	return ioutil.WriteFile(file, []byte(contents), testFileMode)
    53  }
    54  
    55  func createModules(assert *assert.Assertions, cpuInfoFile string, moduleData []testModuleData) {
    56  	for _, d := range moduleData {
    57  		var dir string
    58  
    59  		if d.isDir {
    60  			dir = d.path
    61  		} else {
    62  			dir = path.Dir(d.path)
    63  		}
    64  
    65  		err := os.MkdirAll(dir, testDirMode)
    66  		assert.NoError(err)
    67  
    68  		if !d.isDir {
    69  			err = createFile(d.path, d.contents)
    70  			assert.NoError(err)
    71  		}
    72  
    73  		details := vmContainerCapableDetails{
    74  			cpuInfoFile: cpuInfoFile,
    75  		}
    76  
    77  		err = hostIsVMContainerCapable(details)
    78  		if katautils.FileExists(cpuInfoFile) {
    79  			assert.NoError(err)
    80  		} else {
    81  			assert.Error(err)
    82  		}
    83  	}
    84  }
    85  
    86  func checkKernelParamHandler(assert *assert.Assertions, kernelModulesToCreate, expectedKernelModules map[string]kernelModule, handler kernelParamHandler, expectHandlerError bool, expectedErrorCount uint32) {
    87  	err := os.RemoveAll(sysModuleDir)
    88  	assert.NoError(err)
    89  
    90  	count, err := checkKernelModules(map[string]kernelModule{}, handler)
    91  
    92  	// No required modules means no error
    93  	assert.NoError(err)
    94  	assert.Equal(count, uint32(0))
    95  
    96  	count, err = checkKernelModules(expectedKernelModules, handler)
    97  	assert.NoError(err)
    98  
    99  	// No modules exist
   100  	expectedCount := len(expectedKernelModules)
   101  	assert.Equal(count, uint32(expectedCount))
   102  
   103  	err = os.MkdirAll(sysModuleDir, testDirMode)
   104  	assert.NoError(err)
   105  
   106  	for module, details := range kernelModulesToCreate {
   107  		path := filepath.Join(sysModuleDir, module)
   108  		err = os.MkdirAll(path, testDirMode)
   109  		assert.NoError(err)
   110  
   111  		paramDir := filepath.Join(path, "parameters")
   112  		err = os.MkdirAll(paramDir, testDirMode)
   113  		assert.NoError(err)
   114  
   115  		for param, value := range details.parameters {
   116  			paramPath := filepath.Join(paramDir, param)
   117  			err = createFile(paramPath, value)
   118  			assert.NoError(err)
   119  		}
   120  	}
   121  
   122  	count, err = checkKernelModules(expectedKernelModules, handler)
   123  
   124  	if expectHandlerError {
   125  		assert.Error(err)
   126  		return
   127  	}
   128  
   129  	assert.NoError(err)
   130  	assert.Equal(count, expectedErrorCount)
   131  }
   132  
   133  func makeCPUInfoFile(path, vendorID, flags string) error {
   134  	t := template.New("cpuinfo")
   135  
   136  	t, err := t.Parse(testCPUInfoTemplate)
   137  	if err != nil {
   138  		return err
   139  	}
   140  
   141  	args := map[string]string{
   142  		"Flags":    flags,
   143  		"VendorID": vendorID,
   144  	}
   145  
   146  	contents := &bytes.Buffer{}
   147  
   148  	err = t.Execute(contents, args)
   149  	if err != nil {
   150  		return err
   151  	}
   152  
   153  	return ioutil.WriteFile(path, contents.Bytes(), testFileMode)
   154  }
   155  
   156  // nolint: unused, deadcode
   157  func genericTestGetCPUDetails(t *testing.T, validVendor string, validModel string, validContents string, data []testCPUDetail) {
   158  	tmpdir, err := ioutil.TempDir("", "")
   159  	if err != nil {
   160  		panic(err)
   161  	}
   162  	defer os.RemoveAll(tmpdir)
   163  
   164  	savedProcCPUInfo := procCPUInfo
   165  
   166  	testProcCPUInfo := filepath.Join(tmpdir, "cpuinfo")
   167  
   168  	// override
   169  	procCPUInfo = testProcCPUInfo
   170  
   171  	defer func() {
   172  		procCPUInfo = savedProcCPUInfo
   173  	}()
   174  
   175  	_, _, err = getCPUDetails()
   176  	// ENOENT
   177  	assert.Error(t, err)
   178  	assert.True(t, os.IsNotExist(err))
   179  
   180  	for _, d := range data {
   181  		err := createFile(procCPUInfo, d.contents)
   182  		assert.NoError(t, err)
   183  
   184  		vendor, model, err := getCPUDetails()
   185  
   186  		if d.expectError {
   187  			assert.Error(t, err, fmt.Sprintf("%+v", d))
   188  			continue
   189  		} else {
   190  			assert.NoError(t, err, fmt.Sprintf("%+v", d))
   191  			assert.Equal(t, d.expectedVendor, vendor)
   192  			assert.Equal(t, d.expectedModel, model)
   193  		}
   194  	}
   195  }
   196  
   197  func genericCheckCLIFunction(t *testing.T, cpuData []testCPUData, moduleData []testModuleData) {
   198  	assert := assert.New(t)
   199  
   200  	dir, err := ioutil.TempDir("", "")
   201  	if err != nil {
   202  		t.Fatal(err)
   203  	}
   204  	defer os.RemoveAll(dir)
   205  
   206  	_, config, err := makeRuntimeConfig(dir)
   207  	assert.NoError(err)
   208  
   209  	savedSysModuleDir := sysModuleDir
   210  	savedProcCPUInfo := procCPUInfo
   211  
   212  	cpuInfoFile := filepath.Join(dir, "cpuinfo")
   213  
   214  	// XXX: override
   215  	sysModuleDir = filepath.Join(dir, "sys/module")
   216  	procCPUInfo = cpuInfoFile
   217  
   218  	defer func() {
   219  		sysModuleDir = savedSysModuleDir
   220  		procCPUInfo = savedProcCPUInfo
   221  	}()
   222  
   223  	// Replace sysModuleDir in moduleData with the test temp path
   224  	for i := range moduleData {
   225  		moduleData[i].path = strings.Replace(moduleData[i].path, savedSysModuleDir, sysModuleDir, 1)
   226  	}
   227  
   228  	err = os.MkdirAll(sysModuleDir, testDirMode)
   229  	if err != nil {
   230  		t.Fatal(err)
   231  	}
   232  
   233  	devNull, err := os.OpenFile(os.DevNull, os.O_WRONLY, 0666)
   234  	assert.NoError(err)
   235  	defer devNull.Close()
   236  
   237  	savedLogOutput := kataLog.Logger.Out
   238  
   239  	// discard normal output
   240  	kataLog.Logger.Out = devNull
   241  
   242  	defer func() {
   243  		kataLog.Logger.Out = savedLogOutput
   244  	}()
   245  
   246  	setupCheckHostIsVMContainerCapable(assert, cpuInfoFile, cpuData, moduleData)
   247  
   248  	flagSet := &flag.FlagSet{}
   249  	ctx := createCLIContext(flagSet)
   250  	ctx.App.Name = "foo"
   251  	ctx.App.Metadata["runtimeConfig"] = config
   252  
   253  	// create buffer to save logger output
   254  	buf := &bytes.Buffer{}
   255  
   256  	// capture output this time
   257  	kataLog.Logger.Out = buf
   258  
   259  	fn, ok := kataCheckCLICommand.Action.(func(context *cli.Context) error)
   260  	assert.True(ok)
   261  
   262  	err = fn(ctx)
   263  	assert.NoError(err)
   264  
   265  	output := buf.String()
   266  
   267  	for _, c := range cpuData {
   268  		if c == fakeCPUData {
   269  			continue
   270  		}
   271  
   272  		assert.True(findAnchoredString(output, c.vendorID))
   273  		for _, flag := range strings.Fields(c.flags) {
   274  			assert.True(findAnchoredString(output, flag))
   275  		}
   276  	}
   277  
   278  	for _, m := range moduleData {
   279  		name := path.Base(m.path)
   280  		assert.True(findAnchoredString(output, name))
   281  	}
   282  }
   283  func TestCheckGetCPUInfo(t *testing.T) {
   284  	assert := assert.New(t)
   285  
   286  	type testData struct {
   287  		contents       string
   288  		expectedResult string
   289  		expectError    bool
   290  	}
   291  
   292  	data := []testData{
   293  		{"", "", true},
   294  		{" ", "", true},
   295  		{"\n", "", true},
   296  		{"\n\n", "", true},
   297  		{"hello\n", "hello", false},
   298  		{"foo\n\n", "foo", false},
   299  		{"foo\n\nbar\n\n", "foo", false},
   300  		{"foo\n\nbar\nbaz\n\n", "foo", false},
   301  	}
   302  
   303  	dir, err := ioutil.TempDir("", "")
   304  	if err != nil {
   305  		t.Fatal(err)
   306  	}
   307  	defer os.RemoveAll(dir)
   308  
   309  	file := filepath.Join(dir, "cpuinfo")
   310  	// file doesn't exist
   311  	_, err = getCPUInfo(file)
   312  	assert.Error(err)
   313  
   314  	for _, d := range data {
   315  		err = ioutil.WriteFile(file, []byte(d.contents), testFileMode)
   316  		if err != nil {
   317  			t.Fatal(err)
   318  		}
   319  		defer os.Remove(file)
   320  
   321  		contents, err := getCPUInfo(file)
   322  		if d.expectError {
   323  			assert.Error(err, fmt.Sprintf("got %q, test data: %+v", contents, d))
   324  		} else {
   325  			assert.NoError(err, fmt.Sprintf("got %q, test data: %+v", contents, d))
   326  		}
   327  
   328  		assert.Equal(d.expectedResult, contents)
   329  	}
   330  }
   331  
   332  func TestCheckFindAnchoredString(t *testing.T) {
   333  	assert := assert.New(t)
   334  
   335  	type testData struct {
   336  		haystack      string
   337  		needle        string
   338  		expectSuccess bool
   339  	}
   340  
   341  	data := []testData{
   342  		{"", "", false},
   343  		{"", "foo", false},
   344  		{"foo", "", false},
   345  		{"food", "foo", false},
   346  		{"foo", "foo", true},
   347  		{"foo bar", "foo", true},
   348  		{"foo bar baz", "bar", true},
   349  	}
   350  
   351  	for _, d := range data {
   352  		result := findAnchoredString(d.haystack, d.needle)
   353  
   354  		if d.expectSuccess {
   355  			assert.True(result)
   356  		} else {
   357  			assert.False(result)
   358  		}
   359  	}
   360  }
   361  
   362  func TestCheckGetCPUFlags(t *testing.T) {
   363  	assert := assert.New(t)
   364  
   365  	type testData struct {
   366  		cpuinfo       string
   367  		expectedFlags string
   368  	}
   369  
   370  	data := []testData{
   371  		{"", ""},
   372  		{"foo", ""},
   373  		{"foo bar", ""},
   374  		{":", ""},
   375  
   376  		{
   377  			cpuFlagsTag,
   378  			"",
   379  		},
   380  		{
   381  			cpuFlagsTag + ":",
   382  			"",
   383  		},
   384  		{
   385  			fmt.Sprintf("%s: a b c", cpuFlagsTag),
   386  			"a b c",
   387  		},
   388  		{
   389  			fmt.Sprintf("%s: a b c foo bar d", cpuFlagsTag),
   390  			"a b c foo bar d",
   391  		},
   392  	}
   393  
   394  	for _, d := range data {
   395  		result := getCPUFlags(d.cpuinfo)
   396  		assert.Equal(d.expectedFlags, result)
   397  	}
   398  }
   399  
   400  func TestCheckCheckCPUFlags(t *testing.T) {
   401  	assert := assert.New(t)
   402  
   403  	type testData struct {
   404  		cpuflags    string
   405  		required    map[string]string
   406  		expectCount uint32
   407  	}
   408  
   409  	data := []testData{
   410  		{
   411  			"",
   412  			map[string]string{},
   413  			0,
   414  		},
   415  		{
   416  			"",
   417  			map[string]string{
   418  				"a": "A flag",
   419  			},
   420  			0,
   421  		},
   422  		{
   423  			"",
   424  			map[string]string{
   425  				"a": "A flag",
   426  				"b": "B flag",
   427  			},
   428  			0,
   429  		},
   430  		{
   431  			"a b c",
   432  			map[string]string{
   433  				"b": "B flag",
   434  			},
   435  			0,
   436  		},
   437  		{
   438  			"a b c",
   439  			map[string]string{
   440  				"x": "X flag",
   441  				"y": "Y flag",
   442  				"z": "Z flag",
   443  			},
   444  			3,
   445  		},
   446  	}
   447  
   448  	for _, d := range data {
   449  		count := checkCPUFlags(d.cpuflags, d.required)
   450  		assert.Equal(d.expectCount, count, "%+v", d)
   451  	}
   452  }
   453  
   454  func TestCheckCheckCPUAttribs(t *testing.T) {
   455  	assert := assert.New(t)
   456  
   457  	type testData struct {
   458  		cpuinfo     string
   459  		required    map[string]string
   460  		expectCount uint32
   461  	}
   462  
   463  	data := []testData{
   464  		{
   465  			"",
   466  			map[string]string{},
   467  			0,
   468  		},
   469  		{
   470  			"",
   471  			map[string]string{
   472  				"a": "",
   473  			},
   474  			0,
   475  		},
   476  		{
   477  			"a: b",
   478  			map[string]string{
   479  				"b": "B attribute",
   480  			},
   481  			0,
   482  		},
   483  		{
   484  			"a: b\nc: d\ne: f",
   485  			map[string]string{
   486  				"b": "B attribute",
   487  			},
   488  			0,
   489  		},
   490  		{
   491  			"a: b\n",
   492  			map[string]string{
   493  				"b": "B attribute",
   494  				"c": "C attribute",
   495  				"d": "D attribute",
   496  			},
   497  			2,
   498  		},
   499  		{
   500  			"a: b\nc: d\ne: f",
   501  			map[string]string{
   502  				"b": "B attribute",
   503  				"d": "D attribute",
   504  				"f": "F attribute",
   505  			},
   506  			0,
   507  		},
   508  	}
   509  
   510  	for _, d := range data {
   511  		count := checkCPUAttribs(d.cpuinfo, d.required)
   512  		assert.Equal(d.expectCount, count, "%+v", d)
   513  	}
   514  }
   515  
   516  func TestCheckHaveKernelModule(t *testing.T) {
   517  	t.Skip(testDisabledAsNonRoot)
   518  
   519  	assert := assert.New(t)
   520  
   521  	dir, err := ioutil.TempDir("", "")
   522  	if err != nil {
   523  		t.Fatal(err)
   524  	}
   525  	defer os.RemoveAll(dir)
   526  
   527  	savedModProbeCmd := modProbeCmd
   528  	savedSysModuleDir := sysModuleDir
   529  
   530  	// XXX: override (fake the modprobe command failing)
   531  	modProbeCmd = "false"
   532  	sysModuleDir = filepath.Join(dir, "sys/module")
   533  
   534  	defer func() {
   535  		modProbeCmd = savedModProbeCmd
   536  		sysModuleDir = savedSysModuleDir
   537  	}()
   538  
   539  	err = os.MkdirAll(sysModuleDir, testDirMode)
   540  	if err != nil {
   541  		t.Fatal(err)
   542  	}
   543  
   544  	module := "foo"
   545  
   546  	result := haveKernelModule(module)
   547  	assert.False(result)
   548  
   549  	// XXX: override - make our fake "modprobe" succeed
   550  	modProbeCmd = "true"
   551  
   552  	result = haveKernelModule(module)
   553  	assert.True(result)
   554  
   555  	// disable "modprobe" again
   556  	modProbeCmd = "false"
   557  
   558  	fooDir := filepath.Join(sysModuleDir, module)
   559  	err = os.MkdirAll(fooDir, testDirMode)
   560  	if err != nil {
   561  		t.Fatal(err)
   562  	}
   563  
   564  	result = haveKernelModule(module)
   565  	assert.True(result)
   566  }
   567  
   568  func TestCheckCheckKernelModules(t *testing.T) {
   569  	assert := assert.New(t)
   570  
   571  	dir, err := ioutil.TempDir("", "")
   572  	if err != nil {
   573  		t.Fatal(err)
   574  	}
   575  	defer os.RemoveAll(dir)
   576  
   577  	savedModProbeCmd := modProbeCmd
   578  	savedSysModuleDir := sysModuleDir
   579  
   580  	// XXX: override (fake the modprobe command failing)
   581  	modProbeCmd = "false"
   582  	sysModuleDir = filepath.Join(dir, "sys/module")
   583  
   584  	defer func() {
   585  		modProbeCmd = savedModProbeCmd
   586  		sysModuleDir = savedSysModuleDir
   587  	}()
   588  
   589  	err = os.MkdirAll(sysModuleDir, testDirMode)
   590  	if err != nil {
   591  		t.Fatal(err)
   592  	}
   593  
   594  	testData := map[string]kernelModule{
   595  		"foo": {
   596  			desc:       "desc",
   597  			parameters: map[string]string{},
   598  			required:   true,
   599  		},
   600  		"bar": {
   601  			desc: "desc",
   602  			parameters: map[string]string{
   603  				"param1": "hello",
   604  				"param2": "world",
   605  				"param3": "a",
   606  				"param4": ".",
   607  			},
   608  			required: true,
   609  		},
   610  	}
   611  
   612  	count, err := checkKernelModules(map[string]kernelModule{}, nil)
   613  	// No required modules means no error
   614  	assert.NoError(err)
   615  	assert.Equal(count, uint32(0))
   616  
   617  	count, err = checkKernelModules(testData, nil)
   618  	assert.NoError(err)
   619  	// No modules exist
   620  	assert.Equal(count, uint32(2))
   621  
   622  	for module, details := range testData {
   623  		path := filepath.Join(sysModuleDir, module)
   624  		err = os.MkdirAll(path, testDirMode)
   625  		if err != nil {
   626  			t.Fatal(err)
   627  		}
   628  
   629  		paramDir := filepath.Join(path, "parameters")
   630  		err = os.MkdirAll(paramDir, testDirMode)
   631  		if err != nil {
   632  			t.Fatal(err)
   633  		}
   634  
   635  		for param, value := range details.parameters {
   636  			paramPath := filepath.Join(paramDir, param)
   637  			err = createFile(paramPath, value)
   638  			if err != nil {
   639  				t.Fatal(err)
   640  			}
   641  		}
   642  	}
   643  
   644  	count, err = checkKernelModules(testData, nil)
   645  	assert.NoError(err)
   646  	assert.Equal(count, uint32(0))
   647  }
   648  
   649  func TestCheckCheckKernelModulesUnreadableFile(t *testing.T) {
   650  	assert := assert.New(t)
   651  
   652  	if tc.NotValid(ktu.NeedNonRoot()) {
   653  		t.Skip(ktu.TestDisabledNeedNonRoot)
   654  	}
   655  
   656  	dir, err := ioutil.TempDir("", "")
   657  	if err != nil {
   658  		t.Fatal(err)
   659  	}
   660  	defer os.RemoveAll(dir)
   661  
   662  	testData := map[string]kernelModule{
   663  		"foo": {
   664  			desc: "desc",
   665  			parameters: map[string]string{
   666  				"param1": "wibble",
   667  			},
   668  			required: true,
   669  		},
   670  	}
   671  
   672  	savedModProbeCmd := modProbeCmd
   673  	savedSysModuleDir := sysModuleDir
   674  
   675  	// XXX: override (fake the modprobe command failing)
   676  	modProbeCmd = "false"
   677  	sysModuleDir = filepath.Join(dir, "sys/module")
   678  
   679  	defer func() {
   680  		modProbeCmd = savedModProbeCmd
   681  		sysModuleDir = savedSysModuleDir
   682  	}()
   683  
   684  	modPath := filepath.Join(sysModuleDir, "foo/parameters")
   685  	err = os.MkdirAll(modPath, testDirMode)
   686  	assert.NoError(err)
   687  
   688  	modParamFile := filepath.Join(modPath, "param1")
   689  
   690  	err = createEmptyFile(modParamFile)
   691  	assert.NoError(err)
   692  
   693  	// make file unreadable by non-root user
   694  	err = os.Chmod(modParamFile, 0000)
   695  	assert.NoError(err)
   696  
   697  	_, err = checkKernelModules(testData, nil)
   698  	assert.Error(err)
   699  }
   700  
   701  func TestCheckCheckKernelModulesInvalidFileContents(t *testing.T) {
   702  	assert := assert.New(t)
   703  
   704  	dir, err := ioutil.TempDir("", "")
   705  	if err != nil {
   706  		t.Fatal(err)
   707  	}
   708  	defer os.RemoveAll(dir)
   709  
   710  	testData := map[string]kernelModule{
   711  		"foo": {
   712  			desc: "desc",
   713  			parameters: map[string]string{
   714  				"param1": "wibble",
   715  			},
   716  			required: true,
   717  		},
   718  	}
   719  
   720  	savedModProbeCmd := modProbeCmd
   721  	savedSysModuleDir := sysModuleDir
   722  
   723  	// XXX: override (fake the modprobe command failing)
   724  	modProbeCmd = "false"
   725  	sysModuleDir = filepath.Join(dir, "sys/module")
   726  
   727  	defer func() {
   728  		modProbeCmd = savedModProbeCmd
   729  		sysModuleDir = savedSysModuleDir
   730  	}()
   731  
   732  	modPath := filepath.Join(sysModuleDir, "foo/parameters")
   733  	err = os.MkdirAll(modPath, testDirMode)
   734  	assert.NoError(err)
   735  
   736  	modParamFile := filepath.Join(modPath, "param1")
   737  
   738  	err = createFile(modParamFile, "burp")
   739  	assert.NoError(err)
   740  
   741  	count, err := checkKernelModules(testData, nil)
   742  	assert.NoError(err)
   743  	assert.Equal(count, uint32(1))
   744  }
   745  
   746  func TestCheckCLIFunctionFail(t *testing.T) {
   747  	assert := assert.New(t)
   748  
   749  	dir, err := ioutil.TempDir("", "")
   750  	if err != nil {
   751  		t.Fatal(err)
   752  	}
   753  	defer os.RemoveAll(dir)
   754  
   755  	_, config, err := makeRuntimeConfig(dir)
   756  	assert.NoError(err)
   757  
   758  	oldProcCPUInfo := procCPUInfo
   759  
   760  	// doesn't exist
   761  	procCPUInfo = filepath.Join(dir, "cpuinfo")
   762  
   763  	defer func() {
   764  		procCPUInfo = oldProcCPUInfo
   765  	}()
   766  
   767  	flagSet := &flag.FlagSet{}
   768  	ctx := createCLIContext(flagSet)
   769  	ctx.App.Name = "foo"
   770  	ctx.App.Metadata["runtimeConfig"] = config
   771  
   772  	fn, ok := kataCheckCLICommand.Action.(func(context *cli.Context) error)
   773  	assert.True(ok)
   774  
   775  	err = fn(ctx)
   776  	assert.Error(err)
   777  }
   778  
   779  func TestCheckKernelParamHandler(t *testing.T) {
   780  	assert := assert.New(t)
   781  
   782  	dir, err := ioutil.TempDir("", "")
   783  	if err != nil {
   784  		t.Fatal(err)
   785  	}
   786  	defer os.RemoveAll(dir)
   787  
   788  	savedModProbeCmd := modProbeCmd
   789  	savedSysModuleDir := sysModuleDir
   790  
   791  	// XXX: override (fake the modprobe command failing)
   792  	modProbeCmd = "false"
   793  	sysModuleDir = filepath.Join(dir, "sys/module")
   794  
   795  	defer func() {
   796  		modProbeCmd = savedModProbeCmd
   797  		sysModuleDir = savedSysModuleDir
   798  	}()
   799  
   800  	handler := func(onVMM bool, fields logrus.Fields, msg string) bool {
   801  		param, ok := fields["parameter"].(string)
   802  		if !ok {
   803  			return false
   804  		}
   805  
   806  		if param == "param1" {
   807  			return true
   808  		}
   809  
   810  		// don't ignore the error
   811  		return false
   812  	}
   813  
   814  	testData1 := map[string]kernelModule{
   815  		"foo": {
   816  			desc:       "desc",
   817  			parameters: map[string]string{},
   818  			required:   true,
   819  		},
   820  		"bar": {
   821  			desc: "desc",
   822  			parameters: map[string]string{
   823  				"param1": "hello",
   824  				"param2": "world",
   825  			},
   826  			required: true,
   827  		},
   828  	}
   829  
   830  	checkKernelParamHandler(assert, testData1, testData1, handler, false, uint32(0))
   831  
   832  	testDataToCreate := map[string]kernelModule{
   833  		"foo": {
   834  			desc: "desc",
   835  			parameters: map[string]string{
   836  				"param1": "moo",
   837  			},
   838  			required: true,
   839  		},
   840  	}
   841  
   842  	testDataToExpect := map[string]kernelModule{
   843  		"foo": {
   844  			desc: "desc",
   845  			parameters: map[string]string{
   846  				"param1": "bar",
   847  			},
   848  			required: true,
   849  		},
   850  	}
   851  
   852  	// Expected and actual are different, but the handler should deal with
   853  	// the problem.
   854  	checkKernelParamHandler(assert, testDataToCreate, testDataToExpect, handler, false, uint32(0))
   855  
   856  	// Expected and actual are different, so with no handler we expect a
   857  	// single error (due to "param1"'s value being different)
   858  	checkKernelParamHandler(assert, testDataToCreate, testDataToExpect, nil, false, uint32(1))
   859  }
   860  
   861  func TestArchRequiredKernelModules(t *testing.T) {
   862  	assert := assert.New(t)
   863  
   864  	tmpdir, err := ioutil.TempDir("", "")
   865  	assert.NoError(err)
   866  	defer os.RemoveAll(tmpdir)
   867  
   868  	_, config, err := makeRuntimeConfig(tmpdir)
   869  	assert.NoError(err)
   870  
   871  	err = setCPUtype(config.HypervisorType)
   872  	assert.NoError(err)
   873  
   874  	if len(archRequiredKernelModules) == 0 {
   875  		// No modules to check
   876  		return
   877  	}
   878  
   879  	dir, err := ioutil.TempDir("", "")
   880  	if err != nil {
   881  		t.Fatal(err)
   882  	}
   883  	defer os.RemoveAll(dir)
   884  
   885  	savedModProbeCmd := modProbeCmd
   886  	savedSysModuleDir := sysModuleDir
   887  
   888  	// XXX: override
   889  	sysModuleDir = filepath.Join(dir, "sys/module")
   890  	modProbeCmd = "false"
   891  
   892  	defer func() {
   893  		sysModuleDir = savedSysModuleDir
   894  		modProbeCmd = savedModProbeCmd
   895  	}()
   896  
   897  	// Running check with no modules
   898  	count, err := checkKernelModules(archRequiredKernelModules, nil)
   899  	assert.NoError(err)
   900  
   901  	// Test that count returned matches the # of modules with required set.
   902  	expectedCount := 0
   903  	for _, module := range archRequiredKernelModules {
   904  		if module.required {
   905  			expectedCount++
   906  		}
   907  	}
   908  
   909  	assert.EqualValues(count, expectedCount)
   910  }
   911  
   912  func TestCheckVersionConsistencyInComponents(t *testing.T) {
   913  	type testData struct {
   914  		proxyExist     bool
   915  		expectError    bool
   916  		shimVersion    string
   917  		proxyVersion   string
   918  		runtimeVersion string
   919  	}
   920  
   921  	data := []testData{
   922  		{
   923  			true,
   924  			true,
   925  			"kata-shim version 0.2.0-rc0-xxxxxxxxxxxxx",
   926  			"kata-proxy version 0.1.0-rc0-xxxxxxxxxxxxx",
   927  			"0.2.0-rc0",
   928  		},
   929  		{
   930  			true,
   931  			true,
   932  			"kata-shim version 0.1.0-rc0-xxxxxxxxxxxxx",
   933  			"kata-proxy version 0.2.0-rc0-xxxxxxxxxxxxx",
   934  			"0.2.0-rc0",
   935  		},
   936  		{
   937  			true,
   938  			true,
   939  			"kata-shim version 0.1.0-rc0-xxxxxxxxxxxxx",
   940  			"kata-proxy version 0.1.0-rc0-xxxxxxxxxxxxx",
   941  			"0.2.0-rc0",
   942  		},
   943  		{
   944  			true,
   945  			false,
   946  			"kata-shim version 0.2.0-rc0-xxxxxxxxxxxxx",
   947  			"kata-proxy version 0.2.0-rc0-xxxxxxxxxxxxx",
   948  			"0.2.0-rc0",
   949  		},
   950  		{
   951  			false,
   952  			true,
   953  			"kata-shim version 0.1.0-rc0-xxxxxxxxxxxxx",
   954  			"",
   955  			"0.2.0-rc0",
   956  		},
   957  		{
   958  			false,
   959  			false,
   960  			"kata-shim version 0.2.0-rc0-xxxxxxxxxxxxx",
   961  			"",
   962  			"0.2.0-rc0",
   963  		},
   964  		{
   965  			false,
   966  			false,
   967  			"kata-shim version 0.2.0-xxxxxxxxxxxxx",
   968  			"",
   969  			"0.2.0",
   970  		},
   971  	}
   972  
   973  	origVersion := version
   974  	for _, d := range data {
   975  		tmpdir, err := ioutil.TempDir("", "")
   976  		assert.NoError(t, err)
   977  		defer os.RemoveAll(tmpdir)
   978  
   979  		testShimVersion = d.shimVersion
   980  		if d.proxyExist {
   981  			testProxyVersion = d.proxyVersion
   982  		}
   983  		_, config, err := makeRuntimeConfig(tmpdir)
   984  		assert.NoError(t, err)
   985  		if !d.proxyExist {
   986  			config.ProxyType = vc.NoProxyType
   987  		}
   988  		version = d.runtimeVersion
   989  		defer func() {
   990  			version = origVersion
   991  		}()
   992  
   993  		err = checkVersionConsistencyInComponents(config)
   994  		if d.expectError {
   995  			assert.Error(t, err, fmt.Sprintf("%+v", d))
   996  			continue
   997  		} else {
   998  			assert.NoError(t, err, fmt.Sprintf("%+v", d))
   999  		}
  1000  	}
  1001  }