github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/cmd/snap/cmd_disconnect_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016 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 main_test 21 22 import ( 23 "fmt" 24 "net/http" 25 "os" 26 27 "github.com/jessevdk/go-flags" 28 . "gopkg.in/check.v1" 29 30 . "github.com/snapcore/snapd/cmd/snap" 31 ) 32 33 func (s *SnapSuite) TestDisconnectHelp(c *C) { 34 msg := `Usage: 35 snap.test disconnect [disconnect-OPTIONS] [<snap>:<plug>] [<snap>:<slot>] 36 37 The disconnect command disconnects a plug from a slot. 38 It may be called in the following ways: 39 40 $ snap disconnect <snap>:<plug> <snap>:<slot> 41 42 Disconnects the specific plug from the specific slot. 43 44 $ snap disconnect <snap>:<slot or plug> 45 46 Disconnects everything from the provided plug or slot. 47 The snap name may be omitted for the core snap. 48 49 When an automatic connection is manually disconnected, its disconnected state 50 is retained after a snap refresh. The --forget flag can be added to the 51 disconnect command to reset this behaviour, and consequently re-enable 52 an automatic reconnection after a snap refresh. 53 54 [disconnect command options] 55 --no-wait Do not wait for the operation to finish but just print 56 the change id. 57 --forget Forget remembered state about the given connection. 58 ` 59 s.testSubCommandHelp(c, "disconnect", msg) 60 } 61 62 func (s *SnapSuite) TestDisconnectExplicitEverything(c *C) { 63 s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) { 64 switch r.URL.Path { 65 case "/v2/interfaces": 66 c.Check(r.Method, Equals, "POST") 67 c.Check(DecodedRequestBody(c, r), DeepEquals, map[string]interface{}{ 68 "action": "disconnect", 69 "plugs": []interface{}{ 70 map[string]interface{}{ 71 "snap": "producer", 72 "plug": "plug", 73 }, 74 }, 75 "slots": []interface{}{ 76 map[string]interface{}{ 77 "snap": "consumer", 78 "slot": "slot", 79 }, 80 }, 81 }) 82 w.WriteHeader(202) 83 fmt.Fprintln(w, `{"type":"async", "status-code": 202, "change": "zzz"}`) 84 case "/v2/changes/zzz": 85 c.Check(r.Method, Equals, "GET") 86 fmt.Fprintln(w, `{"type":"sync", "result":{"ready": true, "status": "Done"}}`) 87 default: 88 c.Fatalf("unexpected path %q", r.URL.Path) 89 } 90 }) 91 rest, err := Parser(Client()).ParseArgs([]string{"disconnect", "producer:plug", "consumer:slot"}) 92 c.Assert(err, IsNil) 93 c.Assert(rest, DeepEquals, []string{}) 94 c.Assert(s.Stdout(), Equals, "") 95 c.Assert(s.Stderr(), Equals, "") 96 } 97 98 func (s *SnapSuite) TestDisconnectWithForgetFlag(c *C) { 99 s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) { 100 switch r.URL.Path { 101 case "/v2/interfaces": 102 c.Check(r.Method, Equals, "POST") 103 c.Check(DecodedRequestBody(c, r), DeepEquals, map[string]interface{}{ 104 "action": "disconnect", 105 "forget": true, 106 "plugs": []interface{}{ 107 map[string]interface{}{ 108 "snap": "consumer", 109 "plug": "plug", 110 }, 111 }, 112 "slots": []interface{}{ 113 map[string]interface{}{ 114 "snap": "producer", 115 "slot": "slot", 116 }, 117 }, 118 }) 119 w.WriteHeader(202) 120 fmt.Fprintln(w, `{"type":"async", "status-code": 202, "change": "zzz"}`) 121 case "/v2/changes/zzz": 122 c.Check(r.Method, Equals, "GET") 123 fmt.Fprintln(w, `{"type":"sync", "result":{"ready": true, "status": "Done"}}`) 124 default: 125 c.Fatalf("unexpected path %q", r.URL.Path) 126 } 127 }) 128 rest, err := Parser(Client()).ParseArgs([]string{"disconnect", "--forget", "consumer:plug", "producer:slot"}) 129 c.Assert(err, IsNil) 130 c.Assert(rest, DeepEquals, []string{}) 131 c.Assert(s.Stdout(), Equals, "") 132 c.Assert(s.Stderr(), Equals, "") 133 } 134 135 func (s *SnapSuite) TestDisconnectEverythingFromSpecificSlot(c *C) { 136 s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) { 137 switch r.URL.Path { 138 case "/v2/interfaces": 139 c.Check(r.Method, Equals, "POST") 140 c.Check(DecodedRequestBody(c, r), DeepEquals, map[string]interface{}{ 141 "action": "disconnect", 142 "plugs": []interface{}{ 143 map[string]interface{}{ 144 "snap": "", 145 "plug": "", 146 }, 147 }, 148 "slots": []interface{}{ 149 map[string]interface{}{ 150 "snap": "consumer", 151 "slot": "slot", 152 }, 153 }, 154 }) 155 w.WriteHeader(202) 156 fmt.Fprintln(w, `{"type":"async", "status-code": 202, "change": "zzz"}`) 157 case "/v2/changes/zzz": 158 c.Check(r.Method, Equals, "GET") 159 fmt.Fprintln(w, `{"type":"sync", "result":{"ready": true, "status": "Done"}}`) 160 default: 161 c.Fatalf("unexpected path %q", r.URL.Path) 162 } 163 }) 164 rest, err := Parser(Client()).ParseArgs([]string{"disconnect", "consumer:slot"}) 165 c.Assert(err, IsNil) 166 c.Assert(rest, DeepEquals, []string{}) 167 c.Assert(s.Stdout(), Equals, "") 168 c.Assert(s.Stderr(), Equals, "") 169 } 170 171 func (s *SnapSuite) TestDisconnectEverythingFromSpecificSnapPlugOrSlot(c *C) { 172 s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) { 173 switch r.URL.Path { 174 case "/v2/interfaces": 175 c.Check(r.Method, Equals, "POST") 176 c.Check(DecodedRequestBody(c, r), DeepEquals, map[string]interface{}{ 177 "action": "disconnect", 178 "plugs": []interface{}{ 179 map[string]interface{}{ 180 "snap": "", 181 "plug": "", 182 }, 183 }, 184 "slots": []interface{}{ 185 map[string]interface{}{ 186 "snap": "consumer", 187 "slot": "plug-or-slot", 188 }, 189 }, 190 }) 191 w.WriteHeader(202) 192 fmt.Fprintln(w, `{"type":"async", "status-code": 202, "change": "zzz"}`) 193 case "/v2/changes/zzz": 194 c.Check(r.Method, Equals, "GET") 195 fmt.Fprintln(w, `{"type":"sync", "result":{"ready": true, "status": "Done"}}`) 196 default: 197 c.Fatalf("unexpected path %q", r.URL.Path) 198 } 199 }) 200 rest, err := Parser(Client()).ParseArgs([]string{"disconnect", "consumer:plug-or-slot"}) 201 c.Assert(err, IsNil) 202 c.Assert(rest, DeepEquals, []string{}) 203 c.Assert(s.Stdout(), Equals, "") 204 c.Assert(s.Stderr(), Equals, "") 205 } 206 207 func (s *SnapSuite) TestDisconnectEverythingFromSpecificSnap(c *C) { 208 s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) { 209 c.Fatalf("expected nothing to reach the server") 210 }) 211 rest, err := Parser(Client()).ParseArgs([]string{"disconnect", "consumer"}) 212 c.Assert(err, ErrorMatches, `please provide the plug or slot name to disconnect from snap "consumer"`) 213 c.Assert(rest, DeepEquals, []string{"consumer"}) 214 c.Assert(s.Stdout(), Equals, "") 215 c.Assert(s.Stderr(), Equals, "") 216 } 217 218 func (s *SnapSuite) TestDisconnectCompletion(c *C) { 219 s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) { 220 switch r.URL.Path { 221 case "/v2/connections": 222 c.Assert(r.Method, Equals, "GET") 223 EncodeResponseBody(c, w, map[string]interface{}{ 224 "type": "sync", 225 "result": fortestingConnectionList, 226 }) 227 default: 228 c.Fatalf("unexpected path %q", r.URL.Path) 229 } 230 }) 231 os.Setenv("GO_FLAGS_COMPLETION", "verbose") 232 defer os.Unsetenv("GO_FLAGS_COMPLETION") 233 234 expected := []flags.Completion{} 235 parser := Parser(Client()) 236 parser.CompletionHandler = func(obtained []flags.Completion) { 237 c.Check(obtained, DeepEquals, expected) 238 } 239 240 expected = []flags.Completion{{Item: "canonical-pi2:"}, {Item: "core:"}, {Item: "keyboard-lights:"}} 241 _, err := parser.ParseArgs([]string{"disconnect", ""}) 242 c.Assert(err, IsNil) 243 244 expected = []flags.Completion{{Item: "canonical-pi2:pin-13", Description: "slot"}} 245 _, err = parser.ParseArgs([]string{"disconnect", "ca"}) 246 c.Assert(err, IsNil) 247 248 expected = []flags.Completion{{Item: ":core-support", Description: "slot"}, {Item: ":core-support-plug", Description: "plug"}} 249 _, err = parser.ParseArgs([]string{"disconnect", ":"}) 250 c.Assert(err, IsNil) 251 252 expected = []flags.Completion{{Item: "keyboard-lights:capslock-led", Description: "plug"}} 253 _, err = parser.ParseArgs([]string{"disconnect", "k"}) 254 c.Assert(err, IsNil) 255 256 expected = []flags.Completion{{Item: "canonical-pi2:"}, {Item: "core:"}} 257 _, err = parser.ParseArgs([]string{"disconnect", "keyboard-lights:capslock-led", ""}) 258 c.Assert(err, IsNil) 259 260 expected = []flags.Completion{{Item: "canonical-pi2:pin-13", Description: "slot"}} 261 _, err = parser.ParseArgs([]string{"disconnect", "keyboard-lights:capslock-led", "ca"}) 262 c.Assert(err, IsNil) 263 264 expected = []flags.Completion{{Item: ":core-support", Description: "slot"}} 265 _, err = parser.ParseArgs([]string{"disconnect", ":core-support-plug", ":"}) 266 c.Assert(err, IsNil) 267 268 c.Assert(s.Stdout(), Equals, "") 269 c.Assert(s.Stderr(), Equals, "") 270 }