package org.exist.xupdate; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.exist.TestUtils; import org.exist.security.Account; import org.exist.security.Permission; import org.exist.xmldb.DatabaseInstanceManager; import org.exist.xmldb.UserManagementService; import org.exist.xmldb.XmldbURI; import org.junit.After; import org.junit.Assume; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; import static java.nio.charset.StandardCharsets.UTF_8; import static org.hamcrest.Matchers.*; import org.junit.runners.Parameterized.Parameters; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.traversal.DocumentTraversal; import org.w3c.dom.traversal.NodeFilter; import org.w3c.dom.traversal.NodeIterator; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xmldb.api.DatabaseManager; import org.xmldb.api.base.Collection; import org.xmldb.api.base.Database; import org.xmldb.api.base.Resource; import org.xmldb.api.base.XMLDBException; import org.xmldb.api.modules.CollectionManagementService; import org.xmldb.api.modules.XMLResource; import org.xmldb.api.modules.XUpdateQueryService; /** * @author berlinge-to */ @RunWith(Parameterized.class) public class XUpdateTest { //TODO should not execute as 'admin' user //also additional tests needed to verify update permissions @Parameters(name = "{0}") public static java.util.Collection<Object[]> data() { return Arrays.asList(new Object[][] { {"append", "address.xml"}, {"insertafter", "address.xml"}, {"insertbefore", "address.xml"}, {"remove", "address.xml"}, {"update", "address.xml"}, {"append_attribute", "address.xml"}, {"append_child", "address.xml"}, {"append_child", "address.xml"}, {"insertafter_big", "address_big.xml"}, {"conditional", "address.xml"}, {"variables", "address.xml"}, {"replace", "address.xml"}, {"whitespace", "address.xml"}, {"namespaces", "namespaces.xml"}, /* TODO Added by Geoff Shuetrim (geoff@galexy.net) on 15 July 2006 to highlight that root element renaming does not currently succeed, resulting instead in a null pointer exception because the renaming relies upon obtaining the parent element of the element being renamed and this is null for the root element. */ {"rename_root_element", "address.xml"}, /* TODO Added by Geoff Shuetrim (geoff@galexy.net) on 15 July 2006 to highlight that renaming of an element fails when the renaming also involves a change of namespace */ {"rename_including_namespace", "namespaces.xml"} }); } @Parameter public String testName; @Parameter(value = 1) public String sourceFile; private final static String URI = XmldbURI.LOCAL_DB; private final static String DRIVER = "org.exist.xmldb.DatabaseImpl"; private final static String XUPDATE_COLLECTION = "xupdate_tests"; static Path existDir; static { String existHome = System.getProperty("exist.home"); existDir = existHome == null ? Paths.get(".") : Paths.get(existHome); existDir = existDir.normalize(); } private final static Path MODIFICATION_DIR = existDir.resolve("test/src/org/exist/xupdate/modifications").toAbsolutePath(); private final static Path RESULT_DIR = existDir.resolve("test/src/org/exist/xupdate/results").toAbsolutePath(); private final static Path SOURCE_DIR = existDir.resolve("test/src/org/exist/xupdate/input").toAbsolutePath(); private final static String XUPDATE_FILE = "xu.xml"; // xlm document name in eXist private Collection col = null; @Test public void xupdate() throws Exception { //skip tests from Geoff Shuetrim (see above!) Assume.assumeThat(testName, not(anyOf(equalTo("rename_root_element"), equalTo("rename_including_namespace")))); addDocument(sourceFile); //update input xml file Document xupdateResult = updateDocument(MODIFICATION_DIR.resolve(testName + ".xml")); removeWhiteSpace(xupdateResult); //Read reference xml file DocumentBuilderFactory parserFactory = DocumentBuilderFactory.newInstance(); parserFactory.setNamespaceAware(true); DocumentBuilder builder = parserFactory.newDocumentBuilder(); Document referenceXML = builder.parse(RESULT_DIR.resolve(testName + ".xml").toFile()); removeWhiteSpace(referenceXML); //compare new CompareDocuments().compare(referenceXML, xupdateResult, "", false); removeDocument(); } /* * helperfunctions * */ public void addDocument(final String sourceFile) throws XMLDBException { final XMLResource document = (XMLResource) col.createResource(XUPDATE_FILE, "XMLResource"); final Path f = SOURCE_DIR.resolve(sourceFile); if (!Files.isReadable(f)) { System.err.println("can't read file " + sourceFile); } document.setContent(f); col.storeResource(document); } public void removeDocument() throws XMLDBException { final Resource document = col.getResource(XUPDATE_FILE); col.removeResource(document); } private Document updateDocument(final Path updateFile) throws XMLDBException, IOException, ParserConfigurationException, SAXException { final XUpdateQueryService service = (XUpdateQueryService) col.getService("XUpdateQueryService", "1.0"); // Read XUpdate-Modifcations final String xUpdateModifications = new String(Files.readAllBytes(updateFile), UTF_8); // service.update(xUpdateModifications); //col.setProperty("pretty", "true"); //col.setProperty("encoding", "UTF-8"); final XMLResource ret = (XMLResource) col.getResource(XUPDATE_FILE); final String xmlString = ((String) ret.getContent()); // convert xml string to dom // todo: make it nicer final DocumentBuilderFactory parserFactory = DocumentBuilderFactory.newInstance(); parserFactory.setNamespaceAware(true); try(final InputStream is = new ByteArrayInputStream(xmlString.getBytes())) { final InputSource in = new InputSource(is); final DocumentBuilder builder = parserFactory.newDocumentBuilder(); return builder.parse(in); } } private void removeWhiteSpace(final Document document) { final DocumentTraversal dt = (DocumentTraversal) document; final NodeIterator nodeIterator = dt.createNodeIterator(document, NodeFilter.SHOW_TEXT, null, true); Node node = nodeIterator.nextNode(); while (node != null) { if (node.getNodeValue().trim().compareTo("") == 0) { node.getParentNode().removeChild(node); } node = nodeIterator.nextNode(); } } @Before public void startup() throws ClassNotFoundException, InstantiationException, IllegalAccessException, XMLDBException { final Class<?> cl = Class.forName(DRIVER); final Database database = (Database) cl.newInstance(); database.setProperty("create-database", "true"); DatabaseManager.registerDatabase(database); col = DatabaseManager.getCollection(URI + "/" + XUPDATE_COLLECTION); if (col == null) { final Collection root = DatabaseManager.getCollection(URI, "admin", ""); CollectionManagementService mgtService = (CollectionManagementService) root.getService("CollectionManagementService", "1.0"); col = mgtService.createCollection(XUPDATE_COLLECTION); final UserManagementService ums = (UserManagementService) col.getService("UserManagementService", "1.0"); // change ownership to guest final Account guest = ums.getAccount("guest"); ums.chown(guest, guest.getPrimaryGroup()); ums.chmod(Permission.DEFAULT_COLLECTION_PERM); } } @After public void shutdown() throws XMLDBException { TestUtils.cleanupDB(); final Collection root = DatabaseManager.getCollection(URI, "admin", ""); final DatabaseInstanceManager mgr = (DatabaseInstanceManager) root.getService("DatabaseInstanceManager", "1.0"); mgr.shutdown(); } }