| /******************************************************************************* |
| * Copyright (c) 2004 IBM Corporation and others. |
| * 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: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.osgi.tests.services.datalocation; |
| |
| import java.io.*; |
| |
| import junit.framework.Test; |
| import junit.framework.TestSuite; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.osgi.storagemanager.StorageManager; |
| import org.eclipse.osgi.tests.OSGiTest; |
| |
| public class FileManagerTests extends OSGiTest { |
| StorageManager manager1; |
| StorageManager manager2; |
| File base; |
| |
| /** |
| * Constructs a test case with the given name. |
| */ |
| public FileManagerTests(String name) { |
| super(name); |
| } |
| |
| public static Test suite() { |
| return new TestSuite(FileManagerTests.class); |
| } |
| |
| protected void setUp() throws Exception { |
| super.setUp(); |
| base = new File(Platform.getConfigurationLocation().getURL().getPath(), "FileManagerTests"); |
| manager1 = null; |
| manager2 = null; |
| } |
| |
| protected void tearDown() throws Exception { |
| super.tearDown(); |
| if (manager1 != null) |
| manager1.close(); |
| if (manager2 != null) |
| manager2.close(); |
| rm(base); |
| } |
| |
| private void rm(File file) { |
| if (file.isDirectory()) { |
| File[] list = file.listFiles(); |
| if (list != null) { |
| for (int idx=0; idx<list.length; idx++) { |
| rm(list[idx]); |
| } |
| } |
| } |
| file.delete(); |
| } |
| |
| |
| /** |
| * Open a filemanager in readonly and ensure files are |
| * not created. |
| */ |
| public void testReadOnly() { |
| File testDir = new File(base, "readOnlyManager"); |
| String fileName = "testReadOnly"; |
| testDir.mkdirs(); |
| String[] files = testDir.list(); |
| assertEquals(files.length, 0); |
| manager1 = new StorageManager(testDir, null, true); |
| try { |
| manager1.open(true); |
| } catch(IOException e) { |
| fail("unexpected exception", e); |
| } |
| files = testDir.list(); |
| assertEquals(files.length, 0); |
| try { |
| manager1.add(fileName); |
| fail("add succedded"); |
| } catch(IOException e) { |
| //good |
| } |
| |
| try { |
| manager1.lookup(fileName, true); |
| fail("lookup succedded"); |
| } catch(IOException e) { |
| //good |
| } |
| |
| try { |
| manager1.createTempFile(fileName); |
| fail("create temp file succedded"); |
| } catch(IOException e) { |
| //good |
| } |
| files = testDir.list(); |
| assertEquals(files.length, 0); |
| manager1.close(); |
| manager1 = null; |
| |
| try { |
| // lets create a file in a writable file manager |
| manager2 = new StorageManager(testDir, null, false); |
| manager2.open(true); |
| manager2.lookup(fileName, true); |
| File tmpFile = manager2.createTempFile(fileName); |
| writeToFile(tmpFile, "This file exists"); |
| manager2.update(new String[] {fileName}, new String[] {tmpFile.getName()}); |
| manager2.close(); |
| manager2 = null; |
| } catch(IOException e) { |
| fail("unexpected exception", e); |
| } |
| } |
| |
| |
| void writeToFile(File file, String str) throws IOException { |
| FileOutputStream fos = new FileOutputStream(file); |
| try { |
| fos.write(str.getBytes()); |
| fos.flush(); |
| fos.getFD().sync(); |
| } finally { |
| fos.close(); |
| } |
| } |
| |
| |
| private String getInputStreamContents(InputStream is) throws IOException { |
| StringBuffer sb = new StringBuffer(); |
| byte[] data = new byte[64]; |
| int len; |
| try { |
| while ((len = is.read(data)) != -1) { |
| sb.append(new String(data, 0, len)); |
| } |
| } finally { |
| is.close(); |
| } |
| return sb.toString(); |
| } |
| |
| |
| /** |
| * This tests a FM update where the a specific file is managed with a |
| * revision number of (n) and an update is requested while there already |
| * exists a file with revision number (n+1). FM should skip that generation |
| * number and update the database with file version set to (n+2). This test is |
| * possible if a power loss occurs between FM rename() and FM save(). |
| */ |
| public void testExistingVersion() { |
| String testFile = "testExistingVersion.txt"; |
| manager1 = new StorageManager(base, null); |
| try { |
| manager1.open(false); |
| File file1 = new File(base, testFile+".1"); |
| File file2 = new File(base, testFile+".2"); |
| File file3 = new File(base, testFile+".3"); |
| File file4 = new File(base, testFile+".4"); |
| if (file1.exists() || file2.exists() || file3.exists() || file4.exists()) { |
| fail("Test files already exists."); |
| return; |
| } |
| // create file version (1) |
| manager1.add(testFile); |
| File file = manager1.createTempFile(testFile); |
| writeToFile(file, "contents irrelevant"); |
| manager1.update(new String[] {testFile}, new String[] {file.getName()}); |
| if (!file1.exists() || file2.exists() || file3.exists() || file4.exists()) { |
| fail("Failed to create a single test file"); |
| return; |
| } |
| |
| // create file version (2) outside filemanager |
| writeToFile(file2, "file2 exists"); |
| |
| // update another file after generation 2 already exists... |
| file = manager1.createTempFile(testFile); |
| writeToFile(file, "file 3 contents"); |
| manager1.update(new String[] {testFile}, new String[] {file.getName()}); |
| if (!file3.exists() || file4.exists()) { |
| fail("Failed to skip existing filemanager file."); |
| return; |
| } |
| |
| // open a new manager, ensure a lookup results in file version (3) |
| manager2 = new StorageManager(base, null); |
| manager2.open(true); |
| file = manager2.lookup(testFile, false); |
| if (file == null) { |
| fail("Unable to lookup exising file"); |
| return; |
| } |
| assertTrue(file.getName().endsWith(".3")); |
| assertTrue(file.exists()); |
| FileInputStream fis = new FileInputStream(file); |
| assertEquals(getInputStreamContents(fis), "file 3 contents"); |
| |
| manager2.close(); |
| manager2=null; |
| |
| manager1.close(); |
| manager1=null; |
| } catch(IOException e) { |
| fail("unexpected exception", e); |
| } |
| } |
| |
| |
| /** |
| * This tests that FM apis throw exceptions if FM has not yet been opened |
| * or if FM has been closed. |
| */ |
| public void testNotOpen() { |
| String permanentFile = "testNotOpen.txt"; |
| String scratchFile = "testNotOpenScratch"; |
| manager1 = new StorageManager(base, null); |
| // create a permanent file and a managed scratch file |
| try { |
| manager1.open(true); |
| manager1.add(permanentFile); |
| File tmpFile = manager1.createTempFile(permanentFile); |
| this.writeToFile(tmpFile, "File exists"); |
| manager1.update(new String[] {permanentFile}, new String[] {tmpFile.getName()}); |
| manager1.add(scratchFile); |
| } catch(IOException e) { |
| fail("unexpected exception", e); |
| } |
| |
| // create a new manager, and try making calls |
| manager2 = new StorageManager(base, null); |
| checkOpen(false, permanentFile, scratchFile); |
| // open the manager, try again |
| try { |
| manager2.open(true); |
| } catch(IOException e) { |
| fail("unexpected exception", e); |
| } |
| checkOpen(true, permanentFile, scratchFile); |
| // close manager, try again |
| manager2.close(); |
| checkOpen(false, permanentFile, scratchFile); |
| manager2 = null; |
| |
| manager1.close(); |
| manager1 = null; |
| } |
| |
| void checkOpen(boolean open, String permanentFile, String scratchFile) { |
| // check add() |
| try { |
| manager2.add("failFile"); |
| if (!open) |
| fail("add did not fail."); |
| manager2.remove("failFile"); |
| } catch(IOException e) { |
| if (open) |
| fail("unexpected exception", e); |
| } |
| // check lookup() |
| try { |
| // expect TEST2 to exist |
| manager2.lookup(permanentFile, false); |
| if (!open) |
| fail("lookup did not fail."); |
| } catch(IOException e) { |
| if (open) |
| fail("unexpected exception", e); |
| } |
| // check update, first create a real file to add |
| File tmpFile; |
| try { |
| tmpFile = manager2.createTempFile("openTest"); |
| writeToFile(tmpFile, "contents irrelevant"); |
| } catch (IOException e) { |
| fail("unexpected exception", e); |
| tmpFile = null; |
| } |
| if (tmpFile != null) { |
| try { |
| manager2.update(new String[] {permanentFile}, new String[] {tmpFile.getName()}); |
| if (!open) |
| fail("update did not fail."); |
| } catch(IOException e) { |
| if (open) |
| fail("unexpected exception", e); |
| } |
| } |
| // check remove() |
| try { |
| manager2.remove(scratchFile); |
| if (!open) |
| fail("remove did not fail"); |
| else // add the file back if expected to complete |
| manager2.add(scratchFile); |
| } catch(IOException e) { |
| if (open) |
| fail("unexpected exception", e); |
| } |
| } |
| |
| |
| /** |
| * This tests FM remove() then add(). On a remove(), the file can not be deleted as it may |
| * be in use by another FM. Then add() the file back and see if the version number written to |
| * is (n+1) where (n) is the version when remove() called. This is likely if framework uses |
| * -clean where on clean we remove the file, then on exit we add the file back. Make sure |
| * this is orderly. |
| * |
| * Currently is is a known issues that remove() will never delete any old manager contents. |
| */ |
| public void testRemoveThenAdd() { |
| String fileName = "testRemoveThenAdd.txt"; |
| File file1 = new File(base, fileName+".1"); |
| File file2 = new File(base, fileName+".2"); |
| File file3 = new File(base, fileName+".3"); |
| manager1 = new StorageManager(base, null); |
| // create a permanent file |
| try { |
| manager1.open(true); |
| manager1.add(fileName); |
| // create version (1) |
| File tmpFile = manager1.createTempFile(fileName); |
| writeToFile(tmpFile, "File exists"); |
| manager1.update(new String[] {fileName}, new String[] {tmpFile.getName()}); |
| // do it again, now version (2) |
| tmpFile = manager1.createTempFile(fileName); |
| writeToFile(tmpFile, "File exists #2"); |
| manager1.update(new String[] {fileName}, new String[] {tmpFile.getName()}); |
| manager1.close(); // force a cleanup |
| manager1 = null; |
| // sanity check |
| if (file1.exists() || !file2.exists() || file3.exists()) |
| fail("Failed creating a file revision"); |
| |
| manager2 = new StorageManager(base, null); |
| manager2.open(true); |
| manager2.remove(fileName); |
| // check lookup & getInputStream |
| File testFile = manager2.lookup(fileName, false); |
| assertNull(testFile); |
| manager2.add(fileName); |
| testFile = manager2.lookup(fileName, false); |
| assertNotNull(testFile); |
| assertTrue(testFile.getName().endsWith(".0")); |
| // write new file, ensure it version 3 |
| tmpFile = manager2.createTempFile(fileName); |
| writeToFile(tmpFile, "File exists #3"); |
| manager2.update(new String[] {fileName}, new String[] {tmpFile.getName()}); |
| testFile = manager2.lookup(fileName, false); |
| assertNotNull(testFile); |
| assertTrue(testFile.getName().endsWith(".3")); |
| assertTrue(file3.exists()); |
| |
| // open a new manager, ensure that the database was updated |
| // by checking version is also #3 |
| manager1 = new StorageManager(base, null); |
| manager1.open(true); |
| testFile = manager1.lookup(fileName, false); |
| assertNotNull(testFile); |
| assertTrue(testFile.getName().endsWith(".3")); |
| |
| manager1.close(); |
| manager1 = null; |
| manager2.close(); |
| manager2 = null; |
| } catch(IOException e) { |
| fail("unexpected exception", e); |
| } |
| } |
| |
| /** |
| * Test multiple FM do not cleanup any old files as they may be in use. |
| */ |
| public void testMultipleFileManagers() { |
| // This test relies on a file lock to fail if the same process already |
| // holds a file lock. This is true on Win32 but not on Linux. So run |
| // this test for windows only. |
| if (!"win32".equalsIgnoreCase(System.getProperty("osgi.os"))) |
| // this is a Windows-only test |
| return; |
| String fileName = "testMultipleFileManagers.txt"; |
| File file1 = new File(base, fileName+".1"); |
| File file2 = new File(base, fileName+".2"); |
| manager1 = new StorageManager(base, null); |
| try { |
| manager1.open(true); |
| File file = manager1.lookup(fileName, true); |
| assertNotNull(file); |
| file = manager1.createTempFile(fileName); |
| writeToFile(file, "test contents #1"); |
| manager1.update(new String[] {fileName}, new String[] {file.getName()}); |
| |
| // ensure file is version #1 |
| file = manager1.lookup(fileName, false); |
| assertNotNull(file); |
| assertTrue(file.getName().endsWith(".1")); |
| assertTrue(file1.exists()); |
| |
| //new fileMangager using version #1 |
| manager2 = new StorageManager(base, null); |
| manager2.open(true); |
| // sanity check |
| file = manager2.lookup(fileName, false); |
| assertNotNull(file); |
| assertTrue(file.getName().endsWith(".1")); |
| assertTrue(file1.exists() && !file2.exists()); |
| |
| // back to manager #1, update file again, close |
| file = manager1.createTempFile(fileName); |
| writeToFile(file, "test contents #2"); |
| manager1.update(new String[] {fileName}, new String[] {file.getName()}); |
| //sanity check |
| assertTrue(file1.exists()); |
| assertTrue(file2.exists()); |
| manager1.close(); |
| manager1 = null; |
| // both files better still exists |
| assertTrue(file1.exists()); |
| assertTrue(file2.exists()); |
| |
| // manager #2 |
| // sanity check |
| file = manager2.lookup(fileName, false); |
| assertNotNull(file); |
| assertTrue(file.getName().endsWith(".1")); |
| // close manager2, cleanup should occur |
| manager2.close(); |
| manager2 = null; |
| assertTrue(!file1.exists()); |
| assertTrue(file2.exists()); |
| |
| // new manager1, does it get version 1? |
| manager1 = new StorageManager(base, null); |
| manager1.open(true); |
| file = manager1.lookup(fileName, false); |
| assertNotNull(file); |
| assertTrue(file.getName().endsWith(".2")); |
| manager1.close(); |
| manager1 = null; |
| } catch(IOException e) { |
| fail("unexpected exception", e); |
| } |
| } |
| |
| /** |
| * This test will verify that a FM will fail if a lock is held |
| */ |
| public void testJavaIOLocking() { |
| // This type of locking is only sure to work on Win32. |
| if (!"win32".equalsIgnoreCase(System.getProperty("osgi.os"))) |
| // this is a Windows-only test |
| return; |
| String fileName = "testJavaIOLocking"; |
| File lockFile = new File(new File(base,".manager"),".fileTableLock"); |
| lockFile.getParentFile().mkdirs(); |
| try { |
| new FileOutputStream(lockFile).close(); |
| } catch(IOException e) { |
| fail("unexpected exception", e); |
| } |
| assertTrue(lockFile.exists()); |
| FileOutputStream fos = null; |
| try { |
| fos = new FileOutputStream(lockFile); |
| // we hold the lock, lets open a FM |
| manager1 = new StorageManager(base, "java.io"); |
| try { |
| manager1.open(true); // wait for lock |
| fail("open with lock succedded"); |
| } catch(IOException e) { |
| //good |
| } |
| |
| manager1.open(false); // don't wait, should work |
| try { |
| manager1.add(fileName); |
| fail("add succedded"); |
| } catch(IOException e) { |
| //good |
| } |
| //sanity check, file should not be managed |
| assertNull(manager1.lookup(fileName, false)); |
| manager1.close(); |
| manager1 = null; |
| } catch(IOException e) { |
| fail("unexpected exception", e); |
| } finally { |
| try { |
| if (fos != null) |
| fos.close(); |
| } catch(IOException e) { |
| fail("unexpected exception", e); |
| } |
| } |
| } |
| } |