github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/overlord/snapstate/refresh_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2019 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 . "gopkg.in/check.v1" 24 25 "github.com/snapcore/snapd/dirs" 26 "github.com/snapcore/snapd/overlord/snapstate" 27 "github.com/snapcore/snapd/overlord/state" 28 "github.com/snapcore/snapd/snap" 29 "github.com/snapcore/snapd/snap/snaptest" 30 "github.com/snapcore/snapd/testutil" 31 ) 32 33 type refreshSuite struct { 34 testutil.BaseTest 35 state *state.State 36 info *snap.Info 37 pids map[string][]int 38 } 39 40 var _ = Suite(&refreshSuite{}) 41 42 func (s *refreshSuite) SetUpTest(c *C) { 43 dirs.SetRootDir(c.MkDir()) 44 yamlText := ` 45 name: pkg 46 version: 1 47 apps: 48 daemon: 49 command: dummy 50 daemon: simple 51 app: 52 command: dummy 53 hooks: 54 configure: 55 ` 56 s.info = snaptest.MockInfo(c, yamlText, nil) 57 s.pids = nil 58 restore := snapstate.MockPidsOfSnap(func(instanceName string) (map[string][]int, error) { 59 c.Assert(instanceName, Equals, s.info.InstanceName()) 60 return s.pids, nil 61 }) 62 s.AddCleanup(restore) 63 s.AddCleanup(func() { dirs.SetRootDir("") }) 64 } 65 66 func (s *refreshSuite) TestSoftNothingRunningRefreshCheck(c *C) { 67 // Services are not blocking soft refresh check, 68 // they will be stopped before refresh. 69 s.pids = map[string][]int{ 70 "snap.pkg.daemon": {100}, 71 } 72 err := snapstate.SoftNothingRunningRefreshCheck(s.info) 73 c.Check(err, IsNil) 74 75 // Apps are blocking soft refresh check. They are not stopped by 76 // snapd, unless the app is running for longer than the maximum 77 // duration allowed for postponing refreshes. 78 s.pids = map[string][]int{ 79 "snap.pkg.daemon": {100}, 80 "snap.pkg.app": {101}, 81 } 82 err = snapstate.SoftNothingRunningRefreshCheck(s.info) 83 c.Assert(err, NotNil) 84 c.Check(err.Error(), Equals, `snap "pkg" has running apps (app)`) 85 c.Check(err.(*snapstate.BusySnapError).Pids(), DeepEquals, []int{101}) 86 87 // Hooks behave just like apps. IDEA: perhaps hooks should not be 88 // killed this way? They have their own life-cycle management. 89 s.pids = map[string][]int{ 90 "snap.pkg.hook.configure": {105}, 91 } 92 err = snapstate.SoftNothingRunningRefreshCheck(s.info) 93 c.Assert(err, NotNil) 94 c.Check(err.Error(), Equals, `snap "pkg" has running hooks (configure)`) 95 c.Check(err.(*snapstate.BusySnapError).Pids(), DeepEquals, []int{105}) 96 97 // Both apps and hooks can be running. 98 s.pids = map[string][]int{ 99 "snap.pkg.hook.configure": {105}, 100 "snap.pkg.app": {106}, 101 } 102 err = snapstate.SoftNothingRunningRefreshCheck(s.info) 103 c.Assert(err, NotNil) 104 c.Check(err.Error(), Equals, `snap "pkg" has running apps (app) and hooks (configure)`) 105 c.Check(err.(*snapstate.BusySnapError).Pids(), DeepEquals, []int{105, 106}) 106 } 107 108 func (s *refreshSuite) TestHardNothingRunningRefreshCheck(c *C) { 109 // Regular services are blocking hard refresh check. 110 // We were expecting them to be gone by now. 111 s.pids = map[string][]int{ 112 "snap.pkg.daemon": {100}, 113 } 114 err := snapstate.HardNothingRunningRefreshCheck(s.info) 115 c.Assert(err, NotNil) 116 c.Check(err.Error(), Equals, `snap "pkg" has running apps (daemon)`) 117 c.Check(err.(*snapstate.BusySnapError).Pids(), DeepEquals, []int{100}) 118 119 // When the service is supposed to endure refreshes it will not be 120 // stopped. As such such services cannot block refresh. 121 s.info.Apps["daemon"].RefreshMode = "endure" 122 err = snapstate.HardNothingRunningRefreshCheck(s.info) 123 c.Check(err, IsNil) 124 s.info.Apps["daemon"].RefreshMode = "" 125 126 // Applications are also blocking hard refresh check. 127 s.pids = map[string][]int{ 128 "snap.pkg.app": {101}, 129 } 130 err = snapstate.HardNothingRunningRefreshCheck(s.info) 131 c.Assert(err, NotNil) 132 c.Check(err.Error(), Equals, `snap "pkg" has running apps (app)`) 133 c.Assert(err, FitsTypeOf, &snapstate.BusySnapError{}) 134 c.Check(err.(*snapstate.BusySnapError).Pids(), DeepEquals, []int{101}) 135 136 // Hooks are equally blocking hard refresh check. 137 s.pids = map[string][]int{ 138 "snap.pkg.hook.configure": {105}, 139 } 140 err = snapstate.HardNothingRunningRefreshCheck(s.info) 141 c.Assert(err, NotNil) 142 c.Check(err.Error(), Equals, `snap "pkg" has running hooks (configure)`) 143 c.Check(err.(*snapstate.BusySnapError).Pids(), DeepEquals, []int{105}) 144 }