You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2014/04/07 10:52:57 UTC

[06/13] [KARAF-2888] New FeaturesService based on the real OSGi resolver

http://git-wip-us.apache.org/repos/asf/karaf/blob/38502e41/features/core/src/test/java/org/apache/karaf/features/FeaturesServiceTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/FeaturesServiceTest.java b/features/core/src/test/java/org/apache/karaf/features/FeaturesServiceTest.java
index bce3735..db7a4fc 100644
--- a/features/core/src/test/java/org/apache/karaf/features/FeaturesServiceTest.java
+++ b/features/core/src/test/java/org/apache/karaf/features/FeaturesServiceTest.java
@@ -30,28 +30,25 @@ import static org.junit.Assert.fail;
 import java.io.File;
 import java.io.FileWriter;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.net.MalformedURLException;
 import java.net.URI;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.List;
 import java.util.concurrent.CopyOnWriteArraySet;
 
-import org.apache.karaf.features.internal.BundleManager;
-import org.apache.karaf.features.internal.BundleManager.BundleInstallerResult;
-import org.apache.karaf.features.internal.FeaturesServiceImpl;
-import org.apache.karaf.features.internal.TestBase;
+import org.apache.karaf.features.internal.service.FeaturesServiceImpl;
+import org.apache.karaf.features.internal.service.StateStorage;
 import org.easymock.EasyMock;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleException;
