You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2019/10/17 15:51:08 UTC

[sling-org-apache-sling-feature-extension-apiregions] 01/02: SLING-8784 : Move api regions analysers to api regions extension

This is an automated email from the ASF dual-hosted git repository.

cziegeler pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-extension-apiregions.git

commit e054c2940ca4fba7f3cd222c40d453efd52b1604
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Thu Oct 17 17:15:18 2019 +0200

    SLING-8784 : Move api regions analysers to api regions extension
---
 .../CheckApiRegionsBundleExportsImports.java       |  30 +-
 .../CheckApiRegionsBundleExportsImportsTest.java   | 336 +++++++++++++++++++++
 .../f_f_1/bundleOrigins.properties                 |   2 +
 .../f_f_1/regionOrigins.properties                 |   2 +
 .../f_f_1/bundleOrigins.properties                 |   2 +
 .../f_f_1/regionOrigins.properties                 |   2 +
 .../f_f_1/bundleOrigins.properties                 |   2 +
 .../f_f_1/regionOrigins.properties                 |   2 +
 .../f_f_1/bundleOrigins.properties                 |   2 +
 .../f_f_1/regionOrigins.properties                 |   1 +
 .../f_f_1/bundleOrigins.properties                 |   2 +
 .../f_f_1/regionOrigins.properties                 |   2 +
 .../f_f_2/bundleOrigins.properties                 |   4 +
 .../f_f_2/regionOrigins.properties                 |   3 +
 src/test/resources/test-bundle1.jar                | Bin 0 -> 434 bytes
 src/test/resources/test-bundle2.jar                | Bin 0 -> 457 bytes
 src/test/resources/test-bundle3.jar                | Bin 0 -> 431 bytes
 src/test/resources/test-bundle4.jar                | Bin 0 -> 420 bytes
 src/test/resources/test-framework.jar              | Bin 0 -> 13288 bytes
 19 files changed, 388 insertions(+), 4 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/analyser/CheckApiRegionsBundleExportsImports.java b/src/main/java/org/apache/sling/feature/extension/apiregions/analyser/CheckApiRegionsBundleExportsImports.java
index 42635da..cd2d34e 100644
--- a/src/main/java/org/apache/sling/feature/extension/apiregions/analyser/CheckApiRegionsBundleExportsImports.java
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/analyser/CheckApiRegionsBundleExportsImports.java
@@ -37,15 +37,20 @@ import java.util.SortedMap;
 import java.util.TreeMap;
 import java.util.stream.Collectors;
 
+import javax.json.JsonArray;
+import javax.json.stream.JsonParsingException;
+
 import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.Extensions;
 import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.analyser.task.AnalyserTask;
 import org.apache.sling.feature.analyser.task.AnalyserTaskContext;
 import org.apache.sling.feature.extension.apiregions.api.ApiRegions;
 import org.apache.sling.feature.scanner.BundleDescriptor;
 import org.apache.sling.feature.scanner.PackageInfo;
 import org.osgi.framework.Version;
 
