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

hefengen 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 e5bde9c79b [type:test] Add e2e web socket sync (#5264)
e5bde9c79b is described below

commit e5bde9c79b901f922c2fa71e9f616f75ee249765
Author: wenlongbrother <[email protected]>
AuthorDate: Thu Nov 2 13:22:13 2023 +0800

    [type:test] Add e2e web socket sync (#5264)
    
    * add websocket client dependency
    
    * update websocket e2e test
    
    * add k8s script
    
    * update sh file
    
    * add cm.yaml
    
    * add e2e to yaml
    
    * remove unused file and update configmap
    
    * update e2e-websocket-sync.sh
    
    * Change the code to comply with the specification
    
    * Change the code to comply with the specification
    
    * Change the code to comply with the specification
    
    * update code
    
    * update code
    
    * update code
    
    * update code
    
    * update code
    
    * update code
    
    * update code
    
    * update code
    
    * update code
    
    * update code
    
    * update code
    
    * update code
    
    * add test code to test
    
    * remove unused code
    
    * add test code to test
    
    * add test code to test
    
    * add test code to test
    
    * add test code to test
    
    * update code
    
    * update code
    
    * update code
    
    * update code
    
    * update code
    
    * add healthcheck
    
    * reset
    
    * reset config
    
    * reset config
    
    * reset config
    
    * reset config
    
    * reset config
    
    * reset config
    
    * reset config
    
    * reset config
    
    * update port from 9095 to 31095
    
    ---------
    
    Co-authored-by: ”qingge“ <“[email protected]”>
    Co-authored-by: xiaoyu <[email protected]>
    Co-authored-by: moremind <[email protected]>
---
 .github/workflows/e2e-k8s.yml                      |  2 +
 shenyu-e2e/pom.xml                                 |  7 ++
 shenyu-e2e/shenyu-e2e-case/pom.xml                 |  1 +
 .../k8s/script/e2e-websocket-sync.sh               | 78 ++++++++++++++++++
 .../k8s/script/healthcheck.sh                      | 39 +++++++++
 .../k8s/shenyu-examples-websocket.yml              | 72 ++++++++++++++++
 .../{ => shenyu-e2e-case-websocket}/pom.xml        | 33 +++-----
 .../e2e/testcase/websocket/DataSynTest.java        | 59 +++++++++++++
 .../testcase/websocket/WebSocketPluginCases.java   | 57 +++++++++++++
 .../testcase/websocket/WebSocketPluginTest.java    | 83 +++++++++++++++++++
 .../shenyu/e2e/client/gateway/GatewayClient.java   | 57 ++++++++++++-
 .../engine/scenario/function/WebSocketChecker.java | 52 ++++++++++++
 .../scenario/function/WebSocketCheckers.java       | 96 ++++++++++++++++++++++
 .../WebSocketVerifier.java}                        | 31 ++++---
 .../engine/scenario/specification/CaseSpec.java    |  6 ++
 .../specification/ScenarioSpecLogProxy.java        |  9 +-
 .../scenario/specification/ShenYuCaseSpec.java     | 51 +++++++++++-
 17 files changed, 690 insertions(+), 43 deletions(-)

diff --git a/.github/workflows/e2e-k8s.yml b/.github/workflows/e2e-k8s.yml
index 6072527b0a..f0fa44b761 100644
--- a/.github/workflows/e2e-k8s.yml
+++ b/.github/workflows/e2e-k8s.yml
@@ -209,6 +209,8 @@ jobs:
             script: e2e-sofa-sync
           - case: shenyu-e2e-case-grpc
             script: e2e-grpc-sync
+          - case: shenyu-e2e-case-websocket
+            script: e2e-websocket-sync
     steps:
       - uses: actions/checkout@v2
         with:
diff --git a/shenyu-e2e/pom.xml b/shenyu-e2e/pom.xml
index 2e38489c72..7373080925 100644
--- a/shenyu-e2e/pom.xml
+++ b/shenyu-e2e/pom.xml
@@ -57,6 +57,7 @@
         
<maven-checkstyle-plugin.version>3.1.0</maven-checkstyle-plugin.version>
         <guava.version>31.1-jre</guava.version>
         <commons-collection.verion>4.4</commons-collection.verion>
+        <websocket.version>1.5.1</websocket.version>
     </properties>
 
     <modules>
@@ -67,6 +68,12 @@
     </modules>
 
     <dependencies>
+        <dependency>
+            <groupId>org.java-websocket</groupId>
+            <artifactId>Java-WebSocket</artifactId>
+            <version>${websocket.version}</version>
+        </dependency>
+
         <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
diff --git a/shenyu-e2e/shenyu-e2e-case/pom.xml 
b/shenyu-e2e/shenyu-e2e-case/pom.xml
index a3e3e11a52..e72a646df7 100644
--- a/shenyu-e2e/shenyu-e2e-case/pom.xml
+++ b/shenyu-e2e/shenyu-e2e-case/pom.xml
@@ -37,6 +37,7 @@
         <module>shenyu-e2e-case-motan</module>
         <module>shenyu-e2e-case-grpc</module>
         <module>shenyu-e2e-case-brpc</module>
+        <module>shenyu-e2e-case-websocket</module>
     </modules>
 
     <dependencies>
diff --git 
a/shenyu-e2e/shenyu-e2e-case/shenyu-e2e-case-websocket/k8s/script/e2e-websocket-sync.sh
 
b/shenyu-e2e/shenyu-e2e-case/shenyu-e2e-case-websocket/k8s/script/e2e-websocket-sync.sh
new file mode 100644
index 0000000000..5d96dd4883
--- /dev/null
+++ 
b/shenyu-e2e/shenyu-e2e-case/shenyu-e2e-case-websocket/k8s/script/e2e-websocket-sync.sh
@@ -0,0 +1,78 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+docker save shenyu-example-spring-native-websocket:latest | sudo k3s ctr 
images import -
+
+# init kubernetes for mysql
+SHENYU_TESTCASE_DIR=$(dirname "$(dirname "$(dirname "$(dirname "$0")")")")
+bash "${SHENYU_TESTCASE_DIR}"/k8s/script/storage/storage_init_mysql.sh
+
+# init register center
+CUR_PATH=$(readlink -f "$(dirname "$0")")
+PRGDIR=$(dirname "$CUR_PATH")
+echo "$PRGDIR"
+kubectl apply -f "${SHENYU_TESTCASE_DIR}"/k8s/sync/shenyu-cm.yml
+
+# init shenyu sync
+SYNC_ARRAY=("websocket" "http" "zookeeper" "etcd")
+#SYNC_ARRAY=("websocket" "nacos")
+MIDDLEWARE_SYNC_ARRAY=("zookeeper" "etcd" "nacos")
+for sync in ${SYNC_ARRAY[@]}; do
+  echo -e "------------------\n"
+  kubectl apply -f "$SHENYU_TESTCASE_DIR"/k8s/shenyu-mysql.yml
+  sleep 30s
+  echo "[Start ${sync} synchronous] create shenyu-admin-${sync}.yml 
shenyu-bootstrap-${sync}.yml shenyu-examples-websocket.yml"
+  # shellcheck disable=SC2199
+  # shellcheck disable=SC2076
+  if [[ "${MIDDLEWARE_SYNC_ARRAY[@]}" =~ "${sync}" ]]; then
+    kubectl apply -f "${SHENYU_TESTCASE_DIR}"/k8s/shenyu-"${sync}".yml
+    sleep 10s
+  fi
+  kubectl apply -f "${SHENYU_TESTCASE_DIR}"/k8s/sync/shenyu-admin-"${sync}".yml
+  sh "${CUR_PATH}"/healthcheck.sh http://localhost:31095/actuator/health
+  kubectl apply -f 
"${SHENYU_TESTCASE_DIR}"/k8s/sync/shenyu-bootstrap-"${sync}".yml
+  sh "${CUR_PATH}"/healthcheck.sh http://localhost:31195/actuator/health
+  kubectl apply -f "${PRGDIR}"/shenyu-examples-websocket.yml
+  sh "${CUR_PATH}"/healthcheck.sh http://localhost:31191/actuator/health
+  sleep 10s
+  kubectl get pod -o wide
+
+  ## run e2e-test
+  ./mvnw -B -f ./shenyu-e2e/pom.xml -pl 
shenyu-e2e-case/shenyu-e2e-case-websocket -am test
+  # shellcheck disable=SC2181
+  if (($?)); then
+    echo "${sync}-sync-e2e-test failed"
+    echo "shenyu-admin log:"
+    echo "------------------"
+    kubectl logs "$(kubectl get pod -o wide | grep shenyu-admin | awk '{print 
$1}')"
+    echo "shenyu-bootstrap log:"
+    echo "------------------"
+    kubectl logs "$(kubectl get pod -o wide | grep shenyu-bootstrap | awk 
'{print $1}')"
+    exit 1
+  fi
+  kubectl delete -f "${SHENYU_TESTCASE_DIR}"/k8s/shenyu-mysql.yml
+  kubectl delete -f 
"${SHENYU_TESTCASE_DIR}"/k8s/sync/shenyu-admin-"${sync}".yml
+  kubectl delete -f 
"${SHENYU_TESTCASE_DIR}"/k8s/sync/shenyu-bootstrap-"${sync}".yml
+  kubectl delete -f "${PRGDIR}"/shenyu-examples-websocket.yml
+  # shellcheck disable=SC2199
+  # shellcheck disable=SC2076
+  if [[ "${MIDDLEWARE_SYNC_ARRAY[@]}" =~ "${sync}" ]]; then
+    kubectl delete -f "${SHENYU_TESTCASE_DIR}"/k8s/shenyu-"${sync}".yml
+  fi
+  echo "[Remove ${sync} synchronous] delete shenyu-admin-${sync}.yml 
shenyu-bootstrap-${sync}.yml shenyu-examples-websocket.yml"
+done
diff --git 
a/shenyu-e2e/shenyu-e2e-case/shenyu-e2e-case-websocket/k8s/script/healthcheck.sh
 
