github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/auditconfigupdater/worker_test.go (about)

     1  // Copyright 2018 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package auditconfigupdater_test
     5  
     6  import (
     7  	"reflect"
     8  	"sync"
     9  
    10  	"github.com/juju/collections/set"
    11  	"github.com/juju/testing"
    12  	jc "github.com/juju/testing/checkers"
    13  	gc "gopkg.in/check.v1"
    14  	"gopkg.in/juju/worker.v1"
    15  	"gopkg.in/juju/worker.v1/workertest"
    16  
    17  	apitesting "github.com/juju/juju/apiserver/testing"
    18  	"github.com/juju/juju/controller"
    19  	"github.com/juju/juju/core/auditlog"
    20  	"github.com/juju/juju/state"
    21  	"github.com/juju/juju/state/watcher/watchertest"
    22  	jujutesting "github.com/juju/juju/testing"
    23  	"github.com/juju/juju/worker/auditconfigupdater"
    24  )
    25  
    26  type updaterSuite struct {
    27  	jujutesting.BaseSuite
    28  }
    29  
    30  var _ = gc.Suite(&updaterSuite{})
    31  
    32  var ding = struct{}{}
    33  
    34  func (s *updaterSuite) TestWorker(c *gc.C) {
    35  	configChanged := make(chan struct{}, 1)
    36  	initial := auditlog.Config{
    37  		Enabled: false,
    38  	}
    39  	source := configSource{
    40  		watcher: watchertest.NewNotifyWatcher(configChanged),
    41  		cfg:     makeControllerConfig(false, false),
    42  	}
    43  
    44  	fakeTarget := apitesting.FakeAuditLog{}
    45  	var calls []auditlog.Config
    46  	factory := func(cfg auditlog.Config) auditlog.AuditLog {
    47  		calls = append(calls, cfg)
    48  		return &fakeTarget
    49  	}
    50  
    51  	w, err := auditconfigupdater.New(&source, initial, factory)
    52  	c.Assert(err, jc.ErrorIsNil)
    53  	defer workertest.CleanKill(c, w)
    54  
    55  	source.setConfig(makeControllerConfig(true, false))
    56  	configChanged <- ding
    57  
    58  	newConfig := waitForConfig(c, w, func(cfg auditlog.Config) bool {
    59  		return cfg.Enabled
    60  	})
    61  
    62  	c.Assert(newConfig.Enabled, gc.Equals, true)
    63  	c.Assert(newConfig.CaptureAPIArgs, gc.Equals, false)
    64  	c.Assert(newConfig.ExcludeMethods, gc.DeepEquals, set.NewStrings())
    65  	c.Assert(newConfig.Target, gc.Equals, auditlog.AuditLog(&fakeTarget))
    66  	c.Assert(calls, gc.HasLen, 1)
    67  }
    68  
    69  func waitForConfig(c *gc.C, w worker.Worker, predicate func(auditlog.Config) bool) auditlog.Config {
    70  	for a := jujutesting.LongAttempt.Start(); a.Next(); {
    71  		config := getWorkerConfig(c, w)
    72  		if predicate(config) {
    73  			return config
    74  		}
    75  	}
    76  	c.Fatalf("timed out waiting for matching config")
    77  	return auditlog.Config{}
    78  }
    79  
    80  func (s *updaterSuite) TestKeepsLogFileWhenAuditingDisabled(c *gc.C) {
    81  	configChanged := make(chan struct{}, 1)
    82  	initial := auditlog.Config{
    83  		Enabled: true,
    84  		Target:  &apitesting.FakeAuditLog{},
    85  	}
    86  	source := configSource{
    87  		watcher: watchertest.NewNotifyWatcher(configChanged),
    88  		cfg:     makeControllerConfig(true, false),
    89  	}
    90  
    91  	// Passing a nil factory means we can be sure it didn't try to
    92  	// create a new logfile.
    93  	w, err := auditconfigupdater.New(&source, initial, nil)
    94  	c.Assert(err, jc.ErrorIsNil)
    95  	defer workertest.CleanKill(c, w)
    96  
    97  	source.setConfig(makeControllerConfig(false, false))
    98  	configChanged <- ding
    99  
   100  	newConfig := waitForConfig(c, w, func(cfg auditlog.Config) bool {
   101  		return !cfg.Enabled
   102  	})
   103  
   104  	c.Assert(newConfig.Enabled, gc.Equals, false)
   105  	c.Assert(newConfig.Target, gc.Equals, initial.Target)
   106  }
   107  
   108  func (s *updaterSuite) TestKeepsLogFileWhenEnabled(c *gc.C) {
   109  	configChanged := make(chan struct{}, 1)
   110  	initial := auditlog.Config{
   111  		Enabled: false,
   112  		Target:  &apitesting.FakeAuditLog{},
   113  	}
   114  	source := configSource{
   115  		watcher: watchertest.NewNotifyWatcher(configChanged),
   116  		cfg:     makeControllerConfig(false, false),
   117  	}
   118  
   119  	// Passing a nil factory means we can be sure it didn't try to
   120  	// create a new logfile.
   121  	w, err := auditconfigupdater.New(&source, initial, nil)
   122  	c.Assert(err, jc.ErrorIsNil)
   123  	defer workertest.CleanKill(c, w)
   124  
   125  	source.setConfig(makeControllerConfig(true, false))
   126  	configChanged <- ding
   127  
   128  	newConfig := waitForConfig(c, w, func(cfg auditlog.Config) bool {
   129  		return cfg.Enabled
   130  	})
   131  
   132  	c.Assert(newConfig.Enabled, gc.Equals, true)
   133  	c.Assert(newConfig.Target, gc.Equals, initial.Target)
   134  }
   135  
   136  func (s *updaterSuite) TestChangingExcludeMethod(c *gc.C) {
   137  	configChanged := make(chan struct{}, 1)
   138  	initial := auditlog.Config{
   139  		Enabled:        true,
   140  		ExcludeMethods: set.NewStrings("Pink.Floyd"),
   141  		Target:         &apitesting.FakeAuditLog{},
   142  	}
   143  	source := configSource{
   144  		watcher: watchertest.NewNotifyWatcher(configChanged),
   145  		cfg:     makeControllerConfig(true, false, "Pink.Floyd"),
   146  	}
   147  
   148  	w, err := auditconfigupdater.New(&source, initial, nil)
   149  	c.Assert(err, jc.ErrorIsNil)
   150  	defer workertest.CleanKill(c, w)
   151  
   152  	source.setConfig(makeControllerConfig(true, false, "Pink.Floyd", "Led.Zeppelin"))
   153  	configChanged <- ding
   154  
   155  	waitForConfig(c, w, func(cfg auditlog.Config) bool {
   156  		return reflect.DeepEqual(cfg.ExcludeMethods, set.NewStrings("Pink.Floyd", "Led.Zeppelin"))
   157  	})
   158  
   159  	source.setConfig(makeControllerConfig(true, false, "Led.Zeppelin"))
   160  	configChanged <- ding
   161  
   162  	waitForConfig(c, w, func(cfg auditlog.Config) bool {
   163  		return reflect.DeepEqual(cfg.ExcludeMethods, set.NewStrings("Led.Zeppelin"))
   164  	})
   165  }
   166  
   167  func (s *updaterSuite) TestChangingCaptureArgs(c *gc.C) {
   168  	configChanged := make(chan struct{}, 1)
   169  	initial := auditlog.Config{
   170  		Enabled:        true,
   171  		CaptureAPIArgs: false,
   172  		Target:         &apitesting.FakeAuditLog{},
   173  	}
   174  	source := configSource{
   175  		watcher: watchertest.NewNotifyWatcher(configChanged),
   176  		cfg:     makeControllerConfig(true, false, "Pink.Floyd"),
   177  	}
   178  
   179  	w, err := auditconfigupdater.New(&source, initial, nil)
   180  	c.Assert(err, jc.ErrorIsNil)
   181  	defer workertest.CleanKill(c, w)
   182  
   183  	source.setConfig(makeControllerConfig(true, true))
   184  	configChanged <- ding
   185  
   186  	waitForConfig(c, w, func(cfg auditlog.Config) bool {
   187  		return cfg.CaptureAPIArgs
   188  	})
   189  }
   190  
   191  func makeControllerConfig(auditEnabled bool, captureArgs bool, methods ...interface{}) controller.Config {
   192  	result := map[string]interface{}{
   193  		"other-setting":             "something",
   194  		"auditing-enabled":          auditEnabled,
   195  		"audit-log-capture-args":    captureArgs,
   196  		"audit-log-exclude-methods": methods,
   197  	}
   198  	return result
   199  }
   200  
   201  func getWorkerConfig(c *gc.C, w worker.Worker) auditlog.Config {
   202  	getter, ok := w.(interface {
   203  		CurrentConfig() auditlog.Config
   204  	})
   205  	if !ok {
   206  		c.Fatalf("worker %T doesn't expose CurrentConfig()", w)
   207  	}
   208  	return getter.CurrentConfig()
   209  }
   210  
   211  type configSource struct {
   212  	mu      sync.Mutex
   213  	stub    testing.Stub
   214  	watcher *watchertest.NotifyWatcher
   215  	cfg     controller.Config
   216  }
   217  
   218  func (s *configSource) WatchControllerConfig() state.NotifyWatcher {
   219  	s.stub.AddCall("WatchControllerConfig")
   220  	return s.watcher
   221  }
   222  
   223  func (s *configSource) ControllerConfig() (controller.Config, error) {
   224  	s.mu.Lock()
   225  	defer s.mu.Unlock()
   226  	s.stub.AddCall("ControllerConfig")
   227  	if err := s.stub.NextErr(); err != nil {
   228  		return nil, err
   229  	}
   230  	return s.cfg, nil
   231  }
   232  
   233  func (s *configSource) setConfig(cfg controller.Config) {
   234  	s.mu.Lock()
   235  	defer s.mu.Unlock()
   236  	s.cfg = cfg
   237  }