github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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  	jc "github.com/juju/testing/checkers"
    11  	"github.com/juju/utils"
    12  	gc "gopkg.in/check.v1"
    13  	"gopkg.in/juju/names.v2"
    14  
    15  	"github.com/juju/juju/state"
    16  	"github.com/juju/juju/testing"
    17  	"github.com/juju/juju/testing/factory"
    18  )
    19  
    20  type MetricSuite struct {
    21  	ConnSuite
    22  	unit         *state.Unit
    23  	application  *state.Application
    24  	meteredCharm *state.Charm
    25  }
    26  
    27  var _ = gc.Suite(&MetricSuite{})
    28  
    29  func (s *MetricSuite) SetUpTest(c *gc.C) {
    30  	s.ConnSuite.SetUpTest(c)
    31  	s.meteredCharm = s.Factory.MakeCharm(c, &factory.CharmParams{Name: "metered", URL: "cs:quantal/metered"})
    32  	s.application = s.Factory.MakeApplication(c, &factory.ApplicationParams{Charm: s.meteredCharm})
    33  	s.unit = s.Factory.MakeUnit(c, &factory.UnitParams{Application: s.application, SetCharmURL: true})
    34  }
    35  
    36  func (s *MetricSuite) TestAddNoMetrics(c *gc.C) {
    37  	now := s.State.NowToTheSecond()
    38  	_, err := s.State.AddMetrics(state.BatchParam{
    39  		UUID:     utils.MustNewUUID().String(),
    40  		CharmURL: s.meteredCharm.URL().String(),
    41  		Created:  now,
    42  		Metrics:  []state.Metric{},
    43  		Unit:     s.unit.UnitTag(),
    44  	})
    45  	c.Assert(err, gc.ErrorMatches, "cannot add a batch of 0 metrics")
    46  }
    47  
    48  func removeUnit(c *gc.C, unit *state.Unit) {
    49  	ensureUnitDead(c, unit)
    50  	err := unit.Remove()
    51  	c.Assert(err, jc.ErrorIsNil)
    52  }
    53  
    54  func ensureUnitDead(c *gc.C, unit *state.Unit) {
    55  	err := unit.EnsureDead()
    56  	c.Assert(err, jc.ErrorIsNil)
    57  }
    58  
    59  func (s *MetricSuite) TestAddMetric(c *gc.C) {
    60  	now := s.State.NowToTheSecond()
    61  	modelUUID := s.State.ModelUUID()
    62  	m := state.Metric{"pings", "5", now}
    63  	metricBatch, err := s.State.AddMetrics(
    64  		state.BatchParam{
    65  			UUID:     utils.MustNewUUID().String(),
    66  			Created:  now,
    67  			CharmURL: s.meteredCharm.URL().String(),
    68  			Metrics:  []state.Metric{m},
    69  			Unit:     s.unit.UnitTag(),
    70  		},
    71  	)
    72  	c.Assert(err, jc.ErrorIsNil)
    73  	c.Assert(metricBatch.Unit(), gc.Equals, "metered/0")
    74  	c.Assert(metricBatch.ModelUUID(), gc.Equals, modelUUID)
    75  	c.Assert(metricBatch.CharmURL(), gc.Equals, "cs:quantal/metered")
    76  	c.Assert(metricBatch.Sent(), jc.IsFalse)
    77  	c.Assert(metricBatch.Created(), gc.Equals, now)
    78  	c.Assert(metricBatch.Metrics(), gc.HasLen, 1)
    79  
    80  	metric := metricBatch.Metrics()[0]
    81  	c.Assert(metric.Key, gc.Equals, "pings")
    82  	c.Assert(metric.Value, gc.Equals, "5")
    83  	c.Assert(metric.Time.Equal(now), jc.IsTrue)
    84  
    85  	saved, err := s.State.MetricBatch(metricBatch.UUID())
    86  	c.Assert(err, jc.ErrorIsNil)
    87  	c.Assert(saved.Unit(), gc.Equals, "metered/0")
    88  	c.Assert(metricBatch.CharmURL(), gc.Equals, "cs:quantal/metered")
    89  	c.Assert(saved.Sent(), jc.IsFalse)
    90  	c.Assert(saved.Metrics(), gc.HasLen, 1)
    91  	metric = saved.Metrics()[0]
    92  	c.Assert(metric.Key, gc.Equals, "pings")
    93  	c.Assert(metric.Value, gc.Equals, "5")
    94  	c.Assert(metric.Time.Equal(now), jc.IsTrue)
    95  }
    96  
    97  func (s *MetricSuite) TestAddMetricNonExistentUnit(c *gc.C) {
    98  	removeUnit(c, s.unit)
    99  	now := s.State.NowToTheSecond()
   100  	m := state.Metric{"pings", "5", now}
   101  	unitTag := names.NewUnitTag("test/0")
   102  	_, err := s.State.AddMetrics(
   103  		state.BatchParam{
   104  			UUID:     utils.MustNewUUID().String(),
   105  			Created:  now,
   106  			CharmURL: s.meteredCharm.URL().String(),
   107  			Metrics:  []state.Metric{m},
   108  			Unit:     unitTag,
   109  		},
   110  	)
   111  	c.Assert(err, gc.ErrorMatches, ".*not found")
   112  }
   113  
   114  func (s *MetricSuite) TestAddMetricDeadUnit(c *gc.C) {
   115  	ensureUnitDead(c, s.unit)
   116  	now := s.State.NowToTheSecond()
   117  	m := state.Metric{"pings", "5", now}
   118  	_, err := s.State.AddMetrics(
   119  		state.BatchParam{
   120  			UUID:     utils.MustNewUUID().String(),
   121  			Created:  now,
   122  			CharmURL: s.meteredCharm.URL().String(),
   123  			Metrics:  []state.Metric{m},
   124  			Unit:     s.unit.UnitTag(),
   125  		},
   126  	)
   127  	c.Assert(err, gc.ErrorMatches, `metered/0 not found`)
   128  }
   129  
   130  func (s *MetricSuite) TestSetMetricSent(c *gc.C) {
   131  	now := s.State.NowToTheSecond()
   132  	m := state.Metric{"pings", "5", now}
   133  	added, err := s.State.AddMetrics(
   134  		state.BatchParam{
   135  			UUID:     utils.MustNewUUID().String(),
   136  			Created:  now,
   137  			CharmURL: s.meteredCharm.URL().String(),
   138  			Metrics:  []state.Metric{m},
   139  			Unit:     s.unit.UnitTag(),
   140  		},
   141  	)
   142  	c.Assert(err, jc.ErrorIsNil)
   143  	saved, err := s.State.MetricBatch(added.UUID())
   144  	c.Assert(err, jc.ErrorIsNil)
   145  	err = saved.SetSent(testing.NonZeroTime())
   146  	c.Assert(err, jc.ErrorIsNil)
   147  	c.Assert(saved.Sent(), jc.IsTrue)
   148  	saved, err = s.State.MetricBatch(added.UUID())
   149  	c.Assert(err, jc.ErrorIsNil)
   150  	c.Assert(saved.Sent(), jc.IsTrue)
   151  }
   152  
   153  func (s *MetricSuite) TestCleanupMetrics(c *gc.C) {
   154  	oldTime := testing.NonZeroTime().Add(-(time.Hour * 25))
   155  	now := testing.NonZeroTime()
   156  	m := state.Metric{"pings", "5", oldTime}
   157  	oldMetric1, err := s.State.AddMetrics(
   158  		state.BatchParam{
   159  			UUID:     utils.MustNewUUID().String(),
   160  			Created:  now,
   161  			CharmURL: s.meteredCharm.URL().String(),
   162  			Metrics:  []state.Metric{m},
   163  			Unit:     s.unit.UnitTag(),
   164  		},
   165  	)
   166  	c.Assert(err, jc.ErrorIsNil)
   167  	oldMetric1.SetSent(testing.NonZeroTime().Add(-25 * time.Hour))
   168  
   169  	oldMetric2, err := s.State.AddMetrics(
   170  		state.BatchParam{
   171  			UUID:     utils.MustNewUUID().String(),
   172  			Created:  now,
   173  			CharmURL: s.meteredCharm.URL().String(),
   174  			Metrics:  []state.Metric{m},
   175  			Unit:     s.unit.UnitTag(),
   176  		},
   177  	)
   178  	c.Assert(err, jc.ErrorIsNil)
   179  	oldMetric2.SetSent(testing.NonZeroTime().Add(-25 * time.Hour))
   180  
   181  	m = state.Metric{"pings", "5", now}
   182  	newMetric, err := s.State.AddMetrics(
   183  		state.BatchParam{
   184  			UUID:     utils.MustNewUUID().String(),
   185  			Created:  now,
   186  			CharmURL: s.meteredCharm.URL().String(),
   187  			Metrics:  []state.Metric{m},
   188  			Unit:     s.unit.UnitTag(),
   189  		},
   190  	)
   191  	c.Assert(err, jc.ErrorIsNil)
   192  	newMetric.SetSent(testing.NonZeroTime())
   193  	err = s.State.CleanupOldMetrics()
   194  	c.Assert(err, jc.ErrorIsNil)
   195  
   196  	_, err = s.State.MetricBatch(newMetric.UUID())
   197  	c.Assert(err, jc.ErrorIsNil)
   198  
   199  	_, err = s.State.MetricBatch(oldMetric1.UUID())
   200  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   201  
   202  	_, err = s.State.MetricBatch(oldMetric2.UUID())
   203  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   204  }
   205  
   206  func (s *MetricSuite) TestCleanupNoMetrics(c *gc.C) {
   207  	err := s.State.CleanupOldMetrics()
   208  	c.Assert(err, jc.ErrorIsNil)
   209  }
   210  
   211  func (s *MetricSuite) TestCleanupMetricsIgnoreNotSent(c *gc.C) {
   212  	oldTime := testing.NonZeroTime().Add(-(time.Hour * 25))
   213  	m := state.Metric{"pings", "5", oldTime}
   214  	oldMetric, err := s.State.AddMetrics(
   215  		state.BatchParam{
   216  			UUID:     utils.MustNewUUID().String(),
   217  			Created:  oldTime,
   218  			CharmURL: s.meteredCharm.URL().String(),
   219  			Metrics:  []state.Metric{m},
   220  			Unit:     s.unit.UnitTag(),
   221  		},
   222  	)
   223  	c.Assert(err, jc.ErrorIsNil)
   224  
   225  	now := testing.NonZeroTime()
   226  	m = state.Metric{"pings", "5", now}
   227  	newMetric, err := s.State.AddMetrics(
   228  		state.BatchParam{
   229  			UUID:     utils.MustNewUUID().String(),
   230  			Created:  now,
   231  			CharmURL: s.meteredCharm.URL().String(),
   232  			Metrics:  []state.Metric{m},
   233  			Unit:     s.unit.UnitTag(),
   234  		},
   235  	)
   236  	c.Assert(err, jc.ErrorIsNil)
   237  	newMetric.SetSent(testing.NonZeroTime())
   238  	err = s.State.CleanupOldMetrics()
   239  	c.Assert(err, jc.ErrorIsNil)
   240  
   241  	_, err = s.State.MetricBatch(newMetric.UUID())
   242  	c.Assert(err, jc.ErrorIsNil)
   243  
   244  	_, err = s.State.MetricBatch(oldMetric.UUID())
   245  	c.Assert(err, jc.ErrorIsNil)
   246  }
   247  
   248  func (s *MetricSuite) TestAllMetricBatches(c *gc.C) {
   249  	now := s.State.NowToTheSecond()
   250  	m := state.Metric{"pings", "5", now}
   251  	_, err := s.State.AddMetrics(
   252  		state.BatchParam{
   253  			UUID:     utils.MustNewUUID().String(),
   254  			Created:  now,
   255  			CharmURL: s.meteredCharm.URL().String(),
   256  			Metrics:  []state.Metric{m},
   257  			Unit:     s.unit.UnitTag(),
   258  		},
   259  	)
   260  	c.Assert(err, jc.ErrorIsNil)
   261  	metricBatches, err := s.State.AllMetricBatches()
   262  	c.Assert(err, jc.ErrorIsNil)
   263  	c.Assert(metricBatches, gc.HasLen, 1)
   264  	c.Assert(metricBatches[0].Unit(), gc.Equals, "metered/0")
   265  	c.Assert(metricBatches[0].CharmURL(), gc.Equals, "cs:quantal/metered")
   266  	c.Assert(metricBatches[0].Sent(), jc.IsFalse)
   267  	c.Assert(metricBatches[0].Metrics(), gc.HasLen, 1)
   268  }
   269  
   270  func (s *MetricSuite) TestAllMetricBatchesCustomCharmURLAndUUID(c *gc.C) {
   271  	now := s.State.NowToTheSecond()
   272  	m := state.Metric{"pings", "5", now}
   273  	uuid := utils.MustNewUUID().String()
   274  	charmURL := "cs:quantal/metered"
   275  	_, err := s.State.AddMetrics(
   276  		state.BatchParam{
   277  			UUID:     uuid,
   278  			Created:  now,
   279  			CharmURL: charmURL,
   280  			Metrics:  []state.Metric{m},
   281  			Unit:     s.unit.UnitTag(),
   282  		},
   283  	)
   284  	c.Assert(err, jc.ErrorIsNil)
   285  	metricBatches, err := s.State.AllMetricBatches()
   286  	c.Assert(err, jc.ErrorIsNil)
   287  	c.Assert(metricBatches, gc.HasLen, 1)
   288  	c.Assert(metricBatches[0].Unit(), gc.Equals, "metered/0")
   289  	c.Assert(metricBatches[0].UUID(), gc.Equals, uuid)
   290  	c.Assert(metricBatches[0].CharmURL(), gc.Equals, charmURL)
   291  	c.Assert(metricBatches[0].Sent(), jc.IsFalse)
   292  	c.Assert(metricBatches[0].Metrics(), gc.HasLen, 1)
   293  }
   294  
   295  func (s *MetricSuite) TestMetricCredentials(c *gc.C) {
   296  	now := s.State.NowToTheSecond()
   297  	m := state.Metric{"pings", "5", now}
   298  	err := s.application.SetMetricCredentials([]byte("hello there"))
   299  	c.Assert(err, gc.IsNil)
   300  	_, err = s.State.AddMetrics(
   301  		state.BatchParam{
   302  			UUID:     utils.MustNewUUID().String(),
   303  			Created:  now,
   304  			CharmURL: s.meteredCharm.URL().String(),
   305  			Metrics:  []state.Metric{m},
   306  			Unit:     s.unit.UnitTag(),
   307  		},
   308  	)
   309  	c.Assert(err, jc.ErrorIsNil)
   310  	metricBatches, err := s.State.AllMetricBatches()
   311  	c.Assert(err, jc.ErrorIsNil)
   312  	c.Assert(metricBatches, gc.HasLen, 1)
   313  	c.Assert(metricBatches[0].Credentials(), gc.DeepEquals, []byte("hello there"))
   314  }
   315  
   316  // TestCountMetrics asserts the correct values are returned
   317  // by CountOfUnsentMetrics and CountOfSentMetrics.
   318  func (s *MetricSuite) TestCountMetrics(c *gc.C) {
   319  	now := testing.NonZeroTime()
   320  	m := []state.Metric{{Key: "pings", Value: "123", Time: now}}
   321  	s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.unit, Sent: false, Time: &now, Metrics: m})
   322  	s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.unit, Sent: false, Time: &now, Metrics: m})
   323  	s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.unit, Sent: true, Time: &now, Metrics: m})
   324  	sent, err := s.State.CountOfSentMetrics()
   325  	c.Assert(err, jc.ErrorIsNil)
   326  	c.Assert(sent, gc.Equals, 1)
   327  	unsent, err := s.State.CountOfUnsentMetrics()
   328  	c.Assert(err, jc.ErrorIsNil)
   329  	c.Assert(unsent, gc.Equals, 2)
   330  	c.Assert(unsent+sent, gc.Equals, 3)
   331  }
   332  
   333  func (s *MetricSuite) TestSetMetricBatchesSent(c *gc.C) {
   334  	now := testing.NonZeroTime()
   335  	metrics := make([]*state.MetricBatch, 3)
   336  	for i := range metrics {
   337  		m := []state.Metric{{Key: "pings", Value: "123", Time: now}}
   338  		metrics[i] = s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.unit, Sent: false, Time: &now, Metrics: m})
   339  	}
   340  	uuids := make([]string, len(metrics))
   341  	for i, m := range metrics {
   342  		uuids[i] = m.UUID()
   343  	}
   344  	err := s.State.SetMetricBatchesSent(uuids)
   345  	c.Assert(err, jc.ErrorIsNil)
   346  	sent, err := s.State.CountOfSentMetrics()
   347  	c.Assert(err, jc.ErrorIsNil)
   348  	c.Assert(sent, gc.Equals, 3)
   349  
   350  }
   351  
   352  func (s *MetricSuite) TestMetricsToSend(c *gc.C) {
   353  	now := s.State.NowToTheSecond()
   354  	m := []state.Metric{{Key: "pings", Value: "123", Time: now}}
   355  	s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.unit, Sent: false, Time: &now, Metrics: m})
   356  	s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.unit, Sent: false, Time: &now, Metrics: m})
   357  	s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.unit, Sent: true, Time: &now, Metrics: m})
   358  	result, err := s.State.MetricsToSend(5)
   359  	c.Assert(err, jc.ErrorIsNil)
   360  	c.Assert(result, gc.HasLen, 2)
   361  }
   362  
   363  // TestMetricsToSendBatches checks that metrics are properly batched.
   364  func (s *MetricSuite) TestMetricsToSendBatches(c *gc.C) {
   365  	now := s.State.NowToTheSecond()
   366  	for i := 0; i < 6; i++ {
   367  		m := []state.Metric{{Key: "pings", Value: "123", Time: now}}
   368  		s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.unit, Sent: false, Time: &now, Metrics: m})
   369  	}
   370  	for i := 0; i < 4; i++ {
   371  		m := []state.Metric{{Key: "pings", Value: "123", Time: now}}
   372  		s.Factory.MakeMetric(c, &factory.MetricParams{Unit: s.unit, Sent: true, Time: &now, Metrics: m})
   373  	}
   374  	for i := 0; i < 3; i++ {
   375  		result, err := s.State.MetricsToSend(2)
   376  		c.Assert(err, jc.ErrorIsNil)
   377  		c.Assert(result, gc.HasLen, 2)
   378  		uuids := make([]string, len(result))
   379  		for i, m := range result {
   380  			uuids[i] = m.UUID()
   381  		}
   382  		s.State.SetMetricBatchesSent(uuids)
   383  	}
   384  	result, err := s.State.MetricsToSend(2)
   385  	c.Assert(err, jc.ErrorIsNil)
   386  	c.Assert(result, gc.HasLen, 0)
   387  }
   388  
   389  func (s *MetricSuite) TestMetricValidation(c *gc.C) {
   390  	nonMeteredUnit := s.Factory.MakeUnit(c, &factory.UnitParams{SetCharmURL: true})
   391  	meteredApplication := s.Factory.MakeApplication(c, &factory.ApplicationParams{Name: "metered-service", Charm: s.meteredCharm})
   392  	meteredUnit := s.Factory.MakeUnit(c, &factory.UnitParams{Application: meteredApplication, SetCharmURL: true})
   393  	dyingUnit, err := meteredApplication.AddUnit()
   394  	c.Assert(err, jc.ErrorIsNil)
   395  	err = dyingUnit.SetCharmURL(s.meteredCharm.URL())
   396  	c.Assert(err, jc.ErrorIsNil)
   397  	err = dyingUnit.Destroy()
   398  	c.Assert(err, jc.ErrorIsNil)
   399  	now := testing.NonZeroTime()
   400  	tests := []struct {
   401  		about   string
   402  		metrics []state.Metric
   403  		unit    *state.Unit
   404  		err     string
   405  	}{{
   406  		"assert non metered unit returns an error",
   407  		[]state.Metric{{"metric-key", "1", now}},
   408  		nonMeteredUnit,
   409  		"charm doesn't implement metrics",
   410  	}, {
   411  		"assert metric with no errors and passes validation",
   412  		[]state.Metric{{"pings", "1", now}},
   413  		meteredUnit,
   414  		"",
   415  	}, {
   416  		"assert valid metric fails on dying unit",
   417  		[]state.Metric{{"pings", "1", now}},
   418  		dyingUnit,
   419  		"unit \"metered-service/1\" not found",
   420  	}, {
   421  		"assert charm doesn't implement key returns error",
   422  		[]state.Metric{{"not-implemented", "1", now}},
   423  		meteredUnit,
   424  		`metric "not-implemented" not defined`,
   425  	}, {
   426  		"assert invalid value returns error",
   427  		[]state.Metric{{"pings", "foobar", now}},
   428  		meteredUnit,
   429  		`invalid value type: expected float, got "foobar"`,
   430  	}, {
   431  		"long value returns error",
   432  		[]state.Metric{{"pings", "3.141592653589793238462643383279", now}},
   433  		meteredUnit,
   434  		`metric value is too large`,
   435  	}, {
   436  		"negative value returns error",
   437  		[]state.Metric{{"pings", "-42.0", now}},
   438  		meteredUnit,
   439  		`invalid value: value must be greater or equal to zero, got -42.0`,
   440  	}, {
   441  		"non-float value returns an error",
   442  		[]state.Metric{{"pings", "abcd", now}},
   443  		meteredUnit,
   444  		`invalid value type: expected float, got "abcd"`,
   445  	}}
   446  	for i, t := range tests {
   447  		c.Logf("test %d: %s", i, t.about)
   448  		chURL, ok := t.unit.CharmURL()
   449  		c.Assert(ok, jc.IsTrue)
   450  		_, err := s.State.AddMetrics(
   451  			state.BatchParam{
   452  				UUID:     utils.MustNewUUID().String(),
   453  				Created:  now,
   454  				CharmURL: chURL.String(),
   455  				Metrics:  t.metrics,
   456  				Unit:     t.unit.UnitTag(),
   457  			},
   458  		)
   459  		if t.err == "" {
   460  			c.Assert(err, jc.ErrorIsNil)
   461  		} else {
   462  			c.Assert(err, gc.ErrorMatches, t.err)
   463  		}
   464  	}
   465  }
   466  
   467  func (s *MetricSuite) TestAddMetricDuplicateUUID(c *gc.C) {
   468  	now := s.State.NowToTheSecond()
   469  	mUUID := utils.MustNewUUID().String()
   470  	_, err := s.State.AddMetrics(
   471  		state.BatchParam{
   472  			UUID:     mUUID,
   473  			Created:  now,
   474  			CharmURL: s.meteredCharm.URL().String(),
   475  			Metrics:  []state.Metric{{"pings", "5", now}},
   476  			Unit:     s.unit.UnitTag(),
   477  		},
   478  	)
   479  	c.Assert(err, jc.ErrorIsNil)
   480  
   481  	_, err = s.State.AddMetrics(
   482  		state.BatchParam{
   483  			UUID:     mUUID,
   484  			Created:  now,
   485  			CharmURL: s.meteredCharm.URL().String(),
   486  			Metrics:  []state.Metric{{"pings", "10", now}},
   487  			Unit:     s.unit.UnitTag(),
   488  		},
   489  	)
   490  	c.Assert(err, gc.ErrorMatches, "metrics batch .* already exists")
   491  }
   492  
   493  func (s *MetricSuite) TestAddBuiltInMetric(c *gc.C) {
   494  	tests := []struct {
   495  		about         string
   496  		value         string
   497  		expectedError string
   498  	}{{
   499  		about: "adding a positive value must succeed",
   500  		value: "5",
   501  	}, {
   502  		about:         "negative values return an error",
   503  		value:         "-42.0",
   504  		expectedError: "invalid value: value must be greater or equal to zero, got -42.0",
   505  	}, {
   506  		about:         "non-float values return an error",
   507  		value:         "abcd",
   508  		expectedError: `invalid value type: expected float, got "abcd"`,
   509  	}, {
   510  		about:         "long values return an error",
   511  		value:         "1234567890123456789012345678901234567890",
   512  		expectedError: "metric value is too large",
   513  	},
   514  	}
   515  	for _, test := range tests {
   516  		c.Logf("running test: %v", test.about)
   517  		now := s.State.NowToTheSecond()
   518  		modelUUID := s.State.ModelUUID()
   519  		m := state.Metric{"juju-units", test.value, now}
   520  		metricBatch, err := s.State.AddMetrics(
   521  			state.BatchParam{
   522  				UUID:     utils.MustNewUUID().String(),
   523  				Created:  now,
   524  				CharmURL: s.meteredCharm.URL().String(),
   525  				Metrics:  []state.Metric{m},
   526  				Unit:     s.unit.UnitTag(),
   527  			},
   528  		)
   529  		if test.expectedError == "" {
   530  			c.Assert(err, jc.ErrorIsNil)
   531  			c.Assert(metricBatch.Unit(), gc.Equals, "metered/0")
   532  			c.Assert(metricBatch.ModelUUID(), gc.Equals, modelUUID)
   533  			c.Assert(metricBatch.CharmURL(), gc.Equals, "cs:quantal/metered")
   534  			c.Assert(metricBatch.Sent(), jc.IsFalse)
   535  			c.Assert(metricBatch.Created(), gc.Equals, now)
   536  			c.Assert(metricBatch.Metrics(), gc.HasLen, 1)
   537  
   538  			metric := metricBatch.Metrics()[0]
   539  			c.Assert(metric.Key, gc.Equals, "juju-units")
   540  			c.Assert(metric.Value, gc.Equals, test.value)
   541  			c.Assert(metric.Time.Equal(now), jc.IsTrue)
   542  
   543  			saved, err := s.State.MetricBatch(metricBatch.UUID())
   544  			c.Assert(err, jc.ErrorIsNil)
   545  			c.Assert(saved.Unit(), gc.Equals, "metered/0")
   546  			c.Assert(metricBatch.CharmURL(), gc.Equals, "cs:quantal/metered")
   547  			c.Assert(saved.Sent(), jc.IsFalse)
   548  			c.Assert(saved.Metrics(), gc.HasLen, 1)
   549  			metric = saved.Metrics()[0]
   550  			c.Assert(metric.Key, gc.Equals, "juju-units")
   551  			c.Assert(metric.Value, gc.Equals, test.value)
   552  			c.Assert(metric.Time.Equal(now), jc.IsTrue)
   553  		} else {
   554  			c.Assert(err, gc.ErrorMatches, test.expectedError)
   555  		}
   556  	}
   557  }
   558  
   559  func (s *MetricSuite) TestUnitMetricBatchesMatchesAllCharms(c *gc.C) {
   560  	now := s.State.NowToTheSecond()
   561  	m := state.Metric{"pings", "5", now}
   562  	_, err := s.State.AddMetrics(
   563  		state.BatchParam{
   564  			UUID:     utils.MustNewUUID().String(),
   565  			Created:  now,
   566  			CharmURL: s.meteredCharm.URL().String(),
   567  			Metrics:  []state.Metric{m},
   568  			Unit:     s.unit.UnitTag(),
   569  		},
   570  	)
   571  	c.Assert(err, jc.ErrorIsNil)
   572  	localMeteredCharm := s.Factory.MakeCharm(c, &factory.CharmParams{Name: "metered", URL: "local:quantal/metered"})
   573  	application := s.Factory.MakeApplication(c, &factory.ApplicationParams{Name: "localmetered", Charm: localMeteredCharm})
   574  	unit := s.Factory.MakeUnit(c, &factory.UnitParams{Application: application, SetCharmURL: true})
   575  	_, err = s.State.AddMetrics(
   576  		state.BatchParam{
   577  			UUID:     utils.MustNewUUID().String(),
   578  			Created:  now,
   579  			CharmURL: localMeteredCharm.URL().String(),
   580  			Metrics:  []state.Metric{m},
   581  			Unit:     unit.UnitTag(),
   582  		},
   583  	)
   584  
   585  	c.Assert(err, jc.ErrorIsNil)
   586  	metricBatches, err := s.State.MetricBatchesForUnit("metered/0")
   587  	c.Assert(metricBatches, gc.HasLen, 1)
   588  	metricBatches, err = s.State.MetricBatchesForUnit("localmetered/0")
   589  	c.Assert(metricBatches, gc.HasLen, 1)
   590  }
   591  
   592  func (s *MetricSuite) TestNoSuchUnitMetricBatches(c *gc.C) {
   593  	_, err := s.State.MetricBatchesForUnit("chimerical-unit/0")
   594  	c.Assert(err, gc.ErrorMatches, `unit "chimerical-unit/0" not found`)
   595  }
   596  
   597  func (s *MetricSuite) TestNoSuchApplicationMetricBatches(c *gc.C) {
   598  	_, err := s.State.MetricBatchesForApplication("unicorn-app")
   599  	c.Assert(err, gc.ErrorMatches, `application "unicorn-app" not found`)
   600  }
   601  
   602  type MetricLocalCharmSuite struct {
   603  	ConnSuite
   604  	unit         *state.Unit
   605  	application  *state.Application
   606  	meteredCharm *state.Charm
   607  }
   608  
   609  var _ = gc.Suite(&MetricLocalCharmSuite{})
   610  
   611  func (s *MetricLocalCharmSuite) SetUpTest(c *gc.C) {
   612  	s.ConnSuite.SetUpTest(c)
   613  	s.meteredCharm = s.Factory.MakeCharm(c, &factory.CharmParams{Name: "metered", URL: "local:quantal/metered"})
   614  	s.application = s.Factory.MakeApplication(c, &factory.ApplicationParams{Charm: s.meteredCharm})
   615  	s.unit = s.Factory.MakeUnit(c, &factory.UnitParams{Application: s.application, SetCharmURL: true})
   616  }
   617  
   618  func (s *MetricLocalCharmSuite) TestUnitMetricBatches(c *gc.C) {
   619  	now := s.State.NowToTheSecond()
   620  	m := state.Metric{"pings", "5", now}
   621  	m2 := state.Metric{"pings", "10", now}
   622  	_, err := s.State.AddMetrics(
   623  		state.BatchParam{
   624  			UUID:     utils.MustNewUUID().String(),
   625  			Created:  now,
   626  			CharmURL: s.meteredCharm.URL().String(),
   627  			Metrics:  []state.Metric{m},
   628  			Unit:     s.unit.UnitTag(),
   629  		},
   630  	)
   631  	c.Assert(err, jc.ErrorIsNil)
   632  	newUnit, err := s.application.AddUnit()
   633  	c.Assert(err, jc.ErrorIsNil)
   634  	_, err = s.State.AddMetrics(
   635  		state.BatchParam{
   636  			UUID:     utils.MustNewUUID().String(),
   637  			Created:  now,
   638  			CharmURL: s.meteredCharm.URL().String(),
   639  			Metrics:  []state.Metric{m2},
   640  			Unit:     newUnit.UnitTag(),
   641  		},
   642  	)
   643  	c.Assert(err, jc.ErrorIsNil)
   644  
   645  	metricBatches, err := s.State.MetricBatchesForUnit("metered/0")
   646  	c.Assert(err, jc.ErrorIsNil)
   647  	c.Assert(metricBatches, gc.HasLen, 1)
   648  	c.Check(metricBatches[0].Unit(), gc.Equals, "metered/0")
   649  	c.Check(metricBatches[0].CharmURL(), gc.Equals, "local:quantal/metered")
   650  	c.Check(metricBatches[0].Sent(), jc.IsFalse)
   651  	c.Assert(metricBatches[0].Metrics(), gc.HasLen, 1)
   652  	c.Check(metricBatches[0].Metrics()[0].Value, gc.Equals, "5")
   653  
   654  	metricBatches, err = s.State.MetricBatchesForUnit("metered/1")
   655  	c.Assert(err, jc.ErrorIsNil)
   656  	c.Assert(metricBatches, gc.HasLen, 1)
   657  	c.Check(metricBatches[0].Unit(), gc.Equals, "metered/1")
   658  	c.Check(metricBatches[0].CharmURL(), gc.Equals, "local:quantal/metered")
   659  	c.Check(metricBatches[0].Sent(), jc.IsFalse)
   660  	c.Assert(metricBatches[0].Metrics(), gc.HasLen, 1)
   661  	c.Check(metricBatches[0].Metrics()[0].Value, gc.Equals, "10")
   662  }
   663  
   664  func (s *MetricLocalCharmSuite) TestApplicationMetricBatches(c *gc.C) {
   665  	now := s.State.NowToTheSecond()
   666  	m := state.Metric{"pings", "5", now}
   667  	m2 := state.Metric{"pings", "10", now}
   668  	_, err := s.State.AddMetrics(
   669  		state.BatchParam{
   670  			UUID:     utils.MustNewUUID().String(),
   671  			Created:  now,
   672  			CharmURL: s.meteredCharm.URL().String(),
   673  			Metrics:  []state.Metric{m},
   674  			Unit:     s.unit.UnitTag(),
   675  		},
   676  	)
   677  	c.Assert(err, jc.ErrorIsNil)
   678  	newUnit, err := s.application.AddUnit()
   679  	c.Assert(err, jc.ErrorIsNil)
   680  	_, err = s.State.AddMetrics(
   681  		state.BatchParam{
   682  			UUID:     utils.MustNewUUID().String(),
   683  			Created:  now,
   684  			CharmURL: s.meteredCharm.URL().String(),
   685  			Metrics:  []state.Metric{m2},
   686  			Unit:     newUnit.UnitTag(),
   687  		},
   688  	)
   689  	c.Assert(err, jc.ErrorIsNil)
   690  
   691  	metricBatches, err := s.State.MetricBatchesForApplication("metered")
   692  	c.Assert(err, jc.ErrorIsNil)
   693  	c.Assert(metricBatches, gc.HasLen, 2)
   694  
   695  	c.Check(metricBatches[0].Unit(), gc.Equals, "metered/0")
   696  	c.Check(metricBatches[0].CharmURL(), gc.Equals, "local:quantal/metered")
   697  	c.Check(metricBatches[0].Sent(), jc.IsFalse)
   698  	c.Assert(metricBatches[0].Metrics(), gc.HasLen, 1)
   699  	c.Check(metricBatches[0].Metrics()[0].Value, gc.Equals, "5")
   700  
   701  	c.Check(metricBatches[1].Unit(), gc.Equals, "metered/1")
   702  	c.Check(metricBatches[1].CharmURL(), gc.Equals, "local:quantal/metered")
   703  	c.Check(metricBatches[1].Sent(), jc.IsFalse)
   704  	c.Assert(metricBatches[1].Metrics(), gc.HasLen, 1)
   705  	c.Check(metricBatches[1].Metrics()[0].Value, gc.Equals, "10")
   706  }
   707  
   708  func (s *MetricLocalCharmSuite) TestModelMetricBatches(c *gc.C) {
   709  	now := s.State.NowToTheSecond()
   710  	// Add 2 metric batches to a single unit.
   711  	m := state.Metric{"pings", "5", now}
   712  	m2 := state.Metric{"pings", "10", now}
   713  	_, err := s.State.AddMetrics(
   714  		state.BatchParam{
   715  			UUID:     utils.MustNewUUID().String(),
   716  			Created:  now,
   717  			CharmURL: s.meteredCharm.URL().String(),
   718  			Metrics:  []state.Metric{m},
   719  			Unit:     s.unit.UnitTag(),
   720  		},
   721  	)
   722  	c.Assert(err, jc.ErrorIsNil)
   723  	newUnit, err := s.application.AddUnit()
   724  	c.Assert(err, jc.ErrorIsNil)
   725  	_, err = s.State.AddMetrics(
   726  		state.BatchParam{
   727  			UUID:     utils.MustNewUUID().String(),
   728  			Created:  now.Add(time.Second),
   729  			CharmURL: s.meteredCharm.URL().String(),
   730  			Metrics:  []state.Metric{m2},
   731  			Unit:     newUnit.UnitTag(),
   732  		},
   733  	)
   734  	c.Assert(err, jc.ErrorIsNil)
   735  
   736  	// Create a new model and add a metric batch.
   737  	st := s.Factory.MakeModel(c, nil)
   738  	defer st.Close()
   739  	f := factory.NewFactory(st)
   740  	meteredCharm := f.MakeCharm(c, &factory.CharmParams{Name: "metered", URL: "cs:quantal/metered"})
   741  	service := f.MakeApplication(c, &factory.ApplicationParams{Charm: meteredCharm})
   742  	unit := f.MakeUnit(c, &factory.UnitParams{Application: service, SetCharmURL: true})
   743  	_, err = st.AddMetrics(
   744  		state.BatchParam{
   745  			UUID:     utils.MustNewUUID().String(),
   746  			Created:  now,
   747  			CharmURL: meteredCharm.URL().String(),
   748  			Metrics:  []state.Metric{m},
   749  			Unit:     unit.UnitTag(),
   750  		},
   751  	)
   752  	c.Assert(err, jc.ErrorIsNil)
   753  
   754  	// We expect 2 metric batches in our first model.
   755  	metricBatches, err := s.State.MetricBatchesForModel()
   756  	c.Assert(err, jc.ErrorIsNil)
   757  	c.Assert(metricBatches, gc.HasLen, 2)
   758  
   759  	var first, second state.MetricBatch
   760  	for _, m := range metricBatches {
   761  		if m.Unit() == "metered/0" {
   762  			first = m
   763  		}
   764  		if m.Unit() == "metered/1" {
   765  			second = m
   766  		}
   767  	}
   768  	c.Assert(first, gc.NotNil)
   769  	c.Assert(second, gc.NotNil)
   770  
   771  	c.Check(first.Unit(), gc.Equals, "metered/0")
   772  	c.Check(first.CharmURL(), gc.Equals, "local:quantal/metered")
   773  	c.Check(first.ModelUUID(), gc.Equals, s.State.ModelUUID())
   774  	c.Check(first.Sent(), jc.IsFalse)
   775  	c.Assert(first.Metrics(), gc.HasLen, 1)
   776  	c.Check(first.Metrics()[0].Value, gc.Equals, "5")
   777  
   778  	c.Check(second.Unit(), gc.Equals, "metered/1")
   779  	c.Check(second.CharmURL(), gc.Equals, "local:quantal/metered")
   780  	c.Check(second.ModelUUID(), gc.Equals, s.State.ModelUUID())
   781  	c.Check(second.Sent(), jc.IsFalse)
   782  	c.Assert(second.Metrics(), gc.HasLen, 1)
   783  	c.Check(second.Metrics()[0].Value, gc.Equals, "10")
   784  
   785  	// And a single metric batch in the second model.
   786  	metricBatches, err = st.MetricBatchesForModel()
   787  	c.Assert(err, jc.ErrorIsNil)
   788  	c.Assert(metricBatches, gc.HasLen, 1)
   789  }
   790  
   791  func (s *MetricLocalCharmSuite) TestMetricsSorted(c *gc.C) {
   792  	newUnit, err := s.application.AddUnit()
   793  	c.Assert(err, jc.ErrorIsNil)
   794  
   795  	t0 := time.Date(2016, time.August, 16, 16, 00, 35, 0, time.Local)
   796  	var times []time.Time
   797  	for i := 0; i < 3; i++ {
   798  		times = append(times, t0.Add(time.Minute*time.Duration(i)))
   799  	}
   800  
   801  	for _, t := range times {
   802  		_, err := s.State.AddMetrics(
   803  			state.BatchParam{
   804  				UUID:     utils.MustNewUUID().String(),
   805  				Created:  t,
   806  				CharmURL: s.meteredCharm.URL().String(),
   807  				Metrics:  []state.Metric{{"pings", "5", t}},
   808  				Unit:     s.unit.UnitTag(),
   809  			},
   810  		)
   811  		c.Assert(err, jc.ErrorIsNil)
   812  
   813  		_, err = s.State.AddMetrics(
   814  			state.BatchParam{
   815  				UUID:     utils.MustNewUUID().String(),
   816  				Created:  t,
   817  				CharmURL: s.meteredCharm.URL().String(),
   818  				Metrics:  []state.Metric{{"pings", "10", t}},
   819  				Unit:     newUnit.UnitTag(),
   820  			},
   821  		)
   822  		c.Assert(err, jc.ErrorIsNil)
   823  	}
   824  
   825  	metricBatches, err := s.State.MetricBatchesForUnit("metered/0")
   826  	c.Assert(err, jc.ErrorIsNil)
   827  	assertMetricBatchesTimeAscending(c, metricBatches)
   828  
   829  	metricBatches, err = s.State.MetricBatchesForUnit("metered/1")
   830  	c.Assert(err, jc.ErrorIsNil)
   831  	assertMetricBatchesTimeAscending(c, metricBatches)
   832  
   833  	metricBatches, err = s.State.MetricBatchesForApplication("metered")
   834  	c.Assert(err, jc.ErrorIsNil)
   835  	assertMetricBatchesTimeAscending(c, metricBatches)
   836  
   837  	metricBatches, err = s.State.MetricBatchesForModel()
   838  	c.Assert(err, jc.ErrorIsNil)
   839  	assertMetricBatchesTimeAscending(c, metricBatches)
   840  
   841  }
   842  
   843  func assertMetricBatchesTimeAscending(c *gc.C, batches []state.MetricBatch) {
   844  	var tPrev time.Time
   845  
   846  	for i := range batches {
   847  		if i > 0 {
   848  			afterOrEqualPrev := func(t time.Time) bool {
   849  				return t.After(tPrev) || t.Equal(tPrev)
   850  			}
   851  			desc := gc.Commentf("%+v <= %+v", batches[i-1], batches[i])
   852  			c.Assert(batches[i].Created(), jc.Satisfies, afterOrEqualPrev, desc)
   853  			c.Assert(batches[i].Metrics(), gc.HasLen, 1)
   854  			c.Assert(batches[i].Metrics()[0].Time, jc.Satisfies, afterOrEqualPrev, desc)
   855  		}
   856  		tPrev = batches[i].Created()
   857  	}
   858  }
   859  
   860  func (s *MetricLocalCharmSuite) TestUnitMetricBatchesReturnsAllCharms(c *gc.C) {
   861  	now := s.State.NowToTheSecond()
   862  	m := state.Metric{"pings", "5", now}
   863  	_, err := s.State.AddMetrics(
   864  		state.BatchParam{
   865  			UUID:     utils.MustNewUUID().String(),
   866  			Created:  now,
   867  			CharmURL: s.meteredCharm.URL().String(),
   868  			Metrics:  []state.Metric{m},
   869  			Unit:     s.unit.UnitTag(),
   870  		},
   871  	)
   872  	c.Assert(err, jc.ErrorIsNil)
   873  	csMeteredCharm := s.Factory.MakeCharm(c, &factory.CharmParams{Name: "metered", URL: "cs:quantal/metered"})
   874  	application := s.Factory.MakeApplication(c, &factory.ApplicationParams{Name: "csmetered", Charm: csMeteredCharm})
   875  	unit := s.Factory.MakeUnit(c, &factory.UnitParams{Application: application, SetCharmURL: true})
   876  	_, err = s.State.AddMetrics(
   877  		state.BatchParam{
   878  			UUID:     utils.MustNewUUID().String(),
   879  			Created:  now,
   880  			CharmURL: csMeteredCharm.URL().String(),
   881  			Metrics:  []state.Metric{m},
   882  			Unit:     unit.UnitTag(),
   883  		},
   884  	)
   885  
   886  	c.Assert(err, jc.ErrorIsNil)
   887  	metricBatches, err := s.State.MetricBatchesForUnit("metered/0")
   888  	c.Assert(metricBatches, gc.HasLen, 1)
   889  	metricBatches, err = s.State.MetricBatchesForUnit("csmetered/0")
   890  	c.Assert(metricBatches, gc.HasLen, 1)
   891  }
   892  
   893  func (s *MetricLocalCharmSuite) TestUnique(c *gc.C) {
   894  	t0 := s.State.NowToTheSecond()
   895  	t1 := t0.Add(time.Second)
   896  	batch, err := s.State.AddMetrics(
   897  		state.BatchParam{
   898  			UUID:     utils.MustNewUUID().String(),
   899  			Created:  t0,
   900  			CharmURL: s.meteredCharm.URL().String(),
   901  			Metrics: []state.Metric{{
   902  				Key:   "pings",
   903  				Value: "1",
   904  				Time:  t0,
   905  			}, {
   906  				Key:   "pings",
   907  				Value: "2",
   908  				Time:  t1,
   909  			}, {
   910  				Key:   "juju-units",
   911  				Value: "1",
   912  				Time:  t1,
   913  			}, {
   914  				Key:   "juju-units",
   915  				Value: "2",
   916  				Time:  t0,
   917  			}},
   918  			Unit: s.unit.UnitTag(),
   919  		},
   920  	)
   921  	c.Assert(err, jc.ErrorIsNil)
   922  	metrics := batch.UniqueMetrics()
   923  	c.Assert(metrics, gc.HasLen, 2)
   924  	c.Assert(metrics, jc.SameContents, []state.Metric{{
   925  		Key:   "pings",
   926  		Value: "2",
   927  		Time:  t1,
   928  	}, {
   929  		Key:   "juju-units",
   930  		Value: "1",
   931  		Time:  t1,
   932  	}})
   933  }
   934  
   935  type modelData struct {
   936  	state        *state.State
   937  	application  *state.Application
   938  	unit         *state.Unit
   939  	meteredCharm *state.Charm
   940  }
   941  
   942  type CrossModelMetricSuite struct {
   943  	ConnSuite
   944  	models []modelData
   945  }
   946  
   947  var _ = gc.Suite(&CrossModelMetricSuite{})
   948  
   949  func (s *CrossModelMetricSuite) SetUpTest(c *gc.C) {
   950  	s.ConnSuite.SetUpTest(c)
   951  	// Set up two models.
   952  	s.models = make([]modelData, 2)
   953  	var cleanup func(*gc.C)
   954  	for i := 0; i < 2; i++ {
   955  		s.models[i], cleanup = mustCreateMeteredModel(c, s.Factory)
   956  		s.AddCleanup(cleanup)
   957  	}
   958  }
   959  
   960  func mustCreateMeteredModel(c *gc.C, stateFactory *factory.Factory) (modelData, func(*gc.C)) {
   961  	st := stateFactory.MakeModel(c, nil)
   962  	localFactory := factory.NewFactory(st)
   963  
   964  	meteredCharm := localFactory.MakeCharm(c, &factory.CharmParams{Name: "metered", URL: "cs:quantal/metered"})
   965  	application := localFactory.MakeApplication(c, &factory.ApplicationParams{Charm: meteredCharm})
   966  	unit := localFactory.MakeUnit(c, &factory.UnitParams{Application: application, SetCharmURL: true})
   967  	cleanup := func(*gc.C) { st.Close() }
   968  	return modelData{
   969  		state:        st,
   970  		application:  application,
   971  		unit:         unit,
   972  		meteredCharm: meteredCharm,
   973  	}, cleanup
   974  }
   975  
   976  func (s *CrossModelMetricSuite) TestMetricsAcrossEnvironments(c *gc.C) {
   977  	now := s.State.NowToTheSecond().Add(-48 * time.Hour)
   978  	m := state.Metric{"pings", "5", now}
   979  	m1, err := s.models[0].state.AddMetrics(
   980  		state.BatchParam{
   981  			UUID:     utils.MustNewUUID().String(),
   982  			Created:  now,
   983  			CharmURL: s.models[0].meteredCharm.URL().String(),
   984  			Metrics:  []state.Metric{m},
   985  			Unit:     s.models[0].unit.UnitTag(),
   986  		},
   987  	)
   988  	c.Assert(err, jc.ErrorIsNil)
   989  
   990  	m2, err := s.models[1].state.AddMetrics(
   991  		state.BatchParam{
   992  			UUID:     utils.MustNewUUID().String(),
   993  			Created:  now,
   994  			CharmURL: s.models[1].meteredCharm.URL().String(),
   995  			Metrics:  []state.Metric{m},
   996  			Unit:     s.models[1].unit.UnitTag(),
   997  		},
   998  	)
   999  	c.Assert(err, jc.ErrorIsNil)
  1000  
  1001  	batches, err := s.State.AllMetricBatches()
  1002  	c.Assert(err, jc.ErrorIsNil)
  1003  	c.Assert(batches, gc.HasLen, 2)
  1004  
  1005  	unsent, err := s.models[0].state.CountOfUnsentMetrics()
  1006  	c.Assert(err, jc.ErrorIsNil)
  1007  	c.Assert(unsent, gc.Equals, 1)
  1008  
  1009  	toSend, err := s.models[0].state.MetricsToSend(10)
  1010  	c.Assert(err, jc.ErrorIsNil)
  1011  	c.Assert(toSend, gc.HasLen, 1)
  1012  
  1013  	err = m1.SetSent(testing.NonZeroTime().Add(-25 * time.Hour))
  1014  	c.Assert(err, jc.ErrorIsNil)
  1015  	err = m2.SetSent(testing.NonZeroTime().Add(-25 * time.Hour))
  1016  	c.Assert(err, jc.ErrorIsNil)
  1017  
  1018  	sent, err := s.models[0].state.CountOfSentMetrics()
  1019  	c.Assert(err, jc.ErrorIsNil)
  1020  	c.Assert(sent, gc.Equals, 1)
  1021  
  1022  	err = s.models[0].state.CleanupOldMetrics()
  1023  	c.Assert(err, jc.ErrorIsNil)
  1024  
  1025  	// The metric from model s.models[1] should still be in place.
  1026  	batches, err = s.State.AllMetricBatches()
  1027  	c.Assert(err, jc.ErrorIsNil)
  1028  	c.Assert(batches, gc.HasLen, 1)
  1029  }