github.com/anonymouse64/snapd@v0.0.0-20210824153203-04c4c42d842d/snap/channel/channel_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2018 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 channel_test 21 22 import ( 23 "testing" 24 25 . "gopkg.in/check.v1" 26 27 "github.com/snapcore/snapd/arch" 28 "github.com/snapcore/snapd/snap/channel" 29 ) 30 31 func Test(t *testing.T) { TestingT(t) } 32 33 type storeChannelSuite struct{} 34 35 var _ = Suite(&storeChannelSuite{}) 36 37 func (s storeChannelSuite) TestParse(c *C) { 38 ch, err := channel.Parse("stable", "") 39 c.Assert(err, IsNil) 40 c.Check(ch, DeepEquals, channel.Channel{ 41 Architecture: arch.DpkgArchitecture(), 42 Name: "stable", 43 Track: "", 44 Risk: "stable", 45 Branch: "", 46 }) 47 48 ch, err = channel.Parse("latest/stable", "") 49 c.Assert(err, IsNil) 50 c.Check(ch, DeepEquals, channel.Channel{ 51 Architecture: arch.DpkgArchitecture(), 52 Name: "stable", 53 Track: "", 54 Risk: "stable", 55 Branch: "", 56 }) 57 58 ch, err = channel.Parse("1.0/edge", "") 59 c.Assert(err, IsNil) 60 c.Check(ch, DeepEquals, channel.Channel{ 61 Architecture: arch.DpkgArchitecture(), 62 Name: "1.0/edge", 63 Track: "1.0", 64 Risk: "edge", 65 Branch: "", 66 }) 67 68 ch, err = channel.Parse("1.0", "") 69 c.Assert(err, IsNil) 70 c.Check(ch, DeepEquals, channel.Channel{ 71 Architecture: arch.DpkgArchitecture(), 72 Name: "1.0/stable", 73 Track: "1.0", 74 Risk: "stable", 75 Branch: "", 76 }) 77 78 ch, err = channel.Parse("1.0/beta/foo", "") 79 c.Assert(err, IsNil) 80 c.Check(ch, DeepEquals, channel.Channel{ 81 Architecture: arch.DpkgArchitecture(), 82 Name: "1.0/beta/foo", 83 Track: "1.0", 84 Risk: "beta", 85 Branch: "foo", 86 }) 87 88 ch, err = channel.Parse("candidate/foo", "") 89 c.Assert(err, IsNil) 90 c.Check(ch, DeepEquals, channel.Channel{ 91 Architecture: arch.DpkgArchitecture(), 92 Name: "candidate/foo", 93 Track: "", 94 Risk: "candidate", 95 Branch: "foo", 96 }) 97 98 ch, err = channel.Parse("candidate/foo", "other-arch") 99 c.Assert(err, IsNil) 100 c.Check(ch, DeepEquals, channel.Channel{ 101 Architecture: "other-arch", 102 Name: "candidate/foo", 103 Track: "", 104 Risk: "candidate", 105 Branch: "foo", 106 }) 107 } 108 109 func mustParse(c *C, channelStr string) channel.Channel { 110 ch, err := channel.Parse(channelStr, "") 111 c.Assert(err, IsNil) 112 return ch 113 } 114 115 func (s storeChannelSuite) TestParseVerbatim(c *C) { 116 ch, err := channel.ParseVerbatim("sometrack", "") 117 c.Assert(err, IsNil) 118 c.Check(ch, DeepEquals, channel.Channel{ 119 Architecture: arch.DpkgArchitecture(), 120 Track: "sometrack", 121 }) 122 c.Check(ch.VerbatimTrackOnly(), Equals, true) 123 c.Check(ch.VerbatimRiskOnly(), Equals, false) 124 c.Check(mustParse(c, "sometrack"), DeepEquals, ch.Clean()) 125 126 ch, err = channel.ParseVerbatim("latest", "") 127 c.Assert(err, IsNil) 128 c.Check(ch, DeepEquals, channel.Channel{ 129 Architecture: arch.DpkgArchitecture(), 130 Track: "latest", 131 }) 132 c.Check(ch.VerbatimTrackOnly(), Equals, true) 133 c.Check(ch.VerbatimRiskOnly(), Equals, false) 134 c.Check(mustParse(c, "latest"), DeepEquals, ch.Clean()) 135 136 ch, err = channel.ParseVerbatim("edge", "") 137 c.Assert(err, IsNil) 138 c.Check(ch, DeepEquals, channel.Channel{ 139 Architecture: arch.DpkgArchitecture(), 140 Risk: "edge", 141 }) 142 c.Check(ch.VerbatimTrackOnly(), Equals, false) 143 c.Check(ch.VerbatimRiskOnly(), Equals, true) 144 c.Check(mustParse(c, "edge"), DeepEquals, ch.Clean()) 145 146 ch, err = channel.ParseVerbatim("latest/stable", "") 147 c.Assert(err, IsNil) 148 c.Check(ch, DeepEquals, channel.Channel{ 149 Architecture: arch.DpkgArchitecture(), 150 Track: "latest", 151 Risk: "stable", 152 }) 153 c.Check(ch.VerbatimTrackOnly(), Equals, false) 154 c.Check(ch.VerbatimRiskOnly(), Equals, false) 155 c.Check(mustParse(c, "latest/stable"), DeepEquals, ch.Clean()) 156 157 ch, err = channel.ParseVerbatim("latest/stable/foo", "") 158 c.Assert(err, IsNil) 159 c.Check(ch, DeepEquals, channel.Channel{ 160 Architecture: arch.DpkgArchitecture(), 161 Track: "latest", 162 Risk: "stable", 163 Branch: "foo", 164 }) 165 c.Check(ch.VerbatimTrackOnly(), Equals, false) 166 c.Check(ch.VerbatimRiskOnly(), Equals, false) 167 c.Check(mustParse(c, "latest/stable/foo"), DeepEquals, ch.Clean()) 168 } 169 170 func (s storeChannelSuite) TestClean(c *C) { 171 ch := channel.Channel{ 172 Architecture: "arm64", 173 Track: "latest", 174 Name: "latest/stable", 175 Risk: "stable", 176 } 177 178 cleanedCh := ch.Clean() 179 c.Check(cleanedCh, Not(DeepEquals), c) 180 c.Check(cleanedCh, DeepEquals, channel.Channel{ 181 Architecture: "arm64", 182 Track: "", 183 Name: "stable", 184 Risk: "stable", 185 }) 186 } 187 188 func (s storeChannelSuite) TestParseErrors(c *C) { 189 for _, tc := range []struct { 190 channel string 191 err string 192 full string 193 }{ 194 {"", "channel name cannot be empty", ""}, 195 {"1.0////", "channel name has too many components: 1.0////", "1.0/stable"}, 196 {"1.0/cand", "invalid risk in channel name: 1.0/cand", ""}, 197 {"fix//hotfix", "invalid risk in channel name: fix//hotfix", ""}, 198 {"/stable/", "invalid track in channel name: /stable/", "latest/stable"}, 199 {"//stable", "invalid risk in channel name: //stable", "latest/stable"}, 200 {"stable/", "invalid branch in channel name: stable/", "latest/stable"}, 201 {"/stable", "invalid track in channel name: /stable", "latest/stable"}, 202 } { 203 _, err := channel.Parse(tc.channel, "") 204 c.Check(err, ErrorMatches, tc.err) 205 _, err = channel.ParseVerbatim(tc.channel, "") 206 c.Check(err, ErrorMatches, tc.err) 207 if tc.full != "" { 208 // testing Full behavior on the malformed channel 209 full, err := channel.Full(tc.channel) 210 c.Check(err, IsNil) 211 c.Check(full, Equals, tc.full) 212 } 213 } 214 } 215 216 func (s *storeChannelSuite) TestString(c *C) { 217 tests := []struct { 218 channel string 219 str string 220 }{ 221 {"stable", "stable"}, 222 {"latest/stable", "stable"}, 223 {"1.0/edge", "1.0/edge"}, 224 {"1.0/beta/foo", "1.0/beta/foo"}, 225 {"1.0", "1.0/stable"}, 226 {"candidate/foo", "candidate/foo"}, 227 } 228 229 for _, t := range tests { 230 ch, err := channel.Parse(t.channel, "") 231 c.Assert(err, IsNil) 232 233 c.Check(ch.String(), Equals, t.str) 234 } 235 } 236 237 func (s *storeChannelSuite) TestChannelFull(c *C) { 238 tests := []struct { 239 channel string 240 str string 241 }{ 242 {"stable", "latest/stable"}, 243 {"latest/stable", "latest/stable"}, 244 {"1.0/edge", "1.0/edge"}, 245 {"1.0/beta/foo", "1.0/beta/foo"}, 246 {"1.0", "1.0/stable"}, 247 {"candidate/foo", "latest/candidate/foo"}, 248 } 249 250 for _, t := range tests { 251 ch, err := channel.Parse(t.channel, "") 252 c.Assert(err, IsNil) 253 254 c.Check(ch.Full(), Equals, t.str) 255 } 256 } 257 258 func (s *storeChannelSuite) TestFuncFull(c *C) { 259 tests := []struct { 260 channel string 261 str string 262 }{ 263 {"stable", "latest/stable"}, 264 {"latest/stable", "latest/stable"}, 265 {"1.0/edge", "1.0/edge"}, 266 {"1.0/beta/foo", "1.0/beta/foo"}, 267 {"1.0", "1.0/stable"}, 268 {"candidate/foo", "latest/candidate/foo"}, 269 // store behaviour compat; expect these to fail when we stop accommodating the madness :) 270 {"//stable//", "latest/stable"}, 271 // rather weird corner case 272 {"///", ""}, 273 // empty string is OK 274 {"", ""}, 275 } 276 277 for _, t := range tests { 278 can, err := channel.Full(t.channel) 279 c.Assert(err, IsNil) 280 c.Check(can, Equals, t.str) 281 } 282 } 283 284 func (s *storeChannelSuite) TestFuncFullErr(c *C) { 285 _, err := channel.Full("foo/bar/baz/quux") 286 c.Check(err, ErrorMatches, "invalid channel") 287 } 288 289 func (s *storeChannelSuite) TestMatch(c *C) { 290 tests := []struct { 291 req string 292 c1 string 293 sameArch bool 294 res string 295 }{ 296 {"stable", "stable", true, "architecture:track:risk"}, 297 {"stable", "beta", true, "architecture:track"}, 298 {"beta", "stable", true, "architecture:track:risk"}, 299 {"stable", "edge", false, "track"}, 300 {"edge", "stable", false, "track:risk"}, 301 {"1.0/stable", "1.0/edge", true, "architecture:track"}, 302 {"1.0/edge", "stable", true, "architecture:risk"}, 303 {"1.0/edge", "stable", false, "risk"}, 304 {"1.0/stable", "stable", false, "risk"}, 305 {"1.0/stable", "beta", false, ""}, 306 {"1.0/stable", "2.0/beta", false, ""}, 307 {"2.0/stable", "2.0/beta", false, "track"}, 308 {"1.0/stable", "2.0/beta", true, "architecture"}, 309 } 310 311 for _, t := range tests { 312 reqArch := "amd64" 313 c1Arch := "amd64" 314 if !t.sameArch { 315 c1Arch = "arm64" 316 } 317 req, err := channel.Parse(t.req, reqArch) 318 c.Assert(err, IsNil) 319 c1, err := channel.Parse(t.c1, c1Arch) 320 c.Assert(err, IsNil) 321 322 c.Check(req.Match(&c1).String(), Equals, t.res) 323 } 324 } 325 326 func (s *storeChannelSuite) TestResolve(c *C) { 327 tests := []struct { 328 channel string 329 new string 330 result string 331 expErr string 332 }{ 333 {"", "", "", ""}, 334 {"", "edge", "edge", ""}, 335 {"track/foo", "", "track/foo", ""}, 336 {"stable", "", "stable", ""}, 337 {"stable", "edge", "edge", ""}, 338 {"stable/branch1", "edge/branch2", "edge/branch2", ""}, 339 {"track", "track", "track", ""}, 340 {"track", "beta", "track/beta", ""}, 341 {"track/stable", "beta", "track/beta", ""}, 342 {"track/stable", "stable/branch", "track/stable/branch", ""}, 343 {"track/stable", "track/edge/branch", "track/edge/branch", ""}, 344 {"track/stable", "track/candidate", "track/candidate", ""}, 345 {"track/stable", "track/stable/branch", "track/stable/branch", ""}, 346 {"track1/stable", "track2/stable", "track2/stable", ""}, 347 {"track1/stable", "track2/stable/branch", "track2/stable/branch", ""}, 348 {"track/foo", "track/stable/branch", "", "invalid risk in channel name: track/foo"}, 349 } 350 351 for _, t := range tests { 352 r, err := channel.Resolve(t.channel, t.new) 353 tcomm := Commentf("%#v", t) 354 if t.expErr == "" { 355 c.Assert(err, IsNil, tcomm) 356 c.Check(r, Equals, t.result, tcomm) 357 } else { 358 c.Assert(err, ErrorMatches, t.expErr, tcomm) 359 } 360 } 361 } 362 363 func (s *storeChannelSuite) TestResolvePinned(c *C) { 364 tests := []struct { 365 track string 366 new string 367 result string 368 expErr string 369 }{ 370 {"", "", "", ""}, 371 {"", "anytrack/stable", "anytrack/stable", ""}, 372 {"track/foo", "", "", "invalid pinned track: track/foo"}, 373 {"track", "", "track", ""}, 374 {"track", "track", "track", ""}, 375 {"track", "beta", "track/beta", ""}, 376 {"track", "stable/branch", "track/stable/branch", ""}, 377 {"track", "track/edge/branch", "track/edge/branch", ""}, 378 {"track", "track/candidate", "track/candidate", ""}, 379 {"track", "track/stable/branch", "track/stable/branch", ""}, 380 {"track1", "track2/stable", "track2/stable", "cannot switch pinned track"}, 381 {"track1", "track2/stable/branch", "track2/stable/branch", "cannot switch pinned track"}, 382 } 383 for _, t := range tests { 384 r, err := channel.ResolvePinned(t.track, t.new) 385 tcomm := Commentf("%#v", t) 386 if t.expErr == "" { 387 c.Assert(err, IsNil, tcomm) 388 c.Check(r, Equals, t.result, tcomm) 389 } else { 390 c.Assert(err, ErrorMatches, t.expErr, tcomm) 391 } 392 } 393 }