github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/overlord/snapstate/handlers_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  	. "gopkg.in/check.v1"
    24  	"gopkg.in/tomb.v2"
    25  
    26  	"github.com/snapcore/snapd/overlord/snapstate"
    27  	"github.com/snapcore/snapd/overlord/snapstate/backend"
    28  	"github.com/snapcore/snapd/overlord/state"
    29  	"github.com/snapcore/snapd/snap"
    30  )
    31  
    32  func (s *snapmgrTestSuite) TestDoSetAutoAliases(c *C) {
    33  	s.state.Lock()
    34  	defer s.state.Unlock()
    35  
    36  	snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) {
    37  		c.Check(info.InstanceName(), Equals, "alias-snap")
    38  		return map[string]string{
    39  			"alias1": "cmd1",
    40  			"alias2": "cmd2",
    41  			"alias4": "cmd4",
    42  		}, nil
    43  	}
    44  
    45  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
    46  		Sequence: []*snap.SideInfo{
    47  			{RealName: "alias-snap", Revision: snap.R(11)},
    48  		},
    49  		Current:             snap.R(11),
    50  		Active:              true,
    51  		AutoAliasesDisabled: false,
    52  		AliasesPending:      true,
    53  		Aliases: map[string]*snapstate.AliasTarget{
    54  			"alias1": {Auto: "cmd1"},
    55  			"alias2": {Auto: "cmd2x"},
    56  			"alias3": {Auto: "cmd3"},
    57  		},
    58  	})
    59  
    60  	t := s.state.NewTask("set-auto-aliases", "test")
    61  	t.Set("snap-setup", &snapstate.SnapSetup{
    62  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
    63  	})
    64  	chg := s.state.NewChange("dummy", "...")
    65  	chg.AddTask(t)
    66  
    67  	s.state.Unlock()
    68  
    69  	s.se.Ensure()
    70  	s.se.Wait()
    71  
    72  	s.state.Lock()
    73  
    74  	c.Check(t.Status(), Equals, state.DoneStatus, Commentf("%v", chg.Err()))
    75  
    76  	var snapst snapstate.SnapState
    77  	err := snapstate.Get(s.state, "alias-snap", &snapst)
    78  	c.Assert(err, IsNil)
    79  
    80  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
    81  		"alias1": {Auto: "cmd1"},
    82  		"alias2": {Auto: "cmd2"},
    83  		"alias4": {Auto: "cmd4"},
    84  	})
    85  }
    86  
    87  func (s *snapmgrTestSuite) TestDoSetAutoAliasesFirstInstall(c *C) {
    88  	s.state.Lock()
    89  	defer s.state.Unlock()
    90  
    91  	snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) {
    92  		c.Check(info.InstanceName(), Equals, "alias-snap")
    93  		return map[string]string{
    94  			"alias1": "cmd1",
    95  			"alias2": "cmd2",
    96  			"alias4": "cmd4",
    97  		}, nil
    98  	}
    99  
   100  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   101  		Sequence: []*snap.SideInfo{
   102  			{RealName: "alias-snap", Revision: snap.R(11)},
   103  		},
   104  		Current: snap.R(11),
   105  		Active:  true,
   106  	})
   107  
   108  	t := s.state.NewTask("set-auto-aliases", "test")
   109  	t.Set("snap-setup", &snapstate.SnapSetup{
   110  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
   111  	})
   112  	chg := s.state.NewChange("dummy", "...")
   113  	chg.AddTask(t)
   114  
   115  	s.state.Unlock()
   116  
   117  	s.se.Ensure()
   118  	s.se.Wait()
   119  
   120  	s.state.Lock()
   121  
   122  	c.Check(t.Status(), Equals, state.DoneStatus, Commentf("%v", chg.Err()))
   123  
   124  	var snapst snapstate.SnapState
   125  	err := snapstate.Get(s.state, "alias-snap", &snapst)
   126  	c.Assert(err, IsNil)
   127  
   128  	c.Check(snapst.AutoAliasesDisabled, Equals, false)
   129  	c.Check(snapst.AliasesPending, Equals, true)
   130  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
   131  		"alias1": {Auto: "cmd1"},
   132  		"alias2": {Auto: "cmd2"},
   133  		"alias4": {Auto: "cmd4"},
   134  	})
   135  }
   136  
   137  func (s *snapmgrTestSuite) TestDoUndoSetAutoAliases(c *C) {
   138  	s.state.Lock()
   139  	defer s.state.Unlock()
   140  
   141  	snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) {
   142  		c.Check(info.InstanceName(), Equals, "alias-snap")
   143  		return map[string]string{
   144  			"alias1": "cmd1",
   145  			"alias2": "cmd2",
   146  			"alias4": "cmd4",
   147  		}, nil
   148  	}
   149  
   150  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   151  		Sequence: []*snap.SideInfo{
   152  			{RealName: "alias-snap", Revision: snap.R(11)},
   153  		},
   154  		Current:        snap.R(11),
   155  		Active:         true,
   156  		AliasesPending: true,
   157  		Aliases: map[string]*snapstate.AliasTarget{
   158  			"alias1": {Auto: "cmd1"},
   159  			"alias2": {Auto: "cmd2x"},
   160  			"alias3": {Auto: "cmd3"},
   161  		},
   162  	})
   163  
   164  	t := s.state.NewTask("set-auto-aliases", "test")
   165  	t.Set("snap-setup", &snapstate.SnapSetup{
   166  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
   167  	})
   168  	chg := s.state.NewChange("dummy", "...")
   169  	chg.AddTask(t)
   170  
   171  	terr := s.state.NewTask("error-trigger", "provoking total undo")
   172  	terr.WaitFor(t)
   173  	chg.AddTask(terr)
   174  
   175  	s.state.Unlock()
   176  
   177  	for i := 0; i < 3; i++ {
   178  		s.se.Ensure()
   179  		s.se.Wait()
   180  	}
   181  
   182  	s.state.Lock()
   183  
   184  	c.Check(t.Status(), Equals, state.UndoneStatus, Commentf("%v", chg.Err()))
   185  
   186  	var snapst snapstate.SnapState
   187  	err := snapstate.Get(s.state, "alias-snap", &snapst)
   188  	c.Assert(err, IsNil)
   189  
   190  	c.Check(snapst.AliasesPending, Equals, true)
   191  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
   192  		"alias1": {Auto: "cmd1"},
   193  		"alias2": {Auto: "cmd2x"},
   194  		"alias3": {Auto: "cmd3"},
   195  	})
   196  }
   197  
   198  func (s *snapmgrTestSuite) TestDoSetAutoAliasesConflict(c *C) {
   199  	s.state.Lock()
   200  	defer s.state.Unlock()
   201  
   202  	snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) {
   203  		c.Check(info.InstanceName(), Equals, "alias-snap")
   204  		return map[string]string{
   205  			"alias1": "cmd1",
   206  			"alias2": "cmd2",
   207  			"alias4": "cmd4",
   208  		}, nil
   209  	}
   210  
   211  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   212  		Sequence: []*snap.SideInfo{
   213  			{RealName: "alias-snap", Revision: snap.R(11)},
   214  		},
   215  		Current:        snap.R(11),
   216  		Active:         true,
   217  		AliasesPending: true,
   218  		Aliases: map[string]*snapstate.AliasTarget{
   219  			"alias1": {Auto: "cmd1"},
   220  			"alias2": {Auto: "cmd2x"},
   221  			"alias3": {Auto: "cmd3"},
   222  		},
   223  	})
   224  	snapstate.Set(s.state, "other-snap", &snapstate.SnapState{
   225  		Sequence: []*snap.SideInfo{
   226  			{RealName: "other-snap", Revision: snap.R(3)},
   227  		},
   228  		Current:        snap.R(3),
   229  		Active:         true,
   230  		AliasesPending: true,
   231  		Aliases: map[string]*snapstate.AliasTarget{
   232  			"alias4": {Auto: "cmd4"},
   233  		},
   234  	})
   235  
   236  	t := s.state.NewTask("set-auto-aliases", "test")
   237  	t.Set("snap-setup", &snapstate.SnapSetup{
   238  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
   239  	})
   240  	chg := s.state.NewChange("dummy", "...")
   241  	chg.AddTask(t)
   242  
   243  	s.state.Unlock()
   244  
   245  	s.se.Ensure()
   246  	s.se.Wait()
   247  
   248  	s.state.Lock()
   249  
   250  	c.Check(t.Status(), Equals, state.ErrorStatus, Commentf("%v", chg.Err()))
   251  	c.Check(chg.Err(), ErrorMatches, `(?s).*cannot enable alias "alias4" for "alias-snap", already enabled for "other-snap".*`)
   252  }
   253  
   254  func (s *snapmgrTestSuite) TestDoUndoSetAutoAliasesConflict(c *C) {
   255  	s.state.Lock()
   256  	defer s.state.Unlock()
   257  
   258  	snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) {
   259  		c.Check(info.InstanceName(), Equals, "alias-snap")
   260  		return map[string]string{
   261  			"alias1": "cmd1",
   262  			"alias2": "cmd2",
   263  			"alias4": "cmd4",
   264  		}, nil
   265  	}
   266  
   267  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   268  		Sequence: []*snap.SideInfo{
   269  			{RealName: "alias-snap", Revision: snap.R(11)},
   270  		},
   271  		Current:        snap.R(11),
   272  		Active:         true,
   273  		AliasesPending: true,
   274  		Aliases: map[string]*snapstate.AliasTarget{
   275  			"alias1": {Auto: "cmd1"},
   276  			"alias2": {Auto: "cmd2x"},
   277  			"alias3": {Auto: "cmd3"},
   278  		},
   279  	})
   280  
   281  	otherSnapState := &snapstate.SnapState{
   282  		Sequence: []*snap.SideInfo{
   283  			{RealName: "other-snap", Revision: snap.R(3)},
   284  		},
   285  		Current:             snap.R(3),
   286  		Active:              true,
   287  		AutoAliasesDisabled: false,
   288  		Aliases: map[string]*snapstate.AliasTarget{
   289  			"alias5": {Auto: "cmd5"},
   290  		},
   291  	}
   292  	snapstate.Set(s.state, "other-snap", otherSnapState)
   293  
   294  	grabAlias3 := func(t *state.Task, _ *tomb.Tomb) error {
   295  		st := t.State()
   296  		st.Lock()
   297  		defer st.Unlock()
   298  
   299  		otherSnapState.Aliases = map[string]*snapstate.AliasTarget{
   300  			"alias3": {Auto: "cmd3"},
   301  			"alias5": {Auto: "cmd5"},
   302  		}
   303  		snapstate.Set(s.state, "other-snap", otherSnapState)
   304  
   305  		return nil
   306  	}
   307  
   308  	s.o.TaskRunner().AddHandler("grab-alias3", grabAlias3, nil)
   309  
   310  	t := s.state.NewTask("set-auto-aliases", "test")
   311  	t.Set("snap-setup", &snapstate.SnapSetup{
   312  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
   313  	})
   314  	chg := s.state.NewChange("dummy", "...")
   315  	chg.AddTask(t)
   316  
   317  	tgrab3 := s.state.NewTask("grab-alias3", "grab alias3 for other-snap")
   318  	tgrab3.WaitFor(t)
   319  	chg.AddTask(tgrab3)
   320  
   321  	terr := s.state.NewTask("error-trigger", "provoking total undo")
   322  	terr.WaitFor(t)
   323  	chg.AddTask(terr)
   324  
   325  	s.state.Unlock()
   326  
   327  	for i := 0; i < 5; i++ {
   328  		s.se.Ensure()
   329  		s.se.Wait()
   330  	}
   331  
   332  	s.state.Lock()
   333  
   334  	c.Check(t.Status(), Equals, state.UndoneStatus, Commentf("%v", chg.Err()))
   335  
   336  	var snapst snapstate.SnapState
   337  	err := snapstate.Get(s.state, "alias-snap", &snapst)
   338  	c.Assert(err, IsNil)
   339  
   340  	c.Check(snapst.AutoAliasesDisabled, Equals, true)
   341  	c.Check(snapst.AliasesPending, Equals, true)
   342  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
   343  		"alias1": {Auto: "cmd1"},
   344  		"alias2": {Auto: "cmd2x"},
   345  		"alias3": {Auto: "cmd3"},
   346  	})
   347  
   348  	c.Check(t.Log(), HasLen, 1)
   349  	c.Check(t.Log()[0], Matches, `.* ERROR cannot reinstate alias state because of conflicts, disabling: cannot enable alias "alias3" for "alias-snap", already enabled for "other-snap".*`)
   350  }
   351  
   352  func (s *snapmgrTestSuite) TestDoSetAutoAliasesFirstInstallUnaliased(c *C) {
   353  	s.state.Lock()
   354  	defer s.state.Unlock()
   355  
   356  	snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) {
   357  		c.Check(info.InstanceName(), Equals, "alias-snap")
   358  		return map[string]string{
   359  			"alias1": "cmd1",
   360  			"alias2": "cmd2",
   361  			"alias4": "cmd4",
   362  		}, nil
   363  	}
   364  
   365  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   366  		Sequence: []*snap.SideInfo{
   367  			{RealName: "alias-snap", Revision: snap.R(11)},
   368  		},
   369  		Current: snap.R(11),
   370  		Active:  true,
   371  	})
   372  
   373  	t := s.state.NewTask("set-auto-aliases", "test")
   374  	t.Set("snap-setup", &snapstate.SnapSetup{
   375  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
   376  		Flags:    snapstate.Flags{Unaliased: true},
   377  	})
   378  	chg := s.state.NewChange("dummy", "...")
   379  	chg.AddTask(t)
   380  
   381  	s.state.Unlock()
   382  
   383  	s.se.Ensure()
   384  	s.se.Wait()
   385  
   386  	s.state.Lock()
   387  
   388  	c.Check(t.Status(), Equals, state.DoneStatus, Commentf("%v", chg.Err()))
   389  
   390  	var snapst snapstate.SnapState
   391  	err := snapstate.Get(s.state, "alias-snap", &snapst)
   392  	c.Assert(err, IsNil)
   393  
   394  	c.Check(snapst.AutoAliasesDisabled, Equals, true)
   395  	c.Check(snapst.AliasesPending, Equals, true)
   396  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
   397  		"alias1": {Auto: "cmd1"},
   398  		"alias2": {Auto: "cmd2"},
   399  		"alias4": {Auto: "cmd4"},
   400  	})
   401  }
   402  
   403  func (s *snapmgrTestSuite) TestDoUndoSetAutoAliasesFirstInstallUnaliased(c *C) {
   404  	s.state.Lock()
   405  	defer s.state.Unlock()
   406  
   407  	snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) {
   408  		c.Check(info.InstanceName(), Equals, "alias-snap")
   409  		return map[string]string{
   410  			"alias1": "cmd1",
   411  			"alias2": "cmd2",
   412  			"alias4": "cmd4",
   413  		}, nil
   414  	}
   415  
   416  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   417  		Sequence: []*snap.SideInfo{
   418  			{RealName: "alias-snap", Revision: snap.R(11)},
   419  		},
   420  		Current: snap.R(11),
   421  		Active:  true,
   422  	})
   423  
   424  	t := s.state.NewTask("set-auto-aliases", "test")
   425  	t.Set("snap-setup", &snapstate.SnapSetup{
   426  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
   427  		Flags:    snapstate.Flags{Unaliased: true},
   428  	})
   429  	chg := s.state.NewChange("dummy", "...")
   430  	chg.AddTask(t)
   431  
   432  	terr := s.state.NewTask("error-trigger", "provoking total undo")
   433  	terr.WaitFor(t)
   434  	chg.AddTask(terr)
   435  
   436  	s.state.Unlock()
   437  
   438  	for i := 0; i < 3; i++ {
   439  		s.se.Ensure()
   440  		s.se.Wait()
   441  	}
   442  
   443  	s.state.Lock()
   444  
   445  	c.Check(t.Status(), Equals, state.UndoneStatus, Commentf("%v", chg.Err()))
   446  
   447  	var snapst snapstate.SnapState
   448  	err := snapstate.Get(s.state, "alias-snap", &snapst)
   449  	c.Assert(err, IsNil)
   450  
   451  	c.Check(snapst.AutoAliasesDisabled, Equals, false)
   452  	c.Check(snapst.AliasesPending, Equals, true)
   453  	c.Check(snapst.Aliases, HasLen, 0)
   454  }
   455  
   456  func (s *snapmgrTestSuite) TestDoSetupAliases(c *C) {
   457  	s.state.Lock()
   458  	defer s.state.Unlock()
   459  
   460  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   461  		Sequence: []*snap.SideInfo{
   462  			{RealName: "alias-snap", Revision: snap.R(11)},
   463  		},
   464  		Current:             snap.R(11),
   465  		Active:              true,
   466  		AutoAliasesDisabled: true,
   467  		AliasesPending:      true,
   468  		Aliases: map[string]*snapstate.AliasTarget{
   469  			"manual1": {Manual: "cmd1"},
   470  		},
   471  	})
   472  
   473  	t := s.state.NewTask("setup-aliases", "test")
   474  	t.Set("snap-setup", &snapstate.SnapSetup{
   475  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
   476  	})
   477  	chg := s.state.NewChange("dummy", "...")
   478  	chg.AddTask(t)
   479  
   480  	s.state.Unlock()
   481  
   482  	s.se.Ensure()
   483  	s.se.Wait()
   484  
   485  	s.state.Lock()
   486  
   487  	c.Check(t.Status(), Equals, state.DoneStatus)
   488  	expected := fakeOps{
   489  		{
   490  			op:      "update-aliases",
   491  			aliases: []*backend.Alias{{Name: "manual1", Target: "alias-snap.cmd1"}},
   492  		},
   493  	}
   494  	// start with an easier-to-read error if this fails:
   495  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops())
   496  	c.Assert(s.fakeBackend.ops, DeepEquals, expected)
   497  
   498  	var snapst snapstate.SnapState
   499  	err := snapstate.Get(s.state, "alias-snap", &snapst)
   500  	c.Assert(err, IsNil)
   501  
   502  	c.Check(snapst.AutoAliasesDisabled, Equals, true)
   503  	c.Check(snapst.AliasesPending, Equals, false)
   504  }
   505  
   506  func (s *snapmgrTestSuite) TestDoUndoSetupAliases(c *C) {
   507  	s.state.Lock()
   508  	defer s.state.Unlock()
   509  
   510  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   511  		Sequence: []*snap.SideInfo{
   512  			{RealName: "alias-snap", Revision: snap.R(11)},
   513  		},
   514  		Current:             snap.R(11),
   515  		Active:              true,
   516  		AutoAliasesDisabled: true,
   517  		AliasesPending:      true,
   518  		Aliases: map[string]*snapstate.AliasTarget{
   519  			"manual1": {Manual: "cmd1"},
   520  		},
   521  	})
   522  
   523  	t := s.state.NewTask("setup-aliases", "test")
   524  	t.Set("snap-setup", &snapstate.SnapSetup{
   525  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
   526  	})
   527  	chg := s.state.NewChange("dummy", "...")
   528  	chg.AddTask(t)
   529  
   530  	terr := s.state.NewTask("error-trigger", "provoking total undo")
   531  	terr.WaitFor(t)
   532  	chg.AddTask(terr)
   533  
   534  	s.state.Unlock()
   535  
   536  	for i := 0; i < 3; i++ {
   537  		s.se.Ensure()
   538  		s.se.Wait()
   539  	}
   540  
   541  	s.state.Lock()
   542  
   543  	c.Check(t.Status(), Equals, state.UndoneStatus)
   544  	expected := fakeOps{
   545  		{
   546  			op:      "update-aliases",
   547  			aliases: []*backend.Alias{{Name: "manual1", Target: "alias-snap.cmd1"}},
   548  		},
   549  		{
   550  			op:   "remove-snap-aliases",
   551  			name: "alias-snap",
   552  		},
   553  	}
   554  	// start with an easier-to-read error if this fails:
   555  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops())
   556  	c.Assert(s.fakeBackend.ops, DeepEquals, expected)
   557  
   558  	var snapst snapstate.SnapState
   559  	err := snapstate.Get(s.state, "alias-snap", &snapst)
   560  	c.Assert(err, IsNil)
   561  
   562  	c.Check(snapst.AutoAliasesDisabled, Equals, true)
   563  	c.Check(snapst.AliasesPending, Equals, true)
   564  }
   565  
   566  func (s *snapmgrTestSuite) TestDoSetupAliasesAuto(c *C) {
   567  	s.state.Lock()
   568  	defer s.state.Unlock()
   569  
   570  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   571  		Sequence: []*snap.SideInfo{
   572  			{RealName: "alias-snap", Revision: snap.R(11)},
   573  		},
   574  		Current:             snap.R(11),
   575  		Active:              true,
   576  		AutoAliasesDisabled: false,
   577  		AliasesPending:      true,
   578  		Aliases: map[string]*snapstate.AliasTarget{
   579  			"alias1": {Auto: "cmd1"},
   580  		},
   581  	})
   582  
   583  	t := s.state.NewTask("setup-aliases", "test")
   584  	t.Set("snap-setup", &snapstate.SnapSetup{
   585  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
   586  	})
   587  	chg := s.state.NewChange("dummy", "...")
   588  	chg.AddTask(t)
   589  
   590  	s.state.Unlock()
   591  
   592  	s.se.Ensure()
   593  	s.se.Wait()
   594  
   595  	s.state.Lock()
   596  
   597  	c.Check(t.Status(), Equals, state.DoneStatus)
   598  	expected := fakeOps{
   599  		{
   600  			op:      "update-aliases",
   601  			aliases: []*backend.Alias{{Name: "alias1", Target: "alias-snap.cmd1"}},
   602  		},
   603  	}
   604  	// start with an easier-to-read error if this fails:
   605  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops())
   606  	c.Assert(s.fakeBackend.ops, DeepEquals, expected)
   607  
   608  	var snapst snapstate.SnapState
   609  	err := snapstate.Get(s.state, "alias-snap", &snapst)
   610  	c.Assert(err, IsNil)
   611  
   612  	c.Check(snapst.AutoAliasesDisabled, Equals, false)
   613  	c.Check(snapst.AliasesPending, Equals, false)
   614  }
   615  
   616  func (s *snapmgrTestSuite) TestDoUndoSetupAliasesAuto(c *C) {
   617  	s.state.Lock()
   618  	defer s.state.Unlock()
   619  
   620  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   621  		Sequence: []*snap.SideInfo{
   622  			{RealName: "alias-snap", Revision: snap.R(11)},
   623  		},
   624  		Current:             snap.R(11),
   625  		Active:              true,
   626  		AutoAliasesDisabled: false,
   627  		AliasesPending:      true,
   628  		Aliases: map[string]*snapstate.AliasTarget{
   629  			"alias1": {Auto: "cmd1"},
   630  		},
   631  	})
   632  
   633  	t := s.state.NewTask("setup-aliases", "test")
   634  	t.Set("snap-setup", &snapstate.SnapSetup{
   635  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
   636  	})
   637  	chg := s.state.NewChange("dummy", "...")
   638  	chg.AddTask(t)
   639  
   640  	terr := s.state.NewTask("error-trigger", "provoking total undo")
   641  	terr.WaitFor(t)
   642  	chg.AddTask(terr)
   643  
   644  	s.state.Unlock()
   645  
   646  	for i := 0; i < 3; i++ {
   647  		s.se.Ensure()
   648  		s.se.Wait()
   649  	}
   650  
   651  	s.state.Lock()
   652  
   653  	c.Check(t.Status(), Equals, state.UndoneStatus)
   654  	expected := fakeOps{
   655  		{
   656  			op:      "update-aliases",
   657  			aliases: []*backend.Alias{{Name: "alias1", Target: "alias-snap.cmd1"}},
   658  		},
   659  		{
   660  			op:   "remove-snap-aliases",
   661  			name: "alias-snap",
   662  		},
   663  	}
   664  	// start with an easier-to-read error if this fails:
   665  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops())
   666  	c.Assert(s.fakeBackend.ops, DeepEquals, expected)
   667  
   668  	var snapst snapstate.SnapState
   669  	err := snapstate.Get(s.state, "alias-snap", &snapst)
   670  	c.Assert(err, IsNil)
   671  
   672  	c.Check(snapst.AutoAliasesDisabled, Equals, false)
   673  	c.Check(snapst.AliasesPending, Equals, true)
   674  }
   675  
   676  func (s *snapmgrTestSuite) TestDoSetupAliasesNothing(c *C) {
   677  	s.state.Lock()
   678  	defer s.state.Unlock()
   679  
   680  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   681  		Sequence: []*snap.SideInfo{
   682  			{RealName: "alias-snap", Revision: snap.R(11)},
   683  		},
   684  		Current: snap.R(11),
   685  		Active:  true,
   686  	})
   687  
   688  	t := s.state.NewTask("setup-aliases", "test")
   689  	t.Set("snap-setup", &snapstate.SnapSetup{
   690  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
   691  	})
   692  	chg := s.state.NewChange("dummy", "...")
   693  	chg.AddTask(t)
   694  
   695  	s.state.Unlock()
   696  
   697  	for i := 0; i < 3; i++ {
   698  		s.se.Ensure()
   699  		s.se.Wait()
   700  	}
   701  
   702  	s.state.Lock()
   703  
   704  	c.Check(t.Status(), Equals, state.DoneStatus)
   705  	expected := fakeOps{
   706  		{
   707  			op: "update-aliases",
   708  		},
   709  	}
   710  	// start with an easier-to-read error if this fails:
   711  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops())
   712  	c.Assert(s.fakeBackend.ops, DeepEquals, expected)
   713  
   714  	var snapst snapstate.SnapState
   715  	err := snapstate.Get(s.state, "alias-snap", &snapst)
   716  	c.Assert(err, IsNil)
   717  
   718  	c.Check(snapst.AutoAliasesDisabled, Equals, false)
   719  	c.Check(snapst.AliasesPending, Equals, false)
   720  }
   721  
   722  func (s *snapmgrTestSuite) TestDoUndoSetupAliasesNothing(c *C) {
   723  	s.state.Lock()
   724  	defer s.state.Unlock()
   725  
   726  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   727  		Sequence: []*snap.SideInfo{
   728  			{RealName: "alias-snap", Revision: snap.R(11)},
   729  		},
   730  		Current: snap.R(11),
   731  		Active:  true,
   732  	})
   733  
   734  	t := s.state.NewTask("setup-aliases", "test")
   735  	t.Set("snap-setup", &snapstate.SnapSetup{
   736  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
   737  	})
   738  	chg := s.state.NewChange("dummy", "...")
   739  	chg.AddTask(t)
   740  
   741  	terr := s.state.NewTask("error-trigger", "provoking total undo")
   742  	terr.WaitFor(t)
   743  	chg.AddTask(terr)
   744  
   745  	s.state.Unlock()
   746  
   747  	for i := 0; i < 3; i++ {
   748  		s.se.Ensure()
   749  		s.se.Wait()
   750  	}
   751  
   752  	s.state.Lock()
   753  
   754  	c.Check(t.Status(), Equals, state.UndoneStatus)
   755  	expected := fakeOps{
   756  		{
   757  			op: "update-aliases",
   758  		},
   759  		{
   760  			op:   "remove-snap-aliases",
   761  			name: "alias-snap",
   762  		},
   763  	}
   764  	// start with an easier-to-read error if this fails:
   765  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops())
   766  	c.Assert(s.fakeBackend.ops, DeepEquals, expected)
   767  
   768  	var snapst snapstate.SnapState
   769  	err := snapstate.Get(s.state, "alias-snap", &snapst)
   770  	c.Assert(err, IsNil)
   771  
   772  	c.Check(snapst.AutoAliasesDisabled, Equals, false)
   773  	c.Check(snapst.AliasesPending, Equals, true)
   774  }
   775  
   776  func (s *snapmgrTestSuite) TestDoPruneAutoAliasesAuto(c *C) {
   777  	s.state.Lock()
   778  	defer s.state.Unlock()
   779  
   780  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   781  		Sequence: []*snap.SideInfo{
   782  			{RealName: "alias-snap", Revision: snap.R(11)},
   783  		},
   784  		Current:        snap.R(11),
   785  		Active:         true,
   786  		AliasesPending: false,
   787  		Aliases: map[string]*snapstate.AliasTarget{
   788  			"alias1": {Auto: "cmd1"},
   789  			"alias2": {Auto: "cmd2"},
   790  			"alias3": {Auto: "cmd3"},
   791  		},
   792  	})
   793  
   794  	t := s.state.NewTask("prune-auto-aliases", "test")
   795  	t.Set("snap-setup", &snapstate.SnapSetup{
   796  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
   797  	})
   798  	t.Set("aliases", []string{"alias2", "alias3"})
   799  	chg := s.state.NewChange("dummy", "...")
   800  	chg.AddTask(t)
   801  
   802  	s.state.Unlock()
   803  
   804  	s.se.Ensure()
   805  	s.se.Wait()
   806  
   807  	s.state.Lock()
   808  
   809  	c.Check(t.Status(), Equals, state.DoneStatus, Commentf("%v", chg.Err()))
   810  
   811  	expected := fakeOps{
   812  		{
   813  			op: "update-aliases",
   814  			rmAliases: []*backend.Alias{
   815  				{Name: "alias2", Target: "alias-snap.cmd2"},
   816  				{Name: "alias3", Target: "alias-snap.cmd3"},
   817  			},
   818  		},
   819  	}
   820  	// start with an easier-to-read error if this fails:
   821  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops())
   822  	c.Assert(s.fakeBackend.ops, DeepEquals, expected)
   823  
   824  	var snapst snapstate.SnapState
   825  	err := snapstate.Get(s.state, "alias-snap", &snapst)
   826  	c.Assert(err, IsNil)
   827  
   828  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
   829  		"alias1": {Auto: "cmd1"},
   830  	})
   831  }
   832  
   833  func (s *snapmgrTestSuite) TestDoPruneAutoAliasesAutoPending(c *C) {
   834  	s.state.Lock()
   835  	defer s.state.Unlock()
   836  
   837  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   838  		Sequence: []*snap.SideInfo{
   839  			{RealName: "alias-snap", Revision: snap.R(11)},
   840  		},
   841  		Current:        snap.R(11),
   842  		Active:         true,
   843  		AliasesPending: true,
   844  		Aliases: map[string]*snapstate.AliasTarget{
   845  			"alias1": {Auto: "cmd1"},
   846  			"alias2": {Auto: "cmd2"},
   847  			"alias3": {Auto: "cmd3"},
   848  		},
   849  	})
   850  
   851  	t := s.state.NewTask("prune-auto-aliases", "test")
   852  	t.Set("snap-setup", &snapstate.SnapSetup{
   853  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
   854  	})
   855  	t.Set("aliases", []string{"alias2", "alias3"})
   856  	chg := s.state.NewChange("dummy", "...")
   857  	chg.AddTask(t)
   858  
   859  	s.state.Unlock()
   860  
   861  	s.se.Ensure()
   862  	s.se.Wait()
   863  
   864  	s.state.Lock()
   865  
   866  	c.Check(t.Status(), Equals, state.DoneStatus, Commentf("%v", chg.Err()))
   867  
   868  	// pending: nothing to do on disk
   869  	c.Assert(s.fakeBackend.ops, HasLen, 0)
   870  
   871  	var snapst snapstate.SnapState
   872  	err := snapstate.Get(s.state, "alias-snap", &snapst)
   873  	c.Assert(err, IsNil)
   874  
   875  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
   876  		"alias1": {Auto: "cmd1"},
   877  	})
   878  }
   879  
   880  func (s *snapmgrTestSuite) TestDoPruneAutoAliasesManualAndDisabled(c *C) {
   881  	s.state.Lock()
   882  	defer s.state.Unlock()
   883  
   884  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   885  		Sequence: []*snap.SideInfo{
   886  			{RealName: "alias-snap", Revision: snap.R(11)},
   887  		},
   888  		Current:             snap.R(11),
   889  		Active:              true,
   890  		AutoAliasesDisabled: true,
   891  		AliasesPending:      false,
   892  		Aliases: map[string]*snapstate.AliasTarget{
   893  			"alias1": {Auto: "cmd1"},
   894  			"alias2": {Auto: "cmd2"},
   895  			"alias3": {Manual: "cmdx", Auto: "cmd3"},
   896  			"alias4": {Manual: "cmd4"},
   897  		},
   898  	})
   899  
   900  	t := s.state.NewTask("prune-auto-aliases", "test")
   901  	t.Set("snap-setup", &snapstate.SnapSetup{
   902  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
   903  	})
   904  	t.Set("aliases", []string{"alias2", "alias3", "alias4"})
   905  	chg := s.state.NewChange("dummy", "...")
   906  	chg.AddTask(t)
   907  
   908  	s.state.Unlock()
   909  
   910  	s.se.Ensure()
   911  	s.se.Wait()
   912  
   913  	s.state.Lock()
   914  
   915  	c.Check(t.Status(), Equals, state.DoneStatus, Commentf("%v", chg.Err()))
   916  
   917  	expected := fakeOps{
   918  		{
   919  			op: "update-aliases",
   920  		},
   921  	}
   922  	// start with an easier-to-read error if this fails:
   923  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops())
   924  	c.Assert(s.fakeBackend.ops, DeepEquals, expected)
   925  
   926  	var snapst snapstate.SnapState
   927  	err := snapstate.Get(s.state, "alias-snap", &snapst)
   928  	c.Assert(err, IsNil)
   929  
   930  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
   931  		"alias1": {Auto: "cmd1"},
   932  		"alias3": {Manual: "cmdx"},
   933  		"alias4": {Manual: "cmd4"},
   934  	})
   935  }
   936  
   937  func (s *snapmgrTestSuite) TestDoRefreshAliases(c *C) {
   938  	s.state.Lock()
   939  	defer s.state.Unlock()
   940  
   941  	snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) {
   942  		c.Check(info.InstanceName(), Equals, "alias-snap")
   943  		return map[string]string{
   944  			"alias1": "cmd1",
   945  			"alias2": "cmd2",
   946  			"alias4": "cmd4",
   947  		}, nil
   948  	}
   949  
   950  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
   951  		Sequence: []*snap.SideInfo{
   952  			{RealName: "alias-snap", Revision: snap.R(11)},
   953  		},
   954  		Current:        snap.R(11),
   955  		Active:         true,
   956  		AliasesPending: false,
   957  		Aliases: map[string]*snapstate.AliasTarget{
   958  			"alias1": {Auto: "cmd1"},
   959  			"alias2": {Auto: "cmd2x"},
   960  			"alias3": {Auto: "cmd3"},
   961  		},
   962  	})
   963  
   964  	t := s.state.NewTask("refresh-aliases", "test")
   965  	t.Set("snap-setup", &snapstate.SnapSetup{
   966  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
   967  	})
   968  	chg := s.state.NewChange("dummy", "...")
   969  	chg.AddTask(t)
   970  
   971  	s.state.Unlock()
   972  
   973  	s.se.Ensure()
   974  	s.se.Wait()
   975  
   976  	s.state.Lock()
   977  
   978  	c.Check(t.Status(), Equals, state.DoneStatus, Commentf("%v", chg.Err()))
   979  
   980  	expected := fakeOps{
   981  		{
   982  			op: "update-aliases",
   983  			rmAliases: []*backend.Alias{
   984  				{Name: "alias2", Target: "alias-snap.cmd2x"},
   985  				{Name: "alias3", Target: "alias-snap.cmd3"},
   986  			},
   987  			aliases: []*backend.Alias{
   988  				{Name: "alias2", Target: "alias-snap.cmd2"},
   989  				{Name: "alias4", Target: "alias-snap.cmd4"},
   990  			},
   991  		},
   992  	}
   993  	// start with an easier-to-read error if this fails:
   994  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops())
   995  	c.Assert(s.fakeBackend.ops, DeepEquals, expected)
   996  
   997  	var snapst snapstate.SnapState
   998  	err := snapstate.Get(s.state, "alias-snap", &snapst)
   999  	c.Assert(err, IsNil)
  1000  
  1001  	c.Check(snapst.AutoAliasesDisabled, Equals, false)
  1002  	c.Check(snapst.AliasesPending, Equals, false)
  1003  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1004  		"alias1": {Auto: "cmd1"},
  1005  		"alias2": {Auto: "cmd2"},
  1006  		"alias4": {Auto: "cmd4"},
  1007  	})
  1008  }
  1009  
  1010  func (s *snapmgrTestSuite) TestDoUndoRefreshAliases(c *C) {
  1011  	s.state.Lock()
  1012  	defer s.state.Unlock()
  1013  
  1014  	snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) {
  1015  		c.Check(info.InstanceName(), Equals, "alias-snap")
  1016  		return map[string]string{
  1017  			"alias1": "cmd1",
  1018  			"alias2": "cmd2",
  1019  			"alias4": "cmd4",
  1020  		}, nil
  1021  	}
  1022  
  1023  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
  1024  		Sequence: []*snap.SideInfo{
  1025  			{RealName: "alias-snap", Revision: snap.R(11)},
  1026  		},
  1027  		Current:        snap.R(11),
  1028  		Active:         true,
  1029  		AliasesPending: false,
  1030  		Aliases: map[string]*snapstate.AliasTarget{
  1031  			"alias1": {Auto: "cmd1"},
  1032  			"alias2": {Auto: "cmd2x"},
  1033  			"alias3": {Auto: "cmd3"},
  1034  		},
  1035  	})
  1036  
  1037  	t := s.state.NewTask("refresh-aliases", "test")
  1038  	t.Set("snap-setup", &snapstate.SnapSetup{
  1039  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
  1040  	})
  1041  	chg := s.state.NewChange("dummy", "...")
  1042  	chg.AddTask(t)
  1043  
  1044  	terr := s.state.NewTask("error-trigger", "provoking total undo")
  1045  	terr.WaitFor(t)
  1046  	chg.AddTask(terr)
  1047  
  1048  	s.state.Unlock()
  1049  
  1050  	for i := 0; i < 3; i++ {
  1051  		s.se.Ensure()
  1052  		s.se.Wait()
  1053  	}
  1054  
  1055  	s.state.Lock()
  1056  
  1057  	c.Check(t.Status(), Equals, state.UndoneStatus, Commentf("%v", chg.Err()))
  1058  
  1059  	expected := fakeOps{
  1060  		{
  1061  			op: "update-aliases",
  1062  			rmAliases: []*backend.Alias{
  1063  				{Name: "alias2", Target: "alias-snap.cmd2x"},
  1064  				{Name: "alias3", Target: "alias-snap.cmd3"},
  1065  			},
  1066  			aliases: []*backend.Alias{
  1067  				{Name: "alias2", Target: "alias-snap.cmd2"},
  1068  				{Name: "alias4", Target: "alias-snap.cmd4"},
  1069  			},
  1070  		},
  1071  		{
  1072  			op: "update-aliases",
  1073  			aliases: []*backend.Alias{
  1074  				{Name: "alias2", Target: "alias-snap.cmd2x"},
  1075  				{Name: "alias3", Target: "alias-snap.cmd3"},
  1076  			},
  1077  			rmAliases: []*backend.Alias{
  1078  				{Name: "alias2", Target: "alias-snap.cmd2"},
  1079  				{Name: "alias4", Target: "alias-snap.cmd4"},
  1080  			},
  1081  		},
  1082  	}
  1083  	// start with an easier-to-read error if this fails:
  1084  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops())
  1085  	c.Assert(s.fakeBackend.ops, DeepEquals, expected)
  1086  
  1087  	var snapst snapstate.SnapState
  1088  	err := snapstate.Get(s.state, "alias-snap", &snapst)
  1089  	c.Assert(err, IsNil)
  1090  
  1091  	c.Check(snapst.AutoAliasesDisabled, Equals, false)
  1092  	c.Check(snapst.AliasesPending, Equals, false)
  1093  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1094  		"alias1": {Auto: "cmd1"},
  1095  		"alias2": {Auto: "cmd2x"},
  1096  		"alias3": {Auto: "cmd3"},
  1097  	})
  1098  }
  1099  
  1100  func (s *snapmgrTestSuite) TestDoUndoRefreshAliasesFromEmpty(c *C) {
  1101  	s.state.Lock()
  1102  	defer s.state.Unlock()
  1103  
  1104  	snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) {
  1105  		c.Check(info.InstanceName(), Equals, "alias-snap")
  1106  		return map[string]string{
  1107  			"alias1": "cmd1",
  1108  			"alias2": "cmd2",
  1109  			"alias4": "cmd4",
  1110  		}, nil
  1111  	}
  1112  
  1113  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
  1114  		Sequence: []*snap.SideInfo{
  1115  			{RealName: "alias-snap", Revision: snap.R(11)},
  1116  		},
  1117  		Current:        snap.R(11),
  1118  		Active:         true,
  1119  		AliasesPending: false,
  1120  	})
  1121  
  1122  	t := s.state.NewTask("refresh-aliases", "test")
  1123  	t.Set("snap-setup", &snapstate.SnapSetup{
  1124  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
  1125  	})
  1126  	chg := s.state.NewChange("dummy", "...")
  1127  	chg.AddTask(t)
  1128  
  1129  	terr := s.state.NewTask("error-trigger", "provoking total undo")
  1130  	terr.WaitFor(t)
  1131  	chg.AddTask(terr)
  1132  
  1133  	s.state.Unlock()
  1134  
  1135  	for i := 0; i < 3; i++ {
  1136  		s.se.Ensure()
  1137  		s.se.Wait()
  1138  	}
  1139  
  1140  	s.state.Lock()
  1141  
  1142  	c.Check(t.Status(), Equals, state.UndoneStatus, Commentf("%v", chg.Err()))
  1143  
  1144  	expected := fakeOps{
  1145  		{
  1146  			op: "update-aliases",
  1147  			aliases: []*backend.Alias{
  1148  				{Name: "alias1", Target: "alias-snap.cmd1"},
  1149  				{Name: "alias2", Target: "alias-snap.cmd2"},
  1150  				{Name: "alias4", Target: "alias-snap.cmd4"},
  1151  			},
  1152  		},
  1153  		{
  1154  			op: "update-aliases",
  1155  			rmAliases: []*backend.Alias{
  1156  				{Name: "alias1", Target: "alias-snap.cmd1"},
  1157  				{Name: "alias2", Target: "alias-snap.cmd2"},
  1158  				{Name: "alias4", Target: "alias-snap.cmd4"},
  1159  			},
  1160  		},
  1161  	}
  1162  	// start with an easier-to-read error if this fails:
  1163  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops())
  1164  	c.Assert(s.fakeBackend.ops, DeepEquals, expected)
  1165  
  1166  	var snapst snapstate.SnapState
  1167  	err := snapstate.Get(s.state, "alias-snap", &snapst)
  1168  	c.Assert(err, IsNil)
  1169  
  1170  	c.Check(snapst.AutoAliasesDisabled, Equals, false)
  1171  	c.Check(snapst.AliasesPending, Equals, false)
  1172  	c.Check(snapst.Aliases, HasLen, 0)
  1173  }
  1174  
  1175  func (s *snapmgrTestSuite) TestDoRefreshAliasesPending(c *C) {
  1176  	s.state.Lock()
  1177  	defer s.state.Unlock()
  1178  
  1179  	snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) {
  1180  		c.Check(info.InstanceName(), Equals, "alias-snap")
  1181  		return map[string]string{
  1182  			"alias1": "cmd1",
  1183  			"alias2": "cmd2",
  1184  			"alias4": "cmd4",
  1185  		}, nil
  1186  	}
  1187  
  1188  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
  1189  		Sequence: []*snap.SideInfo{
  1190  			{RealName: "alias-snap", Revision: snap.R(11)},
  1191  		},
  1192  		Current:        snap.R(11),
  1193  		Active:         true,
  1194  		AliasesPending: true,
  1195  		Aliases: map[string]*snapstate.AliasTarget{
  1196  			"alias1": {Auto: "cmd1"},
  1197  			"alias2": {Auto: "cmd2x"},
  1198  			"alias3": {Auto: "cmd3"},
  1199  		},
  1200  	})
  1201  
  1202  	t := s.state.NewTask("refresh-aliases", "test")
  1203  	t.Set("snap-setup", &snapstate.SnapSetup{
  1204  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
  1205  	})
  1206  	chg := s.state.NewChange("dummy", "...")
  1207  	chg.AddTask(t)
  1208  
  1209  	s.state.Unlock()
  1210  
  1211  	s.se.Ensure()
  1212  	s.se.Wait()
  1213  
  1214  	s.state.Lock()
  1215  
  1216  	c.Check(t.Status(), Equals, state.DoneStatus, Commentf("%v", chg.Err()))
  1217  
  1218  	// pending: nothing to do on disk
  1219  	c.Assert(s.fakeBackend.ops, HasLen, 0)
  1220  
  1221  	var snapst snapstate.SnapState
  1222  	err := snapstate.Get(s.state, "alias-snap", &snapst)
  1223  	c.Assert(err, IsNil)
  1224  
  1225  	c.Check(snapst.AutoAliasesDisabled, Equals, false)
  1226  	c.Check(snapst.AliasesPending, Equals, true)
  1227  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1228  		"alias1": {Auto: "cmd1"},
  1229  		"alias2": {Auto: "cmd2"},
  1230  		"alias4": {Auto: "cmd4"},
  1231  	})
  1232  }
  1233  
  1234  func (s *snapmgrTestSuite) TestDoUndoRefreshAliasesPending(c *C) {
  1235  	s.state.Lock()
  1236  	defer s.state.Unlock()
  1237  
  1238  	snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) {
  1239  		c.Check(info.InstanceName(), Equals, "alias-snap")
  1240  		return map[string]string{
  1241  			"alias1": "cmd1",
  1242  			"alias2": "cmd2",
  1243  			"alias4": "cmd4",
  1244  		}, nil
  1245  	}
  1246  
  1247  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
  1248  		Sequence: []*snap.SideInfo{
  1249  			{RealName: "alias-snap", Revision: snap.R(11)},
  1250  		},
  1251  		Current:        snap.R(11),
  1252  		Active:         true,
  1253  		AliasesPending: true,
  1254  		Aliases: map[string]*snapstate.AliasTarget{
  1255  			"alias1": {Auto: "cmd1"},
  1256  			"alias2": {Auto: "cmd2x"},
  1257  			"alias3": {Auto: "cmd3"},
  1258  		},
  1259  	})
  1260  
  1261  	t := s.state.NewTask("refresh-aliases", "test")
  1262  	t.Set("snap-setup", &snapstate.SnapSetup{
  1263  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
  1264  	})
  1265  	chg := s.state.NewChange("dummy", "...")
  1266  	chg.AddTask(t)
  1267  
  1268  	terr := s.state.NewTask("error-trigger", "provoking total undo")
  1269  	terr.WaitFor(t)
  1270  	chg.AddTask(terr)
  1271  
  1272  	s.state.Unlock()
  1273  
  1274  	for i := 0; i < 3; i++ {
  1275  		s.se.Ensure()
  1276  		s.se.Wait()
  1277  	}
  1278  
  1279  	s.state.Lock()
  1280  
  1281  	c.Check(t.Status(), Equals, state.UndoneStatus, Commentf("%v", chg.Err()))
  1282  
  1283  	// pending: nothing to do on disk
  1284  	c.Assert(s.fakeBackend.ops, HasLen, 0)
  1285  
  1286  	var snapst snapstate.SnapState
  1287  	err := snapstate.Get(s.state, "alias-snap", &snapst)
  1288  	c.Assert(err, IsNil)
  1289  
  1290  	c.Check(snapst.AutoAliasesDisabled, Equals, false)
  1291  	c.Check(snapst.AliasesPending, Equals, true)
  1292  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1293  		"alias1": {Auto: "cmd1"},
  1294  		"alias2": {Auto: "cmd2x"},
  1295  		"alias3": {Auto: "cmd3"},
  1296  	})
  1297  }
  1298  
  1299  func (s *snapmgrTestSuite) TestDoRefreshAliasesConflict(c *C) {
  1300  	s.state.Lock()
  1301  	defer s.state.Unlock()
  1302  
  1303  	snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) {
  1304  		c.Check(info.InstanceName(), Equals, "alias-snap")
  1305  		return map[string]string{
  1306  			"alias1": "cmd1",
  1307  			"alias2": "cmd2",
  1308  			"alias4": "cmd4",
  1309  		}, nil
  1310  	}
  1311  
  1312  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
  1313  		Sequence: []*snap.SideInfo{
  1314  			{RealName: "alias-snap", Revision: snap.R(11)},
  1315  		},
  1316  		Current: snap.R(11),
  1317  		Active:  true,
  1318  		Aliases: map[string]*snapstate.AliasTarget{
  1319  			"alias1": {Auto: "cmd1"},
  1320  			"alias2": {Auto: "cmd2x"},
  1321  			"alias3": {Auto: "cmd3"},
  1322  		},
  1323  	})
  1324  	snapstate.Set(s.state, "other-snap", &snapstate.SnapState{
  1325  		Sequence: []*snap.SideInfo{
  1326  			{RealName: "other-snap", Revision: snap.R(3)},
  1327  		},
  1328  		Current: snap.R(3),
  1329  		Active:  true,
  1330  		Aliases: map[string]*snapstate.AliasTarget{
  1331  			"alias4": {Auto: "cmd4"},
  1332  		},
  1333  	})
  1334  
  1335  	t := s.state.NewTask("refresh-aliases", "test")
  1336  	t.Set("snap-setup", &snapstate.SnapSetup{
  1337  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
  1338  	})
  1339  	chg := s.state.NewChange("dummy", "...")
  1340  	chg.AddTask(t)
  1341  
  1342  	s.state.Unlock()
  1343  
  1344  	s.se.Ensure()
  1345  	s.se.Wait()
  1346  
  1347  	s.state.Lock()
  1348  
  1349  	c.Check(t.Status(), Equals, state.ErrorStatus, Commentf("%v", chg.Err()))
  1350  	c.Check(chg.Err(), ErrorMatches, `(?s).*cannot enable alias "alias4" for "alias-snap", already enabled for "other-snap".*`)
  1351  }
  1352  
  1353  func (s *snapmgrTestSuite) TestDoUndoRefreshAliasesConflict(c *C) {
  1354  	s.state.Lock()
  1355  	defer s.state.Unlock()
  1356  
  1357  	snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) {
  1358  		c.Check(info.InstanceName(), Equals, "alias-snap")
  1359  		return map[string]string{
  1360  			"alias1": "cmd1",
  1361  			"alias2": "cmd2",
  1362  			"alias4": "cmd4",
  1363  		}, nil
  1364  	}
  1365  
  1366  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
  1367  		Sequence: []*snap.SideInfo{
  1368  			{RealName: "alias-snap", Revision: snap.R(11)},
  1369  		},
  1370  		Current:        snap.R(11),
  1371  		Active:         true,
  1372  		AliasesPending: false,
  1373  		Aliases: map[string]*snapstate.AliasTarget{
  1374  			"alias1": {Auto: "cmd1"},
  1375  			"alias2": {Auto: "cmd2x"},
  1376  			"alias3": {Auto: "cmd3"},
  1377  		},
  1378  	})
  1379  
  1380  	grabAlias3 := func(t *state.Task, _ *tomb.Tomb) error {
  1381  		st := t.State()
  1382  		st.Lock()
  1383  		defer st.Unlock()
  1384  
  1385  		snapstate.Set(s.state, "other-snap", &snapstate.SnapState{
  1386  			Sequence: []*snap.SideInfo{
  1387  				{RealName: "other-snap", Revision: snap.R(3)},
  1388  			},
  1389  			Current:        snap.R(3),
  1390  			Active:         true,
  1391  			AliasesPending: false,
  1392  			Aliases: map[string]*snapstate.AliasTarget{
  1393  				"alias3": {Auto: "cmd3x"},
  1394  			},
  1395  		})
  1396  
  1397  		return nil
  1398  	}
  1399  
  1400  	s.o.TaskRunner().AddHandler("grab-alias3", grabAlias3, nil)
  1401  
  1402  	t := s.state.NewTask("refresh-aliases", "test")
  1403  	t.Set("snap-setup", &snapstate.SnapSetup{
  1404  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
  1405  	})
  1406  	chg := s.state.NewChange("dummy", "...")
  1407  	chg.AddTask(t)
  1408  
  1409  	tgrab3 := s.state.NewTask("grab-alias3", "grab alias3 for other-snap")
  1410  	tgrab3.WaitFor(t)
  1411  	chg.AddTask(tgrab3)
  1412  
  1413  	terr := s.state.NewTask("error-trigger", "provoking total undo")
  1414  	terr.WaitFor(t)
  1415  	chg.AddTask(terr)
  1416  
  1417  	s.state.Unlock()
  1418  
  1419  	for i := 0; i < 5; i++ {
  1420  		s.se.Ensure()
  1421  		s.se.Wait()
  1422  	}
  1423  
  1424  	s.state.Lock()
  1425  
  1426  	c.Check(t.Status(), Equals, state.UndoneStatus, Commentf("%v", chg.Err()))
  1427  
  1428  	expected := fakeOps{
  1429  		{
  1430  			op: "update-aliases",
  1431  			rmAliases: []*backend.Alias{
  1432  				{Name: "alias2", Target: "alias-snap.cmd2x"},
  1433  				{Name: "alias3", Target: "alias-snap.cmd3"},
  1434  			},
  1435  			aliases: []*backend.Alias{
  1436  				{Name: "alias2", Target: "alias-snap.cmd2"},
  1437  				{Name: "alias4", Target: "alias-snap.cmd4"},
  1438  			},
  1439  		},
  1440  		{
  1441  			op: "update-aliases",
  1442  			rmAliases: []*backend.Alias{
  1443  				{Name: "alias1", Target: "alias-snap.cmd1"},
  1444  				{Name: "alias2", Target: "alias-snap.cmd2"},
  1445  				{Name: "alias4", Target: "alias-snap.cmd4"},
  1446  			},
  1447  		},
  1448  	}
  1449  	// start with an easier-to-read error if this fails:
  1450  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops())
  1451  	c.Check(s.fakeBackend.ops, DeepEquals, expected)
  1452  
  1453  	var snapst snapstate.SnapState
  1454  	err := snapstate.Get(s.state, "alias-snap", &snapst)
  1455  	c.Assert(err, IsNil)
  1456  
  1457  	c.Check(snapst.AutoAliasesDisabled, Equals, true)
  1458  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1459  		"alias1": {Auto: "cmd1"},
  1460  		"alias2": {Auto: "cmd2x"},
  1461  		"alias3": {Auto: "cmd3"},
  1462  	})
  1463  
  1464  	var snapst2 snapstate.SnapState
  1465  	err = snapstate.Get(s.state, "other-snap", &snapst2)
  1466  	c.Assert(err, IsNil)
  1467  
  1468  	c.Check(snapst2.AutoAliasesDisabled, Equals, false)
  1469  	c.Check(snapst2.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1470  		"alias3": {Auto: "cmd3x"},
  1471  	})
  1472  
  1473  	c.Check(t.Log(), HasLen, 1)
  1474  	c.Check(t.Log()[0], Matches, `.* ERROR cannot reinstate alias state because of conflicts, disabling: cannot enable alias "alias3" for "alias-snap", already enabled for "other-snap".*`)
  1475  }
  1476  
  1477  func (s *snapmgrTestSuite) TestDoUndoDisableAliases(c *C) {
  1478  	s.state.Lock()
  1479  	defer s.state.Unlock()
  1480  
  1481  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
  1482  		Sequence: []*snap.SideInfo{
  1483  			{RealName: "alias-snap", Revision: snap.R(11)},
  1484  		},
  1485  		Current: snap.R(11),
  1486  		Active:  true,
  1487  		Aliases: map[string]*snapstate.AliasTarget{
  1488  			"alias1": {Manual: "cmd5", Auto: "cmd1"},
  1489  			"alias2": {Auto: "cmd2"},
  1490  			"alias3": {Manual: "cmd3"},
  1491  		},
  1492  	})
  1493  
  1494  	t := s.state.NewTask("disable-aliases", "test")
  1495  	t.Set("snap-setup", &snapstate.SnapSetup{
  1496  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
  1497  	})
  1498  	chg := s.state.NewChange("dummy", "...")
  1499  	chg.AddTask(t)
  1500  
  1501  	terr := s.state.NewTask("error-trigger", "provoking total undo")
  1502  	terr.WaitFor(t)
  1503  	chg.AddTask(terr)
  1504  
  1505  	s.state.Unlock()
  1506  
  1507  	for i := 0; i < 3; i++ {
  1508  		s.se.Ensure()
  1509  		s.se.Wait()
  1510  	}
  1511  
  1512  	s.state.Lock()
  1513  	c.Check(t.Status(), Equals, state.UndoneStatus, Commentf("%v", chg.Err()))
  1514  
  1515  	expected := fakeOps{
  1516  		{
  1517  			op: "update-aliases",
  1518  			rmAliases: []*backend.Alias{
  1519  				{Name: "alias1", Target: "alias-snap.cmd5"},
  1520  				{Name: "alias2", Target: "alias-snap.cmd2"},
  1521  				{Name: "alias3", Target: "alias-snap.cmd3"},
  1522  			},
  1523  		},
  1524  		{
  1525  			op: "update-aliases",
  1526  			aliases: []*backend.Alias{
  1527  				{Name: "alias1", Target: "alias-snap.cmd5"},
  1528  				{Name: "alias2", Target: "alias-snap.cmd2"},
  1529  				{Name: "alias3", Target: "alias-snap.cmd3"},
  1530  			},
  1531  		},
  1532  	}
  1533  	// start with an easier-to-read error if this fails:
  1534  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops())
  1535  	c.Assert(s.fakeBackend.ops, DeepEquals, expected)
  1536  
  1537  	var snapst snapstate.SnapState
  1538  	err := snapstate.Get(s.state, "alias-snap", &snapst)
  1539  	c.Assert(err, IsNil)
  1540  
  1541  	c.Check(snapst.AutoAliasesDisabled, Equals, false)
  1542  	c.Check(snapst.AliasesPending, Equals, false)
  1543  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1544  		"alias1": {Manual: "cmd5", Auto: "cmd1"},
  1545  		"alias2": {Auto: "cmd2"},
  1546  		"alias3": {Manual: "cmd3"},
  1547  	})
  1548  }
  1549  
  1550  func (s *snapmgrTestSuite) TestDoPreferAliases(c *C) {
  1551  	s.state.Lock()
  1552  	defer s.state.Unlock()
  1553  
  1554  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
  1555  		Sequence: []*snap.SideInfo{
  1556  			{RealName: "alias-snap", Revision: snap.R(11)},
  1557  		},
  1558  		Current:             snap.R(11),
  1559  		Active:              true,
  1560  		AutoAliasesDisabled: true,
  1561  		Aliases: map[string]*snapstate.AliasTarget{
  1562  			"alias1": {Auto: "cmd1"},
  1563  			"alias2": {Auto: "cmd2"},
  1564  			"alias3": {Auto: "cmd3"},
  1565  		},
  1566  	})
  1567  	snapstate.Set(s.state, "other-alias-snap1", &snapstate.SnapState{
  1568  		Sequence: []*snap.SideInfo{
  1569  			{RealName: "other-alias-snap1", Revision: snap.R(3)},
  1570  		},
  1571  		Current: snap.R(3),
  1572  		Active:  true,
  1573  		Aliases: map[string]*snapstate.AliasTarget{
  1574  			"alias1": {Auto: "cmd1"},
  1575  		},
  1576  	})
  1577  	snapstate.Set(s.state, "other-alias-snap2", &snapstate.SnapState{
  1578  		Sequence: []*snap.SideInfo{
  1579  			{RealName: "other-alias-snap2", Revision: snap.R(3)},
  1580  		},
  1581  		Current:        snap.R(3),
  1582  		Active:         true,
  1583  		AliasesPending: true,
  1584  		Aliases: map[string]*snapstate.AliasTarget{
  1585  			"alias2": {Manual: "cmd2"},
  1586  			"aliasx": {Manual: "cmdx"},
  1587  		},
  1588  	})
  1589  	snapstate.Set(s.state, "other-alias-snap3", &snapstate.SnapState{
  1590  		Sequence: []*snap.SideInfo{
  1591  			{RealName: "other-alias-snap3", Revision: snap.R(3)},
  1592  		},
  1593  		Current: snap.R(3),
  1594  		Active:  true,
  1595  		Aliases: map[string]*snapstate.AliasTarget{
  1596  			"alias3": {Manual: "cmd5", Auto: "cmd3"},
  1597  		},
  1598  	})
  1599  
  1600  	t := s.state.NewTask("prefer-aliases", "test")
  1601  	t.Set("snap-setup", &snapstate.SnapSetup{
  1602  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
  1603  	})
  1604  	chg := s.state.NewChange("dummy", "...")
  1605  	chg.AddTask(t)
  1606  
  1607  	s.state.Unlock()
  1608  	for i := 0; i < 3; i++ {
  1609  		s.se.Ensure()
  1610  		s.se.Wait()
  1611  	}
  1612  	s.state.Lock()
  1613  	c.Check(t.Status(), Equals, state.DoneStatus, Commentf("%v", chg.Err()))
  1614  
  1615  	// start with an easier-to-read error if this fails:
  1616  	c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, []string{"update-aliases", "update-aliases", "update-aliases"})
  1617  	c.Assert(s.fakeBackend.ops[0].aliases, HasLen, 0)
  1618  	c.Assert(s.fakeBackend.ops[0].rmAliases, HasLen, 1)
  1619  	c.Assert(s.fakeBackend.ops[1].aliases, HasLen, 0)
  1620  	c.Assert(s.fakeBackend.ops[1].rmAliases, HasLen, 1)
  1621  	c.Assert(s.fakeBackend.ops[2], DeepEquals, fakeOp{
  1622  		op: "update-aliases",
  1623  		aliases: []*backend.Alias{
  1624  			{Name: "alias1", Target: "alias-snap.cmd1"},
  1625  			{Name: "alias2", Target: "alias-snap.cmd2"},
  1626  			{Name: "alias3", Target: "alias-snap.cmd3"},
  1627  		},
  1628  	})
  1629  
  1630  	var snapst snapstate.SnapState
  1631  	err := snapstate.Get(s.state, "alias-snap", &snapst)
  1632  	c.Assert(err, IsNil)
  1633  
  1634  	c.Check(snapst.AutoAliasesDisabled, Equals, false)
  1635  	c.Check(snapst.AliasesPending, Equals, false)
  1636  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1637  		"alias1": {Auto: "cmd1"},
  1638  		"alias2": {Auto: "cmd2"},
  1639  		"alias3": {Auto: "cmd3"},
  1640  	})
  1641  
  1642  	var otherst1 snapstate.SnapState
  1643  	err = snapstate.Get(s.state, "other-alias-snap1", &otherst1)
  1644  	c.Assert(err, IsNil)
  1645  	c.Check(otherst1.AutoAliasesDisabled, Equals, true)
  1646  	c.Check(otherst1.AliasesPending, Equals, false)
  1647  	c.Check(otherst1.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1648  		"alias1": {Auto: "cmd1"},
  1649  	})
  1650  
  1651  	var otherst2 snapstate.SnapState
  1652  	err = snapstate.Get(s.state, "other-alias-snap2", &otherst2)
  1653  	c.Assert(err, IsNil)
  1654  	c.Check(otherst2.AutoAliasesDisabled, Equals, false)
  1655  	c.Check(otherst2.AliasesPending, Equals, true)
  1656  	c.Check(otherst2.Aliases, HasLen, 0)
  1657  
  1658  	var otherst3 snapstate.SnapState
  1659  	err = snapstate.Get(s.state, "other-alias-snap3", &otherst3)
  1660  	c.Assert(err, IsNil)
  1661  	c.Check(otherst3.AutoAliasesDisabled, Equals, true)
  1662  	c.Check(otherst3.AliasesPending, Equals, false)
  1663  	c.Check(otherst3.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1664  		"alias3": {Auto: "cmd3"},
  1665  	})
  1666  
  1667  	var trace traceData
  1668  	err = chg.Get("api-data", &trace)
  1669  	c.Assert(err, IsNil)
  1670  	c.Check(trace.Added, HasLen, 3)
  1671  	c.Check(trace.Removed, HasLen, 4)
  1672  }
  1673  
  1674  func (s *snapmgrTestSuite) TestDoUndoPreferAliases(c *C) {
  1675  	s.state.Lock()
  1676  	defer s.state.Unlock()
  1677  
  1678  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
  1679  		Sequence: []*snap.SideInfo{
  1680  			{RealName: "alias-snap", Revision: snap.R(11)},
  1681  		},
  1682  		Current:             snap.R(11),
  1683  		Active:              true,
  1684  		AutoAliasesDisabled: true,
  1685  		Aliases: map[string]*snapstate.AliasTarget{
  1686  			"alias1": {Auto: "cmd1"},
  1687  			"alias2": {Auto: "cmd2"},
  1688  			"alias3": {Auto: "cmd3"},
  1689  		},
  1690  	})
  1691  	snapstate.Set(s.state, "other-alias-snap1", &snapstate.SnapState{
  1692  		Sequence: []*snap.SideInfo{
  1693  			{RealName: "other-alias-snap1", Revision: snap.R(3)},
  1694  		},
  1695  		Current: snap.R(3),
  1696  		Active:  true,
  1697  		Aliases: map[string]*snapstate.AliasTarget{
  1698  			"alias1": {Auto: "cmd1"},
  1699  		},
  1700  	})
  1701  	snapstate.Set(s.state, "other-alias-snap2", &snapstate.SnapState{
  1702  		Sequence: []*snap.SideInfo{
  1703  			{RealName: "other-alias-snap2", Revision: snap.R(3)},
  1704  		},
  1705  		Current:        snap.R(3),
  1706  		Active:         true,
  1707  		AliasesPending: true,
  1708  		Aliases: map[string]*snapstate.AliasTarget{
  1709  			"alias2": {Manual: "cmd2"},
  1710  			"aliasx": {Manual: "cmdx"},
  1711  		},
  1712  	})
  1713  	snapstate.Set(s.state, "other-alias-snap3", &snapstate.SnapState{
  1714  		Sequence: []*snap.SideInfo{
  1715  			{RealName: "other-alias-snap3", Revision: snap.R(3)},
  1716  		},
  1717  		Current: snap.R(3),
  1718  		Active:  true,
  1719  		Aliases: map[string]*snapstate.AliasTarget{
  1720  			"alias3": {Manual: "cmd5", Auto: "cmd3"},
  1721  		},
  1722  	})
  1723  
  1724  	t := s.state.NewTask("prefer-aliases", "test")
  1725  	t.Set("snap-setup", &snapstate.SnapSetup{
  1726  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
  1727  	})
  1728  	chg := s.state.NewChange("dummy", "...")
  1729  	chg.AddTask(t)
  1730  
  1731  	terr := s.state.NewTask("error-trigger", "provoking total undo")
  1732  	terr.WaitFor(t)
  1733  	chg.AddTask(terr)
  1734  
  1735  	s.state.Unlock()
  1736  	for i := 0; i < 3; i++ {
  1737  		s.se.Ensure()
  1738  		s.se.Wait()
  1739  	}
  1740  	s.state.Lock()
  1741  	c.Check(t.Status(), Equals, state.UndoneStatus, Commentf("%v", chg.Err()))
  1742  
  1743  	// start with an easier-to-read error if this fails:
  1744  	c.Assert(s.fakeBackend.ops.Ops(), HasLen, 6)
  1745  	c.Assert(s.fakeBackend.ops[3], DeepEquals, fakeOp{
  1746  		op: "update-aliases",
  1747  		rmAliases: []*backend.Alias{
  1748  			{Name: "alias1", Target: "alias-snap.cmd1"},
  1749  			{Name: "alias2", Target: "alias-snap.cmd2"},
  1750  			{Name: "alias3", Target: "alias-snap.cmd3"},
  1751  		},
  1752  	})
  1753  	c.Assert(s.fakeBackend.ops[4].aliases, HasLen, 1)
  1754  	c.Assert(s.fakeBackend.ops[4].rmAliases, HasLen, 0)
  1755  	c.Assert(s.fakeBackend.ops[5].aliases, HasLen, 1)
  1756  	c.Assert(s.fakeBackend.ops[5].rmAliases, HasLen, 0)
  1757  
  1758  	var snapst snapstate.SnapState
  1759  	err := snapstate.Get(s.state, "alias-snap", &snapst)
  1760  	c.Assert(err, IsNil)
  1761  
  1762  	c.Check(snapst.AutoAliasesDisabled, Equals, true)
  1763  	c.Check(snapst.AliasesPending, Equals, false)
  1764  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1765  		"alias1": {Auto: "cmd1"},
  1766  		"alias2": {Auto: "cmd2"},
  1767  		"alias3": {Auto: "cmd3"},
  1768  	})
  1769  
  1770  	var otherst1 snapstate.SnapState
  1771  	err = snapstate.Get(s.state, "other-alias-snap1", &otherst1)
  1772  	c.Assert(err, IsNil)
  1773  	c.Check(otherst1.AutoAliasesDisabled, Equals, false)
  1774  	c.Check(otherst1.AliasesPending, Equals, false)
  1775  	c.Check(otherst1.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1776  		"alias1": {Auto: "cmd1"},
  1777  	})
  1778  
  1779  	var otherst2 snapstate.SnapState
  1780  	err = snapstate.Get(s.state, "other-alias-snap2", &otherst2)
  1781  	c.Assert(err, IsNil)
  1782  	c.Check(otherst2.AutoAliasesDisabled, Equals, false)
  1783  	c.Check(otherst2.AliasesPending, Equals, true)
  1784  	c.Check(otherst2.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1785  		"alias2": {Manual: "cmd2"},
  1786  	})
  1787  
  1788  	var otherst3 snapstate.SnapState
  1789  	err = snapstate.Get(s.state, "other-alias-snap3", &otherst3)
  1790  	c.Assert(err, IsNil)
  1791  	c.Check(otherst3.AutoAliasesDisabled, Equals, false)
  1792  	c.Check(otherst3.AliasesPending, Equals, false)
  1793  	c.Check(otherst3.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1794  		"alias3": {Manual: "cmd5", Auto: "cmd3"},
  1795  	})
  1796  }
  1797  
  1798  func (s *snapmgrTestSuite) TestDoUndoPreferAliasesConflict(c *C) {
  1799  	s.state.Lock()
  1800  	defer s.state.Unlock()
  1801  
  1802  	snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{
  1803  		Sequence: []*snap.SideInfo{
  1804  			{RealName: "alias-snap", Revision: snap.R(11)},
  1805  		},
  1806  		Current:             snap.R(11),
  1807  		Active:              true,
  1808  		AutoAliasesDisabled: true,
  1809  		Aliases: map[string]*snapstate.AliasTarget{
  1810  			"alias1": {Auto: "cmd1"},
  1811  			"alias2": {Auto: "cmd2"},
  1812  			"alias3": {Auto: "cmd3"},
  1813  		},
  1814  	})
  1815  	snapstate.Set(s.state, "other-alias-snap1", &snapstate.SnapState{
  1816  		Sequence: []*snap.SideInfo{
  1817  			{RealName: "other-alias-snap1", Revision: snap.R(3)},
  1818  		},
  1819  		Current: snap.R(3),
  1820  		Active:  true,
  1821  		Aliases: map[string]*snapstate.AliasTarget{
  1822  			"alias1": {Auto: "cmd1"},
  1823  		},
  1824  	})
  1825  	snapstate.Set(s.state, "other-alias-snap2", &snapstate.SnapState{
  1826  		Sequence: []*snap.SideInfo{
  1827  			{RealName: "other-alias-snap2", Revision: snap.R(3)},
  1828  		},
  1829  		Current:        snap.R(3),
  1830  		Active:         true,
  1831  		AliasesPending: true,
  1832  		Aliases: map[string]*snapstate.AliasTarget{
  1833  			"alias2": {Manual: "cmd2"},
  1834  			"aliasx": {Manual: "cmdx"},
  1835  		},
  1836  	})
  1837  	snapstate.Set(s.state, "other-alias-snap3", &snapstate.SnapState{
  1838  		Sequence: []*snap.SideInfo{
  1839  			{RealName: "other-alias-snap3", Revision: snap.R(3)},
  1840  		},
  1841  		Current: snap.R(3),
  1842  		Active:  true,
  1843  		Aliases: map[string]*snapstate.AliasTarget{
  1844  			"alias3": {Manual: "cmd5", Auto: "cmd3"},
  1845  		},
  1846  	})
  1847  
  1848  	conflictAlias5 := func(t *state.Task, _ *tomb.Tomb) error {
  1849  		st := t.State()
  1850  		st.Lock()
  1851  		defer st.Unlock()
  1852  
  1853  		var snapst1, snapst2 snapstate.SnapState
  1854  		err := snapstate.Get(st, "other-alias-snap1", &snapst1)
  1855  		c.Assert(err, IsNil)
  1856  		err = snapstate.Get(st, "other-alias-snap2", &snapst2)
  1857  		c.Assert(err, IsNil)
  1858  		snapst1.Aliases = map[string]*snapstate.AliasTarget{
  1859  			"alias1": {Auto: "cmd1"},
  1860  			"alias5": {Auto: "cmd5"},
  1861  		}
  1862  		snapst2.Aliases = map[string]*snapstate.AliasTarget{
  1863  			"alias5": {Manual: "cmd5"},
  1864  		}
  1865  		snapstate.Set(st, "other-alias-snap1", &snapst1)
  1866  		snapstate.Set(st, "other-alias-snap2", &snapst2)
  1867  
  1868  		return nil
  1869  	}
  1870  
  1871  	s.o.TaskRunner().AddHandler("conflict-alias5", conflictAlias5, nil)
  1872  
  1873  	t := s.state.NewTask("prefer-aliases", "test")
  1874  	t.Set("snap-setup", &snapstate.SnapSetup{
  1875  		SideInfo: &snap.SideInfo{RealName: "alias-snap"},
  1876  	})
  1877  	chg := s.state.NewChange("dummy", "...")
  1878  	chg.AddTask(t)
  1879  
  1880  	tconflict5 := s.state.NewTask("conflict-alias5", "create conflict on alias5")
  1881  	tconflict5.WaitFor(t)
  1882  	chg.AddTask(tconflict5)
  1883  
  1884  	terr := s.state.NewTask("error-trigger", "provoking total undo")
  1885  	terr.WaitFor(tconflict5)
  1886  	chg.AddTask(terr)
  1887  
  1888  	s.state.Unlock()
  1889  	for i := 0; i < 5; i++ {
  1890  		s.se.Ensure()
  1891  		s.se.Wait()
  1892  	}
  1893  	s.state.Lock()
  1894  	c.Check(t.Status(), Equals, state.UndoneStatus, Commentf("%v", chg.Err()))
  1895  
  1896  	// start with an easier-to-read error if this fails:
  1897  	c.Assert(s.fakeBackend.ops.Ops(), HasLen, 5)
  1898  	c.Assert(s.fakeBackend.ops[3], DeepEquals, fakeOp{
  1899  		op: "update-aliases",
  1900  		rmAliases: []*backend.Alias{
  1901  			{Name: "alias1", Target: "alias-snap.cmd1"},
  1902  			{Name: "alias2", Target: "alias-snap.cmd2"},
  1903  			{Name: "alias3", Target: "alias-snap.cmd3"},
  1904  		},
  1905  	})
  1906  	c.Assert(s.fakeBackend.ops[4], DeepEquals, fakeOp{
  1907  		op: "update-aliases",
  1908  		aliases: []*backend.Alias{
  1909  			{Name: "alias3", Target: "other-alias-snap3.cmd5"},
  1910  		},
  1911  	})
  1912  
  1913  	var snapst snapstate.SnapState
  1914  	err := snapstate.Get(s.state, "alias-snap", &snapst)
  1915  	c.Assert(err, IsNil)
  1916  
  1917  	c.Check(snapst.AutoAliasesDisabled, Equals, true)
  1918  	c.Check(snapst.AliasesPending, Equals, false)
  1919  	c.Check(snapst.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1920  		"alias1": {Auto: "cmd1"},
  1921  		"alias2": {Auto: "cmd2"},
  1922  		"alias3": {Auto: "cmd3"},
  1923  	})
  1924  
  1925  	var otherst1 snapstate.SnapState
  1926  	err = snapstate.Get(s.state, "other-alias-snap1", &otherst1)
  1927  	c.Assert(err, IsNil)
  1928  	c.Check(otherst1.AutoAliasesDisabled, Equals, true)
  1929  	c.Check(otherst1.AliasesPending, Equals, false)
  1930  	c.Check(otherst1.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1931  		"alias1": {Auto: "cmd1"},
  1932  		"alias5": {Auto: "cmd5"},
  1933  	})
  1934  
  1935  	var otherst2 snapstate.SnapState
  1936  	err = snapstate.Get(s.state, "other-alias-snap2", &otherst2)
  1937  	c.Assert(err, IsNil)
  1938  	c.Check(otherst2.AutoAliasesDisabled, Equals, false)
  1939  	c.Check(otherst2.AliasesPending, Equals, true)
  1940  	c.Check(otherst2.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1941  		"alias5": {Manual: "cmd5"},
  1942  	})
  1943  
  1944  	var otherst3 snapstate.SnapState
  1945  	err = snapstate.Get(s.state, "other-alias-snap3", &otherst3)
  1946  	c.Assert(err, IsNil)
  1947  	c.Check(otherst3.AutoAliasesDisabled, Equals, false)
  1948  	c.Check(otherst3.AliasesPending, Equals, false)
  1949  	c.Check(otherst3.Aliases, DeepEquals, map[string]*snapstate.AliasTarget{
  1950  		"alias3": {Manual: "cmd5", Auto: "cmd3"},
  1951  	})
  1952  }