diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigAutoConfigurationResource.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigAutoConfigurationResource.java index 2198262275..b265f2929d 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigAutoConfigurationResource.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigAutoConfigurationResource.java @@ -7,7 +7,9 @@ import com.webcohesion.enunciate.metadata.rs.TypeHint; import sonia.scm.config.ConfigurationPermissions; import sonia.scm.repository.HgConfig; import sonia.scm.repository.HgRepositoryHandler; +import sonia.scm.web.HgVndMediaType; +import javax.ws.rs.Consumes; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.core.Response; @@ -15,9 +17,12 @@ import javax.ws.rs.core.Response; public class HgConfigAutoConfigurationResource { private final HgRepositoryHandler repositoryHandler; + private final HgConfigDtoToHgConfigMapper dtoToConfigMapper; @Inject - public HgConfigAutoConfigurationResource(HgRepositoryHandler repositoryHandler) { + public HgConfigAutoConfigurationResource(HgConfigDtoToHgConfigMapper dtoToConfigMapper, + HgRepositoryHandler repositoryHandler) { + this.dtoToConfigMapper = dtoToConfigMapper; this.repositoryHandler = repositoryHandler; } @@ -44,6 +49,7 @@ public class HgConfigAutoConfigurationResource { */ @PUT @Path("") + @Consumes(HgVndMediaType.CONFIG) @StatusCodes({ @ResponseCode(code = 204, condition = "update success"), @ResponseCode(code = 401, condition = "not authenticated / invalid credentials"), @@ -52,11 +58,13 @@ public class HgConfigAutoConfigurationResource { }) @TypeHint(TypeHint.NO_CONTENT.class) public Response autoConfiguration(HgConfigDto configDto) { - HgConfig config = repositoryHandler.getConfig(); - if (config == null) { + HgConfig config; + + if (configDto != null) { + config = dtoToConfigMapper.map(configDto); + } else { config = new HgConfig(); - repositoryHandler.setConfig(config); } ConfigurationPermissions.write(config).check(); diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigPackageResource.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigPackageResource.java index a2fca37ff2..7e3c0e9a66 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigPackageResource.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigPackageResource.java @@ -80,7 +80,7 @@ public class HgConfigPackageResource { HgPackage pkg = pkgReader.getPackage(pkgId); - // First path parm cannot be null (leaving it results in 405) + // First path param cannot be null (leaving it results in 405) if (HgInstallerFactory.createInstaller() .installPackage(client, handler, SCMContext.getContext().getBaseDirectory(), pkg)) { response = Response.noContent().build(); diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigResource.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigResource.java index f98300251f..e6a8f01238 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigResource.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigResource.java @@ -60,6 +60,8 @@ public class HgConfigResource { }) public Response get() { + ConfigurationPermissions.read(HgConfig.PERMISSION).check(); + HgConfig config = repositoryHandler.getConfig(); if (config == null) { @@ -67,8 +69,6 @@ public class HgConfigResource { repositoryHandler.setConfig(config); } - ConfigurationPermissions.read(config).check(); - return Response.ok(configToDtoMapper.map(config)).build(); } diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigAutoConfigurationResourceTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigAutoConfigurationResourceTest.java new file mode 100644 index 0000000000..0c766eb4e6 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigAutoConfigurationResourceTest.java @@ -0,0 +1,125 @@ +package sonia.scm.api.v2.resources; + +import com.github.sdorra.shiro.ShiroRule; +import com.github.sdorra.shiro.SubjectAware; +import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.mock.MockDispatcherFactory; +import org.jboss.resteasy.mock.MockHttpRequest; +import org.jboss.resteasy.mock.MockHttpResponse; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import sonia.scm.repository.HgConfig; +import sonia.scm.repository.HgRepositoryHandler; +import sonia.scm.web.HgVndMediaType; + +import javax.inject.Provider; +import javax.servlet.http.HttpServletResponse; +import java.net.URISyntaxException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@SubjectAware( + configuration = "classpath:sonia/scm/configuration/shiro.ini", + password = "secret" +) +@RunWith(MockitoJUnitRunner.class) +public class HgConfigAutoConfigurationResourceTest { + + @Rule + public ShiroRule shiro = new ShiroRule(); + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private Dispatcher dispatcher = MockDispatcherFactory.createDispatcher(); + + @InjectMocks + private HgConfigDtoToHgConfigMapperImpl dtoToConfigMapper; + + @Mock + private HgRepositoryHandler repositoryHandler; + + @Mock + private Provider resourceProvider; + + @Before + public void prepareEnvironment() { + HgConfigAutoConfigurationResource resource = + new HgConfigAutoConfigurationResource(dtoToConfigMapper, repositoryHandler); + + when(resourceProvider.get()).thenReturn(resource); + dispatcher.getRegistry().addSingletonResource( + new HgConfigResource(null, null, null, null, + resourceProvider, null)); + } + + @Test + @SubjectAware(username = "writeOnly") + public void shouldSetDefaultConfigAndInstallHg() throws Exception { + MockHttpResponse response = put(null); + + assertEquals(HttpServletResponse.SC_NO_CONTENT, response.getStatus()); + + HgConfig actualConfig = captureConfig(); + assertFalse(actualConfig.isDisabled()); + } + + @Test + @SubjectAware(username = "readOnly") + public void shouldSetDefaultConfigAndInstallHgOnlyWhenAuthorized() throws Exception { + thrown.expectMessage("Subject does not have permission [configuration:write:hg]"); + + put(null); + } + + @Test + @SubjectAware(username = "writeOnly") + public void shouldUpdateConfigAndInstallHg() throws Exception { + MockHttpResponse response = put("{\"disabled\":true}"); + + assertEquals(HttpServletResponse.SC_NO_CONTENT, response.getStatus()); + + HgConfig actualConfig = captureConfig(); + assertTrue(actualConfig.isDisabled()); + } + + @Test + @SubjectAware(username = "readOnly") + public void shouldUpdateConfigAndInstallHgOnlyWhenAuthorized() throws Exception { + thrown.expectMessage("Subject does not have permission [configuration:write:hg]"); + + put("{\"disabled\":true}"); + } + + private MockHttpResponse put(String content) throws URISyntaxException { + MockHttpRequest request = MockHttpRequest.put("/" + HgConfigResource.HG_CONFIG_PATH_V2 + "/auto-configuration"); + + if (content != null) { + request + .contentType(HgVndMediaType.CONFIG) + .content(content.getBytes()); + } + + MockHttpResponse response = new MockHttpResponse(); + dispatcher.invoke(request, response); + return response; + } + + private HgConfig captureConfig() { + ArgumentCaptor configCaptor = ArgumentCaptor.forClass(HgConfig.class); + verify(repositoryHandler).doAutoConfiguration(configCaptor.capture()); + return configCaptor.getValue(); + } + +}