/*
* 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.test.patching;
import static org.jboss.as.test.patching.PatchingTestUtil.MODULES_PATH;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.jboss.as.cli.CommandContext;
import org.jboss.as.cli.CommandContextFactory;
import org.jboss.as.controller.client.ModelControllerClient;
import org.jboss.as.patching.HashUtils;
import org.jboss.as.test.patching.util.module.Module;
import org.jboss.as.test.shared.TestSuiteEnvironment;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.wildfly.core.testrunner.ServerControl;
import org.wildfly.core.testrunner.WildflyTestRunner;
/**
*
* @author Alexey Loubyansky
*/
@RunWith(WildflyTestRunner.class)
@ServerControl(manual = true)
public class PatchInfoTestCase extends PatchInfoTestBase {
private static final String BASE = "base";
private static final String CUMULATIVE_PATCH_ID = "Cumulative patch ID";
private static final String LAYER = "Layer";
private static final String NONE = "none";
private static final String ONE_OFF_PATCHES = "One-off patches";
private static final String VERSION = "Version";
private CLIOutputReader reader = new CLIOutputReader();
private ByteArrayOutputStream bytesOs;
private File moduleDir;
@Before
public void setup() throws Exception {
bytesOs = new ByteArrayOutputStream();
final Module module = new Module.Builder("module-test").
miscFile(new ResourceItem("resource-test", ("module resource").getBytes(StandardCharsets.UTF_8))).
build();
moduleDir = module.writeToDisk(new File(MODULES_PATH));
}
@After
public void cleanup() throws Exception {
if(bytesOs != null) {
bytesOs = null;
}
}
@Test
public void testUnpatched() throws Exception {
readPatchInfo(false);
Map<String,String> table = reader.readTable();
assertNotNull(table);
assertEquals(3, table.size());
assertTrue(table.containsKey(VERSION));
assertEquals(NONE, table.get(ONE_OFF_PATCHES));
assertEquals(BASE, table.get(CUMULATIVE_PATCH_ID));
assertNull(reader.readTable());
readPatchInfo(true);
table = reader.readTable();
assertNotNull(table);
assertEquals(3, table.size());
assertTrue(table.containsKey(VERSION));
assertEquals(NONE, table.get(ONE_OFF_PATCHES));
assertEquals(BASE, table.get(CUMULATIVE_PATCH_ID));
table = reader.readTable();
assertNotNull(table);
assertEquals(3, table.size());
assertEquals(BASE, table.get(LAYER));
assertEquals(NONE, table.get(ONE_OFF_PATCHES));
assertEquals(BASE, table.get(CUMULATIVE_PATCH_ID));
assertNull(reader.readTable());
}
@Test
public void testCP() throws Exception {
byte[] targetHash = HashUtils.hashFile(moduleDir);
targetHash = applyCP("cp1", "base-cp1", targetHash);
readPatchInfo(false);
Map<String,String> table = reader.readTable();
assertNotNull(table);
assertEquals(3, table.size());
assertTrue(table.containsKey(VERSION));
assertEquals(NONE, table.get(ONE_OFF_PATCHES));
assertEquals("cp1", table.get(CUMULATIVE_PATCH_ID));
assertNull(reader.readTable());
readPatchInfo(true);
table = reader.readTable();
assertNotNull(table);
assertEquals(3, table.size());
assertTrue(table.containsKey(VERSION));
assertEquals(NONE, table.get(ONE_OFF_PATCHES));
assertEquals("cp1", table.get(CUMULATIVE_PATCH_ID));
table = reader.readTable();
assertNotNull(table);
assertEquals(3, table.size());
assertEquals(BASE, table.get(LAYER));
assertEquals(NONE, table.get(ONE_OFF_PATCHES));
assertEquals("base-cp1", table.get(CUMULATIVE_PATCH_ID));
assertNull(reader.readTable());
}
@Test
public void testOneOff() throws Exception {
byte[] targetHash = HashUtils.hashFile(moduleDir);
targetHash = applyOneOff("oneOff1", "base-oneOff1", targetHash);
readPatchInfo(false);
Map<String,String> table = reader.readTable();
assertNotNull(table);
assertEquals(3, table.size());
assertTrue(table.containsKey(VERSION));
assertEquals("oneOff1", table.get(ONE_OFF_PATCHES));
assertEquals(BASE, table.get(CUMULATIVE_PATCH_ID));
assertNull(reader.readTable());
readPatchInfo(true);
table = reader.readTable();
assertNotNull(table);
assertEquals(3, table.size());
assertTrue(table.containsKey(VERSION));
assertEquals("oneOff1", table.get(ONE_OFF_PATCHES));
assertEquals(BASE, table.get(CUMULATIVE_PATCH_ID));
table = reader.readTable();
assertNotNull(table);
assertEquals(3, table.size());
assertEquals(BASE, table.get(LAYER));
assertEquals("base-oneOff1", table.get(ONE_OFF_PATCHES));
assertEquals(BASE, table.get(CUMULATIVE_PATCH_ID));
assertNull(reader.readTable());
}
@Test
public void testCPAndOneOffsOnline() throws Exception {
doTestCPAndOneOffs(false);
}
@Test
public void testCPAndOneOffsOffline() throws Exception {
doTestCPAndOneOffs(true);
}
private void doTestCPAndOneOffs(boolean offline) throws Exception {
byte[] targetHash = HashUtils.hashFile(moduleDir);
targetHash = applyCP("cp1", "base-cp1", targetHash);
targetHash = applyOneOff("oneOff1", "base-oneOff1", targetHash);
targetHash = applyOneOff("oneOff2", "base-oneOff2", targetHash);
readPatchInfo(false, offline);
Map<String,String> table = reader.readTable();
assertNotNull(table);
assertEquals(3, table.size());
assertTrue(table.containsKey(VERSION));
assertEquals("oneOff2,oneOff1", table.get(ONE_OFF_PATCHES));
assertEquals("cp1", table.get(CUMULATIVE_PATCH_ID));
assertNull(reader.readTable());
readPatchInfo(true, offline);
table = reader.readTable();
assertNotNull(table);
assertEquals(3, table.size());
assertTrue(table.containsKey(VERSION));
assertEquals("oneOff2,oneOff1", table.get(ONE_OFF_PATCHES));
assertEquals("cp1", table.get(CUMULATIVE_PATCH_ID));
table = reader.readTable();
assertNotNull(table);
assertEquals(3, table.size());
assertEquals(BASE, table.get(LAYER));
assertEquals("base-oneOff2,base-oneOff1", table.get(ONE_OFF_PATCHES));
assertEquals("base-cp1", table.get(CUMULATIVE_PATCH_ID));
assertNull(reader.readTable());
}
private void readPatchInfo(boolean verbose) throws Exception {
readPatchInfo(verbose, false);
}
private void readPatchInfo(boolean verbose, boolean offline) throws Exception {
String line = "patch info";
if(verbose) {
line += " --verbose";
}
// to avoid the need to reset the terminal manually after the tests, e.g. 'stty sane'
System.setProperty("aesh.terminal", "org.jboss.aesh.terminal.TestTerminal");
final CommandContext ctx = CommandContextFactory.getInstance().newCommandContext(null, null, null, System.in, bytesOs);
if(!offline) {
controller.start();
final ModelControllerClient client = ModelControllerClient.Factory.create(TestSuiteEnvironment.getServerAddress(), TestSuiteEnvironment.getServerPort());
ctx.bindClient(client);
} else {
line += " --distribution=" + PatchingTestUtil.AS_DISTRIBUTION;
}
bytesOs.reset();
try {
ctx.handle(line);
} finally {
ctx.terminateSession();
if(!offline) {
controller.stop();
}
}
reader.refresh();
}
class CLIOutputReader {
String line;
BufferedReader reader;
CLIOutputReader() {
}
void refresh() {
if(bytesOs.size() > 0) {
reader = new BufferedReader(new StringReader(new String(bytesOs.toByteArray(), StandardCharsets.UTF_8)));
} else {
reader = null;
}
}
protected Map<String, String> readTable() throws IOException {
String line = reader.readLine();
if(line == null) {
return null;
}
if(line.isEmpty()) {
return Collections.emptyMap();
}
final Map<String, String> map = new HashMap<String,String>();
addLine(map, line);
while(!(line == null || line.isEmpty())) {
addLine(map, line);
line = reader.readLine();
}
return map;
}
protected void addLine(Map<String, String> map, String line) {
final int i = line.indexOf(':');
if(i < 0) {
map.put(line, null);
} else {
final String key = line.substring(0, i).trim();
final String value;
if(i + 1 < line.length()) {
value = line.substring(i + 1, line.length()).trim();
} else {
value = "";
}
map.put(key, value);
}
}
}
}