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 }