github.com/stolowski/snapd@v0.0.0-20210407085831-115137ce5a22/overlord/snapstate/aliasesv2_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2016-2017 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 snapstate_test
    21  
    22  import (
    23  	"fmt"
    24  	"sort"
    25  	"strings"
    26  
    27  	. "gopkg.in/check.v1"
    28  
    29  	"github.com/snapcore/snapd/overlord/snapstate"
    30  	"github.com/snapcore/snapd/overlord/snapstate/backend"
    31  	"github.com/snapcore/snapd/overlord/state"
    32  	"github.com/snapcore/snapd/snap"
    33  	"github.com/snapcore/snapd/snap/snaptest"
    34  )
    35  
    36  func target(at *snapstate.AliasTarget) string {
    37  	if at.Manual != "" {
    38  		return at.Manual
    39  	}
    40  	return at.Auto
    41  }
    42  
    43  func (s *snapmgrTestSuite) TestApplyAliasesChange(c *C) {
    44  	auto1 := &snapstate.AliasTarget{
    45  		Auto: "cmd1",
    46  	}
    47  
    48  	auto2 := &snapstate.AliasTarget{
    49  		Auto: "cmd2",
    50  	}
    51  
    52  	manual1 := &snapstate.AliasTarget{
    53  		Manual: "cmd1",
    54  	}
    55  
    56  	manual2 := &snapstate.AliasTarget{
    57  		Manual: "manual2",
    58  		Auto:   "cmd1",
    59  	}
    60  
    61  	scenarios := []struct {
    62  		autoDisabled    bool
    63  		newAutoDisabled bool
    64  		target          *snapstate.AliasTarget
    65  		newTarget       *snapstate.AliasTarget
    66  		ops             string
    67  	}{
    68  		{false, false, nil, auto1, "add"},
    69  		{false, true, auto1, auto1, "rm"},
    70  		{false, false, auto1, auto2, "rm add"},
    71  		{false, false, auto1, nil, "rm"},
    72  		{false, false, nil, manual1, "add"},
    73  		{true, true, nil, manual1, "add"},
    74  		{false, true, auto1, manual2, "rm add"},
    75  		{false, false, manual2, nil, "rm"},
    76  		{false, false, manual2, auto1, "rm add"},
    77  		{false, false, manual1, auto1, ""},
    78  		{true, false, manual1, auto1, ""},
    79  	}
    80  
    81  	for _, scenario := range scenarios {
    82  		prevAliases := make(map[string]*snapstate.AliasTarget)
    83  		if scenario.target != nil {
    84  			prevAliases["myalias"] = scenario.target
    85  		}
    86  		newAliases := make(map[string]*snapstate.AliasTarget)
    87  		if scenario.newTarget != nil {
    88  			newAliases["myalias"] = scenario.newTarget
    89  		}
    90  
    91  		add1, rm1, err := snapstate.ApplyAliasesChange("alias-snap1", scenario.autoDisabled, prevAliases, scenario.newAutoDisabled, newAliases, s.fakeBackend, false)
    92  		c.Assert(err, IsNil)
    93  
    94  		var add, rm []*backend.Alias
    95  		if strings.Contains(scenario.ops, "rm") {
    96  			rm = []*backend.Alias{{Name: "myalias", Target: fmt.Sprintf("alias-snap1.%s", target(scenario.target))}}
    97  		}
    98  
    99  		if strings.Contains(scenario.ops, "add") {
   100  			add = []*backend.Alias{{Name: "myalias", Target: fmt.Sprintf("alias-snap1.%s", target(scenario.newTarget))}}
   101  		}
   102  
   103  		expected := fakeOps{
   104  			{
   105  				op:        "update-aliases",
   106  				rmAliases: rm,
   107  				aliases:   add,
   108  			},
   109  		}
   110  
   111  		// start with an easier-to-read error if this fails:
   112  		c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops(), Commentf("%v", scenario))
   113  		c.Assert(s.fakeBackend.ops, DeepEquals, expected, Commentf("%v", scenario))
   114  
   115  		c.Check(add1, DeepEquals, add)
   116  		c.Check(rm1, DeepEquals, rm)
   117  
   118  		s.fakeBackend.ops = nil
   119  	}
   120  }
   121  
   122  func (s *snapmgrTestSuite) TestApplyAliasesChangeMulti(c *C) {
   123  	prevAliases := map[string]*snapstate.AliasTarget{
   124  		"myalias0": {Auto: "cmd0"},
   125  	}
   126  	newAliases := map[string]*snapstate.AliasTarget{
   127  		"myalias1": {Auto: "alias-snap1"},
   128  	}
   129  
   130  	_, _, err := snapstate.ApplyAliasesChange("alias-snap1", false, prevAliases, false, newAliases, s.fakeBackend, false)
   131  	c.Assert(err, IsNil)
   132  
   133  	expected := fakeOps{
   134  		{
   135  			op:        "update-aliases",
   136  			rmAliases: []*backend.Alias{{Name: "myalias0", Target: "alias-snap1.cmd0"}},
   137  			aliases:   []*backend.Alias{{Name: "myalias1", Target: "alias-snap1"}},
   138  		},
   139  	}
   140  
   141  	// start with an easier-to-read error if this fails:
   142  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops())
   143  	c.Assert(s.fakeBackend.ops, DeepEquals, expected)
   144  }
   145  
   146  func (s *snapmgrTestSuite) TestAutoAliasesDelta(c *C) {
   147  	snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) {
   148  		c.Check(info.InstanceName(), Equals, "alias-snap")
   149  		return map[string]string{
   150  			"alias1": "cmd1",
   151  			"alias2": "cmd2",
   152  			"alias4": "cmd4",
   153  			"alias5": "cmd5",
   154  			"alias6": "cmd6b",
   155  		}, nil
   156  	}
   157  
   158  	s.state.Lock()
   159  	defer s.state.Unlock()
   160  
   161  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   162  		Sequence: []*snap.SideInfo{
   163  			{RealName: "alias-snap", Revision: snap.R(11)},
   164  		},
   165  		Current: snap.R(11),
   166  		Active:  true,
   167  		Aliases: map[string]*snapstate.AliasTarget{
   168  			"alias1": {Manual: "cmdx", Auto: "cmd1"},
   169  			"alias2": {Auto: "cmd2"},
   170  			"alias3": {Auto: "cmd3"},
   171  			"alias6": {Auto: "cmd6"},
   172  		},
   173  	})
   174  
   175  	changed, dropped, err := snapstate.AutoAliasesDelta(s.state, []string{"alias-snap"})
   176  	c.Assert(err, IsNil)
   177  
   178  	c.Check(changed, HasLen, 1)
   179  	which := changed["alias-snap"]
   180  	sort.Strings(which)
   181  	c.Check(which, DeepEquals, []string{"alias4", "alias5", "alias6"})
   182  
   183  	c.Check(dropped, DeepEquals, map[string][]string{
   184  		"alias-snap": {"alias3"},
   185  	})
   186  }
   187  
   188  func (s *snapmgrTestSuite) TestAutoAliasesDeltaAll(c *C) {
   189  	seen := make(map[string]bool)
   190  	snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) {
   191  		seen[info.InstanceName()] = true
   192  		if info.InstanceName() == "alias-snap" {
   193  			return map[string]string{
   194  				"alias1": "cmd1",
   195  				"alias2": "cmd2",
   196  				"alias4": "cmd4",
   197  				"alias5": "cmd5",
   198  			}, nil
   199  		}
   200  		return nil, nil
   201  	}
   202  
   203  	s.state.Lock()
   204  	defer s.state.Unlock()
   205  
   206  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   207  		Sequence: []*snap.SideInfo{
   208  			{RealName: "alias-snap", Revision: snap.R(11)},
   209  		},
   210  		Current: snap.R(11),
   211  		Active:  true,
   212  	})
   213  	snapstate.Set(s.state, "other-snap", &snapstate.SnapState{
   214  		Sequence: []*snap.SideInfo{
   215  			{RealName: "other-snap", Revision: snap.R(2)},
   216  		},
   217  		Current: snap.R(2),
   218  		Active:  true,
   219  	})
   220  
   221  	changed, dropped, err := snapstate.AutoAliasesDelta(s.state, nil)
   222  	c.Assert(err, IsNil)
   223  
   224  	c.Check(changed, HasLen, 1)
   225  	which := changed["alias-snap"]
   226  	sort.Strings(which)
   227  	c.Check(which, DeepEquals, []string{"alias1", "alias2", "alias4", "alias5"})
   228  
   229  	c.Check(dropped, HasLen, 0)
   230  
   231  	c.Check(seen, DeepEquals, map[string]bool{
   232  		"core":       true,
   233  		"alias-snap": true,
   234  		"other-snap": true,
   235  	})
   236  }
   237  
   238  func (s *snapmgrTestSuite) TestAutoAliasesDeltaOverManual(c *C) {
   239  	snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) {
   240  		c.Check(info.InstanceName(), Equals, "alias-snap")
   241  		return map[string]string{
   242  			"alias1": "cmd1",
   243  			"alias2": "cmd2",
   244  		}, nil
   245  	}
   246  
   247  	s.state.Lock()
   248  	defer s.state.Unlock()
   249  
   250  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   251  		Sequence: []*snap.SideInfo{
   252  			{RealName: "alias-snap", Revision: snap.R(11)},
   253  		},
   254  		Current: snap.R(11),
   255  		Active:  true,
   256  		Aliases: map[string]*snapstate.AliasTarget{
   257  			"alias1": {Manual: "manual1"},
   258  		},
   259  	})
   260  
   261  	changed, dropped, err := snapstate.AutoAliasesDelta(s.state, []string{"alias-snap"})
   262  	c.Assert(err, IsNil)
   263  
   264  	c.Check(changed, HasLen, 1)
   265  	which := changed["alias-snap"]
   266  	sort.Strings(which)
   267  	c.Check(which, DeepEquals, []string{"alias1", "alias2"})
   268  
   269  	c.Check(dropped, HasLen, 0)
   270  }
   271  
   272  func (s *snapmgrTestSuite) TestRefreshAliases(c *C) {
   273  	s.state.Lock()
   274  	defer s.state.Unlock()
   275  
   276  	snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) {
   277  		c.Check(info.InstanceName(), Equals, "alias-snap")
   278  		return map[string]string{
   279  			"alias1": "cmd1",
   280  			"alias2": "cmd2",
   281  			"alias4": "cmd4",
   282  			"alias5": "cmd5",
   283  		}, nil
   284  	}
   285  
   286  	info := snaptest.MockInfo(c, `
   287  name: alias-snap
   288  version: 0
   289  apps:
   290      cmd1:
   291      cmd2:
   292      cmd3:
   293      cmd4:
   294  `, &snap.SideInfo{SnapID: "snap-id"})
   295  
   296  	new, err := snapstate.RefreshAliases(s.state, info, nil)
   297  	c.Assert(err, IsNil)
   298  	c.Check(new, DeepEquals, map[string]*snapstate.AliasTarget{
   299  		"alias1": {Auto: "cmd1"},
   300  		"alias2": {Auto: "cmd2"},
   301  		"alias4": {Auto: "cmd4"},
   302  	})
   303  
   304  	new, err = snapstate.RefreshAliases(s.state, info, map[string]*snapstate.AliasTarget{
   305  		"alias1":  {Auto: "cmd1old"},
   306  		"alias5":  {Auto: "cmd5"},
   307  		"alias6":  {Auto: "cmd6"},
   308  		"alias4":  {Manual: "cmd3", Auto: "cmd4"},
   309  		"manual3": {Manual: "cmd3"},
   310  		"manual7": {Manual: "cmd7"},
   311  	})
   312  	c.Assert(err, IsNil)
   313  	c.Check(new, DeepEquals, map[string]*snapstate.AliasTarget{
   314  		"alias1":  {Auto: "cmd1"},
   315  		"alias2":  {Auto: "cmd2"},
   316  		"alias4":  {Manual: "cmd3", Auto: "cmd4"},
   317  		"manual3": {Manual: "cmd3"},
   318  	})
   319  }
   320  
   321  func (s *snapmgrTestSuite) TestCheckAliasesConflictsAgainstAliases(c *C) {
   322  	s.state.Lock()
   323  	defer s.state.Unlock()
   324  
   325  	snapstate.Set(s.state, "other-snap1", &snapstate.SnapState{
   326  		Sequence: []*snap.SideInfo{
   327  			{RealName: "other-snap", Revision: snap.R(2)},
   328  		},
   329  		Current:             snap.R(2),
   330  		Active:              true,
   331  		AutoAliasesDisabled: true,
   332  		Aliases: map[string]*snapstate.AliasTarget{
   333  			"alias1": {Auto: "cmd1"},
   334  			"alias2": {Auto: "cmd2"},
   335  		},
   336  	})
   337  
   338  	snapstate.Set(s.state, "other-snap2", &snapstate.SnapState{
   339  		Sequence: []*snap.SideInfo{
   340  			{RealName: "other-snap", Revision: snap.R(2)},
   341  		},
   342  		Current:             snap.R(2),
   343  		Active:              true,
   344  		AutoAliasesDisabled: false,
   345  		Aliases: map[string]*snapstate.AliasTarget{
   346  			"alias2": {Auto: "cmd2"},
   347  			"alias3": {Auto: "cmd3"},
   348  		},
   349  	})
   350  
   351  	snapst3 := snapstate.SnapState{
   352  		Sequence: []*snap.SideInfo{
   353  			{RealName: "other-snap", Revision: snap.R(2)},
   354  		},
   355  		Current:             snap.R(2),
   356  		Active:              true,
   357  		AutoAliasesDisabled: true,
   358  		Aliases: map[string]*snapstate.AliasTarget{
   359  			"alias4": {Manual: "cmd8"},
   360  			"alias5": {Auto: "cmd5"},
   361  		},
   362  	}
   363  	snapstate.Set(s.state, "other-snap3", &snapst3)
   364  
   365  	confl, err := snapstate.CheckAliasesConflicts(s.state, "alias-snap", false, map[string]*snapstate.AliasTarget{
   366  		"alias1": {Auto: "cmd1"},
   367  		"alias5": {Auto: "cmd5"},
   368  	}, nil)
   369  	c.Check(err, IsNil)
   370  	c.Check(confl, IsNil)
   371  
   372  	confl, err = snapstate.CheckAliasesConflicts(s.state, "alias-snap", false, map[string]*snapstate.AliasTarget{
   373  		"alias1": {Auto: "cmd1"},
   374  		"alias2": {Auto: "cmd2"},
   375  		"alias3": {Auto: "cmd3"},
   376  		"alias4": {Auto: "cmd4"},
   377  	}, nil)
   378  	c.Check(err, FitsTypeOf, &snapstate.AliasConflictError{})
   379  	c.Check(confl, HasLen, 2)
   380  	which := confl["other-snap2"]
   381  	sort.Strings(which)
   382  	c.Check(which, DeepEquals, []string{"alias2", "alias3"})
   383  	c.Check(confl["other-snap3"], DeepEquals, []string{"alias4"})
   384  
   385  	confl, err = snapstate.CheckAliasesConflicts(s.state, "alias-snap", true, map[string]*snapstate.AliasTarget{
   386  		"alias1": {Auto: "cmd1"},
   387  		"alias2": {Auto: "cmd2"},
   388  		"alias3": {Auto: "cmd3"},
   389  		"alias4": {Auto: "cmd4"},
   390  	}, nil)
   391  	c.Check(err, IsNil)
   392  	c.Check(confl, IsNil)
   393  
   394  	confl, err = snapstate.CheckAliasesConflicts(s.state, "other-snap4", false, map[string]*snapstate.AliasTarget{
   395  		"alias2": {Manual: "cmd12"},
   396  	}, nil)
   397  	c.Check(err, FitsTypeOf, &snapstate.AliasConflictError{})
   398  	c.Check(confl, HasLen, 1)
   399  	which = confl["other-snap2"]
   400  	sort.Strings(which)
   401  	c.Check(which, DeepEquals, []string{"alias2"})
   402  
   403  	snapst3En := snapst3
   404  	snapst3En.AutoAliasesDisabled = false
   405  	confl, err = snapstate.CheckAliasesConflicts(s.state, "alias-snap", false, map[string]*snapstate.AliasTarget{
   406  		"alias1": {Auto: "cmd1"},
   407  		"alias5": {Auto: "cmd5"},
   408  	}, map[string]*snapstate.SnapState{
   409  		"other-snap3": &snapst3En,
   410  	})
   411  	c.Check(err, FitsTypeOf, &snapstate.AliasConflictError{})
   412  	c.Check(confl, HasLen, 1)
   413  	which = confl["other-snap3"]
   414  	sort.Strings(which)
   415  	c.Check(which, DeepEquals, []string{"alias5"})
   416  }
   417  
   418  func (s *snapmgrTestSuite) TestAliasConflictError(c *C) {
   419  	e := &snapstate.AliasConflictError{Snap: "foo", Conflicts: map[string][]string{
   420  		"bar": {"baz"},
   421  	}}
   422  	c.Check(e, ErrorMatches, `cannot enable alias "baz" for "foo", already enabled for "bar"`)
   423  
   424  	e = &snapstate.AliasConflictError{Snap: "foo", Conflicts: map[string][]string{
   425  		"bar": {"baz1", "baz2"},
   426  	}}
   427  	c.Check(e, ErrorMatches, `cannot enable aliases "baz1", "baz2" for "foo", already enabled for "bar"`)
   428  
   429  	e = &snapstate.AliasConflictError{Snap: "foo", Conflicts: map[string][]string{
   430  		"bar1": {"baz1"},
   431  		"bar2": {"baz2"},
   432  	}}
   433  	c.Check(e, ErrorMatches, `cannot enable alias "baz." for "foo", already enabled for "bar." nor alias "baz." already enabled for "bar."`)
   434  }
   435  
   436  func (s *snapmgrTestSuite) TestCheckAliasesConflictsAgainstSnaps(c *C) {
   437  	s.state.Lock()
   438  	defer s.state.Unlock()
   439  
   440  	snapstate.Set(s.state, "some-snap", &snapstate.SnapState{
   441  		Active:   true,
   442  		Sequence: []*snap.SideInfo{{RealName: "some-snap", SnapID: "some-snap-id", Revision: snap.R(7)}},
   443  		Current:  snap.R(7),
   444  		SnapType: "app",
   445  	})
   446  
   447  	confl, err := snapstate.CheckAliasesConflicts(s.state, "alias-snap", false, map[string]*snapstate.AliasTarget{
   448  		"alias1": {Auto: "cmd1"},
   449  	}, nil)
   450  	c.Check(err, IsNil)
   451  	c.Check(confl, IsNil)
   452  
   453  	confl, err = snapstate.CheckAliasesConflicts(s.state, "alias-snap", false, map[string]*snapstate.AliasTarget{
   454  		"alias1":    {Auto: "cmd1"},
   455  		"some-snap": {Auto: "cmd1"},
   456  	}, nil)
   457  	c.Check(err, ErrorMatches, `cannot enable alias "some-snap" for "alias-snap", it conflicts with the command namespace of installed snap "some-snap"`)
   458  	c.Check(confl, IsNil)
   459  
   460  	confl, err = snapstate.CheckAliasesConflicts(s.state, "alias-snap", true, map[string]*snapstate.AliasTarget{
   461  		"alias1":    {Auto: "cmd1"},
   462  		"some-snap": {Auto: "cmd1"},
   463  	}, nil)
   464  	c.Check(err, IsNil)
   465  	c.Check(confl, IsNil)
   466  
   467  	confl, err = snapstate.CheckAliasesConflicts(s.state, "alias-snap", false, map[string]*snapstate.AliasTarget{
   468  		"alias1":        {Auto: "cmd1"},
   469  		"some-snap.foo": {Auto: "cmd1"},
   470  	}, nil)
   471  	c.Check(err, ErrorMatches, `cannot enable alias "some-snap.foo" for "alias-snap", it conflicts with the command namespace of installed snap "some-snap"`)
   472  	c.Check(confl, IsNil)
   473  }
   474  
   475  func (s *snapmgrTestSuite) TestDisableAliases(c *C) {
   476  	aliases := map[string]*snapstate.AliasTarget{
   477  		"alias1": {Auto: "cmd1"},
   478  		"alias2": {Auto: "cmd2"},
   479  		"alias3": {Manual: "manual3", Auto: "cmd3"},
   480  		"alias4": {Manual: "manual4"},
   481  	}
   482  
   483  	dis, manuals := snapstate.DisableAliases(aliases)
   484  	c.Check(dis, DeepEquals, map[string]*snapstate.AliasTarget{
   485  		"alias1": {Auto: "cmd1"},
   486  		"alias2": {Auto: "cmd2"},
   487  		"alias3": {Auto: "cmd3"},
   488  	})
   489  	c.Check(manuals, DeepEquals, map[string]string{
   490  		"alias3": "manual3",
   491  		"alias4": "manual4",
   492  	})
   493  
   494  	aliases = map[string]*snapstate.AliasTarget{
   495  		"alias1": {Auto: "cmd1"},
   496  		"alias2": {Auto: "cmd2"},
   497  	}
   498  	dis, manuals = snapstate.DisableAliases(aliases)
   499  	c.Check(dis, DeepEquals, map[string]*snapstate.AliasTarget{
   500  		"alias1": {Auto: "cmd1"},
   501  		"alias2": {Auto: "cmd2"},
   502  	})
   503  	c.Check(manuals, DeepEquals, map[string]string(nil))
   504  }
   505  
   506  func (s *snapmgrTestSuite) TestAliasTasks(c *C) {
   507  	s.state.Lock()
   508  	defer s.state.Unlock()
   509  
   510  	snapstate.Set(s.state, "some-snap", &snapstate.SnapState{
   511  		Sequence: []*snap.SideInfo{
   512  			{RealName: "some-snap", Revision: snap.R(11)},
   513  		},
   514  		Current: snap.R(11),
   515  		Active:  true,
   516  	})
   517  	snapstate.Set(s.state, "some-snap_instance", &snapstate.SnapState{
   518  		Sequence: []*snap.SideInfo{
   519  			{RealName: "some-snap", Revision: snap.R(11)},
   520  		},
   521  		Current:     snap.R(11),
   522  		Active:      true,
   523  		InstanceKey: "instance",
   524  	})
   525  
   526  	ts, err := snapstate.Alias(s.state, "some-snap", "cmd1", "alias1")
   527  	c.Assert(err, IsNil)
   528  
   529  	c.Assert(s.state.TaskCount(), Equals, len(ts.Tasks()))
   530  	c.Assert(taskKinds(ts.Tasks()), DeepEquals, []string{
   531  		"alias",
   532  	})
   533  
   534  	ts, err = snapstate.Alias(s.state, "some-snap_instance", "cmd1", "alias1")
   535  	c.Assert(err, IsNil)
   536  
   537  	c.Assert(s.state.TaskCount(), Equals, 2)
   538  	c.Assert(taskKinds(ts.Tasks()), DeepEquals, []string{
   539  		"alias",
   540  	})
   541  
   542  	var snapsup snapstate.SnapSetup
   543  	tasks := ts.Tasks()
   544  	c.Assert(tasks, HasLen, 1)
   545  	err = tasks[0].Get("snap-setup", &snapsup)
   546  	c.Assert(err, IsNil)
   547  	c.Check(snapsup.InstanceKey, Equals, "instance")
   548  	c.Check(snapsup.InstanceName(), Equals, "some-snap_instance")
   549  }
   550  
   551  type changedAlias struct {
   552  	Snap  string `json:"snap"`
   553  	App   string `json:"app"`
   554  	Alias string `json:"alias"`
   555  }
   556  
   557  type traceData struct {
   558  	Added   []*changedAlias `json:"aliases-added,omitempty"`
   559  	Removed []*changedAlias `json:"aliases-removed,omitempty"`
   560  }
   561  
   562  func (s *snapmgrTestSuite) TestAliasRunThrough(c *C) {
   563  	s.state.Lock()
   564  	defer s.state.Unlock()
   565  
   566  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   567  		Sequence: []*snap.SideInfo{
   568  			{RealName: "alias-snap", Revision: snap.R(11)},
   569  		},
   570  		Current: snap.R(11),
   571  		Active:  true,
   572  	})
   573  
   574  	chg := s.state.NewChange("alias", "manual alias")
   575  	ts, err := snapstate.Alias(s.state, "alias-snap", "cmd1", "alias1")
   576  	c.Assert(err, IsNil)
   577  	chg.AddAll(ts)
   578  
   579  	s.state.Unlock()
   580  	defer s.se.Stop()
   581  	s.settle(c)
   582  	s.state.Lock()
   583  
   584  	c.Assert(chg.Status(), Equals, state.DoneStatus, Commentf("%v", chg.Err()))
   585  	expected := fakeOps{
   586  		{
   587  			op:      "update-aliases",
   588  			aliases: []*backend.Alias{{Name: "alias1", Target: "alias-snap.cmd1"}},
   589  		},
   590  	}
   591  	// start with an easier-to-read error if this fails:
   592  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops())
   593  	c.Assert(s.fakeBackend.ops, DeepEquals, expected)
   594  
   595  	var snapst snapstate.SnapState
   596  	err = snapstate.Get(s.state, "alias-snap", &snapst)
   597  	c.Assert(err, IsNil)
   598  
   599  	c.Check(snapst.AutoAliasesDisabled, Equals, false)
   600  	c.Check(snapst.AliasesPending, Equals, false)
   601  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
   602  		"alias1": {Manual: "cmd1"},
   603  	})
   604  
   605  	var trace traceData
   606  	err = chg.Get("api-data", &trace)
   607  	c.Assert(err, IsNil)
   608  	c.Check(trace, DeepEquals, traceData{
   609  		Added: []*changedAlias{{Snap: "alias-snap", App: "cmd1", Alias: "alias1"}},
   610  	})
   611  }
   612  
   613  func (s *snapmgrTestSuite) TestParallelInstanceAliasRunThrough(c *C) {
   614  	s.state.Lock()
   615  	defer s.state.Unlock()
   616  
   617  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   618  		Sequence: []*snap.SideInfo{
   619  			{RealName: "alias-snap", Revision: snap.R(11)},
   620  		},
   621  		Current: snap.R(11),
   622  		Active:  true,
   623  	})
   624  	snapstate.Set(s.state, "alias-snap_foo", &snapstate.SnapState{
   625  		Sequence: []*snap.SideInfo{
   626  			{RealName: "alias-snap", Revision: snap.R(11)},
   627  		},
   628  		Current:     snap.R(11),
   629  		Active:      true,
   630  		InstanceKey: "foo",
   631  	})
   632  
   633  	chg := s.state.NewChange("alias", "manual alias")
   634  	ts, err := snapstate.Alias(s.state, "alias-snap_foo", "cmd1", "alias1")
   635  	c.Assert(err, IsNil)
   636  	chg.AddAll(ts)
   637  
   638  	s.state.Unlock()
   639  	defer s.se.Stop()
   640  	s.settle(c)
   641  	s.state.Lock()
   642  
   643  	c.Assert(chg.Status(), Equals, state.DoneStatus, Commentf("%v", chg.Err()))
   644  	expected := fakeOps{
   645  		{
   646  			op:      "update-aliases",
   647  			aliases: []*backend.Alias{{Name: "alias1", Target: "alias-snap_foo.cmd1"}},
   648  		},
   649  	}
   650  	// start with an easier-to-read error if this fails:
   651  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops())
   652  	c.Assert(s.fakeBackend.ops, DeepEquals, expected)
   653  
   654  	var snapst snapstate.SnapState
   655  	err = snapstate.Get(s.state, "alias-snap_foo", &snapst)
   656  	c.Assert(err, IsNil)
   657  
   658  	c.Check(snapst.AutoAliasesDisabled, Equals, false)
   659  	c.Check(snapst.AliasesPending, Equals, false)
   660  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
   661  		"alias1": {Manual: "cmd1"},
   662  	})
   663  
   664  	// snap without instance key is unchanged
   665  	err = snapstate.Get(s.state, "alias-snap", &snapst)
   666  	c.Assert(err, IsNil)
   667  	c.Check(snapst.Aliases, HasLen, 0)
   668  
   669  	var trace traceData
   670  	err = chg.Get("api-data", &trace)
   671  	c.Assert(err, IsNil)
   672  	c.Check(trace, DeepEquals, traceData{
   673  		Added: []*changedAlias{{Snap: "alias-snap_foo", App: "cmd1", Alias: "alias1"}},
   674  	})
   675  }
   676  
   677  func (s *snapmgrTestSuite) TestAliasNoTarget(c *C) {
   678  	s.state.Lock()
   679  	defer s.state.Unlock()
   680  
   681  	snapstate.Set(s.state, "some-snap", &snapstate.SnapState{
   682  		Sequence: []*snap.SideInfo{
   683  			{RealName: "some-snap", Revision: snap.R(11)},
   684  		},
   685  		Current: snap.R(11),
   686  		Active:  true,
   687  	})
   688  
   689  	chg := s.state.NewChange("alias", "manual alias")
   690  	ts, err := snapstate.Alias(s.state, "some-snap", "cmdno", "alias1")
   691  	c.Assert(err, IsNil)
   692  	chg.AddAll(ts)
   693  
   694  	s.state.Unlock()
   695  	s.se.Ensure()
   696  	s.se.Wait()
   697  	s.state.Lock()
   698  
   699  	c.Check(chg.Status(), Equals, state.ErrorStatus)
   700  	c.Check(chg.Err(), ErrorMatches, `(?s).*cannot enable alias "alias1" for "some-snap", target application "cmdno" does not exist.*`)
   701  }
   702  
   703  func (s *snapmgrTestSuite) TestAliasTargetIsDaemon(c *C) {
   704  	s.state.Lock()
   705  	defer s.state.Unlock()
   706  
   707  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   708  		Sequence: []*snap.SideInfo{
   709  			{RealName: "alias-snap", Revision: snap.R(11)},
   710  		},
   711  		Current: snap.R(11),
   712  		Active:  true,
   713  	})
   714  
   715  	chg := s.state.NewChange("alias", "manual alias")
   716  	ts, err := snapstate.Alias(s.state, "alias-snap", "cmddaemon", "alias1")
   717  	c.Assert(err, IsNil)
   718  	chg.AddAll(ts)
   719  
   720  	s.state.Unlock()
   721  	s.se.Ensure()
   722  	s.se.Wait()
   723  	s.state.Lock()
   724  
   725  	c.Check(chg.Status(), Equals, state.ErrorStatus)
   726  	c.Check(chg.Err(), ErrorMatches, `(?s).*cannot enable alias "alias1" for "alias-snap", target application "cmddaemon" is a daemon.*`)
   727  }
   728  
   729  func (s *snapmgrTestSuite) TestAliasInvalidAlias(c *C) {
   730  	s.state.Lock()
   731  	defer s.state.Unlock()
   732  
   733  	_, err := snapstate.Alias(s.state, "some-snap", "cmd", ".alias")
   734  	c.Assert(err, ErrorMatches, `invalid alias name: ".alias"`)
   735  }
   736  
   737  func (s *snapmgrTestSuite) TestAliasOverAutoRunThrough(c *C) {
   738  	s.state.Lock()
   739  	defer s.state.Unlock()
   740  
   741  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   742  		Sequence: []*snap.SideInfo{
   743  			{RealName: "alias-snap", Revision: snap.R(11)},
   744  		},
   745  		Current: snap.R(11),
   746  		Active:  true,
   747  		Aliases: map[string]*snapstate.AliasTarget{
   748  			"alias1": {Auto: "cmd1"},
   749  			"alias2": {Auto: "cmd2"},
   750  		},
   751  	})
   752  
   753  	chg := s.state.NewChange("alias", "manual alias")
   754  	ts, err := snapstate.Alias(s.state, "alias-snap", "cmd5", "alias1")
   755  	c.Assert(err, IsNil)
   756  	chg.AddAll(ts)
   757  
   758  	s.state.Unlock()
   759  	defer s.se.Stop()
   760  	s.settle(c)
   761  	s.state.Lock()
   762  
   763  	c.Assert(chg.Status(), Equals, state.DoneStatus, Commentf("%v", chg.Err()))
   764  	expected := fakeOps{
   765  		{
   766  			op:        "update-aliases",
   767  			rmAliases: []*backend.Alias{{Name: "alias1", Target: "alias-snap.cmd1"}},
   768  			aliases:   []*backend.Alias{{Name: "alias1", Target: "alias-snap.cmd5"}},
   769  		},
   770  	}
   771  	// start with an easier-to-read error if this fails:
   772  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops())
   773  	c.Assert(s.fakeBackend.ops, DeepEquals, expected)
   774  
   775  	var snapst snapstate.SnapState
   776  	err = snapstate.Get(s.state, "alias-snap", &snapst)
   777  	c.Assert(err, IsNil)
   778  
   779  	c.Check(snapst.AutoAliasesDisabled, Equals, false)
   780  	c.Check(snapst.AliasesPending, Equals, false)
   781  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
   782  		"alias1": {Manual: "cmd5", Auto: "cmd1"},
   783  		"alias2": {Auto: "cmd2"},
   784  	})
   785  }
   786  
   787  func (s *snapmgrTestSuite) TestAliasUpdateChangeConflict(c *C) {
   788  	s.state.Lock()
   789  	defer s.state.Unlock()
   790  
   791  	snapstate.Set(s.state, "some-snap", &snapstate.SnapState{
   792  		Active:   true,
   793  		Sequence: []*snap.SideInfo{{RealName: "some-snap", SnapID: "some-snap-id", Revision: snap.R(7)}},
   794  		Current:  snap.R(7),
   795  		SnapType: "app",
   796  	})
   797  
   798  	ts, err := snapstate.Alias(s.state, "some-snap", "cmd1", "alias1")
   799  	c.Assert(err, IsNil)
   800  	// need a change to make the tasks visible
   801  	s.state.NewChange("alias", "...").AddAll(ts)
   802  
   803  	_, err = snapstate.Update(s.state, "some-snap", nil, s.user.ID, snapstate.Flags{})
   804  	c.Assert(err, ErrorMatches, `snap "some-snap" has "alias" change in progress`)
   805  }
   806  
   807  func (s *snapmgrTestSuite) TestUpdateAliasChangeConflict(c *C) {
   808  	s.state.Lock()
   809  	defer s.state.Unlock()
   810  
   811  	snapstate.Set(s.state, "some-snap", &snapstate.SnapState{
   812  		Active:   true,
   813  		Sequence: []*snap.SideInfo{{RealName: "some-snap", SnapID: "some-snap-id", Revision: snap.R(7)}},
   814  		Current:  snap.R(7),
   815  		SnapType: "app",
   816  	})
   817  
   818  	ts, err := snapstate.Update(s.state, "some-snap", nil, s.user.ID, snapstate.Flags{})
   819  	c.Assert(err, IsNil)
   820  	// need a change to make the tasks visible
   821  	s.state.NewChange("update", "...").AddAll(ts)
   822  
   823  	_, err = snapstate.Alias(s.state, "some-snap", "cmd1", "alias1")
   824  	c.Assert(err, ErrorMatches, `snap "some-snap" has "update" change in progress`)
   825  }
   826  
   827  func (s *snapmgrTestSuite) TestAliasAliasConflict(c *C) {
   828  	s.state.Lock()
   829  	defer s.state.Unlock()
   830  
   831  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   832  		Sequence: []*snap.SideInfo{
   833  			{RealName: "alias-snap", Revision: snap.R(11)},
   834  		},
   835  		Current: snap.R(11),
   836  		Active:  true,
   837  	})
   838  	snapstate.Set(s.state, "other-snap", &snapstate.SnapState{
   839  		Sequence: []*snap.SideInfo{
   840  			{RealName: "other-snap", Revision: snap.R(2)},
   841  		},
   842  		Current: snap.R(2),
   843  		Active:  true,
   844  		Aliases: map[string]*snapstate.AliasTarget{
   845  			"alias1": {Auto: "cmd1"},
   846  		},
   847  	})
   848  
   849  	chg := s.state.NewChange("alias", "alias")
   850  	ts, err := snapstate.Alias(s.state, "alias-snap", "cmd5", "alias1")
   851  	c.Assert(err, IsNil)
   852  	chg.AddAll(ts)
   853  
   854  	s.state.Unlock()
   855  	s.se.Ensure()
   856  	s.se.Wait()
   857  	s.state.Lock()
   858  
   859  	c.Check(chg.Status(), Equals, state.ErrorStatus)
   860  	c.Check(chg.Err(), ErrorMatches, `(?s).*cannot enable alias "alias1" for "alias-snap", already enabled for "other-snap".*`)
   861  }
   862  
   863  func (s *snapmgrTestSuite) TestParallelInstanceAliasConflict(c *C) {
   864  	s.state.Lock()
   865  	defer s.state.Unlock()
   866  
   867  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   868  		Sequence: []*snap.SideInfo{
   869  			{RealName: "alias-snap", Revision: snap.R(11)},
   870  		},
   871  		Current: snap.R(11),
   872  		Active:  true,
   873  		Aliases: map[string]*snapstate.AliasTarget{
   874  			"alias2": {Auto: "cmd2"},
   875  		},
   876  	})
   877  	snapstate.Set(s.state, "alias-snap_foo", &snapstate.SnapState{
   878  		Sequence: []*snap.SideInfo{
   879  			{RealName: "alias-snap", Revision: snap.R(11)},
   880  		},
   881  		Current:     snap.R(11),
   882  		Active:      true,
   883  		InstanceKey: "foo",
   884  		Aliases: map[string]*snapstate.AliasTarget{
   885  			"alias1": {Auto: "cmd1"},
   886  		},
   887  	})
   888  
   889  	chg := s.state.NewChange("alias", "alias")
   890  	// conflicts with aliases of alias-snap_foo
   891  	ts, err := snapstate.Alias(s.state, "alias-snap", "cmd5", "alias1")
   892  	c.Assert(err, IsNil)
   893  	chg.AddAll(ts)
   894  
   895  	s.state.Unlock()
   896  	s.se.Ensure()
   897  	s.se.Wait()
   898  	s.state.Lock()
   899  
   900  	c.Check(chg.Status(), Equals, state.ErrorStatus)
   901  	c.Check(chg.Err(), ErrorMatches, `(?s).*cannot enable alias "alias1" for "alias-snap", already enabled for "alias-snap_foo".*`)
   902  
   903  	chg = s.state.NewChange("alias", "alias")
   904  	// conflicts with aliases of alias-snap
   905  	ts, err = snapstate.Alias(s.state, "alias-snap_foo", "cmd5", "alias2")
   906  	c.Assert(err, IsNil)
   907  	chg.AddAll(ts)
   908  
   909  	s.state.Unlock()
   910  	s.se.Ensure()
   911  	s.se.Wait()
   912  	s.state.Lock()
   913  
   914  	c.Check(chg.Status(), Equals, state.ErrorStatus)
   915  	c.Check(chg.Err(), ErrorMatches, `(?s).*cannot enable alias "alias2" for "alias-snap_foo", already enabled for "alias-snap".*`)
   916  }
   917  
   918  func (s *snapmgrTestSuite) TestDisableAllAliasesTasks(c *C) {
   919  	s.state.Lock()
   920  	defer s.state.Unlock()
   921  
   922  	snapstate.Set(s.state, "some-snap", &snapstate.SnapState{
   923  		Sequence: []*snap.SideInfo{
   924  			{RealName: "some-snap", Revision: snap.R(11)},
   925  		},
   926  		Current: snap.R(11),
   927  		Active:  true,
   928  	})
   929  
   930  	ts, err := snapstate.DisableAllAliases(s.state, "some-snap")
   931  	c.Assert(err, IsNil)
   932  
   933  	c.Assert(s.state.TaskCount(), Equals, len(ts.Tasks()))
   934  	c.Assert(taskKinds(ts.Tasks()), DeepEquals, []string{
   935  		"disable-aliases",
   936  	})
   937  }
   938  
   939  func (s *snapmgrTestSuite) TestDisableAllAliasesRunThrough(c *C) {
   940  	s.state.Lock()
   941  	defer s.state.Unlock()
   942  
   943  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   944  		Sequence: []*snap.SideInfo{
   945  			{RealName: "alias-snap", Revision: snap.R(11)},
   946  		},
   947  		Current: snap.R(11),
   948  		Active:  true,
   949  		Aliases: map[string]*snapstate.AliasTarget{
   950  			"alias1": {Manual: "cmd5", Auto: "cmd1"},
   951  			"alias2": {Auto: "cmd2"},
   952  			"alias3": {Manual: "cmd3"},
   953  		},
   954  	})
   955  
   956  	chg := s.state.NewChange("unalias", "unalias")
   957  	ts, err := snapstate.DisableAllAliases(s.state, "alias-snap")
   958  	c.Assert(err, IsNil)
   959  	chg.AddAll(ts)
   960  
   961  	s.state.Unlock()
   962  	defer s.se.Stop()
   963  	s.settle(c)
   964  	s.state.Lock()
   965  
   966  	c.Assert(chg.Status(), Equals, state.DoneStatus, Commentf("%v", chg.Err()))
   967  	expected := fakeOps{
   968  		{
   969  			op: "update-aliases",
   970  			rmAliases: []*backend.Alias{
   971  				{Name: "alias1", Target: "alias-snap.cmd5"},
   972  				{Name: "alias2", Target: "alias-snap.cmd2"},
   973  				{Name: "alias3", Target: "alias-snap.cmd3"},
   974  			},
   975  		},
   976  	}
   977  	// start with an easier-to-read error if this fails:
   978  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops())
   979  	c.Assert(s.fakeBackend.ops, DeepEquals, expected)
   980  
   981  	var snapst snapstate.SnapState
   982  	err = snapstate.Get(s.state, "alias-snap", &snapst)
   983  	c.Assert(err, IsNil)
   984  
   985  	c.Check(snapst.AutoAliasesDisabled, Equals, true)
   986  	c.Check(snapst.AliasesPending, Equals, false)
   987  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
   988  		"alias1": {Auto: "cmd1"},
   989  		"alias2": {Auto: "cmd2"},
   990  	})
   991  
   992  	var trace traceData
   993  	err = chg.Get("api-data", &trace)
   994  	c.Assert(err, IsNil)
   995  	c.Check(trace.Added, HasLen, 0)
   996  	c.Check(trace.Removed, HasLen, 3)
   997  }
   998  
   999  func (s *snapmgrTestSuite) TestParallelInstanceDisableAllAliasesRunThrough(c *C) {
  1000  	s.state.Lock()
  1001  	defer s.state.Unlock()
  1002  
  1003  	snapstate.Set(s.state, "alias-snap_instance", &snapstate.SnapState{
  1004  		Sequence: []*snap.SideInfo{
  1005  			{RealName: "alias-snap", Revision: snap.R(11)},
  1006  		},
  1007  		Current: snap.R(11),
  1008  		Active:  true,
  1009  		Aliases: map[string]*snapstate.AliasTarget{
  1010  			"alias1": {Auto: "cmd1"},
  1011  			"alias2": {Auto: "cmd2"},
  1012  			"alias3": {Manual: "cmd3"},
  1013  		},
  1014  		InstanceKey: "instance",
  1015  	})
  1016  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
  1017  		Sequence: []*snap.SideInfo{
  1018  			{RealName: "alias-snap", Revision: snap.R(11)},
  1019  		},
  1020  		Current: snap.R(11),
  1021  		Active:  true,
  1022  		Aliases: map[string]*snapstate.AliasTarget{
  1023  			"alias1": {Manual: "cmd6"},
  1024  			"alias2": {Manual: "cmd7"},
  1025  		},
  1026  	})
  1027  
  1028  	chg := s.state.NewChange("unalias", "unalias")
  1029  	ts, err := snapstate.DisableAllAliases(s.state, "alias-snap_instance")
  1030  	c.Assert(err, IsNil)
  1031  	chg.AddAll(ts)
  1032  
  1033  	s.state.Unlock()
  1034  	defer s.se.Stop()
  1035  	s.settle(c)
  1036  	s.state.Lock()
  1037  
  1038  	c.Assert(chg.Status(), Equals, state.DoneStatus, Commentf("%v", chg.Err()))
  1039  	expected := fakeOps{
  1040  		{
  1041  			op: "update-aliases",
  1042  			rmAliases: []*backend.Alias{
  1043  				{Name: "alias1", Target: "alias-snap_instance.cmd1"},
  1044  				{Name: "alias2", Target: "alias-snap_instance.cmd2"},
  1045  				{Name: "alias3", Target: "alias-snap_instance.cmd3"},
  1046  			},
  1047  		},
  1048  	}
  1049  	// start with an easier-to-read error if this fails:
  1050  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops())
  1051  	c.Assert(s.fakeBackend.ops, DeepEquals, expected)
  1052  
  1053  	var snapst snapstate.SnapState
  1054  	err = snapstate.Get(s.state, "alias-snap_instance", &snapst)
  1055  	c.Assert(err, IsNil)
  1056  
  1057  	c.Check(snapst.AutoAliasesDisabled, Equals, true)
  1058  	c.Check(snapst.AliasesPending, Equals, false)
  1059  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1060  		"alias1": {Auto: "cmd1"},
  1061  		"alias2": {Auto: "cmd2"},
  1062  	})
  1063  
  1064  	var trace traceData
  1065  	err = chg.Get("api-data", &trace)
  1066  	c.Assert(err, IsNil)
  1067  	c.Check(trace.Added, HasLen, 0)
  1068  	c.Check(trace.Removed, HasLen, 3)
  1069  
  1070  	// non _instance instance is unchanged
  1071  	err = snapstate.Get(s.state, "alias-snap", &snapst)
  1072  	c.Assert(err, IsNil)
  1073  	c.Check(snapst.AutoAliasesDisabled, Equals, false)
  1074  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1075  		"alias1": {Manual: "cmd6"},
  1076  		"alias2": {Manual: "cmd7"},
  1077  	})
  1078  }
  1079  
  1080  func (s *snapmgrTestSuite) TestRemoveManualAliasTasks(c *C) {
  1081  	s.state.Lock()
  1082  	defer s.state.Unlock()
  1083  
  1084  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
  1085  		Sequence: []*snap.SideInfo{
  1086  			{RealName: "alias-snap", Revision: snap.R(11)},
  1087  		},
  1088  		Current: snap.R(11),
  1089  		Active:  true,
  1090  		Aliases: map[string]*snapstate.AliasTarget{
  1091  			"alias1": {Manual: "cmd5"},
  1092  		},
  1093  	})
  1094  
  1095  	ts, snapName, err := snapstate.RemoveManualAlias(s.state, "alias1")
  1096  	c.Assert(err, IsNil)
  1097  	c.Check(snapName, Equals, "alias-snap")
  1098  
  1099  	c.Assert(s.state.TaskCount(), Equals, len(ts.Tasks()))
  1100  	c.Assert(taskKinds(ts.Tasks()), DeepEquals, []string{
  1101  		"unalias",
  1102  	})
  1103  	task := ts.Tasks()[0]
  1104  	var alias string
  1105  	err = task.Get("alias", &alias)
  1106  	c.Assert(err, IsNil)
  1107  	c.Check(alias, Equals, "alias1")
  1108  }
  1109  
  1110  func (s *snapmgrTestSuite) TestRemoveManualAliasRunThrough(c *C) {
  1111  	s.state.Lock()
  1112  	defer s.state.Unlock()
  1113  
  1114  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
  1115  		Sequence: []*snap.SideInfo{
  1116  			{RealName: "alias-snap", Revision: snap.R(11)},
  1117  		},
  1118  		Current: snap.R(11),
  1119  		Active:  true,
  1120  		Aliases: map[string]*snapstate.AliasTarget{
  1121  			"alias1": {Manual: "cmd5"},
  1122  		},
  1123  	})
  1124  
  1125  	chg := s.state.NewChange("alias", "manual alias")
  1126  	ts, _, err := snapstate.RemoveManualAlias(s.state, "alias1")
  1127  	c.Assert(err, IsNil)
  1128  	chg.AddAll(ts)
  1129  
  1130  	s.state.Unlock()
  1131  	defer s.se.Stop()
  1132  	s.settle(c)
  1133  	s.state.Lock()
  1134  
  1135  	c.Assert(chg.Status(), Equals, state.DoneStatus, Commentf("%v", chg.Err()))
  1136  	expected := fakeOps{
  1137  		{
  1138  			op:        "update-aliases",
  1139  			rmAliases: []*backend.Alias{{Name: "alias1", Target: "alias-snap.cmd5"}},
  1140  		},
  1141  	}
  1142  	// start with an easier-to-read error if this fails:
  1143  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops())
  1144  	c.Assert(s.fakeBackend.ops, DeepEquals, expected)
  1145  
  1146  	var snapst snapstate.SnapState
  1147  	err = snapstate.Get(s.state, "alias-snap", &snapst)
  1148  	c.Assert(err, IsNil)
  1149  
  1150  	c.Check(snapst.AutoAliasesDisabled, Equals, false)
  1151  	c.Check(snapst.AliasesPending, Equals, false)
  1152  	c.Check(snapst.Aliases, HasLen, 0)
  1153  
  1154  	var trace traceData
  1155  	err = chg.Get("api-data", &trace)
  1156  	c.Assert(err, IsNil)
  1157  	c.Check(trace, DeepEquals, traceData{
  1158  		Removed: []*changedAlias{{Snap: "alias-snap", App: "cmd5", Alias: "alias1"}},
  1159  	})
  1160  }
  1161  
  1162  func (s *snapmgrTestSuite) TestRemoveManualAliasOverAutoRunThrough(c *C) {
  1163  	s.state.Lock()
  1164  	defer s.state.Unlock()
  1165  
  1166  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
  1167  		Sequence: []*snap.SideInfo{
  1168  			{RealName: "alias-snap", Revision: snap.R(11)},
  1169  		},
  1170  		Current: snap.R(11),
  1171  		Active:  true,
  1172  		Aliases: map[string]*snapstate.AliasTarget{
  1173  			"alias1": {Manual: "cmd5", Auto: "cmd1"},
  1174  		},
  1175  	})
  1176  
  1177  	chg := s.state.NewChange("alias", "manual alias")
  1178  	ts, _, err := snapstate.RemoveManualAlias(s.state, "alias1")
  1179  	c.Assert(err, IsNil)
  1180  	chg.AddAll(ts)
  1181  
  1182  	s.state.Unlock()
  1183  	defer s.se.Stop()
  1184  	s.settle(c)
  1185  	s.state.Lock()
  1186  
  1187  	c.Assert(chg.Status(), Equals, state.DoneStatus, Commentf("%v", chg.Err()))
  1188  	expected := fakeOps{
  1189  		{
  1190  			op:        "update-aliases",
  1191  			rmAliases: []*backend.Alias{{Name: "alias1", Target: "alias-snap.cmd5"}},
  1192  			aliases:   []*backend.Alias{{Name: "alias1", Target: "alias-snap.cmd1"}},
  1193  		},
  1194  	}
  1195  	// start with an easier-to-read error if this fails:
  1196  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops())
  1197  	c.Assert(s.fakeBackend.ops, DeepEquals, expected)
  1198  
  1199  	var snapst snapstate.SnapState
  1200  	err = snapstate.Get(s.state, "alias-snap", &snapst)
  1201  	c.Assert(err, IsNil)
  1202  
  1203  	c.Check(snapst.AutoAliasesDisabled, Equals, false)
  1204  	c.Check(snapst.AliasesPending, Equals, false)
  1205  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1206  		"alias1": {Auto: "cmd1"},
  1207  	})
  1208  }
  1209  
  1210  func (s *snapmgrTestSuite) TestParallelInstanceRemoveManualAliasRunThrough(c *C) {
  1211  	s.state.Lock()
  1212  	defer s.state.Unlock()
  1213  
  1214  	snapstate.Set(s.state, "alias-snap_instance", &snapstate.SnapState{
  1215  		Sequence: []*snap.SideInfo{
  1216  			{RealName: "alias-snap", Revision: snap.R(11)},
  1217  		},
  1218  		Current: snap.R(11),
  1219  		Active:  true,
  1220  		Aliases: map[string]*snapstate.AliasTarget{
  1221  			"alias1": {Manual: "cmd2", Auto: "cmd1"},
  1222  		},
  1223  		InstanceKey: "instance",
  1224  	})
  1225  
  1226  	chg := s.state.NewChange("alias", "manual alias")
  1227  	ts, _, err := snapstate.RemoveManualAlias(s.state, "alias1")
  1228  	c.Assert(err, IsNil)
  1229  	chg.AddAll(ts)
  1230  
  1231  	s.state.Unlock()
  1232  	defer s.se.Stop()
  1233  	s.settle(c)
  1234  	s.state.Lock()
  1235  
  1236  	c.Assert(chg.Status(), Equals, state.DoneStatus, Commentf("%v", chg.Err()))
  1237  	expected := fakeOps{
  1238  		{
  1239  			op:        "update-aliases",
  1240  			rmAliases: []*backend.Alias{{Name: "alias1", Target: "alias-snap_instance.cmd2"}},
  1241  			aliases:   []*backend.Alias{{Name: "alias1", Target: "alias-snap_instance.cmd1"}},
  1242  		},
  1243  	}
  1244  	// start with an easier-to-read error if this fails:
  1245  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops())
  1246  	c.Assert(s.fakeBackend.ops, DeepEquals, expected)
  1247  
  1248  	var snapst snapstate.SnapState
  1249  	err = snapstate.Get(s.state, "alias-snap_instance", &snapst)
  1250  	c.Assert(err, IsNil)
  1251  
  1252  	c.Check(snapst.AutoAliasesDisabled, Equals, false)
  1253  	c.Check(snapst.AliasesPending, Equals, false)
  1254  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1255  		"alias1": {Auto: "cmd1"},
  1256  	})
  1257  }
  1258  
  1259  func (s *snapmgrTestSuite) TestRemoveManualAliasNoAlias(c *C) {
  1260  	s.state.Lock()
  1261  	defer s.state.Unlock()
  1262  
  1263  	_, _, err := snapstate.RemoveManualAlias(s.state, "alias1")
  1264  	c.Assert(err, ErrorMatches, `cannot find manual alias "alias1" in any snap`)
  1265  }
  1266  
  1267  func (s *snapmgrTestSuite) TestUpdateDisableAllAliasesChangeConflict(c *C) {
  1268  	s.state.Lock()
  1269  	defer s.state.Unlock()
  1270  
  1271  	snapstate.Set(s.state, "some-snap", &snapstate.SnapState{
  1272  		Active:   true,
  1273  		Sequence: []*snap.SideInfo{{RealName: "some-snap", SnapID: "some-snap-id", Revision: snap.R(7)}},
  1274  		Current:  snap.R(7),
  1275  		SnapType: "app",
  1276  		Aliases: map[string]*snapstate.AliasTarget{
  1277  			"alias1": {Manual: "cmd5"},
  1278  		},
  1279  	})
  1280  
  1281  	ts, err := snapstate.Update(s.state, "some-snap", nil, s.user.ID, snapstate.Flags{})
  1282  	c.Assert(err, IsNil)
  1283  	// need a change to make the tasks visible
  1284  	s.state.NewChange("update", "...").AddAll(ts)
  1285  
  1286  	_, err = snapstate.DisableAllAliases(s.state, "some-snap")
  1287  	c.Assert(err, ErrorMatches, `snap "some-snap" has "update" change in progress`)
  1288  }
  1289  
  1290  func (s *snapmgrTestSuite) TestUpdateRemoveManualAliasChangeConflict(c *C) {
  1291  	s.state.Lock()
  1292  	defer s.state.Unlock()
  1293  
  1294  	snapstate.Set(s.state, "some-snap", &snapstate.SnapState{
  1295  		Active:   true,
  1296  		Sequence: []*snap.SideInfo{{RealName: "some-snap", SnapID: "some-snap-id", Revision: snap.R(7)}},
  1297  		Current:  snap.R(7),
  1298  		SnapType: "app",
  1299  		Aliases: map[string]*snapstate.AliasTarget{
  1300  			"alias1": {Manual: "cmd5"},
  1301  		},
  1302  	})
  1303  
  1304  	ts, err := snapstate.Update(s.state, "some-snap", nil, s.user.ID, snapstate.Flags{})
  1305  	c.Assert(err, IsNil)
  1306  	// need a change to make the tasks visible
  1307  	s.state.NewChange("update", "...").AddAll(ts)
  1308  
  1309  	_, _, err = snapstate.RemoveManualAlias(s.state, "alias1")
  1310  	c.Assert(err, ErrorMatches, `snap "some-snap" has "update" change in progress`)
  1311  }
  1312  
  1313  func (s *snapmgrTestSuite) TestDisableAllAliasesUpdateChangeConflict(c *C) {
  1314  	s.state.Lock()
  1315  	defer s.state.Unlock()
  1316  
  1317  	snapstate.Set(s.state, "some-snap", &snapstate.SnapState{
  1318  		Active:   true,
  1319  		Sequence: []*snap.SideInfo{{RealName: "some-snap", SnapID: "some-snap-id", Revision: snap.R(7)}},
  1320  		Current:  snap.R(7),
  1321  		SnapType: "app",
  1322  	})
  1323  
  1324  	ts, err := snapstate.DisableAllAliases(s.state, "some-snap")
  1325  	c.Assert(err, IsNil)
  1326  	// need a change to make the tasks visible
  1327  	s.state.NewChange("alias", "...").AddAll(ts)
  1328  
  1329  	_, err = snapstate.Update(s.state, "some-snap", nil, s.user.ID, snapstate.Flags{})
  1330  	c.Assert(err, ErrorMatches, `snap "some-snap" has "alias" change in progress`)
  1331  }
  1332  
  1333  func (s *snapmgrTestSuite) TestRemoveManualAliasUpdateChangeConflict(c *C) {
  1334  	s.state.Lock()
  1335  	defer s.state.Unlock()
  1336  
  1337  	snapstate.Set(s.state, "some-snap", &snapstate.SnapState{
  1338  		Active:   true,
  1339  		Sequence: []*snap.SideInfo{{RealName: "some-snap", SnapID: "some-snap-id", Revision: snap.R(7)}},
  1340  		Current:  snap.R(7),
  1341  		SnapType: "app",
  1342  		Aliases: map[string]*snapstate.AliasTarget{
  1343  			"alias1": {Manual: "cmd5"},
  1344  		},
  1345  	})
  1346  
  1347  	ts, _, err := snapstate.RemoveManualAlias(s.state, "alias1")
  1348  	c.Assert(err, IsNil)
  1349  	// need a change to make the tasks visible
  1350  	s.state.NewChange("unalias", "...").AddAll(ts)
  1351  
  1352  	_, err = snapstate.Update(s.state, "some-snap", nil, s.user.ID, snapstate.Flags{})
  1353  	c.Assert(err, ErrorMatches, `snap "some-snap" has "unalias" change in progress`)
  1354  }
  1355  
  1356  func (s *snapmgrTestSuite) TestPreferTasks(c *C) {
  1357  	s.state.Lock()
  1358  	defer s.state.Unlock()
  1359  
  1360  	snapstate.Set(s.state, "some-snap", &snapstate.SnapState{
  1361  		Sequence: []*snap.SideInfo{
  1362  			{RealName: "some-snap", Revision: snap.R(11)},
  1363  		},
  1364  		Current: snap.R(11),
  1365  		Active:  true,
  1366  	})
  1367  
  1368  	ts, err := snapstate.Prefer(s.state, "some-snap")
  1369  	c.Assert(err, IsNil)
  1370  
  1371  	c.Assert(s.state.TaskCount(), Equals, len(ts.Tasks()))
  1372  	c.Assert(taskKinds(ts.Tasks()), DeepEquals, []string{
  1373  		"prefer-aliases",
  1374  	})
  1375  }
  1376  
  1377  func (s *snapmgrTestSuite) TestPreferRunThrough(c *C) {
  1378  	s.state.Lock()
  1379  	defer s.state.Unlock()
  1380  
  1381  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
  1382  		Sequence: []*snap.SideInfo{
  1383  			{RealName: "alias-snap", Revision: snap.R(11)},
  1384  		},
  1385  		Current:             snap.R(11),
  1386  		Active:              true,
  1387  		AutoAliasesDisabled: true,
  1388  		Aliases: map[string]*snapstate.AliasTarget{
  1389  			"alias1": {Auto: "cmd1"},
  1390  			"alias2": {Auto: "cmd2"},
  1391  		},
  1392  	})
  1393  
  1394  	chg := s.state.NewChange("prefer", "prefer")
  1395  	ts, err := snapstate.Prefer(s.state, "alias-snap")
  1396  	c.Assert(err, IsNil)
  1397  	chg.AddAll(ts)
  1398  
  1399  	s.state.Unlock()
  1400  	defer s.se.Stop()
  1401  	s.settle(c)
  1402  	s.state.Lock()
  1403  
  1404  	c.Assert(chg.Status(), Equals, state.DoneStatus, Commentf("%v", chg.Err()))
  1405  	expected := fakeOps{
  1406  		{
  1407  			op: "update-aliases",
  1408  			aliases: []*backend.Alias{
  1409  				{Name: "alias1", Target: "alias-snap.cmd1"},
  1410  				{Name: "alias2", Target: "alias-snap.cmd2"},
  1411  			},
  1412  		},
  1413  	}
  1414  	// start with an easier-to-read error if this fails:
  1415  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops())
  1416  	c.Assert(s.fakeBackend.ops, DeepEquals, expected)
  1417  
  1418  	var snapst snapstate.SnapState
  1419  	err = snapstate.Get(s.state, "alias-snap", &snapst)
  1420  	c.Assert(err, IsNil)
  1421  
  1422  	c.Check(snapst.AutoAliasesDisabled, Equals, false)
  1423  	c.Check(snapst.AliasesPending, Equals, false)
  1424  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1425  		"alias1": {Auto: "cmd1"},
  1426  		"alias2": {Auto: "cmd2"},
  1427  	})
  1428  }
  1429  
  1430  func (s *snapmgrTestSuite) TestParallelInstancePreferRunThrough(c *C) {
  1431  	s.state.Lock()
  1432  	defer s.state.Unlock()
  1433  
  1434  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
  1435  		Sequence: []*snap.SideInfo{
  1436  			{RealName: "alias-snap", Revision: snap.R(11)},
  1437  		},
  1438  		Current: snap.R(11),
  1439  		Active:  true,
  1440  		Aliases: map[string]*snapstate.AliasTarget{
  1441  			"alias1": {Auto: "cmd1"},
  1442  			"alias2": {Auto: "cmd2"},
  1443  		},
  1444  	})
  1445  	snapstate.Set(s.state, "alias-snap_instance", &snapstate.SnapState{
  1446  		Sequence: []*snap.SideInfo{
  1447  			{RealName: "alias-snap", Revision: snap.R(11)},
  1448  		},
  1449  		Current:             snap.R(11),
  1450  		Active:              true,
  1451  		AutoAliasesDisabled: true,
  1452  		Aliases: map[string]*snapstate.AliasTarget{
  1453  			"alias1": {Auto: "cmd1"},
  1454  			"alias2": {Auto: "cmd2"},
  1455  		},
  1456  	})
  1457  
  1458  	chg := s.state.NewChange("prefer", "prefer")
  1459  	ts, err := snapstate.Prefer(s.state, "alias-snap_instance")
  1460  	c.Assert(err, IsNil)
  1461  	chg.AddAll(ts)
  1462  
  1463  	s.state.Unlock()
  1464  	defer s.se.Stop()
  1465  	s.settle(c)
  1466  	s.state.Lock()
  1467  
  1468  	c.Assert(chg.Status(), Equals, state.DoneStatus, Commentf("%v", chg.Err()))
  1469  	expected := fakeOps{
  1470  		{
  1471  			op: "update-aliases",
  1472  			rmAliases: []*backend.Alias{
  1473  				{Name: "alias1", Target: "alias-snap.cmd1"},
  1474  				{Name: "alias2", Target: "alias-snap.cmd2"},
  1475  			},
  1476  		},
  1477  		{
  1478  			op: "update-aliases",
  1479  			aliases: []*backend.Alias{
  1480  				{Name: "alias1", Target: "alias-snap_instance.cmd1"},
  1481  				{Name: "alias2", Target: "alias-snap_instance.cmd2"},
  1482  			},
  1483  		},
  1484  	}
  1485  	// start with an easier-to-read error if this fails:
  1486  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops())
  1487  	c.Assert(s.fakeBackend.ops, DeepEquals, expected)
  1488  
  1489  	var snapst snapstate.SnapState
  1490  	err = snapstate.Get(s.state, "alias-snap_instance", &snapst)
  1491  	c.Assert(err, IsNil)
  1492  	// _instance aliases are preferred now
  1493  	c.Check(snapst.AutoAliasesDisabled, Equals, false)
  1494  	c.Check(snapst.AliasesPending, Equals, false)
  1495  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1496  		"alias1": {Auto: "cmd1"},
  1497  		"alias2": {Auto: "cmd2"},
  1498  	})
  1499  
  1500  	err = snapstate.Get(s.state, "alias-snap", &snapst)
  1501  	c.Assert(err, IsNil)
  1502  	c.Check(snapst.AutoAliasesDisabled, Equals, true)
  1503  	c.Check(snapst.AliasesPending, Equals, false)
  1504  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1505  		"alias1": {Auto: "cmd1"},
  1506  		"alias2": {Auto: "cmd2"},
  1507  	})
  1508  
  1509  }
  1510  
  1511  func (s *snapmgrTestSuite) TestUpdatePreferChangeConflict(c *C) {
  1512  	s.state.Lock()
  1513  	defer s.state.Unlock()
  1514  
  1515  	snapstate.Set(s.state, "some-snap", &snapstate.SnapState{
  1516  		Active:              true,
  1517  		Sequence:            []*snap.SideInfo{{RealName: "some-snap", SnapID: "some-snap-id", Revision: snap.R(7)}},
  1518  		Current:             snap.R(7),
  1519  		SnapType:            "app",
  1520  		AutoAliasesDisabled: true,
  1521  		Aliases: map[string]*snapstate.AliasTarget{
  1522  			"alias1": {Auto: "cmd1"},
  1523  		},
  1524  	})
  1525  
  1526  	ts, err := snapstate.Update(s.state, "some-snap", nil, s.user.ID, snapstate.Flags{})
  1527  	c.Assert(err, IsNil)
  1528  	// need a change to make the tasks visible
  1529  	s.state.NewChange("update", "...").AddAll(ts)
  1530  
  1531  	_, err = snapstate.Prefer(s.state, "some-snap")
  1532  	c.Assert(err, ErrorMatches, `snap "some-snap" has "update" change in progress`)
  1533  }
  1534  
  1535  func (s *snapmgrTestSuite) TestPreferUpdateChangeConflict(c *C) {
  1536  	s.state.Lock()
  1537  	defer s.state.Unlock()
  1538  
  1539  	snapstate.Set(s.state, "some-snap", &snapstate.SnapState{
  1540  		Active:              true,
  1541  		Sequence:            []*snap.SideInfo{{RealName: "some-snap", SnapID: "some-snap-id", Revision: snap.R(7)}},
  1542  		Current:             snap.R(7),
  1543  		SnapType:            "app",
  1544  		AutoAliasesDisabled: true,
  1545  		Aliases: map[string]*snapstate.AliasTarget{
  1546  			"alias1": {Auto: "cmd1"},
  1547  		},
  1548  	})
  1549  
  1550  	ts, err := snapstate.Prefer(s.state, "some-snap")
  1551  	c.Assert(err, IsNil)
  1552  	// need a change to make the tasks visible
  1553  	s.state.NewChange("prefer", "...").AddAll(ts)
  1554  
  1555  	_, err = snapstate.Update(s.state, "some-snap", nil, s.user.ID, snapstate.Flags{})
  1556  	c.Assert(err, ErrorMatches, `snap "some-snap" has "prefer" change in progress`)
  1557  }