Exemple #1
0
func (s *FirstBootTestSuite) SetUpTest(c *C) {
	tempdir := c.MkDir()
	dirs.SetRootDir(tempdir)

	// mock the world!
	err := os.MkdirAll(filepath.Join(dirs.SnapSeedDir, "snaps"), 0755)
	c.Assert(err, IsNil)
	err = os.MkdirAll(filepath.Join(dirs.SnapSeedDir, "assertions"), 0755)
	c.Assert(err, IsNil)

	err = os.MkdirAll(dirs.SnapServicesDir, 0755)
	c.Assert(err, IsNil)
	os.Setenv("SNAPPY_SQUASHFS_UNPACK_FOR_TESTS", "1")
	s.systemctl = testutil.MockCommand(c, "systemctl", "")
	s.mockUdevAdm = testutil.MockCommand(c, "udevadm", "")

	err = ioutil.WriteFile(filepath.Join(dirs.SnapSeedDir, "seed.yaml"), nil, 0644)
	c.Assert(err, IsNil)

	rootPrivKey, _ := assertstest.GenerateKey(1024)
	storePrivKey, _ := assertstest.GenerateKey(752)
	s.storeSigning = assertstest.NewStoreStack("can0nical", rootPrivKey, storePrivKey)
	s.restore = sysdb.InjectTrusted(s.storeSigning.Trusted)

	s.brandPrivKey, _ = assertstest.GenerateKey(752)
	s.brandSigning = assertstest.NewSigningDB("my-brand", s.brandPrivKey)

	ovld, err := overlord.New()
	c.Assert(err, IsNil)
	s.overlord = ovld
}
Exemple #2
0
func (ms *mgrsSuite) SetUpTest(c *C) {
	ms.tempdir = c.MkDir()
	dirs.SetRootDir(ms.tempdir)
	err := os.MkdirAll(filepath.Dir(dirs.SnapStateFile), 0755)
	c.Assert(err, IsNil)

	os.Setenv("SNAPPY_SQUASHFS_UNPACK_FOR_TESTS", "1")

	// create a fake systemd environment
	os.MkdirAll(filepath.Join(dirs.SnapServicesDir, "multi-user.target.wants"), 0755)

	ms.prevctlCmd = systemd.SystemctlCmd
	systemd.SystemctlCmd = func(cmd ...string) ([]byte, error) {
		return []byte("ActiveState=inactive\n"), nil
	}
	ms.aa = testutil.MockCommand(c, "apparmor_parser", "")
	ms.udev = testutil.MockCommand(c, "udevadm", "")
	ms.umount = testutil.MockCommand(c, "umount", "")
	ms.snapDiscardNs = testutil.MockCommand(c, "snap-discard-ns", "")
	dirs.LibExecDir = ms.snapDiscardNs.BinDir()

	ms.storeSigning = assertstest.NewStoreStack("can0nical", rootPrivKey, storePrivKey)
	ms.restoreTrusted = sysdb.InjectTrusted(ms.storeSigning.Trusted)

	ms.devAcct = assertstest.NewAccount(ms.storeSigning, "devdevev", map[string]interface{}{
		"account-id": "devdevdev",
	}, "")
	err = ms.storeSigning.Add(ms.devAcct)
	c.Assert(err, IsNil)

	o, err := overlord.New()
	c.Assert(err, IsNil)
	ms.o = o
}
Exemple #3
0
func (s *hookManagerSuite) TestHookTaskCorrectlyIncludesContext(c *C) {
	// Register a handler generator for the "test-hook" hook
	mockHandler := hooktest.NewMockHandler()
	mockHandlerGenerator := func(context *hookstate.Context) hookstate.Handler {
		return mockHandler
	}

	// Force the snap command to exit with a failure and print to stderr so we
	// can catch and verify it.
	s.command = testutil.MockCommand(
		c, "snap", ">&2 echo \"SNAP_CONTEXT=$SNAP_CONTEXT\"; exit 1")

	s.manager.Register(regexp.MustCompile("test-hook"), mockHandlerGenerator)

	s.manager.Ensure()
	s.manager.Wait()

	s.state.Lock()
	defer s.state.Unlock()

	c.Check(mockHandler.BeforeCalled, Equals, true)
	c.Check(mockHandler.DoneCalled, Equals, false)
	c.Check(mockHandler.ErrorCalled, Equals, true)

	c.Check(s.task.Kind(), Equals, "run-hook")
	c.Check(s.task.Status(), Equals, state.ErrorStatus)
	c.Check(s.change.Status(), Equals, state.ErrorStatus)
	checkTaskLogContains(c, s.task, regexp.MustCompile(".*SNAP_CONTEXT=\\S+"))
}
Exemple #4
0
func (s *hookManagerSuite) TestHookTaskCanKillHook(c *C) {
	// Force the snap command to hang
	s.command = testutil.MockCommand(c, "snap", "while true; do sleep 1; done")

	s.manager.Ensure()
	completed := make(chan struct{})
	go func() {
		s.manager.Wait()
		close(completed)
	}()

	// Abort the change, which should kill the hanging hook, and wait for the
	// task to complete.
	s.state.Lock()
	s.change.Abort()
	s.state.Unlock()
	s.manager.Ensure()
	<-completed

	s.state.Lock()
	defer s.state.Unlock()

	c.Check(s.mockHandler.BeforeCalled, Equals, true)
	c.Check(s.mockHandler.DoneCalled, Equals, false)
	c.Check(s.mockHandler.ErrorCalled, Equals, true)
	c.Check(s.mockHandler.Err, ErrorMatches, ".*hook \"configure\" aborted.*")

	c.Check(s.task.Kind(), Equals, "run-hook")
	c.Check(s.task.Status(), Equals, state.ErrorStatus)
	c.Check(s.change.Status(), Equals, state.ErrorStatus)
	checkTaskLogContains(c, s.task, `.*hook "configure" aborted.*`)
}
Exemple #5
0
func (s *createUserSuite) SetUpTest(c *check.C) {
	s.mockHome = c.MkDir()
	s.restorer = osutil.MockUserLookup(func(string) (*user.User, error) {
		current, err := user.Current()
		if err != nil {
			c.Fatalf("user.Current() failed with %s", err)
		}
		return &user.User{
			HomeDir: s.mockHome,
			Gid:     current.Gid,
			Uid:     current.Uid,
		}, nil
	})
	s.mockAddUser = testutil.MockCommand(c, "adduser", "")
	s.mockUserMod = testutil.MockCommand(c, "usermod", "")
}
Exemple #6
0
func (s *hookManagerSuite) TestHookTaskHandlerErrorError(c *C) {
	// Register a handler generator for the "test-hook" hook
	mockHandler := hooktest.NewMockHandler()
	mockHandler.ErrorError = true
	mockHandlerGenerator := func(context *hookstate.Context) hookstate.Handler {
		return mockHandler
	}

	// Force the snap command to simply exit 1, so the handler Error() runs
	s.command = testutil.MockCommand(c, "snap", "exit 1")

	s.manager.Register(regexp.MustCompile("test-hook"), mockHandlerGenerator)

	s.manager.Ensure()
	s.manager.Wait()

	s.state.Lock()
	defer s.state.Unlock()

	c.Check(mockHandler.BeforeCalled, Equals, true)
	c.Check(mockHandler.DoneCalled, Equals, false)
	c.Check(mockHandler.ErrorCalled, Equals, true)

	c.Check(s.task.Kind(), Equals, "run-hook")
	c.Check(s.task.Status(), Equals, state.ErrorStatus)
	c.Check(s.change.Status(), Equals, state.ErrorStatus)
	checkTaskLogContains(c, s.task, regexp.MustCompile(".*Error failed at user request.*"))
}
Exemple #7
0
func (s *appArmorSuite) TestUnloadProfileReportsErrors(c *C) {
	cmd := testutil.MockCommand(c, "apparmor_parser", "exit 42")
	defer cmd.Restore()
	err := apparmor.UnloadProfile("snap.samba.smbd")
	c.Assert(err.Error(), Equals, `cannot unload apparmor profile: exit status 42
apparmor_parser output:
`)
}
Exemple #8
0
func (s *appArmorSuite) TestLoadProfileRunsAppArmorParserReplace(c *C) {
	cmd := testutil.MockCommand(c, "apparmor_parser", "")
	defer cmd.Restore()
	err := apparmor.LoadProfile("/path/to/snap.samba.smbd")
	c.Assert(err, IsNil)
	c.Assert(cmd.Calls(), DeepEquals, [][]string{
		{"apparmor_parser", "--replace", "--write-cache", "-O", "no-expr-simplify", "--cache-loc=/var/cache/apparmor", "/path/to/snap.samba.smbd"},
	})
}
Exemple #9
0
func (s *appArmorSuite) TestUnloadProfileRunsAppArmorParserRemove(c *C) {
	cmd := testutil.MockCommand(c, "apparmor_parser", "")
	defer cmd.Restore()
	err := apparmor.UnloadProfile("snap.samba.smbd")
	c.Assert(err, IsNil)
	c.Assert(cmd.Calls(), DeepEquals, [][]string{
		{"apparmor_parser", "--remove", "snap.samba.smbd"},
	})
}
Exemple #10
0
func (s *uDevSuite) TestReloadUDevRulesRunsUDevAdm(c *C) {
	cmd := testutil.MockCommand(c, "udevadm", "")
	defer cmd.Restore()
	err := udev.ReloadRules()
	c.Assert(err, IsNil)
	c.Assert(cmd.Calls(), DeepEquals, [][]string{
		{"udevadm", "control", "--reload-rules"},
		{"udevadm", "trigger"},
	})
}
Exemple #11
0
func (s *appArmorSuite) TestLoadProfileReportsErrors(c *C) {
	cmd := testutil.MockCommand(c, "apparmor_parser", "exit 42")
	defer cmd.Restore()
	err := apparmor.LoadProfile("/path/to/snap.samba.smbd")
	c.Assert(err.Error(), Equals, `cannot load apparmor profile: exit status 42
apparmor_parser output:
`)
	c.Assert(cmd.Calls(), DeepEquals, [][]string{
		{"apparmor_parser", "--replace", "--write-cache", "-O", "no-expr-simplify", "--cache-loc=/var/cache/apparmor", "/path/to/snap.samba.smbd"},
	})
}
Exemple #12
0
func (s *SystemdTestSuite) TestFuseInContainer(c *C) {
	if !osutil.FileExists("/dev/fuse") {
		c.Skip("No /dev/fuse on the system")
	}

	systemdCmd := testutil.MockCommand(c, "systemd-detect-virt", `
echo lxc
exit 0
	`)
	defer systemdCmd.Restore()

	fuseCmd := testutil.MockCommand(c, "squashfuse", `
exit 0
	`)
	defer fuseCmd.Restore()

	mockSnapPath := filepath.Join(c.MkDir(), "/var/lib/snappy/snaps/foo_1.0.snap")
	err := os.MkdirAll(filepath.Dir(mockSnapPath), 0755)
	c.Assert(err, IsNil)
	err = ioutil.WriteFile(mockSnapPath, nil, 0644)
	c.Assert(err, IsNil)

	mountUnitName, err := New("", nil).WriteMountUnitFile("foo", mockSnapPath, "/apps/foo/1.0", "squashfs")
	c.Assert(err, IsNil)
	defer os.Remove(mountUnitName)

	mount, err := ioutil.ReadFile(filepath.Join(dirs.SnapServicesDir, mountUnitName))
	c.Assert(err, IsNil)
	c.Assert(string(mount), Equals, fmt.Sprintf(`[Unit]
Description=Mount unit for foo

[Mount]
What=%s
Where=/apps/foo/1.0
Type=fuse.squashfuse
Options=ro,allow_other

[Install]
WantedBy=multi-user.target
`, mockSnapPath))
}
Exemple #13
0
func (s *setupSuite) SetUpTest(c *C) {
	dirs.SetRootDir(c.MkDir())

	err := os.MkdirAll(filepath.Join(dirs.GlobalRootDir, "etc", "systemd", "system", "multi-user.target.wants"), 0755)
	c.Assert(err, IsNil)

	s.prevctlCmd = systemd.SystemctlCmd
	systemd.SystemctlCmd = func(cmd ...string) ([]byte, error) {
		return []byte("ActiveState=inactive\n"), nil
	}
	s.umount = testutil.MockCommand(c, "umount", "")
}
Exemple #14
0
func (s *backendSuite) SetUpTest(c *C) {
	s.Backend = &udev.Backend{}

	s.BackendSuite.SetUpTest(c)

	// Mock away any real udev interaction
	s.udevadmCmd = testutil.MockCommand(c, "udevadm", "")
	// Prepare a directory for udev rules
	// NOTE: Normally this is a part of the OS snap.
	err := os.MkdirAll(dirs.SnapUdevRulesDir, 0700)
	c.Assert(err, IsNil)
}
Exemple #15
0
func (s *nsSuite) TestDiscardNamespaceMntFileAbsent(c *C) {
	// Mock the snap-discard-ns command
	cmd := testutil.MockCommand(c, "snap-discard-ns", "")
	dirs.LibExecDir = cmd.BinDir()
	defer cmd.Restore()

	// don't create the .mnt file that triggers the discard operation

	// ask the backend to discard the namespace
	err := s.be.DiscardSnapNamespace("snap-name")
	c.Assert(err, IsNil)
	c.Check(cmd.Calls(), IsNil)
}
Exemple #16
0
func (s *backendSuite) SetUpTest(c *C) {
	s.Backend = &apparmor.Backend{}
	s.BackendSuite.SetUpTest(c)

	// Prepare a directory for apparmor profiles.
	// NOTE: Normally this is a part of the OS snap.
	err := os.MkdirAll(dirs.SnapAppArmorDir, 0700)
	c.Assert(err, IsNil)
	err = os.MkdirAll(dirs.AppArmorCacheDir, 0700)
	c.Assert(err, IsNil)
	// Mock away any real apparmor interaction
	s.parserCmd = testutil.MockCommand(c, "apparmor_parser", fakeAppArmorParser)
}
Exemple #17
0
func (s *nsSuite) TestDiscardNamespaceMntFilePresent(c *C) {
	// Mock the snap-discard-ns command
	cmd := testutil.MockCommand(c, "snap-discard-ns", "")
	dirs.LibExecDir = cmd.BinDir()
	defer cmd.Restore()

	// the presence of the .mnt file is the trigger so create it now
	c.Assert(os.MkdirAll(dirs.SnapRunNsDir, 0755), IsNil)
	c.Assert(ioutil.WriteFile(filepath.Join(dirs.SnapRunNsDir, "snap-name.mnt"), nil, 0644), IsNil)

	err := s.be.DiscardSnapNamespace("snap-name")
	c.Assert(err, IsNil)
	c.Check(cmd.Calls(), DeepEquals, [][]string{{"snap-discard-ns", "snap-name"}})
}
Exemple #18
0
func (s *kmodSuite) TestModprobeCall(c *C) {
	cmd := testutil.MockCommand(c, "modprobe", "")
	defer cmd.Restore()

	err := kmod.LoadModules([]string{
		"module1",
		"module2",
	})
	c.Assert(err, IsNil)
	c.Assert(cmd.Calls(), DeepEquals, [][]string{
		{"modprobe", "--syslog", "module1"},
		{"modprobe", "--syslog", "module2"},
	})
}
Exemple #19
0
func (s *nsSuite) TestDiscardNamespaceSilentFailure(c *C) {
	// Mock the snap-discard-ns command, make it fail
	cmd := testutil.MockCommand(c, "snap-discard-ns", "exit 1")
	dirs.LibExecDir = cmd.BinDir()
	defer cmd.Restore()

	// the presence of the .mnt file is the trigger so create it now
	c.Assert(os.MkdirAll(dirs.SnapRunNsDir, 0755), IsNil)
	c.Assert(ioutil.WriteFile(filepath.Join(dirs.SnapRunNsDir, "snap-name.mnt"), nil, 0644), IsNil)

	// ask the backend to discard the namespace
	err := s.be.DiscardSnapNamespace("snap-name")
	c.Assert(err, ErrorMatches, `cannot discard preserved namespaces of snap "snap-name": exit status 1`)
	c.Check(cmd.Calls(), DeepEquals, [][]string{{"snap-discard-ns", "snap-name"}})
}
Exemple #20
0
func (s *appArmorSuite) TestUnloadRemovesCachedProfile(c *C) {
	cmd := testutil.MockCommand(c, "apparmor_parser", "")
	defer cmd.Restore()

	dirs.SetRootDir(c.MkDir())
	defer dirs.SetRootDir("")
	err := os.MkdirAll(dirs.AppArmorCacheDir, 0755)
	c.Assert(err, IsNil)

	fname := filepath.Join(dirs.AppArmorCacheDir, "profile")
	ioutil.WriteFile(fname, []byte("blob"), 0600)
	err = apparmor.UnloadProfile("profile")
	c.Assert(err, IsNil)
	_, err = os.Stat(fname)
	c.Check(os.IsNotExist(err), Equals, true)
}
Exemple #21
0
func (s *hookManagerSuite) SetUpTest(c *C) {
	dirs.SetRootDir(c.MkDir())
	s.state = state.New(nil)
	manager, err := hookstate.Manager(s.state)
	c.Assert(err, IsNil)
	s.manager = manager

	s.state.Lock()
	s.task = hookstate.HookTask(s.state, "test summary", "test-snap", snap.R(1), "test-hook")
	c.Assert(s.task, NotNil, Commentf("Expected HookTask to return a task"))

	s.change = s.state.NewChange("kind", "summary")
	s.change.AddTask(s.task)
	s.state.Unlock()

	s.command = testutil.MockCommand(c, "snap", "")
}
Exemple #22
0
func (s *cpSuite) TestCopyPreserveAllSyncCpFailure(c *C) {
	dir := c.MkDir()
	mocked := testutil.MockCommand(c, "cp", "echo OUCH: cp failed.;exit 42").Also("sync", "")
	defer mocked.Restore()

	src := filepath.Join(dir, "meep")
	dst := filepath.Join(dir, "copied-meep")

	err := ioutil.WriteFile(src, []byte(nil), 0644)
	c.Assert(err, IsNil)

	err = CopyFile(src, dst, CopyFlagPreserveAll|CopyFlagSync)
	c.Assert(err, ErrorMatches, `failed to copy all: "OUCH: cp failed." \(42\)`)
	c.Check(mocked.Calls(), DeepEquals, [][]string{
		{"cp", "-av", src, dst},
	})
}
Exemple #23
0
func (s *uDevSuite) TestReloadUDevRulesReportsErrorsFromReloadRules(c *C) {
	cmd := testutil.MockCommand(c, "udevadm", `
if [ "$1" = "control" ]; then
	echo "failure 1"
	exit 1
fi
	`)
	defer cmd.Restore()
	err := udev.ReloadRules()
	c.Assert(err.Error(), Equals, ""+
		"cannot reload udev rules: exit status 1\n"+
		"udev output:\n"+
		"failure 1\n")
	c.Assert(cmd.Calls(), DeepEquals, [][]string{
		{"udevadm", "control", "--reload-rules"},
	})
}
Exemple #24
0
func (s *copydataSuite) TestCopyDataCopyFailure(c *C) {
	v1 := snaptest.MockSnap(c, helloYaml1, helloContents, &snap.SideInfo{Revision: snap.R(10)})
	s.populateData(c, snap.R(10))

	// pretend we install a new version
	v2 := snaptest.MockSnap(c, helloYaml2, helloContents, &snap.SideInfo{Revision: snap.R(20)})

	defer testutil.MockCommand(c, "cp", "echo cp: boom; exit 3").Restore()

	q := func(s string) string {
		return regexp.QuoteMeta(strconv.Quote(s))
	}

	// copy data will fail
	err := s.be.CopySnapData(v2, v1, &s.nullProgress)
	c.Assert(err, ErrorMatches, fmt.Sprintf(`cannot copy %s to %s: .*: "cp: boom" \(3\)`, q(v1.DataDir()), q(v2.DataDir())))
}
Exemple #25
0
func (s *cpSuite) TestCopySpecialFileSimple(c *C) {
	sync := testutil.MockCommand(c, "sync", "")
	defer sync.Restore()

	src := filepath.Join(c.MkDir(), "fifo")
	err := syscall.Mkfifo(src, 0644)
	c.Assert(err, IsNil)
	dir := c.MkDir()
	dst := filepath.Join(dir, "copied-fifo")

	err = CopySpecialFile(src, dst)
	c.Assert(err, IsNil)

	st, err := os.Stat(dst)
	c.Assert(err, IsNil)
	c.Check((st.Mode() & os.ModeNamedPipe), Equals, os.ModeNamedPipe)
	c.Check(sync.Calls(), DeepEquals, [][]string{{"sync", dir}})
}
Exemple #26
0
func (s *cpSuite) TestCopyPreserveAllSync(c *C) {
	dir := c.MkDir()
	mocked := testutil.MockCommand(c, "cp", "").Also("sync", "")
	defer mocked.Restore()

	src := filepath.Join(dir, "meep")
	dst := filepath.Join(dir, "copied-meep")

	err := ioutil.WriteFile(src, []byte(nil), 0644)
	c.Assert(err, IsNil)

	err = CopyFile(src, dst, CopyFlagPreserveAll|CopyFlagSync)
	c.Assert(err, IsNil)

	c.Check(mocked.Calls(), DeepEquals, [][]string{
		{"cp", "-av", src, dst},
		{"sync"},
	})
}
Exemple #27
0
func (s *hookManagerSuite) SetUpTest(c *C) {
	dirs.SetRootDir(c.MkDir())
	s.state = state.New(nil)
	manager, err := hookstate.Manager(s.state)
	c.Assert(err, IsNil)
	s.manager = manager

	hooksup := &hookstate.HookSetup{
		Snap:     "test-snap",
		Hook:     "configure",
		Revision: snap.R(1),
	}

	initialContext := map[string]interface{}{
		"test-key": "test-value",
	}

	s.state.Lock()
	s.task = hookstate.HookTask(s.state, "test summary", hooksup, initialContext)
	c.Assert(s.task, NotNil, Commentf("Expected HookTask to return a task"))

	s.change = s.state.NewChange("kind", "summary")
	s.change.AddTask(s.task)

	sideInfo := &snap.SideInfo{RealName: "test-snap", SnapID: "some-snap-id", Revision: snap.R(1)}
	snaptest.MockSnap(c, snapYaml, snapContents, sideInfo)
	snapstate.Set(s.state, "test-snap", &snapstate.SnapState{
		Active:   true,
		Sequence: []*snap.SideInfo{sideInfo},
		Current:  snap.R(1),
	})
	s.state.Unlock()

	s.command = testutil.MockCommand(c, "snap", "")

	s.context = nil
	s.mockHandler = hooktest.NewMockHandler()
	s.manager.Register(regexp.MustCompile("configure"), func(context *hookstate.Context) hookstate.Handler {
		s.context = context
		return s.mockHandler
	})
}
Exemple #28
0
func (s *hookManagerSuite) TestHookTaskHandlesHookError(c *C) {
	// Force the snap command to exit 1, and print something to stderr
	s.command = testutil.MockCommand(
		c, "snap", ">&2 echo 'hook failed at user request'; exit 1")

	s.manager.Ensure()
	s.manager.Wait()

	s.state.Lock()
	defer s.state.Unlock()

	c.Check(s.mockHandler.BeforeCalled, Equals, true)
	c.Check(s.mockHandler.DoneCalled, Equals, false)
	c.Check(s.mockHandler.ErrorCalled, Equals, true)

	c.Check(s.task.Kind(), Equals, "run-hook")
	c.Check(s.task.Status(), Equals, state.ErrorStatus)
	c.Check(s.change.Status(), Equals, state.ErrorStatus)
	checkTaskLogContains(c, s.task, ".*failed at user request.*")
}
Exemple #29
0
func (s *hookManagerSuite) TestHookTaskCorrectlyIncludesContext(c *C) {
	// Force the snap command to exit with a failure and print to stderr so we
	// can catch and verify it.
	s.command = testutil.MockCommand(
		c, "snap", ">&2 echo \"SNAP_CONTEXT=$SNAP_CONTEXT\"; exit 1")

	s.manager.Ensure()
	s.manager.Wait()

	s.state.Lock()
	defer s.state.Unlock()

	c.Check(s.mockHandler.BeforeCalled, Equals, true)
	c.Check(s.mockHandler.DoneCalled, Equals, false)
	c.Check(s.mockHandler.ErrorCalled, Equals, true)

	c.Check(s.task.Kind(), Equals, "run-hook")
	c.Check(s.task.Status(), Equals, state.ErrorStatus)
	c.Check(s.change.Status(), Equals, state.ErrorStatus)
	checkTaskLogContains(c, s.task, `.*SNAP_CONTEXT=\S+`)
}
Exemple #30
0
func (s *hookManagerSuite) TestHookTaskHandlerErrorError(c *C) {
	s.mockHandler.ErrorError = true

	// Force the snap command to simply exit 1, so the handler Error() runs
	s.command = testutil.MockCommand(c, "snap", "exit 1")

	s.manager.Ensure()
	s.manager.Wait()

	s.state.Lock()
	defer s.state.Unlock()

	c.Check(s.mockHandler.BeforeCalled, Equals, true)
	c.Check(s.mockHandler.DoneCalled, Equals, false)
	c.Check(s.mockHandler.ErrorCalled, Equals, true)

	c.Check(s.task.Kind(), Equals, "run-hook")
	c.Check(s.task.Status(), Equals, state.ErrorStatus)
	c.Check(s.change.Status(), Equals, state.ErrorStatus)
	checkTaskLogContains(c, s.task, `.*Error failed at user request.*`)
}