-public class CheckApiRegionsBundleExportsImports extends AbstractApiRegionsAnalyserTask {
+public class CheckApiRegionsBundleExportsImports implements AnalyserTask {
 
     private static final String FILE_STORAGE_CONFIG_KEY = "fileStorage";
     private static final String IGNORE_API_REGIONS_CONFIG_KEY = "ignoreAPIRegions";
@@ -118,7 +123,7 @@ public class CheckApiRegionsBundleExportsImports extends AbstractApiRegionsAnaly
     }
 
     @Override
-    protected void execute(ApiRegions apiRegions, AnalyserTaskContext ctx) throws Exception {
+    public void execute(final AnalyserTaskContext ctx) throws Exception {
         boolean ignoreAPIRegions = ctx.getConfiguration().getOrDefault(
                 IGNORE_API_REGIONS_CONFIG_KEY, "false").equalsIgnoreCase("true");
 
@@ -145,13 +150,29 @@ public class CheckApiRegionsBundleExportsImports extends AbstractApiRegionsAnaly
 
         Map<String, Set<String>> bundleToOriginalFeatures;
         Map<String, Set<String>> featureToOriginalRegions;
+        ApiRegions apiRegions = new ApiRegions(); // Empty API Regions;
+
         if (ignoreAPIRegions) {
-            apiRegions = new ApiRegions(); // Empty API Regions
             bundleToOriginalFeatures = Collections.emptyMap();
             featureToOriginalRegions = Collections.emptyMap();
         } else {
             bundleToOriginalFeatures = readBundleOrigins(ctx);
             featureToOriginalRegions = readRegionOrigins(ctx);
+            Feature feature = ctx.getFeature();
+
+            // extract and check the api-regions
+
+            Extensions extensions = feature.getExtensions();
+            Extension apiRegionsExtension = extensions.getByName(ApiRegions.EXTENSION_NAME);
+            if (apiRegionsExtension != null && apiRegionsExtension.getJSONStructure() != null) {
+                try {
+                    apiRegions = ApiRegions.parse((JsonArray) apiRegionsExtension.getJSONStructure());
+                } catch (IllegalStateException | IllegalArgumentException | JsonParsingException e) {
+                    ctx.reportError("API Regions '" + apiRegionsExtension.getJSON()
+                            + "' does not represent a valid JSON 'api-regions': " + e.getMessage());
+                    return;
+                }
+            }
         }
 
         for(final Map.Entry<Integer, List<BundleDescriptor>> entry : bundlesMap.entrySet()) {
@@ -351,7 +372,8 @@ public class CheckApiRegionsBundleExportsImports extends AbstractApiRegionsAnaly
 
                 for (String region : getBundleRegions(info, bundleToOriginalFeatures, featureToOriginalRegions)) {
                     if (!NO_REGION.equals(region) &&
-                            apiRegions.getRegionByName(region).getExportByName(pck.getName()) == null)
+                            (apiRegions.getRegionByName(region) == null
+                                    || apiRegions.getRegionByName(region).getExportByName(pck.getName()) == null))
                         continue;
 
                     Set<String> regions = candidates.get(info);
diff --git a/src/test/java/org/apache/sling/feature/extension/apiregions/analyser/CheckApiRegionsBundleExportsImportsTest.java b/src/test/java/org/apache/sling/feature/extension/apiregions/analyser/CheckApiRegionsBundleExportsImportsTest.java
new file mode 100644
index 0000000..4600dfc
--- /dev/null
+++ b/src/test/java/org/apache/sling/feature/extension/apiregions/analyser/CheckApiRegionsBundleExportsImportsTest.java
@@ -0,0 +1,336 @@
+/*
+ * 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.extension.apiregions.analyser;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.feature.Artifact;
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.ExtensionState;
+import org.apache.sling.feature.ExtensionType;
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.analyser.task.AnalyserTaskContext;
+import org.apache.sling.feature.extension.apiregions.api.ApiRegions;
+import org.apache.sling.feature.scanner.BundleDescriptor;
+import org.apache.sling.feature.scanner.FeatureDescriptor;
+import org.apache.sling.feature.scanner.impl.BundleDescriptorImpl;
+import org.apache.sling.feature.scanner.impl.FeatureDescriptorImpl;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class CheckApiRegionsBundleExportsImportsTest {
+    private static File resourceRoot;
+
+    @BeforeClass
+    public static void setupClass() {
+        resourceRoot =
+                new File(CheckApiRegionsBundleExportsImportsTest.class.
+                        getResource("/test-framework.jar").getFile()).getParentFile();
+    }
+
+    @Test
+    public void testId() {
+        assertEquals(ApiRegions.EXTENSION_NAME + "-exportsimports", new CheckApiRegionsBundleExportsImports().getId());
+    }
+
+    @Test
+    /*
+     * Bundle b3 imports org.foo.e, but no bundle exports it. The feature is marked
+     * as complete which it isn't
+     */
+    public void testImportExportNoRegionsMarkedAsComplete() throws Exception {
+        CheckApiRegionsBundleExportsImports t = new CheckApiRegionsBundleExportsImports();
+
+        Feature f = new Feature(ArtifactId.fromMvnId("f:f:1"));
+        f.setComplete(true);
+        FeatureDescriptor fd = new FeatureDescriptorImpl(f);
+
+        fdAddBundle(fd, "g:b1:1", "test-bundle1.jar");
+        fdAddBundle(fd, "g:b3:1", "test-bundle3.jar");
+
+        AnalyserTaskContext ctx = Mockito.mock(AnalyserTaskContext.class);
+        Mockito.when(ctx.getFeature()).thenReturn(f);
+        Mockito.when(ctx.getFeatureDescriptor()).thenReturn(fd);
+        t.execute(ctx);
+
+        Mockito.verify(ctx, Mockito.times(2)).reportError(Mockito.anyString());
+        Mockito.verify(ctx).reportError(Mockito.contains("org.foo.e"));
+        Mockito.verify(ctx).reportError(Mockito.contains("marked as 'complete'"));
+        Mockito.verify(ctx, Mockito.never()).reportWarning(Mockito.anyString());
+    }
+
+    @Test
+    public void testImportExportNoRegionsAllOk() throws Exception {
+        CheckApiRegionsBundleExportsImports t = new CheckApiRegionsBundleExportsImports();
+
+        Feature f = new Feature(ArtifactId.fromMvnId("f:f:1"));
+        FeatureDescriptor fd = new FeatureDescriptorImpl(f);
+
+        fdAddBundle(fd, "g:b1:1", "test-bundle1.jar");
+        fdAddBundle(fd, "g:b2:1", "test-bundle2.jar");
+
+        AnalyserTaskContext ctx = Mockito.mock(AnalyserTaskContext.class);
+        Mockito.when(ctx.getFeature()).thenReturn(f);
+        Mockito.when(ctx.getFeatureDescriptor()).thenReturn(fd);
+        t.execute(ctx);
+
+        Mockito.verify(ctx, Mockito.never()).reportError(Mockito.anyString());
+        Mockito.verify(ctx, Mockito.never()).reportWarning(Mockito.anyString());
+    }
+
+    @Test
+    /*
+     * Bundle b3 imports org.foo.e, but no bundle exports it
+     */
+    public void testImportExportNoRegionsMissing() throws Exception {
+        CheckApiRegionsBundleExportsImports t = new CheckApiRegionsBundleExportsImports();
+
+        Feature f = new Feature(ArtifactId.fromMvnId("f:f:1"));
+        FeatureDescriptor fd = new FeatureDescriptorImpl(f);
+
+        fdAddBundle(fd, "g:b1:1", "test-bundle1.jar");
+        fdAddBundle(fd, "g:b3:1", "test-bundle3.jar");
+
+        AnalyserTaskContext ctx = Mockito.mock(AnalyserTaskContext.class);
+        Mockito.when(ctx.getFeature()).thenReturn(f);
+        Mockito.when(ctx.getFeatureDescriptor()).thenReturn(fd);
+        t.execute(ctx);
+
+        Mockito.verify(ctx).reportError(Mockito.contains("org.foo.e"));
+        Mockito.verify(ctx, Mockito.times(1)).reportError(Mockito.anyString());
+        Mockito.verify(ctx, Mockito.never()).reportWarning(Mockito.anyString());
+    }
+
+    @Test
+    /*
+     * Bundle 2 imports org.foo.b from bundle 1, but bundle 1 exports it in a
+     * different region, bundle 2 is in no region.
+     */
+    public void testImportExportWithRegionsMissing() throws Exception {
+        String exJson = "[{\"name\": \"something\", \"exports\": [\"org.foo.b\"]}]";
+
+        CheckApiRegionsBundleExportsImports t = new CheckApiRegionsBundleExportsImports();
+
+        Feature f = new Feature(ArtifactId.fromMvnId("f:f:1"));
+        Extension ex = new Extension(ExtensionType.JSON, "api-regions", ExtensionState.OPTIONAL);
+        ex.setJSON(exJson);
+        f.getExtensions().add(ex);
+
+        FeatureDescriptor fd = new FeatureDescriptorImpl(f);
+
+        fdAddBundle(fd, "g:b1:1", "test-bundle1.jar");
+        fdAddBundle(fd, "g:b2:1", "test-bundle2.jar");
+
+        AnalyserTaskContext ctx = Mockito.mock(AnalyserTaskContext.class);
+        Mockito.when(ctx.getFeature()).thenReturn(f);
+        Mockito.when(ctx.getFeatureDescriptor()).thenReturn(fd);
+        Mockito.when(ctx.getConfiguration()).thenReturn(
+                Collections.singletonMap("fileStorage",
+                        resourceRoot + "/origins/testImportExportWithRegionsMissing"));
+        t.execute(ctx);
+
+        Mockito.verify(ctx).reportError(Mockito.contains("org.foo.b"));
+        Mockito.verify(ctx, Mockito.times(1)).reportError(Mockito.anyString());
+        Mockito.verify(ctx, Mockito.never()).reportWarning(Mockito.anyString());
+    }
+
+    @Test
+    /*
+     * Bundle 2 imports org.foo.b from bundle 1, but bundle 1 exports it in a different
+     * region, bundle 1 is in something region, and bundle 2 is in somethingelse region.
+     */
+    public void testImportExportWithRegionMismatch() throws Exception {
+        String exJson = "[{\"name\": \"something\", \"exports\": [\"org.foo.b\"]}]";
+
+        CheckApiRegionsBundleExportsImports t = new CheckApiRegionsBundleExportsImports();
+
+        Feature f = new Feature(ArtifactId.fromMvnId("f:f:1"));
+        Extension ex = new Extension(ExtensionType.JSON, "api-regions", ExtensionState.OPTIONAL);
+        ex.setJSON(exJson);
+        f.getExtensions().add(ex);
+
+        FeatureDescriptor fd = new FeatureDescriptorImpl(f);
+
+        fdAddBundle(fd, "g:b1:1", "test-bundle1.jar");
+        fdAddBundle(fd, "g:b2:1", "test-bundle2.jar");
+
+        Map<String, String> cfgMap = new HashMap<String, String>();
+        cfgMap.put("fileStorage", resourceRoot + "/origins/testImportExportWithRegionMismatch");
+        cfgMap.put("ignoreAPIRegions", "false");
+
+        AnalyserTaskContext ctx = Mockito.mock(AnalyserTaskContext.class);
+        Mockito.when(ctx.getFeature()).thenReturn(f);
+        Mockito.when(ctx.getFeatureDescriptor()).thenReturn(fd);
+        Mockito.when(ctx.getConfiguration()).thenReturn(cfgMap);
+        t.execute(ctx);
+
+        Mockito.verify(ctx).reportError(Mockito.contains("org.foo.b"));
+        Mockito.verify(ctx).reportError(Mockito.contains("something"));
+        Mockito.verify(ctx).reportError(Mockito.contains("somethingelse"));
+        Mockito.verify(ctx, Mockito.times(1)).reportError(Mockito.anyString());
+        Mockito.verify(ctx, Mockito.never()).reportWarning(Mockito.anyString());
+    }
+
+    @Test
+    /*
+     * Bundle 2 imports org.foo.b from bundle 1, but bundle 1 exports it in a different
+     * region, bundle 1 is in something region, and bundle 2 is in somethingelse region.
+     * However this should still pass as the analyzer is configured to ignore regions.
+     */
+    public void testImportExportWithRegionMismatchIgnoreRegions() throws Exception {
+        String exJson = "[{\"name\": \"something\", \"exports\": [\"org.foo.b\"]}]";
+
+        CheckApiRegionsBundleExportsImports t = new CheckApiRegionsBundleExportsImports();
+
+        Feature f = new Feature(ArtifactId.fromMvnId("f:f:1"));
+        Extension ex = new Extension(ExtensionType.JSON, "api-regions", ExtensionState.OPTIONAL);
+        ex.setJSON(exJson);
+        f.getExtensions().add(ex);
+
+        FeatureDescriptor fd = new FeatureDescriptorImpl(f);
+
+        fdAddBundle(fd, "g:b1:1", "test-bundle1.jar");
+        fdAddBundle(fd, "g:b2:1", "test-bundle2.jar");
+
+        Map<String, String> cfgMap = new HashMap<String, String>();
+        cfgMap.put("fileStorage", resourceRoot + "/origins/testImportExportWithRegionMismatch");
+        cfgMap.put("ignoreAPIRegions", "true");
+
+        AnalyserTaskContext ctx = Mockito.mock(AnalyserTaskContext.class);
+        Mockito.when(ctx.getFeature()).thenReturn(f);
+        Mockito.when(ctx.getFeatureDescriptor()).thenReturn(fd);
+        Mockito.when(ctx.getConfiguration()).thenReturn(cfgMap);
+        t.execute(ctx);
+
+        Mockito.verify(ctx, Mockito.never()).reportError(Mockito.anyString());
+        Mockito.verify(ctx, Mockito.never()).reportWarning(Mockito.anyString());
+    }
+
+    @Test
+    /*
+     * Bundle 3 imports org.foo.a from Bundle 1 and org.foo.e from Bundle 4.
+     * The Feature is in a region called 'blah' which exports nothing, but because
+     * all these bundles are in the same feature they can all see each other.
+     */
+    public void testImportFromOtherBundleInSameFeature() throws Exception {
+        String exJson = "[{\"name\": \"blah\"}]"; // no exports
+
+        CheckApiRegionsBundleExportsImports t = new CheckApiRegionsBundleExportsImports();
+
+        Feature f = new Feature(ArtifactId.fromMvnId("f:f:2"));
+        Extension ex = new Extension(ExtensionType.JSON, "api-regions", ExtensionState.OPTIONAL);
+        ex.setJSON(exJson);
+        f.getExtensions().add(ex);
+
+        FeatureDescriptor fd = new FeatureDescriptorImpl(f);
+
+        fdAddBundle(fd, "g:b1:1", "test-bundle1.jar");
+        fdAddBundle(fd, "g:b3:1", "test-bundle3.jar");
+        fdAddBundle(fd, "g:b4:1", "test-bundle4.jar");
+
+        AnalyserTaskContext ctx = Mockito.mock(AnalyserTaskContext.class);
+        Mockito.when(ctx.getFeature()).thenReturn(f);
+        Mockito.when(ctx.getFeatureDescriptor()).thenReturn(fd);
+        Mockito.when(ctx.getConfiguration()).thenReturn(
+                Collections.singletonMap("fileStorage",
+                        resourceRoot + "/origins/testImportFromOtherBundleInSameFeature"));
+        t.execute(ctx);
+
+        Mockito.verify(ctx, Mockito.never()).reportError(Mockito.anyString());
+        Mockito.verify(ctx, Mockito.never()).reportWarning(Mockito.anyString());
+    }
+
+    @Test
+    /*
+     * Bundle 2 imports org.foo.b from bundle 1. Bundle 1 exports it in the something region
+     * and bundle 2 imports it in the something region, so this succeeds.
+     */
+    public void testImportExportWithMatchingRegion() throws Exception {
+        String exJson = "[{\"name\": \"something\", \"exports\": [\"org.foo.b\"]}]";
+
+        CheckApiRegionsBundleExportsImports t = new CheckApiRegionsBundleExportsImports();
+
+        Feature f = new Feature(ArtifactId.fromMvnId("f:f:1"));
+        Extension ex = new Extension(ExtensionType.JSON, "api-regions", ExtensionState.OPTIONAL);
+        ex.setJSON(exJson);
+        f.getExtensions().add(ex);
+
+        FeatureDescriptor fd = new FeatureDescriptorImpl(f);
+
+        fdAddBundle(fd, "g:b1:1", "test-bundle1.jar");
+        fdAddBundle(fd, "g:b2:1", "test-bundle2.jar");
+
+        AnalyserTaskContext ctx = Mockito.mock(AnalyserTaskContext.class);
+        Mockito.when(ctx.getFeature()).thenReturn(f);
+        Mockito.when(ctx.getFeatureDescriptor()).thenReturn(fd);
+        Mockito.when(ctx.getConfiguration()).thenReturn(
+                Collections.singletonMap("fileStorage",
+                        resourceRoot + "/origins/testImportExportWithMatchingRegion"));
+        t.execute(ctx);
+
+        Mockito.verify(ctx, Mockito.never()).reportError(Mockito.anyString());
+        Mockito.verify(ctx, Mockito.never()).reportWarning(Mockito.anyString());
+    }
+
+    @Test
+    /*
+     * Bundle 2 imports org.foo.b from bundle 1. Bundle 1 exports it in the global region.
+     * Bundle 2 is not explicitly part of the global region, but can still see it
+     */
+    public void testImportFromGlobalAlwaysSucceeds() throws Exception {
+        String exJson = "[{\"name\": \"global\", \"exports\": [\"org.foo.b\"]}]";
+
+        CheckApiRegionsBundleExportsImports t = new CheckApiRegionsBundleExportsImports();
+
+        Feature f = new Feature(ArtifactId.fromMvnId("f:f:1"));
+        Extension ex = new Extension(ExtensionType.JSON, "api-regions", ExtensionState.OPTIONAL);
+        ex.setJSON(exJson);
+        f.getExtensions().add(ex);
+
+        FeatureDescriptor fd = new FeatureDescriptorImpl(f);
+
+        fdAddBundle(fd, "g:b1:1", "test-bundle1.jar");
+        fdAddBundle(fd, "g:b2:1", "test-bundle2.jar");
+
+        AnalyserTaskContext ctx = Mockito.mock(AnalyserTaskContext.class);
+        Mockito.when(ctx.getFeature()).thenReturn(f);
+        Mockito.when(ctx.getFeatureDescriptor()).thenReturn(fd);
+        Mockito.when(ctx.getConfiguration()).thenReturn(
+                Collections.singletonMap("fileStorage",
+                        resourceRoot + "/origins/testImportFromGlobalAlwaysSucceeds"));
+        t.execute(ctx);
+
+        Mockito.verify(ctx, Mockito.never()).reportError(Mockito.anyString());
+        Mockito.verify(ctx, Mockito.never()).reportWarning(Mockito.anyString());
+    }
+
+    private void fdAddBundle(FeatureDescriptor fd, String id, String file) throws IOException {
+        BundleDescriptor bd1 = new BundleDescriptorImpl(
+                new Artifact(ArtifactId.fromMvnId(id)), new File(resourceRoot, file).toURI().toURL(), 0);
+        fd.getBundleDescriptors().add(bd1);
+    }
+}
diff --git a/src/test/resources/origins/testImportExportWithMatchingRegion/f_f_1/bundleOrigins.properties b/src/test/resources/origins/testImportExportWithMatchingRegion/f_f_1/bundleOrigins.properties
new file mode 100644
index 0000000..788c4fa
--- /dev/null
+++ b/src/test/resources/origins/testImportExportWithMatchingRegion/f_f_1/bundleOrigins.properties
@@ -0,0 +1,2 @@
+g\:b1\:1=f\:f1\:1
+g\:b2\:1=f\:f2\:1
diff --git a/src/test/resources/origins/testImportExportWithMatchingRegion/f_f_1/regionOrigins.properties b/src/test/resources/origins/testImportExportWithMatchingRegion/f_f_1/regionOrigins.properties
new file mode 100644
index 0000000..ceb9131
--- /dev/null
+++ b/src/test/resources/origins/testImportExportWithMatchingRegion/f_f_1/regionOrigins.properties
@@ -0,0 +1,2 @@
+f\:f1\:1=something,someotherthing
+f\:f2\:1=something
diff --git a/src/test/resources/origins/testImportExportWithRegionMismatch/f_f_1/bundleOrigins.properties b/src/test/resources/origins/testImportExportWithRegionMismatch/f_f_1/bundleOrigins.properties
new file mode 100644
index 0000000..788c4fa
--- /dev/null
+++ b/src/test/resources/origins/testImportExportWithRegionMismatch/f_f_1/bundleOrigins.properties
@@ -0,0 +1,2 @@
+g\:b1\:1=f\:f1\:1
+g\:b2\:1=f\:f2\:1
diff --git a/src/test/resources/origins/testImportExportWithRegionMismatch/f_f_1/regionOrigins.properties b/src/test/resources/origins/testImportExportWithRegionMismatch/f_f_1/regionOrigins.properties
new file mode 100644
index 0000000..3134d99
--- /dev/null
+++ b/src/test/resources/origins/testImportExportWithRegionMismatch/f_f_1/regionOrigins.properties
@@ -0,0 +1,2 @@
+f\:f1\:1=something,someotherthing
+f\:f2\:1=somethingelse
diff --git a/src/test/resources/origins/testImportExportWithRegionMismatchIgnoreRegions/f_f_1/bundleOrigins.properties b/src/test/resources/origins/testImportExportWithRegionMismatchIgnoreRegions/f_f_1/bundleOrigins.properties
new file mode 100644
index 0000000..788c4fa
--- /dev/null
+++ b/src/test/resources/origins/testImportExportWithRegionMismatchIgnoreRegions/f_f_1/bundleOrigins.properties
@@ -0,0 +1,2 @@
+g\:b1\:1=f\:f1\:1
+g\:b2\:1=f\:f2\:1
diff --git a/src/test/resources/origins/testImportExportWithRegionMismatchIgnoreRegions/f_f_1/regionOrigins.properties b/src/test/resources/origins/testImportExportWithRegionMismatchIgnoreRegions/f_f_1/regionOrigins.properties
new file mode 100644
index 0000000..3134d99
--- /dev/null
+++ b/src/test/resources/origins/testImportExportWithRegionMismatchIgnoreRegions/f_f_1/regionOrigins.properties
@@ -0,0 +1,2 @@
+f\:f1\:1=something,someotherthing
+f\:f2\:1=somethingelse
diff --git a/src/test/resources/origins/testImportExportWithRegionsMissing/f_f_1/bundleOrigins.properties b/src/test/resources/origins/testImportExportWithRegionsMissing/f_f_1/bundleOrigins.properties
new file mode 100644
index 0000000..788c4fa
--- /dev/null
+++ b/src/test/resources/origins/testImportExportWithRegionsMissing/f_f_1/bundleOrigins.properties
@@ -0,0 +1,2 @@
+g\:b1\:1=f\:f1\:1
+g\:b2\:1=f\:f2\:1
diff --git a/src/test/resources/origins/testImportExportWithRegionsMissing/f_f_1/regionOrigins.properties b/src/test/resources/origins/testImportExportWithRegionsMissing/f_f_1/regionOrigins.properties
new file mode 100644
index 0000000..019a972
--- /dev/null
+++ b/src/test/resources/origins/testImportExportWithRegionsMissing/f_f_1/regionOrigins.properties
@@ -0,0 +1 @@
+f\:f1\:1=something
diff --git a/src/test/resources/origins/testImportFromGlobalAlwaysSucceeds/f_f_1/bundleOrigins.properties b/src/test/resources/origins/testImportFromGlobalAlwaysSucceeds/f_f_1/bundleOrigins.properties
new file mode 100644
index 0000000..788c4fa
--- /dev/null
+++ b/src/test/resources/origins/testImportFromGlobalAlwaysSucceeds/f_f_1/bundleOrigins.properties
@@ -0,0 +1,2 @@
+g\:b1\:1=f\:f1\:1
+g\:b2\:1=f\:f2\:1
diff --git a/src/test/resources/origins/testImportFromGlobalAlwaysSucceeds/f_f_1/regionOrigins.properties b/src/test/resources/origins/testImportFromGlobalAlwaysSucceeds/f_f_1/regionOrigins.properties
new file mode 100644
index 0000000..a94edd0
--- /dev/null
+++ b/src/test/resources/origins/testImportFromGlobalAlwaysSucceeds/f_f_1/regionOrigins.properties
@@ -0,0 +1,2 @@
+f\:f1\:1=someotherthing,global,lalala
+f\:f2\:1=something
diff --git a/src/test/resources/origins/testImportFromOtherBundleInSameFeature/f_f_2/bundleOrigins.properties b/src/test/resources/origins/testImportFromOtherBundleInSameFeature/f_f_2/bundleOrigins.properties
new file mode 100644
index 0000000..7910020
--- /dev/null
+++ b/src/test/resources/origins/testImportFromOtherBundleInSameFeature/f_f_2/bundleOrigins.properties
@@ -0,0 +1,4 @@
+g\:b1\:1=f\:f3\:1
+g\:b2\:1=f\:f3\:1
+g\:b3\:1=f\:f3\:1
+g\:b4\:1=f\:f3\:1
diff --git a/src/test/resources/origins/testImportFromOtherBundleInSameFeature/f_f_2/regionOrigins.properties b/src/test/resources/origins/testImportFromOtherBundleInSameFeature/f_f_2/regionOrigins.properties
new file mode 100644
index 0000000..3488a06
--- /dev/null
+++ b/src/test/resources/origins/testImportFromOtherBundleInSameFeature/f_f_2/regionOrigins.properties
@@ -0,0 +1,3 @@
+f\:f1\:1=something,someotherthing
+f\:f2\:1=abc,xyz
+f\:f3\:1=blah
diff --git a/src/test/resources/test-bundle1.jar b/src/test/resources/test-bundle1.jar
new file mode 100644
index 0000000..394c883
Binary files /dev/null and b/src/test/resources/test-bundle1.jar differ
diff --git a/src/test/resources/test-bundle2.jar b/src/test/resources/test-bundle2.jar
new file mode 100644
index 0000000..8fb2589
Binary files /dev/null and b/src/test/resources/test-bundle2.jar differ
diff --git a/src/test/resources/test-bundle3.jar b/src/test/resources/test-bundle3.jar
new file mode 100644
index 0000000..dcc0887
Binary files /dev/null and b/src/test/resources/test-bundle3.jar differ
diff --git a/src/test/resources/test-bundle4.jar b/src/test/resources/test-bundle4.jar
new file mode 100644
index 0000000..27d4f74
Binary files /dev/null and b/src/test/resources/test-bundle4.jar differ
diff --git a/src/test/resources/test-framework.jar b/src/test/resources/test-framework.jar
new file mode 100644
index 0000000..9ce022d
Binary files /dev/null and b/src/test/resources/test-framework.jar differ