github.com/uber-go/tally/v4@v4.1.17/scope_registry_external_test.go (about) 1 // Copyright (c) 2023 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 tally_test 22 23 import ( 24 "io" 25 "sync" 26 "testing" 27 "time" 28 29 "github.com/golang/mock/gomock" 30 "github.com/stretchr/testify/require" 31 "github.com/uber-go/tally/v4" 32 "github.com/uber-go/tally/v4/tallymock" 33 "go.uber.org/atomic" 34 ) 35 36 func TestTestScopesNotPruned(t *testing.T) { 37 var ( 38 root = tally.NewTestScope("", nil) 39 subscope = root.SubScope("foo") 40 counter = subscope.Counter("bar") 41 ) 42 43 counter.Inc(123) 44 45 closer, ok := subscope.(io.Closer) 46 require.True(t, ok) 47 require.NoError(t, closer.Close()) 48 49 subscope = root.SubScope("foo") 50 counter = subscope.Counter("bar") 51 counter.Inc(123) 52 53 var ( 54 snapshot = root.Snapshot() 55 counters = snapshot.Counters() 56 ) 57 require.Len(t, counters, 1) 58 require.Len(t, snapshot.Gauges(), 0) 59 require.Len(t, snapshot.Timers(), 0) 60 require.Len(t, snapshot.Histograms(), 0) 61 62 val, ok := counters["foo.bar+"] 63 require.True(t, ok) 64 require.Equal(t, "foo.bar", val.Name()) 65 require.EqualValues(t, 246, val.Value()) 66 } 67 68 func TestNoDefunctSubscopes(t *testing.T) { 69 ctrl := gomock.NewController(t) 70 defer ctrl.Finish() 71 72 var ( 73 tags = map[string]string{ 74 "hello": "world", 75 } 76 mockreporter = tallymock.NewMockStatsReporter(ctrl) 77 ready = make(chan struct{}) 78 closed atomic.Bool 79 wg sync.WaitGroup 80 ) 81 wg.Add(2) 82 83 mockreporter.EXPECT(). 84 ReportCounter("a", gomock.Any(), int64(123)). 85 Do(func(_ string, _ map[string]string, _ int64) { 86 wg.Done() 87 }). 88 Times(1) 89 mockreporter.EXPECT(). 90 ReportCounter("b", gomock.Any(), int64(456)). 91 Do(func(_ string, _ map[string]string, _ int64) { 92 wg.Done() 93 }). 94 Times(1) 95 96 // Use flushing as a signal to determine if/when a closed scope 97 // would be removed from the registry's cache. 98 mockreporter.EXPECT(). 99 Flush(). 100 Do(func() { 101 // Don't unblock the ready channel until we've explicitly 102 // closed the scope. 103 if !closed.Load() { 104 return 105 } 106 107 select { 108 case <-ready: 109 default: 110 close(ready) 111 } 112 }). 113 MinTimes(1) 114 115 root, _ := tally.NewRootScope(tally.ScopeOptions{ 116 Reporter: mockreporter, 117 OmitCardinalityMetrics: true, 118 }, time.Millisecond) 119 120 subscope := root.Tagged(tags) 121 requireClose(t, subscope) 122 subscope = root.Tagged(tags) 123 124 // Signal and wait for the next flush to ensure that subscope can 125 // be a closed scope. 126 closed.Store(true) 127 <-ready 128 129 // Use the maybe-closed subscope for counter A. 130 subscope.Counter("a").Inc(123) 131 132 // Guarantee that counter B will not use a closed subscope. 133 subscope = root.Tagged(tags) 134 subscope.Counter("b").Inc(456) 135 136 requireClose(t, root) 137 wg.Wait() 138 } 139 140 func requireClose(t *testing.T, scope tally.Scope) { 141 x, ok := scope.(io.Closer) 142 require.True(t, ok) 143 require.NoError(t, x.Close()) 144 }