github.com/rigado/snapd@v2.42.5-go-mod+incompatible/overlord/standby/standby_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  /*
     3   * Copyright (C) 2018 Canonical Ltd
     4   *
     5   * This program is free software: you can redistribute it and/or modify
     6   * it under the terms of the GNU General Public License version 3 as
     7   * published by the Free Software Foundation.
     8   *
     9   * This program is distributed in the hope that it will be useful,
    10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   * GNU General Public License for more details.
    13   *
    14   * You should have received a copy of the GNU General Public License
    15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16   *
    17   */
    18  package standby_test
    19  
    20  import (
    21  	"testing"
    22  	"time"
    23  
    24  	. "gopkg.in/check.v1"
    25  
    26  	"github.com/snapcore/snapd/overlord/standby"
    27  	"github.com/snapcore/snapd/overlord/state"
    28  )
    29  
    30  // Hook up v1 into the "go test" runner
    31  func Test(t *testing.T) { TestingT(t) }
    32  
    33  type standbySuite struct {
    34  	state *state.State
    35  
    36  	canStandby bool
    37  }
    38  
    39  var _ = Suite(&standbySuite{})
    40  
    41  func (s *standbySuite) SetUpTest(c *C) {
    42  	s.state = state.New(nil)
    43  }
    44  
    45  func (s *standbySuite) TestCanStandbyNoChanges(c *C) {
    46  	m := standby.New(s.state)
    47  	c.Check(m.CanStandby(), Equals, false)
    48  
    49  	m.SetStartTime(time.Time{})
    50  	c.Check(m.CanStandby(), Equals, true)
    51  }
    52  
    53  func (s *standbySuite) TestCanStandbyPendingChanges(c *C) {
    54  	st := s.state
    55  	st.Lock()
    56  	chg := st.NewChange("foo", "fake change")
    57  	chg.AddTask(st.NewTask("bar", "fake task"))
    58  	c.Assert(chg.Status(), Equals, state.DoStatus)
    59  	st.Unlock()
    60  
    61  	m := standby.New(s.state)
    62  	m.SetStartTime(time.Time{})
    63  	c.Check(m.CanStandby(), Equals, false)
    64  }
    65  
    66  func (s *standbySuite) TestCanStandbyPendingClean(c *C) {
    67  	st := s.state
    68  	st.Lock()
    69  	t := st.NewTask("bar", "fake task")
    70  	chg := st.NewChange("foo", "fake change")
    71  	chg.AddTask(t)
    72  	t.SetStatus(state.DoneStatus)
    73  	c.Assert(chg.Status(), Equals, state.DoneStatus)
    74  	c.Assert(t.IsClean(), Equals, false)
    75  	st.Unlock()
    76  
    77  	m := standby.New(s.state)
    78  	m.SetStartTime(time.Time{})
    79  	c.Check(m.CanStandby(), Equals, false)
    80  }
    81  
    82  func (s *standbySuite) TestCanStandbyOnlyDonePendingChanges(c *C) {
    83  	st := s.state
    84  	st.Lock()
    85  	t := st.NewTask("bar", "fake task")
    86  	chg := st.NewChange("foo", "fake change")
    87  	chg.AddTask(t)
    88  	t.SetStatus(state.DoneStatus)
    89  	t.SetClean()
    90  	c.Assert(chg.Status(), Equals, state.DoneStatus)
    91  	c.Assert(t.IsClean(), Equals, true)
    92  	st.Unlock()
    93  
    94  	m := standby.New(s.state)
    95  	m.SetStartTime(time.Time{})
    96  	c.Check(m.CanStandby(), Equals, true)
    97  }
    98  
    99  func (s *standbySuite) CanStandby() bool {
   100  	return s.canStandby
   101  }
   102  
   103  func (s *standbySuite) TestCanStandbyWithOpinion(c *C) {
   104  	m := standby.New(s.state)
   105  	m.AddOpinion(s)
   106  	m.SetStartTime(time.Time{})
   107  
   108  	s.canStandby = true
   109  	c.Check(m.CanStandby(), Equals, true)
   110  
   111  	s.canStandby = false
   112  	c.Check(m.CanStandby(), Equals, false)
   113  }
   114  
   115  type opine func() bool
   116  
   117  func (f opine) CanStandby() bool {
   118  	return f()
   119  }
   120  
   121  func (s *standbySuite) TestStartChecks(c *C) {
   122  	n := 0
   123  	ch1 := make(chan bool, 1)
   124  	ch2 := make(chan struct{})
   125  
   126  	defer standby.MockStandbyWait(time.Millisecond)()
   127  	defer standby.MockStateRequestRestart(func(_ *state.State, t state.RestartType) {
   128  		c.Check(t, Equals, state.RestartSocket)
   129  		n++
   130  		<-ch2
   131  	})()
   132  
   133  	m := standby.New(s.state)
   134  	m.AddOpinion(opine(func() bool {
   135  		opinion := <-ch1
   136  		return opinion
   137  	}))
   138  
   139  	m.Start()
   140  	ch1 <- false
   141  	c.Check(n, Equals, 0)
   142  	ch1 <- false
   143  	c.Check(n, Equals, 0)
   144  
   145  	ch1 <- true
   146  	ch2 <- struct{}{}
   147  	c.Check(n, Equals, 1)
   148  
   149  	m.Stop()
   150  }
   151  
   152  func (s *standbySuite) TestStopWaits(c *C) {
   153  	defer standby.MockStandbyWait(time.Millisecond)()
   154  	defer standby.MockStateRequestRestart(func(*state.State, state.RestartType) {
   155  		c.Fatal("request restart should have not been called")
   156  	})()
   157  
   158  	ch := make(chan struct{})
   159  	opineReady := make(chan struct{})
   160  	done := make(chan struct{})
   161  	m := standby.New(s.state)
   162  	synced := false
   163  	m.AddOpinion(opine(func() bool {
   164  		if !synced {
   165  			// synchronize with the main goroutine only at the
   166  			// beginning
   167  			close(opineReady)
   168  			synced = true
   169  		}
   170  		select {
   171  		case <-time.After(200 * time.Millisecond):
   172  		case <-done:
   173  		}
   174  		return false
   175  	}))
   176  
   177  	m.Start()
   178  
   179  	// let the opinionator start its delay
   180  	<-opineReady
   181  	go func() {
   182  		// this will block until standby stops
   183  		m.Stop()
   184  		close(ch)
   185  	}()
   186  
   187  	select {
   188  	case <-time.After(100 * time.Millisecond):
   189  		// wheee
   190  	case <-ch:
   191  		c.Fatal("stop should have blocked and didn't")
   192  	}
   193  
   194  	close(done)
   195  
   196  	// wait for Stop to complete now
   197  	select {
   198  	case <-ch:
   199  		// nothing to do here
   200  	case <-time.After(10 * time.Second):
   201  		c.Fatal("stop did not complete")
   202  	}
   203  }