/*
* JBoss, Home of Professional Open Source.
* Copyright 2012, 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.runner;
import java.util.Arrays;
import java.util.Collections;
import org.jboss.as.patching.metadata.ContentModification;
import org.jboss.as.patching.metadata.MiscContentItem;
import org.jboss.as.patching.metadata.ModificationType;
import org.jboss.as.patching.metadata.Patch;
import org.jboss.as.patching.metadata.PatchElement;
import org.jboss.as.patching.metadata.PatchImpl;
import org.junit.Assert;
import org.junit.Test;
/**
* @author Emanuel Muckenhuber
*/
public class PatchMergeUnitTestCase {
static final String name = "jboss-client.jar";
static final String[] path = new String[] { "bin", "client" };
static byte[] one = new byte[] { 'a', 'b', 'c', '1', '2', '3' };
static byte[] two = new byte[] { 'c', 'd', 'e', '4', '5', '6' };
static byte[] three = new byte[] { 'f', 'g', 'h', '7', '8', '9' };
static byte[] four = new byte[] { 'i', 'j', 'k', '9', '8', '7' };
@Test
public void testSimple() throws Exception {
// content-item 'two' replacing 'one'
final RollbackInfo patch01 = createRollbackInfo("patch01", two, one);
// content-item 'three' replacing 'two'
final RollbackInfo patch02 = createRollbackInfo("patch02", three, two);
// [patch-two, patch-one]
final ContentTaskDefinitions defs = process(patch02, patch01);
Assert.assertEquals(1, defs.size());
final PatchingTasks.ContentTaskDefinition def = defs.get(new Location(new MiscContentItem(name, path, one)));
Assert.assertNotNull(def);
Assert.assertFalse(def.hasConflicts());
// We want to restore one (from the backup)
Assert.assertEquals(one, def.getTarget().getItem().getContentHash());
// The original target was two
Assert.assertEquals(two, def.getTarget().getTargetHash());
// The current content however is three
Assert.assertEquals(three, def.getLatest().getTargetHash());
// And originally replaced two
Assert.assertEquals(two, def.getLatest().getItem().getContentHash());
// The resulting operation should replace 'three' with 'one'
final ContentModification modification = PatchingTaskDescription.resolveDefinition(def);
Assert.assertEquals(one, modification.getItem().getContentHash());
Assert.assertEquals(three, modification.getTargetHash());
}
@Test
public void testOverrideExisting() throws Exception {
// content-item 'two' replacing 'four', originally targeting 'one'
final RollbackInfo patch01 = createRollbackInfo("patch01", two, one, four, two);
// content-item 'three' replacing 'two'
final RollbackInfo patch02 = createRollbackInfo("patch02", three, two);
// [patch-two, patch-one]
final ContentTaskDefinitions defs = process(patch02, patch01);
Assert.assertEquals(1, defs.size());
final PatchingTasks.ContentTaskDefinition def = defs.get(new Location(new MiscContentItem(name, path, one)));
Assert.assertNotNull(def);
Assert.assertTrue(def.hasConflicts());
// We want to restore four (from the backup)
Assert.assertEquals(four, def.getTarget().getItem().getContentHash());
// The original target was two
Assert.assertEquals(two, def.getTarget().getTargetHash());
// The current content however is three
Assert.assertEquals(three, def.getLatest().getTargetHash());
// And originally replaced two
Assert.assertEquals(two, def.getLatest().getItem().getContentHash());
// The resulting operation should replace 'three' with 'four'
final ContentModification modification = PatchingTaskDescription.resolveDefinition(def);
Assert.assertEquals(four, modification.getItem().getContentHash());
Assert.assertEquals(three, modification.getTargetHash());
}
@Test
public void testPreserveExisting() throws Exception {
// content-item 'two' replacing 'one', but kept 'four'
final RollbackInfo patch01 = createRollbackInfo("patch01", two, one, four, four);
// content-item 'three' replacing 'two'
final RollbackInfo patch02 = createRollbackInfo("patch02", three, four);
// [patch-two, patch-one]
final ContentTaskDefinitions defs = process(patch02, patch01);
Assert.assertEquals(1, defs.size());
final PatchingTasks.ContentTaskDefinition def = defs.get(new Location(new MiscContentItem(name, path, one)));
Assert.assertNotNull(def);
Assert.assertTrue(def.hasConflicts());
// We want to got back to four
Assert.assertEquals(four, def.getTarget().getItem().getContentHash());
// The recorded action was preserving four
Assert.assertEquals(four, def.getTarget().getTargetHash());
// The current content however is three
Assert.assertEquals(three, def.getLatest().getTargetHash());
// And originally replaced four
Assert.assertEquals(four, def.getLatest().getItem().getContentHash());
// The resulting operation should replace 'three' with 'four'
final ContentModification modification = PatchingTaskDescription.resolveDefinition(def);
Assert.assertEquals(four, modification.getItem().getContentHash());
Assert.assertEquals(three, modification.getTargetHash());
}
static ContentTaskDefinitions process(final RollbackInfo... rollbackInfos) {
final ContentTaskDefinitions foo = new ContentTaskDefinitions();
for(final RollbackInfo info : rollbackInfos) {
PatchingTasks.rollback(info.original.getPatchId(), info.original.getModifications(), info.rollback.getModifications(), foo, ContentItemFilter.MISC_ONLY, PatchingTaskContext.Mode.APPLY);
}
return foo;
}
static RollbackInfo createRollbackInfo(String id, byte[] ih, byte[] rh) {
return createRollbackInfo(id, ih, rh, rh, ih);
}
static RollbackInfo createRollbackInfo(String id, byte[] oih, byte[] oth, byte[] rih, byte[] rth) {
//
final MiscContentItem oi = new MiscContentItem(name, path, oih);
final MiscContentItem ri = new MiscContentItem(name, path, rih);
//
final Patch o = createPatch(id, Patch.PatchType.ONE_OFF, new ContentModification(oi, oth, ModificationType.MODIFY));
final Patch r = createPatch(id, Patch.PatchType.ONE_OFF, new ContentModification(ri, rth, ModificationType.MODIFY));
//
return new RollbackInfo(o, r);
}
static class RollbackInfo {
final Patch original;
final Patch rollback;
RollbackInfo(Patch original, Patch rollback) {
this.original = original;
this.rollback = rollback;
}
}
static Patch createPatch(final String id, final Patch.PatchType type, final ContentModification... item) {
return new PatchImpl(id, "test", null, Collections.<PatchElement>emptyList(), Arrays.asList(item));
}
}