github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/wrench/wrench_test.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package wrench_test 5 6 import ( 7 "os" 8 "path/filepath" 9 "runtime" 10 stdtesting "testing" 11 12 "github.com/juju/loggo" 13 jc "github.com/juju/testing/checkers" 14 gc "gopkg.in/check.v1" 15 16 coretesting "github.com/juju/juju/testing" 17 "github.com/juju/juju/wrench" 18 ) 19 20 func TestPackage(t *stdtesting.T) { 21 gc.TestingT(t) 22 } 23 24 type wrenchSuite struct { 25 coretesting.BaseSuite 26 wrenchDir string 27 logWriter loggo.TestWriter 28 } 29 30 var _ = gc.Suite(&wrenchSuite{}) 31 32 func (s *wrenchSuite) SetUpTest(c *gc.C) { 33 s.BaseSuite.SetUpTest(c) 34 35 // BaseSuite turns off wrench so restore the non-testing default. 36 wrench.SetEnabled(true) 37 38 logger := loggo.GetLogger("juju.wrench") 39 oldLevel := logger.LogLevel() 40 logger.SetLogLevel(loggo.TRACE) 41 42 c.Assert(loggo.RegisterWriter("wrench-tests", &s.logWriter), gc.IsNil) 43 s.AddCleanup(func(*gc.C) { 44 s.logWriter.Clear() 45 logger.SetLogLevel(oldLevel) 46 loggo.RemoveWriter("wrench-tests") 47 // Ensure the wrench is turned off when these tests are done. 48 wrench.SetEnabled(false) 49 }) 50 } 51 52 func (s *wrenchSuite) createWrenchDir(c *gc.C) { 53 s.wrenchDir = c.MkDir() 54 s.PatchValue(wrench.WrenchDir, s.wrenchDir) 55 } 56 57 func (s *wrenchSuite) createWrenchFile(c *gc.C, name, content string) string { 58 filename := filepath.Join(s.wrenchDir, name) 59 err := os.WriteFile(filename, []byte(content), 0700) 60 c.Assert(err, jc.ErrorIsNil) 61 return filename 62 } 63 64 func (s *wrenchSuite) TestIsActive(c *gc.C) { 65 s.createWrenchDir(c) 66 s.createWrenchFile(c, "foo", "bar") 67 c.Assert(wrench.IsActive("foo", "bar"), jc.IsTrue) 68 s.AssertActivationLogged(c) 69 } 70 71 func (s *wrenchSuite) TestIsActiveWithWhitespace(c *gc.C) { 72 s.createWrenchDir(c) 73 s.createWrenchFile(c, "foo", "\tbar ") 74 c.Assert(wrench.IsActive("foo", "bar"), jc.IsTrue) 75 s.AssertActivationLogged(c) 76 } 77 78 func (s *wrenchSuite) TestIsActiveMultiFeatures(c *gc.C) { 79 s.createWrenchDir(c) 80 s.createWrenchFile(c, "foo", "one\ntwo\nbar\n") 81 c.Assert(wrench.IsActive("foo", "bar"), jc.IsTrue) 82 s.AssertActivationLogged(c) 83 } 84 85 func (s *wrenchSuite) TestIsActiveMultiFeaturesWithMixedNewlines(c *gc.C) { 86 s.createWrenchDir(c) 87 s.createWrenchFile(c, "foo", "one\ntwo\r\nthree\nbar\n") 88 c.Assert(wrench.IsActive("foo", "bar"), jc.IsTrue) 89 s.AssertActivationLogged(c) 90 } 91 92 func (s *wrenchSuite) TestNotActive(c *gc.C) { 93 s.createWrenchDir(c) 94 s.createWrenchFile(c, "foo", "abc") 95 c.Assert(wrench.IsActive("foo", "bar"), jc.IsFalse) 96 s.AssertNothingLogged(c) 97 } 98 99 func (s *wrenchSuite) TestNoFile(c *gc.C) { 100 s.createWrenchDir(c) 101 c.Assert(wrench.IsActive("foo", "bar"), jc.IsFalse) 102 s.AssertFileErrorLogged(c) 103 } 104 105 func (s *wrenchSuite) TestMatchInOtherCategory(c *gc.C) { 106 s.createWrenchDir(c) 107 s.createWrenchFile(c, "other", "bar") 108 c.Assert(wrench.IsActive("foo", "bar"), jc.IsFalse) 109 s.AssertFileErrorLogged(c) 110 } 111 112 func (s *wrenchSuite) TestNoDirectory(c *gc.C) { 113 s.PatchValue(wrench.WrenchDir, "/does/not/exist") 114 c.Assert(wrench.IsActive("foo", "bar"), jc.IsFalse) 115 s.AssertDirErrorLogged(c) 116 } 117 118 func (s *wrenchSuite) TestFileNotOwnedByJujuUser(c *gc.C) { 119 s.createWrenchDir(c) 120 filename := s.createWrenchFile(c, "foo", "bar") 121 s.tweakOwner(c, filename) 122 123 c.Assert(wrench.IsActive("foo", "bar"), jc.IsFalse) 124 125 c.Assert(s.logWriter.Log(), jc.LogMatches, []jc.SimpleMessage{{ 126 loggo.ERROR, 127 `wrench file for foo/bar has incorrect ownership - ignoring ` + filename, 128 }}) 129 } 130 131 func (s *wrenchSuite) TestFilePermsTooLoose(c *gc.C) { 132 if runtime.GOOS == "windows" { 133 c.Skip("Windows is not fully POSIX compliant") 134 } 135 s.createWrenchDir(c) 136 filename := s.createWrenchFile(c, "foo", "bar") 137 err := os.Chmod(filename, 0666) 138 c.Assert(err, jc.ErrorIsNil) 139 140 c.Assert(wrench.IsActive("foo", "bar"), jc.IsFalse) 141 142 c.Assert(s.logWriter.Log(), jc.LogMatches, []jc.SimpleMessage{{ 143 loggo.ERROR, 144 `wrench file for foo/bar should only be writable by owner - ignoring ` + filename, 145 }}) 146 } 147 148 func (s *wrenchSuite) TestDirectoryNotOwnedByJujuUser(c *gc.C) { 149 s.createWrenchDir(c) 150 s.tweakOwner(c, s.wrenchDir) 151 152 c.Assert(wrench.IsActive("foo", "bar"), jc.IsFalse) 153 154 c.Assert(s.logWriter.Log(), jc.LogMatches, []jc.SimpleMessage{{ 155 loggo.ERROR, 156 `wrench directory has incorrect ownership - wrench functionality disabled \(.+\)`, 157 }}) 158 } 159 160 func (s *wrenchSuite) TestSetEnabled(c *gc.C) { 161 s.createWrenchDir(c) 162 s.createWrenchFile(c, "foo", "bar") 163 164 // Starts enabled. 165 c.Assert(wrench.IsEnabled(), jc.IsTrue) 166 c.Assert(wrench.IsActive("foo", "bar"), jc.IsTrue) 167 168 // Disable. 169 c.Assert(wrench.SetEnabled(false), jc.IsTrue) 170 c.Assert(wrench.IsEnabled(), jc.IsFalse) 171 c.Assert(wrench.IsActive("foo", "bar"), jc.IsFalse) 172 173 // Enable again. 174 c.Assert(wrench.SetEnabled(true), jc.IsFalse) 175 c.Assert(wrench.IsEnabled(), jc.IsTrue) 176 c.Assert(wrench.IsActive("foo", "bar"), jc.IsTrue) 177 } 178 179 var notJujuUid = uint32(os.Getuid() + 1) 180 181 func (s *wrenchSuite) AssertActivationLogged(c *gc.C) { 182 c.Assert(s.logWriter.Log(), jc.LogMatches, []jc.SimpleMessage{ 183 {loggo.TRACE, `wrench for foo/bar is active`}}) 184 } 185 186 func (s *wrenchSuite) AssertNothingLogged(c *gc.C) { 187 c.Assert(len(s.logWriter.Log()), gc.Equals, 0) 188 } 189 190 func (s *wrenchSuite) AssertFileErrorLogged(c *gc.C) { 191 c.Assert(s.logWriter.Log(), jc.LogMatches, []jc.SimpleMessage{ 192 {loggo.TRACE, `no wrench data for foo/bar \(ignored\): ` + fileNotFound}}) 193 } 194 195 func (s *wrenchSuite) AssertDirErrorLogged(c *gc.C) { 196 c.Assert(s.logWriter.Log(), jc.LogMatches, []jc.SimpleMessage{ 197 {loggo.TRACE, `couldn't read wrench directory: ` + fileNotFound}}) 198 }