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  }