/*
* JBoss, Home of Professional Open Source.
* Copyright 2011, 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.integration.domain.slavereconnect;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.BLOCKING;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.CHILD_TYPE;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.GROUP;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.HOST;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OUTCOME;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.PORT_OFFSET;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.PROFILE;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.READ_CHILDREN_NAMES_OPERATION;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RESULT;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SERVER_CONFIG;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SERVER_GROUP;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SOCKET_BINDING_GROUP;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.START;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.STOP;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUCCESS;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBSYSTEM;
import java.util.List;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.client.helpers.domain.DomainClient;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.NAME;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.READ_ATTRIBUTE_OPERATION;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SERVER;
import org.jboss.as.controller.operations.common.Util;
import org.jboss.as.test.integration.domain.management.util.DomainLifecycleUtil;
import org.jboss.as.test.integration.domain.management.util.DomainTestSupport;
import org.jboss.as.test.integration.domain.management.util.DomainTestUtils;
import org.jboss.as.test.integration.domain.suites.DomainTestSuite;
import org.jboss.as.test.shared.TimeoutUtil;
import org.jboss.dmr.ModelNode;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
/**
* Wrapper for several tests which require a slave to master reconnect, so that we need as few reconnects as possible.
* It makes some assumptions about the HC/server process states,
* so don't run this within a suite.
*
* @author Kabir Khan
*/
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class SlaveReconnectTestCase {
static final PathAddress SLAVE_ADDR = PathAddress.pathAddress(HOST, "slave");
private static DomainTestSupport testSupport;
private static DomainLifecycleUtil domainMasterLifecycleUtil;
private static DomainLifecycleUtil domainSlaveLifecycleUtil;
private static final int ADJUSTED_SECOND = TimeoutUtil.adjust(1000);
@BeforeClass
public static void setupDomain() throws Exception {
testSupport = DomainTestSuite.createSupport(SlaveReconnectTestCase.class.getSimpleName());
domainMasterLifecycleUtil = testSupport.getDomainMasterLifecycleUtil();
domainSlaveLifecycleUtil = testSupport.getDomainSlaveLifecycleUtil();
}
@AfterClass
public static void tearDownDomain() throws Exception {
testSupport = null;
domainMasterLifecycleUtil = null;
domainSlaveLifecycleUtil = null;
DomainTestSuite.stopSupport();
}
@Test
public void test01_OrderedExtensionsAndDeployments() throws Exception {
testReconnect(new ReconnectTestScenario[]{
new UnaffectedScenario(650),
new OrderedChildResourceScenario(),
new DeploymentScenario(750)
});
}
@Test
public void test02_DeploymentOverlays() throws Exception {
//Since deployment-overlays affect all servers (https://issues.jboss.org/browse/WFCORE-710), this needs to
//be tested separately, and to come last since the server state gets affected
testReconnect(new ReconnectTestScenario[]{
new UnaffectedScenario(650),
new DeploymentOverlayScenario(750)
});
}
private void testReconnect(ReconnectTestScenario[] scenarios) throws Exception {
int initialisedScenarios = -1;
try {
DomainClient masterClient = domainMasterLifecycleUtil.getDomainClient();
DomainClient slaveClient = domainSlaveLifecycleUtil.getDomainClient();
for (int i = 0; i < scenarios.length; i++) {
initialisedScenarios = i;
scenarios[i].setUpDomain(testSupport, masterClient, slaveClient);
}
for (ReconnectTestScenario scenario : scenarios) {
scenario.testOnInitialStartup(masterClient, slaveClient);
}
//Restart the DC as admin-only
ModelNode restartAdminOnly = Util.createEmptyOperation("reload", PathAddress.pathAddress(HOST, "master"));
restartAdminOnly.get("admin-only").set(true);
domainMasterLifecycleUtil.executeAwaitConnectionClosed(restartAdminOnly);
domainMasterLifecycleUtil.connect();
domainMasterLifecycleUtil.awaitHostController(System.currentTimeMillis());
masterClient = domainMasterLifecycleUtil.createDomainClient();
for (ReconnectTestScenario scenario : scenarios) {
scenario.testWhileMasterInAdminOnly(masterClient, slaveClient);
}
//Restart the DC as normal
restartAdminOnly.get("admin-only").set(false);
domainMasterLifecycleUtil.executeAwaitConnectionClosed(restartAdminOnly);
domainMasterLifecycleUtil.connect();
domainMasterLifecycleUtil.awaitHostController(System.currentTimeMillis());
masterClient = domainMasterLifecycleUtil.createDomainClient();
//Wait for the slave to reconnect, look for the slave in the list of hosts
long end = System.currentTimeMillis() + 20 * ADJUSTED_SECOND;
boolean slaveReconnected = false;
do {
Thread.sleep(1 * ADJUSTED_SECOND);
slaveReconnected = checkSlaveReconnected(masterClient);
} while (!slaveReconnected && System.currentTimeMillis() < end);
//Wait for master servers to come up
end = System.currentTimeMillis() + 60 * ADJUSTED_SECOND;
boolean serversUp = false;
do {
Thread.sleep(1 * ADJUSTED_SECOND);
serversUp = checkHostServersStarted(masterClient, "master");
} while (!serversUp && System.currentTimeMillis() < end);
for (ReconnectTestScenario scenario : scenarios) {
scenario.testAfterReconnect(masterClient, slaveClient);
}
} finally {
for (int i = initialisedScenarios; i >=0 ; i--) {
scenarios[i].tearDownDomain(
domainMasterLifecycleUtil.getDomainClient(), domainSlaveLifecycleUtil.getDomainClient());
}
}
}
private boolean checkSlaveReconnected(DomainClient masterClient) throws Exception {
ModelNode op = Util.createEmptyOperation(READ_CHILDREN_NAMES_OPERATION, PathAddress.EMPTY_ADDRESS);
op.get(CHILD_TYPE).set(HOST);
try {
ModelNode ret = DomainTestUtils.executeForResult(op, masterClient);
List<ModelNode> list = ret.asList();
if (list.size() == 2) {
for (ModelNode entry : list) {
if ("slave".equals(entry.asString())){
return true;
}
}
}
} catch (Exception e) {
}
return false;
}
private boolean checkHostServersStarted(DomainClient masterClient, String host) {
try {
ModelNode op = Util.createEmptyOperation(READ_CHILDREN_NAMES_OPERATION, PathAddress.pathAddress(HOST, host));
op.get(CHILD_TYPE).set(SERVER);
ModelNode ret = DomainTestUtils.executeForResult(op, masterClient);
List<ModelNode> list = ret.asList();
for (ModelNode entry : list) {
String server = entry.asString();
op = Util.createEmptyOperation(READ_ATTRIBUTE_OPERATION, PathAddress.pathAddress(HOST, host).append(SERVER, server));
op.get(NAME).set("server-state");
ModelNode state = DomainTestUtils.executeForResult(op, masterClient);
if (SUCCESS.equals(state.get(OUTCOME).asString())) {
return "running".equals(state.get(RESULT).asString());
}
}
return false;
} catch (Exception e) {
return false;
}
}
static void cloneProfile(DomainClient masterClient, String source, String target) throws Exception {
ModelNode clone = Util.createEmptyOperation("clone", PathAddress.pathAddress(PROFILE, source));
clone.get("to-profile").set(target);
DomainTestUtils.executeForResult(clone, masterClient);
}
static void createServerGroup(DomainClient masterClient, String name, String profile) throws Exception {
ModelNode add = Util.createAddOperation(PathAddress.pathAddress(SERVER_GROUP, name));
add.get(PROFILE).set(profile);
add.get(SOCKET_BINDING_GROUP).set("standard-sockets");
DomainTestUtils.executeForResult(add, masterClient);
}
static void createServer(DomainClient slaveClient, String name, String serverGroup, int portOffset) throws Exception {
ModelNode add = Util.createAddOperation(SLAVE_ADDR.append(SERVER_CONFIG, name));
add.get(GROUP).set(serverGroup);
add.get(PORT_OFFSET).set(portOffset);
DomainTestUtils.executeForResult(add, slaveClient);
}
static void startServer(DomainClient slaveClient, String name) throws Exception {
ModelNode start = Util.createEmptyOperation(START, SLAVE_ADDR.append(SERVER_CONFIG, name));
start.get(BLOCKING).set(true);
DomainTestUtils.executeForResult(start, slaveClient);
}
static void stopServer(DomainClient slaveClient, String name) throws Exception {
PathAddress serverAddr = SLAVE_ADDR.append(SERVER_CONFIG, name);
ModelNode stop = Util.createEmptyOperation(STOP, serverAddr);
stop.get(BLOCKING).set(true);
DomainTestUtils.executeForResult(stop, slaveClient);
}
static void removeProfile(DomainClient masterClient, String name) throws Exception {
PathAddress profileAddr = PathAddress.pathAddress(PROFILE, name);
DomainTestUtils.executeForResult(Util.createRemoveOperation(profileAddr.append(SUBSYSTEM, "logging")), masterClient);
DomainTestUtils.executeForResult(
Util.createRemoveOperation(profileAddr), masterClient);
}
}