Sync from bytedesk-private: update

This commit is contained in:
jack ning
2024-12-24 14:01:02 +08:00
parent 670ff2cc85
commit 62a2a14bed
6 changed files with 436 additions and 74 deletions

15
jmeter/readme.md Normal file
View File

@@ -0,0 +1,15 @@
<!--
* @Author: jackning 270580156@qq.com
* @Date: 2024-07-09 16:47:04
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-12-24 13:59:35
* @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.
* 仅支持企业内部员工自用严禁私自用于销售、二次销售或者部署SaaS方式销售
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
-->
# jmeter

View File

@@ -0,0 +1,308 @@
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.6.3">
<hashTree>
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="requestThread接口测试">
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="用户定义的变量">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<boolProp name="TestPlan.functional_mode">false</boolProp>
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
</TestPlan>
<hashTree>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="线程组">
<intProp name="ThreadGroup.num_threads">10</intProp>
<intProp name="ThreadGroup.ramp_time">10</intProp>
<boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="循环控制器">
<stringProp name="LoopController.loops">10</stringProp>
<boolProp name="LoopController.continue_forever">false</boolProp>
</elementProp>
</ThreadGroup>
<hashTree>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="HTTP请求" enabled="true">
<stringProp name="HTTPSampler.domain">127.0.0.1</stringProp>
<stringProp name="HTTPSampler.port">9003</stringProp>
<stringProp name="HTTPSampler.protocol">http</stringProp>
<stringProp name="HTTPSampler.path">/visitor/api/v1/thread</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.postBodyRaw">false</boolProp>
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="用户定义的变量">
<collectionProp name="Arguments.arguments">
<elementProp name="type" elementType="HTTPArgument">
<boolProp name="HTTPArgument.always_encode">false</boolProp>
<stringProp name="Argument.value">0</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
<boolProp name="HTTPArgument.use_equals">true</boolProp>
<stringProp name="Argument.name">type</stringProp>
</elementProp>
<elementProp name="sid" elementType="HTTPArgument">
<boolProp name="HTTPArgument.always_encode">false</boolProp>
<stringProp name="Argument.value">default_agent_uid</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
<boolProp name="HTTPArgument.use_equals">true</boolProp>
<stringProp name="Argument.name">sid</stringProp>
</elementProp>
<elementProp name="uid" elementType="HTTPArgument">
<boolProp name="HTTPArgument.always_encode">false</boolProp>
<stringProp name="Argument.value">1395890719817857</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
<boolProp name="HTTPArgument.use_equals">true</boolProp>
<stringProp name="Argument.name">uid</stringProp>
</elementProp>
<elementProp name="nickname" elementType="HTTPArgument">
<boolProp name="HTTPArgument.always_encode">false</boolProp>
<stringProp name="Argument.value">LOCAL9686</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
<boolProp name="HTTPArgument.use_equals">true</boolProp>
<stringProp name="Argument.name">nickname</stringProp>
</elementProp>
<elementProp name="avatar" elementType="HTTPArgument">
<boolProp name="HTTPArgument.always_encode">false</boolProp>
<stringProp name="Argument.value">https://chainsnow.oss-cn-shenzhen.aliyuncs.com/avatars/visitor_default_avatar.png</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
<boolProp name="HTTPArgument.use_equals">true</boolProp>
<stringProp name="Argument.name">avatar</stringProp>
</elementProp>
</collectionProp>
</elementProp>
</HTTPSamplerProxy>
<hashTree/>
<ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="查看结果树" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>true</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<sentBytes>true</sentBytes>
<url>true</url>
<threadCounts>true</threadCounts>
<idleTime>true</idleTime>
<connectTime>true</connectTime>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="汇总报告" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>true</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<sentBytes>true</sentBytes>
<url>true</url>
<threadCounts>true</threadCounts>
<idleTime>true</idleTime>
<connectTime>true</connectTime>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="StatVisualizer" testclass="ResultCollector" testname="聚合报告" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>true</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<sentBytes>true</sentBytes>
<url>true</url>
<threadCounts>true</threadCounts>
<idleTime>true</idleTime>
<connectTime>true</connectTime>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultSaver guiclass="ResultSaverGui" testclass="ResultSaver" testname="保存响应到文件" enabled="true">
<stringProp name="FileSaver.filename"></stringProp>
<boolProp name="FileSaver.errorsonly">false</boolProp>
<boolProp name="FileSaver.successonly">false</boolProp>
<boolProp name="FileSaver.skipsuffix">false</boolProp>
<boolProp name="FileSaver.skipautonumber">false</boolProp>
</ResultSaver>
<hashTree/>
<ResultCollector guiclass="RespTimeGraphVisualizer" testclass="ResultCollector" testname="响应时间图" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>true</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<sentBytes>true</sentBytes>
<url>true</url>
<threadCounts>true</threadCounts>
<idleTime>true</idleTime>
<connectTime>true</connectTime>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="StatGraphVisualizer" testclass="ResultCollector" testname="汇总图" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>true</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<sentBytes>true</sentBytes>
<url>true</url>
<threadCounts>true</threadCounts>
<idleTime>true</idleTime>
<connectTime>true</connectTime>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<Summariser guiclass="SummariserGui" testclass="Summariser" testname="生成概要结果" enabled="true"/>
<hashTree/>
<ResultCollector guiclass="TableVisualizer" testclass="ResultCollector" testname="用表格查看结果" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>true</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<sentBytes>true</sentBytes>
<url>true</url>
<threadCounts>true</threadCounts>
<idleTime>true</idleTime>
<connectTime>true</connectTime>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
</hashTree>
</hashTree>
</hashTree>
</jmeterTestPlan>

View File

@@ -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,
;
// 根据字符串查找对应的枚举常量

View File

@@ -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.

View File

@@ -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;

View File

@@ -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> 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<VisitorRequest> requestEntity = new HttpEntity<>(initRequest, headers);
// 然后再进行实际的测试请求
ResponseEntity<VisitorResponse> 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<String> 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<VisitorResponse> 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<VisitorRequest> requestEntity = new HttpEntity<>(initRequest, headers);
ResponseEntity<VisitorResponse> 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<String, String> params = new LinkedMultiValueMap<>();
params.add("type", TYPE); // Missing orgUid and sid
ResponseEntity<VisitorResponse> 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> 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<VisitorRequest> requestEntity = new HttpEntity<>(initRequest, headers);
ResponseEntity<VisitorResponse> 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<String> 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");
}
}
}