github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/state/metrics_test.go (about) 1 // Copyright 2013, 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state_test 5 6 import ( 7 "time" 8 9 "github.com/juju/errors" 10 "github.com/juju/names" 11 jc "github.com/juju/testing/checkers" 12 "github.com/juju/utils" 13 gc "gopkg.in/check.v1" 14 15 "github.com/juju/juju/state" 16 "github.com/juju/juju/testing/factory" 17 ) 18 19 type MetricSuite struct { 20 ConnSuite 21 unit *state.Unit 22 service *state.Service 23 meteredCharm *state.Charm 24 } 25 26 var _ = gc.Suite(&MetricSuite{}) 27 28 func (s *MetricSuite) SetUpTest(c *gc.C) { 29 s.ConnSuite.SetUpTest(c) 30 s.assertAddUnit(c) 31 } 32 33 func (s *MetricSuite) TestAddNoMetrics(c *gc.C) { 34 now := state.NowToTheSecond() 35 _, err := s.State.AddMetrics(state.BatchParam{ 36 UUID: utils.MustNewUUID().String(), 37 CharmURL: s.meteredCharm.URL().String(), 38 Created: now, 39 Metrics: []state.Metric{}, 40 Unit: s.unit.UnitTag(), 41 }) 42 c.Assert(err, gc.ErrorMatches, "cannot add a batch of 0 metrics") 43 } 44 45 func removeUnit(c *gc.C, unit *state.Unit) { 46 ensureUnitDead(c, unit) 47 err := unit.Remove() 48 c.Assert(err, jc.ErrorIsNil) 49 } 50 51 func ensureUnitDead(c *gc.C, unit *state.Unit) { 52 err := unit.EnsureDead() 53 c.Assert(err, jc.ErrorIsNil) 54 } 55 56 func (s *MetricSuite) assertAddUnit(c *gc.C) { 57 s.meteredCharm = s.Factory.MakeCharm(c, &factory.CharmParams{Name: "metered", URL: "cs:quantal/metered"}) 58 s.service = s.Factory.MakeService(c, &factory.ServiceParams{Charm: s.meteredCharm}) 59 s.unit = s.Factory.MakeUnit(c, &factory.UnitParams{Service: s.service, SetCharmURL: true}) 60 } 61 62 func (s *MetricSuite) TestAddMetric(c *gc.C) { 63 now := state.NowToTheSecond() 64 modelUUID := s.State.ModelUUID() 65 m := state.Metric{"pings", "5", now} 66 metricBatch, err := s.State.AddMetrics( 67 state.BatchParam{ 68 UUID: utils.MustNewUUID().String(), 69 Created: now, 70 CharmURL: s.meteredCharm.URL().String(), 71 Metrics: []state.Metric{m}, 72 Unit: s.unit.UnitTag(), 73 }, 74 ) 75 c.Assert(err, jc.ErrorIsNil) 76 c.Assert(metricBatch.Unit(), gc.Equals, "metered/0") 77 c.Assert(metricBatch.ModelUUID(), gc.Equals, modelUUID) 78 c.Assert(metricBatch.CharmURL(), gc.Equals, "cs:quantal/metered") 79 c.Assert(metricBatch.Sent(), jc.IsFalse) 80 c.Assert(metricBatch.Created(), gc.Equals, now) 81 c.Assert(metricBatch.Metrics(), gc.HasLen, 1) 82 83 metric := metricBatch.Metrics()[0] 84 c.Assert(metric.Key, gc.Equals, "pings") 85 c.Assert(metric.Value, gc.Equals, "5") 86 c.Assert(metric.Time.Equal(now), jc.IsTrue) 87 88 saved, err := s.State.MetricBatch(metricBatch.UUID()) 89 c.Assert(err, jc.ErrorIsNil) 90 c.Assert(saved.Unit(), gc.Equals, "metered/0") 91 c.Assert(metricBatch.CharmURL(), gc.Equals, "cs:quantal/metered") 92 c.Assert(saved.Sent(), jc.IsFalse) 93 c.Assert(saved.Metrics(), gc.HasLen, 1) 94 metric = saved.Metrics()[0] 95 c.Assert(metric.Key, gc.Equals, "pings") 96 c.Assert(metric.Value, gc.Equals, "5") 97 c.Assert(metric.Time.Equal(now), jc.IsTrue) 98 } 99 100 func (s *MetricSuite) TestAddMetricNonExistentUnit(c *gc.C) { 101 removeUnit(c, s.unit) 102 now := state.NowToTheSecond() 103 m := state.Metric{"pings", "5", now} 104 unitTag := names.NewUnitTag("test/0") 105 _, err := s.State.AddMetrics( 106 state.BatchParam{ 107 UUID: utils.MustNewUUID().String(), 108 Created: now, 109 CharmURL: s.meteredCharm.URL().String(), 110 Metrics: []state.Metric{m}, 111 Unit: unitTag, 112 }, 113 ) 114 c.Assert(err, gc.ErrorMatches, ".*not found") 115 } 116 117 func (s *MetricSuite) TestAddMetricDeadUnit(c *gc.C) { 118 ensureUnitDead(c, s.unit) 119 now := state.NowToTheSecond() 120 m := state.Metric{"pings", "5", now} 121 _, err := s.State.AddMetrics( 122 state.BatchParam{ 123 UUID: utils.MustNewUUID().String(), 124 Created: now, 125 CharmURL: s.meteredCharm.URL().String(), 126 Metrics: []state.Metric{m}, 127 Unit: s.unit.UnitTag(), 128 }, 129 ) 130 c.Assert(err, gc.ErrorMatches, `metered/0 not found`) 131 } 132 133 func (s *MetricSuite) TestSetMetricSent(c *gc.C) { 134 now := state.NowToTheSecond() 135 m := state.Metric{"pings", "5", now} 136 added, err := s.State.AddMetrics( 137 state.BatchParam{ 138 UUID: utils.MustNewUUID().String(), 139 Created: now, 140 CharmURL: s.meteredCharm.URL().String(), 141 Metrics: []state.Metric{m}, 142 Unit: s.unit.UnitTag(), 143 }, 144 ) 145 c.Assert(err, jc.ErrorIsNil) 146 saved, err := s.State.MetricBatch(added.UUID()) 147 c.Assert(err, jc.ErrorIsNil) 148 err = saved.SetSent(time.Now()) 149 c.Assert(err, jc.ErrorIsNil) 150 c.Assert(saved.Sent(), jc.IsTrue) 151 saved, err = s.State.MetricBatch(added.UUID()) 152 c.Assert(err, jc.ErrorIsNil) 153 c.Assert(saved.Sent(), jc.IsTrue) 154 } 155 156 func (s *MetricSuite) TestCleanupMetrics(c *gc.C) { 157 oldTime := time.Now().Add(-(time.Hour * 25)) 158 now := time.Now() 159 m := state.Metric{"pings", "5", oldTime} 160 oldMetric1, err := s.State.AddMetrics( 161 state.BatchParam{ 162 UUID: utils.MustNewUUID().String(), 163 Created: now, 164 CharmURL: s.meteredCharm.URL().String(), 165 Metrics: []state.Metric{m}, 166 Unit: s.unit.UnitTag(), 167 }, 168 ) 169 c.Assert(err, jc.ErrorIsNil) 170 oldMetric1.SetSent(time.Now().Add(-25 * time.Hour)) 171 172 oldMetric2, err := s.State.AddMetrics( 173 state.BatchParam{ 174 UUID: utils.MustNewUUID().String(), 175 Created: now, 176 CharmURL: s.meteredCharm.URL().String(), 177 Metrics: []state.Metric{m}, 178 Unit: s.unit.UnitTag(), 179 }, 180 ) 181 c.Assert(err, jc.ErrorIsNil) 182 oldMetric2.SetSent(time.Now().Add(-25 * time.Hour)) 183 184 m = state.Metric{"pings", "5", now} 185 newMetric, err := s.State.AddMetrics( 186 state.BatchParam{ 187 UUID: utils.MustNewUUID().String(), 188 Created: now, 189 CharmURL: s.meteredCharm.URL().String(), 190 Metrics: []state.Metric{m}, 191 Unit: s.unit.UnitTag(), 192 }, 193 ) 194 c.Assert(err, jc.ErrorIsNil) 195 newMetric.SetSent(time.Now()) 196 err = s.State.CleanupOldMetrics() 197 c.Assert(err, jc.ErrorIsNil) 198 199 _, err = s.State.MetricBatch(newMetric.UUID()) 200 c.Assert(err, jc.ErrorIsNil) 201 202 _, err = s.State.MetricBatch(oldMetric1.UUID()) 203 c.Assert(err, jc.Satisfies, errors.IsNotFound) 204 205 _, err = s.State.MetricBatch(oldMetric2.UUID()) 206 c.Assert(err, jc.Satisfies, errors.IsNotFound) 207 } 208 209 func (s *MetricSuite) TestCleanupNoMetrics(c *gc.C) { 210 err := s.State.CleanupOldMetrics() 211 c.Assert(err, jc.ErrorIsNil) 212 } 213 214 func (s *MetricSuite) TestCleanupMetricsIgnoreNotSent(c *gc.C) { 215 oldTime := time.Now().Add(-(time.Hour * 25)) 216 m := state.Metric{"pings", "5", oldTime} 217 oldMetric, err := s.State.AddMetrics( 218 state.BatchParam{ 219 UUID: utils.MustNewUUID().String(), 220 Created: oldTime, 221 CharmURL: s.meteredCharm.URL().String(), 222 Metrics: []state.Metric{m}, 223 Unit: s.unit.UnitTag(), 224 }, 225 ) 226 c.Assert(err, jc.ErrorIsNil) 227 228 now := time.Now() 229 m = state.Metric{"pings", "5", now} 230 newMetric, err := s.State.AddMetrics( 231 state.BatchParam{ 232 UUID: utils.MustNewUUID().String(), 233 Created: now, 234 CharmURL: s.meteredCharm.URL().String(), 235 Metrics: []state.Metric{m}, 236 Unit: s.unit.UnitTag(), 237 }, 238 ) 239 c.Assert(err, jc.ErrorIsNil) 240 newMetric.SetSent(time.Now()) 241 err = s.State.CleanupOldMetrics() 242 c.Assert(err, jc.ErrorIsNil) 243 244 _, err = s.State.MetricBatch(newMetric.UUID()) 245 c.Assert(err, jc.ErrorIsNil) 246 247 _, err = s.State.MetricBatch(oldMetric.UUID()) 248 c.Assert(err, jc.ErrorIsNil) 249 } 250 251 func (s *MetricSuite) TestAllMetricBatches(c *gc.C) { 252 now := state.NowToTheSecond() 253 m := state.Metric{"pings", "5", now} 254 _, err := s.State.AddMetrics( 255 state.BatchParam{ 256 UUID: utils.MustNewUUID().String(), 257 Created: now, 258 CharmURL: s.meteredCharm.URL().String(), 259 Metrics: []state.Metric{m}, 260 Unit: s.unit.UnitTag(), 261 }, 262 ) 263 c.Assert(err, jc.ErrorIsNil) 264 metricBatches, err := s.State.AllMetricBatches() 265 c.Assert(err, jc.ErrorIsNil) 266 c.Assert(metricBatches, gc.HasLen, 1) 267 c.Assert(metricBatches[0].Unit(), gc.Equals, "metered/0") 268 c.Assert(metricBatches[0].CharmURL(), gc.Equals, "cs:quantal/metered") 269 c.Assert(metricBatches[0].Sent(), jc.IsFalse) 270 c.Assert(metricBatches[0].Metrics(), gc.HasLen, 1) 271 } 272 273 func (s *MetricSuite) TestAllMetricBatchesCustomCharmURLAndUUID(c *gc.C) { 274 now := state.NowToTheSecond() 275 m := state.Metric{"pings", "5", now} 276 uuid := utils.MustNewUUID().String() 277 charmUrl := "cs:quantal/metered" 278 _, err := s.State.AddMetrics( 279 state.BatchParam{ 280 UUID: uuid, 281 Created: now, 282 CharmURL: charmUrl, 283 Metrics: []state.Metric{m}, 284 Unit: s.unit.UnitTag(), 285 }, 286 ) 287 c.Assert(err, jc.ErrorIsNil) 288 metricBatches, err := s.State.AllMetricBatches() 289 c.Assert(err, jc.ErrorIsNil) 290 c.Assert(metricBatches, gc.HasLen, 1) 291 c.Assert(metricBatches[0].Unit(), gc.Equals, "metered/0") 292 c.Assert(metricBatches[0].UUID(), gc.Equals, uuid) 293 c.Assert(metricBatches[0].CharmURL(), gc.Equals, charmUrl) 294 c.Assert(metricBatches[0].Sent(), jc.IsFalse) 295 c.Assert(metricBatches[0].Metrics(), gc.HasLen, 1) 296 } 297 298 func (s *MetricSuite) TestMetricCredentials(c *gc.C) { 299 now := state.NowToTheSecond() 300 m := state.Metric{"pings", "5", now} 301 err := s.service.SetMetricCredentials([]byte("hello there")) 302 c.Assert(err, gc.IsNil) 303 _, err = s.State.AddMetrics( 304 state.BatchParam{ 305 UUID: utils.MustNewUUID().String(), 306 Created: now, 307 CharmURL: s.meteredCharm.URL().String(), 308 Metrics: []state.Metric{m}, 309 Unit: s.unit.UnitTag(), 310 }, 311 ) 312 c.Assert(err, jc.ErrorIsNil) 313 metricBatches, err := s.State.AllMetricBatches() 314 c.Assert(err, jc.ErrorIsNil) 315 c.Assert(metricBatches, gc.HasLen, 1) 316 c.Assert(metricBatches[0].Credentials(), gc.DeepEquals, []byte("hello there")) 317 } 318 319 // TestCountMetrics asserts the correct values are returned 320 // by CountOfUnsentMetrics and CountOfSentMetrics. 321 func (s *MetricSuite) TestCountMetrics(c *gc.C) { 322 now := time.Now() 323 m := []state.Metric{{Key: "pings", Value: "123", Time: now}} 324 s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.unit, Sent: false, Time: &now, Metrics: m}) 325 s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.unit, Sent: false, Time: &now, Metrics: m}) 326 s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.unit, Sent: true, Time: &now, Metrics: m}) 327 sent, err := s.State.CountOfSentMetrics() 328 c.Assert(err, jc.ErrorIsNil) 329 c.Assert(sent, gc.Equals, 1) 330 unsent, err := s.State.CountOfUnsentMetrics() 331 c.Assert(err, jc.ErrorIsNil) 332 c.Assert(unsent, gc.Equals, 2) 333 c.Assert(unsent+sent, gc.Equals, 3) 334 } 335 336 func (s *MetricSuite) TestSetMetricBatchesSent(c *gc.C) { 337 now := time.Now() 338 metrics := make([]*state.MetricBatch, 3) 339 for i := range metrics { 340 m := []state.Metric{{Key: "pings", Value: "123", Time: now}} 341 metrics[i] = s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.unit, Sent: false, Time: &now, Metrics: m}) 342 } 343 uuids := make([]string, len(metrics)) 344 for i, m := range metrics { 345 uuids[i] = m.UUID() 346 } 347 err := s.State.SetMetricBatchesSent(uuids) 348 c.Assert(err, jc.ErrorIsNil) 349 sent, err := s.State.CountOfSentMetrics() 350 c.Assert(err, jc.ErrorIsNil) 351 c.Assert(sent, gc.Equals, 3) 352 353 } 354 355 func (s *MetricSuite) TestMetricsToSend(c *gc.C) { 356 now := state.NowToTheSecond() 357 m := []state.Metric{{Key: "pings", Value: "123", Time: now}} 358 s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.unit, Sent: false, Time: &now, Metrics: m}) 359 s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.unit, Sent: false, Time: &now, Metrics: m}) 360 s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.unit, Sent: true, Time: &now, Metrics: m}) 361 result, err := s.State.MetricsToSend(5) 362 c.Assert(err, jc.ErrorIsNil) 363 c.Assert(result, gc.HasLen, 2) 364 } 365 366 // TestMetricsToSendBatches checks that metrics are properly batched. 367 func (s *MetricSuite) TestMetricsToSendBatches(c *gc.C) { 368 now := state.NowToTheSecond() 369 for i := 0; i < 6; i++ { 370 m := []state.Metric{{Key: "pings", Value: "123", Time: now}} 371 s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.unit, Sent: false, Time: &now, Metrics: m}) 372 } 373 for i := 0; i < 4; i++ { 374 m := []state.Metric{{Key: "pings", Value: "123", Time: now}} 375 s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.unit, Sent: true, Time: &now, Metrics: m}) 376 } 377 for i := 0; i < 3; i++ { 378 result, err := s.State.MetricsToSend(2) 379 c.Assert(err, jc.ErrorIsNil) 380 c.Assert(result, gc.HasLen, 2) 381 uuids := make([]string, len(result)) 382 for i, m := range result { 383 uuids[i] = m.UUID() 384 } 385 s.State.SetMetricBatchesSent(uuids) 386 } 387 result, err := s.State.MetricsToSend(2) 388 c.Assert(err, jc.ErrorIsNil) 389 c.Assert(result, gc.HasLen, 0) 390 } 391 392 func (s *MetricSuite) TestMetricValidation(c *gc.C) { 393 nonMeteredUnit := s.Factory.MakeUnit(c, &factory.UnitParams{SetCharmURL: true}) 394 meteredService := s.Factory.MakeService(c, &factory.ServiceParams{Name: "metered-service", Charm: s.meteredCharm}) 395 meteredUnit := s.Factory.MakeUnit(c, &factory.UnitParams{Service: meteredService, SetCharmURL: true}) 396 dyingUnit, err := meteredService.AddUnit() 397 c.Assert(err, jc.ErrorIsNil) 398 err = dyingUnit.SetCharmURL(s.meteredCharm.URL()) 399 c.Assert(err, jc.ErrorIsNil) 400 err = dyingUnit.Destroy() 401 c.Assert(err, jc.ErrorIsNil) 402 now := time.Now() 403 tests := []struct { 404 about string 405 metrics []state.Metric 406 unit *state.Unit 407 err string 408 }{{ 409 "assert non metered unit returns an error", 410 []state.Metric{{"metric-key", "1", now}}, 411 nonMeteredUnit, 412 "charm doesn't implement metrics", 413 }, { 414 "assert metric with no errors and passes validation", 415 []state.Metric{{"pings", "1", now}}, 416 meteredUnit, 417 "", 418 }, { 419 "assert valid metric fails on dying unit", 420 []state.Metric{{"pings", "1", now}}, 421 dyingUnit, 422 "unit \"metered-service/1\" not found", 423 }, { 424 "assert charm doesn't implement key returns error", 425 []state.Metric{{"not-implemented", "1", now}}, 426 meteredUnit, 427 `metric "not-implemented" not defined`, 428 }, { 429 "assert invalid value returns error", 430 []state.Metric{{"pings", "foobar", now}}, 431 meteredUnit, 432 `invalid value type: expected float, got "foobar"`, 433 }, { 434 "long value returns error", 435 []state.Metric{{"pings", "3.141592653589793238462643383279", now}}, 436 meteredUnit, 437 `metric value is too large`, 438 }, { 439 "negative value returns error", 440 []state.Metric{{"pings", "-42.0", now}}, 441 meteredUnit, 442 `invalid value: value must be greater or equal to zero, got -42.0`, 443 }, { 444 "non-float value returns an error", 445 []state.Metric{{"pings", "abcd", now}}, 446 meteredUnit, 447 `invalid value type: expected float, got "abcd"`, 448 }} 449 for i, t := range tests { 450 c.Logf("test %d: %s", i, t.about) 451 chURL, ok := t.unit.CharmURL() 452 c.Assert(ok, jc.IsTrue) 453 _, err := s.State.AddMetrics( 454 state.BatchParam{ 455 UUID: utils.MustNewUUID().String(), 456 Created: now, 457 CharmURL: chURL.String(), 458 Metrics: t.metrics, 459 Unit: t.unit.UnitTag(), 460 }, 461 ) 462 if t.err == "" { 463 c.Assert(err, jc.ErrorIsNil) 464 } else { 465 c.Assert(err, gc.ErrorMatches, t.err) 466 } 467 } 468 } 469 470 func (s *MetricSuite) TestMetricsAcrossEnvironments(c *gc.C) { 471 now := state.NowToTheSecond().Add(-48 * time.Hour) 472 m := state.Metric{"pings", "5", now} 473 m1, err := s.State.AddMetrics( 474 state.BatchParam{ 475 UUID: utils.MustNewUUID().String(), 476 Created: now, 477 CharmURL: s.meteredCharm.URL().String(), 478 Metrics: []state.Metric{m}, 479 Unit: s.unit.UnitTag(), 480 }, 481 ) 482 c.Assert(err, jc.ErrorIsNil) 483 484 st := s.Factory.MakeModel(c, nil) 485 defer st.Close() 486 f := factory.NewFactory(st) 487 meteredCharm := f.MakeCharm(c, &factory.CharmParams{Name: "metered", URL: "cs:quantal/metered"}) 488 service := f.MakeService(c, &factory.ServiceParams{Charm: meteredCharm}) 489 unit := f.MakeUnit(c, &factory.UnitParams{Service: service, SetCharmURL: true}) 490 m2, err := s.State.AddMetrics( 491 state.BatchParam{ 492 UUID: utils.MustNewUUID().String(), 493 Created: now, 494 CharmURL: s.meteredCharm.URL().String(), 495 Metrics: []state.Metric{m}, 496 Unit: unit.UnitTag(), 497 }, 498 ) 499 c.Assert(err, jc.ErrorIsNil) 500 501 batches, err := s.State.AllMetricBatches() 502 c.Assert(err, jc.ErrorIsNil) 503 c.Assert(batches, gc.HasLen, 2) 504 505 unsent, err := s.State.CountOfUnsentMetrics() 506 c.Assert(err, jc.ErrorIsNil) 507 c.Assert(unsent, gc.Equals, 2) 508 509 toSend, err := s.State.MetricsToSend(10) 510 c.Assert(err, jc.ErrorIsNil) 511 c.Assert(toSend, gc.HasLen, 2) 512 513 err = m1.SetSent(time.Now().Add(-25 * time.Hour)) 514 c.Assert(err, jc.ErrorIsNil) 515 err = m2.SetSent(time.Now().Add(-25 * time.Hour)) 516 c.Assert(err, jc.ErrorIsNil) 517 518 sent, err := s.State.CountOfSentMetrics() 519 c.Assert(err, jc.ErrorIsNil) 520 c.Assert(sent, gc.Equals, 2) 521 522 err = s.State.CleanupOldMetrics() 523 c.Assert(err, jc.ErrorIsNil) 524 525 batches, err = s.State.AllMetricBatches() 526 c.Assert(err, jc.ErrorIsNil) 527 c.Assert(batches, gc.HasLen, 0) 528 } 529 530 func (s *MetricSuite) TestAddMetricDuplicateUUID(c *gc.C) { 531 now := state.NowToTheSecond() 532 mUUID := utils.MustNewUUID().String() 533 _, err := s.State.AddMetrics( 534 state.BatchParam{ 535 UUID: mUUID, 536 Created: now, 537 CharmURL: s.meteredCharm.URL().String(), 538 Metrics: []state.Metric{{"pings", "5", now}}, 539 Unit: s.unit.UnitTag(), 540 }, 541 ) 542 c.Assert(err, jc.ErrorIsNil) 543 544 _, err = s.State.AddMetrics( 545 state.BatchParam{ 546 UUID: mUUID, 547 Created: now, 548 CharmURL: s.meteredCharm.URL().String(), 549 Metrics: []state.Metric{{"pings", "10", now}}, 550 Unit: s.unit.UnitTag(), 551 }, 552 ) 553 c.Assert(err, gc.ErrorMatches, "metrics batch .* already exists") 554 } 555 556 func (s *MetricSuite) TestAddBuiltInMetric(c *gc.C) { 557 tests := []struct { 558 about string 559 value string 560 expectedError string 561 }{{ 562 about: "adding a positive value must succeed", 563 value: "5", 564 }, { 565 about: "negative values return an error", 566 value: "-42.0", 567 expectedError: "invalid value: value must be greater or equal to zero, got -42.0", 568 }, { 569 about: "non-float values return an error", 570 value: "abcd", 571 expectedError: `invalid value type: expected float, got "abcd"`, 572 }, { 573 about: "long values return an error", 574 value: "1234567890123456789012345678901234567890", 575 expectedError: "metric value is too large", 576 }, 577 } 578 for _, test := range tests { 579 c.Logf("running test: %v", test.about) 580 now := state.NowToTheSecond() 581 modelUUID := s.State.ModelUUID() 582 m := state.Metric{"juju-units", test.value, now} 583 metricBatch, err := s.State.AddMetrics( 584 state.BatchParam{ 585 UUID: utils.MustNewUUID().String(), 586 Created: now, 587 CharmURL: s.meteredCharm.URL().String(), 588 Metrics: []state.Metric{m}, 589 Unit: s.unit.UnitTag(), 590 }, 591 ) 592 if test.expectedError == "" { 593 c.Assert(err, jc.ErrorIsNil) 594 c.Assert(metricBatch.Unit(), gc.Equals, "metered/0") 595 c.Assert(metricBatch.ModelUUID(), gc.Equals, modelUUID) 596 c.Assert(metricBatch.CharmURL(), gc.Equals, "cs:quantal/metered") 597 c.Assert(metricBatch.Sent(), jc.IsFalse) 598 c.Assert(metricBatch.Created(), gc.Equals, now) 599 c.Assert(metricBatch.Metrics(), gc.HasLen, 1) 600 601 metric := metricBatch.Metrics()[0] 602 c.Assert(metric.Key, gc.Equals, "juju-units") 603 c.Assert(metric.Value, gc.Equals, test.value) 604 c.Assert(metric.Time.Equal(now), jc.IsTrue) 605 606 saved, err := s.State.MetricBatch(metricBatch.UUID()) 607 c.Assert(err, jc.ErrorIsNil) 608 c.Assert(saved.Unit(), gc.Equals, "metered/0") 609 c.Assert(metricBatch.CharmURL(), gc.Equals, "cs:quantal/metered") 610 c.Assert(saved.Sent(), jc.IsFalse) 611 c.Assert(saved.Metrics(), gc.HasLen, 1) 612 metric = saved.Metrics()[0] 613 c.Assert(metric.Key, gc.Equals, "juju-units") 614 c.Assert(metric.Value, gc.Equals, test.value) 615 c.Assert(metric.Time.Equal(now), jc.IsTrue) 616 } else { 617 c.Assert(err, gc.ErrorMatches, test.expectedError) 618 } 619 } 620 } 621 622 func (s *MetricSuite) TestUnitMetricBatchesReturnsJustLocal(c *gc.C) { 623 now := state.NowToTheSecond() 624 m := state.Metric{"pings", "5", now} 625 _, err := s.State.AddMetrics( 626 state.BatchParam{ 627 UUID: utils.MustNewUUID().String(), 628 Created: now, 629 CharmURL: s.meteredCharm.URL().String(), 630 Metrics: []state.Metric{m}, 631 Unit: s.unit.UnitTag(), 632 }, 633 ) 634 c.Assert(err, jc.ErrorIsNil) 635 localMeteredCharm := s.Factory.MakeCharm(c, &factory.CharmParams{Name: "metered", URL: "local:quantal/metered"}) 636 service := s.Factory.MakeService(c, &factory.ServiceParams{Name: "localmetered", Charm: localMeteredCharm}) 637 unit := s.Factory.MakeUnit(c, &factory.UnitParams{Service: service, SetCharmURL: true}) 638 _, err = s.State.AddMetrics( 639 state.BatchParam{ 640 UUID: utils.MustNewUUID().String(), 641 Created: now, 642 CharmURL: localMeteredCharm.URL().String(), 643 Metrics: []state.Metric{m}, 644 Unit: unit.UnitTag(), 645 }, 646 ) 647 648 c.Assert(err, jc.ErrorIsNil) 649 metricBatches, err := s.State.MetricBatchesForUnit("metered/0") 650 c.Assert(metricBatches, gc.HasLen, 0) 651 metricBatches, err = s.State.MetricBatchesForUnit("localmetered/0") 652 c.Assert(metricBatches, gc.HasLen, 1) 653 } 654 655 type MetricLocalCharmSuite struct { 656 ConnSuite 657 unit *state.Unit 658 service *state.Service 659 meteredCharm *state.Charm 660 } 661 662 var _ = gc.Suite(&MetricLocalCharmSuite{}) 663 664 func (s *MetricLocalCharmSuite) SetUpTest(c *gc.C) { 665 s.ConnSuite.SetUpTest(c) 666 s.assertAddLocalUnit(c) 667 } 668 669 func (s *MetricLocalCharmSuite) assertAddLocalUnit(c *gc.C) { 670 s.meteredCharm = s.Factory.MakeCharm(c, &factory.CharmParams{Name: "metered", URL: "local:quantal/metered"}) 671 s.service = s.Factory.MakeService(c, &factory.ServiceParams{Charm: s.meteredCharm}) 672 s.unit = s.Factory.MakeUnit(c, &factory.UnitParams{Service: s.service, SetCharmURL: true}) 673 } 674 675 func (s *MetricLocalCharmSuite) TestUnitMetricBatches(c *gc.C) { 676 now := state.NowToTheSecond() 677 m := state.Metric{"pings", "5", now} 678 m2 := state.Metric{"pings", "10", now} 679 _, err := s.State.AddMetrics( 680 state.BatchParam{ 681 UUID: utils.MustNewUUID().String(), 682 Created: now, 683 CharmURL: s.meteredCharm.URL().String(), 684 Metrics: []state.Metric{m}, 685 Unit: s.unit.UnitTag(), 686 }, 687 ) 688 c.Assert(err, jc.ErrorIsNil) 689 newUnit, err := s.service.AddUnit() 690 c.Assert(err, jc.ErrorIsNil) 691 _, err = s.State.AddMetrics( 692 state.BatchParam{ 693 UUID: utils.MustNewUUID().String(), 694 Created: now, 695 CharmURL: s.meteredCharm.URL().String(), 696 Metrics: []state.Metric{m2}, 697 Unit: newUnit.UnitTag(), 698 }, 699 ) 700 c.Assert(err, jc.ErrorIsNil) 701 702 metricBatches, err := s.State.MetricBatchesForUnit("metered/0") 703 c.Assert(err, jc.ErrorIsNil) 704 c.Assert(metricBatches, gc.HasLen, 1) 705 c.Assert(metricBatches[0].Unit(), gc.Equals, "metered/0") 706 c.Assert(metricBatches[0].CharmURL(), gc.Equals, "local:quantal/metered") 707 c.Assert(metricBatches[0].Sent(), jc.IsFalse) 708 c.Assert(metricBatches[0].Metrics(), gc.HasLen, 1) 709 c.Assert(metricBatches[0].Metrics()[0].Value, gc.Equals, "5") 710 711 metricBatches, err = s.State.MetricBatchesForUnit("metered/1") 712 c.Assert(err, jc.ErrorIsNil) 713 c.Assert(metricBatches, gc.HasLen, 1) 714 c.Assert(metricBatches[0].Unit(), gc.Equals, "metered/1") 715 c.Assert(metricBatches[0].CharmURL(), gc.Equals, "local:quantal/metered") 716 c.Assert(metricBatches[0].Sent(), jc.IsFalse) 717 c.Assert(metricBatches[0].Metrics(), gc.HasLen, 1) 718 c.Assert(metricBatches[0].Metrics()[0].Value, gc.Equals, "10") 719 } 720 721 func (s *MetricLocalCharmSuite) TestServiceMetricBatches(c *gc.C) { 722 now := state.NowToTheSecond() 723 m := state.Metric{"pings", "5", now} 724 m2 := state.Metric{"pings", "10", now} 725 _, err := s.State.AddMetrics( 726 state.BatchParam{ 727 UUID: utils.MustNewUUID().String(), 728 Created: now, 729 CharmURL: s.meteredCharm.URL().String(), 730 Metrics: []state.Metric{m}, 731 Unit: s.unit.UnitTag(), 732 }, 733 ) 734 c.Assert(err, jc.ErrorIsNil) 735 newUnit, err := s.service.AddUnit() 736 c.Assert(err, jc.ErrorIsNil) 737 _, err = s.State.AddMetrics( 738 state.BatchParam{ 739 UUID: utils.MustNewUUID().String(), 740 Created: now, 741 CharmURL: s.meteredCharm.URL().String(), 742 Metrics: []state.Metric{m2}, 743 Unit: newUnit.UnitTag(), 744 }, 745 ) 746 c.Assert(err, jc.ErrorIsNil) 747 748 metricBatches, err := s.State.MetricBatchesForService("metered") 749 c.Assert(err, jc.ErrorIsNil) 750 c.Assert(metricBatches, gc.HasLen, 2) 751 752 c.Assert(metricBatches[0].Unit(), gc.Equals, "metered/0") 753 c.Assert(metricBatches[0].CharmURL(), gc.Equals, "local:quantal/metered") 754 c.Assert(metricBatches[0].Sent(), jc.IsFalse) 755 c.Assert(metricBatches[0].Metrics(), gc.HasLen, 1) 756 c.Assert(metricBatches[0].Metrics()[0].Value, gc.Equals, "5") 757 758 c.Assert(metricBatches[1].Unit(), gc.Equals, "metered/1") 759 c.Assert(metricBatches[1].CharmURL(), gc.Equals, "local:quantal/metered") 760 c.Assert(metricBatches[1].Sent(), jc.IsFalse) 761 c.Assert(metricBatches[1].Metrics(), gc.HasLen, 1) 762 c.Assert(metricBatches[1].Metrics()[0].Value, gc.Equals, "10") 763 } 764 765 func (s *MetricLocalCharmSuite) TestUnitMetricBatchesReturnsJustLocal(c *gc.C) { 766 now := state.NowToTheSecond() 767 m := state.Metric{"pings", "5", now} 768 _, err := s.State.AddMetrics( 769 state.BatchParam{ 770 UUID: utils.MustNewUUID().String(), 771 Created: now, 772 CharmURL: s.meteredCharm.URL().String(), 773 Metrics: []state.Metric{m}, 774 Unit: s.unit.UnitTag(), 775 }, 776 ) 777 c.Assert(err, jc.ErrorIsNil) 778 csMeteredCharm := s.Factory.MakeCharm(c, &factory.CharmParams{Name: "metered", URL: "cs:quantal/metered"}) 779 service := s.Factory.MakeService(c, &factory.ServiceParams{Name: "csmetered", Charm: csMeteredCharm}) 780 unit := s.Factory.MakeUnit(c, &factory.UnitParams{Service: service, SetCharmURL: true}) 781 _, err = s.State.AddMetrics( 782 state.BatchParam{ 783 UUID: utils.MustNewUUID().String(), 784 Created: now, 785 CharmURL: csMeteredCharm.URL().String(), 786 Metrics: []state.Metric{m}, 787 Unit: unit.UnitTag(), 788 }, 789 ) 790 791 c.Assert(err, jc.ErrorIsNil) 792 metricBatches, err := s.State.MetricBatchesForUnit("metered/0") 793 c.Assert(metricBatches, gc.HasLen, 1) 794 metricBatches, err = s.State.MetricBatchesForUnit("csmetered/0") 795 c.Assert(metricBatches, gc.HasLen, 0) 796 }