| /* |
| * 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 org.apache.sling.feature.ArtifactId; |
| import org.apache.sling.feature.Extension; |
| import org.apache.sling.feature.Feature; |
| import org.apache.sling.feature.analyser.Analyser; |
| import org.apache.sling.feature.analyser.AnalyserResult; |
| import org.apache.sling.feature.analyser.AnalyserResult.ArtifactReport; |
| import org.apache.sling.feature.analyser.task.AnalyserTask; |
| import org.apache.sling.feature.builder.ArtifactProvider; |
| import org.apache.sling.feature.extension.apiregions.api.ApiRegions; |
| import org.apache.sling.feature.io.json.FeatureJSONReader; |
| import org.apache.sling.feature.scanner.ContainerDescriptor; |
| import org.apache.sling.feature.scanner.Scanner; |
| import org.apache.sling.feature.scanner.spi.ExtensionScanner; |
| import org.junit.Test; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.StringReader; |
| import java.net.URL; |
| import java.nio.file.Files; |
| import java.nio.file.Path; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertTrue; |
| |
| public class CheckApiRegionsCrossFeatureDupsTest { |
| @Test |
| public void testOverlapError() throws Exception { |
| Path fp = new File(getClass().getResource("/crossfeatdups/fm1.json").getFile()).toPath(); |
| String fm = new String(Files.readAllBytes(fp)); |
| |
| Feature f = FeatureJSONReader.read(new StringReader(fm), null); |
| |
| Scanner scanner = getScanner(); |
| AnalyserTask at = new CheckApiRegionsCrossFeatureDups(); |
| Map<String, Map<String,String>> configs = |
| Collections.singletonMap("api-regions-crossfeature-dups", |
| Collections.singletonMap("warningPackages", "x.y.z")); |
| Analyser a = new Analyser(scanner, configs, at); |
| AnalyserResult res = a.analyse(f); |
| assertEquals(1, res.getArtifactErrors().size()); |
| assertEquals(0, res.getArtifactWarnings().size()); |
| assertEquals(0, res.getGlobalWarnings().size()); |
| assertEquals(0, res.getGlobalErrors().size()); |
| |
| ArtifactReport err = res.getArtifactErrors().get(0); |
| assertEquals(ArtifactId.parse("g:exp2:1"), err.getKey()); |
| assertTrue(err.getValue().contains("a.b.c")); |
| assertTrue(err.getValue().contains("g:f3:1")); |
| assertTrue(err.getValue().contains("feature-export2")); |
| } |
| |
| @Test |
| public void testOverlapWarning() throws Exception { |
| Path fp = new File(getClass().getResource("/crossfeatdups/fm1.json").getFile()).toPath(); |
| String fm = new String(Files.readAllBytes(fp)); |
| |
| Feature f = FeatureJSONReader.read(new StringReader(fm), null); |
| |
| Scanner scanner = getScanner(); |
| CheckApiRegionsCrossFeatureDups at = new CheckApiRegionsCrossFeatureDups(); |
| Map<String, String> cfg = new HashMap<>(); |
| cfg.put("warningPackages", "a.b.c"); |
| cfg.put("ignoredPackages", "x.y.z"); |
| Map<String, Map<String,String>> configs = |
| Collections.singletonMap("api-regions-crossfeature-dups", cfg); |
| Analyser a = new Analyser(scanner, configs, at); |
| AnalyserResult res = a.analyse(f); |
| assertEquals(0, res.getArtifactErrors().size()); |
| assertEquals(1, res.getArtifactWarnings().size()); |
| assertEquals(0, res.getGlobalWarnings().size()); |
| assertEquals(0, res.getGlobalErrors().size()); |
| |
| ArtifactReport err = res.getArtifactWarnings().get(0); |
| assertEquals(ArtifactId.parse("g:exp2:1"), err.getKey()); |
| assertTrue(err.getValue().contains("a.b.c")); |
| assertTrue(err.getValue().contains("g:f3:1")); |
| assertTrue(err.getValue().contains("feature-export2")); |
| } |
| |
| @Test |
| public void testOverlapWarning2() throws Exception { |
| Path fp = new File(getClass().getResource("/crossfeatdups/fm1.json").getFile()).toPath(); |
| String fm = new String(Files.readAllBytes(fp)); |
| |
| Feature f = FeatureJSONReader.read(new StringReader(fm), null); |
| |
| Scanner scanner = getScanner(); |
| CheckApiRegionsCrossFeatureDups at = new CheckApiRegionsCrossFeatureDups(); |
| Map<String, String> cfg = new HashMap<>(); |
| cfg.put("warningPackages", "x.*, a.*"); |
| Map<String, Map<String,String>> configs = |
| Collections.singletonMap("api-regions-crossfeature-dups", cfg); |
| Analyser a = new Analyser(scanner, configs, at); |
| AnalyserResult res = a.analyse(f); |
| assertEquals(0, res.getArtifactErrors().size()); |
| assertEquals(1, res.getArtifactWarnings().size()); |
| assertEquals(0, res.getGlobalWarnings().size()); |
| assertEquals(0, res.getGlobalErrors().size()); |
| |
| ArtifactReport err = res.getArtifactWarnings().get(0); |
| assertEquals(ArtifactId.parse("g:exp2:1"), err.getKey()); |
| assertTrue(err.getValue().contains("a.b.c")); |
| assertTrue(err.getValue().contains("g:f3:1")); |
| assertTrue(err.getValue().contains("feature-export2")); |
| } |
| |
| @Test |
| public void testOverlapIgnore() throws Exception { |
| Path fp = new File(getClass().getResource("/crossfeatdups/fm1.json").getFile()).toPath(); |
| String fm = new String(Files.readAllBytes(fp)); |
| |
| Feature f = FeatureJSONReader.read(new StringReader(fm), null); |
| |
| Scanner scanner = getScanner(); |
| CheckApiRegionsCrossFeatureDups at = new CheckApiRegionsCrossFeatureDups(); |
| Map<String, String> cfg = new HashMap<>(); |
| cfg.put("ignoredPackages", "a.b.c"); |
| Map<String, Map<String,String>> configs = |
| Collections.singletonMap("api-regions-crossfeature-dups", cfg); |
| Analyser a = new Analyser(scanner, configs, at); |
| AnalyserResult res = a.analyse(f); |
| assertEquals(0, res.getArtifactErrors().size()); |
| assertEquals(0, res.getArtifactWarnings().size()); |
| assertEquals(0, res.getGlobalWarnings().size()); |
| assertEquals(0, res.getGlobalErrors().size()); |
| } |
| |
| @Test |
| public void testOverlapError2() throws Exception { |
| Path fp = new File(getClass().getResource("/crossfeatdups/fm1.json").getFile()).toPath(); |
| String fm = new String(Files.readAllBytes(fp)); |
| |
| Feature f = FeatureJSONReader.read(new StringReader(fm), null); |
| |
| Scanner scanner = getScanner2(); |
| AnalyserTask at = new CheckApiRegionsCrossFeatureDups(); |
| Analyser a = new Analyser(scanner, at); |
| AnalyserResult res = a.analyse(f); |
| assertEquals(2, res.getArtifactErrors().size()); |
| assertEquals(0, res.getArtifactWarnings().size()); |
| assertEquals(0, res.getGlobalWarnings().size()); |
| assertEquals(0, res.getGlobalErrors().size()); |
| |
| ArtifactReport err1 = res.getArtifactErrors().get(0); |
| assertEquals(ArtifactId.parse("g:extra:1"), err1.getKey()); |
| assertTrue(err1.getValue().contains("zzz.zzz")); |
| |
| ArtifactReport err2 = res.getArtifactErrors().get(1); |
| assertEquals(ArtifactId.parse("g:exp2:1"), err2.getKey()); |
| assertTrue(err2.getValue().contains("a.b.c")); |
| } |
| |
| @Test |
| public void testOverlapErrorOnlyGlobal() throws Exception { |
| Path fp = new File(getClass().getResource("/crossfeatdups/fm1.json").getFile()).toPath(); |
| String fm = new String(Files.readAllBytes(fp)); |
| |
| Feature f = FeatureJSONReader.read(new StringReader(fm), null); |
| |
| Scanner scanner = getScanner2(); |
| AnalyserTask at = new CheckApiRegionsCrossFeatureDups(); |
| Map<String, Map<String,String>> configs = |
| Collections.singletonMap("api-regions-crossfeature-dups", |
| Collections.singletonMap("regions", "something,global")); |
| Analyser a = new Analyser(scanner, configs, at); |
| AnalyserResult res = a.analyse(f); |
| assertEquals(1, res.getArtifactErrors().size()); |
| assertEquals(0, res.getArtifactWarnings().size()); |
| assertEquals(0, res.getGlobalWarnings().size()); |
| assertEquals(0, res.getGlobalErrors().size()); |
| |
| ArtifactReport err1 = res.getArtifactErrors().get(0); |
| assertEquals(ArtifactId.parse("g:extra:1"), err1.getKey()); |
| assertTrue(err1.getValue().contains("zzz.zzz")); |
| } |
| |
| @Test |
| public void testDefiningFeatures() throws Exception { |
| Path fp = new File(getClass().getResource("/crossfeatdups/fm2.json").getFile()).toPath(); |
| String fm = new String(Files.readAllBytes(fp)); |
| |
| Feature f = FeatureJSONReader.read(new StringReader(fm), null); |
| |
| Scanner scanner = getScanner3(); |
| AnalyserTask at = new CheckApiRegionsCrossFeatureDups(); |
| Map<String, Map<String,String>> configs = |
| Collections.singletonMap("api-regions-crossfeature-dups", |
| Collections.singletonMap("definingFeatures", "g:f1:1")); |
| Analyser a = new Analyser(scanner, configs, at); |
| AnalyserResult res = a.analyse(f); |
| |
| assertEquals(1, res.getErrors().size()); |
| assertEquals(0, res.getWarnings().size()); |
| |
| String err = res.getErrors().get(0); |
| assertTrue(err.contains("org.foo.bar.bingo")); |
| assertTrue(err.contains("g:f2:1")); |
| assertTrue(err.contains("feature-export")); |
| } |
| |
| @Test |
| public void testDefiningFeaturesRegex() throws Exception { |
| Path fp = new File(getClass().getResource("/crossfeatdups/fm2.json").getFile()).toPath(); |
| String fm = new String(Files.readAllBytes(fp)); |
| |
| Feature f = FeatureJSONReader.read(new StringReader(fm), null); |
| |
| Scanner scanner = getScanner3(); |
| AnalyserTask at = new CheckApiRegionsCrossFeatureDups(); |
| Map<String, Map<String,String>> configs = |
| Collections.singletonMap("api-regions-crossfeature-dups", |
| Collections.singletonMap("definingFeatures", "g:f1:*")); |
| Analyser a = new Analyser(scanner, configs, at); |
| AnalyserResult res = a.analyse(f); |
| |
| assertEquals(1, res.getErrors().size()); |
| assertEquals(0, res.getWarnings().size()); |
| |
| String err = res.getErrors().get(0); |
| assertTrue(err.contains("org.foo.bar.bingo")); |
| assertTrue(err.contains("g:f2:1")); |
| assertTrue(err.contains("feature-export")); |
| } |
| |
| @Test |
| public void testMultipleExportsFromNondefiningFeatures() throws Exception { |
| Path fp = new File(getClass().getResource("/crossfeatdups/fm3.json").getFile()).toPath(); |
| String fm = new String(Files.readAllBytes(fp)); |
| |
| Feature f = FeatureJSONReader.read(new StringReader(fm), null); |
| |
| Scanner scanner = getScanner3(); |
| AnalyserTask at = new CheckApiRegionsCrossFeatureDups(); |
| Map<String, Map<String,String>> configs = |
| Collections.singletonMap("api-regions-crossfeature-dups", |
| Collections.singletonMap("definingFeatures", "g:f2:*")); |
| Analyser a = new Analyser(scanner, configs, at); |
| AnalyserResult res = a.analyse(f); |
| |
| assertEquals(0, res.getErrors().size()); |
| assertEquals(0, res.getWarnings().size()); |
| } |
| |
| private Scanner getScanner() throws IOException { |
| ArtifactProvider ap = new ArtifactProvider() { |
| @Override |
| public URL provide(ArtifactId id) { |
| switch (id.toMvnId()) { |
| case "g:exp1:1": |
| return getClass().getResource("/crossfeatdups/test-bundles/feature-export.jar"); |
| case "g:exp2:1": |
| return getClass().getResource("/crossfeatdups/test-bundles/feature-export2.jar"); |
| case "g:noexp:1": |
| return getClass().getResource("/crossfeatdups/test-bundles/no-exports.jar"); |
| case "g:extra:1": |
| return getClass().getResource("/crossfeatdups/test-bundles/no-exports.jar"); |
| case "g:extra:2": |
| return getClass().getResource("/crossfeatdups/test-bundles/feature-export4.jar"); |
| } |
| return null; |
| } |
| }; |
| Scanner scanner = new Scanner(ap, Collections.singletonList(new RegionScanner()), Collections.emptyList()); |
| return scanner; |
| } |
| |
| private Scanner getScanner2() throws IOException { |
| ArtifactProvider ap = new ArtifactProvider() { |
| @Override |
| public URL provide(ArtifactId id) { |
| switch (id.toMvnId()) { |
| case "g:exp1:1": |
| return getClass().getResource("/crossfeatdups/test-bundles/feature-export.jar"); |
| case "g:exp2:1": |
| return getClass().getResource("/crossfeatdups/test-bundles/feature-export2.jar"); |
| case "g:noexp:1": |
| return getClass().getResource("/crossfeatdups/test-bundles/no-exports.jar"); |
| case "g:extra:1": |
| return getClass().getResource("/crossfeatdups/test-bundles/feature-export3.jar"); |
| case "g:extra:2": |
| return getClass().getResource("/crossfeatdups/test-bundles/feature-export4.jar"); |
| } |
| return null; |
| } |
| }; |
| Scanner scanner = new Scanner(ap, Collections.singletonList(new RegionScanner()), Collections.emptyList()); |
| return scanner; |
| } |
| |
| private Scanner getScanner3() throws IOException { |
| ArtifactProvider ap = new ArtifactProvider() { |
| @Override |
| public URL provide(ArtifactId id) { |
| switch (id.toMvnId()) { |
| case "g:exp0:1": |
| return getClass().getResource("/crossfeatdups/test-bundles/feature-export.jar"); |
| case "g:exp1:1": |
| return getClass().getResource("/crossfeatdups/test-bundles/feature-export1.jar"); |
| } |
| return null; |
| } |
| }; |
| Scanner scanner = new Scanner(ap, Collections.singletonList(new RegionScanner()), Collections.emptyList()); |
| return scanner; |
| } |
| |
| private static final class RegionScanner implements ExtensionScanner { |
| |
| @Override |
| public String getId() { |
| return "region"; |
| } |
| |
| @Override |
| public String getName() { |
| return "region"; |
| } |
| |
| @Override |
| public ContainerDescriptor scan(Feature arg0, Extension arg1, ArtifactProvider arg2) throws IOException { |
| if ( arg1.getName().equals(ApiRegions.EXTENSION_NAME) ) { |
| final ContainerDescriptor desc = new ContainerDescriptor(arg1.getName()) { |
| |
| }; |
| desc.lock(); |
| return desc; |
| } |
| return null; |
| } |
| |
| } |
| } |