You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by si...@apache.org on 2019/06/11 15:58:33 UTC

[sling-org-apache-sling-feature-analyser] branch SLING-8251 updated: SLING-8251 - Support checking dependencies for content packages

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

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


The following commit(s) were added to refs/heads/SLING-8251 by this push:
     new 23521a7  SLING-8251 - Support checking dependencies for content packages
23521a7 is described below

commit 23521a71469a259a994617f6eac35f28bebfc0b1
Author: Simo Tripodi <st...@adobe.com>
AuthorDate: Tue Jun 11 17:58:24 2019 +0200

    SLING-8251 - Support checking dependencies for content packages
    
    Implementation fixed using Jackrabbit Vault APIs
    Added unit tests
---
 pom.xml                                            |  27 ++++-
 .../impl/CheckContentPackagesDependencies.java     |  99 +++++++---------
 .../impl/CheckContentPackagesDependenciesTest.java | 126 +++++++++++++++++++++
 src/test/resources/test_a-1.0.zip                  | Bin 0 -> 4470 bytes
 src/test/resources/test_b-1.0.zip                  | Bin 0 -> 4442 bytes
 src/test/resources/test_c-1.0.zip                  | Bin 0 -> 4402 bytes
 src/test/resources/test_d-1.0.zip                  | Bin 0 -> 4450 bytes
 src/test/resources/test_e-1.0.zip                  | Bin 0 -> 4439 bytes
 8 files changed, 191 insertions(+), 61 deletions(-)

diff --git a/pom.xml b/pom.xml
index c91d51a..fbc04ae 100644
--- a/pom.xml
+++ b/pom.xml
@@ -143,7 +143,32 @@
             <version>1.11.0</version>
             <scope>provided</scope>
         </dependency>
-        
+
+        <!-- | Content-Package check -->
+        <dependency>
+            <groupId>org.apache.jackrabbit.vault</groupId>
+            <artifactId>org.apache.jackrabbit.vault</artifactId>
+            <version>3.2.6</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.jackrabbit</groupId>
+            <artifactId>jackrabbit-spi-commons</artifactId>
+            <version>2.19.1</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.jcr</groupId>
+            <artifactId>jcr</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.6</version>
+            <scope>provided</scope>
+        </dependency>
+
         <!-- Testing -->
         <dependency>
             <groupId>junit</groupId>
diff --git a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckContentPackagesDependencies.java b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckContentPackagesDependencies.java
index 001fdd5..937472a 100644
--- a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckContentPackagesDependencies.java
+++ b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckContentPackagesDependencies.java
@@ -20,31 +20,22 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.Map;
-import java.util.Properties;
+import java.util.Map.Entry;
 import java.util.Queue;
 import java.util.Set;
-import java.util.StringTokenizer;
-import java.util.TreeSet;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
 
