diff --git a/.kokoro/coerce_logs.sh b/.kokoro/coerce_logs.sh new file mode 100644 index 000000000..883ee0faa --- /dev/null +++ b/.kokoro/coerce_logs.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# 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. + +# This script finds and moves sponge logs so that they can be found by placer +# and are not flagged as flaky by sponge. + +set -eo pipefail + +## Get the directory of the build script +scriptDir=$(realpath $(dirname "${BASH_SOURCE[0]}")) +## cd to the parent directory, i.e. the root of the git repo +cd ${scriptDir}/.. + +job=$(basename ${KOKORO_JOB_NAME}) + +echo "coercing sponge logs..." +for xml in `find . -name *-sponge_log.xml` +do + class=$(basename ${xml} | cut -d- -f2) + dir=$(dirname ${xml})/${job}/${class} + text=$(dirname ${xml})/${class}-sponge_log.txt + mkdir -p ${dir} + mv ${xml} ${dir}/sponge_log.xml + mv ${text} ${dir}/sponge_log.txt +done \ No newline at end of file diff --git a/.kokoro/conformance.sh b/.kokoro/conformance.sh index 777cc4aef..6763daa45 100755 --- a/.kokoro/conformance.sh +++ b/.kokoro/conformance.sh @@ -41,5 +41,8 @@ cd cloud-bigtable-clients-test/tests eval "go test -v -proxy_addr=:9999" RETURN_CODE=$? +# fix output location of logs +bash .kokoro/coerce_logs.sh + echo "exiting with ${RETURN_CODE}" exit ${RETURN_CODE} \ No newline at end of file diff --git a/src/mutation.ts b/src/mutation.ts index 0aef34202..456528c57 100644 --- a/src/mutation.ts +++ b/src/mutation.ts @@ -25,6 +25,24 @@ export type ISetCell = btTypes.bigtable.v2.Mutation.ISetCell; export type Bytes = string | Buffer; // eslint-disable-next-line @typescript-eslint/no-explicit-any export type Data = any; +/* +The Data type is expected to be in the following format: +{ + columnFamily1: { + column1: Cell, + column2: Cell + }, + columnFamily2: { + otherColumn1: Cell, + otherColumn2: Cell + } +} +Where the Cell data type has the following structure: +Uint8Array | string | { + value: Uint8Array|string, + timestamp: number|Long|string, +} +*/ export interface JsonObj { [k: string]: string | JsonObj; } diff --git a/src/table.ts b/src/table.ts index e7c286c0f..a1bf7f886 100644 --- a/src/table.ts +++ b/src/table.ts @@ -287,6 +287,14 @@ export interface MutateOptions { // eslint-disable-next-line @typescript-eslint/no-explicit-any export type Entry = any; +/* +The Entry type is expected to be in the following format: +{ + key?: Uint8Array|string, + data?: Data, // The Data type is described in the Mutation class. + method?: typeof mutation.methods +} +*/ export type DeleteTableCallback = ( err: ServiceError | null, diff --git a/system-test/bigtable.ts b/system-test/bigtable.ts index 10e70e6bc..225426847 100644 --- a/system-test/bigtable.ts +++ b/system-test/bigtable.ts @@ -33,6 +33,7 @@ import {Row} from '../src/row.js'; import {Table} from '../src/table.js'; import {RawFilter} from '../src/filter'; import {generateId, PREFIX} from './common'; +import {Mutation} from '../src/mutation'; describe('Bigtable', () => { const bigtable = new Bigtable(); @@ -1712,6 +1713,90 @@ describe('Bigtable', () => { }); }); }); + + describe('mutateRows entries tests', () => { + const table = INSTANCE.table(generateId('table')); + + afterEach(async () => { + await table.delete(); + }); + + it('should only insert one row in the table with mutate', async () => { + // Create table + const tableOptions = { + families: ['columnFamily'], + }; + await table.create(tableOptions); + // Add entries + const entry = { + columnFamily: { + column: 1, + }, + }; + const mutation = { + key: 'rowKey', + data: entry, + method: Mutation.methods.INSERT, + }; + const gaxOptions = {maxRetries: 4}; + await table.mutate(mutation, {gaxOptions}); + // Get rows and compare + const [rows] = await table.getRows(); + assert.strictEqual(rows.length, 1); + }); + + it('should insert one row in the table using mutate in a similar way to how the documentation says to use insert', async () => { + // Create table + const tableOptions = { + families: ['columnFamily'], + }; + await table.create(tableOptions); + // Add entries + const mutation = { + key: 'rowKey', + data: { + columnFamily: { + column: 1, + }, + }, + method: Mutation.methods.INSERT, + }; + const gaxOptions = {maxRetries: 4}; + await table.mutate(mutation, {gaxOptions}); + // Get rows and compare + const [rows] = await table.getRows(); + assert.strictEqual(rows.length, 1); + }); + + it('should only insert one row in the table with insert as described by the GCP documentation', async () => { + // Create table + const tableOptions = { + families: ['follows'], + }; + await table.create(tableOptions); + // Add entries + const greetings = ['Hello World!', 'Hello Bigtable!', 'Hello Node!']; + const rowsToInsert = greetings.map((greeting, index) => ({ + key: `greeting${index}`, + data: { + follows: { + // 'follows' is the column family + someColumn: { + // Setting the timestamp allows the client to perform retries. If + // server-side time is used, retries may cause multiple cells to + // be generated. + timestamp: new Date(), + value: greeting, + }, + }, + }, + })); + await table.insert(rowsToInsert); + // Get rows and compare + const [rows] = await table.getRows(); + assert.strictEqual(rows.length, 3); + }); + }); }); function createInstanceConfig( diff --git a/testproxy/known_failures.txt b/testproxy/known_failures.txt new file mode 100644 index 000000000..cce1bd7fa --- /dev/null +++ b/testproxy/known_failures.txt @@ -0,0 +1 @@ +TestMutateRow_Generic_Headers\|TestMutateRow_Generic_DeadlineExceeded|TestMutateRows_Generic_CloseClient\|TestMutateRows_Retry_WithRoutingCookie\|TestReadModifyWriteRow_Generic_Headers\|TestReadModifyWriteRow_NoRetry_TransientError\|TestReadModifyWriteRow_Generic_DeadlineExceeded\|TestReadRow_Generic_DeadlineExceeded\|TestReadRow_Retry_WithRoutingCookie\|TestReadRow_Retry_WithRetryInfo\|TestReadRows_ReverseScans_FeatureFlag_Enabled\|TestReadRows_NoRetry_OutOfOrderError_Reverse\|TestReadRows_Retry_PausedScan\|TestReadRows_Retry_LastScannedRow\|TestReadRows_Retry_LastScannedRow_Reverse\|TestCheckAndMutateRow_NoRetry_TransientError\|TestCheckAndMutateRow_Generic_DeadlineExceeded \ No newline at end of file