| /* |
| * 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.modelconverter; |
| |
| import org.apache.sling.feature.Bundles; |
| import org.apache.sling.feature.Configurations; |
| import org.apache.sling.feature.Extension; |
| import org.apache.sling.feature.ExtensionType; |
| import org.apache.sling.feature.Extensions; |
| import org.apache.sling.feature.builder.FeatureProvider; |
| import org.apache.sling.feature.io.file.ArtifactHandler; |
| import org.apache.sling.feature.io.file.ArtifactManager; |
| import org.apache.sling.feature.io.file.ArtifactManagerConfig; |
| import org.apache.sling.feature.io.json.FeatureJSONReader; |
| import org.apache.sling.provisioning.model.Artifact; |
| import org.apache.sling.provisioning.model.ArtifactGroup; |
| import org.apache.sling.provisioning.model.Configuration; |
| import org.apache.sling.provisioning.model.Feature; |
| import org.apache.sling.provisioning.model.KeyValueMap; |
| import org.apache.sling.provisioning.model.MergeUtility; |
| import org.apache.sling.provisioning.model.Model; |
| import org.apache.sling.provisioning.model.ModelConstants; |
| import org.apache.sling.provisioning.model.ModelUtility; |
| import org.apache.sling.provisioning.model.ModelUtility.ResolverOptions; |
| import org.apache.sling.provisioning.model.ModelUtility.VariableResolver; |
| import org.apache.sling.provisioning.model.RunMode; |
| import org.apache.sling.provisioning.model.Section; |
| import org.apache.sling.provisioning.model.io.ModelReader; |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.mockito.Mockito; |
| import org.mockito.invocation.InvocationOnMock; |
| import org.mockito.stubbing.Answer; |
| |
| import java.io.File; |
| import java.io.FileReader; |
| import java.io.IOException; |
| import java.io.Reader; |
| import java.io.UncheckedIOException; |
| import java.net.URISyntaxException; |
| import java.nio.file.Files; |
| import java.nio.file.Path; |
| import java.nio.file.Paths; |
| import java.nio.file.StandardOpenOption; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.Dictionary; |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotEquals; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| public class ModelConverterTest { |
| private Path tempDir; |
| private ArtifactManager artifactManager; |
| private FeatureProvider featureProvider; |
| |
| @Before |
| public void setup() throws Exception { |
| String tmpDir = System.getProperty("test.prov.files.tempdir"); |
| if (tmpDir != null) { |
| tempDir = Paths.get(tmpDir); |
| System.out.println("*** Using directory for generated files: " + tempDir); |
| } else { |
| tempDir = Files.createTempDirectory(getClass().getSimpleName()); |
| } |
| artifactManager = ArtifactManager.getArtifactManager( |
| new ArtifactManagerConfig()); |
| featureProvider = |
| id -> { |
| try { |
| File file = artifactManager.getArtifactHandler(id.toMvnUrl()).getFile(); |
| try (Reader reader = new FileReader(file)) { |
| return FeatureJSONReader.read(reader, file.toURI().toURL().toString()); |
| } |
| } catch (IOException e) { |
| throw new UncheckedIOException(e); |
| } |
| }; |
| } |
| |
| @After |
| public void tearDown() throws Exception { |
| if(System.getProperty("test.prov.files.tempdir") == null) { |
| // Delete the temp dir again |
| Files.walk(tempDir) |
| .sorted(Comparator.reverseOrder()) |
| .map(Path::toFile) |
| .forEach(File::delete); |
| } |
| } |
| |
| @Test |
| public void testBootToProvModel() throws Exception { |
| testConvertToProvisioningModel("/boot.json", "/boot.txt"); |
| } |
| |
| @Test |
| public void testBootToFeature() throws Exception { |
| testConvertToFeature("/boot.txt", "/boot.json"); |
| } |
| |
| @Test |
| public void testOakToProvModel() throws Exception { |
| testConvertToProvisioningModel("/oak.json", "/oak.txt"); |
| } |
| |
| @Test |
| public void testSeparateRunmodeFiles() throws Exception { |
| testConvertToProvisioningModel( |
| new String[] { |
| "/runmodeseparation/oak_no_runmode.json", |
| "/runmodeseparation/oak_mongo.json", |
| "/runmodeseparation/oak_tar.json"}, |
| "/oak.txt"); |
| } |
| |
| @Test |
| public void testDifferentSourceIdenticalProvModel() throws Exception { |
| String dir1 = System.getProperty("test.json.dir1"); |
| String dir2 = System.getProperty("test.json.dir2"); |
| |
| File[] files1, files2; |
| if (dir1 != null && dir2 != null) { |
| files1 = new File(dir1).listFiles((d, n) -> n.endsWith(".json")); |
| files2 = new File(dir2).listFiles((d, n) -> n.endsWith(".json")); |
| } else { |
| files1 = new File[] { |
| getFile("/runmodeseparation/oak_no_runmode.json"), |
| getFile("/runmodeseparation/oak_mongo.json"), |
| getFile("/runmodeseparation/oak_tar.json") |
| }; |
| files2 = new File[] {getFile("/oak.json")}; |
| } |
| |
| testConvertToProvisioningModel(files2, files1); |
| } |
| |
| private File getFile(String f) throws URISyntaxException { |
| return new File(getClass().getResource(f).toURI()); |
| } |
| |
| @Test |
| public void testOakToFeature() throws Exception { |
| testConvertToFeature("/oak.txt", "/oak.json"); |
| } |
| |
| @Test |
| public void testRepoinitToProvModel() throws Exception { |
| testConvertToProvisioningModel("/repoinit.json", "/repoinit.txt"); |
| } |
| |
| @Test |
| public void testRepoinitToFeature() throws Exception { |
| testConvertToFeature("/repoinit.txt", "/repoinit.json"); |
| } |
| |
| @Test |
| public void testLaunchpadToProvModel() throws Exception { |
| testConvertToProvisioningModel("/launchpad.json", "/launchpad.txt"); |
| } |
| |
| @Test |
| public void testLaunchpadToFeature() throws Exception { |
| testConvertToFeature("/launchpad.txt", "/launchpad.json"); |
| } |
| |
| @Test |
| public void testSimpleToProvModel() throws Exception { |
| testConvertToProvisioningModel("/simple.json", "/simple.txt"); |
| } |
| |
| @Test |
| public void testSimpleToFeature() throws Exception { |
| testConvertToFeature("/simple.txt", "/simple.json"); |
| } |
| |
| @Test |
| public void testSimpleInheritsToProvModel() throws Exception { |
| testConvertToProvisioningModel("/simple_inherits.json", "/simple_inherits.txt", "/simple.json"); |
| testConvertToProvisioningModel("/simple_inherits.json", "/simple_inherits.txt", "/simple.json", "/simple_inherits.json"); |
| } |
| |
| @Test |
| public void testSimpleInheritsViaMavenRepoToProvModel() throws Exception { |
| artifactManager = Mockito.mock(ArtifactManager.class); |
| Mockito.when(artifactManager.getArtifactHandler(Mockito.anyString())).then(new Answer<ArtifactHandler>() { |
| @Override |
| public ArtifactHandler answer(InvocationOnMock in) throws Throwable { |
| String url = in.getArgument(0).toString(); |
| |
| if (url.endsWith("simple_inherits.json")) { |
| return new ArtifactHandler(url, new File(url)); |
| } else if ("mvn:generated/simple/1.0.0".equals(url)) { |
| return new ArtifactHandler(url, new File(getClass().getResource("/simple.json").toURI())); |
| } |
| return null; |
| } |
| }); |
| |
| testConvertToProvisioningModel("/simple_inherits.json", "/simple_inherits.txt"); |
| } |
| |
| @Test |
| public void testSimple2ToProvModel() throws Exception { |
| testConvertToProvisioningModel("/simple2.json", "/simple2.txt"); |
| } |
| |
| @Test |
| public void testSimple2ToFeature() throws Exception { |
| testConvertToFeature("/simple2.txt", "/simple2.json"); |
| } |
| |
| @Test |
| public void testProvModelRoundtripFolder() throws Exception { |
| String dir = System.getProperty("test.prov.files.dir"); |
| File filesDir; |
| if (dir != null) { |
| filesDir = new File(dir); |
| } else { |
| filesDir = new File(getClass().getResource("/repoinit.txt").toURI()). |
| getParentFile(); |
| } |
| |
| for (File f : filesDir.listFiles((d, n) -> n.endsWith(".txt"))) { |
| testConvertFromProvModelRoundTrip(f); |
| } |
| } |
| |
| @Test |
| public void testModelGAV() throws Exception { |
| String originalProvModel = "/boot.txt"; |
| String expectedJSON = "/boot_gav.json"; |
| |
| File inFile = new File(getClass().getResource(originalProvModel).toURI()); |
| |
| Map<String, Object> options = new HashMap<>(); |
| options.put("groupId", "testing123"); |
| options.put("version", "4.5.6"); |
| List<File> files = ProvisioningToFeature.convert(inFile, tempDir.toFile(), options); |
| assertEquals("The testing code expects a single output file here", 1, files.size()); |
| File outFile = files.get(0); |
| |
| File expectedFile = new File(getClass().getResource(expectedJSON).toURI()); |
| org.apache.sling.feature.Feature expected = FeatureToProvisioning.getFeature(expectedFile); |
| org.apache.sling.feature.Feature actual = FeatureToProvisioning.getFeature(outFile); |
| assertFeaturesEqual(expected, actual); |
| } |
| |
| @Test |
| public void testConvertToProvisioningModelOverwriteLogic() throws Exception { |
| String originalJSON = "/boot.json"; |
| String expectedProvModel = "/boot.txt"; |
| |
| File inFile = new File(getClass().getResource(originalJSON).toURI()); |
| File outFile = new File(tempDir.toFile(), expectedProvModel + ".generated"); |
| |
| FeatureToProvisioning.convert(inFile, outFile, featureProvider); |
| List<String> orgLines = Files.readAllLines(outFile.toPath()); |
| assertNotEquals("Test precondition", "modified!", orgLines.get(orgLines.size() - 1)); |
| |
| // Append to the output file: |
| Files.write(outFile.toPath(), "\nmodified!".getBytes(), StandardOpenOption.APPEND); |
| |
| // Convert again and see that the output file is not modified |
| FeatureToProvisioning.convert(inFile, outFile, featureProvider); |
| |
| List<String> lines = Files.readAllLines(outFile.toPath()); |
| assertEquals("modified!", lines.get(lines.size() - 1)); |
| |
| // Modify the modification time of the generated file to be older than the input file |
| outFile.setLastModified(inFile.lastModified() - 100000); |
| FeatureToProvisioning.convert(inFile, outFile, featureProvider); |
| |
| List<String> owLines = Files.readAllLines(outFile.toPath()); |
| assertEquals("The file should have been overwritten since the source has modified since it's edit timestamp", |
| orgLines, owLines); |
| } |
| |
| @Test |
| public void testConvertToFeature() throws Exception { |
| File inFile = new File(getClass().getResource("/boot.txt").toURI()); |
| |
| List<File> files = ProvisioningToFeature.convert(inFile, tempDir.toFile(), Collections.emptyMap()); |
| assertEquals("The testing code expects a single output file here", 1, files.size()); |
| File outFile = files.get(0); |
| |
| List<String> orgLines = Files.readAllLines(outFile.toPath()); |
| assertNotEquals("Test precondition", "modified!", orgLines.get(orgLines.size() - 1)); |
| |
| // Append to the output file: |
| Files.write(outFile.toPath(), "\nmodified!".getBytes(), StandardOpenOption.APPEND); |
| |
| // Convert again and see that the output file is not modified |
| List<File> files2 = ProvisioningToFeature.convert(inFile, tempDir.toFile(), Collections.emptyMap()); |
| assertEquals("Should return the same file list", files, files2); |
| |
| List<String> lines = Files.readAllLines(outFile.toPath()); |
| assertEquals("modified!", lines.get(lines.size() - 1)); |
| |
| // Modify the modification time of the generated file to be older than the input file |
| outFile.setLastModified(inFile.lastModified() - 100000); |
| List<File> files3 = ProvisioningToFeature.convert(inFile, tempDir.toFile(), Collections.emptyMap()); |
| assertEquals("Should return the same file list", files, files3); |
| |
| List<String> owLines = Files.readAllLines(outFile.toPath()); |
| assertEquals("The file should have been overwritten since the source has modified since it's edit timestamp", |
| orgLines, owLines); |
| } |
| |
| @Test |
| public void testMultipleRepoinitSections() throws Exception { |
| testConvertToFeature("/more/repoinit-multiple.txt", "/more/repoinit-multiple.json"); |
| } |
| |
| public void testConvertFromProvModelRoundTrip(File orgProvModel) throws Exception { |
| System.out.println("*** Roundtrip converting: " + orgProvModel.getName()); |
| List<File> allGenerateProvisioningModelFiles = new ArrayList<>(); |
| |
| List<File> generated = ProvisioningToFeature.convert(orgProvModel, tempDir.toFile(), Collections.emptyMap()); |
| |
| for (File f : generated) { |
| String baseName = f.getName().substring(0, f.getName().length() - ".json".length()); |
| assertFalse("File name cannot contain a colon", baseName.contains(":")); |
| File genFile = new File(tempDir.toFile(), baseName + ".txt"); |
| allGenerateProvisioningModelFiles.add(genFile); |
| FeatureToProvisioning.convert(f, genFile, featureProvider); |
| } |
| |
| Model expected = readProvisioningModel(orgProvModel); |
| Model actual = readProvisioningModel(allGenerateProvisioningModelFiles); |
| assertModelsEqual(expected, actual); |
| } |
| |
| public void testConvertToFeature(String originalProvModel, String expectedJSON) throws Exception { |
| File inFile = new File(getClass().getResource(originalProvModel).toURI()); |
| |
| List<File> files = ProvisioningToFeature.convert(inFile, tempDir.toFile(), Collections.emptyMap()); |
| assertEquals("The testing code expects a single output file here", 1, files.size()); |
| File outFile = files.get(0); |
| |
| File expectedFile = new File(getClass().getResource(expectedJSON).toURI()); |
| org.apache.sling.feature.Feature expected = FeatureToProvisioning.getFeature(expectedFile); |
| org.apache.sling.feature.Feature actual = FeatureToProvisioning.getFeature(outFile); |
| assertFeaturesEqual(expected, actual); |
| } |
| |
| public void testConvertToProvisioningModel(String originalJSON, String expectedProvModel, String ... additionalContextFiles) throws URISyntaxException, IOException { |
| File inFile = new File(getClass().getResource(originalJSON).toURI()); |
| File outFile = new File(tempDir.toFile(), expectedProvModel + ".generated"); |
| List<File> addFiles = new ArrayList<>(); |
| for (String af : additionalContextFiles) { |
| addFiles.add(new File(getClass().getResource(af).toURI())); |
| } |
| |
| FeatureToProvisioning.convert(inFile, outFile, featureProvider, addFiles.toArray(new File[] {})); |
| |
| File expectedFile = new File(getClass().getResource(expectedProvModel).toURI()); |
| Model expected = readProvisioningModel(expectedFile); |
| Model actual = readProvisioningModel(outFile); |
| assertModelsEqual(expected, actual); |
| } |
| |
| public void testConvertToProvisioningModel(String [] jsonFiles, String expectedProvModel) throws URISyntaxException, IOException { |
| List<File> inFiles = new ArrayList<>(); |
| for (String jf : jsonFiles) { |
| inFiles.add(new File(getClass().getResource(jf).toURI())); |
| } |
| |
| List<File> generatedFiles = convertFeatureFilesToProvisioningModel(inFiles.toArray(new File[] {})); |
| |
| File expectedFile = new File(getClass().getResource(expectedProvModel).toURI()); |
| Model expected = readProvisioningModel(expectedFile); |
| Model actual = readProvisioningModel(generatedFiles); |
| assertModelsEqual(expected, actual); |
| assertModelsEqual(actual, expected); |
| } |
| |
| public void testConvertToProvisioningModel(File[] jsonFiles1, File[] jsonFiles2) throws URISyntaxException, IOException { |
| List<File> generatedFiles1 = convertFeatureFilesToProvisioningModel(jsonFiles1); |
| List<File> generatedFiles2 = convertFeatureFilesToProvisioningModel(jsonFiles2); |
| |
| Model actual1 = readProvisioningModel(generatedFiles1); |
| Model actual2 = readProvisioningModel(generatedFiles2); |
| assertModelsEqual(actual1, actual2); |
| assertModelsEqual(actual2, actual1); |
| } |
| |
| private List<File> convertFeatureFilesToProvisioningModel(File[] jsonFiles) throws URISyntaxException, IOException { |
| List<File> generatedFiles = new ArrayList<>(); |
| for (File inFile : jsonFiles) { |
| File outFile; |
| int counter = 0; |
| do { |
| outFile = new File(tempDir.toFile(), inFile.getName() + (counter++) + ".txt.generated"); |
| } while (outFile.exists()); |
| |
| FeatureToProvisioning.convert(inFile, outFile, featureProvider); |
| generatedFiles.add(outFile); |
| } |
| return generatedFiles; |
| } |
| |
| private static Model readProvisioningModel(File modelFile) throws IOException { |
| return readProvisioningModel(Collections.singletonList(modelFile)); |
| } |
| |
| private static Model readProvisioningModel(List<File> modelFiles) throws IOException { |
| Model model = null; |
| for (File modelFile : modelFiles) { |
| try (FileReader fr = new FileReader(modelFile)) { |
| Model nextModel = ModelReader.read(fr, modelFile.getAbsolutePath()); |
| |
| if (model == null) { |
| model = nextModel; |
| } else { |
| MergeUtility.merge(model, nextModel); |
| } |
| } |
| } |
| |
| // Fix the configurations up from the internal format to the Dictionary-based format |
| return ModelUtility.getEffectiveModel(model, |
| new ResolverOptions().variableResolver(new VariableResolver() { |
| @Override |
| public String resolve(final Feature feature, final String name) { |
| // Keep variables as-is in the model |
| return "${" + name + "}"; |
| } |
| })); |
| } |
| |
| private void assertFeaturesEqual(org.apache.sling.feature.Feature expected, org.apache.sling.feature.Feature actual) { |
| assertEquals(expected.getId(), actual.getId()); |
| assertEquals(expected.getTitle(), actual.getTitle()); |
| assertEquals(expected.getDescription(), actual.getDescription()); |
| assertEquals(expected.getVendor(), actual.getVendor()); |
| assertEquals(expected.getLicense(), actual.getLicense()); |
| |
| assertEquals(expected.getVariables(), actual.getVariables()); |
| assertBundlesEqual(expected.getBundles(), actual.getBundles()); |
| assertConfigurationsEqual(expected.getConfigurations(), actual.getConfigurations(), expected.getBundles(), actual.getBundles()); |
| assertEquals(expected.getFrameworkProperties(), actual.getFrameworkProperties()); |
| assertExtensionEqual(expected.getExtensions(), actual.getExtensions()); |
| |
| // Ignore caps and reqs, includes and here since they cannot come from the prov model. |
| } |
| |
| private void assertBundlesEqual(Bundles expected, Bundles actual) { |
| for (Iterator<org.apache.sling.feature.Artifact> it = expected.iterator(); it.hasNext(); ) { |
| org.apache.sling.feature.Artifact ex = it.next(); |
| |
| boolean found = false; |
| for (Iterator<org.apache.sling.feature.Artifact> it2 = actual.iterator(); it2.hasNext(); ) { |
| org.apache.sling.feature.Artifact ac = it2.next(); |
| if (ac.getId().equals(ex.getId())) { |
| found = true; |
| assertEquals(ex.getMetadata(), ac.getMetadata()); |
| break; |
| } |
| } |
| assertTrue("Not found: " + ex, found); |
| } |
| } |
| |
| private void assertConfigurationsEqual(Configurations expected, Configurations actual, Bundles exBundles, Bundles acBundles) { |
| for (Iterator<org.apache.sling.feature.Configuration> it = expected.iterator(); it.hasNext(); ) { |
| org.apache.sling.feature.Configuration ex = it.next(); |
| |
| boolean found = false; |
| for (Iterator<org.apache.sling.feature.Configuration> it2 = actual.iterator(); it2.hasNext(); ) { |
| org.apache.sling.feature.Configuration ac = it2.next(); |
| if (ex.getPid().equals(ac.getPid())) { |
| found = true; |
| assertConfigProps(ex, ac, exBundles, acBundles); |
| } |
| } |
| assertTrue(found); |
| } |
| } |
| |
| private void assertConfigProps(org.apache.sling.feature.Configuration expected, org.apache.sling.feature.Configuration actual, Bundles exBundles, Bundles acBundles) { |
| assertTrue("Configurations not equal: " + expected.getProperties() + " vs " + actual.getProperties(), |
| configPropsEqual(expected.getProperties(), actual.getProperties())); |
| } |
| |
| private boolean configPropsEqual(Dictionary<String, Object> d1, Dictionary<String, Object> d2) { |
| if (d1.size() != d2.size()) { |
| return false; |
| } |
| |
| for (Enumeration<String> e = d1.keys(); e.hasMoreElements(); ) { |
| String k = e.nextElement(); |
| Object v = d1.get(k); |
| if (v instanceof Object[]) { |
| if (!Arrays.equals((Object[]) v, (Object[]) d2.get(k))) |
| return false; |
| } else { |
| if (!v.equals(d2.get(k))) |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| private void assertModelsEqual(Model expected, Model actual) { |
| for (int i=0; i<expected.getFeatures().size(); i++) { |
| Feature expectedFeature = expected.getFeatures().get(i); |
| Feature actualFeature = actual.getFeatures().get(i); |
| assertFeaturesEqual(expectedFeature, actualFeature); |
| } |
| } |
| |
| private void assertFeaturesEqual(Feature expected, Feature actual) { |
| assertEquals(expected.getName(), actual.getName()); |
| assertEquals(expected.getVersion(), actual.getVersion()); |
| assertEquals(expected.getType(), actual.getType()); |
| assertRunModesEqual(expected.getName(), expected.getRunModes(), actual.getRunModes()); |
| assertKVMapEquals(expected.getVariables(), actual.getVariables()); |
| assertSectionsEqual(expected.getAdditionalSections(), actual.getAdditionalSections()); |
| } |
| |
| private void assertRunModesEqual(String featureName, List<RunMode> expected, List<RunMode> actual) { |
| assertEquals(expected.size(), actual.size()); |
| for (RunMode rm : expected) { |
| boolean found = false; |
| for (RunMode arm : actual) { |
| if (runModesEqual(featureName, rm, arm)) { |
| found = true; |
| break; |
| } |
| |
| } |
| if (!found) { |
| fail("Run Mode " + rm + " not found in actual list " + actual); |
| } |
| } |
| } |
| |
| private boolean runModesEqual(String featureName, RunMode rm1, RunMode rm2) { |
| if (rm1.getNames() == null) { |
| if (rm2.getNames() != null) |
| return false; |
| } else { |
| if (rm2.getNames() == null) |
| return false; |
| |
| HashSet<String> names1 = new HashSet<>(Arrays.asList(rm1.getNames())); |
| HashSet<String> names2 = new HashSet<>(Arrays.asList(rm2.getNames())); |
| |
| if (!names1.equals(names2)) |
| return false; |
| } |
| |
| List<ArtifactGroup> ag1 = rm1.getArtifactGroups(); |
| List<ArtifactGroup> ag2 = rm2.getArtifactGroups(); |
| if (ag1.size() != ag2.size()) |
| return false; |
| |
| for (ArtifactGroup g1 : ag1) { |
| boolean found = false; |
| for (ArtifactGroup g2 : ag2) { |
| if (artifactGroupsEquals(featureName, g1, g2)) { |
| found = true; |
| break; |
| } |
| } |
| if (!found) |
| return false; |
| } |
| |
| List<Configuration> configs1 = new ArrayList<>(); |
| rm1.getConfigurations().iterator().forEachRemaining(configs1::add); |
| List<Configuration> configs2 = new ArrayList<>(); |
| rm2.getConfigurations().iterator().forEachRemaining(configs2::add); |
| if (configs1.size() != configs2.size()) |
| return false; |
| |
| for (int i=0; i < configs1.size(); i++) { |
| Configuration cfg1 = configs1.get(i); |
| |
| boolean found = false; |
| for (Configuration cfg2 : configs2) { |
| if (cfg1.getFactoryPid() == null) { |
| if (cfg2.getFactoryPid() != null) { |
| continue; |
| } |
| } else if (!cfg1.getFactoryPid().equals(cfg2.getFactoryPid())) { |
| continue; |
| } |
| |
| if (!cfg1.getPid().equals(cfg2.getPid())) { |
| continue; |
| } |
| |
| // Factory and ordinary PIDs are equal, so check the content |
| found = true; |
| |
| if (!configPropsEqual(cfg1.getProperties(), cfg2.getProperties())) { |
| return false; |
| } |
| |
| break; |
| } |
| if (!found) { |
| // Configuration with this PID not found |
| return false; |
| } |
| } |
| |
| Map<String, String> m1 = kvToMap(rm1.getSettings()); |
| Map<String, String> m2 = kvToMap(rm2.getSettings()); |
| |
| return m1.equals(m2); |
| } |
| |
| private Map<String, String> kvToMap(KeyValueMap<String> kvm) { |
| Map<String, String> m = new HashMap<>(); |
| |
| for (Map.Entry<String, String> entry : kvm) { |
| m.put(entry.getKey(), entry.getValue()); |
| } |
| |
| return m; |
| } |
| |
| private boolean artifactGroupsEquals(String featureName, ArtifactGroup g1, ArtifactGroup g2) { |
| int sl1 = effectiveStartLevel(featureName, g1.getStartLevel()); |
| int sl2 = effectiveStartLevel(featureName, g2.getStartLevel()); |
| if (sl1 != sl2) |
| return false; |
| |
| List<Artifact> al1 = new ArrayList<>(); |
| g1.iterator().forEachRemaining(al1::add); |
| |
| List<Artifact> al2 = new ArrayList<>(); |
| g2.iterator().forEachRemaining(al2::add); |
| |
| for (int i=0; i<al1.size(); i++) { |
| Artifact a1 = al1.get(i); |
| boolean found = false; |
| for (Iterator<Artifact> it = al2.iterator(); it.hasNext(); ) { |
| Artifact a2 = it.next(); |
| if (a1.compareTo(a2) == 0) { |
| found = true; |
| it.remove(); |
| } |
| } |
| if (!found) { |
| return false; |
| } |
| } |
| |
| // Should have found all artifacts |
| return (al2.size() == 0); |
| } |
| |
| private int effectiveStartLevel(String featureName, int startLevel) { |
| if (startLevel != 0) |
| return startLevel; |
| |
| if (ModelConstants.FEATURE_BOOT.equals(featureName)) { |
| return 1; |
| } else { |
| return 20; |
| } |
| } |
| |
| private void assertKVMapEquals(KeyValueMap<String> expected, KeyValueMap<String> actual) { |
| assertEquals(kvToMap(expected), kvToMap(actual)); |
| } |
| |
| private void assertExtensionEqual(Extensions expected, Extensions actual) { |
| assertEquals(expected.size(), actual.size()); |
| |
| for (int i=0; i<expected.size(); i++) { |
| // TODO support the fact that they may be out of order |
| Extension ex = expected.get(i); |
| Extension ac = actual.get(i); |
| |
| assertEquals(ex.getType(), ac.getType()); |
| assertEquals(ex.getName(), ac.getName()); |
| assertEquals(ex.isRequired(), ac.isRequired()); |
| |
| if (ex.getType() == ExtensionType.TEXT) { |
| String exTxt = ex.getText().replaceAll("\\s+", ""); |
| String acTxt = ac.getText().replaceAll("\\s+", ""); |
| assertEquals(exTxt, acTxt); |
| } else if (ex.getType() == ExtensionType.JSON) { |
| String exJson = ex.getJSON().replaceAll("\\s+", "").replaceAll("\"\",", ""); |
| String acJson = ac.getJSON().replaceAll("\\s+", "").replaceAll("\"\",", ""); |
| assertEquals(exJson, acJson); |
| } |
| |
| /* TODO reinstantiate for Artifacts extentions |
| assertEquals(ex.getArtifacts().size(), ac.getArtifacts().size()); |
| for (int j = 0; j<ex.getArtifacts().size(); j++) { |
| org.apache.sling.feature.Artifact exa = ex.getArtifacts().get(j); |
| org.apache.sling.feature.Artifact aca = ac.getArtifacts().get(j); |
| assertEquals(exa.getId().toMvnId(), aca.getId().toMvnId()); |
| } |
| */ |
| } |
| } |
| |
| private void assertSectionsEqual(List<Section> expected, List<Section> actual) { |
| assertEquals(expected.size(), actual.size()); |
| |
| for (int i=0; i<expected.size(); i++) { |
| Section esec = expected.get(i); |
| Section asec = actual.get(i); |
| assertEquals(esec.getName(), asec.getName()); |
| assertEquals(esec.getContents().replaceAll("\\s+", ""), |
| asec.getContents().replaceAll("\\s+", "")); |
| assertEquals(esec.getAttributes(), asec.getAttributes()); |
| } |
| } |
| } |