18 changed files with 26 additions and 965 deletions
@ -1,301 +0,0 @@ |
|||
//package com.zdxt.rest.test;
|
|||
//
|
|||
//import cn.dev33.satoken.context.mock.SaTokenContextMockUtil;
|
|||
//import org.dromara.ZdxtAdminApplication;
|
|||
//import org.junit.jupiter.api.*;
|
|||
//import org.springframework.beans.factory.annotation.Autowired;
|
|||
//import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
|||
//import org.springframework.boot.test.context.SpringBootTest;
|
|||
//import org.springframework.http.MediaType;
|
|||
//import org.springframework.test.web.servlet.MockMvc;
|
|||
//import org.springframework.test.web.servlet.MvcResult;
|
|||
//
|
|||
//import java.nio.charset.StandardCharsets;
|
|||
//
|
|||
//import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
|||
//import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
|
|||
//import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
|||
//
|
|||
///**
|
|||
// * AppEnterpriseLoginController 企业端-用户登录接口测试
|
|||
// * <p>
|
|||
// * 覆盖以下接口:
|
|||
// * 1. POST /app-ent/login/siqLogin - 深i企用户登录
|
|||
// * </p>
|
|||
// * <p>
|
|||
// * 注意:此测试需要配置真实的深i企接口地址,或在测试环境中 Mock 相关服务
|
|||
// * </p>
|
|||
// *
|
|||
// * @author zdxt
|
|||
// */
|
|||
//@SpringBootTest(classes = ZdxtAdminApplication.class)
|
|||
//@AutoConfigureMockMvc
|
|||
//@DisplayName("AppEnterpriseLoginController 企业端-用户登录接口测试")
|
|||
//@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
|||
//public class AppEnterpriseLoginControllerTest {
|
|||
//
|
|||
// @Autowired
|
|||
// private MockMvc mockMvc;
|
|||
//
|
|||
// private static final String BASE_URL = "/app-ent/login";
|
|||
// private static final String TEST_CLIENT_ID = "e5cd7e4891bf95d1d19206ce24a7b32e";
|
|||
//
|
|||
// @BeforeEach
|
|||
// public void setUp() {
|
|||
// SaTokenContextMockUtil.setMockContext();
|
|||
// }
|
|||
//
|
|||
// @AfterEach
|
|||
// public void tearDown() {
|
|||
// SaTokenContextMockUtil.clearContext();
|
|||
// }
|
|||
//
|
|||
// // ==================== siqLogin 接口测试 ====================
|
|||
//
|
|||
// @DisplayName("深i企登录 - 正常请求(需要有效的授权码)")
|
|||
// @Test
|
|||
// @Order(1)
|
|||
// public void testSiqLoginSuccess() throws Exception {
|
|||
// String requestBody = "{\"code\":\"test_authorization_code\"}";
|
|||
//
|
|||
// MvcResult result = mockMvc.perform(post(BASE_URL + "/siqLogin")
|
|||
// .contentType(MediaType.APPLICATION_JSON)
|
|||
// .content(requestBody))
|
|||
// .andDo(print())
|
|||
// .andExpect(status().isOk())
|
|||
// .andReturn();
|
|||
//
|
|||
// String responseBody = result.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
|||
// System.out.println("深i企登录接口响应: " + responseBody);
|
|||
//
|
|||
// if (responseBody.contains("\"code\":200")) {
|
|||
// Assertions.assertTrue(responseBody.contains("token"), "返回数据应包含 token");
|
|||
// Assertions.assertTrue(responseBody.contains("userId"), "返回数据应包含 userId");
|
|||
// Assertions.assertTrue(responseBody.contains("userName"), "返回数据应包含 userName");
|
|||
// Assertions.assertTrue(responseBody.contains("enterpriseId"), "返回数据应包含 enterpriseId");
|
|||
// Assertions.assertTrue(responseBody.contains("enterpriseName"), "返回数据应包含 enterpriseName");
|
|||
// System.out.println("深i企登录成功,返回了完整的用户和企业信息");
|
|||
// } else {
|
|||
// System.out.println("深i企登录失败(可能由于授权码无效或深i企接口未配置): " + responseBody);
|
|||
// }
|
|||
// }
|
|||
//
|
|||
// @DisplayName("深i企登录 - 缺少授权码参数应返回失败")
|
|||
// @Test
|
|||
// @Order(2)
|
|||
// public void testSiqLoginMissingCode() throws Exception {
|
|||
// String requestBody = "{}";
|
|||
//
|
|||
// mockMvc.perform(post(BASE_URL + "/siqLogin")
|
|||
// .contentType(MediaType.APPLICATION_JSON)
|
|||
// .content(requestBody))
|
|||
// .andDo(print())
|
|||
// .andExpect(status().isOk())
|
|||
// .andExpect(jsonPath("$.code").value(500));
|
|||
//
|
|||
// System.out.println("缺少授权码参数返回失败测试成功");
|
|||
// }
|
|||
//
|
|||
// @DisplayName("深i企登录 - 空授权码应返回失败")
|
|||
// @Test
|
|||
// @Order(3)
|
|||
// public void testSiqLoginEmptyCode() throws Exception {
|
|||
// String requestBody = "{\"code\":\"\"}";
|
|||
//
|
|||
// mockMvc.perform(post(BASE_URL + "/siqLogin")
|
|||
// .contentType(MediaType.APPLICATION_JSON)
|
|||
// .content(requestBody))
|
|||
// .andDo(print())
|
|||
// .andExpect(status().isOk())
|
|||
// .andExpect(jsonPath("$.code").value(500));
|
|||
//
|
|||
// System.out.println("空授权码返回失败测试成功");
|
|||
// }
|
|||
//
|
|||
// @DisplayName("深i企登录 - 无效授权码应返回失败")
|
|||
// @Test
|
|||
// @Order(4)
|
|||
// public void testSiqLoginInvalidCode() throws Exception {
|
|||
// String requestBody = "{\"code\":\"invalid_code_12345\"}";
|
|||
//
|
|||
// MvcResult result = mockMvc.perform(post(BASE_URL + "/siqLogin")
|
|||
// .contentType(MediaType.APPLICATION_JSON)
|
|||
// .content(requestBody))
|
|||
// .andDo(print())
|
|||
// .andExpect(status().isOk())
|
|||
// .andReturn();
|
|||
//
|
|||
// String responseBody = result.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
|||
//
|
|||
// if (responseBody.contains("\"code\":500")) {
|
|||
// System.out.println("无效授权码返回失败测试成功");
|
|||
// } else {
|
|||
// System.out.println("注意:无效授权码未返回预期错误,响应: " + responseBody);
|
|||
// }
|
|||
// }
|
|||
//
|
|||
// @DisplayName("深i企登录 - 验证返回数据结构完整性")
|
|||
// @Test
|
|||
// @Order(5)
|
|||
// public void testSiqLoginResponseStructure() throws Exception {
|
|||
// String requestBody = "{\"code\":\"test_code\"}";
|
|||
//
|
|||
// MvcResult result = mockMvc.perform(post(BASE_URL + "/siqLogin")
|
|||
// .contentType(MediaType.APPLICATION_JSON)
|
|||
// .content(requestBody))
|
|||
// .andDo(print())
|
|||
// .andExpect(status().isOk())
|
|||
// .andReturn();
|
|||
//
|
|||
// String responseBody = result.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
|||
// System.out.println("验证返回数据结构响应: " + responseBody);
|
|||
//
|
|||
// if (responseBody.contains("\"code\":200")) {
|
|||
// Assertions.assertTrue(responseBody.contains("\"data\""), "返回数据应包含 data 字段");
|
|||
//
|
|||
// String data = extractDataJson(responseBody);
|
|||
// if (data != null) {
|
|||
// Assertions.assertTrue(data.contains("token"), "data 中应包含 token");
|
|||
// Assertions.assertTrue(data.contains("userId"), "data 中应包含 userId");
|
|||
// Assertions.assertTrue(data.contains("userName"), "data 中应包含 userName");
|
|||
// Assertions.assertTrue(data.contains("loginName"), "data 中应包含 loginName");
|
|||
// Assertions.assertTrue(data.contains("phonenumber"), "data 中应包含 phonenumber");
|
|||
// Assertions.assertTrue(data.contains("enterpriseId"), "data 中应包含 enterpriseId");
|
|||
// Assertions.assertTrue(data.contains("enterpriseName"), "data 中应包含 enterpriseName");
|
|||
// Assertions.assertTrue(data.contains("enterpriseNumber"), "data 中应包含 enterpriseNumber");
|
|||
// System.out.println("返回数据结构完整,包含所有必需字段");
|
|||
// }
|
|||
// } else {
|
|||
// System.out.println("登录失败,无法验证数据结构");
|
|||
// }
|
|||
// }
|
|||
//
|
|||
// @DisplayName("深i企登录 - 重复登录应能正常处理(同一授权码多次调用)")
|
|||
// @Test
|
|||
// @Order(6)
|
|||
// public void testSiqLoginDuplicateCall() throws Exception {
|
|||
// String requestBody = "{\"code\":\"test_code\"}";
|
|||
//
|
|||
// for (int i = 1; i <= 3; i++) {
|
|||
// System.out.println("========== 第 " + i + " 次调用深i企登录 ==========");
|
|||
//
|
|||
// MvcResult result = mockMvc.perform(post(BASE_URL + "/siqLogin")
|
|||
// .contentType(MediaType.APPLICATION_JSON)
|
|||
// .content(requestBody))
|
|||
// .andDo(print())
|
|||
// .andExpect(status().isOk())
|
|||
// .andReturn();
|
|||
//
|
|||
// String responseBody = result.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
|||
// System.out.println("第 " + i + " 次调用响应: " + responseBody);
|
|||
//
|
|||
// Thread.sleep(1000);
|
|||
// }
|
|||
//
|
|||
// System.out.println("========== 重复登录测试完成 ==========");
|
|||
// }
|
|||
//
|
|||
// @DisplayName("深i企登录 - 验证 Token 格式")
|
|||
// @Test
|
|||
// @Order(7)
|
|||
// public void testSiqLoginTokenFormat() throws Exception {
|
|||
// String requestBody = "{\"code\":\"test_code\"}";
|
|||
//
|
|||
// MvcResult result = mockMvc.perform(post(BASE_URL + "/siqLogin")
|
|||
// .contentType(MediaType.APPLICATION_JSON)
|
|||
// .content(requestBody))
|
|||
// .andDo(print())
|
|||
// .andExpect(status().isOk())
|
|||
// .andReturn();
|
|||
//
|
|||
// String responseBody = result.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
|||
//
|
|||
// if (responseBody.contains("\"code\":200")) {
|
|||
// String token = extractTokenFromResponse(responseBody);
|
|||
// if (token != null && !token.isEmpty()) {
|
|||
// Assertions.assertTrue(token.length() > 10, "Token 长度应大于10个字符");
|
|||
// System.out.println("Token 格式验证通过,Token: " + token);
|
|||
// } else {
|
|||
// System.out.println("未能提取到 Token");
|
|||
// }
|
|||
// } else {
|
|||
// System.out.println("登录失败,无法验证 Token 格式");
|
|||
// }
|
|||
// }
|
|||
//
|
|||
// @DisplayName("深i企登录 - 验证企业信息关联")
|
|||
// @Test
|
|||
// @Order(8)
|
|||
// public void testSiqLoginEnterpriseAssociation() throws Exception {
|
|||
// String requestBody = "{\"code\":\"test_code\"}";
|
|||
//
|
|||
// MvcResult result = mockMvc.perform(post(BASE_URL + "/siqLogin")
|
|||
// .contentType(MediaType.APPLICATION_JSON)
|
|||
// .content(requestBody))
|
|||
// .andDo(print())
|
|||
// .andExpect(status().isOk())
|
|||
// .andReturn();
|
|||
//
|
|||
// String responseBody = result.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
|||
//
|
|||
// if (responseBody.contains("\"code\":200")) {
|
|||
// String data = extractDataJson(responseBody);
|
|||
// if (data != null) {
|
|||
// String enterpriseId = extractJsonValue(data, "enterpriseId");
|
|||
// String enterpriseName = extractJsonValue(data, "enterpriseName");
|
|||
// String enterpriseNumber = extractJsonValue(data, "enterpriseNumber");
|
|||
//
|
|||
// if (enterpriseId != null && enterpriseName != null && enterpriseNumber != null) {
|
|||
// Assertions.assertFalse(enterpriseId.isEmpty(), "企业ID不应为空");
|
|||
// Assertions.assertFalse(enterpriseName.isEmpty(), "企业名称不应为空");
|
|||
// Assertions.assertFalse(enterpriseNumber.isEmpty(), "企业统一信用代码不应为空");
|
|||
// System.out.println("企业信息关联验证通过");
|
|||
// System.out.println("企业ID: " + enterpriseId);
|
|||
// System.out.println("企业名称: " + enterpriseName);
|
|||
// System.out.println("企业统一信用代码: " + enterpriseNumber);
|
|||
// }
|
|||
// }
|
|||
// } else {
|
|||
// System.out.println("登录失败,无法验证企业信息关联");
|
|||
// }
|
|||
// }
|
|||
//
|
|||
// // ==================== 工具方法 ====================
|
|||
//
|
|||
// /**
|
|||
// * 从 JSON 响应中提取 data 字段
|
|||
// */
|
|||
// private String extractDataJson(String responseBody) {
|
|||
// if (responseBody != null && responseBody.contains("\"data\":{")) {
|
|||
// int start = responseBody.indexOf("\"data\":{") + 7;
|
|||
// int end = responseBody.lastIndexOf("}");
|
|||
// if (start > 0 && end > start) {
|
|||
// return responseBody.substring(start, end + 1);
|
|||
// }
|
|||
// }
|
|||
// return null;
|
|||
// }
|
|||
//
|
|||
// /**
|
|||
// * 从响应中提取 Token
|
|||
// */
|
|||
// private String extractTokenFromResponse(String responseBody) {
|
|||
// return extractJsonValue(responseBody, "token");
|
|||
// }
|
|||
//
|
|||
// /**
|
|||
// * 从 JSON 字符串中提取指定字段的值
|
|||
// */
|
|||
// private String extractJsonValue(String json, String key) {
|
|||
// if (json != null && json.contains("\"" + key + "\"")) {
|
|||
// int start = json.indexOf("\"" + key + "\":\"") + key.length() + 4;
|
|||
// int end = json.indexOf("\"", start);
|
|||
// if (start > 0 && end > start) {
|
|||
// return json.substring(start, end);
|
|||
// }
|
|||
// }
|
|||
// return null;
|
|||
// }
|
|||
//}
|
|||
//{
|
|||
//}
|
|||
@ -1,329 +0,0 @@ |
|||
package com.zdxt.rest.test.cp; |
|||
|
|||
import cn.dev33.satoken.context.mock.SaTokenContextMockUtil; |
|||
import cn.dev33.satoken.stp.StpUtil; |
|||
import cn.dev33.satoken.stp.parameter.SaLoginParameter; |
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import com.fasterxml.jackson.databind.ObjectMapper; |
|||
import com.zdxt.enforcementcode.domain.bo.EnterpriseInformationBo; |
|||
import com.zdxt.enforcementcode.domain.vo.EnterpriseInformationVo; |
|||
import com.zdxt.enforcementcode.service.IEnterpriseInformationService; |
|||
import org.dromara.ZdxtAdminApplication; |
|||
import org.dromara.common.core.domain.model.LoginUser; |
|||
import org.dromara.common.satoken.utils.LoginHelper; |
|||
import org.junit.jupiter.api.*; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; |
|||
import org.springframework.boot.test.context.SpringBootTest; |
|||
import org.springframework.http.MediaType; |
|||
import org.springframework.mock.web.MockHttpServletRequest; |
|||
import org.springframework.test.context.ActiveProfiles; |
|||
import org.springframework.test.web.servlet.MockMvc; |
|||
import org.springframework.test.web.servlet.MvcResult; |
|||
import org.springframework.web.context.request.RequestContextHolder; |
|||
import org.springframework.web.context.request.ServletRequestAttributes; |
|||
|
|||
import javax.crypto.Cipher; |
|||
import javax.crypto.spec.IvParameterSpec; |
|||
import javax.crypto.spec.SecretKeySpec; |
|||
import java.nio.charset.StandardCharsets; |
|||
import java.text.SimpleDateFormat; |
|||
import java.util.*; |
|||
|
|||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; |
|||
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; |
|||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; |
|||
|
|||
/** |
|||
* AppEnfCpPlanController 新增计划批量测试 |
|||
* <p> |
|||
* 为多个用户批量创建执法计划(每人100条) |
|||
* </p> |
|||
*/ |
|||
@SpringBootTest(classes = ZdxtAdminApplication.class) |
|||
@AutoConfigureMockMvc |
|||
@ActiveProfiles({"dev", "dev-cust-zrb"}) |
|||
@DisplayName("AppEnfCpPlanController 批量新增计划测试") |
|||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) |
|||
public class AppEnfCpPlanControllerTest { |
|||
|
|||
@Autowired |
|||
private MockMvc mockMvc; |
|||
|
|||
@Autowired |
|||
private ObjectMapper objectMapper; |
|||
|
|||
@Autowired |
|||
private IEnterpriseInformationService enterpriseInformationService; |
|||
|
|||
private static final String BASE_URL = "/app-enf/cpPlan"; |
|||
private static final String LOGIN_URL = "/app-enf/login/do"; |
|||
private static final String AES_KEY = "1234567898745621"; |
|||
private static final String CLIENT_ID = "f0535c2a32ab4d0496ab9a699b2a7d36"; |
|||
private static final String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"; |
|||
|
|||
/** 通用密码 */ |
|||
private static final String PASSWORD = "szsf@zfjd"; |
|||
|
|||
@BeforeEach |
|||
public void setUp() { |
|||
// 初始化 Sa-Token 上下文
|
|||
SaTokenContextMockUtil.setMockContext(); |
|||
MockHttpServletRequest mockRequest = new MockHttpServletRequest(); |
|||
mockRequest.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"); |
|||
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(mockRequest)); |
|||
} |
|||
|
|||
@AfterEach |
|||
public void tearDown() { |
|||
try { |
|||
StpUtil.logout(); |
|||
} catch (Exception ignored) { |
|||
} |
|||
RequestContextHolder.resetRequestAttributes(); |
|||
SaTokenContextMockUtil.clearContext(); |
|||
} |
|||
|
|||
/** |
|||
* 登录指定账号,返回登录信息 |
|||
*/ |
|||
private Map<String, String> doLogin(String account) throws Exception { |
|||
String encryptedPassword = encryptByAes(PASSWORD); |
|||
Map<String, String> loginParams = new HashMap<>(); |
|||
loginParams.put("secretName", account); |
|||
loginParams.put("secretKey", encryptedPassword); |
|||
|
|||
MvcResult loginResult = mockMvc.perform(post(LOGIN_URL) |
|||
.header("User-Agent", USER_AGENT) |
|||
.contentType(MediaType.APPLICATION_JSON) |
|||
.content(objectMapper.writeValueAsString(loginParams))) |
|||
.andExpect(status().isOk()) |
|||
.andExpect(jsonPath("$.code").value(200)) |
|||
.andReturn(); |
|||
|
|||
String loginBody = loginResult.getResponse().getContentAsString(StandardCharsets.UTF_8); |
|||
JsonNode loginJson = objectMapper.readTree(loginBody); |
|||
JsonNode data = loginJson.get("data"); |
|||
|
|||
Map<String, String> info = new HashMap<>(); |
|||
info.put("token", data.get("token").asText()); |
|||
info.put("userId", data.get("userId").asText()); |
|||
// nickName 可能为空,回退到 userName(中文姓名)
|
|||
String nickName = data.has("nickName") ? data.get("nickName").asText() : ""; |
|||
if (nickName == null || nickName.isBlank()) { |
|||
nickName = data.has("userName") ? data.get("userName").asText() : account; |
|||
} |
|||
info.put("nickName", nickName); |
|||
info.put("deptId", data.get("deptId").asText()); |
|||
info.put("deptName", data.get("deptName").asText()); |
|||
info.put("organId", data.get("organId").asText()); |
|||
info.put("organName", data.get("organName").asText()); |
|||
info.put("bureauUnitId", data.get("bureauUnitId").asText()); |
|||
info.put("bureauUnitName", data.get("bureauUnitName").asText()); |
|||
info.put("phonenumber", data.has("phonenumber") ? data.get("phonenumber").asText() : ""); |
|||
|
|||
System.out.println("[" + account + "] 登录成功: userId=" + info.get("userId")); |
|||
return info; |
|||
} |
|||
|
|||
// ==================== 各账号批量新增测试 ====================
|
|||
|
|||
@DisplayName("liuqianlin(刘倩琳)批量新增100条执法计划") |
|||
@Test |
|||
@Order(1) |
|||
public void testBatchCreate_liuqianlin() throws Exception { |
|||
batchCreatePlans("liuqianlin", 100); |
|||
} |
|||
|
|||
@DisplayName("baining(白宁)批量新增100条执法计划") |
|||
@Test |
|||
@Order(2) |
|||
public void testBatchCreate_baining() throws Exception { |
|||
batchCreatePlans("baining", 100); |
|||
} |
|||
|
|||
@DisplayName("caizifan(蔡梓帆)批量新增100条执法计划") |
|||
@Test |
|||
@Order(3) |
|||
public void testBatchCreate_caizifan() throws Exception { |
|||
batchCreatePlans("caizifan", 100); |
|||
} |
|||
|
|||
@DisplayName("chenchong4(陈冲)批量新增100条执法计划") |
|||
@Test |
|||
@Order(4) |
|||
public void testBatchCreate_chenchong4() throws Exception { |
|||
batchCreatePlans("chenchong4", 100); |
|||
} |
|||
|
|||
/** |
|||
* 为指定账号批量新增计划 |
|||
* <p> |
|||
* 唯一性约束:同一人 + 日期 + 时间段 + 企业 只能有一条计划。 |
|||
* 日期循环31天(7月1~31日),时间段2个(上午/下午),企业循环7家, |
|||
* 因 31、2、7 两两互素,由中国剩余定理(CRT)保证前 31×2×7=434 条组合均唯一, |
|||
* 故 count≤434 时所有计划不会重复。 |
|||
* </p> |
|||
*/ |
|||
private void batchCreatePlans(String account, int count) throws Exception { |
|||
Map<String, String> loginInfo = doLogin(account); |
|||
String token = loginInfo.get("token"); |
|||
String userId = loginInfo.get("userId"); |
|||
String nickName = loginInfo.get("nickName"); |
|||
|
|||
// 从数据库加载指定企业列表
|
|||
List<EnterpriseInformationVo> enterprises = loadEnterprises(); |
|||
Assertions.assertFalse(enterprises.isEmpty(), "数据库中无可用企业数据"); |
|||
|
|||
// --- 唯一性预测验证 ---
|
|||
int days = 31; // 7月有31天
|
|||
int timeSlots = 2; // 上午/下午
|
|||
int entCount = enterprises.size(); |
|||
// 由CRT保证的最大不重复组合数 = lcm(days, timeSlots, entCount) 当两两互素时 = days * timeSlots * entCount
|
|||
int maxUnique = days * timeSlots * entCount; |
|||
int expectedSuccess = Math.min(count, maxUnique); |
|||
System.out.println("[" + account + "] 企业数=" + entCount |
|||
+ ", 可用唯一组合(日期×时段×企业)=" + maxUnique |
|||
+ ", 计划生成数=" + count |
|||
+ ", 预计成功数=" + expectedSuccess); |
|||
Assertions.assertTrue(count <= maxUnique, |
|||
"计划数(" + count + ")超过最大唯一组合数(" + maxUnique + "),必然产生重复"); |
|||
|
|||
Random random = new Random(); |
|||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); |
|||
Calendar cal = Calendar.getInstance(); |
|||
|
|||
int successCount = 0; |
|||
int failCount = 0; |
|||
|
|||
for (int i = 0; i < count; i++) { |
|||
// 所有计划日期限定在2026年7月内,循环使用7月1日~31日
|
|||
int dayOfMonth = (i % days) + 1; |
|||
cal.set(2026, Calendar.JULY, dayOfMonth); |
|||
String planDate = sdf.format(cal.getTime()); |
|||
long planTime = (i % 2 == 0) ? 1L : 2L; // 交替上午/下午
|
|||
|
|||
// 确定性循环选取企业,保证 (日期, 时段, 企业) 三元组唯一
|
|||
EnterpriseInformationVo enterprise = enterprises.get(i % entCount); |
|||
Map<String, Object> planBo = buildPlanBo(planDate, planTime, i, nickName, userId, loginInfo, enterprise, random); |
|||
String requestBody = objectMapper.writeValueAsString(planBo); |
|||
|
|||
MvcResult result = mockMvc.perform(post(BASE_URL) |
|||
.header("Authorization", "Bearer " + token) |
|||
.header("clientid", CLIENT_ID) |
|||
.header("User-Agent", USER_AGENT) |
|||
.contentType(MediaType.APPLICATION_JSON) |
|||
.content(requestBody)) |
|||
.andReturn(); |
|||
|
|||
String responseBody = result.getResponse().getContentAsString(StandardCharsets.UTF_8); |
|||
JsonNode respJson = objectMapper.readTree(responseBody); |
|||
int code = respJson.get("code").asInt(); |
|||
|
|||
if (code == 200) { |
|||
successCount++; |
|||
} else { |
|||
failCount++; |
|||
System.out.println("[" + account + "] 第" + (i + 1) + "条失败: " + responseBody); |
|||
} |
|||
|
|||
if ((i + 1) % 10 == 0) { |
|||
System.out.println("[" + account + "] 已处理 " + (i + 1) + "/" + count |
|||
+ ", 成功=" + successCount + ", 失败=" + failCount); |
|||
} |
|||
} |
|||
|
|||
System.out.println("========== [" + account + "] 批量新增完成 =========="); |
|||
System.out.println("总计: " + count + ", 成功: " + successCount + ", 失败: " + failCount); |
|||
Assertions.assertEquals(expectedSuccess, successCount, |
|||
"[" + account + "] 预期成功" + expectedSuccess + "条,实际成功" + successCount + "条"); |
|||
} |
|||
|
|||
/** 指定的企业统一社会信用代码列表 */ |
|||
private static final String[][] ENTERPRISE_DATA = { |
|||
{"吉田拉链(深圳)有限公司公明工厂", "91440300788302281W"}, |
|||
{"欧姆龙电子部件(深圳)有限公司", "914403007261811621"}, |
|||
{"深圳农牧美益肉业有限公司", "91440300662678582M"}, |
|||
{"深圳市深水龙岗污水处理有限公司", "914403006820066603"}, |
|||
{"深圳市强达电路股份有限公司", "91440300763461366N"}, |
|||
{"深圳康泰生物制品股份有限公司", "91440300618837873J"}, |
|||
{"深圳市里程食品有限公司", "91440300738848091F"}, |
|||
}; |
|||
|
|||
/** |
|||
* 从数据库加载指定的7家企业 |
|||
*/ |
|||
private List<EnterpriseInformationVo> loadEnterprises() { |
|||
List<EnterpriseInformationVo> result = new ArrayList<>(); |
|||
for (String[] entry : ENTERPRISE_DATA) { |
|||
EnterpriseInformationBo queryBo = new EnterpriseInformationBo(); |
|||
queryBo.setEnterpriseNumber(entry[1]); |
|||
queryBo.setIsDelete(0L); |
|||
List<EnterpriseInformationVo> list = enterpriseInformationService.queryList(queryBo); |
|||
if (!list.isEmpty()) { |
|||
result.add(list.get(0)); |
|||
} else { |
|||
System.out.println("[警告] 未找到企业: " + entry[0] + " (" + entry[1] + ")"); |
|||
} |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
/** |
|||
* 构建计划BO的Map |
|||
*/ |
|||
private Map<String, Object> buildPlanBo(String planDate, long planTime, int index, |
|||
String userName, String userId, Map<String, String> loginInfo, |
|||
EnterpriseInformationVo enterprise, Random random) { |
|||
Map<String, Object> bo = new LinkedHashMap<>(); |
|||
bo.put("planType", 1L); // 日常计划
|
|||
bo.put("planDate", planDate); |
|||
bo.put("planTime", planTime); |
|||
bo.put("enforceContent", "批量测试执法事项-第" + (index + 1) + "条"); |
|||
bo.put("enterpriseName", enterprise.getEnterpriseName()); |
|||
bo.put("enterpriseNumber", enterprise.getEnterpriseNumber()); |
|||
bo.put("enterpriseId", enterprise.getId()); |
|||
bo.put("enforceUserNames", userName); |
|||
bo.put("enforceUserIds", userId); |
|||
bo.put("enforceUserTels", loginInfo.get("phonenumber")); |
|||
bo.put("enforceUserCodes", "-"); |
|||
bo.put("isPublic", random.nextInt(2) == 0 ? 0L : 1L); // 随机公开/不公开
|
|||
bo.put("isUnion", 1L); // 必须为联合执法,否则afterInsert会直接生成任务导致status变为3
|
|||
bo.put("reserveStatus", 1L); // 待预约
|
|||
bo.put("systemReserved", 0L); |
|||
bo.put("manualReserved", 0L); |
|||
bo.put("bureauDeptId", loginInfo.get("bureauUnitId")); |
|||
bo.put("bureauDeptName", loginInfo.get("bureauUnitName")); |
|||
bo.put("organId", loginInfo.get("organId")); |
|||
bo.put("organName", loginInfo.get("organName")); |
|||
bo.put("deptId", loginInfo.get("deptId")); |
|||
bo.put("deptName", loginInfo.get("deptName")); |
|||
bo.put("isDelete", 0L); |
|||
return bo; |
|||
} |
|||
|
|||
/** |
|||
* AES/CBC/ZeroPadding 加密(与前端 CryptoJS 对应) |
|||
*/ |
|||
private String encryptByAes(String plainText) throws Exception { |
|||
byte[] keyBytes = AES_KEY.getBytes(StandardCharsets.UTF_8); |
|||
byte[] ivBytes = AES_KEY.getBytes(StandardCharsets.UTF_8); |
|||
|
|||
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES"); |
|||
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes); |
|||
|
|||
// NoPadding 需要手动补零到16字节倍数
|
|||
byte[] plainBytes = plainText.getBytes(StandardCharsets.UTF_8); |
|||
int blockSize = 16; |
|||
int paddedLen = ((plainBytes.length / blockSize) + 1) * blockSize; |
|||
byte[] padded = new byte[paddedLen]; |
|||
System.arraycopy(plainBytes, 0, padded, 0, plainBytes.length); |
|||
// 剩余字节默认为0(ZeroPadding)
|
|||
|
|||
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); |
|||
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); |
|||
byte[] encrypted = cipher.doFinal(padded); |
|||
|
|||
return Base64.getEncoder().encodeToString(encrypted); |
|||
} |
|||
} |
|||
@ -1,225 +0,0 @@ |
|||
package com.zdxt.service.test; |
|||
|
|||
import cn.hutool.crypto.digest.DigestUtil; |
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
|||
import com.zdxt.enforcementcode.domain.EnterpriseUser; |
|||
import com.zdxt.enforcementcode.mapper.EnterpriseUserMapper; |
|||
import org.dromara.ZdxtAdminApplication; |
|||
import org.dromara.system.domain.SysUser; |
|||
import org.dromara.system.mapper.SysUserMapper; |
|||
import org.junit.jupiter.api.DisplayName; |
|||
import org.junit.jupiter.api.Test; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; |
|||
import org.springframework.boot.test.context.SpringBootTest; |
|||
|
|||
import java.util.Arrays; |
|||
import java.util.HashSet; |
|||
import java.util.List; |
|||
|
|||
import cn.dev33.satoken.context.mock.SaTokenContextMockUtil; |
|||
import cn.dev33.satoken.stp.parameter.SaLoginParameter; |
|||
import cn.dev33.satoken.stp.StpUtil; |
|||
import org.dromara.common.core.domain.model.LoginUser; |
|||
import org.dromara.common.satoken.utils.LoginHelper; |
|||
import org.junit.jupiter.api.AfterEach; |
|||
import org.junit.jupiter.api.BeforeEach; |
|||
import org.springframework.mock.web.MockHttpServletRequest; |
|||
import org.springframework.test.context.ActiveProfiles; |
|||
import org.springframework.web.context.request.RequestContextHolder; |
|||
import org.springframework.web.context.request.ServletRequestAttributes; |
|||
|
|||
/** |
|||
* 批量重置 enterprise_user 表用户密码 |
|||
* <p> |
|||
* 密码加密规则: MD5(userName + password + salt) |
|||
* </p> |
|||
*/ |
|||
@SpringBootTest(classes = ZdxtAdminApplication.class) |
|||
@AutoConfigureMockMvc |
|||
@ActiveProfiles({"dev", "dev-cust-zrb"}) |
|||
@DisplayName("批量重置企业用户密码") |
|||
public class ResetUserPasswordTest { |
|||
|
|||
@Autowired |
|||
private EnterpriseUserMapper enterpriseUserMapper; |
|||
|
|||
@Autowired |
|||
private SysUserMapper sysUserMapper; |
|||
|
|||
/** 重置后的明文密码 */ |
|||
private static final String NEW_PASSWORD = "szsf@zfjd"; |
|||
//private static final String NEW_PASSWORD = "Szsf@123";
|
|||
|
|||
private static final String TEST_CLIENT_ID = "e5cd7e4891bf95d1d19206ce24a7b32e"; |
|||
|
|||
@BeforeEach |
|||
public void setUp() { |
|||
// 初始化 Sa-Token 上下文(非 Web 环境下 StpUtil.login 需要)
|
|||
SaTokenContextMockUtil.setMockContext(); |
|||
|
|||
// 设置模拟请求上下文(数据权限拦截器需要从 SaToken 上下文获取用户信息)
|
|||
MockHttpServletRequest mockRequest = new MockHttpServletRequest(); |
|||
mockRequest.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"); |
|||
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(mockRequest)); |
|||
|
|||
// 构造测试用登录用户
|
|||
LoginUser loginUser = new LoginUser(); |
|||
loginUser.setUserId(1L); |
|||
loginUser.setUserType("sys_user"); |
|||
loginUser.setTenantId("000000"); |
|||
loginUser.setUsername("test_admin"); |
|||
loginUser.setNickname("测试管理员"); |
|||
loginUser.setDeptId("103"); |
|||
loginUser.setDeptName("测试部门"); |
|||
loginUser.setRolePermission(new HashSet<>()); |
|||
loginUser.setMenuPermission(new HashSet<>()); |
|||
|
|||
// 模拟登录
|
|||
SaLoginParameter param = new SaLoginParameter(); |
|||
param.setExtra(LoginHelper.CLIENT_KEY, TEST_CLIENT_ID); |
|||
LoginHelper.login(loginUser, param); |
|||
} |
|||
|
|||
@AfterEach |
|||
public void tearDown() { |
|||
try { |
|||
StpUtil.logout(); |
|||
} catch (Exception ignored) { |
|||
} |
|||
RequestContextHolder.resetRequestAttributes(); |
|||
SaTokenContextMockUtil.clearContext(); |
|||
} |
|||
|
|||
@DisplayName("批量重置 enterprise_user 所有用户密码为 szsf@zfjd") |
|||
@Test |
|||
public void resetAllEnterpriseUserPassword() { |
|||
|
|||
/*-- 17608540150,weil45,"",15817307171,深圳农牧美益肉业有限公司,91440300662678582M,21 |
|||
-- 17608557492,DGD440881199506180622,"",15817381630,深圳市深水龙岗污水处理有限公司,914403006820066603,12 |
|||
-- 17608540121,smiledzb1982,"",13723454151,深圳康泰生物制品股份有限公司,91440300618837873J,10 |
|||
-- 17608594890,A7271888,"",13751661770,深圳市里程食品有限公司,91440300738848091F,9 |
|||
-- 17608565612,qintongzhen138,"",13823610579,欧姆龙电子部件(深圳)有限公司,914403007261811621,9 |
|||
-- 17608601734,XP073215,"",15012671807,深圳市强达电路股份有限公司,91440300763461366N,9 |
|||
-- 17608556724,33ef1970fd449676fa4bc197,"",13537602265,吉田拉链(深圳)有限公司公明工厂,91440300788302281W,8*/ |
|||
|
|||
// 1. 指定需要重置密码的用户ID列表
|
|||
List<String> userIds = Arrays.asList( |
|||
// TODO: 在此填入需要重置的用户ID
|
|||
"17608540150", "17608557492", "17608540121", "17608594890", "17608565612", "17608601734", "17608556724","2064275054386966530","2064274295779979265","17608629742" |
|||
); |
|||
|
|||
// 2. 根据ID列表查询企业用户
|
|||
List<EnterpriseUser> userList = enterpriseUserMapper.selectList( |
|||
new LambdaQueryWrapper<EnterpriseUser>() |
|||
.select(EnterpriseUser::getUserId, EnterpriseUser::getLoginName, EnterpriseUser::getUserName, EnterpriseUser::getSalt) |
|||
.in(EnterpriseUser::getUserId, userIds) |
|||
); |
|||
|
|||
System.out.println("查询到企业用户总数: " + userList.size()); |
|||
|
|||
int successCount = 0; |
|||
int skipCount = 0; |
|||
|
|||
for (EnterpriseUser user : userList) { |
|||
String loginName = user.getLoginName(); |
|||
String salt = user.getSalt(); |
|||
|
|||
if (loginName == null || loginName.isBlank()) { |
|||
System.out.println("跳过: userId=" + user.getUserId() + ", loginName为空"); |
|||
skipCount++; |
|||
continue; |
|||
} |
|||
if (salt == null || salt.isBlank()) { |
|||
System.out.println("跳过: userId=" + user.getUserId() + ", salt为空"); |
|||
skipCount++; |
|||
continue; |
|||
} |
|||
|
|||
// 3. 按规则生成新密码: MD5(loginName + newPassword + salt)
|
|||
String newMd5Password = DigestUtil.md5Hex(loginName + NEW_PASSWORD + salt); |
|||
|
|||
// 4. 更新密码
|
|||
int rows = enterpriseUserMapper.update(null, |
|||
new LambdaUpdateWrapper<EnterpriseUser>() |
|||
.eq(EnterpriseUser::getUserId, user.getUserId()) |
|||
.set(EnterpriseUser::getPassword, newMd5Password) |
|||
); |
|||
|
|||
if (rows > 0) { |
|||
successCount++; |
|||
} |
|||
} |
|||
|
|||
System.out.println("========== 重置完成 =========="); |
|||
System.out.println("成功: " + successCount + " 条"); |
|||
System.out.println("跳过: " + skipCount + " 条"); |
|||
System.out.println("新密码(明文): " + NEW_PASSWORD); |
|||
} |
|||
|
|||
|
|||
@DisplayName("批量重置 sys_user 指定用户密码为 szsf@zfjd") |
|||
@Test |
|||
public void resetSysUserPassword() { |
|||
// 1. 执法端的测试用户
|
|||
List<Long> userIds = Arrays.asList( |
|||
// TODO: 在此填入需要重置的用户ID
|
|||
7897L, 17608416858L,17608416876L, 17608416904L,17608416912L, 17608416926L,17608416927L, 17608416945L,17608417058L,17608642193L,17608502852L,17608515249L,17608497168L |
|||
); |
|||
|
|||
// 监督端的报表测试用户
|
|||
// userIds = Arrays.asList(
|
|||
// // TODO: 在此填入需要重置的用户ID
|
|||
// 17608417340L, 17608417451L,17608417716L, 17608614169L,17608614499L,7897L,17608634290L
|
|||
// );
|
|||
|
|||
// 2. 根据ID列表查询系统用户
|
|||
List<SysUser> userList = sysUserMapper.selectList( |
|||
new LambdaQueryWrapper<SysUser>() |
|||
.select(SysUser::getUserId, SysUser::getLoginName, SysUser::getSalt) |
|||
.in(SysUser::getUserId, userIds) |
|||
); |
|||
|
|||
System.out.println("查询到系统用户总数: " + userList.size()); |
|||
|
|||
int successCount = 0; |
|||
int skipCount = 0; |
|||
|
|||
for (SysUser user : userList) { |
|||
String loginName = user.getLoginName(); |
|||
String salt = user.getSalt(); |
|||
|
|||
if (loginName == null || loginName.isBlank()) { |
|||
System.out.println("跳过: userId=" + user.getUserId() + ", loginName为空"); |
|||
skipCount++; |
|||
continue; |
|||
} |
|||
if (salt == null || salt.isBlank()) { |
|||
System.out.println("跳过: userId=" + user.getUserId() + ", salt为空"); |
|||
skipCount++; |
|||
continue; |
|||
} |
|||
|
|||
// 3. 按规则生成新密码: MD5( + newPassword + salt)
|
|||
String newMd5Password = DigestUtil.md5Hex(loginName + NEW_PASSWORD + salt); |
|||
|
|||
// 4. 更新密码
|
|||
int rows = sysUserMapper.update(null, |
|||
new LambdaUpdateWrapper<SysUser>() |
|||
.eq(SysUser::getUserId, user.getUserId()) |
|||
.set(SysUser::getPassword, newMd5Password) |
|||
); |
|||
|
|||
if (rows > 0) { |
|||
successCount++; |
|||
} |
|||
} |
|||
|
|||
System.out.println("========== sys_user 重置完成 =========="); |
|||
System.out.println("成功: " + successCount + " 条"); |
|||
System.out.println("跳过: " + skipCount + " 条"); |
|||
System.out.println("新密码(明文): " + NEW_PASSWORD); |
|||
} |
|||
|
|||
} |
|||
Loading…
Reference in new issue