/* * Copyright (C) 2009 eXo Platform SAS. * * 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.exoplatform.services.jcr; import junit.framework.TestCase; import org.exoplatform.container.StandaloneContainer; import org.exoplatform.services.jcr.config.WorkspaceEntry; import org.exoplatform.services.jcr.core.CredentialsImpl; import org.exoplatform.services.jcr.core.ManageableRepository; import org.exoplatform.services.jcr.core.WorkspaceContainerFacade; import org.exoplatform.services.jcr.datamodel.ItemData; import org.exoplatform.services.jcr.datamodel.ItemType; import org.exoplatform.services.jcr.datamodel.NodeData; import org.exoplatform.services.jcr.datamodel.PropertyData; import org.exoplatform.services.jcr.datamodel.QPathEntry; import org.exoplatform.services.jcr.impl.core.ItemImpl; import org.exoplatform.services.jcr.impl.core.NodeImpl; import org.exoplatform.services.jcr.impl.core.RepositoryImpl; import org.exoplatform.services.jcr.impl.core.SessionImpl; import org.exoplatform.services.jcr.impl.core.itemfilters.QPathEntryFilter; import org.exoplatform.services.jcr.impl.dataflow.persistent.ACLHolder; import org.exoplatform.services.jcr.impl.dataflow.persistent.ChangedSizeHandler; import org.exoplatform.services.jcr.impl.dataflow.serialization.ReaderSpoolFileHolder; import org.exoplatform.services.jcr.impl.util.io.FileCleaner; import org.exoplatform.services.jcr.impl.util.io.FileCleanerHolder; import org.exoplatform.services.jcr.storage.WorkspaceDataContainer; import org.exoplatform.services.jcr.storage.WorkspaceStorageConnection; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; import java.net.URL; import java.util.ArrayList; import java.util.Calendar; import java.util.Iterator; import java.util.List; import java.util.Random; import javax.jcr.InvalidItemStateException; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.PathNotFoundException; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.ValueFactory; import javax.jcr.Workspace; /** * Created by The eXo Platform SAS. * * @author <a href="mailto:geaz@users.sourceforge.net">Gennady Azarenkov </a> * @version $Id: BaseStandaloneTest.java 11908 2008-03-13 16:00:12Z ksm $ */ public abstract class BaseStandaloneTest extends TestCase { protected static Log log = ExoLogger.getLogger("exo.jcr.component.core.JCRTest"); protected static String WORKSPACE = "ws"; protected SessionImpl session; protected RepositoryImpl repository; protected CredentialsImpl credentials; protected Workspace workspace; protected RepositoryService repositoryService; protected Node root; protected ValueFactory valueFactory; protected StandaloneContainer container; public int maxBufferSize = 200 * 1024; public FileCleaner fileCleaner; public ReaderSpoolFileHolder holder; protected class CompareStreamException extends Exception { CompareStreamException(String message) { super(message); } CompareStreamException(String message, Throwable e) { super(message, e); } } public void setUp() throws Exception { String configPath = System.getProperty("jcr.test.configuration.file"); if (configPath == null) { fail("System property jcr.test.configuration.file not found"); } URL configUrl = BaseStandaloneTest.class.getResource(configPath); if (configUrl != null) { StandaloneContainer.addConfigurationURL(configUrl.toString()); } else { StandaloneContainer.addConfigurationPath(configPath); } // .addConfigurationPath("src/test/java/conf/standalone/test-configuration.xml"); // .addConfigurationPath("src/test/java/conf/standalone/test-configuration-sjdbc.xml"); // .addConfigurationPath("src/test/java/conf/standalone/test-configuration-sjdbc.pgsql.xml"); // .addConfigurationPath("src/test/java/conf/standalone/test-configuration-sjdbc.ora.xml"); // .addConfigurationPath("src/test/java/conf/standalone/test-configuration-mjdbc.mysql.xml"); String loginConf = BaseStandaloneTest.class.getResource("/login.conf").toString(); container = StandaloneContainer.getInstance(); if (System.getProperty("java.security.auth.login.config") == null) { System.setProperty("java.security.auth.login.config", loginConf); } credentials = new CredentialsImpl("admin", "admin".toCharArray()); repositoryService = (RepositoryService)container.getComponentInstanceOfType(RepositoryService.class); repository = (RepositoryImpl)repositoryService.getDefaultRepository(); session = (SessionImpl)repository.login(credentials, "ws"); workspace = session.getWorkspace(); root = session.getRootNode(); valueFactory = session.getValueFactory(); initRepository(); ManageableRepository repository = repositoryService.getDefaultRepository(); WorkspaceContainerFacade wsc = repository.getWorkspaceContainer("ws"); WorkspaceEntry wconf = (WorkspaceEntry)wsc.getComponent(WorkspaceEntry.class); maxBufferSize = wconf.getContainer().getParameterInteger(WorkspaceDataContainer.MAXBUFFERSIZE_PROP, WorkspaceDataContainer.DEF_MAXBUFFERSIZE); fileCleaner = FileCleanerHolder.getDefaultFileCleaner(); holder = new ReaderSpoolFileHolder(); } /** * This method has been added to be able to call tearDown from JUnit 4 test cases. * This is a workaround to avoid having to modify too many classes */ public void after() throws Exception { tearDown(); } protected void tearDown() throws Exception { if (session != null) { Session sysSession = repository.getSystemSession(session.getWorkspace().getName()); try { Node rootNode = sysSession.getRootNode(); if (rootNode.hasNodes()) { // clean test root for (NodeIterator children = rootNode.getNodes(); children.hasNext();) { Node node = children.nextNode(); if (!node.getPath().startsWith("/jcr:system")) { // log.info("DELETing ------------- "+node.getPath()); node.remove(); } } sysSession.save(); } } catch (Exception e) { log.error("tearDown() ERROR " + getClass().getName() + "." + getName() + " " + e, e); } finally { sysSession.logout(); session.logout(); } } super.tearDown(); } protected abstract String getRepositoryName(); public void initRepository() throws RepositoryException { } // ====== utils ======= protected void checkItemsExisted(String[] exists, String[] notExists) throws RepositoryException { String path = null; if (exists != null) { try { for (String nodePath : exists) { path = nodePath; session.getItem(path); } } catch (PathNotFoundException e) { fail("Item must exists " + path + ". " + e.getMessage()); } } if (notExists != null) { try { for (String nodePath : notExists) { session.getItem(nodePath); fail("Item must not exists " + nodePath); } } catch (PathNotFoundException e) { // ok } } } protected void checkNodesExistedByUUID(String[] exists, String[] notExists) throws RepositoryException { String uuid = null; if (exists != null) { try { for (String nodePath : exists) { uuid = nodePath; session.getNodeByUUID(uuid); } } catch (PathNotFoundException e) { fail("Node must exists, UUID " + uuid + ". " + e.getMessage()); } } if (notExists != null) { try { for (String nodeUUID : notExists) { session.getNodeByUUID(nodeUUID); fail("Node must not exists, UUID " + nodeUUID); } } catch (PathNotFoundException e) { // ok } } } protected void compareStream(InputStream etalon, InputStream data) throws IOException { try { compareStream(etalon, data, 0, 0, -1); } catch (CompareStreamException e) { fail(e.getMessage()); } } /** * Compare etalon stream with data stream begining from the offset in etalon * and position in data. Length bytes will be readed and compared. if length * is lower 0 then compare streams till one of them will be read. * * @param etalon * @param data * @param etalonPos * @param length * @param dataPos * @throws IOException */ protected void compareStream(InputStream etalon, InputStream data, long etalonPos, long dataPos, long length) throws IOException, CompareStreamException { int dindex = 0; skipStream(etalon, etalonPos); skipStream(data, dataPos); byte[] ebuff = new byte[1024]; int eread = 0; while ((eread = etalon.read(ebuff)) > 0) { byte[] dbuff = new byte[eread]; int erindex = 0; while (erindex < eread) { int dread = -1; try { dread = data.read(dbuff); } catch (IOException e) { throw new CompareStreamException("Streams is not equals by length or data stream is unreadable. Cause: " + e.getMessage()); } if (dread == -1) { throw new CompareStreamException( "Streams is not equals by length. Data end-of-stream reached at position " + dindex); } for (int i = 0; i < dread; i++) { byte eb = ebuff[i]; byte db = dbuff[i]; if (eb != db) { throw new CompareStreamException("Streams is not equals. Wrong byte stored at position " + dindex + " of data stream. Expected 0x" + Integer.toHexString(eb) + " '" + new String(new byte[]{eb}) + "' but found 0x" + Integer.toHexString(db) + " '" + new String(new byte[]{db}) + "'"); } erindex++; dindex++; if (length > 0 && dindex >= length) { return; // tested length reached } } if (dread < eread) { dbuff = new byte[eread - dread]; } } } if (data.available() > 0) { throw new CompareStreamException("Streams is not equals by length. Data stream contains more data. Were read " + dindex); } } protected void skipStream(InputStream stream, long pos) throws IOException { long curPos = pos; long sk = 0; while ((sk = stream.skip(curPos)) > 0) { curPos -= sk; }; if (sk < 0) { fail("Can not read the stream (skip bytes)"); } if (curPos != 0) { fail("Can not skip bytes from the stream (" + pos + " bytes)"); } } public File createBLOBTempFile(int sizeInKb) throws IOException { return createBLOBTempFile("exo_jcr_test_temp_file_", sizeInKb); } protected File createBLOBTempFile(String prefix, int sizeInKb) throws IOException { // create test file byte[] data = new byte[1024]; // 1Kb File testFile = File.createTempFile(prefix, ".tmp"); FileOutputStream tempOut = new FileOutputStream(testFile); Random random = new Random(); for (int i = 0; i < sizeInKb; i++) { random.nextBytes(data); tempOut.write(data); } tempOut.close(); testFile.deleteOnExit(); // delete on test exit if (log.isDebugEnabled()) { log.debug("Temp file created: " + testFile.getAbsolutePath() + " size: " + testFile.length()); } return testFile; } protected void checkMixins(String[] mixins, NodeImpl node) throws RepositoryException { try { String[] nodeMixins = node.getMixinTypeNames(); assertEquals("Mixins count is different", mixins.length, nodeMixins.length); compareMixins(mixins, nodeMixins); } catch (RepositoryException e) { fail("Mixins isn't accessible on the node " + node.getPath()); } } protected void compareMixins(String[] mixins, String[] nodeMixins) { nextMixin : for (String mixin : mixins) { for (String nodeMixin : nodeMixins) { if (mixin.equals(nodeMixin)) { continue nextMixin; } } fail("Mixin '" + mixin + "' isn't accessible"); } } protected String memoryInfo() { String info = ""; info = "free: " + mb(Runtime.getRuntime().freeMemory()) + "M of " + mb(Runtime.getRuntime().totalMemory()) + "M (max: " + mb(Runtime.getRuntime().maxMemory()) + "M)"; return info; } // bytes to Mbytes protected String mb(long mem) { return String.valueOf(Math.round(mem * 100d / (1024d * 1024d)) / 100d); } protected String execTime(long from) { return Math.round(((System.currentTimeMillis() - from) * 100.00d / 60000.00d)) / 100.00d + "min"; } /** * Force a garbage collector. */ protected static void forceGC() { WeakReference<Object> dumbReference = new WeakReference<Object>(new Object()); // A loop that will wait GC, using the minimal time as possible while (dumbReference.get() != null) { System.gc(); try { Thread.sleep(500); } catch (InterruptedException e) { } } } protected void testNames(Iterator iterator, String[] expectedNames) throws RepositoryException { List<String> names = new ArrayList<String>(); while (iterator.hasNext()) { ItemImpl item = (ItemImpl)iterator.next(); names.add(item.getName()); } //compare names assertEquals(expectedNames.length, names.size()); for (String expectedName : expectedNames) { boolean finded = false; for (String name : names) { if (expectedName.equals(name)) { finded = true; break; } } assertTrue(finded); } } /** * @return the session */ public SessionImpl getSession() { return session; } /** * @return the repository */ public RepositoryImpl getRepository() { return repository; } /** * @return the credentials */ public CredentialsImpl getCredentials() { return credentials; } /** * @return the root */ public Node getRoot() { return root; } /** * Test WorkspaceDataContainer. * Does nothing, must be extended in tests. * * @author <a href="mailto:skarpenko@exoplatform.com">Sergiy Karpenko</a> * @version $Id: exo-jboss-codetemplates.xml 34360 18.08.2011 skarpenko $ */ public class TestWorkspaceDataContainer implements WorkspaceDataContainer { public String getInfo() { return null; } public String getName() { return null; } public String getUniqueName() { return null; } public String getStorageVersion() { return null; } public Calendar getCurrentTime() { return null; } public boolean isSame(WorkspaceDataContainer another) { return false; } public WorkspaceStorageConnection openConnection() throws RepositoryException { return null; } public WorkspaceStorageConnection openConnection(boolean readOnly) throws RepositoryException { return null; } public WorkspaceStorageConnection reuseConnection(WorkspaceStorageConnection original) throws RepositoryException { return null; } public boolean isCheckSNSNewConnection() { return false; } } /** * Test WorkspaceStorageConnection. * Does nothing, must be extended in tests. * * @author <a href="mailto:skarpenko@exoplatform.com">Sergiy Karpenko</a> * @version $Id: exo-jboss-codetemplates.xml 34360 18.08.2011 skarpenko $ */ public class TestWorkspaceStorageConnection implements WorkspaceStorageConnection { public ItemData getItemData(NodeData parentData, QPathEntry name, ItemType itemType) throws RepositoryException, IllegalStateException { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } public ItemData getItemData(String identifier) throws RepositoryException, IllegalStateException { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } public List<NodeData> getChildNodesData(NodeData parent) throws RepositoryException, IllegalStateException { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } public List<NodeData> getChildNodesData(NodeData parent, List<QPathEntryFilter> pattern) throws RepositoryException, IllegalStateException { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } public int getChildNodesCount(NodeData parent) throws RepositoryException { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } public int getLastOrderNumber(NodeData parent) throws RepositoryException { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } public List<PropertyData> getChildPropertiesData(NodeData parent) throws RepositoryException, IllegalStateException { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } public List<PropertyData> getChildPropertiesData(NodeData parent, List<QPathEntryFilter> pattern) throws RepositoryException, IllegalStateException { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } public List<PropertyData> listChildPropertiesData(NodeData parent) throws RepositoryException, IllegalStateException { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } public List<PropertyData> getReferencesData(String nodeIdentifier) throws RepositoryException, IllegalStateException, UnsupportedOperationException { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } public void add(NodeData data) throws RepositoryException, UnsupportedOperationException, InvalidItemStateException, IllegalStateException { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } public void add(PropertyData data, ChangedSizeHandler sizeHandler) throws RepositoryException, UnsupportedOperationException, InvalidItemStateException, IllegalStateException { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } public void update(NodeData data) throws RepositoryException, UnsupportedOperationException, InvalidItemStateException, IllegalStateException { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } public void update(PropertyData data, ChangedSizeHandler sizeHandler) throws RepositoryException, UnsupportedOperationException, InvalidItemStateException, IllegalStateException { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } public void rename(NodeData data) throws RepositoryException, UnsupportedOperationException, InvalidItemStateException, IllegalStateException { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } public void delete(NodeData data) throws RepositoryException, UnsupportedOperationException, InvalidItemStateException, IllegalStateException { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } public void delete(PropertyData data, ChangedSizeHandler sizeHandler) throws RepositoryException, UnsupportedOperationException, InvalidItemStateException, IllegalStateException { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } public void commit() throws IllegalStateException, RepositoryException { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } public void rollback() throws IllegalStateException, RepositoryException { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } public void close() throws IllegalStateException, RepositoryException { } public boolean isOpened() { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } public List<ACLHolder> getACLHolders() throws RepositoryException, IllegalStateException, UnsupportedOperationException { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } /** * @see org.exoplatform.services.jcr.storage.WorkspaceStorageConnection#getChildNodesDataByPage(org.exoplatform.services.jcr.datamodel.NodeData, int, int, java.util.List) */ public boolean getChildNodesDataByPage(NodeData parent, int fromOrderNum, int offset, int pageSize, List<NodeData> childs) throws RepositoryException { return false; } /** * @see org.exoplatform.services.jcr.storage.WorkspaceStorageConnection#getNodesCount() */ public long getNodesCount() throws RepositoryException { throw new UnsupportedOperationException(); } public void prepare() throws IllegalStateException, RepositoryException { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } public boolean hasItemData(NodeData parentData, QPathEntry name, ItemType itemType) throws RepositoryException, IllegalStateException { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } public long getWorkspaceDataSize() throws RepositoryException { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } public long getNodeDataSize(String parentId) throws RepositoryException { throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported."); } } }