github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/x/instrument/string_list_emitter_test.go (about)

     1  // Copyright (c) 2019 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package instrument
    22  
    23  import (
    24  	"fmt"
    25  	"reflect"
    26  	"testing"
    27  
    28  	"github.com/stretchr/testify/require"
    29  	"github.com/uber-go/tally"
    30  	promreporter "github.com/uber-go/tally/prometheus"
    31  )
    32  
    33  var bootstrappers = [][]string{
    34  	{
    35  		"filesystem",
    36  		"peers",
    37  		"commitlog",
    38  		"uninitialized_topology",
    39  	},
    40  	{
    41  		"uninitialized_topology",
    42  		"filesystem",
    43  		"peers",
    44  		"commitlog",
    45  	},
    46  	{
    47  		"a",
    48  		"b",
    49  		"c",
    50  		"d",
    51  	},
    52  	{
    53  		"foo",
    54  		"bar",
    55  		"hello",
    56  		"world",
    57  		"more",
    58  		"labels",
    59  	},
    60  	{
    61  		"x",
    62  		"y",
    63  	},
    64  	{
    65  		"foo",
    66  	},
    67  	{"", "", "", ""},
    68  	{},
    69  }
    70  
    71  func TestBootstrapGaugeEmitterNoopScope(t *testing.T) {
    72  	scope := tally.NewTestScope("testScope", nil)
    73  	t.Run("TestNewBootstrapGaugeEmitter", func(t *testing.T) {
    74  		for _, bs := range bootstrappers {
    75  
    76  			bge := NewStringListEmitter(scope, "bootstrappers")
    77  			require.NotNil(t, bge)
    78  			require.NotNil(t, bge.gauges)
    79  			require.Equal(t, 1, len(bge.gauges))
    80  
    81  			g := bge.newGauges(scope, bs)
    82  			require.NotNil(t, g)
    83  			require.Equal(t, len(bs), len(g))
    84  
    85  			require.False(t, bge.running)
    86  
    87  			err := bge.UpdateStringList(bs)
    88  			require.Error(t, err)
    89  			require.NotNil(t, bge.gauges)
    90  			require.Equal(t, 1, len(bge.gauges))
    91  
    92  			err = bge.Close()
    93  			require.Error(t, err)
    94  
    95  			err = bge.Start(bs)
    96  			require.NoError(t, err)
    97  			require.NotNil(t, bge.gauges)
    98  			require.True(t, bge.running)
    99  			require.Equal(t, len(bs), len(bge.gauges))
   100  			if !reflect.DeepEqual(g, bge.gauges) {
   101  				t.Errorf("expected: %#v, got: %#v", g, bge.gauges)
   102  			}
   103  
   104  			err = bge.Close()
   105  			require.NoError(t, err)
   106  			require.False(t, bge.running)
   107  		}
   108  	})
   109  
   110  	t.Run("TestEmitting", func(t *testing.T) {
   111  		scope := tally.NewTestScope("testScope", nil)
   112  		bs0 := bootstrappers[0]
   113  		bge := NewStringListEmitter(scope, "bootstrappers")
   114  		require.NotNil(t, bge)
   115  		require.NotNil(t, bge.gauges)
   116  		require.Equal(t, len(bge.gauges), 1)
   117  
   118  		// Start
   119  		err := bge.Start(bs0)
   120  		require.NoError(t, err)
   121  		require.True(t, bge.running)
   122  		require.NotNil(t, bge.gauges)
   123  		require.Equal(t, len(bge.gauges), len(bs0))
   124  
   125  		gauges := scope.Snapshot().Gauges()
   126  		require.Equal(t, len(bs0), len(gauges), "length of gauges after start")
   127  
   128  		for _, id := range []string{
   129  			fmt.Sprintf("testScope.bootstrappers_0+type=%s", bs0[0]),
   130  			fmt.Sprintf("testScope.bootstrappers_1+type=%s", bs0[1]),
   131  			fmt.Sprintf("testScope.bootstrappers_2+type=%s", bs0[2]),
   132  			fmt.Sprintf("testScope.bootstrappers_3+type=%s", bs0[3]),
   133  		} {
   134  			g, ok := gauges[id]
   135  			require.True(t, ok)
   136  			require.Equal(t, float64(1), g.Value(), "gauge value after start")
   137  		}
   138  
   139  		// 	// Update to new
   140  		bs1 := bootstrappers[1]
   141  		err = bge.UpdateStringList(bs1)
   142  		require.NoError(t, err)
   143  		require.True(t, bge.running, "state of bootstrapGaugeEmitter after update")
   144  		require.NotNil(t, bge.gauges)
   145  		require.Equal(t, len(bge.gauges), len(bs1))
   146  
   147  		gauges = scope.Snapshot().Gauges()
   148  		require.Equal(t, 8, len(gauges), "length of gauges after updating")
   149  		for i, id := range []string{
   150  			fmt.Sprintf("testScope.bootstrappers_0+type=%s", bs0[0]),
   151  			fmt.Sprintf("testScope.bootstrappers_1+type=%s", bs0[1]),
   152  			fmt.Sprintf("testScope.bootstrappers_2+type=%s", bs0[2]),
   153  			fmt.Sprintf("testScope.bootstrappers_3+type=%s", bs0[3]),
   154  			fmt.Sprintf("testScope.bootstrappers_0+type=%s", bs1[0]),
   155  			fmt.Sprintf("testScope.bootstrappers_1+type=%s", bs1[1]),
   156  			fmt.Sprintf("testScope.bootstrappers_2+type=%s", bs1[2]),
   157  			fmt.Sprintf("testScope.bootstrappers_3+type=%s", bs1[3]),
   158  		} {
   159  			g, ok := gauges[id]
   160  			require.True(t, ok)
   161  			if i < 4 {
   162  				require.Equal(t, float64(0), g.Value(), "first gauge value of after update")
   163  			} else {
   164  				require.Equal(t, float64(1), g.Value(), "second gauge value of after update")
   165  			}
   166  		}
   167  
   168  		// Update back to old
   169  		err = bge.UpdateStringList(bs0)
   170  		require.NoError(t, err)
   171  		require.True(t, bge.running, "state of bootstrapGaugeEmitter after update")
   172  		require.NotNil(t, bge.gauges)
   173  		require.Equal(t, len(bge.gauges), len(bs0))
   174  
   175  		gauges = scope.Snapshot().Gauges()
   176  		require.Equal(t, 8, len(gauges), "length of gauges after updating")
   177  		for i, id := range []string{
   178  			fmt.Sprintf("testScope.bootstrappers_0+type=%s", bs0[0]),
   179  			fmt.Sprintf("testScope.bootstrappers_1+type=%s", bs0[1]),
   180  			fmt.Sprintf("testScope.bootstrappers_2+type=%s", bs0[2]),
   181  			fmt.Sprintf("testScope.bootstrappers_3+type=%s", bs0[3]),
   182  			fmt.Sprintf("testScope.bootstrappers_0+type=%s", bs1[0]),
   183  			fmt.Sprintf("testScope.bootstrappers_1+type=%s", bs1[1]),
   184  			fmt.Sprintf("testScope.bootstrappers_2+type=%s", bs1[2]),
   185  			fmt.Sprintf("testScope.bootstrappers_3+type=%s", bs1[3]),
   186  		} {
   187  			g, ok := gauges[id]
   188  			require.True(t, ok)
   189  			if i < 4 {
   190  				require.Equal(t, float64(1), g.Value(), "first gauge value of after update")
   191  			} else {
   192  				require.Equal(t, float64(0), g.Value(), "second gauge value of after update")
   193  			}
   194  		}
   195  
   196  		// Update back to old again -- test emitting same metric twice
   197  		err = bge.UpdateStringList(bs0)
   198  		require.NoError(t, err)
   199  		require.True(t, bge.running, "state of bootstrapGaugeEmitter after update")
   200  		require.NotNil(t, bge.gauges)
   201  		require.Equal(t, len(bge.gauges), len(bs0))
   202  
   203  		gauges = scope.Snapshot().Gauges()
   204  		require.Equal(t, 8, len(gauges), "length of gauges after updating")
   205  		for i, id := range []string{
   206  			fmt.Sprintf("testScope.bootstrappers_0+type=%s", bs0[0]),
   207  			fmt.Sprintf("testScope.bootstrappers_1+type=%s", bs0[1]),
   208  			fmt.Sprintf("testScope.bootstrappers_2+type=%s", bs0[2]),
   209  			fmt.Sprintf("testScope.bootstrappers_3+type=%s", bs0[3]),
   210  			fmt.Sprintf("testScope.bootstrappers_0+type=%s", bs1[0]),
   211  			fmt.Sprintf("testScope.bootstrappers_1+type=%s", bs1[1]),
   212  			fmt.Sprintf("testScope.bootstrappers_2+type=%s", bs1[2]),
   213  			fmt.Sprintf("testScope.bootstrappers_3+type=%s", bs1[3]),
   214  		} {
   215  			g, ok := gauges[id]
   216  			require.True(t, ok)
   217  			if i < 4 {
   218  				require.Equal(t, float64(1), g.Value(), "first gauge value of after update")
   219  			} else {
   220  				require.Equal(t, float64(0), g.Value(), "second gauge value of after update")
   221  			}
   222  		}
   223  
   224  		// Close
   225  		err = bge.Close()
   226  		require.NoError(t, err)
   227  		require.False(t, bge.running)
   228  	})
   229  
   230  	t.Run("MultipleLabelCombinations", func(t *testing.T) {
   231  		bge := NewStringListEmitter(scope, "bootstrappers")
   232  		require.NotNil(t, bge)
   233  		require.NotNil(t, bge.gauges)
   234  
   235  		err := bge.Start(bootstrappers[0])
   236  		require.NoError(t, err)
   237  		require.True(t, bge.running)
   238  		require.NotNil(t, bge.gauges)
   239  
   240  		// Update same Gauge with standard bootstrappers
   241  		for _, bs := range bootstrappers {
   242  			err = bge.UpdateStringList(bs)
   243  			require.NoError(t, err)
   244  			require.True(t, bge.running)
   245  			require.NotNil(t, bge.gauges)
   246  		}
   247  
   248  		err = bge.Close()
   249  		require.NoError(t, err)
   250  		require.False(t, bge.running)
   251  	})
   252  }
   253  
   254  // This test might timeout instead of just fail
   255  func TestStringListEmitterPrometheusScope(t *testing.T) {
   256  	r := promreporter.NewReporter(promreporter.Options{})
   257  	scope, closer := tally.NewRootScope(tally.ScopeOptions{
   258  		Prefix:         "",
   259  		Tags:           map[string]string{},
   260  		CachedReporter: r,
   261  	}, 0)
   262  	defer closer.Close()
   263  
   264  	bge := NewStringListEmitter(scope, "bootstrappers")
   265  	require.NotNil(t, bge)
   266  	require.NotNil(t, bge.gauges)
   267  
   268  	err := bge.Start(bootstrappers[0])
   269  	require.NoError(t, err)
   270  	require.True(t, bge.running)
   271  	require.NotNil(t, bge.gauges)
   272  
   273  	for _, bs := range bootstrappers {
   274  		err = bge.UpdateStringList(bs)
   275  		require.NoError(t, err)
   276  		require.True(t, bge.running)
   277  		require.NotNil(t, bge.gauges)
   278  	}
   279  
   280  	err = bge.Close()
   281  	require.NoError(t, err)
   282  	require.False(t, bge.running)
   283  }