github.com/Lephar/snapd@v0.0.0-20210825215435-c7fba9cef4d2/cmd/snap-exec/main_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016 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 main_test 21 22 import ( 23 "fmt" 24 "io/ioutil" 25 "os" 26 "os/exec" 27 "path/filepath" 28 "testing" 29 30 . "gopkg.in/check.v1" 31 32 snapExec "github.com/snapcore/snapd/cmd/snap-exec" 33 "github.com/snapcore/snapd/dirs" 34 "github.com/snapcore/snapd/osutil" 35 "github.com/snapcore/snapd/release" 36 "github.com/snapcore/snapd/snap" 37 "github.com/snapcore/snapd/snap/snaptest" 38 "github.com/snapcore/snapd/testutil" 39 ) 40 41 // Hook up check.v1 into the "go test" runner 42 func Test(t *testing.T) { TestingT(t) } 43 44 type snapExecSuite struct{} 45 46 var _ = Suite(&snapExecSuite{}) 47 48 func (s *snapExecSuite) SetUpTest(c *C) { 49 // clean previous parse runs 50 snapExec.SetOptsCommand("") 51 snapExec.SetOptsHook("") 52 } 53 54 func (s *snapExecSuite) TearDown(c *C) { 55 dirs.SetRootDir("/") 56 } 57 58 var mockYaml = []byte(`name: snapname 59 version: 1.0 60 apps: 61 app: 62 command: run-app cmd-arg1 $SNAP_DATA 63 stop-command: stop-app 64 post-stop-command: post-stop-app 65 completer: you/complete/me 66 environment: 67 BASE_PATH: /some/path 68 LD_LIBRARY_PATH: ${BASE_PATH}/lib 69 MY_PATH: $PATH 70 TEST_PATH: /custom 71 app2: 72 command: run-app2 73 stop-command: stop-app2 74 post-stop-command: post-stop-app2 75 command-chain: [chain1, chain2] 76 nostop: 77 command: nostop 78 `) 79 80 var mockClassicYaml = append([]byte("confinement: classic\n"), mockYaml...) 81 82 var mockHookYaml = []byte(`name: snapname 83 version: 1.0 84 hooks: 85 configure: 86 `) 87 88 var mockHookCommandChainYaml = []byte(`name: snapname 89 version: 1.0 90 hooks: 91 configure: 92 command-chain: [chain1, chain2] 93 `) 94 95 var binaryTemplate = `#!/bin/sh 96 echo "$(basename $0)" >> %[1]q 97 for arg in "$@"; do 98 echo "$arg" >> %[1]q 99 done 100 printf "\n" >> %[1]q` 101 102 func (s *snapExecSuite) TestInvalidCombinedParameters(c *C) { 103 invalidParameters := []string{"--hook=hook-name", "--command=command-name", "snap-name"} 104 _, _, err := snapExec.ParseArgs(invalidParameters) 105 c.Check(err, ErrorMatches, ".*cannot use --hook and --command together.*") 106 } 107 108 func (s *snapExecSuite) TestInvalidExtraParameters(c *C) { 109 invalidParameters := []string{"--hook=hook-name", "snap-name", "foo", "bar"} 110 _, _, err := snapExec.ParseArgs(invalidParameters) 111 c.Check(err, ErrorMatches, ".*too many arguments for hook \"hook-name\": snap-name foo bar.*") 112 } 113 114 func (s *snapExecSuite) TestFindCommand(c *C) { 115 info, err := snap.InfoFromSnapYaml(mockYaml) 116 c.Assert(err, IsNil) 117 118 for _, t := range []struct { 119 cmd string 120 expected string 121 }{ 122 {cmd: "", expected: `run-app cmd-arg1 $SNAP_DATA`}, 123 {cmd: "stop", expected: "stop-app"}, 124 {cmd: "post-stop", expected: "post-stop-app"}, 125 } { 126 cmd, err := snapExec.FindCommand(info.Apps["app"], t.cmd) 127 c.Check(err, IsNil) 128 c.Check(cmd, Equals, t.expected) 129 } 130 } 131 132 func (s *snapExecSuite) TestFindCommandInvalidCommand(c *C) { 133 info, err := snap.InfoFromSnapYaml(mockYaml) 134 c.Assert(err, IsNil) 135 136 _, err = snapExec.FindCommand(info.Apps["app"], "xxx") 137 c.Check(err, ErrorMatches, `cannot use "xxx" command`) 138 } 139 140 func (s *snapExecSuite) TestFindCommandNoCommand(c *C) { 141 info, err := snap.InfoFromSnapYaml(mockYaml) 142 c.Assert(err, IsNil) 143 144 _, err = snapExec.FindCommand(info.Apps["nostop"], "stop") 145 c.Check(err, ErrorMatches, `no "stop" command found for "nostop"`) 146 } 147 148 func (s *snapExecSuite) TestSnapExecAppIntegration(c *C) { 149 dirs.SetRootDir(c.MkDir()) 150 snaptest.MockSnap(c, string(mockYaml), &snap.SideInfo{ 151 Revision: snap.R("42"), 152 }) 153 154 execArgv0 := "" 155 execArgs := []string{} 156 execEnv := []string{} 157 restore := snapExec.MockSyscallExec(func(argv0 string, argv []string, env []string) error { 158 execArgv0 = argv0 159 execArgs = argv 160 execEnv = env 161 return nil 162 }) 163 defer restore() 164 165 // FIXME: TEST_PATH was meant to be just PATH but this uncovers another 166 // bug in the test suite where mocking binaries misbehaves. 167 oldPath := os.Getenv("TEST_PATH") 168 os.Setenv("TEST_PATH", "/vanilla") 169 defer os.Setenv("TEST_PATH", oldPath) 170 171 // launch and verify its run the right way 172 err := snapExec.ExecApp("snapname.app", "42", "stop", []string{"arg1", "arg2"}) 173 c.Assert(err, IsNil) 174 c.Check(execArgv0, Equals, fmt.Sprintf("%s/snapname/42/stop-app", dirs.SnapMountDir)) 175 c.Check(execArgs, DeepEquals, []string{execArgv0, "arg1", "arg2"}) 176 c.Check(execEnv, testutil.Contains, "BASE_PATH=/some/path") 177 c.Check(execEnv, testutil.Contains, "LD_LIBRARY_PATH=/some/path/lib") 178 c.Check(execEnv, testutil.Contains, fmt.Sprintf("MY_PATH=%s", os.Getenv("PATH"))) 179 // TEST_PATH is properly handled and we only see one value, /custom, defined 180 // as an app-specific override. 181 // See also https://bugs.launchpad.net/snapd/+bug/1860369 182 c.Check(execEnv, Not(testutil.Contains), "TEST_PATH=/vanilla") 183 c.Check(execEnv, testutil.Contains, "TEST_PATH=/custom") 184 } 185 186 func (s *snapExecSuite) TestSnapExecAppCommandChainIntegration(c *C) { 187 dirs.SetRootDir(c.MkDir()) 188 snaptest.MockSnap(c, string(mockYaml), &snap.SideInfo{ 189 Revision: snap.R("42"), 190 }) 191 192 execArgv0 := "" 193 execArgs := []string{} 194 restore := snapExec.MockSyscallExec(func(argv0 string, argv []string, env []string) error { 195 execArgv0 = argv0 196 execArgs = argv 197 return nil 198 }) 199 defer restore() 200 201 chain1_path := fmt.Sprintf("%s/snapname/42/chain1", dirs.SnapMountDir) 202 chain2_path := fmt.Sprintf("%s/snapname/42/chain2", dirs.SnapMountDir) 203 app_path := fmt.Sprintf("%s/snapname/42/run-app2", dirs.SnapMountDir) 204 stop_path := fmt.Sprintf("%s/snapname/42/stop-app2", dirs.SnapMountDir) 205 post_stop_path := fmt.Sprintf("%s/snapname/42/post-stop-app2", dirs.SnapMountDir) 206 207 for _, t := range []struct { 208 cmd string 209 args []string 210 expected []string 211 }{ 212 // Normal command 213 {expected: []string{chain1_path, chain2_path, app_path}}, 214 {args: []string{"arg1", "arg2"}, expected: []string{chain1_path, chain2_path, app_path, "arg1", "arg2"}}, 215 216 // Stop command 217 {cmd: "stop", expected: []string{chain1_path, chain2_path, stop_path}}, 218 {cmd: "stop", args: []string{"arg1", "arg2"}, expected: []string{chain1_path, chain2_path, stop_path, "arg1", "arg2"}}, 219 220 // Post-stop command 221 {cmd: "post-stop", expected: []string{chain1_path, chain2_path, post_stop_path}}, 222 {cmd: "post-stop", args: []string{"arg1", "arg2"}, expected: []string{chain1_path, chain2_path, post_stop_path, "arg1", "arg2"}}, 223 } { 224 err := snapExec.ExecApp("snapname.app2", "42", t.cmd, t.args) 225 c.Assert(err, IsNil) 226 c.Check(execArgv0, Equals, t.expected[0]) 227 c.Check(execArgs, DeepEquals, t.expected) 228 } 229 } 230 231 func (s *snapExecSuite) TestSnapExecHookIntegration(c *C) { 232 dirs.SetRootDir(c.MkDir()) 233 snaptest.MockSnap(c, string(mockHookYaml), &snap.SideInfo{ 234 Revision: snap.R("42"), 235 }) 236 237 execArgv0 := "" 238 execArgs := []string{} 239 restore := snapExec.MockSyscallExec(func(argv0 string, argv []string, env []string) error { 240 execArgv0 = argv0 241 execArgs = argv 242 return nil 243 }) 244 defer restore() 245 246 // launch and verify it ran correctly 247 err := snapExec.ExecHook("snapname", "42", "configure") 248 c.Assert(err, IsNil) 249 c.Check(execArgv0, Equals, fmt.Sprintf("%s/snapname/42/meta/hooks/configure", dirs.SnapMountDir)) 250 c.Check(execArgs, DeepEquals, []string{execArgv0}) 251 } 252 253 func (s *snapExecSuite) TestSnapExecHookCommandChainIntegration(c *C) { 254 dirs.SetRootDir(c.MkDir()) 255 snaptest.MockSnap(c, string(mockHookCommandChainYaml), &snap.SideInfo{ 256 Revision: snap.R("42"), 257 }) 258 259 execArgv0 := "" 260 execArgs := []string{} 261 restore := snapExec.MockSyscallExec(func(argv0 string, argv []string, env []string) error { 262 execArgv0 = argv0 263 execArgs = argv 264 return nil 265 }) 266 defer restore() 267 268 chain1_path := fmt.Sprintf("%s/snapname/42/chain1", dirs.SnapMountDir) 269 chain2_path := fmt.Sprintf("%s/snapname/42/chain2", dirs.SnapMountDir) 270 hook_path := fmt.Sprintf("%s/snapname/42/meta/hooks/configure", dirs.SnapMountDir) 271 272 err := snapExec.ExecHook("snapname", "42", "configure") 273 c.Assert(err, IsNil) 274 c.Check(execArgv0, Equals, chain1_path) 275 c.Check(execArgs, DeepEquals, []string{chain1_path, chain2_path, hook_path}) 276 } 277 278 func (s *snapExecSuite) TestSnapExecHookMissingHookIntegration(c *C) { 279 dirs.SetRootDir(c.MkDir()) 280 snaptest.MockSnap(c, string(mockHookYaml), &snap.SideInfo{ 281 Revision: snap.R("42"), 282 }) 283 284 err := snapExec.ExecHook("snapname", "42", "missing-hook") 285 c.Assert(err, NotNil) 286 c.Assert(err, ErrorMatches, "cannot find hook \"missing-hook\" in \"snapname\"") 287 } 288 289 func (s *snapExecSuite) TestSnapExecIgnoresUnknownArgs(c *C) { 290 snapApp, rest, err := snapExec.ParseArgs([]string{"--command=shell", "snapname.app", "--arg1", "arg2"}) 291 c.Assert(err, IsNil) 292 c.Assert(snapExec.GetOptsCommand(), Equals, "shell") 293 c.Assert(snapApp, DeepEquals, "snapname.app") 294 c.Assert(rest, DeepEquals, []string{"--arg1", "arg2"}) 295 } 296 297 func (s *snapExecSuite) TestSnapExecErrorsOnUnknown(c *C) { 298 _, _, err := snapExec.ParseArgs([]string{"--command=shell", "--unknown", "snapname.app", "--arg1", "arg2"}) 299 c.Check(err, ErrorMatches, "unknown flag `unknown'") 300 } 301 302 func (s *snapExecSuite) TestSnapExecErrorsOnMissingSnapApp(c *C) { 303 _, _, err := snapExec.ParseArgs([]string{"--command=shell"}) 304 c.Check(err, ErrorMatches, "need the application to run as argument") 305 } 306 307 func (s *snapExecSuite) TestSnapExecAppRealIntegration(c *C) { 308 // we need a lot of mocks 309 dirs.SetRootDir(c.MkDir()) 310 311 oldOsArgs := os.Args 312 defer func() { os.Args = oldOsArgs }() 313 314 os.Setenv("SNAP_REVISION", "42") 315 defer os.Unsetenv("SNAP_REVISION") 316 317 snaptest.MockSnap(c, string(mockYaml), &snap.SideInfo{ 318 Revision: snap.R("42"), 319 }) 320 321 canaryFile := filepath.Join(c.MkDir(), "canary.txt") 322 script := fmt.Sprintf("%s/snapname/42/run-app", dirs.SnapMountDir) 323 err := ioutil.WriteFile(script, []byte(fmt.Sprintf(binaryTemplate, canaryFile)), 0755) 324 c.Assert(err, IsNil) 325 326 // we can not use the real syscall.execv here because it would 327 // replace the entire test :) 328 restore := snapExec.MockSyscallExec(actuallyExec) 329 defer restore() 330 331 // run it 332 os.Args = []string{"snap-exec", "snapname.app", "foo", "--bar=baz", "foobar"} 333 err = snapExec.Run() 334 c.Assert(err, IsNil) 335 336 c.Assert(canaryFile, testutil.FileEquals, `run-app 337 cmd-arg1 338 foo 339 --bar=baz 340 foobar 341 342 `) 343 } 344 345 func (s *snapExecSuite) TestSnapExecHookRealIntegration(c *C) { 346 // we need a lot of mocks 347 dirs.SetRootDir(c.MkDir()) 348 349 oldOsArgs := os.Args 350 defer func() { os.Args = oldOsArgs }() 351 352 os.Setenv("SNAP_REVISION", "42") 353 defer os.Unsetenv("SNAP_REVISION") 354 355 canaryFile := filepath.Join(c.MkDir(), "canary.txt") 356 357 testSnap := snaptest.MockSnap(c, string(mockHookYaml), &snap.SideInfo{ 358 Revision: snap.R("42"), 359 }) 360 hookPath := filepath.Join("meta", "hooks", "configure") 361 hookPathAndContents := []string{hookPath, fmt.Sprintf(binaryTemplate, canaryFile)} 362 snaptest.PopulateDir(testSnap.MountDir(), [][]string{hookPathAndContents}) 363 hookPath = filepath.Join(testSnap.MountDir(), hookPath) 364 c.Assert(os.Chmod(hookPath, 0755), IsNil) 365 366 // we can not use the real syscall.execv here because it would 367 // replace the entire test :) 368 restore := snapExec.MockSyscallExec(actuallyExec) 369 defer restore() 370 371 // run it 372 os.Args = []string{"snap-exec", "--hook=configure", "snapname"} 373 err := snapExec.Run() 374 c.Assert(err, IsNil) 375 376 c.Assert(canaryFile, testutil.FileEquals, "configure\n\n") 377 } 378 379 func actuallyExec(argv0 string, argv []string, env []string) error { 380 cmd := exec.Command(argv[0], argv[1:]...) 381 cmd.Env = env 382 output, err := cmd.CombinedOutput() 383 if len(output) > 0 { 384 return fmt.Errorf("Expected output length to be 0, it was %d", len(output)) 385 } 386 return err 387 } 388 389 func (s *snapExecSuite) TestSnapExecShellIntegration(c *C) { 390 dirs.SetRootDir(c.MkDir()) 391 snaptest.MockSnap(c, string(mockYaml), &snap.SideInfo{ 392 Revision: snap.R("42"), 393 }) 394 395 execArgv0 := "" 396 execArgs := []string{} 397 execEnv := []string{} 398 restore := snapExec.MockSyscallExec(func(argv0 string, argv []string, env []string) error { 399 execArgv0 = argv0 400 execArgs = argv 401 execEnv = env 402 return nil 403 }) 404 defer restore() 405 406 // launch and verify its run the right way 407 err := snapExec.ExecApp("snapname.app", "42", "shell", []string{"-c", "echo foo"}) 408 c.Assert(err, IsNil) 409 c.Check(execArgv0, Equals, "/bin/bash") 410 c.Check(execArgs, DeepEquals, []string{execArgv0, "-c", "echo foo"}) 411 c.Check(execEnv, testutil.Contains, "LD_LIBRARY_PATH=/some/path/lib") 412 413 // launch and verify shell still runs the command chain 414 err = snapExec.ExecApp("snapname.app2", "42", "shell", []string{"-c", "echo foo"}) 415 c.Assert(err, IsNil) 416 chain1 := fmt.Sprintf("%s/snapname/42/chain1", dirs.SnapMountDir) 417 chain2 := fmt.Sprintf("%s/snapname/42/chain2", dirs.SnapMountDir) 418 c.Check(execArgv0, Equals, chain1) 419 c.Check(execArgs, DeepEquals, []string{chain1, chain2, "/bin/bash", "-c", "echo foo"}) 420 } 421 422 func (s *snapExecSuite) TestSnapExecAppIntegrationWithVars(c *C) { 423 dirs.SetRootDir(c.MkDir()) 424 snaptest.MockSnap(c, string(mockYaml), &snap.SideInfo{ 425 Revision: snap.R("42"), 426 }) 427 428 execArgv0 := "" 429 execArgs := []string{} 430 execEnv := []string{} 431 restore := snapExec.MockSyscallExec(func(argv0 string, argv []string, env []string) error { 432 execArgv0 = argv0 433 execArgs = argv 434 execEnv = env 435 return nil 436 }) 437 defer restore() 438 439 // setup env 440 os.Setenv("SNAP_DATA", "/var/snap/snapname/42") 441 defer os.Unsetenv("SNAP_DATA") 442 443 // launch and verify its run the right way 444 err := snapExec.ExecApp("snapname.app", "42", "", []string{"user-arg1"}) 445 c.Assert(err, IsNil) 446 c.Check(execArgv0, Equals, fmt.Sprintf("%s/snapname/42/run-app", dirs.SnapMountDir)) 447 c.Check(execArgs, DeepEquals, []string{execArgv0, "cmd-arg1", "/var/snap/snapname/42", "user-arg1"}) 448 c.Check(execEnv, testutil.Contains, "BASE_PATH=/some/path") 449 c.Check(execEnv, testutil.Contains, "LD_LIBRARY_PATH=/some/path/lib") 450 c.Check(execEnv, testutil.Contains, fmt.Sprintf("MY_PATH=%s", os.Getenv("PATH"))) 451 } 452 453 func (s *snapExecSuite) TestSnapExecExpandEnvCmdArgs(c *C) { 454 for _, t := range []struct { 455 args []string 456 env map[string]string 457 expected []string 458 }{ 459 { 460 args: []string{"foo"}, 461 env: nil, 462 expected: []string{"foo"}, 463 }, 464 { 465 args: []string{"$var"}, 466 env: map[string]string{"var": "value"}, 467 expected: []string{"value"}, 468 }, 469 { 470 args: []string{"foo", "$not_existing"}, 471 env: nil, 472 expected: []string{"foo"}, 473 }, 474 { 475 args: []string{"foo", "$var", "baz"}, 476 env: map[string]string{"var": "bar", "unrelated": "env"}, 477 expected: []string{"foo", "bar", "baz"}, 478 }, 479 } { 480 env := osutil.Environment(t.env) 481 c.Check(snapExec.ExpandEnvCmdArgs(t.args, env), DeepEquals, t.expected) 482 } 483 } 484 485 func (s *snapExecSuite) TestSnapExecCompleteError(c *C) { 486 dirs.SetRootDir(c.MkDir()) 487 snaptest.MockSnap(c, string(mockYaml), &snap.SideInfo{ 488 Revision: snap.R("42"), 489 }) 490 491 restore := snapExec.MockOsReadlink(func(p string) (string, error) { 492 c.Assert(p, Equals, "/proc/self/exe") 493 return "", fmt.Errorf("fail") 494 }) 495 defer restore() 496 497 // setup env 498 os.Setenv("SNAP_DATA", "/var/snap/snapname/42") 499 defer os.Unsetenv("SNAP_DATA") 500 501 // launch and verify its run the right way 502 err := snapExec.ExecApp("snapname.app", "42", "complete", []string{"foo"}) 503 c.Assert(err, ErrorMatches, "cannot find completion helper: fail") 504 } 505 506 func (s *snapExecSuite) TestSnapExecCompleteConfined(c *C) { 507 dirs.SetRootDir(c.MkDir()) 508 snaptest.MockSnap(c, string(mockYaml), &snap.SideInfo{ 509 Revision: snap.R("42"), 510 }) 511 512 execArgv0 := "" 513 execArgs := []string{} 514 restore := snapExec.MockSyscallExec(func(argv0 string, argv []string, env []string) error { 515 execArgv0 = argv0 516 execArgs = argv 517 return nil 518 }) 519 defer restore() 520 521 restore = snapExec.MockOsReadlink(func(p string) (string, error) { 522 c.Assert(p, Equals, "/proc/self/exe") 523 // as if running inside the snap mount namespace 524 return "/usr/lib/snapd/snap-exec", nil 525 }) 526 defer restore() 527 528 // setup env 529 os.Setenv("SNAP_DATA", "/var/snap/snapname/42") 530 defer os.Unsetenv("SNAP_DATA") 531 532 // launch and verify its run the right way 533 err := snapExec.ExecApp("snapname.app", "42", "complete", []string{"foo"}) 534 c.Assert(err, IsNil) 535 c.Check(execArgv0, Equals, "/bin/bash") 536 c.Check(execArgs, DeepEquals, []string{execArgv0, 537 dirs.CompletionHelperInCore, 538 filepath.Join(dirs.SnapMountDir, "snapname/42/you/complete/me"), 539 "foo"}) 540 } 541 542 func (s *snapExecSuite) TestSnapExecCompleteClassicReexec(c *C) { 543 restore := release.MockReleaseInfo(&release.OS{ID: "ubuntu"}) 544 defer restore() 545 dirs.SetRootDir(c.MkDir()) 546 snaptest.MockSnap(c, string(mockClassicYaml), &snap.SideInfo{ 547 Revision: snap.R("42"), 548 }) 549 550 execArgv0 := "" 551 execArgs := []string{} 552 restore = snapExec.MockSyscallExec(func(argv0 string, argv []string, env []string) error { 553 execArgv0 = argv0 554 execArgs = argv 555 return nil 556 }) 557 defer restore() 558 559 restore = snapExec.MockOsReadlink(func(p string) (string, error) { 560 c.Assert(p, Equals, "/proc/self/exe") 561 // as if it's reexeced from the snap 562 return filepath.Join(dirs.SnapMountDir, "core/current", dirs.CoreLibExecDir, "snap-exec"), nil 563 }) 564 defer restore() 565 566 // setup env 567 os.Setenv("SNAP_DATA", "/var/snap/snapname/42") 568 defer os.Unsetenv("SNAP_DATA") 569 570 // launch and verify its run the right way 571 err := snapExec.ExecApp("snapname.app", "42", "complete", []string{"foo"}) 572 c.Assert(err, IsNil) 573 c.Check(execArgv0, Equals, "/bin/bash") 574 c.Check(execArgs, DeepEquals, []string{execArgv0, 575 filepath.Join(dirs.SnapMountDir, "core/current", dirs.CompletionHelperInCore), 576 filepath.Join(dirs.SnapMountDir, "snapname/42/you/complete/me"), 577 "foo"}) 578 } 579 580 func (s *snapExecSuite) TestSnapExecCompleteClassicNoReexec(c *C) { 581 restore := release.MockReleaseInfo(&release.OS{ID: "centos"}) 582 defer restore() 583 dirs.SetRootDir(c.MkDir()) 584 snaptest.MockSnap(c, string(mockClassicYaml), &snap.SideInfo{ 585 Revision: snap.R("42"), 586 }) 587 588 execArgv0 := "" 589 execArgs := []string{} 590 execEnv := []string{} 591 restore = snapExec.MockSyscallExec(func(argv0 string, argv []string, env []string) error { 592 execArgv0 = argv0 593 execArgs = argv 594 execEnv = env 595 return nil 596 }) 597 defer restore() 598 599 restore = snapExec.MockOsReadlink(func(p string) (string, error) { 600 c.Assert(p, Equals, "/proc/self/exe") 601 // running from distro libexecdir 602 return filepath.Join(dirs.DistroLibExecDir, "snap-exec"), nil 603 }) 604 defer restore() 605 606 // setup env 607 os.Setenv("SNAP_DATA", "/var/snap/snapname/42") 608 defer os.Unsetenv("SNAP_DATA") 609 os.Setenv("SNAP_SAVED_TMPDIR", "/var/tmp99") 610 defer os.Unsetenv("SNAP_SAVED_TMPDIR") 611 612 // launch and verify its run the right way 613 err := snapExec.ExecApp("snapname.app", "42", "complete", []string{"foo"}) 614 c.Assert(err, IsNil) 615 c.Check(execArgv0, Equals, "/bin/bash") 616 c.Check(execArgs, DeepEquals, []string{execArgv0, 617 filepath.Join(dirs.DistroLibExecDir, "etelpmoc.sh"), 618 filepath.Join(dirs.SnapMountDir, "snapname/42/you/complete/me"), 619 "foo"}) 620 c.Check(execEnv, testutil.Contains, "SNAP_DATA=/var/snap/snapname/42") 621 c.Check(execEnv, testutil.Contains, "TMPDIR=/var/tmp99") 622 }