From 080325a4d9c17e92ef9df43f5b68aba75b6cb39e Mon Sep 17 00:00:00 2001 From: Swapnil Nagar Date: Mon, 11 Aug 2025 14:59:28 -0700 Subject: [PATCH 1/9] Fixing TypeScript import equals declaration is not supported in strip-only mode --- src/coreApi/setProgrammingModel.ts | 6 +-- .../FunctionEnvironmentReloadHandler.ts | 18 ++++---- src/eventHandlers/FunctionLoadHandler.ts | 6 +-- src/eventHandlers/FunctionsMetadataHandler.ts | 6 +-- src/eventHandlers/WorkerInitHandler.ts | 14 +++---- src/eventHandlers/terminateWorker.ts | 6 +-- src/hooks/executeHooks.ts | 10 ++--- src/loadScriptFile.ts | 18 ++++---- src/setupEventStream.ts | 6 +-- src/startApp.ts | 18 ++++---- src/utils/blockedMonitor.ts | 6 +-- test/blockMonitorTest.ts | 3 +- test/eventHandlers/InvocationHandler.test.ts | 12 ++++-- test/eventHandlers/msg.ts | 42 +++++++++---------- 14 files changed, 75 insertions(+), 96 deletions(-) diff --git a/src/coreApi/setProgrammingModel.ts b/src/coreApi/setProgrammingModel.ts index 0c4e3878..ac568218 100644 --- a/src/coreApi/setProgrammingModel.ts +++ b/src/coreApi/setProgrammingModel.ts @@ -4,16 +4,14 @@ import { ProgrammingModel } from '@azure/functions-core'; import { AzureFunctionsRpcMessages as rpc } from '../../azure-functions-language-worker-protobuf/src/rpc'; import { worker } from '../WorkerContext'; -import LogCategory = rpc.RpcLog.RpcLogCategory; -import LogLevel = rpc.RpcLog.Level; export function setProgrammingModel(programmingModel: ProgrammingModel): void { // Log when setting the programming model, except for the initial default one (partially because the grpc channels aren't fully setup at that time) if (worker.app.programmingModel) { worker.log({ message: `Setting Node.js programming model to "${programmingModel.name}" version "${programmingModel.version}"`, - level: LogLevel.Information, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Information, + logCategory: rpc.RpcLog.RpcLogCategory.System, }); } else { worker.defaultProgrammingModel = programmingModel; diff --git a/src/eventHandlers/FunctionEnvironmentReloadHandler.ts b/src/eventHandlers/FunctionEnvironmentReloadHandler.ts index b9bd3afe..4f622eb7 100644 --- a/src/eventHandlers/FunctionEnvironmentReloadHandler.ts +++ b/src/eventHandlers/FunctionEnvironmentReloadHandler.ts @@ -7,8 +7,6 @@ import { worker } from '../WorkerContext'; import { EventHandler } from './EventHandler'; import { getWorkerCapabilities } from './getWorkerCapabilities'; import { getWorkerMetadata } from './getWorkerMetadata'; -import LogCategory = rpc.RpcLog.RpcLogCategory; -import LogLevel = rpc.RpcLog.Level; import CapabilitiesUpdateStrategy = rpc.FunctionEnvironmentReloadResponse.CapabilitiesUpdateStrategy; import * as path from 'path'; @@ -31,8 +29,8 @@ export class FunctionEnvironmentReloadHandler extends EventHandler< if (!msg.functionAppDirectory) { worker.log({ message: `FunctionEnvironmentReload functionAppDirectory is not defined`, - level: LogLevel.Debug, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Debug, + logCategory: rpc.RpcLog.RpcLogCategory.System, }); } @@ -43,8 +41,8 @@ export class FunctionEnvironmentReloadHandler extends EventHandler< ) { worker.log({ message: `FunctionEnvironmentReload functionAppDirectory has not changed`, - level: LogLevel.Debug, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Debug, + logCategory: rpc.RpcLog.RpcLogCategory.System, }); } @@ -56,8 +54,8 @@ export class FunctionEnvironmentReloadHandler extends EventHandler< const numVariables = (msg.environmentVariables && Object.keys(msg.environmentVariables).length) || 0; worker.log({ message: `Reloading environment variables. Found ${numVariables} variables to reload.`, - level: LogLevel.Information, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Information, + logCategory: rpc.RpcLog.RpcLogCategory.System, }); // reset existing env vars @@ -69,8 +67,8 @@ export class FunctionEnvironmentReloadHandler extends EventHandler< if (msg.functionAppDirectory) { worker.log({ message: `Changing current working directory to ${msg.functionAppDirectory}`, - level: LogLevel.Information, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Information, + logCategory: rpc.RpcLog.RpcLogCategory.System, }); process.chdir(msg.functionAppDirectory); await startApp(msg.functionAppDirectory); diff --git a/src/eventHandlers/FunctionLoadHandler.ts b/src/eventHandlers/FunctionLoadHandler.ts index f60f1196..1799de0b 100644 --- a/src/eventHandlers/FunctionLoadHandler.ts +++ b/src/eventHandlers/FunctionLoadHandler.ts @@ -7,8 +7,6 @@ import { loadLegacyFunction } from '../LegacyFunctionLoader'; import { isDefined, nonNullProp } from '../utils/nonNull'; import { worker } from '../WorkerContext'; import { EventHandler } from './EventHandler'; -import LogCategory = rpc.RpcLog.RpcLogCategory; -import LogLevel = rpc.RpcLog.Level; /** * Worker responds after loading required metadata to load function with the load result @@ -27,8 +25,8 @@ export class FunctionLoadHandler extends EventHandler<'functionLoadRequest', 'fu worker.log({ message: `Worker ${worker.id} received FunctionLoadRequest`, - level: LogLevel.Debug, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Debug, + logCategory: rpc.RpcLog.RpcLogCategory.System, }); if (isDefined(worker.app.blockingAppStartError)) { diff --git a/src/eventHandlers/FunctionsMetadataHandler.ts b/src/eventHandlers/FunctionsMetadataHandler.ts index ced7f773..5dc4bcf3 100644 --- a/src/eventHandlers/FunctionsMetadataHandler.ts +++ b/src/eventHandlers/FunctionsMetadataHandler.ts @@ -5,8 +5,6 @@ import { AzureFunctionsRpcMessages as rpc } from '../../azure-functions-language import { isDefined } from '../utils/nonNull'; import { worker } from '../WorkerContext'; import { EventHandler } from './EventHandler'; -import LogCategory = rpc.RpcLog.RpcLogCategory; -import LogLevel = rpc.RpcLog.Level; export class FunctionsMetadataHandler extends EventHandler<'functionsMetadataRequest', 'functionMetadataResponse'> { readonly responseName = 'functionMetadataResponse'; @@ -24,8 +22,8 @@ export class FunctionsMetadataHandler extends EventHandler<'functionsMetadataReq worker.log({ message: `Worker ${worker.id} received FunctionsMetadataRequest`, - level: LogLevel.Debug, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Debug, + logCategory: rpc.RpcLog.RpcLogCategory.System, }); if (worker.app.isUsingWorkerIndexing) { diff --git a/src/eventHandlers/WorkerInitHandler.ts b/src/eventHandlers/WorkerInitHandler.ts index 37186305..d489e34a 100644 --- a/src/eventHandlers/WorkerInitHandler.ts +++ b/src/eventHandlers/WorkerInitHandler.ts @@ -11,8 +11,6 @@ import { worker } from '../WorkerContext'; import { EventHandler } from './EventHandler'; import { getWorkerCapabilities } from './getWorkerCapabilities'; import { getWorkerMetadata } from './getWorkerMetadata'; -import LogCategory = rpc.RpcLog.RpcLogCategory; -import LogLevel = rpc.RpcLog.Level; /** * Host sends capabilities/init data to worker and requests the worker to initialize itself @@ -30,8 +28,8 @@ export class WorkerInitHandler extends EventHandler<'workerInitRequest', 'worker if (!msg.functionAppDirectory) { worker.log({ message: `WorkerInit functionAppDirectory is not defined`, - level: LogLevel.Debug, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Debug, + logCategory: rpc.RpcLog.RpcLogCategory.System, }); } worker.app.functionAppDirectory = msg.functionAppDirectory; @@ -40,8 +38,8 @@ export class WorkerInitHandler extends EventHandler<'workerInitRequest', 'worker worker.log({ message: `Worker ${worker.id} received WorkerInitRequest`, - level: LogLevel.Debug, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Debug, + logCategory: rpc.RpcLog.RpcLogCategory.System, }); logColdStartWarning(); @@ -75,8 +73,8 @@ export function logColdStartWarning(delayInMs?: number): void { worker.log({ message: 'package.json is not found at the root of the Function App in Azure Files - cold start for NodeJs can be affected.', - level: LogLevel.Debug, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Debug, + logCategory: rpc.RpcLog.RpcLogCategory.System, }); } }); diff --git a/src/eventHandlers/terminateWorker.ts b/src/eventHandlers/terminateWorker.ts index 08256c8d..939c1603 100644 --- a/src/eventHandlers/terminateWorker.ts +++ b/src/eventHandlers/terminateWorker.ts @@ -6,14 +6,12 @@ import { AzureFunctionsRpcMessages as rpc } from '../../azure-functions-language import { ReadOnlyError } from '../errors'; import { executeHooks } from '../hooks/executeHooks'; import { worker } from '../WorkerContext'; -import LogCategory = rpc.RpcLog.RpcLogCategory; -import LogLevel = rpc.RpcLog.Level; export async function terminateWorker(_msg: rpc.IWorkerTerminate) { worker.log({ message: 'Received workerTerminate message; gracefully shutting down worker', - level: LogLevel.Debug, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Debug, + logCategory: rpc.RpcLog.RpcLogCategory.System, }); const appTerminateContext: AppTerminateContext = { diff --git a/src/hooks/executeHooks.ts b/src/hooks/executeHooks.ts index acccd72b..ff2d8fc0 100644 --- a/src/hooks/executeHooks.ts +++ b/src/hooks/executeHooks.ts @@ -5,8 +5,6 @@ import { HookContext } from '@azure/functions-core'; import { AzureFunctionsRpcMessages as rpc } from '../../azure-functions-language-worker-protobuf/src/rpc'; import { worker } from '../WorkerContext'; import { getHooks } from './getHooks'; -import LogLevel = rpc.RpcLog.Level; -import LogCategory = rpc.RpcLog.RpcLogCategory; export async function executeHooks( hookName: string, @@ -18,8 +16,8 @@ export async function executeHooks( if (callbacks.length > 0) { worker.log({ message: `Executing ${callbacks.length} "${hookName}" hooks`, - level: LogLevel.Debug, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Debug, + logCategory: rpc.RpcLog.RpcLogCategory.System, invocationId, category: msgCategory, }); @@ -28,8 +26,8 @@ export async function executeHooks( } worker.log({ message: `Executed "${hookName}" hooks`, - level: LogLevel.Debug, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Debug, + logCategory: rpc.RpcLog.RpcLogCategory.System, invocationId, category: msgCategory, }); diff --git a/src/loadScriptFile.ts b/src/loadScriptFile.ts index a6f332dc..0bebf5ae 100644 --- a/src/loadScriptFile.ts +++ b/src/loadScriptFile.ts @@ -8,8 +8,6 @@ import { AzureFunctionsRpcMessages as rpc } from '../azure-functions-language-wo import { AzFuncSystemError } from './errors'; import { PackageJson } from './parsers/parsePackageJson'; import { worker } from './WorkerContext'; -import LogCategory = rpc.RpcLog.RpcLogCategory; -import LogLevel = rpc.RpcLog.Level; let hasLoggedAttempt = 0; let hasLoggedWarning = false; @@ -23,8 +21,8 @@ export async function loadScriptFile(filePath: string, packageJson: PackageJson) if (currentAttempt > 1 && currentAttempt > hasLoggedAttempt) { worker.log({ message: `Retrying file load. Attempt ${currentAttempt}/${retries + 1}`, - level: LogLevel.Debug, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Debug, + logCategory: rpc.RpcLog.RpcLogCategory.System, }); hasLoggedAttempt = currentAttempt; } @@ -40,8 +38,8 @@ export async function loadScriptFile(filePath: string, packageJson: PackageJson) } else if (error.retriesLeft > 0 && !hasLoggedWarning) { worker.log({ message: `Warning: Failed to load file with error "${error.message}"`, - level: LogLevel.Warning, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Warning, + logCategory: rpc.RpcLog.RpcLogCategory.System, }); hasLoggedWarning = true; } @@ -82,13 +80,13 @@ function warnIfLongLoadTime(filePath: string, start: number): void { ) { worker.log({ message: `Loading "${path.basename(filePath)}" took ${timeElapsed}ms`, - level: LogLevel.Warning, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Warning, + logCategory: rpc.RpcLog.RpcLogCategory.System, }); worker.log({ message: `Set "${rfpName}" to "1" to significantly improve load times. Learn more here: https://aka.ms/AAjon54`, - level: LogLevel.Warning, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Warning, + logCategory: rpc.RpcLog.RpcLogCategory.System, }); } } diff --git a/src/setupEventStream.ts b/src/setupEventStream.ts index 3f5a7603..71fb2e30 100644 --- a/src/setupEventStream.ts +++ b/src/setupEventStream.ts @@ -13,8 +13,6 @@ import { WorkerInitHandler } from './eventHandlers/WorkerInitHandler'; import { systemError } from './utils/Logger'; import { nonNullProp } from './utils/nonNull'; import { worker } from './WorkerContext'; -import LogCategory = rpc.RpcLog.RpcLogCategory; -import LogLevel = rpc.RpcLog.Level; /** * Configures handlers for incoming gRPC messages on the client @@ -101,8 +99,8 @@ async function handleMessage(inMsg: rpc.StreamingMessage): Promise { if (error.isAzureFunctionsSystemError && !error.loggedOverRpc) { worker.log({ message: error.message, - level: LogLevel.Error, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Error, + logCategory: rpc.RpcLog.RpcLogCategory.System, }); } diff --git a/src/startApp.ts b/src/startApp.ts index 134e3e71..83e3ce5f 100644 --- a/src/startApp.ts +++ b/src/startApp.ts @@ -12,8 +12,6 @@ import { isEnvironmentVariableSet, isNode20Plus } from './utils/util'; import { worker } from './WorkerContext'; import globby = require('globby'); import path = require('path'); -import LogLevel = rpc.RpcLog.Level; -import LogCategory = rpc.RpcLog.RpcLogCategory; /** * Starting an app can happen in two places, depending on if the worker was specialized or not @@ -51,8 +49,8 @@ async function updatePackageJson(functionAppDirectory: string): Promise { const error = ensureErrorType(err); worker.log({ message: `Worker failed to load package.json: ${error.message}`, - level: LogLevel.Warning, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Warning, + logCategory: rpc.RpcLog.RpcLogCategory.System, }); worker.app.packageJson = {}; } @@ -81,8 +79,8 @@ async function loadEntryPointFile(functionAppDirectory: string): Promise { currentFile = file; worker.log({ message: `Loading entry point file "${file}"`, - level: LogLevel.Debug, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Debug, + logCategory: rpc.RpcLog.RpcLogCategory.System, }); try { const entryPointFilePath = path.join(functionAppDirectory, file); @@ -93,8 +91,8 @@ async function loadEntryPointFile(functionAppDirectory: string): Promise { } worker.log({ message: `Loaded entry point file "${file}"`, - level: LogLevel.Debug, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Debug, + logCategory: rpc.RpcLog.RpcLogCategory.System, }); } } catch (err) { @@ -119,8 +117,8 @@ async function loadEntryPointFile(functionAppDirectory: string): Promise { // Always log as rpc system log, which goes to our internal telemetry worker.log({ message: newMessage, - level: LogLevel.Error, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Error, + logCategory: rpc.RpcLog.RpcLogCategory.System, }); error.loggedOverRpc = true; } diff --git a/src/utils/blockedMonitor.ts b/src/utils/blockedMonitor.ts index b302df7e..91cac3fe 100644 --- a/src/utils/blockedMonitor.ts +++ b/src/utils/blockedMonitor.ts @@ -2,8 +2,6 @@ // Licensed under the MIT License. import { AzureFunctionsRpcMessages as rpc } from './../../azure-functions-language-worker-protobuf/src/rpc'; -import LogCategory = rpc.RpcLog.RpcLogCategory; -import LogLevel = rpc.RpcLog.Level; import blockedAt = require('blocked-at'); export function startBlockedMonitor( @@ -14,8 +12,8 @@ export function startBlockedMonitor( function logBlockedWarning(message: string) { worker.log({ message, - level: LogLevel.Warning, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Warning, + logCategory: rpc.RpcLog.RpcLogCategory.System, }); } diff --git a/test/blockMonitorTest.ts b/test/blockMonitorTest.ts index 64d5548c..bdeb35d6 100644 --- a/test/blockMonitorTest.ts +++ b/test/blockMonitorTest.ts @@ -5,7 +5,6 @@ import 'mocha'; import { expect } from 'chai'; import { AzureFunctionsRpcMessages as rpc } from './../azure-functions-language-worker-protobuf/src/rpc'; import { startBlockedMonitor } from './../src/utils/blockedMonitor'; -import LogLevel = rpc.RpcLog.Level; describe('Event loop blocking operation monitor', () => { it('startBlockMonitor logs warning', async () => { @@ -13,7 +12,7 @@ describe('Event loop blocking operation monitor', () => { let timer: NodeJS.Timer | null = null; let isTimerDestroyed = false; const logFun = function (log: rpc.IRpcLog): void { - expect(log.level).to.equal(LogLevel.Warning); + expect(log.level).to.equal(rpc.RpcLog.Level.Warning); if (log.message && log.message.startsWith('Blocking code monitoring history')) { if (timer) { clearInterval(timer); diff --git a/test/eventHandlers/InvocationHandler.test.ts b/test/eventHandlers/InvocationHandler.test.ts index d4f3219f..f0134ff2 100644 --- a/test/eventHandlers/InvocationHandler.test.ts +++ b/test/eventHandlers/InvocationHandler.test.ts @@ -13,8 +13,6 @@ import { worker } from '../../src/WorkerContext'; import { beforeEventHandlerSuite } from './beforeEventHandlerSuite'; import { msg } from './msg'; import { TestEventStream } from './TestEventStream'; -import LogCategory = rpc.RpcLog.RpcLogCategory; -import LogLevel = rpc.RpcLog.Level; namespace Binding { export const httpInput = { @@ -382,7 +380,13 @@ describe('InvocationHandler', () => { const errorMessage = "Function code for 'testFuncId' is not loaded and cannot be invoked."; stream.addTestMessage(msg.invocation.request()); await stream.assertCalledWith( - { rpcLog: { level: LogLevel.Error, logCategory: LogCategory.System, message: errorMessage } }, + { + rpcLog: { + level: rpc.RpcLog.Level.Error, + logCategory: rpc.RpcLog.RpcLogCategory.System, + message: errorMessage, + }, + }, msg.invocation.failedResponse(errorMessage) ); }); @@ -1076,7 +1080,7 @@ describe('InvocationHandler', () => { stream.addTestMessage(msg.invocation.request([InputData.http])); await stream.assertCalledWith( msg.invocation.receivedRequestLog, - msg.invocation.userLog('testUserLogUpdatedFromHook', LogLevel.Error), + msg.invocation.userLog('testUserLogUpdatedFromHook', rpc.RpcLog.Level.Error), msg.invocation.response([]) ); }); diff --git a/test/eventHandlers/msg.ts b/test/eventHandlers/msg.ts index bcaa3b6b..134ecaeb 100644 --- a/test/eventHandlers/msg.ts +++ b/test/eventHandlers/msg.ts @@ -5,8 +5,6 @@ import 'mocha'; import { AzureFunctionsRpcMessages as rpc } from '../../azure-functions-language-worker-protobuf/src/rpc'; import { testAppPath, testAppSrcPath } from './testAppUtils'; import { RegExpProps, RegExpStreamingMessage } from './TestEventStream'; -import LogCategory = rpc.RpcLog.RpcLogCategory; -import LogLevel = rpc.RpcLog.Level; import escapeStringRegexp = require('escape-string-regexp'); import path = require('path'); @@ -29,28 +27,28 @@ function workerMetadataRegExps(responseName: string) { export namespace msg { export function errorLog(message: string | RegExp): TestMessage { - return log(message, LogLevel.Error); + return log(message, rpc.RpcLog.Level.Error); } export function warningLog(message: string | RegExp): TestMessage { - return log(message, LogLevel.Warning); + return log(message, rpc.RpcLog.Level.Warning); } export function debugLog(message: string | RegExp): TestMessage { - return log(message, LogLevel.Debug); + return log(message, rpc.RpcLog.Level.Debug); } export function infoLog(message: string | RegExp): TestMessage { - return log(message, LogLevel.Information); + return log(message, rpc.RpcLog.Level.Information); } - export function log(message: string | RegExp, level: LogLevel): TestMessage { + export function log(message: string | RegExp, level: rpc.RpcLog.Level): TestMessage { if (typeof message === 'string') { return { rpcLog: { message, level, - logCategory: LogCategory.System, + logCategory: rpc.RpcLog.RpcLogCategory.System, }, }; } else { @@ -58,7 +56,7 @@ export namespace msg { { rpcLog: { level, - logCategory: LogCategory.System, + logCategory: rpc.RpcLog.RpcLogCategory.System, }, }, { @@ -90,8 +88,8 @@ export namespace msg { category: undefined, invocationId: undefined, message: `Executing ${count} "${hookName}" hooks`, - level: LogLevel.Debug, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Debug, + logCategory: rpc.RpcLog.RpcLogCategory.System, }, }; } @@ -102,8 +100,8 @@ export namespace msg { category: undefined, invocationId: undefined, message: `Executed "${hookName}" hooks`, - level: LogLevel.Debug, - logCategory: LogCategory.System, + level: rpc.RpcLog.Level.Debug, + logCategory: rpc.RpcLog.RpcLogCategory.System, }, }; } @@ -322,22 +320,22 @@ export namespace msg { export namespace invocation { export function errorLog(message: string | RegExp): TestMessage { - return log(message, LogLevel.Error); + return log(message, rpc.RpcLog.Level.Error); } export function warningLog(message: string | RegExp): TestMessage { - return log(message, LogLevel.Warning); + return log(message, rpc.RpcLog.Level.Warning); } export function debugLog(message: string | RegExp): TestMessage { - return log(message, LogLevel.Debug); + return log(message, rpc.RpcLog.Level.Debug); } export function infoLog(message: string | RegExp): TestMessage { - return log(message, LogLevel.Information); + return log(message, rpc.RpcLog.Level.Information); } - export function log(message: string | RegExp, level: LogLevel): TestMessage { + export function log(message: string | RegExp, level: rpc.RpcLog.Level): TestMessage { if (typeof message === 'string') { return { rpcLog: { @@ -345,7 +343,7 @@ export namespace msg { invocationId: '1', message, level, - logCategory: LogCategory.System, + logCategory: rpc.RpcLog.RpcLogCategory.System, }, }; } else { @@ -355,7 +353,7 @@ export namespace msg { category: 'testFuncName.Invocation', invocationId: '1', level, - logCategory: LogCategory.System, + logCategory: rpc.RpcLog.RpcLogCategory.System, }, }, { @@ -389,14 +387,14 @@ export namespace msg { "Warning: Unexpected call to 'log' on the context object after function execution has completed. Please check for asynchronous calls that are not awaited or calls to 'done' made before function execution completes. Function name: testFuncName. Invocation Id: 1. Learn more: https://go.microsoft.com/fwlink/?linkid=2097909" ); - export function userLog(data = 'testUserLog', level = LogLevel.Information): TestMessage { + export function userLog(data = 'testUserLog', level = rpc.RpcLog.Level.Information): TestMessage { return { rpcLog: { category: 'testFuncName.Invocation', invocationId: '1', message: data, level, - logCategory: LogCategory.User, + logCategory: rpc.RpcLog.RpcLogCategory.User, }, }; } From be05afa013d92afcaf36ce2c7212864b4f4fbeb6 Mon Sep 17 00:00:00 2001 From: Swapnil Nagar Date: Mon, 11 Aug 2025 15:13:21 -0700 Subject: [PATCH 2/9] Updating pipelline to add Node 24 support --- azure-pipelines/templates/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/azure-pipelines/templates/test.yml b/azure-pipelines/templates/test.yml index 0bbead66..43aedbc7 100644 --- a/azure-pipelines/templates/test.yml +++ b/azure-pipelines/templates/test.yml @@ -13,6 +13,8 @@ jobs: NODE_VERSION: '20.x' Node22: NODE_VERSION: '22.x' + Node22: + NODE_VERSION: '24.x' steps: - task: NodeTool@0 From d62faef2adbe753b9b716387a0f692a5e366e09d Mon Sep 17 00:00:00 2001 From: Swapnil Nagar Date: Tue, 12 Aug 2025 09:37:18 -0700 Subject: [PATCH 3/9] Updating Staging --- azure-pipelines/templates/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/templates/test.yml b/azure-pipelines/templates/test.yml index 43aedbc7..324ea9a6 100644 --- a/azure-pipelines/templates/test.yml +++ b/azure-pipelines/templates/test.yml @@ -13,7 +13,7 @@ jobs: NODE_VERSION: '20.x' Node22: NODE_VERSION: '22.x' - Node22: + Node24: NODE_VERSION: '24.x' steps: From 93304e46c035bee3d262f64bb89a14a8611b28f5 Mon Sep 17 00:00:00 2001 From: Swapnil Nagar Date: Tue, 12 Aug 2025 09:44:33 -0700 Subject: [PATCH 4/9] Fixing tests --- test/eventHandlers/InvocationHandler.test.ts | 74 ++++++++++---------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/test/eventHandlers/InvocationHandler.test.ts b/test/eventHandlers/InvocationHandler.test.ts index f0134ff2..4ba5cb9e 100644 --- a/test/eventHandlers/InvocationHandler.test.ts +++ b/test/eventHandlers/InvocationHandler.test.ts @@ -14,38 +14,23 @@ import { beforeEventHandlerSuite } from './beforeEventHandlerSuite'; import { msg } from './msg'; import { TestEventStream } from './TestEventStream'; -namespace Binding { - export const httpInput = { +export const Binding = { + httpInput: { type: 'httpTrigger', direction: 0, dataType: 1, - }; - export const httpOutput = { + }, + httpOutput: { type: 'http', direction: 1, dataType: 1, - }; - export const queueOutput = { + }, + queueOutput: { type: 'queue', direction: 1, dataType: 1, - }; - - export const httpReturn = { - bindings: { - req: httpInput, - $return: httpOutput, - }, - name: 'testFuncName', - }; - export const httpRes = { - bindings: { - req: httpInput, - res: httpOutput, - }, - name: 'testFuncName', - }; - export const activity = { + }, + activity: { bindings: { name: { type: 'activityTrigger', @@ -54,8 +39,8 @@ namespace Binding { }, }, name: 'testFuncName', - }; - export const queue = { + }, + queue: { bindings: { testOutput: { type: 'queue', @@ -64,8 +49,25 @@ namespace Binding { }, }, name: 'testFuncName', - }; -} + }, +}; + +export const BindingObj = { + httpReturn: { + bindings: { + req: Binding.httpInput, + $return: Binding.httpOutput, + }, + name: 'testFuncName', + }, + httpRes: { + bindings: { + req: Binding.httpInput, + res: Binding.httpOutput, + }, + name: 'testFuncName', + }, +}; const testError = new Error('testErrorMessage'); @@ -265,7 +267,7 @@ describe('InvocationHandler', () => { for (const [func, suffix] of TestFunc.basic) { it('invokes function' + suffix, async () => { - registerV3Func(Binding.httpRes, func); + registerV3Func(BindingObj.httpRes, func); stream.addTestMessage(msg.invocation.request([InputData.http])); await stream.assertCalledWith( msg.invocation.receivedRequestLog, @@ -277,7 +279,7 @@ describe('InvocationHandler', () => { for (const [func, suffix] of TestFunc.returnHttp) { it('returns correct data with $return binding' + suffix, async () => { - registerV3Func(Binding.httpReturn, func); + registerV3Func(BindingObj.httpReturn, func); stream.addTestMessage(msg.invocation.request([InputData.http])); const expectedOutput = getHttpResponse(undefined, '$return'); const expectedReturnValue = { @@ -311,7 +313,7 @@ describe('InvocationHandler', () => { for (const [func, suffix] of TestFunc.returnArray) { it('returned output is ignored if http' + suffix, async () => { - registerV3Func(Binding.httpRes, func); + registerV3Func(BindingObj.httpRes, func); stream.addTestMessage(msg.invocation.request([])); await stream.assertCalledWith(msg.invocation.receivedRequestLog, msg.invocation.response([], undefined)); }); @@ -319,7 +321,7 @@ describe('InvocationHandler', () => { for (const [func, suffix] of TestFunc.resHttp) { it('serializes output binding data through context.done' + suffix, async () => { - registerV3Func(Binding.httpRes, func); + registerV3Func(BindingObj.httpRes, func); stream.addTestMessage(msg.invocation.request([InputData.http])); const expectedOutput = [getHttpResponse({ hello: 'world' })]; await stream.assertCalledWith(msg.invocation.receivedRequestLog, msg.invocation.response(expectedOutput)); @@ -392,13 +394,13 @@ describe('InvocationHandler', () => { }); it('empty function does not return invocation response', async () => { - registerV3Func(Binding.httpRes, () => {}); + registerV3Func(BindingObj.httpRes, () => {}); stream.addTestMessage(msg.invocation.request([InputData.http])); await stream.assertCalledWith(msg.invocation.receivedRequestLog); }); it('logs error on calling context.done in async function', async () => { - registerV3Func(Binding.httpRes, async (context: Context) => { + registerV3Func(BindingObj.httpRes, async (context: Context) => { context.done(); }); stream.addTestMessage(msg.invocation.request([InputData.http])); @@ -410,7 +412,7 @@ describe('InvocationHandler', () => { }); it('logs error on calling context.done more than once', async () => { - registerV3Func(Binding.httpRes, (context: Context) => { + registerV3Func(BindingObj.httpRes, (context: Context) => { context.done(); context.done(); }); @@ -423,7 +425,7 @@ describe('InvocationHandler', () => { }); it('logs error on calling context.log after context.done', async () => { - registerV3Func(Binding.httpRes, (context: Context) => { + registerV3Func(BindingObj.httpRes, (context: Context) => { context.done(); context.log('testUserLog'); }); @@ -438,7 +440,7 @@ describe('InvocationHandler', () => { it('logs error on calling context.log after async function', async () => { let _context: Context; - registerV3Func(Binding.httpRes, async (context: Context) => { + registerV3Func(BindingObj.httpRes, async (context: Context) => { _context = context; return 'hello'; }); From b97ce5eeac8b51dc9581a084e5941c4aae2ecfaa Mon Sep 17 00:00:00 2001 From: Swapnil Nagar Date: Tue, 12 Aug 2025 14:16:16 -0700 Subject: [PATCH 5/9] Unit tests fix and avoid transpiling --- test/eventHandlers/InvocationHandler.test.ts | 258 ++++++----- test/eventHandlers/msg.ts | 461 +++++++++---------- test/eventHandlers/terminateWorker.test.ts | 2 +- test/eventHandlers/testAppUtils.ts | 4 +- test/startApp.test.ts | 12 +- 5 files changed, 368 insertions(+), 369 deletions(-) diff --git a/test/eventHandlers/InvocationHandler.test.ts b/test/eventHandlers/InvocationHandler.test.ts index 4ba5cb9e..5f3c785d 100644 --- a/test/eventHandlers/InvocationHandler.test.ts +++ b/test/eventHandlers/InvocationHandler.test.ts @@ -80,137 +80,151 @@ function addSuffix(asyncFunc: AzureFunction, callbackFunc: AzureFunction): [Azur let hookData: string; -namespace TestFunc { - const basicAsync = async (context: Context) => { - context.log('testUserLog'); - }; - const basicCallback = (context: Context) => { - context.log('testUserLog'); - context.done(); - }; - export const basic = addSuffix(basicAsync, basicCallback); - - const returnHttpAsync = async (_context: Context) => { - return { body: { hello: 'world' } }; - }; - const returnHttpCallback = (context: Context) => { - context.done(null, { body: { hello: 'world' } }); - }; - export const returnHttp = addSuffix(returnHttpAsync, returnHttpCallback); +const basicAsync = async (context: Context) => { + context.log('testUserLog'); +}; +const basicCallback = (context: Context) => { + context.log('testUserLog'); + context.done(); +}; +export const basic = addSuffix(basicAsync, basicCallback); - const returnArrayAsync = async (_context: Context) => { - return ['hello, seattle!', 'hello, tokyo!']; - }; - const returnArrayCallback = (context: Context) => { - context.done(null, ['hello, seattle!', 'hello, tokyo!']); - }; - export const returnArray = addSuffix(returnArrayAsync, returnArrayCallback); +const returnHttpAsync = async (_context: Context) => { + return { body: { hello: 'world' } }; +}; +const returnHttpCallback = (context: Context) => { + context.done(null, { body: { hello: 'world' } }); +}; +export const returnHttp = addSuffix(returnHttpAsync, returnHttpCallback); - const resHttpAsync = async (_context: Context) => { - return { res: { body: { hello: 'world' } } }; - }; - const resHttpCallback = (context: Context) => { - context.done(null, { res: { body: { hello: 'world' } } }); - }; - export const resHttp = addSuffix(resHttpAsync, resHttpCallback); +const returnArrayAsync = async (_context: Context) => { + return ['hello, seattle!', 'hello, tokyo!']; +}; +const returnArrayCallback = (context: Context) => { + context.done(null, ['hello, seattle!', 'hello, tokyo!']); +}; +export const returnArray = addSuffix(returnArrayAsync, returnArrayCallback); - const logHookDataAsync = async (context: Context) => { - hookData += 'invoc'; - context.log(hookData); - return 'hello'; - }; - const logHookDataCallback = (context: Context) => { - hookData += 'invoc'; - context.log(hookData); - context.done(null, 'hello'); - }; - export const logHookData = addSuffix(logHookDataAsync, logHookDataCallback); +const resHttpAsync = async (_context: Context) => { + return { res: { body: { hello: 'world' } } }; +}; +const resHttpCallback = (context: Context) => { + context.done(null, { res: { body: { hello: 'world' } } }); +}; +export const resHttp = addSuffix(resHttpAsync, resHttpCallback); - const logInputAsync = async (context: Context, input: any) => { - context.log(input); - }; - const logInputCallback = (context: Context, input: any) => { - context.log(input); - context.done(); - }; - export const logInput = addSuffix(logInputAsync, logInputCallback); +const logHookDataAsync = async (context: Context) => { + hookData += 'invoc'; + context.log(hookData); + return 'hello'; +}; +const logHookDataCallback = (context: Context) => { + hookData += 'invoc'; + context.log(hookData); + context.done(null, 'hello'); +}; +export const logHookData = addSuffix(logHookDataAsync, logHookDataCallback); - const multipleBindingsAsync = async (context: Context) => { - context.bindings.queueOutput = 'queue message'; - context.bindings.overriddenQueueOutput = 'start message'; - return { - res: { body: { hello: 'world' } }, - overriddenQueueOutput: 'override', - }; - }; - const multipleBindingsCallback = (context: Context) => { - context.bindings.queueOutput = 'queue message'; - context.bindings.overriddenQueueOutput = 'start message'; - context.done(null, { - res: { body: { hello: 'world' } }, - overriddenQueueOutput: 'override', - }); +const logInputAsync = async (context: Context, input: any) => { + context.log(input); +}; +const logInputCallback = (context: Context, input: any) => { + context.log(input); + context.done(); +}; +export const logInput = addSuffix(logInputAsync, logInputCallback); + +const multipleBindingsAsync = async (context: Context) => { + context.bindings.queueOutput = 'queue message'; + context.bindings.overriddenQueueOutput = 'start message'; + return { + res: { body: { hello: 'world' } }, + overriddenQueueOutput: 'override', }; - export const multipleBindings = addSuffix(multipleBindingsAsync, multipleBindingsCallback); +}; +const multipleBindingsCallback = (context: Context) => { + context.bindings.queueOutput = 'queue message'; + context.bindings.overriddenQueueOutput = 'start message'; + context.done(null, { + res: { body: { hello: 'world' } }, + overriddenQueueOutput: 'override', + }); +}; +export const multipleBindings = addSuffix(multipleBindingsAsync, multipleBindingsCallback); - const errorAsync = async (_context: Context) => { - throw testError; - }; - const errorCallback = (context: Context) => { - context.done(testError); - }; - export const error = addSuffix(errorAsync, errorCallback); +const errorAsync = async (_context: Context) => { + throw testError; +}; +const errorCallback = (context: Context) => { + context.done(testError); +}; +export const error = addSuffix(errorAsync, errorCallback); - const returnEmptyStringAsync = async (_context: Context) => { - return ''; - }; - const returnEmptyStringCallback = (context: Context) => { - context.done(null, ''); - }; - export const returnEmptyString = addSuffix(returnEmptyStringAsync, returnEmptyStringCallback); +const returnEmptyStringAsync = async (_context: Context) => { + return ''; +}; +const returnEmptyStringCallback = (context: Context) => { + context.done(null, ''); +}; +export const returnEmptyString = addSuffix(returnEmptyStringAsync, returnEmptyStringCallback); - const returnZeroAsync = async (_context: Context) => { - return 0; - }; - const returnZeroCallback = (context: Context) => { - context.done(null, 0); - }; - export const returnZero = addSuffix(returnZeroAsync, returnZeroCallback); +const returnZeroAsync = async (_context: Context) => { + return 0; +}; +const returnZeroCallback = (context: Context) => { + context.done(null, 0); +}; +export const returnZero = addSuffix(returnZeroAsync, returnZeroCallback); - const returnFalseAsync = async (_context: Context) => { - return false; - }; - const returnFalseCallback = (context: Context) => { - context.done(null, false); - }; - export const returnFalse = addSuffix(returnFalseAsync, returnFalseCallback); -} +const returnFalseAsync = async (_context: Context) => { + return false; +}; +const returnFalseCallback = (context: Context) => { + context.done(null, false); +}; +export const returnFalse = addSuffix(returnFalseAsync, returnFalseCallback); + +export const TestFunc = { + basic, + returnHttp, + returnArray, + resHttp, + logHookData, + logInput, + multipleBindings, + error, + returnEmptyString, + returnZero, + returnFalse, +}; -namespace InputData { - export const http = { - name: 'req', - data: { - data: 'http', - http: { - body: { - string: 'blahh', - }, - rawBody: { - string: 'blahh', - }, +export const http = { + name: 'req', + data: { + data: 'http', + http: { + body: { + string: 'blahh', + }, + rawBody: { + string: 'blahh', }, }, - }; + }, +}; - export const string = { - name: 'testInput', - data: { - data: 'string', - string: 'testStringData', - }, - }; -} +export const string = { + name: 'testInput', + data: { + data: 'string', + string: 'testStringData', + }, +}; +export const InputData = { + http, + string, +}; describe('InvocationHandler', () => { let stream: TestEventStream; let coreApi: typeof coreTypes; @@ -260,7 +274,7 @@ describe('InvocationHandler', () => { function registerV3Func(metadata: rpc.IRpcFunctionMetadata, callback: AzureFunction): void { worker.app.legacyFunctions.testFuncId = { metadata, - callback: callback, + callback: callback as coreTypes.FunctionCallback, thisArg: undefined, }; } @@ -372,9 +386,9 @@ describe('InvocationHandler', () => { it('throws for malformed messages', () => { expect(() => { - stream.write({ + stream.write({ functionLoadResponse: 1, - }); + } as any); }).to.throw('functionLoadResponse.object expected'); }); @@ -500,9 +514,9 @@ describe('InvocationHandler', () => { coreApi.registerHook('preInvocation', (context: coreTypes.PreInvocationContext) => { expect(context.functionCallback).to.be.a('function'); - context.functionCallback = (async (invocContext: Context) => { + context.functionCallback = (async (invocContext: Context) => { invocContext.log('new function'); - }); + }) as coreTypes.FunctionCallback; }); stream.addTestMessage(msg.invocation.request([InputData.string])); @@ -523,7 +537,7 @@ describe('InvocationHandler', () => { hookData += 'post'; expect(context.result).to.equal('hello'); expect(context.error).to.be.null; - (context.invocationContext).log('hello from post'); + (context.invocationContext as Context).log('hello from post'); }); stream.addTestMessage(msg.invocation.request([InputData.http])); diff --git a/test/eventHandlers/msg.ts b/test/eventHandlers/msg.ts index 134ecaeb..8a089d1b 100644 --- a/test/eventHandlers/msg.ts +++ b/test/eventHandlers/msg.ts @@ -2,11 +2,11 @@ // Licensed under the MIT License. import 'mocha'; +import * as escapeStringRegexp from 'escape-string-regexp'; +import * as path from 'path'; import { AzureFunctionsRpcMessages as rpc } from '../../azure-functions-language-worker-protobuf/src/rpc'; import { testAppPath, testAppSrcPath } from './testAppUtils'; import { RegExpProps, RegExpStreamingMessage } from './TestEventStream'; -import escapeStringRegexp = require('escape-string-regexp'); -import path = require('path'); type TestMessage = rpc.IStreamingMessage | RegExpStreamingMessage; @@ -25,181 +25,194 @@ function workerMetadataRegExps(responseName: string) { }; } -export namespace msg { - export function errorLog(message: string | RegExp): TestMessage { - return log(message, rpc.RpcLog.Level.Error); - } +export function errorLog(message: string | RegExp): TestMessage { + return log(message, rpc.RpcLog.Level.Error); +} - export function warningLog(message: string | RegExp): TestMessage { - return log(message, rpc.RpcLog.Level.Warning); - } +export function warningLog(message: string | RegExp): TestMessage { + return log(message, rpc.RpcLog.Level.Warning); +} - export function debugLog(message: string | RegExp): TestMessage { - return log(message, rpc.RpcLog.Level.Debug); - } +export function debugLog(message: string | RegExp): TestMessage { + return log(message, rpc.RpcLog.Level.Debug); +} - export function infoLog(message: string | RegExp): TestMessage { - return log(message, rpc.RpcLog.Level.Information); - } +export function infoLog(message: string | RegExp): TestMessage { + return log(message, rpc.RpcLog.Level.Information); +} - export function log(message: string | RegExp, level: rpc.RpcLog.Level): TestMessage { - if (typeof message === 'string') { - return { +export function log(message: string | RegExp, level: rpc.RpcLog.Level): TestMessage { + if (typeof message === 'string') { + return { + rpcLog: { + message, + level, + logCategory: rpc.RpcLog.RpcLogCategory.System, + }, + }; + } else { + return new RegExpStreamingMessage( + { rpcLog: { - message, level, logCategory: rpc.RpcLog.RpcLogCategory.System, }, - }; - } else { - return new RegExpStreamingMessage( - { - rpcLog: { - level, - logCategory: rpc.RpcLog.RpcLogCategory.System, - }, - }, - { - 'rpcLog.message': message, - } - ); - } + }, + { + 'rpcLog.message': message, + } + ); } +} - export const noHandlerError = msg.errorLog("Worker had no handler for message 'undefined'"); - - export const noPackageJsonWarning = msg.warningLog('Worker failed to load package.json: file does not exist'); - - export function receivedRequestLog(requestName: string): TestMessage { - return debugLog(`Worker 00000000-0000-0000-0000-000000000000 received ${requestName}`); - } +export const noHandlerError = errorLog("Worker had no handler for message 'undefined'"); - export function loadingEntryPoint(fileName: string): TestMessage { - return msg.debugLog(`Loading entry point file "${fileName}"`); - } +export const noPackageJsonWarning = warningLog('Worker failed to load package.json: file does not exist'); - export function loadedEntryPoint(fileName: string): TestMessage { - return msg.debugLog(`Loaded entry point file "${fileName}"`); - } +export function receivedRequestLog(requestName: string): TestMessage { + return debugLog(`Worker 00000000-0000-0000-0000-000000000000 received ${requestName}`); +} - export function executingAppHooksLog(count: number, hookName: string): TestMessage { - return { - rpcLog: { - category: undefined, - invocationId: undefined, - message: `Executing ${count} "${hookName}" hooks`, - level: rpc.RpcLog.Level.Debug, - logCategory: rpc.RpcLog.RpcLogCategory.System, - }, - }; - } +export function loadingEntryPoint(fileName: string): TestMessage { + return msg.debugLog(`Loading entry point file "${fileName}"`); +} - export function executedAppHooksLog(hookName: string): TestMessage { - return { - rpcLog: { - category: undefined, - invocationId: undefined, - message: `Executed "${hookName}" hooks`, - level: rpc.RpcLog.Level.Debug, - logCategory: rpc.RpcLog.RpcLogCategory.System, - }, - }; - } +export function loadedEntryPoint(fileName: string): TestMessage { + return msg.debugLog(`Loaded entry point file "${fileName}"`); +} - const capabilities = { - RawHttpBodyBytes: 'true', - RpcHttpBodyOnly: 'true', - RpcHttpTriggerMetadataRemoved: 'true', - IgnoreEmptyValuedRpcHttpHeaders: 'true', - UseNullableValueDictionaryForHttp: 'true', - WorkerStatus: 'true', - TypedDataCollection: 'true', - HandlesWorkerTerminateMessage: 'true', +export function executingAppHooksLog(count: number, hookName: string): TestMessage { + return { + rpcLog: { + category: undefined, + invocationId: undefined, + message: `Executing ${count} "${hookName}" hooks`, + level: rpc.RpcLog.Level.Debug, + logCategory: rpc.RpcLog.RpcLogCategory.System, + }, }; +} - export namespace init { - export const receivedRequestLog = msg.receivedRequestLog('WorkerInitRequest'); +export function executedAppHooksLog(hookName: string): TestMessage { + return { + rpcLog: { + category: undefined, + invocationId: undefined, + message: `Executed "${hookName}" hooks`, + level: rpc.RpcLog.Level.Debug, + logCategory: rpc.RpcLog.RpcLogCategory.System, + }, + }; +} - export const coldStartWarning = msg.debugLog( - 'package.json is not found at the root of the Function App in Azure Files - cold start for NodeJs can be affected.' - ); +const capabilities = { + RawHttpBodyBytes: 'true', + RpcHttpBodyOnly: 'true', + RpcHttpTriggerMetadataRemoved: 'true', + IgnoreEmptyValuedRpcHttpHeaders: 'true', + UseNullableValueDictionaryForHttp: 'true', + WorkerStatus: 'true', + TypedDataCollection: 'true', + HandlesWorkerTerminateMessage: 'true', +}; + +export const coldStartWarning = debugLog( + 'package.json is not found at the root of the Function App in Azure Files - cold start for NodeJs can be affected.' +); + +export function request(functionAppDirectory: string = __dirname, hostVersion = '2.7.0'): rpc.IStreamingMessage { + return { + requestId: 'testReqId', + workerInitRequest: { + capabilities: {}, + functionAppDirectory, + hostVersion, + }, + }; +} - export function request( - functionAppDirectory: string = __dirname, - hostVersion = '2.7.0' - ): rpc.IStreamingMessage { - return { - requestId: 'testReqId', - workerInitRequest: { - capabilities: {}, - functionAppDirectory, - hostVersion, +export const response = new RegExpStreamingMessage( + { + requestId: 'testReqId', + workerInitResponse: { + capabilities, + result: { + status: rpc.StatusResult.Status.Success, + }, + workerMetadata: { + runtimeName: 'node', + customProperties: { + modelName: '@azure/functions', }, - }; - } - - export const response = new RegExpStreamingMessage( - { - requestId: 'testReqId', - workerInitResponse: { - capabilities, - result: { - status: rpc.StatusResult.Status.Success, - }, - workerMetadata: { - runtimeName: 'node', - customProperties: { - modelName: '@azure/functions', - }, - }, + }, + }, + }, + workerMetadataRegExps('workerInitResponse') +); + +export function failedResponse(errorMessage: string): RegExpStreamingMessage { + const expectedMsg: rpc.IStreamingMessage = { + requestId: 'testReqId', + workerInitResponse: { + result: { + status: rpc.StatusResult.Status.Failure, + exception: { + message: errorMessage, }, }, - workerMetadataRegExps('workerInitResponse') - ); - - export function failedResponse(errorMessage: string): RegExpStreamingMessage { - const expectedMsg: rpc.IStreamingMessage = { - requestId: 'testReqId', - workerInitResponse: { - result: { - status: rpc.StatusResult.Status.Failure, - exception: { - message: errorMessage, - }, - }, - workerMetadata: { - runtimeName: 'node', - customProperties: { - modelName: '@azure/functions', - }, - }, + workerMetadata: { + runtimeName: 'node', + customProperties: { + modelName: '@azure/functions', }, - }; - return new RegExpStreamingMessage(expectedMsg, { - ...stackTraceRegExpProps('workerInitResponse', errorMessage), - ...workerMetadataRegExps('workerInitResponse'), - }); - } - } - - export namespace envReload { - export function reloadEnvVarsLog(numVars: number): TestMessage { - return msg.infoLog(`Reloading environment variables. Found ${numVars} variables to reload.`); - } - - export function changingCwdLog(dir = '/'): TestMessage { - return msg.infoLog(`Changing current working directory to ${dir}`); - } + }, + }, + }; + return new RegExpStreamingMessage(expectedMsg, { + ...stackTraceRegExpProps('workerInitResponse', errorMessage), + ...workerMetadataRegExps('workerInitResponse'), + }); +} - export const funcAppDirNotDefined = msg.debugLog( - 'FunctionEnvironmentReload functionAppDirectory is not defined' - ); +export function reloadEnvVarsLog(numVars: number): TestMessage { + return msg.infoLog(`Reloading environment variables. Found ${numVars} variables to reload.`); +} - export const funcAppDirNotChanged = msg.debugLog( - 'FunctionEnvironmentReload functionAppDirectory has not changed' - ); +export function changingCwdLog(dir = '/'): TestMessage { + return msg.infoLog(`Changing current working directory to ${dir}`); +} - export const response = new RegExpStreamingMessage( +export const funcAppDirNotDefined = debugLog('FunctionEnvironmentReload functionAppDirectory is not defined'); + +export const funcAppDirNotChanged = debugLog('FunctionEnvironmentReload functionAppDirectory has not changed'); + +export const msg = { + errorLog, + warningLog, + debugLog, + infoLog, + log, + noHandlerError, + noPackageJsonWarning, + receivedRequestLog, + loadingEntryPoint, + loadedEntryPoint, + executingAppHooksLog, + executedAppHooksLog, + capabilities, + init: { + receivedRequestLog: receivedRequestLog('WorkerInitRequest'), + coldStartWarning, + request, + response, + failedResponse, + }, + envReload: { + reloadEnvVarsLog, + changingCwdLog, + funcAppDirNotDefined, + funcAppDirNotChanged, + response: new RegExpStreamingMessage( { requestId: 'testReqId', functionEnvironmentReloadResponse: { @@ -218,23 +231,19 @@ export namespace msg { }, }, workerMetadataRegExps('functionEnvironmentReloadResponse') - ); - } - - export namespace indexing { - export const request = { + ), + }, + indexing: { + request: { requestId: 'testReqId', functionsMetadataRequest: { functionAppDirectory: testAppPath, }, - }; + }, - export const receivedRequestLog = msg.receivedRequestLog('FunctionsMetadataRequest'); + receivedRequestLog: receivedRequestLog('FunctionsMetadataRequest'), - export function response( - functions: rpc.IRpcFunctionMetadata[], - useDefaultMetadataIndexing: boolean - ): TestMessage { + response(functions: rpc.IRpcFunctionMetadata[], useDefaultMetadataIndexing: boolean): TestMessage { const response: rpc.IStreamingMessage = { requestId: 'testReqId', functionMetadataResponse: { @@ -248,12 +257,9 @@ export namespace msg { response.functionMetadataResponse!.functionMetadataResults = functions; } return response; - } + }, - export function failedResponse( - errorMessage: string, - useDefaultMetadataIndexing: boolean - ): RegExpStreamingMessage { + failedResponse(errorMessage: string, useDefaultMetadataIndexing: boolean): RegExpStreamingMessage { const expectedMsg: rpc.IStreamingMessage = { requestId: 'testReqId', functionMetadataResponse: { @@ -269,13 +275,12 @@ export namespace msg { return new RegExpStreamingMessage(expectedMsg, { ...stackTraceRegExpProps('functionMetadataResponse', errorMessage), }); - } - } - - export namespace funcLoad { - export const receivedRequestLog = msg.receivedRequestLog('FunctionLoadRequest'); + }, + }, + funcLoad: { + receivedRequestLog: receivedRequestLog('FunctionLoadRequest'), - export function request(fileName: string, extraMetadata?: rpc.IRpcFunctionMetadata): rpc.IStreamingMessage { + request(fileName: string, extraMetadata?: rpc.IRpcFunctionMetadata): rpc.IStreamingMessage { return { requestId: 'testReqId', functionLoadRequest: { @@ -287,9 +292,9 @@ export namespace msg { }, }, }; - } + }, - export const response = { + response: { requestId: 'testReqId', functionLoadResponse: { functionId: 'testFuncId', @@ -297,9 +302,9 @@ export namespace msg { status: rpc.StatusResult.Status.Success, }, }, - }; + }, - export function failedResponse(message: string): TestMessage { + failedResponse(message: string): TestMessage { return new RegExpStreamingMessage( { requestId: 'testReqId', @@ -315,27 +320,22 @@ export namespace msg { }, stackTraceRegExpProps('functionLoadResponse', message) ); - } - } - - export namespace invocation { - export function errorLog(message: string | RegExp): TestMessage { + }, + }, + invocation: { + errorLog(message: string | RegExp): TestMessage { return log(message, rpc.RpcLog.Level.Error); - } - - export function warningLog(message: string | RegExp): TestMessage { + }, + warningLog(message: string | RegExp): TestMessage { return log(message, rpc.RpcLog.Level.Warning); - } - - export function debugLog(message: string | RegExp): TestMessage { + }, + debugLog(message: string | RegExp): TestMessage { return log(message, rpc.RpcLog.Level.Debug); - } - - export function infoLog(message: string | RegExp): TestMessage { + }, + infoLog(message: string | RegExp): TestMessage { return log(message, rpc.RpcLog.Level.Information); - } - - export function log(message: string | RegExp, level: rpc.RpcLog.Level): TestMessage { + }, + log(message: string | RegExp, level: rpc.RpcLog.Level): TestMessage { if (typeof message === 'string') { return { rpcLog: { @@ -361,33 +361,26 @@ export namespace msg { } ); } - } - - export const receivedRequestLog = msg.invocation.debugLog( + }, + receivedRequestLog: debugLog( 'Worker 00000000-0000-0000-0000-000000000000 received FunctionInvocationRequest with invocationId 1' - ); - - export function executingHooksLog(count: number, hookName: string): TestMessage { + ), + executingHooksLog(count: number, hookName: string): TestMessage { return msg.invocation.debugLog(`Executing ${count} "${hookName}" hooks`); - } - - export function executedHooksLog(hookName: string): TestMessage { + }, + executedHooksLog(hookName: string): TestMessage { return msg.invocation.debugLog(`Executed "${hookName}" hooks`); - } - - export const asyncAndDoneError = msg.invocation.errorLog( + }, + asyncAndDoneError: errorLog( "Error: Choose either to return a promise or call 'done'. Do not use both in your script. Learn more: https://go.microsoft.com/fwlink/?linkid=2097909" - ); - - export const duplicateDoneError = msg.invocation.errorLog( + ), + duplicateDoneError: errorLog( "Error: 'done' has already been called. Please check your script for extraneous calls to 'done'." - ); - - export const unexpectedLogAfterDoneLog = msg.invocation.warningLog( + ), + unexpectedLogAfterDoneLog: warningLog( "Warning: Unexpected call to 'log' on the context object after function execution has completed. Please check for asynchronous calls that are not awaited or calls to 'done' made before function execution completes. Function name: testFuncName. Invocation Id: 1. Learn more: https://go.microsoft.com/fwlink/?linkid=2097909" - ); - - export function userLog(data = 'testUserLog', level = rpc.RpcLog.Level.Information): TestMessage { + ), + userLog(data = 'testUserLog', level = rpc.RpcLog.Level.Information): TestMessage { return { rpcLog: { category: 'testFuncName.Invocation', @@ -397,9 +390,8 @@ export namespace msg { logCategory: rpc.RpcLog.RpcLogCategory.User, }, }; - } - - export function request(inputData?: rpc.IParameterBinding[] | null): rpc.IStreamingMessage { + }, + request(inputData?: rpc.IParameterBinding[] | null): rpc.IStreamingMessage { return { requestId: 'testReqId', invocationRequest: { @@ -408,12 +400,8 @@ export namespace msg { inputData: inputData, }, }; - } - - export function response( - expectedOutputData?: rpc.IParameterBinding[] | null, - expectedReturnValue?: rpc.ITypedData | null - ) { + }, + response(expectedOutputData?: rpc.IParameterBinding[] | null, expectedReturnValue?: rpc.ITypedData | null) { const msg: TestMessage = {}; msg.requestId = 'testReqId'; msg.invocationResponse = { @@ -427,9 +415,8 @@ export namespace msg { msg.invocationResponse.returnValue = expectedReturnValue; } return msg; - } - - export function failedResponse(message = 'testErrorMessage'): TestMessage { + }, + failedResponse(message = 'testErrorMessage'): TestMessage { return new RegExpStreamingMessage( { requestId: 'testReqId', @@ -445,11 +432,10 @@ export namespace msg { }, stackTraceRegExpProps('invocationResponse', message) ); - } - } - - export namespace terminate { - export function request(gracePeriodSeconds = 5): rpc.IStreamingMessage { + }, + }, + terminate: { + request(gracePeriodSeconds = 5): rpc.IStreamingMessage { return { workerTerminate: { gracePeriod: { @@ -457,10 +443,7 @@ export namespace msg { }, }, }; - } - - export const receivedWorkerTerminateLog = msg.debugLog( - 'Received workerTerminate message; gracefully shutting down worker' - ); - } -} + }, + receivedWorkerTerminateLog: debugLog('Received workerTerminate message; gracefully shutting down worker'), + }, +}; diff --git a/test/eventHandlers/terminateWorker.test.ts b/test/eventHandlers/terminateWorker.test.ts index 7e113666..62722490 100644 --- a/test/eventHandlers/terminateWorker.test.ts +++ b/test/eventHandlers/terminateWorker.test.ts @@ -3,11 +3,11 @@ import * as coreTypes from '@azure/functions-core'; import { expect } from 'chai'; +import * as sinon from 'sinon'; import { worker } from '../../src/WorkerContext'; import { beforeEventHandlerSuite } from './beforeEventHandlerSuite'; import { msg } from './msg'; import { TestEventStream } from './TestEventStream'; -import sinon = require('sinon'); describe('terminateWorker', () => { let stream: TestEventStream; diff --git a/test/eventHandlers/testAppUtils.ts b/test/eventHandlers/testAppUtils.ts index 0dbf4f80..241b619d 100644 --- a/test/eventHandlers/testAppUtils.ts +++ b/test/eventHandlers/testAppUtils.ts @@ -4,8 +4,10 @@ import * as fs from 'fs/promises'; import * as path from 'path'; +const directory: string = path.resolve(); + export const tempFile = 'temp.js'; -export const testAppPath = path.join(__dirname, 'testApp'); +export const testAppPath = path.join(directory, 'test/eventHandlers/testApp'); export const testAppSrcPath = path.join(testAppPath, 'src'); export const testPackageJsonPath = path.join(testAppPath, 'package.json'); diff --git a/test/startApp.test.ts b/test/startApp.test.ts index f8911cae..0c4a7bb9 100644 --- a/test/startApp.test.ts +++ b/test/startApp.test.ts @@ -111,20 +111,20 @@ describe('startApp', () => { }); it('fails (v4)', async () => { - worker.app.programmingModel = { name: '@azure/functions', version: '4.0.0' }; + worker.app.programmingModel = { name: '@azure/functions', version: '4.0.0' } as any; worker.app.isUsingWorkerIndexing = true; await verifyAppStartFails(true); }); it('fails (v4) (app setting=0)', async () => { - worker.app.programmingModel = { name: '@azure/functions', version: '4.0.0' }; + worker.app.programmingModel = { name: '@azure/functions', version: '4.0.0' } as any; worker.app.isUsingWorkerIndexing = true; process.env.FUNCTIONS_NODE_BLOCK_ON_ENTRY_POINT_ERROR = '0'; await verifyAppStartFails(true); }); it('fails (v4) (app setting=1)', async () => { - worker.app.programmingModel = { name: '@azure/functions', version: '4.0.0' }; + worker.app.programmingModel = { name: '@azure/functions', version: '4.0.0' } as any; worker.app.isUsingWorkerIndexing = true; process.env.FUNCTIONS_NODE_BLOCK_ON_ENTRY_POINT_ERROR = '1'; await verifyAppStartFails(true); @@ -166,14 +166,14 @@ describe('startApp', () => { }); it('fails (v4)', async () => { - worker.app.programmingModel = { name: '@azure/functions', version: '4.0.0' }; + worker.app.programmingModel = { name: '@azure/functions', version: '4.0.0' } as any; worker.app.isUsingWorkerIndexing = true; await verifyAppStartFails(true); }); it('succeeds but still logs error (v4) (app setting=0)', async () => { - worker.app.programmingModel = { name: '@azure/functions', version: '4.0.0' }; + worker.app.programmingModel = { name: '@azure/functions', version: '4.0.0' } as any; worker.app.isUsingWorkerIndexing = true; process.env.FUNCTIONS_NODE_BLOCK_ON_ENTRY_POINT_ERROR = '0'; @@ -181,7 +181,7 @@ describe('startApp', () => { }); it('fails (v4) (app setting=1)', async () => { - worker.app.programmingModel = { name: '@azure/functions', version: '4.0.0' }; + worker.app.programmingModel = { name: '@azure/functions', version: '4.0.0' } as any; worker.app.isUsingWorkerIndexing = true; process.env.FUNCTIONS_NODE_BLOCK_ON_ENTRY_POINT_ERROR = '1'; From 4a06bed0dd0661f55f6bbe60be02be96452f2870 Mon Sep 17 00:00:00 2001 From: Swapnil Nagar Date: Tue, 12 Aug 2025 23:36:57 -0700 Subject: [PATCH 6/9] Fixing the tests --- test/eventHandlers/msg.ts | 56 ++++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/test/eventHandlers/msg.ts b/test/eventHandlers/msg.ts index 8a089d1b..59466d13 100644 --- a/test/eventHandlers/msg.ts +++ b/test/eventHandlers/msg.ts @@ -186,6 +186,34 @@ export const funcAppDirNotDefined = debugLog('FunctionEnvironmentReload function export const funcAppDirNotChanged = debugLog('FunctionEnvironmentReload functionAppDirectory has not changed'); +export function logWithInvocation(message: string | RegExp, level: rpc.RpcLog.Level): TestMessage { + if (typeof message === 'string') { + return { + rpcLog: { + category: 'testFuncName.Invocation', + invocationId: '1', + message, + level, + logCategory: rpc.RpcLog.RpcLogCategory.System, + }, + }; + } else { + return new RegExpStreamingMessage( + { + rpcLog: { + category: 'testFuncName.Invocation', + invocationId: '1', + level, + logCategory: rpc.RpcLog.RpcLogCategory.System, + }, + }, + { + 'rpcLog.message': message, + } + ); + } +} + export const msg = { errorLog, warningLog, @@ -324,16 +352,16 @@ export const msg = { }, invocation: { errorLog(message: string | RegExp): TestMessage { - return log(message, rpc.RpcLog.Level.Error); + return logWithInvocation(message, rpc.RpcLog.Level.Error); }, warningLog(message: string | RegExp): TestMessage { - return log(message, rpc.RpcLog.Level.Warning); + return logWithInvocation(message, rpc.RpcLog.Level.Warning); }, debugLog(message: string | RegExp): TestMessage { - return log(message, rpc.RpcLog.Level.Debug); + return logWithInvocation(message, rpc.RpcLog.Level.Debug); }, infoLog(message: string | RegExp): TestMessage { - return log(message, rpc.RpcLog.Level.Information); + return logWithInvocation(message, rpc.RpcLog.Level.Information); }, log(message: string | RegExp, level: rpc.RpcLog.Level): TestMessage { if (typeof message === 'string') { @@ -362,8 +390,9 @@ export const msg = { ); } }, - receivedRequestLog: debugLog( - 'Worker 00000000-0000-0000-0000-000000000000 received FunctionInvocationRequest with invocationId 1' + receivedRequestLog: logWithInvocation( + 'Worker 00000000-0000-0000-0000-000000000000 received FunctionInvocationRequest with invocationId 1', + rpc.RpcLog.Level.Debug ), executingHooksLog(count: number, hookName: string): TestMessage { return msg.invocation.debugLog(`Executing ${count} "${hookName}" hooks`); @@ -371,14 +400,17 @@ export const msg = { executedHooksLog(hookName: string): TestMessage { return msg.invocation.debugLog(`Executed "${hookName}" hooks`); }, - asyncAndDoneError: errorLog( - "Error: Choose either to return a promise or call 'done'. Do not use both in your script. Learn more: https://go.microsoft.com/fwlink/?linkid=2097909" + asyncAndDoneError: logWithInvocation( + "Error: Choose either to return a promise or call 'done'. Do not use both in your script. Learn more: https://go.microsoft.com/fwlink/?linkid=2097909", + rpc.RpcLog.Level.Error ), - duplicateDoneError: errorLog( - "Error: 'done' has already been called. Please check your script for extraneous calls to 'done'." + duplicateDoneError: logWithInvocation( + "Error: 'done' has already been called. Please check your script for extraneous calls to 'done'.", + rpc.RpcLog.Level.Error ), - unexpectedLogAfterDoneLog: warningLog( - "Warning: Unexpected call to 'log' on the context object after function execution has completed. Please check for asynchronous calls that are not awaited or calls to 'done' made before function execution completes. Function name: testFuncName. Invocation Id: 1. Learn more: https://go.microsoft.com/fwlink/?linkid=2097909" + unexpectedLogAfterDoneLog: logWithInvocation( + "Warning: Unexpected call to 'log' on the context object after function execution has completed. Please check for asynchronous calls that are not awaited or calls to 'done' made before function execution completes. Function name: testFuncName. Invocation Id: 1. Learn more: https://go.microsoft.com/fwlink/?linkid=2097909", + rpc.RpcLog.Level.Warning ), userLog(data = 'testUserLog', level = rpc.RpcLog.Level.Information): TestMessage { return { From 327a48a49ef265af6b0e5eda51f138524848402c Mon Sep 17 00:00:00 2001 From: Swapnil Nagar Date: Tue, 12 Aug 2025 23:54:23 -0700 Subject: [PATCH 7/9] Updating a minor version for strip-only mode support --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index fb9beb7d..a748983e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "azure-functions-nodejs-worker", - "version": "3.10.1", + "version": "3.11.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "azure-functions-nodejs-worker", - "version": "3.10.1", + "version": "3.11.1", "license": "(MIT OR Apache-2.0)", "dependencies": { "@azure/functions": "^3.5.0", diff --git a/package.json b/package.json index b26359ae..cf299480 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "azure-functions-nodejs-worker", "author": "Microsoft Corporation", - "version": "3.10.1", + "version": "3.11.1", "description": "Microsoft Azure Functions NodeJS Worker", "license": "(MIT OR Apache-2.0)", "dependencies": { From 7dfee55fb1c234c9d1e61994774b6f307f6afab7 Mon Sep 17 00:00:00 2001 From: Swapnil Nagar Date: Wed, 13 Aug 2025 09:52:20 -0700 Subject: [PATCH 8/9] Updating the Version --- src/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants.ts b/src/constants.ts index 745c758f..f8ffc1df 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,4 +1,4 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. -export const version = '3.10.1'; +export const version = '3.11.1'; From 389c7b5e4f1f0c60f35b3afdf9e9122bb87f49e2 Mon Sep 17 00:00:00 2001 From: Swapnil Nagar Date: Wed, 13 Aug 2025 10:16:51 -0700 Subject: [PATCH 9/9] Fixing the package.json --- Worker.nuspec | 2 +- package-lock.json | 4 ++-- package.json | 2 +- src/constants.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Worker.nuspec b/Worker.nuspec index ef33b837..ee88a493 100644 --- a/Worker.nuspec +++ b/Worker.nuspec @@ -2,7 +2,7 @@ Microsoft.Azure.Functions.NodeJsWorker - 3.10.1 + 3.11.0 Microsoft Microsoft false diff --git a/package-lock.json b/package-lock.json index a748983e..7a745bc1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "azure-functions-nodejs-worker", - "version": "3.11.1", + "version": "3.11.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "azure-functions-nodejs-worker", - "version": "3.11.1", + "version": "3.11.0", "license": "(MIT OR Apache-2.0)", "dependencies": { "@azure/functions": "^3.5.0", diff --git a/package.json b/package.json index cf299480..12ef28da 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "azure-functions-nodejs-worker", "author": "Microsoft Corporation", - "version": "3.11.1", + "version": "3.11.0", "description": "Microsoft Azure Functions NodeJS Worker", "license": "(MIT OR Apache-2.0)", "dependencies": { diff --git a/src/constants.ts b/src/constants.ts index f8ffc1df..8df5e674 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,4 +1,4 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. -export const version = '3.11.1'; +export const version = '3.11.0';