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

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package logforwarder_test
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/loggo"
    11  	"github.com/juju/testing"
    12  	jc "github.com/juju/testing/checkers"
    13  	gc "gopkg.in/check.v1"
    14  	"gopkg.in/juju/worker.v1/workertest"
    15  
    16  	"github.com/juju/juju/api/base"
    17  	"github.com/juju/juju/apiserver/params"
    18  	"github.com/juju/juju/core/watcher"
    19  	"github.com/juju/juju/logfwd"
    20  	"github.com/juju/juju/logfwd/syslog"
    21  	coretesting "github.com/juju/juju/testing"
    22  	"github.com/juju/juju/version"
    23  	"github.com/juju/juju/worker/logforwarder"
    24  )
    25  
    26  type LogForwarderSuite struct {
    27  	testing.IsolationSuite
    28  
    29  	stream *stubStream
    30  	sender *stubSender
    31  	rec    logfwd.Record
    32  }
    33  
    34  var _ = gc.Suite(&LogForwarderSuite{})
    35  
    36  func (s *LogForwarderSuite) SetUpTest(c *gc.C) {
    37  	s.IsolationSuite.SetUpTest(c)
    38  
    39  	s.stream = newStubStream()
    40  	s.sender = newStubSender()
    41  	s.rec = logfwd.Record{
    42  		Origin: logfwd.Origin{
    43  			ControllerUUID: "feebdaed-2f18-4fd2-967d-db9663db7bea",
    44  			ModelUUID:      "deadbeef-2f18-4fd2-967d-db9663db7bea",
    45  			Hostname:       "machine-99.deadbeef-2f18-4fd2-967d-db9663db7bea",
    46  			Type:           logfwd.OriginTypeMachine,
    47  			Name:           "99",
    48  			Software: logfwd.Software{
    49  				PrivateEnterpriseNumber: 28978,
    50  				Name:                    "jujud-machine-agent",
    51  				Version:                 version.Current,
    52  			},
    53  		},
    54  		ID:        10,
    55  		Timestamp: time.Now(),
    56  		Level:     loggo.INFO,
    57  		Location: logfwd.SourceLocation{
    58  			Module:   "api.logstream.test",
    59  			Filename: "test.go",
    60  			Line:     42,
    61  		},
    62  		Message: "send to 10.0.0.1",
    63  	}
    64  }
    65  
    66  func (s *LogForwarderSuite) newLogForwarderArgs(
    67  	c *gc.C,
    68  	stream logforwarder.LogStream,
    69  	sender *stubSender,
    70  ) logforwarder.OpenLogForwarderArgs {
    71  	api := &mockLogForwardConfig{
    72  		enabled: stream != nil,
    73  		host:    "10.0.0.1",
    74  	}
    75  	return s.newLogForwarderArgsWithAPI(c, api, stream, sender)
    76  }
    77  
    78  func (s *LogForwarderSuite) newLogForwarderArgsWithAPI(
    79  	c *gc.C,
    80  	configAPI logforwarder.LogForwardConfig,
    81  	stream logforwarder.LogStream,
    82  	sender *stubSender,
    83  ) logforwarder.OpenLogForwarderArgs {
    84  	return logforwarder.OpenLogForwarderArgs{
    85  		Caller:           &mockCaller{},
    86  		LogForwardConfig: configAPI,
    87  		ControllerUUID:   "feebdaed-2f18-4fd2-967d-db9663db7bea",
    88  		OpenSink: func(cfg *syslog.RawConfig) (*logforwarder.LogSink, error) {
    89  			sender.host = cfg.Host
    90  			sink := &logforwarder.LogSink{
    91  				sender,
    92  			}
    93  			return sink, nil
    94  		},
    95  		OpenLogStream: func(_ base.APICaller, _ params.LogStreamConfig, controllerUUID string) (logforwarder.LogStream, error) {
    96  			c.Assert(controllerUUID, gc.Equals, "feebdaed-2f18-4fd2-967d-db9663db7bea")
    97  			return stream, nil
    98  		},
    99  	}
   100  }
   101  
   102  func (s *LogForwarderSuite) TestOne(c *gc.C) {
   103  	s.stream.addRecords(c, s.rec)
   104  	lf, err := logforwarder.NewLogForwarder(s.newLogForwarderArgs(c, s.stream, s.sender))
   105  	c.Assert(err, jc.ErrorIsNil)
   106  	defer workertest.DirtyKill(c, lf)
   107  
   108  	s.sender.waitForSend(c)
   109  	workertest.CleanKill(c, lf)
   110  	s.sender.stub.CheckCalls(c, []testing.StubCall{
   111  		{"Send", []interface{}{[]logfwd.Record{s.rec}}},
   112  		{"Close", nil},
   113  	})
   114  }
   115  
   116  func (s *LogForwarderSuite) TestConfigChange(c *gc.C) {
   117  	rec0 := s.rec
   118  	rec1 := s.rec
   119  	rec1.ID = 11
   120  
   121  	api := &mockLogForwardConfig{
   122  		enabled: true,
   123  		host:    "10.0.0.1",
   124  	}
   125  	lf, err := logforwarder.NewLogForwarder(s.newLogForwarderArgsWithAPI(c, api, s.stream, s.sender))
   126  	c.Assert(err, jc.ErrorIsNil)
   127  	defer workertest.DirtyKill(c, lf)
   128  
   129  	// Send the first record.
   130  	s.stream.addRecords(c, rec0)
   131  	s.sender.waitForSend(c)
   132  
   133  	// Config change.
   134  	api.host = "10.0.0.2"
   135  	api.changes <- struct{}{}
   136  	s.sender.waitForClose(c)
   137  
   138  	// Send the second record.
   139  	s.stream.addRecords(c, rec1)
   140  	s.sender.waitForSend(c)
   141  
   142  	workertest.CleanKill(c, lf)
   143  
   144  	// Check that both records were sent with the config change
   145  	// applied for the second send.
   146  	rec1.Message = "send to 10.0.0.2"
   147  	s.sender.stub.CheckCalls(c, []testing.StubCall{
   148  		{"Send", []interface{}{[]logfwd.Record{rec0}}},
   149  		{"Close", nil},
   150  		{"Send", []interface{}{[]logfwd.Record{rec1}}},
   151  		{"Close", nil},
   152  	})
   153  }
   154  
   155  func (s *LogForwarderSuite) TestNotEnabled(c *gc.C) {
   156  	lf, err := logforwarder.NewLogForwarder(s.newLogForwarderArgs(c, nil, s.sender))
   157  	c.Assert(err, jc.ErrorIsNil)
   158  
   159  	time.Sleep(coretesting.ShortWait)
   160  	workertest.CleanKill(c, lf)
   161  
   162  	// There should be no stream or sender activity when log
   163  	// forwarding is disabled.
   164  	s.stream.stub.CheckCallNames(c)
   165  	s.sender.stub.CheckCallNames(c)
   166  }
   167  
   168  func (s *LogForwarderSuite) TestStreamError(c *gc.C) {
   169  	failure := errors.New("<failure>")
   170  	s.stream.stub.SetErrors(nil, failure)
   171  	s.stream.addRecords(c, s.rec)
   172  
   173  	lf, err := logforwarder.NewLogForwarder(s.newLogForwarderArgs(c, s.stream, s.sender))
   174  	c.Assert(err, jc.ErrorIsNil)
   175  	defer workertest.DirtyKill(c, lf)
   176  
   177  	err = workertest.CheckKilled(c, lf)
   178  	c.Check(errors.Cause(err), gc.Equals, failure)
   179  
   180  	s.sender.stub.CheckCalls(c, []testing.StubCall{
   181  		{"Send", []interface{}{[]logfwd.Record{s.rec}}},
   182  		{"Close", nil},
   183  	})
   184  }
   185  
   186  func (s *LogForwarderSuite) TestSenderError(c *gc.C) {
   187  	failure := errors.New("<failure>")
   188  	s.sender.stub.SetErrors(nil, failure)
   189  
   190  	rec0 := s.rec
   191  	rec1 := s.rec
   192  	rec1.ID = 11
   193  	s.stream.addRecords(c, rec0, rec1)
   194  
   195  	lf, err := logforwarder.NewLogForwarder(s.newLogForwarderArgs(c, s.stream, s.sender))
   196  	c.Assert(err, jc.ErrorIsNil)
   197  	defer workertest.DirtyKill(c, lf)
   198  
   199  	err = workertest.CheckKilled(c, lf)
   200  	c.Check(errors.Cause(err), gc.Equals, failure)
   201  
   202  	s.sender.stub.CheckCalls(c, []testing.StubCall{
   203  		{"Send", []interface{}{[]logfwd.Record{rec0}}},
   204  		{"Send", []interface{}{[]logfwd.Record{rec1}}},
   205  		{"Close", nil},
   206  	})
   207  }
   208  
   209  type mockLogForwardConfig struct {
   210  	enabled bool
   211  	host    string
   212  	changes chan struct{}
   213  }
   214  
   215  type mockWatcher struct {
   216  	watcher.NotifyWatcher
   217  	changes chan struct{}
   218  }
   219  
   220  func (m *mockWatcher) Changes() watcher.NotifyChannel {
   221  	return m.changes
   222  }
   223  
   224  func (*mockWatcher) Kill() {
   225  }
   226  
   227  func (*mockWatcher) Wait() error {
   228  	return nil
   229  }
   230  
   231  type mockCaller struct {
   232  	base.APICaller
   233  }
   234  
   235  func (*mockCaller) APICall(objType string, version int, id, request string, params, response interface{}) error {
   236  	return nil
   237  }
   238  
   239  func (*mockCaller) BestFacadeVersion(facade string) int {
   240  	return 0
   241  }
   242  
   243  func (c *mockLogForwardConfig) WatchForLogForwardConfigChanges() (watcher.NotifyWatcher, error) {
   244  	c.changes = make(chan struct{}, 1)
   245  	c.changes <- struct{}{}
   246  	return &mockWatcher{
   247  		changes: c.changes,
   248  	}, nil
   249  }
   250  
   251  func (c *mockLogForwardConfig) LogForwardConfig() (*syslog.RawConfig, bool, error) {
   252  	return &syslog.RawConfig{
   253  		Enabled:    c.enabled,
   254  		Host:       c.host,
   255  		CACert:     coretesting.CACert,
   256  		ClientCert: coretesting.ServerCert,
   257  		ClientKey:  coretesting.ServerKey,
   258  	}, true, nil
   259  }
   260  
   261  type stubStream struct {
   262  	stub     *testing.Stub
   263  	nextRecs chan logfwd.Record
   264  }
   265  
   266  func newStubStream() *stubStream {
   267  	return &stubStream{
   268  		stub:     new(testing.Stub),
   269  		nextRecs: make(chan logfwd.Record, 16),
   270  	}
   271  }
   272  
   273  func (s *stubStream) addRecords(c *gc.C, recs ...logfwd.Record) {
   274  	for _, rec := range recs {
   275  		s.nextRecs <- rec
   276  	}
   277  }
   278  
   279  func (s *stubStream) Next() ([]logfwd.Record, error) {
   280  	s.stub.AddCall("Next")
   281  	if err := s.stub.NextErr(); err != nil {
   282  		return []logfwd.Record{}, errors.Trace(err)
   283  	}
   284  	return []logfwd.Record{<-s.nextRecs}, nil
   285  }
   286  
   287  type stubSender struct {
   288  	stub     *testing.Stub
   289  	activity chan string
   290  	host     string
   291  }
   292  
   293  func newStubSender() *stubSender {
   294  	return &stubSender{
   295  		stub:     new(testing.Stub),
   296  		activity: make(chan string, 16),
   297  	}
   298  }
   299  
   300  func (s *stubSender) Send(records []logfwd.Record) error {
   301  	for i, rec := range records {
   302  		rec.Message = "send to " + s.host
   303  		records[i] = rec
   304  	}
   305  	s.stub.AddCall("Send", records)
   306  	s.activity <- "Send"
   307  	return errors.Trace(s.stub.NextErr())
   308  }
   309  
   310  func (s *stubSender) Close() error {
   311  	s.stub.AddCall("Close")
   312  	s.activity <- "Close"
   313  	return errors.Trace(s.stub.NextErr())
   314  }
   315  
   316  func (s *stubSender) waitForSend(c *gc.C) {
   317  	s.waitForActivity(c, "Send")
   318  }
   319  
   320  func (s *stubSender) waitForClose(c *gc.C) {
   321  	s.waitForActivity(c, "Close")
   322  }
   323  
   324  func (s *stubSender) waitForActivity(c *gc.C, name string) {
   325  	select {
   326  	case a := <-s.activity:
   327  		if a != name {
   328  			c.Fatalf("expected %v, got %v", name, a)
   329  		}
   330  	case <-time.After(coretesting.LongWait):
   331  		c.Fatalf("timeout out waiting for %v", name)
   332  	}
   333  }