PosFoodControllerAuditTest.java 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. package com.ruoyi.app.mendian;
  2. import com.ruoyi.common.annotation.Anonymous;
  3. import com.ruoyi.common.utils.MessageUtils;
  4. import com.ruoyi.system.domain.PosFood;
  5. import com.ruoyi.system.service.IPosFoodService;
  6. import com.ruoyi.system.service.MerchantStoreAccessService;
  7. import com.ruoyi.system.utils.Auth;
  8. import org.junit.jupiter.api.AfterEach;
  9. import org.junit.jupiter.api.BeforeEach;
  10. import org.junit.jupiter.api.Test;
  11. import org.mockito.ArgumentCaptor;
  12. import org.mockito.MockedStatic;
  13. import org.springframework.http.MediaType;
  14. import org.springframework.security.access.prepost.PreAuthorize;
  15. import org.springframework.test.util.ReflectionTestUtils;
  16. import org.springframework.test.web.servlet.MockMvc;
  17. import org.springframework.test.web.servlet.setup.MockMvcBuilders;
  18. import org.springframework.web.bind.annotation.PutMapping;
  19. import java.lang.reflect.Method;
  20. import java.util.Arrays;
  21. import static org.junit.jupiter.api.Assertions.*;
  22. import static org.mockito.ArgumentMatchers.any;
  23. import static org.mockito.ArgumentMatchers.anyString;
  24. import static org.mockito.Mockito.*;
  25. import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
  26. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
  27. /** 平台审核独立于商家 token/门店归属,只更新审核状态,不能误走商品保存或规格处理。 */
  28. class PosFoodControllerAuditTest {
  29. private IPosFoodService foods;
  30. private MerchantStoreAccessService merchantAccess;
  31. private MockMvc mvc;
  32. private MockedStatic<MessageUtils> messages;
  33. @BeforeEach
  34. void setup() {
  35. messages = mockStatic(MessageUtils.class);
  36. messages.when(() -> MessageUtils.message(anyString())).thenAnswer(call -> call.getArgument(0));
  37. PosFoodController controller = new PosFoodController();
  38. foods = mock(IPosFoodService.class);
  39. merchantAccess = mock(MerchantStoreAccessService.class);
  40. ReflectionTestUtils.setField(controller, "posFoodService", foods);
  41. ReflectionTestUtils.setField(controller, "merchantStoreAccessService", merchantAccess);
  42. mvc = MockMvcBuilders.standaloneSetup(controller).build();
  43. when(foods.updatePosFood(any(PosFood.class))).thenReturn(1);
  44. }
  45. @AfterEach
  46. void cleanup() { messages.close(); }
  47. @Test
  48. void platformAuditUsesExistingEditPermissionAndNeverMerchantAuth() {
  49. Method audit = Arrays.stream(PosFoodController.class.getDeclaredMethods())
  50. .filter(method -> method.isAnnotationPresent(PutMapping.class)
  51. && Arrays.asList(method.getAnnotation(PutMapping.class).value()).contains("/audit"))
  52. .findFirst().orElse(null);
  53. assertNotNull(audit, "platform audit endpoint must exist");
  54. assertNotNull(audit.getAnnotation(PreAuthorize.class));
  55. assertEquals("@ss.hasPermi('chanting:food:edit')", audit.getAnnotation(PreAuthorize.class).value());
  56. assertNull(audit.getAnnotation(Anonymous.class));
  57. assertNull(audit.getAnnotation(Auth.class));
  58. }
  59. @Test
  60. void approveAndRevokeWorkWithoutMerchantTokenHeader() throws Exception {
  61. for (String state : new String[] {"1", "0"}) {
  62. mvc.perform(put("/chanting/food/audit").header("Authorization", "Bearer platform-test")
  63. .contentType(MediaType.APPLICATION_JSON).content("{\"id\":9137,\"toExamine\":\"" + state + "\"}"))
  64. .andExpect(status().isOk()).andExpect(jsonPath("$.code").value(200));
  65. }
  66. ArgumentCaptor<PosFood> update = ArgumentCaptor.forClass(PosFood.class);
  67. verify(foods, times(2)).updatePosFood(update.capture());
  68. assertEquals("1", update.getAllValues().get(0).getToExamine());
  69. assertEquals("0", update.getAllValues().get(1).getToExamine());
  70. verifyNoInteractions(merchantAccess);
  71. verify(foods, never()).saveOrUpdate(any(PosFood.class));
  72. }
  73. @Test
  74. void auditIgnoresInjectedContentAndNeverChangesStoreOrSpecs() throws Exception {
  75. mvc.perform(put("/chanting/food/audit").contentType(MediaType.APPLICATION_JSON)
  76. .content("{\"id\":9137,\"toExamine\":\"1\",\"mdid\":999,\"price\":1,\"name\":\"injected\",\"stackingUp\":\"0\",\"foodSpecs\":[]}"))
  77. .andExpect(status().isOk()).andExpect(jsonPath("$.code").value(200));
  78. ArgumentCaptor<PosFood> update = ArgumentCaptor.forClass(PosFood.class);
  79. verify(foods).updatePosFood(update.capture());
  80. PosFood changed = update.getValue();
  81. assertEquals(9137L, changed.getId());
  82. assertEquals("1", changed.getToExamine());
  83. assertNull(changed.getMdid());
  84. assertNull(changed.getPrice());
  85. assertNull(changed.getName());
  86. assertNull(changed.getStackingUp());
  87. assertNull(changed.getFoodSpecs());
  88. assertNull(changed.getRecommend());
  89. }
  90. @Test
  91. void invalidIdOrAuditStateIsRejectedBeforeWrite() throws Exception {
  92. for (String payload : new String[] {"{}", "{\"id\":0,\"toExamine\":\"1\"}",
  93. "{\"id\":-1,\"toExamine\":\"1\"}", "{\"id\":9137}",
  94. "{\"id\":9137,\"toExamine\":\"2\"}", "{\"id\":9137,\"toExamine\":\"\"}"}) {
  95. mvc.perform(put("/chanting/food/audit").contentType(MediaType.APPLICATION_JSON).content(payload))
  96. .andExpect(status().isOk()).andExpect(jsonPath("$.code").value(500))
  97. .andExpect(jsonPath("$.msg").value("food.audit.invalid"));
  98. }
  99. verifyNoInteractions(foods);
  100. }
  101. @Test
  102. void missingFoodDoesNotCreateProductOrReportSuccess() throws Exception {
  103. when(foods.updatePosFood(any(PosFood.class))).thenReturn(0);
  104. mvc.perform(put("/chanting/food/audit").contentType(MediaType.APPLICATION_JSON)
  105. .content("{\"id\":9137,\"toExamine\":\"1\"}"))
  106. .andExpect(status().isOk()).andExpect(jsonPath("$.code").value(500));
  107. verify(foods, never()).saveOrUpdate(any(PosFood.class));
  108. }
  109. @Test
  110. void originalMerchantEndpointStillRequiresMerchantToken() throws Exception {
  111. mvc.perform(put("/chanting/food/changerecommend").header("Authorization", "Bearer platform-test")
  112. .contentType(MediaType.APPLICATION_JSON).content("{\"id\":9137,\"toExamine\":\"1\"}"))
  113. .andExpect(status().isBadRequest());
  114. verifyNoInteractions(foods, merchantAccess);
  115. }
  116. }