This is an automated email from the ASF dual-hosted git repository.

technoboy pushed a commit to branch branch-4.0
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit 796603ea1b00e36d5833d0eef1e2f3bce301b7d3
Author: Phineas <62228193+falser...@users.noreply.github.com>
AuthorDate: Fri Aug 8 00:32:54 2025 +0800

    [improve][io] Add dependency file name information to error message when 
.nar file validation fails with ZipException (#24604)
    
    Co-authored-by: Lari Hotari <lhot...@apache.org>
---
 .../PulsarFunctionTestTemporaryDirectory.java      |  4 ++++
 .../apache/pulsar/io/AbstractPulsarE2ETest.java    |  3 ++-
 .../apache/pulsar/io/PulsarFunctionE2ETest.java    | 23 ++++++++++++++++++++++
 .../functions/utils/FunctionFilePackage.java       |  3 ++-
 4 files changed, 31 insertions(+), 2 deletions(-)

diff --git 
a/pulsar-broker/src/test/java/org/apache/pulsar/functions/worker/PulsarFunctionTestTemporaryDirectory.java
 
b/pulsar-broker/src/test/java/org/apache/pulsar/functions/worker/PulsarFunctionTestTemporaryDirectory.java
index 336aca37439..cd8a64e662b 100644
--- 
a/pulsar-broker/src/test/java/org/apache/pulsar/functions/worker/PulsarFunctionTestTemporaryDirectory.java
+++ 
b/pulsar-broker/src/test/java/org/apache/pulsar/functions/worker/PulsarFunctionTestTemporaryDirectory.java
@@ -80,4 +80,8 @@ public class PulsarFunctionTestTemporaryDirectory {
         Assert.assertEquals(foundFiles.length, 0, "Temporary files left over: "
                 + Arrays.asList(foundFiles));
     }
+
+    public File getTempDirectory() {
+        return tempDirectory;
+    }
 }
diff --git 
a/pulsar-broker/src/test/java/org/apache/pulsar/io/AbstractPulsarE2ETest.java 
b/pulsar-broker/src/test/java/org/apache/pulsar/io/AbstractPulsarE2ETest.java
index 74f76e7eb59..5b1a66fafb4 100644
--- 
a/pulsar-broker/src/test/java/org/apache/pulsar/io/AbstractPulsarE2ETest.java
+++ 
b/pulsar-broker/src/test/java/org/apache/pulsar/io/AbstractPulsarE2ETest.java
@@ -313,7 +313,8 @@ public abstract class AbstractPulsarE2ETest {
         workerConfig.setAuthorizationEnabled(true);
 
         List<String> urlPatterns =
-                List.of(getPulsarApiExamplesJar().getParentFile().toURI() + 
".*", "http://127\\.0\\.0\\.1:.*";);
+                List.of(getPulsarApiExamplesJar().getParentFile().toURI() + 
".*", "http://127\\.0\\.0\\.1:.*";,
+                        tempDirectory.getTempDirectory().toURI() + ".*");
         workerConfig.setAdditionalEnabledConnectorUrlPatterns(urlPatterns);
         workerConfig.setAdditionalEnabledFunctionsUrlPatterns(urlPatterns);
 
diff --git 
a/pulsar-broker/src/test/java/org/apache/pulsar/io/PulsarFunctionE2ETest.java 
b/pulsar-broker/src/test/java/org/apache/pulsar/io/PulsarFunctionE2ETest.java
index e3114b2dd4b..bb3c969b5d4 100644
--- 
a/pulsar-broker/src/test/java/org/apache/pulsar/io/PulsarFunctionE2ETest.java
+++ 
b/pulsar-broker/src/test/java/org/apache/pulsar/io/PulsarFunctionE2ETest.java
@@ -21,6 +21,7 @@ package org.apache.pulsar.io;
 import static 
org.apache.pulsar.broker.auth.MockedPulsarServiceBaseTest.retryStrategically;
 import static 
org.apache.pulsar.functions.worker.PulsarFunctionLocalRunTest.getPulsarApiExamplesJar;
 import static 
org.apache.pulsar.functions.worker.PulsarFunctionLocalRunTest.getPulsarApiExamplesNar;
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.spy;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
@@ -32,6 +33,7 @@ import static org.testng.Assert.fail;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import java.io.File;
 import java.nio.ByteBuffer;
 import java.util.Collections;
 import java.util.HashMap;
@@ -68,6 +70,7 @@ import 
org.apache.pulsar.functions.worker.TestPulsarFunctionUtils;
 import org.awaitility.Awaitility;
 import org.testng.Assert;
 import org.testng.annotations.Test;
+import org.zeroturnaround.zip.ZipUtil;
 
 /**
  * Test Pulsar sink on function.
@@ -203,6 +206,26 @@ public class PulsarFunctionE2ETest extends 
AbstractPulsarE2ETest {
         testE2EPulsarFunction(jarFilePathUrl);
     }
 
+    @Test(timeOut = 20000)
+    public void testE2EPulsarFunctionWithInvalidJarDependencyInNarFile() 
throws Exception {
+        File narFile = getPulsarApiExamplesNar();
+        File invalidNarFile = File.createTempFile("invalidJarDependency", 
".nar", tempDirectory.getTempDirectory());
+        try {
+            // Add an invalid dependency to the nar file
+            ZipUtil.addEntry(narFile, 
"META-INF/bundled-dependencies/invalid-dependency.jar",
+                    "Invalid jar content".getBytes(), invalidNarFile);
+            String jarFilePathUrl = invalidNarFile.toURI().toString();
+            testE2EPulsarFunction(jarFilePathUrl);
+            fail("Expected PulsarAdminException to be thrown due to invalid 
jar dependency in nar file");
+        } catch (PulsarAdminException e) {
+            assertThat(e.getMessage())
+                    
.contains("META-INF/bundled-dependencies/invalid-dependency.jar' failed due to 
zip END header not "
+                            + "found");
+        } finally {
+            invalidNarFile.delete();
+        }
+    }
+
     @Test(timeOut = 40000)
     public void testE2EPulsarFunctionWithUrl() throws Exception {
         
testE2EPulsarFunction(fileServer.getUrl("/pulsar-functions-api-examples.jar"));
diff --git 
a/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionFilePackage.java
 
b/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionFilePackage.java
index 8224de32521..44e33410bd6 100644
--- 
a/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionFilePackage.java
+++ 
b/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionFilePackage.java
@@ -79,7 +79,8 @@ public class FunctionFilePackage implements AutoCloseable, 
ValidatableFunctionPa
                         }
                         classFileLocators.add(locator);
                     } catch (IOException e) {
-                        throw new UncheckedIOException(e);
+                        throw new UncheckedIOException("Loading '" + classpath 
+ "' failed due to " + e.getMessage(),
+                                e);
                     }
                 }
             }

Reply via email to