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