github.com/rigado/snapd@v2.42.5-go-mod+incompatible/overlord/configstate/configcore/watchdog_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 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 configcore_test 21 22 import ( 23 "fmt" 24 "io/ioutil" 25 "os" 26 "path/filepath" 27 "time" 28 29 . "gopkg.in/check.v1" 30 31 "github.com/snapcore/snapd/dirs" 32 "github.com/snapcore/snapd/osutil" 33 "github.com/snapcore/snapd/overlord/configstate/configcore" 34 "github.com/snapcore/snapd/release" 35 "github.com/snapcore/snapd/testutil" 36 ) 37 38 type watchdogSuite struct { 39 configcoreSuite 40 41 mockEtcEnvironment string 42 } 43 44 var _ = Suite(&watchdogSuite{}) 45 46 func (s *watchdogSuite) SetUpTest(c *C) { 47 s.configcoreSuite.SetUpTest(c) 48 49 dirs.SetRootDir(c.MkDir()) 50 s.mockEtcEnvironment = filepath.Join(dirs.SnapSystemdConfDir, "10-snapd-watchdog.conf") 51 err := os.MkdirAll(dirs.SnapSystemdConfDir, 0755) 52 c.Assert(err, IsNil) 53 } 54 55 func (s *watchdogSuite) TearDownTest(c *C) { 56 dirs.SetRootDir("/") 57 } 58 59 func (s *watchdogSuite) TestConfigureWatchdog(c *C) { 60 restore := release.MockOnClassic(false) 61 defer restore() 62 63 for option, val := range map[string]string{"runtime-timeout": "10", "shutdown-timeout": "60"} { 64 65 err := configcore.Run(&mockConf{ 66 state: s.state, 67 conf: map[string]interface{}{ 68 fmt.Sprintf("watchdog.%s", option): val + "s", 69 }, 70 }) 71 c.Assert(err, IsNil) 72 73 var systemdOption string 74 switch option { 75 case "runtime-timeout": 76 systemdOption = "RuntimeWatchdogSec" 77 case "shutdown-timeout": 78 systemdOption = "ShutdownWatchdogSec" 79 } 80 c.Check(s.mockEtcEnvironment, testutil.FileEquals, 81 fmt.Sprintf("[Manager]\n%s=%s\n", systemdOption, val)) 82 } 83 } 84 85 func (s *watchdogSuite) TestConfigureWatchdogUnits(c *C) { 86 restore := release.MockOnClassic(false) 87 defer restore() 88 89 times := []int{56, 432} 90 type timeUnit struct { 91 unit string 92 toSec int 93 } 94 95 for _, tunit := range []timeUnit{{"s", 1}, {"m", 60}, {"h", 3600}} { 96 err := configcore.Run(&mockConf{ 97 state: s.state, 98 conf: map[string]interface{}{ 99 "watchdog.runtime-timeout": fmt.Sprintf("%d", times[0]) + tunit.unit, 100 "watchdog.shutdown-timeout": fmt.Sprintf("%d", times[1]) + tunit.unit, 101 }, 102 }) 103 c.Assert(err, IsNil) 104 c.Check(s.mockEtcEnvironment, testutil.FileEquals, "[Manager]\n"+ 105 fmt.Sprintf("RuntimeWatchdogSec=%d\n", times[0]*tunit.toSec)+ 106 fmt.Sprintf("ShutdownWatchdogSec=%d\n", times[1]*tunit.toSec)) 107 } 108 } 109 110 func (s *watchdogSuite) TestConfigureWatchdogAll(c *C) { 111 restore := release.MockOnClassic(false) 112 defer restore() 113 114 times := []int{10, 100} 115 err := configcore.Run(&mockConf{ 116 state: s.state, 117 conf: map[string]interface{}{ 118 "watchdog.runtime-timeout": fmt.Sprintf("%ds", times[0]), 119 "watchdog.shutdown-timeout": fmt.Sprintf("%ds", times[1]), 120 }, 121 }) 122 c.Assert(err, IsNil) 123 c.Check(s.mockEtcEnvironment, testutil.FileEquals, "[Manager]\n"+ 124 fmt.Sprintf("RuntimeWatchdogSec=%d\n", times[0])+ 125 fmt.Sprintf("ShutdownWatchdogSec=%d\n", times[1])) 126 } 127 128 func (s *watchdogSuite) TestConfigureWatchdogBadFormat(c *C) { 129 restore := release.MockOnClassic(false) 130 defer restore() 131 132 type badValErr struct { 133 val string 134 err string 135 } 136 for _, badVal := range []badValErr{{"BAD", ".*invalid duration.*"}, 137 {"-5s", ".*negative duration.*"}, 138 {"34k", ".*unknown unit.*"}} { 139 err := configcore.Run(&mockConf{ 140 state: s.state, 141 conf: map[string]interface{}{ 142 "watchdog.runtime-timeout": badVal.val, 143 }, 144 }) 145 c.Assert(err, ErrorMatches, badVal.err) 146 } 147 } 148 149 func (s *watchdogSuite) TestConfigureWatchdogNoFileUpdate(c *C) { 150 restore := release.MockOnClassic(false) 151 defer restore() 152 153 times := []int{10, 100} 154 content := "[Manager]\n" + 155 fmt.Sprintf("RuntimeWatchdogSec=%d\n", times[0]) + 156 fmt.Sprintf("ShutdownWatchdogSec=%d\n", times[1]) 157 err := ioutil.WriteFile(s.mockEtcEnvironment, []byte(content), 0644) 158 c.Assert(err, IsNil) 159 160 info, err := os.Stat(s.mockEtcEnvironment) 161 c.Assert(err, IsNil) 162 163 fileModTime := info.ModTime() 164 165 // To make sure the times will defer if the file is newly written 166 time.Sleep(100 * time.Millisecond) 167 168 err = configcore.Run(&mockConf{ 169 state: s.state, 170 conf: map[string]interface{}{ 171 "watchdog.runtime-timeout": fmt.Sprintf("%ds", times[0]), 172 "watchdog.shutdown-timeout": fmt.Sprintf("%ds", times[1]), 173 }, 174 }) 175 c.Assert(err, IsNil) 176 c.Check(s.mockEtcEnvironment, testutil.FileEquals, content) 177 178 info, err = os.Stat(s.mockEtcEnvironment) 179 c.Assert(err, IsNil) 180 c.Assert(info.ModTime(), Equals, fileModTime) 181 } 182 183 func (s *watchdogSuite) TestConfigureWatchdogRemovesIfEmpty(c *C) { 184 restore := release.MockOnClassic(false) 185 defer restore() 186 187 // add canary to ensure we don't touch other files 188 canary := filepath.Join(dirs.SnapSystemdConfDir, "05-canary.conf") 189 err := ioutil.WriteFile(canary, nil, 0644) 190 c.Assert(err, IsNil) 191 192 content := `[Manager] 193 RuntimeWatchdogSec=10 194 ShutdownWatchdogSec=20 195 ` 196 err = ioutil.WriteFile(s.mockEtcEnvironment, []byte(content), 0644) 197 c.Assert(err, IsNil) 198 199 err = configcore.Run(&mockConf{ 200 state: s.state, 201 conf: map[string]interface{}{ 202 "watchdog.runtime-timeout": 0, 203 "watchdog.shutdown-timeout": 0, 204 }, 205 }) 206 c.Assert(err, IsNil) 207 208 // ensure the file got deleted 209 c.Check(osutil.FileExists(s.mockEtcEnvironment), Equals, false) 210 // but the canary is still here 211 c.Check(osutil.FileExists(canary), Equals, true) 212 }