You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by an...@apache.org on 2021/06/09 12:30:19 UTC

[sling-org-apache-sling-feature-cpconverter] branch SLING-10468 created (now d0dddcb)

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

angela pushed a change to branch SLING-10468
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-cpconverter.git.


      at d0dddcb  SLING-10468 : Converted content package is missing some .content.xml

This branch includes the following new commits:

     new d0dddcb  SLING-10468 : Converted content package is missing some .content.xml

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[sling-org-apache-sling-feature-cpconverter] 01/01: SLING-10468 : Converted content package is missing some .content.xml

Posted by an...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

angela pushed a commit to branch SLING-10468
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-cpconverter.git

commit d0dddcbc46bec71a74dc38b7f5516ab3f78e30b9
Author: angela <an...@adobe.com>
AuthorDate: Wed Jun 9 14:30:01 2021 +0200

    SLING-10468 : Converted content package is missing some .content.xml
---
 .../handlers/AbstractUserEntryHandler.java         |  30 +++++-
 .../cpconverter/handlers/AbstractUserParser.java   |   7 +-
 .../cpconverter/handlers/UsersEntryHandler.java    |  10 +-
 .../ContentPackage2FeatureModelConverterTest.java  | 107 +++++++++++++++------
 .../feature/cpconverter/handlers/TestUtils.java    |  13 +--
 .../apache/sling/feature/cpconverter/demo-cp.zip   | Bin 0 -> 16491 bytes
 6 files changed, 121 insertions(+), 46 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractUserEntryHandler.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractUserEntryHandler.java
index cc2eb1c..6dfdb5f 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractUserEntryHandler.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractUserEntryHandler.java
@@ -16,18 +16,29 @@
  */
 package org.apache.sling.feature.cpconverter.handlers;
 
+import org.apache.commons.io.IOUtils;
 import org.apache.jackrabbit.vault.fs.io.Archive;
 import org.apache.jackrabbit.vault.fs.io.Archive.Entry;
 import org.apache.jackrabbit.vault.util.PlatformNameFormat;
 import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
 import org.apache.sling.feature.cpconverter.shared.RepoPath;
