@@ -18,7 +18,6 @@ import (
1818 "context"
1919 "fmt"
2020 "strings"
21- "testing"
2221
2322 monitoring "cloud.google.com/go/monitoring/apiv3"
2423 gax "github.com/googleapis/gax-go"
@@ -28,7 +27,8 @@ import (
2827)
2928
3029// This file defines various mocks for testing, and checking functions for mocked data. We mock
31- // metric client and bundler because their actions involves RPC calls or non-deterministic behavior.
30+ // metric client and bundler because their actions involves monitoring API calls or
31+ // behavior of bundler controlled by its internal timer.
3232
3333// Following data are used to store various data generated by exporters' activity. They are used by
3434// each test to verify intended behavior. Each test should call testDataInit() to clear these data.
5050)
5151
5252func init () {
53- // For testing convenience, we reduce maximum time series that metric client accepts.
54- MaxTimeSeriesPerUpload = 3
55-
5653 // Mock functions.
5754 newMetricClient = mockNewMetricClient
5855 createTimeSeries = mockCreateTimeSeries
@@ -126,22 +123,29 @@ func mockAddToBundler(bndler *bundler.Bundler, item interface{}, _ int) error {
126123// One of these functions once and only once, and never call NewExporter() directly.
127124
128125// newTestExp creates an exporter which saves error to errStorage. Caller should not set
129- // opts.OnError.
130- func newTestExp (t * testing. T , opts Options ) * Exporter {
126+ // opts.OnError and opts.BundleCountThreshold .
127+ func newTestExp (opts Options ) ( * Exporter , error ) {
131128 opts .OnError = testOnError
129+ // For testing convenience, we reduce the number of timeseris in one upload monitoring API
130+ // call.
131+ opts .BundleCountThreshold = 3
132132 exp , err := NewExporter (ctx , opts )
133133 if err != nil {
134- t . Fatalf ("creating exporter failed: %v" , err )
134+ return nil , fmt . Errorf ("creating exporter failed: %v" , err )
135135 }
136136 // Expose projDataMap so that mockAddToBundler() can use it.
137137 projDataMap = exp .projDataMap
138- return exp
138+ return exp , nil
139139}
140140
141141// newTestProjData creates a projectData object to test behavior of projectData.uploadRowData. Other
142142// uses are not recommended. As newTestExp, all errors are saved to errStorage.
143- func newTestProjData (t * testing.T , opts Options ) * projectData {
144- return newTestExp (t , opts ).newProjectData (project1 )
143+ func newTestProjData (opts Options ) (* projectData , error ) {
144+ exp , err := newTestExp (opts )
145+ if err != nil {
146+ return nil , err
147+ }
148+ return exp .newProjectData (project1 ), nil
145149}
146150
147151// We define a storage for all errors happened in export operation.
@@ -157,33 +161,54 @@ func testOnError(err error, rds ...*RowData) {
157161 errStorage = append (errStorage , errRowData {err , rds })
158162}
159163
164+ // multiError stores a sequence of errors. To convert it to an actual error, call toError().
165+ type multiError struct {
166+ errs []error
167+ }
168+
169+ func (me * multiError ) addf (format string , args ... interface {}) {
170+ me .errs = append (me .errs , fmt .Errorf (format , args ... ))
171+ }
172+
173+ func (me * multiError ) toError () error {
174+ switch len (me .errs ) {
175+ case 0 :
176+ return nil
177+ case 1 :
178+ return me .errs [0 ]
179+ default :
180+ return fmt .Errorf ("multiple errors: %q" , me .errs )
181+ }
182+ }
183+
160184// checkMetricClient checks all recorded requests to the metric client. We only compare int64
161185// values of the time series. To make this work, we assigned different int64 values for all valid
162186// rows in the test.
163- func checkMetricClient (t * testing. T , wantReqsValues [][]int64 ) {
187+ func checkMetricClient (wantReqsValues [][]int64 ) error {
164188 reqsLen , wantReqsLen := len (timeSeriesReqs ), len (wantReqsValues )
165189 if reqsLen != wantReqsLen {
166- t .Errorf ("number of requests got: %d, want %d" , reqsLen , wantReqsLen )
167- return
190+ return fmt .Errorf ("number of requests got: %d, want %d" , reqsLen , wantReqsLen )
168191 }
192+ var errs multiError
169193 for i := 0 ; i < reqsLen ; i ++ {
170194 prefix := fmt .Sprintf ("%d-th request mismatch" , i + 1 )
171195 tsArr := timeSeriesReqs [i ].TimeSeries
172196 wantTsValues := wantReqsValues [i ]
173197 tsArrLen , wantTsArrLen := len (tsArr ), len (wantTsValues )
174198 if tsArrLen != wantTsArrLen {
175- t . Errorf ("%s: number of time series got: %d, want: %d" , prefix , tsArrLen , wantTsArrLen )
199+ errs . addf ("%s: number of time series got: %d, want: %d" , prefix , tsArrLen , wantTsArrLen )
176200 continue
177201 }
178202 for j := 0 ; j < tsArrLen ; j ++ {
179203 // This is how monitoring API stores the int64 value.
180204 tsVal := tsArr [j ].Points [0 ].Value .Value .(* mpb.TypedValue_Int64Value ).Int64Value
181205 wantTsVal := wantTsValues [j ]
182206 if tsVal != wantTsVal {
183- t . Errorf ("%s: Value got: %d, want: %d" , prefix , tsVal , wantTsVal )
207+ errs . addf ("%s: Value got: %d, want: %d" , prefix , tsVal , wantTsVal )
184208 }
185209 }
186210 }
211+ return errs .toError ()
187212}
188213
189214// errRowDataCheck contains data for checking content of error storage.
@@ -193,96 +218,99 @@ type errRowDataCheck struct {
193218}
194219
195220// checkErrStorage checks content of error storage. For returned errors, we check prefix and suffix.
196- func checkErrStorage (t * testing. T , wantErrRdCheck []errRowDataCheck ) {
221+ func checkErrStorage (wantErrRdCheck []errRowDataCheck ) error {
197222 gotLen , wantLen := len (errStorage ), len (wantErrRdCheck )
198223 if gotLen != wantLen {
199- t .Errorf ("number of reported errors: %d, want: %d" , gotLen , wantLen )
200- return
224+ return fmt .Errorf ("number of reported errors: %d, want: %d" , gotLen , wantLen )
201225 }
226+ var errs multiError
202227 for i := 0 ; i < gotLen ; i ++ {
203228 prefix := fmt .Sprintf ("%d-th reported error mismatch" , i + 1 )
204229 errRd , wantErrRd := errStorage [i ], wantErrRdCheck [i ]
205230 errStr := errRd .err .Error ()
206231 if errPrefix := wantErrRd .errPrefix ; ! strings .HasPrefix (errStr , errPrefix ) {
207- t . Errorf ("%s: error got: %q, want: prefixed by %q" , prefix , errStr , errPrefix )
232+ errs . addf ("%s: error got: %q, want: prefixed by %q" , prefix , errStr , errPrefix )
208233 }
209234 if errSuffix := wantErrRd .errSuffix ; ! strings .HasSuffix (errStr , errSuffix ) {
210- t . Errorf ("%s: error got: %q, want: suffiexd by %q" , prefix , errStr , errSuffix )
235+ errs . addf ("%s: error got: %q, want: suffiexd by %q" , prefix , errStr , errSuffix )
211236 }
212237 if err := checkRowDataArr (errRd .rds , wantErrRd .rds ); err != nil {
213- t . Errorf ("%s: RowData array mismatch: %v" , prefix , err )
238+ errs . addf ("%s: RowData array mismatch: %v" , prefix , err )
214239 }
215240 }
241+ return errs .toError ()
216242}
217243
218244func checkRowDataArr (rds , wantRds []* RowData ) error {
219245 rdLen , wantRdLen := len (rds ), len (wantRds )
220246 if rdLen != wantRdLen {
221247 return fmt .Errorf ("number row data got: %d, want: %d" , rdLen , wantRdLen )
222248 }
249+ var errs multiError
223250 for i := 0 ; i < rdLen ; i ++ {
224251 if err := checkRowData (rds [i ], wantRds [i ]); err != nil {
225- return fmt . Errorf ("%d-th row data mismatch: %v" , i + 1 , err )
252+ errs . addf ("%d-th row data mismatch: %v" , i + 1 , err )
226253 }
227254 }
228- return nil
255+ return errs . toError ()
229256}
230257
231258func checkRowData (rd , wantRd * RowData ) error {
259+ var errs multiError
232260 if rd .View != wantRd .View {
233- return fmt . Errorf ("View got: %s, want: %s" , rd .View .Name , wantRd .View .Name )
261+ errs . addf ("View got: %s, want: %s" , rd .View .Name , wantRd .View .Name )
234262 }
235263 if rd .Start != wantRd .Start {
236- return fmt . Errorf ("Start got: %v, want: %v" , rd .Start , wantRd .Start )
264+ errs . addf ("Start got: %v, want: %v" , rd .Start , wantRd .Start )
237265 }
238266 if rd .End != wantRd .End {
239- return fmt . Errorf ("End got: %v, want: %v" , rd .End , wantRd .End )
267+ errs . addf ("End got: %v, want: %v" , rd .End , wantRd .End )
240268 }
241269 if rd .Row != wantRd .Row {
242- return fmt . Errorf ("Row got: %v, want: %v" , rd .Row , wantRd .Row )
270+ errs . addf ("Row got: %v, want: %v" , rd .Row , wantRd .Row )
243271 }
244- return nil
272+ return errs . toError ()
245273}
246274
247275// checkProjData checks all data passed to the bundler by bundler.Add().
248- func checkProjData (t * testing.T , wantProjData map [string ][]* RowData ) {
249- wantProj := map [string ]bool {}
250- for proj := range wantProjData {
251- wantProj [proj ] = true
252- }
276+ func checkProjData (wantProjData map [string ][]* RowData ) error {
277+ var errs multiError
253278 for proj := range projRds {
254- if ! wantProj [proj ] {
255- t . Errorf ("project in exporter's project data not wanted: %s" , proj )
279+ if _ , ok := wantProjData [proj ]; ! ok {
280+ errs . addf ("project in exporter's project data not wanted: %s" , proj )
256281 }
257282 }
258283
259284 for proj , wantRds := range wantProjData {
260285 rds , ok := projRds [proj ]
261286 if ! ok {
262- t . Errorf ("wanted project not found in exporter's project data: %v" , proj )
287+ errs . addf ("wanted project not found in exporter's project data: %v" , proj )
263288 continue
264289 }
265290 if err := checkRowDataArr (* rds , wantRds ); err != nil {
266- t . Errorf ("RowData array mismatch for project %s: %v" , proj , err )
291+ errs . addf ("RowData array mismatch for project %s: %v" , proj , err )
267292 }
268293 }
294+ return errs .toError ()
269295}
270296
271297// checkLabels checks data in labels.
272- func checkLabels (t * testing.T , prefix string , labels , wantLabels map [string ]string ) {
298+ func checkLabels (prefix string , labels , wantLabels map [string ]string ) error {
299+ var errs multiError
273300 for labelName , value := range labels {
274301 wantValue , ok := wantLabels [labelName ]
275302 if ! ok {
276- t . Errorf ("%s: label name in time series not wanted: %s" , prefix , labelName )
303+ errs . addf ("%s: label name in time series not wanted: %s" , prefix , labelName )
277304 continue
278305 }
279306 if value != wantValue {
280- t . Errorf ("%s: value for label name %s got: %s, want: %s" , prefix , labelName , value , wantValue )
307+ errs . addf ("%s: value for label name %s got: %s, want: %s" , prefix , labelName , value , wantValue )
281308 }
282309 }
283310 for wantLabelName := range wantLabels {
284311 if _ , ok := labels [wantLabelName ]; ! ok {
285- t . Errorf ("%s: wanted label name not found in time series: %s" , prefix , wantLabelName )
312+ errs . addf ("%s: wanted label name not found in time series: %s" , prefix , wantLabelName )
286313 }
287314 }
315+ return errs .toError ()
288316}
0 commit comments