github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/worker/metrics/collect/manifold_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package collect_test
     5  
     6  import (
     7  	"os"
     8  	"path/filepath"
     9  	"time"
    10  
    11  	"github.com/juju/names"
    12  	jc "github.com/juju/testing/checkers"
    13  	"github.com/juju/utils"
    14  	gc "gopkg.in/check.v1"
    15  	corecharm "gopkg.in/juju/charm.v6-unstable"
    16  
    17  	"github.com/juju/juju/agent"
    18  	"github.com/juju/juju/api/base"
    19  	coretesting "github.com/juju/juju/testing"
    20  	"github.com/juju/juju/worker/charmdir"
    21  	"github.com/juju/juju/worker/dependency"
    22  	dt "github.com/juju/juju/worker/dependency/testing"
    23  	"github.com/juju/juju/worker/metrics/collect"
    24  	"github.com/juju/juju/worker/metrics/spool"
    25  	"github.com/juju/juju/worker/uniter/runner/context"
    26  	"github.com/juju/juju/worker/uniter/runner/jujuc"
    27  )
    28  
    29  type ManifoldSuite struct {
    30  	coretesting.BaseSuite
    31  
    32  	dataDir  string
    33  	oldLcAll string
    34  
    35  	manifoldConfig collect.ManifoldConfig
    36  	manifold       dependency.Manifold
    37  	dummyResources dt.StubResources
    38  	getResource    dependency.GetResourceFunc
    39  }
    40  
    41  var _ = gc.Suite(&ManifoldSuite{})
    42  
    43  func (s *ManifoldSuite) SetUpTest(c *gc.C) {
    44  	s.BaseSuite.SetUpTest(c)
    45  	s.manifoldConfig = collect.ManifoldConfig{
    46  		AgentName:       "agent-name",
    47  		APICallerName:   "apicaller-name",
    48  		MetricSpoolName: "metric-spool-name",
    49  		CharmDirName:    "charmdir-name",
    50  	}
    51  	s.manifold = collect.Manifold(s.manifoldConfig)
    52  	s.dataDir = c.MkDir()
    53  
    54  	// create unit agent base dir so that hooks can run.
    55  	err := os.MkdirAll(filepath.Join(s.dataDir, "agents", "unit-u-0"), 0777)
    56  	c.Assert(err, jc.ErrorIsNil)
    57  
    58  	s.dummyResources = dt.StubResources{
    59  		"agent-name":        dt.StubResource{Output: &dummyAgent{dataDir: s.dataDir}},
    60  		"apicaller-name":    dt.StubResource{Output: &dummyAPICaller{}},
    61  		"metric-spool-name": dt.StubResource{Output: &dummyMetricFactory{}},
    62  		"charmdir-name":     dt.StubResource{Output: &dummyCharmdir{available: true}},
    63  	}
    64  	s.getResource = dt.StubGetResource(s.dummyResources)
    65  }
    66  
    67  // TestInputs ensures the collect manifold has the expected defined inputs.
    68  func (s *ManifoldSuite) TestInputs(c *gc.C) {
    69  	c.Check(s.manifold.Inputs, jc.DeepEquals, []string{
    70  		"agent-name", "apicaller-name", "metric-spool-name", "charmdir-name",
    71  	})
    72  }
    73  
    74  // TestStartMissingDeps ensures that the manifold correctly handles a missing
    75  // resource dependency.
    76  func (s *ManifoldSuite) TestStartMissingDeps(c *gc.C) {
    77  	for _, missingDep := range []string{
    78  		"agent-name", "apicaller-name", "metric-spool-name", "charmdir-name",
    79  	} {
    80  		testResources := dt.StubResources{}
    81  		for k, v := range s.dummyResources {
    82  			if k == missingDep {
    83  				testResources[k] = dt.StubResource{Error: dependency.ErrMissing}
    84  			} else {
    85  				testResources[k] = v
    86  			}
    87  		}
    88  		getResource := dt.StubGetResource(testResources)
    89  		worker, err := s.manifold.Start(getResource)
    90  		c.Check(worker, gc.IsNil)
    91  		c.Check(err, gc.Equals, dependency.ErrMissing)
    92  	}
    93  }
    94  
    95  // TestCollectWorkerStarts ensures that the manifold correctly sets up the worker.
    96  func (s *ManifoldSuite) TestCollectWorkerStarts(c *gc.C) {
    97  	s.PatchValue(collect.NewRecorder,
    98  		func(_ names.UnitTag, _ context.Paths, _ collect.UnitCharmLookup, _ spool.MetricFactory) (spool.MetricRecorder, error) {
    99  			// Return a dummyRecorder here, because otherwise a real one
   100  			// *might* get instantiated and error out, if the periodic worker
   101  			// happens to fire before the worker shuts down (as seen in
   102  			// LP:#1497355).
   103  			return &dummyRecorder{
   104  				charmURL: "cs:ubuntu-1",
   105  				unitTag:  "ubuntu/0",
   106  			}, nil
   107  		})
   108  	getResource := dt.StubGetResource(s.dummyResources)
   109  	worker, err := s.manifold.Start(getResource)
   110  	c.Assert(err, jc.ErrorIsNil)
   111  	c.Assert(worker, gc.NotNil)
   112  	worker.Kill()
   113  	err = worker.Wait()
   114  	c.Assert(err, jc.ErrorIsNil)
   115  }
   116  
   117  // TestJujuUnitsBuiltinMetric tests that the juju-units built-in metric is collected
   118  // with a mock implementation of newRecorder.
   119  func (s *ManifoldSuite) TestJujuUnitsBuiltinMetric(c *gc.C) {
   120  	recorder := &dummyRecorder{
   121  		charmURL:         "cs:wordpress-37",
   122  		unitTag:          "wp/0",
   123  		isDeclaredMetric: true,
   124  	}
   125  	s.PatchValue(collect.NewRecorder,
   126  		func(_ names.UnitTag, _ context.Paths, _ collect.UnitCharmLookup, _ spool.MetricFactory) (spool.MetricRecorder, error) {
   127  			return recorder, nil
   128  		})
   129  	collectEntity, err := (*collect.NewCollect)(s.manifoldConfig, s.getResource)
   130  	c.Assert(err, jc.ErrorIsNil)
   131  	err = collectEntity.Do(nil)
   132  	c.Assert(err, jc.ErrorIsNil)
   133  	c.Assert(recorder.closed, jc.IsTrue)
   134  	c.Assert(recorder.batches, gc.HasLen, 1)
   135  	c.Assert(recorder.batches[0].CharmURL, gc.Equals, "cs:wordpress-37")
   136  	c.Assert(recorder.batches[0].UnitTag, gc.Equals, "wp/0")
   137  	c.Assert(recorder.batches[0].Metrics, gc.HasLen, 1)
   138  	c.Assert(recorder.batches[0].Metrics[0].Key, gc.Equals, "juju-units")
   139  	c.Assert(recorder.batches[0].Metrics[0].Value, gc.Equals, "1")
   140  }
   141  
   142  // TestAvailability tests that the charmdir resource is properly checked.
   143  func (s *ManifoldSuite) TestAvailability(c *gc.C) {
   144  	recorder := &dummyRecorder{
   145  		charmURL:         "cs:wordpress-37",
   146  		unitTag:          "wp/0",
   147  		isDeclaredMetric: true,
   148  	}
   149  	s.PatchValue(collect.NewRecorder,
   150  		func(_ names.UnitTag, _ context.Paths, _ collect.UnitCharmLookup, _ spool.MetricFactory) (spool.MetricRecorder, error) {
   151  			return recorder, nil
   152  		})
   153  	charmdir := &dummyCharmdir{available: false}
   154  	s.dummyResources["charmdir-name"] = dt.StubResource{Output: charmdir}
   155  	getResource := dt.StubGetResource(s.dummyResources)
   156  	collectEntity, err := (*collect.NewCollect)(s.manifoldConfig, getResource)
   157  	c.Assert(err, jc.ErrorIsNil)
   158  	err = collectEntity.Do(nil)
   159  	c.Assert(err, jc.ErrorIsNil)
   160  	c.Assert(recorder.batches, gc.HasLen, 0)
   161  
   162  	charmdir = &dummyCharmdir{available: true}
   163  	s.dummyResources["charmdir-name"] = dt.StubResource{Output: charmdir}
   164  	getResource = dt.StubGetResource(s.dummyResources)
   165  	collectEntity, err = (*collect.NewCollect)(s.manifoldConfig, getResource)
   166  	c.Assert(err, jc.ErrorIsNil)
   167  	err = collectEntity.Do(nil)
   168  	c.Assert(err, jc.ErrorIsNil)
   169  	c.Assert(recorder.closed, jc.IsTrue)
   170  	c.Assert(recorder.batches, gc.HasLen, 1)
   171  }
   172  
   173  // TestNoMetricsDeclared tests that if metrics are not declared, none are
   174  // collected, not even builtin.
   175  func (s *ManifoldSuite) TestNoMetricsDeclared(c *gc.C) {
   176  	recorder := &dummyRecorder{
   177  		charmURL:         "cs:wordpress-37",
   178  		unitTag:          "wp/0",
   179  		isDeclaredMetric: false,
   180  	}
   181  	s.PatchValue(collect.NewRecorder,
   182  		func(_ names.UnitTag, _ context.Paths, _ collect.UnitCharmLookup, _ spool.MetricFactory) (spool.MetricRecorder, error) {
   183  			return recorder, nil
   184  		})
   185  	collectEntity, err := (*collect.NewCollect)(s.manifoldConfig, s.getResource)
   186  	c.Assert(err, jc.ErrorIsNil)
   187  	err = collectEntity.Do(nil)
   188  	c.Assert(err, jc.ErrorIsNil)
   189  	c.Assert(recorder.closed, jc.IsTrue)
   190  	c.Assert(recorder.batches, gc.HasLen, 0)
   191  }
   192  
   193  type dummyAgent struct {
   194  	agent.Agent
   195  	dataDir string
   196  }
   197  
   198  func (a dummyAgent) CurrentConfig() agent.Config {
   199  	return &dummyAgentConfig{dataDir: a.dataDir}
   200  }
   201  
   202  type dummyAgentConfig struct {
   203  	agent.Config
   204  	dataDir string
   205  }
   206  
   207  // Tag implements agent.AgentConfig.
   208  func (ac dummyAgentConfig) Tag() names.Tag {
   209  	return names.NewUnitTag("u/0")
   210  }
   211  
   212  // DataDir implements agent.AgentConfig.
   213  func (ac dummyAgentConfig) DataDir() string {
   214  	return ac.dataDir
   215  }
   216  
   217  type dummyAPICaller struct {
   218  	base.APICaller
   219  }
   220  
   221  type dummyCharmdir struct {
   222  	charmdir.Consumer
   223  
   224  	available bool
   225  }
   226  
   227  func (a *dummyCharmdir) Run(f func() error) error {
   228  	if a.available {
   229  		return f()
   230  	}
   231  	return nil
   232  }
   233  
   234  type dummyMetricFactory struct {
   235  	spool.MetricFactory
   236  }
   237  
   238  type dummyRecorder struct {
   239  	spool.MetricRecorder
   240  
   241  	// inputs
   242  	charmURL, unitTag string
   243  	metrics           map[string]corecharm.Metric
   244  	isDeclaredMetric  bool
   245  
   246  	// outputs
   247  	closed  bool
   248  	batches []spool.MetricBatch
   249  }
   250  
   251  func (r *dummyRecorder) AddMetric(key, value string, created time.Time) error {
   252  	then := time.Date(2015, 8, 20, 15, 48, 0, 0, time.UTC)
   253  	r.batches = append(r.batches, spool.MetricBatch{
   254  		CharmURL: r.charmURL,
   255  		UUID:     utils.MustNewUUID().String(),
   256  		Created:  then,
   257  		Metrics: []jujuc.Metric{{
   258  			Key:   key,
   259  			Value: value,
   260  			Time:  then,
   261  		}},
   262  		UnitTag: r.unitTag,
   263  	})
   264  	return nil
   265  }
   266  
   267  func (r *dummyRecorder) IsDeclaredMetric(key string) bool {
   268  	if r.isDeclaredMetric {
   269  		return true
   270  	}
   271  	_, ok := r.metrics[key]
   272  	return ok
   273  }
   274  
   275  func (r *dummyRecorder) Close() error {
   276  	r.closed = true
   277  	return nil
   278  }