This is an automated email from the ASF dual-hosted git repository.
simonetripodi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git
The following commit(s) were added to refs/heads/master by this push:
new ee26e98 [cp2fm] added configurations unit-test cases code refactoring
for correct JSON handling code refactoring for correct Properties handling
ee26e98 is described below
commit ee26e98e29553d5a4febc0f64a9c911be3f2d978
Author: Simo Tripodi <[email protected]>
AuthorDate: Wed Mar 6 17:12:47 2019 +0100
[cp2fm] added configurations unit-test cases
code refactoring for correct JSON handling
code refactoring for correct Properties handling
---
content-package-2-feature-model/pom.xml | 14 ++++
.../ContentPackage2FeatureModelConverter.java | 2 +-
.../AbstractConfigurationEntryHandler.java | 44 +++++-----
.../AbstractSingleConfigurationEntryHandler.java | 55 -------------
.../cp2fm/handlers/ConfigurationEntryHandler.java | 4 +-
.../handlers/JsonConfigurationEntryHandler.java | 47 +++++++++--
.../PropertiesConfigurationEntryHandler.java | 22 +++--
.../handlers/XmlConfigurationEntryHandler.java | 4 +-
.../handlers/ConfigurationEntryHandlerTest.java | 95 ++++++++++++++++++++++
...rviceusermapping.impl.ServiceUserMapperImpl.cfg | 17 ++++
...usermapping.impl.ServiceUserMapperImpl.cfg.json | 7 ++
...ceusermapping.impl.ServiceUserMapperImpl.config | 17 ++++
...rviceusermapping.impl.ServiceUserMapperImpl.xml | 21 +++++
13 files changed, 256 insertions(+), 93 deletions(-)
diff --git a/content-package-2-feature-model/pom.xml
b/content-package-2-feature-model/pom.xml
index 95fb311..2a0ca31 100644
--- a/content-package-2-feature-model/pom.xml
+++ b/content-package-2-feature-model/pom.xml
@@ -201,6 +201,20 @@
<version>3.6.0</version>
<scope>provided</scope>
</dependency>
+
+ <!--
+ | Test only dependencies
+ -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <version>2.25.0</version>
+ </dependency>
</dependencies>
<build>
diff --git
a/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/ContentPackage2FeatureModelConverter.java
b/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/ContentPackage2FeatureModelConverter.java
index 69b694f..edb36b9 100644
---
a/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/ContentPackage2FeatureModelConverter.java
+++
b/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/ContentPackage2FeatureModelConverter.java
@@ -47,7 +47,7 @@ import org.codehaus.plexus.archiver.util.DefaultFileSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public final class ContentPackage2FeatureModelConverter {
+public class ContentPackage2FeatureModelConverter {
public static final String POM_TYPE = "pom";
diff --git
a/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/handlers/AbstractConfigurationEntryHandler.java
b/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/handlers/AbstractConfigurationEntryHandler.java
index 71e1d71..86d0879 100644
---
a/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/handlers/AbstractConfigurationEntryHandler.java
+++
b/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/handlers/AbstractConfigurationEntryHandler.java
@@ -17,6 +17,7 @@
package org.apache.sling.cp2fm.handlers;
import java.io.InputStream;
+import java.util.Dictionary;
import java.util.Enumeration;
import org.apache.jackrabbit.vault.fs.io.Archive;
@@ -37,35 +38,34 @@ abstract class AbstractConfigurationEntryHandler extends
AbstractRegexEntryHandl
logger.info("Processing configuration '{}'.", name);
- Configurations parsedConfigurations;
-
+ Dictionary<String, Object> configurationProperties;
try (InputStream input = archive.openInputStream(entry)) {
- parsedConfigurations = parseConfigurations(name, input);
+ configurationProperties = parseConfiguration(name, input);
+ }
+
+ if (configurationProperties.isEmpty()) {
+ logger.info("No configuration properties found for configuration
{}", path);
+ return;
}
- if (!parsedConfigurations.isEmpty()) {
- for (Configuration currentConfiguration : parsedConfigurations) {
+ Configurations configurations = converter.getTargetFeature()
+ .getConfigurations();
- Configuration configuration = converter.getTargetFeature()
- .getConfigurations()
-
.getConfiguration(currentConfiguration.getPid());
+ Configuration configuration = configurations.getConfiguration(name);
+
+ if (configuration == null) {
+ configuration = new Configuration(name);
+ configurations.add(configuration);
+ }
- if (configuration == null) {
-
converter.getTargetFeature().getConfigurations().add(currentConfiguration);
- } else {
- Enumeration<String> keys =
currentConfiguration.getConfigurationProperties().keys();
- while (keys.hasMoreElements()) {
- String key = keys.nextElement();
- Object value =
currentConfiguration.getConfigurationProperties().get(key);
- configuration.getProperties().put(key, value);
- }
- }
- }
- } else {
- logger.warn("{} configuration is empty, omitting it from the
Feature File", name);
+ Enumeration<String> keys = configurationProperties.keys();
+ while (keys.hasMoreElements()) {
+ String key = keys.nextElement();
+ Object value = configurationProperties.get(key);
+ configuration.getProperties().put(key, value);
}
}
- protected abstract Configurations parseConfigurations(String name,
InputStream input) throws Exception;
+ protected abstract Dictionary<String, Object> parseConfiguration(String
name, InputStream input) throws Exception;
}
diff --git
a/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/handlers/AbstractSingleConfigurationEntryHandler.java
b/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/handlers/AbstractSingleConfigurationEntryHandler.java
deleted file mode 100644
index aff3a11..0000000
---
a/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/handlers/AbstractSingleConfigurationEntryHandler.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.cp2fm.handlers;
-
-import java.io.InputStream;
-import java.util.Dictionary;
-import java.util.Enumeration;
-
-import org.apache.sling.feature.Configuration;
-import org.apache.sling.feature.Configurations;
-
-abstract class AbstractSingleConfigurationEntryHandler extends
AbstractConfigurationEntryHandler {
-
- public AbstractSingleConfigurationEntryHandler(String regex) {
- super(regex);
- }
-
- @Override
- protected final Configurations parseConfigurations(String name,
InputStream input) throws Exception {
- Configurations configurations = new Configurations();
-
- Dictionary<String, Object> configurationProperties =
parseConfiguration(input);
-
- if (!configurationProperties.isEmpty()) {
- Configuration configuration = new Configuration(name);
- Enumeration<String> keys = configurationProperties.keys();
- while (keys.hasMoreElements()) {
- String key = keys.nextElement();
- Object value = configurationProperties.get(key);
- configuration.getProperties().put(key, value);
- }
-
- configurations.add(configuration);
- }
-
- return configurations;
- }
-
- protected abstract Dictionary<String, Object>
parseConfiguration(InputStream input) throws Exception;
-
-}
diff --git
a/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/handlers/ConfigurationEntryHandler.java
b/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/handlers/ConfigurationEntryHandler.java
index 2044cd3..c8838fb 100644
---
a/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/handlers/ConfigurationEntryHandler.java
+++
b/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/handlers/ConfigurationEntryHandler.java
@@ -21,7 +21,7 @@ import java.util.Dictionary;
import org.apache.felix.cm.file.ConfigurationHandler;
-public final class ConfigurationEntryHandler extends
AbstractSingleConfigurationEntryHandler {
+public final class ConfigurationEntryHandler extends
AbstractConfigurationEntryHandler {
public ConfigurationEntryHandler() {
super(".+\\.config");
@@ -29,7 +29,7 @@ public final class ConfigurationEntryHandler extends
AbstractSingleConfiguration
@Override
@SuppressWarnings("unchecked")
- protected Dictionary<String, Object> parseConfiguration(InputStream input)
throws Exception {
+ protected Dictionary<String, Object> parseConfiguration(String name,
InputStream input) throws Exception {
return ConfigurationHandler.read(input);
}
diff --git
a/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/handlers/JsonConfigurationEntryHandler.java
b/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/handlers/JsonConfigurationEntryHandler.java
index 8494b13..401c425 100644
---
a/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/handlers/JsonConfigurationEntryHandler.java
+++
b/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/handlers/JsonConfigurationEntryHandler.java
@@ -16,11 +16,18 @@
*/
package org.apache.sling.cp2fm.handlers;
+import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.net.URL;
+import java.util.Dictionary;
-import org.apache.sling.feature.Configurations;
-import org.apache.sling.feature.io.json.ConfigurationJSONReader;
+import org.apache.commons.io.IOUtils;
+import org.apache.felix.configurator.impl.json.JSONUtil;
+import org.apache.felix.configurator.impl.json.TypeConverter;
+import org.apache.felix.configurator.impl.model.ConfigurationFile;
public final class JsonConfigurationEntryHandler extends
AbstractConfigurationEntryHandler {
@@ -29,10 +36,40 @@ public final class JsonConfigurationEntryHandler extends
AbstractConfigurationEn
}
@Override
- protected Configurations parseConfigurations(String name, InputStream
input) throws Exception {
- try (InputStreamReader reader = new InputStreamReader(input)) {
- return ConfigurationJSONReader.read(reader, name);
+ protected Dictionary<String, Object> parseConfiguration(String name,
InputStream input) throws Exception {
+ StringBuilder content = new StringBuilder()
+ .append("{ \"")
+ .append(name)
+ .append("\" : ");
+ try (Reader reader = new InputStreamReader(input); StringWriter writer
= new StringWriter()) {
+ IOUtils.copy(reader, writer);
+ content.append(writer.toString());
}
+ content.append("}");
+
+ JSONUtil.Report report = new JSONUtil.Report();
+ ConfigurationFile configuration = JSONUtil.readJSON(new
TypeConverter(null),
+ name,
+ new
URL("file://content-package/" + name),
+ 0,
+ content.toString(),
+ report);
+
+ if (!report.errors.isEmpty() || !report.warnings.isEmpty()) {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Errors in configuration:");
+ for (final String w : report.warnings) {
+ builder.append("\n");
+ builder.append(w);
+ }
+ for (final String e : report.errors) {
+ builder.append("\n");
+ builder.append(e);
+ }
+ throw new IOException(builder.toString());
+ }
+
+ return configuration.getConfigurations().get(0).getProperties();
}
}
diff --git
a/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/handlers/PropertiesConfigurationEntryHandler.java
b/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/handlers/PropertiesConfigurationEntryHandler.java
index 54f946f..2628da8 100644
---
a/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/handlers/PropertiesConfigurationEntryHandler.java
+++
b/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/handlers/PropertiesConfigurationEntryHandler.java
@@ -18,19 +18,29 @@ package org.apache.sling.cp2fm.handlers;
import java.io.InputStream;
import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
-import org.apache.felix.utils.properties.ConfigurationHandler;
-
-public final class PropertiesConfigurationEntryHandler extends
AbstractSingleConfigurationEntryHandler {
+public final class PropertiesConfigurationEntryHandler extends
AbstractConfigurationEntryHandler {
public PropertiesConfigurationEntryHandler() {
super("[^/]+\\.(cfg|properties)");
}
@Override
- @SuppressWarnings("unchecked")
- protected Dictionary<String, Object> parseConfiguration(InputStream input)
throws Exception {
- return ConfigurationHandler.read(input);
+ protected Dictionary<String, Object> parseConfiguration(String name,
InputStream input) throws Exception {
+ final Properties properties = new Properties();
+ properties.load(input);
+
+ Dictionary<String, Object> configuration = new Hashtable<>();
+ final Enumeration<Object> i = properties.keys();
+ while (i.hasMoreElements()) {
+ final Object key = i.nextElement();
+ configuration.put(key.toString(), properties.get(key));
+ }
+
+ return configuration;
}
}
diff --git
a/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/handlers/XmlConfigurationEntryHandler.java
b/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/handlers/XmlConfigurationEntryHandler.java
index 57d3513..fb54f88 100644
---
a/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/handlers/XmlConfigurationEntryHandler.java
+++
b/content-package-2-feature-model/src/main/java/org/apache/sling/cp2fm/handlers/XmlConfigurationEntryHandler.java
@@ -30,7 +30,7 @@ import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
-public final class XmlConfigurationEntryHandler extends
AbstractSingleConfigurationEntryHandler {
+public final class XmlConfigurationEntryHandler extends
AbstractConfigurationEntryHandler {
private static final String JCR_ROOT = "jcr:root";
@@ -43,7 +43,7 @@ public final class XmlConfigurationEntryHandler extends
AbstractSingleConfigurat
}
@Override
- protected Dictionary<String, Object> parseConfiguration(InputStream input)
throws Exception {
+ protected Dictionary<String, Object> parseConfiguration(String name,
InputStream input) throws Exception {
SAXParser saxParser = saxParserFactory.newSAXParser();
JcrConfigurationHandler configurationHandler = new
JcrConfigurationHandler();
saxParser.parse(input, configurationHandler);
diff --git
a/content-package-2-feature-model/src/test/java/org/apache/sling/cp2fm/handlers/ConfigurationEntryHandlerTest.java
b/content-package-2-feature-model/src/test/java/org/apache/sling/cp2fm/handlers/ConfigurationEntryHandlerTest.java
new file mode 100644
index 0000000..e682545
--- /dev/null
+++
b/content-package-2-feature-model/src/test/java/org/apache/sling/cp2fm/handlers/ConfigurationEntryHandlerTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.cp2fm.handlers;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.apache.jackrabbit.vault.fs.io.Archive;
+import org.apache.jackrabbit.vault.fs.io.Archive.Entry;
+import org.apache.sling.cp2fm.ContentPackage2FeatureModelConverter;
+import org.apache.sling.feature.Configuration;
+import org.apache.sling.feature.Configurations;
+import org.apache.sling.feature.Feature;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ConfigurationEntryHandlerTest {
+
+ private static final String EXPECTED_PID =
"org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl";
+
+ private final String resourceConfiguration;
+
+ private final AbstractConfigurationEntryHandler configurationEntryHandler;
+
+ public ConfigurationEntryHandlerTest(String resourceConfiguration,
+ AbstractConfigurationEntryHandler
configurationEntryHandler) {
+ this.resourceConfiguration = resourceConfiguration;
+ this.configurationEntryHandler = configurationEntryHandler;
+ }
+
+ @Test
+ public void matches() {
+
assertFalse(configurationEntryHandler.matches("/this/is/a/path/not/pointing/to/a/valid/configuration.asd"));
+ assertTrue(configurationEntryHandler.matches(resourceConfiguration));
+ }
+
+ @Test
+ public void parseConfiguration() throws Exception {
+ Archive archive = mock(Archive.class);
+ Entry entry = mock(Entry.class);
+
+ when(entry.getName()).thenReturn(resourceConfiguration);
+
when(archive.openInputStream(entry)).thenReturn(getClass().getResourceAsStream(resourceConfiguration));
+
+ Feature feature = mock(Feature.class);
+ when(feature.getConfigurations()).thenReturn(new Configurations());
+ ContentPackage2FeatureModelConverter converter =
mock(ContentPackage2FeatureModelConverter.class);
+ when(converter.getTargetFeature()).thenReturn(feature);
+
+ configurationEntryHandler.handle(resourceConfiguration, archive,
entry, converter);
+
+ Configurations configurations =
converter.getTargetFeature().getConfigurations();
+ assertFalse(configurations.isEmpty());
+ assertEquals(1, configurations.size());
+
+ Configuration configuration = configurations.get(0);
+
+ assertTrue(configuration.getPid().startsWith(EXPECTED_PID));
+ assertEquals(2, configuration.getProperties().size());
+ }
+
+ @Parameters
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] {
+ { EXPECTED_PID + ".cfg", new PropertiesConfigurationEntryHandler()
},
+ { EXPECTED_PID + ".cfg.json", new JsonConfigurationEntryHandler()
},
+ { EXPECTED_PID + ".config", new ConfigurationEntryHandler() },
+ { EXPECTED_PID + ".xml", new XmlConfigurationEntryHandler() }
+ });
+ }
+
+}
diff --git
a/content-package-2-feature-model/src/test/resources/org/apache/sling/cp2fm/handlers/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.cfg
b/content-package-2-feature-model/src/test/resources/org/apache/sling/cp2fm/handlers/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.cfg
new file mode 100644
index 0000000..bf91183
--- /dev/null
+++
b/content-package-2-feature-model/src/test/resources/org/apache/sling/cp2fm/handlers/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.cfg
@@ -0,0 +1,17 @@
+# 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.
+
+user.default=admin
+user.mapping=[com.adobe.acs.acs-aem-samples-bundle=admin,com.adobe.acs.acs-aem-samples-bundle:sample-service=oauthservice]
diff --git
a/content-package-2-feature-model/src/test/resources/org/apache/sling/cp2fm/handlers/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.cfg.json
b/content-package-2-feature-model/src/test/resources/org/apache/sling/cp2fm/handlers/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.cfg.json
new file mode 100644
index 0000000..98e506c
--- /dev/null
+++
b/content-package-2-feature-model/src/test/resources/org/apache/sling/cp2fm/handlers/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.cfg.json
@@ -0,0 +1,7 @@
+{
+ "user.default":"admin",
+ "user.mapping": [
+ "com.adobe.acs.acs-aem-samples-bundle=admin",
+ "com.adobe.acs.acs-aem-samples-bundle:sample-service=oauthservice"
+ ]
+}
diff --git
a/content-package-2-feature-model/src/test/resources/org/apache/sling/cp2fm/handlers/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.config
b/content-package-2-feature-model/src/test/resources/org/apache/sling/cp2fm/handlers/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.config
new file mode 100644
index 0000000..4c50ea3
--- /dev/null
+++
b/content-package-2-feature-model/src/test/resources/org/apache/sling/cp2fm/handlers/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.config
@@ -0,0 +1,17 @@
+# 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.
+
+user.default="admin"
+user.mapping=["com.adobe.acs.acs-aem-samples-bundle\=admin","com.adobe.acs.acs-aem-samples-bundle:sample-service\=oauthservice"]
diff --git
a/content-package-2-feature-model/src/test/resources/org/apache/sling/cp2fm/handlers/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.xml
b/content-package-2-feature-model/src/test/resources/org/apache/sling/cp2fm/handlers/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.xml
new file mode 100644
index 0000000..f23afc9
--- /dev/null
+++
b/content-package-2-feature-model/src/test/resources/org/apache/sling/cp2fm/handlers/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0"
+ jcr:primaryType="sling:OsgiConfig"
+ user.default="admin"
+
user.mapping="[com.adobe.acs.acs-aem-samples-bundle=admin,com.adobe.acs.acs-aem-samples-bundle:sample-service=oauthservice]"/>