From d0de897c052c285429674c243adeb4423fc90560 Mon Sep 17 00:00:00 2001 From: Stephen Bourke Date: Wed, 20 May 2026 12:23:13 +0100 Subject: [PATCH 1/3] Fix functions update issue where artifact is provided as a http url --- .../worker/rest/api/ComponentImpl.java | 4 +- .../v3/AbstractFunctionApiResourceTest.java | 40 +++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/ComponentImpl.java b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/ComponentImpl.java index 28fe2c5ea8fbe..f74ccf4a26b8f 100644 --- a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/ComponentImpl.java +++ b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/ComponentImpl.java @@ -1926,7 +1926,7 @@ protected File getPackageFile(FunctionDetails.ComponentType componentType, Strin if (isNotBlank(functionPkgUrl)) { componentPackageFile = getPackageFile(componentType, functionPkgUrl); } else if (existingPackagePath.startsWith(Utils.FILE) || existingPackagePath.startsWith(Utils.HTTP)) { - if (!worker().getPackageUrlValidator().isValidPackageUrl(componentType, functionPkgUrl)) { + if (!worker().getPackageUrlValidator().isValidPackageUrl(componentType, existingPackagePath)) { throw new IllegalArgumentException("Function Package url is not valid." + "supported url (http/https/file)"); } @@ -1935,7 +1935,7 @@ protected File getPackageFile(FunctionDetails.ComponentType componentType, Strin } catch (Exception e) { throw new IllegalArgumentException(String.format("Encountered error \"%s\" " + "when getting %s package from %s", e.getMessage(), - ComponentTypeUtils.toString(componentType), functionPkgUrl)); + ComponentTypeUtils.toString(componentType), existingPackagePath)); } } else if (Utils.hasPackageTypePrefix(existingPackagePath)) { componentPackageFile = getPackageFile(componentType, existingPackagePath); diff --git a/pulsar-functions/worker/src/test/java/org/apache/pulsar/functions/worker/rest/api/v3/AbstractFunctionApiResourceTest.java b/pulsar-functions/worker/src/test/java/org/apache/pulsar/functions/worker/rest/api/v3/AbstractFunctionApiResourceTest.java index f5b11c4567adc..a2cdb0d1491f3 100644 --- a/pulsar-functions/worker/src/test/java/org/apache/pulsar/functions/worker/rest/api/v3/AbstractFunctionApiResourceTest.java +++ b/pulsar-functions/worker/src/test/java/org/apache/pulsar/functions/worker/rest/api/v3/AbstractFunctionApiResourceTest.java @@ -1020,6 +1020,46 @@ public void testUpdateFunctionWithUrl() throws IOException { } + @Test + public void testUpdateFunctionWithExistingFileUrl() throws IOException { + Configurator.setRootLevel(Level.DEBUG); + + String fileLocation = FutureUtil.class.getProtectionDomain().getCodeSource().getLocation().getPath(); + String filePackageUrl = "file://" + fileLocation; + + FunctionConfig functionConfig = new FunctionConfig(); + functionConfig.setOutput(OUTPUT_TOPIC); + functionConfig.setOutputSerdeClassName(OUTPUT_SERDE_CLASS_NAME); + functionConfig.setTenant(TENANT); + functionConfig.setNamespace(NAMESPACE); + functionConfig.setName(FUNCTION); + functionConfig.setClassName(CLASS_NAME); + // increment parallelism to avoid 'Update contains no change' exception + functionConfig.setParallelism(PARALLELISM + 1); + functionConfig.setRuntime(FunctionConfig.Runtime.JAVA); + functionConfig.setCustomSerdeInputs(TOPICS_TO_SER_DE_CLASS_NAME); + + FunctionMetaData existingMetaData = FunctionMetaData.newBuilder() + .setFunctionDetails(createDefaultFunctionDetails()) + .setPackageLocation(org.apache.pulsar.functions.proto.Function.PackageLocationMetaData.newBuilder() + .setPackagePath(filePackageUrl) + .build()) + .build(); + + when(mockedManager.containsFunction(eq(TENANT), eq(NAMESPACE), eq(FUNCTION))).thenReturn(true); + when(mockedManager.getFunctionMetaData(any(), any(), any())).thenReturn(existingMetaData); + + updateFunction( + TENANT, + NAMESPACE, + FUNCTION, + null, + null, + null, + functionConfig, + null, null); + } + @Test(expectedExceptions = RestException.class, expectedExceptionsMessageRegExp = "function failed to register") public void testUpdateFunctionFailure() throws Exception { try { From db97beea1b16f2ebaa99b0aefb806a05a04cfa38 Mon Sep 17 00:00:00 2001 From: Stephen Bourke Date: Wed, 20 May 2026 17:59:41 +0100 Subject: [PATCH 2/3] Fix broken test --- .../rest/api/v3/AbstractFunctionApiResourceTest.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/pulsar-functions/worker/src/test/java/org/apache/pulsar/functions/worker/rest/api/v3/AbstractFunctionApiResourceTest.java b/pulsar-functions/worker/src/test/java/org/apache/pulsar/functions/worker/rest/api/v3/AbstractFunctionApiResourceTest.java index a2cdb0d1491f3..29204fe349de1 100644 --- a/pulsar-functions/worker/src/test/java/org/apache/pulsar/functions/worker/rest/api/v3/AbstractFunctionApiResourceTest.java +++ b/pulsar-functions/worker/src/test/java/org/apache/pulsar/functions/worker/rest/api/v3/AbstractFunctionApiResourceTest.java @@ -1039,12 +1039,9 @@ public void testUpdateFunctionWithExistingFileUrl() throws IOException { functionConfig.setRuntime(FunctionConfig.Runtime.JAVA); functionConfig.setCustomSerdeInputs(TOPICS_TO_SER_DE_CLASS_NAME); - FunctionMetaData existingMetaData = FunctionMetaData.newBuilder() - .setFunctionDetails(createDefaultFunctionDetails()) - .setPackageLocation(org.apache.pulsar.functions.proto.Function.PackageLocationMetaData.newBuilder() - .setPackagePath(filePackageUrl) - .build()) - .build(); + FunctionMetaData existingMetaData = new FunctionMetaData(); + existingMetaData.setFunctionDetails().copyFrom(createDefaultFunctionDetails()); + existingMetaData.setPackageLocation().setPackagePath(filePackageUrl); when(mockedManager.containsFunction(eq(TENANT), eq(NAMESPACE), eq(FUNCTION))).thenReturn(true); when(mockedManager.getFunctionMetaData(any(), any(), any())).thenReturn(existingMetaData); From d7a77824fe5fc5014df7a72c5c1a4a706407a90f Mon Sep 17 00:00:00 2001 From: Lari Hotari Date: Thu, 21 May 2026 09:48:12 +0300 Subject: [PATCH 3/3] Remove log level change Co-authored-by: Zixuan Liu --- .../worker/rest/api/v3/AbstractFunctionApiResourceTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/pulsar-functions/worker/src/test/java/org/apache/pulsar/functions/worker/rest/api/v3/AbstractFunctionApiResourceTest.java b/pulsar-functions/worker/src/test/java/org/apache/pulsar/functions/worker/rest/api/v3/AbstractFunctionApiResourceTest.java index 29204fe349de1..453e39e4132e8 100644 --- a/pulsar-functions/worker/src/test/java/org/apache/pulsar/functions/worker/rest/api/v3/AbstractFunctionApiResourceTest.java +++ b/pulsar-functions/worker/src/test/java/org/apache/pulsar/functions/worker/rest/api/v3/AbstractFunctionApiResourceTest.java @@ -1022,7 +1022,6 @@ public void testUpdateFunctionWithUrl() throws IOException { @Test public void testUpdateFunctionWithExistingFileUrl() throws IOException { - Configurator.setRootLevel(Level.DEBUG); String fileLocation = FutureUtil.class.getProtectionDomain().getCodeSource().getLocation().getPath(); String filePackageUrl = "file://" + fileLocation;