b/shenyu-e2e/shenyu-e2e-case/shenyu-e2e-case-websocket/k8s/script/healthcheck.sh
new file mode 100644
index 0000000000..1159a0f417
--- /dev/null
+++ 
b/shenyu-e2e/shenyu-e2e-case/shenyu-e2e-case-websocket/k8s/script/healthcheck.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+for loop in $(seq 1 30); do
+  status=$(curl -s -o /dev/null -w %{http_code} -X GET "${1}" -H "accept: */*")
+  echo -e "${loop} curl ${1} response $status"
+  if [ "$status" -eq 200 ]; then
+    break
+  fi
+  sleep 2s
+done
+
+status=$(curl -s -o /dev/null -w "%{http_code}" -X GET "${1}" -H "accept: */*")
+
+if [ "$status" -eq 200 ]; then
+  echo -e "\n-------------------"
+  echo -e "Success to ${1} send request: $status"
+  echo -e "\n-------------------"
+  exit 0
+fi
+echo -e "\n-------------------"
+echo -e "Failed to send request from shenyu-admin : $status"
+echo -e "\n-------------------"
+exit 1
diff --git 
a/shenyu-e2e/shenyu-e2e-case/shenyu-e2e-case-websocket/k8s/shenyu-examples-websocket.yml
 