-import org.osgi.service.packageadmin.PackageAdmin;
 
 public class FeaturesServiceTest extends TestBase {
     private static final String FEATURE_WITH_INVALID_BUNDLE = "<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
@@ -74,6 +71,9 @@ public class FeaturesServiceTest extends TestBase {
         return tmp.toURI();
     }
 
+    /*
+       TODO: migrate those tests
+
     @Test
     public void testInstallFeature() throws Exception {
         URI uri = createTempRepo(
@@ -322,27 +322,20 @@ public class FeaturesServiceTest extends TestBase {
                 + "  <feature name='f2' version='0.2'><bundle>%s</bundle></feature>"
                 + "</features>", bundleVer01Uri, bundleVer02Uri);
         
-        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
         BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
-        Bundle bundleVer01 = createDummyBundle(12345L, "bundleVer01", headers());
-        expect(bundleManager.getDataFile(EasyMock.<String>anyObject())).andReturn(dataFile).anyTimes();
-        expect(bundleManager.installBundleIfNeeded(bundleVer01Uri, 0, null)).andReturn(new BundleInstallerResult(bundleVer01, true));
-        expect(bundleManager.installBundleIfNeeded(bundleVer01Uri, 0, null)).andReturn(new BundleInstallerResult(bundleVer01, false));
-        expect(bundleManager.getBundleContext()).andReturn(bundleContext);
-        ignoreRefreshes(bundleManager);
-        bundleManager.uninstall(Collections.EMPTY_LIST, true);
-        
-        EasyMock.expectLastCall().times(2);
+        expect(bundleContext.getBundles()).andReturn(new Bundle[0]);
+        replay(bundleContext);
 
-        replay(bundleManager);
-        FeaturesServiceImpl svc = new FeaturesServiceImpl(bundleManager);
+        FeaturesServiceImpl svc = new FeaturesServiceImpl(null, bundleContext, new Storage(), null, null, null, null);
         svc.addRepository(uri);
         svc.installFeature("f2", "0.1");
         svc.installFeature("f1", "0.1");
         svc.uninstallFeature("f1", "0.1");
         svc.uninstallFeature("f2", "0.1");
-        verify(bundleManager);
+
+        verify(bundleContext);
     }
+    */
 
     @Test
     public void testGetFeaturesShouldHandleDifferentVersionPatterns() throws Exception {
@@ -351,14 +344,9 @@ public class FeaturesServiceTest extends TestBase {
                 + "  <feature name='f2' version='0.1'><bundle>bundle1</bundle></feature>"
                 + "  <feature name='f2' version='0.2'><bundle>bundle2</bundle></feature>"
                 + "</features>");
-        
-        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
-        expect(bundleManager.getDataFile(EasyMock.<String>anyObject())).andReturn(dataFile).anyTimes();
-        
-        replay(bundleManager);
-        FeaturesServiceImpl svc = new FeaturesServiceImpl(bundleManager);
+
+        FeaturesServiceImpl svc = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, null);
         svc.addRepository(uri);
-        verify(bundleManager);
 
         assertEquals(feature("f2", "0.2"), svc.getFeature("f2", "[0.1,0.3)"));
         assertEquals(feature("f2", "0.2"), svc.getFeature("f2", "0.0.0"));
@@ -367,104 +355,17 @@ public class FeaturesServiceTest extends TestBase {
     }
 
     @Test
-    public void testInstallBatchFeatureWithContinueOnFailureNoClean() throws Exception {
-        String bundle1Uri = "bundle1";
-        String bundle2Uri = "bundle2";
-
-        URI uri = createTempRepo(FEATURE_WITH_INVALID_BUNDLE, bundle1Uri, bundle2Uri);
-        
-        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
-        Bundle installedBundle1 = createDummyBundle(12345L, "bundle1", headers());
-        Bundle installedBundle2 = createDummyBundle(54321L, "bundle2", headers());
-        expect(bundleManager.getDataFile(EasyMock.<String>anyObject())).andReturn(dataFile).anyTimes();
-        expect(bundleManager.installBundleIfNeeded(bundle1Uri, 0, null)).andReturn(new BundleInstallerResult(installedBundle1, true));
-        expect(bundleManager.installBundleIfNeeded(bundle2Uri, 0, null)).andReturn(new BundleInstallerResult(installedBundle2, true));
-        expect(bundleManager.installBundleIfNeeded("zfs:unknown", 0, null)).andThrow(new MalformedURLException());
-        EasyMock.expectLastCall();
-        ignoreRefreshes(bundleManager);
-
-        replay(bundleManager);
-        FeaturesServiceImpl svc = new FeaturesServiceImpl(bundleManager);
-        svc.addRepository(uri);
-        svc.installFeatures(new CopyOnWriteArraySet<Feature>(Arrays.asList(svc.listFeatures())),
-                            EnumSet.of(FeaturesService.Option.ContinueBatchOnFailure, FeaturesService.Option.NoCleanIfFailure));
-        verify(bundleManager);
-    }
-    
-    @Test
-    public void testInstallBatchFeatureWithContinueOnFailureClean() throws Exception {
-        String bundle1Uri = "file:bundle1";
-        String bundle2Uri = "file:bundle2";
-
-        URI uri = createTempRepo(FEATURE_WITH_INVALID_BUNDLE, bundle1Uri, bundle2Uri);
-
-        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
-        Bundle installedBundle1 = createDummyBundle(12345L, "bundle1", headers());
-        Bundle installedBundle2 = createDummyBundle(54321L, "bundle2", headers());
-        expect(bundleManager.getDataFile(EasyMock.<String>anyObject())).andReturn(dataFile).anyTimes();
-        expect(bundleManager.installBundleIfNeeded(bundle1Uri, 0, null)).andReturn(new BundleInstallerResult(installedBundle1, true));
-        expect(bundleManager.installBundleIfNeeded(bundle2Uri, 0, null)).andReturn(new BundleInstallerResult(installedBundle2, true));
-        expect(bundleManager.installBundleIfNeeded("zfs:unknown", 0, null)).andThrow(new MalformedURLException());
-        bundleManager.uninstall(setOf(installedBundle1));
-        EasyMock.expectLastCall();
-        ignoreRefreshes(bundleManager);
-
-        replay(bundleManager);
-        FeaturesServiceImpl svc = new FeaturesServiceImpl(bundleManager);
-        svc.addRepository(uri);
-        svc.installFeatures(new CopyOnWriteArraySet<Feature>(Arrays.asList(svc.listFeatures())),
-                            EnumSet.of(FeaturesService.Option.ContinueBatchOnFailure));
-        verify(bundleManager);
-    }
-
-    @Test
-    public void testInstallBatchFeatureWithoutContinueOnFailureNoClean() throws Exception {
-        String bundle1Uri = "file:bundle1";
-        String bundle2Uri = "file:bundle2";
-
-        URI uri = createTempRepo(FEATURE_WITH_INVALID_BUNDLE, bundle1Uri, bundle2Uri);
-
-        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
-        Bundle installedBundle1 = createDummyBundle(12345L, bundle1Uri, headers());
-        Bundle installedBundle2 = createDummyBundle(54321L, bundle2Uri, headers());
-        expect(bundleManager.getDataFile(EasyMock.<String>anyObject())).andReturn(dataFile).anyTimes();
-        expect(bundleManager.installBundleIfNeeded(bundle1Uri, 0, null)).andReturn(new BundleInstallerResult(installedBundle1, true));
-        expect(bundleManager.installBundleIfNeeded(bundle2Uri, 0, null)).andReturn(new BundleInstallerResult(installedBundle2, true));
-        expect(bundleManager.installBundleIfNeeded("zfs:unknown", 0, null)).andThrow(new MalformedURLException());
-        
-        replay(bundleManager);
-        FeaturesServiceImpl svc = new FeaturesServiceImpl(bundleManager);
-        svc.addRepository(uri);
-        try {
-            List<Feature> features = Arrays.asList(svc.listFeatures());
-            Collections.reverse(features);
-            svc.installFeatures(new CopyOnWriteArraySet<Feature>(features),
-                                EnumSet.of(FeaturesService.Option.NoCleanIfFailure));
-            fail("Call should have thrown an exception");
-        } catch (MalformedURLException e) {
-        }
-        verify(bundleManager);
-    }
-
-    @Test
-    public void testInstallBatchFeatureWithoutContinueOnFailureClean() throws Exception {
+    public void testInstallBatchFeatureWithFailure() throws Exception {
         String bundle1Uri = "file:bundle1";
         String bundle2Uri = "file:bundle2";
 
         URI uri = createTempRepo(FEATURE_WITH_INVALID_BUNDLE, bundle1Uri, bundle2Uri);
         
-        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
-        Bundle installedBundle1 = createDummyBundle(12345L, "bundle1", headers());
-        Bundle installedBundle2 = createDummyBundle(54321L, "bundle2", headers());
-        expect(bundleManager.getDataFile(EasyMock.<String>anyObject())).andReturn(dataFile).anyTimes();
-        expect(bundleManager.installBundleIfNeeded(bundle1Uri, 0, null)).andReturn(new BundleInstallerResult(installedBundle1, true));
-        expect(bundleManager.installBundleIfNeeded(bundle2Uri, 0, null)).andReturn(new BundleInstallerResult(installedBundle2, true));
-        expect(bundleManager.installBundleIfNeeded("zfs:unknown", 0, null)).andThrow(new MalformedURLException());
-        bundleManager.uninstall(setOf(installedBundle1, installedBundle2));
-        EasyMock.expectLastCall();
+        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
+        expect(bundleContext.getBundles()).andReturn(new Bundle[0]);
+        replay(bundleContext);
 
-        replay(bundleManager);
-        FeaturesServiceImpl svc = new FeaturesServiceImpl(bundleManager);
+        FeaturesServiceImpl svc = new FeaturesServiceImpl(null, bundleContext, new Storage(), null, null, null, null);
         svc.addRepository(uri);
         try {
             List<Feature> features = Arrays.asList(svc.listFeatures());
@@ -474,7 +375,7 @@ public class FeaturesServiceTest extends TestBase {
             fail("Call should have thrown an exception");
         } catch (MalformedURLException e) {
         }
-        verify(bundleManager);
+        verify(bundleContext);
     }
 
     /**
@@ -485,18 +386,13 @@ public class FeaturesServiceTest extends TestBase {
         URI uri = createTempRepo("<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
                 + "  <featur><bundle>somebundle</bundle></featur></features>");
 
-        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
-        expect(bundleManager.getDataFile(EasyMock.<String>anyObject())).andReturn(dataFile).anyTimes();
-
-        replay(bundleManager);
-        FeaturesServiceImpl svc = new FeaturesServiceImpl(bundleManager);
+        FeaturesServiceImpl svc = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, null);
         try {
             svc.addRepository(uri);
             fail("exception expected");
         } catch (Exception e) {
             assertTrue(e.getMessage().contains("Unable to validate"));
         }
-        verify(bundleManager);
     }
 
     /**
@@ -508,11 +404,7 @@ public class FeaturesServiceTest extends TestBase {
                 + "  <feature name='f1'><bundle>file:bundle1</bundle><bundle>file:bundle2</bundle></feature>"
                 + "</features>");
 
-        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
-        expect(bundleManager.getDataFile(EasyMock.<String>anyObject())).andReturn(dataFile).anyTimes();
-
-        replay(bundleManager);
-        FeaturesServiceImpl svc = new FeaturesServiceImpl(bundleManager);
+        FeaturesServiceImpl svc = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, null);
         svc.addRepository(uri);
         Feature feature = svc.getFeature("f1");
         Assert.assertNotNull("No feature named fi found", feature);        
@@ -520,4 +412,15 @@ public class FeaturesServiceTest extends TestBase {
         Assert.assertEquals(2, bundles.size());
     }
 
+    static class Storage extends StateStorage {
+        @Override
+        protected InputStream getInputStream() throws IOException {
+            return null;
+        }
+        @Override
+        protected OutputStream getOutputStream() throws IOException {
+            return null;
+        }
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/38502e41/features/core/src/test/java/org/apache/karaf/features/RepositoryTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/RepositoryTest.java b/features/core/src/test/java/org/apache/karaf/features/RepositoryTest.java
index cf97a20..164dc79 100644
--- a/features/core/src/test/java/org/apache/karaf/features/RepositoryTest.java
+++ b/features/core/src/test/java/org/apache/karaf/features/RepositoryTest.java
@@ -19,7 +19,9 @@ package org.apache.karaf.features;
 import java.net.URI;
 
 import junit.framework.TestCase;
-import org.apache.karaf.features.internal.RepositoryImpl;
+import org.apache.karaf.features.internal.resolver.FeatureResource;
+import org.apache.karaf.features.internal.service.RepositoryImpl;
+import org.osgi.resource.Resource;
 
 
 public class RepositoryTest extends TestCase {
@@ -107,7 +109,25 @@ public class RepositoryTest extends TestCase {
         assertEquals(true, features[2].getConfigurationFiles().get(0).isOverride());
         assertEquals("cfloc", features[2].getConfigurationFiles().get(0).getLocation());
     }
-    
+
+    public void testLoadRepoWithCapabilitiesAndRequirement() throws Exception {
+        RepositoryImpl r = new RepositoryImpl(getClass().getResource("repo3.xml").toURI());
+        // Check features
+        Feature[] features = r.getFeatures();
+        assertNotNull(features);
+        assertEquals(1, features.length);
+        assertNotNull(features[0]);
+        assertEquals("f1", features[0].getName());
+        assertEquals(1, features[0].getCapabilities().size());
+        assertEquals("cap", features[0].getCapabilities().get(0).getValue().trim());
+        assertEquals(1, features[0].getRequirements().size());
+        assertEquals("req", features[0].getRequirements().get(0).getValue().trim());
+
+        Resource res = FeatureResource.build(features[0], null, null);
+        assertEquals(1, res.getCapabilities("cap").size());
+        assertEquals(1, res.getRequirements("req").size());
+    }
+
     public void testShowWrongUriInException() throws Exception {
         String uri = "src/test/resources/org/apache/karaf/shell/features/repo1.xml";
         RepositoryImpl r = new RepositoryImpl(new URI(uri));

http://git-wip-us.apache.org/repos/asf/karaf/blob/38502e41/features/core/src/test/java/org/apache/karaf/features/TestBase.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/TestBase.java b/features/core/src/test/java/org/apache/karaf/features/TestBase.java
new file mode 100644
index 0000000..ac8f3d9
--- /dev/null
+++ b/features/core/src/test/java/org/apache/karaf/features/TestBase.java
@@ -0,0 +1,105 @@
+/*
+ * 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.karaf.features;
+
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+
+import org.easymock.EasyMock;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.startlevel.BundleStartLevel;
+
+import static java.util.Arrays.asList;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+
+public class TestBase {
+    public Bundle createDummyBundle(long id, final String symbolicName, Dictionary<String,String> headers) {
+        Bundle bundle = EasyMock.createNiceMock(Bundle.class);
+        
+        // Be aware that this means all bundles are treated as different
+        expect(bundle.compareTo(EasyMock.<Bundle>anyObject())).andReturn(1).anyTimes();
+
+        expect(bundle.getBundleId()).andReturn(id).anyTimes();
+        expect(bundle.getSymbolicName()).andReturn(symbolicName).anyTimes();
+        expect(bundle.getHeaders()).andReturn(headers).anyTimes();
+        BundleStartLevel sl = EasyMock.createMock(BundleStartLevel.class);
+        expect(sl.isPersistentlyStarted()).andReturn(true).anyTimes();
+        expect(bundle.adapt(BundleStartLevel.class)).andReturn(sl).anyTimes();
+        replay(bundle, sl);
+        return bundle;
+    }
+    
+    public Dictionary<String, String> headers(String ... keyAndHeader) {
+        Hashtable<String, String> headersTable = new Hashtable<String, String>();
+        int c=0;
+        while (c < keyAndHeader.length) {
+            String key = keyAndHeader[c++];
+            String value = keyAndHeader[c++];
+            headersTable.put(key, value);
+        }
+        return headersTable;
+    }
+    
+    public Map<String, Map<String, Feature>> features(Feature ... features) {
+        final Map<String, Map<String, Feature>> featuresMap = new HashMap<String, Map<String,Feature>>();
+        for (Feature feature : features) {
+            Map<String, Feature> featureVersion = getOrCreate(featuresMap, feature);
+            featureVersion.put(feature.getVersion(), feature);
+        }
+        return featuresMap;
+    }
+    
+    private Map<String, Feature> getOrCreate(final Map<String, Map<String, Feature>> featuresMap, Feature feature) {
+        Map<String, Feature> featureVersion = featuresMap.get(feature.getName());
+        if (featureVersion == null) {
+            featureVersion = new HashMap<String, Feature>();
+            featuresMap.put(feature.getName(), featureVersion);
+        }
+        return featureVersion;
+    }
+
+    public Feature feature(String name) {
+        return feature(name, null);
+    }
+
+    public Feature feature(String name, String version) {
+        return new org.apache.karaf.features.internal.model.Feature(name, version);
+    }
+    
+    public Set<Bundle> setOf(Bundle ... elements) {
+        return new HashSet<Bundle>(Arrays.asList(elements));
+    }
+    
+    public Set<Long> setOf(Long ... elements) {
+        return new HashSet<Long>(Arrays.asList(elements));
+    }
+    
+    public Set<String> setOf(String ... elements) {
+        return new HashSet<String>(asList(elements));
+    }
+    
+    public Set<Feature> setOf(Feature ... elements) {
+        return new HashSet<Feature>(Arrays.asList(elements));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/38502e41/features/core/src/test/java/org/apache/karaf/features/internal/BootFeaturesInstallerTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/BootFeaturesInstallerTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/BootFeaturesInstallerTest.java
deleted file mode 100644
index b59806d..0000000
--- a/features/core/src/test/java/org/apache/karaf/features/internal/BootFeaturesInstallerTest.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * 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.karaf.features.internal;
-
-import static java.util.Arrays.asList;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-
-import java.util.EnumSet;
-
-import org.apache.karaf.features.Feature;
-import org.apache.karaf.features.FeaturesService.Option;
-import org.easymock.EasyMock;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class BootFeaturesInstallerTest extends TestBase {
-
-    @Test
-    @SuppressWarnings("unchecked")
-    public void testParser() {
-        BootFeaturesInstaller installer = new BootFeaturesInstaller(null, null, "", false);
-        Assert.assertEquals(asList(setOf("test1", "test2"),setOf("test3")), installer.parseBootFeatures("(test1, test2), test3"));
-        Assert.assertEquals(asList(setOf("test1", "test2", "test3")), installer.parseBootFeatures("test1, test2, test3"));
-    }
-    
-    @Test
-    public void testDefaultBootFeatures() throws Exception  {
-        FeaturesServiceImpl impl = EasyMock.createMock(FeaturesServiceImpl.class);
-        Feature configFeature = feature("config", "1.0.0");
-        Feature standardFeature = feature("standard", "1.0.0");
-        Feature regionFeature = feature("region", "1.0.0");
-        expect(impl.listInstalledFeatures()).andStubReturn(new Feature[]{});
-        expect(impl.getFeature("config", "0.0.0")).andReturn(configFeature);
-        expect(impl.getFeature("standard", "0.0.0")).andReturn(standardFeature);
-        expect(impl.getFeature("region", "0.0.0")).andReturn(regionFeature);
-
-        impl.installFeatures(setOf(configFeature, standardFeature, regionFeature), EnumSet.of(Option.NoCleanIfFailure, Option.ContinueBatchOnFailure));
-        EasyMock.expectLastCall();
-        
-        replay(impl);
-        BootFeaturesInstaller bootFeatures = new BootFeaturesInstaller(null, impl, "config,standard,region", false);
-        bootFeatures.installBootFeatures();
-        EasyMock.verify(impl);        
-    }
-
-    /**
-     * This test checks KARAF-388 which allows you to specify version of boot feature.
-     * @throws Exception 
-     */
-    @Test
-    public void testStartDoesNotFailWithNonExistentVersion() throws Exception  {
-        FeaturesServiceImpl impl = EasyMock.createMock(FeaturesServiceImpl.class);
-        expect(impl.listInstalledFeatures()).andReturn(new Feature[]{});
-        EasyMock.expectLastCall();
-        Feature sshFeature = feature("ssh", "1.0.0");
-        expect(impl.getFeature("ssh", "1.0.0")).andReturn(sshFeature);
-        expect(impl.getFeature("transaction", "1.2")).andReturn(null);
-        
-        // Only the ssh feature should get installed
-        impl.installFeatures(setOf(sshFeature), EnumSet.of(Option.NoCleanIfFailure, Option.ContinueBatchOnFailure));
-        EasyMock.expectLastCall();
-        
-        replay(impl);
-        BootFeaturesInstaller bootFeatures = new BootFeaturesInstaller(null, impl , "transaction;version=1.2,ssh;version=1.0.0", false);
-        bootFeatures.installBootFeatures();
-        EasyMock.verify(impl);        
-    }
-    
-    @Test
-    public void testStagedBoot() throws Exception  {
-        FeaturesServiceImpl impl = EasyMock.createStrictMock(FeaturesServiceImpl.class);
-        Feature sshFeature = feature("ssh", "1.0.0");
-        Feature transactionFeature = feature("transaction", "2.0.0");
-        expect(impl.listInstalledFeatures()).andStubReturn(new Feature[]{});
-        expect(impl.getFeature("transaction", "0.0.0")).andStubReturn(transactionFeature);
-        expect(impl.getFeature("ssh", "0.0.0")).andStubReturn(sshFeature);
-
-        impl.installFeatures(setOf(transactionFeature), EnumSet.of(Option.NoCleanIfFailure, Option.ContinueBatchOnFailure));
-        EasyMock.expectLastCall();
-        impl.installFeatures(setOf(sshFeature), EnumSet.of(Option.NoCleanIfFailure, Option.ContinueBatchOnFailure));
-        EasyMock.expectLastCall();
-        
-        replay(impl);
-        BootFeaturesInstaller bootFeatures = new BootFeaturesInstaller(null, impl , "(transaction), ssh", false);
-        bootFeatures.installBootFeatures();
-        EasyMock.verify(impl);        
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/38502e41/features/core/src/test/java/org/apache/karaf/features/internal/BundleManagerTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/BundleManagerTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/BundleManagerTest.java
deleted file mode 100644
index 0a7c6fe..0000000
--- a/features/core/src/test/java/org/apache/karaf/features/internal/BundleManagerTest.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.karaf.features.internal;
-
-import static org.easymock.EasyMock.replay;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-import junit.framework.Assert;
-
-import org.easymock.EasyMock;
-import org.junit.Test;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-
-public class BundleManagerTest extends TestBase {
-    
-    @Test
-    public void testfindBundlestoRefreshWithHostToRefresh() throws Exception {
-        Bundle hostBundle = createDummyBundle(12345l, "Host", headers());
-        Bundle fragmentBundle = createDummyBundle(54321l, "fragment", headers(Constants.FRAGMENT_HOST, "Host"));
-
-        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
-        BundleManager bundleManager = new BundleManager(bundleContext);
-
-        // Host was already installed, fragment is new
-        Set<Bundle> existing = new HashSet<Bundle>(Arrays.asList(hostBundle, fragmentBundle));
-        Set<Bundle> installed = new HashSet<Bundle>(Arrays.asList(fragmentBundle));
-        
-        replay(bundleContext);
-        Set<Bundle> bundles = bundleManager.findBundlesWithFragmentsToRefresh(existing, installed);
-        EasyMock.verify(bundleContext);
-
-        Assert.assertEquals(1, bundles.size());
-        Assert.assertEquals(hostBundle, bundles.iterator().next());
-    }
-    
-    @Test
-    public void testfindBundlestoRefreshWithOptionalPackages() throws Exception {
-        Bundle exporterBundle = createDummyBundle(12345l, "exporter", headers(Constants.EXPORT_PACKAGE, "org.my.package"));
-        Bundle importerBundle = createDummyBundle(54321l, "importer", headers(Constants.IMPORT_PACKAGE, "org.my.package;resolution:=optional"));
-
-        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
-        BundleManager bundleManager = new BundleManager(bundleContext);
-
-        // Importer was already installed, exporter is new
-        Set<Bundle> existing = new HashSet<Bundle>(Arrays.asList(importerBundle, exporterBundle));
-        Set<Bundle> installed = new HashSet<Bundle>(Arrays.asList(exporterBundle));
-        
-        replay(bundleContext);
-        Set<Bundle> bundles = bundleManager.findBundlesWithOptionalPackagesToRefresh(existing, installed);
-        EasyMock.verify(bundleContext);
-
-        Assert.assertEquals(1, bundles.size());
-        Assert.assertEquals(importerBundle, bundles.iterator().next());
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/38502e41/features/core/src/test/java/org/apache/karaf/features/internal/FeaturesServiceImplTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/FeaturesServiceImplTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/FeaturesServiceImplTest.java
deleted file mode 100644
index 4776bf4..0000000
--- a/features/core/src/test/java/org/apache/karaf/features/internal/FeaturesServiceImplTest.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * 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.karaf.features.internal;
-
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.fail;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.EnumSet;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.felix.utils.manifest.Clause;
-import org.apache.karaf.features.Feature;
-import org.apache.karaf.features.internal.BundleManager.BundleInstallerResult;
-import org.easymock.EasyMock;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * Test cases for {@link FeaturesServiceImpl}
- */
-public class FeaturesServiceImplTest extends TestBase {
-    
-    File dataFile;
-
-    @Before
-    public void setUp() throws IOException {
-        dataFile = File.createTempFile("features", null, null);
-    }
-
-    @Test
-    public void testGetFeature() throws Exception {
-        Feature transactionFeature = feature("transaction", "1.0.0");
-        final Map<String, Map<String, Feature>> features = features(transactionFeature);
-        final FeaturesServiceImpl impl = new FeaturesServiceImpl(null, null) {
-            protected Map<String,Map<String,Feature>> getFeatures() throws Exception {
-                return features;
-            };
-        };
-        assertNotNull(impl.getFeature("transaction", org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION));
-        assertSame(transactionFeature, impl.getFeature("transaction", org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION));
-    }
-    
-    @Test
-    public void testGetFeatureStripVersion() throws Exception {
-        final FeaturesServiceImpl impl = new FeaturesServiceImpl(null, null) {
-            protected Map<String,Map<String,Feature>> getFeatures() throws Exception {
-                return features(feature("transaction", "1.0.0"));
-            };
-        };
-        Feature feature = impl.getFeature("transaction", "  1.0.0  ");
-        assertNotNull(feature);
-        assertSame("transaction", feature.getName());
-    }
-    
-    @Test
-    public void testGetFeatureNotAvailable() throws Exception {
-        final FeaturesServiceImpl impl = new FeaturesServiceImpl(null, null) {
-            protected Map<String,Map<String,Feature>> getFeatures() throws Exception {
-                return features(feature("transaction", "1.0.0"));
-            };
-        };
-        assertNull(impl.getFeature("activemq", org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION));
-    }
-    
-    @Test
-    public void testGetFeatureHighestAvailable() throws Exception {
-        final Map<String, Map<String, Feature>> features = features(
-                feature("transaction", "1.0.0"),
-                feature("transaction", "2.0.0")
-        );
-        final FeaturesServiceImpl impl = new FeaturesServiceImpl(null, null) {
-            protected Map<String,Map<String,Feature>> getFeatures() throws Exception {
-                return features;
-            };
-        };
-        assertNotNull(impl.getFeature("transaction", org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION));
-        assertSame("2.0.0", impl.getFeature("transaction", org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION).getVersion());
-    }
-
-    @Test
-    public void testStartDoesNotFailWithOneInvalidUri()  {
-        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
-        expect(bundleManager.getDataFile(EasyMock.<String>anyObject())).andReturn(dataFile).anyTimes();
-        expect(bundleManager.createAndRegisterEventAdminListener()).andReturn(null);
-        replay(bundleManager);
-        FeaturesServiceImpl service = new FeaturesServiceImpl(bundleManager, null);
-        try {
-            service.setUrls("mvn:inexistent/features/1.0/xml/features");
-            service.start();
-        } catch (Exception e) {
-            fail(String.format("Service should not throw start-up exception but log the error instead: %s", e));
-        }
-    }
-
-
-    
-    /**
-     * This test ensures that every feature get installed only once, even if it appears multiple times in the list
-     * of transitive feature dependencies (KARAF-1600)
-     */
-    @Test
-    @SuppressWarnings("unchecked")
-    public void testNoDuplicateFeaturesInstallation() throws Exception {
-        final List<Feature> installed = new LinkedList<Feature>();
-        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
-        expect(bundleManager.installBundleIfNeeded(EasyMock.anyObject(String.class), EasyMock.anyInt(), EasyMock.anyObject(String.class)))
-            .andReturn(new BundleInstallerResult(createDummyBundle(1l, "", headers()), true)).anyTimes();
-        bundleManager.refreshBundles(EasyMock.anyObject(Set.class), EasyMock.anyObject(Set.class), EasyMock.anyObject(EnumSet.class));
-        EasyMock.expectLastCall();
-        final FeaturesServiceImpl impl = new FeaturesServiceImpl(bundleManager, null) {
-            // override methods which refers to bundle context to avoid mocking everything
-            @Override
-            protected boolean loadState() {
-                return true;
-            }
-
-            @Override
-            protected void saveState() {
-
-            }
-
-            @Override
-            protected void doInstallFeature(InstallationState state, Feature feature, boolean verbose) throws Exception {
-                installed.add(feature);
-
-                super.doInstallFeature(state, feature, verbose);
-            }
-
-        };
-        replay(bundleManager);
-        impl.addRepository(getClass().getResource("repo2.xml").toURI());
-        impl.installFeature("all");
-
-        // copying the features to a set to filter out the duplicates
-        Set<Feature> noduplicates = new HashSet<Feature>();
-        noduplicates.addAll(installed);
-
-        assertEquals("Every feature should only have been installed once", installed.size(), noduplicates.size());
-    }
-
-    @Test
-    public void testGetOptionalImportsOnly() {
-        BundleManager bundleManager = new BundleManager(null, 0l);
-
-        List<Clause> result = bundleManager.getOptionalImports("org.apache.karaf,org.apache.karaf.optional;resolution:=optional");
-        assertEquals("One optional import expected", 1, result.size());
-        assertEquals("org.apache.karaf.optional", result.get(0).getName());
-
-        result = bundleManager.getOptionalImports(null);
-        assertNotNull(result);
-        assertEquals("No optional imports expected", 0, result.size());
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/38502e41/features/core/src/test/java/org/apache/karaf/features/internal/FeaturesValidationTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/FeaturesValidationTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/FeaturesValidationTest.java
deleted file mode 100644
index 09f9c62..0000000
--- a/features/core/src/test/java/org/apache/karaf/features/internal/FeaturesValidationTest.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.karaf.features.internal;
-
-import org.junit.Test;
-
-import static org.junit.Assert.fail;
-
-public class FeaturesValidationTest {
-
-    @Test
-    public void testNoNs() throws Exception {
-        FeatureValidationUtil.validate(getClass().getResource("f01.xml").toURI());
-    }
-
-    @Test
-    public void testNs10() throws Exception {
-        FeatureValidationUtil.validate(getClass().getResource("f02.xml").toURI());
-    }
-
-    @Test
-    public void testNs10NoName() throws Exception {
-        FeatureValidationUtil.validate(getClass().getResource("f03.xml").toURI());
-    }
-
-    @Test
-    public void testNs11() throws Exception {
-        FeatureValidationUtil.validate(getClass().getResource("f04.xml").toURI());
-    }
-
-    @Test
-    public void testNs12() throws Exception {
-        FeatureValidationUtil.validate(getClass().getResource("f06.xml").toURI());
-    }
-
-    @Test
-    public void testNs13() throws Exception {
-        try {
-            FeatureValidationUtil.validate(getClass().getResource("f05.xml").toURI());
-            fail("Validation should have failed");
-        } catch (Exception e) {
-            // ok
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/38502e41/features/core/src/test/java/org/apache/karaf/features/internal/OverridesTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/OverridesTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/OverridesTest.java
deleted file mode 100644
index 99feb32..0000000
--- a/features/core/src/test/java/org/apache/karaf/features/internal/OverridesTest.java
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * 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.karaf.features.internal;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.Writer;
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.felix.utils.manifest.Clause;
-import org.apache.karaf.features.BundleInfo;
-import org.apache.karaf.features.internal.model.Bundle;
-import org.junit.Before;
-import org.junit.Test;
-import org.ops4j.pax.tinybundles.core.TinyBundles;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-public class OverridesTest {
-
-    private String bsn = "bsn";
-    private File b100;
-    private File b101;
-    private File b102;
-    private File b110;
-    private File c100;
-    private File c101;
-    private File c110;
-
-    @Before
-    public void setUp() throws IOException {
-        b100 = File.createTempFile("karaf", "-100.jar");
-        copy(TinyBundles.bundle()
-                .set("Bundle-SymbolicName", bsn)
-                .set("Bundle-Version", "1.0.0")
-                .build(),
-                new FileOutputStream(b100));
-
-        b101 = File.createTempFile("karaf", "-101.jar");
-        copy(TinyBundles.bundle()
-                .set("Bundle-SymbolicName", bsn)
-                .set("Bundle-Version", "1.0.1")
-                .build(),
-                new FileOutputStream(b101));
-
-        b102 = File.createTempFile("karaf", "-102.jar");
-        copy(TinyBundles.bundle()
-                .set("Bundle-SymbolicName", bsn)
-                .set("Bundle-Version", "1.0.2")
-                .build(),
-                new FileOutputStream(b102));
-
-        b110 = File.createTempFile("karaf", "-110.jar");
-        copy(TinyBundles.bundle()
-                .set("Bundle-SymbolicName", bsn)
-                .set("Bundle-Version", "1.1.0")
-                .build(),
-                new FileOutputStream(b110));
-
-        c100 = File.createTempFile("karafc", "-100.jar");
-        copy(TinyBundles.bundle()
-                .set("Bundle-SymbolicName", bsn)
-                .set("Bundle-Version", "1.0.0")
-                .set("Bundle-Vendor", "Apache")
-                .build(),
-                new FileOutputStream(c100));
-
-        c101 = File.createTempFile("karafc", "-101.jar");
-        copy(TinyBundles.bundle()
-                .set("Bundle-SymbolicName", bsn)
-                .set("Bundle-Version", "1.0.1")
-                .set("Bundle-Vendor", "NotApache")
-                .build(),
-                new FileOutputStream(c101)); 
-
-        c110 = File.createTempFile("karafc", "-110.jar");
-        copy(TinyBundles.bundle()
-                .set("Bundle-SymbolicName", bsn)
-                .set("Bundle-Version", "1.1.0")
-                .set("Bundle-Vendor", "NotApache")
-                .build(),
-                new FileOutputStream(c110));
-    }
-
-    @Test
-    public void testDifferentVendors() throws IOException {
-        File props = File.createTempFile("karaf", "properties");
-        Writer w = new FileWriter(props);
-        w.write(c101.toURI().toString());
-        w.write("\n");
-        w.write(c110.toURI().toString());
-        w.write("\n");
-        w.close();
-
-        List<BundleInfo> res = Overrides.override(
-                Arrays.<BundleInfo>asList(new Bundle(c100.toURI().toString())),
-                props.toURI().toString());
-        assertNotNull(res);
-        assertEquals(1, res.size());
-        BundleInfo out = res.get(0);
-        assertNotNull(out);
-        assertEquals(c101.toURI().toString(), out.getLocation());
-    }
-
-    @Test
-    public void testMatching101() throws IOException {
-        File props = File.createTempFile("karaf", "properties");
-        Writer w = new FileWriter(props);
-        w.write(b101.toURI().toString());
-        w.write("\n");
-        w.write(b110.toURI().toString());
-        w.write("\n");
-        w.close();
-
-        List<BundleInfo> res = Overrides.override(
-                Arrays.<BundleInfo>asList(new Bundle(b100.toURI().toString())),
-                props.toURI().toString());
-        assertNotNull(res);
-        assertEquals(1, res.size());
-        BundleInfo out = res.get(0);
-        assertNotNull(out);
-        assertEquals(b101.toURI().toString(), out.getLocation());
-    }
-
-    @Test
-    public void testMatching102() throws IOException {
-        File props = File.createTempFile("karaf", "properties");
-        Writer w = new FileWriter(props);
-        w.write(b101.toURI().toString());
-        w.write("\n");
-        w.write(b102.toURI().toString());
-        w.write("\n");
-        w.write(b110.toURI().toString());
-        w.write("\n");
-        w.close();
-
-        List<BundleInfo> res = Overrides.override(
-                Arrays.<BundleInfo>asList(new Bundle(b100.toURI().toString())),
-                props.toURI().toString());
-        assertNotNull(res);
-        assertEquals(1, res.size());
-        BundleInfo out = res.get(0);
-        assertNotNull(out);
-        assertEquals(b102.toURI().toString(), out.getLocation());
-    }
-
-    @Test
-    public void testMatchingRange() throws IOException {
-        File props = File.createTempFile("karaf", "properties");
-        Writer w = new FileWriter(props);
-        w.write(b101.toURI().toString());
-        w.write("\n");
-        w.write(b110.toURI().toString());
-        w.write(";range=\"[1.0, 2.0)\"\n");
-        w.close();
-
-        List<BundleInfo> res = Overrides.override(
-                Arrays.<BundleInfo>asList(new Bundle(b100.toURI().toString())),
-                props.toURI().toString());
-        assertNotNull(res);
-        assertEquals(1, res.size());
-        BundleInfo out = res.get(0);
-        assertNotNull(out);
-        assertEquals(b110.toURI().toString(), out.getLocation());
-    }
-
-    @Test
-    public void testNotMatching() throws IOException {
-        File props = File.createTempFile("karaf", "properties");
-        Writer w = new FileWriter(props);
-        w.write(b110.toURI().toString());
-        w.write("\n");
-        w.close();
-
-        List<BundleInfo> res = Overrides.override(
-                Arrays.<BundleInfo>asList(new Bundle(b100.toURI().toString())),
-                props.toURI().toString());
-        assertNotNull(res);
-        assertEquals(1, res.size());
-        BundleInfo out = res.get(0);
-        assertNotNull(out);
-        assertEquals(b100.toURI().toString(), out.getLocation());
-    }
-
-    @Test
-    public void testLoadOverrides() {
-        List<Clause> overrides = Overrides.loadOverrides(getClass().getResource("overrides.properties").toExternalForm());
-        assertEquals(2, overrides.size());
-
-        Clause karafAdminCommand = null;
-        Clause karafAdminCore = null;
-        for (Clause clause : overrides) {
-            if (clause.getName().equals("mvn:org.apache.karaf.admin/org.apache.karaf.admin.command/2.3.0.redhat-61033X")) {
-                karafAdminCommand = clause;
-            }
-            if (clause.getName().equals("mvn:org.apache.karaf.admin/org.apache.karaf.admin.core/2.3.0.redhat-61033X")) {
-                karafAdminCore = clause;
-            }
-        }
-        assertNotNull("Missing admin.command bundle override", karafAdminCommand);
-        assertNotNull("Missing admin.core bundle override", karafAdminCore);
-        assertNotNull("Missing range on admin.core override", karafAdminCore.getAttribute(Overrides.OVERRIDE_RANGE));
-    }
-
-    /**
-     * Copies the content of {@link java.io.InputStream} to {@link java.io.OutputStream}.
-     *
-     * @param input
-     * @param output
-     * @throws java.io.IOException
-     */
-    private void copy(final InputStream input, final OutputStream output) throws IOException {
-        byte[] buffer = new byte[1024 * 16];
-        int n;
-        while (-1 != (n = input.read(buffer))) {
-            output.write(buffer, 0, n);
-            output.flush();
-        }
-        input.close();
-        output.close();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/38502e41/features/core/src/test/java/org/apache/karaf/features/internal/TestBase.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/TestBase.java b/features/core/src/test/java/org/apache/karaf/features/internal/TestBase.java
deleted file mode 100644
index e651a6c..0000000
--- a/features/core/src/test/java/org/apache/karaf/features/internal/TestBase.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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.karaf.features.internal;
-
-import static java.util.Arrays.asList;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-
-import java.util.Arrays;
-import java.util.Dictionary;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.karaf.features.Feature;
-import org.easymock.EasyMock;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.startlevel.BundleStartLevel;
-
-public class TestBase {
-    public Bundle createDummyBundle(long id, final String symbolicName, Dictionary<String,String> headers) {
-        Bundle bundle = EasyMock.createNiceMock(Bundle.class);
-        
-        // Be aware that this means all bundles are treated as different
-        expect(bundle.compareTo(EasyMock.<Bundle>anyObject())).andReturn(1).anyTimes();
-
-        expect(bundle.getBundleId()).andReturn(id).anyTimes();
-        expect(bundle.getSymbolicName()).andReturn(symbolicName).anyTimes();
-        expect(bundle.getHeaders()).andReturn(headers).anyTimes();
-        BundleStartLevel sl = EasyMock.createMock(BundleStartLevel.class);
-        expect(sl.isPersistentlyStarted()).andReturn(true).anyTimes();
-        expect(bundle.adapt(BundleStartLevel.class)).andReturn(sl).anyTimes();
-        replay(bundle, sl);
-        return bundle;
-    }
-    
-    public Dictionary<String, String> headers(String ... keyAndHeader) {
-        Hashtable<String, String> headersTable = new Hashtable<String, String>();
-        int c=0;
-        while (c < keyAndHeader.length) {
-            String key = keyAndHeader[c++];
-            String value = keyAndHeader[c++];
-            headersTable.put(key, value);
-        }
-        return headersTable;
-    }
-    
-    public Map<String, Map<String, Feature>> features(Feature ... features) {
-        final Map<String, Map<String, Feature>> featuresMap = new HashMap<String, Map<String,Feature>>();
-        for (Feature feature : features) {
-            Map<String, Feature> featureVersion = getOrCreate(featuresMap, feature);
-            featureVersion.put(feature.getVersion(), feature);
-        }
-        return featuresMap;
-    }
-    
-    private Map<String, Feature> getOrCreate(final Map<String, Map<String, Feature>> featuresMap, Feature feature) {
-        Map<String, Feature> featureVersion = featuresMap.get(feature.getName());
-        if (featureVersion == null) {
-            featureVersion = new HashMap<String, Feature>();
-            featuresMap.put(feature.getName(), featureVersion);
-        }
-        return featureVersion;
-    }
-
-    public Feature feature(String name, String version) {
-        return new org.apache.karaf.features.internal.model.Feature(name, version);
-    }
-    
-    public Set<Bundle> setOf(Bundle ... elements) {
-        return new HashSet<Bundle>(Arrays.asList(elements));
-    }
-    
-    public Set<Long> setOf(Long ... elements) {
-        return new HashSet<Long>(Arrays.asList(elements));
-    }
-    
-    public Set<String> setOf(String ... elements) {
-        return new HashSet<String>(asList(elements));
-    }
-    
-    public Set<Feature> setOf(Feature ... elements) {
-        return new HashSet<Feature>(Arrays.asList(elements));
-    }
-
-    @SuppressWarnings("unchecked")
-    public void ignoreRefreshes(BundleManager bundleManager) {
-        bundleManager.refreshBundles(EasyMock.anyObject(Set.class), EasyMock.anyObject(Set.class), EasyMock.anyObject(EnumSet.class));        
-        EasyMock.expectLastCall().anyTimes();
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/38502e41/features/core/src/test/java/org/apache/karaf/features/internal/service/BootFeaturesInstallerTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/service/BootFeaturesInstallerTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/service/BootFeaturesInstallerTest.java
new file mode 100644
index 0000000..ab11b6b
--- /dev/null
+++ b/features/core/src/test/java/org/apache/karaf/features/internal/service/BootFeaturesInstallerTest.java
@@ -0,0 +1,128 @@
+/*
+ * 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.karaf.features.internal.service;
+
+import static java.util.Arrays.asList;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.junit.Assert.fail;
+
+import java.net.URI;
+import java.util.EnumSet;
+
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.FeaturesService.Option;
+import org.apache.karaf.features.TestBase;
+import org.easymock.EasyMock;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class BootFeaturesInstallerTest extends TestBase {
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testParser() {
+        BootFeaturesInstaller installer = new BootFeaturesInstaller(null, null, "", "", false);
+        Assert.assertEquals(asList(setOf("test1", "test2"),setOf("test3")), installer.parseBootFeatures("(test1, test2), test3"));
+        Assert.assertEquals(asList(setOf("test1", "test2", "test3")), installer.parseBootFeatures("test1, test2, test3"));
+    }
+    
+    @Test
+    public void testDefaultBootFeatures() throws Exception  {
+        FeaturesServiceImpl impl = EasyMock.createMock(FeaturesServiceImpl.class);
+        Feature configFeature = feature("config", "1.0.0");
+        Feature standardFeature = feature("standard", "1.0.0");
+        Feature regionFeature = feature("region", "1.0.0");
+        expect(impl.listInstalledFeatures()).andStubReturn(new Feature[]{});
+        expect(impl.getFeature("config", "0.0.0")).andReturn(configFeature);
+        expect(impl.getFeature("standard", "0.0.0")).andReturn(standardFeature);
+        expect(impl.getFeature("region", "0.0.0")).andReturn(regionFeature);
+
+        impl.installFeatures(setOf(configFeature, standardFeature, regionFeature), EnumSet.of(Option.NoCleanIfFailure, Option.ContinueBatchOnFailure));
+        EasyMock.expectLastCall();
+
+        impl.bootDone();
+        EasyMock.expectLastCall();
+
+        replay(impl);
+        BootFeaturesInstaller bootFeatures = new BootFeaturesInstaller(null, impl, "", "config,standard,region", false);
+        bootFeatures.installBootFeatures();
+        EasyMock.verify(impl);        
+    }
+
+    /**
+     * This test checks KARAF-388 which allows you to specify version of boot feature.
+     * @throws Exception 
+     */
+    @Test
+    public void testStartDoesNotFailWithNonExistentVersion() throws Exception  {
+        FeaturesServiceImpl impl = EasyMock.createMock(FeaturesServiceImpl.class);
+        Feature sshFeature = feature("ssh", "1.0.0");
+        expect(impl.getFeature("ssh", "1.0.0")).andReturn(sshFeature);
+        expect(impl.getFeature("transaction", "1.2")).andReturn(null);
+        
+        // Only the ssh feature should get installed
+        impl.installFeatures(setOf(sshFeature), EnumSet.of(Option.NoCleanIfFailure, Option.ContinueBatchOnFailure));
+        EasyMock.expectLastCall();
+
+        impl.bootDone();
+        EasyMock.expectLastCall();
+        
+        replay(impl);
+        BootFeaturesInstaller bootFeatures = new BootFeaturesInstaller(null, impl , "", "transaction;version=1.2,ssh;version=1.0.0", false);
+        bootFeatures.installBootFeatures();
+        EasyMock.verify(impl);        
+    }
+    
+    @Test
+    public void testStagedBoot() throws Exception  {
+        FeaturesServiceImpl impl = EasyMock.createStrictMock(FeaturesServiceImpl.class);
+        Feature sshFeature = feature("ssh", "1.0.0");
+        Feature transactionFeature = feature("transaction", "2.0.0");
+        expect(impl.getFeature("transaction", "0.0.0")).andStubReturn(transactionFeature);
+        expect(impl.getFeature("ssh", "0.0.0")).andStubReturn(sshFeature);
+
+        impl.installFeatures(setOf(transactionFeature), EnumSet.of(Option.NoCleanIfFailure, Option.ContinueBatchOnFailure));
+        EasyMock.expectLastCall();
+        impl.installFeatures(setOf(sshFeature), EnumSet.of(Option.NoCleanIfFailure, Option.ContinueBatchOnFailure));
+        EasyMock.expectLastCall();
+
+        impl.bootDone();
+        EasyMock.expectLastCall();
+
+        replay(impl);
+        BootFeaturesInstaller bootFeatures = new BootFeaturesInstaller(null, impl , "", "(transaction), ssh", false);
+        bootFeatures.installBootFeatures();
+        EasyMock.verify(impl);        
+    }
+
+    @Test
+    public void testStartDoesNotFailWithOneInvalidUri() throws Exception {
+        FeaturesServiceImpl impl = EasyMock.createStrictMock(FeaturesServiceImpl.class);
+        impl.addRepository(URI.create("mvn:inexistent/features/1.0/xml/features"));
+        EasyMock.expectLastCall().andThrow(new IllegalArgumentException());
+
+        impl.bootDone();
+        EasyMock.expectLastCall();
+
+        replay(impl);
+        BootFeaturesInstaller bootFeatures = new BootFeaturesInstaller(null, impl, "mvn:inexistent/features/1.0/xml/features", "", false);
+        bootFeatures.installBootFeatures();
+        EasyMock.verify(impl);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/38502e41/features/core/src/test/java/org/apache/karaf/features/internal/service/BundleManagerTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/service/BundleManagerTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/service/BundleManagerTest.java
new file mode 100644
index 0000000..bed8104
--- /dev/null
+++ b/features/core/src/test/java/org/apache/karaf/features/internal/service/BundleManagerTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.karaf.features.internal.service;
+
+import org.apache.karaf.features.TestBase;
+
+public class BundleManagerTest extends TestBase {
+
+    /*
+    @Test
+    public void testfindBundlestoRefreshWithHostToRefresh() throws Exception {
+        Bundle hostBundle = createDummyBundle(12345l, "Host", headers());
+        Bundle fragmentBundle = createDummyBundle(54321l, "fragment", headers(Constants.FRAGMENT_HOST, "Host"));
+
+        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
+        BundleManager bundleManager = new BundleManager(bundleContext);
+
+        // Host was already installed, fragment is new
+        Set<Bundle> existing = new HashSet<Bundle>(Arrays.asList(hostBundle, fragmentBundle));
+        Set<Bundle> installed = new HashSet<Bundle>(Arrays.asList(fragmentBundle));
+        
+        replay(bundleContext);
+        Set<Bundle> bundles = bundleManager.findBundlesWithFragmentsToRefresh(existing, installed);
+        EasyMock.verify(bundleContext);
+
+        Assert.assertEquals(1, bundles.size());
+        Assert.assertEquals(hostBundle, bundles.iterator().next());
+    }
+    
+    @Test
+    public void testfindBundlestoRefreshWithOptionalPackages() throws Exception {
+        Bundle exporterBundle = createDummyBundle(12345l, "exporter", headers(Constants.EXPORT_PACKAGE, "org.my.package"));
+        Bundle importerBundle = createDummyBundle(54321l, "importer", headers(Constants.IMPORT_PACKAGE, "org.my.package;resolution:=optional"));
+
+        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
+        BundleManager bundleManager = new BundleManager(bundleContext);
+
+        // Importer was already installed, exporter is new
+        Set<Bundle> existing = new HashSet<Bundle>(Arrays.asList(importerBundle, exporterBundle));
+        Set<Bundle> installed = new HashSet<Bundle>(Arrays.asList(exporterBundle));
+        
+        replay(bundleContext);
+        Set<Bundle> bundles = bundleManager.findBundlesWithOptionalPackagesToRefresh(existing, installed);
+        EasyMock.verify(bundleContext);
+
+        Assert.assertEquals(1, bundles.size());
+        Assert.assertEquals(importerBundle, bundles.iterator().next());
+    }
+    */
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/38502e41/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesServiceImplTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesServiceImplTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesServiceImplTest.java
new file mode 100644
index 0000000..8339151
--- /dev/null
+++ b/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesServiceImplTest.java
@@ -0,0 +1,167 @@
+/*
+ * 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.karaf.features.internal.service;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Map;
+
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.TestBase;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test cases for {@link org.apache.karaf.features.internal.service.FeaturesServiceImpl}
+ */
+public class FeaturesServiceImplTest extends TestBase {
+    
+    File dataFile;
+
+    @Before
+    public void setUp() throws IOException {
+        dataFile = File.createTempFile("features", null, null);
+    }
+
+    @Test
+    public void testGetFeature() throws Exception {
+        Feature transactionFeature = feature("transaction", "1.0.0");
+        final Map<String, Map<String, Feature>> features = features(transactionFeature);
+        final FeaturesServiceImpl impl = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, "") {
+            protected Map<String,Map<String,Feature>> getFeatures() throws Exception {
+                return features;
+            }
+        };
+        assertNotNull(impl.getFeature("transaction", org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION));
+        assertSame(transactionFeature, impl.getFeature("transaction", org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION));
+    }
+    
+    @Test
+    public void testGetFeatureStripVersion() throws Exception {
+        final FeaturesServiceImpl impl = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, "") {
+            protected Map<String,Map<String,Feature>> getFeatures() throws Exception {
+                return features(feature("transaction", "1.0.0"));
+            }
+        };
+        Feature feature = impl.getFeature("transaction", "  1.0.0  ");
+        assertNotNull(feature);
+        assertSame("transaction", feature.getName());
+    }
+    
+    @Test
+    public void testGetFeatureNotAvailable() throws Exception {
+        final FeaturesServiceImpl impl = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, "") {
+            protected Map<String,Map<String,Feature>> getFeatures() throws Exception {
+                return features(feature("transaction", "1.0.0"));
+            }
+        };
+        assertNull(impl.getFeature("activemq", org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION));
+    }
+    
+    @Test
+    public void testGetFeatureHighestAvailable() throws Exception {
+        final Map<String, Map<String, Feature>> features = features(
+                feature("transaction", "1.0.0"),
+                feature("transaction", "2.0.0")
+        );
+        final FeaturesServiceImpl impl = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, "") {
+            protected Map<String,Map<String,Feature>> getFeatures() throws Exception {
+                return features;
+            }
+        };
+        assertNotNull(impl.getFeature("transaction", org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION));
+        assertSame("2.0.0", impl.getFeature("transaction", org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION).getVersion());
+    }
+
+    /**
+     * This test ensures that every feature get installed only once, even if it appears multiple times in the list
+     * of transitive feature dependencies (KARAF-1600)
+     */
+    /*
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testNoDuplicateFeaturesInstallation() throws Exception {
+        final List<Feature> installed = new LinkedList<Feature>();
+        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
+        expect(bundleManager.installBundleIfNeeded(EasyMock.anyObject(String.class), EasyMock.anyInt(), EasyMock.anyObject(String.class)))
+            .andReturn(new BundleInstallerResult(createDummyBundle(1l, "", headers()), true)).anyTimes();
+        bundleManager.refreshBundles(EasyMock.anyObject(Set.class), EasyMock.anyObject(Set.class), EasyMock.anyObject(EnumSet.class));
+        EasyMock.expectLastCall();
+        final FeaturesServiceImpl impl = new FeaturesServiceImpl(bundleManager, null) {
+            // override methods which refers to bundle context to avoid mocking everything
+            @Override
+            protected boolean loadState() {
+                return true;
+            }
+
+            @Override
+            protected void saveState() {
+
+            }
+
+            @Override
+            protected void doInstallFeature(InstallationState state, Feature feature, boolean verbose) throws Exception {
+                installed.add(feature);
+
+                super.doInstallFeature(state, feature, verbose);
+            }
+
+        };
+        replay(bundleManager);
+        impl.addRepository(getClass().getResource("repo2.xml").toURI());
+        impl.installFeature("all");
+
+        // copying the features to a set to filter out the duplicates
+        Set<Feature> noduplicates = new HashSet<Feature>();
+        noduplicates.addAll(installed);
+
+        assertEquals("Every feature should only have been installed once", installed.size(), noduplicates.size());
+    }
+
+    @Test
+    public void testGetOptionalImportsOnly() {
+        BundleManager bundleManager = new BundleManager(null, 0l);
+
+        List<Clause> result = bundleManager.getOptionalImports("org.apache.karaf,org.apache.karaf.optional;resolution:=optional");
+        assertEquals("One optional import expected", 1, result.size());
+        assertEquals("org.apache.karaf.optional", result.get(0).getName());
+
+        result = bundleManager.getOptionalImports(null);
+        assertNotNull(result);
+        assertEquals("No optional imports expected", 0, result.size());
+    }
+    */
+
+    static class Storage extends StateStorage {
+        @Override
+        protected InputStream getInputStream() throws IOException {
+            return null;
+        }
+        @Override
+        protected OutputStream getOutputStream() throws IOException {
+            return null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/38502e41/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesValidationTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesValidationTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesValidationTest.java
new file mode 100644
index 0000000..f3ca2e6
--- /dev/null
+++ b/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesValidationTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.karaf.features.internal.service;
+
+import org.junit.Test;
+
+import static org.junit.Assert.fail;
+
+public class FeaturesValidationTest {
+
+    @Test
+    public void testNoNs() throws Exception {
+        FeatureValidationUtil.validate(getClass().getResource("f01.xml").toURI());
+    }
+
+    @Test
+    public void testNs10() throws Exception {
+        FeatureValidationUtil.validate(getClass().getResource("f02.xml").toURI());
+    }
+
+    @Test
+    public void testNs10NoName() throws Exception {
+        FeatureValidationUtil.validate(getClass().getResource("f03.xml").toURI());
+    }
+
+    @Test
+    public void testNs11() throws Exception {
+        FeatureValidationUtil.validate(getClass().getResource("f04.xml").toURI());
+    }
+
+    @Test
+    public void testNs12() throws Exception {
+        FeatureValidationUtil.validate(getClass().getResource("f06.xml").toURI());
+    }
+
+    @Test
+    public void testNs11NoName() throws Exception {
+        try {
+            FeatureValidationUtil.validate(getClass().getResource("f05.xml").toURI());
+            fail("Validation should have failed");
+        } catch (Exception e) {
+            // ok
+        }
+    }
+
+    @Test
+    public void testNs13() throws Exception {
+        FeatureValidationUtil.validate(getClass().getResource("f07.xml").toURI());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/38502e41/features/core/src/test/java/org/apache/karaf/features/internal/service/OverridesTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/service/OverridesTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/service/OverridesTest.java
new file mode 100644
index 0000000..c4976cf
--- /dev/null
+++ b/features/core/src/test/java/org/apache/karaf/features/internal/service/OverridesTest.java
@@ -0,0 +1,208 @@
+/*
+ * 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.karaf.features.internal.service;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.felix.utils.manifest.Parser;
+import org.apache.karaf.features.BundleInfo;
+import org.apache.karaf.features.internal.model.Bundle;
+import org.apache.karaf.features.internal.resolver.ResourceBuilder;
+import org.apache.karaf.features.internal.resolver.UriNamespace;
+import org.junit.Before;
+import org.junit.Test;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.BundleException;
+import org.osgi.resource.Resource;
+
+import static org.apache.karaf.features.internal.resolver.UriNamespace.getUri;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class OverridesTest {
+
+    private String bsn = "bsn";
+    private Resource b100;
+    private Resource b101;
+    private Resource b102;
+    private Resource b110;
+    private Resource c100;
+    private Resource c101;
+    private Resource c110;
+
+    @Before
+    public void setUp() throws BundleException {
+        b100 = resource("karaf-100.jar")
+                .set("Bundle-SymbolicName", bsn)
+                .set("Bundle-Version", "1.0.0")
+                .build();
+
+        b101 = resource("karaf-101.jar")
+                .set("Bundle-SymbolicName", bsn)
+                .set("Bundle-Version", "1.0.1")
+                .build();
+
+        b102 = resource("karaf-102.jar")
+                .set("Bundle-SymbolicName", bsn)
+                .set("Bundle-Version", "1.0.2")
+                .build();
+
+        b110 = resource("karaf-110.jar")
+                .set("Bundle-SymbolicName", bsn)
+                .set("Bundle-Version", "1.1.0")
+                .build();
+
+        c100 = resource("karafc-100.jar")
+                .set("Bundle-SymbolicName", bsn)
+                .set("Bundle-Version", "1.0.0")
+                .set("Bundle-Vendor", "Apache")
+                .build();
+
+        c101 = resource("karafc-101.jar")
+                .set("Bundle-SymbolicName", bsn)
+                .set("Bundle-Version", "1.0.1")
+                .set("Bundle-Vendor", "NotApache")
+                .build();
+
+        c110 = resource("karafc-110.jar")
+                .set("Bundle-SymbolicName", bsn)
+                .set("Bundle-Version", "1.1.0")
+                .set("Bundle-Vendor", "NotApache")
+                .build();
+    }
+
+    @Test
+    public void testDifferentVendors() throws IOException {
+        Map<String, Resource> map = asResourceMap(c100, c101, c110);
+        assertEquals(c100, map.get(getUri(c100)));
+        Overrides.override(map, Arrays.asList(getUri(c101), getUri(c110)));
+        assertEquals(c101, map.get(getUri(c100)));
+    }
+
+    @Test
+    public void testMatching101() throws IOException {
+        Map<String, Resource> map = asResourceMap(b100, b101, b110);
+        assertEquals(b100, map.get(getUri(b100)));
+        Overrides.override(map, Arrays.asList(getUri(b101), getUri(b110)));
+        assertEquals(b101, map.get(getUri(b100)));
+    }
+
+    @Test
+    public void testMatching102() throws IOException {
+        Map<String, Resource> map = asResourceMap(b100, b101, b102, b110);
+        assertEquals(b100, map.get(getUri(b100)));
+        Overrides.override(map, Arrays.asList(getUri(b101), getUri(b102), getUri(b110)));
+        assertEquals(b102, map.get(getUri(b100)));
+    }
+
+    @Test
+    public void testMatchingRange() throws IOException {
+        Map<String, Resource> map = asResourceMap(b100, b101, b110);
+        assertEquals(b100, map.get(getUri(b100)));
+        Overrides.override(map, Arrays.asList(getUri(b101), getUri(b110) + ";range=\"[1.0, 2.0)\""));
+        assertEquals(b110, map.get(getUri(b100)));
+    }
+
+    @Test
+    public void testNotMatching() throws IOException {
+        Map<String, Resource> map = asResourceMap(b100, b110);
+        assertEquals(b100, map.get(getUri(b100)));
+        Overrides.override(map, Arrays.asList(getUri(b110)));
+        assertEquals(b100, map.get(getUri(b100)));
+    }
+
+    @Test
+    public void testLoadOverrides() {
+        Set<String> overrides = Overrides.loadOverrides(getClass().getResource("overrides.properties").toExternalForm());
+        assertEquals(2, overrides.size());
+
+        Clause karafAdminCommand = null;
+        Clause karafAdminCore = null;
+        for (Clause clause : Parser.parseClauses(overrides.toArray(new String[overrides.size()]))) {
+            if (clause.getName().equals("mvn:org.apache.karaf.admin/org.apache.karaf.admin.command/2.3.0.redhat-61033X")) {
+                karafAdminCommand = clause;
+            }
+            if (clause.getName().equals("mvn:org.apache.karaf.admin/org.apache.karaf.admin.core/2.3.0.redhat-61033X")) {
+                karafAdminCore = clause;
+            }
+        }
+        assertNotNull("Missing admin.command bundle override", karafAdminCommand);
+        assertNotNull("Missing admin.core bundle override", karafAdminCore);
+        assertNotNull("Missing range on admin.core override", karafAdminCore.getAttribute(Overrides.OVERRIDE_RANGE));
+    }
+
+    /**
+     * Copies the content of {@link java.io.InputStream} to {@link java.io.OutputStream}.
+     *
+     * @param input
+     * @param output
+     * @throws java.io.IOException
+     */
+    private void copy(final InputStream input, final OutputStream output) throws IOException {
+        byte[] buffer = new byte[1024 * 16];
+        int n;
+        while (-1 != (n = input.read(buffer))) {
+            output.write(buffer, 0, n);
+            output.flush();
+        }
+        input.close();
+        output.close();
+    }
+
+    static Builder resource(String uri) {
+        return new Builder(uri);
+    }
+
+    static Map<String, Resource> asResourceMap(Resource... resources) {
+        Map<String, Resource> map = new HashMap<String, Resource>();
+        for (Resource resource : resources) {
+            map.put(getUri(resource), resource);
+        }
+        return map;
+    }
+
+    static class Builder {
+        String uri;
+        Map<String,String> headers = new HashMap<String,String>();
+        Builder(String uri) {
+            this.uri = uri;
+            this.headers.put("Bundle-ManifestVersion", "2");
+        }
+        Builder set(String key, String value) {
+            this.headers.put(key, value);
+            return this;
+        }
+        Resource build() throws BundleException {
+            return ResourceBuilder.build(uri, headers);
+        }
+    }
+
+}