|
@@ -0,0 +1,486 @@
|
|
|
|
|
+package com.etotem.num.controller;
|
|
|
|
|
+
|
|
|
|
|
+import com.etotem.num.common.Result;
|
|
|
|
|
+import com.etotem.num.config.JwtConfig;
|
|
|
|
|
+import com.etotem.num.entity.*;
|
|
|
|
|
+import com.etotem.num.repository.*;
|
|
|
|
|
+import com.etotem.num.service.ConfigService;
|
|
|
|
|
+import com.etotem.num.service.WithdrawService;
|
|
|
|
|
+import org.junit.jupiter.api.BeforeEach;
|
|
|
|
|
+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 org.springframework.boot.test.mock.mockito.MockBean;
|
|
|
|
|
+import org.springframework.http.MediaType;
|
|
|
|
|
+import org.springframework.test.web.servlet.MockMvc;
|
|
|
|
|
+
|
|
|
|
|
+import java.time.LocalDateTime;
|
|
|
|
|
+import java.util.*;
|
|
|
|
|
+
|
|
|
|
|
+import static org.hamcrest.Matchers.*;
|
|
|
|
|
+import static org.mockito.ArgumentMatchers.argThat;
|
|
|
|
|
+import static org.mockito.Mockito.*;
|
|
|
|
|
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
|
|
|
|
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
|
|
|
|
+
|
|
|
|
|
+@SpringBootTest
|
|
|
|
|
+@AutoConfigureMockMvc
|
|
|
|
|
+class AdminControllerApiTest {
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private MockMvc mockMvc;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private JwtConfig jwtConfig;
|
|
|
|
|
+
|
|
|
|
|
+ @MockBean
|
|
|
|
|
+ private UserRepository userRepository;
|
|
|
|
|
+
|
|
|
|
|
+ @MockBean
|
|
|
|
|
+ private OrderRepository orderRepository;
|
|
|
|
|
+
|
|
|
|
|
+ @MockBean
|
|
|
|
|
+ private ChartRecordRepository chartRecordRepository;
|
|
|
|
|
+
|
|
|
|
|
+ @MockBean
|
|
|
|
|
+ private CommissionRepository commissionRepository;
|
|
|
|
|
+
|
|
|
|
|
+ @MockBean
|
|
|
|
|
+ private WithdrawService withdrawService;
|
|
|
|
|
+
|
|
|
|
|
+ @MockBean
|
|
|
|
|
+ private ConfigService configService;
|
|
|
|
|
+
|
|
|
|
|
+ private String adminToken;
|
|
|
|
|
+ private String userToken;
|
|
|
|
|
+
|
|
|
|
|
+ @BeforeEach
|
|
|
|
|
+ void setUp() {
|
|
|
|
|
+ adminToken = jwtConfig.generate(0L, "admin");
|
|
|
|
|
+ userToken = jwtConfig.generate(100L, "user");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== POST /api/admin/login ====================
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testAdminLogin_success() throws Exception {
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/login")
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
|
|
+ .content("{\"username\":\"admin\",\"password\":\"admin123\"}"))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(0))
|
|
|
|
|
+ .andExpect(jsonPath("$.data.token").exists());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testAdminLogin_wrongPassword() throws Exception {
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/login")
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
|
|
+ .content("{\"username\":\"admin\",\"password\":\"wrong\"}"))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(1001))
|
|
|
|
|
+ .andExpect(jsonPath("$.message").value("Invalid admin credentials"));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testAdminLogin_wrongUsername() throws Exception {
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/login")
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
|
|
+ .content("{\"username\":\"hacker\",\"password\":\"admin123\"}"))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(1001))
|
|
|
|
|
+ .andExpect(jsonPath("$.message").value("Invalid admin credentials"));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== Auth Interceptor for Admin Endpoints ====================
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testAdminEndpoint_withoutToken_rejected() throws Exception {
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/users")
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(1001));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testAdminEndpoint_withUserToken_rejected() throws Exception {
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/users")
|
|
|
|
|
+ .header("Authorization", "Bearer " + userToken)
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(1001))
|
|
|
|
|
+ .andExpect(jsonPath("$.message").value("Admin access required"));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== POST /api/admin/users ====================
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testListUsers() throws Exception {
|
|
|
|
|
+ User u1 = new User();
|
|
|
|
|
+ u1.setId(1L);
|
|
|
|
|
+ u1.setNickname("用户A");
|
|
|
|
|
+ User u2 = new User();
|
|
|
|
|
+ u2.setId(2L);
|
|
|
|
|
+ u2.setNickname("用户B");
|
|
|
|
|
+ when(userRepository.findAll()).thenReturn(Arrays.asList(u1, u2));
|
|
|
|
|
+
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/users")
|
|
|
|
|
+ .header("Authorization", "Bearer " + adminToken)
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(0))
|
|
|
|
|
+ .andExpect(jsonPath("$.data.length()").value(2))
|
|
|
|
|
+ .andExpect(jsonPath("$.data[0].nickname").value("用户A"));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== POST /api/admin/user/upgrade ====================
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testUpgradeUserVip_success() throws Exception {
|
|
|
|
|
+ User user = new User();
|
|
|
|
|
+ user.setId(1L);
|
|
|
|
|
+ user.setVipEndTime(null);
|
|
|
|
|
+ when(userRepository.findById(1L)).thenReturn(Optional.of(user));
|
|
|
|
|
+ when(userRepository.save(any())).thenReturn(user);
|
|
|
|
|
+
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/user/upgrade")
|
|
|
|
|
+ .header("Authorization", "Bearer " + adminToken)
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
|
|
+ .content("{\"userId\":1}"))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(0));
|
|
|
|
|
+
|
|
|
|
|
+ verify(userRepository).save(argThat(u -> u.getVipEndTime() != null));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testUpgradeUserVip_notFound() throws Exception {
|
|
|
|
|
+ when(userRepository.findById(999L)).thenReturn(Optional.empty());
|
|
|
|
|
+
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/user/upgrade")
|
|
|
|
|
+ .header("Authorization", "Bearer " + adminToken)
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
|
|
+ .content("{\"userId\":999}"))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(1002))
|
|
|
|
|
+ .andExpect(jsonPath("$.message").value("User not found"));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== POST /api/admin/user/downgrade ====================
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testDowngradeUserVip_success() throws Exception {
|
|
|
|
|
+ User user = new User();
|
|
|
|
|
+ user.setId(1L);
|
|
|
|
|
+ user.setVipEndTime(LocalDateTime.now().plusDays(30));
|
|
|
|
|
+ when(userRepository.findById(1L)).thenReturn(Optional.of(user));
|
|
|
|
|
+ when(userRepository.save(any())).thenReturn(user);
|
|
|
|
|
+
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/user/downgrade")
|
|
|
|
|
+ .header("Authorization", "Bearer " + adminToken)
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
|
|
+ .content("{\"userId\":1}"))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(0));
|
|
|
|
|
+
|
|
|
|
|
+ verify(userRepository).save(argThat(u -> u.getVipEndTime() == null));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testDowngradeUserVip_notFound() throws Exception {
|
|
|
|
|
+ when(userRepository.findById(999L)).thenReturn(Optional.empty());
|
|
|
|
|
+
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/user/downgrade")
|
|
|
|
|
+ .header("Authorization", "Bearer " + adminToken)
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
|
|
+ .content("{\"userId\":999}"))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(1002));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== POST /api/admin/user/set-admin ====================
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testSetAdmin_grant() throws Exception {
|
|
|
|
|
+ User user = new User();
|
|
|
|
|
+ user.setId(1L);
|
|
|
|
|
+ user.setIsAdmin(false);
|
|
|
|
|
+ when(userRepository.findById(1L)).thenReturn(Optional.of(user));
|
|
|
|
|
+ when(userRepository.save(any())).thenReturn(user);
|
|
|
|
|
+
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/user/set-admin")
|
|
|
|
|
+ .header("Authorization", "Bearer " + adminToken)
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
|
|
+ .content("{\"userId\":1,\"isAdmin\":true}"))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(0));
|
|
|
|
|
+
|
|
|
|
|
+ verify(userRepository).save(argThat(u -> u.getIsAdmin() == true));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testSetAdmin_revoke() throws Exception {
|
|
|
|
|
+ User user = new User();
|
|
|
|
|
+ user.setId(1L);
|
|
|
|
|
+ user.setIsAdmin(true);
|
|
|
|
|
+ when(userRepository.findById(1L)).thenReturn(Optional.of(user));
|
|
|
|
|
+ when(userRepository.save(any())).thenReturn(user);
|
|
|
|
|
+
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/user/set-admin")
|
|
|
|
|
+ .header("Authorization", "Bearer " + adminToken)
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
|
|
+ .content("{\"userId\":1,\"isAdmin\":false}"))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(0));
|
|
|
|
|
+
|
|
|
|
|
+ verify(userRepository).save(argThat(u -> u.getIsAdmin() == false));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testSetAdmin_userNotFound() throws Exception {
|
|
|
|
|
+ when(userRepository.findById(999L)).thenReturn(Optional.empty());
|
|
|
|
|
+
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/user/set-admin")
|
|
|
|
|
+ .header("Authorization", "Bearer " + adminToken)
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
|
|
+ .content("{\"userId\":999,\"isAdmin\":true}"))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(1002));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== POST /api/admin/orders ====================
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testListOrders() throws Exception {
|
|
|
|
|
+ Order o = new Order();
|
|
|
|
|
+ o.setId(1L);
|
|
|
|
|
+ o.setTotalFee(39800);
|
|
|
|
|
+ when(orderRepository.findAll()).thenReturn(Collections.singletonList(o));
|
|
|
|
|
+
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/orders")
|
|
|
|
|
+ .header("Authorization", "Bearer " + adminToken)
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(0))
|
|
|
|
|
+ .andExpect(jsonPath("$.data[0].totalFee").value(39800));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== POST /api/admin/commissions ====================
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testListAllCommissions() throws Exception {
|
|
|
|
|
+ Commission c = new Commission();
|
|
|
|
|
+ c.setId(1L);
|
|
|
|
|
+ c.setAmount(5000);
|
|
|
|
|
+ when(commissionRepository.findAll()).thenReturn(Collections.singletonList(c));
|
|
|
|
|
+
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/commissions")
|
|
|
|
|
+ .header("Authorization", "Bearer " + adminToken)
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(0))
|
|
|
|
|
+ .andExpect(jsonPath("$.data[0].amount").value(5000));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== POST /api/admin/charts ====================
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testListAllCharts() throws Exception {
|
|
|
|
|
+ ChartRecord r = new ChartRecord();
|
|
|
|
|
+ r.setId(1L);
|
|
|
|
|
+ r.setBirthday("1990-01-01");
|
|
|
|
|
+ when(chartRecordRepository.findAll()).thenReturn(Collections.singletonList(r));
|
|
|
|
|
+
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/charts")
|
|
|
|
|
+ .header("Authorization", "Bearer " + adminToken)
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(0))
|
|
|
|
|
+ .andExpect(jsonPath("$.data[0].birthday").value("1990-01-01"));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== POST /api/admin/withdraws ====================
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testListWithdraws() throws Exception {
|
|
|
|
|
+ Withdraw w = new Withdraw();
|
|
|
|
|
+ w.setId(1L);
|
|
|
|
|
+ w.setStatus("pending");
|
|
|
|
|
+ when(withdrawService.getAllPending()).thenReturn(Collections.singletonList(w));
|
|
|
|
|
+
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/withdraws")
|
|
|
|
|
+ .header("Authorization", "Bearer " + adminToken)
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(0))
|
|
|
|
|
+ .andExpect(jsonPath("$.data[0].status").value("pending"));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== POST /api/admin/withdraw/approve ====================
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testApproveWithdraw() throws Exception {
|
|
|
|
|
+ doNothing().when(withdrawService).approve(1L);
|
|
|
|
|
+
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/withdraw/approve")
|
|
|
|
|
+ .header("Authorization", "Bearer " + adminToken)
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
|
|
+ .content("{\"id\":1}"))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(0));
|
|
|
|
|
+
|
|
|
|
|
+ verify(withdrawService).approve(1L);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== POST /api/admin/withdraw/reject ====================
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testRejectWithdraw() throws Exception {
|
|
|
|
|
+ doNothing().when(withdrawService).reject(1L);
|
|
|
|
|
+
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/withdraw/reject")
|
|
|
|
|
+ .header("Authorization", "Bearer " + adminToken)
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
|
|
+ .content("{\"id\":1}"))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(0));
|
|
|
|
|
+
|
|
|
|
|
+ verify(withdrawService).reject(1L);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== POST /api/admin/stats ====================
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testStats() throws Exception {
|
|
|
|
|
+ when(userRepository.count()).thenReturn(10L);
|
|
|
|
|
+ when(userRepository.countByVipEndTimeAfterAndVipEndTimeIsNotNull(any())).thenReturn(3L);
|
|
|
|
|
+ when(orderRepository.count()).thenReturn(5L);
|
|
|
|
|
+ when(chartRecordRepository.count()).thenReturn(20L);
|
|
|
|
|
+ when(commissionRepository.count()).thenReturn(8L);
|
|
|
|
|
+ when(orderRepository.findAll()).thenReturn(Collections.emptyList());
|
|
|
|
|
+
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/stats")
|
|
|
|
|
+ .header("Authorization", "Bearer " + adminToken)
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(0))
|
|
|
|
|
+ .andExpect(jsonPath("$.data.totalUsers").value(10))
|
|
|
|
|
+ .andExpect(jsonPath("$.data.vipUsers").value(3))
|
|
|
|
|
+ .andExpect(jsonPath("$.data.totalOrders").value(5))
|
|
|
|
|
+ .andExpect(jsonPath("$.data.totalCharts").value(20))
|
|
|
|
|
+ .andExpect(jsonPath("$.data.totalCommissions").value(8))
|
|
|
|
|
+ .andExpect(jsonPath("$.data.totalRevenue").value(0));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== POST /api/admin/config/list ====================
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testListConfigs() throws Exception {
|
|
|
|
|
+ SystemConfig cfg = new SystemConfig();
|
|
|
|
|
+ cfg.setConfigKey("quota_chart");
|
|
|
|
|
+ cfg.setConfigValue("3");
|
|
|
|
|
+ when(configService.getAllConfigs()).thenReturn(Collections.singletonList(cfg));
|
|
|
|
|
+
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/config/list")
|
|
|
|
|
+ .header("Authorization", "Bearer " + adminToken)
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(0))
|
|
|
|
|
+ .andExpect(jsonPath("$.data[0].configKey").value("quota_chart"))
|
|
|
|
|
+ .andExpect(jsonPath("$.data[0].configValue").value("3"));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== POST /api/admin/config (flat map) ====================
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testGetConfigMap() throws Exception {
|
|
|
|
|
+ Map<String, String> configMap = new HashMap<>();
|
|
|
|
|
+ configMap.put("quota_chart", "3");
|
|
|
|
|
+ configMap.put("quota_chat", "3");
|
|
|
|
|
+ when(configService.getAll()).thenReturn(configMap);
|
|
|
|
|
+
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/config")
|
|
|
|
|
+ .header("Authorization", "Bearer " + adminToken)
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(0))
|
|
|
|
|
+ .andExpect(jsonPath("$.data.quota_chart").value("3"));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== POST /api/admin/config/update ====================
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testUpdateConfig_singleKeyValue() throws Exception {
|
|
|
|
|
+ doNothing().when(configService).setValue("quota_chart", "5");
|
|
|
|
|
+
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/config/update")
|
|
|
|
|
+ .header("Authorization", "Bearer " + adminToken)
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
|
|
+ .content("{\"key\":\"quota_chart\",\"value\":\"5\"}"))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(0));
|
|
|
|
|
+
|
|
|
|
|
+ verify(configService).setValue("quota_chart", "5");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testUpdateConfig_batch() throws Exception {
|
|
|
|
|
+ Map<String, String> batch = new HashMap<>();
|
|
|
|
|
+ batch.put("quota_chart", "10");
|
|
|
|
|
+ batch.put("quota_chat", "5");
|
|
|
|
|
+ doNothing().when(configService).batchUpdate(batch);
|
|
|
|
|
+
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/config/update")
|
|
|
|
|
+ .header("Authorization", "Bearer " + adminToken)
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
|
|
+ .content("{\"quota_chart\":\"10\",\"quota_chat\":\"5\"}"))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(0));
|
|
|
|
|
+
|
|
|
|
|
+ verify(configService).batchUpdate(argThat(m ->
|
|
|
|
|
+ "10".equals(m.get("quota_chart")) && "5".equals(m.get("quota_chat"))));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== POST /api/admin/config/reset ====================
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testResetConfig_success() throws Exception {
|
|
|
|
|
+ when(configService.resetToDefault("quota_chart")).thenReturn(true);
|
|
|
|
|
+
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/config/reset")
|
|
|
|
|
+ .header("Authorization", "Bearer " + adminToken)
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
|
|
+ .content("{\"configKey\":\"quota_chart\"}"))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(0));
|
|
|
|
|
+
|
|
|
|
|
+ verify(configService).resetToDefault("quota_chart");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testResetConfig_missingKey() throws Exception {
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/config/reset")
|
|
|
|
|
+ .header("Authorization", "Bearer " + adminToken)
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
|
|
+ .content("{}"))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(1003))
|
|
|
|
|
+ .andExpect(jsonPath("$.message").value("configKey is required"));
|
|
|
|
|
+
|
|
|
|
|
+ verify(configService, never()).resetToDefault(anyString());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void testResetConfig_unknownKey() throws Exception {
|
|
|
|
|
+ when(configService.resetToDefault("bad_key")).thenReturn(false);
|
|
|
|
|
+
|
|
|
|
|
+ mockMvc.perform(post("/api/admin/config/reset")
|
|
|
|
|
+ .header("Authorization", "Bearer " + adminToken)
|
|
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
|
|
+ .content("{\"configKey\":\"bad_key\"}"))
|
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
|
+ .andExpect(jsonPath("$.code").value(1004))
|
|
|
|
|
+ .andExpect(jsonPath("$.message").value("Unknown config key: bad_key"));
|
|
|
|
|
+ }
|
|
|
|
|
+}
|