package com.battery.business.web.device;
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.when;
|
|
import java.lang.reflect.Method;
|
import org.junit.jupiter.api.Test;
|
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
|
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
import com.ruoyi.common.annotation.Anonymous;
|
import com.ruoyi.common.exception.ServiceException;
|
import com.battery.business.service.DeviceAdapterErrorCodes;
|
import com.battery.business.service.DeviceIngestErrorCodes;
|
import com.battery.business.service.IDeviceIngestService;
|
import com.battery.business.service.IDeviceIngestService.IngestResult;
|
|
/**
|
* 接收端点的应答契约:拒绝一律用非 2xx 状态码——取数程序只在收到 2xx 后才推进自己的读取位置,
|
* 所以"响应 200 但体内是错误码"是不能接受的:那会让程序把没落库的数据当成已送达。
|
*/
|
class DeviceIngestControllerTest
|
{
|
private final IDeviceIngestService ingest = mock(IDeviceIngestService.class);
|
private final MockMvc mvc = MockMvcBuilders.standaloneSetup(new DeviceIngestController(ingest)).build();
|
|
@Test
|
void acceptedBatchAnswersOkSoTheProgramMayAdvanceItsWatermark() throws Exception
|
{
|
when(ingest.ingest(any(), any(), any())).thenReturn(new IngestResult(2, 0, 0));
|
|
mvc.perform(MockMvcRequestBuilders.post("/device-ingest/j22")
|
.header(DeviceIngestController.TOKEN_HEADER, "token").content("{}"))
|
.andExpect(MockMvcResultMatchers.status().isOk())
|
.andExpect(MockMvcResultMatchers.jsonPath("$.accepted").value(2));
|
}
|
|
@Test
|
void rejectionsAnswerWithNonOkStatusesSoTheProgramKeepsItsPosition() throws Exception
|
{
|
assertStatus(DeviceIngestErrorCodes.TOKEN_INVALID, 401);
|
assertStatus(DeviceIngestErrorCodes.SOURCE_DISABLED, 403);
|
assertStatus(DeviceAdapterErrorCodes.UNSUPPORTED_TYPE, 403);
|
assertStatus(DeviceIngestErrorCodes.PAYLOAD_INVALID, 400);
|
assertStatus(DeviceAdapterErrorCodes.NOT_FOUND, 404);
|
assertStatus(59999, 500);
|
}
|
|
/** 端点匿名放行(取数程序没有登录态),凭据由请求头里的来源令牌自己校验。 */
|
@Test
|
void endpointIsAnonymousAndAuthenticatesWithTheSourceTokenHeader() throws Exception
|
{
|
Method receive = DeviceIngestController.class.getMethod("receive", String.class, String.class, String.class);
|
assertTrue(DeviceIngestController.class.isAnnotationPresent(Anonymous.class));
|
assertEquals("X-Device-Ingest-Token", DeviceIngestController.TOKEN_HEADER);
|
assertTrue(receive.getParameters()[1].toString().contains("token"));
|
}
|
|
private void assertStatus(int code, int expected) throws Exception
|
{
|
// 用 doThrow/when 形式重新打桩:直接调 mock 方法会被上一次的桩立即抛异常。
|
org.mockito.Mockito.doThrow(new ServiceException("拒绝", code)).when(ingest).ingest(any(), any(), any());
|
|
mvc.perform(MockMvcRequestBuilders.post("/device-ingest/j22").content("{}"))
|
.andExpect(MockMvcResultMatchers.status().is(expected));
|
}
|
}
|