@@ -26,10 +26,12 @@ import (
26
26
"cloud.google.com/go/internal/testutil"
27
27
"cloud.google.com/go/internal/uid"
28
28
"google.golang.org/api/option"
29
+ "google.golang.org/protobuf/encoding/protojson"
29
30
"google.golang.org/protobuf/proto"
30
31
"google.golang.org/protobuf/reflect/protodesc"
31
32
"google.golang.org/protobuf/reflect/protoreflect"
32
33
"google.golang.org/protobuf/types/descriptorpb"
34
+ "google.golang.org/protobuf/types/dynamicpb"
33
35
)
34
36
35
37
var (
@@ -120,7 +122,7 @@ func setupDynamicDescriptors(t *testing.T, schema bigquery.Schema) (protoreflect
120
122
return messageDescriptor , protodesc .ToDescriptorProto (messageDescriptor )
121
123
}
122
124
123
- func TestIntegration_ManagedWriter_BasicOperation (t * testing.T ) {
125
+ func TestIntegration_ManagedWriter_DefaultStream (t * testing.T ) {
124
126
mwClient , bqClient := getTestClients (context .Background (), t )
125
127
defer mwClient .Close ()
126
128
defer bqClient .Close ()
@@ -205,3 +207,162 @@ func TestIntegration_ManagedWriter_BasicOperation(t *testing.T) {
205
207
wantRows = wantRows * 2
206
208
validateRowCount (ctx , t , bqClient , testTable , wantRows )
207
209
}
210
+
211
+ func TestIntegration_ManagedWriter_DynamicJSON (t * testing.T ) {
212
+ mwClient , bqClient := getTestClients (context .Background (), t )
213
+ defer mwClient .Close ()
214
+ defer bqClient .Close ()
215
+
216
+ dataset , cleanup , err := setupTestDataset (context .Background (), t , bqClient )
217
+ if err != nil {
218
+ t .Fatalf ("failed to init test dataset: %v" , err )
219
+ }
220
+ defer cleanup ()
221
+
222
+ ctx , cancel := context .WithTimeout (context .Background (), defaultTestTimeout )
223
+ defer cancel ()
224
+
225
+ // prep a suitable destination table.
226
+ testTable := dataset .Table (tableIDs .New ())
227
+ schema := bigquery.Schema {
228
+ {Name : "name" , Type : bigquery .StringFieldType , Required : true },
229
+ {Name : "value" , Type : bigquery .IntegerFieldType , Required : true },
230
+ }
231
+ if err := testTable .Create (ctx , & bigquery.TableMetadata {Schema : schema }); err != nil {
232
+ t .Fatalf ("failed to create test table %s: %v" , testTable .FullyQualifiedName (), err )
233
+ }
234
+
235
+ md , descriptorProto := setupDynamicDescriptors (t , schema )
236
+
237
+ // setup a new stream.
238
+ ms , err := mwClient .NewManagedStream (ctx ,
239
+ WithDestinationTable (fmt .Sprintf ("projects/%s/datasets/%s/tables/%s" , testTable .ProjectID , testTable .DatasetID , testTable .TableID )),
240
+ WithType (DefaultStream ),
241
+ WithSchemaDescriptor (descriptorProto ),
242
+ )
243
+ if err != nil {
244
+ t .Fatalf ("NewManagedStream: %v" , err )
245
+ }
246
+
247
+ sampleData := [][]byte {
248
+ []byte (`{"name": "one", "value": 1}` ),
249
+ []byte (`{"name": "two", "value": 2}` ),
250
+ []byte (`{"name": "three", "value": 3}` ),
251
+ []byte (`{"name": "four", "value": 4}` ),
252
+ []byte (`{"name": "five", "value": 5}` ),
253
+ }
254
+
255
+ // prevalidate we have no data in table.
256
+ validateRowCount (ctx , t , bqClient , testTable , 0 )
257
+
258
+ // First, append rows individually.
259
+ var results []* AppendResult
260
+ for k , v := range sampleData {
261
+ message := dynamicpb .NewMessage (md )
262
+
263
+ // First, json->proto message
264
+ err = protojson .Unmarshal (v , message )
265
+ if err != nil {
266
+ t .Fatalf ("failed to Unmarshal json message for row %d: %v" , k , err )
267
+ }
268
+ // Then, proto message -> bytes.
269
+ b , err := proto .Marshal (message )
270
+ if err != nil {
271
+ t .Fatalf ("failed to marshal proto bytes for row %d: %v" , k , err )
272
+ }
273
+ results , err = ms .AppendRows (ctx , [][]byte {b }, NoStreamOffset )
274
+ if err != nil {
275
+ t .Errorf ("single-row append %d failed: %v" , k , err )
276
+ }
277
+ }
278
+
279
+ // wait for the result to indicate ready, then validate.
280
+ results [0 ].Ready ()
281
+ wantRows := int64 (len (sampleData ))
282
+ validateRowCount (ctx , t , bqClient , testTable , wantRows )
283
+ }
284
+
285
+ func TestIntegration_ManagedWriter_BufferedStream (t * testing.T ) {
286
+ mwClient , bqClient := getTestClients (context .Background (), t )
287
+ defer mwClient .Close ()
288
+ defer bqClient .Close ()
289
+
290
+ dataset , cleanup , err := setupTestDataset (context .Background (), t , bqClient )
291
+ if err != nil {
292
+ t .Fatalf ("failed to init test dataset: %v" , err )
293
+ }
294
+ defer cleanup ()
295
+
296
+ ctx , cancel := context .WithTimeout (context .Background (), defaultTestTimeout )
297
+ defer cancel ()
298
+
299
+ // prep a suitable destination table.
300
+ testTable := dataset .Table (tableIDs .New ())
301
+ schema := bigquery.Schema {
302
+ {Name : "name" , Type : bigquery .StringFieldType , Required : true },
303
+ {Name : "value" , Type : bigquery .IntegerFieldType , Required : true },
304
+ }
305
+ if err := testTable .Create (ctx , & bigquery.TableMetadata {Schema : schema }); err != nil {
306
+ t .Fatalf ("failed to create test table %s: %v" , testTable .FullyQualifiedName (), err )
307
+ }
308
+ // We'll use a precompiled test proto, but we need it's corresponding descriptorproto representation
309
+ // to send as the stream's schema.
310
+ m := & testdata.SimpleMessage {}
311
+ descriptorProto := protodesc .ToDescriptorProto (m .ProtoReflect ().Descriptor ())
312
+
313
+ // setup a new stream.
314
+ ms , err := mwClient .NewManagedStream (ctx ,
315
+ WithDestinationTable (fmt .Sprintf ("projects/%s/datasets/%s/tables/%s" , testTable .ProjectID , testTable .DatasetID , testTable .TableID )),
316
+ WithType (BufferedStream ),
317
+ WithSchemaDescriptor (descriptorProto ),
318
+ )
319
+ if err != nil {
320
+ t .Fatalf ("NewManagedStream: %v" , err )
321
+ }
322
+
323
+ info , err := ms .c .getWriteStream (ctx , ms .streamSettings .streamID )
324
+ if err != nil {
325
+ t .Errorf ("couldn't get stream info: %v" , err )
326
+ }
327
+ if info .GetType ().String () != string (ms .StreamType ()) {
328
+ t .Errorf ("mismatch on stream type, got %s want %s" , info .GetType (), ms .StreamType ())
329
+ }
330
+
331
+ // prevalidate we have no data in table.
332
+ validateRowCount (ctx , t , bqClient , testTable , 0 )
333
+
334
+ testData := []* testdata.SimpleMessage {
335
+ {Name : "one" , Value : 1 },
336
+ {Name : "two" , Value : 2 },
337
+ {Name : "three" , Value : 3 },
338
+ {Name : "four" , Value : 1 },
339
+ {Name : "five" , Value : 2 },
340
+ }
341
+
342
+ // First, send the test rows individually, validate, then advance.
343
+ var expectedRows int64
344
+ for k , mesg := range testData {
345
+ b , err := proto .Marshal (mesg )
346
+ if err != nil {
347
+ t .Errorf ("failed to marshal message %d: %v" , k , err )
348
+ }
349
+ data := [][]byte {b }
350
+ results , err := ms .AppendRows (ctx , data , NoStreamOffset )
351
+ if err != nil {
352
+ t .Errorf ("single-row append %d failed: %v" , k , err )
353
+ }
354
+ // wait for ack
355
+ offset , err := results [0 ].GetResult (ctx )
356
+ if err != nil {
357
+ t .Errorf ("got error from pending result %d: %v" , k , err )
358
+ }
359
+ validateRowCount (ctx , t , bqClient , testTable , expectedRows )
360
+ // move offset and re-validate.
361
+ flushOffset , err := ms .FlushRows (ctx , offset )
362
+ if err != nil {
363
+ t .Errorf ("failed to flush offset to %d: %v" , offset , err )
364
+ }
365
+ expectedRows = flushOffset + 1
366
+ validateRowCount (ctx , t , bqClient , testTable , expectedRows )
367
+ }
368
+ }
0 commit comments