@@ -0,0 +1,49 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2023 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.common; | |||
import org.junit.Before; | |||
import org.junit.runner.RunWith; | |||
import org.sonar.server.v2.config.MockConfigForControllers; | |||
import org.sonar.server.v2.config.PlatformLevel4WebConfig; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import org.springframework.test.context.ContextConfiguration; | |||
import org.springframework.test.context.junit4.SpringRunner; | |||
import org.springframework.test.context.web.WebAppConfiguration; | |||
import org.springframework.test.web.servlet.MockMvc; | |||
import org.springframework.test.web.servlet.setup.MockMvcBuilders; | |||
import org.springframework.web.context.WebApplicationContext; | |||
@WebAppConfiguration | |||
@ContextConfiguration( | |||
classes = {PlatformLevel4WebConfig.class, MockConfigForControllers.class} | |||
) | |||
@RunWith(SpringRunner.class) | |||
public abstract class ControllerIT { | |||
@Autowired | |||
protected WebApplicationContext webAppContext; | |||
protected MockMvc mockMvc; | |||
@Before | |||
public void setup() { | |||
mockMvc = MockMvcBuilders.webAppContextSetup(webAppContext).build(); | |||
} | |||
} |
@@ -0,0 +1,101 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2023 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.config; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.server.health.CeStatusNodeCheck; | |||
import org.sonar.server.health.DbConnectionNodeCheck; | |||
import org.sonar.server.health.EsStatusNodeCheck; | |||
import org.sonar.server.health.HealthChecker; | |||
import org.sonar.server.health.WebServerStatusNodeCheck; | |||
import org.sonar.server.management.ManagedInstanceChecker; | |||
import org.sonar.server.platform.NodeInformation; | |||
import org.sonar.server.platform.ws.LivenessChecker; | |||
import org.sonar.server.user.SystemPasscode; | |||
import org.sonar.server.user.UserSession; | |||
import org.sonar.server.user.UserUpdater; | |||
import org.springframework.context.annotation.Bean; | |||
import org.springframework.context.annotation.Configuration; | |||
import static org.mockito.Mockito.mock; | |||
@Configuration | |||
public class MockConfigForControllers { | |||
@Bean | |||
public DbClient dbClient() { | |||
return mock(DbClient.class); | |||
} | |||
@Bean | |||
public DbConnectionNodeCheck dbConnectionNodeCheck() { | |||
return mock(DbConnectionNodeCheck.class); | |||
} | |||
@Bean | |||
public WebServerStatusNodeCheck webServerStatusNodeCheck() { | |||
return mock(WebServerStatusNodeCheck.class); | |||
} | |||
@Bean | |||
public CeStatusNodeCheck ceStatusNodeCheck() { | |||
return mock(CeStatusNodeCheck.class); | |||
} | |||
@Bean | |||
public EsStatusNodeCheck esStatusNodeCheck() { | |||
return mock(EsStatusNodeCheck.class); | |||
} | |||
@Bean | |||
public LivenessChecker livenessChecker() { | |||
return mock(LivenessChecker.class); | |||
} | |||
@Bean | |||
public HealthChecker healthChecker() { | |||
return mock(HealthChecker.class); | |||
} | |||
@Bean | |||
public SystemPasscode systemPasscode() { | |||
return mock(SystemPasscode.class); | |||
} | |||
@Bean | |||
public NodeInformation nodeInformation() { | |||
return mock(NodeInformation.class); | |||
} | |||
@Bean | |||
public UserSession userSession() { | |||
return mock(UserSession.class); | |||
} | |||
@Bean | |||
UserUpdater userUpdater() { | |||
return mock(UserUpdater.class); | |||
} | |||
@Bean | |||
ManagedInstanceChecker managedInstanceChecker() { | |||
return mock(ManagedInstanceChecker.class); | |||
} | |||
} |
@@ -0,0 +1,100 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2023 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.controller; | |||
import org.junit.After; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.mockito.Mockito; | |||
import org.sonar.server.platform.ws.LivenessChecker; | |||
import org.sonar.server.user.SystemPasscode; | |||
import org.sonar.server.user.UserSession; | |||
import org.sonar.server.v2.common.ControllerIT; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.server.user.SystemPasscodeImpl.PASSCODE_HTTP_HEADER; | |||
import static org.sonar.server.v2.WebApiEndpoints.LIVENESS_ENDPOINT; | |||
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; | |||
public class DefaultLivenessControllerIT extends ControllerIT { | |||
private static final String VALID_PASSCODE = "valid_passcode"; | |||
private static final String INVALID_PASSCODE = "invalid_passcode"; | |||
@Before | |||
public void setup() { | |||
super.setup(); | |||
when(webAppContext.getBean(LivenessChecker.class).liveness()).thenReturn(true); | |||
} | |||
@After | |||
public void resetUsedMocks() { | |||
Mockito.reset(webAppContext.getBean(SystemPasscode.class)); | |||
Mockito.reset(webAppContext.getBean(UserSession.class)); | |||
} | |||
@Test | |||
public void getSystemLiveness_whenValidPasscode_shouldSucceed() throws Exception { | |||
when(webAppContext.getBean(SystemPasscode.class).isValidPasscode(VALID_PASSCODE)).thenReturn(true); | |||
mockMvc.perform(get(LIVENESS_ENDPOINT).header(PASSCODE_HTTP_HEADER, VALID_PASSCODE)) | |||
.andExpect(status().isNoContent()); | |||
} | |||
@Test | |||
public void getSystemLiveness_whenAdminCredential_shouldSucceed() throws Exception { | |||
when(webAppContext.getBean(UserSession.class).isSystemAdministrator()).thenReturn(true); | |||
mockMvc.perform(get(LIVENESS_ENDPOINT)) | |||
.andExpect(status().isNoContent()); | |||
} | |||
@Test | |||
public void getSystemLiveness_whenNoUserSessionAndNoPasscode_shouldReturnForbidden() throws Exception { | |||
mockMvc.perform(get(LIVENESS_ENDPOINT)) | |||
.andExpectAll( | |||
status().isForbidden(), | |||
content().string("Insufficient privileges")); | |||
} | |||
@Test | |||
public void getSystemLiveness_whenInvalidPasscodeAndNoAdminCredentials_shouldReturnForbidden() throws Exception { | |||
when(webAppContext.getBean(SystemPasscode.class).isValidPasscode(INVALID_PASSCODE)).thenReturn(false); | |||
when(webAppContext.getBean(UserSession.class).isSystemAdministrator()).thenReturn(false); | |||
mockMvc.perform(get(LIVENESS_ENDPOINT).header(PASSCODE_HTTP_HEADER, INVALID_PASSCODE)) | |||
.andExpectAll( | |||
status().isForbidden(), | |||
content().string("Insufficient privileges")); | |||
} | |||
@Test | |||
public void getSystemLiveness_whenLivenessCheckFails_shouldReturnServerError() throws Exception { | |||
when(webAppContext.getBean(SystemPasscode.class).isValidPasscode(VALID_PASSCODE)).thenReturn(true); | |||
when(webAppContext.getBean(LivenessChecker.class).liveness()).thenReturn(false); | |||
mockMvc.perform(get(LIVENESS_ENDPOINT).header(PASSCODE_HTTP_HEADER, VALID_PASSCODE)) | |||
.andExpectAll( | |||
status().isInternalServerError(), | |||
content().string("Liveness check failed")); | |||
} | |||
} |
@@ -0,0 +1,138 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2023 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.controller; | |||
import org.junit.After; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.mockito.Mockito; | |||
import org.sonar.server.exceptions.UnauthorizedException; | |||
import org.sonar.server.health.Health; | |||
import org.sonar.server.health.HealthChecker; | |||
import org.sonar.server.platform.NodeInformation; | |||
import org.sonar.server.user.SystemPasscode; | |||
import org.sonar.server.user.UserSession; | |||
import org.sonar.server.v2.common.ControllerIT; | |||
import static java.net.HttpURLConnection.HTTP_NOT_IMPLEMENTED; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.server.user.SystemPasscodeImpl.PASSCODE_HTTP_HEADER; | |||
import static org.sonar.server.v2.WebApiEndpoints.HEALTH_ENDPOINT; | |||
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; | |||
public class HealthControllerIT extends ControllerIT { | |||
private static final String VALID_PASSCODE = "valid_passcode"; | |||
private static final String INVALID_PASSCODE = "invalid_passcode"; | |||
private static final Health HEALTH_RESULT = Health.builder(). | |||
setStatus(Health.Status.YELLOW) | |||
.addCause("One cause") | |||
.build(); | |||
@Before | |||
public void setup() { | |||
super.setup(); | |||
when(webAppContext.getBean(HealthChecker.class).checkNode()).thenReturn(HEALTH_RESULT); | |||
} | |||
@After | |||
public void resetUsedMocks() { | |||
Mockito.reset(webAppContext.getBean(SystemPasscode.class)); | |||
Mockito.reset(webAppContext.getBean(NodeInformation.class)); | |||
Mockito.reset(webAppContext.getBean(UserSession.class)); | |||
} | |||
@Test | |||
public void getSystemHealth_whenValidPasscodeAndStandaloneMode_shouldSucceed() throws Exception { | |||
when(webAppContext.getBean(SystemPasscode.class).isValidPasscode(VALID_PASSCODE)).thenReturn(true); | |||
when(webAppContext.getBean(NodeInformation.class).isStandalone()).thenReturn(true); | |||
mockMvc.perform(get(HEALTH_ENDPOINT).header(PASSCODE_HTTP_HEADER, VALID_PASSCODE)) | |||
.andExpectAll( | |||
status().isOk(), | |||
content().json(""" | |||
{ | |||
"status":"YELLOW", | |||
"causes":[ | |||
"One cause" | |||
] | |||
}""")); | |||
} | |||
@Test | |||
public void getSystemHealth_whenAdminCredentialAndStandaloneMode_shouldSucceed() throws Exception { | |||
when(webAppContext.getBean(UserSession.class).isSystemAdministrator()).thenReturn(true); | |||
when(webAppContext.getBean(NodeInformation.class).isStandalone()).thenReturn(true); | |||
mockMvc.perform(get(HEALTH_ENDPOINT)) | |||
.andExpectAll( | |||
status().isOk(), | |||
content().json(""" | |||
{ | |||
"status":"YELLOW", | |||
"causes":[ | |||
"One cause" | |||
] | |||
}""")); | |||
} | |||
@Test | |||
public void getSystemHealth_whenNoCredentials_shouldReturnForbidden() throws Exception { | |||
mockMvc.perform(get(HEALTH_ENDPOINT)) | |||
.andExpectAll( | |||
status().isForbidden(), | |||
content().string("Insufficient privileges")); | |||
} | |||
@Test | |||
public void getSystemHealth_whenInvalidPasscodeAndNoAdminCredentials_shouldReturnForbidden() throws Exception { | |||
when(webAppContext.getBean(SystemPasscode.class).isValidPasscode(INVALID_PASSCODE)).thenReturn(false); | |||
when(webAppContext.getBean(UserSession.class).isSystemAdministrator()).thenReturn(false); | |||
mockMvc.perform(get(HEALTH_ENDPOINT).header(PASSCODE_HTTP_HEADER, INVALID_PASSCODE)) | |||
.andExpectAll( | |||
status().isForbidden(), | |||
content().string("Insufficient privileges")); | |||
} | |||
@Test | |||
public void getSystemHealth_whenUnauthorizedExceptionThrown_shouldReturnUnauthorized() throws Exception { | |||
when(webAppContext.getBean(UserSession.class).isSystemAdministrator()).thenThrow(new UnauthorizedException("UnauthorizedException")); | |||
mockMvc.perform(get(HEALTH_ENDPOINT)) | |||
.andExpectAll( | |||
status().isUnauthorized(), | |||
content().string("UnauthorizedException")); | |||
} | |||
@Test | |||
public void getSystemHealth_whenValidPasscodeAndClusterMode_shouldReturnNotImplemented() throws Exception { | |||
when(webAppContext.getBean(SystemPasscode.class).isValidPasscode(VALID_PASSCODE)).thenReturn(true); | |||
when(webAppContext.getBean(NodeInformation.class).isStandalone()).thenReturn(false); | |||
mockMvc.perform(get(HEALTH_ENDPOINT).header(PASSCODE_HTTP_HEADER, VALID_PASSCODE)) | |||
.andExpectAll( | |||
status().is(HTTP_NOT_IMPLEMENTED), | |||
content().string("Unsupported in cluster mode")); | |||
} | |||
} |
@@ -20,7 +20,7 @@ | |||
package org.sonar.server.v2; | |||
public class WebApiEndpoints { | |||
private static final String SYSTEM_ENDPOINTS = "/system/"; | |||
private static final String SYSTEM_ENDPOINTS = "/system"; | |||
public static final String LIVENESS_ENDPOINT = SYSTEM_ENDPOINTS + "/liveness"; | |||
@@ -28,5 +28,4 @@ public class WebApiEndpoints { | |||
private WebApiEndpoints() { | |||
} | |||
} |
@@ -32,13 +32,14 @@ import org.springframework.web.bind.annotation.RequestMapping; | |||
import org.springframework.web.bind.annotation.RestController; | |||
import static java.net.HttpURLConnection.HTTP_NOT_IMPLEMENTED; | |||
import static org.sonar.server.v2.WebApiEndpoints.HEALTH_ENDPOINT; | |||
/* | |||
This controller does not support the cluster mode. | |||
This is not the final implementation, as we have to first define what are endpoint contracts. | |||
*/ | |||
@RestController | |||
@RequestMapping("/system/health") | |||
@RequestMapping(HEALTH_ENDPOINT) | |||
public class HealthController { | |||
private final HealthChecker healthChecker; |
@@ -1,111 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2023 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.controller; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.junit.runner.RunWith; | |||
import org.mockito.InjectMocks; | |||
import org.mockito.Mock; | |||
import org.mockito.junit.MockitoJUnitRunner; | |||
import org.sonar.server.platform.ws.LivenessChecker; | |||
import org.sonar.server.user.SystemPasscode; | |||
import org.sonar.server.user.UserSession; | |||
import org.sonar.server.v2.common.RestResponseEntityExceptionHandler; | |||
import org.springframework.test.web.servlet.MockMvc; | |||
import org.springframework.test.web.servlet.setup.MockMvcBuilders; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.server.user.SystemPasscodeImpl.PASSCODE_HTTP_HEADER; | |||
import static org.sonar.server.v2.WebApiEndpoints.LIVENESS_ENDPOINT; | |||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; | |||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | |||
@RunWith(MockitoJUnitRunner.class) | |||
public class DefautLivenessControllerTest { | |||
private static final String PASSCODE = "1234"; | |||
@Mock | |||
private LivenessChecker livenessChecker; | |||
@Mock | |||
private UserSession userSession; | |||
@Mock | |||
private SystemPasscode systemPasscode; | |||
@InjectMocks | |||
private DefautLivenessController defautLivenessController; | |||
private MockMvc mockMvc; | |||
@Before | |||
public void setUp() { | |||
mockMvc = MockMvcBuilders.standaloneSetup(defautLivenessController) | |||
.setControllerAdvice(RestResponseEntityExceptionHandler.class) | |||
.build(); | |||
} | |||
@Test | |||
public void livenessCheck_inSafeModeWithoutUserSessionAndPasscode_returnsForbidden() throws Exception { | |||
LivenessController safeModeLivenessController = new DefautLivenessController(livenessChecker, systemPasscode, null); | |||
MockMvc mockMvcSafeMode = MockMvcBuilders.standaloneSetup(safeModeLivenessController) | |||
.setControllerAdvice(RestResponseEntityExceptionHandler.class) | |||
.build(); | |||
mockMvcSafeMode.perform(get(LIVENESS_ENDPOINT)) | |||
.andExpect(status().isForbidden()); | |||
} | |||
@Test | |||
public void livenessCheck_should_returnForbiddenWithNoCredentials() throws Exception { | |||
mockMvc.perform(get(LIVENESS_ENDPOINT)) | |||
.andExpect(status().isForbidden()); | |||
} | |||
@Test | |||
public void livenessCheck_should_returnForbiddenWithWrongPasscodeAndNoAdminCredentials() throws Exception { | |||
when(systemPasscode.isValidPasscode(PASSCODE)).thenReturn(false); | |||
when(userSession.isSystemAdministrator()).thenReturn(false); | |||
mockMvc.perform(get(LIVENESS_ENDPOINT).header(PASSCODE_HTTP_HEADER, PASSCODE)) | |||
.andExpect(status().isForbidden()); | |||
} | |||
@Test | |||
public void livenessCheck_should_returnNoContentWithSystemPasscode() throws Exception { | |||
when(systemPasscode.isValidPasscode(PASSCODE)).thenReturn(true); | |||
when(livenessChecker.liveness()).thenReturn(true); | |||
mockMvc.perform(get(LIVENESS_ENDPOINT).header(PASSCODE_HTTP_HEADER, PASSCODE)) | |||
.andExpect(status().isNoContent()); | |||
} | |||
@Test | |||
public void livenessCheck_should_returnNoContentWithWhenUserIsAdmin() throws Exception { | |||
when(userSession.isSystemAdministrator()).thenReturn(true); | |||
when(livenessChecker.liveness()).thenReturn(true); | |||
mockMvc.perform(get(LIVENESS_ENDPOINT).header(PASSCODE_HTTP_HEADER, PASSCODE)) | |||
.andExpect(status().isNoContent()); | |||
} | |||
@Test | |||
public void livenessCheck_should_returnServerErrorWhenLivenessCheckFails() throws Exception { | |||
when(systemPasscode.isValidPasscode(PASSCODE)).thenReturn(true); | |||
when(livenessChecker.liveness()).thenReturn(false); | |||
mockMvc.perform(get(LIVENESS_ENDPOINT).header(PASSCODE_HTTP_HEADER, PASSCODE)) | |||
.andExpect(status().isInternalServerError()); | |||
} | |||
} |
@@ -1,157 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2023 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.controller; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.junit.runner.RunWith; | |||
import org.mockito.Mock; | |||
import org.mockito.junit.MockitoJUnitRunner; | |||
import org.sonar.server.exceptions.UnauthorizedException; | |||
import org.sonar.server.health.Health; | |||
import org.sonar.server.health.HealthChecker; | |||
import org.sonar.server.platform.NodeInformation; | |||
import org.sonar.server.user.SystemPasscode; | |||
import org.sonar.server.user.UserSession; | |||
import org.sonar.server.v2.common.RestResponseEntityExceptionHandler; | |||
import org.springframework.test.web.servlet.MockMvc; | |||
import org.springframework.test.web.servlet.setup.MockMvcBuilders; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.server.user.SystemPasscodeImpl.PASSCODE_HTTP_HEADER; | |||
import static org.sonar.server.v2.WebApiEndpoints.HEALTH_ENDPOINT; | |||
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; | |||
@RunWith(MockitoJUnitRunner.class) | |||
public class HealthControllerTest { | |||
private static final String PASSCODE = "1234"; | |||
private static final Health HEALTH_RESULT = Health.builder(). | |||
setStatus(Health.Status.YELLOW) | |||
.addCause("One cause") | |||
.build(); | |||
@Mock | |||
private HealthChecker healthChecker; | |||
@Mock | |||
private UserSession userSession; | |||
@Mock | |||
private SystemPasscode systemPasscode; | |||
@Mock | |||
private NodeInformation nodeInformation; | |||
private HealthController level4HealthController; | |||
private HealthController safeModeHealthController; | |||
private MockMvc level4mockMvc; | |||
private MockMvc safeModeMockMvc; | |||
@Before | |||
public void setUp() { | |||
level4HealthController = new HealthController(healthChecker, systemPasscode, nodeInformation, userSession); | |||
level4mockMvc = MockMvcBuilders.standaloneSetup(level4HealthController) | |||
.setControllerAdvice(RestResponseEntityExceptionHandler.class) | |||
.build(); | |||
safeModeHealthController = new HealthController(healthChecker, systemPasscode); | |||
safeModeMockMvc = MockMvcBuilders.standaloneSetup(safeModeHealthController) | |||
.setControllerAdvice(RestResponseEntityExceptionHandler.class) | |||
.build(); | |||
when(healthChecker.checkNode()).thenReturn(HEALTH_RESULT); | |||
} | |||
@Test | |||
public void getHealth_inSafeModeWithoutUserSessionAndPasscode_returnsForbidden() throws Exception { | |||
safeModeMockMvc.perform(get(HEALTH_ENDPOINT)) | |||
.andExpect(status().isForbidden()); | |||
} | |||
@Test | |||
public void getHealth_inSafeModeWithValidPasscode_succeeds() throws Exception { | |||
when(systemPasscode.isValidPasscode(PASSCODE)).thenReturn(true); | |||
safeModeMockMvc.perform(get(HEALTH_ENDPOINT).header(PASSCODE_HTTP_HEADER, PASSCODE)) | |||
.andExpect(status().isOk()); | |||
} | |||
@Test | |||
public void getHealth_should_returnForbiddenWithNoCredentials() throws Exception { | |||
level4mockMvc.perform(get(HEALTH_ENDPOINT)) | |||
.andExpect(status().isForbidden()); | |||
} | |||
@Test | |||
public void getHealth_should_returnForbiddenWithWrongPasscodeAndNoAdminCredentials() throws Exception { | |||
when(systemPasscode.isValidPasscode(PASSCODE)).thenReturn(false); | |||
when(userSession.isSystemAdministrator()).thenReturn(false); | |||
level4mockMvc.perform(get(HEALTH_ENDPOINT).header(PASSCODE_HTTP_HEADER, PASSCODE)) | |||
.andExpect(status().isForbidden()); | |||
} | |||
@Test | |||
public void getHealth_withValidPasscodeAndStandaloneNode_returnHealth() throws Exception { | |||
when(systemPasscode.isValidPasscode(PASSCODE)).thenReturn(true); | |||
when(nodeInformation.isStandalone()).thenReturn(true); | |||
level4mockMvc.perform(get(HEALTH_ENDPOINT).header(PASSCODE_HTTP_HEADER, PASSCODE)) | |||
.andExpect(status().isOk()) | |||
.andExpect(content().json(""" | |||
{ | |||
"status":"YELLOW", | |||
"causes":[ | |||
"One cause" | |||
] | |||
}""")); | |||
} | |||
@Test | |||
public void getHealth_asSysadminAndStandaloneNode_returnHealth() throws Exception { | |||
when(userSession.isSystemAdministrator()).thenReturn(true); | |||
when(nodeInformation.isStandalone()).thenReturn(true); | |||
level4mockMvc.perform(get(HEALTH_ENDPOINT)) | |||
.andExpect(status().isOk()) | |||
.andExpect(content().json(""" | |||
{ | |||
"status":"YELLOW", | |||
"causes":[ | |||
"One cause" | |||
] | |||
}""")); | |||
} | |||
@Test | |||
public void getHealth_whenUnauthorizedExceptionThrown_returnHttpUnauthorized() throws Exception { | |||
when(userSession.isSystemAdministrator()).thenThrow(new UnauthorizedException("unauthorized")); | |||
level4mockMvc.perform(get(HEALTH_ENDPOINT)) | |||
.andExpect(status().isUnauthorized()); | |||
} | |||
@Test | |||
public void getHealth_should_returnServerErrorForCluster() throws Exception { | |||
when(systemPasscode.isValidPasscode(PASSCODE)).thenReturn(true); | |||
when(nodeInformation.isStandalone()).thenReturn(false); | |||
level4mockMvc.perform(get(HEALTH_ENDPOINT).header(PASSCODE_HTTP_HEADER, PASSCODE)) | |||
.andExpect(status().isNotImplemented()) | |||
.andExpect(content().string("Unsupported in cluster mode")); | |||
} | |||
} |