blob: 39c9cc38d0258d8bce2717a74093fd44b48b7b11 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 SAP AG.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Eduard Bartsch (SAP AG) - initial API and implementation
* Mathias Kinzler (SAP AG) - initial API and implementation
*******************************************************************************/
package org.eclipse.core.resources.semantic.test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import junit.framework.Assert;
import org.eclipse.core.resources.semantic.ISemanticFileSystem;
import org.eclipse.core.resources.semantic.spi.FileCacheServiceFactory;
import org.eclipse.core.resources.semantic.spi.ICacheService;
import org.eclipse.core.resources.semantic.spi.ICacheUpdateCallback;
import org.eclipse.core.resources.semantic.spi.MemoryCacheServiceFactory;
import org.eclipse.core.resources.semantic.spi.SemanticFileCache;
import org.eclipse.core.resources.semantic.spi.Util;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.junit.Test;
/**
*
*/
public class TestCacheService {
/**
* @throws Exception
*/
@Test
public void testCacheService() throws Exception {
ICacheService service = new FileCacheServiceFactory().getCacheService();
IPath path = new Path("/test/file.txt");
String content = "test";
InputStream input = new ByteArrayInputStream(content.getBytes("UTF-8"));
writeToCache(service, path, input);
String content2 = "test2";
InputStream input2 = new ByteArrayInputStream(content2.getBytes("UTF-8"));
writeToCache(service, path, input2);
readFromCache(service, path, content2);
String content3 = "test3";
writeToCacheViaOutputStream(service, path, content3);
readFromCache(service, path, content3);
String content4 = "appended";
InputStream input4 = new ByteArrayInputStream(content4.getBytes("UTF-8"));
appendToCache(service, path, input4);
readFromCache(service, path, content3 + content4);
IPath path2 = new Path("/test/file2.txt");
writeToCache(service, path2, input2);
removeFromCache(service, path2);
manipulateTimestamp(service, path);
String content5 = "test5";
writeToCacheAndUseBeforeCacheUpdate(service, path, content5);
readFromCache(service, path, content5);
// this call must leave cache content unchanged
String content6 = "test6";
writeToCacheAndThrowExceptionInBeforeCacheUpdate(service, path, content6);
// we must still read content5 from cache
readFromCache(service, path, content5);
}
/**
* @throws Exception
*/
@Test
public void testFileSystemCompaction() throws Exception {
ICacheService service = new FileCacheServiceFactory().getCacheService();
IPath path = new Path("/test2/file.txt");
String content = "test";
InputStream input = new ByteArrayInputStream(content.getBytes("UTF-8"));
appendToCache(service, path, input);
removeFromCache(service, path);
File cacheFile = new File(SemanticFileCache.getCache().getCacheDir(), path.toString());
Assert.assertTrue(!cacheFile.exists());
Assert.assertTrue(!cacheFile.getParentFile().exists());
}
/**
* @throws Exception
*/
@Test
public void testContentDeletion() throws Exception {
ICacheService service = new FileCacheServiceFactory().getCacheService();
IPath path = new Path("/test2/file.txt");
String content = "test";
InputStream input = new ByteArrayInputStream(content.getBytes("UTF-8"));
File cacheFile = new File(SemanticFileCache.getCache().getCacheDir(), path.toString());
appendToCache(service, path, input);
// this will open an input stream that will prevent a file from being
// deleted
InputStream is = service.getContent(path);
try {
removeFromCache(service, path);
} catch (CoreException e) {
// $JL-EXC$ ignore exception
// the cache file must still be there but hasContent must report
// false
Assert.assertTrue(!service.hasContent(path));
Assert.assertTrue(cacheFile.exists());
} finally {
// this will close the stream so that a file can be deleted
Util.safeClose(is);
}
// the cache file must be removed during check method and both checks
// return false
Assert.assertTrue(!service.hasContent(path));
Assert.assertTrue(!cacheFile.exists());
Assert.assertTrue(!cacheFile.getParentFile().exists());
}
/**
* @throws Exception
*/
@Test
public void testRecursiveContentDeletion() throws Exception {
ICacheService service = new FileCacheServiceFactory().getCacheService();
IPath rootPath = new Path("/testrecursive/testroot/");
IPath path = rootPath.append("/test2/file.txt");
String content = "test";
InputStream input = new ByteArrayInputStream(content.getBytes("UTF-8"));
File cacheFile = new File(SemanticFileCache.getCache().getCacheDir(), path.toString());
IPath path2 = rootPath.append("/test2/test3/file.txt");
String content2 = "test";
InputStream input2 = new ByteArrayInputStream(content2.getBytes("UTF-8"));
File cacheFile2 = new File(SemanticFileCache.getCache().getCacheDir(), path.toString());
appendToCache(service, path, input);
appendToCache(service, path2, input2);
removeFromCacheRecursive(service, rootPath);
Assert.assertTrue(!service.hasContent(path));
Assert.assertTrue(!service.hasContent(path2));
Assert.assertTrue(!cacheFile.exists());
Assert.assertTrue(!cacheFile.getParentFile().exists());
Assert.assertTrue(!cacheFile2.exists());
Assert.assertTrue(!cacheFile2.getParentFile().exists());
}
/**
* @throws Exception
*/
@Test
public void testRecursiveContentDeletionDeepHierarchy() throws Exception {
ICacheService service = new FileCacheServiceFactory().getCacheService();
IPath rootPath = new Path("/testrecursive/testroot/");
IPath path = rootPath.append("/test2/file.txt");
String content = "test";
InputStream input = new ByteArrayInputStream(content.getBytes("UTF-8"));
File cacheFile = new File(SemanticFileCache.getCache().getCacheDir(), path.toString());
IPath path2 = rootPath.append("/test2/test3/file.txt");
String content2 = "test";
InputStream input2 = new ByteArrayInputStream(content2.getBytes("UTF-8"));
File cacheFile2 = new File(SemanticFileCache.getCache().getCacheDir(), path.toString());
appendToCache(service, path, input);
appendToCache(service, path2, input2);
removeFromCacheRecursive(service, rootPath);
Assert.assertTrue(!service.hasContent(path));
Assert.assertTrue(!service.hasContent(path2));
Assert.assertTrue(!cacheFile.exists());
Assert.assertTrue(!cacheFile.getParentFile().exists());
Assert.assertTrue(!cacheFile2.exists());
Assert.assertTrue(!cacheFile2.getParentFile().exists());
}
/**
* @throws Exception
*/
@Test
public void testRecursiveContentDeletion2() throws Exception {
ICacheService service = new FileCacheServiceFactory().getCacheService();
IPath rootPath = new Path("/testrecursive/testroot/");
IPath path = rootPath.append("/test2/file.txt");
String content = "test";
InputStream input = new ByteArrayInputStream(content.getBytes("UTF-8"));
File cacheFile = new File(SemanticFileCache.getCache().getCacheDir(), path.toString());
IPath path2 = rootPath.append("/test2/test3/file.txt");
String content2 = "test";
InputStream input2 = new ByteArrayInputStream(content2.getBytes("UTF-8"));
File cacheFile2 = new File(SemanticFileCache.getCache().getCacheDir(), path.toString());
appendToCache(service, path, input);
appendToCache(service, path2, input2);
// this will open an input stream that will prevent a file from being
// deleted
InputStream is = service.getContent(path);
try {
removeFromCacheRecursive(service, rootPath);
} finally {
Util.safeClose(is);
}
if (Platform.OS_WIN32.equals(Platform.getOS())) {
Assert.assertTrue("File must still be present", cacheFile.exists());
Assert.assertTrue("Parent folder must still be present", cacheFile.getParentFile().exists());
}
// the cache file must be removed during check method and both checks
// return false
Assert.assertTrue(!service.hasContent(path));
Assert.assertTrue(!service.hasContent(path2));
Assert.assertTrue(!cacheFile.exists());
Assert.assertTrue(!cacheFile.getParentFile().exists());
Assert.assertTrue(!cacheFile2.exists());
Assert.assertTrue(!cacheFile2.getParentFile().exists());
}
/**
* @throws Exception
*/
@Test
public void testRecursiveContentDeletion3() throws Exception {
ICacheService service = new MemoryCacheServiceFactory().getCacheService();
IPath rootPath = new Path("/testrecursive/testroot/");
IPath path = rootPath.append("/test2/file.txt");
String content = "test";
InputStream input = new ByteArrayInputStream(content.getBytes("UTF-8"));
IPath path2 = rootPath.append("/test2/test3/file.txt");
String content2 = "test";
InputStream input2 = new ByteArrayInputStream(content2.getBytes("UTF-8"));
appendToCache(service, path, input);
appendToCache(service, path2, input2);
removeFromCacheRecursive(service, rootPath);
Assert.assertTrue(!service.hasContent(path));
Assert.assertTrue(!service.hasContent(path2));
}
/**
* @throws Exception
*/
@Test
public void testRecursiveContentDeletion4() throws Exception {
ICacheService service = new MemoryCacheServiceFactory().getCacheService();
IPath rootPath = new Path("/testrecursive/testroot/");
IPath path = rootPath.append("/test2/file.txt");
String content = "test";
InputStream input = new ByteArrayInputStream(content.getBytes("UTF-8"));
IPath path2 = rootPath.append("/test2/test3/file.txt");
String content2 = "test";
InputStream input2 = new ByteArrayInputStream(content2.getBytes("UTF-8"));
appendToCache(service, path, input);
appendToCache(service, path2, input2);
removeFromCacheRecursive(service, path);
Assert.assertTrue(!service.hasContent(path));
Assert.assertTrue(service.hasContent(path2));
}
/**
* @throws Exception
*/
@Test
public void testConcurrentAccess() throws Exception {
ICacheService service = new FileCacheServiceFactory().getCacheService();
IPath path = new Path("/test2/file.txt");
String content = "test";
InputStream input = new ByteArrayInputStream(content.getBytes("UTF-8"));
writeToCache(service, path, input);
IPath path1 = new Path("/test2/file1.txt");
String content1 = "test1";
InputStream input1 = new ByteArrayInputStream(content1.getBytes("UTF-8"));
writeToCache(service, path1, input1);
// this will open an input stream that will prevent a file from being
// deleted
InputStream is = service.getContent(path);
InputStream is1 = service.getContent(path1);
try {
writeToCache(service, path, new ByteArrayInputStream("test2".getBytes("UTF-8")));
writeToCache(service, path1, new ByteArrayInputStream("test2".getBytes("UTF-8")));
readFromCache(service, path, "test2");
readFromCache(service, path1, "test2");
// this will open an input stream that will prevent an alternative
// file from being
// deleted
InputStream is2 = service.getContent(path);
InputStream is3 = service.getContent(path1);
try {
writeToCache(service, path, new ByteArrayInputStream("test3".getBytes("UTF-8")));
writeToCache(service, path1, new ByteArrayInputStream("test3".getBytes("UTF-8")));
readFromCache(service, path, "test3");
readFromCache(service, path1, "test3");
} finally {
// this will close the stream so that an alternative file can be
// deleted
Util.safeClose(is2);
Util.safeClose(is3);
}
} catch (CoreException e) {
// $JL-EXC$ ignore exception
Assert.fail("Should not fail even if file open");
} finally {
// this will close the stream so that a file can be deleted
Util.safeClose(is);
Util.safeClose(is1);
}
File cacheFile = new File(SemanticFileCache.getCache().getCacheDir(), path.toString());
Assert.assertTrue(cacheFile.exists());
// this should remove the alternate files and go back to original
writeToCache(service, path, new ByteArrayInputStream("test4".getBytes("UTF-8")));
Assert.assertTrue(cacheFile.exists());
Assert.assertTrue(service.hasContent(path));
}
/**
* @throws Exception
*/
@Test
public void testFileMoveSameFolder() throws Exception {
ICacheService service = new FileCacheServiceFactory().getCacheService();
IPath path = new Path("/test3/file.txt");
String content = "test";
InputStream input = new ByteArrayInputStream(content.getBytes("UTF-8"));
writeToCache(service, path, input);
IPath targetPath = new Path("/test3/file2.txt");
service.moveContent(path, targetPath, null);
File cacheFile = new File(SemanticFileCache.getCache().getCacheDir(), path.toString());
Assert.assertFalse(cacheFile.exists());
Assert.assertTrue(service.hasContent(targetPath));
readFromCache(service, targetPath, content);
}
/**
* @throws Exception
*/
@Test
public void testFileMoveAnotherFolder() throws Exception {
ICacheService service = new FileCacheServiceFactory().getCacheService();
IPath path = new Path("/test3/folder1/file.txt");
String content = "test";
InputStream input = new ByteArrayInputStream(content.getBytes("UTF-8"));
writeToCache(service, path, input);
IPath targetPath = new Path("/test3/folder2/file2.txt");
service.moveContent(path, targetPath, null);
File cacheFile = new File(SemanticFileCache.getCache().getCacheDir(), path.toString());
Assert.assertFalse(cacheFile.exists());
Assert.assertTrue(service.hasContent(targetPath));
readFromCache(service, targetPath, content);
}
/**
* @param service
* @param path
* @throws CoreException
*/
public void manipulateTimestamp(ICacheService service, IPath path) throws CoreException {
// TODO removed due to problems with less than millisecond accuracy
// long timestamp = 1234567890123L;
//
// service.setContentTimestamp(path, timestamp);
//
// Assert.assertEquals(timestamp, service.getContentTimestamp(path));
}
/**
* @param service
* @param path
* @param input
* @throws CoreException
*/
public void writeToCache(ICacheService service, IPath path, InputStream input) throws CoreException {
service.addContent(path, input, ISemanticFileSystem.NONE, null);
Assert.assertTrue(service.hasContent(path));
}
/**
* @param service
* @param path
* @param input
* @throws CoreException
*/
public void appendToCache(ICacheService service, IPath path, InputStream input) throws CoreException {
service.addContent(path, input, ISemanticFileSystem.CONTENT_APPEND, null);
Assert.assertTrue(service.hasContent(path));
}
/**
* @param service
* @param path
* @throws CoreException
*/
public void removeFromCache(ICacheService service, IPath path) throws CoreException {
service.removeContent(path, null);
Assert.assertTrue(!service.hasContent(path));
}
/**
* @param service
* @param path
* @throws CoreException
*/
public void removeFromCacheRecursive(ICacheService service, IPath path) throws CoreException {
service.removeContentRecursive(path, null);
}
/**
* @param service
* @param path
* @param content
* @throws CoreException
*/
public void writeToCacheViaOutputStream(ICacheService service, IPath path, String content) throws CoreException {
final ByteArrayOutputStream remoteOs = new ByteArrayOutputStream();
ICacheUpdateCallback callback = new ICacheUpdateCallback() {
public void cacheUpdated(InputStream newContent, long cacheTimestamp, boolean append) {
try {
Util.transferStreams(newContent, remoteOs, null);
} catch (CoreException e) {
// $JL-EXC$ ignore here
}
}
public boolean beforeCacheUpdate(InputStream newContent, long cacheTimestamp, boolean append) {
// do nothing
return true;
}
};
OutputStream os = service.wrapOutputStream(path, false, callback, null);
try {
os.write(content.getBytes());
os.close();
compareByteArrayWithContent(content, remoteOs.toByteArray());
} catch (IOException e) {
// $JL-EXC$
throw new CoreException(new Status(IStatus.ERROR, "test", 0, content, e));
}
}
public void writeToCacheAndUseBeforeCacheUpdate(ICacheService service, IPath path, String content) throws CoreException {
final ByteArrayOutputStream remoteOs = new ByteArrayOutputStream();
ICacheUpdateCallback callback = new ICacheUpdateCallback() {
public void cacheUpdated(InputStream newContent, long cacheTimestamp, boolean append) {
// do nothing
}
public boolean beforeCacheUpdate(InputStream newContent, long cacheTimestamp, boolean append) throws CoreException {
Util.transferStreams(newContent, remoteOs, null);
return true;
}
};
OutputStream os = service.wrapOutputStream(path, false, callback, null);
try {
os.write(content.getBytes());
os.close();
compareByteArrayWithContent(content, remoteOs.toByteArray());
} catch (IOException e) {
// $JL-EXC$
throw new CoreException(new Status(IStatus.ERROR, "test", 0, content, e));
}
}
public void writeToCacheAndThrowExceptionInBeforeCacheUpdate(ICacheService service, IPath path, String content) throws CoreException {
ICacheUpdateCallback callback = new ICacheUpdateCallback() {
public void cacheUpdated(InputStream newContent, long cacheTimestamp, boolean append) {
// do nothing
}
public boolean beforeCacheUpdate(InputStream newContent, long cacheTimestamp, boolean append) throws CoreException {
throw new CoreException(new Status(IStatus.ERROR, "test", "test"));
}
};
OutputStream os = service.wrapOutputStream(path, false, callback, null);
try {
os.write(content.getBytes());
os.close();
Assert.assertTrue("os.close() must fail", false);
} catch (IOException e) {
// ignore and continue
String msg = e.getMessage();
msg.getClass();
}
}
/**
* @param service
* @param path
* @param content
* @throws CoreException
*/
public void readFromCache(ICacheService service, IPath path, String content) throws CoreException {
InputStream is = null;
try {
is = service.getContent(path);
compareInputStreamWithContent(content, is);
} catch (IOException e) {
// $JL-EXC$
throw new CoreException(new Status(IStatus.ERROR, "test", 0, content, e));
} finally {
Util.safeClose(is);
}
}
private void compareInputStreamWithContent(String content, InputStream is) throws IOException {
byte b[] = new byte[content.length() + 2];
int size = is.read(b);
Assert.assertEquals(content.length(), size);
for (int i = 0; i < size; i++) {
byte c = b[i];
Assert.assertTrue("Content is different", c == content.charAt(i));
}
}
private void compareByteArrayWithContent(String content, byte[] b) {
Assert.assertEquals(content.length(), b.length);
for (int i = 0; i < b.length; i++) {
byte c = b[i];
Assert.assertTrue("Content is different", c == content.charAt(i));
}
}
}