Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/snap, daemon, overlord/snapstate: tests and fixes for "snap refresh" of a classic snap #2612

Merged
merged 3 commits into from Jan 11, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/snap/cmd_snap_op.go
Expand Up @@ -623,6 +623,7 @@ func (x *cmdRefresh) Execute([]string) error {
opts := &client.SnapOptions{
Channel: x.Channel,
DevMode: x.DevMode,
Classic: x.Classic,
JailMode: x.JailMode,
IgnoreValidation: x.IgnoreValidation,
Revision: x.Revision,
Expand Down
14 changes: 14 additions & 0 deletions cmd/snap/cmd_snap_op_test.go
Expand Up @@ -406,6 +406,20 @@ func (s *SnapOpSuite) TestRefreshOneSwitchChannel(c *check.C) {
c.Check(s.Stdout(), check.Matches, `(?sm).*foo \(beta\) 1.0 from 'bar' refreshed`)
}

func (s *SnapOpSuite) TestRefreshOneClassic(c *check.C) {
s.RedirectClientToTestServer(s.srv.handle)
s.srv.checker = func(r *http.Request) {
c.Check(r.Method, check.Equals, "POST")
c.Check(r.URL.Path, check.Equals, "/v2/snaps/one")
c.Check(DecodedRequestBody(c, r), check.DeepEquals, map[string]interface{}{
"action": "refresh",
"classic": true,
})
}
_, err := snap.Parser().ParseArgs([]string{"refresh", "--classic", "one"})
c.Assert(err, check.IsNil)
}

func (s *SnapOpSuite) TestRefreshOneDevmode(c *check.C) {
s.RedirectClientToTestServer(s.srv.handle)
s.srv.checker = func(r *http.Request) {
Expand Down
32 changes: 32 additions & 0 deletions daemon/api_test.go
Expand Up @@ -2426,6 +2426,38 @@ func (s *apiSuite) TestRefreshDevMode(c *check.C) {
c.Check(summary, check.Equals, `Refresh "some-snap" snap`)
}

func (s *apiSuite) TestRefreshClassic(c *check.C) {
var calledFlags snapstate.Flags

snapstateCoreInfo = func(s *state.State) (*snap.Info, error) {
// we have ubuntu-core
return nil, nil
}
snapstateUpdate = func(s *state.State, name, channel string, revision snap.Revision, userID int, flags snapstate.Flags) (*state.TaskSet, error) {
calledFlags = flags
return nil, nil
}
assertstateRefreshSnapDeclarations = func(s *state.State, userID int) error {
return nil
}

d := s.daemon(c)
inst := &snapInstruction{
Action: "refresh",
Classic: true,
Snaps: []string{"some-snap"},
userID: 17,
}

st := d.overlord.State()
st.Lock()
defer st.Unlock()
_, _, err := inst.dispatch()(inst, st)
c.Check(err, check.IsNil)

c.Check(calledFlags, check.DeepEquals, snapstate.Flags{Classic: true})
}

func (s *apiSuite) TestRefreshIgnoreValidation(c *check.C) {
var calledFlags snapstate.Flags
calledUserID := 0
Expand Down
70 changes: 65 additions & 5 deletions overlord/snapstate/snapmgr_test.go
Expand Up @@ -824,11 +824,25 @@ func (s *snapmgrTestSuite) TestUpdateClassicConfinementFiltering(c *C) {
c.Assert(err, ErrorMatches, `snap "some-snap" has no updates available`)

// updated snap is classic, refresh with --classic
_, err = snapstate.Update(s.state, "some-snap", "", snap.R(0), s.user.ID, snapstate.Flags{Classic: true})
ts, err := snapstate.Update(s.state, "some-snap", "", snap.R(0), s.user.ID, snapstate.Flags{Classic: true})
c.Assert(err, IsNil)

chg := s.state.NewChange("refresh", "refresh snap")
chg.AddAll(ts)

s.state.Unlock()
defer s.snapmgr.Stop()
s.settle()
s.state.Lock()

// verify snap is in classic
var snapst snapstate.SnapState
err = snapstate.Get(s.state, "some-snap", &snapst)
c.Assert(err, IsNil)
c.Check(snapst.Classic, Equals, true)
}

func (s *snapmgrTestSuite) TestUpdateClassic(c *C) {
func (s *snapmgrTestSuite) TestUpdateClassicFromClassic(c *C) {
s.state.Lock()
defer s.state.Unlock()

Expand All @@ -841,13 +855,59 @@ func (s *snapmgrTestSuite) TestUpdateClassic(c *C) {
Flags: snapstate.Flags{Classic: true},
})

// snap installed with --classic, update needs classic, refresh with --classic works
ts, err := snapstate.Update(s.state, "some-snap", "", snap.R(0), s.user.ID, snapstate.Flags{Classic: true})
c.Assert(err, IsNil)
c.Assert(ts.Tasks(), Not(HasLen), 0)
snapsup, err := snapstate.TaskSnapSetup(ts.Tasks()[0])
c.Assert(err, IsNil)
c.Check(snapsup.Flags.Classic, Equals, true)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sort of feel a test where we actually run the tasks and look also at final snapstate would be even better

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to be clear I think such a test would show the problem @mvo5 hit, these were passing anyway


// devmode overrides the snapsetup classic flag
ts, err = snapstate.Update(s.state, "some-snap", "", snap.R(0), s.user.ID, snapstate.Flags{DevMode: true})
c.Assert(err, IsNil)
c.Assert(ts.Tasks(), Not(HasLen), 0)
snapsup, err = snapstate.TaskSnapSetup(ts.Tasks()[0])
c.Assert(err, IsNil)
c.Check(snapsup.Flags.Classic, Equals, false)

// jailmode overrides it too (you need to provide both)
ts, err = snapstate.Update(s.state, "some-snap", "", snap.R(0), s.user.ID, snapstate.Flags{JailMode: true})
c.Assert(err, IsNil)
c.Assert(ts.Tasks(), Not(HasLen), 0)
snapsup, err = snapstate.TaskSnapSetup(ts.Tasks()[0])
c.Assert(err, IsNil)
c.Check(snapsup.Flags.Classic, Equals, false)

// jailmode and classic together gets you both
ts, err = snapstate.Update(s.state, "some-snap", "", snap.R(0), s.user.ID, snapstate.Flags{JailMode: true, Classic: true})
c.Assert(err, IsNil)
c.Assert(ts.Tasks(), Not(HasLen), 0)
snapsup, err = snapstate.TaskSnapSetup(ts.Tasks()[0])
c.Assert(err, IsNil)
c.Check(snapsup.Flags.Classic, Equals, true)

// snap installed with --classic, update needs classic, refresh without --classic works
_, err := snapstate.Update(s.state, "some-snap", "", snap.R(0), s.user.ID, snapstate.Flags{})
ts, err = snapstate.Update(s.state, "some-snap", "", snap.R(0), s.user.ID, snapstate.Flags{})
c.Assert(err, IsNil)
c.Assert(ts.Tasks(), Not(HasLen), 0)
snapsup, err = snapstate.TaskSnapSetup(ts.Tasks()[0])
c.Assert(err, IsNil)
c.Check(snapsup.Flags.Classic, Equals, true)

// snap installed with --classic, update needs classic, refresh with --classic also works
_, err = snapstate.Update(s.state, "some-snap", "", snap.R(0), s.user.ID, snapstate.Flags{Classic: true})
chg := s.state.NewChange("refresh", "refresh snap")
chg.AddAll(ts)

s.state.Unlock()
defer s.snapmgr.Stop()
s.settle()
s.state.Lock()

// verify snap is in classic
var snapst snapstate.SnapState
err = snapstate.Get(s.state, "some-snap", &snapst)
c.Assert(err, IsNil)
c.Check(snapst.Classic, Equals, true)
}

func (s *snapmgrTestSuite) TestUpdateStrictFromClassic(c *C) {
Expand Down
4 changes: 4 additions & 0 deletions overlord/snapstate/snapstate.go
Expand Up @@ -520,6 +520,10 @@ func Update(st *state.State, name, channel string, revision snap.Revision, userI
channel = snapst.Channel
}

if !(flags.JailMode || flags.DevMode) {
flags.Classic = flags.Classic || snapst.Flags.Classic
}

info, err := infoForUpdate(st, &snapst, name, channel, revision, userID, flags)
if err != nil {
return nil, err
Expand Down