gopkg.in/juju/charm.v6-unstable@v6.0.0-20171026192109-50d0c219b496/metrics_test.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the LGPLv3, see LICENCE file for details.
     3  
     4  package charm_test
     5  
     6  import (
     7  	"sort"
     8  	"strings"
     9  
    10  	gc "gopkg.in/check.v1"
    11  
    12  	"gopkg.in/juju/charm.v6-unstable"
    13  )
    14  
    15  // Keys returns a list of all defined metrics keys.
    16  func Keys(m *charm.Metrics) []string {
    17  	result := make([]string, 0, len(m.Metrics))
    18  
    19  	for name := range m.Metrics {
    20  		result = append(result, name)
    21  
    22  	}
    23  	sort.Strings(result)
    24  	return result
    25  }
    26  
    27  type MetricsSuite struct{}
    28  
    29  var _ = gc.Suite(&MetricsSuite{})
    30  
    31  func (s *MetricsSuite) TestReadEmpty(c *gc.C) {
    32  	metrics, err := charm.ReadMetrics(strings.NewReader(""))
    33  	c.Assert(err, gc.IsNil)
    34  	c.Assert(metrics, gc.NotNil)
    35  }
    36  
    37  func (s *MetricsSuite) TestReadAlmostEmpty(c *gc.C) {
    38  	metrics, err := charm.ReadMetrics(strings.NewReader(`
    39  metrics:
    40  `))
    41  	c.Assert(err, gc.IsNil)
    42  	c.Assert(metrics, gc.NotNil)
    43  }
    44  
    45  func (s *MetricsSuite) TestNoDescription(c *gc.C) {
    46  	metrics, err := charm.ReadMetrics(strings.NewReader(`
    47  metrics:
    48    some-metric:
    49      type: gauge
    50  `))
    51  	c.Assert(err, gc.ErrorMatches, "invalid metrics declaration: metric \"some-metric\" lacks description")
    52  	c.Assert(metrics, gc.IsNil)
    53  }
    54  
    55  func (s *MetricsSuite) TestIncorrectType(c *gc.C) {
    56  	metrics, err := charm.ReadMetrics(strings.NewReader(`
    57  metrics:
    58    some-metric:
    59      type: not-a-type
    60      description: Some description.
    61  `))
    62  	c.Assert(err, gc.ErrorMatches, "invalid metrics declaration: metric \"some-metric\" has unknown type \"not-a-type\"")
    63  	c.Assert(metrics, gc.IsNil)
    64  }
    65  
    66  func (s *MetricsSuite) TestMultipleDefinition(c *gc.C) {
    67  	metrics, err := charm.ReadMetrics(strings.NewReader(`
    68  metrics:
    69    some-metric:
    70      type: gauge
    71      description: Some description.
    72    some-metric:
    73      type: absolute
    74      description: Some other description.
    75  
    76  `))
    77  	c.Assert(err, gc.IsNil)
    78  	c.Assert(metrics.Metrics, gc.HasLen, 1)
    79  	c.Assert(metrics.Metrics["some-metric"].Type, gc.Equals, charm.MetricTypeAbsolute)
    80  }
    81  
    82  func (s *MetricsSuite) TestIsBuiltinMetric(c *gc.C) {
    83  	tests := []struct {
    84  		input     string
    85  		isbuiltin bool
    86  	}{{
    87  		"juju-thing",
    88  		true,
    89  	}, {
    90  		"jujuthing",
    91  		true,
    92  	}, {
    93  		"thing",
    94  		false,
    95  	},
    96  	}
    97  
    98  	for i, test := range tests {
    99  		c.Logf("test %d isBuiltinMetric(%v) = %v", i, test.input, test.isbuiltin)
   100  		is := charm.IsBuiltinMetric(test.input)
   101  		c.Assert(is, gc.Equals, test.isbuiltin)
   102  	}
   103  }
   104  
   105  func (s *MetricsSuite) TestValidYaml(c *gc.C) {
   106  	metrics, err := charm.ReadMetrics(strings.NewReader(`
   107  metrics:
   108    blips:
   109      type: absolute
   110      description: An absolute metric.
   111    blops:
   112      type: gauge
   113      description: A gauge metric.
   114    juju-unit-time:
   115  `))
   116  	c.Assert(err, gc.IsNil)
   117  	c.Assert(metrics, gc.NotNil)
   118  	c.Assert(Keys(metrics), gc.DeepEquals, []string{"blips", "blops", "juju-unit-time"})
   119  
   120  	testCases := []struct {
   121  		about string
   122  		name  string
   123  		value string
   124  		err   string
   125  	}{{
   126  		about: "valid gauge metric",
   127  		name:  "blops",
   128  		value: "1",
   129  		err:   "",
   130  	}, {
   131  		about: "valid absolute metric",
   132  		name:  "blips",
   133  		value: "0",
   134  		err:   "",
   135  	}, {
   136  		about: "valid gauge metric, float value",
   137  		name:  "blops",
   138  		value: "0.15",
   139  		err:   "",
   140  	}, {
   141  		about: "valid absolute metric, float value",
   142  		name:  "blips",
   143  		value: "6.015e15",
   144  		err:   "",
   145  	}, {
   146  		about: "undeclared metric",
   147  		name:  "undeclared",
   148  		value: "6.015e15",
   149  		err:   "metric \"undeclared\" not defined",
   150  	}, {
   151  		about: "invalid type for gauge metric",
   152  		name:  "blops",
   153  		value: "true",
   154  		err:   "invalid value type: expected float, got \"true\"",
   155  	}, {
   156  		about: "metric value too large",
   157  		name:  "blips",
   158  		value: "1111111111111111111111111111111",
   159  		err:   "metric value is too large",
   160  	},
   161  	}
   162  
   163  	for i, t := range testCases {
   164  		c.Logf("test %d: %s", i, t.about)
   165  		err := metrics.ValidateMetric(t.name, t.value)
   166  		if t.err == "" {
   167  			c.Check(err, gc.IsNil)
   168  		} else {
   169  			c.Check(err, gc.ErrorMatches, t.err)
   170  		}
   171  	}
   172  
   173  }
   174  
   175  func (s *MetricsSuite) TestBuiltInMetrics(c *gc.C) {
   176  	tests := []string{`
   177  metrics:
   178    some-metric:
   179      type: gauge
   180      description: Some description.
   181    juju-unit-time:
   182      type: absolute
   183  `, `
   184  metrics:
   185    some-metric:
   186      type: gauge
   187      description: Some description.
   188    juju-unit-time:
   189      description: Some description
   190  `,
   191  	}
   192  	for _, test := range tests {
   193  		c.Logf("%s", test)
   194  		_, err := charm.ReadMetrics(strings.NewReader(test))
   195  		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`)
   196  	}
   197  }
   198  
   199  func (s *MetricsSuite) TestValidateValue(c *gc.C) {
   200  	tests := []struct {
   201  		value         string
   202  		expectedError string
   203  	}{{
   204  		value: "1234567890",
   205  	}, {
   206  		value: "0",
   207  	}, {
   208  		value:         "abcd",
   209  		expectedError: `invalid value type: expected float, got "abcd"`,
   210  	}, {
   211  		value:         "1234567890123456789012345678901234567890",
   212  		expectedError: "metric value is too large",
   213  	}, {
   214  		value:         "-42",
   215  		expectedError: "invalid value: value must be greater or equal to zero, got -42",
   216  	},
   217  	}
   218  
   219  	for _, test := range tests {
   220  		err := charm.ValidateValue(test.value)
   221  		if test.expectedError != "" {
   222  			c.Assert(err, gc.ErrorMatches, test.expectedError)
   223  		} else {
   224  			c.Assert(err, gc.IsNil)
   225  		}
   226  	}
   227  }
   228  
   229  func (s *MetricsSuite) TestPlanRequired(c *gc.C) {
   230  	tests := []struct {
   231  		about        string
   232  		input        string
   233  		planRequired bool
   234  	}{{
   235  		about: "not specified",
   236  		input: `
   237  metrics:
   238    some-metric:
   239      type: gauge
   240      description: thing
   241  `,
   242  		planRequired: false,
   243  	}, {
   244  		about: "plan optional",
   245  		input: `
   246  plan: 
   247    required: false
   248  metrics:
   249  `,
   250  		planRequired: false,
   251  	}, {
   252  		about: "plan required",
   253  		input: `
   254  plan: 
   255    required: true
   256  metrics:
   257  `,
   258  		planRequired: true,
   259  	}, {
   260  		about: "not set",
   261  		input: `
   262  plan:
   263  metrics:
   264  `,
   265  		planRequired: false,
   266  	},
   267  	}
   268  	for i, test := range tests {
   269  		c.Logf("testplanrequired %d: %s", i, test.about)
   270  		metrics, err := charm.ReadMetrics(strings.NewReader(test.input))
   271  		c.Assert(err, gc.IsNil)
   272  		c.Assert(metrics.PlanRequired(), gc.Equals, test.planRequired)
   273  	}
   274  }