/* * 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.flamingo.test.ui; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.Charset; import java.util.Arrays; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.junit.Rule; import org.junit.Test; import org.xwiki.model.reference.EntityReference; import org.xwiki.test.ui.AbstractTest; import org.xwiki.test.ui.SuperAdminAuthenticationRule; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; /** * Verify that the HTML export features works fine. * * @version $Id: 84a3ebbeb8d5a051cc84b0af4ca7d48fb0a6b6f0 $ */ public class HTMLExportTest extends AbstractTest { @Rule public SuperAdminAuthenticationRule adminAuthenticationRule = new SuperAdminAuthenticationRule(getUtil()); private interface PageValidator { void validate(ZipInputStream zis, ZipEntry entry) throws Exception; void assertResult(); } private class TopPageValidator implements PageValidator { private boolean result; @Override public void validate(ZipInputStream zis, ZipEntry entry) throws Exception { if (entry.getName().equals("pages/xwiki/TopPage/WebHome.html")) { String content = IOUtils.toString(zis, Charset.defaultCharset()); // Verify that the content was rendered properly assertTrue("Title should have contained 'Top content'", content.contains("Top content")); assertTrue("Content should have contained 'Top title: Creator'", content.contains("Top title: Creator")); this.result = true; } } @Override public void assertResult() { assertTrue("Failed to find the pages/xwiki/TopPage/WebHome.html entry", this.result); } } private class NestedPageValidator implements PageValidator { private boolean result; @Override public void validate(ZipInputStream zis, ZipEntry entry) throws Exception { if (entry.getName().equals("pages/xwiki/TopPage/NestedPage/WebHome.html")) { String content = IOUtils.toString(zis, Charset.defaultCharset()); // Verify that the link to a locally exported page is correct assertTrue("Content should have contained a local link to the Top page", content.contains("<a href=\"../../../../pages/xwiki/TopPage/WebHome.html\">top</a>")); this.result = true; } } @Override public void assertResult() { assertTrue("Failed to find the pages/xwiki/TopPage/NestedPage/WebHome.html entry", this.result); } } @Test public void exportHTML() throws Exception { // Step 1: Create 2 pages that we'll then export EntityReference topReference = getUtil().resolveDocumentReference("TopPage.WebHome"); getUtil().deletePage(topReference); EntityReference nestedReference = getUtil().resolveDocumentReference("TopPage.NestedPage.WebHome"); getUtil().deletePage(nestedReference); // Note: Verify that Velocity is correctly evaluated getUtil().createPage(topReference, "Top content", "Top title: $services.localization.render('creator')"); // Note: we define a link to the top page to verify that the export will resolve the links locally when the // page linked is part of the export. getUtil().createPage(nestedReference, "[[top>>TopPage.WebHome]]", "Nested Page"); // Step 2: Call the export URL to get the ZIP and to assert its content, when no "pages" query string param is // used (only the TopPage will be exported) assertHTMLExportURL("http://localhost:8080/xwiki/bin/export/TopPage/WebHome?format=html", Arrays.asList(new TopPageValidator())); // Step 3: Call the export URL to get the ZIP and to assert its content, when a "pages" query string param is // used with some regex assertHTMLExportURL("http://localhost:8080/xwiki/bin/export/UnexistingSpace/UnexistingPage?format=html" + "&pages=TopPage.%25", Arrays.asList(new TopPageValidator(), new NestedPageValidator())); } private void assertHTMLExportURL(String htmlExportURL, List<PageValidator> validators) throws Exception { URL url = new URL(htmlExportURL); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); InputStream is = connection.getInputStream(); ZipInputStream zis = new ZipInputStream(is); boolean foundResourcesDirectory = false; boolean foundSkinsDirectory = false; boolean foundSkinCSS = false; boolean foundWebjars = false; // We must read the full stream as otherwise if we close it before we've fully read it // then the server side will get a broken pipe since it's still trying to send data on it. for (ZipEntry entry; (entry = zis.getNextEntry()) != null; zis.closeEntry()) { for (PageValidator validator : validators) { validator.validate(zis, entry); } if (entry.getName().endsWith(".vm")) { fail("There shouldn't be any *.vm files in the generated zip!"); } else if (entry.getName().endsWith(".less")) { fail("There shouldn't be any *.less files in the generated zip!"); } else if (entry.getName().equals("xwiki.properties")) { fail("There shouldn't be any xwiki.properties file in the generated zip!"); } else if (entry.getName().startsWith("resources/")) { foundResourcesDirectory = true; IOUtils.readLines(zis, Charset.defaultCharset()); } else if (entry.getName().startsWith("skins/")) { foundSkinsDirectory = true; // Verify that the skin is correctly going to be applied by verifying the flamingo/style.css file is // found and is correctly referenced. This fixes https://jira.xwiki.org/browse/XWIKI-9145 if (entry.getName().equals("skins/flamingo/style.css")) { assertSkinIsActive(IOUtils.readLines(zis, Charset.defaultCharset())); foundSkinCSS = true; } else { IOUtils.readLines(zis, Charset.defaultCharset()); } } else if (entry.getName().startsWith("webjars")) { // We verify here that webjars URLs have been properly exported foundWebjars = true; IOUtils.readLines(zis, Charset.defaultCharset()); } else { IOUtils.readLines(zis, Charset.defaultCharset()); } } for (PageValidator validator : validators) { validator.assertResult(); } assertTrue("Failed to find the resources/ directory entry", foundResourcesDirectory); assertTrue("Failed to find the skins/ directory entry", foundSkinsDirectory); assertTrue("Failed to find the link to colibri.css in style.css", foundSkinCSS); assertTrue("Failed to find webjar resources in the HTML export", foundWebjars); zis.close(); } private void assertSkinIsActive(List<String> content) throws Exception { assertTrue("style.css is not the one output by the flamingo skin", StringUtils.join(content.toArray()) .contains("skin-flamingo")); } }