1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package managedwriter
16
17 import (
18 "context"
19 "math"
20 "testing"
21
22 "cloud.google.com/go/bigquery"
23 "cloud.google.com/go/bigquery/storage/managedwriter/adapt"
24 "cloud.google.com/go/bigquery/storage/managedwriter/testdata"
25 "google.golang.org/protobuf/proto"
26 "google.golang.org/protobuf/reflect/protodesc"
27 "google.golang.org/protobuf/reflect/protoreflect"
28 "google.golang.org/protobuf/types/descriptorpb"
29 "google.golang.org/protobuf/types/dynamicpb"
30 )
31
32 func TestValidation_Values(t *testing.T) {
33
34 testcases := []struct {
35 description string
36 tableSchema bigquery.Schema
37 inputRow proto.Message
38 constraints []constraintOption
39 }{
40 {
41 description: "proto2 optional w/nulls",
42 tableSchema: testdata.ValidationBaseSchema,
43 inputRow: &testdata.ValidationP2Optional{},
44 constraints: []constraintOption{
45 withExactRowCount(1),
46 withNullCount("double_field", 1),
47 withNullCount("float_field", 1),
48 withNullCount("int32_field", 1),
49 withNullCount("int64_field", 1),
50 withNullCount("uint32_field", 1),
51 withNullCount("sint32_field", 1),
52 withNullCount("sint64_field", 1),
53 withNullCount("fixed32_field", 1),
54 withNullCount("sfixed32_field", 1),
55 withNullCount("sfixed64_field", 1),
56 withNullCount("bool_field", 1),
57 withNullCount("string_field", 1),
58 withNullCount("bytes_field", 1),
59 withNullCount("enum_field", 1),
60 },
61 },
62 {
63 description: "proto2 optionals w/values",
64 tableSchema: testdata.ValidationBaseSchema,
65 inputRow: &testdata.ValidationP2Optional{
66 DoubleField: proto.Float64(math.Inf(1)),
67 FloatField: proto.Float32(2.0),
68 Int32Field: proto.Int32(11),
69 Int64Field: proto.Int64(-22),
70 Uint32Field: proto.Uint32(365),
71 Sint32Field: proto.Int32(123),
72 Sint64Field: proto.Int64(45),
73 Fixed32Field: proto.Uint32(1000),
74 Sfixed32Field: proto.Int32(999),
75 Sfixed64Field: proto.Int64(33),
76 BoolField: proto.Bool(true),
77 StringField: proto.String("test"),
78 BytesField: []byte("some byte data"),
79 EnumField: testdata.Proto2ExampleEnum_P2_THING.Enum(),
80 },
81 constraints: []constraintOption{
82 withExactRowCount(1),
83 withFloatValueCount("double_field", math.Inf(1), 1),
84 withFloatValueCount("float_field", 2.0, 1),
85 withIntegerValueCount("int32_field", 11, 1),
86 withIntegerValueCount("int64_field", -22, 1),
87 withIntegerValueCount("uint32_field", 365, 1),
88 withIntegerValueCount("sint32_field", 123, 1),
89 withIntegerValueCount("sint64_field", 45, 1),
90 withIntegerValueCount("fixed32_field", 1000, 1),
91 withIntegerValueCount("sfixed32_field", 999, 1),
92 withIntegerValueCount("sfixed64_field", 33, 1),
93 withBoolValueCount("bool_field", true, 1),
94 withStringValueCount("string_field", "test", 1),
95 withBytesValueCount("bytes_field", []byte("some byte data"), 1),
96 withIntegerValueCount("enum_field", int64(testdata.Proto2ExampleEnum_P2_THING), 1),
97 },
98 },
99 {
100 description: "proto2 required",
101 tableSchema: testdata.ValidationBaseSchema,
102 inputRow: &testdata.ValidationP2Required{
103 DoubleField: proto.Float64(math.Inf(1)),
104 FloatField: proto.Float32(2.0),
105 Int32Field: proto.Int32(11),
106 Int64Field: proto.Int64(-22),
107 Uint32Field: proto.Uint32(365),
108 Sint32Field: proto.Int32(123),
109 Sint64Field: proto.Int64(45),
110 Fixed32Field: proto.Uint32(1000),
111 Sfixed32Field: proto.Int32(999),
112 Sfixed64Field: proto.Int64(33),
113 BoolField: proto.Bool(true),
114 StringField: proto.String("test"),
115 BytesField: []byte("some byte data"),
116 EnumField: testdata.Proto2ExampleEnum_P2_THING.Enum(),
117 },
118 constraints: []constraintOption{
119 withExactRowCount(1),
120 withFloatValueCount("double_field", math.Inf(1), 1),
121 withFloatValueCount("float_field", 2.0, 1),
122 withIntegerValueCount("int32_field", 11, 1),
123 withIntegerValueCount("int64_field", -22, 1),
124 withIntegerValueCount("uint32_field", 365, 1),
125 withIntegerValueCount("sint32_field", 123, 1),
126 withIntegerValueCount("sint64_field", 45, 1),
127 withIntegerValueCount("fixed32_field", 1000, 1),
128 withIntegerValueCount("sfixed32_field", 999, 1),
129 withIntegerValueCount("sfixed64_field", 33, 1),
130 withBoolValueCount("bool_field", true, 1),
131 withStringValueCount("string_field", "test", 1),
132 withBytesValueCount("bytes_field", []byte("some byte data"), 1),
133 withIntegerValueCount("enum_field", int64(testdata.Proto2ExampleEnum_P2_THING), 1),
134 },
135 },
136 {
137 description: "proto2 default values w/nulls",
138 tableSchema: testdata.ValidationBaseSchema,
139 inputRow: &testdata.ValidationP2OptionalWithDefaults{},
140 constraints: []constraintOption{
141 withExactRowCount(1),
142 withFloatValueCount("double_field", 1.11, 1),
143 withFloatValueCount("float_field", 2.22, 1),
144 withIntegerValueCount("int32_field", 3, 1),
145 withIntegerValueCount("int64_field", 4, 1),
146 withIntegerValueCount("uint32_field", 5, 1),
147 withIntegerValueCount("sint32_field", 7, 1),
148 withIntegerValueCount("sint64_field", 8, 1),
149 withIntegerValueCount("fixed32_field", 9, 1),
150 withIntegerValueCount("sfixed32_field", 11, 1),
151 withIntegerValueCount("sfixed64_field", 12, 1),
152 withBoolValueCount("bool_field", true, 1),
153 withStringValueCount("string_field", "custom default", 1),
154 withBytesValueCount("bytes_field", []byte("optional bytes"), 1),
155 withIntegerValueCount("enum_field", int64(testdata.Proto2ExampleEnum_P2_OTHER_THING), 1),
156 },
157 },
158
159 {
160 description: "proto3 default values",
161 tableSchema: testdata.ValidationBaseSchema,
162 inputRow: &testdata.ValidationP3Defaults{},
163 constraints: []constraintOption{
164 withExactRowCount(1),
165 withFloatValueCount("double_field", 0, 1),
166 withFloatValueCount("float_field", 0, 1),
167 withIntegerValueCount("int32_field", 0, 1),
168 withIntegerValueCount("int64_field", 0, 1),
169 withIntegerValueCount("uint32_field", 0, 1),
170 withIntegerValueCount("sint32_field", 0, 1),
171 withIntegerValueCount("sint64_field", 0, 1),
172 withIntegerValueCount("fixed32_field", 0, 1),
173 withIntegerValueCount("sfixed32_field", 0, 1),
174 withIntegerValueCount("sfixed64_field", 0, 1),
175 withBoolValueCount("bool_field", false, 1),
176 withStringValueCount("string_field", "", 1),
177 withBytesValueCount("bytes_field", []byte(""), 1),
178 withIntegerValueCount("enum_field", int64(0), 1),
179 },
180 },
181
195 {
196 description: "proto3 optional presence w/o explicit values",
197 tableSchema: testdata.ValidationBaseSchema,
198 inputRow: &testdata.ValidationP3Optional{},
199 constraints: []constraintOption{
200 withExactRowCount(1),
201 withNullCount("double_field", 1),
202 withNullCount("float_field", 1),
203 withNullCount("int32_field", 1),
204 withNullCount("int64_field", 1),
205 withNullCount("uint32_field", 1),
206 withNullCount("sint32_field", 1),
207 withNullCount("sint64_field", 1),
208 withNullCount("fixed32_field", 1),
209 withNullCount("sfixed32_field", 1),
210 withNullCount("sfixed64_field", 1),
211 withNullCount("bool_field", 1),
212 withNullCount("string_field", 1),
213 withNullCount("bytes_field", 1),
214 withNullCount("enum_field", 1),
215 },
216 },
217 {
218 description: "proto2 unpacked repeated non-empty",
219 tableSchema: testdata.ValidationRepeatedSchema,
220 inputRow: &testdata.ValidationP2UnpackedRepeated{
221 Id: proto.Int64(2022),
222 DoubleRepeated: []float64{1.1, 2.2, 3.3},
223 FloatRepeated: []float32{-4.4, -5.5, -6.6, -7.7},
224 Int32Repeated: []int32{2, 4, 6, 6, 10},
225 Int64Repeated: []int64{100, 200, 300, 300, 300, 600, 700},
226 Uint32Repeated: []uint32{8675309, 8675309, 8675309, 8675309, 8675309, 8675309, 8675309},
227 Sint32Repeated: []int32{-1, -2, -3, 4, 5, 6},
228 Sint64Repeated: []int64{2},
229 Fixed32Repeated: []uint32{},
230 Sfixed32Repeated: []int32{-88, 100, -99, -88},
231 Sfixed64Repeated: []int64{88, -100, 99, -2020},
232 BoolRepeated: []bool{true, true, false, true},
233 EnumRepeated: []testdata.Proto2ExampleEnum{testdata.Proto2ExampleEnum_P2_OTHER_THING, testdata.Proto2ExampleEnum_P2_THIRD_THING, testdata.Proto2ExampleEnum_P2_OTHER_THING},
234 },
235 constraints: []constraintOption{
236 withExactRowCount(1),
237
238 withArrayLength("double_repeated", 3, 1),
239 withArrayLength("float_repeated", 4, 1),
240 withArrayLength("int32_repeated", 5, 1),
241 withArrayLength("int64_repeated", 7, 1),
242 withArrayLength("uint32_repeated", 7, 1),
243 withArrayLength("sint32_repeated", 6, 1),
244 withArrayLength("sint64_repeated", 1, 1),
245 withArrayLength("fixed32_repeated", 0, 1),
246 withArrayLength("sfixed32_repeated", 4, 1),
247 withArrayLength("sfixed64_repeated", 4, 1),
248 withArrayLength("bool_repeated", 4, 1),
249 withArrayLength("enum_repeated", 3, 1),
250
251 withDistinctArrayValues("double_repeated", 3, 1),
252 withDistinctArrayValues("float_repeated", 4, 1),
253 withDistinctArrayValues("int32_repeated", 4, 1),
254 withDistinctArrayValues("int64_repeated", 5, 1),
255 withDistinctArrayValues("uint32_repeated", 1, 1),
256 withDistinctArrayValues("sint32_repeated", 6, 1),
257 withDistinctArrayValues("sint64_repeated", 1, 1),
258 withDistinctArrayValues("fixed32_repeated", 0, 1),
259 withDistinctArrayValues("sfixed32_repeated", 3, 1),
260 withDistinctArrayValues("sfixed64_repeated", 4, 1),
261 withDistinctArrayValues("bool_repeated", 2, 1),
262 withDistinctArrayValues("enum_repeated", 2, 1),
263
264 withFloatArraySum("double_repeated", 6.6, 1),
265 withFloatArraySum("float_repeated", -24.2, 1),
266
267 withIntegerArraySum("int32_repeated", 28, 1),
268 withIntegerArraySum("int64_repeated", 2500, 1),
269 withIntegerArraySum("uint32_repeated", 60727163, 1),
270 withIntegerArraySum("sint32_repeated", 9, 1),
271 withIntegerArraySum("sint64_repeated", 2, 1),
272 withIntegerArraySum("enum_repeated", 7, 1),
273 },
274 },
275 {
276 description: "proto2 packed repeated non-empty",
277 tableSchema: testdata.ValidationRepeatedSchema,
278 inputRow: &testdata.ValidationP2PackedRepeated{
279 Id: proto.Int64(2022),
280 DoubleRepeated: []float64{1.1, 2.2, 3.3},
281 FloatRepeated: []float32{-4.4, -5.5, -6.6, -7.7},
282 Int32Repeated: []int32{2, 4, 6, 6, 10},
283 Int64Repeated: []int64{100, 200, 300, 300, 300, 600, 700},
284 Uint32Repeated: []uint32{8675309, 8675309, 8675309, 8675309, 8675309, 8675309, 8675309},
285 Sint32Repeated: []int32{-1, -2, -3, 4, 5, 6},
286 Sint64Repeated: []int64{2},
287 Fixed32Repeated: []uint32{},
288 Sfixed32Repeated: []int32{-88, 100, -99, -88},
289 Sfixed64Repeated: []int64{88, -100, 99, -2020},
290 BoolRepeated: []bool{true, true, false, true},
291 EnumRepeated: []testdata.Proto2ExampleEnum{testdata.Proto2ExampleEnum_P2_OTHER_THING, testdata.Proto2ExampleEnum_P2_THIRD_THING, testdata.Proto2ExampleEnum_P2_OTHER_THING},
292 },
293 constraints: []constraintOption{
294 withExactRowCount(1),
295
296 withArrayLength("double_repeated", 3, 1),
297 withArrayLength("float_repeated", 4, 1),
298 withArrayLength("int32_repeated", 5, 1),
299 withArrayLength("int64_repeated", 7, 1),
300 withArrayLength("uint32_repeated", 7, 1),
301 withArrayLength("sint32_repeated", 6, 1),
302 withArrayLength("sint64_repeated", 1, 1),
303 withArrayLength("fixed32_repeated", 0, 1),
304 withArrayLength("sfixed32_repeated", 4, 1),
305 withArrayLength("sfixed64_repeated", 4, 1),
306 withArrayLength("bool_repeated", 4, 1),
307 withArrayLength("enum_repeated", 3, 1),
308
309 withDistinctArrayValues("double_repeated", 3, 1),
310 withDistinctArrayValues("float_repeated", 4, 1),
311 withDistinctArrayValues("int32_repeated", 4, 1),
312 withDistinctArrayValues("int64_repeated", 5, 1),
313 withDistinctArrayValues("uint32_repeated", 1, 1),
314 withDistinctArrayValues("sint32_repeated", 6, 1),
315 withDistinctArrayValues("sint64_repeated", 1, 1),
316 withDistinctArrayValues("fixed32_repeated", 0, 1),
317 withDistinctArrayValues("sfixed32_repeated", 3, 1),
318 withDistinctArrayValues("sfixed64_repeated", 4, 1),
319 withDistinctArrayValues("bool_repeated", 2, 1),
320 withDistinctArrayValues("enum_repeated", 2, 1),
321
322 withFloatArraySum("double_repeated", 6.6, 1),
323 withFloatArraySum("float_repeated", -24.2, 1),
324
325 withIntegerArraySum("int32_repeated", 28, 1),
326 withIntegerArraySum("int64_repeated", 2500, 1),
327 withIntegerArraySum("uint32_repeated", 60727163, 1),
328 withIntegerArraySum("sint32_repeated", 9, 1),
329 withIntegerArraySum("sint64_repeated", 2, 1),
330 withIntegerArraySum("enum_repeated", 7, 1),
331 },
332 },
333 {
334 description: "proto3 packed repeated non-empty",
335 tableSchema: testdata.ValidationRepeatedSchema,
336 inputRow: &testdata.ValidationP3PackedRepeated{
337 Id: proto.Int64(2022),
338 DoubleRepeated: []float64{1.1, 2.2, 3.3},
339 FloatRepeated: []float32{-4.4, -5.5, -6.6, -7.7},
340 Int32Repeated: []int32{2, 4, 6, 6, 10},
341 Int64Repeated: []int64{100, 200, 300, 300, 300, 600, 700},
342 Uint32Repeated: []uint32{8675309, 8675309, 8675309, 8675309, 8675309, 8675309, 8675309},
343 Sint32Repeated: []int32{-1, -2, -3, 4, 5, 6},
344 Sint64Repeated: []int64{2},
345 Fixed32Repeated: []uint32{},
346 Sfixed32Repeated: []int32{-88, 100, -99, -88},
347 Sfixed64Repeated: []int64{88, -100, 99, -2020},
348 BoolRepeated: []bool{true, true, false, true},
349 EnumRepeated: []testdata.Proto3ExampleEnum{testdata.Proto3ExampleEnum_P3_OTHER_THING, testdata.Proto3ExampleEnum_P3_THIRD_THING, testdata.Proto3ExampleEnum_P3_OTHER_THING},
350 },
351 constraints: []constraintOption{
352 withExactRowCount(1),
353
354 withArrayLength("double_repeated", 3, 1),
355 withArrayLength("float_repeated", 4, 1),
356 withArrayLength("int32_repeated", 5, 1),
357 withArrayLength("int64_repeated", 7, 1),
358 withArrayLength("uint32_repeated", 7, 1),
359 withArrayLength("sint32_repeated", 6, 1),
360 withArrayLength("sint64_repeated", 1, 1),
361 withArrayLength("fixed32_repeated", 0, 1),
362 withArrayLength("sfixed32_repeated", 4, 1),
363 withArrayLength("sfixed64_repeated", 4, 1),
364 withArrayLength("bool_repeated", 4, 1),
365 withArrayLength("enum_repeated", 3, 1),
366
367 withDistinctArrayValues("double_repeated", 3, 1),
368 withDistinctArrayValues("float_repeated", 4, 1),
369 withDistinctArrayValues("int32_repeated", 4, 1),
370 withDistinctArrayValues("int64_repeated", 5, 1),
371 withDistinctArrayValues("uint32_repeated", 1, 1),
372 withDistinctArrayValues("sint32_repeated", 6, 1),
373 withDistinctArrayValues("sint64_repeated", 1, 1),
374 withDistinctArrayValues("fixed32_repeated", 0, 1),
375 withDistinctArrayValues("sfixed32_repeated", 3, 1),
376 withDistinctArrayValues("sfixed64_repeated", 4, 1),
377 withDistinctArrayValues("bool_repeated", 2, 1),
378 withDistinctArrayValues("enum_repeated", 2, 1),
379
380 withFloatArraySum("double_repeated", 6.6, 1),
381 withFloatArraySum("float_repeated", -24.2, 1),
382
383 withIntegerArraySum("int32_repeated", 28, 1),
384 withIntegerArraySum("int64_repeated", 2500, 1),
385 withIntegerArraySum("uint32_repeated", 60727163, 1),
386 withIntegerArraySum("sint32_repeated", 9, 1),
387 withIntegerArraySum("sint64_repeated", 2, 1),
388 withIntegerArraySum("enum_repeated", 7, 1),
389 },
390 },
391 {
392 description: "proto2 w/column annotations",
393 tableSchema: testdata.ValidationColumnAnnotations,
394 inputRow: &testdata.ValidationP2ColumnAnnotations{
395 First: proto.String("first_val"),
396 Second: proto.String("second_val"),
397 Third: proto.String("third_val"),
398 },
399 constraints: []constraintOption{
400 withExactRowCount(1),
401 withStringValueCount("first", "first_val", 1),
402 withStringValueCount("second", "third_val", 1),
403 withStringValueCount("特別コラム", "second_val", 1),
404 },
405 },
406 }
407
408
409 mwClient, bqClient := getTestClients(context.Background(), t)
410 defer mwClient.Close()
411 defer bqClient.Close()
412
413 dataset, cleanup, err := setupTestDataset(context.Background(), t, bqClient, "us-east4")
414 if err != nil {
415 t.Fatalf("failed to init test dataset: %v", err)
416 }
417 defer cleanup()
418
419 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
420 defer cancel()
421
422 for _, tc := range testcases {
423
424 testTable := dataset.Table(tableIDs.New())
425 if err := testTable.Create(ctx, &bigquery.TableMetadata{Schema: tc.tableSchema}); err != nil {
426 t.Errorf("%s: failed to create test table %q: %v", tc.description, testTable.FullyQualifiedName(), err)
427 continue
428 }
429
430
431 descriptor, err := adapt.NormalizeDescriptor(tc.inputRow.ProtoReflect().Descriptor())
432 if err != nil {
433 t.Errorf("%s: failed to normalize descriptor: %v", tc.description, err)
434 continue
435 }
436
437 ms, err := mwClient.NewManagedStream(ctx,
438 WithDestinationTable(TableParentFromParts(testTable.ProjectID, testTable.DatasetID, testTable.TableID)),
439 WithType(DefaultStream),
440 WithSchemaDescriptor(descriptor),
441 )
442 if err != nil {
443 t.Errorf("%s: NewManagedStream: %v", tc.description, err)
444 continue
445 }
446
447
448 b, err := proto.Marshal(tc.inputRow)
449 if err != nil {
450 t.Errorf("%s failed proto.Marshall(): %v", tc.description, err)
451 continue
452 }
453 data := [][]byte{b}
454 result, err := ms.AppendRows(ctx, data)
455 if err != nil {
456 t.Errorf("%s append failed: %v", tc.description, err)
457 continue
458 }
459 if _, err = result.GetResult(ctx); err != nil {
460 t.Errorf("%s append response error: %v", tc.description, err)
461 continue
462 }
463
464 validateTableConstraints(ctx, t, bqClient, testTable, tc.description, tc.constraints...)
465 }
466 }
467
468 func TestValidationRoundtripRepeated(t *testing.T) {
469
470
471
472
473 input := &testdata.ValidationP3PackedRepeated{
474 Id: proto.Int64(2022),
475 Int64Repeated: []int64{1, 2, 4, -88},
476 }
477 b, err := proto.Marshal(input)
478 if err != nil {
479 t.Fatalf("proto.Marshal: %v", err)
480 }
481
482
483 origDescriptor := input.ProtoReflect().Descriptor()
484 origFD := origDescriptor.Fields().ByName(protoreflect.Name("int64_repeated"))
485 if !origFD.IsPacked() {
486 t.Errorf("expected original field to be packed, wasn't")
487 }
488
489
490 normalized, err := adapt.NormalizeDescriptor(input.ProtoReflect().Descriptor())
491 if err != nil {
492 t.Fatalf("NormalizeDescriptor: %v", err)
493 }
494 fdp := &descriptorpb.FileDescriptorProto{
495 MessageType: []*descriptorpb.DescriptorProto{normalized},
496 Name: proto.String("lookup"),
497 Syntax: proto.String("proto2"),
498 }
499 fds := &descriptorpb.FileDescriptorSet{
500 File: []*descriptorpb.FileDescriptorProto{fdp},
501 }
502 files, err := protodesc.NewFiles(fds)
503 if err != nil {
504 t.Fatalf("protodesc.NewFiles: %v", err)
505 }
506 found, err := files.FindDescriptorByName("testdata_ValidationP3PackedRepeated")
507 if err != nil {
508 t.Fatalf("FindDescriptorByName: %v", err)
509 }
510 md := found.(protoreflect.MessageDescriptor)
511
512
513 msg := dynamicpb.NewMessage(md)
514 if err := proto.Unmarshal(b, msg); err != nil {
515 t.Fatalf("Unmarshal: %v", err)
516 }
517
518
519 int64FD := msg.Descriptor().Fields().ByName(protoreflect.Name("int64_repeated"))
520 if int64FD == nil {
521 t.Fatalf("failed to get field")
522 }
523 if int64FD.IsPacked() {
524 t.Errorf("expected normalized descriptor to be un-packed, but it was packed")
525 }
526
527 list := msg.Get(int64FD).List()
528 wantLen := 4
529 if list.Len() != wantLen {
530 t.Errorf("wanted %d values, got %d", wantLen, list.Len())
531 }
532
533 wantVals := []int64{1, 2, 4, -88}
534 for i := 0; i < list.Len(); i++ {
535 got := list.Get(i).Int()
536 if got != wantVals[i] {
537 t.Errorf("expected elem %d to be %d, was %d", i, wantVals[i], got)
538 }
539 }
540 }
541
View as plain text