github.com/cilium/cilium@v1.16.2/pkg/hive/health/metrics_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package health
     5  
     6  import (
     7  	"context"
     8  	"testing"
     9  
    10  	"github.com/cilium/hive"
    11  	"github.com/cilium/hive/cell"
    12  	"github.com/cilium/hive/hivetest"
    13  	"github.com/cilium/hive/job"
    14  	"github.com/cilium/statedb"
    15  	"github.com/stretchr/testify/assert"
    16  	"github.com/stretchr/testify/require"
    17  
    18  	"github.com/cilium/cilium/pkg/hive/health/types"
    19  )
    20  
    21  func Test_Metrics(t *testing.T) {
    22  	var db *statedb.DB
    23  	var table statedb.Table[types.Status]
    24  	resChan := make(chan map[types.Level]uint64)
    25  	// Using upstream hive here to avoid import cycles and be able to inject the right metric
    26  	// publishing func for the test.
    27  	h := hive.New(
    28  		statedb.Cell,
    29  		job.Cell,
    30  
    31  		cell.ProvidePrivate(newTablesPrivate),
    32  		cell.Provide(
    33  			newHealthV2Provider,
    34  			statedb.RWTable[types.Status].ToTable,
    35  		),
    36  		cell.Provide(func(lc cell.Lifecycle, p types.Provider, jr job.Registry) job.Group {
    37  			h := p.ForModule(cell.FullModuleID{"test"})
    38  			jg := jr.NewGroup(h)
    39  			lc.Append(jg)
    40  			return jg
    41  		}),
    42  
    43  		cell.Module("health-metrics-test", "hive module health metrics test",
    44  			cell.Provide(newMetrics),
    45  			cell.Invoke(func(p metricPublisherParams) {
    46  				// Writes the updates to a chan to synchronise with the test.
    47  				publish := func(stats map[types.Level]uint64) {
    48  					resChan <- stats
    49  				}
    50  
    51  				p.JobGroup.Add(job.OneShot("module-status-metrics",
    52  					func(ctx context.Context, health cell.Health) error {
    53  						return publishJob(ctx, p, publish)
    54  					}))
    55  			}),
    56  
    57  			// Generate some test module health data
    58  			cell.Invoke(func(db_ *statedb.DB, table_ statedb.RWTable[types.Status]) {
    59  				db = db_
    60  				table = table_
    61  				txn := db_.WriteTxn(table_)
    62  				_, _, err := table_.Insert(txn, types.Status{
    63  					ID: types.Identifier{
    64  						Module: cell.FullModuleID{"test"},
    65  					},
    66  					Level: types.LevelDegraded,
    67  				})
    68  				assert.NoError(t, err)
    69  				_, _, err = table_.Insert(txn, types.Status{
    70  					ID: types.Identifier{
    71  						Module: cell.FullModuleID{"test2"},
    72  					},
    73  					Level: types.LevelOK,
    74  				})
    75  				assert.NoError(t, err)
    76  				txn.Commit()
    77  			}),
    78  		),
    79  	)
    80  	require.NotNil(t, h)
    81  
    82  	tlog := hivetest.Logger(t)
    83  	err := h.Start(tlog, context.TODO())
    84  	require.NoError(t, err)
    85  
    86  	t.Cleanup(func() {
    87  		err = h.Stop(tlog, context.TODO())
    88  		require.NoError(t, err)
    89  	})
    90  
    91  	// Metrics as they would be published
    92  	resMetrics := <-resChan
    93  	it := table.All(db.ReadTxn())
    94  	ok, degraded, stopped := count(it)
    95  
    96  	assert.Equal(t, resMetrics[types.LevelOK], ok)
    97  	assert.Greater(t, resMetrics[types.LevelOK], uint64(1))
    98  	assert.Equal(t, resMetrics[types.LevelDegraded], degraded)
    99  	assert.Equal(t, resMetrics[types.LevelDegraded], uint64(1))
   100  	assert.Equal(t, resMetrics[types.LevelStopped], stopped)
   101  }
   102  
   103  func count(it statedb.Iterator[types.Status]) (ok uint64, degraded uint64, stopped uint64) {
   104  	for obj, _, hasMore := it.Next(); hasMore; obj, _, hasMore = it.Next() {
   105  		switch obj.Level {
   106  		case types.LevelOK:
   107  			ok++
   108  		case types.LevelDegraded:
   109  			degraded++
   110  		case types.LevelStopped:
   111  			stopped++
   112  		}
   113  	}
   114  	return
   115  }