github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/overlord/hookstate/ctlcmd/is_connected_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2019 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 ctlcmd_test 21 22 import ( 23 "github.com/snapcore/snapd/dirs" 24 "github.com/snapcore/snapd/overlord/hookstate" 25 "github.com/snapcore/snapd/overlord/hookstate/ctlcmd" 26 "github.com/snapcore/snapd/overlord/hookstate/hooktest" 27 "github.com/snapcore/snapd/overlord/snapstate" 28 "github.com/snapcore/snapd/overlord/state" 29 "github.com/snapcore/snapd/snap" 30 "github.com/snapcore/snapd/snap/snaptest" 31 "github.com/snapcore/snapd/testutil" 32 33 . "gopkg.in/check.v1" 34 ) 35 36 type isConnectedSuite struct { 37 testutil.BaseTest 38 st *state.State 39 mockHandler *hooktest.MockHandler 40 } 41 42 var _ = Suite(&isConnectedSuite{}) 43 44 func (s *isConnectedSuite) SetUpTest(c *C) { 45 s.BaseTest.SetUpTest(c) 46 dirs.SetRootDir(c.MkDir()) 47 s.AddCleanup(func() { dirs.SetRootDir("/") }) 48 s.st = state.New(nil) 49 s.mockHandler = hooktest.NewMockHandler() 50 } 51 52 var isConnectedTests = []struct { 53 args []string 54 stdout, stderr, err string 55 exitCode int 56 }{{ 57 args: []string{"is-connected"}, 58 err: "the required argument `<plug|slot>` was not provided", 59 }, { 60 args: []string{"is-connected", "plug1"}, 61 }, { 62 args: []string{"is-connected", "slot1"}, 63 }, { 64 // reported as not connected because of undesired flag 65 args: []string{"is-connected", "plug2"}, 66 exitCode: 1, 67 }, { 68 // reported as not connected because of hotplug-gone flag 69 args: []string{"is-connected", "plug3"}, 70 exitCode: 1, 71 }, { 72 args: []string{"is-connected", "slot2"}, 73 err: `snap "snap1" has no plug or slot named "slot2"`, 74 }, { 75 args: []string{"is-connected", "foo"}, 76 err: `snap "snap1" has no plug or slot named "foo"`, 77 }} 78 79 func mockInstalledSnap(c *C, st *state.State, snapYaml string) { 80 info := snaptest.MockSnapCurrent(c, snapYaml, &snap.SideInfo{Revision: snap.R(1)}) 81 snapstate.Set(st, info.InstanceName(), &snapstate.SnapState{ 82 Active: true, 83 Sequence: []*snap.SideInfo{ 84 { 85 RealName: info.SnapName(), 86 Revision: info.Revision, 87 SnapID: info.InstanceName() + "-id", 88 }, 89 }, 90 Current: info.Revision, 91 }) 92 } 93 94 func (s *isConnectedSuite) testIsConnected(c *C, context *hookstate.Context) { 95 mockInstalledSnap(c, s.st, `name: snap1 96 plugs: 97 plug1: 98 interface: x11 99 plug2: 100 interface: x11 101 plug3: 102 interface: x11 103 slots: 104 slot1: 105 interface: x11`) 106 107 s.st.Set("conns", map[string]interface{}{ 108 "snap1:plug1 snap2:slot2": map[string]interface{}{}, 109 "snap1:plug2 snap3:slot3": map[string]interface{}{"undesired": true}, 110 "snap1:plug3 snap4:slot4": map[string]interface{}{"hotplug-gone": true}, 111 "snap3:plug4 snap1:slot1": map[string]interface{}{}, 112 }) 113 114 s.st.Unlock() 115 defer s.st.Lock() 116 117 for _, test := range isConnectedTests { 118 stdout, stderr, err := ctlcmd.Run(context, test.args, 0) 119 comment := Commentf("%s", test.args) 120 if test.exitCode > 0 { 121 c.Check(err, DeepEquals, &ctlcmd.UnsuccessfulError{ExitCode: test.exitCode}, comment) 122 } else { 123 if test.err == "" { 124 c.Check(err, IsNil, comment) 125 } else { 126 c.Check(err, ErrorMatches, test.err, comment) 127 } 128 } 129 130 c.Check(string(stdout), Equals, test.stdout, comment) 131 c.Check(string(stderr), Equals, "", comment) 132 } 133 } 134 135 func (s *isConnectedSuite) TestIsConnectedFromHook(c *C) { 136 s.st.Lock() 137 defer s.st.Unlock() 138 139 task := s.st.NewTask("test-task", "my test task") 140 setup := &hookstate.HookSetup{Snap: "snap1", Revision: snap.R(1), Hook: "test-hook"} 141 142 mockContext, err := hookstate.NewContext(task, s.st, setup, s.mockHandler, "") 143 c.Check(err, IsNil) 144 145 s.testIsConnected(c, mockContext) 146 } 147 148 func (s *isConnectedSuite) TestIsConnectedFromApp(c *C) { 149 s.st.Lock() 150 defer s.st.Unlock() 151 152 // ephemeral context 153 setup := &hookstate.HookSetup{Snap: "snap1", Revision: snap.R(1)} 154 mockContext, err := hookstate.NewContext(nil, s.st, setup, s.mockHandler, "") 155 c.Check(err, IsNil) 156 157 // sanity 158 c.Assert(mockContext.IsEphemeral(), Equals, true) 159 160 s.testIsConnected(c, mockContext) 161 } 162 163 func (s *isConnectedSuite) TestNoContextError(c *C) { 164 stdout, stderr, err := ctlcmd.Run(nil, []string{"is-connected", "foo"}, 0) 165 c.Check(err, ErrorMatches, `cannot check connection status without a context`) 166 c.Check(string(stdout), Equals, "") 167 c.Check(string(stderr), Equals, "") 168 } 169 170 func (s *isConnectedSuite) TestGetRegularUser(c *C) { 171 s.st.Lock() 172 173 mockInstalledSnap(c, s.st, `name: snap1 174 plugs: 175 plug1: 176 interface: x11`) 177 178 s.st.Set("conns", map[string]interface{}{ 179 "snap1:plug1 snap2:slot2": map[string]interface{}{}, 180 }) 181 182 setup := &hookstate.HookSetup{Snap: "snap1", Revision: snap.R(1)} 183 184 s.st.Unlock() 185 186 mockContext, err := hookstate.NewContext(nil, s.st, setup, s.mockHandler, "") 187 c.Assert(err, IsNil) 188 stdout, stderr, err := ctlcmd.Run(mockContext, []string{"is-connected", "plug1"}, 1000) 189 c.Check(err, IsNil) 190 c.Check(string(stdout), Equals, "") 191 c.Check(string(stderr), Equals, "") 192 }