1616
1717package com .google .cloud .bigquery .storage .v1 .it ;
1818
19+ import static com .google .cloud .bigquery .storage .v1 .it .util .Helper .EXPECTED_TIMESTAMPS_HIGHER_PRECISION_ISO_OUTPUT ;
1920import static com .google .cloud .bigquery .storage .v1 .it .util .Helper .TIMESTAMP_COLUMN_NAME ;
2021import static com .google .cloud .bigquery .storage .v1 .it .util .Helper .TIMESTAMP_HIGHER_PRECISION_COLUMN_NAME ;
2122import static com .google .common .truth .Truth .assertThat ;
@@ -131,8 +132,9 @@ public class ITBigQueryStorageWriteClientTest {
131132 {165846896123456L /* 1975-04-04T12:34:56.123456Z */ , 165846896123456789L }
132133 };
133134
134- // Arrow's higher precision column is padded with extra 0's.
135- public static final Object [][] EXPECTED_ARROW_WRITE_TIMESTAMPS =
135+ // Arrow's higher precision column is padded with extra 0's if configured to return
136+ // ISO as output for any picosecond enabled column.
137+ public static final Object [][] EXPECTED_ARROW_WRITE_TIMESTAMPS_ISO_OUTPUT =
136138 new Object [][] {
137139 {1735734896123456L /* 2025-01-01T12:34:56.123456Z */ , "2025-01-01T12:34:56.123456789000Z" },
138140 {1580646896123456L /* 2020-02-02T12:34:56.123456Z */ , "2020-02-02T12:34:56.123456789000Z" },
@@ -2296,25 +2298,18 @@ public void testLargeRequest() throws IOException, InterruptedException, Executi
22962298 }
22972299 }
22982300
2301+ // Tests that inputs for micro and picos are able to use Arrow to write
2302+ // to BQ
22992303 @ Test
23002304 public void timestamp_arrowWrite () throws IOException {
2301- com .google .cloud .bigquery .Schema bigqueryTableSchema =
2302- com .google .cloud .bigquery .Schema .of (
2303- Field .newBuilder (TIMESTAMP_COLUMN_NAME , StandardSQLTypeName .TIMESTAMP )
2304- .setMode (Mode .NULLABLE )
2305- .build (),
2306- Field .newBuilder (TIMESTAMP_HIGHER_PRECISION_COLUMN_NAME , StandardSQLTypeName .TIMESTAMP )
2307- .setMode (Mode .NULLABLE )
2308- .setTimestampPrecision (12L )
2309- .build ());
2310-
23112305 String tableName = "bqstorage_timestamp_write_arrow" ;
2312- TableId testTableId = TableId . of ( DATASET , tableName );
2313- bigquery . create (
2314- TableInfo . of (
2315- testTableId ,
2316- StandardTableDefinition . newBuilder (). setSchema ( bigqueryTableSchema ). build ()) );
2306+ // Opt to create a new table to write to instead of re-using table to prevent
2307+ // the test from failing due to any issues with deleting data after test.
2308+ // Increases the test time duration, but would be more resilient to transient
2309+ // failures
2310+ createTimestampTable ( tableName );
23172311
2312+ // Define the fields as Arrow types that are compatible with BQ Schema types
23182313 List <org .apache .arrow .vector .types .pojo .Field > fields =
23192314 ImmutableList .of (
23202315 new org .apache .arrow .vector .types .pojo .Field (
@@ -2332,7 +2327,7 @@ public void timestamp_arrowWrite() throws IOException {
23322327 org .apache .arrow .vector .types .pojo .Schema arrowSchema =
23332328 new org .apache .arrow .vector .types .pojo .Schema (fields , null );
23342329
2335- int numRows = Helper . INPUT_TIMESTAMPS .length ;
2330+ int numRows = INPUT_ARROW_WRITE_TIMESTAMPS .length ;
23362331 TableName parent = TableName .of (ServiceOptions .getDefaultProjectId (), DATASET , tableName );
23372332 try (StreamWriter streamWriter =
23382333 StreamWriter .newBuilder (parent .toString () + "/_default" )
@@ -2365,44 +2360,23 @@ public void timestamp_arrowWrite() throws IOException {
23652360 future , new Helper .AppendCompleteCallback (), MoreExecutors .directExecutor ());
23662361 }
23672362 }
2368- String table =
2369- BigQueryResource .formatTableResource (
2370- ServiceOptions .getDefaultProjectId (), DATASET , tableName );
2371- List <GenericData .Record > rows = Helper .readAllRows (readClient , parentProjectId , table , null );
2372- List <Long > timestamps =
2373- rows .stream ().map (x -> (Long ) x .get (TIMESTAMP_COLUMN_NAME )).collect (Collectors .toList ());
2374- List <String > timestampHigherPrecision =
2375- rows .stream ()
2376- .map (x -> x .get (TIMESTAMP_HIGHER_PRECISION_COLUMN_NAME ).toString ())
2377- .collect (Collectors .toList ());
2378- assertEquals (timestamps .size (), Helper .EXPECTED_TIMESTAMPS_ISO_HIGHER_PRECISION .length );
2379- assertEquals (
2380- timestampHigherPrecision .size (), Helper .EXPECTED_TIMESTAMPS_ISO_HIGHER_PRECISION .length );
2381- for (int i = 0 ; i < timestampHigherPrecision .size (); i ++) {
2382- assertEquals (timestamps .get (i ), Helper .EXPECTED_TIMESTAMPS_ISO_HIGHER_PRECISION [i ][0 ]);
2383- assertEquals (timestampHigherPrecision .get (i ), EXPECTED_ARROW_WRITE_TIMESTAMPS [i ][1 ]);
2384- }
2363+ assertTimestamps (tableName , EXPECTED_ARROW_WRITE_TIMESTAMPS_ISO_OUTPUT );
23852364 }
23862365
2366+ // Tests that inputs for micro and picos are able to converted to protobuf
2367+ // and written to BQ
23872368 @ Test
23882369 public void timestamp_protobufWrite ()
23892370 throws IOException , DescriptorValidationException , InterruptedException {
2390- com .google .cloud .bigquery .Schema bqTableSchema =
2391- com .google .cloud .bigquery .Schema .of (
2392- Field .newBuilder (TIMESTAMP_COLUMN_NAME , StandardSQLTypeName .TIMESTAMP )
2393- .setMode (Mode .NULLABLE )
2394- .build (),
2395- Field .newBuilder (TIMESTAMP_HIGHER_PRECISION_COLUMN_NAME , StandardSQLTypeName .TIMESTAMP )
2396- .setMode (Mode .NULLABLE )
2397- .setTimestampPrecision (12L )
2398- .build ());
2399-
24002371 String tableName = "bqstorage_timestamp_write_protobuf" ;
2401- TableId testTableId = TableId .of (DATASET , tableName );
2402- bigquery .create (
2403- TableInfo .of (
2404- testTableId , StandardTableDefinition .newBuilder ().setSchema (bqTableSchema ).build ()));
2405-
2372+ // Opt to create a new table to write to instead of re-using table to prevent
2373+ // the test from failing due to any issues with deleting data after test.
2374+ // Increases the test time duration, but would be more resilient to transient
2375+ // failures
2376+ createTimestampTable (tableName );
2377+
2378+ // Define the table schema so that the automatic converter is able to
2379+ // determine how to convert from Json -> Protobuf
24062380 TableFieldSchema testTimestamp =
24072381 TableFieldSchema .newBuilder ()
24082382 .setName (TIMESTAMP_COLUMN_NAME )
@@ -2436,24 +2410,48 @@ public void timestamp_protobufWrite()
24362410 ApiFutures .addCallback (
24372411 future , new Helper .AppendCompleteCallback (), MoreExecutors .directExecutor ());
24382412 }
2413+ assertTimestamps (tableName , EXPECTED_TIMESTAMPS_HIGHER_PRECISION_ISO_OUTPUT );
2414+ }
24392415
2416+ private void createTimestampTable (String tableName ) {
2417+ Schema bqTableSchema =
2418+ Schema .of (
2419+ Field .newBuilder (TIMESTAMP_COLUMN_NAME , StandardSQLTypeName .TIMESTAMP )
2420+ .setMode (Mode .NULLABLE )
2421+ .build (),
2422+ Field .newBuilder (TIMESTAMP_HIGHER_PRECISION_COLUMN_NAME , StandardSQLTypeName .TIMESTAMP )
2423+ .setMode (Mode .NULLABLE )
2424+ .setTimestampPrecision (12L )
2425+ .build ());
2426+
2427+ TableId testTableId = TableId .of (DATASET , tableName );
2428+ bigquery .create (
2429+ TableInfo .of (
2430+ testTableId , StandardTableDefinition .newBuilder ().setSchema (bqTableSchema ).build ()));
2431+ }
2432+
2433+ private void assertTimestamps (String tableName , Object [][] expected ) throws IOException {
24402434 String table =
24412435 BigQueryResource .formatTableResource (
24422436 ServiceOptions .getDefaultProjectId (), DATASET , tableName );
2437+
2438+ // Read all the data as Avro GenericRecords
24432439 List <GenericData .Record > rows = Helper .readAllRows (readClient , parentProjectId , table , null );
2440+
2441+ // Each timestamp response is expected to contain two fields:
2442+ // 1. Micros from timestamp as a Long and 2. ISO8601 instant with picos precision
24442443 List <Long > timestamps =
24452444 rows .stream ().map (x -> (Long ) x .get (TIMESTAMP_COLUMN_NAME )).collect (Collectors .toList ());
24462445 List <String > timestampHigherPrecision =
24472446 rows .stream ()
24482447 .map (x -> x .get (TIMESTAMP_HIGHER_PRECISION_COLUMN_NAME ).toString ())
24492448 .collect (Collectors .toList ());
2450- assertEquals (timestamps .size (), Helper .EXPECTED_TIMESTAMPS_ISO_HIGHER_PRECISION .length );
2451- assertEquals (
2452- timestampHigherPrecision .size (), Helper .EXPECTED_TIMESTAMPS_ISO_HIGHER_PRECISION .length );
2453- for (int i = 0 ; i < timestamps .size (); i ++) {
2454- assertEquals (timestamps .get (i ), Helper .EXPECTED_TIMESTAMPS_ISO_HIGHER_PRECISION [i ][0 ]);
2455- assertEquals (
2456- timestampHigherPrecision .get (i ), Helper .EXPECTED_TIMESTAMPS_ISO_HIGHER_PRECISION [i ][1 ]);
2449+
2450+ assertEquals (timestamps .size (), expected .length );
2451+ assertEquals (timestampHigherPrecision .size (), expected .length );
2452+ for (int i = 0 ; i < timestampHigherPrecision .size (); i ++) {
2453+ assertEquals (timestamps .get (i ), expected [i ][0 ]);
2454+ assertEquals (timestampHigherPrecision .get (i ), expected [i ][1 ]);
24572455 }
24582456 }
24592457}
0 commit comments