github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/cmd/snap/cmd_validate_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 main_test 21 22 import ( 23 "fmt" 24 "io/ioutil" 25 "net/http" 26 27 "gopkg.in/check.v1" 28 29 "github.com/snapcore/snapd/cmd/snap" 30 ) 31 32 type validateSuite struct { 33 BaseSnapSuite 34 } 35 36 var _ = check.Suite(&validateSuite{}) 37 38 func makeFakeValidationSetPostHandler(c *check.C, body, action string, sequence int) func(w http.ResponseWriter, r *http.Request) { 39 var called bool 40 return func(w http.ResponseWriter, r *http.Request) { 41 if called { 42 c.Fatalf("expected a single request") 43 } 44 called = true 45 c.Check(r.URL.Path, check.Equals, "/v2/validation-sets/foo/bar") 46 c.Check(r.Method, check.Equals, "POST") 47 48 buf, err := ioutil.ReadAll(r.Body) 49 c.Assert(err, check.IsNil) 50 switch { 51 case sequence != 0 && action != "forget": 52 c.Check(string(buf), check.DeepEquals, fmt.Sprintf("{\"action\":\"apply\",\"mode\":%q,\"sequence\":%d}\n", action, sequence)) 53 case sequence == 0 && action != "forget": 54 c.Check(string(buf), check.DeepEquals, fmt.Sprintf("{\"action\":\"apply\",\"mode\":%q}\n", action)) 55 case sequence != 0 && action == "forget": 56 c.Check(string(buf), check.DeepEquals, fmt.Sprintf("{\"action\":\"forget\",\"sequence\":%d}\n", sequence)) 57 case action == "forget": 58 c.Check(string(buf), check.DeepEquals, "{\"action\":\"forget\"}\n") 59 default: 60 c.Fatalf("unexpected action: %s", action) 61 } 62 63 w.WriteHeader(200) 64 fmt.Fprintln(w, body) 65 } 66 } 67 68 func makeFakeValidationSetQueryHandler(c *check.C, body string) func(w http.ResponseWriter, r *http.Request) { 69 var called bool 70 return func(w http.ResponseWriter, r *http.Request) { 71 if called { 72 c.Fatalf("expected a single request") 73 } 74 called = true 75 c.Check(r.URL.Path, check.Equals, "/v2/validation-sets/foo/bar") 76 c.Check(r.Method, check.Equals, "GET") 77 w.WriteHeader(200) 78 fmt.Fprintln(w, body) 79 } 80 } 81 82 func makeFakeListValidationsSetsHandler(c *check.C, body string) func(w http.ResponseWriter, r *http.Request) { 83 var called bool 84 return func(w http.ResponseWriter, r *http.Request) { 85 if called { 86 c.Fatalf("expected a single request") 87 } 88 called = true 89 c.Check(r.URL.Path, check.Equals, "/v2/validation-sets") 90 c.Check(r.Method, check.Equals, "GET") 91 w.WriteHeader(200) 92 fmt.Fprintln(w, body) 93 } 94 } 95 96 func (s *validateSuite) TestValidateInvalidArgs(c *check.C) { 97 for _, args := range []struct { 98 args []string 99 err string 100 }{ 101 {[]string{"foo"}, `cannot parse validation set "foo": expected a single account/name`}, 102 {[]string{"foo/bar/baz"}, `cannot parse validation set "foo/bar/baz": expected a single account/name`}, 103 {[]string{"--monitor", "--enforce"}, `cannot use --monitor and --enforce together`}, 104 {[]string{"--monitor", "--forget"}, `cannot use --monitor and --forget together`}, 105 {[]string{"--enforce", "--forget"}, `cannot use --enforce and --forget together`}, 106 {[]string{"--enforce"}, `missing validation set argument`}, 107 {[]string{"--monitor"}, `missing validation set argument`}, 108 {[]string{"--forget"}, `missing validation set argument`}, 109 {[]string{"--forget", "foo/-"}, `cannot parse validation set "foo/-": invalid validation set name "-"`}, 110 } { 111 s.stdout.Reset() 112 s.stderr.Reset() 113 114 _, err := main.Parser(main.Client()).ParseArgs(append([]string{"validate"}, args.args...)) 115 c.Assert(err, check.ErrorMatches, args.err) 116 } 117 } 118 119 func (s *validateSuite) TestValidateMonitor(c *check.C) { 120 s.RedirectClientToTestServer(makeFakeValidationSetPostHandler(c, `{"type": "sync", "status-code": 200, "result": []}`, "monitor", 0)) 121 122 rest, err := main.Parser(main.Client()).ParseArgs([]string{"validate", "--monitor", "foo/bar"}) 123 c.Assert(err, check.IsNil) 124 c.Check(rest, check.HasLen, 0) 125 c.Check(s.Stderr(), check.Equals, "") 126 c.Check(s.Stdout(), check.Equals, "") 127 } 128 129 func (s *validateSuite) TestValidateMonitorPinned(c *check.C) { 130 s.RedirectClientToTestServer(makeFakeValidationSetPostHandler(c, `{"type": "sync", "status-code": 200, "result": []}`, "monitor", 3)) 131 132 rest, err := main.Parser(main.Client()).ParseArgs([]string{"validate", "--monitor", "foo/bar=3"}) 133 c.Assert(err, check.IsNil) 134 c.Check(rest, check.HasLen, 0) 135 c.Check(s.Stderr(), check.Equals, "") 136 c.Check(s.Stdout(), check.Equals, "") 137 } 138 139 func (s *validateSuite) TestValidateEnforce(c *check.C) { 140 s.RedirectClientToTestServer(makeFakeValidationSetPostHandler(c, `{"type": "sync", "status-code": 200, "result": []}`, "enforce", 0)) 141 142 rest, err := main.Parser(main.Client()).ParseArgs([]string{"validate", "--enforce", "foo/bar"}) 143 c.Assert(err, check.IsNil) 144 c.Check(rest, check.HasLen, 0) 145 c.Check(s.Stderr(), check.Equals, "") 146 c.Check(s.Stdout(), check.Equals, "") 147 } 148 149 func (s *validateSuite) TestValidateEnforcePinned(c *check.C) { 150 s.RedirectClientToTestServer(makeFakeValidationSetPostHandler(c, `{"type": "sync", "status-code": 200, "result": []}`, "enforce", 5)) 151 152 rest, err := main.Parser(main.Client()).ParseArgs([]string{"validate", "--enforce", "foo/bar=5"}) 153 c.Assert(err, check.IsNil) 154 c.Check(rest, check.HasLen, 0) 155 c.Check(s.Stderr(), check.Equals, "") 156 c.Check(s.Stdout(), check.Equals, "") 157 } 158 159 func (s *validateSuite) TestValidateForget(c *check.C) { 160 s.RedirectClientToTestServer(makeFakeValidationSetPostHandler(c, `{"type": "sync", "status-code": 200, "result": []}`, "forget", 0)) 161 162 rest, err := main.Parser(main.Client()).ParseArgs([]string{"validate", "--forget", "foo/bar"}) 163 c.Assert(err, check.IsNil) 164 c.Check(rest, check.HasLen, 0) 165 c.Check(s.Stderr(), check.Equals, "") 166 c.Check(s.Stdout(), check.Equals, "") 167 } 168 169 func (s *validateSuite) TestValidateForgetPinned(c *check.C) { 170 s.RedirectClientToTestServer(makeFakeValidationSetPostHandler(c, `{"type": "sync", "status-code": 200, "result": []}`, "forget", 5)) 171 172 rest, err := main.Parser(main.Client()).ParseArgs([]string{"validate", "--forget", "foo/bar=5"}) 173 c.Assert(err, check.IsNil) 174 c.Check(rest, check.HasLen, 0) 175 c.Check(s.Stderr(), check.Equals, "") 176 c.Check(s.Stdout(), check.Equals, "") 177 } 178 179 func (s *validateSuite) TestValidateQueryOne(c *check.C) { 180 restore := main.MockIsStdinTTY(true) 181 defer restore() 182 183 s.RedirectClientToTestServer(makeFakeValidationSetQueryHandler(c, `{"type": "sync", "status-code": 200, "result": {"account-id":"foo","name":"bar","mode":"monitor","sequence":3,"valid":true}}`)) 184 185 rest, err := main.Parser(main.Client()).ParseArgs([]string{"validate", "foo/bar"}) 186 c.Assert(err, check.IsNil) 187 c.Check(rest, check.HasLen, 0) 188 c.Check(s.Stderr(), check.Equals, "") 189 c.Check(s.Stdout(), check.Equals, "valid") 190 } 191 192 func (s *validateSuite) TestValidateQueryOneInvalid(c *check.C) { 193 restore := main.MockIsStdinTTY(true) 194 defer restore() 195 196 s.RedirectClientToTestServer(makeFakeValidationSetQueryHandler(c, `{"type": "sync", "status-code": 200, "result": {"account-id":"foo","name":"bar","mode":"monitor","sequence":3,"valid":false}}`)) 197 198 rest, err := main.Parser(main.Client()).ParseArgs([]string{"validate", "foo/bar"}) 199 c.Assert(err, check.IsNil) 200 c.Check(rest, check.HasLen, 0) 201 c.Check(s.Stderr(), check.Equals, "") 202 c.Check(s.Stdout(), check.Equals, "invalid") 203 } 204 205 func (s *validateSuite) TestValidationSetsList(c *check.C) { 206 restore := main.MockIsStdinTTY(true) 207 defer restore() 208 209 s.RedirectClientToTestServer(makeFakeListValidationsSetsHandler(c, `{"type": "sync", "status-code": 200, "result": [ 210 {"account-id":"foo","name":"bar","mode":"monitor","pinned-at":2,"sequence":3,"valid":true}, 211 {"account-id":"foo","name":"baz","mode":"enforce","sequence":1,"valid":false} 212 ]}`)) 213 214 rest, err := main.Parser(main.Client()).ParseArgs([]string{"validate"}) 215 c.Assert(err, check.IsNil) 216 c.Check(rest, check.HasLen, 0) 217 c.Check(s.Stderr(), check.Equals, "") 218 c.Check(s.Stdout(), check.Equals, "Validation Mode Seq Current Notes\n"+ 219 "foo/bar=2 monitor 3 valid \n"+ 220 "foo/baz enforce 1 invalid \n", 221 ) 222 } 223 224 func (s *validateSuite) TestValidationSetsListEmpty(c *check.C) { 225 restore := main.MockIsStdinTTY(true) 226 defer restore() 227 228 s.RedirectClientToTestServer(makeFakeListValidationsSetsHandler(c, `{"type": "sync", "status-code": 200, "result": []}`)) 229 230 rest, err := main.Parser(main.Client()).ParseArgs([]string{"validate"}) 231 c.Assert(err, check.IsNil) 232 c.Check(rest, check.HasLen, 0) 233 c.Check(s.Stderr(), check.Equals, "No validations are available\n") 234 c.Check(s.Stdout(), check.Equals, "") 235 }