From 9e9df35fdba8abe6b9974aae333814417311c783 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Wed, 20 Nov 2019 10:57:32 +0100 Subject: [PATCH 01/14] upgrade resteasy, legman and hibernate-validator * resteasy from 3.6.2.Final to 4.4.1.Final * legman from 1.5.1 to 1.6.0 * hibernate-validator from 5.3.6.Final to 6.1.0.Final --- pom.xml | 12 ++++++--- scm-core/pom.xml | 2 +- scm-plugins/pom.xml | 8 +++++- .../v2/resources/GitConfigResourceTest.java | 2 +- ...HgConfigAutoConfigurationResourceTest.java | 2 +- .../HgConfigInstallationsResourceTest.java | 2 +- .../HgConfigPackageResourceTest.java | 2 +- .../v2/resources/HgConfigResourceTest.java | 2 +- .../v2/resources/SvnConfigResourceTest.java | 2 +- scm-webapp/pom.xml | 26 ++++++++++++++----- .../ResteasyAllInOneServletDispatcher.java | 7 ++++- .../resources/AuthenticationResourceTest.java | 7 +++-- .../resources/AutoCompleteResourceTest.java | 2 +- .../AvailablePluginResourceTest.java | 2 +- .../v2/resources/BranchRootResourceTest.java | 16 +++++------- .../resources/ChangesetRootResourceTest.java | 2 +- .../api/v2/resources/ConfigResourceTest.java | 2 +- .../api/v2/resources/DiffResourceTest.java | 2 +- .../scm/api/v2/resources/DispatcherMock.java | 2 +- .../v2/resources/FileHistoryResourceTest.java | 2 +- .../v2/resources/GroupRootResourceTest.java | 2 +- .../resources/IncomingRootResourceTest.java | 2 +- .../InstalledPluginResourceTest.java | 2 +- .../scm/api/v2/resources/MeResourceTest.java | 2 +- .../resources/ModificationsResourceTest.java | 2 +- .../resources/PendingPluginResourceTest.java | 2 +- .../RepositoryPermissionRootResourceTest.java | 2 +- .../RepositoryRoleRootResourceTest.java | 2 +- .../resources/RepositoryRootResourceTest.java | 2 +- .../RepositoryTypeRootResourceTest.java | 2 +- .../v2/resources/SourceRootResourceTest.java | 2 +- .../api/v2/resources/TagRootResourceTest.java | 2 +- .../api/v2/resources/UIRootResourceTest.java | 2 +- .../v2/resources/UserRootResourceTest.java | 2 +- 34 files changed, 78 insertions(+), 54 deletions(-) diff --git a/pom.xml b/pom.xml index 910287abf0..9fa7045684 100644 --- a/pom.xml +++ b/pom.xml @@ -220,7 +220,13 @@ org.jboss.resteasy - resteasy-jaxrs + resteasy-core + ${resteasy.version} + + + + org.jboss.resteasy + resteasy-core-spi ${resteasy.version} @@ -831,7 +837,7 @@ 3.0.1 2.1.1 - 3.6.2.Final + 4.4.1.Final 1.19.4 2.11.1 2.10.0 @@ -839,7 +845,7 @@ 2.3.0 - 1.5.1 + 1.6.0 9.4.22.v20191022 diff --git a/scm-core/pom.xml b/scm-core/pom.xml index 8437b256b2..4e8e315253 100644 --- a/scm-core/pom.xml +++ b/scm-core/pom.xml @@ -98,7 +98,7 @@ org.jboss.resteasy - resteasy-jaxrs + resteasy-core test diff --git a/scm-plugins/pom.xml b/scm-plugins/pom.xml index 1611633449..e6b2929bd2 100644 --- a/scm-plugins/pom.xml +++ b/scm-plugins/pom.xml @@ -72,7 +72,13 @@ org.jboss.resteasy - resteasy-jaxrs + resteasy-core + test + + + + org.jboss.resteasy + resteasy-core-spi test diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigResourceTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigResourceTest.java index c25b5c5b60..7cfc79835b 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigResourceTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigResourceTest.java @@ -2,7 +2,7 @@ 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.spi.Dispatcher; import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; 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 index 1f88bfe665..21da84e7ec 100644 --- 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 @@ -2,7 +2,7 @@ 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.spi.Dispatcher; import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsResourceTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsResourceTest.java index bcd9543d28..2293d1ddb7 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsResourceTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsResourceTest.java @@ -2,7 +2,7 @@ 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.spi.Dispatcher; import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageResourceTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageResourceTest.java index 473ddfe4b4..29032ac8de 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageResourceTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageResourceTest.java @@ -5,7 +5,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; -import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigResourceTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigResourceTest.java index e0253ad86a..910f5721e9 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigResourceTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigResourceTest.java @@ -4,7 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; -import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; diff --git a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigResourceTest.java b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigResourceTest.java index f7ccf039b2..6a854471dd 100644 --- a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigResourceTest.java +++ b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigResourceTest.java @@ -4,7 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; -import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index 571c3b5370..cd7a9e1c3c 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -124,7 +124,7 @@ org.jboss.resteasy - resteasy-jaxrs + resteasy-core @@ -154,26 +154,38 @@ org.jboss.resteasy - resteasy-validator-provider-11 + resteasy-validator-provider ${resteasy.version} - org.hibernate + org.hibernate.validator hibernate-validator - 5.3.6.Final + 6.1.0.Final javax.el javax.el-api - 2.2.4 + 3.0.0 - org.glassfish.web + org.glassfish javax.el - 2.2.4 + 3.0.1-b11 + + + + javax.xml.bind + jaxb-api + 2.3.0 + + + + org.glassfish.jaxb + jaxb-runtime + 2.3.0 diff --git a/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/ResteasyAllInOneServletDispatcher.java b/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/ResteasyAllInOneServletDispatcher.java index a30cb20c01..0cbb3cd671 100644 --- a/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/ResteasyAllInOneServletDispatcher.java +++ b/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/ResteasyAllInOneServletDispatcher.java @@ -72,8 +72,13 @@ public class ResteasyAllInOneServletDispatcher extends HttpServletDispatcher { // ensure everything gets cleared, to avoid classloader leaks ResteasyProviderFactory.clearInstanceIfEqual(ResteasyProviderFactory.getInstance()); - ResteasyProviderFactory.clearContextData(); RuntimeDelegate.setInstance(null); + + removeDeploymentFromServletContext(); + } + + private void removeDeploymentFromServletContext() { + getServletContext().removeAttribute(ResteasyDeployment.class.getName()); } private ResteasyDeployment getDeploymentFromServletContext() { diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AuthenticationResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AuthenticationResourceTest.java index 177f975971..c5756fadd6 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AuthenticationResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AuthenticationResourceTest.java @@ -2,7 +2,7 @@ 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.spi.Dispatcher; import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; @@ -125,10 +125,9 @@ public class AuthenticationResourceTest { when(accessTokenBuilderFactory.create()).thenReturn(accessTokenBuilder); HttpServletRequest servletRequest = mock(HttpServletRequest.class); - ResteasyProviderFactory.getContextDataMap().put(HttpServletRequest.class, servletRequest); - + dispatcher.getDefaultContextObjects().put(HttpServletRequest.class, servletRequest); HttpServletResponse servletResponse = mock(HttpServletResponse.class); - ResteasyProviderFactory.getContextDataMap().put(HttpServletResponse.class, servletResponse); + dispatcher.getDefaultContextObjects().put(HttpServletResponse.class, servletResponse); } @Test diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AutoCompleteResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AutoCompleteResourceTest.java index ac89d02bfb..f8b4236b41 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AutoCompleteResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AutoCompleteResourceTest.java @@ -5,7 +5,7 @@ import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; import org.apache.shiro.util.ThreadContext; import org.assertj.core.util.Lists; -import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.After; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AvailablePluginResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AvailablePluginResourceTest.java index 32eadf7af0..99190d942d 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AvailablePluginResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AvailablePluginResourceTest.java @@ -4,7 +4,7 @@ import de.otto.edison.hal.HalRepresentation; import org.apache.shiro.ShiroException; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.ThreadContext; -import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java index 2c83d5e3e1..45a2d1613c 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java @@ -7,10 +7,9 @@ import org.apache.shiro.subject.support.SubjectThreadState; import org.apache.shiro.util.ThreadContext; import org.apache.shiro.util.ThreadState; import org.assertj.core.util.Lists; -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.jboss.resteasy.spi.Dispatcher; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -32,6 +31,7 @@ import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; import sonia.scm.web.VndMediaType; +import javax.ws.rs.core.MediaType; import java.net.URI; import java.time.Instant; import java.util.Date; @@ -39,13 +39,8 @@ import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; @RunWith(MockitoJUnitRunner.Silent.class) @Slf4j @@ -129,7 +124,8 @@ public class BranchRootResourceTest extends RepositoryTestBase { dispatcher.invoke(request, response); assertEquals(404, response.getStatus()); - assertEquals("application/vnd.scmm-error+json;v=2", response.getOutputHeaders().getFirst("Content-Type")); + MediaType contentType = (MediaType) response.getOutputHeaders().getFirst("Content-Type"); + assertEquals("application/vnd.scmm-error+json;v=2", contentType.toString()); } @Test diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java index 952c8504f6..601a4a4652 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java @@ -8,7 +8,7 @@ import org.apache.shiro.subject.support.SubjectThreadState; import org.apache.shiro.util.ThreadContext; import org.apache.shiro.util.ThreadState; import org.assertj.core.util.Lists; -import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.After; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ConfigResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ConfigResourceTest.java index 15c23dbd3c..74bb0ab38a 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ConfigResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ConfigResourceTest.java @@ -4,7 +4,7 @@ import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; import com.google.common.io.Resources; import org.apache.shiro.util.ThreadContext; -import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTest.java index 33d4d7e9e1..c3d4b2fffa 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTest.java @@ -7,7 +7,7 @@ import org.apache.shiro.subject.Subject; import org.apache.shiro.subject.support.SubjectThreadState; import org.apache.shiro.util.ThreadContext; import org.apache.shiro.util.ThreadState; -import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DispatcherMock.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DispatcherMock.java index fe205e88a1..40b2ac54b7 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DispatcherMock.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DispatcherMock.java @@ -1,6 +1,6 @@ package sonia.scm.api.v2.resources; -import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockDispatcherFactory; import sonia.scm.api.rest.AlreadyExistsExceptionMapper; import sonia.scm.api.rest.AuthorizationExceptionMapper; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTest.java index a8b3c15158..b5b903508a 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTest.java @@ -7,7 +7,7 @@ import org.apache.shiro.subject.support.SubjectThreadState; import org.apache.shiro.util.ThreadContext; import org.apache.shiro.util.ThreadState; import org.assertj.core.util.Lists; -import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.After; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupRootResourceTest.java index 09236c0e19..bb024eb67c 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupRootResourceTest.java @@ -4,7 +4,7 @@ import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; import com.google.common.io.Resources; import com.google.inject.util.Providers; -import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.Before; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/IncomingRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/IncomingRootResourceTest.java index 0c1f4235b9..de0eaeb992 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/IncomingRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/IncomingRootResourceTest.java @@ -8,7 +8,7 @@ import org.apache.shiro.subject.support.SubjectThreadState; import org.apache.shiro.util.ThreadContext; import org.apache.shiro.util.ThreadState; import org.assertj.core.util.Lists; -import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.After; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/InstalledPluginResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/InstalledPluginResourceTest.java index e2a23f0d52..8c9ed5ef2a 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/InstalledPluginResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/InstalledPluginResourceTest.java @@ -3,7 +3,7 @@ package sonia.scm.api.v2.resources; import de.otto.edison.hal.HalRepresentation; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.ThreadContext; -import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MeResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MeResourceTest.java index 7a3d1b4304..7aeabe6bec 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MeResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MeResourceTest.java @@ -7,7 +7,7 @@ import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.credential.PasswordService; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.Subject; -import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.Before; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java index fc4598081d..8e84f9d1bb 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java @@ -7,7 +7,7 @@ import org.apache.shiro.subject.support.SubjectThreadState; import org.apache.shiro.util.ThreadContext; import org.apache.shiro.util.ThreadState; import org.assertj.core.util.Lists; -import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.After; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PendingPluginResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PendingPluginResourceTest.java index da6e1b65d7..3613069d63 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PendingPluginResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PendingPluginResourceTest.java @@ -4,7 +4,7 @@ import com.google.inject.util.Providers; import org.apache.shiro.ShiroException; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.ThreadContext; -import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java index f2b835a0a1..a2e63dd50e 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java @@ -13,7 +13,7 @@ import org.apache.shiro.subject.support.SubjectThreadState; import org.apache.shiro.util.ThreadContext; import org.apache.shiro.util.ThreadState; import org.assertj.core.util.Lists; -import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.jboss.resteasy.spi.HttpRequest; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRoleRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRoleRootResourceTest.java index af968efd1f..d60a32f5dc 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRoleRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRoleRootResourceTest.java @@ -3,7 +3,7 @@ package sonia.scm.api.v2.resources; import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; import com.google.inject.util.Providers; -import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.Before; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java index af1e91344a..fcd34334b2 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java @@ -6,7 +6,7 @@ import com.google.common.io.Resources; import com.google.inject.util.Providers; import org.apache.shiro.subject.SimplePrincipalCollection; import org.apache.shiro.subject.Subject; -import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.Before; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTypeRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTypeRootResourceTest.java index 2476785d70..17ea3248c2 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTypeRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTypeRootResourceTest.java @@ -3,7 +3,7 @@ package sonia.scm.api.v2.resources; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.google.inject.util.Providers; -import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java index 1a45d3b233..a25aabaca1 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java @@ -1,7 +1,7 @@ package sonia.scm.api.v2.resources; import com.google.inject.util.Providers; -import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.Before; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java index 803f2b106c..e97f6c726f 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java @@ -7,7 +7,7 @@ import org.apache.shiro.subject.support.SubjectThreadState; import org.apache.shiro.util.ThreadContext; import org.apache.shiro.util.ThreadState; import org.assertj.core.util.Lists; -import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.After; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UIRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UIRootResourceTest.java index 4987dec644..0391e43c81 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UIRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UIRootResourceTest.java @@ -3,7 +3,7 @@ package sonia.scm.api.v2.resources; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.google.inject.util.Providers; -import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UserRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UserRootResourceTest.java index 06d9b89120..e055bbf3b5 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UserRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UserRootResourceTest.java @@ -5,7 +5,7 @@ import com.github.sdorra.shiro.SubjectAware; import com.google.common.io.Resources; import com.google.inject.util.Providers; import org.apache.shiro.authc.credential.PasswordService; -import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.Before; From c944f234472a891d7f72b66d8d034043fb4f9508 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 21 Nov 2019 16:13:25 +0100 Subject: [PATCH 02/14] update legman to version 1.6.1, in order to fix a ExecutorService leak --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9fa7045684..98ddfde58a 100644 --- a/pom.xml +++ b/pom.xml @@ -845,7 +845,7 @@ 2.3.0 - 1.6.0 + 1.6.1 9.4.22.v20191022 From ff7b8ca842097dd0e4a5de0a6cde847ed910d85e Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 21 Nov 2019 16:16:15 +0100 Subject: [PATCH 03/14] make ClassLoaderLeakPreventorFactory configurable and mark BootstrapClassLoader as shutdown --- .../classloading/BootstrapClassLoader.java | 22 +++++ .../classloading/ClassLoaderLifeCycle.java | 97 ++++++++++++++++--- .../ClassLoaderLifeCycleTest.java | 7 +- 3 files changed, 111 insertions(+), 15 deletions(-) diff --git a/scm-webapp/src/main/java/sonia/scm/lifecycle/classloading/BootstrapClassLoader.java b/scm-webapp/src/main/java/sonia/scm/lifecycle/classloading/BootstrapClassLoader.java index 64d9b75d36..a274dbb33c 100644 --- a/scm-webapp/src/main/java/sonia/scm/lifecycle/classloading/BootstrapClassLoader.java +++ b/scm-webapp/src/main/java/sonia/scm/lifecycle/classloading/BootstrapClassLoader.java @@ -5,7 +5,29 @@ package sonia.scm.lifecycle.classloading; * find it in a heap dump. */ class BootstrapClassLoader extends ClassLoader { + + /** + * Marker to find a BootstrapClassLoader, which is already shutdown. + */ + private boolean shutdown = false; + BootstrapClassLoader(ClassLoader webappClassLoader) { super(webappClassLoader); } + + /** + * Returns {@code true} if the classloader was shutdown. + * + * @return {@code true} if the classloader was shutdown + */ + boolean isShutdown() { + return shutdown; + } + + /** + * Mark the class loader as shutdown. + */ + void markAsShutdown() { + shutdown = true; + } } diff --git a/scm-webapp/src/main/java/sonia/scm/lifecycle/classloading/ClassLoaderLifeCycle.java b/scm-webapp/src/main/java/sonia/scm/lifecycle/classloading/ClassLoaderLifeCycle.java index 24d1c239b4..a64ed6fa43 100644 --- a/scm-webapp/src/main/java/sonia/scm/lifecycle/classloading/ClassLoaderLifeCycle.java +++ b/scm-webapp/src/main/java/sonia/scm/lifecycle/classloading/ClassLoaderLifeCycle.java @@ -5,7 +5,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor; import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventorFactory; +import se.jiderhamn.classloader.leak.prevention.cleanup.IIOServiceProviderCleanUp; import se.jiderhamn.classloader.leak.prevention.cleanup.MBeanCleanUp; +import se.jiderhamn.classloader.leak.prevention.cleanup.ShutdownHookCleanUp; +import se.jiderhamn.classloader.leak.prevention.cleanup.StopThreadsCleanUp; +import se.jiderhamn.classloader.leak.prevention.preinit.AwtToolkitInitiator; +import se.jiderhamn.classloader.leak.prevention.preinit.Java2dDisposerInitiator; +import se.jiderhamn.classloader.leak.prevention.preinit.Java2dRenderQueueInitiator; import se.jiderhamn.classloader.leak.prevention.preinit.SunAwtAppContextInitiator; import sonia.scm.lifecycle.LifeCycle; import sonia.scm.plugin.ChildFirstPluginClassLoader; @@ -16,9 +22,9 @@ import java.io.IOException; import java.net.URL; import java.util.ArrayDeque; import java.util.Deque; -import java.util.function.UnaryOperator; import static com.google.common.base.Preconditions.checkState; +import static se.jiderhamn.classloader.leak.prevention.cleanup.ShutdownHookCleanUp.SHUTDOWN_HOOK_WAIT_MS_DEFAULT; /** * Creates and shutdown SCM-Manager ClassLoaders. @@ -27,23 +33,25 @@ public final class ClassLoaderLifeCycle implements LifeCycle { private static final Logger LOG = LoggerFactory.getLogger(ClassLoaderLifeCycle.class); - private final Deque classLoaders = new ArrayDeque<>(); + private Deque classLoaders = new ArrayDeque<>(); private final ClassLoaderLeakPreventorFactory classLoaderLeakPreventorFactory; private final ClassLoader webappClassLoader; - private ClassLoader bootstrapClassLoader; - private UnaryOperator classLoaderAppendListener = c -> c; + private BootstrapClassLoader bootstrapClassLoader; + + private ClassLoaderAppendListener classLoaderAppendListener = new ClassLoaderAppendListener() { + @Override + public C apply(C classLoader) { + return classLoader; + } + }; @VisibleForTesting public static ClassLoaderLifeCycle create() { - ClassLoaderLeakPreventorFactory classLoaderLeakPreventorFactory = new ClassLoaderLeakPreventorFactory(); - classLoaderLeakPreventorFactory.setLogger(new LoggingAdapter()); - // the SunAwtAppContextInitiator causes a lot of exceptions and we use no awt - classLoaderLeakPreventorFactory.removePreInitiator(SunAwtAppContextInitiator.class); - // the MBeanCleanUp causes a Exception and we use no mbeans - classLoaderLeakPreventorFactory.removeCleanUp(MBeanCleanUp.class); - return new ClassLoaderLifeCycle(Thread.currentThread().getContextClassLoader(), classLoaderLeakPreventorFactory); + ClassLoader webappClassLoader = Thread.currentThread().getContextClassLoader(); + ClassLoaderLeakPreventorFactory classLoaderLeakPreventorFactory = createClassLoaderLeakPreventorFactory(webappClassLoader); + return new ClassLoaderLifeCycle(webappClassLoader, classLoaderLeakPreventorFactory); } ClassLoaderLifeCycle(ClassLoader webappClassLoader, ClassLoaderLeakPreventorFactory classLoaderLeakPreventorFactory) { @@ -51,12 +59,64 @@ public final class ClassLoaderLifeCycle implements LifeCycle { this.webappClassLoader = initAndAppend(webappClassLoader); } + private static ClassLoaderLeakPreventorFactory createClassLoaderLeakPreventorFactory(ClassLoader webappClassLoader) { + // Should threads tied to the web app classloader be forced to stop at application shutdown? + boolean stopThreads = Boolean.getBoolean("ClassLoaderLeakPreventor.stopThreads"); + + // Should Timer threads tied to the web app classloader be forced to stop at application shutdown? + boolean stopTimerThreads = Boolean.getBoolean("ClassLoaderLeakPreventor.stopTimerThreads"); + + // Should shutdown hooks registered from the application be executed at application shutdown? + boolean executeShutdownHooks = Boolean.getBoolean("ClassLoaderLeakPreventor.executeShutdownHooks"); + + // No of milliseconds to wait for threads to finish execution, before stopping them. + int threadWaitMs = Integer.getInteger("ClassLoaderLeakPreventor.threadWaitMs", ClassLoaderLeakPreventor.THREAD_WAIT_MS_DEFAULT); + + /* + * No of milliseconds to wait for shutdown hooks to finish execution, before stopping them. + * If set to -1 there will be no waiting at all, but Thread is allowed to run until finished. + */ + int shutdownHookWaitMs = Integer.getInteger("ClassLoaderLeakPreventor.shutdownHookWaitMs", SHUTDOWN_HOOK_WAIT_MS_DEFAULT); + + LOG.info("Settings for {} (CL: 0x{}):", ClassLoaderLifeCycle.class.getName(), Integer.toHexString(System.identityHashCode(webappClassLoader)) ); + LOG.info(" stopThreads = {}", stopThreads); + LOG.info(" stopTimerThreads = {}", stopTimerThreads); + LOG.info(" executeShutdownHooks = {}", executeShutdownHooks); + LOG.info(" threadWaitMs = {} ms", threadWaitMs); + LOG.info(" shutdownHookWaitMs = {} ms", shutdownHookWaitMs); + + // use webapp classloader as safe base? or system? + ClassLoaderLeakPreventorFactory classLoaderLeakPreventorFactory = new ClassLoaderLeakPreventorFactory(webappClassLoader); + classLoaderLeakPreventorFactory.setLogger(new LoggingAdapter()); + + final ShutdownHookCleanUp shutdownHookCleanUp = classLoaderLeakPreventorFactory.getCleanUp(ShutdownHookCleanUp.class); + shutdownHookCleanUp.setExecuteShutdownHooks(executeShutdownHooks); + shutdownHookCleanUp.setShutdownHookWaitMs(shutdownHookWaitMs); + + final StopThreadsCleanUp stopThreadsCleanUp = classLoaderLeakPreventorFactory.getCleanUp(StopThreadsCleanUp.class); + stopThreadsCleanUp.setStopThreads(stopThreads); + stopThreadsCleanUp.setStopTimerThreads(stopTimerThreads); + stopThreadsCleanUp.setThreadWaitMs(threadWaitMs); + + // remove awt and imageio cleanup + classLoaderLeakPreventorFactory.removePreInitiator(AwtToolkitInitiator.class); + classLoaderLeakPreventorFactory.removePreInitiator(SunAwtAppContextInitiator.class); + classLoaderLeakPreventorFactory.removeCleanUp(IIOServiceProviderCleanUp.class); + classLoaderLeakPreventorFactory.removePreInitiator(Java2dRenderQueueInitiator.class); + classLoaderLeakPreventorFactory.removePreInitiator(Java2dDisposerInitiator.class); + + // the MBeanCleanUp causes a Exception and we use no mbeans + classLoaderLeakPreventorFactory.removeCleanUp(MBeanCleanUp.class); + + return classLoaderLeakPreventorFactory; + } + public void initialize() { bootstrapClassLoader = initAndAppend(new BootstrapClassLoader(webappClassLoader)); } @VisibleForTesting - void setClassLoaderAppendListener(UnaryOperator classLoaderAppendListener) { + void setClassLoaderAppendListener(ClassLoaderAppendListener classLoaderAppendListener) { this.classLoaderAppendListener = classLoaderAppendListener; } @@ -84,12 +144,17 @@ public final class ClassLoaderLifeCycle implements LifeCycle { clap.shutdown(); clap = classLoaders.poll(); } + // be sure it is realy empty + classLoaders.clear(); + classLoaders = new ArrayDeque<>(); + + bootstrapClassLoader.markAsShutdown(); bootstrapClassLoader = null; } - private ClassLoader initAndAppend(ClassLoader originalClassLoader) { + private T initAndAppend(T originalClassLoader) { LOG.debug("init classloader {}", originalClassLoader); - ClassLoader classLoader = classLoaderAppendListener.apply(originalClassLoader); + T classLoader = classLoaderAppendListener.apply(originalClassLoader); ClassLoaderLeakPreventor preventor = classLoaderLeakPreventorFactory.newLeakPreventor(classLoader); preventor.runPreClassLoaderInitiators(); @@ -98,6 +163,10 @@ public final class ClassLoaderLifeCycle implements LifeCycle { return classLoader; } + interface ClassLoaderAppendListener { + C apply(C classLoader); + } + private class ClassLoaderAndPreventor { private final ClassLoader classLoader; diff --git a/scm-webapp/src/test/java/sonia/scm/lifecycle/classloading/ClassLoaderLifeCycleTest.java b/scm-webapp/src/test/java/sonia/scm/lifecycle/classloading/ClassLoaderLifeCycleTest.java index 0ab98039d1..a8f37777d7 100644 --- a/scm-webapp/src/test/java/sonia/scm/lifecycle/classloading/ClassLoaderLifeCycleTest.java +++ b/scm-webapp/src/test/java/sonia/scm/lifecycle/classloading/ClassLoaderLifeCycleTest.java @@ -70,7 +70,12 @@ class ClassLoaderLifeCycleTest { URLClassLoader webappClassLoader = spy(new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader())); ClassLoaderLifeCycle lifeCycle = createMockedLifeCycle(webappClassLoader); - lifeCycle.setClassLoaderAppendListener(c -> spy(c)); + lifeCycle.setClassLoaderAppendListener(new ClassLoaderLifeCycle.ClassLoaderAppendListener() { + @Override + public C apply(C classLoader) { + return spy(classLoader); + } + }); lifeCycle.initialize(); ClassLoader pluginA = lifeCycle.createChildFirstPluginClassLoader(new URL[0], null, "a"); From 755b99f52447d2879cd4612c82b2ee2ba0b60a1b Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 21 Nov 2019 16:17:30 +0100 Subject: [PATCH 04/14] close CronThreadFactory to avoid thread leak --- .../src/main/java/sonia/scm/schedule/CronScheduler.java | 5 ++++- .../src/main/java/sonia/scm/schedule/CronThreadFactory.java | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/scm-webapp/src/main/java/sonia/scm/schedule/CronScheduler.java b/scm-webapp/src/main/java/sonia/scm/schedule/CronScheduler.java index 7899697746..8577768495 100644 --- a/scm-webapp/src/main/java/sonia/scm/schedule/CronScheduler.java +++ b/scm-webapp/src/main/java/sonia/scm/schedule/CronScheduler.java @@ -17,15 +17,17 @@ public class CronScheduler implements Scheduler { private final ScheduledExecutorService executorService; private final CronTaskFactory taskFactory; + private final CronThreadFactory threadFactory; @Inject public CronScheduler(CronTaskFactory taskFactory) { this.taskFactory = taskFactory; + this.threadFactory = new CronThreadFactory(); this.executorService = createExecutor(); } private ScheduledExecutorService createExecutor() { - return Executors.newScheduledThreadPool(2, new CronThreadFactory()); + return Executors.newScheduledThreadPool(2, threadFactory); } @Override @@ -52,6 +54,7 @@ public class CronScheduler implements Scheduler { @Override public void close() { LOG.debug("shutdown underlying executor service"); + threadFactory.close(); executorService.shutdown(); } } diff --git a/scm-webapp/src/main/java/sonia/scm/schedule/CronThreadFactory.java b/scm-webapp/src/main/java/sonia/scm/schedule/CronThreadFactory.java index 6519f500fa..bb732b4512 100644 --- a/scm-webapp/src/main/java/sonia/scm/schedule/CronThreadFactory.java +++ b/scm-webapp/src/main/java/sonia/scm/schedule/CronThreadFactory.java @@ -1,5 +1,6 @@ package sonia.scm.schedule; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import org.apache.shiro.util.ThreadContext; import java.util.concurrent.ExecutionException; @@ -19,7 +20,10 @@ class CronThreadFactory implements ThreadFactory, AutoCloseable { private static final AtomicLong FACTORY_COUNTER = new AtomicLong(); - private final ExecutorService executorService = Executors.newSingleThreadExecutor(); + private final ExecutorService executorService = Executors.newSingleThreadExecutor( + new ThreadFactoryBuilder().setNameFormat("CronThreadFactory-%d").build() + ); + private final long factoryId = FACTORY_COUNTER.incrementAndGet(); private final AtomicLong threadCounter = new AtomicLong(); From d1a5f6f24b33405f5882f8761e63dfa974b208fa Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 21 Nov 2019 16:20:55 +0100 Subject: [PATCH 05/14] fix wrong ClassLoader for Delayed-Restart Thread, which has caused an ClassLoader leak. Also added system properties to configure shutdown only, wait between stop and start and possibility to disable gc. --- .../sonia/scm/event/LegmanScmEventBus.java | 52 +++++++++++++------ .../scm/event/ShutdownEventBusEvent.java | 4 ++ .../scm/lifecycle/BootstrapContextFilter.java | 7 ++- .../InjectionContextRestartStrategy.java | 49 +++++++++++++++-- .../sonia/scm/lifecycle/RestartStrategy.java | 5 +- .../InjectionContextRestartStrategyTest.java | 5 +- 6 files changed, 97 insertions(+), 25 deletions(-) create mode 100644 scm-webapp/src/main/java/sonia/scm/event/ShutdownEventBusEvent.java diff --git a/scm-webapp/src/main/java/sonia/scm/event/LegmanScmEventBus.java b/scm-webapp/src/main/java/sonia/scm/event/LegmanScmEventBus.java index 85f760a71f..52b80679d9 100644 --- a/scm-webapp/src/main/java/sonia/scm/event/LegmanScmEventBus.java +++ b/scm-webapp/src/main/java/sonia/scm/event/LegmanScmEventBus.java @@ -90,8 +90,12 @@ public class LegmanScmEventBus extends ScmEventBus @Override public void post(Object event) { - logger.debug("post {} to event bus {}", event, name); - eventBus.post(event); + if (eventBus != null) { + logger.debug("post {} to event bus {}", event, name); + eventBus.post(event); + } else { + logger.error("failed to post event {}, because event bus is shutdown", event); + } } /** @@ -104,9 +108,12 @@ public class LegmanScmEventBus extends ScmEventBus @Override public void register(Object object) { - logger.trace("register {} to event bus {}", object, name); - eventBus.register(object); - + if (eventBus != null) { + logger.trace("register {} to event bus {}", object, name); + eventBus.register(object); + } else { + logger.error("failed to register {}, because eventbus is shutdown", object); + } } /** @@ -118,22 +125,37 @@ public class LegmanScmEventBus extends ScmEventBus @Override public void unregister(Object object) { - logger.trace("unregister {} from event bus {}", object, name); - - try - { - eventBus.unregister(object); + if (eventBus != null) { + logger.trace("unregister {} from event bus {}", object, name); + + try { + eventBus.unregister(object); + } catch (IllegalArgumentException ex) { + logger.trace("object {} was not registered", object); + } + } else { + logger.error("failed to unregister object {}, because event bus is shutdown", object); } - catch (IllegalArgumentException ex) - { - logger.trace("object {} was not registered", object); + } + + @Subscribe(async = false) + public void shutdownEventBus(ShutdownEventBusEvent shutdownEventBusEvent) { + if (eventBus != null) { + logger.info("shutdown event bus executor for {}, because of received ShutdownEventBusEvent", name); + eventBus.shutdown(); + eventBus = null; + } else { + logger.warn("event bus was already shutdown"); } } @Subscribe(async = false) public void recreateEventBus(RecreateEventBusEvent recreateEventBusEvent) { - logger.info("shutdown event bus executor for {}", name); - eventBus.shutdown(); + if (eventBus != null) { + logger.info("shutdown event bus executor for {}, because of received RecreateEventBusEvent", name); + eventBus.shutdown(); + } + logger.info("recreate event bus because of received RecreateEventBusEvent"); eventBus = create(); } diff --git a/scm-webapp/src/main/java/sonia/scm/event/ShutdownEventBusEvent.java b/scm-webapp/src/main/java/sonia/scm/event/ShutdownEventBusEvent.java new file mode 100644 index 0000000000..5e5ab9ca5c --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/event/ShutdownEventBusEvent.java @@ -0,0 +1,4 @@ +package sonia.scm.event; + +public class ShutdownEventBusEvent { +} diff --git a/scm-webapp/src/main/java/sonia/scm/lifecycle/BootstrapContextFilter.java b/scm-webapp/src/main/java/sonia/scm/lifecycle/BootstrapContextFilter.java index ffb7631922..1d642d9c66 100644 --- a/scm-webapp/src/main/java/sonia/scm/lifecycle/BootstrapContextFilter.java +++ b/scm-webapp/src/main/java/sonia/scm/lifecycle/BootstrapContextFilter.java @@ -58,13 +58,16 @@ public class BootstrapContextFilter extends GuiceFilter { private final BootstrapContextListener listener = new BootstrapContextListener(); + private ClassLoader webAppClassLoader; + /** Field description */ private FilterConfig filterConfig; @Override public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; - + // store webapp classloader for delayed restarts + webAppClassLoader = Thread.currentThread().getContextClassLoader(); initializeContext(); } @@ -97,7 +100,7 @@ public class BootstrapContextFilter extends GuiceFilter { if (filterConfig == null) { LOG.error("filter config is null, scm-manager is not initialized"); } else { - RestartStrategy restartStrategy = RestartStrategy.get(); + RestartStrategy restartStrategy = RestartStrategy.get(webAppClassLoader); restartStrategy.restart(new GuiceInjectionContext()); } } diff --git a/scm-webapp/src/main/java/sonia/scm/lifecycle/InjectionContextRestartStrategy.java b/scm-webapp/src/main/java/sonia/scm/lifecycle/InjectionContextRestartStrategy.java index 683507c563..2db60580b1 100644 --- a/scm-webapp/src/main/java/sonia/scm/lifecycle/InjectionContextRestartStrategy.java +++ b/scm-webapp/src/main/java/sonia/scm/lifecycle/InjectionContextRestartStrategy.java @@ -5,6 +5,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.event.RecreateEventBusEvent; import sonia.scm.event.ScmEventBus; +import sonia.scm.event.ShutdownEventBusEvent; import java.util.concurrent.atomic.AtomicLong; @@ -13,20 +14,47 @@ import java.util.concurrent.atomic.AtomicLong; */ public class InjectionContextRestartStrategy implements RestartStrategy { + private static final String DISABLE_RESTART_PROPERTY = "sonia.scm.restart.disable"; + private static final String WAIT_PROPERTY = "sonia.scm.restart.wait"; + private static final String DISABLE_GC_PROPERTY = "sonia.scm.restart.disable-gc"; + private static final AtomicLong INSTANCE_COUNTER = new AtomicLong(); private static final Logger LOG = LoggerFactory.getLogger(InjectionContextRestartStrategy.class); - private long waitInMs = 250L; + private boolean restartEnabled = !Boolean.getBoolean(DISABLE_RESTART_PROPERTY); + private long waitInMs = Integer.getInteger(WAIT_PROPERTY, 250); + private boolean gcEnabled = !Boolean.getBoolean(DISABLE_GC_PROPERTY); + + private final ClassLoader webAppClassLoader; + + InjectionContextRestartStrategy(ClassLoader webAppClassLoader) { + this.webAppClassLoader = webAppClassLoader; + } @VisibleForTesting void setWaitInMs(long waitInMs) { this.waitInMs = waitInMs; } + @VisibleForTesting + void setGcEnabled(boolean gcEnabled) { + this.gcEnabled = gcEnabled; + } + @Override public void restart(InjectionContext context) { - LOG.warn("destroy injection context"); - context.destroy(); + stop(context); + if (restartEnabled) { + start(context); + } else { + LOG.warn("restarting context is disabled"); + } + } + + @SuppressWarnings("squid:S1215") // suppress explicit gc call warning + private void start(InjectionContext context) { + LOG.debug("use WebAppClassLoader as ContextClassLoader, to avoid ClassLoader leaks"); + Thread.currentThread().setContextClassLoader(webAppClassLoader); LOG.warn("send recreate eventbus event"); ScmEventBus.getInstance().post(new RecreateEventBusEvent()); @@ -34,6 +62,12 @@ public class InjectionContextRestartStrategy implements RestartStrategy { // restart context delayed, to avoid timing problems new Thread(() -> { try { + if (gcEnabled){ + LOG.info("call gc to clean up memory from old instances"); + System.gc(); + } + + LOG.info("wait {}ms before re starting the context", waitInMs); Thread.sleep(waitInMs); LOG.warn("reinitialize injection context"); @@ -45,6 +79,15 @@ public class InjectionContextRestartStrategy implements RestartStrategy { LOG.error("failed to restart", ex); } }, "Delayed-Restart-" + INSTANCE_COUNTER.incrementAndGet()).start(); + } + private void stop(InjectionContext context) { + LOG.warn("destroy injection context"); + context.destroy(); + + if (!restartEnabled) { + // shutdown eventbus, but do this only if restart is disabled + ScmEventBus.getInstance().post(new ShutdownEventBusEvent()); + } } } diff --git a/scm-webapp/src/main/java/sonia/scm/lifecycle/RestartStrategy.java b/scm-webapp/src/main/java/sonia/scm/lifecycle/RestartStrategy.java index 769351a850..6c7dd69259 100644 --- a/scm-webapp/src/main/java/sonia/scm/lifecycle/RestartStrategy.java +++ b/scm-webapp/src/main/java/sonia/scm/lifecycle/RestartStrategy.java @@ -13,7 +13,6 @@ public interface RestartStrategy { * Initialize the injection context. */ void initialize(); - /** * Destroys the injection context. */ @@ -31,8 +30,8 @@ public interface RestartStrategy { * * @return configured strategy */ - static RestartStrategy get() { - return new InjectionContextRestartStrategy(); + static RestartStrategy get(ClassLoader webAppClassLoader) { + return new InjectionContextRestartStrategy(webAppClassLoader); } } diff --git a/scm-webapp/src/test/java/sonia/scm/lifecycle/InjectionContextRestartStrategyTest.java b/scm-webapp/src/test/java/sonia/scm/lifecycle/InjectionContextRestartStrategyTest.java index 355dca4a16..ddd691e5da 100644 --- a/scm-webapp/src/test/java/sonia/scm/lifecycle/InjectionContextRestartStrategyTest.java +++ b/scm-webapp/src/test/java/sonia/scm/lifecycle/InjectionContextRestartStrategyTest.java @@ -18,11 +18,13 @@ class InjectionContextRestartStrategyTest { @Mock private RestartStrategy.InjectionContext context; - private InjectionContextRestartStrategy strategy = new InjectionContextRestartStrategy(); + private InjectionContextRestartStrategy strategy = new InjectionContextRestartStrategy(Thread.currentThread().getContextClassLoader()); @BeforeEach void setWaitToZero() { strategy.setWaitInMs(0L); + // disable gc during tests + strategy.setGcEnabled(false); } @Test @@ -47,7 +49,6 @@ class InjectionContextRestartStrategyTest { @Test void shouldRegisterContextAfterRestart() throws InterruptedException { TestingInjectionContext ctx = new TestingInjectionContext(); - strategy.restart(ctx); Thread.sleep(50L); From 571f5aa4212536900b90f6101affe679feb7fdc9 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 21 Nov 2019 16:21:52 +0100 Subject: [PATCH 06/14] destroy guice context from BootstrapContextListener --- .../java/sonia/scm/lifecycle/BootstrapContextListener.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scm-webapp/src/main/java/sonia/scm/lifecycle/BootstrapContextListener.java b/scm-webapp/src/main/java/sonia/scm/lifecycle/BootstrapContextListener.java index 223e3cf65b..5b9f40dbc2 100644 --- a/scm-webapp/src/main/java/sonia/scm/lifecycle/BootstrapContextListener.java +++ b/scm-webapp/src/main/java/sonia/scm/lifecycle/BootstrapContextListener.java @@ -66,7 +66,7 @@ public class BootstrapContextListener extends GuiceServletContextListener { private static final Logger LOG = LoggerFactory.getLogger(BootstrapContextListener.class); - private final ClassLoaderLifeCycle classLoaderLifeCycle = ClassLoaderLifeCycle.create(); + private ClassLoaderLifeCycle classLoaderLifeCycle = ClassLoaderLifeCycle.create(); private ServletContext context; private InjectionLifeCycle injectionLifeCycle; @@ -110,6 +110,8 @@ public class BootstrapContextListener extends GuiceServletContextListener { injectionLifeCycle.shutdown(); injectionLifeCycle = null; classLoaderLifeCycle.shutdown(); + + super.contextDestroyed(sce); } private Injector createStageTwoInjector() { From 2fde62256063931de8c79726aa31ba1a4db1fa1b Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 21 Nov 2019 16:22:39 +0100 Subject: [PATCH 07/14] reset resteasy StatisticsController to avoid ClassLoader leaks --- .../modules/ResteasyAllInOneServletDispatcher.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/ResteasyAllInOneServletDispatcher.java b/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/ResteasyAllInOneServletDispatcher.java index 0cbb3cd671..8f602db766 100644 --- a/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/ResteasyAllInOneServletDispatcher.java +++ b/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/ResteasyAllInOneServletDispatcher.java @@ -7,6 +7,7 @@ import org.jboss.resteasy.plugins.server.servlet.ListenerBootstrap; import org.jboss.resteasy.spi.Registry; import org.jboss.resteasy.spi.ResteasyDeployment; import org.jboss.resteasy.spi.ResteasyProviderFactory; +import org.jboss.resteasy.spi.statistics.StatisticsController; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -70,6 +71,12 @@ public class ResteasyAllInOneServletDispatcher extends HttpServletDispatcher { super.destroy(); deployment.stop(); + // clear ResourceLocatorInvoker leaks + StatisticsController statisticsController = ResteasyProviderFactory.getInstance().getStatisticsController(); + if (statisticsController != null) { + statisticsController.reset(); + } + // ensure everything gets cleared, to avoid classloader leaks ResteasyProviderFactory.clearInstanceIfEqual(ResteasyProviderFactory.getInstance()); RuntimeDelegate.setInstance(null); From ca8d5956e0c3246f78e5930cf28587f17a451821 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 21 Nov 2019 16:23:04 +0100 Subject: [PATCH 08/14] shutdown executor on context destroy --- .../java/sonia/scm/web/cgi/DefaultCGIExecutorFactory.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scm-webapp/src/main/java/sonia/scm/web/cgi/DefaultCGIExecutorFactory.java b/scm-webapp/src/main/java/sonia/scm/web/cgi/DefaultCGIExecutorFactory.java index 8da159f3c0..fa8507c917 100644 --- a/scm-webapp/src/main/java/sonia/scm/web/cgi/DefaultCGIExecutorFactory.java +++ b/scm-webapp/src/main/java/sonia/scm/web/cgi/DefaultCGIExecutorFactory.java @@ -52,7 +52,7 @@ import javax.servlet.http.HttpServletResponse; * * @author Sebastian Sdorra */ -public class DefaultCGIExecutorFactory implements CGIExecutorFactory +public class DefaultCGIExecutorFactory implements CGIExecutorFactory, AutoCloseable { /** @@ -92,6 +92,11 @@ public class DefaultCGIExecutorFactory implements CGIExecutorFactory //~--- fields --------------------------------------------------------------- + @Override + public void close() { + executor.shutdown(); + } + /** Field description */ private final ExecutorService executor; } From 6bf86fab8d98ccd35afd5c00f2ace5e9730051ab Mon Sep 17 00:00:00 2001 From: Rene Pfeuffer Date: Mon, 25 Nov 2019 17:04:58 +0100 Subject: [PATCH 09/14] Introduce abstraction layer for RESTeasy mock dispatcher --- .../v2/resources/GitConfigResourceTest.java | 25 ++-- ...HgConfigAutoConfigurationResourceTest.java | 25 ++-- .../HgConfigInstallationsResourceTest.java | 21 ++-- .../HgConfigPackageResourceTest.java | 21 ++-- .../v2/resources/HgConfigResourceTest.java | 25 ++-- .../v2/resources/SvnConfigResourceTest.java | 25 ++-- scm-test/pom.xml | 14 +++ .../java/sonia/scm/web/ScmTestDispatcher.java | 109 ++++++++++++++++++ .../AuthorizationExceptionMapperTest.java | 5 + .../resources/AuthenticationResourceTest.java | 14 +-- .../resources/AutoCompleteResourceTest.java | 8 +- .../AvailablePluginResourceTest.java | 28 +++-- .../v2/resources/BranchRootResourceTest.java | 19 ++- .../resources/ChangesetRootResourceTest.java | 6 +- .../api/v2/resources/ConfigResourceTest.java | 23 ++-- .../api/v2/resources/DiffResourceTest.java | 16 ++- .../scm/api/v2/resources/DispatcherMock.java | 24 ---- .../v2/resources/FileHistoryResourceTest.java | 6 +- .../v2/resources/GroupRootResourceTest.java | 10 +- .../resources/IncomingRootResourceTest.java | 10 +- .../InstalledPluginResourceTest.java | 34 +++--- .../scm/api/v2/resources/MeResourceTest.java | 8 +- .../resources/ModificationsResourceTest.java | 6 +- .../resources/PendingPluginResourceTest.java | 19 +-- .../RepositoryPermissionRootResourceTest.java | 20 +--- .../RepositoryRoleRootResourceTest.java | 10 +- .../resources/RepositoryRootResourceTest.java | 8 +- .../RepositoryTypeRootResourceTest.java | 7 +- .../v2/resources/SourceRootResourceTest.java | 7 +- .../api/v2/resources/TagRootResourceTest.java | 12 +- .../api/v2/resources/UIRootResourceTest.java | 18 ++- .../v2/resources/UserRootResourceTest.java | 7 +- 32 files changed, 327 insertions(+), 263 deletions(-) create mode 100644 scm-test/src/main/java/sonia/scm/web/ScmTestDispatcher.java create mode 100644 scm-webapp/src/test/java/sonia/scm/api/rest/AuthorizationExceptionMapperTest.java delete mode 100644 scm-webapp/src/test/java/sonia/scm/api/v2/resources/DispatcherMock.java diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigResourceTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigResourceTest.java index 7cfc79835b..3d3987aca3 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigResourceTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigResourceTest.java @@ -2,14 +2,11 @@ package sonia.scm.api.v2.resources; import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; -import org.jboss.resteasy.spi.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.Answers; import org.mockito.ArgumentCaptor; @@ -27,6 +24,7 @@ import sonia.scm.repository.RepositoryManager; import sonia.scm.store.ConfigurationStore; import sonia.scm.store.ConfigurationStoreFactory; import sonia.scm.web.GitVndMediaType; +import sonia.scm.web.ScmTestDispatcher; import javax.servlet.http.HttpServletResponse; import java.io.UnsupportedEncodingException; @@ -52,10 +50,7 @@ public class GitConfigResourceTest { @Rule public ShiroRule shiro = new ShiroRule(); - @Rule - public ExpectedException thrown = ExpectedException.none(); - - private Dispatcher dispatcher = MockDispatcherFactory.createDispatcher(); + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); private final URI baseUri = URI.create("/"); @@ -89,7 +84,7 @@ public class GitConfigResourceTest { when(repositoryHandler.getConfig()).thenReturn(gitConfig); GitRepositoryConfigResource gitRepositoryConfigResource = new GitRepositoryConfigResource(repositoryConfigMapper, repositoryManager, new GitRepositoryConfigStoreProvider(configurationStoreFactory)); GitConfigResource gitConfigResource = new GitConfigResource(dtoToConfigMapper, configToDtoMapper, repositoryHandler, of(gitRepositoryConfigResource)); - dispatcher.getRegistry().addSingletonResource(gitConfigResource); + dispatcher.addSingletonResource(gitConfigResource); when(scmPathInfoStore.get().getApiRestUri()).thenReturn(baseUri); } @@ -137,10 +132,11 @@ public class GitConfigResourceTest { @Test @SubjectAware(username = "writeOnly") - public void shouldNotGetConfigWhenNotAuthorized() throws URISyntaxException { - thrown.expectMessage("Subject does not have permission [configuration:read:git]"); + public void shouldNotGetConfigWhenNotAuthorized() throws URISyntaxException, UnsupportedEncodingException { + MockHttpResponse response = get(); - get(); + assertEquals("Subject does not have permission [configuration:read:git]", response.getContentAsString()); + assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus()); } @Test @@ -152,10 +148,11 @@ public class GitConfigResourceTest { @Test @SubjectAware(username = "readOnly") - public void shouldNotUpdateConfigWhenNotAuthorized() throws URISyntaxException { - thrown.expectMessage("Subject does not have permission [configuration:write:git]"); + public void shouldNotUpdateConfigWhenNotAuthorized() throws URISyntaxException, UnsupportedEncodingException { + MockHttpResponse response = put(); - put(); + assertEquals("Subject does not have permission [configuration:write:git]", response.getContentAsString()); + assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus()); } @Test 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 index 21da84e7ec..fa2b559041 100644 --- 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 @@ -2,14 +2,11 @@ package sonia.scm.api.v2.resources; import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; -import org.jboss.resteasy.spi.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; @@ -18,12 +15,15 @@ import org.mockito.junit.MockitoJUnitRunner; import sonia.scm.repository.HgConfig; import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.web.HgVndMediaType; +import sonia.scm.web.ScmTestDispatcher; import javax.inject.Provider; import javax.servlet.http.HttpServletResponse; import java.net.URISyntaxException; -import static org.junit.Assert.*; +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; @@ -37,10 +37,7 @@ public class HgConfigAutoConfigurationResourceTest { @Rule public ShiroRule shiro = new ShiroRule(); - @Rule - public ExpectedException thrown = ExpectedException.none(); - - private Dispatcher dispatcher = MockDispatcherFactory.createDispatcher(); + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); @InjectMocks private HgConfigDtoToHgConfigMapperImpl dtoToConfigMapper; @@ -57,7 +54,7 @@ public class HgConfigAutoConfigurationResourceTest { new HgConfigAutoConfigurationResource(dtoToConfigMapper, repositoryHandler); when(resourceProvider.get()).thenReturn(resource); - dispatcher.getRegistry().addSingletonResource( + dispatcher.addSingletonResource( new HgConfigResource(null, null, null, null, resourceProvider, null)); } @@ -76,9 +73,10 @@ public class HgConfigAutoConfigurationResourceTest { @Test @SubjectAware(username = "readOnly") public void shouldNotSetDefaultConfigAndInstallHgWhenNotAuthorized() throws Exception { - thrown.expectMessage("Subject does not have permission [configuration:write:hg]"); + MockHttpResponse response = put(null); - put(null); + assertEquals("Subject does not have permission [configuration:write:hg]", response.getContentAsString()); + assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus()); } @Test @@ -95,9 +93,10 @@ public class HgConfigAutoConfigurationResourceTest { @Test @SubjectAware(username = "readOnly") public void shouldNotUpdateConfigAndInstallHgWhenNotAuthorized() throws Exception { - thrown.expectMessage("Subject does not have permission [configuration:write:hg]"); + MockHttpResponse response = put("{\"disabled\":true}"); - put("{\"disabled\":true}"); + assertEquals("Subject does not have permission [configuration:write:hg]", response.getContentAsString()); + assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus()); } private MockHttpResponse put(String content) throws URISyntaxException { diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsResourceTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsResourceTest.java index 2293d1ddb7..827c69d57f 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsResourceTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsResourceTest.java @@ -2,19 +2,17 @@ package sonia.scm.api.v2.resources; import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; -import org.jboss.resteasy.spi.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.Answers; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import sonia.scm.web.ScmTestDispatcher; import javax.inject.Provider; import javax.servlet.http.HttpServletResponse; @@ -35,10 +33,7 @@ public class HgConfigInstallationsResourceTest { @Rule public ShiroRule shiro = new ShiroRule(); - @Rule - public ExpectedException thrown = ExpectedException.none(); - - private Dispatcher dispatcher = MockDispatcherFactory.createDispatcher(); + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); private final URI baseUri = URI.create("/"); @@ -57,7 +52,7 @@ public class HgConfigInstallationsResourceTest { HgConfigInstallationsResource resource = new HgConfigInstallationsResource(mapper); when(resourceProvider.get()).thenReturn(resource); - dispatcher.getRegistry().addSingletonResource( + dispatcher.addSingletonResource( new HgConfigResource(null, null, null, null, null, resourceProvider)); @@ -82,9 +77,10 @@ public class HgConfigInstallationsResourceTest { @Test @SubjectAware(username = "writeOnly") public void shouldNotGetHgInstallationsWhenNotAuthorized() throws Exception { - thrown.expectMessage("Subject does not have permission [configuration:read:hg]"); + MockHttpResponse response = get("hg"); - get("hg"); + assertEquals("Subject does not have permission [configuration:read:hg]", response.getContentAsString()); + assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus()); } @Test @@ -104,9 +100,10 @@ public class HgConfigInstallationsResourceTest { @Test @SubjectAware(username = "writeOnly") public void shouldNotGetPythonInstallationsWhenNotAuthorized() throws Exception { - thrown.expectMessage("Subject does not have permission [configuration:read:hg]"); + MockHttpResponse response = get("python"); - get("python"); + assertEquals("Subject does not have permission [configuration:read:hg]", response.getContentAsString()); + assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus()); } private MockHttpResponse get(String path) throws URISyntaxException { diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageResourceTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageResourceTest.java index 29032ac8de..6b77b7a0fc 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageResourceTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageResourceTest.java @@ -5,14 +5,11 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; -import org.jboss.resteasy.spi.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.Answers; import org.mockito.InjectMocks; @@ -23,6 +20,7 @@ import sonia.scm.installer.HgPackageReader; import sonia.scm.net.ahc.AdvancedHttpClient; import sonia.scm.repository.HgConfig; import sonia.scm.repository.HgRepositoryHandler; +import sonia.scm.web.ScmTestDispatcher; import javax.inject.Provider; import javax.servlet.http.HttpServletResponse; @@ -49,10 +47,7 @@ public class HgConfigPackageResourceTest { @Rule public ShiroRule shiro = new ShiroRule(); - @Rule - public ExpectedException thrown = ExpectedException.none(); - - private Dispatcher dispatcher = MockDispatcherFactory.createDispatcher(); + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); private final URI baseUri = java.net.URI.create("/"); @@ -113,9 +108,10 @@ public class HgConfigPackageResourceTest { @Test @SubjectAware(username = "writeOnly") public void shouldNotGetPackagesWhenNotAuthorized() throws Exception { - thrown.expectMessage("Subject does not have permission [configuration:read:hg]"); + MockHttpResponse response = get(); - get(); + assertEquals("Subject does not have permission [configuration:read:hg]", response.getContentAsString()); + assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus()); } @Test @@ -158,9 +154,10 @@ public class HgConfigPackageResourceTest { @Test @SubjectAware(username = "readOnly") public void shouldNotInstallPackageWhenNotAuthorized() throws Exception { - thrown.expectMessage("Subject does not have permission [configuration:write:hg]"); + MockHttpResponse response = put("don-t-care"); - put("don-t-care"); + assertEquals("Subject does not have permission [configuration:write:hg]", response.getContentAsString()); + assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus()); } private List createPackages() { @@ -191,7 +188,7 @@ public class HgConfigPackageResourceTest { new HgConfigPackageResource(hgPackageReader, advancedHttpClient, repositoryHandler, mapper); when(hgConfigPackageResourceProvider.get()).thenReturn(hgConfigPackageResource); - dispatcher.getRegistry().addSingletonResource( + dispatcher.addSingletonResource( new HgConfigResource(null, null, null, hgConfigPackageResourceProvider, null, null)); } diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigResourceTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigResourceTest.java index 910f5721e9..f03c894b13 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigResourceTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigResourceTest.java @@ -4,14 +4,11 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; -import org.jboss.resteasy.spi.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.Answers; import org.mockito.InjectMocks; @@ -20,6 +17,7 @@ import org.mockito.junit.MockitoJUnitRunner; import sonia.scm.repository.HgConfig; import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.web.HgVndMediaType; +import sonia.scm.web.ScmTestDispatcher; import javax.inject.Provider; import javax.servlet.http.HttpServletResponse; @@ -43,10 +41,7 @@ public class HgConfigResourceTest { @Rule public ShiroRule shiro = new ShiroRule(); - @Rule - public ExpectedException thrown = ExpectedException.none(); - - private Dispatcher dispatcher = MockDispatcherFactory.createDispatcher(); + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); private final URI baseUri = URI.create("/"); @@ -78,7 +73,7 @@ public class HgConfigResourceTest { HgConfigResource gitConfigResource = new HgConfigResource(dtoToConfigMapper, configToDtoMapper, repositoryHandler, packagesResource, autoconfigResource, installationsResource); - dispatcher.getRegistry().addSingletonResource(gitConfigResource); + dispatcher.addSingletonResource(gitConfigResource); when(scmPathInfoStore.get().getApiRestUri()).thenReturn(baseUri); } @@ -120,10 +115,11 @@ public class HgConfigResourceTest { @Test @SubjectAware(username = "writeOnly") - public void shouldNotGetConfigWhenNotAuthorized() throws URISyntaxException { - thrown.expectMessage("Subject does not have permission [configuration:read:hg]"); + public void shouldNotGetConfigWhenNotAuthorized() throws URISyntaxException, UnsupportedEncodingException { + MockHttpResponse response = get(); - get(); + assertEquals("Subject does not have permission [configuration:read:hg]", response.getContentAsString()); + assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus()); } @Test @@ -135,10 +131,11 @@ public class HgConfigResourceTest { @Test @SubjectAware(username = "readOnly") - public void shouldNotUpdateConfigWhenNotAuthorized() throws URISyntaxException { - thrown.expectMessage("Subject does not have permission [configuration:write:hg]"); + public void shouldNotUpdateConfigWhenNotAuthorized() throws URISyntaxException, UnsupportedEncodingException { + MockHttpResponse response = put(); - put(); + assertEquals("Subject does not have permission [configuration:write:hg]", response.getContentAsString()); + assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus()); } private MockHttpResponse get() throws URISyntaxException { diff --git a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigResourceTest.java b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigResourceTest.java index 6a854471dd..225c838a6c 100644 --- a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigResourceTest.java +++ b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigResourceTest.java @@ -4,14 +4,11 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; -import org.jboss.resteasy.spi.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.Answers; import org.mockito.InjectMocks; @@ -19,6 +16,7 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import sonia.scm.repository.SvnConfig; import sonia.scm.repository.SvnRepositoryHandler; +import sonia.scm.web.ScmTestDispatcher; import sonia.scm.web.SvnVndMediaType; import javax.servlet.http.HttpServletResponse; @@ -42,10 +40,7 @@ public class SvnConfigResourceTest { @Rule public ShiroRule shiro = new ShiroRule(); - @Rule - public ExpectedException thrown = ExpectedException.none(); - - private Dispatcher dispatcher = MockDispatcherFactory.createDispatcher(); + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); private final URI baseUri = URI.create("/"); @@ -66,7 +61,7 @@ public class SvnConfigResourceTest { SvnConfig gitConfig = createConfiguration(); when(repositoryHandler.getConfig()).thenReturn(gitConfig); SvnConfigResource gitConfigResource = new SvnConfigResource(dtoToConfigMapper, configToDtoMapper, repositoryHandler); - dispatcher.getRegistry().addSingletonResource(gitConfigResource); + dispatcher.addSingletonResource(gitConfigResource); when(scmPathInfoStore.get().getApiRestUri()).thenReturn(baseUri); } @@ -108,10 +103,11 @@ public class SvnConfigResourceTest { @Test @SubjectAware(username = "writeOnly") - public void shouldNotGetConfigWhenNotAuthorized() throws URISyntaxException { - thrown.expectMessage("Subject does not have permission [configuration:read:svn]"); + public void shouldNotGetConfigWhenNotAuthorized() throws URISyntaxException, UnsupportedEncodingException { + MockHttpResponse response = get(); - get(); + assertEquals("Subject does not have permission [configuration:read:svn]", response.getContentAsString()); + assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus()); } @Test @@ -123,10 +119,11 @@ public class SvnConfigResourceTest { @Test @SubjectAware(username = "readOnly") - public void shouldNotUpdateConfigWhenNotAuthorized() throws URISyntaxException { - thrown.expectMessage("Subject does not have permission [configuration:write:svn]"); + public void shouldNotUpdateConfigWhenNotAuthorized() throws URISyntaxException, UnsupportedEncodingException { + MockHttpResponse response = put(); - put(); + assertEquals("Subject does not have permission [configuration:write:svn]", response.getContentAsString()); + assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus()); } private MockHttpResponse get() throws URISyntaxException { diff --git a/scm-test/pom.xml b/scm-test/pom.xml index bddbcf2c85..d36b8c55f8 100644 --- a/scm-test/pom.xml +++ b/scm-test/pom.xml @@ -42,6 +42,20 @@ ${mockito.version} + + org.jboss.resteasy + resteasy-core-spi + + + org.jboss.resteasy + resteasy-core + + + org.jboss.resteasy + resteasy-jackson2-provider + ${resteasy.version} + + org.slf4j slf4j-simple diff --git a/scm-test/src/main/java/sonia/scm/web/ScmTestDispatcher.java b/scm-test/src/main/java/sonia/scm/web/ScmTestDispatcher.java new file mode 100644 index 0000000000..f8b3040f73 --- /dev/null +++ b/scm-test/src/main/java/sonia/scm/web/ScmTestDispatcher.java @@ -0,0 +1,109 @@ +package sonia.scm.web; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.shiro.authz.AuthorizationException; +import org.apache.shiro.authz.UnauthorizedException; +import org.jboss.resteasy.mock.MockDispatcherFactory; +import org.jboss.resteasy.spi.Dispatcher; +import org.jboss.resteasy.spi.HttpRequest; +import org.jboss.resteasy.spi.HttpResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import sonia.scm.AlreadyExistsException; +import sonia.scm.BadRequestException; +import sonia.scm.ConcurrentModificationException; +import sonia.scm.NotFoundException; + +import javax.ws.rs.Produces; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.ext.ContextResolver; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; +import java.util.HashMap; +import java.util.Map; + +public class ScmTestDispatcher { + + private static final Logger LOG = LoggerFactory.getLogger(ScmTestDispatcher.class); + + private final Dispatcher dispatcher; + private final EnhanceableExceptionMapper exceptionMapper; + + public ScmTestDispatcher() { + dispatcher = MockDispatcherFactory.createDispatcher(); + exceptionMapper = new EnhanceableExceptionMapper(); + dispatcher.getProviderFactory().register(exceptionMapper); + dispatcher.getProviderFactory().registerProviderInstance(new JacksonProducer()); + } + + public void addSingletonResource(Object resource) { + dispatcher.getRegistry().addSingletonResource(resource); + } + + public void invoke(HttpRequest in, HttpResponse response) { + dispatcher.invoke(in, response); + } + + public void registerException(Class exceptionClass, Status status) { + exceptionMapper.registerException(exceptionClass, status); + } + + public void putDefaultContextObject(Class clazz, T object) { + dispatcher.getDefaultContextObjects().put(clazz, object); + } + + private static class EnhanceableExceptionMapper implements ExceptionMapper { + + private final Map, Integer> statusCodes = new HashMap<>(); + + public EnhanceableExceptionMapper() { + registerException(NotFoundException.class, Status.NOT_FOUND); + registerException(AlreadyExistsException.class, Status.CONFLICT); + registerException(ConcurrentModificationException.class, Status.CONFLICT); + registerException(UnauthorizedException.class, Status.FORBIDDEN); + registerException(AuthorizationException.class, Status.FORBIDDEN); + registerException(BadRequestException.class, Status.BAD_REQUEST); + } + + private void registerException(Class exceptionClass, Status status) { + statusCodes.put(exceptionClass, status.getStatusCode()); + } + + @Override + public Response toResponse(Exception e) { + return Response.status(getStatus(e)).entity(e.getMessage()).build(); + } + + private Integer getStatus(Exception ex) { + return statusCodes + .entrySet() + .stream() + .filter(e -> e.getKey().isAssignableFrom(ex.getClass())) + .map(Map.Entry::getValue) + .findAny() + .orElse(handleUnknownException(ex)); + } + + private Integer handleUnknownException(Exception ex) { + LOG.info("got unknown exception in rest api test", ex); + return 500; + } + } + + @Provider + @Produces("application/*+json") + public static class JacksonProducer implements ContextResolver { + public JacksonProducer() { + this.json + = new ObjectMapper().findAndRegisterModules(); + } + + @Override + public ObjectMapper getContext(Class objectType) { + return json; + } + + private final ObjectMapper json; + } +} diff --git a/scm-webapp/src/test/java/sonia/scm/api/rest/AuthorizationExceptionMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/rest/AuthorizationExceptionMapperTest.java new file mode 100644 index 0000000000..f546a7cf34 --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/api/rest/AuthorizationExceptionMapperTest.java @@ -0,0 +1,5 @@ +package sonia.scm.api.rest; + +class AuthorizationExceptionMapperTest { +// TODO verify differentiation between normal user and anonymous +} diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AuthenticationResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AuthenticationResourceTest.java index c5756fadd6..e96301ad2a 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AuthenticationResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AuthenticationResourceTest.java @@ -2,11 +2,8 @@ package sonia.scm.api.v2.resources; import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; -import org.jboss.resteasy.spi.Dispatcher; -import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; -import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -19,18 +16,17 @@ import sonia.scm.security.AccessTokenBuilder; import sonia.scm.security.AccessTokenBuilderFactory; import sonia.scm.security.AccessTokenCookieIssuer; import sonia.scm.security.DefaultAccessTokenCookieIssuer; +import sonia.scm.web.ScmTestDispatcher; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.core.MediaType; import java.io.UnsupportedEncodingException; -import java.net.URI; import java.net.URISyntaxException; import java.util.Date; import java.util.Optional; import static java.net.URI.create; -import static java.util.Optional.empty; import static java.util.Optional.of; import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertEquals; @@ -47,7 +43,7 @@ public class AuthenticationResourceTest { @Rule public ShiroRule shiro = new ShiroRule(); - private Dispatcher dispatcher = MockDispatcherFactory.createDispatcher(); + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); @Mock private AccessTokenBuilderFactory accessTokenBuilderFactory; @@ -116,7 +112,7 @@ public class AuthenticationResourceTest { @Before public void prepareEnvironment() { authenticationResource = new AuthenticationResource(accessTokenBuilderFactory, cookieIssuer); - dispatcher.getRegistry().addSingletonResource(authenticationResource); + dispatcher.addSingletonResource(authenticationResource); AccessToken accessToken = mock(AccessToken.class); when(accessToken.getExpiration()).thenReturn(new Date(Long.MAX_VALUE)); @@ -125,9 +121,9 @@ public class AuthenticationResourceTest { when(accessTokenBuilderFactory.create()).thenReturn(accessTokenBuilder); HttpServletRequest servletRequest = mock(HttpServletRequest.class); - dispatcher.getDefaultContextObjects().put(HttpServletRequest.class, servletRequest); + dispatcher.putDefaultContextObject(HttpServletRequest.class, servletRequest); HttpServletResponse servletResponse = mock(HttpServletResponse.class); - dispatcher.getDefaultContextObjects().put(HttpServletResponse.class, servletResponse); + dispatcher.putDefaultContextObject(HttpServletResponse.class, servletResponse); } @Test diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AutoCompleteResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AutoCompleteResourceTest.java index f8b4236b41..7356feafe1 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AutoCompleteResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AutoCompleteResourceTest.java @@ -5,7 +5,6 @@ import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; import org.apache.shiro.util.ThreadContext; import org.assertj.core.util.Lists; -import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.After; @@ -23,6 +22,7 @@ import sonia.scm.store.ConfigurationStoreFactory; import sonia.scm.user.DefaultUserDisplayManager; import sonia.scm.user.User; import sonia.scm.user.xml.XmlUserDAO; +import sonia.scm.web.ScmTestDispatcher; import sonia.scm.web.VndMediaType; import sonia.scm.xml.XmlDatabase; @@ -39,7 +39,6 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; -import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher; @SubjectAware(configuration = "classpath:sonia/scm/shiro-002.ini") @RunWith(MockitoJUnitRunner.Silent.class) @@ -50,7 +49,8 @@ public class AutoCompleteResourceTest { public static final String URL = "/" + AutoCompleteResource.PATH; private final Integer defaultLimit = DisplayManager.DEFAULT_LIMIT; - private Dispatcher dispatcher; + + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); private XmlUserDAO userDao; private XmlGroupDAO groupDao; @@ -74,7 +74,7 @@ public class AutoCompleteResourceTest { DefaultUserDisplayManager userManager = new DefaultUserDisplayManager(this.userDao); DefaultGroupDisplayManager groupManager = new DefaultGroupDisplayManager(groupDao); AutoCompleteResource autoCompleteResource = new AutoCompleteResource(mapper, userManager, groupManager); - dispatcher = createDispatcher(autoCompleteResource); + dispatcher.addSingletonResource(autoCompleteResource); } @After diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AvailablePluginResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AvailablePluginResourceTest.java index 99190d942d..fd8b8b9fe9 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AvailablePluginResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AvailablePluginResourceTest.java @@ -1,14 +1,11 @@ package sonia.scm.api.v2.resources; import de.otto.edison.hal.HalRepresentation; -import org.apache.shiro.ShiroException; +import org.apache.shiro.authz.UnauthorizedException; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.ThreadContext; -import org.jboss.resteasy.spi.Dispatcher; -import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; -import org.jboss.resteasy.spi.UnhandledException; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; @@ -24,6 +21,7 @@ import sonia.scm.plugin.InstalledPluginDescriptor; import sonia.scm.plugin.PluginCondition; import sonia.scm.plugin.PluginInformation; import sonia.scm.plugin.PluginManager; +import sonia.scm.web.ScmTestDispatcher; import sonia.scm.web.VndMediaType; import javax.inject.Provider; @@ -34,7 +32,7 @@ import java.util.Collections; import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doThrow; @@ -46,7 +44,7 @@ import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class AvailablePluginResourceTest { - private Dispatcher dispatcher; + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); @Mock Provider availablePluginResourceProvider; @@ -71,10 +69,9 @@ class AvailablePluginResourceTest { @BeforeEach void prepareEnvironment() { - dispatcher = MockDispatcherFactory.createDispatcher(); pluginRootResource = new PluginRootResource(null, availablePluginResourceProvider, null); when(availablePluginResourceProvider.get()).thenReturn(availablePluginResource); - dispatcher.getRegistry().addSingletonResource(pluginRootResource); + dispatcher.addSingletonResource(pluginRootResource); } @Nested @@ -195,20 +192,23 @@ class AvailablePluginResourceTest { @BeforeEach void bindSubject() { ThreadContext.bind(subject); - doThrow(new ShiroException()).when(subject).checkPermission(any(String.class)); + doThrow(new UnauthorizedException()).when(subject).checkPermission(any(String.class)); } @AfterEach public void unbindSubject() { ThreadContext.unbindSubject(); } + @Test void shouldNotGetAvailablePluginsIfMissingPermission() throws URISyntaxException { MockHttpRequest request = MockHttpRequest.get("/v2/plugins/available"); request.accept(VndMediaType.PLUGIN_COLLECTION); MockHttpResponse response = new MockHttpResponse(); - assertThrows(UnhandledException.class, () -> dispatcher.invoke(request, response)); + dispatcher.invoke(request, response); + + assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus()); verify(subject).checkPermission(any(String.class)); } @@ -218,7 +218,9 @@ class AvailablePluginResourceTest { request.accept(VndMediaType.PLUGIN); MockHttpResponse response = new MockHttpResponse(); - assertThrows(UnhandledException.class, () -> dispatcher.invoke(request, response)); + dispatcher.invoke(request, response); + + assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus()); verify(subject).checkPermission(any(String.class)); } @@ -228,7 +230,9 @@ class AvailablePluginResourceTest { request.accept(VndMediaType.PLUGIN); MockHttpResponse response = new MockHttpResponse(); - assertThrows(UnhandledException.class, () -> dispatcher.invoke(request, response)); + dispatcher.invoke(request, response); + + assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus()); verify(subject).checkPermission(any(String.class)); } } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java index 45a2d1613c..43f3d9f74e 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java @@ -6,10 +6,10 @@ import org.apache.shiro.subject.Subject; import org.apache.shiro.subject.support.SubjectThreadState; import org.apache.shiro.util.ThreadContext; import org.apache.shiro.util.ThreadState; +import org.assertj.core.api.Assertions; import org.assertj.core.util.Lists; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; -import org.jboss.resteasy.spi.Dispatcher; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -29,6 +29,7 @@ import sonia.scm.repository.api.BranchesCommandBuilder; import sonia.scm.repository.api.LogCommandBuilder; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; +import sonia.scm.web.ScmTestDispatcher; import sonia.scm.web.VndMediaType; import javax.ws.rs.core.MediaType; @@ -39,8 +40,13 @@ import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.Silent.class) @Slf4j @@ -49,7 +55,8 @@ public class BranchRootResourceTest extends RepositoryTestBase { public static final String BRANCH_PATH = "space/repo/branches/master"; public static final String BRANCH_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + BRANCH_PATH; public static final String REVISION = "revision"; - private Dispatcher dispatcher; + + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); private final URI baseUri = URI.create("/"); private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri); @@ -96,7 +103,7 @@ public class BranchRootResourceTest extends RepositoryTestBase { BranchCollectionToDtoMapper branchCollectionToDtoMapper = new BranchCollectionToDtoMapper(branchToDtoMapper, resourceLinks); branchRootResource = new BranchRootResource(serviceFactory, branchToDtoMapper, branchCollectionToDtoMapper, changesetCollectionToDtoMapper, resourceLinks); super.branchRootResource = Providers.of(branchRootResource); - dispatcher = DispatcherMock.createDispatcher(getRepositoryRootResource()); + dispatcher.addSingletonResource(getRepositoryRootResource()); when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(service); when(serviceFactory.create(any(Repository.class))).thenReturn(service); when(service.getRepository()).thenReturn(new Repository("repoId", "git", "space", "repo")); @@ -125,7 +132,7 @@ public class BranchRootResourceTest extends RepositoryTestBase { assertEquals(404, response.getStatus()); MediaType contentType = (MediaType) response.getOutputHeaders().getFirst("Content-Type"); - assertEquals("application/vnd.scmm-error+json;v=2", contentType.toString()); + Assertions.assertThat(response.getContentAsString()).contains("branch", "master", "space/repo"); } @Test diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java index 601a4a4652..5e890e36e6 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java @@ -8,7 +8,6 @@ import org.apache.shiro.subject.support.SubjectThreadState; import org.apache.shiro.util.ThreadContext; import org.apache.shiro.util.ThreadState; import org.assertj.core.util.Lists; -import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.After; @@ -26,6 +25,7 @@ import sonia.scm.repository.Repository; import sonia.scm.repository.api.LogCommandBuilder; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; +import sonia.scm.web.ScmTestDispatcher; import sonia.scm.web.VndMediaType; import java.net.URI; @@ -48,7 +48,7 @@ public class ChangesetRootResourceTest extends RepositoryTestBase { public static final String CHANGESET_PATH = "space/repo/changesets/"; public static final String CHANGESET_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + CHANGESET_PATH; - private Dispatcher dispatcher; + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); private final URI baseUri = URI.create("/"); private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri); @@ -79,7 +79,7 @@ public class ChangesetRootResourceTest extends RepositoryTestBase { changesetCollectionToDtoMapper = new ChangesetCollectionToDtoMapper(changesetToChangesetDtoMapper, resourceLinks); changesetRootResource = new ChangesetRootResource(serviceFactory, changesetCollectionToDtoMapper, changesetToChangesetDtoMapper); super.changesetRootResource = Providers.of(changesetRootResource); - dispatcher = DispatcherMock.createDispatcher(getRepositoryRootResource()); + dispatcher.addSingletonResource(getRepositoryRootResource()); when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(repositoryService); when(serviceFactory.create(any(Repository.class))).thenReturn(repositoryService); when(repositoryService.getRepository()).thenReturn(new Repository("repoId", "git", "space", "repo")); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ConfigResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ConfigResourceTest.java index 74bb0ab38a..68a743dab3 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ConfigResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ConfigResourceTest.java @@ -4,18 +4,16 @@ import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; import com.google.common.io.Resources; import org.apache.shiro.util.ThreadContext; -import org.jboss.resteasy.spi.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.mockito.InjectMocks; import org.mockito.Mock; import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.NamespaceStrategyValidator; +import sonia.scm.web.ScmTestDispatcher; import sonia.scm.web.VndMediaType; import javax.servlet.http.HttpServletResponse; @@ -41,10 +39,7 @@ public class ConfigResourceTest { @Rule public ShiroRule shiro = new ShiroRule(); - @Rule - public ExpectedException thrown = ExpectedException.none(); - - private Dispatcher dispatcher = MockDispatcherFactory.createDispatcher(); + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); private final URI baseUri = URI.create("/"); @SuppressWarnings("unused") // Is injected @@ -71,7 +66,7 @@ public class ConfigResourceTest { ConfigResource configResource = new ConfigResource(dtoToConfigMapper, configToDtoMapper, createConfiguration(), namespaceStrategyValidator); - dispatcher.getRegistry().addSingletonResource(configResource); + dispatcher.addSingletonResource(configResource); } @Test @@ -88,13 +83,14 @@ public class ConfigResourceTest { @Test @SubjectAware(username = "writeOnly") - public void shouldNotGetConfigWhenNotAuthorized() throws URISyntaxException { + public void shouldNotGetConfigWhenNotAuthorized() throws URISyntaxException, UnsupportedEncodingException { MockHttpRequest request = MockHttpRequest.get("/" + ConfigResource.CONFIG_PATH_V2); MockHttpResponse response = new MockHttpResponse(); - thrown.expectMessage("Subject does not have permission [configuration:read:global]"); - dispatcher.invoke(request, response); + + assertEquals("Subject does not have permission [configuration:read:global]", response.getContentAsString()); + assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus()); } @Test @@ -120,9 +116,10 @@ public class ConfigResourceTest { MockHttpRequest request = post("sonia/scm/api/v2/config-test-update.json"); MockHttpResponse response = new MockHttpResponse(); - thrown.expectMessage("Subject does not have permission [configuration:write:global]"); - dispatcher.invoke(request, response); + + assertEquals("Subject does not have permission [configuration:write:global]", response.getContentAsString()); + assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus()); } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTest.java index c3d4b2fffa..fd41150aa8 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTest.java @@ -7,8 +7,6 @@ import org.apache.shiro.subject.Subject; import org.apache.shiro.subject.support.SubjectThreadState; import org.apache.shiro.util.ThreadContext; import org.apache.shiro.util.ThreadState; -import org.jboss.resteasy.spi.Dispatcher; -import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.After; @@ -18,16 +16,17 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import sonia.scm.NotFoundException; -import sonia.scm.api.rest.AuthorizationExceptionMapper; -import sonia.scm.api.v2.NotFoundExceptionMapper; import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.Repository; import sonia.scm.repository.api.DiffCommandBuilder; import sonia.scm.repository.api.DiffFormat; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; +import sonia.scm.util.CRLFInjectionException; +import sonia.scm.web.ScmTestDispatcher; import sonia.scm.web.VndMediaType; +import javax.ws.rs.core.Response; import java.net.URISyntaxException; import java.util.Arrays; @@ -46,7 +45,8 @@ public class DiffResourceTest extends RepositoryTestBase { public static final String DIFF_PATH = "space/repo/diff/"; public static final String DIFF_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + DIFF_PATH; - private final Dispatcher dispatcher = MockDispatcherFactory.createDispatcher(); + + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); @Mock private RepositoryServiceFactory serviceFactory; @@ -68,14 +68,12 @@ public class DiffResourceTest extends RepositoryTestBase { public void prepareEnvironment() { diffRootResource = new DiffRootResource(serviceFactory); super.diffRootResource = Providers.of(diffRootResource); - dispatcher.getRegistry().addSingletonResource(getRepositoryRootResource()); + dispatcher.addSingletonResource(getRepositoryRootResource()); when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(service); when(serviceFactory.create(any(Repository.class))).thenReturn(service); when(service.getRepository()).thenReturn(new Repository("repoId", "git", "space", "repo")); ExceptionWithContextToErrorDtoMapperImpl mapper = new ExceptionWithContextToErrorDtoMapperImpl(); - dispatcher.getProviderFactory().register(new NotFoundExceptionMapper(mapper)); - dispatcher.getProviderFactory().registerProvider(AuthorizationExceptionMapper.class); - dispatcher.getProviderFactory().registerProvider(CRLFInjectionExceptionMapper.class); + dispatcher.registerException(CRLFInjectionException.class, Response.Status.BAD_REQUEST); when(service.getDiffCommand()).thenReturn(diffCommandBuilder); subjectThreadState.bind(); ThreadContext.bind(subject); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DispatcherMock.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DispatcherMock.java deleted file mode 100644 index 40b2ac54b7..0000000000 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DispatcherMock.java +++ /dev/null @@ -1,24 +0,0 @@ -package sonia.scm.api.v2.resources; - -import org.jboss.resteasy.spi.Dispatcher; -import org.jboss.resteasy.mock.MockDispatcherFactory; -import sonia.scm.api.rest.AlreadyExistsExceptionMapper; -import sonia.scm.api.rest.AuthorizationExceptionMapper; -import sonia.scm.api.rest.BadRequestExceptionMapper; -import sonia.scm.api.rest.ConcurrentModificationExceptionMapper; -import sonia.scm.api.v2.NotFoundExceptionMapper; - -public class DispatcherMock { - public static Dispatcher createDispatcher(Object resource) { - Dispatcher dispatcher = MockDispatcherFactory.createDispatcher(); - dispatcher.getRegistry().addSingletonResource(resource); - ExceptionWithContextToErrorDtoMapperImpl mapper = new ExceptionWithContextToErrorDtoMapperImpl(); - dispatcher.getProviderFactory().register(new NotFoundExceptionMapper(mapper)); - dispatcher.getProviderFactory().register(new AlreadyExistsExceptionMapper(mapper)); - dispatcher.getProviderFactory().register(new ConcurrentModificationExceptionMapper(mapper)); - dispatcher.getProviderFactory().registerProvider(AuthorizationExceptionMapper.class); - dispatcher.getProviderFactory().register(new InternalRepositoryExceptionMapper(mapper)); - dispatcher.getProviderFactory().register(new BadRequestExceptionMapper(mapper)); - return dispatcher; - } -} diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTest.java index b5b903508a..907729d161 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTest.java @@ -7,7 +7,6 @@ import org.apache.shiro.subject.support.SubjectThreadState; import org.apache.shiro.util.ThreadContext; import org.apache.shiro.util.ThreadState; import org.assertj.core.util.Lists; -import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.After; @@ -28,6 +27,7 @@ import sonia.scm.repository.Repository; import sonia.scm.repository.api.LogCommandBuilder; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; +import sonia.scm.web.ScmTestDispatcher; import sonia.scm.web.VndMediaType; import java.net.URI; @@ -70,7 +70,7 @@ public class FileHistoryResourceTest extends RepositoryTestBase { private FileHistoryRootResource fileHistoryRootResource; - private Dispatcher dispatcher; + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); private final Subject subject = mock(Subject.class); private final ThreadState subjectThreadState = new SubjectThreadState(subject); @@ -80,7 +80,7 @@ public class FileHistoryResourceTest extends RepositoryTestBase { fileHistoryCollectionToDtoMapper = new FileHistoryCollectionToDtoMapper(changesetToChangesetDtoMapper, resourceLinks); fileHistoryRootResource = new FileHistoryRootResource(serviceFactory, fileHistoryCollectionToDtoMapper); super.fileHistoryRootResource = Providers.of(fileHistoryRootResource); - dispatcher = DispatcherMock.createDispatcher(getRepositoryRootResource()); + dispatcher.addSingletonResource(getRepositoryRootResource()); when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(service); when(serviceFactory.create(any(Repository.class))).thenReturn(service); when(service.getRepository()).thenReturn(new Repository("repoId", "git", "space", "repo")); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupRootResourceTest.java index bb024eb67c..97088f9d6f 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupRootResourceTest.java @@ -4,7 +4,6 @@ import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; import com.google.common.io.Resources; import com.google.inject.util.Providers; -import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.Before; @@ -15,12 +14,11 @@ import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; import sonia.scm.PageResult; -import sonia.scm.api.rest.JSONContextResolver; -import sonia.scm.api.rest.ObjectMapperProvider; import sonia.scm.group.Group; import sonia.scm.group.GroupManager; import sonia.scm.security.PermissionAssigner; import sonia.scm.security.PermissionDescriptor; +import sonia.scm.web.ScmTestDispatcher; import sonia.scm.web.VndMediaType; import javax.servlet.http.HttpServletResponse; @@ -43,7 +41,6 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; -import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher; @SubjectAware( username = "trillian", @@ -55,7 +52,7 @@ public class GroupRootResourceTest { @Rule public ShiroRule shiro = new ShiroRule(); - private Dispatcher dispatcher; + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(URI.create("/")); @@ -91,8 +88,7 @@ public class GroupRootResourceTest { GroupResource groupResource = new GroupResource(groupManager, groupToDtoMapper, dtoToGroupMapper, groupPermissionResource); GroupRootResource groupRootResource = new GroupRootResource(Providers.of(groupCollectionResource), Providers.of(groupResource)); - dispatcher = createDispatcher(groupRootResource); - dispatcher.getProviderFactory().registerProviderInstance(new JSONContextResolver(new ObjectMapperProvider().get())); + dispatcher.addSingletonResource(groupRootResource); } @Test diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/IncomingRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/IncomingRootResourceTest.java index de0eaeb992..481960e8c7 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/IncomingRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/IncomingRootResourceTest.java @@ -8,7 +8,6 @@ import org.apache.shiro.subject.support.SubjectThreadState; import org.apache.shiro.util.ThreadContext; import org.apache.shiro.util.ThreadState; import org.assertj.core.util.Lists; -import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.After; @@ -28,8 +27,11 @@ import sonia.scm.repository.api.DiffCommandBuilder; import sonia.scm.repository.api.LogCommandBuilder; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; +import sonia.scm.util.CRLFInjectionException; +import sonia.scm.web.ScmTestDispatcher; import sonia.scm.web.VndMediaType; +import javax.ws.rs.core.Response; import java.net.URI; import java.net.URISyntaxException; import java.time.Instant; @@ -53,7 +55,7 @@ public class IncomingRootResourceTest extends RepositoryTestBase { public static final String INCOMING_CHANGESETS_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + INCOMING_PATH; public static final String INCOMING_DIFF_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + INCOMING_PATH; - private Dispatcher dispatcher; + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); private final URI baseUri = URI.create("/"); private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri); @@ -88,13 +90,13 @@ public class IncomingRootResourceTest extends RepositoryTestBase { incomingChangesetCollectionToDtoMapper = new IncomingChangesetCollectionToDtoMapper(changesetToChangesetDtoMapper, resourceLinks); incomingRootResource = new IncomingRootResource(serviceFactory, incomingChangesetCollectionToDtoMapper); super.incomingRootResource = Providers.of(incomingRootResource); - dispatcher = DispatcherMock.createDispatcher(getRepositoryRootResource()); + dispatcher.addSingletonResource(getRepositoryRootResource()); when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(repositoryService); when(serviceFactory.create(any(Repository.class))).thenReturn(repositoryService); when(repositoryService.getRepository()).thenReturn(new Repository("repoId", "git", "space", "repo")); when(repositoryService.getLogCommand()).thenReturn(logCommandBuilder); when(repositoryService.getDiffCommand()).thenReturn(diffCommandBuilder); - dispatcher.getProviderFactory().registerProvider(CRLFInjectionExceptionMapper.class); + dispatcher.registerException(CRLFInjectionException.class, Response.Status.BAD_REQUEST); subjectThreadState.bind(); ThreadContext.bind(subject); when(subject.isPermitted(any(String.class))).thenReturn(true); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/InstalledPluginResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/InstalledPluginResourceTest.java index 8c9ed5ef2a..5319725c9d 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/InstalledPluginResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/InstalledPluginResourceTest.java @@ -1,13 +1,11 @@ package sonia.scm.api.v2.resources; import de.otto.edison.hal.HalRepresentation; +import org.apache.shiro.authz.UnauthorizedException; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.ThreadContext; -import org.jboss.resteasy.spi.Dispatcher; -import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; -import org.jboss.resteasy.spi.UnhandledException; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; @@ -17,9 +15,9 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import sonia.scm.plugin.InstalledPlugin; -import sonia.scm.plugin.InstalledPluginDescriptor; import sonia.scm.plugin.PluginInformation; import sonia.scm.plugin.PluginManager; +import sonia.scm.web.ScmTestDispatcher; import sonia.scm.web.VndMediaType; import javax.inject.Provider; @@ -31,15 +29,17 @@ import java.util.Optional; import static java.util.Collections.emptyList; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import static sonia.scm.plugin.PluginTestHelper.createInstalled; @ExtendWith(MockitoExtension.class) class InstalledPluginResourceTest { - private Dispatcher dispatcher; + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); @Mock Provider installedPluginResourceProvider; @@ -65,10 +65,9 @@ class InstalledPluginResourceTest { @BeforeEach void prepareEnvironment() { - dispatcher = MockDispatcherFactory.createDispatcher(); pluginRootResource = new PluginRootResource(installedPluginResourceProvider, null, null); when(installedPluginResourceProvider.get()).thenReturn(installedPluginResource); - dispatcher.getRegistry().addSingletonResource(pluginRootResource); + dispatcher.addSingletonResource(pluginRootResource); } @Nested @@ -77,7 +76,6 @@ class InstalledPluginResourceTest { @BeforeEach void bindSubject() { ThreadContext.bind(subject); - when(subject.isPermitted(any(String.class))).thenReturn(true); } @AfterEach @@ -129,7 +127,13 @@ class InstalledPluginResourceTest { class WithoutAuthorization { @BeforeEach - void unbindSubject() { + void bindSubject() { + ThreadContext.bind(subject); + doThrow(new UnauthorizedException()).when(subject).checkPermission(any(String.class)); + } + + @AfterEach + public void unbindSubject() { ThreadContext.unbindSubject(); } @@ -139,7 +143,9 @@ class InstalledPluginResourceTest { request.accept(VndMediaType.PLUGIN_COLLECTION); MockHttpResponse response = new MockHttpResponse(); - assertThrows(UnhandledException.class, () -> dispatcher.invoke(request, response)); + dispatcher.invoke(request, response); + + assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus()); } @Test @@ -148,7 +154,9 @@ class InstalledPluginResourceTest { request.accept(VndMediaType.PLUGIN); MockHttpResponse response = new MockHttpResponse(); - assertThrows(UnhandledException.class, () -> dispatcher.invoke(request, response)); + dispatcher.invoke(request, response); + + assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus()); } } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MeResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MeResourceTest.java index 7aeabe6bec..1c876755a6 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MeResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MeResourceTest.java @@ -7,7 +7,6 @@ import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.credential.PasswordService; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.Subject; -import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.Before; @@ -21,6 +20,7 @@ import sonia.scm.group.GroupCollector; import sonia.scm.user.InvalidPasswordException; import sonia.scm.user.User; import sonia.scm.user.UserManager; +import sonia.scm.web.ScmTestDispatcher; import sonia.scm.web.VndMediaType; import javax.servlet.http.HttpServletResponse; @@ -37,7 +37,6 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; -import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher; @SubjectAware( username = "trillian", @@ -49,9 +48,10 @@ public class MeResourceTest { @Rule public ShiroRule shiro = new ShiroRule(); - private Dispatcher dispatcher; + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(URI.create("/")); + @Mock private ScmPathInfo uriInfo; @Mock @@ -85,7 +85,7 @@ public class MeResourceTest { MeResource meResource = new MeResource(meDtoFactory, userManager, passwordService); when(uriInfo.getApiRestUri()).thenReturn(URI.create("/")); when(scmPathInfoStore.get()).thenReturn(uriInfo); - dispatcher = createDispatcher(meResource); + dispatcher.addSingletonResource(meResource); } @Test diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java index 8e84f9d1bb..6806dd248e 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java @@ -7,7 +7,6 @@ import org.apache.shiro.subject.support.SubjectThreadState; import org.apache.shiro.util.ThreadContext; import org.apache.shiro.util.ThreadState; import org.assertj.core.util.Lists; -import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.After; @@ -24,6 +23,7 @@ import sonia.scm.repository.Repository; import sonia.scm.repository.api.ModificationsCommandBuilder; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; +import sonia.scm.web.ScmTestDispatcher; import sonia.scm.web.VndMediaType; import java.net.URI; @@ -45,7 +45,7 @@ public class ModificationsResourceTest extends RepositoryTestBase { public static final String MODIFICATIONS_PATH = "space/repo/modifications/"; public static final String MODIFICATIONS_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + MODIFICATIONS_PATH; - private Dispatcher dispatcher; + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); private final URI baseUri = URI.create("/"); private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri); @@ -73,7 +73,7 @@ public class ModificationsResourceTest extends RepositoryTestBase { public void prepareEnvironment() { modificationsRootResource = new ModificationsRootResource(serviceFactory, modificationsToDtoMapper); super.modificationsRootResource = Providers.of(modificationsRootResource); - dispatcher = DispatcherMock.createDispatcher(getRepositoryRootResource()); + dispatcher.addSingletonResource(getRepositoryRootResource()); when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(repositoryService); when(serviceFactory.create(any(Repository.class))).thenReturn(repositoryService); when(repositoryService.getRepository()).thenReturn(new Repository("repoId", "git", "space", "repo")); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PendingPluginResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PendingPluginResourceTest.java index 3613069d63..be5374472f 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PendingPluginResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PendingPluginResourceTest.java @@ -4,8 +4,6 @@ import com.google.inject.util.Providers; import org.apache.shiro.ShiroException; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.ThreadContext; -import org.jboss.resteasy.spi.Dispatcher; -import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.jupiter.api.AfterEach; @@ -22,10 +20,10 @@ import sonia.scm.plugin.InstalledPlugin; import sonia.scm.plugin.InstalledPluginDescriptor; import sonia.scm.plugin.PluginInformation; import sonia.scm.plugin.PluginManager; +import sonia.scm.web.ScmTestDispatcher; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.core.Response; -import javax.ws.rs.ext.ExceptionMapper; import java.io.UnsupportedEncodingException; import java.net.URISyntaxException; @@ -42,7 +40,7 @@ import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class PendingPluginResourceTest { - Dispatcher dispatcher = MockDispatcherFactory.createDispatcher(); + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); ResourceLinks resourceLinks = ResourceLinksMock.createMock(create("/")); @@ -61,10 +59,9 @@ class PendingPluginResourceTest { @BeforeEach void prepareEnvironment() { - dispatcher = MockDispatcherFactory.createDispatcher(); - dispatcher.getProviderFactory().register(new PermissionExceptionMapper()); + dispatcher.registerException(ShiroException.class, Response.Status.UNAUTHORIZED); PluginRootResource pluginRootResource = new PluginRootResource(null, null, Providers.of(pendingPluginResource)); - dispatcher.getRegistry().addSingletonResource(pluginRootResource); + dispatcher.addSingletonResource(pluginRootResource); } @BeforeEach @@ -207,14 +204,6 @@ class PendingPluginResourceTest { } } - static class PermissionExceptionMapper implements ExceptionMapper { - - @Override - public Response toResponse(ShiroException exception) { - return Response.status(401).entity(exception.getMessage()).build(); - } - } - private AvailablePlugin createAvailablePlugin(String name) { PluginInformation pluginInformation = new PluginInformation(); pluginInformation.setName(name); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java index a2e63dd50e..8ad4522b4d 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java @@ -13,7 +13,6 @@ import org.apache.shiro.subject.support.SubjectThreadState; import org.apache.shiro.util.ThreadContext; import org.apache.shiro.util.ThreadState; import org.assertj.core.util.Lists; -import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.jboss.resteasy.spi.HttpRequest; @@ -30,6 +29,7 @@ import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.RepositoryPermission; +import sonia.scm.web.ScmTestDispatcher; import sonia.scm.web.VndMediaType; import javax.ws.rs.HttpMethod; @@ -58,7 +58,6 @@ import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; -import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher; import static sonia.scm.api.v2.resources.RepositoryPermissionDto.GROUP_PREFIX; @Slf4j @@ -105,7 +104,7 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { .content(PERMISSION_TEST_PAYLOAD) .path(PATH_OF_ONE_PERMISSION); - private Dispatcher dispatcher; + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); @Mock private RepositoryManager repositoryManager; @@ -133,7 +132,7 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { repositoryPermissionCollectionToDtoMapper = new RepositoryPermissionCollectionToDtoMapper(permissionToPermissionDtoMapper, resourceLinks); repositoryPermissionRootResource = new RepositoryPermissionRootResource(permissionDtoToPermissionMapper, permissionToPermissionDtoMapper, repositoryPermissionCollectionToDtoMapper, resourceLinks, repositoryManager); super.permissionRootResource = Providers.of(repositoryPermissionRootResource); - dispatcher = createDispatcher(getRepositoryRootResource()); + dispatcher.addSingletonResource(getRepositoryRootResource()); subjectThreadState.bind(); ThreadContext.bind(subject); } @@ -180,19 +179,6 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { requestPUTPermission.expectedResponseStatus(403)); } - @TestFactory - @DisplayName("test endpoints on missing permissions and is _anonymous") - Stream missedPermissionAnonymousUnauthorizedTestFactory() { - when(subject.getPrincipal()).thenReturn("_anonymous"); - doThrow(AuthorizationException.class).when(repositoryManager).get(any(NamespaceAndName.class)); - return createDynamicTestsToAssertResponses( - requestGETPermission.expectedResponseStatus(401), - requestPOSTPermission.expectedResponseStatus(401), - requestGETAllPermissions.expectedResponseStatus(401), - requestDELETEPermission.expectedResponseStatus(401), - requestPUTPermission.expectedResponseStatus(401)); - } - @Test public void userWithPermissionWritePermissionShouldGetAllPermissionsWithCreateAndUpdateLinks() throws URISyntaxException { createUserWithRepositoryAndPermissions(TEST_PERMISSIONS, PERMISSION_WRITE); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRoleRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRoleRootResourceTest.java index d60a32f5dc..e458af6a11 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRoleRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRoleRootResourceTest.java @@ -3,7 +3,6 @@ package sonia.scm.api.v2.resources; import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; import com.google.inject.util.Providers; -import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.Before; @@ -16,10 +15,9 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import sonia.scm.PageResult; -import sonia.scm.api.rest.JSONContextResolver; -import sonia.scm.api.rest.ObjectMapperProvider; import sonia.scm.repository.RepositoryRole; import sonia.scm.repository.RepositoryRoleManager; +import sonia.scm.web.ScmTestDispatcher; import sonia.scm.web.VndMediaType; import javax.servlet.http.HttpServletResponse; @@ -36,7 +34,6 @@ import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher; @SubjectAware( username = "trillian", @@ -66,7 +63,7 @@ public class RepositoryRoleRootResourceTest { private RepositoryRoleCollectionToDtoMapper collectionToDtoMapper; - private Dispatcher dispatcher; + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); @Captor private ArgumentCaptor modifyCaptor; @@ -87,8 +84,7 @@ public class RepositoryRoleRootResourceTest { when(repositoryRoleManager.create(createCaptor.capture())).thenAnswer(invocation -> invocation.getArguments()[0]); doNothing().when(repositoryRoleManager).delete(deleteCaptor.capture()); - dispatcher = createDispatcher(rootResource); - dispatcher.getProviderFactory().registerProviderInstance(new JSONContextResolver(new ObjectMapperProvider().get())); + dispatcher.addSingletonResource(rootResource); when(repositoryRoleManager.get(CUSTOM_ROLE)).thenReturn(CUSTOM_REPOSITORY_ROLE); when(repositoryRoleManager.get(SYSTEM_ROLE)).thenReturn(SYSTEM_REPOSITORY_ROLE); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java index fcd34334b2..206f7713a3 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java @@ -6,7 +6,6 @@ import com.google.common.io.Resources; import com.google.inject.util.Providers; import org.apache.shiro.subject.SimplePrincipalCollection; import org.apache.shiro.subject.Subject; -import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.Before; @@ -23,6 +22,7 @@ import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; import sonia.scm.user.User; +import sonia.scm.web.ScmTestDispatcher; import sonia.scm.web.VndMediaType; import javax.servlet.http.HttpServletResponse; @@ -47,12 +47,10 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyObject; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; -import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher; @SubjectAware( username = "trillian", @@ -63,7 +61,7 @@ public class RepositoryRootResourceTest extends RepositoryTestBase { private static final String REALM = "AdminRealm"; - private Dispatcher dispatcher; + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); @Rule public ShiroRule shiro = new ShiroRule(); @@ -98,7 +96,7 @@ public class RepositoryRootResourceTest extends RepositoryTestBase { super.manager = repositoryManager; RepositoryCollectionToDtoMapper repositoryCollectionToDtoMapper = new RepositoryCollectionToDtoMapper(repositoryToDtoMapper, resourceLinks); super.repositoryCollectionResource = Providers.of(new RepositoryCollectionResource(repositoryManager, repositoryCollectionToDtoMapper, dtoToRepositoryMapper, resourceLinks)); - dispatcher = createDispatcher(getRepositoryRootResource()); + dispatcher.addSingletonResource(getRepositoryRootResource()); when(serviceFactory.create(any(Repository.class))).thenReturn(service); when(scmPathInfoStore.get()).thenReturn(uriInfo); when(uriInfo.getApiRestUri()).thenReturn(URI.create("/x/y")); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTypeRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTypeRootResourceTest.java index 17ea3248c2..3dd30e21c0 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTypeRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTypeRootResourceTest.java @@ -3,8 +3,6 @@ package sonia.scm.api.v2.resources; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.google.inject.util.Providers; -import org.jboss.resteasy.spi.Dispatcher; -import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.Before; @@ -15,6 +13,7 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.RepositoryType; +import sonia.scm.web.ScmTestDispatcher; import sonia.scm.web.VndMediaType; import java.net.URI; @@ -32,7 +31,7 @@ import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.Silent.class) public class RepositoryTypeRootResourceTest { - private final Dispatcher dispatcher = MockDispatcherFactory.createDispatcher(); + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); @Mock private RepositoryManager repositoryManager; @@ -56,7 +55,7 @@ public class RepositoryTypeRootResourceTest { RepositoryTypeCollectionResource collectionResource = new RepositoryTypeCollectionResource(repositoryManager, collectionMapper); RepositoryTypeResource resource = new RepositoryTypeResource(repositoryManager, mapper); RepositoryTypeRootResource rootResource = new RepositoryTypeRootResource(Providers.of(collectionResource), Providers.of(resource)); - dispatcher.getRegistry().addSingletonResource(rootResource); + dispatcher.addSingletonResource(rootResource); } @Test diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java index a25aabaca1..4dd694c092 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java @@ -1,7 +1,6 @@ package sonia.scm.api.v2.resources; import com.google.inject.util.Providers; -import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.Before; @@ -18,6 +17,7 @@ import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.api.BrowseCommandBuilder; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; +import sonia.scm.web.ScmTestDispatcher; import java.io.IOException; import java.net.URI; @@ -25,13 +25,12 @@ import java.net.URISyntaxException; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.when; -import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher; @RunWith(MockitoJUnitRunner.Silent.class) public class SourceRootResourceTest extends RepositoryTestBase { - private Dispatcher dispatcher; + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); private final URI baseUri = URI.create("/"); private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri); @@ -58,7 +57,7 @@ public class SourceRootResourceTest extends RepositoryTestBase { SourceRootResource sourceRootResource = new SourceRootResource(serviceFactory, browserResultToFileObjectDtoMapper); super.sourceRootResource = Providers.of(sourceRootResource); - dispatcher = createDispatcher(getRepositoryRootResource()); + dispatcher.addSingletonResource(getRepositoryRootResource()); } @Test diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java index e97f6c726f..29616db703 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java @@ -7,7 +7,6 @@ import org.apache.shiro.subject.support.SubjectThreadState; import org.apache.shiro.util.ThreadContext; import org.apache.shiro.util.ThreadState; import org.assertj.core.util.Lists; -import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.After; @@ -17,8 +16,6 @@ import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; -import sonia.scm.api.rest.AuthorizationExceptionMapper; -import sonia.scm.api.v2.NotFoundExceptionMapper; import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.Repository; import sonia.scm.repository.Tag; @@ -26,6 +23,7 @@ import sonia.scm.repository.Tags; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; import sonia.scm.repository.api.TagsCommandBuilder; +import sonia.scm.web.ScmTestDispatcher; import sonia.scm.web.VndMediaType; import java.net.URI; @@ -36,7 +34,6 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher; @Slf4j @RunWith(MockitoJUnitRunner.Silent.class) @@ -44,7 +41,8 @@ public class TagRootResourceTest extends RepositoryTestBase { public static final String TAG_PATH = "space/repo/tags/"; public static final String TAG_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + TAG_PATH; - private Dispatcher dispatcher ; + + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); private final URI baseUri = URI.create("/"); private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri); @@ -74,12 +72,10 @@ public class TagRootResourceTest extends RepositoryTestBase { tagCollectionToDtoMapper = new TagCollectionToDtoMapper(resourceLinks, tagToTagDtoMapper); tagRootResource = new TagRootResource(serviceFactory, tagCollectionToDtoMapper, tagToTagDtoMapper); super.tagRootResource = Providers.of(tagRootResource); - dispatcher = createDispatcher(getRepositoryRootResource()); + dispatcher.addSingletonResource(getRepositoryRootResource()); when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(repositoryService); when(serviceFactory.create(any(Repository.class))).thenReturn(repositoryService); when(repositoryService.getRepository()).thenReturn(new Repository("repoId", "git", "space", "repo")); - dispatcher.getProviderFactory().registerProvider(NotFoundExceptionMapper.class); - dispatcher.getProviderFactory().registerProvider(AuthorizationExceptionMapper.class); when(repositoryService.getTagsCommand()).thenReturn(tagsCommandBuilder); subjectThreadState.bind(); ThreadContext.bind(subject); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UIRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UIRootResourceTest.java index 0391e43c81..da0c862168 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UIRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UIRootResourceTest.java @@ -3,8 +3,6 @@ package sonia.scm.api.v2.resources; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.google.inject.util.Providers; -import org.jboss.resteasy.spi.Dispatcher; -import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.Before; @@ -12,7 +10,12 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; -import sonia.scm.plugin.*; +import sonia.scm.plugin.InstalledPlugin; +import sonia.scm.plugin.InstalledPluginDescriptor; +import sonia.scm.plugin.PluginInformation; +import sonia.scm.plugin.PluginLoader; +import sonia.scm.plugin.PluginResources; +import sonia.scm.web.ScmTestDispatcher; import sonia.scm.web.VndMediaType; import javax.servlet.http.HttpServletRequest; @@ -24,14 +27,17 @@ import java.util.HashSet; import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND; import static javax.servlet.http.HttpServletResponse.SC_OK; import static org.hamcrest.Matchers.equalToIgnoringCase; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.Silent.class) public class UIRootResourceTest { - private final Dispatcher dispatcher = MockDispatcherFactory.createDispatcher(); + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); @Mock private PluginLoader pluginLoader; @@ -50,7 +56,7 @@ public class UIRootResourceTest { UIPluginResource pluginResource = new UIPluginResource(pluginLoader, collectionMapper, mapper); UIRootResource rootResource = new UIRootResource(Providers.of(pluginResource)); - dispatcher.getRegistry().addSingletonResource(rootResource); + dispatcher.addSingletonResource(rootResource); } @Test diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UserRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UserRootResourceTest.java index e055bbf3b5..6426007556 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UserRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UserRootResourceTest.java @@ -5,7 +5,6 @@ import com.github.sdorra.shiro.SubjectAware; import com.google.common.io.Resources; import com.google.inject.util.Providers; import org.apache.shiro.authc.credential.PasswordService; -import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.Before; @@ -23,6 +22,7 @@ import sonia.scm.security.PermissionDescriptor; import sonia.scm.user.ChangePasswordNotAllowedException; import sonia.scm.user.User; import sonia.scm.user.UserManager; +import sonia.scm.web.ScmTestDispatcher; import sonia.scm.web.VndMediaType; import javax.servlet.http.HttpServletResponse; @@ -45,7 +45,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; -import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher; @SubjectAware( username = "trillian", @@ -57,7 +56,7 @@ public class UserRootResourceTest { @Rule public ShiroRule shiro = new ShiroRule(); - private Dispatcher dispatcher; + private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(URI.create("/")); @@ -99,7 +98,7 @@ public class UserRootResourceTest { UserRootResource userRootResource = new UserRootResource(Providers.of(userCollectionResource), Providers.of(userResource)); - dispatcher = createDispatcher(userRootResource); + dispatcher.addSingletonResource(userRootResource); } @Test From d0f8e4ccf25ea2d8569291368dc0bf406b64b088 Mon Sep 17 00:00:00 2001 From: Rene Pfeuffer Date: Thu, 5 Dec 2019 17:43:21 +0100 Subject: [PATCH 10/14] Rename utility class --- .../sonia/scm/api/v2/resources/GitConfigResourceTest.java | 4 ++-- .../v2/resources/HgConfigAutoConfigurationResourceTest.java | 4 ++-- .../api/v2/resources/HgConfigInstallationsResourceTest.java | 4 ++-- .../scm/api/v2/resources/HgConfigPackageResourceTest.java | 4 ++-- .../sonia/scm/api/v2/resources/HgConfigResourceTest.java | 4 ++-- .../sonia/scm/api/v2/resources/SvnConfigResourceTest.java | 4 ++-- .../scm/web/{ScmTestDispatcher.java => RestDispatcher.java} | 6 +++--- .../scm/api/v2/resources/AuthenticationResourceTest.java | 4 ++-- .../scm/api/v2/resources/AutoCompleteResourceTest.java | 4 ++-- .../scm/api/v2/resources/AvailablePluginResourceTest.java | 4 ++-- .../sonia/scm/api/v2/resources/BranchRootResourceTest.java | 4 ++-- .../scm/api/v2/resources/ChangesetRootResourceTest.java | 4 ++-- .../java/sonia/scm/api/v2/resources/ConfigResourceTest.java | 4 ++-- .../java/sonia/scm/api/v2/resources/DiffResourceTest.java | 4 ++-- .../sonia/scm/api/v2/resources/FileHistoryResourceTest.java | 4 ++-- .../sonia/scm/api/v2/resources/GroupRootResourceTest.java | 4 ++-- .../scm/api/v2/resources/IncomingRootResourceTest.java | 4 ++-- .../scm/api/v2/resources/InstalledPluginResourceTest.java | 4 ++-- .../java/sonia/scm/api/v2/resources/MeResourceTest.java | 4 ++-- .../scm/api/v2/resources/ModificationsResourceTest.java | 4 ++-- .../scm/api/v2/resources/PendingPluginResourceTest.java | 4 ++-- .../v2/resources/RepositoryPermissionRootResourceTest.java | 4 ++-- .../api/v2/resources/RepositoryRoleRootResourceTest.java | 4 ++-- .../scm/api/v2/resources/RepositoryRootResourceTest.java | 4 ++-- .../api/v2/resources/RepositoryTypeRootResourceTest.java | 4 ++-- .../sonia/scm/api/v2/resources/SourceRootResourceTest.java | 4 ++-- .../sonia/scm/api/v2/resources/TagRootResourceTest.java | 4 ++-- .../java/sonia/scm/api/v2/resources/UIRootResourceTest.java | 4 ++-- .../sonia/scm/api/v2/resources/UserRootResourceTest.java | 4 ++-- 29 files changed, 59 insertions(+), 59 deletions(-) rename scm-test/src/main/java/sonia/scm/web/{ScmTestDispatcher.java => RestDispatcher.java} (95%) diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigResourceTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigResourceTest.java index 3d3987aca3..a561914b42 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigResourceTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigResourceTest.java @@ -24,7 +24,7 @@ import sonia.scm.repository.RepositoryManager; import sonia.scm.store.ConfigurationStore; import sonia.scm.store.ConfigurationStoreFactory; import sonia.scm.web.GitVndMediaType; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import javax.servlet.http.HttpServletResponse; import java.io.UnsupportedEncodingException; @@ -50,7 +50,7 @@ public class GitConfigResourceTest { @Rule public ShiroRule shiro = new ShiroRule(); - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); private final URI baseUri = URI.create("/"); 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 index fa2b559041..5a3b809973 100644 --- 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 @@ -15,7 +15,7 @@ import org.mockito.junit.MockitoJUnitRunner; import sonia.scm.repository.HgConfig; import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.web.HgVndMediaType; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import javax.inject.Provider; import javax.servlet.http.HttpServletResponse; @@ -37,7 +37,7 @@ public class HgConfigAutoConfigurationResourceTest { @Rule public ShiroRule shiro = new ShiroRule(); - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); @InjectMocks private HgConfigDtoToHgConfigMapperImpl dtoToConfigMapper; diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsResourceTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsResourceTest.java index 827c69d57f..e77ed917ed 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsResourceTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsResourceTest.java @@ -12,7 +12,7 @@ import org.mockito.Answers; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import javax.inject.Provider; import javax.servlet.http.HttpServletResponse; @@ -33,7 +33,7 @@ public class HgConfigInstallationsResourceTest { @Rule public ShiroRule shiro = new ShiroRule(); - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); private final URI baseUri = URI.create("/"); diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageResourceTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageResourceTest.java index 6b77b7a0fc..9cd0e4b17e 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageResourceTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageResourceTest.java @@ -20,7 +20,7 @@ import sonia.scm.installer.HgPackageReader; import sonia.scm.net.ahc.AdvancedHttpClient; import sonia.scm.repository.HgConfig; import sonia.scm.repository.HgRepositoryHandler; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import javax.inject.Provider; import javax.servlet.http.HttpServletResponse; @@ -47,7 +47,7 @@ public class HgConfigPackageResourceTest { @Rule public ShiroRule shiro = new ShiroRule(); - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); private final URI baseUri = java.net.URI.create("/"); diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigResourceTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigResourceTest.java index f03c894b13..eae03f729d 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigResourceTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigResourceTest.java @@ -17,7 +17,7 @@ import org.mockito.junit.MockitoJUnitRunner; import sonia.scm.repository.HgConfig; import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.web.HgVndMediaType; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import javax.inject.Provider; import javax.servlet.http.HttpServletResponse; @@ -41,7 +41,7 @@ public class HgConfigResourceTest { @Rule public ShiroRule shiro = new ShiroRule(); - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); private final URI baseUri = URI.create("/"); diff --git a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigResourceTest.java b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigResourceTest.java index 225c838a6c..ee2918160c 100644 --- a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigResourceTest.java +++ b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigResourceTest.java @@ -16,7 +16,7 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import sonia.scm.repository.SvnConfig; import sonia.scm.repository.SvnRepositoryHandler; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import sonia.scm.web.SvnVndMediaType; import javax.servlet.http.HttpServletResponse; @@ -40,7 +40,7 @@ public class SvnConfigResourceTest { @Rule public ShiroRule shiro = new ShiroRule(); - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); private final URI baseUri = URI.create("/"); diff --git a/scm-test/src/main/java/sonia/scm/web/ScmTestDispatcher.java b/scm-test/src/main/java/sonia/scm/web/RestDispatcher.java similarity index 95% rename from scm-test/src/main/java/sonia/scm/web/ScmTestDispatcher.java rename to scm-test/src/main/java/sonia/scm/web/RestDispatcher.java index f8b3040f73..bf0a64afc7 100644 --- a/scm-test/src/main/java/sonia/scm/web/ScmTestDispatcher.java +++ b/scm-test/src/main/java/sonia/scm/web/RestDispatcher.java @@ -23,14 +23,14 @@ import javax.ws.rs.ext.Provider; import java.util.HashMap; import java.util.Map; -public class ScmTestDispatcher { +public class RestDispatcher { - private static final Logger LOG = LoggerFactory.getLogger(ScmTestDispatcher.class); + private static final Logger LOG = LoggerFactory.getLogger(RestDispatcher.class); private final Dispatcher dispatcher; private final EnhanceableExceptionMapper exceptionMapper; - public ScmTestDispatcher() { + public RestDispatcher() { dispatcher = MockDispatcherFactory.createDispatcher(); exceptionMapper = new EnhanceableExceptionMapper(); dispatcher.getProviderFactory().register(exceptionMapper); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AuthenticationResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AuthenticationResourceTest.java index e96301ad2a..1c1035b53a 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AuthenticationResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AuthenticationResourceTest.java @@ -16,7 +16,7 @@ import sonia.scm.security.AccessTokenBuilder; import sonia.scm.security.AccessTokenBuilderFactory; import sonia.scm.security.AccessTokenCookieIssuer; import sonia.scm.security.DefaultAccessTokenCookieIssuer; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -43,7 +43,7 @@ public class AuthenticationResourceTest { @Rule public ShiroRule shiro = new ShiroRule(); - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); @Mock private AccessTokenBuilderFactory accessTokenBuilderFactory; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AutoCompleteResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AutoCompleteResourceTest.java index 7356feafe1..3f2473dda0 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AutoCompleteResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AutoCompleteResourceTest.java @@ -22,7 +22,7 @@ import sonia.scm.store.ConfigurationStoreFactory; import sonia.scm.user.DefaultUserDisplayManager; import sonia.scm.user.User; import sonia.scm.user.xml.XmlUserDAO; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import sonia.scm.web.VndMediaType; import sonia.scm.xml.XmlDatabase; @@ -50,7 +50,7 @@ public class AutoCompleteResourceTest { public static final String URL = "/" + AutoCompleteResource.PATH; private final Integer defaultLimit = DisplayManager.DEFAULT_LIMIT; - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); private XmlUserDAO userDao; private XmlGroupDAO groupDao; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AvailablePluginResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AvailablePluginResourceTest.java index fd8b8b9fe9..cfda20f285 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AvailablePluginResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AvailablePluginResourceTest.java @@ -21,7 +21,7 @@ import sonia.scm.plugin.InstalledPluginDescriptor; import sonia.scm.plugin.PluginCondition; import sonia.scm.plugin.PluginInformation; import sonia.scm.plugin.PluginManager; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import sonia.scm.web.VndMediaType; import javax.inject.Provider; @@ -44,7 +44,7 @@ import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class AvailablePluginResourceTest { - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); @Mock Provider availablePluginResourceProvider; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java index 43f3d9f74e..72bf9e96d6 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java @@ -29,7 +29,7 @@ import sonia.scm.repository.api.BranchesCommandBuilder; import sonia.scm.repository.api.LogCommandBuilder; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import sonia.scm.web.VndMediaType; import javax.ws.rs.core.MediaType; @@ -56,7 +56,7 @@ public class BranchRootResourceTest extends RepositoryTestBase { public static final String BRANCH_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + BRANCH_PATH; public static final String REVISION = "revision"; - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); private final URI baseUri = URI.create("/"); private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java index 5e890e36e6..1e2b4a0979 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java @@ -25,7 +25,7 @@ import sonia.scm.repository.Repository; import sonia.scm.repository.api.LogCommandBuilder; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import sonia.scm.web.VndMediaType; import java.net.URI; @@ -48,7 +48,7 @@ public class ChangesetRootResourceTest extends RepositoryTestBase { public static final String CHANGESET_PATH = "space/repo/changesets/"; public static final String CHANGESET_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + CHANGESET_PATH; - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); private final URI baseUri = URI.create("/"); private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ConfigResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ConfigResourceTest.java index 68a743dab3..951f3dc24c 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ConfigResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ConfigResourceTest.java @@ -13,7 +13,7 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.NamespaceStrategyValidator; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import sonia.scm.web.VndMediaType; import javax.servlet.http.HttpServletResponse; @@ -39,7 +39,7 @@ public class ConfigResourceTest { @Rule public ShiroRule shiro = new ShiroRule(); - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); private final URI baseUri = URI.create("/"); @SuppressWarnings("unused") // Is injected diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTest.java index fd41150aa8..f01a20f6c4 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTest.java @@ -23,7 +23,7 @@ import sonia.scm.repository.api.DiffFormat; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; import sonia.scm.util.CRLFInjectionException; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import sonia.scm.web.VndMediaType; import javax.ws.rs.core.Response; @@ -46,7 +46,7 @@ public class DiffResourceTest extends RepositoryTestBase { public static final String DIFF_PATH = "space/repo/diff/"; public static final String DIFF_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + DIFF_PATH; - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); @Mock private RepositoryServiceFactory serviceFactory; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTest.java index 907729d161..5803fbec9f 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTest.java @@ -27,7 +27,7 @@ import sonia.scm.repository.Repository; import sonia.scm.repository.api.LogCommandBuilder; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import sonia.scm.web.VndMediaType; import java.net.URI; @@ -70,7 +70,7 @@ public class FileHistoryResourceTest extends RepositoryTestBase { private FileHistoryRootResource fileHistoryRootResource; - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); private final Subject subject = mock(Subject.class); private final ThreadState subjectThreadState = new SubjectThreadState(subject); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupRootResourceTest.java index 97088f9d6f..5f2abb85f0 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupRootResourceTest.java @@ -18,7 +18,7 @@ import sonia.scm.group.Group; import sonia.scm.group.GroupManager; import sonia.scm.security.PermissionAssigner; import sonia.scm.security.PermissionDescriptor; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import sonia.scm.web.VndMediaType; import javax.servlet.http.HttpServletResponse; @@ -52,7 +52,7 @@ public class GroupRootResourceTest { @Rule public ShiroRule shiro = new ShiroRule(); - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(URI.create("/")); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/IncomingRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/IncomingRootResourceTest.java index 481960e8c7..27a9f0d6a5 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/IncomingRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/IncomingRootResourceTest.java @@ -28,7 +28,7 @@ import sonia.scm.repository.api.LogCommandBuilder; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; import sonia.scm.util.CRLFInjectionException; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import sonia.scm.web.VndMediaType; import javax.ws.rs.core.Response; @@ -55,7 +55,7 @@ public class IncomingRootResourceTest extends RepositoryTestBase { public static final String INCOMING_CHANGESETS_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + INCOMING_PATH; public static final String INCOMING_DIFF_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + INCOMING_PATH; - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); private final URI baseUri = URI.create("/"); private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/InstalledPluginResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/InstalledPluginResourceTest.java index 5319725c9d..d1d406c6af 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/InstalledPluginResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/InstalledPluginResourceTest.java @@ -17,7 +17,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import sonia.scm.plugin.InstalledPlugin; import sonia.scm.plugin.PluginInformation; import sonia.scm.plugin.PluginManager; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import sonia.scm.web.VndMediaType; import javax.inject.Provider; @@ -39,7 +39,7 @@ import static sonia.scm.plugin.PluginTestHelper.createInstalled; @ExtendWith(MockitoExtension.class) class InstalledPluginResourceTest { - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); @Mock Provider installedPluginResourceProvider; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MeResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MeResourceTest.java index 1c876755a6..433a17b49a 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MeResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MeResourceTest.java @@ -20,7 +20,7 @@ import sonia.scm.group.GroupCollector; import sonia.scm.user.InvalidPasswordException; import sonia.scm.user.User; import sonia.scm.user.UserManager; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import sonia.scm.web.VndMediaType; import javax.servlet.http.HttpServletResponse; @@ -48,7 +48,7 @@ public class MeResourceTest { @Rule public ShiroRule shiro = new ShiroRule(); - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(URI.create("/")); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java index 6806dd248e..41217f9fb0 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java @@ -23,7 +23,7 @@ import sonia.scm.repository.Repository; import sonia.scm.repository.api.ModificationsCommandBuilder; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import sonia.scm.web.VndMediaType; import java.net.URI; @@ -45,7 +45,7 @@ public class ModificationsResourceTest extends RepositoryTestBase { public static final String MODIFICATIONS_PATH = "space/repo/modifications/"; public static final String MODIFICATIONS_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + MODIFICATIONS_PATH; - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); private final URI baseUri = URI.create("/"); private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PendingPluginResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PendingPluginResourceTest.java index be5374472f..17e16729b8 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PendingPluginResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PendingPluginResourceTest.java @@ -20,7 +20,7 @@ import sonia.scm.plugin.InstalledPlugin; import sonia.scm.plugin.InstalledPluginDescriptor; import sonia.scm.plugin.PluginInformation; import sonia.scm.plugin.PluginManager; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.core.Response; @@ -40,7 +40,7 @@ import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class PendingPluginResourceTest { - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); ResourceLinks resourceLinks = ResourceLinksMock.createMock(create("/")); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java index 8ad4522b4d..294f55f5d2 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryPermissionRootResourceTest.java @@ -29,7 +29,7 @@ import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.RepositoryPermission; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import sonia.scm.web.VndMediaType; import javax.ws.rs.HttpMethod; @@ -104,7 +104,7 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase { .content(PERMISSION_TEST_PAYLOAD) .path(PATH_OF_ONE_PERMISSION); - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); @Mock private RepositoryManager repositoryManager; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRoleRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRoleRootResourceTest.java index e458af6a11..f288b12006 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRoleRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRoleRootResourceTest.java @@ -17,7 +17,7 @@ import org.mockito.junit.MockitoJUnitRunner; import sonia.scm.PageResult; import sonia.scm.repository.RepositoryRole; import sonia.scm.repository.RepositoryRoleManager; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import sonia.scm.web.VndMediaType; import javax.servlet.http.HttpServletResponse; @@ -63,7 +63,7 @@ public class RepositoryRoleRootResourceTest { private RepositoryRoleCollectionToDtoMapper collectionToDtoMapper; - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); @Captor private ArgumentCaptor modifyCaptor; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java index 206f7713a3..f4c49be693 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java @@ -22,7 +22,7 @@ import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; import sonia.scm.user.User; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import sonia.scm.web.VndMediaType; import javax.servlet.http.HttpServletResponse; @@ -61,7 +61,7 @@ public class RepositoryRootResourceTest extends RepositoryTestBase { private static final String REALM = "AdminRealm"; - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); @Rule public ShiroRule shiro = new ShiroRule(); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTypeRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTypeRootResourceTest.java index 3dd30e21c0..fcbff438a2 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTypeRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTypeRootResourceTest.java @@ -13,7 +13,7 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.RepositoryType; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import sonia.scm.web.VndMediaType; import java.net.URI; @@ -31,7 +31,7 @@ import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.Silent.class) public class RepositoryTypeRootResourceTest { - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); @Mock private RepositoryManager repositoryManager; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java index 4dd694c092..37c7659b1c 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java @@ -17,7 +17,7 @@ import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.api.BrowseCommandBuilder; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import java.io.IOException; import java.net.URI; @@ -30,7 +30,7 @@ import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.Silent.class) public class SourceRootResourceTest extends RepositoryTestBase { - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); private final URI baseUri = URI.create("/"); private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java index 29616db703..8a61dc8e25 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java @@ -23,7 +23,7 @@ import sonia.scm.repository.Tags; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; import sonia.scm.repository.api.TagsCommandBuilder; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import sonia.scm.web.VndMediaType; import java.net.URI; @@ -42,7 +42,7 @@ public class TagRootResourceTest extends RepositoryTestBase { public static final String TAG_PATH = "space/repo/tags/"; public static final String TAG_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + TAG_PATH; - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); private final URI baseUri = URI.create("/"); private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UIRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UIRootResourceTest.java index da0c862168..23e914da35 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UIRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UIRootResourceTest.java @@ -15,7 +15,7 @@ import sonia.scm.plugin.InstalledPluginDescriptor; import sonia.scm.plugin.PluginInformation; import sonia.scm.plugin.PluginLoader; import sonia.scm.plugin.PluginResources; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import sonia.scm.web.VndMediaType; import javax.servlet.http.HttpServletRequest; @@ -37,7 +37,7 @@ import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.Silent.class) public class UIRootResourceTest { - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); @Mock private PluginLoader pluginLoader; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UserRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UserRootResourceTest.java index 6426007556..d49d1a82b9 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UserRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UserRootResourceTest.java @@ -22,7 +22,7 @@ import sonia.scm.security.PermissionDescriptor; import sonia.scm.user.ChangePasswordNotAllowedException; import sonia.scm.user.User; import sonia.scm.user.UserManager; -import sonia.scm.web.ScmTestDispatcher; +import sonia.scm.web.RestDispatcher; import sonia.scm.web.VndMediaType; import javax.servlet.http.HttpServletResponse; @@ -56,7 +56,7 @@ public class UserRootResourceTest { @Rule public ShiroRule shiro = new ShiroRule(); - private ScmTestDispatcher dispatcher = new ScmTestDispatcher(); + private RestDispatcher dispatcher = new RestDispatcher(); private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(URI.create("/")); From 6e40f7797348958c6dba9f7b28c50e14e84749c8 Mon Sep 17 00:00:00 2001 From: Rene Pfeuffer Date: Fri, 6 Dec 2019 13:33:37 +0100 Subject: [PATCH 11/14] Add exception to default exception mapper set --- scm-test/src/main/java/sonia/scm/web/RestDispatcher.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scm-test/src/main/java/sonia/scm/web/RestDispatcher.java b/scm-test/src/main/java/sonia/scm/web/RestDispatcher.java index bf0a64afc7..29d57f204f 100644 --- a/scm-test/src/main/java/sonia/scm/web/RestDispatcher.java +++ b/scm-test/src/main/java/sonia/scm/web/RestDispatcher.java @@ -13,6 +13,7 @@ import sonia.scm.AlreadyExistsException; import sonia.scm.BadRequestException; import sonia.scm.ConcurrentModificationException; import sonia.scm.NotFoundException; +import sonia.scm.ScmConstraintViolationException; import javax.ws.rs.Produces; import javax.ws.rs.core.Response; @@ -64,6 +65,7 @@ public class RestDispatcher { registerException(UnauthorizedException.class, Status.FORBIDDEN); registerException(AuthorizationException.class, Status.FORBIDDEN); registerException(BadRequestException.class, Status.BAD_REQUEST); + registerException(ScmConstraintViolationException.class, Status.BAD_REQUEST); } private void registerException(Class exceptionClass, Status status) { From fb8d512ec678fd9b93303ba9ca64e8d61d0c561a Mon Sep 17 00:00:00 2001 From: Rene Pfeuffer Date: Fri, 6 Dec 2019 13:45:10 +0100 Subject: [PATCH 12/14] Fix integration tests Without this flag, the server will not be shutdown fast enough between the integration tests of scm-webapp and scm-it. Therefore the new server cannot start correctly whicht results in an error (ShutdownMonitor already started) --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 6a9fa7e044..c759de5733 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -37,7 +37,7 @@ node('docker') { } stage('Integration Test') { - mvn 'verify -Pit -pl :scm-webapp,:scm-it -Dmaven.test.failure.ignore=true' + mvn 'verify -Pit -pl :scm-webapp,:scm-it -Dmaven.test.failure.ignore=true -DClassLoaderLeakPreventor.threadWaitMs=10' } stage('SonarQube') { From 4a782db1fa104212bf50876b8a4cbec755a3190d Mon Sep 17 00:00:00 2001 From: Rene Pfeuffer Date: Fri, 6 Dec 2019 14:44:50 +0100 Subject: [PATCH 13/14] Implement test --- .../AuthorizationExceptionMapperTest.java | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/scm-webapp/src/test/java/sonia/scm/api/rest/AuthorizationExceptionMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/rest/AuthorizationExceptionMapperTest.java index f546a7cf34..cd56d966ef 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/rest/AuthorizationExceptionMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/rest/AuthorizationExceptionMapperTest.java @@ -1,5 +1,49 @@ package sonia.scm.api.rest; +import org.apache.shiro.authz.AuthorizationException; +import org.apache.shiro.subject.Subject; +import org.apache.shiro.subject.support.SubjectThreadState; +import org.apache.shiro.util.ThreadContext; +import org.apache.shiro.util.ThreadState; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + class AuthorizationExceptionMapperTest { -// TODO verify differentiation between normal user and anonymous + + private final Subject subject = mock(Subject.class); + private final ThreadState subjectThreadState = new SubjectThreadState(subject); + + @BeforeEach + public void init() { + subjectThreadState.bind(); + ThreadContext.bind(subject); + } + + @AfterEach + public void unbindSubject() { + ThreadContext.unbindSubject(); + } + + @Test + void shouldMapNormalUserToForbidden() { + when(subject.getPrincipal()).thenReturn("someone"); + + assertThat( + new AuthorizationExceptionMapper().toResponse(new AuthorizationException()).getStatus() + ).isEqualTo(403); + } + + @Test + void shouldMapAnonymousUserToUnauthorized() { + when(subject.getPrincipal()).thenReturn("_anonymous"); + + assertThat( + new AuthorizationExceptionMapper().toResponse(new AuthorizationException()).getStatus() + ).isEqualTo(401); + } } From 126649864469b290136b801c2fc81dfdd35e8cbb Mon Sep 17 00:00:00 2001 From: Rene Pfeuffer Date: Fri, 6 Dec 2019 13:45:47 +0000 Subject: [PATCH 14/14] Close branch bugfix/classloader_leak