github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/agent/metricsender/metricsender_test.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package metricsender_test 5 6 import ( 7 "errors" 8 "time" 9 10 "github.com/juju/clock" 11 "github.com/juju/clock/testclock" 12 wireformat "github.com/juju/romulus/wireformat/metrics" 13 jc "github.com/juju/testing/checkers" 14 gc "gopkg.in/check.v1" 15 16 "github.com/juju/juju/apiserver/facades/agent/metricsender" 17 "github.com/juju/juju/apiserver/facades/agent/metricsender/testing" 18 jujujutesting "github.com/juju/juju/juju/testing" 19 "github.com/juju/juju/state" 20 "github.com/juju/juju/testing/factory" 21 ) 22 23 type MetricSenderSuite struct { 24 jujujutesting.JujuConnSuite 25 meteredUnit *state.Unit 26 credUnit *state.Unit 27 clock clock.Clock 28 } 29 30 // TODO(externalreality): This may go away once the separation of 31 // responsibilities between state.State and the different model types become 32 // visible in the code. 33 type TestSenderBackend struct { 34 *state.State 35 *state.Model 36 } 37 38 var _ = gc.Suite(&MetricSenderSuite{}) 39 40 var _ metricsender.MetricSender = (*testing.MockSender)(nil) 41 42 var _ metricsender.MetricSender = (*metricsender.NopSender)(nil) 43 44 func (s *MetricSenderSuite) SetUpTest(c *gc.C) { 45 s.JujuConnSuite.SetUpTest(c) 46 47 meteredCharm := s.Factory.MakeCharm(c, &factory.CharmParams{Name: "metered", URL: "cs:quantal/metered"}) 48 // Application with metrics credentials set. 49 credApp := s.Factory.MakeApplication(c, &factory.ApplicationParams{Charm: meteredCharm, Name: "cred"}) 50 err := credApp.SetMetricCredentials([]byte("something here")) 51 c.Assert(err, jc.ErrorIsNil) 52 meteredApp := s.Factory.MakeApplication(c, &factory.ApplicationParams{Charm: meteredCharm}) 53 s.meteredUnit = s.Factory.MakeUnit(c, &factory.UnitParams{Application: meteredApp, SetCharmURL: true}) 54 s.credUnit = s.Factory.MakeUnit(c, &factory.UnitParams{Application: credApp, SetCharmURL: true}) 55 s.clock = testclock.NewClock(time.Now()) 56 } 57 58 func (s *MetricSenderSuite) TestToWire(c *gc.C) { 59 now := time.Now().Round(time.Second) 60 metric := s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.credUnit, Sent: false, Time: &now}) 61 result := metricsender.ToWire(metric, s.Model.Name()) 62 m := metric.Metrics()[0] 63 metrics := []wireformat.Metric{ 64 { 65 Key: m.Key, 66 Value: m.Value, 67 Time: m.Time.UTC(), 68 Labels: map[string]string{ 69 "foo": "bar", 70 }, 71 }, 72 } 73 expected := &wireformat.MetricBatch{ 74 UUID: metric.UUID(), 75 ModelUUID: metric.ModelUUID(), 76 ModelName: "controller", 77 UnitName: metric.Unit(), 78 CharmUrl: metric.CharmURL(), 79 Created: metric.Created().UTC(), 80 Metrics: metrics, 81 Credentials: metric.Credentials(), 82 SLACredentials: metric.SLACredentials(), 83 } 84 c.Assert(result, gc.DeepEquals, expected) 85 } 86 87 func (s *MetricSenderSuite) TestSendMetricsFromNewModel(c *gc.C) { 88 var sender testing.MockSender 89 now := time.Now() 90 clock := testclock.NewClock(time.Now()) 91 92 state := s.Factory.MakeModel(c, &factory.ModelParams{Name: "test-model"}) 93 defer state.Close() 94 f := factory.NewFactory(state, s.StatePool) 95 model, err := state.Model() 96 c.Assert(err, jc.ErrorIsNil) 97 modelName := model.Name() 98 c.Assert(modelName, gc.Equals, "test-model") 99 100 meteredCharm := f.MakeCharm(c, &factory.CharmParams{Name: "metered", URL: "cs:quantal/metered"}) 101 // Application with metrics credentials set. 102 credApp := f.MakeApplication(c, &factory.ApplicationParams{Charm: meteredCharm, Name: "cred"}) 103 err = credApp.SetMetricCredentials([]byte("something here")) 104 c.Assert(err, jc.ErrorIsNil) 105 meteredApp := f.MakeApplication(c, &factory.ApplicationParams{Charm: meteredCharm}) 106 meteredUnit := f.MakeUnit(c, &factory.UnitParams{Application: meteredApp, SetCharmURL: true}) 107 credUnit := f.MakeUnit(c, &factory.UnitParams{Application: credApp, SetCharmURL: true}) 108 109 f.MakeMetric(c, &factory.MetricParams{Unit: credUnit, Time: &now}) 110 f.MakeMetric(c, &factory.MetricParams{Unit: meteredUnit, Time: &now}) 111 f.MakeMetric(c, &factory.MetricParams{Unit: credUnit, Sent: true, Time: &now}) 112 err = metricsender.SendMetrics(TestSenderBackend{state, model}, &sender, clock, 10, true) 113 c.Assert(err, jc.ErrorIsNil) 114 c.Assert(sender.Data, gc.HasLen, 1) 115 c.Assert(sender.Data[0], gc.HasLen, 2) 116 c.Assert(sender.Data[0][0].ModelName, gc.Equals, "test-model") 117 c.Assert(sender.Data[0][1].ModelName, gc.Equals, "test-model") 118 } 119 120 // TestSendMetrics creates 2 unsent metrics and a sent metric 121 // and checks that the 2 unsent metrics get marked as sent (have their 122 // sent field set to true). 123 func (s *MetricSenderSuite) TestSendMetrics(c *gc.C) { 124 var sender testing.MockSender 125 now := time.Now() 126 unsent1 := s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.credUnit, Time: &now}) 127 unsent2 := s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.meteredUnit, Time: &now}) 128 s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.credUnit, Sent: true, Time: &now}) 129 err := metricsender.SendMetrics(TestSenderBackend{s.State, s.Model}, &sender, s.clock, 10, true) 130 c.Assert(err, jc.ErrorIsNil) 131 c.Assert(sender.Data, gc.HasLen, 1) 132 c.Assert(sender.Data[0], gc.HasLen, 2) 133 134 sent1, err := s.State.MetricBatch(unsent1.UUID()) 135 c.Assert(err, jc.ErrorIsNil) 136 c.Assert(sent1.Sent(), jc.IsTrue) 137 138 sent2, err := s.State.MetricBatch(unsent2.UUID()) 139 c.Assert(err, jc.ErrorIsNil) 140 c.Assert(sent2.Sent(), jc.IsTrue) 141 } 142 143 func (s *MetricSenderSuite) TestSendingHandlesModelMeterStatus(c *gc.C) { 144 var sender testing.MockSender 145 sender.MeterStatusResponse = "RED" 146 now := time.Now() 147 s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.credUnit, Time: &now}) 148 s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.meteredUnit, Time: &now}) 149 s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.credUnit, Sent: true, Time: &now}) 150 err := metricsender.SendMetrics(TestSenderBackend{s.State, s.Model}, &sender, s.clock, 10, true) 151 c.Assert(err, jc.ErrorIsNil) 152 c.Assert(sender.Data, gc.HasLen, 1) 153 c.Assert(sender.Data[0], gc.HasLen, 2) 154 155 meterStatus, err := s.State.ModelMeterStatus() 156 c.Assert(err, jc.ErrorIsNil) 157 c.Assert(meterStatus.Code.String(), gc.Equals, "RED") 158 c.Assert(meterStatus.Info, gc.Equals, "mocked response") 159 } 160 161 func (s *MetricSenderSuite) TestSendingHandlesEmptyModelMeterStatus(c *gc.C) { 162 var sender testing.MockSender 163 sender.MeterStatusResponse = "" 164 now := time.Now() 165 s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.credUnit, Time: &now}) 166 s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.meteredUnit, Time: &now}) 167 s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.credUnit, Sent: true, Time: &now}) 168 err := metricsender.SendMetrics(TestSenderBackend{s.State, s.Model}, &sender, s.clock, 10, true) 169 c.Assert(err, jc.ErrorIsNil) 170 c.Assert(sender.Data, gc.HasLen, 1) 171 c.Assert(sender.Data[0], gc.HasLen, 2) 172 173 meterStatus, err := s.State.ModelMeterStatus() 174 c.Assert(err, jc.ErrorIsNil) 175 c.Assert(meterStatus.Code.String(), gc.Equals, "NOT AVAILABLE") 176 c.Assert(meterStatus.Info, gc.Equals, "") 177 } 178 179 // TestSendMetricsAbort creates 7 unsent metrics and 180 // checks that the sending stops when no more batches are ack'ed. 181 func (s *MetricSenderSuite) TestSendMetricsAbort(c *gc.C) { 182 sender := &testing.MockSender{} 183 now := time.Now() 184 metrics := make([]*state.MetricBatch, 7) 185 for i := 0; i < 7; i++ { 186 metrics[i] = s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.credUnit, Time: &now}) 187 } 188 189 sender.IgnoreBatches(metrics[0:2]...) 190 191 // Send 4 batches per POST. 192 err := metricsender.SendMetrics(TestSenderBackend{s.State, s.Model}, sender, s.clock, 4, true) 193 c.Assert(err, jc.ErrorIsNil) 194 c.Assert(sender.Data, gc.HasLen, 4) 195 196 unsent := 0 197 sent := 0 198 for _, batch := range metrics { 199 b, err := s.State.MetricBatch(batch.UUID()) 200 c.Assert(err, jc.ErrorIsNil) 201 if b.Sent() { 202 sent++ 203 } else { 204 unsent++ 205 } 206 } 207 c.Assert(sent, gc.Equals, 5) 208 c.Assert(unsent, gc.Equals, 2) 209 } 210 211 // TestHoldMetrics creates 2 unsent metrics and a sent metric 212 // and checks that only the metric from the application with credentials is sent. 213 // But both metrics are marked as sent. 214 func (s *MetricSenderSuite) TestHoldMetrics(c *gc.C) { 215 var sender testing.MockSender 216 now := time.Now() 217 unsent1 := s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.credUnit, Time: &now}) 218 unsent2 := s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.meteredUnit, Time: &now}) 219 s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.credUnit, Sent: true, Time: &now}) 220 err := metricsender.SendMetrics(TestSenderBackend{s.State, s.Model}, &sender, s.clock, 10, false) 221 c.Assert(err, jc.ErrorIsNil) 222 c.Assert(sender.Data, gc.HasLen, 1) 223 c.Assert(sender.Data[0], gc.HasLen, 1) 224 c.Assert(sender.Data[0][0].UUID, gc.Equals, unsent1.UUID()) 225 sent1, err := s.State.MetricBatch(unsent1.UUID()) 226 c.Assert(err, jc.ErrorIsNil) 227 c.Assert(sent1.Sent(), jc.IsTrue) 228 229 sent2, err := s.State.MetricBatch(unsent2.UUID()) 230 c.Assert(err, jc.ErrorIsNil) 231 c.Assert(sent2.Sent(), jc.IsTrue) 232 } 233 234 func (s *MetricSenderSuite) TestHoldMetricsSetsMeterStatus(c *gc.C) { 235 var sender testing.MockSender 236 now := time.Now() 237 err := s.credUnit.SetMeterStatus("GREEN", "known starting point") 238 c.Assert(err, jc.ErrorIsNil) 239 err = s.meteredUnit.SetMeterStatus("GREEN", "known starting point") 240 c.Assert(err, jc.ErrorIsNil) 241 unsent1 := s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.credUnit, Time: &now}) 242 s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.meteredUnit, Time: &now}) 243 s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.credUnit, Sent: true, Time: &now}) 244 err = metricsender.SendMetrics(TestSenderBackend{s.State, s.Model}, &sender, s.clock, 10, false) 245 c.Assert(err, jc.ErrorIsNil) 246 c.Assert(sender.Data, gc.HasLen, 1) 247 c.Assert(sender.Data[0], gc.HasLen, 1) 248 c.Assert(sender.Data[0][0].UUID, gc.Equals, unsent1.UUID()) 249 msCred, err := s.credUnit.GetMeterStatus() 250 c.Assert(msCred.Code, gc.Equals, state.MeterGreen) 251 c.Assert(msCred.Info, gc.Equals, "known starting point") 252 msMetered, err := s.meteredUnit.GetMeterStatus() 253 c.Assert(msMetered.Code, gc.Equals, state.MeterRed) 254 c.Assert(msMetered.Info, gc.Equals, "transmit-vendor-metrics turned off") 255 } 256 257 // TestSendBulkMetrics tests the logic of splitting sends 258 // into batches is done correctly. The batch size is changed 259 // to send batches of 10 metrics. If we create 100 metrics 10 calls 260 // will be made to the sender 261 func (s *MetricSenderSuite) TestSendBulkMetrics(c *gc.C) { 262 var sender testing.MockSender 263 now := time.Now() 264 for i := 0; i < 100; i++ { 265 s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.credUnit, Time: &now}) 266 } 267 err := metricsender.SendMetrics(TestSenderBackend{s.State, s.Model}, &sender, s.clock, 10, true) 268 c.Assert(err, jc.ErrorIsNil) 269 270 c.Assert(sender.Data, gc.HasLen, 10) 271 for _, d := range sender.Data { 272 c.Assert(d, gc.HasLen, 10) 273 } 274 } 275 276 // TestDontSendWithNopSender check that if the default sender 277 // is nil we don't send anything, but still mark the items as sent 278 func (s *MetricSenderSuite) TestDontSendWithNopSender(c *gc.C) { 279 now := time.Now() 280 for i := 0; i < 3; i++ { 281 s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.credUnit, Sent: false, Time: &now}) 282 } 283 err := metricsender.SendMetrics(TestSenderBackend{s.State, s.Model}, metricsender.NopSender{}, s.clock, 10, true) 284 c.Assert(err, jc.ErrorIsNil) 285 sent, err := s.State.CountOfSentMetrics() 286 c.Assert(err, jc.ErrorIsNil) 287 c.Assert(sent, gc.Equals, 3) 288 } 289 290 func (s *MetricSenderSuite) TestFailureIncrementsConsecutiveFailures(c *gc.C) { 291 sender := &testing.ErrorSender{Err: errors.New("something went wrong")} 292 now := time.Now() 293 for i := 0; i < 3; i++ { 294 s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.credUnit, Sent: false, Time: &now}) 295 } 296 err := metricsender.SendMetrics(TestSenderBackend{s.State, s.Model}, sender, s.clock, 1, true) 297 c.Assert(err, gc.ErrorMatches, "something went wrong") 298 mm, err := s.State.MetricsManager() 299 c.Assert(err, jc.ErrorIsNil) 300 c.Assert(mm.ConsecutiveErrors(), gc.Equals, 1) 301 } 302 303 func (s *MetricSenderSuite) TestFailuresResetOnSuccessfulSend(c *gc.C) { 304 mm, err := s.State.MetricsManager() 305 c.Assert(err, jc.ErrorIsNil) 306 err = mm.IncrementConsecutiveErrors() 307 c.Assert(err, jc.ErrorIsNil) 308 now := time.Now() 309 for i := 0; i < 3; i++ { 310 s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.credUnit, Sent: false, Time: &now}) 311 } 312 err = metricsender.SendMetrics(TestSenderBackend{s.State, s.Model}, metricsender.NopSender{}, s.clock, 10, true) 313 c.Assert(err, jc.ErrorIsNil) 314 mm, err = s.State.MetricsManager() 315 c.Assert(err, jc.ErrorIsNil) 316 c.Assert(mm.ConsecutiveErrors(), gc.Equals, 0) 317 }