github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/state/statemetrics/statemetrics_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENSE file for details.
     3  
     4  package statemetrics_test
     5  
     6  import (
     7  	"errors"
     8  	"reflect"
     9  
    10  	"github.com/juju/testing"
    11  	jc "github.com/juju/testing/checkers"
    12  	"github.com/prometheus/client_golang/prometheus"
    13  	"github.com/prometheus/client_golang/prometheus/testutil"
    14  	dto "github.com/prometheus/client_model/go"
    15  	gc "gopkg.in/check.v1"
    16  	"gopkg.in/juju/names.v2"
    17  
    18  	"github.com/juju/juju/core/status"
    19  	"github.com/juju/juju/permission"
    20  	"github.com/juju/juju/state"
    21  	"github.com/juju/juju/state/statemetrics"
    22  )
    23  
    24  type collectorSuite struct {
    25  	testing.IsolationSuite
    26  	pool      *mockStatePool
    27  	collector *statemetrics.Collector
    28  }
    29  
    30  var _ = gc.Suite(&collectorSuite{})
    31  
    32  func (s *collectorSuite) SetUpTest(c *gc.C) {
    33  	s.IsolationSuite.SetUpTest(c)
    34  
    35  	users := []*mockUser{{
    36  		tag:              names.NewUserTag("alice"),
    37  		controllerAccess: permission.NoAccess,
    38  	}, {
    39  		tag:              names.NewUserTag("bob"),
    40  		controllerAccess: permission.NoAccess,
    41  	}, {
    42  		tag:              names.NewUserTag("cayley@cambridge"),
    43  		deleted:          true,
    44  		controllerAccess: permission.AddModelAccess,
    45  	}, {
    46  		tag:              names.NewUserTag("dominique"),
    47  		disabled:         true,
    48  		controllerAccess: permission.ReadAccess,
    49  	}}
    50  
    51  	s.pool = &mockStatePool{
    52  		models: []*mockModel{{
    53  			tag:    names.NewModelTag("b266dff7-eee8-4297-b03a-4692796ec193"),
    54  			life:   state.Alive,
    55  			status: status.StatusInfo{Status: status.Available},
    56  			machines: []*mockMachine{{
    57  				life:           state.Alive,
    58  				agentStatus:    status.StatusInfo{Status: status.Started},
    59  				instanceStatus: status.StatusInfo{Status: status.Running},
    60  			}},
    61  		}, {
    62  			tag:    names.NewModelTag("1ab5799e-e72d-4de7-b70d-499edfab0e5c"),
    63  			life:   state.Dying,
    64  			status: status.StatusInfo{Status: status.Destroying},
    65  			machines: []*mockMachine{{
    66  				life:           state.Alive,
    67  				agentStatus:    status.StatusInfo{Status: status.Error},
    68  				instanceStatus: status.StatusInfo{Status: status.ProvisioningError},
    69  			}},
    70  		}},
    71  	}
    72  	s.pool.system = &mockState{
    73  		users:      users,
    74  		modelUUIDs: s.pool.modelUUIDs(),
    75  	}
    76  	s.collector = statemetrics.New(s.pool)
    77  }
    78  
    79  func (s *collectorSuite) TestDescribe(c *gc.C) {
    80  	ch := make(chan *prometheus.Desc)
    81  	go func() {
    82  		defer close(ch)
    83  		s.collector.Describe(ch)
    84  	}()
    85  	var descStrings []string
    86  	for desc := range ch {
    87  		descStrings = append(descStrings, desc.String())
    88  	}
    89  	expect := []string{
    90  		`.*fqName: "juju_state_machines".*`,
    91  		`.*fqName: "juju_state_models".*`,
    92  		`.*fqName: "juju_state_users".*`,
    93  		`.*fqName: "juju_state_scrape_errors".*`,
    94  		`.*fqName: "juju_state_scrape_duration_seconds".*`,
    95  	}
    96  	c.Assert(descStrings, gc.HasLen, len(expect))
    97  	for i, expect := range expect {
    98  		c.Assert(descStrings[i], gc.Matches, expect)
    99  	}
   100  }
   101  
   102  func (s *collectorSuite) collect(c *gc.C) ([]prometheus.Metric, []dto.Metric) {
   103  	ch := make(chan prometheus.Metric)
   104  	go func() {
   105  		defer close(ch)
   106  		s.collector.Collect(ch)
   107  	}()
   108  	var metrics []prometheus.Metric
   109  	for metric := range ch {
   110  		metrics = append(metrics, metric)
   111  	}
   112  	dtoMetrics := make([]dto.Metric, len(metrics))
   113  	for i, metric := range metrics {
   114  		err := metric.Write(&dtoMetrics[i])
   115  		c.Assert(err, jc.ErrorIsNil)
   116  	}
   117  	return metrics, dtoMetrics
   118  }
   119  
   120  func (s *collectorSuite) checkExpected(c *gc.C, actual, expected []dto.Metric) {
   121  	c.Assert(actual, gc.HasLen, len(expected))
   122  	for i, dm := range actual {
   123  		var found bool
   124  		for i, m := range expected {
   125  			if !reflect.DeepEqual(dm, m) {
   126  				continue
   127  			}
   128  			expected = append(expected[:i], expected[i+1:]...)
   129  			found = true
   130  			break
   131  		}
   132  		if !found {
   133  			c.Errorf("metric #%d %+v not expected", i, dm)
   134  		}
   135  	}
   136  }
   137  
   138  func float64ptr(v float64) *float64 {
   139  	return &v
   140  }
   141  
   142  func (s *collectorSuite) TestCollect(c *gc.C) {
   143  	_, dtoMetrics := s.collect(c)
   144  
   145  	// The scrape time metric has a non-deterministic value,
   146  	// so we just check that it is non-zero.
   147  	c.Assert(dtoMetrics, gc.Not(gc.HasLen), 0)
   148  	scrapeDurationMetric := dtoMetrics[len(dtoMetrics)-1]
   149  	c.Assert(scrapeDurationMetric.Gauge.GetValue(), gc.Not(gc.Equals), 0)
   150  
   151  	labelpair := func(n, v string) *dto.LabelPair {
   152  		return &dto.LabelPair{Name: &n, Value: &v}
   153  	}
   154  
   155  	s.checkExpected(c, dtoMetrics, []dto.Metric{
   156  		// juju_state_machines
   157  		{
   158  			Gauge: &dto.Gauge{Value: float64ptr(1)},
   159  			Label: []*dto.LabelPair{
   160  				labelpair("agent_status", "started"),
   161  				labelpair("life", "alive"),
   162  				labelpair("machine_status", "running"),
   163  			},
   164  		},
   165  		{
   166  			Gauge: &dto.Gauge{Value: float64ptr(1)},
   167  			Label: []*dto.LabelPair{
   168  				labelpair("agent_status", "error"),
   169  				labelpair("life", "alive"),
   170  				labelpair("machine_status", "provisioning error"),
   171  			},
   172  		},
   173  
   174  		// juju_state_models
   175  		{
   176  			Gauge: &dto.Gauge{Value: float64ptr(1)},
   177  			Label: []*dto.LabelPair{
   178  				labelpair("life", "alive"),
   179  				labelpair("status", "available"),
   180  			},
   181  		},
   182  		{
   183  			Gauge: &dto.Gauge{Value: float64ptr(1)},
   184  			Label: []*dto.LabelPair{
   185  				labelpair("life", "dying"),
   186  				labelpair("status", "destroying"),
   187  			},
   188  		},
   189  
   190  		// juju_state_users
   191  		{
   192  			Gauge: &dto.Gauge{Value: float64ptr(1)},
   193  			Label: []*dto.LabelPair{
   194  				labelpair("controller_access", "add-model"),
   195  				labelpair("deleted", "true"),
   196  				labelpair("disabled", ""),
   197  				labelpair("domain", "cambridge"),
   198  			},
   199  		},
   200  		{
   201  			Gauge: &dto.Gauge{Value: float64ptr(1)},
   202  			Label: []*dto.LabelPair{
   203  				labelpair("controller_access", "read"),
   204  				labelpair("deleted", ""),
   205  				labelpair("disabled", "true"),
   206  				labelpair("domain", ""),
   207  			},
   208  		},
   209  		{
   210  			Gauge: &dto.Gauge{Value: float64ptr(2)},
   211  			Label: []*dto.LabelPair{
   212  				labelpair("controller_access", ""),
   213  				labelpair("deleted", ""),
   214  				labelpair("disabled", ""),
   215  				labelpair("domain", ""),
   216  			},
   217  		},
   218  
   219  		// juju_state_scrape_errors
   220  		{
   221  			Gauge: &dto.Gauge{Value: float64ptr(0)},
   222  			Label: []*dto.LabelPair{},
   223  		},
   224  
   225  		// juju_state_scrape_interval_seconds
   226  		{
   227  			Gauge: &dto.Gauge{Value: scrapeDurationMetric.Gauge.Value},
   228  			Label: []*dto.LabelPair{},
   229  		},
   230  	})
   231  }
   232  
   233  func (s *collectorSuite) TestCollectErrors(c *gc.C) {
   234  	s.pool.system.SetErrors(
   235  		errors.New("no models for you"),
   236  		errors.New("no users for you"),
   237  	)
   238  	s.collect(c)
   239  	c.Check(testutil.ToFloat64(s.collector.ScrapeDurationGauge()), jc.GreaterThan, float64(0))
   240  	c.Check(testutil.ToFloat64(s.collector.ScrapeErrorsGauge()), gc.Equals, float64(2))
   241  }