package com.ruoyi.app.order; import com.github.pagehelper.PageHelper; import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.utils.MessageUtils; import com.ruoyi.system.domain.vo.PosOrderInvoiceVo; import com.ruoyi.system.utils.AuthAspect; import com.ruoyi.system.utils.JwtUtil; import org.junit.jupiter.api.Test; import org.springframework.aop.aspectj.annotation.AspectJProxyFactory; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.test.util.ReflectionTestUtils; import java.util.List; import java.util.Map; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; /** 使用真实Controller代理复现鉴权失败时的checkcast,而不是直接调用切面绕过代理。 */ class UserInvoiceAuthResponseTest { private MockHttpServletResponse response; @Test void expiredAndRevokedSessionReturn401WithoutCastingPaginationToAjaxResult() { RedisCache redis = mock(RedisCache.class); OrderInvoiceService invoices = mock(OrderInvoiceService.class); MockHttpServletRequest request = new MockHttpServletRequest(); request.addHeader("token", "expired-fixture"); UserOrderController controller = proxy(request, redis, invoices); try (var jwt = mockStatic(JwtUtil.class)) { jwt.when(() -> JwtUtil.verifyToken("expired-fixture")).thenReturn(Map.of("valid", false)); var result = assertDoesNotThrow(() -> controller.myInvoices("expired-fixture", 1, 10)); assertEquals(401, result.getCode()); assertEquals(401, response.getStatus()); assertEquals(0, result.getTotal()); assertTrue(result.getRows().isEmpty()); assertFalse(result.getMsg().isBlank()); assertEquals(401, controller.loveOrgList("expired-fixture", 1, 20, null).getCode()); response.setStatus(200); assertEquals(401, controller.getInvoice("expired-fixture", 123L).get("code")); assertEquals(401, response.getStatus()); // 原AjaxResult接口也是真实HTTP401。 // 签名有效但会话被顶号/登出,也必须返回分页形状的401,不进入查询。 jwt.when(() -> JwtUtil.verifyToken("expired-fixture")).thenReturn( Map.of("valid", true, "id", "7", "jti", "qtw_tokens:user:7:revoked")); when(redis.hasKey("qtw_tokens:user:7:revoked")).thenReturn(false); response.setStatus(200); assertEquals(401, controller.myInvoices("expired-fixture", 1, 10).getCode()); assertEquals(401, response.getStatus()); verifyNoInteractions(invoices); } } @Test void validSessionKeepsExistingUserScopedRowsTotalAndCode() { RedisCache redis = mock(RedisCache.class); OrderInvoiceService invoices = mock(OrderInvoiceService.class); String token = JwtUtil.token("7", "user"); MockHttpServletRequest request = new MockHttpServletRequest(); request.addHeader("token", token); PosOrderInvoiceVo invoice = new PosOrderInvoiceVo(); invoice.setOrderId(123L); when(invoices.listMyInvoices(7L)).thenReturn(List.of(invoice)); try (var messages = mockStatic(MessageUtils.class, call -> call.getArgument(0))) { var result = proxy(request, redis, invoices).myInvoices(token, 1, 10); assertEquals(200, result.getCode()); assertEquals(200, response.getStatus()); assertEquals(1, result.getTotal()); assertSame(invoice, result.getRows().get(0)); verify(invoices).listMyInvoices(7L); } finally { PageHelper.clearPage(); } } private UserOrderController proxy(MockHttpServletRequest request, RedisCache redis, OrderInvoiceService invoices) { UserOrderController target = new UserOrderController(); ReflectionTestUtils.setField(target, "orderInvoiceService", invoices); AuthAspect aspect = new AuthAspect(redis); aspect.setHttpServletRequest(request); response = new MockHttpServletResponse(); aspect.setHttpServletResponse(response); AspectJProxyFactory factory = new AspectJProxyFactory(target); factory.setProxyTargetClass(true); factory.addAspect(aspect); return factory.getProxy(); } }