@@ -18,7 +18,6 @@ import (
18
18
"context"
19
19
"fmt"
20
20
"strings"
21
- "testing"
22
21
23
22
monitoring "cloud.google.com/go/monitoring/apiv3"
24
23
gax "github.com/googleapis/gax-go"
50
49
)
51
50
52
51
func init () {
53
- // For testing convenience, we reduce maximum time series that metric client accepts.
54
- MaxTimeSeriesPerUpload = 3
55
-
56
52
// Mock functions.
57
53
newMetricClient = mockNewMetricClient
58
54
createTimeSeries = mockCreateTimeSeries
@@ -126,22 +122,29 @@ func mockAddToBundler(bndler *bundler.Bundler, item interface{}, _ int) error {
126
122
// One of these functions once and only once, and never call NewExporter() directly.
127
123
128
124
// 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 {
125
+ // opts.OnError and opts.BundleCountThreshold .
126
+ func newTestExp (opts Options ) ( * Exporter , error ) {
131
127
opts .OnError = testOnError
128
+ // For testing convenience, we reduce the number of timeseris in one upload monitoring API
129
+ // call.
130
+ opts .BundleCountThreshold = 3
132
131
exp , err := NewExporter (ctx , opts )
133
132
if err != nil {
134
- t . Fatalf ("creating exporter failed: %v" , err )
133
+ return nil , fmt . Errorf ("creating exporter failed: %v" , err )
135
134
}
136
135
// Expose projDataMap so that mockAddToBundler() can use it.
137
136
projDataMap = exp .projDataMap
138
- return exp
137
+ return exp , nil
139
138
}
140
139
141
140
// newTestProjData creates a projectData object to test behavior of projectData.uploadRowData. Other
142
141
// 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 )
142
+ func newTestProjData (opts Options ) (* projectData , error ) {
143
+ exp , err := newTestExp (opts )
144
+ if err != nil {
145
+ return nil , err
146
+ }
147
+ return exp .newProjectData (project1 ), nil
145
148
}
146
149
147
150
// We define a storage for all errors happened in export operation.
@@ -157,33 +160,54 @@ func testOnError(err error, rds ...*RowData) {
157
160
errStorage = append (errStorage , errRowData {err , rds })
158
161
}
159
162
163
+ // multiError stores a sequence of errors. To convert it to an actual error, call toError().
164
+ type multiError struct {
165
+ errs []error
166
+ }
167
+
168
+ func (me * multiError ) addf (format string , args ... interface {}) {
169
+ me .errs = append (me .errs , fmt .Errorf (format , args ... ))
170
+ }
171
+
172
+ func (me * multiError ) toError () error {
173
+ switch len (me .errs ) {
174
+ case 0 :
175
+ return nil
176
+ case 1 :
177
+ return me .errs [0 ]
178
+ default :
179
+ return fmt .Errorf ("multiple errors: %q" , me .errs )
180
+ }
181
+ }
182
+
160
183
// checkMetricClient checks all recorded requests to the metric client. We only compare int64
161
184
// values of the time series. To make this work, we assigned different int64 values for all valid
162
185
// rows in the test.
163
- func checkMetricClient (t * testing. T , wantReqsValues [][]int64 ) {
186
+ func checkMetricClient (wantReqsValues [][]int64 ) error {
164
187
reqsLen , wantReqsLen := len (timeSeriesReqs ), len (wantReqsValues )
165
188
if reqsLen != wantReqsLen {
166
- t .Errorf ("number of requests got: %d, want %d" , reqsLen , wantReqsLen )
167
- return
189
+ return fmt .Errorf ("number of requests got: %d, want %d" , reqsLen , wantReqsLen )
168
190
}
191
+ var errs multiError
169
192
for i := 0 ; i < reqsLen ; i ++ {
170
193
prefix := fmt .Sprintf ("%d-th request mismatch" , i + 1 )
171
194
tsArr := timeSeriesReqs [i ].TimeSeries
172
195
wantTsValues := wantReqsValues [i ]
173
196
tsArrLen , wantTsArrLen := len (tsArr ), len (wantTsValues )
174
197
if tsArrLen != wantTsArrLen {
175
- t . Errorf ("%s: number of time series got: %d, want: %d" , prefix , tsArrLen , wantTsArrLen )
198
+ errs . addf ("%s: number of time series got: %d, want: %d" , prefix , tsArrLen , wantTsArrLen )
176
199
continue
177
200
}
178
201
for j := 0 ; j < tsArrLen ; j ++ {
179
202
// This is how monitoring API stores the int64 value.
180
203
tsVal := tsArr [j ].Points [0 ].Value .Value .(* mpb.TypedValue_Int64Value ).Int64Value
181
204
wantTsVal := wantTsValues [j ]
182
205
if tsVal != wantTsVal {
183
- t . Errorf ("%s: Value got: %d, want: %d" , prefix , tsVal , wantTsVal )
206
+ errs . addf ("%s: Value got: %d, want: %d" , prefix , tsVal , wantTsVal )
184
207
}
185
208
}
186
209
}
210
+ return errs .toError ()
187
211
}
188
212
189
213
// errRowDataCheck contains data for checking content of error storage.
@@ -193,96 +217,99 @@ type errRowDataCheck struct {
193
217
}
194
218
195
219
// checkErrStorage checks content of error storage. For returned errors, we check prefix and suffix.
196
- func checkErrStorage (t * testing. T , wantErrRdCheck []errRowDataCheck ) {
220
+ func checkErrStorage (wantErrRdCheck []errRowDataCheck ) error {
197
221
gotLen , wantLen := len (errStorage ), len (wantErrRdCheck )
198
222
if gotLen != wantLen {
199
- t .Errorf ("number of reported errors: %d, want: %d" , gotLen , wantLen )
200
- return
223
+ return fmt .Errorf ("number of reported errors: %d, want: %d" , gotLen , wantLen )
201
224
}
225
+ var errs multiError
202
226
for i := 0 ; i < gotLen ; i ++ {
203
227
prefix := fmt .Sprintf ("%d-th reported error mismatch" , i + 1 )
204
228
errRd , wantErrRd := errStorage [i ], wantErrRdCheck [i ]
205
229
errStr := errRd .err .Error ()
206
230
if errPrefix := wantErrRd .errPrefix ; ! strings .HasPrefix (errStr , errPrefix ) {
207
- t . Errorf ("%s: error got: %q, want: prefixed by %q" , prefix , errStr , errPrefix )
231
+ errs . addf ("%s: error got: %q, want: prefixed by %q" , prefix , errStr , errPrefix )
208
232
}
209
233
if errSuffix := wantErrRd .errSuffix ; ! strings .HasSuffix (errStr , errSuffix ) {
210
- t . Errorf ("%s: error got: %q, want: suffiexd by %q" , prefix , errStr , errSuffix )
234
+ errs . addf ("%s: error got: %q, want: suffiexd by %q" , prefix , errStr , errSuffix )
211
235
}
212
236
if err := checkRowDataArr (errRd .rds , wantErrRd .rds ); err != nil {
213
- t . Errorf ("%s: RowData array mismatch: %v" , prefix , err )
237
+ errs . addf ("%s: RowData array mismatch: %v" , prefix , err )
214
238
}
215
239
}
240
+ return errs .toError ()
216
241
}
217
242
218
243
func checkRowDataArr (rds , wantRds []* RowData ) error {
219
244
rdLen , wantRdLen := len (rds ), len (wantRds )
220
245
if rdLen != wantRdLen {
221
246
return fmt .Errorf ("number row data got: %d, want: %d" , rdLen , wantRdLen )
222
247
}
248
+ var errs multiError
223
249
for i := 0 ; i < rdLen ; i ++ {
224
250
if err := checkRowData (rds [i ], wantRds [i ]); err != nil {
225
- return fmt . Errorf ("%d-th row data mismatch: %v" , i + 1 , err )
251
+ errs . addf ("%d-th row data mismatch: %v" , i + 1 , err )
226
252
}
227
253
}
228
- return nil
254
+ return errs . toError ()
229
255
}
230
256
231
257
func checkRowData (rd , wantRd * RowData ) error {
258
+ var errs multiError
232
259
if rd .View != wantRd .View {
233
- return fmt . Errorf ("View got: %s, want: %s" , rd .View .Name , wantRd .View .Name )
260
+ errs . addf ("View got: %s, want: %s" , rd .View .Name , wantRd .View .Name )
234
261
}
235
262
if rd .Start != wantRd .Start {
236
- return fmt . Errorf ("Start got: %v, want: %v" , rd .Start , wantRd .Start )
263
+ errs . addf ("Start got: %v, want: %v" , rd .Start , wantRd .Start )
237
264
}
238
265
if rd .End != wantRd .End {
239
- return fmt . Errorf ("End got: %v, want: %v" , rd .End , wantRd .End )
266
+ errs . addf ("End got: %v, want: %v" , rd .End , wantRd .End )
240
267
}
241
268
if rd .Row != wantRd .Row {
242
- return fmt . Errorf ("Row got: %v, want: %v" , rd .Row , wantRd .Row )
269
+ errs . addf ("Row got: %v, want: %v" , rd .Row , wantRd .Row )
243
270
}
244
- return nil
271
+ return errs . toError ()
245
272
}
246
273
247
274
// 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
- }
275
+ func checkProjData (wantProjData map [string ][]* RowData ) error {
276
+ var errs multiError
253
277
for proj := range projRds {
254
- if ! wantProj [proj ] {
255
- t . Errorf ("project in exporter's project data not wanted: %s" , proj )
278
+ if _ , ok := wantProjData [proj ]; ! ok {
279
+ errs . addf ("project in exporter's project data not wanted: %s" , proj )
256
280
}
257
281
}
258
282
259
283
for proj , wantRds := range wantProjData {
260
284
rds , ok := projRds [proj ]
261
285
if ! ok {
262
- t . Errorf ("wanted project not found in exporter's project data: %v" , proj )
286
+ errs . addf ("wanted project not found in exporter's project data: %v" , proj )
263
287
continue
264
288
}
265
289
if err := checkRowDataArr (* rds , wantRds ); err != nil {
266
- t . Errorf ("RowData array mismatch for project %s: %v" , proj , err )
290
+ errs . addf ("RowData array mismatch for project %s: %v" , proj , err )
267
291
}
268
292
}
293
+ return errs .toError ()
269
294
}
270
295
271
296
// checkLabels checks data in labels.
272
- func checkLabels (t * testing.T , prefix string , labels , wantLabels map [string ]string ) {
297
+ func checkLabels (prefix string , labels , wantLabels map [string ]string ) error {
298
+ var errs multiError
273
299
for labelName , value := range labels {
274
300
wantValue , ok := wantLabels [labelName ]
275
301
if ! ok {
276
- t . Errorf ("%s: label name in time series not wanted: %s" , prefix , labelName )
302
+ errs . addf ("%s: label name in time series not wanted: %s" , prefix , labelName )
277
303
continue
278
304
}
279
305
if value != wantValue {
280
- t . Errorf ("%s: value for label name %s got: %s, want: %s" , prefix , labelName , value , wantValue )
306
+ errs . addf ("%s: value for label name %s got: %s, want: %s" , prefix , labelName , value , wantValue )
281
307
}
282
308
}
283
309
for wantLabelName := range wantLabels {
284
310
if _ , ok := labels [wantLabelName ]; ! ok {
285
- t . Errorf ("%s: wanted label name not found in time series: %s" , prefix , wantLabelName )
311
+ errs . addf ("%s: wanted label name not found in time series: %s" , prefix , wantLabelName )
286
312
}
287
313
}
314
+ return errs .toError ()
288
315
}
0 commit comments