b/shenyu-e2e/shenyu-e2e-case/shenyu-e2e-case-websocket/k8s/shenyu-examples-websocket.yml
new file mode 100644
index 0000000000..449e6ad0ed
--- /dev/null
+++ 
b/shenyu-e2e/shenyu-e2e-case/shenyu-e2e-case-websocket/k8s/shenyu-examples-websocket.yml
@@ -0,0 +1,72 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: shenyu-examples-websocket
+  labels:
+    app: shenyu-examples-websocket
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: shenyu-examples-websocket
+  strategy: {}
+  template:
+    metadata:
+      labels:
+        app: shenyu-examples-websocket
+    spec:
+      containers:
+        - image: shenyu-example-spring-native-websocket:latest
+          name: shenyu-examples-websocket
+          livenessProbe:
+            exec:
+              command:
+                - wget -q -O - http://localhost:8868/actuator/health | grep UP 
|| exit 1
+            initialDelaySeconds: 30
+            failureThreshold: 3
+            timeoutSeconds: 2
+          env:
+            - name: shenyu.register.serverLists
+              value: http://shenyu-admin:9095
+            - name: websocket.registry.address
+              value: zookeeper://shenyu-zookeeper:2181
+          ports:
+            - containerPort: 8868
+          imagePullPolicy: IfNotPresent
+      restartPolicy: Always
+status: {}
+
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: shenyu-examples-websocket
+  labels:
+    app: shenyu-examples-websocket
+spec:
+  selector:
+    app: shenyu-examples-websocket
+  type: NodePort
+  ports:
+    - name: "8868"
+      port: 8868
+      targetPort: 8868
+      nodePort: 31191
+status:
+  loadBalancer: {}
diff --git a/shenyu-e2e/shenyu-e2e-case/pom.xml 
b/shenyu-e2e/shenyu-e2e-case/shenyu-e2e-case-websocket/pom.xml
similarity index 54%
copy from shenyu-e2e/shenyu-e2e-case/pom.xml
copy to shenyu-e2e/shenyu-e2e-case/shenyu-e2e-case-websocket/pom.xml
index a3e3e11a52..024fd51c23 100644
--- a/shenyu-e2e/shenyu-e2e-case/pom.xml
+++ b/shenyu-e2e/shenyu-e2e-case/shenyu-e2e-case-websocket/pom.xml
@@ -15,36 +15,29 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
-         xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
-    <modelVersion>4.0.0</modelVersion>
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
     <parent>
         <groupId>org.apache.shenyu</groupId>
-        <artifactId>shenyu-e2e</artifactId>
+        <artifactId>shenyu-e2e-case</artifactId>
         <version>0.0.1-SNAPSHOT</version>
     </parent>
 
-    <artifactId>shenyu-e2e-case</artifactId>
+    <modelVersion>4.0.0</modelVersion>
 
-    <packaging>pom</packaging>
+    <artifactId>shenyu-e2e-case-websocket</artifactId>
 
-    <modules>
-        <module>shenyu-e2e-case-http</module>
-        <module>shenyu-e2e-case-spring-cloud</module>
-        <module>shenyu-e2e-case-alibaba-dubbo</module>
-        <module>shenyu-e2e-case-apache-dubbo</module>
-        <module>shenyu-e2e-case-sofa</module>
-        <module>shenyu-e2e-case-motan</module>
-        <module>shenyu-e2e-case-grpc</module>
-        <module>shenyu-e2e-case-brpc</module>
-    </modules>
+    <properties>
+        <websocket.version>1.5.1</websocket.version>
+    </properties>
 
     <dependencies>
         <dependency>
-            <groupId>org.apache.shenyu</groupId>
-            <artifactId>shenyu-e2e-engine</artifactId>
-            <version>${project.version}</version>
+            <groupId>org.java-websocket</groupId>
+            <artifactId>Java-WebSocket</artifactId>
+            <version>1.5.3</version>
         </dependency>
-
     </dependencies>
+
 </project>
\ No newline at end of file
diff --git 
a/shenyu-e2e/shenyu-e2e-case/shenyu-e2e-case-websocket/src/test/java/org/apache/shenyue/e2e/testcase/websocket/DataSynTest.java
 
