github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/overlord/hookstate/ctlcmd/unset_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2019 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 ctlcmd_test 21 22 import ( 23 "strings" 24 25 . "gopkg.in/check.v1" 26 27 "github.com/snapcore/snapd/overlord/configstate/config" 28 "github.com/snapcore/snapd/overlord/hookstate" 29 "github.com/snapcore/snapd/overlord/hookstate/ctlcmd" 30 "github.com/snapcore/snapd/overlord/hookstate/hooktest" 31 "github.com/snapcore/snapd/overlord/state" 32 "github.com/snapcore/snapd/snap" 33 ) 34 35 type unsetSuite struct { 36 mockContext *hookstate.Context 37 mockHandler *hooktest.MockHandler 38 } 39 40 var _ = Suite(&unsetSuite{}) 41 42 func (s *unsetSuite) SetUpTest(c *C) { 43 s.mockHandler = hooktest.NewMockHandler() 44 45 state := state.New(nil) 46 state.Lock() 47 defer state.Unlock() 48 49 task := state.NewTask("test-task", "my test task") 50 setup := &hookstate.HookSetup{Snap: "test-snap", Revision: snap.R(1), Hook: "hook"} 51 52 var err error 53 s.mockContext, err = hookstate.NewContext(task, task.State(), setup, s.mockHandler, "") 54 c.Assert(err, IsNil) 55 } 56 57 func (s *unsetSuite) TestInvalidArguments(c *C) { 58 _, _, err := ctlcmd.Run(s.mockContext, []string{"unset"}, 0) 59 c.Check(err, ErrorMatches, "unset which option.*") 60 } 61 62 func (s *unsetSuite) TestUnsetOne(c *C) { 63 // Setup an initial configuration 64 s.mockContext.State().Lock() 65 tr := config.NewTransaction(s.mockContext.State()) 66 tr.Set("test-snap", "foo", "a") 67 tr.Commit() 68 s.mockContext.State().Unlock() 69 70 // Sanity check 71 var value interface{} 72 s.mockContext.State().Lock() 73 tr = config.NewTransaction(s.mockContext.State()) 74 c.Check(tr.Get("test-snap", "foo", &value), IsNil) 75 s.mockContext.State().Unlock() 76 c.Check(value, Equals, "a") 77 78 stdout, stderr, err := ctlcmd.Run(s.mockContext, []string{"unset", "foo"}, 0) 79 c.Check(err, IsNil) 80 c.Check(string(stdout), Equals, "") 81 c.Check(string(stderr), Equals, "") 82 83 // Notify the context that we're done. This should save the config. 84 s.mockContext.Lock() 85 defer s.mockContext.Unlock() 86 c.Check(s.mockContext.Done(), IsNil) 87 88 // Verify that the global config has been updated. 89 tr = config.NewTransaction(s.mockContext.State()) 90 c.Check(tr.Get("test-snap", "foo", &value), ErrorMatches, `snap "test-snap" has no "foo" configuration option`) 91 } 92 93 func (s *unsetSuite) TestUnsetMany(c *C) { 94 // Setup an initial configuration 95 s.mockContext.State().Lock() 96 tr := config.NewTransaction(s.mockContext.State()) 97 tr.Set("test-snap", "foo", "a") 98 tr.Set("test-snap", "bar", "b") 99 tr.Set("test-snap", "baz", "c") 100 tr.Commit() 101 s.mockContext.State().Unlock() 102 103 stdout, stderr, err := ctlcmd.Run(s.mockContext, []string{"unset", "foo", "bar"}, 0) 104 c.Check(err, IsNil) 105 c.Check(string(stdout), Equals, "") 106 c.Check(string(stderr), Equals, "") 107 108 // Notify the context that we're done. This should save the config. 109 s.mockContext.Lock() 110 defer s.mockContext.Unlock() 111 c.Check(s.mockContext.Done(), IsNil) 112 113 // Verify that the global config has been updated. 114 var value interface{} 115 tr = config.NewTransaction(s.mockContext.State()) 116 c.Check(tr.Get("test-snap", "foo", &value), ErrorMatches, `snap "test-snap" has no "foo" configuration option`) 117 c.Check(tr.Get("test-snap", "bar", &value), ErrorMatches, `snap "test-snap" has no "bar" configuration option`) 118 c.Check(tr.Get("test-snap", "baz", &value), IsNil) 119 c.Check(value, Equals, "c") 120 } 121 122 func (s *unsetSuite) TestSetThenUnset(c *C) { 123 // Setup an initial configuration 124 s.mockContext.State().Lock() 125 tr := config.NewTransaction(s.mockContext.State()) 126 tr.Set("test-snap", "agent.x.a", "1") 127 tr.Set("test-snap", "agent.x.b", "2") 128 tr.Commit() 129 s.mockContext.State().Unlock() 130 131 stdout, stderr, err := ctlcmd.Run(s.mockContext, []string{"set", "agent.x!", "agent.x.a!", "agent.x.b!"}, 0) 132 c.Check(err, IsNil) 133 c.Check(string(stdout), Equals, "") 134 c.Check(string(stderr), Equals, "") 135 136 // Notify the context that we're done. This should save the config. 137 s.mockContext.Lock() 138 defer s.mockContext.Unlock() 139 c.Check(s.mockContext.Done(), IsNil) 140 141 // Verify that the global config has been updated. 142 var value interface{} 143 tr = config.NewTransaction(s.mockContext.State()) 144 c.Check(tr.Get("test-snap", "agent.x.a", &value), ErrorMatches, `snap "test-snap" has no "agent.x.a" configuration option`) 145 } 146 147 func (s *unsetSuite) TestUnsetRegularUserForbidden(c *C) { 148 _, _, err := ctlcmd.Run(s.mockContext, []string{"unset", "key"}, 1000) 149 c.Assert(err, ErrorMatches, `cannot use "unset" with uid 1000, try with sudo`) 150 forbidden, _ := err.(*ctlcmd.ForbiddenCommandError) 151 c.Assert(forbidden, NotNil) 152 } 153 154 func (s *unsetSuite) TestUnsetHelpRegularUserAllowed(c *C) { 155 _, _, err := ctlcmd.Run(s.mockContext, []string{"unset", "-h"}, 1000) 156 c.Assert(strings.HasPrefix(err.Error(), "Usage:"), Equals, true) 157 } 158 159 func (s *unsetSuite) TestCommandWithoutContext(c *C) { 160 _, _, err := ctlcmd.Run(nil, []string{"unset", "foo"}, 0) 161 c.Check(err, ErrorMatches, ".*cannot unset without a context.*") 162 }