diff --git a/jmeter/readme.md b/jmeter/readme.md
new file mode 100644
index 0000000000..36f0454ae8
--- /dev/null
+++ b/jmeter/readme.md
@@ -0,0 +1,15 @@
+
+# jmeter
diff --git a/jmeter/requestThread接口测试.jmx b/jmeter/requestThread接口测试.jmx
new file mode 100644
index 0000000000..f4278a8513
--- /dev/null
+++ b/jmeter/requestThread接口测试.jmx
@@ -0,0 +1,308 @@
+
+
+
+
+
+
+
+ false
+ false
+
+
+
+ 10
+ 10
+ true
+ continue
+
+ 10
+ false
+
+
+
+
+ 127.0.0.1
+ 9003
+ http
+ /visitor/api/v1/thread
+ true
+ GET
+ true
+ false
+
+
+
+ false
+ 0
+ =
+ true
+ type
+
+
+ false
+ default_agent_uid
+ =
+ true
+ sid
+
+
+ false
+ 1395890719817857
+ =
+ true
+ uid
+
+
+ false
+ LOCAL9686
+ =
+ true
+ nickname
+
+
+ false
+ https://chainsnow.oss-cn-shenzhen.aliyuncs.com/avatars/visitor_default_avatar.png
+ =
+ true
+ avatar
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ true
+ 0
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ true
+ 0
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ true
+ 0
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+ false
+ false
+ false
+ false
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ true
+ 0
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ true
+ 0
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ true
+ 0
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
diff --git a/modules/core/src/main/java/com/bytedesk/core/enums/ClientEnum.java b/modules/core/src/main/java/com/bytedesk/core/enums/ClientEnum.java
index 02aa3b689e..440a201b43 100644
--- a/modules/core/src/main/java/com/bytedesk/core/enums/ClientEnum.java
+++ b/modules/core/src/main/java/com/bytedesk/core/enums/ClientEnum.java
@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-05-25 13:07:20
* @LastEditors: jackning 270580156@qq.com
- * @LastEditTime: 2024-12-19 15:52:30
+ * @LastEditTime: 2024-12-24 12:49:28
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM –
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -109,6 +109,8 @@ public enum ClientEnum {
SHOPIFY, // Shopify
LAZADA, // 来赞达
SHOPEE, // 虾皮
+ //
+ TEST,
;
// 根据字符串查找对应的枚举常量
diff --git a/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorAnonymousController.java b/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorAnonymousController.java
index 73e1296039..534e793c8e 100644
--- a/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorAnonymousController.java
+++ b/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorAnonymousController.java
@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-01-29 16:21:24
* @LastEditors: jackning 270580156@qq.com
- * @LastEditTime: 2024-12-24 10:55:34
+ * @LastEditTime: 2024-12-24 13:04:17
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM –
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
diff --git a/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorRequest.java b/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorRequest.java
index 622ef1ba5e..ba786a6dca 100644
--- a/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorRequest.java
+++ b/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorRequest.java
@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-04-04 17:05:48
* @LastEditors: jackning 270580156@qq.com
- * @LastEditTime: 2024-12-24 09:46:10
+ * @LastEditTime: 2024-12-24 13:01:36
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM –
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -47,9 +47,11 @@ public class VisitorRequest extends BaseRequest {
private String lang = LanguageEnum.ZH_CN.name();
// location info
- private String ip;
+ @Builder.Default
+ private String ip = "127.0.0.1";
- private String ipLocation;
+ @Builder.Default
+ private String ipLocation = "localhost";
// device info
private String browser;
diff --git a/starter/src/test/java/com/bytedesk/starter/VisitorAnonymousControllerIntegrationTest.java b/starter/src/test/java/com/bytedesk/starter/VisitorAnonymousControllerIntegrationTest.java
index ad10c6d71a..cd41970743 100644
--- a/starter/src/test/java/com/bytedesk/starter/VisitorAnonymousControllerIntegrationTest.java
+++ b/starter/src/test/java/com/bytedesk/starter/VisitorAnonymousControllerIntegrationTest.java
@@ -4,11 +4,13 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
-import org.springframework.util.LinkedMultiValueMap;
-import org.springframework.util.MultiValueMap;
-
+import com.bytedesk.core.enums.ClientEnum;
import com.bytedesk.service.visitor.VisitorRequest;
import com.bytedesk.service.visitor.VisitorResponse;
import static org.assertj.core.api.Assertions.assertThat;
@@ -17,11 +19,11 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
+import java.util.Collections;
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
-properties = {
- "bytedesk.socket.enabled=false", // 禁用MQTT服务器
- "server.port=0" // 使用随机端口
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = {
+ "bytedesk.socket.enabled=false", // 禁用MQTT服务器
+ "server.port=0" // 使用随机端口
})
public class VisitorAnonymousControllerIntegrationTest {
@@ -36,38 +38,60 @@ public class VisitorAnonymousControllerIntegrationTest {
public void testVisitorFlowWithRealServer() {
// Step 1: Create visitor
VisitorRequest initRequest = VisitorRequest.builder()
- .sid(AGENT_UID)
- .build();
+ .sid(AGENT_UID)
+ .nickname("Test Visitor")
+ .build();
+ initRequest.setUid("visitor_test_uid");
initRequest.setOrgUid(ORG_UID);
initRequest.setType(TYPE);
+ initRequest.setClient(ClientEnum.TEST.name());
- ResponseEntity visitorResponse = restTemplate.postForEntity(
- "/visitor/api/v1/init",
- initRequest,
- VisitorResponse.class
- );
+ // 创建HTTP Headers并添加必要的信息
+ HttpHeaders headers = new HttpHeaders();
+ headers.set("User-Agent", "Mozilla/5.0 (Test Browser)");
+ headers.set("X-Real-IP", "127.0.0.1");
+ headers.set("X-Forwarded-For", "127.0.0.1");
+ headers.set("Referer", "https://test.bytedesk.com");
+ headers.setContentType(MediaType.APPLICATION_JSON); // 添加Content-Type
+ headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); // 添加Accept
+
+ // 使用HttpEntity包装请求
+ HttpEntity requestEntity = new HttpEntity<>(initRequest, headers);
+
+ // 然后再进行实际的测试请求
+ ResponseEntity visitorResponse = restTemplate.exchange(
+ "/visitor/api/v1/init",
+ HttpMethod.GET,
+ requestEntity,
+ VisitorResponse.class);
+
+ // 打印原始响应内容
+ System.out.println("Response Status: " + visitorResponse.getStatusCode());
+ System.out.println("Response Headers: " + visitorResponse.getHeaders());
+ System.out.println("Response Body: " + visitorResponse.getBody());
// Verify visitor creation response
assertThat(visitorResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
- assertThat(visitorResponse.getBody()).isNotNull();
+ assertThat(visitorResponse.getBody()).as("Response body should not be null").isNotNull();
assertThat(visitorResponse.getBody().getUid()).isNotNull();
assertThat(visitorResponse.getBody().getNickname()).isNotNull();
assertThat(visitorResponse.getBody().getAvatar()).isNotNull();
// Step 2: Request thread with visitor info
VisitorRequest threadRequest = VisitorRequest.builder()
- .sid(AGENT_UID)
- .nickname(visitorResponse.getBody().getNickname())
- .avatar(visitorResponse.getBody().getAvatar())
- .build();
+ .sid(AGENT_UID)
+ .nickname(visitorResponse.getBody().getNickname())
+ .avatar(visitorResponse.getBody().getAvatar())
+ .build();
threadRequest.setUid(visitorResponse.getBody().getUid());
threadRequest.setOrgUid(ORG_UID);
threadRequest.setType(TYPE);
+ threadRequest.setClient(ClientEnum.TEST.name());
+
ResponseEntity threadResponse = restTemplate.postForEntity(
- "/visitor/api/v1/request",
- threadRequest,
- String.class
- );
+ "/visitor/api/v1/request",
+ threadRequest,
+ String.class);
// Verify thread request response
assertThat(threadResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
@@ -78,24 +102,37 @@ public class VisitorAnonymousControllerIntegrationTest {
public void testConcurrentVisitorRequests() throws InterruptedException {
int concurrentRequests = 10;
Thread[] threads = new Thread[concurrentRequests];
-
+
for (int i = 0; i < concurrentRequests; i++) {
+ final int index = i;
threads[i] = new Thread(() -> {
VisitorRequest initRequest = VisitorRequest.builder()
- .sid(AGENT_UID)
- .build();
+ .sid(AGENT_UID)
+ .build();
+ initRequest.setUid("visitor_test_uid_" + index);
initRequest.setOrgUid(ORG_UID);
initRequest.setType(TYPE);
+ initRequest.setClient(ClientEnum.TEST.name());
- ResponseEntity response = restTemplate.postForEntity(
- "/visitor/api/v1/init",
- initRequest,
- VisitorResponse.class
- );
+ // 创建HTTP Headers并添加必要的信息
+ HttpHeaders headers = new HttpHeaders();
+ headers.set("User-Agent", "Mozilla/5.0 (Test Browser)");
+ headers.set("X-Real-IP", "127.0.0.1");
+ headers.set("X-Forwarded-For", "127.0.0.1");
+ headers.set("Referer", "https://test.bytedesk.com");
- assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
- assertThat(response.getBody()).isNotNull();
- assertThat(response.getBody().getUid()).isNotNull();
+ // 使用HttpEntity包装请求
+ HttpEntity requestEntity = new HttpEntity<>(initRequest, headers);
+
+ ResponseEntity visitorResponse = restTemplate.exchange(
+ "/visitor/api/v1/init",
+ HttpMethod.GET,
+ requestEntity,
+ VisitorResponse.class);
+
+ assertThat(visitorResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
+ assertThat(visitorResponse.getBody()).isNotNull();
+ assertThat(visitorResponse.getBody().getUid()).isNotNull();
});
threads[i].start();
}
@@ -106,46 +143,44 @@ public class VisitorAnonymousControllerIntegrationTest {
}
}
- @Test
- public void testVisitorInitWithInvalidParams() {
- // Test with missing required parameters
- MultiValueMap params = new LinkedMultiValueMap<>();
- params.add("type", TYPE); // Missing orgUid and sid
-
- ResponseEntity response = restTemplate.postForEntity(
- "/visible/api/v1/init",
- params,
- VisitorResponse.class
- );
-
- assertThat(response.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
- }
-
@Test
public void testMultipleVisitorsWithMultipleRequests() throws InterruptedException {
int visitorCount = 100;
int requestsPerVisitor = 100;
-
+
// Create a thread pool for managing concurrent visitors
ExecutorService executorService = Executors.newFixedThreadPool(20);
CountDownLatch completionLatch = new CountDownLatch(visitorCount);
-
+
// Create visitors and their requests
for (int i = 0; i < visitorCount; i++) {
+ final int index = i;
executorService.submit(() -> {
try {
// Step 1: Create visitor
VisitorRequest initRequest = VisitorRequest.builder()
- .sid(AGENT_UID)
- .build();
+ .sid(AGENT_UID)
+ .build();
+ initRequest.setUid("visitor_test_uid_" + index);
initRequest.setOrgUid(ORG_UID);
initRequest.setType(TYPE);
+ initRequest.setClient(ClientEnum.TEST.name());
- ResponseEntity visitorResponse = restTemplate.postForEntity(
- "/visitor/api/v1/init",
- initRequest,
- VisitorResponse.class
- );
+ // 创建HTTP Headers并添加必要的信息
+ HttpHeaders headers = new HttpHeaders();
+ headers.set("User-Agent", "Mozilla/5.0 (Test Browser)");
+ headers.set("X-Real-IP", "127.0.0.1");
+ headers.set("X-Forwarded-For", "127.0.0.1");
+ headers.set("Referer", "https://test.bytedesk.com");
+
+ // 使用HttpEntity包装请求
+ HttpEntity requestEntity = new HttpEntity<>(initRequest, headers);
+
+ ResponseEntity visitorResponse = restTemplate.exchange(
+ "/visitor/api/v1/init",
+ HttpMethod.GET,
+ requestEntity,
+ VisitorResponse.class);
assertThat(visitorResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(visitorResponse.getBody()).isNotNull();
@@ -154,19 +189,19 @@ public class VisitorAnonymousControllerIntegrationTest {
// Step 2: Make multiple thread requests for this visitor
for (int j = 0; j < requestsPerVisitor; j++) {
VisitorRequest threadRequest = VisitorRequest.builder()
- .sid(AGENT_UID)
- .nickname(visitor.getNickname())
- .avatar(visitor.getAvatar())
- .build();
+ .sid(AGENT_UID)
+ .nickname(visitor.getNickname())
+ .avatar(visitor.getAvatar())
+ .build();
threadRequest.setUid(visitor.getUid());
threadRequest.setOrgUid(ORG_UID);
threadRequest.setType(TYPE);
+ threadRequest.setClient(ClientEnum.TEST.name());
ResponseEntity threadResponse = restTemplate.postForEntity(
- "/visitor/api/v1/request",
- threadRequest,
- String.class
- );
+ "/visitor/api/v1/request",
+ threadRequest,
+ String.class);
assertThat(threadResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(threadResponse.getBody()).isNotNull();
@@ -180,9 +215,9 @@ public class VisitorAnonymousControllerIntegrationTest {
// Wait for all visitors to complete their requests
boolean completed = completionLatch.await(5, TimeUnit.MINUTES);
executorService.shutdown();
-
+
assertThat(completed).isTrue()
- .withFailMessage("Not all visitors completed their requests within the timeout period");
+ .withFailMessage("Not all visitors completed their requests within the timeout period");
}
-}
\ No newline at end of file
+}
\ No newline at end of file