@@ -17,6 +17,7 @@ dependencies { | |||
testImplementation 'javax.servlet:javax.servlet-api' | |||
testImplementation 'org.junit.jupiter:junit-jupiter-api' | |||
testImplementation 'org.junit.jupiter:junit-jupiter-params' | |||
testImplementation 'org.mockito:mockito-core' | |||
testImplementation 'org.mockito:mockito-junit-jupiter' | |||
testImplementation 'org.skyscreamer:jsonassert:1.5.1' |
@@ -48,6 +48,7 @@ public class WebApiEndpoints { | |||
public static final String ANALYSIS_ENDPOINT = "/analysis"; | |||
public static final String VERSION_ENDPOINT = ANALYSIS_ENDPOINT + "/version"; | |||
public static final String JRE_ENDPOINT = ANALYSIS_ENDPOINT + "/jres"; | |||
private WebApiEndpoints() { | |||
} |
@@ -0,0 +1,51 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 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 | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.v2.api.analysis.controller; | |||
import java.util.List; | |||
import org.sonar.server.v2.api.analysis.response.JreInfoRestResponse; | |||
import org.sonar.server.v2.api.analysis.service.JresHandler; | |||
import org.springframework.core.io.InputStreamResource; | |||
public class DefaultJresController implements JresController { | |||
private final JresHandler jresHandler; | |||
public DefaultJresController(JresHandler jresHandler) { | |||
this.jresHandler = jresHandler; | |||
} | |||
@Override | |||
public List<JreInfoRestResponse> getJresMetadata(String os, String arch) { | |||
return jresHandler.getJresMetadata(os, arch); | |||
} | |||
@Override | |||
public JreInfoRestResponse getJreMetadata(String id) { | |||
return jresHandler.getJreMetadata(id); | |||
} | |||
@Override | |||
public InputStreamResource downloadJre(String id) { | |||
JreInfoRestResponse jreInfoRestResponse = jresHandler.getJreMetadata(id); | |||
return new InputStreamResource(jresHandler.getJreBinary(jreInfoRestResponse.filename())); | |||
} | |||
} |
@@ -0,0 +1,67 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 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 | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.v2.api.analysis.controller; | |||
import io.swagger.v3.oas.annotations.Operation; | |||
import io.swagger.v3.oas.annotations.Parameter; | |||
import java.util.List; | |||
import org.sonar.server.v2.api.analysis.response.JreInfoRestResponse; | |||
import org.springframework.core.io.InputStreamResource; | |||
import org.springframework.web.bind.annotation.GetMapping; | |||
import org.springframework.web.bind.annotation.PathVariable; | |||
import org.springframework.web.bind.annotation.RequestMapping; | |||
import org.springframework.web.bind.annotation.RequestParam; | |||
import org.springframework.web.bind.annotation.ResponseStatus; | |||
import org.springframework.web.bind.annotation.RestController; | |||
import static io.swagger.v3.oas.annotations.enums.ParameterIn.PATH; | |||
import static org.sonar.server.v2.WebApiEndpoints.JRE_ENDPOINT; | |||
import static org.springframework.http.HttpStatus.OK; | |||
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; | |||
import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE; | |||
@RequestMapping(value = JRE_ENDPOINT, produces = APPLICATION_JSON_VALUE) | |||
@ResponseStatus(OK) | |||
@RestController | |||
public interface JresController { | |||
String OS_PARAM_DESCRIPTION = "Filter the JRE by operating system. Accepted values are 'windows', 'linux', 'macos', 'alpine' (case-insensitive), with some aliases"; | |||
String ARCH_PARAM_DESCRIPTION = "Filter the JRE by CPU architecture. Accepted values are 'x64' and 'aarch64' (case-insensitive), with some aliases."; | |||
String GET_JRE_DESCRIPTION = | |||
"This endpoint return the JRE metadata by default. To download the JRE binary asset, set the Accept header of the request to 'application/octet-stream'."; | |||
String GET_JRE_SUMMARY = "JRE download/metadata"; | |||
String ID_PARAM_DESCRIPTION = "The ID of the JRE"; | |||
@GetMapping | |||
@Operation(summary = "All JREs metadata", description = "Get metadata of all available JREs") | |||
List<JreInfoRestResponse> getJresMetadata( | |||
@RequestParam(value = "os", required = false) @Parameter(description = OS_PARAM_DESCRIPTION) String os, | |||
@RequestParam(value = "arch", required = false) @Parameter(description = ARCH_PARAM_DESCRIPTION) String arch); | |||
@GetMapping(value = "/{id}") | |||
@Operation(summary = GET_JRE_SUMMARY, description = GET_JRE_DESCRIPTION) | |||
JreInfoRestResponse getJreMetadata( | |||
@PathVariable(value = "id") @Parameter(description = ID_PARAM_DESCRIPTION, required = true, in = PATH) String id); | |||
@GetMapping(value = "/{id}", produces = APPLICATION_OCTET_STREAM_VALUE) | |||
@Operation(summary = GET_JRE_SUMMARY, description = GET_JRE_DESCRIPTION) | |||
InputStreamResource downloadJre( | |||
@PathVariable(value = "id") @Parameter(description = ID_PARAM_DESCRIPTION, required = true, in = PATH) String id); | |||
} |
@@ -0,0 +1,30 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 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 | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.v2.api.analysis.response; | |||
public record JreInfoRestResponse( | |||
String id, | |||
String filename, | |||
String sha256, | |||
String javaPath, | |||
String os, | |||
String arch | |||
) { | |||
} |
@@ -0,0 +1,23 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 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 | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
@ParametersAreNonnullByDefault | |||
package org.sonar.server.v2.api.analysis.response; | |||
import javax.annotation.ParametersAreNonnullByDefault; |
@@ -0,0 +1,33 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 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 | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.v2.api.analysis.service; | |||
import java.io.InputStream; | |||
import java.util.List; | |||
import javax.annotation.Nullable; | |||
import org.sonar.server.v2.api.analysis.response.JreInfoRestResponse; | |||
public interface JresHandler { | |||
List<JreInfoRestResponse> getJresMetadata(@Nullable String os, @Nullable String arch); | |||
JreInfoRestResponse getJreMetadata(String id); | |||
InputStream getJreBinary(String jreFilename); | |||
} |
@@ -0,0 +1,148 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 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 | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.v2.api.analysis.service; | |||
import com.fasterxml.jackson.databind.ObjectMapper; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import java.io.FileInputStream; | |||
import java.io.FileNotFoundException; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.UncheckedIOException; | |||
import java.util.Arrays; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Optional; | |||
import java.util.function.Predicate; | |||
import javax.annotation.Nullable; | |||
import javax.annotation.PostConstruct; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
import org.sonar.server.v2.api.analysis.response.JreInfoRestResponse; | |||
import static java.lang.String.join; | |||
import static org.apache.commons.lang.StringUtils.isBlank; | |||
public class JresHandlerImpl implements JresHandler { | |||
private static final String JRES_METADATA_FILENAME = "jres-metadata.json"; | |||
private final String jresMetadataFilename; | |||
private final Map<String, JreInfoRestResponse> metadata = new HashMap<>(); | |||
public JresHandlerImpl() { | |||
this(JRES_METADATA_FILENAME); | |||
} | |||
@VisibleForTesting | |||
public JresHandlerImpl(String jresMetadataFilename) { | |||
this.jresMetadataFilename = jresMetadataFilename; | |||
} | |||
@PostConstruct | |||
void initMetadata() { | |||
metadata.clear(); | |||
readJresMetadata().forEach(jre -> metadata.put(jre.id(), jre)); | |||
} | |||
private List<JreInfoRestResponse> readJresMetadata() { | |||
ObjectMapper objectMapper = new ObjectMapper(); | |||
try (InputStream is = getClass().getClassLoader().getResourceAsStream(jresMetadataFilename)) { | |||
return objectMapper.readValue(is, objectMapper.getTypeFactory().constructCollectionType(List.class, JreInfoRestResponse.class)); | |||
} catch (IOException ioException) { | |||
throw new UncheckedIOException(ioException); | |||
} | |||
} | |||
@Override | |||
public List<JreInfoRestResponse> getJresMetadata(@Nullable String os, @Nullable String arch) { | |||
Predicate<JreInfoRestResponse> osFilter = isBlank(os) ? jre -> true : (jre -> OS.from(jre.os()) == OS.from(os)); | |||
Predicate<JreInfoRestResponse> archFilter = isBlank(arch) ? jre -> true : (jre -> Arch.from(jre.arch()) == Arch.from(arch)); | |||
return metadata.values().stream() | |||
.filter(osFilter) | |||
.filter(archFilter) | |||
.toList(); | |||
} | |||
@Override | |||
public JreInfoRestResponse getJreMetadata(String id) { | |||
return Optional.ofNullable(metadata.get(id)) | |||
.orElseThrow(() -> new NotFoundException("JRE not found for id: " + id)); | |||
} | |||
@Override | |||
public InputStream getJreBinary(String jreFilename) { | |||
try { | |||
return new FileInputStream("jres/" + jreFilename); | |||
} catch (FileNotFoundException fileNotFoundException) { | |||
throw new NotFoundException(String.format("Unable to find JRE '%s'", jreFilename)); | |||
} | |||
} | |||
enum OS { | |||
WINDOWS("win", "windows", "win32"), | |||
LINUX("linux"), | |||
MACOS("mac", "macos", "darwin"), | |||
ALPINE("alpine"); | |||
private final List<String> aliases; | |||
OS(String... aliases) { | |||
this.aliases = Arrays.stream(aliases).toList(); | |||
} | |||
private static OS from(String alias) { | |||
return Arrays.stream(values()) | |||
.filter(os -> os.aliases.contains(alias)) | |||
.findFirst() | |||
.orElseThrow(() -> new IllegalArgumentException(String.format("Unsupported OS: '%s'. Supported values are '%s'", alias, join(", ", supportedValues())))); | |||
} | |||
private static List<String> supportedValues() { | |||
return Arrays.stream(values()) | |||
.flatMap(os -> os.aliases.stream()) | |||
.toList(); | |||
} | |||
} | |||
enum Arch { | |||
X64("x86_64", "x86-64", "amd64", "x64"), | |||
AARCH64("arm64", "aarch64"); | |||
private final List<String> aliases; | |||
Arch(String... aliases) { | |||
this.aliases = Arrays.stream(aliases).toList(); | |||
} | |||
private static Arch from(String alias) { | |||
return Arrays.stream(values()) | |||
.filter(arch -> arch.aliases.contains(alias)) | |||
.findFirst() | |||
.orElseThrow(() -> new IllegalArgumentException(String.format("Unsupported architecture: '%s'. Supported values are '%s'", alias, join(", ", supportedValues())))); | |||
} | |||
private static List<String> supportedValues() { | |||
return Arrays.stream(values()) | |||
.flatMap(arch -> arch.aliases.stream()) | |||
.toList(); | |||
} | |||
} | |||
} |
@@ -0,0 +1,23 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 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 | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
@ParametersAreNonnullByDefault | |||
package org.sonar.server.v2.api.analysis.service; | |||
import javax.annotation.ParametersAreNonnullByDefault; |
@@ -43,8 +43,12 @@ import org.sonar.server.platform.NodeInformation; | |||
import org.sonar.server.rule.RuleDescriptionFormatter; | |||
import org.sonar.server.user.SystemPasscode; | |||
import org.sonar.server.user.UserSession; | |||
import org.sonar.server.v2.api.analysis.controller.DefaultJresController; | |||
import org.sonar.server.v2.api.analysis.controller.DefaultVersionController; | |||
import org.sonar.server.v2.api.analysis.controller.JresController; | |||
import org.sonar.server.v2.api.analysis.controller.VersionController; | |||
import org.sonar.server.v2.api.analysis.service.JresHandler; | |||
import org.sonar.server.v2.api.analysis.service.JresHandlerImpl; | |||
import org.sonar.server.v2.api.dop.controller.DefaultDopSettingsController; | |||
import org.sonar.server.v2.api.dop.controller.DopSettingsController; | |||
import org.sonar.server.v2.api.gitlab.config.controller.DefaultGitlabConfigurationController; | |||
@@ -159,4 +163,14 @@ public class PlatformLevel4WebConfig { | |||
return new DefaultVersionController(server); | |||
} | |||
@Bean | |||
public JresHandler jresHandler() { | |||
return new JresHandlerImpl(); | |||
} | |||
@Bean | |||
public JresController jresController(JresHandler jresHandler) { | |||
return new DefaultJresController(jresHandler); | |||
} | |||
} |
@@ -0,0 +1,132 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 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 | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.v2.api.analysis.controller; | |||
import java.io.ByteArrayInputStream; | |||
import java.util.List; | |||
import java.util.stream.Stream; | |||
import org.junit.jupiter.api.Test; | |||
import org.junit.jupiter.params.ParameterizedTest; | |||
import org.junit.jupiter.params.provider.Arguments; | |||
import org.junit.jupiter.params.provider.MethodSource; | |||
import org.sonar.server.v2.api.analysis.response.JreInfoRestResponse; | |||
import org.sonar.server.v2.api.analysis.service.JresHandler; | |||
import org.springframework.test.web.servlet.MockMvc; | |||
import static org.junit.jupiter.params.provider.Arguments.arguments; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.server.v2.WebApiEndpoints.JRE_ENDPOINT; | |||
import static org.sonar.server.v2.api.ControllerTester.getMockMvc; | |||
import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM; | |||
import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE; | |||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; | |||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; | |||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | |||
class DefaultJresControllerTest { | |||
private final JresHandler jresHandler = mock(JresHandler.class); | |||
private final MockMvc mockMvc = getMockMvc(new DefaultJresController(jresHandler)); | |||
@ParameterizedTest | |||
@MethodSource("osAndArch") | |||
void getJres_shoudlReturnMetadaAsJson(String os, String arch) throws Exception { | |||
JreInfoRestResponse metadata1 = new JreInfoRestResponse("id_1", "filename_1", "sha256_1", "javaPath_1", "os_1", "arch_1"); | |||
JreInfoRestResponse metadata2 = new JreInfoRestResponse("id_2", "filename_2", "sha256_2", "javaPath_2", "os_2", "arch_2"); | |||
when(jresHandler.getJresMetadata(os, arch)).thenReturn(List.of(metadata1, metadata2)); | |||
String expectedJson = | |||
""" | |||
[ | |||
{ | |||
"id": "id_1", | |||
"filename": "filename_1", | |||
"sha256": "sha256_1", | |||
"javaPath": "javaPath_1", | |||
"os": "os_1", | |||
"arch": "arch_1" | |||
}, | |||
{ | |||
"id": "id_2", | |||
"filename": "filename_2", | |||
"sha256": "sha256_2", | |||
"javaPath": "javaPath_2", | |||
"os": "os_2", | |||
"arch": "arch_2" | |||
} | |||
] | |||
"""; | |||
mockMvc.perform(get(JRE_ENDPOINT) | |||
.param("os", os) | |||
.param("arch", arch)) | |||
.andExpect(status().isOk()) | |||
.andExpect(content().json(expectedJson)); | |||
} | |||
@Test | |||
void getJres_shoudlReturnEmptyJsonArray_whenNoResults() throws Exception { | |||
when(jresHandler.getJresMetadata(null, null)).thenReturn(List.of()); | |||
mockMvc.perform(get(JRE_ENDPOINT)) | |||
.andExpect(status().isOk()) | |||
.andExpect(content().json("[]")); | |||
} | |||
private static Stream<Arguments> osAndArch() { | |||
return Stream.of( | |||
arguments(null, null), | |||
arguments("windows", null), | |||
arguments(null, "x64"), | |||
arguments("linux", "aarch64") | |||
); | |||
} | |||
@Test | |||
void getJre_shouldReturnMetadataAsJson() throws Exception { | |||
String anyId = "anyId"; | |||
JreInfoRestResponse jreInfoRestResponse = new JreInfoRestResponse(anyId, "filename", "sha256", "javaPath", "os", "arch"); | |||
when(jresHandler.getJreMetadata(anyId)).thenReturn(jreInfoRestResponse); | |||
String expectedJson = "{\"id\":\"" + anyId + "\",\"filename\":\"filename\",\"sha256\":\"sha256\",\"javaPath\":\"javaPath\",\"os\":\"os\",\"arch\":\"arch\"}"; | |||
mockMvc.perform(get(JRE_ENDPOINT + "/" + anyId)) | |||
.andExpect(status().isOk()) | |||
.andExpect(content().json(expectedJson)); | |||
} | |||
@Test | |||
void getJre_shouldDownloadJre_whenHeaderIsOctetStream() throws Exception { | |||
String anyId = "anyId"; | |||
String anyFilename = "anyFilename"; | |||
JreInfoRestResponse jreInfoRestResponse = new JreInfoRestResponse(anyId, anyFilename, "sha256", "javaPath", "os", "arch"); | |||
when(jresHandler.getJreMetadata(anyId)).thenReturn(jreInfoRestResponse); | |||
byte[] anyBinary = {1, 2, 3}; | |||
when(jresHandler.getJreBinary(anyFilename)).thenReturn(new ByteArrayInputStream(anyBinary)); | |||
mockMvc.perform(get(JRE_ENDPOINT + "/" + anyId) | |||
.header("Accept", APPLICATION_OCTET_STREAM_VALUE)) | |||
.andExpect(status().isOk()) | |||
.andExpect(content().contentType(APPLICATION_OCTET_STREAM)) | |||
.andExpect(content().bytes(anyBinary)); | |||
} | |||
} |
@@ -19,7 +19,7 @@ | |||
*/ | |||
package org.sonar.server.v2.api.analysis.controller; | |||
import org.junit.Test; | |||
import org.junit.jupiter.api.Test; | |||
import org.sonar.api.platform.Server; | |||
import org.springframework.test.web.servlet.MockMvc; | |||
@@ -31,14 +31,14 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder | |||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; | |||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | |||
public class DefaultVersionControllerTest { | |||
class DefaultVersionControllerTest { | |||
private final Server server = mock(Server.class); | |||
private final MockMvc mockMvc = getMockMvc(new DefaultVersionController(server)); | |||
@Test | |||
public void getVersion_shouldReturnServerVersion() throws Exception { | |||
void getVersion_shouldReturnServerVersion() throws Exception { | |||
String serverVersion = "10.6"; | |||
when(server.getVersion()).thenReturn(serverVersion); | |||
@@ -0,0 +1,130 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 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 | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.v2.api.analysis.service; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.stream.Stream; | |||
import org.junit.jupiter.api.BeforeAll; | |||
import org.junit.jupiter.api.Test; | |||
import org.junit.jupiter.params.ParameterizedTest; | |||
import org.junit.jupiter.params.provider.Arguments; | |||
import org.junit.jupiter.params.provider.MethodSource; | |||
import org.junit.jupiter.params.provider.ValueSource; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
import org.sonar.server.v2.api.analysis.response.JreInfoRestResponse; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
import static org.junit.jupiter.params.provider.Arguments.arguments; | |||
class JresHandlerImplTest { | |||
private static final Map<String, JreInfoRestResponse> JRE_METADATA = Map.of( | |||
"1", new JreInfoRestResponse("1", "jre1", "checksum1", "java1", "alpine", "aarch64"), | |||
"2", new JreInfoRestResponse("2", "jre2", "checksum2", "java2", "linux", "aarch64"), | |||
"3", new JreInfoRestResponse("3", "jre3", "checksum3", "java3", "alpine", "x64") | |||
); | |||
private static final JresHandlerImpl jresHandler = new JresHandlerImpl("jres-metadata-tests.json"); | |||
@BeforeAll | |||
static void setup() { | |||
jresHandler.initMetadata(); | |||
} | |||
@Test | |||
void getJresMetadata_shouldReturnAllMetadata_whenNoFiltering() { | |||
List<JreInfoRestResponse> result = jresHandler.getJresMetadata(null, null); | |||
assertThat(result).extracting(JreInfoRestResponse::id).containsExactly("1", "2", "3"); | |||
} | |||
@ParameterizedTest | |||
@MethodSource("filteredMetadata") | |||
void getJresMetadata_shouldReturnFilteredMetadata_whenFiltering(String os, String arch, JreInfoRestResponse expected) { | |||
List<JreInfoRestResponse> resultList = jresHandler.getJresMetadata(os, arch); | |||
assertThat(resultList).hasSize(1); | |||
JreInfoRestResponse result = resultList.get(0); | |||
assertThat(result).usingRecursiveComparison().isEqualTo(expected); | |||
} | |||
@Test | |||
void getJresMetadata_shouldFail_whenFilteredWithUnsupportedOsValue() { | |||
String anyUnsupportedOS = "not-supported"; | |||
assertThatThrownBy(() -> jresHandler.getJresMetadata(anyUnsupportedOS, null)) | |||
.isInstanceOf(IllegalArgumentException.class) | |||
.hasMessageStartingWith("Unsupported OS: '" + anyUnsupportedOS + "'"); | |||
} | |||
@Test | |||
void getJresMetadata_shouldFail_whenFilteredWithUnsupportedArchValue() { | |||
String anyUnsupportedArch = "not-supported"; | |||
assertThatThrownBy(() -> jresHandler.getJresMetadata(null, anyUnsupportedArch)) | |||
.isInstanceOf(IllegalArgumentException.class) | |||
.hasMessageStartingWith("Unsupported architecture: '" + anyUnsupportedArch + "'"); | |||
} | |||
private static Stream<Arguments> filteredMetadata() { | |||
return Stream.of( | |||
arguments("alpine", "aarch64", JRE_METADATA.get("1")), | |||
arguments("linux", null, JRE_METADATA.get("2")), | |||
arguments(null, "x64", JRE_METADATA.get("3")) | |||
); | |||
} | |||
@Test | |||
void getJresMetadata_shouldReturnEmptyList_whenNoMetadata() { | |||
List<JreInfoRestResponse> result = jresHandler.getJresMetadata("windows", "x64"); | |||
assertThat(result).isEmpty(); | |||
} | |||
@Test | |||
void getJresMetadata_shouldReturnEmptyList_whenNoFilteringAndNoMetadata() { | |||
JresHandlerImpl noMetadataHandler = new JresHandlerImpl(""); | |||
List<JreInfoRestResponse> result = noMetadataHandler.getJresMetadata(null, null); | |||
assertThat(result).isEmpty(); | |||
} | |||
@ParameterizedTest | |||
@ValueSource(strings = {"1", "2", "3"}) | |||
void getJreMetadata(String id) { | |||
JreInfoRestResponse result = jresHandler.getJreMetadata(id); | |||
assertThat(result).usingRecursiveComparison().isEqualTo(JRE_METADATA.get(id)); | |||
} | |||
@Test | |||
void getJreMetadata_shouldFail_whenJreNotFound() { | |||
assertThatThrownBy(() -> jresHandler.getJreMetadata("4")) | |||
.isInstanceOf(NotFoundException.class) | |||
.hasMessage("JRE not found for id: 4"); | |||
} | |||
@Test | |||
void getJreBinary_shouldFail_whenFileNotFound() { | |||
assertThatThrownBy(() -> jresHandler.getJreBinary("jre1")) | |||
.isInstanceOf(NotFoundException.class) | |||
.hasMessage("Unable to find JRE 'jre1'"); | |||
} | |||
} |
@@ -19,20 +19,35 @@ | |||
*/ | |||
package org.sonar.server.v2.config; | |||
import org.junit.Test; | |||
import java.util.stream.Stream; | |||
import org.junit.jupiter.params.ParameterizedTest; | |||
import org.junit.jupiter.params.provider.Arguments; | |||
import org.junit.jupiter.params.provider.MethodSource; | |||
import org.sonar.api.platform.Server; | |||
import org.sonar.server.v2.api.analysis.controller.DefaultJresController; | |||
import org.sonar.server.v2.api.analysis.controller.DefaultVersionController; | |||
import org.sonar.server.v2.api.analysis.service.JresHandler; | |||
import org.sonar.server.v2.api.analysis.service.JresHandlerImpl; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.junit.jupiter.params.provider.Arguments.arguments; | |||
import static org.mockito.Mockito.mock; | |||
public class PlatformLevel4WebConfigTest { | |||
private final PlatformLevel4WebConfig platformLevel4WebConfig = new PlatformLevel4WebConfig(); | |||
private static final PlatformLevel4WebConfig platformLevel4WebConfig = new PlatformLevel4WebConfig(); | |||
@Test | |||
public void versionController() { | |||
assertThat(platformLevel4WebConfig.versionController(mock(Server.class))).isNotNull() | |||
.isInstanceOf(DefaultVersionController.class); | |||
private static Stream<Arguments> components() { | |||
return Stream.of( | |||
arguments(platformLevel4WebConfig.versionController(mock(Server.class)), DefaultVersionController.class), | |||
arguments(platformLevel4WebConfig.jresHandler(), JresHandlerImpl.class), | |||
arguments(platformLevel4WebConfig.jresController(mock(JresHandler.class)), DefaultJresController.class) | |||
); | |||
} | |||
@ParameterizedTest | |||
@MethodSource("components") | |||
void components_shouldBeInjectedInPlatformLevel4WebConfig(Object component, Class<?> instanceClass) { | |||
assertThat(component).isNotNull().isInstanceOf(instanceClass); | |||
} | |||
} |
@@ -0,0 +1,22 @@ | |||
[ { | |||
"id" : "1", | |||
"filename" : "jre1", | |||
"sha256" : "checksum1", | |||
"javaPath" : "java1", | |||
"os" : "alpine", | |||
"arch" : "aarch64" | |||
}, { | |||
"id" : "2", | |||
"filename" : "jre2", | |||
"sha256" : "checksum2", | |||
"javaPath" : "java2", | |||
"os" : "linux", | |||
"arch" : "aarch64" | |||
}, { | |||
"id" : "3", | |||
"filename" : "jre3", | |||
"sha256" : "checksum3", | |||
"javaPath" : "java3", | |||
"os" : "alpine", | |||
"arch" : "x64" | |||
} ] |