github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/overlord/snapstate/refreshhints_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2017-2018 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  	"context"
    24  	"time"
    25  
    26  	. "gopkg.in/check.v1"
    27  
    28  	"github.com/snapcore/snapd/overlord/auth"
    29  	"github.com/snapcore/snapd/overlord/snapstate"
    30  	"github.com/snapcore/snapd/overlord/state"
    31  	"github.com/snapcore/snapd/release"
    32  	"github.com/snapcore/snapd/snap"
    33  	"github.com/snapcore/snapd/store"
    34  	"github.com/snapcore/snapd/store/storetest"
    35  )
    36  
    37  type recordingStore struct {
    38  	storetest.Store
    39  
    40  	ops []string
    41  }
    42  
    43  func (r *recordingStore) SnapAction(ctx context.Context, currentSnaps []*store.CurrentSnap, actions []*store.SnapAction, assertQuery store.AssertionQuery, user *auth.UserState, opts *store.RefreshOptions) ([]store.SnapActionResult, []store.AssertionResult, error) {
    44  	if assertQuery != nil {
    45  		panic("no assertion query support")
    46  	}
    47  	if ctx == nil || !auth.IsEnsureContext(ctx) {
    48  		panic("Ensure marked context required")
    49  	}
    50  	if len(currentSnaps) != len(actions) || len(currentSnaps) == 0 {
    51  		panic("expected in test one action for each current snaps, and at least one snap")
    52  	}
    53  	for _, a := range actions {
    54  		if a.Action != "refresh" {
    55  			panic("expected refresh actions")
    56  		}
    57  	}
    58  	r.ops = append(r.ops, "list-refresh")
    59  	return nil, nil, nil
    60  }
    61  
    62  type refreshHintsTestSuite struct {
    63  	state *state.State
    64  
    65  	store *recordingStore
    66  }
    67  
    68  var _ = Suite(&refreshHintsTestSuite{})
    69  
    70  func (s *refreshHintsTestSuite) SetUpTest(c *C) {
    71  	s.state = state.New(nil)
    72  
    73  	s.store = &recordingStore{}
    74  	s.state.Lock()
    75  	defer s.state.Unlock()
    76  	snapstate.ReplaceStore(s.state, s.store)
    77  
    78  	snapstate.Set(s.state, "some-snap", &snapstate.SnapState{
    79  		Active: true,
    80  		Sequence: []*snap.SideInfo{
    81  			{RealName: "some-snap", Revision: snap.R(5), SnapID: "some-snap-id"},
    82  		},
    83  		Current:  snap.R(5),
    84  		SnapType: "app",
    85  		UserID:   1,
    86  	})
    87  
    88  	snapstate.CanAutoRefresh = func(*state.State) (bool, error) { return true, nil }
    89  	snapstate.AutoAliases = func(*state.State, *snap.Info) (map[string]string, error) {
    90  		return nil, nil
    91  	}
    92  
    93  	s.state.Set("refresh-privacy-key", "privacy-key")
    94  }
    95  
    96  func (s *refreshHintsTestSuite) TearDownTest(c *C) {
    97  	snapstate.CanAutoRefresh = nil
    98  	snapstate.AutoAliases = nil
    99  }
   100  
   101  func (s *refreshHintsTestSuite) TestLastRefresh(c *C) {
   102  	rh := snapstate.NewRefreshHints(s.state)
   103  	err := rh.Ensure()
   104  	c.Check(err, IsNil)
   105  	c.Check(s.store.ops, DeepEquals, []string{"list-refresh"})
   106  }
   107  
   108  func (s *refreshHintsTestSuite) TestLastRefreshNoRefreshNeeded(c *C) {
   109  	s.state.Lock()
   110  	s.state.Set("last-refresh-hints", time.Now().Add(-23*time.Hour))
   111  	s.state.Unlock()
   112  
   113  	rh := snapstate.NewRefreshHints(s.state)
   114  	err := rh.Ensure()
   115  	c.Check(err, IsNil)
   116  	c.Check(s.store.ops, HasLen, 0)
   117  }
   118  
   119  func (s *refreshHintsTestSuite) TestLastRefreshNoRefreshNeededBecauseOfFullAutoRefresh(c *C) {
   120  	s.state.Lock()
   121  	s.state.Set("last-refresh-hints", time.Now().Add(-48*time.Hour))
   122  	s.state.Unlock()
   123  
   124  	s.state.Lock()
   125  	s.state.Set("last-refresh", time.Now().Add(-23*time.Hour))
   126  	s.state.Unlock()
   127  
   128  	rh := snapstate.NewRefreshHints(s.state)
   129  	err := rh.Ensure()
   130  	c.Check(err, IsNil)
   131  	c.Check(s.store.ops, HasLen, 0)
   132  }
   133  
   134  func (s *refreshHintsTestSuite) TestAtSeedPolicy(c *C) {
   135  	r := release.MockOnClassic(false)
   136  	defer r()
   137  
   138  	s.state.Lock()
   139  	defer s.state.Unlock()
   140  
   141  	rh := snapstate.NewRefreshHints(s.state)
   142  
   143  	// on core, does nothing
   144  	err := rh.AtSeed()
   145  	c.Assert(err, IsNil)
   146  	var t1 time.Time
   147  	err = s.state.Get("last-refresh-hints", &t1)
   148  	c.Check(err, Equals, state.ErrNoState)
   149  
   150  	release.MockOnClassic(true)
   151  	// on classic it sets last-refresh-hints to now,
   152  	// postponing it of 24h
   153  	err = rh.AtSeed()
   154  	c.Assert(err, IsNil)
   155  	err = s.state.Get("last-refresh-hints", &t1)
   156  	c.Check(err, IsNil)
   157  
   158  	// nop if tried again
   159  	err = rh.AtSeed()
   160  	c.Assert(err, IsNil)
   161  	var t2 time.Time
   162  	err = s.state.Get("last-refresh-hints", &t2)
   163  	c.Check(err, IsNil)
   164  	c.Check(t1.Equal(t2), Equals, true)
   165  }