b/shenyu-e2e/shenyu-e2e-case/shenyu-e2e-case-websocket/src/test/java/org/apache/shenyue/e2e/testcase/websocket/DataSynTest.java
new file mode 100644
index 0000000000..8f04ce167e
--- /dev/null
+++ 
b/shenyu-e2e/shenyu-e2e-case/shenyu-e2e-case-websocket/src/test/java/org/apache/shenyue/e2e/testcase/websocket/DataSynTest.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyue.e2e.testcase.websocket;
+
+import org.apache.shenyu.e2e.client.WaitDataSync;
+import org.apache.shenyu.e2e.client.admin.AdminClient;
+import org.apache.shenyu.e2e.client.gateway.GatewayClient;
+import org.apache.shenyu.e2e.engine.annotation.ShenYuTest;
+import org.apache.shenyu.e2e.enums.ServiceTypeEnum;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Testing the correctness of etcd data synchronization method.
+ */
+@ShenYuTest(environments = {
+        @ShenYuTest.Environment(
+                serviceName = "shenyu-e2e-admin",
+                service = @ShenYuTest.ServiceConfigure(moduleName = 
"shenyu-e2e",
+                        baseUrl = "http://localhost:31095";,
+                        type = ServiceTypeEnum.SHENYU_ADMIN,
+                        parameters = {
+                                @ShenYuTest.Parameter(key = "username", value 
= "admin"),
+                                @ShenYuTest.Parameter(key = "password", value 
= "123456")
+                        }
+                )
+        ),
+        @ShenYuTest.Environment(
+                serviceName = "shenyu-e2e-gateway",
+                service = @ShenYuTest.ServiceConfigure(moduleName = 
"shenyu-e2e",
+                        baseUrl = "http://localhost:31195";,
+                        type = ServiceTypeEnum.SHENYU_GATEWAY
+                )
+        )
+})
+public class DataSynTest {
+
+    @Test
+    void testDataSyn(final AdminClient adminClient, final GatewayClient 
gatewayClient) throws Exception {
+        adminClient.login();
+        
WaitDataSync.waitAdmin2GatewayDataSyncEquals(adminClient::listAllSelectors, 
gatewayClient::getSelectorCache, adminClient);
+        
WaitDataSync.waitAdmin2GatewayDataSyncEquals(adminClient::listAllMetaData, 
gatewayClient::getMetaDataCache, adminClient);
+        
WaitDataSync.waitAdmin2GatewayDataSyncEquals(adminClient::listAllRules, 
gatewayClient::getRuleCache, adminClient);
+    }
+}
diff --git 
a/shenyu-e2e/shenyu-e2e-case/shenyu-e2e-case-websocket/src/test/java/org/apache/shenyue/e2e/testcase/websocket/WebSocketPluginCases.java
 
