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

Aias00 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new d671076d90 fix(wasm): forward discovery upstream deletion events 
(#7568)
d671076d90 is described below

commit d671076d905e4d13acff40ea44d8646f5ca421f1
Author: redyyang <[email protected]>
AuthorDate: Mon Oct 12 22:49:27 2026 +0800

    fix(wasm): forward discovery upstream deletion events (#7568)
---
 .../shenyu/plugin/wasm/api/loader/WasmLoader.java  |  12 +-
 .../plugin/wasm/api/AbstractWasmPluginTest.java    |  18 +++
 shenyu-plugin/shenyu-plugin-wasm-base/README.md    |  35 ++++
 .../base/handler/AbstractWasmDiscoveryHandler.java |  53 ++++--
 .../src/test/go-discovery-handler/main.go          |   9 +-
 .../handler/AbstractWasmDiscoveryHandlerTest.java  | 179 +++++++++++++++------
 ...ndlerTest$TestGoWasmPluginDiscoveryHandler.wasm | Bin 4327 -> 4261 bytes
 ...Test$TestLegacyWasmPluginDiscoveryHandler.wasm} | Bin
 ...HandlerTest$TestWasmPluginDiscoveryHandler.wasm | Bin 60991 -> 64328 bytes
 .../src/test/rust-discovery-handler/src/lib.rs     |  11 +-
 10 files changed, 250 insertions(+), 67 deletions(-)

diff --git 
a/shenyu-plugin/shenyu-plugin-wasm-api/src/main/java/org/apache/shenyu/plugin/wasm/api/loader/WasmLoader.java
 
b/shenyu-plugin/shenyu-plugin-wasm-api/src/main/java/org/apache/shenyu/plugin/wasm/api/loader/WasmLoader.java
index 66c0772263..e3f1f7140b 100644
--- 
a/shenyu-plugin/shenyu-plugin-wasm-api/src/main/java/org/apache/shenyu/plugin/wasm/api/loader/WasmLoader.java
+++ 
b/shenyu-plugin/shenyu-plugin-wasm-api/src/main/java/org/apache/shenyu/plugin/wasm/api/loader/WasmLoader.java
@@ -25,6 +25,7 @@ import com.dylibso.chicory.runtime.Memory;
 import com.dylibso.chicory.runtime.Store;
 import com.dylibso.chicory.wasm.Parser;
 import com.dylibso.chicory.wasm.WasmModule;
+import com.dylibso.chicory.wasm.types.ExportSection;
 import com.dylibso.chicory.wasm.types.FunctionType;
 import com.dylibso.chicory.wasm.types.ValType;
 import org.apache.shenyu.plugin.wasm.api.exception.ShenyuWasmException;
@@ -275,11 +276,14 @@ public class WasmLoader implements AutoCloseable {
      * @return an Optional containing the ExportFunction if found, otherwise 
empty
      */
     public Optional<ExportFunction> getWasmExtern(final String funcName) {
-        ExportFunction fn = instance.export(funcName);
-        if (Objects.isNull(fn)) {
-            LOG.debug("WASM export function '{}' not found in {}", funcName, 
wasmName);
+        ExportSection exports = instance.module().exportSection();
+        for (int index = 0; index < exports.exportCount(); index++) {
+            if (funcName.equals(exports.getExport(index).name())) {
+                return Optional.of(instance.export(funcName));
+            }
         }
-        return Optional.ofNullable(fn);
+        LOG.debug("WASM export function '{}' not found in {}", funcName, 
wasmName);
+        return Optional.empty();
     }
     
     /**
diff --git 
a/shenyu-plugin/shenyu-plugin-wasm-api/src/test/java/org/apache/shenyu/plugin/wasm/api/AbstractWasmPluginTest.java
 
b/shenyu-plugin/shenyu-plugin-wasm-api/src/test/java/org/apache/shenyu/plugin/wasm/api/AbstractWasmPluginTest.java
index 40d501ca5b..8534678bad 100644
--- 
a/shenyu-plugin/shenyu-plugin-wasm-api/src/test/java/org/apache/shenyu/plugin/wasm/api/AbstractWasmPluginTest.java
+++ 
b/shenyu-plugin/shenyu-plugin-wasm-api/src/test/java/org/apache/shenyu/plugin/wasm/api/AbstractWasmPluginTest.java
@@ -18,9 +18,11 @@
 package org.apache.shenyu.plugin.wasm.api;
 
 import com.dylibso.chicory.runtime.Memory;
+import com.dylibso.chicory.wasm.InvalidException;
 import org.apache.shenyu.common.config.ShenyuConfig;
 import org.apache.shenyu.plugin.api.ShenyuPluginChain;
 import org.apache.shenyu.plugin.api.utils.SpringBeanUtils;
+import org.apache.shenyu.plugin.wasm.api.loader.WasmLoader;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.springframework.context.ConfigurableApplicationContext;
@@ -35,6 +37,7 @@ import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -74,6 +77,21 @@ public class AbstractWasmPluginTest {
         StepVerifier.create(rustPlugin.execute(exchange, 
shenyuPluginChain)).expectSubscription().verifyComplete();
         verify(shenyuPluginChain).execute(exchange);
     }
+
+    @Test
+    public void missingExportReturnsEmptyTest() {
+        try (WasmLoader loader = new WasmLoader(RustWasmPlugin.class, null)) {
+            assertTrue(loader.getWasmExtern("missingCallback").isEmpty());
+            assertTrue(loader.getWasmExtern("execute").isPresent());
+        }
+    }
+
+    @Test
+    public void nonFunctionExportStillFailsTest() {
+        try (WasmLoader loader = new WasmLoader(RustWasmPlugin.class, null)) {
+            assertThrows(InvalidException.class, () -> 
loader.getWasmExtern("memory"));
+        }
+    }
     
     private void mockShenyuConfig() {
         ConfigurableApplicationContext context = 
mock(ConfigurableApplicationContext.class);
diff --git a/shenyu-plugin/shenyu-plugin-wasm-base/README.md 
b/shenyu-plugin/shenyu-plugin-wasm-base/README.md
new file mode 100644
index 0000000000..84c35ee41f
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-wasm-base/README.md
@@ -0,0 +1,35 @@
+# WASM discovery callbacks
+
+`AbstractWasmDiscoveryHandler` forwards discovery updates to the required guest
+export `handlerDiscoveryUpstreamData(argId: i64) -> ()` and deletions to the
+optional export `removeDiscoveryUpstreamData(argId: i64) -> ()`.
+
+Both callbacks use the existing Java argument bridge. `getArgumentId` supplies
+the ID, and `ARGUMENTS.get(argId)` exposes a `DiscoverySyncData` for the 
duration
+of the callback. A Java subclass can serialize this object from `onGetArgs`,
+which serves the guest's `shenyu.get_args` import.
+
+For deletion, the object contains exactly the identity from 
`DiscoveryUpstreamKey`:
+
+- `pluginName`: the plugin owning the discovery state.
+- `selectorId`: the selector to remove.
+- `selectorName`: the optional selector name, which can be null.
+
+The remaining fields, including `upstreamDataList`, are null. The guest should
+remove the state identified by this key when the deletion callback runs. For a
+subclass using JSON serialization, a deletion payload can look like:
+
+```json
+{"pluginName":"divide","selectorId":"selector-id","selectorName":"my-selector"}
+```
+
+Guests that omit the deletion export receive no callback, preserving the legacy
+no-op behavior. Existing Java subclasses do not need a new argument-ID method.
+Callback failures propagate to the caller, and the temporary argument is 
removed
+whether the callback succeeds or fails.
+
+The Go and Rust test guests read the deletion payload and echo it through
+`shenyu.put_result`. Their build instructions are in 
`src/test/go-discovery-handler`
+and `src/test/rust-discovery-handler`. The 
`TestLegacyWasmPluginDiscoveryHandler`
+fixture preserves the original Go binary without the deletion export to test
+compatibility with existing guests.
diff --git 
a/shenyu-plugin/shenyu-plugin-wasm-base/src/main/java/org/apache/shenyu/plugin/wasm/base/handler/AbstractWasmDiscoveryHandler.java
 
b/shenyu-plugin/shenyu-plugin-wasm-base/src/main/java/org/apache/shenyu/plugin/wasm/base/handler/AbstractWasmDiscoveryHandler.java
index 91b6057a7e..bc33c25e97 100644
--- 
a/shenyu-plugin/shenyu-plugin-wasm-base/src/main/java/org/apache/shenyu/plugin/wasm/base/handler/AbstractWasmDiscoveryHandler.java
+++ 
b/shenyu-plugin/shenyu-plugin-wasm-base/src/main/java/org/apache/shenyu/plugin/wasm/base/handler/AbstractWasmDiscoveryHandler.java
@@ -17,10 +17,12 @@
 
 package org.apache.shenyu.plugin.wasm.base.handler;
 
+import com.dylibso.chicory.runtime.ExportFunction;
 import org.apache.shenyu.common.dto.DiscoverySyncData;
 import org.apache.shenyu.plugin.base.handler.DiscoveryUpstreamDataHandler;
 import org.apache.shenyu.plugin.wasm.api.exception.ShenyuWasmInitException;
 import org.apache.shenyu.plugin.wasm.api.loader.WasmLoader;
+import org.apache.shenyu.sync.data.api.DiscoveryUpstreamKey;
 
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
@@ -33,23 +35,48 @@ public abstract class AbstractWasmDiscoveryHandler extends 
WasmLoader implements
     protected static final Map<Long, DiscoverySyncData> ARGUMENTS = new 
ConcurrentHashMap<>();
     
     protected static final String METHOD_NAME = "handlerDiscoveryUpstreamData";
+
+    protected static final String REMOVE_METHOD_NAME = 
"removeDiscoveryUpstreamData";
     
     @Override
     public void handlerDiscoveryUpstreamData(final DiscoverySyncData 
discoverySyncData) {
         super.getWasmExtern(METHOD_NAME)
-                .map(handlerDiscoveryUpstreamData -> {
-                    // WASI cannot easily pass Java objects like JNI, here we 
pass Long as arg
-                    // then we can get the argument by Long
-                    final Long argumentId = getArgumentId(discoverySyncData);
-                    ARGUMENTS.put(argumentId, discoverySyncData);
-                    // call WASI function
-                    try {
-                        handlerDiscoveryUpstreamData.apply(argumentId);
-                    } finally {
-                        ARGUMENTS.remove(argumentId);
-                    }
-                    return argumentId;
-                }).orElseThrow(() -> new ShenyuWasmInitException(METHOD_NAME + 
" function not find in wasm file: " + getWasmName()));
+                .map(handlerDiscoveryUpstreamData -> 
callWASI(discoverySyncData, handlerDiscoveryUpstreamData))
+                .orElseThrow(() -> new ShenyuWasmInitException(METHOD_NAME + " 
function not find in wasm file: " + getWasmName()));
+    }
+
+    /**
+     * Forward deletion to the optional guest export {@code 
removeDiscoveryUpstreamData(i64) -> ()}.
+     *
+     * <p>The argument id uses the same {@link 
#getArgumentId(DiscoverySyncData)} and {@link #ARGUMENTS}
+     * bridge as updates. During the callback, the argument is a {@link 
DiscoverySyncData} containing
+     * the key's plugin name, selector id and optional selector name; all 
other fields are null.
+     * Subclasses can serialize it through {@code shenyu.get_args} as they do 
for updates.
+     * The argument is removed after the callback, including when the guest 
throws.
+     * Guests without this export keep the default no-op deletion behavior.
+     *
+     * @param key discovery upstream selector identity
+     */
+    @Override
+    public void removeDiscoveryUpstreamData(final DiscoveryUpstreamKey key) {
+        super.getWasmExtern(REMOVE_METHOD_NAME).ifPresent(remove -> {
+            DiscoverySyncData data = new DiscoverySyncData();
+            data.setPluginName(key.pluginName());
+            data.setSelectorId(key.selectorId());
+            data.setSelectorName(key.selectorName());
+            callWASI(data, remove);
+        });
+    }
+
+    private Long callWASI(final DiscoverySyncData discoverySyncData, final 
ExportFunction execute) {
+        final Long argumentId = getArgumentId(discoverySyncData);
+        ARGUMENTS.put(argumentId, discoverySyncData);
+        try {
+            execute.apply(argumentId);
+        } finally {
+            ARGUMENTS.remove(argumentId);
+        }
+        return argumentId;
     }
     
     protected abstract Long getArgumentId(DiscoverySyncData discoverySyncData);
diff --git 
a/shenyu-plugin/shenyu-plugin-wasm-base/src/test/go-discovery-handler/main.go 
b/shenyu-plugin/shenyu-plugin-wasm-base/src/test/go-discovery-handler/main.go
index 2665713c37..c7e1dad1db 100644
--- 
a/shenyu-plugin/shenyu-plugin-wasm-base/src/test/go-discovery-handler/main.go
+++ 
b/shenyu-plugin/shenyu-plugin-wasm-base/src/test/go-discovery-handler/main.go
@@ -16,7 +16,7 @@
  */
 
 // Go WASM handler for AbstractWasmDiscoveryHandler.
-// Exports handlerDiscoveryUpstreamData — (i64) -> ().
+// Exports update and optional deletion callbacks — (i64) -> ().
 // Compile with: tinygo build -target wasm-unknown -opt=2 -no-debug 
-panic=trap -o plugin.wasm main.go
 
 package main
@@ -36,5 +36,12 @@ func handlerDiscoveryUpstreamData(argId int64) {
        wasmabi.PutResult(argId, []byte("go result"))
 }
 
+//go:wasmexport removeDiscoveryUpstreamData
+func removeDiscoveryUpstreamData(argId int64) {
+       buf := make([]byte, 1024)
+       input := wasmabi.GetArgs(argId, buf)
+       wasmabi.PutResult(argId, append([]byte("removed:"), input...))
+}
+
 // main is required by TinyGo's WASI target but is never called.
 func main() {}
diff --git 
a/shenyu-plugin/shenyu-plugin-wasm-base/src/test/java/org/apache/shenyu/plugin/wasm/base/handler/AbstractWasmDiscoveryHandlerTest.java
 
b/shenyu-plugin/shenyu-plugin-wasm-base/src/test/java/org/apache/shenyu/plugin/wasm/base/handler/AbstractWasmDiscoveryHandlerTest.java
index 25e946264a..2e6369289a 100644
--- 
a/shenyu-plugin/shenyu-plugin-wasm-base/src/test/java/org/apache/shenyu/plugin/wasm/base/handler/AbstractWasmDiscoveryHandlerTest.java
+++ 
b/shenyu-plugin/shenyu-plugin-wasm-base/src/test/java/org/apache/shenyu/plugin/wasm/base/handler/AbstractWasmDiscoveryHandlerTest.java
@@ -19,81 +19,164 @@ package org.apache.shenyu.plugin.wasm.base.handler;
 
 import com.dylibso.chicory.runtime.Memory;
 import org.apache.shenyu.common.dto.DiscoverySyncData;
+import org.apache.shenyu.common.dto.DiscoveryUpstreamData;
+import org.apache.shenyu.common.utils.GsonUtils;
+import 
org.apache.shenyu.plugin.base.cache.CommonDiscoveryUpstreamDataSubscriber;
+import org.apache.shenyu.sync.data.api.DiscoveryUpstreamKey;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.junit.jupiter.MockitoExtension;
-import org.mockito.junit.jupiter.MockitoSettings;
-import org.mockito.quality.Strictness;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
 
 import java.nio.charset.StandardCharsets;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
 
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
-@ExtendWith(MockitoExtension.class)
-@MockitoSettings(strictness = Strictness.LENIENT)
 class AbstractWasmDiscoveryHandlerTest {
 
     private DiscoverySyncData discoverySyncData;
 
     @BeforeEach
     public void setUp() {
-        this.discoverySyncData = mock(DiscoverySyncData.class);
-        when(discoverySyncData.getSelectorId()).thenReturn("SHENYU");
+        discoverySyncData = new DiscoverySyncData();
+        discoverySyncData.setPluginName("SHENYU_TEST");
+        discoverySyncData.setSelectorId("selector-id");
+        discoverySyncData.setSelectorName("upstream-测试");
+        discoverySyncData.setUpstreamDataList(List.of(new 
DiscoveryUpstreamData()));
     }
 
-    /** Go WASM test. */
-    @Test
-    public void goHandlerDiscoveryUpstreamDataTest() {
-        final TestGoWasmPluginDiscoveryHandler goHandler = new 
TestGoWasmPluginDiscoveryHandler("go result");
-        goHandler.handlerDiscoveryUpstreamData(discoverySyncData);
-        assertEquals("SHENYU_TEST", goHandler.pluginName());
+    @ParameterizedTest
+    @ValueSource(booleans = {true, false})
+    void handlerDiscoveryUpstreamDataTest(final boolean go) {
+        try (WasmTestHandler handler = newHandler(go)) {
+            handler.handlerDiscoveryUpstreamData(discoverySyncData);
+            assertEquals(List.of(go ? "go result" : "rust result"), 
handler.results);
+            assertSame(discoverySyncData, handler.arguments.get(0));
+            assertArgumentsRemoved(handler);
+        }
+    }
+
+    @ParameterizedTest
+    @ValueSource(booleans = {true, false})
+    void removeDiscoveryUpstreamDataTest(final boolean go) {
+        try (WasmTestHandler handler = newHandler(go)) {
+            DiscoveryUpstreamKey key = 
DiscoveryUpstreamKey.from(discoverySyncData);
+            handler.removeDiscoveryUpstreamData(key);
+            assertEquals(1, handler.results.size());
+            assertDeletionResult(handler, key, 0);
+            DiscoveryUpstreamKey unnamedKey = new 
DiscoveryUpstreamKey("SHENYU_TEST", "another-selector-id", null);
+            handler.removeDiscoveryUpstreamData(unnamedKey);
+            assertEquals(2, handler.results.size());
+            assertDeletionResult(handler, unnamedKey, 1);
+            assertArgumentsRemoved(handler);
+        }
+    }
+
+    @ParameterizedTest
+    @ValueSource(booleans = {true, false})
+    void subscriberForwardsUpdateAndDeletionTest(final boolean go) {
+        try (WasmTestHandler handler = newHandler(go)) {
+            CommonDiscoveryUpstreamDataSubscriber subscriber = new 
CommonDiscoveryUpstreamDataSubscriber(List.of(handler));
+            subscriber.onSubscribe(discoverySyncData);
+            DiscoveryUpstreamKey key = 
DiscoveryUpstreamKey.from(discoverySyncData);
+            subscriber.unSubscribe(key);
+            assertEquals(2, handler.results.size());
+            assertEquals(go ? "go result" : "rust result", 
handler.results.get(0));
+            assertDeletionResult(handler, key, 1);
+            assertArgumentsRemoved(handler);
+        }
+    }
+
+    @ParameterizedTest
+    @ValueSource(booleans = {true, false})
+    void deletionFailureRemovesArgumentsTest(final boolean go) {
+        try (WasmTestHandler handler = newHandler(go)) {
+            handler.failOnResult = true;
+            DiscoveryUpstreamKey key = 
DiscoveryUpstreamKey.from(discoverySyncData);
+            assertThrows(RuntimeException.class, () -> 
handler.removeDiscoveryUpstreamData(key));
+            assertEquals(1, handler.results.size());
+            assertDeletionResult(handler, key, 0);
+            assertArgumentsRemoved(handler);
+        }
     }
 
-    /** Rust WASM test. */
     @Test
-    public void rustHandlerDiscoveryUpstreamDataTest() {
-        final TestWasmPluginDiscoveryHandler rustHandler = new 
TestWasmPluginDiscoveryHandler("rust result");
-        rustHandler.handlerDiscoveryUpstreamData(discoverySyncData);
-        assertEquals("SHENYU_TEST", rustHandler.pluginName());
+    void missingOptionalDeletionExportTest() {
+        try (WasmTestHandler handler = new 
TestLegacyWasmPluginDiscoveryHandler()) {
+            
assertTrue(handler.getWasmExtern("removeDiscoveryUpstreamData").isEmpty());
+            DiscoveryUpstreamKey key = 
DiscoveryUpstreamKey.from(discoverySyncData);
+            assertDoesNotThrow(() -> handler.removeDiscoveryUpstreamData(key));
+            CommonDiscoveryUpstreamDataSubscriber subscriber = new 
CommonDiscoveryUpstreamDataSubscriber(List.of(handler));
+            assertDoesNotThrow(() -> subscriber.unSubscribe(key));
+            assertTrue(handler.arguments.isEmpty());
+            assertTrue(handler.argumentIds.isEmpty());
+            assertTrue(handler.results.isEmpty());
+            subscriber.onSubscribe(discoverySyncData);
+            assertEquals(List.of("go result"), handler.results);
+            assertArgumentsRemoved(handler);
+        }
+    }
+
+    private static WasmTestHandler newHandler(final boolean go) {
+        return go ? new TestGoWasmPluginDiscoveryHandler() : new 
TestWasmPluginDiscoveryHandler();
+    }
+
+    private static void assertDeletionResult(final WasmTestHandler handler, 
final DiscoveryUpstreamKey key, final int index) {
+        String result = handler.results.get(index);
+        assertTrue(result.startsWith("removed:"));
+        DiscoverySyncData guestData = 
GsonUtils.getInstance().fromJson(result.substring("removed:".length()), 
DiscoverySyncData.class);
+        assertEquals(key, DiscoveryUpstreamKey.from(guestData));
+        assertNull(guestData.getUpstreamDataList());
+        assertNull(guestData.getNamespaceId());
+        assertNull(guestData.getDiscoveryHandlerId());
+        assertEquals(key, 
DiscoveryUpstreamKey.from(handler.arguments.get(index)));
+    }
+
+    private static void assertArgumentsRemoved(final WasmTestHandler handler) {
+        assertTrue(AbstractWasmDiscoveryHandler.ARGUMENTS.isEmpty());
+        handler.argumentIds.forEach(id -> 
assertNull(AbstractWasmDiscoveryHandler.ARGUMENTS.get(id)));
     }
 
     abstract static class WasmTestHandler extends AbstractWasmDiscoveryHandler 
{
 
-        private static final java.util.concurrent.atomic.AtomicLong ID =
-                new java.util.concurrent.atomic.AtomicLong();
+        private static final AtomicLong ID = new AtomicLong();
 
-        private final Map<Long, String> results = new ConcurrentHashMap<>();
+        private final List<String> results = new ArrayList<>();
 
-        private final String expectedResult;
+        private final List<DiscoverySyncData> arguments = new ArrayList<>();
 
-        WasmTestHandler(final String expectedResult) {
-            this.expectedResult = expectedResult;
-        }
+        private final List<Long> argumentIds = new ArrayList<>();
+
+        private boolean failOnResult;
 
         @Override
         protected long onGetArgs(final long argId, final long addr, final int 
len) {
-            String config = "hello from java " + argId;
-            assertTrue(config.startsWith("hello from java "));
+            DiscoverySyncData argument = ARGUMENTS.get(argId);
+            assertNotNull(argument);
+            arguments.add(argument);
+            byte[] data = 
GsonUtils.getInstance().toJson(argument).getBytes(StandardCharsets.UTF_8);
+            assertTrue(data.length <= len);
             Memory memory = super.getMemory();
-            byte[] data = config.getBytes(StandardCharsets.UTF_8);
-            int writeLen = Math.min(len, data.length);
-            memory.write((int) addr, data, 0, writeLen);
-            return writeLen;
+            memory.write((int) addr, data, 0, data.length);
+            return data.length;
         }
 
         @Override
         protected long onPutResult(final long argId, final long addr, final 
int len) {
-            Memory memory = super.getMemory();
-            byte[] bytes = memory.readBytes((int) addr, len);
-            String result = new String(bytes, StandardCharsets.UTF_8);
-            assertEquals(expectedResult, result);
-            results.put(argId, result);
+            byte[] bytes = super.getMemory().readBytes((int) addr, len);
+            results.add(new String(bytes, StandardCharsets.UTF_8));
+            if (failOnResult) {
+                throw new IllegalStateException("discovery callback failed");
+            }
             return 0;
         }
 
@@ -104,21 +187,21 @@ class AbstractWasmDiscoveryHandlerTest {
 
         @Override
         protected Long getArgumentId(final DiscoverySyncData 
discoverySyncData) {
-            return ID.incrementAndGet();
+            long argumentId = ID.incrementAndGet();
+            argumentIds.add(argumentId);
+            return argumentId;
         }
     }
 
     /** Loads $TestGoWasmPluginDiscoveryHandler.wasm. */
     static class TestGoWasmPluginDiscoveryHandler extends WasmTestHandler {
-        TestGoWasmPluginDiscoveryHandler(final String expected) {
-            super(expected);
-        }
     }
 
     /** Loads $TestWasmPluginDiscoveryHandler.wasm. */
     static class TestWasmPluginDiscoveryHandler extends WasmTestHandler {
-        TestWasmPluginDiscoveryHandler(final String expected) {
-            super(expected);
-        }
+    }
+
+    /** Loads the original Go guest, which only exports the update callback. */
+    static class TestLegacyWasmPluginDiscoveryHandler extends WasmTestHandler {
     }
 }
diff --git 
a/shenyu-plugin/shenyu-plugin-wasm-base/src/test/resources/org.apache.shenyu.plugin.wasm.base.handler.AbstractWasmDiscoveryHandlerTest$TestGoWasmPluginDiscoveryHandler.wasm
 
b/shenyu-plugin/shenyu-plugin-wasm-base/src/test/resources/org.apache.shenyu.plugin.wasm.base.handler.AbstractWasmDiscoveryHandlerTest$TestGoWasmPluginDiscoveryHandler.wasm
index 81cf164a6e..5572618565 100644
Binary files 
a/shenyu-plugin/shenyu-plugin-wasm-base/src/test/resources/org.apache.shenyu.plugin.wasm.base.handler.AbstractWasmDiscoveryHandlerTest$TestGoWasmPluginDiscoveryHandler.wasm
 and 
b/shenyu-plugin/shenyu-plugin-wasm-base/src/test/resources/org.apache.shenyu.plugin.wasm.base.handler.AbstractWasmDiscoveryHandlerTest$TestGoWasmPluginDiscoveryHandler.wasm
 differ
diff --git 
a/shenyu-plugin/shenyu-plugin-wasm-base/src/test/resources/org.apache.shenyu.plugin.wasm.base.handler.AbstractWasmDiscoveryHandlerTest$TestGoWasmPluginDiscoveryHandler.wasm
 
b/shenyu-plugin/shenyu-plugin-wasm-base/src/test/resources/org.apache.shenyu.plugin.wasm.base.handler.AbstractWasmDiscoveryHandlerTest$TestLegacyWasmPluginDiscoveryHandler.wasm
similarity index 100%
copy from 
shenyu-plugin/shenyu-plugin-wasm-base/src/test/resources/org.apache.shenyu.plugin.wasm.base.handler.AbstractWasmDiscoveryHandlerTest$TestGoWasmPluginDiscoveryHandler.wasm
copy to 
shenyu-plugin/shenyu-plugin-wasm-base/src/test/resources/org.apache.shenyu.plugin.wasm.base.handler.AbstractWasmDiscoveryHandlerTest$TestLegacyWasmPluginDiscoveryHandler.wasm
diff --git 
a/shenyu-plugin/shenyu-plugin-wasm-base/src/test/resources/org.apache.shenyu.plugin.wasm.base.handler.AbstractWasmDiscoveryHandlerTest$TestWasmPluginDiscoveryHandler.wasm
 
b/shenyu-plugin/shenyu-plugin-wasm-base/src/test/resources/org.apache.shenyu.plugin.wasm.base.handler.AbstractWasmDiscoveryHandlerTest$TestWasmPluginDiscoveryHandler.wasm
index 4746d9fae0..3db70c65f0 100755
Binary files 
a/shenyu-plugin/shenyu-plugin-wasm-base/src/test/resources/org.apache.shenyu.plugin.wasm.base.handler.AbstractWasmDiscoveryHandlerTest$TestWasmPluginDiscoveryHandler.wasm
 and 
b/shenyu-plugin/shenyu-plugin-wasm-base/src/test/resources/org.apache.shenyu.plugin.wasm.base.handler.AbstractWasmDiscoveryHandlerTest$TestWasmPluginDiscoveryHandler.wasm
 differ
diff --git 
a/shenyu-plugin/shenyu-plugin-wasm-base/src/test/rust-discovery-handler/src/lib.rs
 
b/shenyu-plugin/shenyu-plugin-wasm-base/src/test/rust-discovery-handler/src/lib.rs
index caad200cc3..ad36792773 100644
--- 
a/shenyu-plugin/shenyu-plugin-wasm-base/src/test/rust-discovery-handler/src/lib.rs
+++ 
b/shenyu-plugin/shenyu-plugin-wasm-base/src/test/rust-discovery-handler/src/lib.rs
@@ -24,7 +24,7 @@ extern "C" {
 
 #[no_mangle]
 pub unsafe extern "C" fn handlerDiscoveryUpstreamData(arg_id: i64) {
-    let mut buf = [0u8; 32];
+    let mut buf = [0u8; 1024];
     let buf_ptr = buf.as_mut_ptr() as i64;
     eprintln!("rust side-> buffer base address: {}", buf_ptr);
     // get arg from java
@@ -36,3 +36,12 @@ pub unsafe extern "C" fn 
handlerDiscoveryUpstreamData(arg_id: i64) {
     let result_ptr = rust_result.as_ptr() as i64;
     _ = put_result(arg_id, result_ptr, rust_result.len() as i32);
 }
+
+#[no_mangle]
+pub unsafe extern "C" fn removeDiscoveryUpstreamData(arg_id: i64) {
+    let mut buf = [0u8; 1024];
+    let len = get_args(arg_id, buf.as_mut_ptr() as i64, buf.len() as i32);
+    let input = std::str::from_utf8(&buf[..len as usize]).unwrap();
+    let result = format!("removed:{}", input);
+    _ = put_result(arg_id, result.as_ptr() as i64, result.len() as i32);
+}

Reply via email to