github.com/rigado/snapd@v2.42.5-go-mod+incompatible/overlord/snapstate/catalogrefresh_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 "io" 25 "io/ioutil" 26 "os" 27 "path/filepath" 28 "time" 29 30 . "gopkg.in/check.v1" 31 32 "github.com/snapcore/snapd/advisor" 33 "github.com/snapcore/snapd/dirs" 34 "github.com/snapcore/snapd/osutil" 35 "github.com/snapcore/snapd/overlord/auth" 36 "github.com/snapcore/snapd/overlord/snapstate" 37 "github.com/snapcore/snapd/overlord/state" 38 "github.com/snapcore/snapd/store" 39 "github.com/snapcore/snapd/store/storetest" 40 "github.com/snapcore/snapd/testutil" 41 ) 42 43 type catalogStore struct { 44 storetest.Store 45 46 ops []string 47 tooMany bool 48 } 49 50 func (r *catalogStore) WriteCatalogs(ctx context.Context, w io.Writer, a store.SnapAdder) error { 51 if ctx == nil || !auth.IsEnsureContext(ctx) { 52 panic("Ensure marked context required") 53 } 54 r.ops = append(r.ops, "write-catalog") 55 if r.tooMany { 56 return store.ErrTooManyRequests 57 } 58 w.Write([]byte("pkg1\npkg2")) 59 a.AddSnap("foo", "1.0", "foo summary", []string{"foo", "meh"}) 60 a.AddSnap("bar", "2.0", "bar summray", []string{"bar", "meh"}) 61 return nil 62 } 63 64 func (r *catalogStore) Sections(ctx context.Context, _ *auth.UserState) ([]string, error) { 65 if ctx == nil || !auth.IsEnsureContext(ctx) { 66 panic("Ensure marked context required") 67 } 68 r.ops = append(r.ops, "sections") 69 if r.tooMany { 70 return nil, store.ErrTooManyRequests 71 } 72 return []string{"section1", "section2"}, nil 73 } 74 75 type catalogRefreshTestSuite struct { 76 state *state.State 77 78 store *catalogStore 79 tmpdir string 80 } 81 82 var _ = Suite(&catalogRefreshTestSuite{}) 83 84 func (s *catalogRefreshTestSuite) SetUpTest(c *C) { 85 s.tmpdir = c.MkDir() 86 dirs.SetRootDir(s.tmpdir) 87 s.state = state.New(nil) 88 89 s.store = &catalogStore{} 90 s.state.Lock() 91 snapstate.ReplaceStore(s.state, s.store) 92 s.state.Unlock() 93 94 snapstate.CanAutoRefresh = func(*state.State) (bool, error) { return true, nil } 95 } 96 97 func (s *catalogRefreshTestSuite) TearDownTest(c *C) { 98 snapstate.CanAutoRefresh = nil 99 } 100 101 func (s *catalogRefreshTestSuite) TestCatalogRefresh(c *C) { 102 // start with no catalog 103 c.Check(dirs.SnapSectionsFile, testutil.FileAbsent) 104 c.Check(dirs.SnapNamesFile, testutil.FileAbsent) 105 c.Check(dirs.SnapCommandsDB, testutil.FileAbsent) 106 107 cr7 := snapstate.NewCatalogRefresh(s.state) 108 // next is initially zero 109 c.Check(snapstate.NextCatalogRefresh(cr7).IsZero(), Equals, true) 110 t0 := time.Now() 111 112 err := cr7.Ensure() 113 c.Check(err, IsNil) 114 115 // next now has a delta (next refresh is not before t0 + delta) 116 c.Check(snapstate.NextCatalogRefresh(cr7).Before(t0.Add(snapstate.CatalogRefreshDelayWithDelta)), Equals, false) 117 118 c.Check(s.store.ops, DeepEquals, []string{"sections", "write-catalog"}) 119 120 c.Check(osutil.FileExists(dirs.SnapSectionsFile), Equals, true) 121 c.Check(dirs.SnapSectionsFile, testutil.FileEquals, "section1\nsection2") 122 123 c.Check(osutil.FileExists(dirs.SnapNamesFile), Equals, true) 124 c.Check(dirs.SnapNamesFile, testutil.FileEquals, "pkg1\npkg2") 125 126 c.Check(osutil.FileExists(dirs.SnapCommandsDB), Equals, true) 127 dump, err := advisor.DumpCommands() 128 c.Assert(err, IsNil) 129 c.Check(dump, DeepEquals, map[string]string{ 130 "foo": `[{"snap":"foo","version":"1.0"}]`, 131 "bar": `[{"snap":"bar","version":"2.0"}]`, 132 "meh": `[{"snap":"foo","version":"1.0"},{"snap":"bar","version":"2.0"}]`, 133 }) 134 } 135 136 func (s *catalogRefreshTestSuite) TestCatalogRefreshTooMany(c *C) { 137 s.store.tooMany = true 138 139 cr7 := snapstate.NewCatalogRefresh(s.state) 140 // next is initially zero 141 c.Check(snapstate.NextCatalogRefresh(cr7).IsZero(), Equals, true) 142 t0 := time.Now() 143 144 err := cr7.Ensure() 145 c.Check(err, IsNil) // !! 146 147 // next now has a delta (next refresh is not before t0 + delta) 148 c.Check(snapstate.NextCatalogRefresh(cr7).Before(t0.Add(snapstate.CatalogRefreshDelayWithDelta)), Equals, false) 149 150 // it tried one endpoint and bailed at the first 429 151 c.Check(s.store.ops, HasLen, 1) 152 153 // nothing got created 154 c.Check(osutil.FileExists(dirs.SnapSectionsFile), Equals, false) 155 c.Check(osutil.FileExists(dirs.SnapNamesFile), Equals, false) 156 c.Check(osutil.FileExists(dirs.SnapCommandsDB), Equals, false) 157 } 158 159 func (s *catalogRefreshTestSuite) TestCatalogRefreshNotNeeded(c *C) { 160 cr7 := snapstate.NewCatalogRefresh(s.state) 161 snapstate.MockCatalogRefreshNextRefresh(cr7, time.Now().Add(1*time.Hour)) 162 err := cr7.Ensure() 163 c.Check(err, IsNil) 164 c.Check(s.store.ops, HasLen, 0) 165 c.Check(osutil.FileExists(dirs.SnapSectionsFile), Equals, false) 166 c.Check(osutil.FileExists(dirs.SnapNamesFile), Equals, false) 167 } 168 169 func (s *catalogRefreshTestSuite) TestCatalogRefreshNewEnough(c *C) { 170 // write a fake sections file just to have it 171 c.Assert(os.MkdirAll(filepath.Dir(dirs.SnapNamesFile), 0755), IsNil) 172 c.Assert(ioutil.WriteFile(dirs.SnapNamesFile, nil, 0644), IsNil) 173 // set the timestamp to something known 174 t0 := time.Now().Truncate(time.Hour) 175 c.Assert(os.Chtimes(dirs.SnapNamesFile, t0, t0), IsNil) 176 177 cr7 := snapstate.NewCatalogRefresh(s.state) 178 // next is initially zero 179 c.Check(snapstate.NextCatalogRefresh(cr7).IsZero(), Equals, true) 180 err := cr7.Ensure() 181 c.Assert(err, IsNil) 182 c.Check(s.store.ops, HasLen, 0) 183 next := snapstate.NextCatalogRefresh(cr7) 184 // next is no longer zero, 185 c.Check(next.IsZero(), Equals, false) 186 // but has a delta WRT the timestamp 187 c.Check(next.Equal(t0.Add(snapstate.CatalogRefreshDelayWithDelta)), Equals, true) 188 } 189 190 func (s *catalogRefreshTestSuite) TestCatalogRefreshTooNew(c *C) { 191 // write a fake sections file just to have it 192 c.Assert(os.MkdirAll(filepath.Dir(dirs.SnapNamesFile), 0755), IsNil) 193 c.Assert(ioutil.WriteFile(dirs.SnapNamesFile, nil, 0644), IsNil) 194 // but set the timestamp in the future 195 t := time.Now().Add(time.Hour) 196 c.Assert(os.Chtimes(dirs.SnapNamesFile, t, t), IsNil) 197 198 cr7 := snapstate.NewCatalogRefresh(s.state) 199 err := cr7.Ensure() 200 c.Check(err, IsNil) 201 c.Check(s.store.ops, DeepEquals, []string{"sections", "write-catalog"}) 202 }