package org.exist.storage; import org.exist.EXistException; import org.exist.collections.Collection; import org.exist.collections.IndexInfo; import org.exist.collections.triggers.TriggerException; import org.exist.dom.persistent.BinaryDocument; import org.exist.dom.persistent.DocumentImpl; import org.exist.security.PermissionDeniedException; import org.exist.storage.txn.TransactionManager; import org.exist.storage.txn.Txn; import org.exist.test.ExistEmbeddedServer; import org.exist.test.TestConstants; import org.exist.util.DatabaseConfigurationException; import org.exist.util.LockException; import org.exist.xmldb.XmldbURI; import org.junit.ClassRule; import org.junit.Test; import org.xml.sax.SAXException; import java.io.IOException; import java.util.Optional; import static org.junit.Assert.*; public class ModificationTimeTest { private static final String XML_FILENAME = "test.xml"; private static final String VALID_XML = "<?xml version=\"1.0\"?>" + "<valid/>"; private static final String INVALID_XML = "<?xml version=\"1.0\"?>" + "<invalid>"; /** * Store a binary document, wait for a while and then overwrite it * with another binary document. The document's modification time should * have been updated afterwards. */ @Test public void check_if_modification_time_is_updated_binary() throws EXistException, InterruptedException, PermissionDeniedException, LockException, IOException, TriggerException, DatabaseConfigurationException { final String mimeType = "application/octet-stream"; final String filename = "data.dat"; final String data = "some data"; BinaryDocument binaryDoc = storeBinary(filename, data, mimeType); assertNotNull(binaryDoc); long modificationTimeBefore = binaryDoc.getMetadata().getLastModified(); Thread.sleep(500); binaryDoc = storeBinary(filename, data, mimeType); assertNotNull(binaryDoc); long modificationTimeAfter = binaryDoc.getMetadata().getLastModified(); //check the mimetype has been preserved across database restarts assertNotEquals(modificationTimeBefore, modificationTimeAfter); } /** * Store a valid XML resource, wait for a while and then overwrite it * with another valid XML resource. The resource's modification time should * have been updated afterwards. */ @Test public void check_if_modification_time_is_updated_xml() throws EXistException, InterruptedException, PermissionDeniedException, LockException, IOException, TriggerException, SAXException, DatabaseConfigurationException { IndexInfo info = storeXML(XML_FILENAME, VALID_XML); assertNotNull(info); DocumentImpl doc = info.getDocument(); long modificationTimeBefore = doc.getMetadata().getLastModified(); Thread.sleep(500); info = storeXML(XML_FILENAME, VALID_XML); assertNotNull(info); doc = info.getDocument(); long modificationTimeAfter = doc.getMetadata().getLastModified(); assertNotEquals(modificationTimeBefore, modificationTimeAfter); } /** * Store a valid XML resource, wait for a while and then try to overwrite * it with an invalid XML resource. The invalid XML should be rejected and * the resource's modification time should be the same afterwards. */ @Test public void check_if_modification_time_is_not_updated_on_parse_error() throws EXistException, InterruptedException, PermissionDeniedException, LockException, IOException, TriggerException, SAXException, DatabaseConfigurationException { IndexInfo info = storeXML(XML_FILENAME, VALID_XML); assertNotNull(info); DocumentImpl doc = info.getDocument(); final XmldbURI docUri = doc.getFileURI(); long modificationTimeBefore = doc.getMetadata().getLastModified(); Thread.sleep(500); boolean threw = false; info = null; try { info = storeXML(XML_FILENAME, INVALID_XML); } catch (SAXException e) { threw = true; } assertTrue(threw); assertNull(info); doc = getDocument(docUri); assertNotNull(doc); long modificationTimeAfter = doc.getMetadata().getLastModified(); assertEquals(modificationTimeBefore, modificationTimeAfter); } @ClassRule public static final ExistEmbeddedServer existEmbeddedServer = new ExistEmbeddedServer(true, false); private DocumentImpl getDocument(final XmldbURI uri) throws EXistException, PermissionDeniedException, DatabaseConfigurationException { DocumentImpl doc = null; final BrokerPool pool = existEmbeddedServer.getBrokerPool(); try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()));) { assertNotNull(broker); final Collection root = broker.getCollection(TestConstants.TEST_COLLECTION_URI); assertNotNull(root); doc = root.getDocument(broker, uri); } return doc; } private BinaryDocument storeBinary(String name, String data, String mimeType) throws EXistException, PermissionDeniedException, IOException, TriggerException, LockException, DatabaseConfigurationException { final BrokerPool pool = existEmbeddedServer.getBrokerPool(); final TransactionManager transact = pool.getTransactionManager(); BinaryDocument binaryDoc = null; try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject())); final Txn transaction = transact.beginTransaction()) { final Collection root = broker.getOrCreateCollection(transaction, TestConstants.TEST_COLLECTION_URI); broker.saveCollection(transaction, root); assertNotNull(root); binaryDoc = root.addBinaryResource(transaction, broker, XmldbURI.create(name), data.getBytes(), mimeType); transact.commit(transaction); } return binaryDoc; } private IndexInfo storeXML(String name, String xml) throws EXistException, PermissionDeniedException, IOException, LockException, SAXException, DatabaseConfigurationException { final BrokerPool pool = existEmbeddedServer.getBrokerPool(); final TransactionManager transact = pool.getTransactionManager(); IndexInfo info = null; try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject())); final Txn transaction = transact.beginTransaction()) { final Collection root = broker.getOrCreateCollection(transaction, TestConstants.TEST_COLLECTION_URI); broker.saveCollection(transaction, root); assertNotNull(root); info = root.validateXMLResource(transaction, broker, XmldbURI.create(name), xml); transact.commit(transaction); } return info; } }