github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/overlord/overlord_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 overlord_test
    21  
    22  import (
    23  	"encoding/json"
    24  	"errors"
    25  	"fmt"
    26  	"io/ioutil"
    27  	"os"
    28  	"path/filepath"
    29  	"syscall"
    30  	"testing"
    31  	"time"
    32  
    33  	. "gopkg.in/check.v1"
    34  	"gopkg.in/tomb.v2"
    35  
    36  	"github.com/snapcore/snapd/dirs"
    37  	"github.com/snapcore/snapd/osutil"
    38  	"github.com/snapcore/snapd/overlord"
    39  	"github.com/snapcore/snapd/overlord/auth"
    40  	"github.com/snapcore/snapd/overlord/devicestate/devicestatetest"
    41  	"github.com/snapcore/snapd/overlord/hookstate"
    42  	"github.com/snapcore/snapd/overlord/ifacestate"
    43  	"github.com/snapcore/snapd/overlord/patch"
    44  	"github.com/snapcore/snapd/overlord/snapstate"
    45  	"github.com/snapcore/snapd/overlord/state"
    46  	"github.com/snapcore/snapd/snap"
    47  	"github.com/snapcore/snapd/snapdenv"
    48  	"github.com/snapcore/snapd/snapdtool"
    49  	"github.com/snapcore/snapd/store"
    50  	"github.com/snapcore/snapd/testutil"
    51  	"github.com/snapcore/snapd/timings"
    52  )
    53  
    54  func TestOverlord(t *testing.T) { TestingT(t) }
    55  
    56  type overlordSuite struct {
    57  	testutil.BaseTest
    58  }
    59  
    60  var _ = Suite(&overlordSuite{})
    61  
    62  type ticker struct {
    63  	tickerChannel chan time.Time
    64  }
    65  
    66  func (w *ticker) tick(n int) {
    67  	for i := 0; i < n; i++ {
    68  		w.tickerChannel <- time.Now()
    69  	}
    70  }
    71  
    72  func fakePruneTicker() (w *ticker, restore func()) {
    73  	w = &ticker{
    74  		tickerChannel: make(chan time.Time),
    75  	}
    76  	restore = overlord.MockPruneTicker(func(t *time.Ticker) <-chan time.Time {
    77  		return w.tickerChannel
    78  	})
    79  	return w, restore
    80  }
    81  
    82  func (ovs *overlordSuite) SetUpTest(c *C) {
    83  	tmpdir := c.MkDir()
    84  	dirs.SetRootDir(tmpdir)
    85  	ovs.AddCleanup(func() { dirs.SetRootDir("") })
    86  	ovs.AddCleanup(osutil.MockMountInfo(""))
    87  
    88  	dirs.SnapStateFile = filepath.Join(tmpdir, "test.json")
    89  	snapstate.CanAutoRefresh = nil
    90  	ovs.AddCleanup(func() { ifacestate.MockSecurityBackends(nil) })
    91  }
    92  
    93  func (ovs *overlordSuite) TestNew(c *C) {
    94  	restore := patch.Mock(42, 2, nil)
    95  	defer restore()
    96  
    97  	var configstateInitCalled bool
    98  	overlord.MockConfigstateInit(func(*state.State, *hookstate.HookManager) error {
    99  		configstateInitCalled = true
   100  		return nil
   101  	})
   102  
   103  	o, err := overlord.New(nil)
   104  	c.Assert(err, IsNil)
   105  	c.Check(o, NotNil)
   106  
   107  	c.Check(o.StateEngine(), NotNil)
   108  	c.Check(o.TaskRunner(), NotNil)
   109  	c.Check(o.SnapManager(), NotNil)
   110  	c.Check(o.AssertManager(), NotNil)
   111  	c.Check(o.InterfaceManager(), NotNil)
   112  	c.Check(o.HookManager(), NotNil)
   113  	c.Check(o.DeviceManager(), NotNil)
   114  	c.Check(o.CommandManager(), NotNil)
   115  	c.Check(o.SnapshotManager(), NotNil)
   116  	c.Check(configstateInitCalled, Equals, true)
   117  
   118  	o.InterfaceManager().DisableUDevMonitor()
   119  
   120  	s := o.State()
   121  	c.Check(s, NotNil)
   122  	c.Check(o.Engine().State(), Equals, s)
   123  
   124  	s.Lock()
   125  	defer s.Unlock()
   126  	var patchLevel, patchSublevel int
   127  	s.Get("patch-level", &patchLevel)
   128  	c.Check(patchLevel, Equals, 42)
   129  	s.Get("patch-sublevel", &patchSublevel)
   130  	c.Check(patchSublevel, Equals, 2)
   131  	var refreshPrivacyKey string
   132  	s.Get("refresh-privacy-key", &refreshPrivacyKey)
   133  	c.Check(refreshPrivacyKey, HasLen, 16)
   134  
   135  	// store is setup
   136  	sto := snapstate.Store(s, nil)
   137  	c.Check(sto, FitsTypeOf, &store.Store{})
   138  	c.Check(sto.(*store.Store).CacheDownloads(), Equals, 5)
   139  }
   140  
   141  func (ovs *overlordSuite) TestNewStore(c *C) {
   142  	// this is a shallow test, the deep testing happens in the
   143  	// remodeling tests in managers_test.go
   144  	o, err := overlord.New(nil)
   145  	c.Assert(err, IsNil)
   146  
   147  	devBE := o.DeviceManager().StoreContextBackend()
   148  
   149  	sto := o.NewStore(devBE)
   150  	c.Check(sto, FitsTypeOf, &store.Store{})
   151  	c.Check(sto.(*store.Store).CacheDownloads(), Equals, 5)
   152  }
   153  
   154  func (ovs *overlordSuite) TestNewWithGoodState(c *C) {
   155  	// ensure we don't write state load timing in the state on really
   156  	// slow architectures (e.g. risc-v)
   157  	oldDurationThreshold := timings.DurationThreshold
   158  	timings.DurationThreshold = time.Second * 30
   159  	defer func() { timings.DurationThreshold = oldDurationThreshold }()
   160  
   161  	fakeState := []byte(fmt.Sprintf(`{"data":{"patch-level":%d,"patch-sublevel":%d,"patch-sublevel-last-version":%q,"some":"data","refresh-privacy-key":"0123456789ABCDEF"},"changes":null,"tasks":null,"last-change-id":0,"last-task-id":0,"last-lane-id":0}`, patch.Level, patch.Sublevel, snapdtool.Version))
   162  	err := ioutil.WriteFile(dirs.SnapStateFile, fakeState, 0600)
   163  	c.Assert(err, IsNil)
   164  
   165  	o, err := overlord.New(nil)
   166  	c.Assert(err, IsNil)
   167  
   168  	state := o.State()
   169  	c.Assert(err, IsNil)
   170  	state.Lock()
   171  	defer state.Unlock()
   172  
   173  	d, err := state.MarshalJSON()
   174  	c.Assert(err, IsNil)
   175  
   176  	var got, expected map[string]interface{}
   177  	err = json.Unmarshal(d, &got)
   178  	c.Assert(err, IsNil)
   179  	err = json.Unmarshal(fakeState, &expected)
   180  	c.Assert(err, IsNil)
   181  
   182  	data, _ := got["data"].(map[string]interface{})
   183  	c.Assert(data, NotNil)
   184  
   185  	c.Check(got, DeepEquals, expected)
   186  }
   187  
   188  func (ovs *overlordSuite) TestNewWithStateSnapmgrUpdate(c *C) {
   189  	fakeState := []byte(fmt.Sprintf(`{"data":{"patch-level":%d,"some":"data"},"changes":null,"tasks":null,"last-change-id":0,"last-task-id":0,"last-lane-id":0}`, patch.Level))
   190  	err := ioutil.WriteFile(dirs.SnapStateFile, fakeState, 0600)
   191  	c.Assert(err, IsNil)
   192  
   193  	o, err := overlord.New(nil)
   194  	c.Assert(err, IsNil)
   195  
   196  	state := o.State()
   197  	c.Assert(err, IsNil)
   198  	state.Lock()
   199  	defer state.Unlock()
   200  
   201  	var refreshPrivacyKey string
   202  	state.Get("refresh-privacy-key", &refreshPrivacyKey)
   203  	c.Check(refreshPrivacyKey, HasLen, 16)
   204  }
   205  
   206  func (ovs *overlordSuite) TestNewWithInvalidState(c *C) {
   207  	fakeState := []byte(``)
   208  	err := ioutil.WriteFile(dirs.SnapStateFile, fakeState, 0600)
   209  	c.Assert(err, IsNil)
   210  
   211  	_, err = overlord.New(nil)
   212  	c.Assert(err, ErrorMatches, "cannot read state: EOF")
   213  }
   214  
   215  func (ovs *overlordSuite) TestNewWithPatches(c *C) {
   216  	p := func(s *state.State) error {
   217  		s.Set("patched", true)
   218  		return nil
   219  	}
   220  	sp := func(s *state.State) error {
   221  		s.Set("patched2", true)
   222  		return nil
   223  	}
   224  	patch.Mock(1, 1, map[int][]patch.PatchFunc{1: {p, sp}})
   225  
   226  	fakeState := []byte(fmt.Sprintf(`{"data":{"patch-level":0, "patch-sublevel":0}}`))
   227  	err := ioutil.WriteFile(dirs.SnapStateFile, fakeState, 0600)
   228  	c.Assert(err, IsNil)
   229  
   230  	o, err := overlord.New(nil)
   231  	c.Assert(err, IsNil)
   232  
   233  	state := o.State()
   234  	c.Assert(err, IsNil)
   235  	state.Lock()
   236  	defer state.Unlock()
   237  
   238  	var level int
   239  	err = state.Get("patch-level", &level)
   240  	c.Assert(err, IsNil)
   241  	c.Check(level, Equals, 1)
   242  
   243  	var sublevel int
   244  	c.Assert(state.Get("patch-sublevel", &sublevel), IsNil)
   245  	c.Check(sublevel, Equals, 1)
   246  
   247  	var b bool
   248  	err = state.Get("patched", &b)
   249  	c.Assert(err, IsNil)
   250  	c.Check(b, Equals, true)
   251  
   252  	c.Assert(state.Get("patched2", &b), IsNil)
   253  	c.Check(b, Equals, true)
   254  }
   255  
   256  func (ovs *overlordSuite) TestNewFailedConfigstate(c *C) {
   257  	restore := patch.Mock(42, 2, nil)
   258  	defer restore()
   259  
   260  	var configstateInitCalled bool
   261  	restore = overlord.MockConfigstateInit(func(*state.State, *hookstate.HookManager) error {
   262  		configstateInitCalled = true
   263  		return fmt.Errorf("bad bad")
   264  	})
   265  	defer restore()
   266  
   267  	o, err := overlord.New(nil)
   268  	c.Assert(err, ErrorMatches, "bad bad")
   269  	c.Check(o, IsNil)
   270  	c.Check(configstateInitCalled, Equals, true)
   271  }
   272  
   273  type witnessManager struct {
   274  	state          *state.State
   275  	expectedEnsure int
   276  	ensureCalled   chan struct{}
   277  	ensureCallback func(s *state.State) error
   278  	startedUp      int
   279  }
   280  
   281  func (wm *witnessManager) StartUp() error {
   282  	wm.startedUp++
   283  	return nil
   284  }
   285  
   286  func (wm *witnessManager) Ensure() error {
   287  	if wm.expectedEnsure--; wm.expectedEnsure == 0 {
   288  		close(wm.ensureCalled)
   289  		return nil
   290  	}
   291  	if wm.ensureCallback != nil {
   292  		return wm.ensureCallback(wm.state)
   293  	}
   294  	return nil
   295  }
   296  
   297  // markSeeded flags the state under the overlord as seeded to avoid running the seeding code in these tests
   298  func markSeeded(o *overlord.Overlord) {
   299  	st := o.State()
   300  	st.Lock()
   301  	st.Set("seeded", true)
   302  	devicestatetest.SetDevice(st, &auth.DeviceState{
   303  		Brand:  "canonical",
   304  		Model:  "pc",
   305  		Serial: "serialserial",
   306  	})
   307  	st.Unlock()
   308  }
   309  
   310  func (ovs *overlordSuite) TestTrivialRunAndStop(c *C) {
   311  	o, err := overlord.New(nil)
   312  	c.Assert(err, IsNil)
   313  
   314  	markSeeded(o)
   315  	// make sure we don't try to talk to the store
   316  	snapstate.CanAutoRefresh = nil
   317  
   318  	err = o.StartUp()
   319  	c.Assert(err, IsNil)
   320  
   321  	o.Loop()
   322  
   323  	err = o.Stop()
   324  	c.Assert(err, IsNil)
   325  }
   326  
   327  func (ovs *overlordSuite) TestUnknownTasks(c *C) {
   328  	o, err := overlord.New(nil)
   329  	c.Assert(err, IsNil)
   330  	o.InterfaceManager().DisableUDevMonitor()
   331  
   332  	markSeeded(o)
   333  	// make sure we don't try to talk to the store
   334  	snapstate.CanAutoRefresh = nil
   335  
   336  	// unknown tasks are ignored and succeed
   337  	st := o.State()
   338  	st.Lock()
   339  	defer st.Unlock()
   340  	t := st.NewTask("unknown", "...")
   341  	chg := st.NewChange("change-w-unknown", "...")
   342  	chg.AddTask(t)
   343  
   344  	st.Unlock()
   345  	err = o.Settle(1 * time.Second)
   346  	st.Lock()
   347  	c.Assert(err, IsNil)
   348  
   349  	c.Check(chg.Status(), Equals, state.DoneStatus)
   350  }
   351  
   352  func (ovs *overlordSuite) TestEnsureLoopRunAndStop(c *C) {
   353  	restoreIntv := overlord.MockEnsureInterval(10 * time.Millisecond)
   354  	defer restoreIntv()
   355  	o := overlord.Mock()
   356  
   357  	witness := &witnessManager{
   358  		state:          o.State(),
   359  		expectedEnsure: 3,
   360  		ensureCalled:   make(chan struct{}),
   361  	}
   362  	o.AddManager(witness)
   363  
   364  	err := o.StartUp()
   365  	c.Assert(err, IsNil)
   366  
   367  	o.Loop()
   368  	defer o.Stop()
   369  
   370  	t0 := time.Now()
   371  	select {
   372  	case <-witness.ensureCalled:
   373  	case <-time.After(2 * time.Second):
   374  		c.Fatal("Ensure calls not happening")
   375  	}
   376  	c.Check(time.Since(t0) >= 10*time.Millisecond, Equals, true)
   377  
   378  	err = o.Stop()
   379  	c.Assert(err, IsNil)
   380  
   381  	c.Check(witness.startedUp, Equals, 1)
   382  }
   383  
   384  func (ovs *overlordSuite) TestEnsureLoopMediatedEnsureBeforeImmediate(c *C) {
   385  	restoreIntv := overlord.MockEnsureInterval(10 * time.Minute)
   386  	defer restoreIntv()
   387  	o := overlord.Mock()
   388  
   389  	ensure := func(s *state.State) error {
   390  		s.EnsureBefore(0)
   391  		return nil
   392  	}
   393  
   394  	witness := &witnessManager{
   395  		state:          o.State(),
   396  		expectedEnsure: 2,
   397  		ensureCalled:   make(chan struct{}),
   398  		ensureCallback: ensure,
   399  	}
   400  	o.AddManager(witness)
   401  
   402  	c.Assert(o.StartUp(), IsNil)
   403  
   404  	o.Loop()
   405  	defer o.Stop()
   406  
   407  	select {
   408  	case <-witness.ensureCalled:
   409  	case <-time.After(2 * time.Second):
   410  		c.Fatal("Ensure calls not happening")
   411  	}
   412  }
   413  
   414  func (ovs *overlordSuite) TestEnsureLoopMediatedEnsureBefore(c *C) {
   415  	restoreIntv := overlord.MockEnsureInterval(10 * time.Minute)
   416  	defer restoreIntv()
   417  	o := overlord.Mock()
   418  
   419  	ensure := func(s *state.State) error {
   420  		s.EnsureBefore(10 * time.Millisecond)
   421  		return nil
   422  	}
   423  
   424  	witness := &witnessManager{
   425  		state:          o.State(),
   426  		expectedEnsure: 2,
   427  		ensureCalled:   make(chan struct{}),
   428  		ensureCallback: ensure,
   429  	}
   430  	o.AddManager(witness)
   431  
   432  	c.Assert(o.StartUp(), IsNil)
   433  
   434  	o.Loop()
   435  	defer o.Stop()
   436  
   437  	select {
   438  	case <-witness.ensureCalled:
   439  	case <-time.After(2 * time.Second):
   440  		c.Fatal("Ensure calls not happening")
   441  	}
   442  }
   443  
   444  func (ovs *overlordSuite) TestEnsureBeforeSleepy(c *C) {
   445  	restoreIntv := overlord.MockEnsureInterval(10 * time.Minute)
   446  	defer restoreIntv()
   447  	o := overlord.Mock()
   448  
   449  	ensure := func(s *state.State) error {
   450  		overlord.MockEnsureNext(o, time.Now().Add(-10*time.Hour))
   451  		s.EnsureBefore(0)
   452  		return nil
   453  	}
   454  
   455  	witness := &witnessManager{
   456  		state:          o.State(),
   457  		expectedEnsure: 2,
   458  		ensureCalled:   make(chan struct{}),
   459  		ensureCallback: ensure,
   460  	}
   461  	o.AddManager(witness)
   462  
   463  	c.Assert(o.StartUp(), IsNil)
   464  
   465  	o.Loop()
   466  	defer o.Stop()
   467  
   468  	select {
   469  	case <-witness.ensureCalled:
   470  	case <-time.After(2 * time.Second):
   471  		c.Fatal("Ensure calls not happening")
   472  	}
   473  }
   474  
   475  func (ovs *overlordSuite) TestEnsureBeforeLater(c *C) {
   476  	restoreIntv := overlord.MockEnsureInterval(10 * time.Minute)
   477  	defer restoreIntv()
   478  	o := overlord.Mock()
   479  
   480  	ensure := func(s *state.State) error {
   481  		overlord.MockEnsureNext(o, time.Now().Add(-10*time.Hour))
   482  		s.EnsureBefore(time.Second * 5)
   483  		return nil
   484  	}
   485  
   486  	witness := &witnessManager{
   487  		state:          o.State(),
   488  		expectedEnsure: 2,
   489  		ensureCalled:   make(chan struct{}),
   490  		ensureCallback: ensure,
   491  	}
   492  	o.AddManager(witness)
   493  
   494  	c.Assert(o.StartUp(), IsNil)
   495  
   496  	o.Loop()
   497  	defer o.Stop()
   498  
   499  	select {
   500  	case <-witness.ensureCalled:
   501  	case <-time.After(2 * time.Second):
   502  		c.Fatal("Ensure calls not happening")
   503  	}
   504  }
   505  
   506  func (ovs *overlordSuite) TestEnsureLoopMediatedEnsureBeforeOutsideEnsure(c *C) {
   507  	restoreIntv := overlord.MockEnsureInterval(10 * time.Minute)
   508  	defer restoreIntv()
   509  	o := overlord.Mock()
   510  
   511  	ch := make(chan struct{})
   512  	ensure := func(s *state.State) error {
   513  		close(ch)
   514  		return nil
   515  	}
   516  
   517  	witness := &witnessManager{
   518  		state:          o.State(),
   519  		expectedEnsure: 2,
   520  		ensureCalled:   make(chan struct{}),
   521  		ensureCallback: ensure,
   522  	}
   523  	o.AddManager(witness)
   524  
   525  	c.Assert(o.StartUp(), IsNil)
   526  
   527  	o.Loop()
   528  	defer o.Stop()
   529  
   530  	select {
   531  	case <-ch:
   532  	case <-time.After(2 * time.Second):
   533  		c.Fatal("Ensure calls not happening")
   534  	}
   535  
   536  	o.State().EnsureBefore(0)
   537  
   538  	select {
   539  	case <-witness.ensureCalled:
   540  	case <-time.After(2 * time.Second):
   541  		c.Fatal("Ensure calls not happening")
   542  	}
   543  }
   544  
   545  func (ovs *overlordSuite) TestEnsureLoopPrune(c *C) {
   546  	restoreIntv := overlord.MockPruneInterval(200*time.Millisecond, 1000*time.Millisecond, 1000*time.Millisecond)
   547  	defer restoreIntv()
   548  	o := overlord.Mock()
   549  
   550  	st := o.State()
   551  	st.Lock()
   552  	t1 := st.NewTask("foo", "...")
   553  	chg1 := st.NewChange("abort", "...")
   554  	chg1.AddTask(t1)
   555  	chg2 := st.NewChange("prune", "...")
   556  	chg2.SetStatus(state.DoneStatus)
   557  	t0 := chg2.ReadyTime()
   558  	st.Unlock()
   559  
   560  	// observe the loop cycles to detect when prune should have happened
   561  	pruneHappened := make(chan struct{})
   562  	cycles := -1
   563  	waitForPrune := func(_ *state.State) error {
   564  		if cycles == -1 {
   565  			if time.Since(t0) > 1000*time.Millisecond {
   566  				cycles = 2 // wait a couple more loop cycles
   567  			}
   568  			return nil
   569  		}
   570  		if cycles > 0 {
   571  			cycles--
   572  			if cycles == 0 {
   573  				close(pruneHappened)
   574  			}
   575  		}
   576  		return nil
   577  	}
   578  	witness := &witnessManager{
   579  		ensureCallback: waitForPrune,
   580  	}
   581  	o.AddManager(witness)
   582  
   583  	c.Assert(o.StartUp(), IsNil)
   584  
   585  	o.Loop()
   586  
   587  	select {
   588  	case <-pruneHappened:
   589  	case <-time.After(2 * time.Second):
   590  		c.Fatal("Pruning should have happened by now")
   591  	}
   592  
   593  	err := o.Stop()
   594  	c.Assert(err, IsNil)
   595  
   596  	st.Lock()
   597  	defer st.Unlock()
   598  
   599  	c.Assert(st.Change(chg1.ID()), Equals, chg1)
   600  	c.Assert(st.Change(chg2.ID()), IsNil)
   601  
   602  	c.Assert(t1.Status(), Equals, state.HoldStatus)
   603  }
   604  
   605  func (ovs *overlordSuite) TestEnsureLoopPruneRunsMultipleTimes(c *C) {
   606  	restoreIntv := overlord.MockPruneInterval(100*time.Millisecond, 5*time.Millisecond, 1*time.Hour)
   607  	defer restoreIntv()
   608  	o := overlord.Mock()
   609  
   610  	// create two changes, one that can be pruned now, one in progress
   611  	st := o.State()
   612  	st.Lock()
   613  	t1 := st.NewTask("foo", "...")
   614  	chg1 := st.NewChange("pruneNow", "...")
   615  	chg1.AddTask(t1)
   616  	t1.SetStatus(state.DoneStatus)
   617  	t2 := st.NewTask("foo", "...")
   618  	chg2 := st.NewChange("pruneNext", "...")
   619  	chg2.AddTask(t2)
   620  	t2.SetStatus(state.DoStatus)
   621  	c.Check(st.Changes(), HasLen, 2)
   622  	st.Unlock()
   623  
   624  	w, restoreTicker := fakePruneTicker()
   625  	defer restoreTicker()
   626  
   627  	// start the loop that runs the prune ticker
   628  	o.Loop()
   629  
   630  	// this needs to be more than pruneWait=5ms mocked above
   631  	time.Sleep(10 * time.Millisecond)
   632  	w.tick(2)
   633  
   634  	st.Lock()
   635  	c.Check(st.Changes(), HasLen, 1)
   636  	chg2.SetStatus(state.DoneStatus)
   637  	st.Unlock()
   638  
   639  	// this needs to be more than pruneWait=5ms mocked above
   640  	time.Sleep(10 * time.Millisecond)
   641  	// tick twice for extra Ensure
   642  	w.tick(2)
   643  
   644  	st.Lock()
   645  	c.Check(st.Changes(), HasLen, 0)
   646  	st.Unlock()
   647  
   648  	// cleanup loop ticker
   649  	err := o.Stop()
   650  	c.Assert(err, IsNil)
   651  }
   652  
   653  func (ovs *overlordSuite) TestOverlordStartUpSetsStartOfOperation(c *C) {
   654  	restoreIntv := overlord.MockPruneInterval(100*time.Millisecond, 1000*time.Millisecond, 1*time.Hour)
   655  	defer restoreIntv()
   656  
   657  	// use real overlord, we need device manager to be there
   658  	o, err := overlord.New(nil)
   659  	c.Assert(err, IsNil)
   660  
   661  	st := o.State()
   662  	st.Lock()
   663  	defer st.Unlock()
   664  
   665  	// sanity check, not set
   666  	var opTime time.Time
   667  	c.Assert(st.Get("start-of-operation-time", &opTime), Equals, state.ErrNoState)
   668  	st.Unlock()
   669  
   670  	c.Assert(o.StartUp(), IsNil)
   671  
   672  	st.Lock()
   673  	c.Assert(st.Get("start-of-operation-time", &opTime), IsNil)
   674  }
   675  
   676  func (ovs *overlordSuite) TestEnsureLoopPruneDoesntAbortShortlyAfterStartOfOperation(c *C) {
   677  	w, restoreTicker := fakePruneTicker()
   678  	defer restoreTicker()
   679  
   680  	// use real overlord, we need device manager to be there
   681  	o, err := overlord.New(nil)
   682  	c.Assert(err, IsNil)
   683  
   684  	markSeeded(o)
   685  
   686  	// avoid immediate transition to Done due to unknown kind
   687  	o.TaskRunner().AddHandler("bar", func(t *state.Task, _ *tomb.Tomb) error {
   688  		return &state.Retry{}
   689  	}, nil)
   690  
   691  	st := o.State()
   692  	st.Lock()
   693  
   694  	// start of operation time is 50min ago, this is less then abort limit
   695  	opTime := time.Now().Add(-50 * time.Minute)
   696  	st.Set("start-of-operation-time", opTime)
   697  
   698  	// spawn time one month ago
   699  	spawnTime := time.Now().AddDate(0, -1, 0)
   700  	restoreTimeNow := state.MockTime(spawnTime)
   701  
   702  	t := st.NewTask("bar", "...")
   703  	chg := st.NewChange("other-change", "...")
   704  	chg.AddTask(t)
   705  
   706  	restoreTimeNow()
   707  
   708  	// sanity
   709  	c.Check(st.Changes(), HasLen, 1)
   710  
   711  	st.Unlock()
   712  	c.Assert(o.StartUp(), IsNil)
   713  
   714  	// start the loop that runs the prune ticker
   715  	o.Loop()
   716  	w.tick(2)
   717  
   718  	c.Assert(o.Stop(), IsNil)
   719  
   720  	st.Lock()
   721  	defer st.Unlock()
   722  	c.Assert(st.Changes(), HasLen, 1)
   723  	c.Check(chg.Status(), Equals, state.DoingStatus)
   724  }
   725  
   726  func (ovs *overlordSuite) TestEnsureLoopPruneAbortsOld(c *C) {
   727  	// Ensure interval is not relevant for this test
   728  	restoreEnsureIntv := overlord.MockEnsureInterval(10 * time.Hour)
   729  	defer restoreEnsureIntv()
   730  
   731  	w, restoreTicker := fakePruneTicker()
   732  	defer restoreTicker()
   733  
   734  	// use real overlord, we need device manager to be there
   735  	o, err := overlord.New(nil)
   736  	c.Assert(err, IsNil)
   737  
   738  	// avoid immediate transition to Done due to having unknown kind
   739  	o.TaskRunner().AddHandler("bar", func(t *state.Task, _ *tomb.Tomb) error {
   740  		return &state.Retry{}
   741  	}, nil)
   742  
   743  	markSeeded(o)
   744  
   745  	st := o.State()
   746  	st.Lock()
   747  
   748  	// start of operation time is a year ago
   749  	opTime := time.Now().AddDate(-1, 0, 0)
   750  	st.Set("start-of-operation-time", opTime)
   751  
   752  	st.Unlock()
   753  	c.Assert(o.StartUp(), IsNil)
   754  	st.Lock()
   755  
   756  	// spawn time one month ago
   757  	spawnTime := time.Now().AddDate(0, -1, 0)
   758  	restoreTimeNow := state.MockTime(spawnTime)
   759  	t := st.NewTask("bar", "...")
   760  	chg := st.NewChange("other-change", "...")
   761  	chg.AddTask(t)
   762  
   763  	restoreTimeNow()
   764  
   765  	// sanity
   766  	c.Check(st.Changes(), HasLen, 1)
   767  	st.Unlock()
   768  
   769  	// start the loop that runs the prune ticker
   770  	o.Loop()
   771  	w.tick(2)
   772  
   773  	c.Assert(o.Stop(), IsNil)
   774  
   775  	st.Lock()
   776  	defer st.Unlock()
   777  
   778  	// sanity
   779  	op, err := o.DeviceManager().StartOfOperationTime()
   780  	c.Assert(err, IsNil)
   781  	c.Check(op.Equal(opTime), Equals, true)
   782  
   783  	c.Assert(st.Changes(), HasLen, 1)
   784  	// change was aborted
   785  	c.Check(chg.Status(), Equals, state.HoldStatus)
   786  }
   787  
   788  func (ovs *overlordSuite) TestEnsureLoopNoPruneWhenPreseed(c *C) {
   789  	w, restoreTicker := fakePruneTicker()
   790  	defer restoreTicker()
   791  
   792  	restore := snapdenv.MockPreseeding(true)
   793  	defer restore()
   794  
   795  	restorePreseedExitWithErr := overlord.MockPreseedExitWithError(func(err error) {})
   796  	defer restorePreseedExitWithErr()
   797  
   798  	o, err := overlord.New(nil)
   799  	c.Assert(err, IsNil)
   800  
   801  	// avoid immediate transition to Done due to unknown kind
   802  	o.TaskRunner().AddHandler("bar", func(t *state.Task, _ *tomb.Tomb) error {
   803  		return &state.Retry{}
   804  	}, nil)
   805  
   806  	// sanity
   807  	_, err = o.DeviceManager().StartOfOperationTime()
   808  	c.Assert(err, ErrorMatches, `internal error: unexpected call to StartOfOperationTime in preseed mode`)
   809  
   810  	c.Assert(o.StartUp(), IsNil)
   811  
   812  	st := o.State()
   813  	st.Lock()
   814  
   815  	// spawn time one month ago
   816  	spawnTime := time.Now().AddDate(0, -1, 0)
   817  	restoreTimeNow := state.MockTime(spawnTime)
   818  	t := st.NewTask("bar", "...")
   819  	chg := st.NewChange("change", "...")
   820  	chg.AddTask(t)
   821  	restoreTimeNow()
   822  
   823  	st.Unlock()
   824  	// start the loop that runs the prune ticker
   825  	o.Loop()
   826  	w.tick(2)
   827  
   828  	c.Assert(o.Stop(), IsNil)
   829  
   830  	st.Lock()
   831  	defer st.Unlock()
   832  
   833  	var opTime time.Time
   834  	c.Assert(st.Get("start-of-operation-time", &opTime), Equals, state.ErrNoState)
   835  	c.Check(chg.Status(), Equals, state.DoingStatus)
   836  }
   837  
   838  func (ovs *overlordSuite) TestCheckpoint(c *C) {
   839  	oldUmask := syscall.Umask(0)
   840  	defer syscall.Umask(oldUmask)
   841  
   842  	o, err := overlord.New(nil)
   843  	c.Assert(err, IsNil)
   844  
   845  	s := o.State()
   846  	s.Lock()
   847  	s.Set("mark", 1)
   848  	s.Unlock()
   849  
   850  	st, err := os.Stat(dirs.SnapStateFile)
   851  	c.Assert(err, IsNil)
   852  	c.Assert(st.Mode(), Equals, os.FileMode(0600))
   853  
   854  	c.Check(dirs.SnapStateFile, testutil.FileContains, `"mark":1`)
   855  }
   856  
   857  type sampleManager struct {
   858  	ensureCallback func()
   859  }
   860  
   861  func newSampleManager(s *state.State, runner *state.TaskRunner) *sampleManager {
   862  	sm := &sampleManager{}
   863  
   864  	runner.AddHandler("runMgr1", func(t *state.Task, _ *tomb.Tomb) error {
   865  		s := t.State()
   866  		s.Lock()
   867  		defer s.Unlock()
   868  		s.Set("runMgr1Mark", 1)
   869  		return nil
   870  	}, nil)
   871  	runner.AddHandler("runMgr2", func(t *state.Task, _ *tomb.Tomb) error {
   872  		s := t.State()
   873  		s.Lock()
   874  		defer s.Unlock()
   875  		s.Set("runMgr2Mark", 1)
   876  		return nil
   877  	}, nil)
   878  	runner.AddHandler("runMgrEnsureBefore", func(t *state.Task, _ *tomb.Tomb) error {
   879  		s := t.State()
   880  		s.Lock()
   881  		defer s.Unlock()
   882  		s.EnsureBefore(20 * time.Millisecond)
   883  		return nil
   884  	}, nil)
   885  	runner.AddHandler("runMgrForever", func(t *state.Task, _ *tomb.Tomb) error {
   886  		s := t.State()
   887  		s.Lock()
   888  		defer s.Unlock()
   889  		s.EnsureBefore(20 * time.Millisecond)
   890  		return &state.Retry{}
   891  	}, nil)
   892  	runner.AddHandler("runMgrWCleanup", func(t *state.Task, _ *tomb.Tomb) error {
   893  		s := t.State()
   894  		s.Lock()
   895  		defer s.Unlock()
   896  		s.Set("runMgrWCleanupMark", 1)
   897  		return nil
   898  	}, nil)
   899  	runner.AddCleanup("runMgrWCleanup", func(t *state.Task, _ *tomb.Tomb) error {
   900  		s := t.State()
   901  		s.Lock()
   902  		defer s.Unlock()
   903  		s.Set("runMgrWCleanupCleanedUp", 1)
   904  		return nil
   905  	})
   906  
   907  	return sm
   908  }
   909  
   910  func (sm *sampleManager) Ensure() error {
   911  	if sm.ensureCallback != nil {
   912  		sm.ensureCallback()
   913  	}
   914  	return nil
   915  }
   916  
   917  func (ovs *overlordSuite) TestTrivialSettle(c *C) {
   918  	restoreIntv := overlord.MockEnsureInterval(1 * time.Minute)
   919  	defer restoreIntv()
   920  	o := overlord.Mock()
   921  
   922  	s := o.State()
   923  	sm1 := newSampleManager(s, o.TaskRunner())
   924  	o.AddManager(sm1)
   925  	o.AddManager(o.TaskRunner())
   926  
   927  	defer o.Engine().Stop()
   928  
   929  	s.Lock()
   930  	defer s.Unlock()
   931  
   932  	chg := s.NewChange("chg", "...")
   933  	t1 := s.NewTask("runMgr1", "1...")
   934  	chg.AddTask(t1)
   935  
   936  	s.Unlock()
   937  	o.Settle(5 * time.Second)
   938  	s.Lock()
   939  	c.Check(t1.Status(), Equals, state.DoneStatus)
   940  
   941  	var v int
   942  	err := s.Get("runMgr1Mark", &v)
   943  	c.Check(err, IsNil)
   944  }
   945  
   946  func (ovs *overlordSuite) TestSettleNotConverging(c *C) {
   947  	restoreIntv := overlord.MockEnsureInterval(1 * time.Minute)
   948  	defer restoreIntv()
   949  	o := overlord.Mock()
   950  
   951  	s := o.State()
   952  	sm1 := newSampleManager(s, o.TaskRunner())
   953  	o.AddManager(sm1)
   954  	o.AddManager(o.TaskRunner())
   955  
   956  	defer o.Engine().Stop()
   957  
   958  	s.Lock()
   959  	defer s.Unlock()
   960  
   961  	chg := s.NewChange("chg", "...")
   962  	t1 := s.NewTask("runMgrForever", "1...")
   963  	chg.AddTask(t1)
   964  
   965  	s.Unlock()
   966  	err := o.Settle(250 * time.Millisecond)
   967  	s.Lock()
   968  
   969  	c.Check(err, ErrorMatches, `Settle is not converging`)
   970  
   971  }
   972  
   973  func (ovs *overlordSuite) TestSettleChain(c *C) {
   974  	restoreIntv := overlord.MockEnsureInterval(1 * time.Minute)
   975  	defer restoreIntv()
   976  	o := overlord.Mock()
   977  
   978  	s := o.State()
   979  	sm1 := newSampleManager(s, o.TaskRunner())
   980  	o.AddManager(sm1)
   981  	o.AddManager(o.TaskRunner())
   982  
   983  	defer o.Engine().Stop()
   984  
   985  	s.Lock()
   986  	defer s.Unlock()
   987  
   988  	chg := s.NewChange("chg", "...")
   989  	t1 := s.NewTask("runMgr1", "1...")
   990  	t2 := s.NewTask("runMgr2", "2...")
   991  	t2.WaitFor(t1)
   992  	chg.AddAll(state.NewTaskSet(t1, t2))
   993  
   994  	s.Unlock()
   995  	o.Settle(5 * time.Second)
   996  	s.Lock()
   997  	c.Check(t1.Status(), Equals, state.DoneStatus)
   998  	c.Check(t2.Status(), Equals, state.DoneStatus)
   999  
  1000  	var v int
  1001  	err := s.Get("runMgr1Mark", &v)
  1002  	c.Check(err, IsNil)
  1003  	err = s.Get("runMgr2Mark", &v)
  1004  	c.Check(err, IsNil)
  1005  }
  1006  
  1007  func (ovs *overlordSuite) TestSettleChainWCleanup(c *C) {
  1008  	restoreIntv := overlord.MockEnsureInterval(1 * time.Minute)
  1009  	defer restoreIntv()
  1010  	o := overlord.Mock()
  1011  
  1012  	s := o.State()
  1013  	sm1 := newSampleManager(s, o.TaskRunner())
  1014  	o.AddManager(sm1)
  1015  	o.AddManager(o.TaskRunner())
  1016  
  1017  	defer o.Engine().Stop()
  1018  
  1019  	s.Lock()
  1020  	defer s.Unlock()
  1021  
  1022  	chg := s.NewChange("chg", "...")
  1023  	t1 := s.NewTask("runMgrWCleanup", "1...")
  1024  	t2 := s.NewTask("runMgr2", "2...")
  1025  	t2.WaitFor(t1)
  1026  	chg.AddAll(state.NewTaskSet(t1, t2))
  1027  
  1028  	s.Unlock()
  1029  	o.Settle(5 * time.Second)
  1030  	s.Lock()
  1031  	c.Check(t1.Status(), Equals, state.DoneStatus)
  1032  	c.Check(t2.Status(), Equals, state.DoneStatus)
  1033  
  1034  	var v int
  1035  	err := s.Get("runMgrWCleanupMark", &v)
  1036  	c.Check(err, IsNil)
  1037  	err = s.Get("runMgr2Mark", &v)
  1038  	c.Check(err, IsNil)
  1039  
  1040  	err = s.Get("runMgrWCleanupCleanedUp", &v)
  1041  	c.Check(err, IsNil)
  1042  }
  1043  
  1044  func (ovs *overlordSuite) TestSettleExplicitEnsureBefore(c *C) {
  1045  	restoreIntv := overlord.MockEnsureInterval(1 * time.Minute)
  1046  	defer restoreIntv()
  1047  	o := overlord.Mock()
  1048  
  1049  	s := o.State()
  1050  	sm1 := newSampleManager(s, o.TaskRunner())
  1051  	sm1.ensureCallback = func() {
  1052  		s.Lock()
  1053  		defer s.Unlock()
  1054  		v := 0
  1055  		s.Get("ensureCount", &v)
  1056  		s.Set("ensureCount", v+1)
  1057  	}
  1058  
  1059  	o.AddManager(sm1)
  1060  	o.AddManager(o.TaskRunner())
  1061  
  1062  	defer o.Engine().Stop()
  1063  
  1064  	s.Lock()
  1065  	defer s.Unlock()
  1066  
  1067  	chg := s.NewChange("chg", "...")
  1068  	t := s.NewTask("runMgrEnsureBefore", "...")
  1069  	chg.AddTask(t)
  1070  
  1071  	s.Unlock()
  1072  	o.Settle(5 * time.Second)
  1073  	s.Lock()
  1074  	c.Check(t.Status(), Equals, state.DoneStatus)
  1075  
  1076  	var v int
  1077  	err := s.Get("ensureCount", &v)
  1078  	c.Check(err, IsNil)
  1079  	c.Check(v, Equals, 2)
  1080  }
  1081  
  1082  func (ovs *overlordSuite) TestEnsureErrorWhenPreseeding(c *C) {
  1083  	restore := snapdenv.MockPreseeding(true)
  1084  	defer restore()
  1085  
  1086  	restoreIntv := overlord.MockEnsureInterval(1 * time.Millisecond)
  1087  	defer restoreIntv()
  1088  
  1089  	var errorCallbackError error
  1090  	restoreExitWithErr := overlord.MockPreseedExitWithError(func(err error) {
  1091  		errorCallbackError = err
  1092  	})
  1093  	defer restoreExitWithErr()
  1094  
  1095  	o, err := overlord.New(nil)
  1096  	c.Assert(err, IsNil)
  1097  	markSeeded(o)
  1098  
  1099  	err = o.StartUp()
  1100  	c.Assert(err, IsNil)
  1101  
  1102  	o.TaskRunner().AddHandler("bar", func(t *state.Task, _ *tomb.Tomb) error {
  1103  		return fmt.Errorf("bar error")
  1104  	}, nil)
  1105  
  1106  	s := o.State()
  1107  	s.Lock()
  1108  	defer s.Unlock()
  1109  
  1110  	chg := s.NewChange("chg", "...")
  1111  	t := s.NewTask("bar", "...")
  1112  	chg.AddTask(t)
  1113  
  1114  	s.Unlock()
  1115  	o.Loop()
  1116  	time.Sleep(1 * time.Second)
  1117  	o.Stop()
  1118  
  1119  	s.Lock()
  1120  	c.Check(t.Status(), Equals, state.ErrorStatus)
  1121  	c.Check(errorCallbackError, ErrorMatches, "bar error")
  1122  }
  1123  
  1124  func (ovs *overlordSuite) TestRequestRestartNoHandler(c *C) {
  1125  	o, err := overlord.New(nil)
  1126  	c.Assert(err, IsNil)
  1127  
  1128  	o.State().RequestRestart(state.RestartDaemon)
  1129  }
  1130  
  1131  type testRestartBehavior struct {
  1132  	restartRequested  state.RestartType
  1133  	rebootState       string
  1134  	rebootVerifiedErr error
  1135  }
  1136  
  1137  func (rb *testRestartBehavior) HandleRestart(t state.RestartType) {
  1138  	rb.restartRequested = t
  1139  }
  1140  
  1141  func (rb *testRestartBehavior) RebootAsExpected(_ *state.State) error {
  1142  	rb.rebootState = "as-expected"
  1143  	return rb.rebootVerifiedErr
  1144  }
  1145  
  1146  func (rb *testRestartBehavior) RebootDidNotHappen(_ *state.State) error {
  1147  	rb.rebootState = "did-not-happen"
  1148  	return rb.rebootVerifiedErr
  1149  }
  1150  
  1151  func (ovs *overlordSuite) TestRequestRestartHandler(c *C) {
  1152  	rb := &testRestartBehavior{}
  1153  
  1154  	o, err := overlord.New(rb)
  1155  	c.Assert(err, IsNil)
  1156  
  1157  	o.State().RequestRestart(state.RestartDaemon)
  1158  
  1159  	c.Check(rb.restartRequested, Equals, state.RestartDaemon)
  1160  }
  1161  
  1162  func (ovs *overlordSuite) TestVerifyRebootNoPendingReboot(c *C) {
  1163  	fakeState := []byte(fmt.Sprintf(`{"data":{"patch-level":%d,"patch-sublevel":%d,"some":"data","refresh-privacy-key":"0123456789ABCDEF"},"changes":null,"tasks":null,"last-change-id":0,"last-task-id":0,"last-lane-id":0}`, patch.Level, patch.Sublevel))
  1164  	err := ioutil.WriteFile(dirs.SnapStateFile, fakeState, 0600)
  1165  	c.Assert(err, IsNil)
  1166  
  1167  	rb := &testRestartBehavior{}
  1168  
  1169  	_, err = overlord.New(rb)
  1170  	c.Assert(err, IsNil)
  1171  
  1172  	c.Check(rb.rebootState, Equals, "as-expected")
  1173  }
  1174  
  1175  func (ovs *overlordSuite) TestVerifyRebootOK(c *C) {
  1176  	fakeState := []byte(fmt.Sprintf(`{"data":{"patch-level":%d,"patch-sublevel":%d,"some":"data","refresh-privacy-key":"0123456789ABCDEF","system-restart-from-boot-id":%q},"changes":null,"tasks":null,"last-change-id":0,"last-task-id":0,"last-lane-id":0}`, patch.Level, patch.Sublevel, "boot-id-prev"))
  1177  	err := ioutil.WriteFile(dirs.SnapStateFile, fakeState, 0600)
  1178  	c.Assert(err, IsNil)
  1179  
  1180  	rb := &testRestartBehavior{}
  1181  
  1182  	_, err = overlord.New(rb)
  1183  	c.Assert(err, IsNil)
  1184  
  1185  	c.Check(rb.rebootState, Equals, "as-expected")
  1186  }
  1187  
  1188  func (ovs *overlordSuite) TestVerifyRebootOKButError(c *C) {
  1189  	fakeState := []byte(fmt.Sprintf(`{"data":{"patch-level":%d,"patch-sublevel":%d,"some":"data","refresh-privacy-key":"0123456789ABCDEF","system-restart-from-boot-id":%q},"changes":null,"tasks":null,"last-change-id":0,"last-task-id":0,"last-lane-id":0}`, patch.Level, patch.Sublevel, "boot-id-prev"))
  1190  	err := ioutil.WriteFile(dirs.SnapStateFile, fakeState, 0600)
  1191  	c.Assert(err, IsNil)
  1192  
  1193  	e := errors.New("boom")
  1194  	rb := &testRestartBehavior{rebootVerifiedErr: e}
  1195  
  1196  	_, err = overlord.New(rb)
  1197  	c.Assert(err, Equals, e)
  1198  
  1199  	c.Check(rb.rebootState, Equals, "as-expected")
  1200  }
  1201  
  1202  func (ovs *overlordSuite) TestVerifyRebootDidNotHappen(c *C) {
  1203  	curBootID, err := osutil.BootID()
  1204  	c.Assert(err, IsNil)
  1205  
  1206  	fakeState := []byte(fmt.Sprintf(`{"data":{"patch-level":%d,"patch-sublevel":%d,"some":"data","refresh-privacy-key":"0123456789ABCDEF","system-restart-from-boot-id":%q},"changes":null,"tasks":null,"last-change-id":0,"last-task-id":0,"last-lane-id":0}`, patch.Level, patch.Sublevel, curBootID))
  1207  	err = ioutil.WriteFile(dirs.SnapStateFile, fakeState, 0600)
  1208  	c.Assert(err, IsNil)
  1209  
  1210  	rb := &testRestartBehavior{}
  1211  
  1212  	_, err = overlord.New(rb)
  1213  	c.Assert(err, IsNil)
  1214  
  1215  	c.Check(rb.rebootState, Equals, "did-not-happen")
  1216  }
  1217  
  1218  func (ovs *overlordSuite) TestVerifyRebootDidNotHappenError(c *C) {
  1219  	curBootID, err := osutil.BootID()
  1220  	c.Assert(err, IsNil)
  1221  
  1222  	fakeState := []byte(fmt.Sprintf(`{"data":{"patch-level":%d,"patch-sublevel":%d,"some":"data","refresh-privacy-key":"0123456789ABCDEF","system-restart-from-boot-id":%q},"changes":null,"tasks":null,"last-change-id":0,"last-task-id":0,"last-lane-id":0}`, patch.Level, patch.Sublevel, curBootID))
  1223  	err = ioutil.WriteFile(dirs.SnapStateFile, fakeState, 0600)
  1224  	c.Assert(err, IsNil)
  1225  
  1226  	e := errors.New("boom")
  1227  	rb := &testRestartBehavior{rebootVerifiedErr: e}
  1228  
  1229  	_, err = overlord.New(rb)
  1230  	c.Assert(err, Equals, e)
  1231  
  1232  	c.Check(rb.rebootState, Equals, "did-not-happen")
  1233  }
  1234  
  1235  func (ovs *overlordSuite) TestOverlordCanStandby(c *C) {
  1236  	restoreIntv := overlord.MockEnsureInterval(10 * time.Millisecond)
  1237  	defer restoreIntv()
  1238  	o := overlord.Mock()
  1239  	witness := &witnessManager{
  1240  		state:          o.State(),
  1241  		expectedEnsure: 3,
  1242  		ensureCalled:   make(chan struct{}),
  1243  	}
  1244  	o.AddManager(witness)
  1245  
  1246  	c.Assert(o.StartUp(), IsNil)
  1247  
  1248  	// can only standby after loop ran once
  1249  	c.Assert(o.CanStandby(), Equals, false)
  1250  
  1251  	o.Loop()
  1252  	defer o.Stop()
  1253  
  1254  	select {
  1255  	case <-witness.ensureCalled:
  1256  	case <-time.After(2 * time.Second):
  1257  		c.Fatal("Ensure calls not happening")
  1258  	}
  1259  
  1260  	c.Assert(o.CanStandby(), Equals, true)
  1261  }
  1262  
  1263  func (ovs *overlordSuite) TestStartupTimeout(c *C) {
  1264  	o, err := overlord.New(nil)
  1265  	c.Assert(err, IsNil)
  1266  
  1267  	to, _, err := o.StartupTimeout()
  1268  	c.Assert(err, IsNil)
  1269  	c.Check(to, Equals, 30*time.Second)
  1270  
  1271  	st := o.State()
  1272  	st.Lock()
  1273  	defer st.Unlock()
  1274  
  1275  	// have two snaps
  1276  	snapstate.Set(st, "core18", &snapstate.SnapState{
  1277  		Active: true,
  1278  		Sequence: []*snap.SideInfo{
  1279  			{RealName: "core18", Revision: snap.R(1)},
  1280  		},
  1281  		Current:  snap.R(1),
  1282  		SnapType: "base",
  1283  	})
  1284  	snapstate.Set(st, "foo", &snapstate.SnapState{
  1285  		Active: true,
  1286  		Sequence: []*snap.SideInfo{
  1287  			{RealName: "foo", Revision: snap.R(1)},
  1288  		},
  1289  		Current:  snap.R(1),
  1290  		SnapType: "app",
  1291  	})
  1292  
  1293  	st.Unlock()
  1294  	to, reasoning, err := o.StartupTimeout()
  1295  	st.Lock()
  1296  	c.Assert(err, IsNil)
  1297  
  1298  	c.Check(to, Equals, (30+5+5)*time.Second)
  1299  	c.Check(reasoning, Equals, "pessimistic estimate of 30s plus 5s per snap")
  1300  }