b/shenyu-e2e/shenyu-e2e-case/shenyu-e2e-case-websocket/src/test/java/org/apache/shenyue/e2e/testcase/websocket/WebSocketPluginCases.java
new file mode 100644
index 0000000000..153a068e64
--- /dev/null
+++ 
b/shenyu-e2e/shenyu-e2e-case/shenyu-e2e-case-websocket/src/test/java/org/apache/shenyue/e2e/testcase/websocket/WebSocketPluginCases.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyue.e2e.testcase.websocket;
+
+import com.google.common.collect.Lists;
+import org.apache.shenyu.e2e.engine.scenario.ShenYuScenarioProvider;
+import org.apache.shenyu.e2e.engine.scenario.specification.ScenarioSpec;
+import 
org.apache.shenyu.e2e.engine.scenario.specification.ShenYuBeforeEachSpec;
+import org.apache.shenyu.e2e.engine.scenario.specification.ShenYuCaseSpec;
+import org.apache.shenyu.e2e.engine.scenario.specification.ShenYuScenarioSpec;
+
+import java.util.List;
+
+import static 
org.apache.shenyu.e2e.engine.scenario.function.WebSocketCheckers.exists;
+
+public class WebSocketPluginCases implements ShenYuScenarioProvider {
+
+    @Override
+    public List<ScenarioSpec> get() {
+        return Lists.newArrayList(
+                testWebSocket()
+        );
+    }
+
+    /**
+     * test websocket.
+     *
+     * @return ShenYuScenarioSpec
+     */
+    public ShenYuScenarioSpec testWebSocket() {
+        return ShenYuScenarioSpec.builder()
+                .name("single-websocket test]")
+                .beforeEachSpec(ShenYuBeforeEachSpec.builder()
+                        .checker(exists("/ws-native/myWebSocket?token=Jack", 
"Hello ShenYu", "apache shenyu server send to Jack message : -> Hello ShenYu"))
+                        .build())
+                .caseSpec(ShenYuCaseSpec.builder()
+                        .addExists("/ws-native/myWebSocket?token=Mask", "Hello 
ShenYu", "apache shenyu server send to Mask message : -> Hello ShenYu")
+                        .addNotExists("/ws-annotation/myWs", "Hello ShenYu")
+                        .build())
+                .build();
+    }
+}
diff --git 
a/shenyu-e2e/shenyu-e2e-case/shenyu-e2e-case-websocket/src/test/java/org/apache/shenyue/e2e/testcase/websocket/WebSocketPluginTest.java
 
b/shenyu-e2e/shenyu-e2e-case/shenyu-e2e-case-websocket/src/test/java/org/apache/shenyue/e2e/testcase/websocket/WebSocketPluginTest.java
new file mode 100644
index 0000000000..1b2cdc2bc8
--- /dev/null
+++ 
b/shenyu-e2e/shenyu-e2e-case/shenyu-e2e-case-websocket/src/test/java/org/apache/shenyue/e2e/testcase/websocket/WebSocketPluginTest.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyue.e2e.testcase.websocket;
+
+import org.apache.shenyu.e2e.client.WaitDataSync;
+import org.apache.shenyu.e2e.client.admin.AdminClient;
+import org.apache.shenyu.e2e.client.gateway.GatewayClient;
+import org.apache.shenyu.e2e.engine.annotation.ShenYuScenario;
+import org.apache.shenyu.e2e.engine.annotation.ShenYuTest;
+import org.apache.shenyu.e2e.engine.scenario.specification.CaseSpec;
+import org.apache.shenyu.e2e.enums.ServiceTypeEnum;
+import org.junit.jupiter.api.BeforeAll;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+
+@ShenYuTest(environments = {
+        @ShenYuTest.Environment(
+                serviceName = "shenyu-e2e-admin",
+                service = @ShenYuTest.ServiceConfigure(moduleName = 
"shenyu-e2e",
+                        baseUrl = "http://localhost:31095";,
+                        type = ServiceTypeEnum.SHENYU_ADMIN,
+                        parameters = {
+                                @ShenYuTest.Parameter(key = "username", value 
= "admin"),
+                                @ShenYuTest.Parameter(key = "password", value 
= "123456")
+                        }
+                )
+        ),
+        @ShenYuTest.Environment(
+                serviceName = "shenyu-e2e-gateway",
+                service = @ShenYuTest.ServiceConfigure(moduleName = 
"shenyu-e2e",
+                        baseUrl = "http://localhost:31195";,
+                        type = ServiceTypeEnum.SHENYU_GATEWAY
+                )
+        )
+})
+/**
+ * Testing websocket plugin.
+ */
+public class WebSocketPluginTest {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(WebSocketPluginTest.class);
+
+    @BeforeAll
+    static void setup(final AdminClient adminClient, final GatewayClient 
gatewayClient) throws Exception {
+        adminClient.login();
+        
WaitDataSync.waitAdmin2GatewayDataSyncEquals(adminClient::listAllRules, 
gatewayClient::getRuleCache, adminClient);
+        
WaitDataSync.waitAdmin2GatewayDataSyncEquals(adminClient::listAllSelectors, 
gatewayClient::getSelectorCache, adminClient);
+        
WaitDataSync.waitAdmin2GatewayDataSyncEquals(adminClient::listAllMetaData, 
gatewayClient::getMetaDataCache, adminClient);
+        
WaitDataSync.waitAdmin2GatewayDataSyncEquals(adminClient::listAllRules, 
gatewayClient::getRuleCache, adminClient);
+        LOG.info("start websocket plugin");
+        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
+        formData.add("id", "26");
+        formData.add("name", "websocket");
+        formData.add("enabled", "true");
+        formData.add("role", "Proxy");
+        formData.add("sort", "200");
+        adminClient.changePluginStatus("1", formData);
+        WaitDataSync.waitGatewayPluginUse(gatewayClient, 
"org.apache.shenyu.plugin.websocket.WebSocketPlugin");
+
+    }
+
+    @ShenYuScenario(provider = WebSocketPluginCases.class)
+    void testWebSocket(final GatewayClient gateway, final CaseSpec spec) {
+        spec.getWebSocketVerifiers().forEach(webSocketVerifier -> 
webSocketVerifier.verify(gateway.getWebSocketClientSupplier().get(), gateway));
+    }
+}
diff --git 
a/shenyu-e2e/shenyu-e2e-client/src/main/java/org/apache/shenyu/e2e/client/gateway/GatewayClient.java
 
b/shenyu-e2e/shenyu-e2e-client/src/main/java/org/apache/shenyu/e2e/client/gateway/GatewayClient.java
index 8966e3b05c..9acdc54d10 100644
--- 
a/shenyu-e2e/shenyu-e2e-client/src/main/java/org/apache/shenyu/e2e/client/gateway/GatewayClient.java
+++ 
b/shenyu-e2e/shenyu-e2e-client/src/main/java/org/apache/shenyu/e2e/client/gateway/GatewayClient.java
@@ -27,6 +27,8 @@ import org.apache.shenyu.e2e.common.RequestLogConsumer;
 import org.apache.shenyu.e2e.model.data.MetaData;
 import org.apache.shenyu.e2e.model.data.RuleCacheData;
 import org.apache.shenyu.e2e.model.data.SelectorCacheData;
+import org.java_websocket.client.WebSocketClient;
+import org.java_websocket.handshake.ServerHandshake;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.MDC;
@@ -34,10 +36,14 @@ import org.springframework.http.HttpMethod;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.client.RestTemplate;
 
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Supplier;
 
 import static io.restassured.RestAssured.given;
@@ -53,7 +59,9 @@ public class GatewayClient extends BaseClient {
     private static final RestTemplate TEMPLATE = new RestTemplate();
 
     private static final ObjectMapper MAPPER = new ObjectMapper();
-    
+
+    private static final ArrayBlockingQueue<String> BLOCKING_QUEUE = new 
ArrayBlockingQueue<>(1);
+
     private final String scenarioId;
 
     private final String baseUrl;
@@ -104,6 +112,41 @@ public class GatewayClient extends BaseClient {
                 })
                 .when();
     }
