...

Source file src/cloud.google.com/go/bigquery/storage/managedwriter/validation_test.go

Documentation: cloud.google.com/go/bigquery/storage/managedwriter

     1  // Copyright 2021 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     https://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    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  		/*
   182  			BACKEND BEHAVIOR FOR WRAPPER TYPES CURRENTLY INCORRECT
   183  			{
   184  				description: "proto3 with wrapper types",
   185  				tableSchema: testdata.ValidationBaseSchema,
   186  				inputRow: &testdata.ValidationP3Wrappers{
   187  					DoubleField: &wrapperspb.DoubleValue{Value: 1.0},
   188  				},
   189  				constraints: []constraintOption{
   190  					withExactRowCount(1),
   191  					withFloatValueCount("double_field", 0, 1),
   192  				},
   193  			},
   194  		*/
   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  	// Common setup.
   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  		// Define a test table for each row.
   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  		// normalize the proto schema based on the provided message.
   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  		// setup a new stream.
   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  		// serialize message to wire format and send append.
   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  		// Validate table.
   464  		validateTableConstraints(ctx, t, bqClient, testTable, tc.description, tc.constraints...)
   465  	}
   466  }
   467  
   468  func TestValidationRoundtripRepeated(t *testing.T) {
   469  	// This test exists to confirm packed values are backwards compatible.
   470  	// We create a message using a packed descriptor, and normalize it which
   471  	// loses the packed option, and confirm we can decode the values using the
   472  	// normalized descriptor.
   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  	// Verify original packed option (proto3 is default packed)
   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  	// Normalize and use it to get a new descriptor.
   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  	// Use the new, normalized descriptor to unmarshal the bytes and verify.
   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")) // int64_repeated again
   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  	// Ensure we got the expected values out the other side.
   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  	// Confirm the same values out the other side.
   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