github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/service/upstart/upstart_test.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package upstart_test 5 6 import ( 7 "fmt" 8 "io/ioutil" 9 "os" 10 "path/filepath" 11 "runtime" 12 "testing" 13 14 jc "github.com/juju/testing/checkers" 15 "github.com/juju/utils" 16 "github.com/juju/utils/symlink" 17 gc "gopkg.in/check.v1" 18 19 "github.com/juju/juju/service/common" 20 "github.com/juju/juju/service/upstart" 21 coretesting "github.com/juju/juju/testing" 22 ) 23 24 func Test(t *testing.T) { 25 if runtime.GOOS == "windows" { 26 t.Skip("Skipping upstart tests on windows") 27 } 28 gc.TestingT(t) 29 } 30 31 type UpstartSuite struct { 32 coretesting.BaseSuite 33 testPath string 34 service *upstart.Service 35 initDir string 36 } 37 38 var _ = gc.Suite(&UpstartSuite{}) 39 40 func (s *UpstartSuite) SetUpTest(c *gc.C) { 41 s.testPath = c.MkDir() 42 s.initDir = c.MkDir() 43 s.PatchEnvPathPrepend(s.testPath) 44 s.PatchValue(&upstart.InitDir, s.initDir) 45 s.service = upstart.NewService( 46 "some-application", 47 common.Conf{ 48 Desc: "some service", 49 ExecStart: "/path/to/some-command", 50 }, 51 ) 52 } 53 54 var checkargs = ` 55 #!/bin/bash --norc 56 if [ "$1" != "--system" ]; then 57 exit 255 58 fi 59 if [ "$2" != "some-application" ]; then 60 exit 255 61 fi 62 if [ "$3" != "" ]; then 63 exit 255 64 fi 65 `[1:] 66 67 func (s *UpstartSuite) MakeTool(c *gc.C, name, script string) { 68 path := filepath.Join(s.testPath, name) 69 err := ioutil.WriteFile(path, []byte(checkargs+script), 0755) 70 c.Assert(err, jc.ErrorIsNil) 71 } 72 73 func (s *UpstartSuite) StoppedStatus(c *gc.C) { 74 s.MakeTool(c, "status", `echo "some-application stop/waiting"`) 75 } 76 77 func (s *UpstartSuite) RunningStatusNoProcessID(c *gc.C) { 78 s.MakeTool(c, "status", `echo "some-application start/running"`) 79 } 80 81 func (s *UpstartSuite) RunningStatusWithProcessID(c *gc.C) { 82 s.MakeTool(c, "status", `echo "some-application start/running, process 123"`) 83 } 84 85 func (s *UpstartSuite) goodInstall(c *gc.C) { 86 s.MakeTool(c, "start", "exit 0") 87 err := s.service.Install() 88 c.Assert(err, jc.ErrorIsNil) 89 } 90 91 func (s *UpstartSuite) TestInstalled(c *gc.C) { 92 installed, err := s.service.Installed() 93 c.Assert(err, jc.ErrorIsNil) 94 c.Check(installed, jc.IsFalse) 95 96 s.goodInstall(c) 97 installed, err = s.service.Installed() 98 c.Assert(err, jc.ErrorIsNil) 99 c.Check(installed, jc.IsTrue) 100 } 101 102 func (s *UpstartSuite) TestExists(c *gc.C) { 103 // Setup creates the file, but it is empty. 104 exists, err := s.service.Exists() 105 c.Assert(err, jc.ErrorIsNil) 106 c.Check(exists, jc.IsFalse) 107 108 s.goodInstall(c) 109 exists, err = s.service.Exists() 110 c.Assert(err, jc.ErrorIsNil) 111 c.Check(exists, jc.IsTrue) 112 } 113 114 func (s *UpstartSuite) TestExistsNonEmpty(c *gc.C) { 115 s.goodInstall(c) 116 s.service.Service.Conf.ExecStart = "/path/to/other-command" 117 118 exists, err := s.service.Exists() 119 c.Assert(err, jc.ErrorIsNil) 120 c.Check(exists, jc.IsFalse) 121 } 122 123 func (s *UpstartSuite) TestRunning(c *gc.C) { 124 s.MakeTool(c, "status", "exit 1") 125 running, err := s.service.Running() 126 c.Assert(err, jc.ErrorIsNil) 127 c.Check(running, jc.IsFalse) 128 129 s.MakeTool(c, "status", `echo "GIBBERISH NONSENSE"`) 130 running, err = s.service.Running() 131 c.Assert(err, jc.ErrorIsNil) 132 c.Check(running, jc.IsFalse) 133 134 s.RunningStatusNoProcessID(c) 135 running, err = s.service.Running() 136 c.Assert(err, jc.ErrorIsNil) 137 c.Check(running, jc.IsTrue) 138 139 s.RunningStatusWithProcessID(c) 140 running, err = s.service.Running() 141 c.Assert(err, jc.ErrorIsNil) 142 c.Check(running, jc.IsTrue) 143 } 144 145 func (s *UpstartSuite) TestStart(c *gc.C) { 146 s.RunningStatusWithProcessID(c) 147 s.MakeTool(c, "start", "exit 99") 148 c.Assert(s.service.Start(), jc.ErrorIsNil) 149 s.StoppedStatus(c) 150 c.Assert(s.service.Start(), gc.ErrorMatches, ".*exit status 99.*") 151 s.MakeTool(c, "start", "exit 0") 152 c.Assert(s.service.Start(), jc.ErrorIsNil) 153 } 154 155 func (s *UpstartSuite) TestStop(c *gc.C) { 156 s.StoppedStatus(c) 157 s.MakeTool(c, "stop", "exit 99") 158 c.Assert(s.service.Stop(), jc.ErrorIsNil) 159 s.RunningStatusWithProcessID(c) 160 c.Assert(s.service.Stop(), gc.ErrorMatches, ".*exit status 99.*") 161 s.MakeTool(c, "stop", "exit 0") 162 c.Assert(s.service.Stop(), jc.ErrorIsNil) 163 } 164 165 func (s *UpstartSuite) TestRemoveMissing(c *gc.C) { 166 err := s.service.Remove() 167 168 c.Check(err, jc.ErrorIsNil) 169 } 170 171 func (s *UpstartSuite) TestRemoveStopped(c *gc.C) { 172 s.goodInstall(c) 173 s.StoppedStatus(c) 174 175 err := s.service.Remove() 176 c.Assert(err, jc.ErrorIsNil) 177 178 filename := filepath.Join(upstart.InitDir, "some-application.conf") 179 _, err = os.Stat(filename) 180 c.Check(err, jc.Satisfies, os.IsNotExist) 181 } 182 183 func (s *UpstartSuite) TestStopRunning(c *gc.C) { 184 s.goodInstall(c) 185 s.RunningStatusWithProcessID(c) 186 s.MakeTool(c, "stop", "exit 99") 187 filename := filepath.Join(upstart.InitDir, "some-application.conf") 188 err := s.service.Stop() 189 c.Assert(err, gc.ErrorMatches, ".*exit status 99.*") 190 191 _, err = os.Stat(filename) 192 c.Assert(err, jc.ErrorIsNil) 193 194 s.MakeTool(c, "stop", "exit 0") 195 err = s.service.Stop() 196 c.Assert(err, jc.ErrorIsNil) 197 } 198 199 func (s *UpstartSuite) TestInstallErrors(c *gc.C) { 200 conf := common.Conf{} 201 check := func(msg string) { 202 c.Assert(s.service.Install(), gc.ErrorMatches, msg) 203 _, err := s.service.InstallCommands() 204 c.Assert(err, gc.ErrorMatches, msg) 205 } 206 s.service.Service.Conf = conf 207 s.service.Service.Name = "" 208 check("missing Name") 209 s.service.Service.Name = "some-application" 210 check("missing Desc") 211 s.service.Service.Conf.Desc = "this is an upstart service" 212 check("missing ExecStart") 213 } 214 215 const expectStart = `description "this is an upstart service" 216 author "Juju Team <juju@lists.ubuntu.com>" 217 start on runlevel [2345] 218 stop on runlevel [!2345] 219 respawn 220 normal exit 0 221 ` 222 223 func (s *UpstartSuite) dummyConf(c *gc.C) common.Conf { 224 return common.Conf{ 225 Desc: "this is an upstart service", 226 ExecStart: "/path/to/some-command x y z", 227 } 228 } 229 230 func (s *UpstartSuite) assertInstall(c *gc.C, conf common.Conf, expectEnd string) { 231 expectContent := expectStart + expectEnd 232 expectPath := filepath.Join(upstart.InitDir, "some-application.conf") 233 234 s.service.Service.Conf = conf 235 svc := s.service 236 cmds, err := s.service.InstallCommands() 237 c.Assert(err, jc.ErrorIsNil) 238 c.Assert(cmds, gc.DeepEquals, []string{ 239 "cat > " + expectPath + " << 'EOF'\n" + expectContent + "EOF\n", 240 }) 241 cmds, err = s.service.StartCommands() 242 c.Assert(err, jc.ErrorIsNil) 243 c.Assert(cmds, gc.DeepEquals, []string{ 244 "start some-application", 245 }) 246 247 s.MakeTool(c, "status", `echo "some-application stop/waiting"`) 248 s.MakeTool(c, "start", "exit 99") 249 err = svc.Install() 250 c.Assert(err, jc.ErrorIsNil) 251 err = svc.Start() 252 c.Assert(err, gc.ErrorMatches, ".*exit status 99.*") 253 254 s.MakeTool(c, "start", "exit 0") 255 err = svc.Install() 256 c.Assert(err, jc.ErrorIsNil) 257 err = svc.Start() 258 c.Assert(err, jc.ErrorIsNil) 259 260 content, err := ioutil.ReadFile(expectPath) 261 c.Assert(err, jc.ErrorIsNil) 262 c.Assert(string(content), gc.Equals, expectContent) 263 } 264 265 func (s *UpstartSuite) TestInstallSimple(c *gc.C) { 266 conf := s.dummyConf(c) 267 s.assertInstall(c, conf, ` 268 269 script 270 271 272 exec /path/to/some-command x y z 273 end script 274 `) 275 } 276 277 func (s *UpstartSuite) TestInstallExtraScript(c *gc.C) { 278 conf := s.dummyConf(c) 279 conf.ExtraScript = "extra lines of script" 280 s.assertInstall(c, conf, ` 281 282 script 283 extra lines of script 284 285 exec /path/to/some-command x y z 286 end script 287 `) 288 } 289 290 func (s *UpstartSuite) TestInstallLogfile(c *gc.C) { 291 conf := s.dummyConf(c) 292 conf.Logfile = "/some/output/path" 293 s.assertInstall(c, conf, ` 294 295 script 296 297 298 # Ensure log files are properly protected 299 touch /some/output/path 300 chown syslog:syslog /some/output/path 301 chmod 0600 /some/output/path 302 303 exec /path/to/some-command x y z >> /some/output/path 2>&1 304 end script 305 `) 306 } 307 308 func (s *UpstartSuite) TestInstallEnv(c *gc.C) { 309 conf := s.dummyConf(c) 310 conf.Env = map[string]string{"FOO": "bar baz", "QUX": "ping pong"} 311 s.assertInstall(c, conf, `env FOO="bar baz" 312 env QUX="ping pong" 313 314 315 script 316 317 318 exec /path/to/some-command x y z 319 end script 320 `) 321 } 322 323 func (s *UpstartSuite) TestInstallLimit(c *gc.C) { 324 conf := s.dummyConf(c) 325 conf.Limit = map[string]string{ 326 "nofile": "65000", 327 "nproc": "20000", 328 } 329 s.assertInstall(c, conf, ` 330 limit nofile 65000 65000 331 limit nproc 20000 20000 332 333 script 334 335 336 exec /path/to/some-command x y z 337 end script 338 `) 339 } 340 341 func (s *UpstartSuite) TestInstallAlreadyRunning(c *gc.C) { 342 pathTo := func(name string) string { 343 return filepath.Join(s.testPath, name) 344 } 345 s.MakeTool(c, "status-stopped", `echo "some-application stop/waiting"`) 346 s.MakeTool(c, "status-started", `echo "some-application start/running, process 123"`) 347 s.MakeTool(c, "stop", fmt.Sprintf( 348 "rm %s; ln -s %s %s", 349 pathTo("status"), pathTo("status-stopped"), pathTo("status"), 350 )) 351 s.MakeTool(c, "start", fmt.Sprintf( 352 "rm %s; ln -s %s %s", 353 pathTo("status"), pathTo("status-started"), pathTo("status"), 354 )) 355 err := symlink.New(pathTo("status-started"), pathTo("status")) 356 c.Assert(err, jc.ErrorIsNil) 357 358 svc := upstart.NewService("some-application", s.dummyConf(c)) 359 err = svc.Install() 360 c.Assert(err, jc.ErrorIsNil) 361 installed, err := svc.Running() 362 c.Assert(err, jc.ErrorIsNil) 363 c.Check(installed, jc.IsTrue) 364 } 365 366 type IsRunningSuite struct { 367 coretesting.BaseSuite 368 } 369 370 var _ = gc.Suite(&IsRunningSuite{}) 371 372 const modeExecutable = 0500 373 const modeNotExecutable = 0400 374 375 // createInitctl creates a dummy initctl which returns the given 376 // exitcode and patches the upstart package to use it. 377 func (s *IsRunningSuite) createInitctl(c *gc.C, stderr string, exitcode int, mode os.FileMode) { 378 path := filepath.Join(c.MkDir(), "initctl") 379 var body string 380 if stderr != "" { 381 // Write to stderr. 382 body = ">&2 echo " + utils.ShQuote(stderr) 383 } 384 script := fmt.Sprintf(` 385 #!/usr/bin/env bash 386 %s 387 exit %d 388 `[1:], body, exitcode) 389 c.Logf(script) 390 err := ioutil.WriteFile(path, []byte(script), mode) 391 c.Assert(err, jc.ErrorIsNil) 392 s.PatchValue(upstart.InitctlPath, path) 393 } 394 395 func (s *IsRunningSuite) TestUpstartInstalled(c *gc.C) { 396 s.createInitctl(c, "", 0, modeExecutable) 397 398 isUpstart, err := upstart.IsRunning() 399 c.Assert(isUpstart, jc.IsTrue) 400 c.Assert(err, jc.ErrorIsNil) 401 } 402 403 func (s *IsRunningSuite) TestUpstartNotInstalled(c *gc.C) { 404 s.PatchValue(upstart.InitctlPath, "/foo/bar/not-exist") 405 406 isUpstart, err := upstart.IsRunning() 407 c.Assert(isUpstart, jc.IsFalse) 408 c.Assert(err, jc.ErrorIsNil) 409 } 410 411 func (s *IsRunningSuite) TestUpstartInstalledButBroken(c *gc.C) { 412 const stderr = "<something broke>" 413 const errorCode = 99 414 s.createInitctl(c, stderr, errorCode, modeExecutable) 415 416 isUpstart, err := upstart.IsRunning() 417 c.Assert(isUpstart, jc.IsFalse) 418 c.Assert(err, gc.ErrorMatches, fmt.Sprintf(".*exit status %d", errorCode)) 419 } 420 421 func (s *IsRunningSuite) TestUpstartInstalledButNotRunning(c *gc.C) { 422 const stderr = `Name "com.ubuntu.Upstart" does not exist` 423 const errorCode = 1 424 s.createInitctl(c, stderr, errorCode, modeExecutable) 425 426 isUpstart, err := upstart.IsRunning() 427 c.Assert(isUpstart, jc.IsFalse) 428 c.Assert(err, gc.ErrorMatches, fmt.Sprintf(".*exit status %d", errorCode)) 429 } 430 431 func (s *IsRunningSuite) TestInitctlCantBeRun(c *gc.C) { 432 s.createInitctl(c, "", 0, modeNotExecutable) 433 434 isUpstart, err := upstart.IsRunning() 435 c.Assert(isUpstart, jc.IsFalse) 436 c.Assert(err, gc.ErrorMatches, ".+: permission denied") 437 }