github.com/david-imola/snapd@v0.0.0-20210611180407-2de8ddeece6d/overlord/snapstate/handlers_discard_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2016 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  
    25  	"github.com/snapcore/snapd/interfaces"
    26  	"github.com/snapcore/snapd/overlord/ifacestate/ifacerepo"
    27  	"github.com/snapcore/snapd/overlord/servicestate"
    28  	"github.com/snapcore/snapd/overlord/snapstate"
    29  	"github.com/snapcore/snapd/overlord/snapstate/snapstatetest"
    30  	"github.com/snapcore/snapd/overlord/state"
    31  	"github.com/snapcore/snapd/snap"
    32  )
    33  
    34  type discardSnapSuite struct {
    35  	baseHandlerSuite
    36  }
    37  
    38  var _ = Suite(&discardSnapSuite{})
    39  
    40  func (s *discardSnapSuite) SetUpTest(c *C) {
    41  	s.setup(c, nil)
    42  
    43  	s.state.Lock()
    44  	defer s.state.Unlock()
    45  	repo := interfaces.NewRepository()
    46  	ifacerepo.Replace(s.state, repo)
    47  	oldSnapStateEnsureSnapAbsentFromQuotaGroup := snapstate.EnsureSnapAbsentFromQuotaGroup
    48  	snapstate.EnsureSnapAbsentFromQuotaGroup = servicestate.EnsureSnapAbsentFromQuota
    49  	s.AddCleanup(func() {
    50  		snapstate.EnsureSnapAbsentFromQuotaGroup = oldSnapStateEnsureSnapAbsentFromQuotaGroup
    51  	})
    52  
    53  	s.AddCleanup(snapstatetest.MockDeviceModel(DefaultModel()))
    54  }
    55  
    56  func (s *discardSnapSuite) TestDoDiscardSnapSuccess(c *C) {
    57  	s.state.Lock()
    58  	snapstate.Set(s.state, "foo", &snapstate.SnapState{
    59  		Sequence: []*snap.SideInfo{
    60  			{RealName: "foo", Revision: snap.R(3)},
    61  			{RealName: "foo", Revision: snap.R(33)},
    62  		},
    63  		Current:  snap.R(33),
    64  		SnapType: "app",
    65  	})
    66  	t := s.state.NewTask("discard-snap", "test")
    67  	t.Set("snap-setup", &snapstate.SnapSetup{
    68  		SideInfo: &snap.SideInfo{
    69  			RealName: "foo",
    70  			Revision: snap.R(33),
    71  		},
    72  	})
    73  	s.state.NewChange("dummy", "...").AddTask(t)
    74  
    75  	s.state.Unlock()
    76  
    77  	s.se.Ensure()
    78  	s.se.Wait()
    79  
    80  	s.state.Lock()
    81  	defer s.state.Unlock()
    82  	var snapst snapstate.SnapState
    83  	err := snapstate.Get(s.state, "foo", &snapst)
    84  	c.Assert(err, IsNil)
    85  
    86  	c.Check(snapst.Sequence, HasLen, 1)
    87  	c.Check(snapst.Current, Equals, snap.R(3))
    88  	c.Check(t.Status(), Equals, state.DoneStatus)
    89  }
    90  
    91  func (s *discardSnapSuite) TestDoDiscardSnapInQuotaGroup(c *C) {
    92  	s.state.Lock()
    93  
    94  	old := snapstate.EnsureSnapAbsentFromQuotaGroup
    95  	defer func() {
    96  		snapstate.EnsureSnapAbsentFromQuotaGroup = old
    97  	}()
    98  
    99  	ensureSnapAbsentFromQuotaGroupCalls := 0
   100  	snapstate.EnsureSnapAbsentFromQuotaGroup = func(st *state.State, snap string) error {
   101  		ensureSnapAbsentFromQuotaGroupCalls++
   102  		c.Assert(snap, Equals, "foo")
   103  		return nil
   104  	}
   105  	defer func() { c.Assert(ensureSnapAbsentFromQuotaGroupCalls, Equals, 1) }()
   106  
   107  	snapstate.Set(s.state, "foo", &snapstate.SnapState{
   108  		Sequence: []*snap.SideInfo{
   109  			{RealName: "foo", Revision: snap.R(3)},
   110  		},
   111  		Current:  snap.R(3),
   112  		SnapType: "app",
   113  	})
   114  	t := s.state.NewTask("discard-snap", "test")
   115  	t.Set("snap-setup", &snapstate.SnapSetup{
   116  		SideInfo: &snap.SideInfo{
   117  			RealName: "foo",
   118  			Revision: snap.R(33),
   119  		},
   120  	})
   121  	s.state.NewChange("dummy", "...").AddTask(t)
   122  
   123  	s.state.Unlock()
   124  
   125  	s.se.Ensure()
   126  	s.se.Wait()
   127  
   128  	s.state.Lock()
   129  	defer s.state.Unlock()
   130  	var snapst snapstate.SnapState
   131  	err := snapstate.Get(s.state, "foo", &snapst)
   132  	c.Assert(err, Equals, state.ErrNoState)
   133  
   134  	c.Check(t.Status(), Equals, state.DoneStatus)
   135  }
   136  
   137  func (s *discardSnapSuite) TestDoDiscardSnapToEmpty(c *C) {
   138  	s.state.Lock()
   139  	snapstate.Set(s.state, "foo", &snapstate.SnapState{
   140  		Sequence: []*snap.SideInfo{
   141  			{RealName: "foo", Revision: snap.R(3)},
   142  		},
   143  		Current:  snap.R(3),
   144  		SnapType: "app",
   145  	})
   146  	t := s.state.NewTask("discard-snap", "test")
   147  	t.Set("snap-setup", &snapstate.SnapSetup{
   148  		SideInfo: &snap.SideInfo{
   149  			RealName: "foo",
   150  			Revision: snap.R(33),
   151  		},
   152  	})
   153  	s.state.NewChange("dummy", "...").AddTask(t)
   154  
   155  	s.state.Unlock()
   156  
   157  	s.se.Ensure()
   158  	s.se.Wait()
   159  
   160  	s.state.Lock()
   161  	defer s.state.Unlock()
   162  	var snapst snapstate.SnapState
   163  	err := snapstate.Get(s.state, "foo", &snapst)
   164  	c.Assert(err, Equals, state.ErrNoState)
   165  }
   166  
   167  func (s *discardSnapSuite) TestDoDiscardSnapErrorsForActive(c *C) {
   168  	s.state.Lock()
   169  	snapstate.Set(s.state, "foo", &snapstate.SnapState{
   170  		Sequence: []*snap.SideInfo{
   171  			{RealName: "foo", Revision: snap.R(3)},
   172  		},
   173  		Current:  snap.R(3),
   174  		Active:   true,
   175  		SnapType: "app",
   176  	})
   177  	t := s.state.NewTask("discard-snap", "test")
   178  	t.Set("snap-setup", &snapstate.SnapSetup{
   179  		SideInfo: &snap.SideInfo{
   180  			RealName: "foo",
   181  			Revision: snap.R(3),
   182  		},
   183  	})
   184  	chg := s.state.NewChange("dummy", "...")
   185  	chg.AddTask(t)
   186  
   187  	s.state.Unlock()
   188  
   189  	s.se.Ensure()
   190  	s.se.Wait()
   191  
   192  	s.state.Lock()
   193  	defer s.state.Unlock()
   194  
   195  	c.Check(chg.Status(), Equals, state.ErrorStatus)
   196  	c.Check(chg.Err(), ErrorMatches, `(?s).*internal error: cannot discard snap "foo": still active.*`)
   197  }
   198  
   199  func (s *discardSnapSuite) TestDoDiscardSnapNoErrorsForActive(c *C) {
   200  	s.state.Lock()
   201  	snapstate.Set(s.state, "foo", &snapstate.SnapState{
   202  		Sequence: []*snap.SideInfo{
   203  			{RealName: "foo", Revision: snap.R(3)},
   204  			{RealName: "foo", Revision: snap.R(33)},
   205  		},
   206  		Current:  snap.R(33),
   207  		Active:   true,
   208  		SnapType: "app",
   209  	})
   210  	t := s.state.NewTask("discard-snap", "test")
   211  	t.Set("snap-setup", &snapstate.SnapSetup{
   212  		SideInfo: &snap.SideInfo{
   213  			RealName: "foo",
   214  			Revision: snap.R(3),
   215  		},
   216  	})
   217  	chg := s.state.NewChange("dummy", "...")
   218  	chg.AddTask(t)
   219  
   220  	s.state.Unlock()
   221  
   222  	s.se.Ensure()
   223  	s.se.Wait()
   224  
   225  	s.state.Lock()
   226  	defer s.state.Unlock()
   227  
   228  	var snapst snapstate.SnapState
   229  	err := snapstate.Get(s.state, "foo", &snapst)
   230  	c.Assert(err, IsNil)
   231  
   232  	c.Assert(chg.Err(), IsNil)
   233  	c.Check(snapst.Sequence, HasLen, 1)
   234  	c.Check(snapst.Current, Equals, snap.R(33))
   235  	c.Check(t.Status(), Equals, state.DoneStatus)
   236  }
   237  
   238  func (s *discardSnapSuite) TestDoDiscardSnapdRemovesLate(c *C) {
   239  	var removeLateCalledFor [][]string
   240  	restore := snapstate.MockSecurityProfilesDiscardLate(func(snapName string, rev snap.Revision, typ snap.Type) error {
   241  		removeLateCalledFor = append(removeLateCalledFor, []string{
   242  			snapName, rev.String(), string(typ),
   243  		})
   244  		return nil
   245  	})
   246  	defer restore()
   247  
   248  	s.state.Lock()
   249  
   250  	snapstate.Set(s.state, "snapd", &snapstate.SnapState{
   251  		Sequence: []*snap.SideInfo{
   252  			{RealName: "snapd", Revision: snap.R(3)},
   253  			{RealName: "snapd", Revision: snap.R(33)},
   254  		},
   255  		Current:  snap.R(33),
   256  		SnapType: "snapd",
   257  	})
   258  	t := s.state.NewTask("discard-snap", "test")
   259  	t.Set("snap-setup", &snapstate.SnapSetup{
   260  		SideInfo: &snap.SideInfo{
   261  			RealName: "snapd",
   262  			Revision: snap.R(33),
   263  		},
   264  		Type: snap.TypeSnapd,
   265  	})
   266  	s.state.NewChange("dummy", "...").AddTask(t)
   267  
   268  	s.state.Unlock()
   269  
   270  	s.se.Ensure()
   271  	s.se.Wait()
   272  
   273  	s.state.Lock()
   274  	defer s.state.Unlock()
   275  	var snapst snapstate.SnapState
   276  	err := snapstate.Get(s.state, "snapd", &snapst)
   277  	c.Assert(err, IsNil)
   278  
   279  	c.Check(snapst.Sequence, HasLen, 1)
   280  	c.Check(snapst.Current, Equals, snap.R(3))
   281  	c.Check(t.Status(), Equals, state.DoneStatus)
   282  	c.Check(removeLateCalledFor, DeepEquals, [][]string{
   283  		{"snapd", "33", "snapd"},
   284  	})
   285  }