gitee.com/mysnapcore/mysnapd@v0.1.0/interfaces/builtin/kernel_module_load_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2021 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package builtin_test
    21  
    22  import (
    23  	"fmt"
    24  
    25  	. "gopkg.in/check.v1"
    26  
    27  	"gitee.com/mysnapcore/mysnapd/interfaces"
    28  	"gitee.com/mysnapcore/mysnapd/interfaces/builtin"
    29  	"gitee.com/mysnapcore/mysnapd/interfaces/kmod"
    30  	"gitee.com/mysnapcore/mysnapd/snap"
    31  	"gitee.com/mysnapcore/mysnapd/testutil"
    32  )
    33  
    34  type KernelModuleLoadInterfaceSuite struct {
    35  	testutil.BaseTest
    36  
    37  	iface    interfaces.Interface
    38  	slotInfo *snap.SlotInfo
    39  	slot     *interfaces.ConnectedSlot
    40  	plugInfo *snap.PlugInfo
    41  	plug     *interfaces.ConnectedPlug
    42  }
    43  
    44  var _ = Suite(&KernelModuleLoadInterfaceSuite{
    45  	iface: builtin.MustInterface("kernel-module-load"),
    46  })
    47  
    48  const kernelModuleLoadConsumerYaml = `name: consumer
    49  version: 0
    50  plugs:
    51   kmod:
    52    interface: kernel-module-load
    53    modules:
    54    - name: forbidden
    55      load: denied
    56    - name: mymodule1
    57      load: on-boot
    58      options: p1=3 p2=true p3
    59    - name: mymodule2
    60      options: param_1=ok param_2=false
    61    - name: expandvar
    62      options: opt=$FOO path=$SNAP_COMMON/bar
    63    - name: dyn-module1
    64      load: dynamic
    65      options: opt1=v1 opt2=v2
    66    - name: dyn-module2
    67      load: dynamic
    68      options: "*"
    69  apps:
    70   app:
    71    plugs: [kmod]
    72  `
    73  
    74  const kernelModuleLoadCoreYaml = `name: core
    75  version: 0
    76  type: os
    77  slots:
    78    kernel-module-load:
    79  `
    80  
    81  func (s *KernelModuleLoadInterfaceSuite) SetUpTest(c *C) {
    82  	s.BaseTest.SetUpTest(c)
    83  
    84  	s.plug, s.plugInfo = MockConnectedPlug(c, kernelModuleLoadConsumerYaml, nil, "kmod")
    85  	s.slot, s.slotInfo = MockConnectedSlot(c, kernelModuleLoadCoreYaml, nil, "kernel-module-load")
    86  }
    87  
    88  func (s *KernelModuleLoadInterfaceSuite) TestName(c *C) {
    89  	c.Assert(s.iface.Name(), Equals, "kernel-module-load")
    90  }
    91  
    92  func (s *KernelModuleLoadInterfaceSuite) TestSanitizeSlot(c *C) {
    93  	c.Assert(interfaces.BeforePrepareSlot(s.iface, s.slotInfo), IsNil)
    94  }
    95  
    96  func (s *KernelModuleLoadInterfaceSuite) TestSanitizePlug(c *C) {
    97  	c.Check(interfaces.BeforePreparePlug(s.iface, s.plugInfo), IsNil)
    98  	c.Check(interfaces.BeforeConnectPlug(s.iface, s.plug), IsNil)
    99  }
   100  
   101  func (s *KernelModuleLoadInterfaceSuite) TestSanitizePlugUnhappy(c *C) {
   102  	var kernelModuleLoadYaml = `name: consumer
   103  version: 0
   104  plugs:
   105   kmod:
   106    interface: kernel-module-load
   107    %s
   108  apps:
   109   app:
   110    plugs: [kmod]
   111  `
   112  	data := []struct {
   113  		plugYaml      string
   114  		expectedError string
   115  	}{
   116  		{
   117  			"", // missing "modules" attribute
   118  			`kernel-module-load "modules" attribute must be a list of dictionaries`,
   119  		},
   120  		{
   121  			"modules: a string",
   122  			`kernel-module-load "modules" attribute must be a list of dictionaries`,
   123  		},
   124  		{
   125  			"modules: [this, is, a, list]",
   126  			`kernel-module-load "modules" attribute must be a list of dictionaries`,
   127  		},
   128  		{
   129  			"modules:\n  - name: [this, is, a, list]",
   130  			`kernel-module-load "name" must be a string`,
   131  		},
   132  		{
   133  			"modules:\n  - name: w3/rd*",
   134  			`kernel-module-load "name" attribute is not a valid module name`,
   135  		},
   136  		{
   137  			"modules:\n  - name: pcspkr",
   138  			`kernel-module-load: must specify at least "load" or "options"`,
   139  		},
   140  		{
   141  			"modules:\n  - name: pcspkr\n    load: [yes, no]",
   142  			`kernel-module-load "load" must be a string`,
   143  		},
   144  		{
   145  			"modules:\n  - name: pcspkr\n    load: maybe",
   146  			`kernel-module-load "load" value is unrecognized: "maybe"`,
   147  		},
   148  		{
   149  			"modules:\n  - name: pcspkr\n    options: [one, two]",
   150  			`kernel-module-load "options" must be a string`,
   151  		},
   152  		{
   153  			"modules:\n  - name: pcspkr\n    options: \"a\\nnewline\"",
   154  			`kernel-module-load "options" attribute contains invalid characters: "a\\nnewline"`,
   155  		},
   156  		{
   157  			"modules:\n  - name: pcspkr\n    options: \"5tartWithNumber=1\"",
   158  			`kernel-module-load "options" attribute contains invalid characters: "5tartWithNumber=1"`,
   159  		},
   160  		{
   161  			"modules:\n  - name: pcspkr\n    options: \"no-dashes\"",
   162  			`kernel-module-load "options" attribute contains invalid characters: "no-dashes"`,
   163  		},
   164  		{
   165  			// "*" is only allowed for `load: dynamic`
   166  			"modules:\n  - name: pcspkr\n    options: \"*\"",
   167  			`kernel-module-load "options" attribute contains invalid characters: "\*"`,
   168  		},
   169  		{
   170  			"modules:\n  - name: pcspkr\n    load: denied\n    options: p1=true",
   171  			`kernel-module-load "options" attribute incompatible with "load: denied"`,
   172  		},
   173  	}
   174  
   175  	for _, testData := range data {
   176  		snapYaml := fmt.Sprintf(kernelModuleLoadYaml, testData.plugYaml)
   177  		plug, _ := MockConnectedPlug(c, snapYaml, nil, "kmod")
   178  		err := interfaces.BeforeConnectPlug(s.iface, plug)
   179  		c.Check(err, ErrorMatches, testData.expectedError, Commentf("yaml: %s", testData.plugYaml))
   180  	}
   181  }
   182  
   183  func (s *KernelModuleLoadInterfaceSuite) TestKModSpec(c *C) {
   184  	spec := &kmod.Specification{}
   185  	c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.slot), IsNil)
   186  	c.Check(spec.Modules(), DeepEquals, map[string]bool{
   187  		"mymodule1": true,
   188  	})
   189  	c.Check(spec.ModuleOptions(), DeepEquals, map[string]string{
   190  		"mymodule1":   "p1=3 p2=true p3",
   191  		"mymodule2":   "param_1=ok param_2=false",
   192  		"expandvar":   "opt=$FOO path=/var/snap/consumer/common/bar",
   193  		"dyn-module1": "opt1=v1 opt2=v2",
   194  		// No entry for dyn-module2, which has options set to "*"
   195  	})
   196  	c.Check(spec.DisallowedModules(), DeepEquals, []string{"forbidden"})
   197  }
   198  
   199  func (s *KernelModuleLoadInterfaceSuite) TestStaticInfo(c *C) {
   200  	si := interfaces.StaticInfoOf(s.iface)
   201  	c.Assert(si.ImplicitOnCore, Equals, true)
   202  	c.Assert(si.ImplicitOnClassic, Equals, true)
   203  	c.Assert(si.Summary, Equals, `allows constrained control over kernel module loading`)
   204  	c.Assert(si.BaseDeclarationSlots, testutil.Contains, "kernel-module-load")
   205  }
   206  
   207  func (s *KernelModuleLoadInterfaceSuite) TestAutoConnect(c *C) {
   208  	c.Assert(s.iface.AutoConnect(s.plugInfo, s.slotInfo), Equals, true)
   209  }
   210  
   211  func (s *KernelModuleLoadInterfaceSuite) TestInterfaces(c *C) {
   212  	c.Check(builtin.Interfaces(), testutil.DeepContains, s.iface)
   213  }