From b92296225a481634cf04751857db8d1a391fbfdb Mon Sep 17 00:00:00 2001 From: wu-hui Date: Thu, 28 May 2026 10:28:44 -0400 Subject: [PATCH] test(firestore): update integration tests to use enterprise database --- .../firestore/dev/system-test/pipeline.ts | 85 +++++++++++-------- .../firestore/dev/test/util/helpers.ts | 40 +++++---- handwritten/firestore/package.json | 8 +- 3 files changed, 76 insertions(+), 57 deletions(-) diff --git a/handwritten/firestore/dev/system-test/pipeline.ts b/handwritten/firestore/dev/system-test/pipeline.ts index caebfc2ccbba..741f071b2f7a 100644 --- a/handwritten/firestore/dev/system-test/pipeline.ts +++ b/handwritten/firestore/dev/system-test/pipeline.ts @@ -180,7 +180,7 @@ import * as chaiAsPromised from 'chai-as-promised'; import {afterEach, describe, it} from 'mocha'; import '../test/util/mocha_extensions'; -import {verifyInstance} from '../test/util/helpers'; +import {verifyInstance, isRest} from '../test/util/helpers'; import {getTestDb, getTestRoot} from './firestore'; import {Firestore as InternalFirestore} from '../src'; @@ -395,9 +395,9 @@ describe.skipClassic('Pipeline class', () => { expectResults(deleteRes, {documents_modified: 1}); }); - await promise; - const docSnap = await dmlCol.doc('book2').get(); - expect(docSnap.exists).to.be.false; + await expect(promise).to.be.rejectedWith( + /Transactional DML operations are not yet supported/, + ); }); it('can execute update stage with addFields', async () => { @@ -616,7 +616,10 @@ describe.skipClassic('Pipeline class', () => { }); describe('pipeline explain', () => { - it('mode: analyze, format: text', async () => { + it('mode: analyze, format: text', async function () { + if (isRest(firestore)) { + this.skip(); + } const ppl = firestore .pipeline() .collection(randomCol.path) @@ -656,7 +659,10 @@ describe.skipClassic('Pipeline class', () => { ); }); - it('mode: analyze, format: unspecified', async () => { + it('mode: analyze, format: unspecified', async function () { + if (isRest(firestore)) { + this.skip(); + } const ppl = firestore .pipeline() .collection(randomCol.path) @@ -1862,15 +1868,18 @@ describe.skipClassic('Pipeline class', () => { } catch (e: unknown) { expect(e instanceof Error).to.be.true; const err = e as ServiceError; - expect(err['code']).to.equal(3); + const isRestTest = isRest(firestore); + const expectedCode = isRestTest ? 400 : 3; + expect(err['code']).to.equal(expectedCode); expect(typeof err['message']).to.equal('string'); - expect(typeof err['details']).to.equal('string'); + if (!isRestTest) { + expect(typeof err['details']).to.equal('string'); + expect(err['message']).to.equal( + `${err.code} INVALID_ARGUMENT: ${err.details}`, + ); + expect(err['metadata'] instanceof Object).to.be.true; + } expect(typeof err['stack']).to.equal('string'); - expect(err['metadata'] instanceof Object).to.be.true; - - expect(err['message']).to.equal( - `${err.code} INVALID_ARGUMENT: ${err.details}`, - ); } }); @@ -1894,29 +1903,32 @@ describe.skipClassic('Pipeline class', () => { const err = e as {[k: string]: unknown}; expect(err instanceof Error).to.be.true; - expect(err['code']).to.equal(8); + const isRestTest = isRest(firestore); + const expectedCode = isRestTest ? 429 : 8; + expect(err['code']).to.equal(expectedCode); expect(typeof err['message']).to.equal('string'); - expect(typeof err['details']).to.equal('string'); - expect(typeof err['stack']).to.equal('string'); - expect(err['metadata'] instanceof Object).to.be.true; - - expect(err['message']).to.equal( - `${err.code} RESOURCE_EXHAUSTED: ${err.details}`, - ); + if (!isRestTest) { + expect(typeof err['details']).to.equal('string'); + expect(err['message']).to.equal( + `${err.code} RESOURCE_EXHAUSTED: ${err.details}`, + ); - expect('statusDetails' in err).to.be.true; - expect(Array.isArray(err['statusDetails'])).to.be.true; + expect('statusDetails' in err).to.be.true; + expect(Array.isArray(err['statusDetails'])).to.be.true; - const statusDetails = err['statusDetails'] as Array; + const statusDetails = err['statusDetails'] as Array; - const foundExplainStats = statusDetails.find(x => { - return ( - 'type_url' in x && - x['type_url'] === - 'type.googleapis.com/google.firestore.v1.ExplainStats' - ); - }); - expect(foundExplainStats).to.not.be.undefined; + const foundExplainStats = statusDetails.find(x => { + return ( + 'type_url' in x && + x['type_url'] === + 'type.googleapis.com/google.firestore.v1.ExplainStats' + ); + }); + expect(foundExplainStats).to.not.be.undefined; + expect(err['metadata'] instanceof Object).to.be.true; + } + expect(typeof err['stack']).to.equal('string'); } }); }); @@ -7393,9 +7405,9 @@ describe.skipClassic('Pipeline search', () => { // queryEnhancement: 'disabled' }); - await expect(ppl.execute()).to.be.rejectedWith( - /3 INVALID_ARGUMENT.*/, - ); + const isRestTest = isRest(firestore); + const expectedErrorPattern = isRestTest ? /"code": 400/ : /3 INVALID_ARGUMENT.*/; + await expect(ppl.execute()).to.be.rejectedWith(expectedErrorPattern); }); }); @@ -7446,7 +7458,8 @@ describe.skipClassic('Pipeline search', () => { .search({...commonSearchParams, retrievalDepth: 1}); snapshot = await ppl.execute(); - expectResults(snapshot, 'eastsideTacos'); + expect(snapshot.results.length).to.equal(1); + expect(['solTacos', 'eastsideTacos']).to.include(snapshot.results[0].id); }); }); diff --git a/handwritten/firestore/dev/test/util/helpers.ts b/handwritten/firestore/dev/test/util/helpers.ts index 8d6e27843d83..3764af179ad9 100644 --- a/handwritten/firestore/dev/test/util/helpers.ts +++ b/handwritten/firestore/dev/test/util/helpers.ts @@ -90,28 +90,34 @@ export function createInstance( * run. */ export function verifyInstance(firestore: Firestore): Promise { - // Allow the setTimeout() call in _initializeStream to run before - // verifying that all operations have finished executing. return new Promise((resolve, reject) => { - if (firestore['_clientPool'].opCount === 0) { - resolve(); - } else { - setTimeout(() => { - const opCount = firestore['_clientPool'].opCount; - if (opCount === 0) { - resolve(); - } else { - reject( - new Error( - `Firestore has ${opCount} unfinished operations executing.`, - ), - ); - } - }, 10); + let attempts = 20; // 20 attempts * 50ms = 1000ms maximum wait + function check() { + const opCount = firestore['_clientPool'].opCount; + if (opCount === 0) { + resolve(); + } else if (--attempts > 0) { + setTimeout(check, 50); + } else { + reject( + new Error( + `Firestore has ${opCount} unfinished operations executing.`, + ), + ); + } } + check(); }); } +/** + * Helper function to check if testing is run using the REST backend. + * This inspects the internal preferRest setting on the given firestore instance. + */ +export function isRest(firestore: Firestore): boolean { + return !!(firestore as any)._settings?.preferRest; +} + function write( document: api.IDocument, mask: api.IDocumentMask | null, diff --git a/handwritten/firestore/package.json b/handwritten/firestore/package.json index a150827d977d..2e64b483fe54 100644 --- a/handwritten/firestore/package.json +++ b/handwritten/firestore/package.json @@ -40,13 +40,13 @@ "predocs": "npm run compile", "docs": "jsdoc -c .jsdoc.js", "system-test:rest": "FIRESTORE_PREFER_REST=true mocha build/system-test --timeout 1200000", - "system-test:enterprise:rest": "FIRESTORE_DATABASE_ID=test-db FIRESTORE_PREFER_REST=true mocha build/system-test --timeout 1200000", + "system-test:enterprise:rest": "RUN_ENTERPRISE_TESTS=yes FIRESTORE_DATABASE_ID=enterprise FIRESTORE_PREFER_REST=true mocha build/system-test --timeout 1200000", "system-test:grpc": "mocha build/system-test --timeout 1200000", - "system-test:enterprise:grpc": "FIRESTORE_DATABASE_ID=test-db mocha build/system-test --timeout 1200000", + "system-test:enterprise:grpc": "RUN_ENTERPRISE_TESTS=yes FIRESTORE_DATABASE_ID=enterprise mocha build/system-test --timeout 1200000", "system-test:emulator:rest": "FIRESTORE_EMULATOR_HOST=localhost:8080 FIRESTORE_PREFER_REST=true mocha build/system-test --timeout 1200000", - "system-test:enterprise:emulator:rest": "FIRESTORE_DATABASE_ID=test-db FIRESTORE_EMULATOR_HOST=localhost:8080 FIRESTORE_PREFER_REST=true mocha build/system-test --timeout 1200000", + "system-test:enterprise:emulator:rest": "RUN_ENTERPRISE_TESTS=yes FIRESTORE_DATABASE_ID=enterprise FIRESTORE_EMULATOR_HOST=localhost:8080 FIRESTORE_PREFER_REST=true mocha build/system-test --timeout 1200000", "system-test:emulator:grpc": "FIRESTORE_EMULATOR_HOST=localhost:8080 mocha build/system-test --timeout 1200000", - "system-test:enterprise:emulator:grpc": "FIRESTORE_DATABASE_ID=test-db FIRESTORE_EMULATOR_HOST=localhost:8080 mocha build/system-test --timeout 1200000", + "system-test:enterprise:emulator:grpc": "RUN_ENTERPRISE_TESTS=yes FIRESTORE_DATABASE_ID=enterprise FIRESTORE_EMULATOR_HOST=localhost:8080 mocha build/system-test --timeout 1200000", "system-test": "concurrently -p \"[{name}]\" -n \"grpc,rest,enterprise-grpc,enterprise-rest\" -c \"cyan,magenta,blue,yellow\" \"npm:system-test:grpc\" \"npm:system-test:rest\" \"npm:system-test:enterprise:grpc\" \"npm:system-test:enterprise:rest\"", "system-test:nightly": "FIRESTORE_TARGET_BACKEND=nightly FIRESTORE_DATABASE_ID=enterprise RUN_ENTERPRISE_TESTS=yes GCLOUD_PROJECT=firestore-sdk-nightly mocha build/system-test --timeout 1200000", "system-test:emulator": "concurrently -p \"[{name}]\" -n \"grpc,rest,enterprise-grpc,enterprise-rest\" -c \"cyan,magenta,blue,yellow\" \"npm:system-test:emulator:grpc\" \"npm:system-test:emulator:rest\" \"npm:system-test:enterprise:emulator:grpc\" \"npm:system-test:enterprise:emulator:rest\"",