/* * See the NOTICE file distributed with this work for additional * information regarding copyright ownership. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.xwiki.test.page; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.StringUtils; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.xwiki.cache.Cache; import org.xwiki.cache.CacheManager; import org.xwiki.cache.config.CacheConfiguration; import org.xwiki.context.Execution; import org.xwiki.context.ExecutionContext; import org.xwiki.context.ExecutionContextManager; import org.xwiki.environment.Environment; import org.xwiki.job.event.status.JobProgressManager; import org.xwiki.management.JMXBeanRegistration; import org.xwiki.model.reference.DocumentReference; import org.xwiki.model.reference.SpaceReference; import org.xwiki.query.Query; import org.xwiki.rendering.internal.transformation.MutableRenderingContext; import org.xwiki.rendering.syntax.Syntax; import org.xwiki.rendering.transformation.RenderingContext; import org.xwiki.resource.internal.entity.EntityResourceActionLister; import org.xwiki.test.annotation.AfterComponent; import org.xwiki.test.annotation.BeforeComponent; import org.xwiki.test.mockito.MockitoComponentManagerRule; import org.xwiki.velocity.VelocityManager; import com.xpn.xwiki.XWiki; import com.xpn.xwiki.XWikiContext; import com.xpn.xwiki.doc.XWikiDocument; import com.xpn.xwiki.internal.cache.rendering.RenderingCache; import com.xpn.xwiki.test.MockitoOldcoreRule; import com.xpn.xwiki.web.XWikiServletRequestStub; import com.xpn.xwiki.web.XWikiServletResponseStub; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; /** * Tests that wishes to unit test wiki page should extend this class and call {@link #renderPage(DocumentReference)} * to load and render a page located in the classpath. * * @version $Id: d200e0ce772a58b28b00bbaa4ee3e34418d047ea $ * @since 7.3M1 */ @PageComponentList public class PageTest { /** * Page tests use the Oldcore rule to configure some base mocks (such as XWiki). */ @Rule public MockitoOldcoreRule oldcore = new MockitoOldcoreRule(); /** * The stubbed request used to simulate a real Servlet Request. */ protected XWikiServletRequestStub request; /** * The stubbed response used to simulate a real Servlet Response. */ protected XWikiServletResponseStub response; /** * The mocked XWiki instance, provided for ease of use (can also be retrieved through {@link #oldcore}). */ protected XWiki xwiki; /** * The configured XWiki Context, provided for ease of use (can also be retrieved through {@link #oldcore}). */ protected XWikiContext context; /** * The Component Manager to use for getting Component instances or registering Mock Components in the test, * provided for ease of use (can also be retrieved through {@link #oldcore}). */ protected MockitoComponentManagerRule mocker = oldcore.getMocker(); /** * Set up components before Components declared in {@link org.xwiki.test.annotation.ComponentList} are handled. * * @throws Exception in case of errors */ @BeforeComponent public void setUpComponentsForPageTest() throws Exception { mocker.registerMockComponent(JMXBeanRegistration.class); mocker.registerMockComponent(Environment.class); mocker.registerMockComponent(JobProgressManager.class); mocker.registerMockComponent(RenderingCache.class); mocker.registerMockComponent(EntityResourceActionLister.class); CacheManager cacheManager = mocker.registerMockComponent(CacheManager.class); when(cacheManager.createNewCache(any(CacheConfiguration.class))).thenReturn(mock(Cache.class)); } /** * Set up of Components after the Components declared in {@link org.xwiki.test.annotation.ComponentList} have been * handled but before {@link MockitoOldcoreRule#before(Class)} has been called (i.e. before it has created Mocks * and configured Components). * * @throws Exception in case of errors */ @AfterComponent public void configureComponentsBeforeOldcoreRuleForPageTest() throws Exception { // Configure the Execution Context ExecutionContext ec = new ExecutionContext(); mocker.<Execution>getInstance(Execution.class).setContext(ec); } /** * @param documentReference the reference of the Document to load from the ClassLoader * @return the loaded document * @throws Exception in case of errors */ protected XWikiDocument loadPage(DocumentReference documentReference) throws Exception { List<String> path = new ArrayList<>(); for (SpaceReference spaceReference : documentReference.getSpaceReferences()) { path.add(spaceReference.getName()); } path.add(documentReference.getName() + ".xml"); XWikiDocument document = new XWikiDocument(documentReference); document.fromXML(getClass().getClassLoader().getResourceAsStream(StringUtils.join(path, '/'))); this.xwiki.saveDocument(document, "registering document", true, this.context); return document; } /** * @param reference the reference of the Document to load and render (and thus load from the Classloader) * @return the result of rendering the Document corresponding to the passed reference * @throws Exception in case of errors */ protected String renderPage(DocumentReference reference) throws Exception { XWikiDocument doc = loadPage(reference); // Set up the current doc in the context so that $doc is bound in scripts context.setDoc(doc); return doc.getRenderedContent(this.context); } /** * Sets the Syntax with which the Document to test will be rendered into. If not called, the Document will be * rendered as XHTML. * * @param syntax the Syntax to render the Document into * @throws Exception in case of errors */ protected void setOutputSyntax(Syntax syntax) throws Exception { MutableRenderingContext renderingContext = mocker.getInstance(RenderingContext.class); renderingContext.push(renderingContext.getTransformation(), renderingContext.getXDOM(), renderingContext.getDefaultSyntax(), "test", renderingContext.isRestricted(), syntax); } /** * Configures the various Components and their mocks with default values for page tests. * * @throws Exception in case of errors */ @Before public void setUpForPageTest() throws Exception { // Configure mocks from OldcoreRule context = oldcore.getXWikiContext(); xwiki = oldcore.getSpyXWiki(); // We need this one because some component in its init creates a query... when(oldcore.getQueryManager().createQuery(any(String.class), any(String.class))).thenReturn(mock(Query.class)); // Set up a fake Request // Configure request so that $!request.outputSyntax" == 'plain // Need to be executed before ecm.initialize() so that XWikiScriptContextInitializer will initialize the // script context properly request = new XWikiServletRequestStub(); request.setScheme("http"); context.setRequest(request); response = new XWikiServletResponseStub(); context.setResponse(response); ExecutionContextManager ecm = mocker.getInstance(ExecutionContextManager.class); ecm.initialize(oldcore.getExecutionContext()); // Let the user have view access to all pages when(oldcore.getMockRightService().hasAccessLevel(eq("view"), eq("XWiki.XWikiGuest"), any(), eq(context))).thenReturn(true); // Set up URL Factory URLFactorySetup.setUp(xwiki, context); // Set up Localization LocalizationSetup.setUp(mocker); // Set up Skin Extensions SkinExtensionSetup.setUp(xwiki, context); } /** * Clean up after the test. * * @throws Exception in case of errors */ @After public void tearDown() throws Exception { MutableRenderingContext renderingContext = mocker.getInstance(RenderingContext.class); renderingContext.pop(); } /** * Adds a tool to the Velocity context. * * @param name the name of the tool * @param tool the tool to register; can be a mock * @throws Exception in case of errors * @since 7.4M1 */ protected void registerVelocityTool(String name, Object tool) throws Exception { VelocityManager velocityManager = this.oldcore.getMocker().getInstance(VelocityManager.class); velocityManager.getVelocityContext().put(name, tool); } }