gitee.com/mysnapcore/mysnapd@v0.1.0/cmd/snap-bootstrap/triggerwatch/triggerwatch_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2020 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 triggerwatch_test
    21  
    22  import (
    23  	"errors"
    24  	"fmt"
    25  	"testing"
    26  	"time"
    27  
    28  	. "gopkg.in/check.v1"
    29  
    30  	"gitee.com/mysnapcore/mysnapd/cmd/snap-bootstrap/triggerwatch"
    31  	"gitee.com/mysnapcore/mysnapd/osutil/udev/netlink"
    32  )
    33  
    34  // Hook up check.v1 into the "go test" runner
    35  func Test(t *testing.T) { TestingT(t) }
    36  
    37  type triggerwatchSuite struct{}
    38  
    39  var _ = Suite(&triggerwatchSuite{})
    40  
    41  type mockTriggerDevice struct {
    42  	waitForTriggerCalls int
    43  	closeCalls          int
    44  	ev                  *triggerwatch.KeyEvent
    45  }
    46  
    47  func (m *mockTriggerDevice) WaitForTrigger(n chan triggerwatch.KeyEvent) {
    48  	m.waitForTriggerCalls++
    49  	if m.ev != nil {
    50  		ev := *m.ev
    51  		ev.Dev = m
    52  		n <- ev
    53  	}
    54  }
    55  
    56  func (m *mockTriggerDevice) String() string { return "mock-device" }
    57  func (m *mockTriggerDevice) Close()         { m.closeCalls++ }
    58  
    59  type mockTrigger struct {
    60  	f               triggerwatch.TriggerCapabilityFilter
    61  	d               *mockTriggerDevice
    62  	unlistedDevices map[string]*mockTriggerDevice
    63  
    64  	err error
    65  
    66  	findMatchingCalls int
    67  	openCalls         int
    68  }
    69  
    70  func (m *mockTrigger) FindMatchingDevices(f triggerwatch.TriggerCapabilityFilter) ([]triggerwatch.TriggerDevice, error) {
    71  	m.findMatchingCalls++
    72  
    73  	m.f = f
    74  	if m.err != nil {
    75  		return nil, m.err
    76  	}
    77  	if m.d != nil {
    78  		return []triggerwatch.TriggerDevice{m.d}, nil
    79  	}
    80  	return nil, nil
    81  }
    82  
    83  func (m *mockTrigger) Open(filter triggerwatch.TriggerCapabilityFilter, node string) (triggerwatch.TriggerDevice, error) {
    84  	m.openCalls++
    85  	device, ok := m.unlistedDevices[node]
    86  	if !ok {
    87  		return nil, errors.New("Not found")
    88  	} else {
    89  		return device, nil
    90  	}
    91  }
    92  
    93  const testTriggerTimeout = 5 * time.Millisecond
    94  const testDeviceTimeout = 2 * time.Millisecond
    95  
    96  func (s *triggerwatchSuite) TestNoDevsWaitKey(c *C) {
    97  	md := &mockTriggerDevice{ev: &triggerwatch.KeyEvent{}}
    98  	mi := &mockTrigger{d: md}
    99  	restore := triggerwatch.MockInput(mi)
   100  	defer restore()
   101  
   102  	err := triggerwatch.Wait(testTriggerTimeout, testDeviceTimeout)
   103  	c.Assert(err, IsNil)
   104  	c.Assert(mi.findMatchingCalls, Equals, 1)
   105  	c.Assert(md.waitForTriggerCalls, Equals, 1)
   106  	c.Assert(md.closeCalls, Equals, 1)
   107  }
   108  
   109  func (s *triggerwatchSuite) TestNoDevsWaitKeyTimeout(c *C) {
   110  	md := &mockTriggerDevice{}
   111  	mi := &mockTrigger{d: md}
   112  	restore := triggerwatch.MockInput(mi)
   113  	defer restore()
   114  
   115  	err := triggerwatch.Wait(testTriggerTimeout, testDeviceTimeout)
   116  	c.Assert(err, Equals, triggerwatch.ErrTriggerNotDetected)
   117  	c.Assert(mi.findMatchingCalls, Equals, 1)
   118  	c.Assert(md.waitForTriggerCalls, Equals, 1)
   119  	c.Assert(md.closeCalls, Equals, 1)
   120  }
   121  
   122  func (s *triggerwatchSuite) TestNoDevsWaitNoMatching(c *C) {
   123  	mi := &mockTrigger{}
   124  	restore := triggerwatch.MockInput(mi)
   125  	defer restore()
   126  
   127  	err := triggerwatch.Wait(testTriggerTimeout, testDeviceTimeout)
   128  	c.Assert(err, Equals, triggerwatch.ErrNoMatchingInputDevices)
   129  }
   130  
   131  func (s *triggerwatchSuite) TestNoDevsWaitMatchingError(c *C) {
   132  	mi := &mockTrigger{err: fmt.Errorf("failed")}
   133  	restore := triggerwatch.MockInput(mi)
   134  	defer restore()
   135  
   136  	err := triggerwatch.Wait(testTriggerTimeout, testDeviceTimeout)
   137  	c.Assert(err, ErrorMatches, "cannot list trigger devices: failed")
   138  }
   139  
   140  func (s *triggerwatchSuite) TestChecksInput(c *C) {
   141  	restore := triggerwatch.MockInput(nil)
   142  	defer restore()
   143  
   144  	c.Assert(func() { triggerwatch.Wait(testTriggerTimeout, testDeviceTimeout) },
   145  		Panics, "trigger is unset")
   146  }
   147  
   148  func (s *triggerwatchSuite) TestUdevEvent(c *C) {
   149  	nodepath := "/dev/input/event0"
   150  	devpath := "/devices/SOMEBUS/input/input0/event0"
   151  
   152  	md := &mockTriggerDevice{ev: &triggerwatch.KeyEvent{}}
   153  	mi := &mockTrigger{
   154  		unlistedDevices: map[string]*mockTriggerDevice{
   155  			"/dev/input/event0": md,
   156  		},
   157  	}
   158  	restore := triggerwatch.MockInput(mi)
   159  	defer restore()
   160  
   161  	events := []netlink.UEvent{
   162  		{
   163  			Action: netlink.ADD,
   164  			KObj:   devpath,
   165  			Env: map[string]string{
   166  				"SUBSYSTEM": "input",
   167  				"DEVNAME":   nodepath,
   168  				"DEVPATH":   devpath,
   169  			},
   170  		},
   171  	}
   172  	restoreUevents := triggerwatch.MockUEvent(events)
   173  	defer restoreUevents()
   174  
   175  	err := triggerwatch.Wait(testTriggerTimeout, testDeviceTimeout)
   176  	c.Assert(err, IsNil)
   177  	c.Assert(mi.findMatchingCalls, Equals, 1)
   178  
   179  	c.Assert(mi.openCalls, Equals, 1)
   180  	c.Assert(md.waitForTriggerCalls, Equals, 1)
   181  	c.Assert(md.closeCalls, Equals, 1)
   182  }
   183  
   184  func (s *triggerwatchSuite) TestUdevEventNoKeyEvent(c *C) {
   185  	nodepath := "/dev/input/event0"
   186  	devpath := "/devices/SOMEBUS/input/input0/event0"
   187  
   188  	md := &mockTriggerDevice{}
   189  	mi := &mockTrigger{
   190  		unlistedDevices: map[string]*mockTriggerDevice{
   191  			"/dev/input/event0": md,
   192  		},
   193  	}
   194  	restore := triggerwatch.MockInput(mi)
   195  	defer restore()
   196  
   197  	events := []netlink.UEvent{
   198  		{
   199  			Action: netlink.ADD,
   200  			KObj:   devpath,
   201  			Env: map[string]string{
   202  				"SUBSYSTEM": "input",
   203  				"DEVNAME":   nodepath,
   204  				"DEVPATH":   devpath,
   205  			},
   206  		},
   207  	}
   208  	restoreUevents := triggerwatch.MockUEvent(events)
   209  	defer restoreUevents()
   210  
   211  	err := triggerwatch.Wait(testTriggerTimeout, testDeviceTimeout)
   212  	c.Assert(err, Equals, triggerwatch.ErrTriggerNotDetected)
   213  	c.Assert(mi.findMatchingCalls, Equals, 1)
   214  
   215  	c.Assert(mi.openCalls, Equals, 1)
   216  	c.Assert(md.waitForTriggerCalls, Equals, 1)
   217  	c.Assert(md.closeCalls, Equals, 1)
   218  }