github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/mongo/mongometrics/txnmetrics_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENSE file for details.
     3  
     4  package mongometrics_test
     5  
     6  import (
     7  	"errors"
     8  	"time"
     9  
    10  	"github.com/juju/mgo/v3/bson"
    11  	"github.com/juju/mgo/v3/txn"
    12  	"github.com/juju/testing"
    13  	jc "github.com/juju/testing/checkers"
    14  	"github.com/prometheus/client_golang/prometheus"
    15  	dto "github.com/prometheus/client_model/go"
    16  	gc "gopkg.in/check.v1"
    17  
    18  	"github.com/juju/juju/mongo/mongometrics"
    19  )
    20  
    21  type TxnCollectorSuite struct {
    22  	testing.IsolationSuite
    23  	collector *mongometrics.TxnCollector
    24  }
    25  
    26  var _ = gc.Suite(&TxnCollectorSuite{})
    27  
    28  func (s *TxnCollectorSuite) SetUpTest(c *gc.C) {
    29  	s.IsolationSuite.SetUpTest(c)
    30  	s.collector = mongometrics.NewTxnCollector()
    31  }
    32  
    33  func (s *TxnCollectorSuite) TestDescribe(c *gc.C) {
    34  	ch := make(chan *prometheus.Desc)
    35  	go func() {
    36  		defer close(ch)
    37  		s.collector.Describe(ch)
    38  	}()
    39  	var descs []*prometheus.Desc
    40  	for desc := range ch {
    41  		descs = append(descs, desc)
    42  	}
    43  	c.Assert(descs, gc.HasLen, 3)
    44  	c.Assert(descs[0].String(), gc.Matches, `.*fqName: "juju_mgo_txn_ops_total".*`)
    45  	c.Assert(descs[1].String(), gc.Matches, `.*fqName: "juju_mgo_txn_retries".*`)
    46  	c.Assert(descs[2].String(), gc.Matches, `.*fqName: "juju_mgo_txn_durations".*`)
    47  }
    48  
    49  func (s *TxnCollectorSuite) TestCollect(c *gc.C) {
    50  	s.collector.AfterRunTransaction("dbname", "modeluuid", 1, time.Millisecond, []txn.Op{{
    51  		C:      "update-coll",
    52  		Update: bson.D{},
    53  	}, {
    54  		C:      "insert-coll",
    55  		Insert: bson.D{},
    56  	}, {
    57  		C:      "remove-coll",
    58  		Remove: true,
    59  	}, {
    60  		C: "assert-coll",
    61  	}}, nil)
    62  
    63  	s.collector.AfterRunTransaction("dbname", "modeluuid", 1, time.Millisecond, []txn.Op{{
    64  		C:      "update-coll",
    65  		Update: bson.D{},
    66  	}}, errors.New("bewm"))
    67  
    68  	ch := make(chan prometheus.Metric)
    69  	go func() {
    70  		defer close(ch)
    71  		s.collector.Collect(ch)
    72  	}()
    73  
    74  	var metrics []prometheus.Metric
    75  	for metric := range ch {
    76  		metrics = append(metrics, metric)
    77  	}
    78  	c.Assert(metrics, gc.HasLen, 7)
    79  
    80  	var dtoMetrics [7]dto.Metric
    81  	for i, metric := range metrics {
    82  		err := metric.Write(&dtoMetrics[i])
    83  		c.Assert(err, jc.ErrorIsNil)
    84  	}
    85  
    86  	float64ptr := func(v float64) *float64 {
    87  		return &v
    88  	}
    89  	uint64ptr := func(v uint64) *uint64 {
    90  		return &v
    91  	}
    92  	labelpair := func(n, v string) *dto.LabelPair {
    93  		return &dto.LabelPair{Name: &n, Value: &v}
    94  	}
    95  	var retryBuckets []*dto.Bucket
    96  	for i := 0; i < 50; i++ {
    97  		count := uint64(0)
    98  		if i > 0 {
    99  			count = 5
   100  		}
   101  		retryBuckets = append(retryBuckets, &dto.Bucket{
   102  			CumulativeCount: uint64ptr(count),
   103  			UpperBound:      float64ptr(float64(i)),
   104  		})
   105  	}
   106  	var durationBuckets []*dto.Bucket
   107  	for i := 0; i < 50; i++ {
   108  		count := uint64(0)
   109  		if i > 0 {
   110  			count = 5
   111  		}
   112  		durationBuckets = append(durationBuckets, &dto.Bucket{
   113  			CumulativeCount: uint64ptr(count),
   114  			UpperBound:      float64ptr(float64(2 * i)),
   115  		})
   116  	}
   117  	expected := []dto.Metric{
   118  		{
   119  			Counter: &dto.Counter{Value: float64ptr(1)},
   120  			Label: []*dto.LabelPair{
   121  				labelpair("collection", "update-coll"),
   122  				labelpair("database", "dbname"),
   123  				labelpair("failed", ""),
   124  				labelpair("optype", "update"),
   125  			},
   126  		},
   127  		{
   128  			Counter: &dto.Counter{Value: float64ptr(1)},
   129  			Label: []*dto.LabelPair{
   130  				labelpair("collection", "insert-coll"),
   131  				labelpair("database", "dbname"),
   132  				labelpair("failed", ""),
   133  				labelpair("optype", "insert"),
   134  			},
   135  		},
   136  		{
   137  			Counter: &dto.Counter{Value: float64ptr(1)},
   138  			Label: []*dto.LabelPair{
   139  				labelpair("collection", "remove-coll"),
   140  				labelpair("database", "dbname"),
   141  				labelpair("failed", ""),
   142  				labelpair("optype", "remove"),
   143  			},
   144  		},
   145  		{
   146  			Counter: &dto.Counter{Value: float64ptr(1)},
   147  			Label: []*dto.LabelPair{
   148  				labelpair("collection", "assert-coll"),
   149  				labelpair("database", "dbname"),
   150  				labelpair("failed", ""),
   151  				labelpair("optype", "assert"),
   152  			},
   153  		},
   154  		{
   155  			Counter: &dto.Counter{Value: float64ptr(1)},
   156  			Label: []*dto.LabelPair{
   157  				labelpair("collection", "update-coll"),
   158  				labelpair("database", "dbname"),
   159  				labelpair("failed", "failed"),
   160  				labelpair("optype", "update"),
   161  			},
   162  		},
   163  		{
   164  			Histogram: &dto.Histogram{
   165  				SampleCount: uint64ptr(5),
   166  				SampleSum:   float64ptr(5),
   167  				Bucket:      retryBuckets,
   168  			},
   169  		},
   170  		{
   171  			Histogram: &dto.Histogram{
   172  				SampleCount: uint64ptr(5),
   173  				SampleSum:   float64ptr(5),
   174  				Bucket:      durationBuckets,
   175  			},
   176  		},
   177  	}
   178  	for i := range dtoMetrics {
   179  		var found bool
   180  		for j := range expected {
   181  			if !metricsEqual(&dtoMetrics[i], &expected[j]) {
   182  				continue
   183  			}
   184  			expected = append(expected[:j], expected[j+1:]...)
   185  			found = true
   186  			break
   187  		}
   188  		if !found {
   189  			c.Errorf("metric %+v not expected", &dtoMetrics[i])
   190  		}
   191  	}
   192  }