From 684225600e202d28f98979766e4890c7e2d9bd6f Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 28 Jan 2026 22:44:29 +0000 Subject: [PATCH] feat: add parameterized system tests for high-precision query options This commit adds a new system test file `system-test/high-precision-query-tests.ts` which covers all 15 combinations of `timestampOutputFormat` and `useInt64Timestamp` options for the `bigquery.query` method. The tests verify API validation logic and result parsing, handling environment-specific constraints such as missing credentials by appropriately skipping tests. The options are passed using flattened keys (e.g., 'formatOptions.timestampOutputFormat') to match the library's current implementation and expected query parameters. Co-authored-by: danieljbruce <8935272+danieljbruce@users.noreply.github.com> --- system-test/high-precision-query-tests.ts | 112 ++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 system-test/high-precision-query-tests.ts diff --git a/system-test/high-precision-query-tests.ts b/system-test/high-precision-query-tests.ts new file mode 100644 index 00000000..c260a592 --- /dev/null +++ b/system-test/high-precision-query-tests.ts @@ -0,0 +1,112 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import * as assert from 'assert'; +import {describe, it, before} from 'mocha'; +import {BigQuery} from '../src'; + +describe('High Precision Query System Tests', () => { + let bigquery: BigQuery; + + before(function () { + bigquery = new BigQuery(); + }); + + const timestampOutputFormats = [ + undefined, + 'TIMESTAMP_OUTPUT_FORMAT_UNSPECIFIED', + 'FLOAT64', + 'INT64', + 'ISO8601_STRING', + ]; + + const useInt64Timestamps = [undefined, true, false]; + + timestampOutputFormats.forEach(TOF => { + useInt64Timestamps.forEach(UI64 => { + const testName = `TOF: ${TOF ?? 'omitted'}, UI64: ${UI64 ?? 'omitted'}`; + + // Logic to determine expected success based on BigQuery API validation: + // - FLOAT64 and ISO8601_STRING require useInt64Timestamp to be false. + // - INT64 requires useInt64Timestamp to be true (or omitted). + // - Default useInt64Timestamp is true. + let expectedSuccess = true; + const actualUI64 = UI64 ?? true; + + if (TOF === 'FLOAT64' || TOF === 'ISO8601_STRING') { + if (actualUI64 === true) { + expectedSuccess = false; + } + } else if (TOF === 'INT64') { + if (actualUI64 === false) { + expectedSuccess = false; + } + } + + it(`should handle ${testName}`, async function () { + // Use a parameter to avoid potential library bugs with simple query strings + // and to ensure we are testing the high-precision path. + const query = { + query: 'SELECT ? as ts', + params: [bigquery.timestamp('2024-07-15 10:00:00.123456789123')], + }; + + // The library currently expects flattened keys for formatOptions in bigquery.query + // to match the underlying API's query parameter names. + const options: any = {}; + if (TOF !== undefined) { + options['formatOptions.timestampOutputFormat'] = TOF; + } + if (UI64 !== undefined) { + options['formatOptions.useInt64Timestamp'] = UI64; + } + + try { + const [rows] = await bigquery.query(query, options); + if (!expectedSuccess) { + assert.fail( + `Query should have failed for ${testName}, but succeeded` + ); + } + assert.ok(rows.length > 0); + assert.ok(rows[0].ts); + } catch (err: any) { + // Check for authentication or environment errors + const isAuthError = + err.message.includes('unauthenticated') || + err.message.includes('permission denied') || + err.message.includes('Could not load the default credentials') || + err.message.includes('Unable to detect a Project Id'); + + if (isAuthError) { + this.skip(); + } + + if (expectedSuccess) { + throw err; + } + + // If expected to fail, it should be a validation error (e.g., 400 Bad Request) + const statusCode = + err.code || (err.response && err.response.statusCode); + assert.strictEqual( + statusCode, + 400, + `Expected 400 error for ${testName}, got ${statusCode} (${err.message})` + ); + } + }); + }); + }); +});