diff --git a/pom.xml b/pom.xml index e9eae49..6fe2084 100644 --- a/pom.xml +++ b/pom.xml @@ -81,6 +81,11 @@ junit-jupiter ${junit.version} + + org.mockito + mockito-core + ${mockito.version} + @@ -114,6 +119,11 @@ org.junit.jupiter junit-jupiter + + org.mockito + mockito-core + ${mockito.version} + info.magnolia magnolia-core diff --git a/src/main/java/com/merkle/oss/magnolia/testing/MagnoliaIntegrationBeforeAllTestExtension.java b/src/main/java/com/merkle/oss/magnolia/testing/MagnoliaIntegrationBeforeAllTestExtension.java index 24ae4fb..9929225 100644 --- a/src/main/java/com/merkle/oss/magnolia/testing/MagnoliaIntegrationBeforeAllTestExtension.java +++ b/src/main/java/com/merkle/oss/magnolia/testing/MagnoliaIntegrationBeforeAllTestExtension.java @@ -13,7 +13,7 @@ public class MagnoliaIntegrationBeforeAllTestExtension implements BeforeAllCallb @Override public void beforeAll(final ExtensionContext context) throws Exception { magnoliaIntegrationTestInitializer.init(context); - magnoliaIntegrationTestInitializer.start(); + magnoliaIntegrationTestInitializer.start(true); new RepositoryUtil().load(context); } diff --git a/src/main/java/com/merkle/oss/magnolia/testing/MagnoliaIntegrationTestExtension.java b/src/main/java/com/merkle/oss/magnolia/testing/MagnoliaIntegrationTestExtension.java index bce933a..be5412c 100644 --- a/src/main/java/com/merkle/oss/magnolia/testing/MagnoliaIntegrationTestExtension.java +++ b/src/main/java/com/merkle/oss/magnolia/testing/MagnoliaIntegrationTestExtension.java @@ -13,7 +13,7 @@ public class MagnoliaIntegrationTestExtension implements BeforeEachCallback, Aft @Override public void beforeEach(final ExtensionContext context) throws Exception { magnoliaIntegrationTestInitializer.init(context); - magnoliaIntegrationTestInitializer.start(); + magnoliaIntegrationTestInitializer.start(true); new RepositoryUtil().load(context); } diff --git a/src/main/java/com/merkle/oss/magnolia/testing/configuration/MagnoliaIntegrationTestInitializer.java b/src/main/java/com/merkle/oss/magnolia/testing/configuration/MagnoliaIntegrationTestInitializer.java index d4f91b6..b8185a6 100644 --- a/src/main/java/com/merkle/oss/magnolia/testing/configuration/MagnoliaIntegrationTestInitializer.java +++ b/src/main/java/com/merkle/oss/magnolia/testing/configuration/MagnoliaIntegrationTestInitializer.java @@ -1,12 +1,10 @@ package com.merkle.oss.magnolia.testing.configuration; -import info.magnolia.cms.security.SecuritySupport; -import info.magnolia.cms.security.User; +import info.magnolia.cms.filters.MgnlMainFilter; +import info.magnolia.cms.util.CustomFilterConfig; import info.magnolia.context.AbstractSystemContext; -import info.magnolia.context.DefaultRepositoryStrategy; import info.magnolia.context.MgnlContext; import info.magnolia.context.SystemContext; -import info.magnolia.context.WebContext; import info.magnolia.init.MagnoliaConfigurationProperties; import info.magnolia.init.MagnoliaServletContextListener; import info.magnolia.license.LicenseManager; @@ -21,7 +19,6 @@ import info.magnolia.objectfactory.guice.GuiceComponentProviderBuilder; import info.magnolia.repository.RepositoryManager; import info.magnolia.test.TestMagnoliaConfigurationProperties; -import info.magnolia.test.mock.MockWebContext; import java.io.IOException; import java.nio.file.Files; @@ -29,11 +26,11 @@ import java.util.Arrays; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.servlet.ServletContext; +import javax.servlet.ServletException; import org.apache.commons.lang3.time.StopWatch; import org.junit.jupiter.api.extension.ExtensionContext; @@ -43,7 +40,8 @@ import com.machinezoo.noexception.Exceptions; import com.merkle.oss.magnolia.testing.module.LicenseManagerProvider; import com.merkle.oss.magnolia.testing.properties.IntegrationTestMagnoliaConfigurationProperties; -import com.merkle.oss.magnolia.testing.servlet.MockServletContext; +import com.merkle.oss.magnolia.testing.servlet.MockFilterChain; +import com.merkle.oss.magnolia.testing.servlet.ServletContextProvider; public class MagnoliaIntegrationTestInitializer { @@ -70,24 +68,34 @@ public void init(final ExtensionContext extensionContext) throws Exception { throw new RuntimeException("Failed to init: " + e.getErrorMessages(), e); } watch.stop(); - System.out.println("Initialization took "+watch.getDuration().toMillis()+"ms"); + System.out.println("Initialization took " + watch.getDuration().toMillis() + "ms"); } public void destroy() { - ((AbstractSystemContext)Components.getComponent(SystemContext.class)).getRepositoryStrategy().release(); + ((AbstractSystemContext) Components.getComponent(SystemContext.class)).getRepositoryStrategy().release(); MgnlContext.setInstance(null); } - public void start() throws ModuleManagementException { + public void start(final boolean executeFilterChain) throws ModuleManagementException, ServletException, IOException { final StopWatch watch = new StopWatch(); watch.start(); + System.setProperty("productionMode", "true"); //com.vaadin.server.Constants.SERVLET_PARAMETER_PRODUCTION_MODE final ModuleManager moduleManager = Components.getComponent(ModuleManager.class); moduleManager.checkForInstallOrUpdates(); moduleManager.performInstallOrUpdate(); moduleManager.startModules(); - MgnlContext.setInstance(getUserContext()); + if(executeFilterChain) { + executeFilterChain(); + } watch.stop(); - System.out.println("Start took "+watch.getDuration().toMillis()+"ms"); + System.out.println("Start took " + watch.getDuration().toMillis() + "ms"); + } + + private void executeFilterChain() throws ServletException, IOException { + final ServletContextProvider servletContextProvider = Components.getComponent(ServletContextProvider.class); + final MgnlMainFilter mainFilter = new MgnlMainFilter(); + mainFilter.init(new CustomFilterConfig("magnoliaFilterChain", Components.getComponent(ServletContext.class))); + mainFilter.doFilter(servletContextProvider.getRequest(), servletContextProvider.getResponse(), new MockFilterChain()); } public void stop() { @@ -95,19 +103,10 @@ public void stop() { watch.start(); final ModuleManager moduleManager = Components.getComponent(ModuleManager.class); moduleManager.stopModules(); - ((AbstractSystemContext)Components.getComponent(SystemContext.class)).getRepositoryStrategy().release(); + ((AbstractSystemContext) Components.getComponent(SystemContext.class)).getRepositoryStrategy().release(); MgnlContext.setInstance(null); watch.stop(); - System.out.println("Stop took "+watch.getDuration().toMillis()+"ms"); - } - - private WebContext getUserContext() { - final RepositoryManager repositoryManager = Components.getComponent(RepositoryManager.class); - final MockWebContext webContext = new MockWebContext(); - final User user = Components.getComponent(SecuritySupport.class).getUserManager().getUser("superuser"); - webContext.setUser(user); - webContext.setRepositoryStrategy(new DefaultRepositoryStrategy(repositoryManager, webContext)); - return webContext; + System.out.println("Stop took " + watch.getDuration().toMillis() + "ms"); } private GuiceComponentProvider getPlatformComponentProvider(final Path appRootDir, final ExtensionContext extensionContext) throws IOException { @@ -116,7 +115,8 @@ private GuiceComponentProvider getPlatformComponentProvider(final Path appRootDi MagnoliaServletContextListener.DEFAULT_PLATFORM_COMPONENTS_CONFIG_LOCATION, "/configuration/platform-components.xml" ), "platform"); - config.registerInstance(ServletContext.class, new MockServletContext()); + + config.registerProvider(ServletContext.class, ServletContextProvider.class); applyAnnotationComponents(extensionContext, TestConfiguration.Component.Provider.PLATFORM, config); config.registerInstance(MagnoliaConfigurationProperties.class, properties); config.registerInstance(ExtensionContext.class, extensionContext); diff --git a/src/main/java/com/merkle/oss/magnolia/testing/configuration/TestModuleVersionHandler.java b/src/main/java/com/merkle/oss/magnolia/testing/configuration/TestModuleVersionHandler.java index e28b0a7..606eeea 100644 --- a/src/main/java/com/merkle/oss/magnolia/testing/configuration/TestModuleVersionHandler.java +++ b/src/main/java/com/merkle/oss/magnolia/testing/configuration/TestModuleVersionHandler.java @@ -6,11 +6,19 @@ import java.util.List; +import com.merkle.oss.magnolia.testing.servlet.DeleteFilterTask; +import com.merkle.oss.magnolia.testing.servlet.TestContextFilter; +import com.merkle.oss.magnolia.testing.servlet.TestLoginFilter; + public class TestModuleVersionHandler extends DefaultModuleVersionHandler { @Override protected final List getExtraInstallTasks(final InstallContext installContext) { return List.of( + new TestContextFilter.InstallTask(), + new TestLoginFilter.InstallTask(), + new DeleteFilterTask("logout"), + new DeleteFilterTask("securityCallback") ); } } diff --git a/src/main/java/com/merkle/oss/magnolia/testing/servlet/DeleteFilterTask.java b/src/main/java/com/merkle/oss/magnolia/testing/servlet/DeleteFilterTask.java new file mode 100644 index 0000000..b9f1d7f --- /dev/null +++ b/src/main/java/com/merkle/oss/magnolia/testing/servlet/DeleteFilterTask.java @@ -0,0 +1,23 @@ +package com.merkle.oss.magnolia.testing.servlet; + +import info.magnolia.module.InstallContext; +import info.magnolia.module.delta.AbstractRepositoryTask; +import info.magnolia.repository.RepositoryConstants; + +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +public class DeleteFilterTask extends AbstractRepositoryTask { + private final String name; + + public DeleteFilterTask(final String name) { + super("Delete" + name + "Filter", "Deletes " + name + " filter"); + this.name = name; + } + + @Override + protected void doExecute(final InstallContext installContext) throws RepositoryException { + final Session session = installContext.getJCRSession(RepositoryConstants.CONFIG); + session.removeItem("/server/filters/"+name); + } +} diff --git a/src/main/java/com/merkle/oss/magnolia/testing/servlet/MockFilterChain.java b/src/main/java/com/merkle/oss/magnolia/testing/servlet/MockFilterChain.java new file mode 100644 index 0000000..3298d39 --- /dev/null +++ b/src/main/java/com/merkle/oss/magnolia/testing/servlet/MockFilterChain.java @@ -0,0 +1,10 @@ +package com.merkle.oss.magnolia.testing.servlet; + +import javax.servlet.FilterChain; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +public class MockFilterChain implements FilterChain { + @Override + public void doFilter(final ServletRequest request, final ServletResponse response) {} +} diff --git a/src/main/java/com/merkle/oss/magnolia/testing/servlet/MockServletContext.java b/src/main/java/com/merkle/oss/magnolia/testing/servlet/MockServletContext.java deleted file mode 100644 index 417afe0..0000000 --- a/src/main/java/com/merkle/oss/magnolia/testing/servlet/MockServletContext.java +++ /dev/null @@ -1,317 +0,0 @@ -package com.merkle.oss.magnolia.testing.servlet; - -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Enumeration; -import java.util.EventListener; -import java.util.Map; -import java.util.Set; - -import javax.servlet.Filter; -import javax.servlet.FilterRegistration; -import javax.servlet.RequestDispatcher; -import javax.servlet.Servlet; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRegistration; -import javax.servlet.SessionCookieConfig; -import javax.servlet.SessionTrackingMode; -import javax.servlet.descriptor.JspConfigDescriptor; - -public class MockServletContext implements ServletContext { - @Override - public String getContextPath() { - return ""; - } - - @Override - public ServletContext getContext(String uripath) { - return null; - } - - @Override - public int getMajorVersion() { - return 0; - } - - @Override - public int getMinorVersion() { - return 0; - } - - @Override - public int getEffectiveMajorVersion() { - return 0; - } - - @Override - public int getEffectiveMinorVersion() { - return 0; - } - - @Override - public String getMimeType(String file) { - return ""; - } - - @Override - public Set getResourcePaths(String path) { - return Set.of(); - } - - @Override - public URL getResource(String path) throws MalformedURLException { - return null; - } - - @Override - public InputStream getResourceAsStream(String path) { - return null; - } - - @Override - public RequestDispatcher getRequestDispatcher(String path) { - return null; - } - - @Override - public RequestDispatcher getNamedDispatcher(String name) { - return null; - } - - @Override - public Servlet getServlet(String name) throws ServletException { - return null; - } - - @Override - public Enumeration getServlets() { - return null; - } - - @Override - public Enumeration getServletNames() { - return null; - } - - @Override - public void log(String msg) { - - } - - @Override - public void log(Exception exception, String msg) { - - } - - @Override - public void log(String message, Throwable throwable) { - - } - - @Override - public String getRealPath(String path) { - return ""; - } - - @Override - public String getServerInfo() { - return ""; - } - - @Override - public String getInitParameter(String name) { - return ""; - } - - @Override - public Enumeration getInitParameterNames() { - return null; - } - - @Override - public boolean setInitParameter(String name, String value) { - return false; - } - - @Override - public Object getAttribute(String name) { - return null; - } - - @Override - public Enumeration getAttributeNames() { - return null; - } - - @Override - public void setAttribute(String name, Object object) { - - } - - @Override - public void removeAttribute(String name) { - - } - - @Override - public String getServletContextName() { - return ""; - } - - @Override - public ServletRegistration.Dynamic addServlet(String servletName, String className) { - return null; - } - - @Override - public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) { - return null; - } - - @Override - public ServletRegistration.Dynamic addServlet(String servletName, Class servletClass) { - return null; - } - - @Override - public ServletRegistration.Dynamic addJspFile(String servletName, String jspFile) { - return null; - } - - @Override - public T createServlet(Class clazz) throws ServletException { - return null; - } - - @Override - public ServletRegistration getServletRegistration(String servletName) { - return null; - } - - @Override - public Map getServletRegistrations() { - return Map.of(); - } - - @Override - public FilterRegistration.Dynamic addFilter(String filterName, String className) { - return null; - } - - @Override - public FilterRegistration.Dynamic addFilter(String filterName, Filter filter) { - return null; - } - - @Override - public FilterRegistration.Dynamic addFilter(String filterName, Class filterClass) { - return null; - } - - @Override - public T createFilter(Class clazz) throws ServletException { - return null; - } - - @Override - public FilterRegistration getFilterRegistration(String filterName) { - return null; - } - - @Override - public Map getFilterRegistrations() { - return Map.of(); - } - - @Override - public SessionCookieConfig getSessionCookieConfig() { - return null; - } - - @Override - public void setSessionTrackingModes(Set sessionTrackingModes) { - - } - - @Override - public Set getDefaultSessionTrackingModes() { - return Set.of(); - } - - @Override - public Set getEffectiveSessionTrackingModes() { - return Set.of(); - } - - @Override - public void addListener(String className) { - - } - - @Override - public void addListener(T t) { - - } - - @Override - public void addListener(Class listenerClass) { - - } - - @Override - public T createListener(Class clazz) throws ServletException { - return null; - } - - @Override - public JspConfigDescriptor getJspConfigDescriptor() { - return null; - } - - @Override - public ClassLoader getClassLoader() { - return null; - } - - @Override - public void declareRoles(String... roleNames) { - - } - - @Override - public String getVirtualServerName() { - return ""; - } - - @Override - public int getSessionTimeout() { - return 0; - } - - @Override - public void setSessionTimeout(int sessionTimeout) { - - } - - @Override - public String getRequestCharacterEncoding() { - return ""; - } - - @Override - public void setRequestCharacterEncoding(String encoding) { - - } - - @Override - public String getResponseCharacterEncoding() { - return ""; - } - - @Override - public void setResponseCharacterEncoding(String encoding) { - - } -} diff --git a/src/main/java/com/merkle/oss/magnolia/testing/servlet/ServletContextProvider.java b/src/main/java/com/merkle/oss/magnolia/testing/servlet/ServletContextProvider.java new file mode 100644 index 0000000..cda180f --- /dev/null +++ b/src/main/java/com/merkle/oss/magnolia/testing/servlet/ServletContextProvider.java @@ -0,0 +1,53 @@ +package com.merkle.oss.magnolia.testing.servlet; + +import java.util.Base64; +import java.util.Collections; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.mockito.Mockito; + +import com.google.inject.Provider; + +public interface ServletContextProvider extends Provider { + ServletContext get(); + HttpServletRequest getRequest(); + HttpServletResponse getResponse(); + + class DefaultServletContextProvider implements ServletContextProvider { + @Override + public ServletContext get() { + final ServletContext mock = Mockito.mock(ServletContext.class); + Mockito.doReturn("/").when(mock).getContextPath(); + Mockito.doReturn("").when(mock).getRealPath(Mockito.anyString()); + Mockito.doReturn(Collections.enumeration(Collections.emptySet())).when(mock).getInitParameterNames(); + Mockito.doReturn(Collections.enumeration(Collections.emptySet())).when(mock).getAttributeNames(); + return mock; + } + + @Override + public HttpServletRequest getRequest() { + final HttpServletRequest mock = Mockito.mock(HttpServletRequest.class); + Mockito.doReturn("/mock-uri").when(mock).getRequestURI(); + Mockito.doReturn("/mock-uri").when(mock).getServletPath(); + Mockito.doReturn("/").when(mock).getContextPath(); + Mockito.doReturn(new StringBuffer("https://mock-domain.com/mock-uri")).when(mock).getRequestURL(); + Mockito.doReturn("GET").when(mock).getMethod(); + Mockito.doReturn("Basic " + Base64.getEncoder().encodeToString("superuser:superuser".getBytes())).when(mock).getHeader("Authorization"); + Mockito.doReturn(Collections.enumeration(Collections.emptySet())).when(mock).getHeaders(Mockito.anyString()); + final HttpSession session = Mockito.mock(HttpSession.class); + Mockito.doReturn(session).when(mock).getSession(Mockito.anyBoolean()); + Mockito.doReturn(session).when(mock).getSession(); + return mock; + } + + @Override + public HttpServletResponse getResponse() { + final HttpServletResponse mock = Mockito.mock(HttpServletResponse.class); + return mock; + } + } +} diff --git a/src/main/java/com/merkle/oss/magnolia/testing/servlet/TestContextFilter.java b/src/main/java/com/merkle/oss/magnolia/testing/servlet/TestContextFilter.java new file mode 100644 index 0000000..2410a7d --- /dev/null +++ b/src/main/java/com/merkle/oss/magnolia/testing/servlet/TestContextFilter.java @@ -0,0 +1,66 @@ +package com.merkle.oss.magnolia.testing.servlet; + +import info.magnolia.cms.filters.ContextFilter; +import info.magnolia.context.MgnlContext; +import info.magnolia.context.WebContext; +import info.magnolia.context.WebContextFactory; +import info.magnolia.module.InstallContext; +import info.magnolia.module.delta.AbstractRepositoryTask; +import info.magnolia.module.delta.TaskExecutionException; +import info.magnolia.repository.RepositoryConstants; + +import java.io.IOException; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.google.inject.Inject; + +public class TestContextFilter extends ContextFilter { + private final WebContextFactory webContextFactory; + private ServletContext servletContext; + + @Inject + public TestContextFilter(final WebContextFactory webContextFactory) { + super(webContextFactory); + this.webContextFactory = webContextFactory; + } + + @Override + public void init(final FilterConfig filterConfig) { + this.servletContext = filterConfig.getServletContext(); + } + + @Override + public void doFilter(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain) throws IOException, ServletException { + // This filter can be invoked multiple times. The first time it's called it initializes the MgnlContext. On + // subsequent invocations it only pushes the request and response objects on the stack in WebContext. The + // multiple invocations result from either dispatching a forward, an include or an error request, and also + // when the filter chain is reset (which happens when logging out). + if (!MgnlContext.hasInstance() || MgnlContext.isSystemInstance()) { + final WebContext webContext = webContextFactory.createWebContext(request, response, servletContext); + MgnlContext.setInstance(webContext); + webContext.push(request, response); + } + chain.doFilter(request, response); + } + + public static class InstallTask extends AbstractRepositoryTask { + public InstallTask() { + super("InstallTestContextFilters", "Installs test context filter"); + } + @Override + protected void doExecute(final InstallContext installContext) throws RepositoryException { + final Session session = installContext.getJCRSession(RepositoryConstants.CONFIG); + final Node filter = session.getNode("/server/filters/context"); + filter.setProperty("class", TestContextFilter.class.getName()); + } + } +} diff --git a/src/main/java/com/merkle/oss/magnolia/testing/servlet/TestLoginFilter.java b/src/main/java/com/merkle/oss/magnolia/testing/servlet/TestLoginFilter.java new file mode 100644 index 0000000..f3949f8 --- /dev/null +++ b/src/main/java/com/merkle/oss/magnolia/testing/servlet/TestLoginFilter.java @@ -0,0 +1,40 @@ +package com.merkle.oss.magnolia.testing.servlet; + +import info.magnolia.cms.security.auth.login.BasicLogin; +import info.magnolia.cms.security.auth.login.LoginFilter; +import info.magnolia.cms.security.auth.login.LoginHandler; +import info.magnolia.module.InstallContext; +import info.magnolia.module.delta.AbstractRepositoryTask; +import info.magnolia.repository.RepositoryConstants; + +import java.util.Collection; +import java.util.Set; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import com.google.inject.Inject; + +public class TestLoginFilter extends LoginFilter { + + @Inject + public TestLoginFilter() {} + + @Override + public Collection getLoginHandlers() { + return Set.of(new BasicLogin()); + } + + public static class InstallTask extends AbstractRepositoryTask { + public InstallTask() { + super("InstallTestLoginFilter", "Installs test login filter"); + } + @Override + protected void doExecute(final InstallContext installContext) throws RepositoryException { + final Session session = installContext.getJCRSession(RepositoryConstants.CONFIG); + final Node filter = session.getNode("/server/filters/login"); + filter.setProperty("class", TestLoginFilter.class.getName()); + } + } +} diff --git a/src/main/resources/configuration/platform-components.xml b/src/main/resources/configuration/platform-components.xml index 9ccf545..810b43c 100644 --- a/src/main/resources/configuration/platform-components.xml +++ b/src/main/resources/configuration/platform-components.xml @@ -11,6 +11,10 @@ com.merkle.oss.magnolia.testing.module.TestModuleManager singleton + + com.merkle.oss.magnolia.testing.servlet.ServletContextProvider + com.merkle.oss.magnolia.testing.servlet.ServletContextProvider$DefaultServletContextProvider + info.magnolia.setup.CoreModuleVersionHandler com.merkle.oss.magnolia.testing.module.TestCoreModuleVersionHandler