diff --git a/services/alarm-logger/src/main/java/org/phoebus/alarm/logging/rest/SearchController.java b/services/alarm-logger/src/main/java/org/phoebus/alarm/logging/rest/SearchController.java index 95ab4aba3b..9ad6991ce7 100644 --- a/services/alarm-logger/src/main/java/org/phoebus/alarm/logging/rest/SearchController.java +++ b/services/alarm-logger/src/main/java/org/phoebus/alarm/logging/rest/SearchController.java @@ -3,9 +3,13 @@ import co.elastic.clients.elasticsearch.ElasticsearchClient; import co.elastic.clients.elasticsearch._types.ElasticsearchVersionInfo; import co.elastic.clients.elasticsearch.core.InfoResponse; - import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; import org.phoebus.alarm.logging.AlarmLoggingService; import org.phoebus.alarm.logging.ElasticClientHelper; import org.springframework.beans.factory.annotation.Value; @@ -18,6 +22,7 @@ import org.springframework.web.bind.annotation.RestController; import org.springframework.web.server.ResponseStatusException; +import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.HashMap; import java.util.LinkedHashMap; @@ -26,12 +31,6 @@ import java.util.logging.Level; import java.util.logging.Logger; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.Parameters; - /** * A REST service for querying the alarm message history * @@ -85,16 +84,16 @@ public String info() { @Operation(summary = "Search alarms") @Parameters({ - @Parameter(name = "pv", description = "PV name", schema = @Schema(type = "string"), required = false, example = "*"), - @Parameter(name = "severity", description = "Alarm severity", schema = @Schema(type = "string"), required = false, example = "*"), - @Parameter(name = "message", description = "Alarm message", schema = @Schema(type = "string"), required = false, example = "*"), - @Parameter(name = "current_severity", description = "PV severity", schema = @Schema(type = "string"), required = false, example = "*"), - @Parameter(name = "current_message", description = "PV message", schema = @Schema(type = "string"), required = false, example = "*"), - @Parameter(name = "user", description = "User", schema = @Schema(type = "string"), required = false, example = "*"), - @Parameter(name = "host", description = "Host", schema = @Schema(type = "string"), required = false, example = "*"), - @Parameter(name = "command", description = "Command", schema = @Schema(type = "string"), required = false, example = "*"), - @Parameter(name = "start", description = "Start time", schema = @Schema(type = "string"), required = false, example = "2024-06-12"), - @Parameter(name = "end", description = "End time", schema = @Schema(type = "string"), required = false, example = "2024-06-14"), + @Parameter(name = "pv", description = "PV name", schema = @Schema(type = "string"), required = false, example = "*"), + @Parameter(name = "severity", description = "Alarm severity", schema = @Schema(type = "string"), required = false, example = "*"), + @Parameter(name = "message", description = "Alarm message", schema = @Schema(type = "string"), required = false, example = "*"), + @Parameter(name = "current_severity", description = "PV severity", schema = @Schema(type = "string"), required = false, example = "*"), + @Parameter(name = "current_message", description = "PV message", schema = @Schema(type = "string"), required = false, example = "*"), + @Parameter(name = "user", description = "User", schema = @Schema(type = "string"), required = false, example = "*"), + @Parameter(name = "host", description = "Host", schema = @Schema(type = "string"), required = false, example = "*"), + @Parameter(name = "command", description = "Command", schema = @Schema(type = "string"), required = false, example = "*"), + @Parameter(name = "start", description = "Start time", schema = @Schema(type = "string"), required = false, example = "2024-06-12"), + @Parameter(name = "end", description = "End time", schema = @Schema(type = "string"), required = false, example = "2024-06-14"), }) @RequestMapping(value = "/search/alarm", method = RequestMethod.GET) public List search(@Parameter(hidden = true) @RequestParam Map allRequestParams) { @@ -114,18 +113,29 @@ public List searchPv(@Parameter(description = "PV name") @PathV @Operation(summary = "Search alarm config") @Schema(name = "config", example = "/Accelerator/compteur", required = true) @Parameters({ - @Parameter(name = "config", description = "Config path", schema = @Schema(type = "string"), required = false, example = "/Accelerator/pvname"), + @Parameter(name = "config", description = "Config path", schema = @Schema(type = "string"), required = false, example = "/Accelerator/pvname"), }) @RequestMapping(value = "/search/alarm/config", method = RequestMethod.GET) public List searchConfig(@Parameter(hidden = true) @RequestParam Map allRequestParams) { - if(allRequestParams == null || + if (allRequestParams == null || allRequestParams.isEmpty() || !allRequestParams.containsKey("config") || - allRequestParams.get("config").isEmpty()){ + allRequestParams.get("config").isEmpty()) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST); } List result = AlarmLogSearchUtil.searchConfig(ElasticClientHelper.getInstance().getClient(), allRequestParams); return result; } + /** + * Handles the /swagger-ui URL: redirects to /swagger-ui/index.html to avoid 500 response. + * + * @param response The {@link HttpServletResponse} to configure with a redirect (301). + */ + @GetMapping("/swagger-ui") + public void api(HttpServletResponse response) { + response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); + response.addHeader("Location", "/swagger-ui/index.html"); + } + } diff --git a/services/alarm-logger/src/test/java/org/phoebus/alarm/logging/rest/ControllersTestConfig.java b/services/alarm-logger/src/test/java/org/phoebus/alarm/logging/rest/ControllersTestConfig.java new file mode 100644 index 0000000000..8434ced02b --- /dev/null +++ b/services/alarm-logger/src/test/java/org/phoebus/alarm/logging/rest/ControllersTestConfig.java @@ -0,0 +1,30 @@ +/** + * Copyright (C) 2018 European Spallation Source ERIC. + *

+ * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package org.phoebus.alarm.logging.rest; + +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootConfiguration +@SuppressWarnings("unused") +@ComponentScan(basePackages = "org.phoebus.alarm.logging.rest") +public class ControllersTestConfig { + + +} diff --git a/services/alarm-logger/src/test/java/org/phoebus/alarm/logging/rest/SearchControllerTest.java b/services/alarm-logger/src/test/java/org/phoebus/alarm/logging/rest/SearchControllerTest.java new file mode 100644 index 0000000000..83400e8b9c --- /dev/null +++ b/services/alarm-logger/src/test/java/org/phoebus/alarm/logging/rest/SearchControllerTest.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2025 European Spallation Source ERIC. + */ + +package org.phoebus.alarm.logging.rest; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.junit.jupiter.api.Assertions.*; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = ControllersTestConfig.class) +@WebMvcTest(SearchController.class) +public class SearchControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Test + public void testRedirectSwagger() throws Exception { + MockHttpServletRequestBuilder request = get("/swagger-ui"); + ResultActions resultActions = mockMvc.perform(request).andExpect(status().isMovedPermanently()); + assertEquals("/swagger-ui/index.html", resultActions.andReturn().getResponse().getHeader("Location")); + } +}