+import org.apache.jackrabbit.vault.packaging.Dependency;
+import org.apache.jackrabbit.vault.packaging.PackageId;
+import org.apache.jackrabbit.vault.packaging.PackageManager;
+import org.apache.jackrabbit.vault.packaging.VaultPackage;
+import org.apache.jackrabbit.vault.packaging.impl.PackageManagerImpl;
 import org.apache.sling.feature.analyser.task.AnalyserTask;
 import org.apache.sling.feature.analyser.task.AnalyserTaskContext;
 import org.apache.sling.feature.scanner.ArtifactDescriptor;
 
 public class CheckContentPackagesDependencies implements AnalyserTask {
 
-    private static final String VAULT_PROPERTIES_XML = "META-INF/vault/properties.xml";
-
-    private static final String GROUP = "group";
-
-    private static final String NAME = "name";
-
-    private static final String VERSION = "version";
-
-    private static final String DEPENDENCIES = "dependencies";
-
-    private static final String DEPENDENCIES_DELIM = ",";
+    private final PackageManager packageManager = new PackageManagerImpl();
 
     @Override
     public String getId() {
@@ -63,68 +54,56 @@ public class CheckContentPackagesDependencies implements AnalyserTask {
             return;
         }
 
-        Map<String, Set<String>> dependenciesMap = new HashMap<>();
+        Map<PackageId, Dependency[]> dependenciesMap = new HashMap<>();
 
         for (ArtifactDescriptor descriptor : descriptors) {
             onDescriptor(ctx, descriptor, dependenciesMap);
         }
 
-        for (String contentPackageId : dependenciesMap.keySet()) {
+        for (PackageId contentPackageId : dependenciesMap.keySet()) {
             verifyDependenciesTree(ctx, contentPackageId, dependenciesMap);
         }
     }
 
-    private void onDescriptor(AnalyserTaskContext ctx, ArtifactDescriptor descriptor, Map<String, Set<String>> dependenciesMap) throws Exception {
-        try (ZipFile zipFile = new ZipFile(descriptor.getArtifactFile())) {
-            ZipEntry propertiesEntry = zipFile.getEntry(VAULT_PROPERTIES_XML);
-
-            if (propertiesEntry == null) {
-                ctx.reportWarning("Content-package file "
-                                  + descriptor.getArtifact().getId()
-                                  + " does not contain the 'META-INF/vault/properties.xml' entry, skipping it");
-                return;
-            }
-
-            Properties properties = new Properties();
-            properties.load(zipFile.getInputStream(propertiesEntry));
-
-            String current = String.format("%s:%s:%s",
-                                           properties.getProperty(GROUP),
-                                           properties.getProperty(NAME),
-                                           properties.getProperty(VERSION));
+    private void onDescriptor(AnalyserTaskContext ctx, ArtifactDescriptor descriptor, Map<PackageId, Dependency[]> dependenciesMap) throws Exception {
+        try (VaultPackage vaultPackage = packageManager.open(descriptor.getArtifactFile(), true)) {
+            PackageId packageId = vaultPackage.getId();
 
-            Set<String> dependenciesSet = dependenciesMap.computeIfAbsent(current, k -> new TreeSet<String>());
-
-            String dependencies = properties.getProperty(DEPENDENCIES);
-            if (dependencies == null || dependencies.isEmpty()) {
-                return;
-            }
-
-            StringTokenizer tokenizer = new StringTokenizer(dependencies, DEPENDENCIES_DELIM);
-            while (tokenizer.hasMoreTokens()) {
-                String dependency = tokenizer.nextToken().trim();
-                dependenciesSet.add(dependency);
-            }
+            dependenciesMap.put(packageId, vaultPackage.getDependencies());
         }
     }
 
-    private void verifyDependenciesTree(AnalyserTaskContext ctx, String root, Map<String, Set<String>> dependenciesMap) {
-        Queue<String> toBeVisited = new LinkedList<>();
-        toBeVisited.add(root);
+    private void verifyDependenciesTree(AnalyserTaskContext ctx, PackageId root, Map<PackageId, Dependency[]> dependenciesMap) {
+        Queue<Dependency> toBeVisited = new LinkedList<>();
+        enqueue(toBeVisited, dependenciesMap.get(root));
 
-        Set<String> alreadyVisited = new HashSet<>();
+        Set<Dependency> alreadyVisited = new HashSet<>();
 
         while (!toBeVisited.isEmpty()) {
-            String current = toBeVisited.poll();
-
-            alreadyVisited.add(current);
-
-            if (!dependenciesMap.containsKey(current)) {
-                ctx.reportError(current + " content-package expected, but not found, as a dependency of " + root);
-            } else {
-                toBeVisited.addAll(dependenciesMap.get(current));
+            Dependency current = toBeVisited.poll();
+
+            if (alreadyVisited.add(current)) {
+                boolean found = false;
+
+                for (Entry<PackageId, Dependency[]> entry : dependenciesMap.entrySet()) {
+                    if (current.matches(entry.getKey())) {
+                        enqueue(toBeVisited, entry.getValue());
+                        found = true;
+                        break;
+                    }
+                }
+
+                if (!found) {
+                    ctx.reportError("Missing " + current + " dependency for " + root);
+                }
             }
         }
     }
 
+    private static void enqueue(Queue<Dependency> target, Dependency...dependencies) {
+        for (Dependency dependency : dependencies) {
+            target.offer(dependency);
+        }
+    }
+
 }
diff --git a/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckContentPackagesDependenciesTest.java b/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckContentPackagesDependenciesTest.java
new file mode 100644
index 0000000..4d5210d
--- /dev/null
+++ b/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckContentPackagesDependenciesTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.sling.feature.Artifact;
+import org.apache.sling.feature.ArtifactId;
+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.scanner.ArtifactDescriptor;
+import org.apache.sling.feature.scanner.FeatureDescriptor;
+import org.apache.sling.feature.scanner.impl.FeatureDescriptorImpl;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class CheckContentPackagesDependenciesTest {
+
+    private AnalyserTask task;
+
+    @Before
+    public void setUp() {
+        task = new CheckContentPackagesDependencies();
+    }
+
+    @After
+    public void tearDown() {
+        task = null;
+    }
+
+    @Test
+    public void dependenciesNotResolvedThrowsError() throws Exception {
+        List<String> errors = execute("test_a-1.0.zip");
+
+        assertFalse(errors.isEmpty());
+
+        Iterator<String> errorsIterator = errors.iterator();
+        assertEquals("Missing my_packages:test_b dependency for my_packages:test_a:1.0", errorsIterator.next());
+        assertEquals("Missing my_packages:test_c:[1.0,2.0) dependency for my_packages:test_a:1.0", errorsIterator.next());
+    }
+
+    @Test
+    public void dependenciesResolved() throws Exception {
+        List<String> errors = execute("test_a-1.0.zip",
+                                      "test_b-1.0.zip",
+                                      "test_c-1.0.zip",
+                                      "test_d-1.0.zip",
+                                      "test_e-1.0.zip");
+        assertTrue(errors.isEmpty());
+    }
+
+    private List<String> execute(String...resources) throws Exception {
+        Feature feature = mock(Feature.class);
+        when(feature.getId()).thenReturn(new ArtifactId("org.apache.sling.testing",
+                                                        "org.apache.sling.testing.contentpackages",
+                                                        "1.0.0",
+                                                        null,
+                                                        null));
+        FeatureDescriptor featureDescriptor = new FeatureDescriptorImpl(feature);
+
+        for (String resource : resources) {
+            ArtifactId id = mock(ArtifactId.class);
+            when(id.toMvnId()).thenReturn(resource);
+            when(id.toString()).thenReturn(resource);
+
+            Artifact artifact = mock(Artifact.class);
+            when(artifact.getId()).thenReturn(id);
+
+            ArtifactDescriptor descriptor = mock(ArtifactDescriptor.class);
+
+            when(descriptor.getArtifact()).thenReturn(artifact);
+
+            URL resourceUrl = getClass().getClassLoader().getResource(resource);
+            String filename = resourceUrl.getFile().replace('/', File.separatorChar);
+            when(descriptor.getArtifactFile()).thenReturn(new File(filename));
+
+            featureDescriptor.getArtifactDescriptors().add(descriptor);
+        }
+
+        AnalyserTaskContext ctx = mock(AnalyserTaskContext.class);
+
+        when(ctx.getFeatureDescriptor()).thenReturn(featureDescriptor);
+
+        List<String> errors = new LinkedList<>();
+
+        doAnswer(invocation -> {
+            String error = invocation.getArgument(0);
+            errors.add(error);
+            return null;
+        }).when(ctx).reportError(anyString());
+
+        task.execute(ctx);
+
+        return errors;
+    }
+
+}
diff --git a/src/test/resources/test_a-1.0.zip b/src/test/resources/test_a-1.0.zip
new file mode 100644
index 0000000..08df03a
Binary files /dev/null and b/src/test/resources/test_a-1.0.zip differ
diff --git a/src/test/resources/test_b-1.0.zip b/src/test/resources/test_b-1.0.zip
new file mode 100644
index 0000000..85fac13
Binary files /dev/null and b/src/test/resources/test_b-1.0.zip differ
diff --git a/src/test/resources/test_c-1.0.zip b/src/test/resources/test_c-1.0.zip
new file mode 100644
index 0000000..245291a
Binary files /dev/null and b/src/test/resources/test_c-1.0.zip differ
diff --git a/src/test/resources/test_d-1.0.zip b/src/test/resources/test_d-1.0.zip
new file mode 100644
index 0000000..7acf3d1
Binary files /dev/null and b/src/test/resources/test_d-1.0.zip differ
diff --git a/src/test/resources/test_e-1.0.zip b/src/test/resources/test_e-1.0.zip
new file mode 100644
index 0000000..372bbb9
Binary files /dev/null and b/src/test/resources/test_e-1.0.zip differ