+import org.apache.sling.feature.cpconverter.vltpkg.VaultPackageAssembler;
 import org.jetbrains.annotations.NotNull;
 
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import java.io.ByteArrayInputStream;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.regex.Matcher;
 
 abstract class AbstractUserEntryHandler extends AbstractRegexEntryHandler {
 
+    private final SAXTransformerFactory saxTransformerFactory = (SAXTransformerFactory) TransformerFactory.newInstance();
+    
+    // FIXME: use first segment of 'systemUserRelPath' config value instead of hardcoding 
+    private static final String SYSTEM_USER_SEGMENT = "/system/";
+
     AbstractUserEntryHandler(@NotNull String rexex) {
         super(rexex);
     }
@@ -37,14 +48,23 @@ abstract class AbstractUserEntryHandler extends AbstractRegexEntryHandler {
             throws Exception {
         Matcher matcher = getPattern().matcher(path);
         if (matcher.matches()) {
-            path = matcher.group(1);
-
-            RepoPath originalPath = new RepoPath(PlatformNameFormat.getRepositoryPath(path));
+            RepoPath originalPath = new RepoPath(PlatformNameFormat.getRepositoryPath(matcher.group(1)));
             RepoPath intermediatePath = originalPath.getParent();
 
+            byte[] tmp = IOUtils.toByteArray((archive.openInputStream(entry)));
             AbstractUserParser parser = createParser(converter, originalPath, intermediatePath);
-            try (InputStream input = archive.openInputStream(entry)) {
-                parser.parse(input);
+            boolean converted = parser.parse(new ByteArrayInputStream(tmp));
+            if (!converted && !path.contains(SYSTEM_USER_SEGMENT)) {
+                // write back regular users, groups and their intermediate folders that did not get converted into
+                // repo-init statements to the content package
+                VaultPackageAssembler assembler = converter.getMainPackageAssembler();
+                // FIXME: assembler is null when handler is called from RecollectorVaultPackageScanner (???)
+                if (assembler != null) {
+                    try (InputStream input = new ByteArrayInputStream(tmp);
+                         OutputStream output = assembler.createEntry(path)){
+                        IOUtils.copy(input, output);
+                    }
+                }
             }
         }
     }
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractUserParser.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractUserParser.java
index 354e9fa..338d3f8 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractUserParser.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractUserParser.java
@@ -22,7 +22,7 @@ import org.apache.sling.feature.cpconverter.shared.RepoPath;
 import org.jetbrains.annotations.NotNull;
 import org.xml.sax.Attributes;
 
-abstract class AbstractUserParser extends AbstractJcrNodeParser<Void> {
+abstract class AbstractUserParser extends AbstractJcrNodeParser<Boolean> {
 
     private static final String REP_AUTHORIZABLE_ID = "rep:authorizableId";
 
@@ -54,8 +54,9 @@ abstract class AbstractUserParser extends AbstractJcrNodeParser<Void> {
     }
 
     @Override
-    protected Void getParsingResult() {
-        return null;
+    protected Boolean getParsingResult() {
+        // false for all intermediate paths, regular users and groups
+        return false;
     }
 
     abstract void handleUser(@NotNull String id, @NotNull Attributes attributes);
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/UsersEntryHandler.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/UsersEntryHandler.java
index c55f9f7..e1090ed 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/UsersEntryHandler.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/UsersEntryHandler.java
@@ -47,6 +47,8 @@ public final class UsersEntryHandler extends AbstractUserEntryHandler {
 
         private static final String REP_SYSTEM_USER = "rep:SystemUser";
         private static final String REP_USER = "rep:User";
+        
+        private boolean isSystemUser = false;
 
         /**
          * @param converter - the converter to use.
@@ -64,8 +66,14 @@ public final class UsersEntryHandler extends AbstractUserEntryHandler {
                 converter.getAclManager().addUser(new User(id, path, intermediatePath, disabledReason));
             } else {
                 converter.getAclManager().addSystemUser(new SystemUser(id, path, intermediatePath, disabledReason));
+                isSystemUser = true;
             }
         }
-    }
 
+        @Override
+        protected Boolean getParsingResult() {
+            // intermediate paths and regular users are never handled by repo-init
+            return isSystemUser;
+        }
+    }
 }
diff --git a/src/test/java/org/apache/sling/feature/cpconverter/ContentPackage2FeatureModelConverterTest.java b/src/test/java/org/apache/sling/feature/cpconverter/ContentPackage2FeatureModelConverterTest.java
index 36b0d32..32a39b6 100644
--- a/src/test/java/org/apache/sling/feature/cpconverter/ContentPackage2FeatureModelConverterTest.java
+++ b/src/test/java/org/apache/sling/feature/cpconverter/ContentPackage2FeatureModelConverterTest.java
@@ -71,6 +71,7 @@ import org.apache.sling.feature.cpconverter.handlers.DefaultEntryHandlersManager
 import org.apache.sling.feature.cpconverter.handlers.EntryHandlersManager;
 import org.apache.sling.feature.cpconverter.vltpkg.DefaultPackagesEventsEmitter;
 import org.apache.sling.feature.io.json.FeatureJSONReader;
+import org.jetbrains.annotations.NotNull;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -81,11 +82,11 @@ public class ContentPackage2FeatureModelConverterTest {
      * Test package A-1.0. Depends on B and C-1.X
      * Test package B-1.0. Depends on C
      */
-    private static String[] TEST_PACKAGES_INPUT = { "test_c-1.0.zip", "test_a-1.0.zip", "test_b-1.0.zip" };
+    private static final String[] TEST_PACKAGES_INPUT = { "test_c-1.0.zip", "test_a-1.0.zip", "test_b-1.0.zip" };
 
-    private static String[] TEST_PACKAGES_OUTPUT = { "my_packages:test_c:1.0", "my_packages:test_b:1.0", "my_packages:test_a:1.0" };
+    private static final String[] TEST_PACKAGES_OUTPUT = { "my_packages:test_c:1.0", "my_packages:test_b:1.0", "my_packages:test_a:1.0" };
 
-    private static String[] TEST_PACKAGES_CYCLIC_DEPENDENCY = { "test_d-1.0.zip",
+    private static final String[] TEST_PACKAGES_CYCLIC_DEPENDENCY = { "test_d-1.0.zip",
                                                                 "test_c-1.0.zip",
                                                                 "test_a-1.0.zip",
                                                                 "test_b-1.0.zip",
@@ -156,8 +157,8 @@ public class ContentPackage2FeatureModelConverterTest {
             verifyFeatureFile(outputDirectory,
                             "asd.retail.all.json",
                             "asd.sample:asd.retail.all:slingosgifeature:0.0.1",
-                            Arrays.asList("org.apache.felix:org.apache.felix.framework:6.0.1"),
-                            Arrays.asList("org.apache.sling.commons.log.LogManager.factory.config~asd-retail"),
+                            Collections.singletonList("org.apache.felix:org.apache.felix.framework:6.0.1"),
+                            Collections.singletonList("org.apache.sling.commons.log.LogManager.factory.config~asd-retail"),
                             Arrays.asList("asd.sample:asd.retail.apps:zip:cp2fm-converted:0.0.1",
                                             "asd.sample:Asd.Retail.ui.content:zip:cp2fm-converted:0.0.1",
                                             "asd:Asd.Retail.config:zip:cp2fm-converted:0.0.1",
@@ -165,14 +166,14 @@ public class ContentPackage2FeatureModelConverterTest {
             verifyFeatureFile(outputDirectory,
                             "asd.retail.all-author.json",
                             "asd.sample:asd.retail.all:slingosgifeature:author:0.0.1",
-                            Arrays.asList("org.apache.sling:org.apache.sling.api:2.20.0"),
+                            Collections.singletonList("org.apache.sling:org.apache.sling.api:2.20.0"),
                             Collections.emptyList(),
                             Collections.emptyList());
             verifyFeatureFile(outputDirectory,
                             "asd.retail.all-publish.json",
                             "asd.sample:asd.retail.all:slingosgifeature:publish:0.0.1",
-                            Arrays.asList("org.apache.sling:org.apache.sling.models.api:1.3.8"),
-                            Arrays.asList("org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended~asd-retail"),
+                            Collections.singletonList("org.apache.sling:org.apache.sling.models.api:1.3.8"),
+                            Collections.singletonList("org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended~asd-retail"),
                             Collections.emptyList());
 
             // verify the runmode.mapper integrity
@@ -237,21 +238,20 @@ public class ContentPackage2FeatureModelConverterTest {
             verifyFeatureFile(outputDirectory,
                             "asd.retail.all.json",
                             "asd.sample:asd.retail.all:slingosgifeature:0.0.1",
-                            Arrays.asList("org.apache.felix:org.apache.felix.framework:6.0.1"),
-                            Arrays.asList("org.apache.sling.commons.log.LogManager.factory.config~asd-retail"),
-                            Arrays.asList("asd.sample:asd.retail.apps:zip:cp2fm-converted:0.0.1",
-                                            "asd:Asd.Retail.config:zip:cp2fm-converted:0.0.1"));
+                            Collections.singletonList("org.apache.felix:org.apache.felix.framework:6.0.1"),
+                            Collections.singletonList("org.apache.sling.commons.log.LogManager.factory.config~asd-retail"),
+                            Arrays.asList("asd.sample:asd.retail.apps:zip:cp2fm-converted:0.0.1", "asd:Asd.Retail.config:zip:cp2fm-converted:0.0.1"));
             verifyFeatureFile(outputDirectory,
                             "asd.retail.all-author.json",
                             "asd.sample:asd.retail.all:slingosgifeature:author:0.0.1",
-                            Arrays.asList("org.apache.sling:org.apache.sling.api:2.20.0"),
+                            Collections.singletonList("org.apache.sling:org.apache.sling.api:2.20.0"),
                             Collections.emptyList(),
                             Collections.emptyList());
             verifyFeatureFile(outputDirectory,
                             "asd.retail.all-publish.json",
                             "asd.sample:asd.retail.all:slingosgifeature:publish:0.0.1",
-                            Arrays.asList("org.apache.sling:org.apache.sling.models.api:1.3.8"),
-                            Arrays.asList("org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended~asd-retail"),
+                            Collections.singletonList("org.apache.sling:org.apache.sling.models.api:1.3.8"),
+                            Collections.singletonList("org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended~asd-retail"),
                             Collections.emptyList());
 
             // verify the runmode.mapper integrity
@@ -309,21 +309,21 @@ public class ContentPackage2FeatureModelConverterTest {
             verifyFeatureFile(outputDirectory,
                             "asd.retail.all.json",
                             "asd.sample:asd.retail.all:slingosgifeature:0.0.1",
-                            Arrays.asList("org.apache.felix:org.apache.felix.framework:6.0.1"),
-                            Arrays.asList("org.apache.sling.commons.log.LogManager.factory.config~asd-retail"),
+                            Collections.singletonList("org.apache.felix:org.apache.felix.framework:6.0.1"),
+                            Collections.singletonList("org.apache.sling.commons.log.LogManager.factory.config~asd-retail"),
                             Arrays.asList("asd.sample:asd.retail.apps:zip:cp2fm-converted:0.0.1",
                                     "asd:Asd.Retail.config:zip:cp2fm-converted:0.0.1"));
             verifyFeatureFile(outputDirectory,
                             "asd.retail.all-author.json",
                             "asd.sample:asd.retail.all:slingosgifeature:author:0.0.1",
-                            Arrays.asList("org.apache.sling:org.apache.sling.api:2.20.0"),
+                            Collections.singletonList("org.apache.sling:org.apache.sling.api:2.20.0"),
                             Collections.emptyList(),
                             Collections.emptyList());
             verifyFeatureFile(outputDirectory,
                             "asd.retail.all-publish.json",
                             "asd.sample:asd.retail.all:slingosgifeature:publish:0.0.1",
-                            Arrays.asList("org.apache.sling:org.apache.sling.models.api:1.3.8"),
-                            Arrays.asList("org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended~asd-retail"),
+                            Collections.singletonList("org.apache.sling:org.apache.sling.models.api:1.3.8"),
+                            Collections.singletonList("org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended~asd-retail"),
                             Collections.emptyList());
 
             // verify the runmode.mapper integrity
@@ -584,10 +584,16 @@ public class ContentPackage2FeatureModelConverterTest {
     }
 
     private void verifyContentPackage(File contentPackage, String...expectedEntries) throws Exception {
+        verifyContentPackage(contentPackage, Collections.emptySet(), expectedEntries);
+    }
+    
+    private void verifyContentPackage(File contentPackage, @NotNull Set<String> notExpected, String...expectedEntries) throws Exception {
         try (ZipFile zipFile = new ZipFile(contentPackage)) {
             for (String expectedEntry : expectedEntries) {
-                assertNotNull("Expected entry not found: " + expectedEntry + " in file " + contentPackage,
-                              zipFile.getEntry(expectedEntry));
+                assertNotNull("Expected entry not found: " + expectedEntry + " in file " + contentPackage, zipFile.getEntry(expectedEntry));
+            }
+            for (String notExpectedEntry : notExpected) {
+                assertNull("Not expected entry found: " + notExpectedEntry + " in file " + contentPackage, zipFile.getEntry(notExpectedEntry));
             }
         }
     }
@@ -750,7 +756,7 @@ public class ContentPackage2FeatureModelConverterTest {
         try {
             converter.setBundlesDeployer(new LocalMavenRepositoryArtifactsDeployer(outDir))
             .setFeaturesManager(new DefaultFeaturesManager(false, 5, outDir, null, null, null, new DefaultAclManager())
-                    .setAPIRegions(Arrays.asList("a.b.c")))
+                    .setAPIRegions(Collections.singletonList("a.b.c")))
             .setEmitter(DefaultPackagesEventsEmitter.open(outDir))
             .convert(cpFile);
 
@@ -798,8 +804,8 @@ public class ContentPackage2FeatureModelConverterTest {
             verifyFeatureFile(outputDirectory,
                             "asd.retail.all.json",
                             "${project.groupId}:${project.artifactId}:slingosgifeature:asd.test.all-1.0.0:${project.version}",
-                            Arrays.asList("org.apache.felix:org.apache.felix.framework:6.0.1"),
-                            Arrays.asList("org.apache.sling.commons.log.LogManager.factory.config~asd-retail"),
+                            Collections.singletonList("org.apache.felix:org.apache.felix.framework:6.0.1"),
+                            Collections.singletonList("org.apache.sling.commons.log.LogManager.factory.config~asd-retail"),
                             Arrays.asList("asd.sample:asd.retail.apps:zip:cp2fm-converted:0.0.1",
                                             "asd.sample:Asd.Retail.ui.content:zip:cp2fm-converted:0.0.1",
                                             "asd:Asd.Retail.config:zip:cp2fm-converted:0.0.1",
@@ -807,14 +813,14 @@ public class ContentPackage2FeatureModelConverterTest {
             verifyFeatureFile(outputDirectory,
                             "asd.retail.all-author.json",
                             "${project.groupId}:${project.artifactId}:slingosgifeature:asd.test.all-1.0.0-author:${project.version}",
-                            Arrays.asList("org.apache.sling:org.apache.sling.api:2.20.0"),
+                            Collections.singletonList("org.apache.sling:org.apache.sling.api:2.20.0"),
                             Collections.emptyList(),
                             Collections.emptyList());
             verifyFeatureFile(outputDirectory,
                             "asd.retail.all-publish.json",
                             "${project.groupId}:${project.artifactId}:slingosgifeature:asd.test.all-1.0.0-publish:${project.version}",
-                            Arrays.asList("org.apache.sling:org.apache.sling.models.api:1.3.8"),
-                            Arrays.asList("org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended~asd-retail"),
+                            Collections.singletonList("org.apache.sling:org.apache.sling.models.api:1.3.8"),
+                            Collections.singletonList("org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended~asd-retail"),
                             Collections.emptyList());
 
             verifyContentPackage(new File(outputDirectory, "asd/sample/asd.retail.all/0.0.1/asd.retail.all-0.0.1-cp2fm-converted.zip"),
@@ -978,4 +984,49 @@ public class ContentPackage2FeatureModelConverterTest {
         return loadedResources;
     }
 
+    @Test
+    public void testConvertPackageWithUsersGroupsAndServiceUsers() throws Exception {
+        URL packageUrl = getClass().getResource("demo-cp.zip");
+        File packageFile = FileUtils.toFile(packageUrl);
+        File outputDirectory = new File(System.getProperty("java.io.tmpdir"), getClass().getName() + '_' + System.currentTimeMillis());
+        try {
+            converter.setFeaturesManager(new DefaultFeaturesManager(true, 5, outputDirectory, null, null, null, new DefaultAclManager()))
+                    .setBundlesDeployer(new LocalMavenRepositoryArtifactsDeployer(outputDirectory))
+                    .setEmitter(DefaultPackagesEventsEmitter.open(outputDirectory))
+                    .convert(packageFile);
+
+            File converted = new File(outputDirectory, "my_packages/demo-cp/0.0.0/demo-cp-0.0.0-cp2fm-converted.zip");
+            Set<String> notExpected = new HashSet<>();
+            notExpected.add("jcr_root/apps/demo-cp/.content.xml");
+            notExpected.add("jcr_root/home/users/demo-cp/_rep_policy.xml");
+            notExpected.add("jcr_root/home/groups/demo-cp/_rep_policy.xml");
+            notExpected.add("jcr_root/home/users/system/.content.xml");
+            notExpected.add("jcr_root/home/users/system/_cq_services/.content.xml");
+            notExpected.add("jcr_root/home/users/system/_cq_services/demo-cp/.content.xml");
+            notExpected.add("jcr_root/home/users/system/_cq_services/demo-cp/qStDu7IQBLa95gURmer1/.content.xml");
+            notExpected.add("jcr_root/home/users/system/_cq_services/demo-cp/qStDu7IQBLa95gURmer1/_rep_principalPolicy.xml");
+            verifyContentPackage(converted, 
+                    notExpected,
+                    "META-INF/vault/properties.xml",
+                    "META-INF/vault/config.xml",
+                    "META-INF/vault/filter.xml",
+                    "jcr_root/.content.xml",
+                    "jcr_root/demo-cp/.content.xml",
+                    "jcr_root/demo-cp/_rep_policy.xml",
+                    "jcr_root/apps/.content.xml",
+                    "jcr_root/home/.content.xml",
+                    "jcr_root/home/users/demo-cp/.content.xml",
+                    "jcr_root/home/users/demo-cp/XPXhA_RKMFRKNO8ViIhn/.content.xml",
+                    "jcr_root/home/users/demo-cp/XPXhA_RKMFRKNO8ViIhn/_rep_policy.xml",
+                    "jcr_root/home/groups/.content.xml",
+                    "jcr_root/home/groups/demo-cp/.content.xml",
+                    "jcr_root/home/groups/demo-cp/EsYrXeBdSRkna2kqbxjl/.content.xml",
+                    "jcr_root/home/groups/demo-cp/EsYrXeBdSRkna2kqbxjl/_rep_policy.xml"
+                    );
+
+        } finally {
+            deleteDirTree(outputDirectory);
+        }
+    }
+    
 }
diff --git a/src/test/java/org/apache/sling/feature/cpconverter/handlers/TestUtils.java b/src/test/java/org/apache/sling/feature/cpconverter/handlers/TestUtils.java
index a532490..f470427 100644
--- a/src/test/java/org/apache/sling/feature/cpconverter/handlers/TestUtils.java
+++ b/src/test/java/org/apache/sling/feature/cpconverter/handlers/TestUtils.java
@@ -26,15 +26,13 @@ import org.apache.sling.feature.cpconverter.features.DefaultFeaturesManager;
 import org.apache.sling.feature.cpconverter.features.FeaturesManager;
 import org.apache.sling.feature.cpconverter.vltpkg.VaultPackageAssembler;
 import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.ByteArrayOutputStream;
 import java.io.File;
-import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.security.acl.Acl;
 import java.util.Collections;
 
 import static org.mockito.ArgumentMatchers.anyString;
@@ -49,17 +47,14 @@ class TestUtils {
     private TestUtils() {}
 
     static Extension createRepoInitExtension(@NotNull EntryHandler handler, @NotNull AclManager aclManager, @NotNull String path, @NotNull InputStream is) throws Exception {
-        return createRepoInitExtension(handler, aclManager, path, is, null);
+        return createRepoInitExtension(handler, aclManager, path, is, new ByteArrayOutputStream());
     }
 
-    static Extension createRepoInitExtension(@NotNull EntryHandler handler, @NotNull AclManager aclManager, @NotNull String path, @NotNull InputStream is, @Nullable OutputStream out) throws Exception {
+    static Extension createRepoInitExtension(@NotNull EntryHandler handler, @NotNull AclManager aclManager, @NotNull String path, @NotNull InputStream is, @NotNull OutputStream out) throws Exception {
         Archive archive = mock(Archive.class);
         Archive.Entry entry = mock(Archive.Entry.class);
         VaultPackageAssembler packageAssembler = mock(VaultPackageAssembler.class);
-        if (out != null) {
-            when(packageAssembler.createEntry(anyString())).thenReturn(out);
-        }
-
+        when(packageAssembler.createEntry(anyString())).thenReturn(out);
         when(archive.openInputStream(entry)).thenReturn(is);
 
         Feature feature = new Feature(new ArtifactId("org.apache.sling", "org.apache.sling.cp2fm", "0.0.1", null, null));
diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/demo-cp.zip b/src/test/resources/org/apache/sling/feature/cpconverter/demo-cp.zip
new file mode 100644
index 0000000..8143f45
Binary files /dev/null and b/src/test/resources/org/apache/sling/feature/cpconverter/demo-cp.zip differ