github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/worker/metrics/collect/handler_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package collect_test
     5  
     6  import (
     7  	"net"
     8  	"os"
     9  	"path/filepath"
    10  	"strings"
    11  	"time"
    12  
    13  	"github.com/juju/names"
    14  	"github.com/juju/testing"
    15  	jc "github.com/juju/testing/checkers"
    16  	gc "gopkg.in/check.v1"
    17  	corecharm "gopkg.in/juju/charm.v6-unstable"
    18  
    19  	coretesting "github.com/juju/juju/testing"
    20  	"github.com/juju/juju/worker/dependency"
    21  	dt "github.com/juju/juju/worker/dependency/testing"
    22  	"github.com/juju/juju/worker/metrics/collect"
    23  	"github.com/juju/juju/worker/metrics/spool"
    24  	"github.com/juju/juju/worker/uniter/runner/context"
    25  )
    26  
    27  type handlerSuite struct {
    28  	coretesting.BaseSuite
    29  
    30  	manifoldConfig collect.ManifoldConfig
    31  	manifold       dependency.Manifold
    32  	dataDir        string
    33  	resources      dt.StubResources
    34  	recorder       *dummyRecorder
    35  	listener       *mockListener
    36  }
    37  
    38  var _ = gc.Suite(&handlerSuite{})
    39  
    40  func (s *handlerSuite) SetUpTest(c *gc.C) {
    41  	s.BaseSuite.SetUpTest(c)
    42  	s.manifoldConfig = collect.ManifoldConfig{
    43  		AgentName:       "agent-name",
    44  		MetricSpoolName: "metric-spool-name",
    45  		CharmDirName:    "charmdir-name",
    46  	}
    47  	s.manifold = collect.Manifold(s.manifoldConfig)
    48  	s.dataDir = c.MkDir()
    49  
    50  	// create unit agent base dir so that hooks can run.
    51  	err := os.MkdirAll(filepath.Join(s.dataDir, "agents", "unit-u-0"), 0777)
    52  	c.Assert(err, jc.ErrorIsNil)
    53  
    54  	s.recorder = &dummyRecorder{
    55  		charmURL: "local:trusty/metered-1",
    56  		unitTag:  "metered/0",
    57  		metrics: map[string]corecharm.Metric{
    58  			"pings": corecharm.Metric{
    59  				Description: "test metric",
    60  				Type:        corecharm.MetricTypeAbsolute,
    61  			},
    62  			"juju-units": corecharm.Metric{},
    63  		},
    64  	}
    65  
    66  	s.resources = dt.StubResources{
    67  		"agent-name":        dt.StubResource{Output: &dummyAgent{dataDir: s.dataDir}},
    68  		"metric-spool-name": dt.StubResource{Output: &mockMetricFactory{recorder: s.recorder}},
    69  		"charmdir-name":     dt.StubResource{Output: &dummyCharmdir{aborted: false}},
    70  	}
    71  
    72  	s.PatchValue(collect.NewRecorder,
    73  		func(_ names.UnitTag, _ context.Paths, _ spool.MetricFactory) (spool.MetricRecorder, error) {
    74  			// Return a dummyRecorder here, because otherwise a real one
    75  			// *might* get instantiated and error out, if the periodic worker
    76  			// happens to fire before the worker shuts down (as seen in
    77  			// LP:#1497355).
    78  			return &dummyRecorder{
    79  				charmURL: "local:trusty/metered-1",
    80  				unitTag:  "metered/0",
    81  				metrics: map[string]corecharm.Metric{
    82  					"pings": corecharm.Metric{
    83  						Description: "test metric",
    84  						Type:        corecharm.MetricTypeAbsolute,
    85  					},
    86  					"juju-units": corecharm.Metric{},
    87  				},
    88  			}, nil
    89  		},
    90  	)
    91  	s.PatchValue(collect.ReadCharm,
    92  		func(_ names.UnitTag, _ context.Paths) (*corecharm.URL, map[string]corecharm.Metric, error) {
    93  			return corecharm.MustParseURL("local:trusty/metered-1"),
    94  				map[string]corecharm.Metric{
    95  					"pings":      corecharm.Metric{Description: "test metric", Type: corecharm.MetricTypeAbsolute},
    96  					"juju-units": corecharm.Metric{},
    97  				}, nil
    98  		},
    99  	)
   100  	s.listener = &mockListener{}
   101  	s.PatchValue(collect.NewSocketListener, collect.NewSocketListenerFnc(s.listener))
   102  }
   103  
   104  func (s *handlerSuite) TestListenerStart(c *gc.C) {
   105  	worker, err := s.manifold.Start(s.resources.Context())
   106  	c.Assert(err, jc.ErrorIsNil)
   107  	c.Assert(worker, gc.NotNil)
   108  	c.Assert(s.listener.Calls(), gc.HasLen, 0)
   109  	worker.Kill()
   110  	err = worker.Wait()
   111  	c.Assert(err, jc.ErrorIsNil)
   112  	s.listener.CheckCall(c, 0, "Stop")
   113  }
   114  
   115  func (s *handlerSuite) TestJujuUnitsBuiltinMetric(c *gc.C) {
   116  	worker, err := s.manifold.Start(s.resources.Context())
   117  	c.Assert(err, jc.ErrorIsNil)
   118  	c.Assert(worker, gc.NotNil)
   119  	c.Assert(s.listener.Calls(), gc.HasLen, 0)
   120  
   121  	conn, err := s.listener.trigger()
   122  	c.Assert(err, jc.ErrorIsNil)
   123  	c.Assert(conn.Calls(), gc.HasLen, 3)
   124  	conn.CheckCall(c, 2, "Close")
   125  
   126  	responseString := strings.Trim(string(conn.data), " \n\t")
   127  	c.Assert(responseString, gc.Equals, "ok")
   128  	c.Assert(s.recorder.batches, gc.HasLen, 1)
   129  
   130  	worker.Kill()
   131  	err = worker.Wait()
   132  	c.Assert(err, jc.ErrorIsNil)
   133  	s.listener.CheckCall(c, 0, "Stop")
   134  }
   135  
   136  func (s *handlerSuite) TestHandlerError(c *gc.C) {
   137  	worker, err := s.manifold.Start(s.resources.Context())
   138  	c.Assert(err, jc.ErrorIsNil)
   139  	c.Assert(worker, gc.NotNil)
   140  	c.Assert(s.listener.Calls(), gc.HasLen, 0)
   141  
   142  	s.recorder.err = "well, this is embarassing"
   143  
   144  	conn, err := s.listener.trigger()
   145  	c.Assert(err, gc.ErrorMatches, "failed to collect metrics: error adding 'juju-units' metric: well, this is embarassing")
   146  	c.Assert(conn.Calls(), gc.HasLen, 3)
   147  	conn.CheckCall(c, 2, "Close")
   148  
   149  	responseString := strings.Trim(string(conn.data), " \n\t")
   150  	c.Assert(responseString, gc.Matches, ".*well, this is embarassing")
   151  	c.Assert(s.recorder.batches, gc.HasLen, 0)
   152  
   153  	worker.Kill()
   154  	err = worker.Wait()
   155  	c.Assert(err, jc.ErrorIsNil)
   156  	s.listener.CheckCall(c, 0, "Stop")
   157  }
   158  
   159  type mockListener struct {
   160  	testing.Stub
   161  	handler spool.ConnectionHandler
   162  }
   163  
   164  func (l *mockListener) trigger() (*mockConnection, error) {
   165  	conn := &mockConnection{}
   166  	err := l.handler.Handle(conn)
   167  	if err != nil {
   168  		return conn, err
   169  	}
   170  	return conn, nil
   171  }
   172  
   173  // Stop implements the stopper interface.
   174  func (l *mockListener) Stop() {
   175  	l.AddCall("Stop")
   176  }
   177  
   178  func (l *mockListener) SetHandler(handler spool.ConnectionHandler) {
   179  	l.handler = handler
   180  }
   181  
   182  type mockConnection struct {
   183  	net.Conn
   184  	testing.Stub
   185  	data []byte
   186  }
   187  
   188  // SetDeadline implements the net.Conn interface.
   189  func (c *mockConnection) SetDeadline(t time.Time) error {
   190  	c.AddCall("SetDeadline", t)
   191  	return nil
   192  }
   193  
   194  // Write implements the net.Conn interface.
   195  func (c *mockConnection) Write(data []byte) (int, error) {
   196  	c.AddCall("Write", data)
   197  	c.data = data
   198  	return len(data), nil
   199  }
   200  
   201  // Close implements the net.Conn interface.
   202  func (c *mockConnection) Close() error {
   203  	c.AddCall("Close")
   204  	return nil
   205  }
   206  
   207  type mockMetricFactory struct {
   208  	spool.MetricFactory
   209  	recorder *dummyRecorder
   210  }
   211  
   212  // Recorder implements the spool.MetricFactory interface.
   213  func (f *mockMetricFactory) Recorder(metrics map[string]corecharm.Metric, charmURL, unitTag string) (spool.MetricRecorder, error) {
   214  	return f.recorder, nil
   215  }