| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.felix.fileinstall.internal; |
| |
| |
| import java.io.File; |
| import java.net.URISyntaxException; |
| import java.util.Collection; |
| import java.util.HashSet; |
| import java.util.Hashtable; |
| import java.util.Map; |
| import java.util.Set; |
| import junit.framework.TestCase; |
| import org.apache.felix.fileinstall.ArtifactListener; |
| import org.easymock.EasyMock; |
| import org.easymock.IMocksControl; |
| import org.junit.Assert; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.BundleContext; |
| import org.osgi.framework.BundleListener; |
| import org.osgi.framework.Constants; |
| import org.osgi.framework.ServiceReference; |
| import org.osgi.framework.startlevel.FrameworkStartLevel; |
| import org.osgi.framework.wiring.BundleRevision; |
| import org.osgi.service.log.LogService; |
| |
| |
| /** |
| * Test class for the DirectoryWatcher |
| */ |
| public class DirectoryWatcherTest extends TestCase |
| { |
| |
| private final static String TEST = "test.key"; |
| Map<String, String> props = new Hashtable<String, String>(); |
| DirectoryWatcher dw; |
| BundleContext mockBundleContext; |
| Bundle mockBundle; |
| Bundle mockSysBundle; |
| FrameworkStartLevel mockStartLevel; |
| |
| |
| protected void setUp() throws Exception |
| { |
| super.setUp(); |
| IMocksControl ctrl = EasyMock.createControl(); |
| ctrl.makeThreadSafe(true); |
| mockBundleContext = ctrl.createMock(BundleContext.class); |
| mockBundle = EasyMock.createNiceMock(Bundle.class); |
| mockSysBundle = EasyMock.createNiceMock(Bundle.class); |
| mockStartLevel = EasyMock.createMock(FrameworkStartLevel.class); |
| props.put( DirectoryWatcher.DIR, new File( "target/load" ).getAbsolutePath() ); |
| |
| // Might get called, but most of the time it doesn't matter whether they do or don't. |
| EasyMock.expect(mockBundleContext.getProperty(DirectoryWatcher.LOG_DEFAULT)) |
| .andStubReturn(null); |
| EasyMock.expect(mockBundleContext.getProperty(DirectoryWatcher.LOG_LEVEL)) |
| .andStubReturn(null); |
| EasyMock.expect(mockBundleContext.getServiceReference(LogService.class.getName())) |
| .andStubReturn(null); |
| EasyMock.expect(mockBundleContext.getBundle()).andReturn(mockBundle).anyTimes(); |
| EasyMock.expect(mockBundleContext.getBundle(Constants.SYSTEM_BUNDLE_LOCATION)).andReturn(mockSysBundle).anyTimes(); |
| EasyMock.expect(mockSysBundle.getState()).andReturn(Bundle.ACTIVE).anyTimes(); |
| EasyMock.expect(mockSysBundle.adapt(FrameworkStartLevel.class)).andReturn(mockStartLevel).anyTimes(); |
| EasyMock.expect(mockStartLevel.getStartLevel()).andReturn(50).anyTimes(); |
| } |
| |
| |
| public void testGetLongWithNonExistentProperty() |
| { |
| mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject()); |
| EasyMock.replay(mockBundleContext, mockBundle, mockSysBundle, mockStartLevel); |
| dw = new DirectoryWatcher( new FileInstall(), props, mockBundleContext ); |
| assertEquals( "getLong gives the default value for non-existing properties", 100, dw.getLong( props, TEST, 100 ) ); |
| EasyMock.verify(mockBundleContext); |
| } |
| |
| |
| public void testGetLongWithExistentProperty() |
| { |
| props.put( TEST, "33" ); |
| |
| mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject()); |
| EasyMock.replay(mockBundleContext, mockBundle, mockSysBundle, mockStartLevel); |
| dw = new DirectoryWatcher( new FileInstall(), props, mockBundleContext ); |
| assertEquals( "getLong retrieves the right property value", 33, dw.getLong( props, TEST, 100 ) ); |
| EasyMock.verify(mockBundleContext); |
| } |
| |
| |
| public void testGetLongWithIncorrectValue() |
| { |
| props.put( TEST, "incorrect" ); |
| |
| mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject()); |
| EasyMock.replay(mockBundleContext, mockBundle, mockSysBundle, mockStartLevel); |
| dw = new DirectoryWatcher( new FileInstall(), props, mockBundleContext ); |
| assertEquals( "getLong retrieves the right property value", 100, dw.getLong( props, TEST, 100 ) ); |
| EasyMock.verify(mockBundleContext); |
| } |
| |
| |
| public void testGetBooleanWithNonExistentProperty() |
| { |
| mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject()); |
| EasyMock.replay(mockBundleContext, mockBundle, mockSysBundle, mockStartLevel); |
| dw = new DirectoryWatcher( new FileInstall(), props, mockBundleContext ); |
| assertEquals( "getBoolean gives the default value for non-existing properties", true, dw.getBoolean( props, TEST, true ) ); |
| EasyMock.verify(mockBundleContext); |
| } |
| |
| |
| public void testGetBooleanWithExistentProperty() |
| { |
| props.put( TEST, "true" ); |
| |
| mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject()); |
| EasyMock.replay(mockBundleContext, mockBundle, mockSysBundle, mockStartLevel); |
| dw = new DirectoryWatcher( new FileInstall(), props, mockBundleContext ); |
| assertEquals( "getBoolean retrieves the right property value", true, dw.getBoolean( props, TEST, false ) ); |
| EasyMock.verify(mockBundleContext); |
| } |
| |
| |
| public void testGetBooleanWithIncorrectValue() |
| { |
| props.put( TEST, "incorrect" ); |
| |
| mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject()); |
| EasyMock.replay(mockBundleContext, mockBundle, mockSysBundle, mockStartLevel); |
| dw = new DirectoryWatcher( new FileInstall(), props, mockBundleContext ); |
| assertEquals( "getBoolean retrieves the right property value", false, dw.getBoolean( props, TEST, true ) ); |
| EasyMock.verify(mockBundleContext); |
| } |
| |
| |
| public void testGetFileWithNonExistentProperty() |
| { |
| mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject()); |
| EasyMock.replay(mockBundleContext, mockBundle, mockSysBundle, mockStartLevel); |
| dw = new DirectoryWatcher( new FileInstall(), props, mockBundleContext ); |
| assertEquals( "getFile gives the default value for non-existing properties", new File("tmp"), dw.getFile( props, TEST, new File("tmp") ) ); |
| EasyMock.verify(mockBundleContext); |
| } |
| |
| |
| public void testGetFileWithExistentProperty() |
| { |
| props.put( TEST, "test" ); |
| |
| mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject()); |
| EasyMock.replay(mockBundleContext, mockBundle, mockSysBundle, mockStartLevel); |
| dw = new DirectoryWatcher( new FileInstall(), props, mockBundleContext ); |
| assertEquals( "getBoolean retrieves the right property value", new File("test"), dw.getFile( props, TEST, new File("tmp") ) ); |
| EasyMock.verify(mockBundleContext); |
| } |
| |
| |
| public void testParameterAfterInitialization() |
| { |
| props.put( DirectoryWatcher.POLL, "500" ); |
| props.put( DirectoryWatcher.LOG_LEVEL, "1" ); |
| props.put( DirectoryWatcher.START_NEW_BUNDLES, "false" ); |
| props.put( DirectoryWatcher.DIR, new File( "src/test/resources" ).getAbsolutePath() ); |
| props.put( DirectoryWatcher.TMPDIR, new File( "src/test/resources" ).getAbsolutePath() ); |
| props.put( DirectoryWatcher.FILTER, ".*\\.cfg" ); |
| |
| mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject()); |
| EasyMock.replay(mockBundleContext, mockBundle, mockSysBundle, mockStartLevel); |
| |
| dw = new DirectoryWatcher( new FileInstall(), props, mockBundleContext ); |
| |
| assertEquals( "POLL parameter correctly read", 500l, dw.poll ); |
| assertEquals( "LOG_LEVEL parameter correctly read", 1, dw.logLevel ); |
| assertTrue("DIR parameter correctly read", dw.watchedDirectory.getAbsolutePath().endsWith( |
| "src" + File.separatorChar + "test" + File.separatorChar + "resources")); |
| assertTrue( "TMPDIR parameter correctly read", dw.tmpDir.getAbsolutePath().endsWith( |
| "src" + File.separatorChar + "test" + File.separatorChar + "resources" ) ); |
| assertEquals("START_NEW_BUNDLES parameter correctly read", false, dw.startBundles); |
| assertEquals( "FILTER parameter correctly read", ".*\\.cfg", dw.filter ); |
| EasyMock.verify(mockBundleContext); |
| } |
| |
| |
| public void testDefaultParametersAreSetAfterEmptyInitialization() |
| { |
| props.put( DirectoryWatcher.DIR, new File( "src/test/resources" ).getAbsolutePath() ); |
| |
| mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject()); |
| EasyMock.replay(mockBundleContext, mockBundle, mockSysBundle, mockStartLevel); |
| |
| dw = new DirectoryWatcher( new FileInstall(), props, mockBundleContext ); |
| |
| assertTrue( "DIR parameter correctly read", dw.watchedDirectory.getAbsolutePath().endsWith( |
| "src" + File.separatorChar + "test" + File.separatorChar + "resources" ) ); |
| assertEquals("Default POLL parameter correctly read", 2000l, dw.poll); |
| assertEquals( "Default LOG_LEVEL parameter correctly read", 1, dw.logLevel ); |
| assertTrue("Default TMPDIR parameter correctly read", dw.tmpDir.getAbsolutePath().startsWith( |
| new File(System.getProperty("java.io.tmpdir")).getAbsolutePath())); |
| assertEquals("Default START_NEW_BUNDLES parameter correctly read", true, dw.startBundles); |
| assertEquals( "Default FILTER parameter correctly read", null, dw.filter ); |
| EasyMock.verify(mockBundleContext); |
| } |
| |
| |
| public void testIsFragment() throws Exception |
| { |
| mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject()); |
| BundleRevision mockBundleRevision = EasyMock.createNiceMock(BundleRevision.class); |
| EasyMock.expect(mockBundle.adapt(BundleRevision.class)).andReturn(mockBundleRevision); |
| EasyMock.expect(mockBundleRevision.getTypes()) |
| .andReturn(BundleRevision.TYPE_FRAGMENT); |
| EasyMock.replay(mockBundleContext, mockBundle, mockBundleRevision, mockSysBundle, mockStartLevel); |
| |
| dw = new DirectoryWatcher( new FileInstall(), props, mockBundleContext ); |
| |
| assertTrue( "Fragment type correctly retrieved from Package Admin service", dw.isFragment( mockBundle ) ); |
| |
| EasyMock.verify(mockBundleContext); |
| } |
| |
| public void testInvalidTempDir() throws Exception |
| { |
| String oldTmpDir = System.getProperty("java.io.tmpdir"); |
| |
| try |
| { |
| File parent = new File("target/tmp"); |
| parent.mkdirs(); |
| parent.setWritable(false, false); |
| File tmp = new File(parent, "tmp"); |
| System.setProperty("java.io.tmpdir", tmp.toString()); |
| |
| mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject()); |
| EasyMock.expect(mockBundleContext.createFilter((String) EasyMock.anyObject())) |
| .andReturn(null); |
| |
| BundleRevision mockBundleRevision = EasyMock.createNiceMock(BundleRevision.class); |
| EasyMock.expect(mockBundle.adapt(BundleRevision.class)).andReturn(mockBundleRevision); |
| EasyMock.expect(mockBundleRevision.getTypes()) |
| .andReturn(BundleRevision.TYPE_FRAGMENT); |
| EasyMock.replay(mockBundleContext, mockBundle, mockBundleRevision, mockSysBundle, mockStartLevel); |
| |
| try |
| { |
| dw = new DirectoryWatcher( new FileInstall(), props, mockBundleContext ); |
| fail("Expected an IllegalStateException"); |
| } |
| catch (IllegalStateException e) |
| { |
| // expected |
| } |
| } |
| finally |
| { |
| System.setProperty("java.io.tmpdir", oldTmpDir); |
| } |
| } |
| |
| /** |
| * Test the {@link DirectoryWatcher#initializeCurrentManagedBundles()} in conjunction with a non opaque Bundle Location. |
| * Assert that a new created {@link Artifact} will be added into the {@link DirectoryWatcher#currentManagedArtifacts}. |
| * |
| * The {@link DirectoryWatcher#process(java.util.Set)} execution will not be called. |
| * This test breaks the execution in {@link Scanner#initialize(java.util.Map)}. |
| * @throws URISyntaxException |
| */ |
| public void testInitializeCurrentManagedBundlesNonOpaqueURIOnBundleLocation() throws URISyntaxException |
| { |
| final RuntimeException expectedException = new RuntimeException("expected exception to break execution on defined point."); |
| final File watchedDirectoryFile = new File("src/test/resources/watched"); |
| final String watchedDirectoryPath = watchedDirectoryFile.getAbsolutePath(); |
| |
| final String bundleFileName = "firstjar.jar"; |
| final File bundleFile = new File(watchedDirectoryPath,bundleFileName); |
| final String bundleLocation = "file:"+watchedDirectoryPath+'/'+bundleFileName; |
| |
| // break execution |
| final Scanner scanner = new Scanner(watchedDirectoryFile) |
| { |
| public void initialize(Map checksums) |
| { |
| throw expectedException; |
| } |
| }; |
| |
| mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject()); |
| EasyMock.expect(mockBundleContext.getBundles()).andReturn(new Bundle[]{mockBundle}); |
| EasyMock.expect(mockBundleContext.getDataFile((String) EasyMock.anyObject())).andReturn(null).anyTimes(); |
| EasyMock.expect(mockBundle.getLocation()).andReturn(bundleLocation).anyTimes(); |
| |
| EasyMock.replay(mockBundleContext, mockBundle, mockSysBundle, mockStartLevel); |
| |
| props.put(DirectoryWatcher.DIR, watchedDirectoryPath); |
| |
| dw = new DirectoryWatcher(new FileInstall(), props, mockBundleContext); |
| dw.noInitialDelay = true; |
| dw.scanner = scanner; |
| try { |
| dw.start(); |
| } |
| catch(RuntimeException e) |
| { |
| assertEquals(e, expectedException); |
| } |
| assertEquals(1, dw.currentManagedArtifacts.size()); |
| assertTrue(dw.currentManagedArtifacts.containsKey(bundleFile)); |
| |
| EasyMock.verify(mockBundleContext, mockBundle); |
| } |
| |
| /** |
| * Test the {@link DirectoryWatcher#initializeCurrentManagedBundles()} in conjunction with a opaque Bundle Location. |
| * Assert that a new created {@link Artifact} will be added into the {@link DirectoryWatcher#currentManagedArtifacts}. |
| * |
| * The {@link DirectoryWatcher#process(java.util.Set)} execution will not be called. |
| * This test breaks the execution in {@link Scanner#initialize(java.util.Map)}. |
| * @throws URISyntaxException |
| */ |
| public void testInitializeCurrentManagedBundlesOpaqueURIOnBundleLocation() throws URISyntaxException |
| { |
| final RuntimeException expectedException = new RuntimeException("expected exception to break execution on defined point."); |
| final File watchedDirectoryFile = new File("src/test/resources/watched"); |
| final String watchedDirectoryPath = watchedDirectoryFile.getAbsolutePath(); |
| |
| final String bundleFileName = "firstjar.jar"; |
| final File bundleFile = new File(watchedDirectoryPath,bundleFileName); |
| final String bundleLocation = "blueprint:file:"+watchedDirectoryPath+'/'+bundleFileName+"$Bundle-SymbolicName=foo&Bundle-Version=1.0"; |
| |
| // break execution |
| Scanner scanner = new Scanner(watchedDirectoryFile) |
| { |
| public void initialize(Map checksums) |
| { |
| throw expectedException; |
| } |
| }; |
| |
| mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject()); |
| EasyMock.expect(mockBundleContext.getBundles()).andReturn(new Bundle[]{mockBundle}); |
| EasyMock.expect(mockBundleContext.getDataFile((String) EasyMock.anyObject())).andReturn(null).anyTimes(); |
| EasyMock.expect(mockBundle.getLocation()).andReturn(bundleLocation).anyTimes(); |
| |
| EasyMock.replay(mockBundleContext, mockBundle, mockSysBundle, mockStartLevel); |
| |
| props.put(DirectoryWatcher.DIR, watchedDirectoryPath); |
| |
| dw = new DirectoryWatcher(new FileInstall(), props, mockBundleContext); |
| dw.noInitialDelay = true; |
| dw.scanner = scanner; |
| try { |
| dw.start(); |
| } |
| catch(RuntimeException e) |
| { |
| assertEquals(e, expectedException); |
| } |
| assertEquals(1, dw.currentManagedArtifacts.size()); |
| assertTrue(dw.currentManagedArtifacts.containsKey(bundleFile)); |
| |
| EasyMock.verify(mockBundleContext, mockBundle); |
| } |
| |
| /** |
| * Test the {@link DirectoryWatcher#process(java.util.Set) } in conjunction with a opaque Bundle Location. |
| * Assert that no bundle refresh will be called. |
| * @throws URISyntaxException |
| */ |
| public void testProcessOpaqueURIOnBundleLocation() throws URISyntaxException |
| { |
| final RuntimeException expectedException = new RuntimeException("expected exception to break execution on defined point."); |
| final File watchedDirectoryFile = new File("src/test/resources/watched"); |
| final String watchedDirectoryPath = watchedDirectoryFile.getAbsolutePath(); |
| |
| final String bundleFileName = "firstjar.jar"; |
| final File bundleFile = new File(watchedDirectoryPath,bundleFileName); |
| final String bundleLocation = "blueprint:file:"+watchedDirectoryPath+'/'+bundleFileName; |
| |
| final Scanner scanner = new Scanner(watchedDirectoryFile) |
| { |
| // bypass filesystem scan and return expected bundle file |
| public Set<File> scan(boolean reportImmediately) |
| { |
| Set<File> fileSet = new HashSet<File>(1); |
| fileSet.add(bundleFile); |
| return fileSet; |
| } |
| }; |
| |
| final ArtifactListener mockArtifactListener = EasyMock.createNiceMock(ArtifactListener.class); |
| EasyMock.expect(mockArtifactListener.canHandle(bundleFile)).andReturn(Boolean.TRUE).anyTimes(); |
| final ServiceReference mockServiceReference = EasyMock.createNiceMock(ServiceReference.class); |
| |
| // simulate known/installed bundles |
| mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject()); |
| EasyMock.expect(mockBundleContext.getBundles()).andReturn(new Bundle[]{mockBundle}); |
| EasyMock.expect(mockBundleContext.getDataFile((String) EasyMock.anyObject())).andReturn(null).anyTimes(); |
| EasyMock.expect(mockBundle.getLocation()).andReturn(bundleLocation).anyTimes(); |
| |
| EasyMock.replay(mockBundleContext, mockBundle,mockServiceReference, mockArtifactListener, mockSysBundle, mockStartLevel); |
| |
| final Artifact artifact = new Artifact(); |
| artifact.setBundleId(42); |
| artifact.setChecksum(0); |
| artifact.setListener(mockArtifactListener); |
| artifact.setPath(bundleFile); |
| |
| FileInstall fileInstall = new FileInstall(); |
| fileInstall.listeners.put(mockServiceReference, mockArtifactListener); |
| |
| props.put(DirectoryWatcher.DIR, watchedDirectoryPath); |
| |
| dw = new DirectoryWatcher(fileInstall, props, mockBundleContext) { |
| |
| void refresh(Collection<Bundle> bundles) throws InterruptedException { |
| Assert.fail("bundle refresh called"); |
| } |
| |
| }; |
| dw.noInitialDelay = true; |
| // add expected bundle and artifact to the current managed artifacts |
| dw.currentManagedArtifacts.put(bundleFile, artifact); |
| dw.scanner = scanner; |
| try { |
| dw.start(); |
| } |
| catch(RuntimeException e) |
| { |
| assertEquals(e, expectedException); |
| } |
| |
| EasyMock.verify(mockBundleContext, mockBundle,mockServiceReference, mockArtifactListener); |
| } |
| |
| } |