From 5cdb5e6d0c989f7a3b2470a3975ea6f7bc1d4521 Mon Sep 17 00:00:00 2001 From: Evan Roman Date: Mon, 21 Jul 2025 12:38:25 -0500 Subject: [PATCH 01/24] test --- app/v4/src/functions/storageBlobTrigger.ts | 24 +-- .../functions/storageBlobTriggerAndOutput.ts | 34 ++-- .../storageBlobTriggerSharedOutputBug.ts | 52 +++--- .../templates/test-node-version.yml | 3 + azure-pipelines/templates/test.yml | 12 +- src/index.ts | 9 +- src/storage.test.ts | 150 +++++++++--------- src/utils/servicebus/config.json | 28 ++++ src/utils/servicebus/docker-compose.yml | 0 9 files changed, 175 insertions(+), 137 deletions(-) create mode 100644 src/utils/servicebus/config.json create mode 100644 src/utils/servicebus/docker-compose.yml diff --git a/app/v4/src/functions/storageBlobTrigger.ts b/app/v4/src/functions/storageBlobTrigger.ts index 20a42f63..709421d8 100644 --- a/app/v4/src/functions/storageBlobTrigger.ts +++ b/app/v4/src/functions/storageBlobTrigger.ts @@ -1,15 +1,15 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { app, InvocationContext } from '@azure/functions'; +import { app, InvocationContext } from '@azure/functions'; -// export async function storageBlobTrigger(blob: Buffer, context: InvocationContext): Promise { -// const blobPath = context.triggerMetadata.blobTrigger; -// context.log(`storageBlobTrigger was triggered by blob "${blobPath}" with content "${blob.toString()}"`); -// } +export async function storageBlobTrigger(blob: Buffer, context: InvocationContext): Promise { + const blobPath = context.triggerMetadata.blobTrigger; + context.log(`storageBlobTrigger was triggered by blob "${blobPath}" with content "${blob.toString()}"`); +} -// app.storageBlob('storageBlobTrigger', { -// path: 'e2e-test-container/e2e-test-blob-trigger', -// connection: 'AzureWebJobsStorage', -// handler: storageBlobTrigger, -// }); +app.storageBlob('storageBlobTrigger', { + path: 'e2e-test-container/e2e-test-blob-trigger', + connection: 'AzureWebJobsStorage', + handler: storageBlobTrigger, +}); diff --git a/app/v4/src/functions/storageBlobTriggerAndOutput.ts b/app/v4/src/functions/storageBlobTriggerAndOutput.ts index 01d16a0e..8948fb04 100644 --- a/app/v4/src/functions/storageBlobTriggerAndOutput.ts +++ b/app/v4/src/functions/storageBlobTriggerAndOutput.ts @@ -1,20 +1,20 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { app, InvocationContext, output } from '@azure/functions'; +import { app, InvocationContext, output } from '@azure/functions'; -// export async function storageBlobTriggerAndOutput(blob: Buffer, context: InvocationContext): Promise { -// const blobPath = context.triggerMetadata.blobTrigger; -// context.log(`storageBlobTriggerAndOutput was triggered by blob "${blobPath}" with content "${blob.toString()}"`); -// return blob; -// } +export async function storageBlobTriggerAndOutput(blob: Buffer, context: InvocationContext): Promise { + const blobPath = context.triggerMetadata.blobTrigger; + context.log(`storageBlobTriggerAndOutput was triggered by blob "${blobPath}" with content "${blob.toString()}"`); + return blob; +} -// app.storageBlob('storageBlobTriggerAndOutput', { -// path: 'e2e-test-container/e2e-test-blob-trigger-and-output', -// connection: 'AzureWebJobsStorage', -// return: output.storageBlob({ -// path: 'e2e-test-container/e2e-test-blob-trigger', -// connection: 'AzureWebJobsStorage', -// }), -// handler: storageBlobTriggerAndOutput, -// }); +app.storageBlob('storageBlobTriggerAndOutput', { + path: 'e2e-test-container/e2e-test-blob-trigger-and-output', + connection: 'AzureWebJobsStorage', + return: output.storageBlob({ + path: 'e2e-test-container/e2e-test-blob-trigger', + connection: 'AzureWebJobsStorage', + }), + handler: storageBlobTriggerAndOutput, +}); diff --git a/app/v4/src/functions/storageBlobTriggerSharedOutputBug.ts b/app/v4/src/functions/storageBlobTriggerSharedOutputBug.ts index afd3694c..99d1eb1c 100644 --- a/app/v4/src/functions/storageBlobTriggerSharedOutputBug.ts +++ b/app/v4/src/functions/storageBlobTriggerSharedOutputBug.ts @@ -1,31 +1,31 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { app, InvocationContext, output } from '@azure/functions'; +import { app, InvocationContext, output } from '@azure/functions'; -// // Test for bug https://github.com/Azure/azure-functions-nodejs-library/issues/179 +// Test for bug https://github.com/Azure/azure-functions-nodejs-library/issues/179 -// const queueOutput = output.storageQueue({ -// queueName: 'e2e-test-queue-trigger', -// connection: 'e2eTest_storage', -// }); +const queueOutput = output.storageQueue({ + queueName: 'e2e-test-queue-trigger', + connection: 'AzureWebJobsStorage', +}); -// app.storageBlob('storageBlobTriggerReturnOutput', { -// path: 'e2e-test-container/e2e-test-blob-trigger-shared-output-bug', -// connection: 'e2eTest_storage', -// return: queueOutput, -// handler: (blob: Buffer, context: InvocationContext) => { -// context.log(`storageBlobTriggerReturnOutput was triggered`); -// return `${blob.toString()}-returnOutput`; -// }, -// }); +app.storageBlob('storageBlobTriggerReturnOutput', { + path: 'e2e-test-container/e2e-test-blob-trigger-shared-output-bug', + connection: 'AzureWebJobsStorage', + return: queueOutput, + handler: (blob: Buffer, context: InvocationContext) => { + context.log(`storageBlobTriggerReturnOutput was triggered`); + return `${blob.toString()}-returnOutput`; + }, +}); -// app.storageBlob('storageBlobTriggerExtraOutput', { -// path: 'e2e-test-container/e2e-test-blob-trigger-shared-output-bug', -// connection: 'e2eTest_storage', -// extraOutputs: [queueOutput], -// handler: (blob: Buffer, context: InvocationContext) => { -// context.log(`storageBlobTriggerExtraOutput was triggered`); -// context.extraOutputs.set(queueOutput, `${blob.toString()}-extraOutput`); -// }, -// }); +app.storageBlob('storageBlobTriggerExtraOutput', { + path: 'e2e-test-container/e2e-test-blob-trigger-shared-output-bug', + connection: 'AzureWebJobsStorage', + extraOutputs: [queueOutput], + handler: (blob: Buffer, context: InvocationContext) => { + context.log(`storageBlobTriggerExtraOutput was triggered`); + context.extraOutputs.set(queueOutput, `${blob.toString()}-extraOutput`); + }, +}); diff --git a/azure-pipelines/templates/test-node-version.yml b/azure-pipelines/templates/test-node-version.yml index fcbeca96..380696db 100644 --- a/azure-pipelines/templates/test-node-version.yml +++ b/azure-pipelines/templates/test-node-version.yml @@ -15,6 +15,9 @@ steps: docker compose -f src/utils/eventhub/docker-compose.yml pull docker compose -f src/utils/eventhub/docker-compose.yml up -d displayName: 'Install Azurite and Start EventHub Emulator' + - bash: | + docker logs azurite + displayName: 'Show Azurite Logs' - bash: | npm run ${{ parameters.testCommand }} displayName: 'Run tests Node ${{ parameters.nodeVersion }}' diff --git a/azure-pipelines/templates/test.yml b/azure-pipelines/templates/test.yml index 99aafeed..19f6efe0 100644 --- a/azure-pipelines/templates/test.yml +++ b/azure-pipelines/templates/test.yml @@ -16,13 +16,13 @@ jobs: - template: /azure-pipelines/templates/build-apps.yml@self - - template: /azure-pipelines/templates/test-node-version.yml@self - parameters: - nodeVersion: 18.x + # - template: /azure-pipelines/templates/test-node-version.yml@self + # parameters: + # nodeVersion: 18.x - - template: /azure-pipelines/templates/test-node-version.yml@self - parameters: - nodeVersion: 20.x + # - template: /azure-pipelines/templates/test-node-version.yml@self + # parameters: + # nodeVersion: 20.x - template: /azure-pipelines/templates/test-node-version.yml@self parameters: diff --git a/src/index.ts b/src/index.ts index 0c52d1c2..69118ba6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,9 +6,16 @@ import Mocha from 'mocha'; import path from 'path'; import { defaultTimeout } from './constants'; import { getModelArg, getOldConfigArg } from './getModelArg'; +import yargs from 'yargs'; export async function run(): Promise { try { + const argv = yargs(process.argv.slice(2)).option('exclude', { + type: 'string', + description: 'Glob pattern of tests to exclude', + }).parseSync(); + const excludePattern = argv.exclude ? [argv.exclude] : []; + const oldConfigSuffix = getOldConfigArg() ? '_oldConfig' : ''; const fileName = `${process.platform}_model-${getModelArg()}_Node-${process.version}${oldConfigSuffix}.xml`; const options: Mocha.MochaOptions = { @@ -27,7 +34,7 @@ export async function run(): Promise { const mocha = new Mocha(options); - const files: string[] = await globby('**/**.test.js', { cwd: __dirname }); + const files: string[] = await globby(['**/**.test.js', ...excludePattern.map(p => `!${p}`)], { cwd: __dirname }); files.forEach((f) => mocha.addFile(path.resolve(__dirname, f))); diff --git a/src/storage.test.ts b/src/storage.test.ts index fe2efc09..b6624ea1 100644 --- a/src/storage.test.ts +++ b/src/storage.test.ts @@ -1,14 +1,14 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. -// import { ContainerClient } from '@azure/storage-blob'; +import { ContainerClient } from '@azure/storage-blob'; // import { QueueClient } from '@azure/storage-queue'; // import { expect } from 'chai'; // import { default as fetch } from 'node-fetch'; // import { getFuncUrl } from './constants'; -// import { waitForOutput } from './global.test'; -// import { getRandomTestData } from './utils/getRandomTestData'; -// import { storageConnectionString } from './utils/connectionStrings'; +import { waitForOutput } from './global.test'; +import { getRandomTestData } from './utils/getRandomTestData'; +import { storageConnectionString } from './utils/connectionStrings'; // describe('storage', () => { // it('queue trigger and output', async () => { @@ -22,86 +22,86 @@ // await waitForOutput(`storageQueueTrigger was triggered by "${message}"`); // }); -// it('queue extra output', async () => { -// const url = getFuncUrl('httpTriggerStorageQueueOutput'); + // it('queue extra output', async () => { + // const url = getFuncUrl('httpTriggerStorageQueueOutput'); -// // single -// const message = getRandomTestData(); -// await fetch(url, { method: 'POST', body: JSON.stringify({ output: message }) }); -// await waitForOutput(`storageQueueTrigger was triggered by "${message}"`); + // // single + // const message = getRandomTestData(); + // await fetch(url, { method: 'POST', body: JSON.stringify({ output: message }) }); + // await waitForOutput(`storageQueueTrigger was triggered by "${message}"`); + + // // bulk + // const bulkMsgs: string[] = []; + // for (let i = 0; i < 5; i++) { + // bulkMsgs.push(getRandomTestData()); + // } + // await fetch(url, { method: 'POST', body: JSON.stringify({ output: bulkMsgs }) }); + // for (const msg of bulkMsgs) { + // await waitForOutput(`storageQueueTrigger was triggered by "${msg}"`); + // } + // }); -// // bulk -// const bulkMsgs: string[] = []; -// for (let i = 0; i < 5; i++) { -// bulkMsgs.push(getRandomTestData()); -// } -// await fetch(url, { method: 'POST', body: JSON.stringify({ output: bulkMsgs }) }); -// for (const msg of bulkMsgs) { -// await waitForOutput(`storageQueueTrigger was triggered by "${msg}"`); -// } -// }); + it('blob trigger and output', async () => { + const containerName = 'e2e-test-container'; + const client = new ContainerClient(storageConnectionString, containerName); + await client.createIfNotExists(); + + const message = getRandomTestData(); + const messageBuffer = Buffer.from(message); + const blobName = 'e2e-test-blob-trigger-and-output'; + await client.uploadBlockBlob(blobName, messageBuffer, messageBuffer.byteLength); + + await waitForOutput( + `storageBlobTriggerAndOutput was triggered by blob "${containerName}/${blobName}" with content "${message}"` + ); + await waitForOutput( + `storageBlobTrigger was triggered by blob "${containerName}/e2e-test-blob-trigger" with content "${message}"` + ); + }); + + // type TableItem = { PartitionKey: string; RowKey: string; Name: string }; + + // it('table input and output', async () => { + // const rowKey = getRandomTestData(); + // const items: TableItem[] = [ + // { + // PartitionKey: 'e2eTestPartKey', + // RowKey: rowKey, + // Name: 'e2eTestName', + // }, + // ]; + // const responseOut = await fetch(getFuncUrl('httpTriggerTableOutput'), { + // method: 'POST', + // body: JSON.stringify(items), + // }); + // expect(responseOut.status).to.equal(201); + // await waitForOutput(`httpTriggerTableOutput was triggered`); + + // const responseIn = await fetch(getFuncUrl(`httpTriggerTableInput/${rowKey}`), { method: 'GET' }); + // expect(responseIn.status).to.equal(200); + // const result = await responseIn.json(); + // expect(result).to.deep.equal(items); + // await waitForOutput(`httpTriggerTableInput was triggered`); + // }); + + // Test for bug https://github.com/Azure/azure-functions-nodejs-library/issues/179 + // it('Shared output bug', async function (this: Mocha.Context) { + // if (model === 'v3') { + // this.skip(); + // } - // it('blob trigger and output', async () => { // const containerName = 'e2e-test-container'; // const client = new ContainerClient(storageConnectionString, containerName); // await client.createIfNotExists(); // const message = getRandomTestData(); // const messageBuffer = Buffer.from(message); - // const blobName = 'e2e-test-blob-trigger-and-output'; + // const blobName = 'e2e-test-blob-trigger-shared-output-bug'; // await client.uploadBlockBlob(blobName, messageBuffer, messageBuffer.byteLength); - // await waitForOutput( - // `storageBlobTriggerAndOutput was triggered by blob "${containerName}/${blobName}" with content "${message}"` - // ); - // await waitForOutput( - // `storageBlobTrigger was triggered by blob "${containerName}/e2e-test-blob-trigger" with content "${message}"` - // ); + // await waitForOutput(`storageBlobTriggerReturnOutput was triggered`); + // await waitForOutput(`storageBlobTriggerExtraOutput was triggered`); + // await waitForOutput(`storageQueueTrigger was triggered by "${message}-returnOutput"`); + // await waitForOutput(`storageQueueTrigger was triggered by "${message}-extraOutput"`); // }); - -// type TableItem = { PartitionKey: string; RowKey: string; Name: string }; - -// it('table input and output', async () => { -// const rowKey = getRandomTestData(); -// const items: TableItem[] = [ -// { -// PartitionKey: 'e2eTestPartKey', -// RowKey: rowKey, -// Name: 'e2eTestName', -// }, -// ]; -// const responseOut = await fetch(getFuncUrl('httpTriggerTableOutput'), { -// method: 'POST', -// body: JSON.stringify(items), -// }); -// expect(responseOut.status).to.equal(201); -// await waitForOutput(`httpTriggerTableOutput was triggered`); - -// const responseIn = await fetch(getFuncUrl(`httpTriggerTableInput/${rowKey}`), { method: 'GET' }); -// expect(responseIn.status).to.equal(200); -// const result = await responseIn.json(); -// expect(result).to.deep.equal(items); -// await waitForOutput(`httpTriggerTableInput was triggered`); -// }); - -// // Test for bug https://github.com/Azure/azure-functions-nodejs-library/issues/179 -// it('Shared output bug', async function (this: Mocha.Context) { -// if (model === 'v3') { -// this.skip(); -// } - -// const containerName = 'e2e-test-container'; -// const client = new ContainerClient(storageConnectionString, containerName); -// await client.createIfNotExists(); - -// const message = getRandomTestData(); -// const messageBuffer = Buffer.from(message); -// const blobName = 'e2e-test-blob-trigger-shared-output-bug'; -// await client.uploadBlockBlob(blobName, messageBuffer, messageBuffer.byteLength); - -// await waitForOutput(`storageBlobTriggerReturnOutput was triggered`); -// await waitForOutput(`storageBlobTriggerExtraOutput was triggered`); -// await waitForOutput(`storageQueueTrigger was triggered by "${message}-returnOutput"`); -// await waitForOutput(`storageQueueTrigger was triggered by "${message}-extraOutput"`); -// }); -// }); +}); diff --git a/src/utils/servicebus/config.json b/src/utils/servicebus/config.json new file mode 100644 index 00000000..20cf8344 --- /dev/null +++ b/src/utils/servicebus/config.json @@ -0,0 +1,28 @@ +{ + "UserConfig": { + "Namespaces": [ + { + "Name": "sbemulatorns", + "Queues": [ + { + "Name": "testqueue", + "Properties": { + "DeadLetteringOnMessageExpiration": false, + "DefaultMessageTimeToLive": "PT1H", + "DuplicateDetectionHistoryTimeWindow": "PT20S", + "ForwardDeadLetteredMessagesTo": "", + "ForwardTo": "", + "LockDuration": "PT1M", + "MaxDeliveryCount": 10, + "RequiresDuplicateDetection": false, + "RequiresSession": false + } + } + ] + } + ], + "Logging": { + "Type": "File" + } + } +} \ No newline at end of file diff --git a/src/utils/servicebus/docker-compose.yml b/src/utils/servicebus/docker-compose.yml new file mode 100644 index 00000000..e69de29b From 603bd9606a1188fb24e2480d00d3364d734fa5a7 Mon Sep 17 00:00:00 2001 From: Evan Roman Date: Mon, 21 Jul 2025 13:27:10 -0500 Subject: [PATCH 02/24] test --- __azurite_db_blob__.json | 1 + __azurite_db_blob_extent__.json | 1 + src/storage.test.ts | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 __azurite_db_blob__.json create mode 100644 __azurite_db_blob_extent__.json diff --git a/__azurite_db_blob__.json b/__azurite_db_blob__.json new file mode 100644 index 00000000..4d82d705 --- /dev/null +++ b/__azurite_db_blob__.json @@ -0,0 +1 @@ +{"filename":"c:\\Users\\evanroman\\source\\repos\\azure-functions-nodejs-e2e-tests\\__azurite_db_blob__.json","collections":[{"name":"$SERVICES_COLLECTION$","data":[],"idIndex":null,"binaryIndices":{},"constraints":null,"uniqueNames":["accountName"],"transforms":{},"objType":"$SERVICES_COLLECTION$","dirty":false,"cachedIndex":null,"cachedBinaryIndex":null,"cachedData":null,"adaptiveBinaryIndices":true,"transactional":false,"cloneObjects":false,"cloneMethod":"parse-stringify","asyncListeners":false,"disableMeta":false,"disableChangesApi":true,"disableDeltaChangesApi":true,"autoupdate":false,"serializableIndices":true,"disableFreeze":true,"ttl":null,"maxId":0,"DynamicViews":[],"events":{"insert":[],"update":[],"pre-insert":[],"pre-update":[],"close":[],"flushbuffer":[],"error":[],"delete":[null],"warning":[null]},"changes":[],"dirtyIds":[]},{"name":"$CONTAINERS_COLLECTION$","data":[],"idIndex":null,"binaryIndices":{"accountName":{"name":"accountName","dirty":false,"values":[]},"name":{"name":"name","dirty":false,"values":[]}},"constraints":null,"uniqueNames":[],"transforms":{},"objType":"$CONTAINERS_COLLECTION$","dirty":false,"cachedIndex":null,"cachedBinaryIndex":null,"cachedData":null,"adaptiveBinaryIndices":true,"transactional":false,"cloneObjects":false,"cloneMethod":"parse-stringify","asyncListeners":false,"disableMeta":false,"disableChangesApi":true,"disableDeltaChangesApi":true,"autoupdate":false,"serializableIndices":true,"disableFreeze":true,"ttl":null,"maxId":0,"DynamicViews":[],"events":{"insert":[],"update":[],"pre-insert":[],"pre-update":[],"close":[],"flushbuffer":[],"error":[],"delete":[null],"warning":[null]},"changes":[],"dirtyIds":[]},{"name":"$BLOBS_COLLECTION$","data":[],"idIndex":null,"binaryIndices":{"accountName":{"name":"accountName","dirty":false,"values":[]},"containerName":{"name":"containerName","dirty":false,"values":[]},"name":{"name":"name","dirty":false,"values":[]},"snapshot":{"name":"snapshot","dirty":false,"values":[]}},"constraints":null,"uniqueNames":[],"transforms":{},"objType":"$BLOBS_COLLECTION$","dirty":false,"cachedIndex":null,"cachedBinaryIndex":null,"cachedData":null,"adaptiveBinaryIndices":true,"transactional":false,"cloneObjects":false,"cloneMethod":"parse-stringify","asyncListeners":false,"disableMeta":false,"disableChangesApi":true,"disableDeltaChangesApi":true,"autoupdate":false,"serializableIndices":true,"disableFreeze":true,"ttl":null,"maxId":0,"DynamicViews":[],"events":{"insert":[],"update":[],"pre-insert":[],"pre-update":[],"close":[],"flushbuffer":[],"error":[],"delete":[null],"warning":[null]},"changes":[],"dirtyIds":[]},{"name":"$BLOCKS_COLLECTION$","data":[],"idIndex":null,"binaryIndices":{"accountName":{"name":"accountName","dirty":false,"values":[]},"containerName":{"name":"containerName","dirty":false,"values":[]},"blobName":{"name":"blobName","dirty":false,"values":[]},"name":{"name":"name","dirty":false,"values":[]}},"constraints":null,"uniqueNames":[],"transforms":{},"objType":"$BLOCKS_COLLECTION$","dirty":false,"cachedIndex":null,"cachedBinaryIndex":null,"cachedData":null,"adaptiveBinaryIndices":true,"transactional":false,"cloneObjects":false,"cloneMethod":"parse-stringify","asyncListeners":false,"disableMeta":false,"disableChangesApi":true,"disableDeltaChangesApi":true,"autoupdate":false,"serializableIndices":true,"disableFreeze":true,"ttl":null,"maxId":0,"DynamicViews":[],"events":{"insert":[],"update":[],"pre-insert":[],"pre-update":[],"close":[],"flushbuffer":[],"error":[],"delete":[null],"warning":[null]},"changes":[],"dirtyIds":[]}],"databaseVersion":1.5,"engineVersion":1.5,"autosave":true,"autosaveInterval":5000,"autosaveHandle":null,"throttledSaves":true,"options":{"persistenceMethod":"fs","autosave":true,"autosaveInterval":5000,"serializationMethod":"normal","destructureDelimiter":"$<\n"},"persistenceMethod":"fs","persistenceAdapter":null,"verbose":false,"events":{"init":[null],"loaded":[],"flushChanges":[],"close":[],"changes":[],"warning":[]},"ENV":"NODEJS"} \ No newline at end of file diff --git a/__azurite_db_blob_extent__.json b/__azurite_db_blob_extent__.json new file mode 100644 index 00000000..06515548 --- /dev/null +++ b/__azurite_db_blob_extent__.json @@ -0,0 +1 @@ +{"filename":"c:\\Users\\evanroman\\source\\repos\\azure-functions-nodejs-e2e-tests\\__azurite_db_blob_extent__.json","collections":[{"name":"$EXTENTS_COLLECTION$","data":[],"idIndex":null,"binaryIndices":{"id":{"name":"id","dirty":false,"values":[]}},"constraints":null,"uniqueNames":[],"transforms":{},"objType":"$EXTENTS_COLLECTION$","dirty":false,"cachedIndex":null,"cachedBinaryIndex":null,"cachedData":null,"adaptiveBinaryIndices":true,"transactional":false,"cloneObjects":false,"cloneMethod":"parse-stringify","asyncListeners":false,"disableMeta":false,"disableChangesApi":true,"disableDeltaChangesApi":true,"autoupdate":false,"serializableIndices":true,"disableFreeze":true,"ttl":null,"maxId":0,"DynamicViews":[],"events":{"insert":[],"update":[],"pre-insert":[],"pre-update":[],"close":[],"flushbuffer":[],"error":[],"delete":[null],"warning":[null]},"changes":[],"dirtyIds":[]}],"databaseVersion":1.5,"engineVersion":1.5,"autosave":true,"autosaveInterval":5000,"autosaveHandle":null,"throttledSaves":true,"options":{"persistenceMethod":"fs","autosave":true,"autosaveInterval":5000,"serializationMethod":"normal","destructureDelimiter":"$<\n"},"persistenceMethod":"fs","persistenceAdapter":null,"verbose":false,"events":{"init":[null],"loaded":[],"flushChanges":[],"close":[],"changes":[],"warning":[]},"ENV":"NODEJS"} \ No newline at end of file diff --git a/src/storage.test.ts b/src/storage.test.ts index b6624ea1..ae659dad 100644 --- a/src/storage.test.ts +++ b/src/storage.test.ts @@ -10,7 +10,7 @@ import { waitForOutput } from './global.test'; import { getRandomTestData } from './utils/getRandomTestData'; import { storageConnectionString } from './utils/connectionStrings'; -// describe('storage', () => { +describe('storage', () => { // it('queue trigger and output', async () => { // const client = new QueueClient(storageConnectionString, 'e2e-test-queue-trigger-and-output'); // await client.createIfNotExists(); From 5f2cc67ee5d1ddcb739ce19392edf9df8ac0ad2d Mon Sep 17 00:00:00 2001 From: Evan Roman Date: Mon, 21 Jul 2025 14:18:12 -0500 Subject: [PATCH 03/24] test --- src/index.ts | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/index.ts b/src/index.ts index 69118ba6..0c52d1c2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,16 +6,9 @@ import Mocha from 'mocha'; import path from 'path'; import { defaultTimeout } from './constants'; import { getModelArg, getOldConfigArg } from './getModelArg'; -import yargs from 'yargs'; export async function run(): Promise { try { - const argv = yargs(process.argv.slice(2)).option('exclude', { - type: 'string', - description: 'Glob pattern of tests to exclude', - }).parseSync(); - const excludePattern = argv.exclude ? [argv.exclude] : []; - const oldConfigSuffix = getOldConfigArg() ? '_oldConfig' : ''; const fileName = `${process.platform}_model-${getModelArg()}_Node-${process.version}${oldConfigSuffix}.xml`; const options: Mocha.MochaOptions = { @@ -34,7 +27,7 @@ export async function run(): Promise { const mocha = new Mocha(options); - const files: string[] = await globby(['**/**.test.js', ...excludePattern.map(p => `!${p}`)], { cwd: __dirname }); + const files: string[] = await globby('**/**.test.js', { cwd: __dirname }); files.forEach((f) => mocha.addFile(path.resolve(__dirname, f))); From bae5c5114a0f5749fefa3daf8379e305c8e3b720 Mon Sep 17 00:00:00 2001 From: Evan Roman Date: Mon, 21 Jul 2025 14:49:17 -0500 Subject: [PATCH 04/24] test --- app/v3/storageBlobTrigger/index.ts | 16 +++--- app/v3/storageBlobTriggerAndOutput/index.ts | 18 +++---- .../storageBlobTriggerSharedOutputBug.ts | 52 +++++++++---------- 3 files changed, 43 insertions(+), 43 deletions(-) diff --git a/app/v3/storageBlobTrigger/index.ts b/app/v3/storageBlobTrigger/index.ts index 5f2003e3..2bd017fe 100644 --- a/app/v3/storageBlobTrigger/index.ts +++ b/app/v3/storageBlobTrigger/index.ts @@ -1,11 +1,11 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { AzureFunction, Context } from '@azure/functions'; +import { AzureFunction, Context } from '@azure/functions'; -// const blobTrigger: AzureFunction = async function (context: Context, myBlob: any): Promise { -// const blobPath = context.bindingData.blobTrigger; -// context.log(`storageBlobTrigger was triggered by blob "${blobPath}" with content "${myBlob.toString()}"`); -// }; +const blobTrigger: AzureFunction = async function (context: Context, myBlob: any): Promise { + const blobPath = context.bindingData.blobTrigger; + context.log(`storageBlobTrigger was triggered by blob "${blobPath}" with content "${myBlob.toString()}"`); +}; -// export default blobTrigger; +export default blobTrigger; diff --git a/app/v3/storageBlobTriggerAndOutput/index.ts b/app/v3/storageBlobTriggerAndOutput/index.ts index b195e84f..67d5c723 100644 --- a/app/v3/storageBlobTriggerAndOutput/index.ts +++ b/app/v3/storageBlobTriggerAndOutput/index.ts @@ -1,12 +1,12 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { AzureFunction, Context } from '@azure/functions'; +import { AzureFunction, Context } from '@azure/functions'; -// const blobTrigger: AzureFunction = async function (context: Context, myBlob: any): Promise { -// const blobPath = context.bindingData.blobTrigger; -// context.log(`storageBlobTriggerAndOutput was triggered by blob "${blobPath}" with content "${myBlob.toString()}"`); -// return myBlob; -// }; +const blobTrigger: AzureFunction = async function (context: Context, myBlob: any): Promise { + const blobPath = context.bindingData.blobTrigger; + context.log(`storageBlobTriggerAndOutput was triggered by blob "${blobPath}" with content "${myBlob.toString()}"`); + return myBlob; +}; -// export default blobTrigger; +export default blobTrigger; diff --git a/app/v4/src/functions/storageBlobTriggerSharedOutputBug.ts b/app/v4/src/functions/storageBlobTriggerSharedOutputBug.ts index 99d1eb1c..8c4d824e 100644 --- a/app/v4/src/functions/storageBlobTriggerSharedOutputBug.ts +++ b/app/v4/src/functions/storageBlobTriggerSharedOutputBug.ts @@ -1,31 +1,31 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT License. +// // Copyright (c) .NET Foundation. All rights reserved. +// // Licensed under the MIT License. -import { app, InvocationContext, output } from '@azure/functions'; +// import { app, InvocationContext, output } from '@azure/functions'; -// Test for bug https://github.com/Azure/azure-functions-nodejs-library/issues/179 +// // Test for bug https://github.com/Azure/azure-functions-nodejs-library/issues/179 -const queueOutput = output.storageQueue({ - queueName: 'e2e-test-queue-trigger', - connection: 'AzureWebJobsStorage', -}); +// const queueOutput = output.storageQueue({ +// queueName: 'e2e-test-queue-trigger', +// connection: 'AzureWebJobsStorage', +// }); -app.storageBlob('storageBlobTriggerReturnOutput', { - path: 'e2e-test-container/e2e-test-blob-trigger-shared-output-bug', - connection: 'AzureWebJobsStorage', - return: queueOutput, - handler: (blob: Buffer, context: InvocationContext) => { - context.log(`storageBlobTriggerReturnOutput was triggered`); - return `${blob.toString()}-returnOutput`; - }, -}); +// app.storageBlob('storageBlobTriggerReturnOutput', { +// path: 'e2e-test-container/e2e-test-blob-trigger-shared-output-bug', +// connection: 'AzureWebJobsStorage', +// return: queueOutput, +// handler: (blob: Buffer, context: InvocationContext) => { +// context.log(`storageBlobTriggerReturnOutput was triggered`); +// return `${blob.toString()}-returnOutput`; +// }, +// }); -app.storageBlob('storageBlobTriggerExtraOutput', { - path: 'e2e-test-container/e2e-test-blob-trigger-shared-output-bug', - connection: 'AzureWebJobsStorage', - extraOutputs: [queueOutput], - handler: (blob: Buffer, context: InvocationContext) => { - context.log(`storageBlobTriggerExtraOutput was triggered`); - context.extraOutputs.set(queueOutput, `${blob.toString()}-extraOutput`); - }, -}); +// app.storageBlob('storageBlobTriggerExtraOutput', { +// path: 'e2e-test-container/e2e-test-blob-trigger-shared-output-bug', +// connection: 'AzureWebJobsStorage', +// extraOutputs: [queueOutput], +// handler: (blob: Buffer, context: InvocationContext) => { +// context.log(`storageBlobTriggerExtraOutput was triggered`); +// context.extraOutputs.set(queueOutput, `${blob.toString()}-extraOutput`); +// }, +// }); From 655b7a3bbe59fc3d349fe74254a7d7e11eb3d376 Mon Sep 17 00:00:00 2001 From: Evan Roman Date: Mon, 21 Jul 2025 15:12:12 -0500 Subject: [PATCH 05/24] test --- .../storageBlobTriggerSharedOutputBug.ts | 52 +++++++++---------- src/storage.test.ts | 36 ++++++------- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/app/v4/src/functions/storageBlobTriggerSharedOutputBug.ts b/app/v4/src/functions/storageBlobTriggerSharedOutputBug.ts index 8c4d824e..99d1eb1c 100644 --- a/app/v4/src/functions/storageBlobTriggerSharedOutputBug.ts +++ b/app/v4/src/functions/storageBlobTriggerSharedOutputBug.ts @@ -1,31 +1,31 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { app, InvocationContext, output } from '@azure/functions'; +import { app, InvocationContext, output } from '@azure/functions'; -// // Test for bug https://github.com/Azure/azure-functions-nodejs-library/issues/179 +// Test for bug https://github.com/Azure/azure-functions-nodejs-library/issues/179 -// const queueOutput = output.storageQueue({ -// queueName: 'e2e-test-queue-trigger', -// connection: 'AzureWebJobsStorage', -// }); +const queueOutput = output.storageQueue({ + queueName: 'e2e-test-queue-trigger', + connection: 'AzureWebJobsStorage', +}); -// app.storageBlob('storageBlobTriggerReturnOutput', { -// path: 'e2e-test-container/e2e-test-blob-trigger-shared-output-bug', -// connection: 'AzureWebJobsStorage', -// return: queueOutput, -// handler: (blob: Buffer, context: InvocationContext) => { -// context.log(`storageBlobTriggerReturnOutput was triggered`); -// return `${blob.toString()}-returnOutput`; -// }, -// }); +app.storageBlob('storageBlobTriggerReturnOutput', { + path: 'e2e-test-container/e2e-test-blob-trigger-shared-output-bug', + connection: 'AzureWebJobsStorage', + return: queueOutput, + handler: (blob: Buffer, context: InvocationContext) => { + context.log(`storageBlobTriggerReturnOutput was triggered`); + return `${blob.toString()}-returnOutput`; + }, +}); -// app.storageBlob('storageBlobTriggerExtraOutput', { -// path: 'e2e-test-container/e2e-test-blob-trigger-shared-output-bug', -// connection: 'AzureWebJobsStorage', -// extraOutputs: [queueOutput], -// handler: (blob: Buffer, context: InvocationContext) => { -// context.log(`storageBlobTriggerExtraOutput was triggered`); -// context.extraOutputs.set(queueOutput, `${blob.toString()}-extraOutput`); -// }, -// }); +app.storageBlob('storageBlobTriggerExtraOutput', { + path: 'e2e-test-container/e2e-test-blob-trigger-shared-output-bug', + connection: 'AzureWebJobsStorage', + extraOutputs: [queueOutput], + handler: (blob: Buffer, context: InvocationContext) => { + context.log(`storageBlobTriggerExtraOutput was triggered`); + context.extraOutputs.set(queueOutput, `${blob.toString()}-extraOutput`); + }, +}); diff --git a/src/storage.test.ts b/src/storage.test.ts index ae659dad..c3ece231 100644 --- a/src/storage.test.ts +++ b/src/storage.test.ts @@ -6,7 +6,7 @@ import { ContainerClient } from '@azure/storage-blob'; // import { expect } from 'chai'; // import { default as fetch } from 'node-fetch'; // import { getFuncUrl } from './constants'; -import { waitForOutput } from './global.test'; +import { model, waitForOutput } from './global.test'; import { getRandomTestData } from './utils/getRandomTestData'; import { storageConnectionString } from './utils/connectionStrings'; @@ -85,23 +85,23 @@ describe('storage', () => { // }); // Test for bug https://github.com/Azure/azure-functions-nodejs-library/issues/179 - // it('Shared output bug', async function (this: Mocha.Context) { - // if (model === 'v3') { - // this.skip(); - // } + it('Shared output bug', async function (this: Mocha.Context) { + if (model === 'v3') { + this.skip(); + } - // const containerName = 'e2e-test-container'; - // const client = new ContainerClient(storageConnectionString, containerName); - // await client.createIfNotExists(); + const containerName = 'e2e-test-container'; + const client = new ContainerClient(storageConnectionString, containerName); + await client.createIfNotExists(); - // const message = getRandomTestData(); - // const messageBuffer = Buffer.from(message); - // const blobName = 'e2e-test-blob-trigger-shared-output-bug'; - // await client.uploadBlockBlob(blobName, messageBuffer, messageBuffer.byteLength); - - // await waitForOutput(`storageBlobTriggerReturnOutput was triggered`); - // await waitForOutput(`storageBlobTriggerExtraOutput was triggered`); - // await waitForOutput(`storageQueueTrigger was triggered by "${message}-returnOutput"`); - // await waitForOutput(`storageQueueTrigger was triggered by "${message}-extraOutput"`); - // }); + const message = getRandomTestData(); + const messageBuffer = Buffer.from(message); + const blobName = 'e2e-test-blob-trigger-shared-output-bug'; + await client.uploadBlockBlob(blobName, messageBuffer, messageBuffer.byteLength); + + await waitForOutput(`storageBlobTriggerReturnOutput was triggered`); + await waitForOutput(`storageBlobTriggerExtraOutput was triggered`); + await waitForOutput(`storageQueueTrigger was triggered by "${message}-returnOutput"`); + await waitForOutput(`storageQueueTrigger was triggered by "${message}-extraOutput"`); + }); }); From 655abcd3bfe7d5cb54cfba2505e68c7e038ce2f1 Mon Sep 17 00:00:00 2001 From: Evan Roman Date: Mon, 21 Jul 2025 15:30:02 -0500 Subject: [PATCH 06/24] test --- __azurite_db_blob__.json | 1 - __azurite_db_blob_extent__.json | 1 - app/v3/httpTriggerStorageQueueOutput/index.ts | 22 +++---- app/v3/storageQueueTrigger/index.ts | 14 ++-- app/v3/storageQueueTriggerAndOutput/index.ts | 16 ++--- .../httpTriggerStorageQueueOutput.ts | 42 ++++++------ app/v4/src/functions/storageQueueTrigger.ts | 22 +++---- .../functions/storageQueueTriggerAndOutput.ts | 32 +++++----- src/storage.test.ts | 64 +++++++++---------- 9 files changed, 106 insertions(+), 108 deletions(-) delete mode 100644 __azurite_db_blob__.json delete mode 100644 __azurite_db_blob_extent__.json diff --git a/__azurite_db_blob__.json b/__azurite_db_blob__.json deleted file mode 100644 index 4d82d705..00000000 --- a/__azurite_db_blob__.json +++ /dev/null @@ -1 +0,0 @@ -{"filename":"c:\\Users\\evanroman\\source\\repos\\azure-functions-nodejs-e2e-tests\\__azurite_db_blob__.json","collections":[{"name":"$SERVICES_COLLECTION$","data":[],"idIndex":null,"binaryIndices":{},"constraints":null,"uniqueNames":["accountName"],"transforms":{},"objType":"$SERVICES_COLLECTION$","dirty":false,"cachedIndex":null,"cachedBinaryIndex":null,"cachedData":null,"adaptiveBinaryIndices":true,"transactional":false,"cloneObjects":false,"cloneMethod":"parse-stringify","asyncListeners":false,"disableMeta":false,"disableChangesApi":true,"disableDeltaChangesApi":true,"autoupdate":false,"serializableIndices":true,"disableFreeze":true,"ttl":null,"maxId":0,"DynamicViews":[],"events":{"insert":[],"update":[],"pre-insert":[],"pre-update":[],"close":[],"flushbuffer":[],"error":[],"delete":[null],"warning":[null]},"changes":[],"dirtyIds":[]},{"name":"$CONTAINERS_COLLECTION$","data":[],"idIndex":null,"binaryIndices":{"accountName":{"name":"accountName","dirty":false,"values":[]},"name":{"name":"name","dirty":false,"values":[]}},"constraints":null,"uniqueNames":[],"transforms":{},"objType":"$CONTAINERS_COLLECTION$","dirty":false,"cachedIndex":null,"cachedBinaryIndex":null,"cachedData":null,"adaptiveBinaryIndices":true,"transactional":false,"cloneObjects":false,"cloneMethod":"parse-stringify","asyncListeners":false,"disableMeta":false,"disableChangesApi":true,"disableDeltaChangesApi":true,"autoupdate":false,"serializableIndices":true,"disableFreeze":true,"ttl":null,"maxId":0,"DynamicViews":[],"events":{"insert":[],"update":[],"pre-insert":[],"pre-update":[],"close":[],"flushbuffer":[],"error":[],"delete":[null],"warning":[null]},"changes":[],"dirtyIds":[]},{"name":"$BLOBS_COLLECTION$","data":[],"idIndex":null,"binaryIndices":{"accountName":{"name":"accountName","dirty":false,"values":[]},"containerName":{"name":"containerName","dirty":false,"values":[]},"name":{"name":"name","dirty":false,"values":[]},"snapshot":{"name":"snapshot","dirty":false,"values":[]}},"constraints":null,"uniqueNames":[],"transforms":{},"objType":"$BLOBS_COLLECTION$","dirty":false,"cachedIndex":null,"cachedBinaryIndex":null,"cachedData":null,"adaptiveBinaryIndices":true,"transactional":false,"cloneObjects":false,"cloneMethod":"parse-stringify","asyncListeners":false,"disableMeta":false,"disableChangesApi":true,"disableDeltaChangesApi":true,"autoupdate":false,"serializableIndices":true,"disableFreeze":true,"ttl":null,"maxId":0,"DynamicViews":[],"events":{"insert":[],"update":[],"pre-insert":[],"pre-update":[],"close":[],"flushbuffer":[],"error":[],"delete":[null],"warning":[null]},"changes":[],"dirtyIds":[]},{"name":"$BLOCKS_COLLECTION$","data":[],"idIndex":null,"binaryIndices":{"accountName":{"name":"accountName","dirty":false,"values":[]},"containerName":{"name":"containerName","dirty":false,"values":[]},"blobName":{"name":"blobName","dirty":false,"values":[]},"name":{"name":"name","dirty":false,"values":[]}},"constraints":null,"uniqueNames":[],"transforms":{},"objType":"$BLOCKS_COLLECTION$","dirty":false,"cachedIndex":null,"cachedBinaryIndex":null,"cachedData":null,"adaptiveBinaryIndices":true,"transactional":false,"cloneObjects":false,"cloneMethod":"parse-stringify","asyncListeners":false,"disableMeta":false,"disableChangesApi":true,"disableDeltaChangesApi":true,"autoupdate":false,"serializableIndices":true,"disableFreeze":true,"ttl":null,"maxId":0,"DynamicViews":[],"events":{"insert":[],"update":[],"pre-insert":[],"pre-update":[],"close":[],"flushbuffer":[],"error":[],"delete":[null],"warning":[null]},"changes":[],"dirtyIds":[]}],"databaseVersion":1.5,"engineVersion":1.5,"autosave":true,"autosaveInterval":5000,"autosaveHandle":null,"throttledSaves":true,"options":{"persistenceMethod":"fs","autosave":true,"autosaveInterval":5000,"serializationMethod":"normal","destructureDelimiter":"$<\n"},"persistenceMethod":"fs","persistenceAdapter":null,"verbose":false,"events":{"init":[null],"loaded":[],"flushChanges":[],"close":[],"changes":[],"warning":[]},"ENV":"NODEJS"} \ No newline at end of file diff --git a/__azurite_db_blob_extent__.json b/__azurite_db_blob_extent__.json deleted file mode 100644 index 06515548..00000000 --- a/__azurite_db_blob_extent__.json +++ /dev/null @@ -1 +0,0 @@ -{"filename":"c:\\Users\\evanroman\\source\\repos\\azure-functions-nodejs-e2e-tests\\__azurite_db_blob_extent__.json","collections":[{"name":"$EXTENTS_COLLECTION$","data":[],"idIndex":null,"binaryIndices":{"id":{"name":"id","dirty":false,"values":[]}},"constraints":null,"uniqueNames":[],"transforms":{},"objType":"$EXTENTS_COLLECTION$","dirty":false,"cachedIndex":null,"cachedBinaryIndex":null,"cachedData":null,"adaptiveBinaryIndices":true,"transactional":false,"cloneObjects":false,"cloneMethod":"parse-stringify","asyncListeners":false,"disableMeta":false,"disableChangesApi":true,"disableDeltaChangesApi":true,"autoupdate":false,"serializableIndices":true,"disableFreeze":true,"ttl":null,"maxId":0,"DynamicViews":[],"events":{"insert":[],"update":[],"pre-insert":[],"pre-update":[],"close":[],"flushbuffer":[],"error":[],"delete":[null],"warning":[null]},"changes":[],"dirtyIds":[]}],"databaseVersion":1.5,"engineVersion":1.5,"autosave":true,"autosaveInterval":5000,"autosaveHandle":null,"throttledSaves":true,"options":{"persistenceMethod":"fs","autosave":true,"autosaveInterval":5000,"serializationMethod":"normal","destructureDelimiter":"$<\n"},"persistenceMethod":"fs","persistenceAdapter":null,"verbose":false,"events":{"init":[null],"loaded":[],"flushChanges":[],"close":[],"changes":[],"warning":[]},"ENV":"NODEJS"} \ No newline at end of file diff --git a/app/v3/httpTriggerStorageQueueOutput/index.ts b/app/v3/httpTriggerStorageQueueOutput/index.ts index 8a663ae4..3f3252c0 100644 --- a/app/v3/httpTriggerStorageQueueOutput/index.ts +++ b/app/v3/httpTriggerStorageQueueOutput/index.ts @@ -1,14 +1,14 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { AzureFunction, Context, HttpRequest } from '@azure/functions'; +import { AzureFunction, Context, HttpRequest } from '@azure/functions'; -// const httpTriggerStorageQueueOutput: AzureFunction = async function ( -// context: Context, -// request: HttpRequest -// ): Promise { -// context.bindings.outputMsg = request.body.output; -// context.res = { body: 'done' }; -// }; +const httpTriggerStorageQueueOutput: AzureFunction = async function ( + context: Context, + request: HttpRequest +): Promise { + context.bindings.outputMsg = request.body.output; + context.res = { body: 'done' }; +}; -// export default httpTriggerStorageQueueOutput; +export default httpTriggerStorageQueueOutput; diff --git a/app/v3/storageQueueTrigger/index.ts b/app/v3/storageQueueTrigger/index.ts index bd4359bb..8986179e 100644 --- a/app/v3/storageQueueTrigger/index.ts +++ b/app/v3/storageQueueTrigger/index.ts @@ -1,10 +1,10 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { AzureFunction, Context } from '@azure/functions'; +import { AzureFunction, Context } from '@azure/functions'; -// const queueTrigger: AzureFunction = async function (context: Context, myQueueItem: string): Promise { -// context.log(`storageQueueTrigger was triggered by "${myQueueItem}"`); -// }; +const queueTrigger: AzureFunction = async function (context: Context, myQueueItem: string): Promise { + context.log(`storageQueueTrigger was triggered by "${myQueueItem}"`); +}; -// export default queueTrigger; +export default queueTrigger; diff --git a/app/v3/storageQueueTriggerAndOutput/index.ts b/app/v3/storageQueueTriggerAndOutput/index.ts index 458f91ef..79ee5283 100644 --- a/app/v3/storageQueueTriggerAndOutput/index.ts +++ b/app/v3/storageQueueTriggerAndOutput/index.ts @@ -1,11 +1,11 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { AzureFunction, Context } from '@azure/functions'; +import { AzureFunction, Context } from '@azure/functions'; -// const queueTrigger: AzureFunction = async function (context: Context, myQueueItem: string): Promise { -// context.log(`storageQueueTriggerAndOutput was triggered by "${myQueueItem}"`); -// return myQueueItem; -// }; +const queueTrigger: AzureFunction = async function (context: Context, myQueueItem: string): Promise { + context.log(`storageQueueTriggerAndOutput was triggered by "${myQueueItem}"`); + return myQueueItem; +}; -// export default queueTrigger; +export default queueTrigger; diff --git a/app/v4/src/functions/httpTriggerStorageQueueOutput.ts b/app/v4/src/functions/httpTriggerStorageQueueOutput.ts index 53d9b2a2..5b853fd8 100644 --- a/app/v4/src/functions/httpTriggerStorageQueueOutput.ts +++ b/app/v4/src/functions/httpTriggerStorageQueueOutput.ts @@ -1,25 +1,25 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { app, HttpRequest, HttpResponseInit, InvocationContext, output } from '@azure/functions'; +import { app, HttpRequest, HttpResponseInit, InvocationContext, output } from '@azure/functions'; -// const storageOutput = output.storageQueue({ -// queueName: 'e2e-test-queue-trigger', -// connection: 'e2eTest_storage', -// }); +const storageOutput = output.storageQueue({ + queueName: 'e2e-test-queue-trigger', + connection: 'AzureWebJobsStorage', +}); -// export async function httpTriggerStorageQueueOutput( -// request: HttpRequest, -// context: InvocationContext -// ): Promise { -// const body = <{ output: any }>await request.json(); -// context.extraOutputs.set(storageOutput, body.output); -// return { body: 'done' }; -// } +export async function httpTriggerStorageQueueOutput( + request: HttpRequest, + context: InvocationContext +): Promise { + const body = <{ output: any }>await request.json(); + context.extraOutputs.set(storageOutput, body.output); + return { body: 'done' }; +} -// app.http('httpTriggerStorageQueueOutput', { -// methods: ['POST'], -// authLevel: 'anonymous', -// extraOutputs: [storageOutput], -// handler: httpTriggerStorageQueueOutput, -// }); +app.http('httpTriggerStorageQueueOutput', { + methods: ['POST'], + authLevel: 'anonymous', + extraOutputs: [storageOutput], + handler: httpTriggerStorageQueueOutput, +}); diff --git a/app/v4/src/functions/storageQueueTrigger.ts b/app/v4/src/functions/storageQueueTrigger.ts index a11895e1..3cce0a19 100644 --- a/app/v4/src/functions/storageQueueTrigger.ts +++ b/app/v4/src/functions/storageQueueTrigger.ts @@ -1,14 +1,14 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { app, InvocationContext } from '@azure/functions'; +import { app, InvocationContext } from '@azure/functions'; -// export async function storageQueueTrigger(queueItem: string, context: InvocationContext): Promise { -// context.log(`storageQueueTrigger was triggered by "${queueItem}"`); -// } +export async function storageQueueTrigger(queueItem: string, context: InvocationContext): Promise { + context.log(`storageQueueTrigger was triggered by "${queueItem}"`); +} -// app.storageQueue('storageQueueTrigger', { -// queueName: 'e2e-test-queue-trigger', -// connection: 'e2eTest_storage', -// handler: storageQueueTrigger, -// }); +app.storageQueue('storageQueueTrigger', { + queueName: 'e2e-test-queue-trigger', + connection: 'AzureWebJobsStorage', + handler: storageQueueTrigger, +}); diff --git a/app/v4/src/functions/storageQueueTriggerAndOutput.ts b/app/v4/src/functions/storageQueueTriggerAndOutput.ts index faa110b2..2c5efc4e 100644 --- a/app/v4/src/functions/storageQueueTriggerAndOutput.ts +++ b/app/v4/src/functions/storageQueueTriggerAndOutput.ts @@ -1,19 +1,19 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { app, InvocationContext, output } from '@azure/functions'; +import { app, InvocationContext, output } from '@azure/functions'; -// export async function storageQueueTriggerAndOutput(queueItem: string, context: InvocationContext): Promise { -// context.log(`storageQueueTriggerAndOutput was triggered by "${queueItem}"`); -// return queueItem; -// } +export async function storageQueueTriggerAndOutput(queueItem: string, context: InvocationContext): Promise { + context.log(`storageQueueTriggerAndOutput was triggered by "${queueItem}"`); + return queueItem; +} -// app.storageQueue('storageQueueTriggerAndOutput', { -// queueName: 'e2e-test-queue-trigger-and-output', -// connection: 'e2eTest_storage', -// return: output.storageQueue({ -// queueName: 'e2e-test-queue-trigger', -// connection: 'e2eTest_storage', -// }), -// handler: storageQueueTriggerAndOutput, -// }); +app.storageQueue('storageQueueTriggerAndOutput', { + queueName: 'e2e-test-queue-trigger-and-output', + connection: 'AzureWebJobsStorage', + return: output.storageQueue({ + queueName: 'e2e-test-queue-trigger', + connection: 'AzureWebJobsStorage', + }), + handler: storageQueueTriggerAndOutput, +}); diff --git a/src/storage.test.ts b/src/storage.test.ts index c3ece231..ff8a2ccb 100644 --- a/src/storage.test.ts +++ b/src/storage.test.ts @@ -2,44 +2,44 @@ // Licensed under the MIT License. import { ContainerClient } from '@azure/storage-blob'; -// import { QueueClient } from '@azure/storage-queue'; +import { QueueClient } from '@azure/storage-queue'; // import { expect } from 'chai'; -// import { default as fetch } from 'node-fetch'; -// import { getFuncUrl } from './constants'; +import { default as fetch } from 'node-fetch'; +import { getFuncUrl } from './constants'; import { model, waitForOutput } from './global.test'; import { getRandomTestData } from './utils/getRandomTestData'; import { storageConnectionString } from './utils/connectionStrings'; describe('storage', () => { -// it('queue trigger and output', async () => { -// const client = new QueueClient(storageConnectionString, 'e2e-test-queue-trigger-and-output'); -// await client.createIfNotExists(); - -// const message = getRandomTestData(); -// await client.sendMessage(Buffer.from(message).toString('base64')); - -// await waitForOutput(`storageQueueTriggerAndOutput was triggered by "${message}"`); -// await waitForOutput(`storageQueueTrigger was triggered by "${message}"`); -// }); - - // it('queue extra output', async () => { - // const url = getFuncUrl('httpTriggerStorageQueueOutput'); - - // // single - // const message = getRandomTestData(); - // await fetch(url, { method: 'POST', body: JSON.stringify({ output: message }) }); - // await waitForOutput(`storageQueueTrigger was triggered by "${message}"`); - - // // bulk - // const bulkMsgs: string[] = []; - // for (let i = 0; i < 5; i++) { - // bulkMsgs.push(getRandomTestData()); - // } - // await fetch(url, { method: 'POST', body: JSON.stringify({ output: bulkMsgs }) }); - // for (const msg of bulkMsgs) { - // await waitForOutput(`storageQueueTrigger was triggered by "${msg}"`); - // } - // }); + it('queue trigger and output', async () => { + const client = new QueueClient(storageConnectionString, 'e2e-test-queue-trigger-and-output'); + await client.createIfNotExists(); + + const message = getRandomTestData(); + await client.sendMessage(Buffer.from(message).toString('base64')); + + await waitForOutput(`storageQueueTriggerAndOutput was triggered by "${message}"`); + await waitForOutput(`storageQueueTrigger was triggered by "${message}"`); + }); + + it('queue extra output', async () => { + const url = getFuncUrl('httpTriggerStorageQueueOutput'); + + // single + const message = getRandomTestData(); + await fetch(url, { method: 'POST', body: JSON.stringify({ output: message }) }); + await waitForOutput(`storageQueueTrigger was triggered by "${message}"`); + + // bulk + const bulkMsgs: string[] = []; + for (let i = 0; i < 5; i++) { + bulkMsgs.push(getRandomTestData()); + } + await fetch(url, { method: 'POST', body: JSON.stringify({ output: bulkMsgs }) }); + for (const msg of bulkMsgs) { + await waitForOutput(`storageQueueTrigger was triggered by "${msg}"`); + } + }); it('blob trigger and output', async () => { const containerName = 'e2e-test-container'; From 3da7543ce4a132140738287ae494915c95de9585 Mon Sep 17 00:00:00 2001 From: Evan Roman Date: Mon, 21 Jul 2025 17:38:57 -0500 Subject: [PATCH 07/24] retry --- .../templates/test-node-version.yml | 5 ++++ src/constants.ts | 7 +++++ src/global.test.ts | 4 ++- src/utils/connectionStrings.ts | 2 ++ src/utils/servicebus/config.json | 28 ------------------- src/utils/servicebus/docker-compose.yml | 0 6 files changed, 17 insertions(+), 29 deletions(-) delete mode 100644 src/utils/servicebus/config.json delete mode 100644 src/utils/servicebus/docker-compose.yml diff --git a/azure-pipelines/templates/test-node-version.yml b/azure-pipelines/templates/test-node-version.yml index 380696db..788736b2 100644 --- a/azure-pipelines/templates/test-node-version.yml +++ b/azure-pipelines/templates/test-node-version.yml @@ -11,6 +11,11 @@ steps: versionSpec: ${{ parameters.nodeVersion }} displayName: 'Install Node ${{ parameters.nodeVersion }}' retryCountOnTaskFailure: 10 + - bash: | + docker pull mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-preview + docker run --detach --publish 8081:8081 --publish 1234:1234 mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-preview + docker ps + displayName: "Start CosmosDB Emulator" - bash: | docker compose -f src/utils/eventhub/docker-compose.yml pull docker compose -f src/utils/eventhub/docker-compose.yml up -d diff --git a/src/constants.ts b/src/constants.ts index 894caf79..1716da19 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -3,9 +3,16 @@ export namespace EnvVarNames { export const storage = 'AzureWebJobsStorage'; + export const cosmosDB = 'CosmosDBConnection'; export const eventHub = 'EventHubConnection'; } +export namespace CosmosDB { + export const dbName = 'e2eTestDB'; + export const triggerAndOutputContainerName = 'e2eTestContainerTriggerAndOutput'; + export const triggerContainerName = 'e2eTestContainerTrigger'; +} + 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/global.test.ts b/src/global.test.ts index f07a6118..cb3cbd5e 100644 --- a/src/global.test.ts +++ b/src/global.test.ts @@ -8,6 +8,7 @@ import semver from 'semver'; import { combinedFolder, defaultTimeout, EnvVarNames, oldConfigSuffix } from './constants'; import { getModelArg, getOldConfigArg, Model } from './getModelArg'; import { + cosmosDBConnectionString, eventHubConnectionString, initializeConnectionStrings, storageConnectionString @@ -107,9 +108,10 @@ async function startFuncProcess(appPath: string): Promise { { IsEncrypted: false, Values: { - [EnvVarNames.storage]: storageConnectionString, FUNCTIONS_WORKER_RUNTIME: 'node', logging__logLevel__Worker: 'debug', + [EnvVarNames.storage]: storageConnectionString, + [EnvVarNames.cosmosDB]: cosmosDBConnectionString, [EnvVarNames.eventHub]: eventHubConnectionString, FUNCTIONS_REQUEST_BODY_SIZE_LIMIT: '4294967296', }, diff --git a/src/utils/connectionStrings.ts b/src/utils/connectionStrings.ts index ed8cecc3..e65db531 100644 --- a/src/utils/connectionStrings.ts +++ b/src/utils/connectionStrings.ts @@ -2,9 +2,11 @@ // Licensed under the MIT License. export let storageConnectionString: string; +export let cosmosDBConnectionString: string; export let eventHubConnectionString: string; export async function initializeConnectionStrings(): Promise { storageConnectionString = "UseDevelopmentStorage=true"; + cosmosDBConnectionString = "AccountEndpoint=http://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="; eventHubConnectionString = "Endpoint=sb://localhost;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=SAS_KEY_VALUE;UseDevelopmentEmulator=true;"; } diff --git a/src/utils/servicebus/config.json b/src/utils/servicebus/config.json deleted file mode 100644 index 20cf8344..00000000 --- a/src/utils/servicebus/config.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "UserConfig": { - "Namespaces": [ - { - "Name": "sbemulatorns", - "Queues": [ - { - "Name": "testqueue", - "Properties": { - "DeadLetteringOnMessageExpiration": false, - "DefaultMessageTimeToLive": "PT1H", - "DuplicateDetectionHistoryTimeWindow": "PT20S", - "ForwardDeadLetteredMessagesTo": "", - "ForwardTo": "", - "LockDuration": "PT1M", - "MaxDeliveryCount": 10, - "RequiresDuplicateDetection": false, - "RequiresSession": false - } - } - ] - } - ], - "Logging": { - "Type": "File" - } - } -} \ No newline at end of file diff --git a/src/utils/servicebus/docker-compose.yml b/src/utils/servicebus/docker-compose.yml deleted file mode 100644 index e69de29b..00000000 From 2314cce8ff5bbd18ed0475e2c949b12fd850a3f1 Mon Sep 17 00:00:00 2001 From: Evan Roman Date: Mon, 21 Jul 2025 17:49:15 -0500 Subject: [PATCH 08/24] retry --- app/v3-oldConfig/cosmosDBTrigger/function.json | 2 +- app/v3-oldConfig/cosmosDBTriggerAndOutput/function.json | 4 ++-- app/v3-oldConfig/httpTriggerCosmosDBInput/function.json | 2 +- app/v3-oldConfig/httpTriggerCosmosDBOutput/function.json | 2 +- app/v3/cosmosDBTrigger/function.json | 2 +- app/v3/cosmosDBTriggerAndOutput/function.json | 4 ++-- app/v3/httpTriggerCosmosDBInput/function.json | 2 +- app/v3/httpTriggerCosmosDBOutput/function.json | 2 +- app/v4-oldConfig/src/functions/cosmosDBTrigger.ts | 2 +- app/v4-oldConfig/src/functions/cosmosDBTriggerAndOutput.ts | 4 ++-- app/v4-oldConfig/src/functions/httpTriggerCosmosDBInput.ts | 2 +- app/v4-oldConfig/src/functions/httpTriggerCosmosDBOutput.ts | 2 +- app/v4/src/functions/cosmosDBTrigger.ts | 2 +- app/v4/src/functions/cosmosDBTriggerAndOutput.ts | 4 ++-- app/v4/src/functions/httpTriggerCosmosDBInput.ts | 2 +- app/v4/src/functions/httpTriggerCosmosDBOutput.ts | 2 +- 16 files changed, 20 insertions(+), 20 deletions(-) diff --git a/app/v3-oldConfig/cosmosDBTrigger/function.json b/app/v3-oldConfig/cosmosDBTrigger/function.json index 900e5d06..702e4a80 100644 --- a/app/v3-oldConfig/cosmosDBTrigger/function.json +++ b/app/v3-oldConfig/cosmosDBTrigger/function.json @@ -5,7 +5,7 @@ "name": "documents", "direction": "in", "leaseCollectionName": "leases", - "connectionStringSetting": "e2eTest_cosmosDB", + "connectionStringSetting": "CosmosDBConnection", "databaseName": "e2eTestDB", "collectionName": "e2eTestContainerTrigger", "createLeaseCollectionIfNotExists": true, diff --git a/app/v3-oldConfig/cosmosDBTriggerAndOutput/function.json b/app/v3-oldConfig/cosmosDBTriggerAndOutput/function.json index 154511d4..19be81df 100644 --- a/app/v3-oldConfig/cosmosDBTriggerAndOutput/function.json +++ b/app/v3-oldConfig/cosmosDBTriggerAndOutput/function.json @@ -5,7 +5,7 @@ "name": "documents", "direction": "in", "leaseCollectionName": "leases", - "connectionStringSetting": "e2eTest_cosmosDB", + "connectionStringSetting": "CosmosDBConnection", "databaseName": "e2eTestDB", "collectionName": "e2eTestContainerTriggerAndOutput", "createLeaseCollectionIfNotExists": true, @@ -15,7 +15,7 @@ "type": "cosmosDB", "name": "$return", "direction": "out", - "connectionStringSetting": "e2eTest_cosmosDB", + "connectionStringSetting": "CosmosDBConnection", "databaseName": "e2eTestDB", "collectionName": "e2eTestContainerTrigger" } diff --git a/app/v3-oldConfig/httpTriggerCosmosDBInput/function.json b/app/v3-oldConfig/httpTriggerCosmosDBInput/function.json index f454fcaf..5f0426c3 100644 --- a/app/v3-oldConfig/httpTriggerCosmosDBInput/function.json +++ b/app/v3-oldConfig/httpTriggerCosmosDBInput/function.json @@ -16,7 +16,7 @@ "type": "cosmosDB", "name": "inputDoc", "direction": "in", - "connectionStringSetting": "e2eTest_cosmosDB", + "connectionStringSetting": "CosmosDBConnection", "databaseName": "e2eTestDB", "collectionName": "e2eTestContainerTriggerAndOutput", "partitionKey": "testPartKey", diff --git a/app/v3-oldConfig/httpTriggerCosmosDBOutput/function.json b/app/v3-oldConfig/httpTriggerCosmosDBOutput/function.json index 6d99f5b7..9e9aeee4 100644 --- a/app/v3-oldConfig/httpTriggerCosmosDBOutput/function.json +++ b/app/v3-oldConfig/httpTriggerCosmosDBOutput/function.json @@ -16,7 +16,7 @@ "type": "cosmosDB", "name": "outputDoc", "direction": "out", - "connectionStringSetting": "e2eTest_cosmosDB", + "connectionStringSetting": "CosmosDBConnection", "databaseName": "e2eTestDB", "collectionName": "e2eTestContainerTriggerAndOutput" } diff --git a/app/v3/cosmosDBTrigger/function.json b/app/v3/cosmosDBTrigger/function.json index 7f560a63..02e9d917 100644 --- a/app/v3/cosmosDBTrigger/function.json +++ b/app/v3/cosmosDBTrigger/function.json @@ -5,7 +5,7 @@ "name": "documents", "direction": "in", "leaseContainerName": "leases", - "connection": "e2eTest_cosmosDB", + "connection": "CosmosDBConnection", "databaseName": "e2eTestDB", "containerName": "e2eTestContainerTrigger", "createLeaseContainerIfNotExists": true, diff --git a/app/v3/cosmosDBTriggerAndOutput/function.json b/app/v3/cosmosDBTriggerAndOutput/function.json index 96881bdf..7c9d7487 100644 --- a/app/v3/cosmosDBTriggerAndOutput/function.json +++ b/app/v3/cosmosDBTriggerAndOutput/function.json @@ -5,7 +5,7 @@ "name": "documents", "direction": "in", "leaseContainerName": "leases", - "connection": "e2eTest_cosmosDB", + "connection": "CosmosDBConnection", "databaseName": "e2eTestDB", "containerName": "e2eTestContainerTriggerAndOutput", "createLeaseContainerIfNotExists": true, @@ -15,7 +15,7 @@ "type": "cosmosDB", "name": "$return", "direction": "out", - "connection": "e2eTest_cosmosDB", + "connection": "CosmosDBConnection", "databaseName": "e2eTestDB", "containerName": "e2eTestContainerTrigger" } diff --git a/app/v3/httpTriggerCosmosDBInput/function.json b/app/v3/httpTriggerCosmosDBInput/function.json index d3ddeb95..fb8d4232 100644 --- a/app/v3/httpTriggerCosmosDBInput/function.json +++ b/app/v3/httpTriggerCosmosDBInput/function.json @@ -16,7 +16,7 @@ "type": "cosmosDB", "name": "inputDoc", "direction": "in", - "connection": "e2eTest_cosmosDB", + "connection": "CosmosDBConnection", "databaseName": "e2eTestDB", "containerName": "e2eTestContainerTriggerAndOutput", "partitionKey": "testPartKey", diff --git a/app/v3/httpTriggerCosmosDBOutput/function.json b/app/v3/httpTriggerCosmosDBOutput/function.json index cfc7a368..fc540372 100644 --- a/app/v3/httpTriggerCosmosDBOutput/function.json +++ b/app/v3/httpTriggerCosmosDBOutput/function.json @@ -16,7 +16,7 @@ "type": "cosmosDB", "name": "outputDoc", "direction": "out", - "connection": "e2eTest_cosmosDB", + "connection": "CosmosDBConnection", "databaseName": "e2eTestDB", "containerName": "e2eTestContainerTriggerAndOutput" } diff --git a/app/v4-oldConfig/src/functions/cosmosDBTrigger.ts b/app/v4-oldConfig/src/functions/cosmosDBTrigger.ts index a04a233c..bdec0a40 100644 --- a/app/v4-oldConfig/src/functions/cosmosDBTrigger.ts +++ b/app/v4-oldConfig/src/functions/cosmosDBTrigger.ts @@ -11,7 +11,7 @@ // } // app.cosmosDB('cosmosDBTrigger', { -// connectionStringSetting: 'e2eTest_cosmosDB', +// connectionStringSetting: 'CosmosDBConnection', // databaseName: 'e2eTestDB', // collectionName: 'e2eTestContainerTrigger', // createLeaseCollectionIfNotExists: true, diff --git a/app/v4-oldConfig/src/functions/cosmosDBTriggerAndOutput.ts b/app/v4-oldConfig/src/functions/cosmosDBTriggerAndOutput.ts index fbc87c7f..89eda8f4 100644 --- a/app/v4-oldConfig/src/functions/cosmosDBTriggerAndOutput.ts +++ b/app/v4-oldConfig/src/functions/cosmosDBTriggerAndOutput.ts @@ -12,13 +12,13 @@ // } // app.cosmosDB('cosmosDBTriggerAndOutput', { -// connectionStringSetting: 'e2eTest_cosmosDB', +// connectionStringSetting: 'CosmosDBConnection', // databaseName: 'e2eTestDB', // collectionName: 'e2eTestContainerTriggerAndOutput', // createLeaseCollectionIfNotExists: true, // leaseCollectionPrefix: '1', // return: output.cosmosDB({ -// connectionStringSetting: 'e2eTest_cosmosDB', +// connectionStringSetting: 'CosmosDBConnection', // databaseName: 'e2eTestDB', // collectionName: 'e2eTestContainerTrigger', // }), diff --git a/app/v4-oldConfig/src/functions/httpTriggerCosmosDBInput.ts b/app/v4-oldConfig/src/functions/httpTriggerCosmosDBInput.ts index 96bb41a7..7c65e72e 100644 --- a/app/v4-oldConfig/src/functions/httpTriggerCosmosDBInput.ts +++ b/app/v4-oldConfig/src/functions/httpTriggerCosmosDBInput.ts @@ -8,7 +8,7 @@ // collectionName: 'e2eTestContainerTriggerAndOutput', // id: '{Query.id}', // partitionKey: 'testPartKey', -// connectionStringSetting: 'e2eTest_cosmosDB', +// connectionStringSetting: 'CosmosDBConnection', // }); // export async function httpTriggerCosmosDBInput( diff --git a/app/v4-oldConfig/src/functions/httpTriggerCosmosDBOutput.ts b/app/v4-oldConfig/src/functions/httpTriggerCosmosDBOutput.ts index 9383420c..35740acb 100644 --- a/app/v4-oldConfig/src/functions/httpTriggerCosmosDBOutput.ts +++ b/app/v4-oldConfig/src/functions/httpTriggerCosmosDBOutput.ts @@ -6,7 +6,7 @@ // const cosmosOutput = output.cosmosDB({ // databaseName: 'e2eTestDB', // collectionName: 'e2eTestContainerTrigger', -// connectionStringSetting: 'e2eTest_cosmosDB', +// connectionStringSetting: 'CosmosDBConnection', // }); // export async function httpTriggerCosmosDBOutput( diff --git a/app/v4/src/functions/cosmosDBTrigger.ts b/app/v4/src/functions/cosmosDBTrigger.ts index 832f7d91..b32e3c03 100644 --- a/app/v4/src/functions/cosmosDBTrigger.ts +++ b/app/v4/src/functions/cosmosDBTrigger.ts @@ -11,7 +11,7 @@ // } // app.cosmosDB('cosmosDBTrigger', { -// connection: 'e2eTest_cosmosDB', +// connection: 'CosmosDBConnection', // databaseName: 'e2eTestDB', // containerName: 'e2eTestContainerTrigger', // createLeaseContainerIfNotExists: true, diff --git a/app/v4/src/functions/cosmosDBTriggerAndOutput.ts b/app/v4/src/functions/cosmosDBTriggerAndOutput.ts index d96785cb..37099504 100644 --- a/app/v4/src/functions/cosmosDBTriggerAndOutput.ts +++ b/app/v4/src/functions/cosmosDBTriggerAndOutput.ts @@ -12,13 +12,13 @@ // } // app.cosmosDB('cosmosDBTriggerAndOutput', { -// connection: 'e2eTest_cosmosDB', +// connection: 'CosmosDBConnection', // databaseName: 'e2eTestDB', // containerName: 'e2eTestContainerTriggerAndOutput', // createLeaseContainerIfNotExists: true, // leaseContainerPrefix: '1', // return: output.cosmosDB({ -// connection: 'e2eTest_cosmosDB', +// connection: 'CosmosDBConnection', // databaseName: 'e2eTestDB', // containerName: 'e2eTestContainerTrigger', // }), diff --git a/app/v4/src/functions/httpTriggerCosmosDBInput.ts b/app/v4/src/functions/httpTriggerCosmosDBInput.ts index 0ff46291..25e0f4fd 100644 --- a/app/v4/src/functions/httpTriggerCosmosDBInput.ts +++ b/app/v4/src/functions/httpTriggerCosmosDBInput.ts @@ -8,7 +8,7 @@ // containerName: 'e2eTestContainerTriggerAndOutput', // id: '{Query.id}', // partitionKey: 'testPartKey', -// connection: 'e2eTest_cosmosDB', +// connection: 'CosmosDBConnection', // }); // export async function httpTriggerCosmosDBInput( diff --git a/app/v4/src/functions/httpTriggerCosmosDBOutput.ts b/app/v4/src/functions/httpTriggerCosmosDBOutput.ts index 1f56ab29..12eeb42b 100644 --- a/app/v4/src/functions/httpTriggerCosmosDBOutput.ts +++ b/app/v4/src/functions/httpTriggerCosmosDBOutput.ts @@ -6,7 +6,7 @@ // const cosmosOutput = output.cosmosDB({ // databaseName: 'e2eTestDB', // containerName: 'e2eTestContainerTrigger', -// connection: 'e2eTest_cosmosDB', +// connection: 'CosmosDBConnection', // }); // export async function httpTriggerCosmosDBOutput( From 288f20cc3b93c75000c9afe61bed1618ed964520 Mon Sep 17 00:00:00 2001 From: Evan Roman Date: Mon, 21 Jul 2025 19:18:38 -0500 Subject: [PATCH 09/24] add --- app/v4/src/functions/cosmosDBTrigger.ts | 34 ++++++------ .../src/functions/cosmosDBTriggerAndOutput.ts | 46 ++++++++-------- src/cosmosDB.test.ts | 53 +++++++++++++++++++ 3 files changed, 93 insertions(+), 40 deletions(-) create mode 100644 src/cosmosDB.test.ts diff --git a/app/v4/src/functions/cosmosDBTrigger.ts b/app/v4/src/functions/cosmosDBTrigger.ts index b32e3c03..1f5a5041 100644 --- a/app/v4/src/functions/cosmosDBTrigger.ts +++ b/app/v4/src/functions/cosmosDBTrigger.ts @@ -1,20 +1,20 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { app, InvocationContext } from '@azure/functions'; +import { app, InvocationContext } from '@azure/functions'; -// export async function cosmosDBTrigger(documents: unknown[], context: InvocationContext): Promise { -// context.log(`cosmosDBTrigger processed ${documents.length} documents`); -// for (const document of documents) { -// context.log(`cosmosDBTrigger was triggered by "${(document).testData}"`); -// } -// } +export async function cosmosDBTrigger(documents: unknown[], context: InvocationContext): Promise { + context.log(`cosmosDBTrigger processed ${documents.length} documents`); + for (const document of documents) { + context.log(`cosmosDBTrigger was triggered by "${(document).testData}"`); + } +} -// app.cosmosDB('cosmosDBTrigger', { -// connection: 'CosmosDBConnection', -// databaseName: 'e2eTestDB', -// containerName: 'e2eTestContainerTrigger', -// createLeaseContainerIfNotExists: true, -// leaseContainerPrefix: '2', -// handler: cosmosDBTrigger, -// }); +app.cosmosDB('cosmosDBTrigger', { + connection: 'CosmosDBConnection', + databaseName: 'e2eTestDB', + containerName: 'e2eTestContainerTrigger', + createLeaseContainerIfNotExists: true, + leaseContainerPrefix: '2', + handler: cosmosDBTrigger, +}); diff --git a/app/v4/src/functions/cosmosDBTriggerAndOutput.ts b/app/v4/src/functions/cosmosDBTriggerAndOutput.ts index 37099504..f658b801 100644 --- a/app/v4/src/functions/cosmosDBTriggerAndOutput.ts +++ b/app/v4/src/functions/cosmosDBTriggerAndOutput.ts @@ -1,26 +1,26 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { app, InvocationContext, output } from '@azure/functions'; +import { app, InvocationContext, output } from '@azure/functions'; -// export async function cosmosDBTriggerAndOutput(documents: unknown[], context: InvocationContext): Promise { -// context.log(`cosmosDBTriggerAndOutput processed ${documents.length} documents`); -// for (const document of documents) { -// context.log(`cosmosDBTriggerAndOutput was triggered by "${(document).testData}"`); -// } -// return documents; -// } +export async function cosmosDBTriggerAndOutput(documents: unknown[], context: InvocationContext): Promise { + context.log(`cosmosDBTriggerAndOutput processed ${documents.length} documents`); + for (const document of documents) { + context.log(`cosmosDBTriggerAndOutput was triggered by "${(document).testData}"`); + } + return documents; +} -// app.cosmosDB('cosmosDBTriggerAndOutput', { -// connection: 'CosmosDBConnection', -// databaseName: 'e2eTestDB', -// containerName: 'e2eTestContainerTriggerAndOutput', -// createLeaseContainerIfNotExists: true, -// leaseContainerPrefix: '1', -// return: output.cosmosDB({ -// connection: 'CosmosDBConnection', -// databaseName: 'e2eTestDB', -// containerName: 'e2eTestContainerTrigger', -// }), -// handler: cosmosDBTriggerAndOutput, -// }); +app.cosmosDB('cosmosDBTriggerAndOutput', { + connection: 'CosmosDBConnection', + databaseName: 'e2eTestDB', + containerName: 'e2eTestContainerTriggerAndOutput', + createLeaseContainerIfNotExists: true, + leaseContainerPrefix: '1', + return: output.cosmosDB({ + connection: 'CosmosDBConnection', + databaseName: 'e2eTestDB', + containerName: 'e2eTestContainerTrigger', + }), + handler: cosmosDBTriggerAndOutput, +}); diff --git a/src/cosmosDB.test.ts b/src/cosmosDB.test.ts new file mode 100644 index 00000000..b134a953 --- /dev/null +++ b/src/cosmosDB.test.ts @@ -0,0 +1,53 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. + +import { CosmosClient } from '@azure/cosmos'; +import { expect } from 'chai'; +import { default as fetch } from 'node-fetch'; +import { getFuncUrl, CosmosDB } from './constants'; +import { waitForOutput } from './global.test'; +import { cosmosDBConnectionString } from './utils/connectionStrings'; +import { getRandomTestData } from './utils/getRandomTestData'; + +describe('cosmosDB', () => { + it('trigger, output, input', async () => { + const client = new CosmosClient(cosmosDBConnectionString); + const container = client.database(CosmosDB.dbName).container(CosmosDB.triggerAndOutputContainerName); + const testData = getRandomTestData(); + const createdItem = await container.items.create({ testData, _partitionKey: 'testPartKey' }); + + await waitForOutput(`cosmosDBTriggerAndOutput processed 1 documents`); + await waitForOutput(`cosmosDBTriggerAndOutput was triggered by "${testData}"`); + await waitForOutput(`cosmosDBTrigger processed 1 documents`); + await waitForOutput(`cosmosDBTrigger was triggered by "${testData}"`); + + const url = `${getFuncUrl('httpTriggerCosmosDBInput')}?id=${createdItem.item.id}`; + const response = await fetch(url); + const body = await response.text(); + expect(body).to.equal(testData); + }); + + it('extra output', async () => { + type Doc = { id: string; testData: string }; + function getDoc(): Doc { + const data = getRandomTestData(); + return { id: data, testData: data }; + } + const url = getFuncUrl('httpTriggerCosmosDBOutput'); + + // single doc + const singleDoc = getDoc(); + await fetch(url, { method: 'POST', body: JSON.stringify(singleDoc) }); + await waitForOutput(`cosmosDBTrigger was triggered by "${singleDoc.testData}"`); + + // bulk docs + const bulkDocs: Doc[] = []; + for (let i = 0; i < 5; i++) { + bulkDocs.push(getDoc()); + } + await fetch(url, { method: 'POST', body: JSON.stringify(bulkDocs) }); + for (const doc of bulkDocs) { + await waitForOutput(`cosmosDBTrigger was triggered by "${doc.testData}"`); + } + }); +}); \ No newline at end of file From 1879fcbb7ddda70b910871b9ad4f30a22b206233 Mon Sep 17 00:00:00 2001 From: Evan Roman Date: Tue, 22 Jul 2025 02:40:22 -0500 Subject: [PATCH 10/24] make explicit --- src/constants.ts | 1 + src/global.test.ts | 3 +++ src/utils/azureCli.ts | 50 -------------------------------------- src/utils/setupCosmosDB.ts | 16 ++++++++++++ 4 files changed, 20 insertions(+), 50 deletions(-) delete mode 100644 src/utils/azureCli.ts create mode 100644 src/utils/setupCosmosDB.ts diff --git a/src/constants.ts b/src/constants.ts index 1716da19..63ca0ff9 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -11,6 +11,7 @@ export namespace CosmosDB { export const dbName = 'e2eTestDB'; export const triggerAndOutputContainerName = 'e2eTestContainerTriggerAndOutput'; export const triggerContainerName = 'e2eTestContainerTrigger'; + export const triggerDatabaseName = 'e2eTestDB'; } export namespace EventHub { diff --git a/src/global.test.ts b/src/global.test.ts index cb3cbd5e..f0472763 100644 --- a/src/global.test.ts +++ b/src/global.test.ts @@ -13,6 +13,7 @@ import { initializeConnectionStrings, storageConnectionString } from './utils/connectionStrings'; +import { setupCosmosDB } from './utils/setupCosmosDB'; import { delay } from './utils/delay'; import findProcess = require('find-process'); @@ -39,6 +40,8 @@ before(async function (this: Mocha.Context): Promise { await initializeConnectionStrings(); + await setupCosmosDB(); + isOldConfig = getOldConfigArg(); const appPath = isOldConfig ? path.join(__dirname, '..', 'app', combinedFolder, model + oldConfigSuffix) diff --git a/src/utils/azureCli.ts b/src/utils/azureCli.ts deleted file mode 100644 index cc7e6f8a..00000000 --- a/src/utils/azureCli.ts +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT License. - -import * as cp from 'child_process'; - -export async function getSubscriptionId(): Promise { - return executeCommand('az account show --query id -o tsv'); -} - -export async function getTenantId(): Promise { - return executeCommand('az account show --query tenantId -o tsv'); -} - -export async function getUserName(): Promise { - return executeCommand('az account show --query user.name -o tsv'); -} - -export async function getUserType(): Promise { - return executeCommand('az account show --query user.type -o tsv'); -} - -export async function getObjectId(userName: string): Promise { - const adCmd = (await getUserType()) === 'user' ? 'user' : 'sp'; - return executeCommand(`az ad ${adCmd} show --id ${userName} --query id -o tsv`); -} - -async function executeCommand(command: string): Promise { - return new Promise((resolve, reject) => { - let stdout = ''; - - const childProc = cp.spawn(command, { shell: true }); - - childProc.stdout?.on('data', (data) => { - stdout += data.toString(); - }); - - childProc.stderr?.on('data', (data) => { - console.error(data.toString()); - }); - - childProc.on('error', reject); - childProc.on('close', (code: number) => { - if (code === 0) { - resolve(stdout.trim()); - } else { - reject(new Error(`Command "${command}" failed with exit code ${code}`)); - } - }); - }); -} diff --git a/src/utils/setupCosmosDB.ts b/src/utils/setupCosmosDB.ts new file mode 100644 index 00000000..7767e750 --- /dev/null +++ b/src/utils/setupCosmosDB.ts @@ -0,0 +1,16 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. + +// The CosmosDB emulator requires a container and database to be created before running tests but after the emulator starts +// Otherwise the following error will occur: +// Microsoft.Azure.Cosmos.Client: This builder instance has already been used to build a processor. Create a new instance to build another. + +import { CosmosClient } from '@azure/cosmos'; +import { cosmosDBConnectionString } from './connectionStrings'; +import { CosmosDB } from '../constants'; + +export async function setupCosmosDB() { + const client = new CosmosClient(cosmosDBConnectionString); + await client.databases.createIfNotExists({ id: CosmosDB.triggerDatabaseName }); + await client.database(CosmosDB.triggerDatabaseName).containers.createIfNotExists({ id: CosmosDB.triggerAndOutputContainerName }); +} \ No newline at end of file From 3cbab29ceff4e0c122e579c555510bb743c2b92f Mon Sep 17 00:00:00 2001 From: Evan Roman Date: Tue, 22 Jul 2025 10:11:46 -0500 Subject: [PATCH 11/24] update --- package-lock.json | 325 +++++++++++++++++++++++++++------------------- package.json | 2 +- 2 files changed, 194 insertions(+), 133 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0b84cf79..74e081dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "@azure/arm-servicebus": "^6.1.0", "@azure/arm-sql": "^10.0.0", "@azure/arm-storage": "^18.1.0", - "@azure/cosmos": "^3.17.3", + "@azure/cosmos": "^4.5.0", "@azure/data-tables": "^13.2.2", "@azure/event-hubs": "^5.10.0", "@azure/identity": "^3.4.2", @@ -71,6 +71,46 @@ "node": ">=0.10.0" } }, + "node_modules/@azure-rest/core-client": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@azure-rest/core-client/-/core-client-2.5.0.tgz", + "integrity": "sha512-KMVIPxG6ygcQ1M2hKHahF7eddKejYsWTjoLIfTWiqnaj42dBkYzj4+S8rK9xxmlOaEHKZHcMrRbm0NfN4kgwHw==", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.9.0", + "@azure/core-rest-pipeline": "^1.5.0", + "@azure/core-tracing": "^1.0.1", + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure-rest/core-client/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure-rest/core-client/node_modules/@typespec/ts-http-runtime": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.0.tgz", + "integrity": "sha512-sOx1PKSuFwnIl7z4RN0Ls7N9AQawmR9r66eI5rFCzLDIs8HTIYrIpH9QjYWoX0lkgGrkLxXhi4QnK7MizPRrIg==", + "dependencies": { + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/@azure/abort-controller": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz", @@ -298,13 +338,13 @@ } }, "node_modules/@azure/core-http-compat": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@azure/core-http-compat/-/core-http-compat-2.1.2.tgz", - "integrity": "sha512-5MnV1yqzZwgNLLjlizsU3QqOeQChkIXw781Fwh1xdAqJR5AA32IUaq6xv1BICJvfbHoa+JYcaij2HFkhLbNTJQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@azure/core-http-compat/-/core-http-compat-2.3.0.tgz", + "integrity": "sha512-qLQujmUypBBG0gxHd0j6/Jdmul6ttl24c8WGiLXIk7IHXdBlfoBqW27hyz3Xn6xbfdyVSarl1Ttbk0AwnZBYCw==", "dependencies": { "@azure/abort-controller": "^2.0.0", "@azure/core-client": "^1.3.0", - "@azure/core-rest-pipeline": "^1.3.0" + "@azure/core-rest-pipeline": "^1.20.0" }, "engines": { "node": ">=18.0.0" @@ -342,47 +382,80 @@ } }, "node_modules/@azure/core-lro": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.5.4.tgz", - "integrity": "sha512-3GJiMVH7/10bulzOKGrrLeG/uCBH/9VtxqaMcB9lIqAeamI/xYQSHJL/KcsLDuH+yTjYpro/u6D/MuRe4dN70Q==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.7.2.tgz", + "integrity": "sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==", "dependencies": { - "@azure/abort-controller": "^1.0.0", + "@azure/abort-controller": "^2.0.0", "@azure/core-util": "^1.2.0", "@azure/logger": "^1.0.0", - "tslib": "^2.2.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-lro/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@azure/core-paging": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.5.0.tgz", - "integrity": "sha512-zqWdVIt+2Z+3wqxEOGzR5hXFZ8MGKK52x4vFLw8n58pR6ZfKRx3EXYTxTaYxYHc/PexPUTyimcTWFJbji9Z6Iw==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.6.2.tgz", + "integrity": "sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA==", "dependencies": { - "tslib": "^2.2.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" } }, "node_modules/@azure/core-rest-pipeline": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.12.1.tgz", - "integrity": "sha512-SsyWQ+T5MFQRX+M8H/66AlaI6HyCbQStGfFngx2fuiW+vKI2DkhtOvbYodPyf9fOe/ARLWWc3ohX54lQ5Kmaog==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.22.0.tgz", + "integrity": "sha512-OKHmb3/Kpm06HypvB3g6Q3zJuvyXcpxDpCS1PnU8OV6AJgSFaee/covXBcPbWc6XDDxtEPlbi3EMQ6nUiPaQtw==", "dependencies": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-auth": "^1.4.0", + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.8.0", "@azure/core-tracing": "^1.0.1", - "@azure/core-util": "^1.3.0", + "@azure/core-util": "^1.11.0", "@azure/logger": "^1.0.0", - "form-data": "^4.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "tslib": "^2.2.0" + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/@typespec/ts-http-runtime": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.0.tgz", + "integrity": "sha512-sOx1PKSuFwnIl7z4RN0Ls7N9AQawmR9r66eI5rFCzLDIs8HTIYrIpH9QjYWoX0lkgGrkLxXhi4QnK7MizPRrIg==", + "dependencies": { + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" } }, "node_modules/@azure/core-tracing": { @@ -433,34 +506,35 @@ } }, "node_modules/@azure/cosmos": { - "version": "3.17.3", - "resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-3.17.3.tgz", - "integrity": "sha512-wBglkQ6Irjv5Vo2iw8fd6eYj60WYRSSg4/0DBkeOP6BwQ4RA91znsOHd6s3qG6UAbNgYuzC9Nnq07vlFFZkHEw==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-4.5.0.tgz", + "integrity": "sha512-JsTh4twb6FcwP7rJwxQiNZQ/LGtuF6gmciaxY9Rnp6/A325Lhsw/SH4R2ArpT0yCvozbZpweIwdPfUkXVBtp5w==", "dependencies": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-auth": "^1.3.0", - "@azure/core-rest-pipeline": "^1.2.0", - "@azure/core-tracing": "^1.0.0", - "debug": "^4.1.1", + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.9.0", + "@azure/core-rest-pipeline": "^1.19.1", + "@azure/core-tracing": "^1.2.0", + "@azure/core-util": "^1.11.0", + "@azure/keyvault-keys": "^4.9.0", + "@azure/logger": "^1.1.4", "fast-json-stable-stringify": "^2.1.0", - "jsbi": "^3.1.3", - "node-abort-controller": "^3.0.0", - "priorityqueuejs": "^1.0.0", - "semaphore": "^1.0.5", - "tslib": "^2.2.0", - "universal-user-agent": "^6.0.0", - "uuid": "^8.3.0" + "priorityqueuejs": "^2.0.0", + "semaphore": "^1.1.0", + "tslib": "^2.8.1" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.0.0" } }, - "node_modules/@azure/cosmos/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" + "node_modules/@azure/cosmos/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@azure/data-tables": { @@ -546,27 +620,68 @@ "node": ">=14.0.0" } }, - "node_modules/@azure/keyvault-keys": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/@azure/keyvault-keys/-/keyvault-keys-4.8.0.tgz", - "integrity": "sha512-jkuYxgkw0aaRfk40OQhFqDIupqblIOIlYESWB6DKCVDxQet1pyv86Tfk9M+5uFM0+mCs6+MUHU+Hxh3joiUn4Q==", + "node_modules/@azure/keyvault-common": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@azure/keyvault-common/-/keyvault-common-2.0.0.tgz", + "integrity": "sha512-wRLVaroQtOqfg60cxkzUkGKrKMsCP6uYXAOomOIysSMyt1/YM0eUn9LqieAWM8DLcU4+07Fio2YGpPeqUbpP9w==", "dependencies": { - "@azure/abort-controller": "^1.0.0", + "@azure/abort-controller": "^2.0.0", "@azure/core-auth": "^1.3.0", "@azure/core-client": "^1.5.0", - "@azure/core-http-compat": "^2.0.1", - "@azure/core-lro": "^2.2.0", - "@azure/core-paging": "^1.1.1", - "@azure/core-rest-pipeline": "^1.8.1", + "@azure/core-rest-pipeline": "^1.8.0", "@azure/core-tracing": "^1.0.0", - "@azure/core-util": "^1.0.0", - "@azure/logger": "^1.0.0", + "@azure/core-util": "^1.10.0", + "@azure/logger": "^1.1.4", "tslib": "^2.2.0" }, "engines": { "node": ">=18.0.0" } }, + "node_modules/@azure/keyvault-common/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/keyvault-keys": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@azure/keyvault-keys/-/keyvault-keys-4.10.0.tgz", + "integrity": "sha512-eDT7iXoBTRZ2n3fLiftuGJFD+yjkiB1GNqzU2KbY1TLYeXeSPVTVgn2eJ5vmRTZ11978jy2Kg2wI7xa9Tyr8ag==", + "dependencies": { + "@azure-rest/core-client": "^2.3.3", + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.9.0", + "@azure/core-http-compat": "^2.2.0", + "@azure/core-lro": "^2.7.2", + "@azure/core-paging": "^1.6.2", + "@azure/core-rest-pipeline": "^1.19.0", + "@azure/core-tracing": "^1.2.0", + "@azure/core-util": "^1.11.0", + "@azure/keyvault-common": "^2.0.0", + "@azure/logger": "^1.1.4", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/keyvault-keys/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@azure/logger": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.2.0.tgz", @@ -1071,14 +1186,6 @@ "resolved": "https://registry.npmjs.org/@tediousjs/connection-string/-/connection-string-0.5.0.tgz", "integrity": "sha512-7qSgZbincDDDFyRweCIEvZULFAw5iz/DeunhvuxpL31nfntX3P4Yd4HkHBRg9H8CdqY1e5WFN1PZIz/REL9MVQ==" }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "engines": { - "node": ">= 10" - } - }, "node_modules/@types/chai": { "version": "4.3.8", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.8.tgz", @@ -1388,38 +1495,6 @@ "node": ">=18.0.0" } }, - "node_modules/@typespec/ts-http-runtime/node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "engines": { - "node": ">= 14" - } - }, - "node_modules/@typespec/ts-http-runtime/node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/@typespec/ts-http-runtime/node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/@webassemblyjs/ast": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", @@ -1609,14 +1684,11 @@ } }, "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dependencies": { - "debug": "4" - }, + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "engines": { - "node": ">= 6.0.0" + "node": ">= 14" } }, "node_modules/agentkeepalive": { @@ -3485,28 +3557,27 @@ } }, "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" + "agent-base": "^7.1.0", + "debug": "^4.3.4" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "dependencies": { - "agent-base": "6", + "agent-base": "^7.1.2", "debug": "4" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/humanize-ms": { @@ -3993,11 +4064,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsbi": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-3.2.5.tgz", - "integrity": "sha512-aBE4n43IPvjaddScbvWRA2YlTzKEynHzu7MqOyTipdHucf/VxS63ViCjxYRg86M8Rxwbt/GfzHl1kKERkt45fQ==" - }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -4865,9 +4931,9 @@ } }, "node_modules/priorityqueuejs": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/priorityqueuejs/-/priorityqueuejs-1.0.0.tgz", - "integrity": "sha512-lg++21mreCEOuGWTbO5DnJKAdxfjrdN0S9ysoW9SzdSJvbkWpkaDdpG/cdsPCsEnoLUwmd9m3WcZhngW7yKA2g==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/priorityqueuejs/-/priorityqueuejs-2.0.0.tgz", + "integrity": "sha512-19BMarhgpq3x4ccvVi8k2QpJZcymo/iFUcrhPd4V96kYGovOdTsWwy7fxChYi4QY+m2EnGBWSX9Buakz+tWNQQ==" }, "node_modules/process": { "version": "0.11.10", @@ -6047,11 +6113,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/universal-user-agent": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" - }, "node_modules/update-browserslist-db": { "version": "1.0.13", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", diff --git a/package.json b/package.json index 2132f6d1..7b679fae 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "@azure/arm-servicebus": "^6.1.0", "@azure/arm-sql": "^10.0.0", "@azure/arm-storage": "^18.1.0", - "@azure/cosmos": "^3.17.3", + "@azure/cosmos": "^4.5.0", "@azure/data-tables": "^13.2.2", "@azure/event-hubs": "^5.10.0", "@azure/identity": "^3.4.2", From 6c2e04e40c1bda8318f2254dbee8773944e2dda6 Mon Sep 17 00:00:00 2001 From: Evan Roman Date: Tue, 22 Jul 2025 10:33:27 -0500 Subject: [PATCH 12/24] add key --- src/utils/setupCosmosDB.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/utils/setupCosmosDB.ts b/src/utils/setupCosmosDB.ts index 7767e750..ac1415be 100644 --- a/src/utils/setupCosmosDB.ts +++ b/src/utils/setupCosmosDB.ts @@ -12,5 +12,8 @@ import { CosmosDB } from '../constants'; export async function setupCosmosDB() { const client = new CosmosClient(cosmosDBConnectionString); await client.databases.createIfNotExists({ id: CosmosDB.triggerDatabaseName }); - await client.database(CosmosDB.triggerDatabaseName).containers.createIfNotExists({ id: CosmosDB.triggerAndOutputContainerName }); + await client.database(CosmosDB.triggerDatabaseName).containers.createIfNotExists({ + id: CosmosDB.triggerAndOutputContainerName, + partitionKey: { paths: ['/testPartKey'] }, + }); } \ No newline at end of file From b3845f976a9230dae71faa7e036f17fb377485c4 Mon Sep 17 00:00:00 2001 From: Evan Roman Date: Tue, 22 Jul 2025 10:48:56 -0500 Subject: [PATCH 13/24] add --- src/utils/setupCosmosDB.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/setupCosmosDB.ts b/src/utils/setupCosmosDB.ts index ac1415be..12ee507d 100644 --- a/src/utils/setupCosmosDB.ts +++ b/src/utils/setupCosmosDB.ts @@ -5,7 +5,7 @@ // Otherwise the following error will occur: // Microsoft.Azure.Cosmos.Client: This builder instance has already been used to build a processor. Create a new instance to build another. -import { CosmosClient } from '@azure/cosmos'; +import { CosmosClient, PartitionKeyKind } from '@azure/cosmos'; import { cosmosDBConnectionString } from './connectionStrings'; import { CosmosDB } from '../constants'; @@ -14,6 +14,6 @@ export async function setupCosmosDB() { await client.databases.createIfNotExists({ id: CosmosDB.triggerDatabaseName }); await client.database(CosmosDB.triggerDatabaseName).containers.createIfNotExists({ id: CosmosDB.triggerAndOutputContainerName, - partitionKey: { paths: ['/testPartKey'] }, + partitionKey: { paths: ['/testPartKey'], kind: PartitionKeyKind.Hash } }); } \ No newline at end of file From 29e29306de335da9bfabfa64ca64b9d29fc1f6bc Mon Sep 17 00:00:00 2001 From: Evan Roman Date: Tue, 22 Jul 2025 11:00:45 -0500 Subject: [PATCH 14/24] add --- app/v3/cosmosDBTrigger/index.ts | 20 ++++---- app/v3/cosmosDBTriggerAndOutput/index.ts | 22 ++++----- app/v3/httpTriggerCosmosDBInput/index.ts | 24 +++++----- .../src/functions/httpTriggerCosmosDBInput.ts | 46 +++++++++---------- 4 files changed, 56 insertions(+), 56 deletions(-) diff --git a/app/v3/cosmosDBTrigger/index.ts b/app/v3/cosmosDBTrigger/index.ts index 78aea6fb..fe205aad 100644 --- a/app/v3/cosmosDBTrigger/index.ts +++ b/app/v3/cosmosDBTrigger/index.ts @@ -1,13 +1,13 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { AzureFunction, Context } from '@azure/functions'; +import { AzureFunction, Context } from '@azure/functions'; -// const cosmosDBTrigger: AzureFunction = async function (context: Context, documents: any[]): Promise { -// context.log(`cosmosDBTrigger processed ${documents.length} documents`); -// for (const document of documents) { -// context.log(`cosmosDBTrigger was triggered by "${document.testData}"`); -// } -// }; +const cosmosDBTrigger: AzureFunction = async function (context: Context, documents: any[]): Promise { + context.log(`cosmosDBTrigger processed ${documents.length} documents`); + for (const document of documents) { + context.log(`cosmosDBTrigger was triggered by "${document.testData}"`); + } +}; -// export default cosmosDBTrigger; +export default cosmosDBTrigger; diff --git a/app/v3/cosmosDBTriggerAndOutput/index.ts b/app/v3/cosmosDBTriggerAndOutput/index.ts index 43f42cd3..1eb41f1f 100644 --- a/app/v3/cosmosDBTriggerAndOutput/index.ts +++ b/app/v3/cosmosDBTriggerAndOutput/index.ts @@ -1,14 +1,14 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { AzureFunction, Context } from '@azure/functions'; +import { AzureFunction, Context } from '@azure/functions'; -// const cosmosDBTrigger: AzureFunction = async function (context: Context, documents: any[]): Promise { -// context.log(`cosmosDBTriggerAndOutput processed ${documents.length} documents`); -// for (const document of documents) { -// context.log(`cosmosDBTriggerAndOutput was triggered by "${document.testData}"`); -// } -// return documents; -// }; +const cosmosDBTrigger: AzureFunction = async function (context: Context, documents: any[]): Promise { + context.log(`cosmosDBTriggerAndOutput processed ${documents.length} documents`); + for (const document of documents) { + context.log(`cosmosDBTriggerAndOutput was triggered by "${document.testData}"`); + } + return documents; +}; -// export default cosmosDBTrigger; +export default cosmosDBTrigger; diff --git a/app/v3/httpTriggerCosmosDBInput/index.ts b/app/v3/httpTriggerCosmosDBInput/index.ts index 28550488..d99e123a 100644 --- a/app/v3/httpTriggerCosmosDBInput/index.ts +++ b/app/v3/httpTriggerCosmosDBInput/index.ts @@ -1,15 +1,15 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { AzureFunction, Context, HttpRequest } from '@azure/functions'; +import { AzureFunction, Context, HttpRequest } from '@azure/functions'; -// const httpTriggerCosmosDBInput: AzureFunction = async function ( -// context: Context, -// _request: HttpRequest -// ): Promise { -// context.res = { -// body: context.bindings.inputDoc.testData, -// }; -// }; +const httpTriggerCosmosDBInput: AzureFunction = async function ( + context: Context, + _request: HttpRequest +): Promise { + context.res = { + body: context.bindings.inputDoc.testData, + }; +}; -// export default httpTriggerCosmosDBInput; +export default httpTriggerCosmosDBInput; diff --git a/app/v4/src/functions/httpTriggerCosmosDBInput.ts b/app/v4/src/functions/httpTriggerCosmosDBInput.ts index 25e0f4fd..acadf06e 100644 --- a/app/v4/src/functions/httpTriggerCosmosDBInput.ts +++ b/app/v4/src/functions/httpTriggerCosmosDBInput.ts @@ -1,27 +1,27 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { app, HttpRequest, HttpResponseInit, input, InvocationContext } from '@azure/functions'; +import { app, HttpRequest, HttpResponseInit, input, InvocationContext } from '@azure/functions'; -// const cosmosInput = input.cosmosDB({ -// databaseName: 'e2eTestDB', -// containerName: 'e2eTestContainerTriggerAndOutput', -// id: '{Query.id}', -// partitionKey: 'testPartKey', -// connection: 'CosmosDBConnection', -// }); +const cosmosInput = input.cosmosDB({ + databaseName: 'e2eTestDB', + containerName: 'e2eTestContainerTriggerAndOutput', + id: '{Query.id}', + partitionKey: 'testPartKey', + connection: 'CosmosDBConnection', +}); -// export async function httpTriggerCosmosDBInput( -// _request: HttpRequest, -// context: InvocationContext -// ): Promise { -// const doc = context.extraInputs.get(cosmosInput); -// return { body: (doc).testData }; -// } +export async function httpTriggerCosmosDBInput( + _request: HttpRequest, + context: InvocationContext +): Promise { + const doc = context.extraInputs.get(cosmosInput); + return { body: (doc).testData }; +} -// app.http('httpTriggerCosmosDBInput', { -// methods: ['GET', 'POST'], -// authLevel: 'anonymous', -// extraInputs: [cosmosInput], -// handler: httpTriggerCosmosDBInput, -// }); +app.http('httpTriggerCosmosDBInput', { + methods: ['GET', 'POST'], + authLevel: 'anonymous', + extraInputs: [cosmosInput], + handler: httpTriggerCosmosDBInput, +}); From e722da540a6567aaa276c5710f3ffd4e65910b2b Mon Sep 17 00:00:00 2001 From: Evan Roman Date: Tue, 22 Jul 2025 11:25:17 -0500 Subject: [PATCH 15/24] add --- src/utils/setupCosmosDB.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/utils/setupCosmosDB.ts b/src/utils/setupCosmosDB.ts index 12ee507d..a6c75b5f 100644 --- a/src/utils/setupCosmosDB.ts +++ b/src/utils/setupCosmosDB.ts @@ -12,6 +12,10 @@ import { CosmosDB } from '../constants'; export async function setupCosmosDB() { const client = new CosmosClient(cosmosDBConnectionString); await client.databases.createIfNotExists({ id: CosmosDB.triggerDatabaseName }); + await client.database(CosmosDB.triggerDatabaseName).containers.createIfNotExists({ + id: CosmosDB.triggerContainerName, + partitionKey: { paths: ['/testPartKey'], kind: PartitionKeyKind.Hash } + }); await client.database(CosmosDB.triggerDatabaseName).containers.createIfNotExists({ id: CosmosDB.triggerAndOutputContainerName, partitionKey: { paths: ['/testPartKey'], kind: PartitionKeyKind.Hash } From dcebe469ef4ab8f2c95fd4b6821a953baf5b4ff3 Mon Sep 17 00:00:00 2001 From: Evan Roman Date: Tue, 22 Jul 2025 11:38:05 -0500 Subject: [PATCH 16/24] add --- app/v3/httpTriggerCosmosDBOutput/index.ts | 22 +++++----- .../functions/httpTriggerCosmosDBOutput.ts | 44 +++++++++---------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/app/v3/httpTriggerCosmosDBOutput/index.ts b/app/v3/httpTriggerCosmosDBOutput/index.ts index d2c0236a..9745ee1c 100644 --- a/app/v3/httpTriggerCosmosDBOutput/index.ts +++ b/app/v3/httpTriggerCosmosDBOutput/index.ts @@ -1,14 +1,14 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { AzureFunction, Context, HttpRequest } from '@azure/functions'; +import { AzureFunction, Context, HttpRequest } from '@azure/functions'; -// const httpTriggerCosmosDBOutput: AzureFunction = async function ( -// context: Context, -// request: HttpRequest -// ): Promise { -// context.bindings.outputDoc = request.body; -// context.res = { body: 'done' }; -// }; +const httpTriggerCosmosDBOutput: AzureFunction = async function ( + context: Context, + request: HttpRequest +): Promise { + context.bindings.outputDoc = request.body; + context.res = { body: 'done' }; +}; -// export default httpTriggerCosmosDBOutput; +export default httpTriggerCosmosDBOutput; diff --git a/app/v4/src/functions/httpTriggerCosmosDBOutput.ts b/app/v4/src/functions/httpTriggerCosmosDBOutput.ts index 12eeb42b..a4580a97 100644 --- a/app/v4/src/functions/httpTriggerCosmosDBOutput.ts +++ b/app/v4/src/functions/httpTriggerCosmosDBOutput.ts @@ -1,26 +1,26 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { app, HttpRequest, HttpResponseInit, InvocationContext, output } from '@azure/functions'; +import { app, HttpRequest, HttpResponseInit, InvocationContext, output } from '@azure/functions'; -// const cosmosOutput = output.cosmosDB({ -// databaseName: 'e2eTestDB', -// containerName: 'e2eTestContainerTrigger', -// connection: 'CosmosDBConnection', -// }); +const cosmosOutput = output.cosmosDB({ + databaseName: 'e2eTestDB', + containerName: 'e2eTestContainerTrigger', + connection: 'CosmosDBConnection', +}); -// export async function httpTriggerCosmosDBOutput( -// request: HttpRequest, -// context: InvocationContext -// ): Promise { -// const body = await request.json(); -// context.extraOutputs.set(cosmosOutput, body); -// return { body: 'done' }; -// } +export async function httpTriggerCosmosDBOutput( + request: HttpRequest, + context: InvocationContext +): Promise { + const body = await request.json(); + context.extraOutputs.set(cosmosOutput, body); + return { body: 'done' }; +} -// app.http('httpTriggerCosmosDBOutput', { -// methods: ['GET', 'POST'], -// authLevel: 'anonymous', -// extraOutputs: [cosmosOutput], -// handler: httpTriggerCosmosDBOutput, -// }); +app.http('httpTriggerCosmosDBOutput', { + methods: ['GET', 'POST'], + authLevel: 'anonymous', + extraOutputs: [cosmosOutput], + handler: httpTriggerCosmosDBOutput, +}); From 2a92719aa872f389b9853307a47a4b33ae32d7d4 Mon Sep 17 00:00:00 2001 From: Evan Roman Date: Tue, 22 Jul 2025 11:55:57 -0500 Subject: [PATCH 17/24] add --- .../src/functions/httpTriggerCosmosDBInput.ts | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/app/v4-oldConfig/src/functions/httpTriggerCosmosDBInput.ts b/app/v4-oldConfig/src/functions/httpTriggerCosmosDBInput.ts index 7c65e72e..88288768 100644 --- a/app/v4-oldConfig/src/functions/httpTriggerCosmosDBInput.ts +++ b/app/v4-oldConfig/src/functions/httpTriggerCosmosDBInput.ts @@ -1,27 +1,27 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { app, HttpRequest, HttpResponseInit, input, InvocationContext } from '@azure/functions'; +import { app, HttpRequest, HttpResponseInit, input, InvocationContext } from '@azure/functions'; -// const cosmosInput = input.cosmosDB({ -// databaseName: 'e2eTestDB', -// collectionName: 'e2eTestContainerTriggerAndOutput', -// id: '{Query.id}', -// partitionKey: 'testPartKey', -// connectionStringSetting: 'CosmosDBConnection', -// }); +const cosmosInput = input.cosmosDB({ + databaseName: 'e2eTestDB', + collectionName: 'e2eTestContainerTriggerAndOutput', + id: '{Query.id}', + partitionKey: 'testPartKey', + connectionStringSetting: 'CosmosDBConnection', +}); -// export async function httpTriggerCosmosDBInput( -// _request: HttpRequest, -// context: InvocationContext -// ): Promise { -// const doc = context.extraInputs.get(cosmosInput); -// return { body: (doc).testData }; -// } +export async function httpTriggerCosmosDBInput( + _request: HttpRequest, + context: InvocationContext +): Promise { + const doc = context.extraInputs.get(cosmosInput); + return { body: (doc).testData }; +} -// app.http('httpTriggerCosmosDBInput', { -// methods: ['GET', 'POST'], -// authLevel: 'anonymous', -// extraInputs: [cosmosInput], -// handler: httpTriggerCosmosDBInput, -// }); +app.http('httpTriggerCosmosDBInput', { + methods: ['GET', 'POST'], + authLevel: 'anonymous', + extraInputs: [cosmosInput], + handler: httpTriggerCosmosDBInput, +}); From 880fa874ce6273114f0532a9b52ece2979a0ceaf Mon Sep 17 00:00:00 2001 From: Evan Roman Date: Tue, 22 Jul 2025 12:24:48 -0500 Subject: [PATCH 18/24] add --- .../src/functions/cosmosDBTrigger.ts | 34 +++++++------- .../src/functions/cosmosDBTriggerAndOutput.ts | 46 +++++++++---------- src/cosmosDB.test.ts | 2 +- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/app/v4-oldConfig/src/functions/cosmosDBTrigger.ts b/app/v4-oldConfig/src/functions/cosmosDBTrigger.ts index bdec0a40..3b02a056 100644 --- a/app/v4-oldConfig/src/functions/cosmosDBTrigger.ts +++ b/app/v4-oldConfig/src/functions/cosmosDBTrigger.ts @@ -1,20 +1,20 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { app, InvocationContext } from '@azure/functions'; +import { app, InvocationContext } from '@azure/functions'; -// export async function cosmosDBTrigger(documents: unknown[], context: InvocationContext): Promise { -// context.log(`cosmosDBTrigger processed ${documents.length} documents`); -// for (const document of documents) { -// context.log(`cosmosDBTrigger was triggered by "${(document).testData}"`); -// } -// } +export async function cosmosDBTrigger(documents: unknown[], context: InvocationContext): Promise { + context.log(`cosmosDBTrigger processed ${documents.length} documents`); + for (const document of documents) { + context.log(`cosmosDBTrigger was triggered by "${(document).testData}"`); + } +} -// app.cosmosDB('cosmosDBTrigger', { -// connectionStringSetting: 'CosmosDBConnection', -// databaseName: 'e2eTestDB', -// collectionName: 'e2eTestContainerTrigger', -// createLeaseCollectionIfNotExists: true, -// leaseCollectionPrefix: '2', -// handler: cosmosDBTrigger, -// }); +app.cosmosDB('cosmosDBTrigger', { + connectionStringSetting: 'CosmosDBConnection', + databaseName: 'e2eTestDB', + collectionName: 'e2eTestContainerTrigger', + createLeaseCollectionIfNotExists: true, + leaseCollectionPrefix: '2', + handler: cosmosDBTrigger, +}); diff --git a/app/v4-oldConfig/src/functions/cosmosDBTriggerAndOutput.ts b/app/v4-oldConfig/src/functions/cosmosDBTriggerAndOutput.ts index 89eda8f4..ab00a27a 100644 --- a/app/v4-oldConfig/src/functions/cosmosDBTriggerAndOutput.ts +++ b/app/v4-oldConfig/src/functions/cosmosDBTriggerAndOutput.ts @@ -1,26 +1,26 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { app, InvocationContext, output } from '@azure/functions'; +import { app, InvocationContext, output } from '@azure/functions'; -// export async function cosmosDBTriggerAndOutput(documents: unknown[], context: InvocationContext): Promise { -// context.log(`cosmosDBTriggerAndOutput processed ${documents.length} documents`); -// for (const document of documents) { -// context.log(`cosmosDBTriggerAndOutput was triggered by "${(document).testData}"`); -// } -// return documents; -// } +export async function cosmosDBTriggerAndOutput(documents: unknown[], context: InvocationContext): Promise { + context.log(`cosmosDBTriggerAndOutput processed ${documents.length} documents`); + for (const document of documents) { + context.log(`cosmosDBTriggerAndOutput was triggered by "${(document).testData}"`); + } + return documents; +} -// app.cosmosDB('cosmosDBTriggerAndOutput', { -// connectionStringSetting: 'CosmosDBConnection', -// databaseName: 'e2eTestDB', -// collectionName: 'e2eTestContainerTriggerAndOutput', -// createLeaseCollectionIfNotExists: true, -// leaseCollectionPrefix: '1', -// return: output.cosmosDB({ -// connectionStringSetting: 'CosmosDBConnection', -// databaseName: 'e2eTestDB', -// collectionName: 'e2eTestContainerTrigger', -// }), -// handler: cosmosDBTriggerAndOutput, -// }); +app.cosmosDB('cosmosDBTriggerAndOutput', { + connectionStringSetting: 'CosmosDBConnection', + databaseName: 'e2eTestDB', + collectionName: 'e2eTestContainerTriggerAndOutput', + createLeaseCollectionIfNotExists: true, + leaseCollectionPrefix: '1', + return: output.cosmosDB({ + connectionStringSetting: 'CosmosDBConnection', + databaseName: 'e2eTestDB', + collectionName: 'e2eTestContainerTrigger', + }), + handler: cosmosDBTriggerAndOutput, +}); diff --git a/src/cosmosDB.test.ts b/src/cosmosDB.test.ts index b134a953..ebf6a786 100644 --- a/src/cosmosDB.test.ts +++ b/src/cosmosDB.test.ts @@ -14,7 +14,7 @@ describe('cosmosDB', () => { const client = new CosmosClient(cosmosDBConnectionString); const container = client.database(CosmosDB.dbName).container(CosmosDB.triggerAndOutputContainerName); const testData = getRandomTestData(); - const createdItem = await container.items.create({ testData, _partitionKey: 'testPartKey' }); + const createdItem = await container.items.create({ testData, testPartKey: 'testPartKey' }); await waitForOutput(`cosmosDBTriggerAndOutput processed 1 documents`); await waitForOutput(`cosmosDBTriggerAndOutput was triggered by "${testData}"`); From 5025dc20f008e0ef903f9ee8b3728e939a9cad50 Mon Sep 17 00:00:00 2001 From: Evan Roman Date: Tue, 22 Jul 2025 12:37:34 -0500 Subject: [PATCH 19/24] add all --- .../functions/httpTriggerCosmosDBOutput.ts | 44 +++++++++---------- .../templates/test-node-version.yml | 3 -- azure-pipelines/templates/test.yml | 21 +++++---- 3 files changed, 32 insertions(+), 36 deletions(-) diff --git a/app/v4-oldConfig/src/functions/httpTriggerCosmosDBOutput.ts b/app/v4-oldConfig/src/functions/httpTriggerCosmosDBOutput.ts index 35740acb..2cdfc272 100644 --- a/app/v4-oldConfig/src/functions/httpTriggerCosmosDBOutput.ts +++ b/app/v4-oldConfig/src/functions/httpTriggerCosmosDBOutput.ts @@ -1,26 +1,26 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { HttpRequest, HttpResponseInit, InvocationContext, app, output } from '@azure/functions'; +import { HttpRequest, HttpResponseInit, InvocationContext, app, output } from '@azure/functions'; -// const cosmosOutput = output.cosmosDB({ -// databaseName: 'e2eTestDB', -// collectionName: 'e2eTestContainerTrigger', -// connectionStringSetting: 'CosmosDBConnection', -// }); +const cosmosOutput = output.cosmosDB({ + databaseName: 'e2eTestDB', + collectionName: 'e2eTestContainerTrigger', + connectionStringSetting: 'CosmosDBConnection', +}); -// export async function httpTriggerCosmosDBOutput( -// request: HttpRequest, -// context: InvocationContext -// ): Promise { -// const body = await request.json(); -// context.extraOutputs.set(cosmosOutput, body); -// return { body: 'done' }; -// } +export async function httpTriggerCosmosDBOutput( + request: HttpRequest, + context: InvocationContext +): Promise { + const body = await request.json(); + context.extraOutputs.set(cosmosOutput, body); + return { body: 'done' }; +} -// app.http('httpTriggerCosmosDBOutput', { -// methods: ['GET', 'POST'], -// authLevel: 'anonymous', -// extraOutputs: [cosmosOutput], -// handler: httpTriggerCosmosDBOutput, -// }); +app.http('httpTriggerCosmosDBOutput', { + methods: ['GET', 'POST'], + authLevel: 'anonymous', + extraOutputs: [cosmosOutput], + handler: httpTriggerCosmosDBOutput, +}); diff --git a/azure-pipelines/templates/test-node-version.yml b/azure-pipelines/templates/test-node-version.yml index 788736b2..1064596b 100644 --- a/azure-pipelines/templates/test-node-version.yml +++ b/azure-pipelines/templates/test-node-version.yml @@ -20,9 +20,6 @@ steps: docker compose -f src/utils/eventhub/docker-compose.yml pull docker compose -f src/utils/eventhub/docker-compose.yml up -d displayName: 'Install Azurite and Start EventHub Emulator' - - bash: | - docker logs azurite - displayName: 'Show Azurite Logs' - bash: | npm run ${{ parameters.testCommand }} displayName: 'Run tests Node ${{ parameters.nodeVersion }}' diff --git a/azure-pipelines/templates/test.yml b/azure-pipelines/templates/test.yml index 19f6efe0..98ebca05 100644 --- a/azure-pipelines/templates/test.yml +++ b/azure-pipelines/templates/test.yml @@ -16,24 +16,23 @@ jobs: - template: /azure-pipelines/templates/build-apps.yml@self - # - template: /azure-pipelines/templates/test-node-version.yml@self - # parameters: - # nodeVersion: 18.x + - template: /azure-pipelines/templates/test-node-version.yml@self + parameters: + nodeVersion: 18.x - # - template: /azure-pipelines/templates/test-node-version.yml@self - # parameters: - # nodeVersion: 20.x + - template: /azure-pipelines/templates/test-node-version.yml@self + parameters: + nodeVersion: 20.x - template: /azure-pipelines/templates/test-node-version.yml@self parameters: nodeVersion: 22.x - # These all use Cosmos - so we will come back and emulate this # Run tests for old config (just one Node.js version is enough) - # - template: /azure-pipelines/templates/test-node-version.yml@self - # parameters: - # nodeVersion: 18.x - # testCommand: testOldConfig + - template: /azure-pipelines/templates/test-node-version.yml@self + parameters: + nodeVersion: 18.x + testCommand: testOldConfig - task: PublishTestResults@2 displayName: 'Publish Unit Test Results' From 2428155a37f2651dd43733d1463680f1b499ea27 Mon Sep 17 00:00:00 2001 From: Evan Roman Date: Tue, 22 Jul 2025 12:47:31 -0500 Subject: [PATCH 20/24] add --- src/constants.ts | 1 + src/cosmosDB.test.ts | 2 +- src/utils/setupCosmosDB.ts | 5 +++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index 63ca0ff9..24cebd74 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -12,6 +12,7 @@ export namespace CosmosDB { export const triggerAndOutputContainerName = 'e2eTestContainerTriggerAndOutput'; export const triggerContainerName = 'e2eTestContainerTrigger'; export const triggerDatabaseName = 'e2eTestDB'; + export const partitionKey = 'testPartKey'; } export namespace EventHub { diff --git a/src/cosmosDB.test.ts b/src/cosmosDB.test.ts index ebf6a786..33572a25 100644 --- a/src/cosmosDB.test.ts +++ b/src/cosmosDB.test.ts @@ -14,7 +14,7 @@ describe('cosmosDB', () => { const client = new CosmosClient(cosmosDBConnectionString); const container = client.database(CosmosDB.dbName).container(CosmosDB.triggerAndOutputContainerName); const testData = getRandomTestData(); - const createdItem = await container.items.create({ testData, testPartKey: 'testPartKey' }); + const createdItem = await container.items.create({ testData, testPartKey: CosmosDB.partitionKey }); await waitForOutput(`cosmosDBTriggerAndOutput processed 1 documents`); await waitForOutput(`cosmosDBTriggerAndOutput was triggered by "${testData}"`); diff --git a/src/utils/setupCosmosDB.ts b/src/utils/setupCosmosDB.ts index a6c75b5f..b7a68bc0 100644 --- a/src/utils/setupCosmosDB.ts +++ b/src/utils/setupCosmosDB.ts @@ -10,14 +10,15 @@ import { cosmosDBConnectionString } from './connectionStrings'; import { CosmosDB } from '../constants'; export async function setupCosmosDB() { + const partitionKeyPath = `/${CosmosDB.partitionKey}`; const client = new CosmosClient(cosmosDBConnectionString); await client.databases.createIfNotExists({ id: CosmosDB.triggerDatabaseName }); await client.database(CosmosDB.triggerDatabaseName).containers.createIfNotExists({ id: CosmosDB.triggerContainerName, - partitionKey: { paths: ['/testPartKey'], kind: PartitionKeyKind.Hash } + partitionKey: { paths: [partitionKeyPath], kind: PartitionKeyKind.Hash } }); await client.database(CosmosDB.triggerDatabaseName).containers.createIfNotExists({ id: CosmosDB.triggerAndOutputContainerName, - partitionKey: { paths: ['/testPartKey'], kind: PartitionKeyKind.Hash } + partitionKey: { paths: [partitionKeyPath], kind: PartitionKeyKind.Hash } }); } \ No newline at end of file From 10fd04258ce32935dbeb9b89d970ac7b4481244f Mon Sep 17 00:00:00 2001 From: Evan Roman Date: Tue, 22 Jul 2025 13:20:22 -0500 Subject: [PATCH 21/24] add --- app/v3/httpTriggerTableOutput/index.ts | 22 ++++----- app/v4/src/functions/httpTriggerTableInput.ts | 48 +++++++++---------- .../src/functions/httpTriggerTableOutput.ts | 44 ++++++++--------- azure-pipelines/templates/test.yml | 8 ++-- 4 files changed, 61 insertions(+), 61 deletions(-) diff --git a/app/v3/httpTriggerTableOutput/index.ts b/app/v3/httpTriggerTableOutput/index.ts index 0d6688b9..022d757c 100644 --- a/app/v3/httpTriggerTableOutput/index.ts +++ b/app/v3/httpTriggerTableOutput/index.ts @@ -1,14 +1,14 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { AzureFunction, Context, HttpRequest } from '@azure/functions'; +import { AzureFunction, Context, HttpRequest } from '@azure/functions'; -// const httpTriggerTableOutput: AzureFunction = async function (context: Context, request: HttpRequest): Promise { -// context.log(`httpTriggerTableOutput was triggered`); -// context.bindings.outputItem = request.body; -// context.res = { -// status: 201, -// }; -// }; +const httpTriggerTableOutput: AzureFunction = async function (context: Context, request: HttpRequest): Promise { + context.log(`httpTriggerTableOutput was triggered`); + context.bindings.outputItem = request.body; + context.res = { + status: 201, + }; +}; -// export default httpTriggerTableOutput; +export default httpTriggerTableOutput; diff --git a/app/v4/src/functions/httpTriggerTableInput.ts b/app/v4/src/functions/httpTriggerTableInput.ts index 2674fd5c..50d28b1e 100644 --- a/app/v4/src/functions/httpTriggerTableInput.ts +++ b/app/v4/src/functions/httpTriggerTableInput.ts @@ -1,28 +1,28 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { app, HttpRequest, HttpResponseInit, input, InvocationContext } from '@azure/functions'; +import { app, HttpRequest, HttpResponseInit, input, InvocationContext } from '@azure/functions'; -// const tableInput = input.table({ -// tableName: 'e2etesttable', -// partitionKey: 'e2eTestPartKey', -// filter: "RowKey eq '{rowKey}'", -// connection: 'e2eTest_storage', -// }); +const tableInput = input.table({ + tableName: 'e2etesttable', + partitionKey: 'e2eTestPartKey', + filter: "RowKey eq '{rowKey}'", + connection: 'AzureWebJobsStorage', +}); -// export async function httpTriggerTableInput( -// request: HttpRequest, -// context: InvocationContext -// ): Promise { -// context.log(`httpTriggerTableInput was triggered`); -// const items = context.extraInputs.get(tableInput); -// return { jsonBody: items }; -// } +export async function httpTriggerTableInput( + request: HttpRequest, + context: InvocationContext +): Promise { + context.log(`httpTriggerTableInput was triggered`); + const items = context.extraInputs.get(tableInput); + return { jsonBody: items }; +} -// app.http('httpTriggerTableInput', { -// methods: ['GET', 'POST'], -// authLevel: 'anonymous', -// route: 'httpTriggerTableInput/{rowKey}', -// extraInputs: [tableInput], -// handler: httpTriggerTableInput, -// }); +app.http('httpTriggerTableInput', { + methods: ['GET', 'POST'], + authLevel: 'anonymous', + route: 'httpTriggerTableInput/{rowKey}', + extraInputs: [tableInput], + handler: httpTriggerTableInput, +}); diff --git a/app/v4/src/functions/httpTriggerTableOutput.ts b/app/v4/src/functions/httpTriggerTableOutput.ts index 645228b4..bf9bb2a3 100644 --- a/app/v4/src/functions/httpTriggerTableOutput.ts +++ b/app/v4/src/functions/httpTriggerTableOutput.ts @@ -1,26 +1,26 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { app, HttpRequest, HttpResponseInit, InvocationContext, output } from '@azure/functions'; +import { app, HttpRequest, HttpResponseInit, InvocationContext, output } from '@azure/functions'; -// const tableOutput = output.table({ -// tableName: 'e2etesttable', -// connection: 'e2eTest_storage', -// }); +const tableOutput = output.table({ + tableName: 'e2etesttable', + connection: 'AzureWebJobsStorage', +}); -// export async function httpTriggerTableOutput( -// request: HttpRequest, -// context: InvocationContext -// ): Promise { -// context.log(`httpTriggerTableOutput was triggered`); -// const body = await request.json(); -// context.extraOutputs.set(tableOutput, body); -// return { status: 201 }; -// } +export async function httpTriggerTableOutput( + request: HttpRequest, + context: InvocationContext +): Promise { + context.log(`httpTriggerTableOutput was triggered`); + const body = await request.json(); + context.extraOutputs.set(tableOutput, body); + return { status: 201 }; +} -// app.http('httpTriggerTableOutput', { -// methods: ['GET', 'POST'], -// authLevel: 'anonymous', -// extraOutputs: [tableOutput], -// handler: httpTriggerTableOutput, -// }); +app.http('httpTriggerTableOutput', { + methods: ['GET', 'POST'], + authLevel: 'anonymous', + extraOutputs: [tableOutput], + handler: httpTriggerTableOutput, +}); diff --git a/azure-pipelines/templates/test.yml b/azure-pipelines/templates/test.yml index 98ebca05..e1d1489d 100644 --- a/azure-pipelines/templates/test.yml +++ b/azure-pipelines/templates/test.yml @@ -29,10 +29,10 @@ jobs: nodeVersion: 22.x # Run tests for old config (just one Node.js version is enough) - - template: /azure-pipelines/templates/test-node-version.yml@self - parameters: - nodeVersion: 18.x - testCommand: testOldConfig + # - template: /azure-pipelines/templates/test-node-version.yml@self + # parameters: + # nodeVersion: 18.x + # testCommand: testOldConfig - task: PublishTestResults@2 displayName: 'Publish Unit Test Results' From 433955ea760df779f704f0328d2dbd7f85274394 Mon Sep 17 00:00:00 2001 From: Evan Roman Date: Tue, 22 Jul 2025 14:13:00 -0500 Subject: [PATCH 22/24] adjust --- .../templates/test-node-version.yml | 1 + azure-pipelines/templates/test.yml | 8 +-- src/eventHub.test.ts | 10 +++- src/storage.test.ts | 50 +++++++++---------- 4 files changed, 38 insertions(+), 31 deletions(-) diff --git a/azure-pipelines/templates/test-node-version.yml b/azure-pipelines/templates/test-node-version.yml index 1064596b..029551be 100644 --- a/azure-pipelines/templates/test-node-version.yml +++ b/azure-pipelines/templates/test-node-version.yml @@ -20,6 +20,7 @@ steps: docker compose -f src/utils/eventhub/docker-compose.yml pull docker compose -f src/utils/eventhub/docker-compose.yml up -d displayName: 'Install Azurite and Start EventHub Emulator' + condition: and(succeeded(), ne('${{ parameters.testCommand }}', 'testOldConfig')) - bash: | npm run ${{ parameters.testCommand }} displayName: 'Run tests Node ${{ parameters.nodeVersion }}' diff --git a/azure-pipelines/templates/test.yml b/azure-pipelines/templates/test.yml index e1d1489d..98ebca05 100644 --- a/azure-pipelines/templates/test.yml +++ b/azure-pipelines/templates/test.yml @@ -29,10 +29,10 @@ jobs: nodeVersion: 22.x # Run tests for old config (just one Node.js version is enough) - # - template: /azure-pipelines/templates/test-node-version.yml@self - # parameters: - # nodeVersion: 18.x - # testCommand: testOldConfig + - template: /azure-pipelines/templates/test-node-version.yml@self + parameters: + nodeVersion: 18.x + testCommand: testOldConfig - task: PublishTestResults@2 displayName: 'Publish Unit Test Results' diff --git a/src/eventHub.test.ts b/src/eventHub.test.ts index ed770fc3..9980f455 100644 --- a/src/eventHub.test.ts +++ b/src/eventHub.test.ts @@ -2,7 +2,7 @@ // Licensed under the MIT License. import { EventHubProducerClient } from '@azure/event-hubs'; -import { waitForOutput } from './global.test'; +import { isOldConfig, waitForOutput } from './global.test'; import { eventHubConnectionString } from './utils/connectionStrings'; import { getRandomTestData } from './utils/getRandomTestData'; import { EventHub } from './constants'; @@ -14,7 +14,13 @@ describe('eventHub', () => { let clientManyTrigger: EventHubProducerClient; - before(() => { + before(function (this: Mocha.Context) { + // Old config (Exts bundles < 4.0.0) cannot use EventHub emulator + // Microsoft.Azure.Functions.Worker.Extensions.EventHubs bundle must be >= 6.3.0 + // https://github.com/Azure/azure-event-hubs-emulator-installer/issues/15 + if (isOldConfig) { + this.skip(); + } clientOneTriggerAndOutput = new EventHubProducerClient(eventHubConnectionString, EventHub.eventHubOneTriggerAndOutput); clientOneTrigger = new EventHubProducerClient(eventHubConnectionString, EventHub.eventHubOneTrigger); clientManyTriggerAndOutput = new EventHubProducerClient(eventHubConnectionString, EventHub.eventHubManyTriggerAndOutput); diff --git a/src/storage.test.ts b/src/storage.test.ts index ff8a2ccb..562f0e8f 100644 --- a/src/storage.test.ts +++ b/src/storage.test.ts @@ -3,7 +3,7 @@ import { ContainerClient } from '@azure/storage-blob'; import { QueueClient } from '@azure/storage-queue'; -// import { expect } from 'chai'; +import { expect } from 'chai'; import { default as fetch } from 'node-fetch'; import { getFuncUrl } from './constants'; import { model, waitForOutput } from './global.test'; @@ -59,30 +59,30 @@ describe('storage', () => { ); }); - // type TableItem = { PartitionKey: string; RowKey: string; Name: string }; - - // it('table input and output', async () => { - // const rowKey = getRandomTestData(); - // const items: TableItem[] = [ - // { - // PartitionKey: 'e2eTestPartKey', - // RowKey: rowKey, - // Name: 'e2eTestName', - // }, - // ]; - // const responseOut = await fetch(getFuncUrl('httpTriggerTableOutput'), { - // method: 'POST', - // body: JSON.stringify(items), - // }); - // expect(responseOut.status).to.equal(201); - // await waitForOutput(`httpTriggerTableOutput was triggered`); - - // const responseIn = await fetch(getFuncUrl(`httpTriggerTableInput/${rowKey}`), { method: 'GET' }); - // expect(responseIn.status).to.equal(200); - // const result = await responseIn.json(); - // expect(result).to.deep.equal(items); - // await waitForOutput(`httpTriggerTableInput was triggered`); - // }); + type TableItem = { PartitionKey: string; RowKey: string; Name: string }; + + it('table input and output', async () => { + const rowKey = getRandomTestData(); + const items: TableItem[] = [ + { + PartitionKey: 'e2eTestPartKey', + RowKey: rowKey, + Name: 'e2eTestName', + }, + ]; + const responseOut = await fetch(getFuncUrl('httpTriggerTableOutput'), { + method: 'POST', + body: JSON.stringify(items), + }); + expect(responseOut.status).to.equal(201); + await waitForOutput(`httpTriggerTableOutput was triggered`); + + const responseIn = await fetch(getFuncUrl(`httpTriggerTableInput/${rowKey}`), { method: 'GET' }); + expect(responseIn.status).to.equal(200); + const result = await responseIn.json(); + expect(result).to.deep.equal(items); + await waitForOutput(`httpTriggerTableInput was triggered`); + }); // Test for bug https://github.com/Azure/azure-functions-nodejs-library/issues/179 it('Shared output bug', async function (this: Mocha.Context) { From 40662b7bf23fa1d82df5ba12e694120f58881bad Mon Sep 17 00:00:00 2001 From: Evan Roman Date: Tue, 22 Jul 2025 14:33:20 -0500 Subject: [PATCH 23/24] adjust --- app/v3/httpTriggerTableInput/index.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/v3/httpTriggerTableInput/index.ts b/app/v3/httpTriggerTableInput/index.ts index 34d8c02e..8e01167c 100644 --- a/app/v3/httpTriggerTableInput/index.ts +++ b/app/v3/httpTriggerTableInput/index.ts @@ -1,13 +1,13 @@ -// // Copyright (c) .NET Foundation. All rights reserved. -// // Licensed under the MIT License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. -// import { AzureFunction, Context, HttpRequest } from '@azure/functions'; +import { AzureFunction, Context, HttpRequest } from '@azure/functions'; -// const httpTriggerTableInput: AzureFunction = async function (context: Context, request: HttpRequest): Promise { -// context.log(`httpTriggerTableInput was triggered`); -// context.res = { -// body: context.bindings.inputItem, -// }; -// }; +const httpTriggerTableInput: AzureFunction = async function (context: Context, request: HttpRequest): Promise { + context.log(`httpTriggerTableInput was triggered`); + context.res = { + body: context.bindings.inputItem, + }; +}; -// export default httpTriggerTableInput; +export default httpTriggerTableInput; From 8758b64af1836607ca8e27cc635d432e27c4f735 Mon Sep 17 00:00:00 2001 From: Evan Roman Date: Tue, 22 Jul 2025 15:03:30 -0500 Subject: [PATCH 24/24] adjust --- src/eventHub.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/eventHub.test.ts b/src/eventHub.test.ts index 9980f455..c68ea8e6 100644 --- a/src/eventHub.test.ts +++ b/src/eventHub.test.ts @@ -28,10 +28,10 @@ describe('eventHub', () => { }); after(async () => { - void clientOneTriggerAndOutput.close(); - void clientOneTrigger.close(); - void clientManyTriggerAndOutput.close(); - void clientManyTrigger.close(); + void clientOneTriggerAndOutput?.close(); + void clientOneTrigger?.close(); + void clientManyTriggerAndOutput?.close(); + void clientManyTrigger?.close(); }); describe('cardinality one', () => {