+
+    /**
+     * get websocket client.
+     * @return Supplier
+     */
+    public Supplier<WebSocketClient> getWebSocketClientSupplier() {
+        return () -> {
+            try {
+                return new WebSocketClient(new 
URI(getBaseUrl().replaceAll("http", "ws"))) {
+                    @Override
+                    public void onOpen(final ServerHandshake handshakeData) {
+                        log.info("Open websocket connection successfully");
+                    }
+
+                    @Override
+                    public void onMessage(final String message) {
+                        BLOCKING_QUEUE.add(message);
+                        log.info("Receive Message: " + message);
+                    }
+
+                    @Override
+                    public void onClose(final int code, final String reason, 
final boolean remote) {
+                    }
+
+                    @Override
+                    public void onError(final Exception ex) {
+                        log.error(ex.getMessage());
+                    }
+                };
+            } catch (URISyntaxException e) {
+                throw new RuntimeException("Invalid WebSocket URI", e);
+            }
+        };
+
+    }
     
     /**
      * get meta data cache.
@@ -172,4 +215,16 @@ public class GatewayClient extends BaseClient {
         List body = response.getBody();
         return (Map<String, Integer>) body.get(0);
     }
+
+    /**
+     * get the return message from the server.
+     * @return String String
+     */
+    public String getWebSocketMessage() {
+        try {
+            return BLOCKING_QUEUE.poll(10, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+    }
 }
diff --git 
a/shenyu-e2e/shenyu-e2e-engine/src/main/java/org/apache/shenyu/e2e/engine/scenario/function/WebSocketChecker.java
 
b/shenyu-e2e/shenyu-e2e-engine/src/main/java/org/apache/shenyu/e2e/engine/scenario/function/WebSocketChecker.java
new file mode 100644
index 0000000000..fe759567c3
--- /dev/null
+++ 
b/shenyu-e2e/shenyu-e2e-engine/src/main/java/org/apache/shenyu/e2e/engine/scenario/function/WebSocketChecker.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyu.e2e.engine.scenario.function;
+
+import org.apache.shenyu.e2e.client.gateway.GatewayClient;
+import org.java_websocket.client.WebSocketClient;
+import org.slf4j.MDC;
+
+import java.util.function.Supplier;
+
+/**
+ * WebSocket Checker interface.
+ */
+@FunctionalInterface
+public interface WebSocketChecker extends Checker, WebSocketVerifier {
+
+    /**
+     * check websocket client.
+     * @param client client
+     */
+    default void check(GatewayClient client) {
+        check(client.getWebSocketClientSupplier(), client);
+    }
+
+    /**
+     * check request specification.
+     * @param supplier supplier
+     * @param client client
+     */
+    default void check(Supplier<WebSocketClient> supplier, GatewayClient 
client) {
+        try {
+            verify(supplier.get(), client);
+        } catch (AssertionError e) {
+            throw new AssertionError("failed to request " + 
MDC.get("endpoint"), e);
+        }
+    }
+}
diff --git 
a/shenyu-e2e/shenyu-e2e-engine/src/main/java/org/apache/shenyu/e2e/engine/scenario/function/WebSocketCheckers.java
 
b/shenyu-e2e/shenyu-e2e-engine/src/main/java/org/apache/shenyu/e2e/engine/scenario/function/WebSocketCheckers.java
new file mode 100644
index 0000000000..10fe560a2a
--- /dev/null
+++ 
b/shenyu-e2e/shenyu-e2e-engine/src/main/java/org/apache/shenyu/e2e/engine/scenario/function/WebSocketCheckers.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyu.e2e.engine.scenario.function;
+
+import org.java_websocket.client.WebSocketClient;
+import org.java_websocket.exceptions.WebsocketNotConnectedException;
+import org.junit.jupiter.api.Assertions;
+
+import java.lang.reflect.Field;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Optional;
+
+/**
+ * Check if the endpoint exists.
+ */
+public class WebSocketCheckers {
+
+    /**
+     * exist endpoint.
+     * @param endpoint endpoint
+     * @param sendMessage sendMessage
+     * @param receiveMessage receiveMessage
+     * @return WebSocketChecker
+     */
+    public static WebSocketChecker exists(final String endpoint, final String 
sendMessage, final String receiveMessage) {
+        return (websocketClient, gatewayClient) -> {
+            try {
+                updateWebSocketClientURI(websocketClient, endpoint);
+
+                websocketClient.connectBlocking();
+                websocketClient.send(sendMessage);
+                Optional.of(websocketClient)
+                        .filter(WebSocketClient::isOpen)
+                        .ifPresent(client -> 
Assertions.assertEquals(receiveMessage, gatewayClient.getWebSocketMessage()));
+            } catch (AssertionError | InterruptedException | RuntimeException 
error) {
+                Assertions.fail("websocket endpoint '" + 
websocketClient.getURI() + "' not exists", error);
+            } catch (NoSuchFieldException | IllegalAccessException | 
URISyntaxException e) {
+                throw new RuntimeException(e);
+            }
+        };
+    }
+
+    /**
+     * not exist endpoint.
+     * @param endpoint endpoint
+     * @param message message
+     * @return WebSocketChecker
+     */
+    public static WebSocketChecker notExists(final String endpoint, final 
String message) {
+        return (websocketClient, gatewayClient) -> {
+            try {
+                updateWebSocketClientURI(websocketClient, endpoint);
+
+                websocketClient.connectBlocking();
+                Optional.of(websocketClient)
+                        .filter(WebSocketClient::isOpen)
+                        .ifPresent(client -> Assertions.fail("websocket 
endpoint '" + endpoint + "' exists"));
+            } catch (AssertionError | InterruptedException | 
WebsocketNotConnectedException error) {
+                Assertions.fail("websocket endpoint '" + endpoint + "' not 
exists", error);
+            } catch (URISyntaxException | NoSuchFieldException | 
IllegalAccessException e) {
+                throw new RuntimeException(e);
+            }
+        };
+    }
+
+
+    /**
+     * update websocket client uri.
+     * @param client client
+     * @param endpoint endpoint
+     */
+    private static void updateWebSocketClientURI(final WebSocketClient client, 
final String endpoint)
+            throws NoSuchFieldException, IllegalAccessException, 
URISyntaxException {
+        Field uriField = WebSocketClient.class.getDeclaredField("uri");
+        uriField.setAccessible(true);
+        URI originalUri = client.getURI();
+        URI updatedUri = new URI(originalUri + endpoint);
+        uriField.set(client, updatedUri);
+    }
+}
diff --git 
a/shenyu-e2e/shenyu-e2e-engine/src/main/java/org/apache/shenyu/e2e/engine/scenario/specification/CaseSpec.java
 
b/shenyu-e2e/shenyu-e2e-engine/src/main/java/org/apache/shenyu/e2e/engine/scenario/function/WebSocketVerifier.java
similarity index 62%
copy from 
shenyu-e2e/shenyu-e2e-engine/src/main/java/org/apache/shenyu/e2e/engine/scenario/specification/CaseSpec.java
copy to 
shenyu-e2e/shenyu-e2e-engine/src/main/java/org/apache/shenyu/e2e/engine/scenario/function/WebSocketVerifier.java
index cb30193e5d..4464ac4ec3 100644
--- 
a/shenyu-e2e/shenyu-e2e-engine/src/main/java/org/apache/shenyu/e2e/engine/scenario/specification/CaseSpec.java
+++ 
b/shenyu-e2e/shenyu-e2e-engine/src/main/java/org/apache/shenyu/e2e/engine/scenario/function/WebSocketVerifier.java
@@ -15,26 +15,23 @@
  * limitations under the License.
  */
 
-package org.apache.shenyu.e2e.engine.scenario.specification;
+package org.apache.shenyu.e2e.engine.scenario.function;
 
-import org.apache.shenyu.e2e.engine.annotation.ShenYuScenarioParameter;
-import org.apache.shenyu.e2e.engine.scenario.function.Verifier;
+import org.apache.shenyu.e2e.client.gateway.GatewayClient;
+import org.java_websocket.client.WebSocketClient;
 
-import java.util.List;
+/**
+ * WebSocket Verifier interface.
+ */
+public interface WebSocketVerifier {
+
+    WebSocketVerifier DEFAULT = (webSocketClient, gatewayClient) -> {
+    };
 
-@ShenYuScenarioParameter
-public interface CaseSpec {
-    
-    /**
-     * get case spec name.
-     * @return String
-     */
-    String getName();
-    
     /**
-     * get case spec verifiers.
-     * @return List
+     * Verify WebSocketClient.
+     * @param client WebSocketClient
+     * @param gatewayClient GatewayClient
      */
-    List<Verifier> getVerifiers();
-
+    void verify(WebSocketClient client, GatewayClient gatewayClient);
 }
diff --git 
a/shenyu-e2e/shenyu-e2e-engine/src/main/java/org/apache/shenyu/e2e/engine/scenario/specification/CaseSpec.java
 
b/shenyu-e2e/shenyu-e2e-engine/src/main/java/org/apache/shenyu/e2e/engine/scenario/specification/CaseSpec.java
index cb30193e5d..8e1314d52e 100644
--- 
a/shenyu-e2e/shenyu-e2e-engine/src/main/java/org/apache/shenyu/e2e/engine/scenario/specification/CaseSpec.java
+++ 
b/shenyu-e2e/shenyu-e2e-engine/src/main/java/org/apache/shenyu/e2e/engine/scenario/specification/CaseSpec.java
@@ -19,6 +19,7 @@ package org.apache.shenyu.e2e.engine.scenario.specification;
 
 import org.apache.shenyu.e2e.engine.annotation.ShenYuScenarioParameter;
 import org.apache.shenyu.e2e.engine.scenario.function.Verifier;
+import org.apache.shenyu.e2e.engine.scenario.function.WebSocketVerifier;
 
 import java.util.List;
 
@@ -37,4 +38,9 @@ public interface CaseSpec {
      */
     List<Verifier> getVerifiers();
 
+    /**
+     * get case spec websocket verifiers.
+     * @return List
+     */
+    List<WebSocketVerifier> getWebSocketVerifiers();
 }
diff --git 
a/shenyu-e2e/shenyu-e2e-engine/src/main/java/org/apache/shenyu/e2e/engine/scenario/specification/ScenarioSpecLogProxy.java
 
b/shenyu-e2e/shenyu-e2e-engine/src/main/java/org/apache/shenyu/e2e/engine/scenario/specification/ScenarioSpecLogProxy.java
index 0bbc75721d..472d5926a9 100644
--- 
a/shenyu-e2e/shenyu-e2e-engine/src/main/java/org/apache/shenyu/e2e/engine/scenario/specification/ScenarioSpecLogProxy.java
+++ 
b/shenyu-e2e/shenyu-e2e-engine/src/main/java/org/apache/shenyu/e2e/engine/scenario/specification/ScenarioSpecLogProxy.java
@@ -17,11 +17,12 @@
 
 package org.apache.shenyu.e2e.engine.scenario.specification;
 
-import org.apache.shenyu.e2e.model.ResourcesData;
 import org.apache.shenyu.e2e.engine.scenario.function.Checker;
 import org.apache.shenyu.e2e.engine.scenario.function.Deleter;
 import org.apache.shenyu.e2e.engine.scenario.function.Verifier;
 import org.apache.shenyu.e2e.engine.scenario.function.Waiting;
+import org.apache.shenyu.e2e.engine.scenario.function.WebSocketVerifier;
+import org.apache.shenyu.e2e.model.ResourcesData;
 import org.slf4j.MDC;
 
 import java.util.List;
@@ -74,6 +75,12 @@ public class ScenarioSpecLogProxy implements ScenarioSpec {
                 MDC.put("operate", "verify");
                 return spec.getVerifiers();
             }
+
+            @Override
+            public List<WebSocketVerifier> getWebSocketVerifiers() {
+                MDC.put("operate", "websocketVerify");
+                return spec.getWebSocketVerifiers();
+            }
         };
     }
     
diff --git 
a/shenyu-e2e/shenyu-e2e-engine/src/main/java/org/apache/shenyu/e2e/engine/scenario/specification/ShenYuCaseSpec.java
 
b/shenyu-e2e/shenyu-e2e-engine/src/main/java/org/apache/shenyu/e2e/engine/scenario/specification/ShenYuCaseSpec.java
index 89d138183d..09acc05c51 100644
--- 
a/shenyu-e2e/shenyu-e2e-engine/src/main/java/org/apache/shenyu/e2e/engine/scenario/specification/ShenYuCaseSpec.java
+++ 
b/shenyu-e2e/shenyu-e2e-engine/src/main/java/org/apache/shenyu/e2e/engine/scenario/specification/ShenYuCaseSpec.java
@@ -21,6 +21,8 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableList.Builder;
 import io.restassured.http.Method;
 import org.apache.shenyu.e2e.engine.scenario.function.Verifier;
+import org.apache.shenyu.e2e.engine.scenario.function.WebSocketCheckers;
+import org.apache.shenyu.e2e.engine.scenario.function.WebSocketVerifier;
 import org.hamcrest.Matcher;
 
 import java.util.List;
@@ -38,9 +40,12 @@ public class ShenYuCaseSpec implements CaseSpec {
     
     private final List<Verifier> verifiers;
 
-    public ShenYuCaseSpec(final String name, final List<Verifier> verifiers) {
+    private final List<WebSocketVerifier> webSocketVerifiers;
+
+    public ShenYuCaseSpec(final String name, final List<Verifier> verifiers, 
final List<WebSocketVerifier> webSocketVerifiers) {
         this.name = name;
         this.verifiers = verifiers;
+        this.webSocketVerifiers = webSocketVerifiers;
     }
 
     /**
@@ -62,6 +67,11 @@ public class ShenYuCaseSpec implements CaseSpec {
     public List<Verifier> getVerifiers() {
         return verifiers;
     }
+
+    @Override
+    public List<WebSocketVerifier> getWebSocketVerifiers() {
+        return webSocketVerifiers;
+    }
     
     /**
      * builder.
@@ -86,6 +96,8 @@ public class ShenYuCaseSpec implements CaseSpec {
 
         private final Builder<Verifier> builder = ImmutableList.builder();
 
+        private final Builder<WebSocketVerifier> webSocketBuilder = 
ImmutableList.builder();
+
         public ShenYuTestCaseSpecBuilder() {
         }
 
@@ -112,6 +124,16 @@ public class ShenYuCaseSpec implements CaseSpec {
             builder.add(verifier);
             return this;
         }
+
+        /**
+         * websocket builder add verifier.
+         * @param webSocketVerifier webSocketVerifier
+         * @return ShenYuTestCaseSpecBuilder
+         */
+        public ShenYuTestCaseSpecBuilder add(final WebSocketVerifier 
webSocketVerifier) {
+            webSocketBuilder.add(webSocketVerifier);
+            return this;
+        }
         
         /**
          * add verifier case spec.
@@ -133,7 +155,7 @@ public class ShenYuCaseSpec implements CaseSpec {
          * @return ShenYuTestCaseSpecBuilder
          */
         public ShenYuTestCaseSpecBuilder addVerifier(final Method method, 
final String endpoint, final Matcher<?> matcher, final Matcher<?>... matchers) {
-            return add(supplier -> supplier.when().request(method, 
endpoint).then().assertThat().body(matcher, matchers));
+            return add((Verifier) supplier -> supplier.when().request(method, 
endpoint).then().assertThat().body(matcher, matchers));
         }
         
         /**
@@ -155,6 +177,17 @@ public class ShenYuCaseSpec implements CaseSpec {
             return add(exists(method, endpoint));
         }
 
+        /**
+         * add exist method endpoint case spec.
+         * @param endpoint endpoint
+         * @param sendMessage sendMessage
+         * @param receiveMessage receiveMessage
+         * @return ShenYuTestCaseSpecBuilder
+         */
+        public ShenYuTestCaseSpecBuilder addExists(final String endpoint, 
final String sendMessage, final String receiveMessage) {
+            return add(WebSocketCheckers.exists(endpoint, sendMessage, 
receiveMessage));
+        }
+
 
         /**
          * add exist method endpoint case spec.
@@ -186,13 +219,23 @@ public class ShenYuCaseSpec implements CaseSpec {
         public ShenYuTestCaseSpecBuilder addNotExists(final Method method, 
final String endpoint) {
             return add(notExists(method, endpoint));
         }
-        
+
+        /**
+         * add not exists case spec.
+         * @param endpoint endpoint
+         * @param message message
+         * @return ShenYuTestCaseSpecBuilder
+         */
+        public ShenYuTestCaseSpecBuilder addNotExists(final String endpoint, 
final String message) {
+            return add(WebSocketCheckers.notExists(endpoint, message));
+        }
+
         /**
          * build.
          * @return ShenYuCaseSpec
          */
         public ShenYuCaseSpec build() {
-            return new ShenYuCaseSpec(name, builder.build());
+            return new ShenYuCaseSpec(name, builder.build(), 
webSocketBuilder.build());
         }
     }
 }


Reply via email to