From 4c42de99daaf919827424ddc8a0cad9edce2ead1 Mon Sep 17 00:00:00 2001 From: Simon Richardson Date: Wed, 21 Feb 2024 10:31:19 +0000 Subject: [PATCH] Removes metrics code We no longer support metrics code, so we should remove the code. Moving it to dqlite would require understanding and maintaining code that has not full tested or integrated with romulus or omnibus is sometime. Fully understanding if all parts are correct would be challenging. If in the future we want to reuse parts, we can always look back in the history of the repo to bring back the parts that are required (if any). --- README.md | 5 - charm.go | 1 - charmarchive.go | 11 - charmarchive_test.go | 26 -- charmbase.go | 7 - charmdir.go | 11 - charmdir_test.go | 28 +- export_test.go | 1 - hooks/hooks.go | 4 - .../quantal/all-hooks/hooks/collect-metrics | 2 - .../all-hooks/hooks/meter-status-changed | 2 - .../quantal/metered-empty/manifest.yaml | 5 - .../quantal/metered-empty/metadata.yaml | 3 - .../quantal/metered-empty/metrics.yaml | 0 .../quantal/metered-empty/revision | 1 - .../quantal/metered/manifest.yaml | 5 - .../quantal/metered/metadata.yaml | 3 - .../quantal/metered/metrics.yaml | 5 - .../test-charm-repo/quantal/metered/revision | 1 - meta_test.go | 6 - metrics.go | 125 -------- metrics_test.go | 274 ------------------ 22 files changed, 1 insertion(+), 525 deletions(-) delete mode 100644 internal/test-charm-repo/quantal/all-hooks/hooks/collect-metrics delete mode 100644 internal/test-charm-repo/quantal/all-hooks/hooks/meter-status-changed delete mode 100644 internal/test-charm-repo/quantal/metered-empty/manifest.yaml delete mode 100644 internal/test-charm-repo/quantal/metered-empty/metadata.yaml delete mode 100644 internal/test-charm-repo/quantal/metered-empty/metrics.yaml delete mode 100644 internal/test-charm-repo/quantal/metered-empty/revision delete mode 100644 internal/test-charm-repo/quantal/metered/manifest.yaml delete mode 100644 internal/test-charm-repo/quantal/metered/metadata.yaml delete mode 100644 internal/test-charm-repo/quantal/metered/metrics.yaml delete mode 100644 internal/test-charm-repo/quantal/metered/revision delete mode 100644 metrics.go delete mode 100644 metrics_test.go diff --git a/README.md b/README.md index 9fd49d5c..a643b7b4 100644 --- a/README.md +++ b/README.md @@ -55,11 +55,6 @@ All the other fields are optional. The type can be either a `string`, `int`, `float` or `boolean`. Everything else will cause Juju to error out when reading the charm. -### `metrics.yaml` - -`metrics.yaml` represents an optional metrics gathering configuration yaml. For -more information about metrics, read up on [Metric collecting charms](https://discourse.juju.is/t/metric-collecting-charms/1125) - ### `revision` The `revision` is used to indicate the revision of a charm. It expects that only diff --git a/charm.go b/charm.go index 19a74314..9739c621 100644 --- a/charm.go +++ b/charm.go @@ -26,7 +26,6 @@ type CharmMeta interface { type Charm interface { CharmMeta Config() *Config - Metrics() *Metrics Actions() *Actions Revision() int } diff --git a/charmarchive.go b/charmarchive.go index f28bd9ce..b4273dd5 100644 --- a/charmarchive.go +++ b/charmarchive.go @@ -105,17 +105,6 @@ func readCharmArchive(zopen zipOpener) (archive *CharmArchive, err error) { } } - reader, err = zipOpenFile(zipr, "metrics.yaml") - if err == nil { - b.metrics, err = ReadMetrics(reader) - _ = reader.Close() - if err != nil { - return nil, err - } - } else if _, ok := err.(*noCharmArchiveFile); !ok { - return nil, err - } - if b.actions, err = getActions( b.meta.Name, func(file string) (io.ReadCloser, error) { diff --git a/charmarchive_test.go b/charmarchive_test.go index d848426e..d0dd8c25 100644 --- a/charmarchive_test.go +++ b/charmarchive_test.go @@ -104,32 +104,6 @@ func (s *CharmArchiveSuite) TestReadCharmArchiveWithoutManifest(c *gc.C) { c.Assert(dir.Manifest(), gc.IsNil) } -func (s *CharmArchiveSuite) TestReadCharmArchiveWithoutMetrics(c *gc.C) { - path := archivePath(c, readCharmDir(c, "varnish")) - dir, err := charm.ReadCharmArchive(path) - c.Assert(err, gc.IsNil) - - // A lacking metrics.yaml file indicates the unit will not - // be metered. - c.Assert(dir.Metrics(), gc.IsNil) -} - -func (s *CharmArchiveSuite) TestReadCharmArchiveWithEmptyMetrics(c *gc.C) { - path := archivePath(c, readCharmDir(c, "metered-empty")) - dir, err := charm.ReadCharmArchive(path) - c.Assert(err, gc.IsNil) - c.Assert(Keys(dir.Metrics()), gc.HasLen, 0) -} - -func (s *CharmArchiveSuite) TestReadCharmArchiveWithCustomMetrics(c *gc.C) { - path := archivePath(c, readCharmDir(c, "metered")) - dir, err := charm.ReadCharmArchive(path) - c.Assert(err, gc.IsNil) - - c.Assert(dir.Metrics(), gc.NotNil) - c.Assert(Keys(dir.Metrics()), gc.DeepEquals, []string{"juju-unit-time", "pings"}) -} - func (s *CharmArchiveSuite) TestReadCharmArchiveWithoutActions(c *gc.C) { // Wordpress has config but no actions. path := archivePath(c, readCharmDir(c, "wordpress")) diff --git a/charmbase.go b/charmbase.go index 85aacfb3..c881a726 100644 --- a/charmbase.go +++ b/charmbase.go @@ -8,7 +8,6 @@ package charm type charmBase struct { meta *Meta config *Config - metrics *Metrics actions *Actions lxdProfile *LXDProfile manifest *Manifest @@ -39,12 +38,6 @@ func (c *charmBase) Config() *Config { return c.config } -// Metrics returns the Metrics representing the metrics.yaml file -// for the charm expanded in dir. -func (c *charmBase) Metrics() *Metrics { - return c.metrics -} - // Actions returns the Actions representing the actions.yaml file // for the charm expanded in dir. func (c *charmBase) Actions() *Actions { diff --git a/charmdir.go b/charmdir.go index e281e615..a3baab29 100644 --- a/charmdir.go +++ b/charmdir.go @@ -103,17 +103,6 @@ func ReadCharmDir(path string) (*CharmDir, error) { } } - reader, err = os.Open(b.join("metrics.yaml")) - if err == nil { - b.metrics, err = ReadMetrics(reader) - _ = reader.Close() - if err != nil { - return nil, errors.Annotatef(err, `parsing "metrics.yaml" file`) - } - } else if !os.IsNotExist(err) { - return nil, errors.Annotatef(err, `reading "metrics.yaml" file`) - } - if b.actions, err = getActions( b.meta.Name, func(file string) (io.ReadCloser, error) { diff --git a/charmdir_test.go b/charmdir_test.go index 50c62f72..8a2c5118 100644 --- a/charmdir_test.go +++ b/charmdir_test.go @@ -63,32 +63,6 @@ func (s *CharmDirSuite) TestReadCharmDirWithoutConfig(c *gc.C) { c.Assert(dir.Config().Options, gc.HasLen, 0) } -func (s *CharmDirSuite) TestReadCharmDirWithoutMetrics(c *gc.C) { - path := charmDirPath(c, "varnish") - dir, err := charm.ReadCharmDir(path) - c.Assert(err, gc.IsNil) - - // A lacking metrics.yaml file indicates the unit will not - // be metered. - c.Assert(dir.Metrics(), gc.IsNil) -} - -func (s *CharmDirSuite) TestReadCharmDirWithEmptyMetrics(c *gc.C) { - path := charmDirPath(c, "metered-empty") - dir, err := charm.ReadCharmDir(path) - c.Assert(err, gc.IsNil) - c.Assert(Keys(dir.Metrics()), gc.HasLen, 0) -} - -func (s *CharmDirSuite) TestReadCharmDirWithCustomMetrics(c *gc.C) { - path := charmDirPath(c, "metered") - dir, err := charm.ReadCharmDir(path) - c.Assert(err, gc.IsNil) - - c.Assert(dir.Metrics(), gc.NotNil) - c.Assert(Keys(dir.Metrics()), gc.DeepEquals, []string{"juju-unit-time", "pings"}) -} - func (s *CharmDirSuite) TestReadCharmDirWithoutActions(c *gc.C) { path := charmDirPath(c, "wordpress") dir, err := charm.ReadCharmDir(path) @@ -461,7 +435,7 @@ func (s *CharmDirSuite) assertArchiveTo(c *gc.C, baseDir, charmDir string) { // Bug #864164: Must complain if charm hooks aren't executable func (s *CharmDirSuite) TestArchiveToWithNonExecutableHooks(c *gc.C) { - hooks := []string{"install", "start", "config-changed", "upgrade-charm", "stop", "collect-metrics", "meter-status-changed"} + hooks := []string{"install", "start", "config-changed", "upgrade-charm", "stop"} for _, relName := range []string{"foo", "bar", "self"} { for _, kind := range []string{"joined", "changed", "departed", "broken"} { hooks = append(hooks, relName+"-relation-"+kind) diff --git a/export_test.go b/export_test.go index b97e75f2..36766c61 100644 --- a/export_test.go +++ b/export_test.go @@ -7,7 +7,6 @@ package charm var ( IfaceExpander = ifaceExpander - ValidateValue = validateValue ParsePayloadClass = parsePayloadClass ResourceSchema = resourceSchema diff --git a/hooks/hooks.go b/hooks/hooks.go index 9d28fc8d..f064a3ba 100644 --- a/hooks/hooks.go +++ b/hooks/hooks.go @@ -19,8 +19,6 @@ const ( Stop Kind = "stop" Remove Kind = "remove" Action Kind = "action" - CollectMetrics Kind = "collect-metrics" - MeterStatusChanged Kind = "meter-status-changed" LeaderElected Kind = "leader-elected" LeaderDeposed Kind = "leader-deposed" LeaderSettingsChanged Kind = "leader-settings-changed" @@ -72,8 +70,6 @@ var unitHooks = []Kind{ UpgradeCharm, Stop, Remove, - CollectMetrics, - MeterStatusChanged, LeaderElected, LeaderDeposed, LeaderSettingsChanged, diff --git a/internal/test-charm-repo/quantal/all-hooks/hooks/collect-metrics b/internal/test-charm-repo/quantal/all-hooks/hooks/collect-metrics deleted file mode 100644 index e9948101..00000000 --- a/internal/test-charm-repo/quantal/all-hooks/hooks/collect-metrics +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -echo $0 diff --git a/internal/test-charm-repo/quantal/all-hooks/hooks/meter-status-changed b/internal/test-charm-repo/quantal/all-hooks/hooks/meter-status-changed deleted file mode 100644 index e9948101..00000000 --- a/internal/test-charm-repo/quantal/all-hooks/hooks/meter-status-changed +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -echo $0 diff --git a/internal/test-charm-repo/quantal/metered-empty/manifest.yaml b/internal/test-charm-repo/quantal/metered-empty/manifest.yaml deleted file mode 100644 index d3852da9..00000000 --- a/internal/test-charm-repo/quantal/metered-empty/manifest.yaml +++ /dev/null @@ -1,5 +0,0 @@ -bases: - - name: ubuntu - channel: 18.04/stable - - name: ubuntu - channel: "20.04" diff --git a/internal/test-charm-repo/quantal/metered-empty/metadata.yaml b/internal/test-charm-repo/quantal/metered-empty/metadata.yaml deleted file mode 100644 index f5924d59..00000000 --- a/internal/test-charm-repo/quantal/metered-empty/metadata.yaml +++ /dev/null @@ -1,3 +0,0 @@ -name: metered-empty -summary: "Metered charm with empty metrics" -description: "A charm that will not send metrics" diff --git a/internal/test-charm-repo/quantal/metered-empty/metrics.yaml b/internal/test-charm-repo/quantal/metered-empty/metrics.yaml deleted file mode 100644 index e69de29b..00000000 diff --git a/internal/test-charm-repo/quantal/metered-empty/revision b/internal/test-charm-repo/quantal/metered-empty/revision deleted file mode 100644 index 56a6051c..00000000 --- a/internal/test-charm-repo/quantal/metered-empty/revision +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/internal/test-charm-repo/quantal/metered/manifest.yaml b/internal/test-charm-repo/quantal/metered/manifest.yaml deleted file mode 100644 index d3852da9..00000000 --- a/internal/test-charm-repo/quantal/metered/manifest.yaml +++ /dev/null @@ -1,5 +0,0 @@ -bases: - - name: ubuntu - channel: 18.04/stable - - name: ubuntu - channel: "20.04" diff --git a/internal/test-charm-repo/quantal/metered/metadata.yaml b/internal/test-charm-repo/quantal/metered/metadata.yaml deleted file mode 100644 index 700beeb4..00000000 --- a/internal/test-charm-repo/quantal/metered/metadata.yaml +++ /dev/null @@ -1,3 +0,0 @@ -name: metered -summary: "A metered charm with custom metrics" -description: "" diff --git a/internal/test-charm-repo/quantal/metered/metrics.yaml b/internal/test-charm-repo/quantal/metered/metrics.yaml deleted file mode 100644 index 8b238050..00000000 --- a/internal/test-charm-repo/quantal/metered/metrics.yaml +++ /dev/null @@ -1,5 +0,0 @@ -metrics: - pings: - type: gauge - description: Description of the metric. - juju-unit-time: diff --git a/internal/test-charm-repo/quantal/metered/revision b/internal/test-charm-repo/quantal/metered/revision deleted file mode 100644 index 56a6051c..00000000 --- a/internal/test-charm-repo/quantal/metered/revision +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/meta_test.go b/meta_test.go index 129c0297..c68d2eaf 100644 --- a/meta_test.go +++ b/meta_test.go @@ -730,8 +730,6 @@ func (s *MetaSuite) TestMetaHooks(c *gc.C) { "upgrade-charm": true, "stop": true, "remove": true, - "collect-metrics": true, - "meter-status-changed": true, "leader-elected": true, "leader-deposed": true, "leader-settings-changed": true, @@ -1922,10 +1920,6 @@ func (c *dummyCharm) Config() *charm.Config { panic("unused") } -func (c *dummyCharm) Metrics() *charm.Metrics { - panic("unused") -} - func (c *dummyCharm) Actions() *charm.Actions { panic("unused") } diff --git a/metrics.go b/metrics.go deleted file mode 100644 index 8c0ed283..00000000 --- a/metrics.go +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2014 Canonical Ltd. -// Licensed under the LGPLv3, see LICENCE file for details. - -package charm - -import ( - "fmt" - "io" - "io/ioutil" - "strconv" - "strings" - - goyaml "gopkg.in/yaml.v2" -) - -// MetricType is used to identify metric types supported by juju. -type MetricType string - -const ( - builtinMetricPrefix = "juju" - - // Supported metric types. - MetricTypeGauge MetricType = "gauge" - MetricTypeAbsolute MetricType = "absolute" -) - -// IsBuiltinMetric reports whether the given metric key is in the builtin metric namespace -func IsBuiltinMetric(key string) bool { - return strings.HasPrefix(key, builtinMetricPrefix) -} - -func validateValue(value string) error { - // The largest number of digits that can be returned by strconv.FormatFloat is 24, so - // choose an arbitrary limit somewhat higher than that. - if len(value) > 30 { - return fmt.Errorf("metric value is too large") - } - fValue, err := strconv.ParseFloat(value, 64) - if err != nil { - return fmt.Errorf("invalid value type: expected float, got %q", value) - } - if fValue < 0 { - return fmt.Errorf("invalid value: value must be greater or equal to zero, got %v", value) - } - return nil -} - -// validateValue checks if the supplied metric value fits the requirements -// of its expected type. -func (m MetricType) validateValue(value string) error { - switch m { - case MetricTypeGauge, MetricTypeAbsolute: - return validateValue(value) - default: - return fmt.Errorf("unknown metric type %q", m) - } -} - -// Metric represents a single metric definition -type Metric struct { - Type MetricType `yaml:"type"` - Description string `yaml:"description"` -} - -// Plan represents the plan section of metrics.yaml -type Plan struct { - Required bool `yaml:"required,omitempty"` -} - -// Metrics contains the metrics declarations encoded in the metrics.yaml -// file. -type Metrics struct { - Metrics map[string]Metric `yaml:"metrics"` - Plan *Plan `yaml:"plan,omitempty"` -} - -// ReadMetrics reads a MetricsDeclaration in YAML format. -func ReadMetrics(r io.Reader) (*Metrics, error) { - data, err := ioutil.ReadAll(r) - if err != nil { - return nil, err - } - var metrics Metrics - if err := goyaml.Unmarshal(data, &metrics); err != nil { - return nil, err - } - if metrics.Metrics == nil { - return &metrics, nil - } - for name, metric := range metrics.Metrics { - if IsBuiltinMetric(name) { - if metric.Type != MetricType("") || metric.Description != "" { - return nil, fmt.Errorf("metric %q is using a prefix reserved for built-in metrics: it should not have type or description specification", name) - } - continue - } - switch metric.Type { - case MetricTypeGauge, MetricTypeAbsolute: - default: - return nil, fmt.Errorf("invalid metrics declaration: metric %q has unknown type %q", name, metric.Type) - } - if metric.Description == "" { - return nil, fmt.Errorf("invalid metrics declaration: metric %q lacks description", name) - } - } - return &metrics, nil -} - -// ValidateMetric validates the supplied metric name and value against the loaded -// metric definitions. -func (m Metrics) ValidateMetric(name, value string) error { - metric, exists := m.Metrics[name] - if !exists { - return fmt.Errorf("metric %q not defined", name) - } - if IsBuiltinMetric(name) { - return validateValue(value) - } - return metric.Type.validateValue(value) -} - -// PlanRequired reports whether these metrics require a plan. -func (m Metrics) PlanRequired() bool { - return m.Plan != nil && m.Plan.Required -} diff --git a/metrics_test.go b/metrics_test.go deleted file mode 100644 index ea0c41d8..00000000 --- a/metrics_test.go +++ /dev/null @@ -1,274 +0,0 @@ -// Copyright 2014 Canonical Ltd. -// Licensed under the LGPLv3, see LICENCE file for details. - -package charm_test - -import ( - "sort" - "strings" - - gc "gopkg.in/check.v1" - - "github.com/juju/charm/v13" -) - -// Keys returns a list of all defined metrics keys. -func Keys(m *charm.Metrics) []string { - result := make([]string, 0, len(m.Metrics)) - - for name := range m.Metrics { - result = append(result, name) - - } - sort.Strings(result) - return result -} - -type MetricsSuite struct{} - -var _ = gc.Suite(&MetricsSuite{}) - -func (s *MetricsSuite) TestReadEmpty(c *gc.C) { - metrics, err := charm.ReadMetrics(strings.NewReader("")) - c.Assert(err, gc.IsNil) - c.Assert(metrics, gc.NotNil) -} - -func (s *MetricsSuite) TestReadAlmostEmpty(c *gc.C) { - metrics, err := charm.ReadMetrics(strings.NewReader(` -metrics: -`)) - c.Assert(err, gc.IsNil) - c.Assert(metrics, gc.NotNil) -} - -func (s *MetricsSuite) TestNoDescription(c *gc.C) { - metrics, err := charm.ReadMetrics(strings.NewReader(` -metrics: - some-metric: - type: gauge -`)) - c.Assert(err, gc.ErrorMatches, "invalid metrics declaration: metric \"some-metric\" lacks description") - c.Assert(metrics, gc.IsNil) -} - -func (s *MetricsSuite) TestIncorrectType(c *gc.C) { - metrics, err := charm.ReadMetrics(strings.NewReader(` -metrics: - some-metric: - type: not-a-type - description: Some description. -`)) - c.Assert(err, gc.ErrorMatches, "invalid metrics declaration: metric \"some-metric\" has unknown type \"not-a-type\"") - c.Assert(metrics, gc.IsNil) -} - -func (s *MetricsSuite) TestMultipleDefinition(c *gc.C) { - metrics, err := charm.ReadMetrics(strings.NewReader(` -metrics: - some-metric: - type: gauge - description: Some description. - some-metric: - type: absolute - description: Some other description. - -`)) - c.Assert(err, gc.IsNil) - c.Assert(metrics.Metrics, gc.HasLen, 1) - c.Assert(metrics.Metrics["some-metric"].Type, gc.Equals, charm.MetricTypeAbsolute) -} - -func (s *MetricsSuite) TestIsBuiltinMetric(c *gc.C) { - tests := []struct { - input string - isbuiltin bool - }{{ - "juju-thing", - true, - }, { - "jujuthing", - true, - }, { - "thing", - false, - }, - } - - for i, test := range tests { - c.Logf("test %d isBuiltinMetric(%v) = %v", i, test.input, test.isbuiltin) - is := charm.IsBuiltinMetric(test.input) - c.Assert(is, gc.Equals, test.isbuiltin) - } -} - -func (s *MetricsSuite) TestValidYaml(c *gc.C) { - metrics, err := charm.ReadMetrics(strings.NewReader(` -metrics: - blips: - type: absolute - description: An absolute metric. - blops: - type: gauge - description: A gauge metric. - juju-unit-time: -`)) - c.Assert(err, gc.IsNil) - c.Assert(metrics, gc.NotNil) - c.Assert(Keys(metrics), gc.DeepEquals, []string{"blips", "blops", "juju-unit-time"}) - - testCases := []struct { - about string - name string - value string - err string - }{{ - about: "valid gauge metric", - name: "blops", - value: "1", - err: "", - }, { - about: "valid absolute metric", - name: "blips", - value: "0", - err: "", - }, { - about: "valid gauge metric, float value", - name: "blops", - value: "0.15", - err: "", - }, { - about: "valid absolute metric, float value", - name: "blips", - value: "6.015e15", - err: "", - }, { - about: "undeclared metric", - name: "undeclared", - value: "6.015e15", - err: "metric \"undeclared\" not defined", - }, { - about: "invalid type for gauge metric", - name: "blops", - value: "true", - err: "invalid value type: expected float, got \"true\"", - }, { - about: "metric value too large", - name: "blips", - value: "1111111111111111111111111111111", - err: "metric value is too large", - }, - } - - for i, t := range testCases { - c.Logf("test %d: %s", i, t.about) - err := metrics.ValidateMetric(t.name, t.value) - if t.err == "" { - c.Check(err, gc.IsNil) - } else { - c.Check(err, gc.ErrorMatches, t.err) - } - } - -} - -func (s *MetricsSuite) TestBuiltInMetrics(c *gc.C) { - tests := []string{` -metrics: - some-metric: - type: gauge - description: Some description. - juju-unit-time: - type: absolute -`, ` -metrics: - some-metric: - type: gauge - description: Some description. - juju-unit-time: - description: Some description -`, - } - for _, test := range tests { - c.Logf("%s", test) - _, err := charm.ReadMetrics(strings.NewReader(test)) - c.Assert(err, gc.ErrorMatches, `metric "juju-unit-time" is using a prefix reserved for built-in metrics: it should not have type or description specification`) - } -} - -func (s *MetricsSuite) TestValidateValue(c *gc.C) { - tests := []struct { - value string - expectedError string - }{{ - value: "1234567890", - }, { - value: "0", - }, { - value: "abcd", - expectedError: `invalid value type: expected float, got "abcd"`, - }, { - value: "1234567890123456789012345678901234567890", - expectedError: "metric value is too large", - }, { - value: "-42", - expectedError: "invalid value: value must be greater or equal to zero, got -42", - }, - } - - for _, test := range tests { - err := charm.ValidateValue(test.value) - if test.expectedError != "" { - c.Assert(err, gc.ErrorMatches, test.expectedError) - } else { - c.Assert(err, gc.IsNil) - } - } -} - -func (s *MetricsSuite) TestPlanRequired(c *gc.C) { - tests := []struct { - about string - input string - planRequired bool - }{{ - about: "not specified", - input: ` -metrics: - some-metric: - type: gauge - description: thing -`, - planRequired: false, - }, { - about: "plan optional", - input: ` -plan: - required: false -metrics: -`, - planRequired: false, - }, { - about: "plan required", - input: ` -plan: - required: true -metrics: -`, - planRequired: true, - }, { - about: "not set", - input: ` -plan: -metrics: -`, - planRequired: false, - }, - } - for i, test := range tests { - c.Logf("testplanrequired %d: %s", i, test.about) - metrics, err := charm.ReadMetrics(strings.NewReader(test.input)) - c.Assert(err, gc.IsNil) - c.Assert(metrics.PlanRequired(), gc.Equals, test.planRequired) - } -}