/*
* JBoss, Home of Professional Open Source.
* Copyright 2015, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.as.patching.tests;
import static org.junit.Assert.assertEquals;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.List;
import org.jboss.as.patching.metadata.ContentItem;
import org.jboss.as.patching.metadata.ContentModification;
import org.jboss.as.patching.metadata.ContentType;
import org.jboss.as.patching.metadata.Identity;
import org.jboss.as.patching.metadata.Identity.IdentityUpgrade;
import org.jboss.as.patching.metadata.LayerType;
import org.jboss.as.patching.metadata.ModificationType;
import org.jboss.as.patching.metadata.ModuleItem;
import org.jboss.as.patching.metadata.Patch;
import org.jboss.as.patching.metadata.Patch.PatchType;
import org.jboss.as.patching.metadata.PatchBuilder;
import org.jboss.as.patching.metadata.PatchElement;
import org.jboss.as.patching.metadata.PatchElementBuilder;
import org.jboss.as.patching.metadata.PatchElementProvider;
import org.jboss.as.patching.metadata.PatchMerger;
import org.jboss.as.patching.runner.PatchUtils;
import org.junit.Assert;
import org.junit.Test;
/**
*
* @author Alexey Loubyansky
*/
public class MergingPatchMetadataTestCase {
protected static final MessageDigest DIGEST;
static {
try {
DIGEST = MessageDigest.getInstance("SHA-1");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
static byte[] digest(String str) {
DIGEST.reset();
return DIGEST.digest(str.getBytes(StandardCharsets.UTF_8));
}
@Test
public void testAddModify() throws Exception {
final Patch cp1 = generateCP("base", "cp1", ModificationType.ADD);
final Patch cp2 = generateCP("cp1", "cp2", ModificationType.MODIFY);
final Patch merged = PatchMerger.merge(cp1, cp2);
assertEquals("cp2", merged.getPatchId());
assertEquals("cp2" + " description", merged.getDescription());
final IdentityUpgrade identity = merged.getIdentity().forType(PatchType.CUMULATIVE, Identity.IdentityUpgrade.class);
assertEquals("base", identity.getVersion());
assertEquals("cp2", identity.getResultingVersion());
assertEquals(PatchType.CUMULATIVE, identity.getPatchType());
final List<PatchElement> elements = merged.getElements();
assertEquals(1, elements.size());
final PatchElement e = elements.get(0);
assertEquals("base-" + "cp2", e.getId());
final PatchElementProvider provider = e.getProvider();
assertEquals("base", provider.getName());
assertEquals(PatchType.CUMULATIVE, provider.getPatchType());
assertEquals(LayerType.Layer, provider.getLayerType());
assertEquals(3, e.getModifications().size());
for(ContentModification mod : e.getModifications()) {
assertEquals(ModificationType.ADD, mod.getType());
final ContentItem item = mod.getItem();
assertEquals(0, mod.getTargetHash().length);
if(ContentType.MODULE.equals(item.getContentType())) {
Assert.assertArrayEquals(moduleHash("cp2"), item.getContentHash());
} else if(ContentType.MISC.equals(item.getContentType())) {
Assert.assertArrayEquals(miscHash("cp2"), item.getContentHash());
} else {
Assert.assertArrayEquals(bundleHash("cp2"), item.getContentHash());
}
}
}
@Test
public void testAddRemove() throws Exception {
final Patch cp1 = generateCP("base", "cp1", ModificationType.ADD);
final Patch cp2 = generateCP("cp1", "cp2", ModificationType.REMOVE);
final Patch merged = PatchMerger.merge(cp1, cp2);
assertEquals("cp2", merged.getPatchId());
assertEquals("cp2" + " description", merged.getDescription());
final IdentityUpgrade identity = merged.getIdentity().forType(PatchType.CUMULATIVE, Identity.IdentityUpgrade.class);
assertEquals("base", identity.getVersion());
assertEquals("cp2", identity.getResultingVersion());
assertEquals(PatchType.CUMULATIVE, identity.getPatchType());
final List<PatchElement> elements = merged.getElements();
assertEquals(1, elements.size());
final PatchElement e = elements.get(0);
assertEquals("base-" + "cp2", e.getId());
final PatchElementProvider provider = e.getProvider();
assertEquals("base", provider.getName());
assertEquals(PatchType.CUMULATIVE, provider.getPatchType());
assertEquals(LayerType.Layer, provider.getLayerType());
//assertEquals(0, e.getModifications().size());
// for modules remove is effectively a modify which changes the module xml to indicate an absent module
// so, it will remain an add of an absent module
assertEquals(1, e.getModifications().size());
final ContentModification mod = e.getModifications().iterator().next();
assertEquals(ModificationType.ADD, mod.getType());
Assert.assertArrayEquals(PatchUtils.getAbsentModuleContentHash((ModuleItem) mod.getItem()), mod.getItem().getContentHash());
}
@Test
public void testModifyRemove() throws Exception {
final Patch cp1 = generateCP("base", "cp1", ModificationType.MODIFY);
final Patch cp2 = generateCP("cp1", "cp2", ModificationType.REMOVE);
final Patch merged = PatchMerger.merge(cp1, cp2);
assertEquals("cp2", merged.getPatchId());
assertEquals("cp2" + " description", merged.getDescription());
final IdentityUpgrade identity = merged.getIdentity().forType(PatchType.CUMULATIVE, Identity.IdentityUpgrade.class);
assertEquals("base", identity.getVersion());
assertEquals("cp2", identity.getResultingVersion());
assertEquals(PatchType.CUMULATIVE, identity.getPatchType());
final List<PatchElement> elements = merged.getElements();
assertEquals(1, elements.size());
final PatchElement e = elements.get(0);
assertEquals("base-" + "cp2", e.getId());
final PatchElementProvider provider = e.getProvider();
assertEquals("base", provider.getName());
assertEquals(PatchType.CUMULATIVE, provider.getPatchType());
assertEquals(LayerType.Layer, provider.getLayerType());
assertEquals(3, e.getModifications().size());
for(ContentModification mod : e.getModifications()) {
assertEquals(ModificationType.REMOVE, mod.getType());
final ContentItem item = mod.getItem();
assertEquals(0, item.getContentHash().length);
if(ContentType.MODULE.equals(item.getContentType())) {
Assert.assertArrayEquals(moduleHash("base"), mod.getTargetHash());
} else if(ContentType.MISC.equals(item.getContentType())) {
Assert.assertArrayEquals(miscHash("base"), mod.getTargetHash());
} else {
Assert.assertArrayEquals(bundleHash("base"), mod.getTargetHash());
}
}
}
@Test
public void testRemoveAdd() throws Exception {
final Patch cp1 = generateCP("base", "cp1", ModificationType.REMOVE);
final Patch cp2 = generateCP("cp1", "cp2", ModificationType.ADD);
final Patch merged = PatchMerger.merge(cp1, cp2);
assertEquals("cp2", merged.getPatchId());
assertEquals("cp2" + " description", merged.getDescription());
final IdentityUpgrade identity = merged.getIdentity().forType(PatchType.CUMULATIVE, Identity.IdentityUpgrade.class);
assertEquals("base", identity.getVersion());
assertEquals("cp2", identity.getResultingVersion());
assertEquals(PatchType.CUMULATIVE, identity.getPatchType());
final List<PatchElement> elements = merged.getElements();
assertEquals(1, elements.size());
final PatchElement e = elements.get(0);
assertEquals("base-" + "cp2", e.getId());
final PatchElementProvider provider = e.getProvider();
assertEquals("base", provider.getName());
assertEquals(PatchType.CUMULATIVE, provider.getPatchType());
assertEquals(LayerType.Layer, provider.getLayerType());
assertEquals(3, e.getModifications().size());
for(ContentModification mod : e.getModifications()) {
assertEquals(ModificationType.MODIFY, mod.getType());
final ContentItem item = mod.getItem();
if(ContentType.MODULE.equals(item.getContentType())) {
Assert.assertArrayEquals(moduleHash("base"), mod.getTargetHash());
Assert.assertArrayEquals(moduleHash("cp2"), item.getContentHash());
} else if(ContentType.MISC.equals(item.getContentType())) {
Assert.assertArrayEquals(miscHash("base"), mod.getTargetHash());
Assert.assertArrayEquals(miscHash("cp2"), item.getContentHash());
} else {
Assert.assertArrayEquals(bundleHash("base"), mod.getTargetHash());
Assert.assertArrayEquals(bundleHash("cp2"), item.getContentHash());
}
}
}
@Test
public void testModifyModify() throws Exception {
final Patch cp1 = generateCP("base", "cp1", ModificationType.MODIFY);
final Patch cp2 = generateCP("cp1", "cp2", ModificationType.MODIFY);
final Patch merged = PatchMerger.merge(cp1, cp2);
assertEquals("cp2", merged.getPatchId());
assertEquals("cp2" + " description", merged.getDescription());
final IdentityUpgrade identity = merged.getIdentity().forType(PatchType.CUMULATIVE, Identity.IdentityUpgrade.class);
assertEquals("base", identity.getVersion());
assertEquals("cp2", identity.getResultingVersion());
assertEquals(PatchType.CUMULATIVE, identity.getPatchType());
final List<PatchElement> elements = merged.getElements();
assertEquals(1, elements.size());
final PatchElement e = elements.get(0);
assertEquals("base-" + "cp2", e.getId());
final PatchElementProvider provider = e.getProvider();
assertEquals("base", provider.getName());
assertEquals(PatchType.CUMULATIVE, provider.getPatchType());
assertEquals(LayerType.Layer, provider.getLayerType());
assertEquals(3, e.getModifications().size());
for(ContentModification mod : e.getModifications()) {
assertEquals(ModificationType.MODIFY, mod.getType());
final ContentItem item = mod.getItem();
if(ContentType.MODULE.equals(item.getContentType())) {
Assert.assertArrayEquals(moduleHash("base"), mod.getTargetHash());
Assert.assertArrayEquals(moduleHash("cp2"), item.getContentHash());
} else if(ContentType.MISC.equals(item.getContentType())) {
Assert.assertArrayEquals(miscHash("base"), mod.getTargetHash());
Assert.assertArrayEquals(miscHash("cp2"), item.getContentHash());
} else {
Assert.assertArrayEquals(bundleHash("base"), mod.getTargetHash());
Assert.assertArrayEquals(bundleHash("cp2"), item.getContentHash());
}
}
}
protected Patch generateCP(final String currentCP, final String nextCP, ModificationType type) {
final PatchBuilder patchBuilder = PatchBuilder.create().setPatchId(nextCP).setDescription(nextCP + " description");
patchBuilder.upgradeIdentity("identity", currentCP, nextCP);
final PatchElementBuilder elementBuilder = patchBuilder.upgradeElement("base-" + nextCP, "base", false);
if(ModificationType.ADD.equals(type)) {
elementBuilder.addModule("org.jboss.test", "main", moduleHash(nextCP))
.addBundle("org.jboss.test", "main", bundleHash(nextCP))
.addFile("test.txt", Arrays.asList(new String[]{"org","jboss","test"}), miscHash(nextCP), false);
} else if(ModificationType.MODIFY.equals(type)) {
elementBuilder.modifyModule("org.jboss.test", "main", moduleHash(currentCP), moduleHash(nextCP))
.modifyBundle("org.jboss.test", "main", bundleHash(currentCP), bundleHash(nextCP))
.modifyFile("test.txt", Arrays.asList(new String[]{"org","jboss","test"}), miscHash(currentCP), miscHash(nextCP), false);
} else {
elementBuilder.removeModule("org.jboss.test", "main", moduleHash(currentCP))
.removeBundle("org.jboss.test", "main", bundleHash(currentCP))
.removeFile("test.txt", Arrays.asList(new String[] { "org", "jboss", "test" }), miscHash(currentCP), false);
}
return patchBuilder.build();
}
protected byte[] miscHash(final String nextCP) {
return digest("file:" + nextCP + ":org.jboss.test");
}
protected byte[] bundleHash(final String nextCP) {
return digest("bundle:" + nextCP + ":org.jboss.test:main");
}
protected byte[] moduleHash(final String nextCP) {
return digest("module:" + nextCP + ":org.jboss.test:main");
}
}