You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by da...@apache.org on 2018/11/28 13:43:45 UTC

[sling-org-apache-sling-feature-analyser] branch master updated: SLING-8137 Create an analyser that checks the order of API Regions

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 8b24c5d  SLING-8137 Create an analyser that checks the order of API Regions
8b24c5d is described below

commit 8b24c5d0431f8288f982e16ff94a838fe6a14e72
Author: David Bosschaert <bo...@adobe.com>
AuthorDate: Wed Nov 28 13:39:45 2018 +0000

    SLING-8137 Create an analyser that checks the order of API Regions
---
 .../analyser/task/impl/CheckApiRegionsOrder.java   | 122 ++++++++++++++++
 ...apache.sling.feature.analyser.task.AnalyserTask |   1 +
 .../task/impl/CheckApiRegionsOrderTest.java        | 156 +++++++++++++++++++++
 3 files changed, 279 insertions(+)

diff --git a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckApiRegionsOrder.java b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckApiRegionsOrder.java
new file mode 100644
index 0000000..cd7d6bc
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckApiRegionsOrder.java
@@ -0,0 +1,122 @@
+/*
+ * 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.analyser.task.impl;
+
+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 java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.json.Json;
+import javax.json.stream.JsonParser;
+import javax.json.stream.JsonParser.Event;
+
+public class CheckApiRegionsOrder implements AnalyserTask {
+    protected static final String API_REGIONS_KEY = "api-regions";
+
+    @Override
+    public String getId() {
+        return "api-regions-check-order";
+    }
+
+    @Override
+    public final void execute(AnalyserTaskContext ctx) throws Exception {
+        String order = ctx.getConfiguration().get("order");
+        Feature feature = ctx.getFeature();
+        if (feature == null) {
+            reportError(ctx, "No feature found. Illegal Analyser State.");
+            return;
+        }
+
+        if (order == null) {
+            reportError(ctx, "This analyser task must be configured: " + getId() + " for feature " + feature.getId());
+            reportError(ctx, "Must specify configuration key 'order'.");
+            return;
+        }
+
+        String[] sl = order.split("[,]");
+        List<String> prescribedOrder = new ArrayList<>();
+        for (String s : sl) {
+            s = s.trim();
+            if (s.length() > 0)
+                prescribedOrder.add(s);
+        }
+        if (prescribedOrder.size() == 0) {
+            reportError(ctx, "No regions declared in the 'order' configuration");
+            return;
+        }
+
+        // extract and check the api-regions
+        Extensions extensions = feature.getExtensions();
+        Extension apiRegionsExtension = extensions.getByName(API_REGIONS_KEY);
+        if (apiRegionsExtension == null) {
+            // no need to be analyzed
+            return;
+        }
+
+        String jsonRepresentation = apiRegionsExtension.getJSON();
+        if (jsonRepresentation == null || jsonRepresentation.isEmpty()) {
+            // no need to be analyzed
+            return;
+        }
+
+        int regionIdx = 0;
+        JsonParser parser = Json.createParser(new StringReader(jsonRepresentation));
+        while (parser.hasNext()) {
+            Event event = parser.next();
+            if (Event.KEY_NAME == event) {
+                switch (parser.getString()) {
+                case "name":
+                    parser.next();
+                    String name = parser.getString();
+                    if (!prescribedOrder.contains(name)) {
+                        reportError(ctx, "Region found with undeclared name: " + name);
+                        return;
+                    }
+                    int prevIdx = regionIdx;
+                    regionIdx = validateRegion(regionIdx, prescribedOrder, name);
+                    if (regionIdx < 0) {
+                        reportError(ctx, "Region '" + name + "' appears in the wrong order. It appears after '"
+                                + prescribedOrder.get(prevIdx) + "'. Order of regions should be " + prescribedOrder);
+                    }
+                }
+            }
+        }
+    }
+
+    private int validateRegion(int regionIdx, List<String> order, String name) {
+        for (int i=regionIdx; i<order.size(); i++) {
+            if (name.equals(order.get(i))) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    private String getPrefix() {
+        return getId() + ": ";
+    }
+
+    private void reportError(AnalyserTaskContext ctx, String err) {
+        ctx.reportError(getPrefix() + err);
+    }
+}
diff --git a/src/main/resources/META-INF/services/org.apache.sling.feature.analyser.task.AnalyserTask b/src/main/resources/META-INF/services/org.apache.sling.feature.analyser.task.AnalyserTask
index 72ad971..005b143 100644
--- a/src/main/resources/META-INF/services/org.apache.sling.feature.analyser.task.AnalyserTask
+++ b/src/main/resources/META-INF/services/org.apache.sling.feature.analyser.task.AnalyserTask
@@ -5,3 +5,4 @@ org.apache.sling.feature.analyser.task.impl.CheckRequirementsCapabilities
 org.apache.sling.feature.analyser.task.impl.CheckApiRegions
 org.apache.sling.feature.analyser.task.impl.CheckApiRegionsDependencies
 org.apache.sling.feature.analyser.task.impl.CheckApiRegionsDuplicates
+org.apache.sling.feature.analyser.task.impl.CheckApiRegionsOrder
diff --git a/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckApiRegionsOrderTest.java b/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckApiRegionsOrderTest.java
new file mode 100644
index 0000000..65a7d88
--- /dev/null
+++ b/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckApiRegionsOrderTest.java
@@ -0,0 +1,156 @@
+/*
+ * 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.analyser.task.impl;
+
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.ExtensionType;
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.analyser.task.AnalyserTaskContext;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class CheckApiRegionsOrderTest  {
+    @Test
+    public void testValidOrder() throws Exception {
+        CheckApiRegionsOrder caro = new CheckApiRegionsOrder();
+
+        Extension e = new Extension(ExtensionType.JSON, "api-regions", false);
+        e.setJSON("[{\"name\":\"deprecated\","
+                + "\"exports\": [\"a.b.c\"]},"
+                + "{\"name\":\"internal\","
+                + "\"exports\": [\"d.e.f\"]},"
+                + "{\"name\":\"internal\","
+                + "\"exports\": [\"g.h.i\"]}]");
+
+        Feature f = new Feature(ArtifactId.fromMvnId("a:b:1"));
+        f.getExtensions().add(e);
+
+        Map<String, String> cfgMap = new HashMap<>();
+        cfgMap.put("order", "deprecated, internal ");
+
+        AnalyserTaskContext ctx = Mockito.mock(AnalyserTaskContext.class);
+        Mockito.when(ctx.getConfiguration()).thenReturn(cfgMap);
+        Mockito.when(ctx.getFeature()).thenReturn(f);
+
+        caro.execute(ctx);
+        Mockito.verify(ctx, Mockito.never()).reportError(Mockito.anyString());
+    }
+
+    @Test
+    public void testInvalidOrder() throws Exception {
+        CheckApiRegionsOrder caro = new CheckApiRegionsOrder();
+
+        Extension e = new Extension(ExtensionType.JSON, "api-regions", false);
+        e.setJSON("[{\"name\":\"deprecated\","
+                + "\"exports\": [\"a.b.c\"]},"
+                + "{\"name\":\"internal\","
+                + "\"exports\": [\"d.e.f\"]},"
+                + "{\"name\":\"deprecated\","
+                + "\"exports\": [\"g.h.i\"]}]");
+
+        Feature f = new Feature(ArtifactId.fromMvnId("a:b:1"));
+        f.getExtensions().add(e);
+
+        Map<String, String> cfgMap = new HashMap<>();
+        cfgMap.put("order", "deprecated, internal ");
+
+        AnalyserTaskContext ctx = Mockito.mock(AnalyserTaskContext.class);
+        Mockito.when(ctx.getConfiguration()).thenReturn(cfgMap);
+        Mockito.when(ctx.getFeature()).thenReturn(f);
+
+        caro.execute(ctx);
+        Mockito.verify(ctx).reportError(Mockito.contains("wrong order"));
+    }
+
+    @Test
+    public void testInvalidRegion() throws Exception {
+        CheckApiRegionsOrder caro = new CheckApiRegionsOrder();
+
+        Extension e = new Extension(ExtensionType.JSON, "api-regions", false);
+        e.setJSON("[{\"name\":\"foo\"}]");
+
+        Feature f = new Feature(ArtifactId.fromMvnId("a:b:1"));
+        f.getExtensions().add(e);
+
+        Map<String, String> cfgMap = new HashMap<>();
+        cfgMap.put("order", "bar");
+
+        AnalyserTaskContext ctx = Mockito.mock(AnalyserTaskContext.class);
+        Mockito.when(ctx.getConfiguration()).thenReturn(cfgMap);
+        Mockito.when(ctx.getFeature()).thenReturn(f);
+
+        caro.execute(ctx);
+        Mockito.verify(ctx).reportError(Mockito.contains("undeclared"));
+    }
+
+    @Test
+    public void testNoExtensionsIsValid() throws Exception {
+        CheckApiRegionsOrder caro = new CheckApiRegionsOrder();
+
+        Map<String, String> cfgMap = new HashMap<>();
+        cfgMap.put("order", "deprecated, internal ");
+
+        AnalyserTaskContext ctx = Mockito.mock(AnalyserTaskContext.class);
+        Mockito.when(ctx.getConfiguration()).thenReturn(cfgMap);
+        Mockito.when(ctx.getFeature()).thenReturn(new Feature(ArtifactId.fromMvnId("a:b:1")));
+
+        caro.execute(ctx);
+        Mockito.verify(ctx, Mockito.never()).reportError(Mockito.anyString());
+    }
+
+    @Test
+    public void testEmptyOrder() throws Exception {
+        CheckApiRegionsOrder caro = new CheckApiRegionsOrder();
+
+        Map<String, String> cfgMap = new HashMap<>();
+        cfgMap.put("order", " ");
+
+        AnalyserTaskContext ctx = Mockito.mock(AnalyserTaskContext.class);
+        Mockito.when(ctx.getConfiguration()).thenReturn(cfgMap);
+        Mockito.when(ctx.getFeature()).thenReturn(new Feature(ArtifactId.fromMvnId("a:b:1")));
+
+        caro.execute(ctx);
+        Mockito.verify(ctx).reportError(Mockito.contains("No regions"));
+    }
+
+    @Test
+    public void testNoFeature() throws Exception {
+        CheckApiRegionsOrder caro = new CheckApiRegionsOrder();
+
+        AnalyserTaskContext ctx = Mockito.mock(AnalyserTaskContext.class);
+        Mockito.when(ctx.getConfiguration()).thenReturn(new HashMap<>());
+
+        caro.execute(ctx);
+        Mockito.verify(ctx).reportError(Mockito.contains("No feature"));
+    }
+
+    @Test
+    public void testNoOrderConfig() throws Exception {
+        CheckApiRegionsOrder caro = new CheckApiRegionsOrder();
+
+        AnalyserTaskContext ctx = Mockito.mock(AnalyserTaskContext.class);
+        Mockito.when(ctx.getConfiguration()).thenReturn(new HashMap<>());
+        Mockito.when(ctx.getFeature()).thenReturn(new Feature(ArtifactId.fromMvnId("a:b:1")));
+
+        caro.execute(ctx);
+        Mockito.verify(ctx).reportError(Mockito.contains("'order'"));
+    }
+}