/*
 * 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.sling.feature.apiregions.impl;

import static org.apache.sling.feature.apiregions.impl.RegionConstants.APIREGIONS_JOINGLOBAL;
import static org.apache.sling.feature.apiregions.impl.RegionConstants.BUNDLE_FEATURE_FILENAME;
import static org.apache.sling.feature.apiregions.impl.RegionConstants.DEFAULT_REGIONS;
import static org.apache.sling.feature.apiregions.impl.RegionConstants.FEATURE_REGION_FILENAME;
import static org.apache.sling.feature.apiregions.impl.RegionConstants.IDBSNVER_FILENAME;
import static org.apache.sling.feature.apiregions.impl.RegionConstants.PROPERTIES_FILE_LOCATION;
import static org.apache.sling.feature.apiregions.impl.RegionConstants.PROPERTIES_RESOURCE_PREFIX;
import static org.apache.sling.feature.apiregions.impl.RegionConstants.REGION_PACKAGE_FILENAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URISyntaxException;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Dictionary;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;

import org.junit.Test;
import org.mockito.Mockito;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Version;
import org.osgi.framework.hooks.resolver.ResolverHook;
import org.osgi.framework.namespace.PackageNamespace;
import org.osgi.framework.wiring.BundleCapability;
import org.osgi.framework.wiring.BundleRequirement;
import org.osgi.framework.wiring.BundleRevision;

public class RegionConfigurationTest {
    @Test
    public void testRegionConfigurationNoConfiguration() throws Exception {
        BundleContext ctx = Mockito.mock(BundleContext.class);

        try {
            new RegionConfiguration(ctx);
            fail("Expected exception. Configuration is enabled but is missing configuration");
        } catch (Exception e) {
            // good
        }
    }

    @Test
    public void testLoadBSNVerMap() throws Exception {
        String e = getClass().getResource("/empty.properties").toURI().toString();
        String f = getClass().getResource("/idbsnver1.properties").toURI().toString();
        BundleContext ctx = Mockito.mock(BundleContext.class);
        Mockito.when(ctx.getBundle()).thenReturn(Mockito.mock(Bundle.class));
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + IDBSNVER_FILENAME)).thenReturn(f);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + BUNDLE_FEATURE_FILENAME)).thenReturn(e);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + FEATURE_REGION_FILENAME)).thenReturn(e);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + REGION_PACKAGE_FILENAME)).thenReturn(e);

        RegionConfiguration re = new RegionConfiguration(ctx);
        assertEquals(2, re.bsnVerMap.size());
        assertEquals(Collections.singletonList("g:b1:1"),
                re.bsnVerMap.get(new AbstractMap.SimpleEntry<String,Version>("b1", new Version(1,0,0))));
        assertEquals(new HashSet<>(Arrays.asList("g:b2:1.2.3", "g2:b2:1.2.4")),
                new HashSet<>(re.bsnVerMap.get(new AbstractMap.SimpleEntry<String,Version>("b2", new Version(1,2,3)))));
        assertEquals(f, re.getRegistrationProperties().get(IDBSNVER_FILENAME));
    }

    @Test
    public void testLoadBSNVerMapAndConfig() throws Exception {
        String e = getClass().getResource("/empty.properties").toURI().toString();
        String f = getClass().getResource("/idbsnver1.properties").toURI().toString();
        BundleContext ctx = Mockito.mock(BundleContext.class);
        Mockito.when(ctx.getBundle()).thenReturn(Mockito.mock(Bundle.class));
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + IDBSNVER_FILENAME)).thenReturn(f);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + BUNDLE_FEATURE_FILENAME)).thenReturn(e);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + FEATURE_REGION_FILENAME)).thenReturn(e);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + REGION_PACKAGE_FILENAME)).thenReturn(e);

        RegionConfiguration re = new RegionConfiguration(ctx);
        final Dictionary<String, Object> props = new Hashtable<>();
        props.put(RegionConstants.PROP_idbsnver, "g3:b3:2.7=b3~2.7");
        re.setConfig("new.config", props);

        assertEquals(3, re.bsnVerMap.size());
        assertEquals(Collections.singletonList("g:b1:1"),
                re.bsnVerMap.get(new AbstractMap.SimpleEntry<String,Version>("b1", new Version(1,0,0))));
        assertEquals(new HashSet<>(Arrays.asList("g:b2:1.2.3", "g2:b2:1.2.4")),
                new HashSet<>(re.bsnVerMap.get(new AbstractMap.SimpleEntry<String,Version>("b2", new Version(1,2,3)))));
        assertEquals(Collections.singletonList("g3:b3:2.7"),
                re.bsnVerMap.get(new AbstractMap.SimpleEntry<String,Version>("b3", new Version(2,7,0))));

        re.removeConfig("new.config");
        assertEquals(2, re.bsnVerMap.size());
        assertEquals(Collections.singletonList("g:b1:1"),
                re.bsnVerMap.get(new AbstractMap.SimpleEntry<String,Version>("b1", new Version(1,0,0))));
        assertEquals(new HashSet<>(Arrays.asList("g:b2:1.2.3", "g2:b2:1.2.4")),
                new HashSet<>(re.bsnVerMap.get(new AbstractMap.SimpleEntry<String,Version>("b2", new Version(1,2,3)))));
    }

    @Test
    public void testLoadBundleFeatureMap() throws Exception {
        String e = getClass().getResource("/empty.properties").toURI().toString();
        String f = getClass().getResource("/bundles1.properties").toURI().toString();
        BundleContext ctx = Mockito.mock(BundleContext.class);
        Mockito.when(ctx.getBundle()).thenReturn(Mockito.mock(Bundle.class));
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + IDBSNVER_FILENAME)).thenReturn(e);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + BUNDLE_FEATURE_FILENAME)).thenReturn(f);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + FEATURE_REGION_FILENAME)).thenReturn(e);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + REGION_PACKAGE_FILENAME)).thenReturn(e);

        RegionConfiguration re = new RegionConfiguration(ctx);
        assertEquals(3, re.bundleFeatureMap.size());
        assertEquals(Collections.singleton("org.sling:something:1.2.3:slingosgifeature:myclassifier"),
                re.bundleFeatureMap.get("org.sling:b1:1"));
        assertEquals(Collections.singleton("org.sling:something:1.2.3:slingosgifeature:myclassifier"),
                re.bundleFeatureMap.get("org.sling:b2:1"));
        assertEquals(new HashSet<>(Arrays.asList("some.other:feature:123", "org.sling:something:1.2.3:slingosgifeature:myclassifier")),
                re.bundleFeatureMap.get("org.sling:b3:1"));
        assertEquals(f,  re.getRegistrationProperties().get(BUNDLE_FEATURE_FILENAME));
    }

    @Test
    public void testLoadBundleFeatureMapAndConfig() throws Exception {
        String e = getClass().getResource("/empty.properties").toURI().toString();
        String f = getClass().getResource("/bundles1.properties").toURI().toString();
        BundleContext ctx = Mockito.mock(BundleContext.class);
        Mockito.when(ctx.getBundle()).thenReturn(Mockito.mock(Bundle.class));
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + IDBSNVER_FILENAME)).thenReturn(e);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + BUNDLE_FEATURE_FILENAME)).thenReturn(f);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + FEATURE_REGION_FILENAME)).thenReturn(e);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + REGION_PACKAGE_FILENAME)).thenReturn(e);

        RegionConfiguration re = new RegionConfiguration(ctx);
        final Dictionary<String, Object> props = new Hashtable<>();
        props.put(RegionConstants.PROP_bundleFeatures, "g3:b3:2.7=fg1:fa1:3.0");
        re.setConfig("new.config", props);

        assertEquals(4, re.bundleFeatureMap.size());
        assertEquals(Collections.singleton("fg1:fa1:3.0"),
                re.bundleFeatureMap.get("g3:b3:2.7"));
        assertEquals(Collections.singleton("org.sling:something:1.2.3:slingosgifeature:myclassifier"),
                re.bundleFeatureMap.get("org.sling:b1:1"));
        assertEquals(Collections.singleton("org.sling:something:1.2.3:slingosgifeature:myclassifier"),
                re.bundleFeatureMap.get("org.sling:b2:1"));
        assertEquals(new HashSet<>(Arrays.asList("some.other:feature:123", "org.sling:something:1.2.3:slingosgifeature:myclassifier")),
                re.bundleFeatureMap.get("org.sling:b3:1"));

        re.removeConfig("new.config");
        assertEquals(3, re.bundleFeatureMap.size());
        assertEquals(Collections.singleton("org.sling:something:1.2.3:slingosgifeature:myclassifier"),
                re.bundleFeatureMap.get("org.sling:b1:1"));
        assertEquals(Collections.singleton("org.sling:something:1.2.3:slingosgifeature:myclassifier"),
                re.bundleFeatureMap.get("org.sling:b2:1"));
        assertEquals(new HashSet<>(Arrays.asList("some.other:feature:123", "org.sling:something:1.2.3:slingosgifeature:myclassifier")),
                re.bundleFeatureMap.get("org.sling:b3:1"));

        // add a config with an empty feature list
        props.put(RegionConstants.PROP_bundleFeatures, "g3:b3:2.7=");
        re.setConfig("new.config", props);

        assertEquals(4, re.bundleFeatureMap.size());
        assertEquals(Collections.emptySet(),
            re.bundleFeatureMap.get("g3:b3:2.7"));
        assertEquals(Collections.singleton("org.sling:something:1.2.3:slingosgifeature:myclassifier"),
            re.bundleFeatureMap.get("org.sling:b1:1"));
        assertEquals(Collections.singleton("org.sling:something:1.2.3:slingosgifeature:myclassifier"),
            re.bundleFeatureMap.get("org.sling:b2:1"));
        assertEquals(new HashSet<>(Arrays.asList("some.other:feature:123", "org.sling:something:1.2.3:slingosgifeature:myclassifier")),
            re.bundleFeatureMap.get("org.sling:b3:1"));
    }

    @Test
    public void testLoadFeatureRegionMap() throws Exception {
        String e = getClass().getResource("/empty.properties").toURI().toString();
        String f = getClass().getResource("/features1.properties").toURI().toString();
        BundleContext ctx = Mockito.mock(BundleContext.class);
        Mockito.when(ctx.getBundle()).thenReturn(Mockito.mock(Bundle.class));
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + IDBSNVER_FILENAME)).thenReturn(e);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + BUNDLE_FEATURE_FILENAME)).thenReturn(e);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + FEATURE_REGION_FILENAME)).thenReturn(f);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + REGION_PACKAGE_FILENAME)).thenReturn(e);

        RegionConfiguration re = new RegionConfiguration(ctx);
        assertEquals(2, re.featureRegionMap.size());
        assertEquals(Collections.singletonList("global"),
                re.featureRegionMap.get("an.other:feature:123"));
        assertEquals(Arrays.asList("global", "internal"),
                re.featureRegionMap.get("org.sling:something:1.2.3"));
        assertEquals(f,  re.getRegistrationProperties().get(FEATURE_REGION_FILENAME));
    }

    @Test
    public void testLoadFeatureRegionMapAndConfig() throws Exception {
        String e = getClass().getResource("/empty.properties").toURI().toString();
        String f = getClass().getResource("/features1.properties").toURI().toString();
        BundleContext ctx = Mockito.mock(BundleContext.class);
        Mockito.when(ctx.getBundle()).thenReturn(Mockito.mock(Bundle.class));
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + IDBSNVER_FILENAME)).thenReturn(e);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + BUNDLE_FEATURE_FILENAME)).thenReturn(e);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + FEATURE_REGION_FILENAME)).thenReturn(f);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + REGION_PACKAGE_FILENAME)).thenReturn(e);

        RegionConfiguration re = new RegionConfiguration(ctx);
        final Dictionary<String, Object> props = new Hashtable<>();
        props.put(RegionConstants.PROP_featureRegions, "fg1:fa1:3.0=newregion");
        re.setConfig("new.config", props);

        assertEquals(3, re.featureRegionMap.size());
        assertEquals(Collections.singletonList("newregion"),
                re.featureRegionMap.get("fg1:fa1:3.0"));
        assertEquals(Collections.singletonList("global"),
                re.featureRegionMap.get("an.other:feature:123"));
        assertEquals(Arrays.asList("global", "internal"),
                re.featureRegionMap.get("org.sling:something:1.2.3"));

        re.removeConfig("new.config");
        assertEquals(2, re.featureRegionMap.size());
        assertEquals(Collections.singletonList("global"),
                re.featureRegionMap.get("an.other:feature:123"));
        assertEquals(Arrays.asList("global", "internal"),
                re.featureRegionMap.get("org.sling:something:1.2.3"));
    }

    @Test
    public void testLoadRegionPackageMap() throws Exception {
        String e = getClass().getResource("/empty.properties").toURI().toString();
        String f = getClass().getResource("/regions1.properties").toURI().toString();
        BundleContext ctx = Mockito.mock(BundleContext.class);
        Mockito.when(ctx.getBundle()).thenReturn(Mockito.mock(Bundle.class));
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + IDBSNVER_FILENAME)).thenReturn(e);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + BUNDLE_FEATURE_FILENAME)).thenReturn(e);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + FEATURE_REGION_FILENAME)).thenReturn(e);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + REGION_PACKAGE_FILENAME)).thenReturn(f);

        RegionConfiguration re = new RegionConfiguration(ctx);
        assertEquals(2, re.regionPackageMap.size());
        assertEquals(Collections.singleton("xyz"),
                re.regionPackageMap.get("internal"));
        assertEquals(new HashSet<>(Arrays.asList("a.b.c", "d.e.f", "test")),
                re.regionPackageMap.get("global"));
        assertEquals(f,  re.getRegistrationProperties().get(REGION_PACKAGE_FILENAME));
    }

    @Test
    public void testLoadRegionPackageMapAndConfig() throws Exception {
        String e = getClass().getResource("/empty.properties").toURI().toString();
        String f = getClass().getResource("/regions1.properties").toURI().toString();
        BundleContext ctx = Mockito.mock(BundleContext.class);
        Mockito.when(ctx.getBundle()).thenReturn(Mockito.mock(Bundle.class));
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + IDBSNVER_FILENAME)).thenReturn(e);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + BUNDLE_FEATURE_FILENAME)).thenReturn(e);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + FEATURE_REGION_FILENAME)).thenReturn(e);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + REGION_PACKAGE_FILENAME)).thenReturn(f);

        RegionConfiguration re = new RegionConfiguration(ctx);
        final Dictionary<String, Object> props = new Hashtable<>();
        props.put(RegionConstants.PROP_regionPackage, "internal=r.i.p");
        re.setConfig("new.config", props);

        assertEquals(2, re.regionPackageMap.size());
        assertEquals(new HashSet<>(Arrays.asList("xyz", "r.i.p")),
                re.regionPackageMap.get("internal"));
        assertEquals(new HashSet<>(Arrays.asList("a.b.c", "d.e.f", "test")),
                re.regionPackageMap.get("global"));

        re.removeConfig("new.config");
        assertEquals(2, re.regionPackageMap.size());
        assertEquals(Collections.singleton("xyz"),
                re.regionPackageMap.get("internal"));
        assertEquals(new HashSet<>(Arrays.asList("a.b.c", "d.e.f", "test")),
                re.regionPackageMap.get("global"));
    }

    @Test
    public void testJoinRegionsToGlobal() throws Exception {
        String e = getClass().getResource("/empty.properties").toURI().toString();
        String f = getClass().getResource("/regions2.properties").toURI().toString();
        BundleContext ctx = Mockito.mock(BundleContext.class);
        Mockito.when(ctx.getBundle()).thenReturn(Mockito.mock(Bundle.class));
        Mockito.when(ctx.getProperty(APIREGIONS_JOINGLOBAL)).thenReturn("obsolete,deprecated");
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + IDBSNVER_FILENAME)).thenReturn(e);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + BUNDLE_FEATURE_FILENAME)).thenReturn(e);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + FEATURE_REGION_FILENAME)).thenReturn(e);
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + REGION_PACKAGE_FILENAME)).thenReturn(f);

        RegionConfiguration re = new RegionConfiguration(ctx);
        assertEquals(1, re.regionPackageMap.size());
        assertEquals(new HashSet<>(Arrays.asList("xyz", "a.b.c", "d.e.f", "test")),
                re.regionPackageMap.get("global"));
    }

    @Test
    public void testBegin() throws Exception {
        BundleContext ctx = Mockito.mock(BundleContext.class);
        Mockito.when(ctx.getBundle()).thenReturn(Mockito.mock(Bundle.class));
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + IDBSNVER_FILENAME)).
            thenReturn(getClass().getResource("/idbsnver1.properties").toURI().toString());
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + BUNDLE_FEATURE_FILENAME)).
            thenReturn(getClass().getResource("/bundles1.properties").toURI().toString());
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + FEATURE_REGION_FILENAME)).
            thenReturn(getClass().getResource("/features1.properties").toURI().toString());
        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + REGION_PACKAGE_FILENAME)).
            thenReturn(getClass().getResource("/regions1.properties").toURI().toString());

        RegionConfiguration re = new RegionConfiguration(ctx);
        assertTrue(re.bsnVerMap.size() > 0);
        assertTrue(re.bundleFeatureMap.size() > 0);
        assertTrue(re.featureRegionMap.size() > 0);
        assertTrue(re.regionPackageMap.size() > 0);

        ResolverHookImpl hook = (ResolverHookImpl) new RegionEnforcer(re).begin(null);
        assertEquals(re.bsnVerMap, hook.configuration.bsnVerMap);
        assertEquals(re.bundleFeatureMap, hook.configuration.bundleFeatureMap);
        assertEquals(re.featureRegionMap, hook.configuration.featureRegionMap);
        assertEquals(re.regionPackageMap, hook.configuration.regionPackageMap);
    }

    @Test
    public void testURLs() throws Exception {
        BundleContext ctx = Mockito.mock(BundleContext.class);
        Mockito.when(ctx.getBundle()).thenReturn(Mockito.mock(Bundle.class));
        String location = new File(getClass().getResource("/props1/idbsnver.properties").
                getFile()).getParentFile().toURI().toString();
        Mockito.when(ctx.getProperty(PROPERTIES_FILE_LOCATION)).thenReturn(location);

        RegionConfiguration re = new RegionConfiguration(ctx);
        assertTrue(re.bsnVerMap.size() > 0);
        assertTrue(re.bundleFeatureMap.size() > 0);
        assertTrue(re.featureRegionMap.size() > 0);
        assertTrue(re.regionPackageMap.size() > 0);
    }

    @Test
    public void testClassloaderURLs() throws Exception {
        BundleContext ctx = Mockito.mock(BundleContext.class);
        Mockito.when(ctx.getBundle()).thenReturn(Mockito.mock(Bundle.class));
        Mockito.when(ctx.getProperty(PROPERTIES_FILE_LOCATION)).
            thenReturn("classloader://props1");

        RegionConfiguration re = new RegionConfiguration(ctx);
        assertTrue(re.bsnVerMap.size() > 0);
        assertTrue(re.bundleFeatureMap.size() > 0);
        assertTrue(re.featureRegionMap.size() > 0);
        assertTrue(re.regionPackageMap.size() > 0);
    }

    @Test
    public void testOrderingOfRegionsInFeatures() throws Exception {
        BundleContext ctx = Mockito.mock(BundleContext.class);
        Mockito.when(ctx.getBundle()).thenReturn(Mockito.mock(Bundle.class));
        Mockito.when(ctx.getProperty(PROPERTIES_FILE_LOCATION)).
            thenReturn("classloader://props2");

        RegionConfiguration re = new RegionConfiguration(ctx);
        assertEquals(Arrays.asList("r0", "r1", "r2", "r3"),
                new ArrayList<>(re.featureRegionMap.get("org.sling:something:1.2.3")));
    }

    @Test
    public void testUnModifiableMaps() throws Exception {
        BundleContext ctx = Mockito.mock(BundleContext.class);
        Mockito.when(ctx.getBundle()).thenReturn(Mockito.mock(Bundle.class));
        Mockito.when(ctx.getProperty(PROPERTIES_FILE_LOCATION)).
            thenReturn("classloader://props1");

        RegionConfiguration re = new RegionConfiguration(ctx);
        assertTrue(re.bsnVerMap.size() > 0);
        assertBSNVerMapUnmodifiable(re.bsnVerMap);
        assertTrue(re.bundleFeatureMap.size() > 0);
        assertMapUnmodifiable(re.bundleFeatureMap);
        assertTrue(re.featureRegionMap.size() > 0);
        assertMapUnmodifiable(re.featureRegionMap);
        assertTrue(re.regionPackageMap.size() > 0);
        assertMapUnmodifiable(re.regionPackageMap);
    }

    @Test
    public void testDefaultRegions() throws Exception {
        testDefaultRegions("foo.bar,foo.zar", new HashSet<>(Arrays.asList("foo.bar", "foo.zar")));
        testDefaultRegions("test", Collections.singleton("test"));
        testDefaultRegions("", Collections.emptySet());
        testDefaultRegions(null, Collections.emptySet());
    }

    @Test
    public void testStoreLoadPersistedConfig() throws Exception {
        File f = File.createTempFile("testStorePersistedConfig", ".tmp");

        try {
            Bundle bundle = Mockito.mock(Bundle.class);
            Mockito.when(bundle.getDataFile("bundleLocationToFeature.properties"))
                .thenReturn(f);

            BundleContext ctx = Mockito.mock(BundleContext.class);
            Mockito.when(ctx.getBundle()).thenReturn(bundle);
            Mockito.when(ctx.getProperty(PROPERTIES_FILE_LOCATION)).
                thenReturn("classloader://props1");

            RegionConfiguration cfg = new RegionConfiguration(ctx);

            ConcurrentMap<String, Map.Entry<String, Version>> m = cfg.getBundleLocationConfigMap();
            m.put("foo://bar", new AbstractMap.SimpleEntry<>("blah", new Version(1,0,0,"suffix")));
            m.put("foo://tar", new AbstractMap.SimpleEntry<>("a.b.c", new Version(9,8,7)));
            cfg.storeLocationToConfigMap(ctx);

            RegionConfiguration cfg2 = new RegionConfiguration(ctx);
            ConcurrentMap<String, Map.Entry<String, Version>> m2 = cfg2.getBundleLocationConfigMap();
            assertEquals(m, m2);
        } finally {
            f.delete();
        }
    }

    @Test
    public void testUpdateLocationCacheOnConfigUpdate() throws Exception {
        // Set up a typical configuration scenario

        BundleContext ctx = Mockito.mock(BundleContext.class);
        Mockito.when(ctx.getBundle()).thenReturn(Mockito.mock(Bundle.class));
        Mockito.when(ctx.getProperty(PROPERTIES_FILE_LOCATION)).
            thenReturn("classloader://props4");
        RegionConfiguration cfg = new RegionConfiguration(ctx);

        assertEquals(2, cfg.getBsnVerMap().size());
        assertEquals(Collections.singletonList("g:b1:1"),
                cfg.getBsnVerMap().get(new AbstractMap.SimpleEntry<>("b1", new Version(1,0,0))));
        assertEquals(Collections.singletonList("g:b2:1.2.3"),
                cfg.getBsnVerMap().get(new AbstractMap.SimpleEntry<>("b2", new Version(1,2,3))));

        // Now start invoking the resolver hook, this should fill in some of the location cache
        assertEquals("Precondition", 0, cfg.getBundleLocationConfigMap().size());
        ResolverHookImpl rhi = new ResolverHookImpl(cfg);

        BundleRequirement req = mockRequirement("b4", new Version(9,9,9,"something"), ctx);
        BundleCapability cap1 = mockCapability("org.foo.bar", "b1", new Version(1,0,0), ctx);
        BundleCapability cap2 = mockCapability("org.foo.bar", "b2", new Version(1,2,3), ctx);

        ArrayList<BundleCapability> caps1 = new ArrayList<>(Arrays.asList(cap1, cap2));
        rhi.filterMatches(req, caps1);
        assertEquals("caps should be empty it b4 doesn't have regions configuration yet",
                Collections.emptyList(), caps1);

        // At this point the bundle location to feature map should have some cached info
        assertEquals(3, cfg.getBundleLocationConfigMap().size());
        assertEquals(new AbstractMap.SimpleEntry<>("b1", new Version(1,0,0)),
                cfg.getBundleLocationConfigMap().get("http://b1"));
        assertEquals(new AbstractMap.SimpleEntry<>("b2", new Version(1,2,3)),
                cfg.getBundleLocationConfigMap().get("http://b2"));
        assertEquals(new AbstractMap.SimpleEntry<>("b4", new Version(9,9,9,"something")),
                cfg.getBundleLocationConfigMap().get("http://b4"));


        // Now update the configuration, there is new mappings for bundles b3 and b4 and
        // the features of b2 have changed
        Dictionary<String,Object> d = new Hashtable<>();
        d.put("mapping.bundleid.bsnver",
                new String[] {
                        "g:b3:1.2=a.b3.c~1.2",
                        "g:b4:9.9.9.something=b4~9.9.9.something"});
        d.put("mapping.bundleid.features",
                new String[] {
                        "g:b4:9.9.9.something=org.sling:something:1.2.3"
                });

        cfg.setConfig("my.factory.pid", d);
        assertEquals(4, cfg.getBsnVerMap().size());
        assertEquals(Collections.singletonList("g:b1:1"),
                cfg.getBsnVerMap().get(new AbstractMap.SimpleEntry<>("b1", new Version(1,0,0))));
        assertEquals(Collections.singletonList("g:b2:1.2.3"),
                cfg.getBsnVerMap().get(new AbstractMap.SimpleEntry<>("b2", new Version(1,2,3))));
        assertEquals(Collections.singletonList("g:b3:1.2"),
                cfg.getBsnVerMap().get(new AbstractMap.SimpleEntry<>("a.b3.c", new Version(1,2,0))));
        assertEquals(Collections.singletonList("g:b4:9.9.9.something"),
                cfg.getBsnVerMap().get(new AbstractMap.SimpleEntry<>("b4", new Version(9,9,9,"something"))));

        // Redo a resolve action and check that the cache is now re-filled
        ArrayList<BundleCapability> caps2 = new ArrayList<>(Arrays.asList(cap1, cap2));
        rhi.filterMatches(req, caps2);

        ArrayList<BundleCapability> expected = new ArrayList<>(Arrays.asList(cap1, cap2));
        assertEquals("Now b4 from the req should have visibility to both caps as b4 is now in the feature",
                expected, caps2);
    }

    @Test
    public void testRegionOrderProperty() throws Exception {
        BundleContext ctx = Mockito.mock(BundleContext.class);
        Mockito.when(ctx.getBundle()).thenReturn(Mockito.mock(Bundle.class));
        Mockito.when(ctx.getProperty(PROPERTIES_FILE_LOCATION)).
            thenReturn("classloader://props1");

        RegionConfiguration re = new RegionConfiguration(ctx);
        assertEquals(Arrays.asList("global", "internal"), re.getGlobalRegionOrder());
        assertEquals(2, re.getFeatureRegionMap().size());
        assertNull(re.getFeatureRegionMap().get("__region.order__"));
    }

    private BundleRequirement mockRequirement(String bsn, Version bver, BundleContext mockContext) {
        BundleRevision br = mockBundleRevision(bsn, bver, mockContext);

        BundleRequirement req = Mockito.mock(BundleRequirement.class);
        Mockito.when(req.getRevision()).thenReturn(br);
        Mockito.when(req.getNamespace()).thenReturn(PackageNamespace.PACKAGE_NAMESPACE);
        return req;
    }

    private BundleCapability mockCapability(String pkg, String bsn, Version bver, BundleContext mockContext) {
        Map<String, Object> attrs =
                Collections.<String, Object>singletonMap(PackageNamespace.PACKAGE_NAMESPACE, pkg);

        BundleRevision br = mockBundleRevision(bsn, bver, mockContext);

        BundleCapability cap = Mockito.mock(BundleCapability.class);
        Mockito.when(cap.getRevision()).thenReturn(br);
        Mockito.when(cap.getAttributes()).thenReturn(attrs);
        Mockito.when(cap.getNamespace()).thenReturn(PackageNamespace.PACKAGE_NAMESPACE);
        return cap;
    }

    private BundleRevision mockBundleRevision(String bsn, Version bver, BundleContext mockContext) {
        Bundle b = Mockito.mock(Bundle.class);
        Mockito.when(b.getSymbolicName()).thenReturn(bsn);
        Mockito.when(b.getVersion()).thenReturn(bver);
        String bundleLocation = "http://" + bsn;
        Mockito.when(b.getLocation()).thenReturn(bundleLocation);
        Mockito.when(b.getBundleId()).thenReturn(System.currentTimeMillis()); // Just some random unique ID

        BundleRevision br = Mockito.mock(BundleRevision.class);
        Mockito.when(br.getBundle()).thenReturn(b);

        // Make the bundlecontext aware...
        Mockito.when(mockContext.getBundle(bundleLocation)).thenReturn(b);

        return br;
    }

    private void testDefaultRegions(String defProp, Set<String> expected)
            throws IOException, URISyntaxException, NoSuchFieldException, IllegalAccessException {
        BundleContext ctx = Mockito.mock(BundleContext.class);
        Mockito.when(ctx.getBundle()).thenReturn(Mockito.mock(Bundle.class));
        Mockito.when(ctx.getProperty(DEFAULT_REGIONS)).thenReturn(defProp);
        Mockito.when(ctx.getProperty(PROPERTIES_FILE_LOCATION)).
        thenReturn("classloader://props1");

        RegionConfiguration re = new RegionConfiguration(ctx);
        ResolverHook hook = new RegionEnforcer(re).begin(Collections.emptySet());
        Field f = ResolverHookImpl.class.getDeclaredField("configuration");
        f.setAccessible(true);

        assertEquals(expected, ((RegionConfiguration)f.get(hook)).getDefaultRegions());
    }

    private void assertBSNVerMapUnmodifiable(Map<Map.Entry<String, Version>, List<String>> m) {
        Map.Entry<Map.Entry<String, Version>, List<String>> entry = m.entrySet().iterator().next();
        try {
            List<String> c = entry.getValue();
            c.add("test");
            fail("Changing a value should have thrown an exception");
        } catch (Exception ex) {
            // good
        }

        try {
            m.put(new AbstractMap.SimpleEntry<>("hi", Version.parseVersion("1.2.3")),
                    Collections.singletonList("xyz"));
            fail("Adding a new value should have thrown an exception");
        } catch (Exception ex) {
            // good
        }
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    private void assertMapUnmodifiable(Map<String, ? extends Collection<String>> m) {
        Map.Entry<String, ? extends Collection<String>> entry = m.entrySet().iterator().next();
        try {
            Collection<String> s = entry.getValue();
            s.add("testing");
            fail("Changing a value should have thrown an exception");
        } catch (Exception ex) {
            // good
        }

        try {
            Map m2 = m;
            m2.put("foo", Collections.<String>emptySet());
            fail("Adding a new value should have thrown an exception");
        } catch (Exception ex) {
            // good
        }
    }

}
