From 894bf6f72d2fabc26ed75795c7f0b4fe62712325 Mon Sep 17 00:00:00 2001 From: Xing Fan Date: Fri, 15 May 2026 01:08:24 +0800 Subject: [PATCH] e2e test for mongodb extension --- app/v4/src/functions/cosmosDBMongoTrigger.ts | 35 +++++ .../httpTriggerCosmosDBMongoInput.ts | 30 ++++ .../httpTriggerCosmosDBMongoOutput.ts | 27 ++++ package-lock.json | 134 +++++++++++++++++- package.json | 1 + src/constants.ts | 8 ++ src/cosmosDBMongo.test.ts | 59 ++++++++ src/global.test.ts | 57 +++++++- src/utils/connectionStrings.ts | 6 +- src/utils/cosmosdbmongo/setupCosmosDBMongo.ts | 35 +++++ 10 files changed, 382 insertions(+), 10 deletions(-) create mode 100644 app/v4/src/functions/cosmosDBMongoTrigger.ts create mode 100644 app/v4/src/functions/httpTriggerCosmosDBMongoInput.ts create mode 100644 app/v4/src/functions/httpTriggerCosmosDBMongoOutput.ts create mode 100644 src/cosmosDBMongo.test.ts create mode 100644 src/utils/cosmosdbmongo/setupCosmosDBMongo.ts diff --git a/app/v4/src/functions/cosmosDBMongoTrigger.ts b/app/v4/src/functions/cosmosDBMongoTrigger.ts new file mode 100644 index 0000000..5bfc33e --- /dev/null +++ b/app/v4/src/functions/cosmosDBMongoTrigger.ts @@ -0,0 +1,35 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. + +import { app, InvocationContext } from '@azure/functions'; + +interface CosmosDBMongoChangeDocument { + operationType?: string; + fullDocument?: { + _id?: string; + testData?: string; + }; + documentKey?: { + _id?: string; + }; +} + +export async function cosmosDBMongoTrigger( + change: CosmosDBMongoChangeDocument, + context: InvocationContext +): Promise { + const document = change.fullDocument; + const documentId = document?._id ?? change.documentKey?._id; + context.log(`cosmosDBMongoTrigger operation "${change.operationType}" for "${documentId}"`); + context.log(`cosmosDBMongoTrigger was triggered by "${document?.testData}"`); +} + +(app as any).cosmosDBMongo('cosmosDBMongoTrigger', { + connectionStringSetting: 'CosmosDBMongoConnection', + databaseName: 'e2eTestMongoDB', + collectionName: 'e2eTestMongoCollection', + createIfNotExists: true, + leaseDatabaseName: 'e2eTestMongoDB', + leaseCollectionName: 'e2eTestMongoLeases', + handler: cosmosDBMongoTrigger, +}); diff --git a/app/v4/src/functions/httpTriggerCosmosDBMongoInput.ts b/app/v4/src/functions/httpTriggerCosmosDBMongoInput.ts new file mode 100644 index 0000000..7088bcd --- /dev/null +++ b/app/v4/src/functions/httpTriggerCosmosDBMongoInput.ts @@ -0,0 +1,30 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. + +import { app, HttpRequest, HttpResponseInit, input, InvocationContext } from '@azure/functions'; + +const cosmosDBMongoInput = (input as any).cosmosDBMongo({ + connectionStringSetting: 'CosmosDBMongoConnection', + databaseName: 'e2eTestMongoDB', + collectionName: 'e2eTestMongoCollection', + queryString: '{{"_id":"{Query.id}"}}', + createIfNotExists: true, +}); + +export async function httpTriggerCosmosDBMongoInput( + _request: HttpRequest, + context: InvocationContext +): Promise { + const result = context.extraInputs.get(cosmosDBMongoInput); + const documents = typeof result === 'string' ? JSON.parse(result) : result; + const document = Array.isArray(documents) ? documents[0] : documents; + return { jsonBody: document ?? null }; +} + +app.http('httpTriggerCosmosDBMongoInput', { + methods: ['GET'], + authLevel: 'anonymous', + extraInputs: [cosmosDBMongoInput], + handler: httpTriggerCosmosDBMongoInput, +}); + diff --git a/app/v4/src/functions/httpTriggerCosmosDBMongoOutput.ts b/app/v4/src/functions/httpTriggerCosmosDBMongoOutput.ts new file mode 100644 index 0000000..66e04ff --- /dev/null +++ b/app/v4/src/functions/httpTriggerCosmosDBMongoOutput.ts @@ -0,0 +1,27 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. + +import { app, HttpRequest, HttpResponseInit, InvocationContext, output } from '@azure/functions'; + +const cosmosDBMongoOutput = (output as any).cosmosDBMongo({ + connectionStringSetting: 'CosmosDBMongoConnection', + databaseName: 'e2eTestMongoDB', + collectionName: 'e2eTestMongoCollection', + createIfNotExists: true, +}); + +export async function httpTriggerCosmosDBMongoOutput( + request: HttpRequest, + context: InvocationContext +): Promise { + const body = await request.json(); + context.extraOutputs.set(cosmosDBMongoOutput, body); + return { body: 'done' }; +} + +app.http('httpTriggerCosmosDBMongoOutput', { + methods: ['POST'], + authLevel: 'anonymous', + extraOutputs: [cosmosDBMongoOutput], + handler: httpTriggerCosmosDBMongoOutput, +}); diff --git a/package-lock.json b/package-lock.json index 94f02ef..a99d253 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,6 +50,7 @@ "mocha": "^10.8.2", "mocha-junit-reporter": "^2.0.2", "mocha-multi-reporters": "^1.5.1", + "mongodb": "^6.19.0", "mssql": "^10.0.2", "node-fetch": "2.6.7", "p-retry": "^4.0.0", @@ -1213,6 +1214,14 @@ "dev": true, "license": "MIT" }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.4.11.tgz", + "integrity": "sha512-o9rAHc0IpIjuPSxRutWpE1F62x7n+4mVS4rCNHkzhIUMQcc18bb6xEq5wd2NdN0WjepIyXIppRshYI2kQDOZVA==", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1387,6 +1396,19 @@ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.5.tgz", "integrity": "sha512-xfHdwa1FMJ082prjSJpoEI57GZITiQz10r3vEJCHa2khEFQjKy91aWKz6+zybzssCvXUwE1LQWgWVwZ4nYUvHQ==" }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" + }, + "node_modules/@types/whatwg-url": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "dependencies": { + "@types/webidl-conversions": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "5.62.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", @@ -2243,6 +2265,14 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/bson": { + "version": "6.10.4", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.4.tgz", + "integrity": "sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==", + "engines": { + "node": ">=16.20.1" + } + }, "node_modules/buffer": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", @@ -4973,6 +5003,11 @@ "node": ">= 0.8" } }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" + }, "node_modules/merge-descriptors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", @@ -5209,6 +5244,91 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/mongodb": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.19.0.tgz", + "integrity": "sha512-H3GtYujOJdeKIMLKBT9PwlDhGrQfplABNF1G904w6r5ZXKWyv77aB0X9B+rhmaAwjtllHzaEkvi9mkGVZxs2Bw==", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.9", + "bson": "^6.10.4", + "mongodb-connection-string-url": "^3.0.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.3.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz", + "integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==", + "dependencies": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^14.1.0 || ^13.0.0" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -5706,9 +5826,9 @@ } }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "engines": { "node": ">=6" } @@ -6412,6 +6532,14 @@ "node": ">=0.10.0" } }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", diff --git a/package.json b/package.json index 0c905d0..fa9cdb9 100644 --- a/package.json +++ b/package.json @@ -79,6 +79,7 @@ "mocha": "^10.8.2", "mocha-junit-reporter": "^2.0.2", "mocha-multi-reporters": "^1.5.1", + "mongodb": "^6.19.0", "mssql": "^10.0.2", "node-fetch": "2.6.7", "p-retry": "^4.0.0", diff --git a/src/constants.ts b/src/constants.ts index ff651c7..712ffd9 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -4,6 +4,7 @@ export namespace EnvVarNames { export const storage = 'AzureWebJobsStorage'; export const cosmosDB = 'CosmosDBConnection'; + export const cosmosDBMongo = 'CosmosDBMongoConnection'; export const eventHub = 'EventHubConnection'; export const serviceBus = 'ServiceBusConnection'; export const sql = 'SqlConnection'; @@ -17,6 +18,13 @@ export namespace CosmosDB { export const partitionKey = 'testPartKey'; } +export namespace CosmosDBMongo { + export const dbName = 'e2eTestMongoDB'; + export const collectionName = 'e2eTestMongoCollection'; + export const leaseCollectionName = 'e2eTestMongoLeases'; + export const cosmosDBMongoTestFileName = 'cosmosDBMongo.test'; +} + export namespace EventHub { export const eventHubOneTriggerAndOutput = 'e2e-test-hub-one-trigger-and-output'; export const eventHubManyTriggerAndOutput = 'e2e-test-hub-many-trigger-and-output'; diff --git a/src/cosmosDBMongo.test.ts b/src/cosmosDBMongo.test.ts new file mode 100644 index 0000000..0f8ec5d --- /dev/null +++ b/src/cosmosDBMongo.test.ts @@ -0,0 +1,59 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. + +import { expect } from 'chai'; +import { default as fetch } from 'node-fetch'; +import { getFuncUrl } from './constants'; +import { isOldConfig, model, waitForOutput } from './global.test'; +import { cosmosDBMongoConnectionString } from './utils/connectionStrings'; +import { getRandomTestData } from './utils/getRandomTestData'; + +describe('cosmosDBMongo', () => { + before(function (this: Mocha.Context) { + if (model !== 'v4' || isOldConfig || !cosmosDBMongoConnectionString) { + this.skip(); + } + }); + + type Doc = { _id: string; testData: string }; + + function getDoc(): Doc { + const data = getRandomTestData(); + return { _id: data, testData: data }; + } + + it('trigger, output, input', async () => { + const document = getDoc(); + const outputResponse = await fetch(getFuncUrl('httpTriggerCosmosDBMongoOutput'), { + method: 'POST', + body: JSON.stringify(document), + }); + expect(outputResponse.status).to.equal(200); + + await waitForOutput(`cosmosDBMongoTrigger was triggered by "${document.testData}"`); + + const inputResponse = await fetch( + `${getFuncUrl('httpTriggerCosmosDBMongoInput')}?id=${encodeURIComponent(document._id)}` + ); + expect(inputResponse.status).to.equal(200); + const body = await inputResponse.json(); + expect(body).to.include(document); + }); + + it('bulk output triggers once per document', async () => { + const documents: Doc[] = []; + for (let i = 0; i < 3; i++) { + documents.push(getDoc()); + } + + const outputResponse = await fetch(getFuncUrl('httpTriggerCosmosDBMongoOutput'), { + method: 'POST', + body: JSON.stringify(documents), + }); + expect(outputResponse.status).to.equal(200); + + for (const document of documents) { + await waitForOutput(`cosmosDBMongoTrigger was triggered by "${document.testData}"`); + } + }); +}); diff --git a/src/global.test.ts b/src/global.test.ts index eb2e4e2..8dc15d8 100644 --- a/src/global.test.ts +++ b/src/global.test.ts @@ -5,10 +5,11 @@ import cp from 'child_process'; import * as fs from 'fs/promises'; import path from 'path'; import semver from 'semver'; -import { combinedFolder, defaultTimeout, EnvVarNames, oldConfigSuffix, ServiceBus } from './constants'; +import { combinedFolder, CosmosDBMongo, defaultTimeout, EnvVarNames, oldConfigSuffix, ServiceBus } from './constants'; import { getModelArg, getOldConfigArg, getTestFileFilter, Model } from './getModelArg'; import { cosmosDBConnectionString, + cosmosDBMongoConnectionString, eventHubConnectionString, initializeConnectionStrings, serviceBusConnectionString, @@ -18,6 +19,7 @@ import { import { delay } from './utils/delay'; import findProcess = require('find-process'); import { setupCosmosDB } from './utils/cosmosdb/setupCosmosDB'; +import { setupCosmosDBMongo } from './utils/cosmosdbmongo/setupCosmosDBMongo'; import { setupServiceBus } from './utils/servicebus/setupServiceBus'; import { runSqlSetupQueries } from './utils/sql/setupSql'; @@ -46,10 +48,14 @@ before(async function (this: Mocha.Context): Promise { const { only } = getTestFileFilter(); const disableServiceBusFunctions = shouldDisableServiceBusFunctions(); + const disableCosmosDBMongoFunctions = shouldDisableCosmosDBMongoFunctions(); if (only?.startsWith(ServiceBus.serviceBusTestFileName)) { await runSqlSetupQueries(); await setupCosmosDB(); } + if (!disableCosmosDBMongoFunctions) { + await setupCosmosDBMongo(); + } // Setup ServiceBus entities for v4 model (includes both MCP and ServiceBus functions) // This must be done before starting the functions app so that all trigger bindings can initialize @@ -62,11 +68,11 @@ before(async function (this: Mocha.Context): Promise { ? path.join(__dirname, '..', 'app', combinedFolder, model + oldConfigSuffix) : path.join(__dirname, '..', 'app', model); - await startFuncProcess(appPath, disableServiceBusFunctions); + await startFuncProcess(appPath, disableServiceBusFunctions, disableCosmosDBMongoFunctions); await waitForOutput('Host lock lease acquired by instance ID', { ignoreFailures: true }); await waitForOutput('Functions:', { checkFullOutput: true }); - if (model === 'v4' && !isOldConfig) { + if (model === 'v4' && !isOldConfig && !shouldOnlyRunCosmosDBMongoFunctions()) { await waitForOutput('MCP server endpoint:', { checkFullOutput: true, ignoreFailures: true }); } @@ -92,6 +98,23 @@ async function killFuncProc(): Promise { } } +function shouldOnlyRunCosmosDBMongoFunctions(): boolean { + return getTestFileFilter().only?.startsWith(CosmosDBMongo.cosmosDBMongoTestFileName) ?? false; +} + +function shouldDisableCosmosDBMongoFunctions(): boolean { + if (model !== 'v4' || getOldConfigArg() || !cosmosDBMongoConnectionString) { + return true; + } + + const { only, exclude } = getTestFileFilter(); + if (only) { + return !only.startsWith(CosmosDBMongo.cosmosDBMongoTestFileName); + } + + return exclude?.startsWith(CosmosDBMongo.cosmosDBMongoTestFileName) ?? false; +} + function shouldDisableServiceBusFunctions(): boolean { const { only, exclude } = getTestFileFilter(); if (only) { @@ -134,8 +157,12 @@ export async function waitForOutput(data: string, options?: WaitForOutputOptions } } -async function startFuncProcess(appPath: string, disableServiceBusFunctions: boolean): Promise { - const disabledFunctions = disableServiceBusFunctions +async function startFuncProcess( + appPath: string, + disableServiceBusFunctions: boolean, + disableCosmosDBMongoFunctions: boolean +): Promise { + const disabledServiceBusFunctions = disableServiceBusFunctions ? { 'AzureWebJobs.serviceBusQueueTrigger.Disabled': 'true', 'AzureWebJobs.serviceBusQueueTriggerAndOutput.Disabled': 'true', @@ -146,6 +173,21 @@ async function startFuncProcess(appPath: string, disableServiceBusFunctions: boo 'AzureWebJobs.httpTriggerServiceBusOutput.Disabled': 'true', } : {}; + const onlyCosmosDBMongoFunctions = shouldOnlyRunCosmosDBMongoFunctions(); + const disabledCosmosDBMongoFunctionSettings = disableCosmosDBMongoFunctions + ? { + 'AzureWebJobs.cosmosDBMongoTrigger.Disabled': 'true', + 'AzureWebJobs.httpTriggerCosmosDBMongoInput.Disabled': 'true', + 'AzureWebJobs.httpTriggerCosmosDBMongoOutput.Disabled': 'true', + } + : {}; + const functionAllowlistSettings = onlyCosmosDBMongoFunctions + ? { + AzureFunctionsJobHost__functions__0: 'cosmosDBMongoTrigger', + AzureFunctionsJobHost__functions__1: 'httpTriggerCosmosDBMongoInput', + AzureFunctionsJobHost__functions__2: 'httpTriggerCosmosDBMongoOutput', + } + : {}; await fs.writeFile( path.join(appPath, 'local.settings.json'), @@ -157,12 +199,15 @@ async function startFuncProcess(appPath: string, disableServiceBusFunctions: boo logging__logLevel__Worker: 'debug', [EnvVarNames.storage]: storageConnectionString, [EnvVarNames.cosmosDB]: cosmosDBConnectionString, + [EnvVarNames.cosmosDBMongo]: cosmosDBMongoConnectionString, [EnvVarNames.eventHub]: eventHubConnectionString, [EnvVarNames.serviceBus]: serviceBusConnectionString, [EnvVarNames.sql]: sqlTestConnectionString, WEBSITE_SITE_NAME: 'azure-functions-nodejs-e2e-tests', FUNCTIONS_REQUEST_BODY_SIZE_LIMIT: '4294967296', - ...disabledFunctions, + ...disabledServiceBusFunctions, + ...disabledCosmosDBMongoFunctionSettings, + ...functionAllowlistSettings, }, }, null, diff --git a/src/utils/connectionStrings.ts b/src/utils/connectionStrings.ts index 31b6501..a146670 100644 --- a/src/utils/connectionStrings.ts +++ b/src/utils/connectionStrings.ts @@ -1,8 +1,11 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. +import { EnvVarNames } from '../constants'; + export let storageConnectionString: string; export let cosmosDBConnectionString: string; +export let cosmosDBMongoConnectionString: string | undefined; export let eventHubConnectionString: string; export let serviceBusConnectionString: string; export let sqlConnectionString: string; @@ -11,7 +14,8 @@ export let sqlTestConnectionString: string; export async function initializeConnectionStrings(): Promise { storageConnectionString = "UseDevelopmentStorage=true"; cosmosDBConnectionString = "AccountEndpoint=http://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="; + cosmosDBMongoConnectionString = process.env[EnvVarNames.cosmosDBMongo]; serviceBusConnectionString = eventHubConnectionString = "Endpoint=sb://localhost;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=SAS_KEY_VALUE;UseDevelopmentEmulator=true;"; sqlConnectionString = `Server=localhost,15433;Database=master;User Id=sa;Password=${process.env.SA_PASSWORD};Encrypt=false;TrustServerCertificate=true;`; sqlTestConnectionString = `Server=localhost,15433;Database=e2eTestDB;User Id=sa;Password=${process.env.SA_PASSWORD};Encrypt=false;TrustServerCertificate=true;`; -} +} diff --git a/src/utils/cosmosdbmongo/setupCosmosDBMongo.ts b/src/utils/cosmosdbmongo/setupCosmosDBMongo.ts new file mode 100644 index 0000000..a436aec --- /dev/null +++ b/src/utils/cosmosdbmongo/setupCosmosDBMongo.ts @@ -0,0 +1,35 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. + +import { MongoClient } from 'mongodb'; + +import { CosmosDBMongo } from '../../constants'; +import { cosmosDBMongoConnectionString } from '../connectionStrings'; + +export async function setupCosmosDBMongo(): Promise { + if (!cosmosDBMongoConnectionString) { + throw new Error('Cosmos DB Mongo connection string is not set'); + } + + const client = new MongoClient(cosmosDBMongoConnectionString); + try { + await client.connect(); + const database = client.db(CosmosDBMongo.dbName); + await createCollectionIfNotExists(database, CosmosDBMongo.collectionName); + await createCollectionIfNotExists(database, CosmosDBMongo.leaseCollectionName); + await database.collection(CosmosDBMongo.collectionName).deleteMany({}); + await database.collection(CosmosDBMongo.leaseCollectionName).deleteMany({}); + } finally { + await client.close(); + } +} + +async function createCollectionIfNotExists( + database: ReturnType, + collectionName: string +): Promise { + const collections = await database.listCollections({ name: collectionName }, { nameOnly: true }).toArray(); + if (collections.length === 0) { + await database.createCollection(collectionName); + } +}