@@ -18,10 +18,13 @@ package view
1818import (
1919 "context"
2020 "errors"
21+ "sort"
2122 "sync"
2223 "testing"
2324 "time"
2425
26+ "go.opencensus.io/resource"
27+
2528 "go.opencensus.io/metric/metricdata"
2629 "go.opencensus.io/metric/metricexport"
2730 "go.opencensus.io/stats"
@@ -123,8 +126,13 @@ func Test_Worker_MultiExport(t *testing.T) {
123126
124127 // This test reports the same data for the default worker and a secondary
125128 // worker, and ensures that the stats are kept independently.
129+ extraResource := resource.Resource {
130+ Type : "additional" ,
131+ Labels : map [string ]string {"key1" : "value1" , "key2" : "value2" },
132+ }
126133 worker2 := NewMeter ().(* worker )
127134 worker2 .Start ()
135+ worker2 .SetResource (& extraResource )
128136
129137 m := stats .Float64 ("Test_Worker_MultiExport/MF1" , "desc MF1" , "unit" )
130138 key := tag .MustNewKey (("key" ))
@@ -162,50 +170,62 @@ func Test_Worker_MultiExport(t *testing.T) {
162170 }
163171 }
164172
165- wantRows := []struct {
166- w Meter
167- view string
168- rows []* Row
169- }{{
170- view : count .Name ,
171- rows : []* Row {
173+ makeKey := func (r * resource.Resource , view string ) string {
174+ if r == nil {
175+ r = & resource.Resource {}
176+ }
177+ return resource .EncodeLabels (r .Labels ) + "/" + view
178+ }
179+
180+ // Format is Resource.Labels encoded as string, then
181+ wantPartialData := map [string ][]* Row {
182+ makeKey (nil , count .Name ): []* Row {
172183 {[]tag.Tag {{Key : key , Value : "a" }}, & CountData {Value : 2 }},
173184 {[]tag.Tag {{Key : key , Value : "b" }}, & CountData {Value : 1 }},
174185 },
175- }, {
176- view : sum .Name ,
177- rows : []* Row {
178- {nil , & SumData {Value : 7.5 }}},
179- }, {
180- w : worker2 ,
181- view : count .Name ,
182- rows : []* Row {
186+ makeKey (nil , sum .Name ): []* Row {
187+ {nil , & SumData {Value : 7.5 }},
188+ },
189+ makeKey (& extraResource , count .Name ): []* Row {
183190 {[]tag.Tag {{Key : key , Value : "b" }}, & CountData {Value : 1 }},
184191 },
185- }}
192+ }
186193
187- for _ , wantRow := range wantRows {
188- retrieve := RetrieveData
189- if wantRow . w != nil {
190- retrieve = wantRow . w .( * worker ). RetrieveData
191- }
192- gotRows , err := retrieve ( wantRow . view )
193- if err != nil {
194- t . Fatalf ( "RetrieveData(%v), got error %v" , wantRow . view , err )
194+ te := & testExporter {}
195+ metricexport . NewReader (). ReadAndExport ( te )
196+ for _ , m := range te . metrics {
197+ key := makeKey ( m . Resource , m . Descriptor . Name )
198+ want , ok := wantPartialData [ key ]
199+ if ! ok {
200+ t . Errorf ( "Unexpected data for %q: %v" , key , m )
201+ continue
195202 }
196- for _ , got := range gotRows {
197- if ! containsRow (wantRow .rows , got ) {
198- t .Errorf ("%s: got row %#v; want none" , wantRow .view , got )
199- break
203+ gotTs := m .TimeSeries
204+ sort .Sort (byLabel (gotTs ))
205+
206+ for i , ts := range gotTs {
207+ for j , label := range ts .LabelValues {
208+ if want [i ].Tags [j ].Value != label .Value {
209+ t .Errorf ("Mismatched tag values (want %q, got %q) for %v in %q" , want [i ].Tags [j ].Value , label .Value , ts , key )
210+ }
200211 }
201- }
202- for _ , want := range wantRow .rows {
203- if ! containsRow (gotRows , want ) {
204- t .Errorf ("%s: got none, want %#v" , wantRow .view , want )
205- break
212+ switch wantValue := want [i ].Data .(type ) {
213+ case * CountData :
214+ got := ts .Points [0 ].Value .(int64 )
215+ if wantValue .Value != got {
216+ t .Errorf ("Mismatched value (want %d, got %d) for %v in %q" , wantValue , got , ts , key )
217+ }
218+ case * SumData :
219+ got := ts .Points [0 ].Value .(float64 )
220+ if wantValue .Value != got {
221+ t .Errorf ("Mismatched value (want %f, got %f) for %v in %q" , wantValue , got , ts , key )
222+ }
223+ default :
224+ t .Errorf ("Unexpected type of data: %T for %v in %q" , wantValue , want [i ], key )
206225 }
207226 }
208227 }
228+
209229 // Verify that worker has not been computing sum:
210230 got , err := worker2 .RetrieveData (sum .Name )
211231 if err == nil {
@@ -577,9 +597,11 @@ func TestWorkerRace(t *testing.T) {
577597}
578598
579599type testExporter struct {
600+ metrics []* metricdata.Metric
580601}
581602
582603func (te * testExporter ) ExportMetrics (ctx context.Context , metrics []* metricdata.Metric ) error {
604+ te .metrics = metrics
583605 return nil
584606}
585607
@@ -619,3 +641,20 @@ func restart() {
619641 defaultWorker = NewMeter ().(* worker )
620642 go defaultWorker .start ()
621643}
644+
645+ // byTag implements sort.Interface for *metricdata.TimeSeries by Labels.
646+ type byLabel []* metricdata.TimeSeries
647+
648+ func (ts byLabel ) Len () int { return len (ts ) }
649+ func (ts byLabel ) Swap (i , j int ) { ts [i ], ts [j ] = ts [j ], ts [i ] }
650+ func (ts byLabel ) Less (i , j int ) bool {
651+ if len (ts [i ].LabelValues ) != len (ts [j ].LabelValues ) {
652+ return len (ts [i ].LabelValues ) < len (ts [j ].LabelValues )
653+ }
654+ for k := range ts [i ].LabelValues {
655+ if ts [i ].LabelValues [k ].Value != ts [j ].LabelValues [k ].Value {
656+ return ts [i ].LabelValues [k ].Value < ts [j ].LabelValues [k ].Value
657+ }
658+ }
659+ return false
660+ }
0 commit comments