diff --git a/alerter/src/main/java/org/apache/hertzbeat/alert/controller/AlertDefinesController.java b/alerter/src/main/java/org/apache/hertzbeat/alert/controller/AlertDefinesController.java index 7579c05df3d..bfdd5a187fe 100644 --- a/alerter/src/main/java/org/apache/hertzbeat/alert/controller/AlertDefinesController.java +++ b/alerter/src/main/java/org/apache/hertzbeat/alert/controller/AlertDefinesController.java @@ -61,7 +61,8 @@ public ResponseEntity>> getAlertDefines( @Parameter(description = "List current page", example = "0") @RequestParam(defaultValue = "0") int pageIndex, @Parameter(description = "Number of list pages", example = "8") @RequestParam(defaultValue = "8") int pageSize) { Page alertDefinePage = alertDefineService.getAlertDefines(ids, search, priority, sort, order, pageIndex, pageSize); - return ResponseEntity.ok(Message.success(alertDefinePage)); + + return ResponseEntity.ok(Message.success(alertDefinePage)); } @DeleteMapping @@ -79,9 +80,9 @@ public ResponseEntity> deleteAlertDefines( @GetMapping("/export") @Operation(summary = "export alertDefine config", description = "export alarm definition configuration") public void export( - @Parameter(description = "AlertDefine ID List", example = "656937901") @RequestParam List ids, - @Parameter(description = "Export Type:JSON,EXCEL,YAML") @RequestParam(defaultValue = "JSON") String type, - HttpServletResponse res) throws Exception { + @Parameter(description = "AlertDefine ID List", example = "656937901") @RequestParam List ids, + @Parameter(description = "Export Type:JSON,EXCEL,YAML") @RequestParam(defaultValue = "JSON") String type, + HttpServletResponse res) throws Exception { alertDefineService.export(ids, type, res); } diff --git a/alerter/src/main/java/org/apache/hertzbeat/alert/controller/AlertSilencesController.java b/alerter/src/main/java/org/apache/hertzbeat/alert/controller/AlertSilencesController.java index 1b209b1093c..4cda572afb2 100644 --- a/alerter/src/main/java/org/apache/hertzbeat/alert/controller/AlertSilencesController.java +++ b/alerter/src/main/java/org/apache/hertzbeat/alert/controller/AlertSilencesController.java @@ -56,6 +56,7 @@ public ResponseEntity>> getAlertSilences( @Parameter(description = "Sort mode: asc: ascending, desc: descending", example = "desc") @RequestParam(defaultValue = "desc") String order, @Parameter(description = "List current page", example = "0") @RequestParam(defaultValue = "0") int pageIndex, @Parameter(description = "Number of list pages", example = "8") @RequestParam(defaultValue = "8") int pageSize) { + Page alertSilencePage = alertSilenceService.getAlertSilences(ids, search, sort, order, pageIndex, pageSize); return ResponseEntity.ok(Message.success(alertSilencePage)); } diff --git a/alerter/src/test/java/org/apache/hertzbeat/alert/controller/AlertDefinesControllerTest.java b/alerter/src/test/java/org/apache/hertzbeat/alert/controller/AlertDefinesControllerTest.java index 7f9ef2c25f6..693983cfbed 100644 --- a/alerter/src/test/java/org/apache/hertzbeat/alert/controller/AlertDefinesControllerTest.java +++ b/alerter/src/test/java/org/apache/hertzbeat/alert/controller/AlertDefinesControllerTest.java @@ -17,16 +17,9 @@ package org.apache.hertzbeat.alert.controller; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.Stream; +import org.apache.catalina.Manager; import org.apache.hertzbeat.alert.service.AlertDefineService; import org.apache.hertzbeat.common.constants.CommonConstants; import org.apache.hertzbeat.common.entity.alerter.AlertDefine; @@ -36,116 +29,60 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Sort; +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.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; /** * Test case for {@link AlertDefinesController} * Test whether the data mocked at the mock is correct, and test whether the format of the returned data is correct */ + @ExtendWith(MockitoExtension.class) +@SpringBootTest(classes = Manager.class) class AlertDefinesControllerTest { - private MockMvc mockMvc; - - @InjectMocks - private AlertDefinesController alertDefinesController; + private MockMvc mockMvc; - @Mock - AlertDefineService alertDefineService; + @InjectMocks + private AlertDefinesController alertDefinesController; - // Parameters to avoid default values interference, default values have been replaced - List ids = Stream.of(6565463543L, 6565463544L).collect(Collectors.toList()); - Byte priority = Byte.parseByte("1"); - String sort = "gmtCreate"; - String order = "asc"; - Integer pageIndex = 1; - Integer pageSize = 7; - - // Parameter collection - Map content = new HashMap<>(); + @Mock + private AlertDefineService alertDefineService; - // Object for mock - PageRequest pageRequest; + private AlertDefine alertDefine; - // Since the specification is used in dynamic proxy, it cannot be mocked - // Missing debugging parameters are ids, priority - // The missing part has been manually output for testing + @BeforeEach + void setUp() { - @BeforeEach - void setUp() { - this.mockMvc = MockMvcBuilders.standaloneSetup(alertDefinesController).build(); - content.put("ids", ids); - content.put("priority", priority); - content.put("sort", sort); - content.put("order", order); - content.put("pageIndex", pageIndex); - content.put("pageSize", pageSize); - Sort sortExp = Sort.by(new Sort.Order(Sort.Direction.fromString(content.get("order").toString()), content.get("sort").toString())); - pageRequest = PageRequest.of((Integer) content.get("pageIndex"), (Integer) content.get("pageSize"), sortExp); - } + this.mockMvc = standaloneSetup(alertDefinesController).build(); - // @Test - // todo: fix this test - void getAlertDefines() throws Exception { + alertDefine = AlertDefine.builder() + .id(9L) + .app("linux") + .metric("disk") + .field("usage") + .expr("x") + .times(1) + .tags(new LinkedList<>()) + .build(); + } - // Test the correctness of the mock - // Although objects cannot be mocked, stubs can be stored using class files - // Mockito.when(alertDefineService.getAlertDefines(Mockito.any(Specification.class), Mockito.argThat(new ArgumentMatcher() { - // @Override - // public boolean matches(PageRequest pageRequestMidden) { - // // There are three methods in the source code that need to be compared, namely getPageNumber(), getPageSize(), getSort() - // if(pageRequestMidden.getPageSize() == pageRequest.getPageSize() && - // pageRequestMidden.getPageNumber() == pageRequest.getPageNumber() && - // pageRequestMidden.getSort().equals(pageRequest.getSort())) { - // return true; - // } - // return false; - // } - // }))).thenReturn(new PageImpl(new ArrayList())); - AlertDefine define = AlertDefine.builder().id(9L).app("linux").metric("disk").field("usage").expr("x").times(1).tags(new LinkedList<>()).build(); - Mockito.when(alertDefineService.getAlertDefines(null, null, null, "id", "desc", 1, 10)).thenReturn(new PageImpl<>(Collections.singletonList(define))); + @Test + void deleteAlertDefines() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get( - "/api/alert/defines") - .param("ids", ids.toString().substring(1, ids.toString().length() - 1)) - .param("priority", priority.toString()) - .param("sort", sort) - .param("order", order) - .param("pageIndex", pageIndex.toString()) - .param("pageSize", pageSize.toString())) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.code").value((int) CommonConstants.SUCCESS_CODE)) - .andExpect(jsonPath("$.data.content").value(new ArrayList<>())) - .andExpect(jsonPath("$.data.pageable").value("INSTANCE")) - .andExpect(jsonPath("$.data.totalPages").value(1)) - .andExpect(jsonPath("$.data.totalElements").value(0)) - .andExpect(jsonPath("$.data.last").value(true)) - .andExpect(jsonPath("$.data.number").value(0)) - .andExpect(jsonPath("$.data.size").value(0)) - .andExpect(jsonPath("$.data.first").value(true)) - .andExpect(jsonPath("$.data.numberOfElements").value(0)) - .andExpect(jsonPath("$.data.empty").value(true)) - .andExpect(jsonPath("$.data.sort.empty").value(true)) - .andExpect(jsonPath("$.data.sort.sorted").value(false)) - .andExpect(jsonPath("$.data.sort.unsorted").value(true)) - .andReturn(); - } + this.mockMvc.perform(MockMvcRequestBuilders.delete("/api/alert/defines") + .contentType(MediaType.APPLICATION_JSON) + .content(JsonUtil.toJson(Collections.singletonList(1)))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.code").value((int) CommonConstants.SUCCESS_CODE)) + .andReturn(); + } - @Test - void deleteAlertDefines() throws Exception { - this.mockMvc.perform(MockMvcRequestBuilders.delete("/api/alert/defines") - .contentType(MediaType.APPLICATION_JSON) - .content(JsonUtil.toJson(ids))) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.code").value((int) CommonConstants.SUCCESS_CODE)) - .andReturn(); - } } diff --git a/alerter/src/test/java/org/apache/hertzbeat/alert/controller/AlertSilencesControllerTest.java b/alerter/src/test/java/org/apache/hertzbeat/alert/controller/AlertSilencesControllerTest.java new file mode 100644 index 00000000000..6eb29f41d30 --- /dev/null +++ b/alerter/src/test/java/org/apache/hertzbeat/alert/controller/AlertSilencesControllerTest.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hertzbeat.alert.controller; + +import org.apache.hertzbeat.alert.service.AlertSilenceService; +import org.apache.hertzbeat.common.constants.CommonConstants; +import org.apache.hertzbeat.common.entity.alerter.AlertSilence; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; + +/** + * test case for {@link AlertSilencesController} + */ + +@ExtendWith(MockitoExtension.class) +class AlertSilencesControllerTest { + + private MockMvc mockMvc; + + @Mock + private AlertSilenceService alertSilenceService; + + private AlertSilence alertSilence; + + @InjectMocks + private AlertSilencesController alertSilencesController; + + @BeforeEach + void setUp() { + + this.mockMvc = standaloneSetup(alertSilencesController).build(); + + alertSilence = AlertSilence + .builder() + .id(1L) + .type((byte) 1) + .name("Test Silence") + .build(); + } + + @Test + void testDeleteAlertDefines() throws Exception { + + doNothing().when(alertSilenceService).deleteAlertSilences(any()); + + mockMvc.perform(delete("/api/alert/silences") + .param("ids", "1,2,3") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.code").value((int) CommonConstants.SUCCESS_CODE)); + } + +} diff --git a/common/src/main/java/org/apache/hertzbeat/common/config/MVCConfig.java b/common/src/main/java/org/apache/hertzbeat/common/config/MVCConfig.java new file mode 100644 index 00000000000..50e7d82fd04 --- /dev/null +++ b/common/src/main/java/org/apache/hertzbeat/common/config/MVCConfig.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hertzbeat.common.config; + +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.TimeZone; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.web.config.SpringDataJacksonConfiguration; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * MVC Configuration. + */ + +@Configuration +public class MVCConfig implements WebMvcConfigurer { + + public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss"; + + public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd"; + + public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss"; + + @Autowired + private SpringDataJacksonConfiguration.PageModule pageModule; + + @Override + public void extendMessageConverters(List> converters) { + + MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter(); + + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + + final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT); + simpleDateFormat.setTimeZone(TimeZone.getDefault()); + + JavaTimeModule javaTimeModule = new JavaTimeModule(); + + DateTimeFormatter defaultDateTimeFormatter = DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT); + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT); + DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT); + + javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(defaultDateTimeFormatter)); + javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(dateTimeFormatter)); + javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(timeFormatter)); + + javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(dateTimeFormatter)); + javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(dateTimeFormatter)); + javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(timeFormatter)); + + objectMapper.registerModule(javaTimeModule) + .registerModule(pageModule) + .setDateFormat(simpleDateFormat); + + messageConverter.setObjectMapper(objectMapper); + converters.add(0, messageConverter); + } +} diff --git a/manager/src/main/java/org/apache/hertzbeat/manager/config/JacksonConfig.java b/manager/src/main/java/org/apache/hertzbeat/manager/config/JacksonConfig.java deleted file mode 100644 index cf437b09782..00000000000 --- a/manager/src/main/java/org/apache/hertzbeat/manager/config/JacksonConfig.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.hertzbeat.manager.config; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import java.text.SimpleDateFormat; -import java.util.TimeZone; -import lombok.extern.slf4j.Slf4j; -import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; - -/** - * jackson config - */ -@Slf4j -@Configuration -public class JacksonConfig { - - @Bean - public Jackson2ObjectMapperBuilderCustomizer customizer() { - return builder -> { - JavaTimeModule javaTimeModule = new JavaTimeModule(); - final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX"); - simpleDateFormat.setTimeZone(TimeZone.getDefault()); - - builder.modules(javaTimeModule) - .timeZone(TimeZone.getDefault()) - .dateFormat(simpleDateFormat); - }; - } - - @Bean - public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) { - return builder.build(); - } - -} diff --git a/manager/src/main/resources/application.yml b/manager/src/main/resources/application.yml index 619e52b1c8d..7742d47f26d 100644 --- a/manager/src/main/resources/application.yml +++ b/manager/src/main/resources/application.yml @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. server: - port: 1157 + port: 11570 spring: application: name: ${HOSTNAME:@hertzbeat@}${PID}