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

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

commit 36251afcbe35d76a3893d7962e85b3806b3deb90
Author: David Bosschaert <bossc...@adobe.com>
AuthorDate: Fri Sep 1 15:04:39 2023 +0100

    Expose the bug
---
 .../apiregions/impl/ResolverHookImplTest.java      | 72 +++++++++++++++++++---
 1 file changed, 63 insertions(+), 9 deletions(-)

diff --git 
a/src/test/java/org/apache/sling/feature/apiregions/impl/ResolverHookImplTest.java
 
b/src/test/java/org/apache/sling/feature/apiregions/impl/ResolverHookImplTest.java
index 3f27cb9..46a80e9 100644
--- 
a/src/test/java/org/apache/sling/feature/apiregions/impl/ResolverHookImplTest.java
+++ 
b/src/test/java/org/apache/sling/feature/apiregions/impl/ResolverHookImplTest.java
@@ -18,14 +18,7 @@
  */
 package org.apache.sling.feature.apiregions.impl;
 
-import org.junit.Test;
-import org.mockito.Mockito;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.Version;
-import org.osgi.framework.namespace.PackageNamespace;
-import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.framework.wiring.BundleRequirement;
-import org.osgi.framework.wiring.BundleRevision;
+import static org.junit.Assert.assertEquals;
 
 import java.util.AbstractMap;
 import java.util.ArrayList;
@@ -39,7 +32,14 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
-import static org.junit.Assert.assertEquals;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Version;
+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 ResolverHookImplTest {
     @Test
@@ -812,6 +812,60 @@ public class ResolverHookImplTest {
         assertEquals("There were no candidates, there still are none", 0, 
candidates1.size());
     }
 
+    /* This test exposes a bug that exports the package from the wrong bundle. 
The situation can be reproduced as follows:
+     * - Have a feature f1 that contains a bundle that exports a package, e.g. 
org.soup. Make sure that the feature doesn't
+     *   export the package into an API region.
+     * - Have another feature f2 that contains a different bundle that exports 
the same package. In this case the feature
+     *   exports the package into the 'global' region.
+     * Now when the resolver hook needs to handle the wiring for f2 it gets 2 
candidates, because to OSGi both exporting
+     * bundles are candidates.
+     * The resolver hook finds that org.soup is exported into the global 
region (by f2). Then it looks at what bundles in
+     * the global region and finds that both f1 and f2 are in the global 
region because they are by default.
+     * Then the resolver hook thinks that both candidates are acceptible 
because both are in the global region, so it
+     * produces a wiring to the candidate from f1, even though f1 doesn't 
export the package.
+     *
+     * It should really just return the candidate from f2, but currently the 
data provided to the API regions doesn't have
+     * the richness to know this.
+     */
+    @Test
+    public void testABCXYZ() {
+        Map<Entry<String, Version>, List<String>> bsnvermap = new HashMap<>();
+        bsnvermap.put(new AbstractMap.SimpleEntry<String,Version>(
+                "b1", new Version(1,0,0)), Collections.singletonList("b1"));
+        bsnvermap.put(new AbstractMap.SimpleEntry<String,Version>(
+                "b2", new Version(1,0,0)), Collections.singletonList("b2"));
+
+        Map<String, Set<String>> bfmap = new HashMap<>();
+        bfmap.put("b1", Collections.singleton("g:feat-int:1"));
+        bfmap.put("b2", Collections.singleton("g:feat-global:1"));
+
+        Map<String, List<String>> frmap = new HashMap<>();
+        frmap.put("g:feat-int:1", Arrays.asList("global", 
"org.foo.bar.deprecated"));
+        frmap.put("g:feat-global:1", Arrays.asList("global", 
"org.foo.bar.deprecated"));
+
+        Map<String, Set<String>> rpmap = new HashMap<>();
+        rpmap.put("global", Collections.singleton("spaghetti.soup"));
+
+        RegionConfiguration rc = new RegionConfiguration(bsnvermap, bfmap, 
frmap, rpmap,
+                new HashSet<>(Arrays.asList("global", 
"org.foo.bar.deprecated")));
+
+        ResolverHookImpl rh = new ResolverHookImpl(rc);
+        BundleRequirement req = mockRequirement("b2", bsnvermap);
+        List<BundleCapability> candidates = new ArrayList<>();
+
+        BundleCapability capInt = mockCapability("spaghetti.soup", "b1", 
bsnvermap);
+        BundleCapability capGlob = mockCapability("spaghetti.soup", "b2", 
bsnvermap);
+        candidates.add(capInt);
+        candidates.add(capGlob);
+
+        rh.filterMatches(req, candidates);
+        assertEquals("We should only get the second candidate here because 
that is the one that is exporting " +
+                "spaghetti.soup. However we get both, because the data 
currently doesn't expose what feature exported a package " +
+                "it just states that a package is exported in a certain 
region. So if there is a bundle in a feature that is part " +
+                "of that region and happens to export it, it is automatically 
included, even if that package isn't exported in that feature",
+                1, candidates.size());
+    }
+
     private BundleCapability mockCapability(String pkgName, String bid, 
Map<Entry<String, Version>, List<String>> bsnvermap) {
         for (Map.Entry<Map.Entry<String, Version>, List<String>> entry : 
bsnvermap.entrySet()) {
             if (entry.getValue().contains(bid)) {

Reply via email to