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  }