org.jboss.as.test.clustering.modcluster.WorkerFailoverTestCase.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.as.test.clustering.modcluster.WorkerFailoverTestCase.java

Source

/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2014, 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.clustering.modcluster;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.HttpClientUtils;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.jboss.arquillian.container.test.api.Deployer;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.container.test.api.TargetsContainer;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.as.arquillian.api.WildFlyContainerController;
import org.jboss.as.controller.client.ModelControllerClient;
import org.jboss.as.test.clustering.NodeUtil;
import org.jboss.as.test.clustering.single.web.CommonJvmRoute;
import org.jboss.as.test.clustering.single.web.JvmRouteServlet;
import org.jboss.as.test.http.util.TestHttpClientUtils;
import org.jboss.as.test.shared.ServerReload;
import org.jboss.as.test.shared.TestSuiteEnvironment;
import org.jboss.dmr.ModelNode;
import org.jboss.logging.Logger;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.concurrent.TimeUnit;

import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import static org.jboss.as.controller.client.helpers.ClientConstants.SUCCESS;
import static org.jboss.as.test.integration.management.util.ModelUtil.createOpNode;

/**
 * Worker failover test for modcluster. Creates basic scenario (one balancer and two workers) and sends a request when both
 * workers are alive, then it undeploys worker which responded and sends the request again.
 *
 * @author Matus Madzin
 */
@RunWith(Arquillian.class)
@RunAsClient
public class WorkerFailoverTestCase {

    private static final String MODULE = "jvmroute";
    private static final String DEPLOYMENT_1 = "deployment-1";
    private static final String DEPLOYMENT_2 = "deployment-2";
    private static final String CONTAINER_1 = "con-1";
    private static final String CONTAINER_2 = "con-2";
    private static final String BALANCER = "balancer";
    private static final int TIMEOUT = 90;

    private static final Logger LOGGER = Logger.getLogger(WorkerFailoverTestCase.class);

    @ArquillianResource
    protected WildFlyContainerController controller;
    @ArquillianResource
    protected Deployer deployer;

    private String balancerConfigFile;
    private String worker1ConfigFile;
    private String worker2ConfigFile;
    private String undeployedApp;

    @Deployment(name = DEPLOYMENT_1, managed = false, testable = false)
    @TargetsContainer(CONTAINER_1)
    public static Archive<?> deployment0() {
        return getDeployment();
    }

    @Deployment(name = DEPLOYMENT_2, managed = false, testable = false)
    @TargetsContainer(CONTAINER_2)
    public static Archive<?> deployment1() {
        return getDeployment();
    }

    private static Archive<?> getDeployment() {
        WebArchive war = ShrinkWrap.create(WebArchive.class, MODULE + ".war");
        war.addClasses(JvmRouteServlet.class, CommonJvmRoute.class);

        return war;
    }

    @Before
    public void startAndSetupContainers() throws Exception {

        LOGGER.trace("*** starting balancer");
        controller.start(BALANCER);

        LOGGER.trace("*** will configure server now");
        balancerSetup();

        LOGGER.trace("*** starting worker1");
        controller.start(CONTAINER_1);

        LOGGER.trace("*** will configure worker1 now");
        workerSetup("node1", 10090);

        LOGGER.trace("*** starting worker2");
        controller.start(CONTAINER_2);

        LOGGER.trace("*** will configure worker2 now");
        workerSetup("node2", 10190);

        LOGGER.trace("*** will deploy " + DEPLOYMENT_1 + " and " + DEPLOYMENT_2);
        deployer.deploy(DEPLOYMENT_1);
        deployer.deploy(DEPLOYMENT_2);
    }

    /*
    Configures EAP on node "node0" as a load balancer (undertow filter).
     */
    private void balancerSetup() throws Exception {
        try (ModelControllerClient client = TestSuiteEnvironment.getModelControllerClient(null,
                TestSuiteEnvironment.getServerAddress("node0"), 9990)) {

            /* Configuration backup */
            ModelNode op = createOpNode("path=jboss.server.config.dir", "read-attribute");
            op.get("name").set("path");
            ModelNode response = client.execute(op);
            Assert.assertEquals("Server's configuration file not found!\n" + response.toString(), SUCCESS,
                    response.get("outcome").asString());

            balancerConfigFile = response.get("result").asString() + File.separator
                    + System.getProperty("jboss.server.config.file.standalone", "standalone.xml");
            Files.copy(Paths.get(balancerConfigFile),
                    Paths.get(balancerConfigFile + ".WorkerFailoverTestCase.backup"), REPLACE_EXISTING);

            /* Server configuration */
            op = createOpNode("subsystem=undertow/configuration=filter/mod-cluster=modcluster", "add");
            op.get("management-socket-binding").set("http");
            response = client.execute(op);
            Assert.assertEquals("Server's configuration failed!\n" + response.toString(), SUCCESS,
                    response.get("outcome").asString());

            op = createOpNode("subsystem=undertow/server=default-server/host=default-host/filter-ref=modcluster",
                    "add");
            response = client.execute(op);
            Assert.assertEquals("Server's configuration failed!\n" + response.toString(), SUCCESS,
                    response.get("outcome").asString());
        }

    }

    /*
    Configures EAP as worker with proxies
        
    @param cliAddress - name of node where EAP will be configured e.g. node1.
    @param port - management port of the node.
     */
    private void workerSetup(String cliAddress, int port) throws Exception {
        try (ModelControllerClient client = TestSuiteEnvironment.getModelControllerClient(null,
                TestSuiteEnvironment.getServerAddress(cliAddress), port)) {

            /* Configuration backup */
            ModelNode op = createOpNode("path=jboss.server.config.dir", "read-attribute");
            op.get("name").set("path");
            ModelNode response = client.execute(op);
            Assert.assertEquals("Workers's configuration file not found!\n" + response.toString(), SUCCESS,
                    response.get("outcome").asString());

            String workerConfigFile = response.get("result").asString() + File.separator
                    + System.getProperty("jboss.server.config.file.standalone-ha", "/standalone-ha.xml");
            Files.copy(Paths.get(workerConfigFile), Paths.get(workerConfigFile + ".WorkerFailoverTestCase.backup"),
                    REPLACE_EXISTING);

            if (port == 10090)
                worker1ConfigFile = workerConfigFile;
            else
                worker2ConfigFile = workerConfigFile;

            /* Server configuration */
            op = createOpNode("subsystem=modcluster/mod-cluster-config=configuration/", "write-attribute");
            op.get("name").set("advertise");
            op.get("value").set("false");
            response = client.execute(op);
            Assert.assertEquals("Worker's configuration failed!\n" + response.toString(), SUCCESS,
                    response.get("outcome").asString());

            op = createOpNode(
                    "socket-binding-group=standard-sockets/remote-destination-outbound-socket-binding=proxy1",
                    "add");
            op.get("host").set(TestSuiteEnvironment.getServerAddress("node0"));
            op.get("port").set("8080");
            response = client.execute(op);
            Assert.assertEquals("Worker's configuration failed!\n" + response.toString(), SUCCESS,
                    response.get("outcome").asString());

            op = createOpNode("subsystem=modcluster/mod-cluster-config=configuration", "list-add");
            op.get("name").set("proxies");
            op.get("value").set("proxy1");
            response = client.execute(op);
            Assert.assertEquals("Worker's configuration failed!\n" + response.toString(), SUCCESS,
                    response.get("outcome").asString());

            op = createOpNode("subsystem=modcluster/mod-cluster-config=configuration", "write-attribute");
            op.get("name").set("status-interval");
            op.get("value").set("1");
            response = client.execute(op);
            Assert.assertEquals("Worker's configuration failed!\n" + response.toString(), SUCCESS,
                    response.get("outcome").asString());

            ServerReload.executeReloadAndWaitForCompletion(client, ServerReload.TIMEOUT, false,
                    TestSuiteEnvironment.getServerAddress(cliAddress), port);
        }
    }

    @After
    public void stopContainers() throws Exception {
        LOGGER.trace("*** undeploy applications");

        if (undeployedApp == null || !undeployedApp.equals(DEPLOYMENT_1))
            deployer.undeploy(DEPLOYMENT_1);

        if (undeployedApp == null || !undeployedApp.equals(DEPLOYMENT_2))
            deployer.undeploy(DEPLOYMENT_2);

        LOGGER.trace("*** stopping container");
        controller.stop(CONTAINER_1);
        controller.stop(CONTAINER_2);
        controller.stop(BALANCER);

        LOGGER.trace("*** reseting test configuration");
        Files.move(Paths.get(worker1ConfigFile + ".WorkerFailoverTestCase.backup"), Paths.get(worker1ConfigFile),
                REPLACE_EXISTING);
        Files.move(Paths.get(worker2ConfigFile + ".WorkerFailoverTestCase.backup"), Paths.get(worker2ConfigFile),
                REPLACE_EXISTING);
        Files.move(Paths.get(balancerConfigFile + ".WorkerFailoverTestCase.backup"), Paths.get(balancerConfigFile),
                REPLACE_EXISTING);
    }

    /*
    Checks that both workers are visible for balancer before the test.
     */
    private void infrastructureCheck() {
        /* Connects to the balancer */
        try (ModelControllerClient client = TestSuiteEnvironment.getModelControllerClient(null,
                TestSuiteEnvironment.getServerAddress("node0"), 9990)) {

            ModelNode checkWorker1 = null, checkWorker2 = null;

            /* Prepare opperations for retriving info about workers from the balancer*/
            try {
                checkWorker1 = createOpNode(
                        "subsystem=undertow/configuration=filter/mod-cluster=modcluster/balancer=mycluster/node=node-1",
                        "read-children-names");
                checkWorker1.get("child-type").set("context");

                checkWorker2 = createOpNode(
                        "subsystem=undertow/configuration=filter/mod-cluster=modcluster/balancer=mycluster/node=node-2",
                        "read-children-names");
                checkWorker2.get("child-type").set("context");
            } catch (Exception e) {
                LOGGER.error("Not able to create OpNodes", e);
                Assert.fail("Not able to create OpNodes. For more information look into log file.");
            }

            int iteration = 0;
            ModelNode response1 = null, response2 = null;
            boolean result1 = false, result2 = false;

            /* Periodically checks whether both workers are registered to the balancer in TIMEOUT */
            do {
                try {
                    response1 = client.execute(checkWorker1);
                    response2 = client.execute(checkWorker2);
                    iteration++;

                    result1 = response1.get("result").asString().contains("jvmroute");
                    result2 = response2.get("result").asString().contains("jvmroute");

                    if (result1 && result2)
                        break;

                    TimeUnit.SECONDS.sleep(1);
                } catch (Exception e) {
                    LOGGER.error("Not able to execute OpNode and check the result", e);
                    Assert.fail(
                            "Not able to execute OpNode and check the result. For more information look into log file.");
                }
            } while (iteration < TIMEOUT);

            /* In case any worker is not ready (after timeout) then test fails */
            Assert.assertTrue("TIMEOUT ELAPSED: Balancer is not able to see both workers!\n", result1);
            Assert.assertTrue("TIMEOUT ELAPSED: Balancer is not able to see both workers!\n", result2);

        } catch (IOException e) {
            LOGGER.error("InfrastructureCheck failed", e);
            Assert.fail("IOException: For more information look into log file.");
        }
    }

    @Test
    public void workerFailoverTest() throws URISyntaxException, IOException {
        String address = TestSuiteEnvironment.getServerAddress("node0");
        URL url = new URL("http", address, 8080, "/jvmroute/jvmroute");
        URI uri = url.toURI();

        /* Checks whether all servers are set as expected */
        infrastructureCheck();

        try (CloseableHttpClient httpClient = TestHttpClientUtils.promiscuousCookieHttpClient()) {
            HttpResponse response = null;
            String worker1, worker2;

            try {
                /* The first HTTP request */
                response = httpClient.execute(new HttpGet(uri));

                Assert.assertEquals(HttpServletResponse.SC_OK, response.getStatusLine().getStatusCode());
                HttpEntity entity = response.getEntity();
                Assert.assertNotNull(entity);
                worker1 = EntityUtils.toString(entity);

                if (!worker1.equals("worker-1"))
                    Assert.assertEquals("worker-2", worker1);

                /* Undeploy worker which responsed the first HTTP request */
                if (worker1.equals("worker-1")) {
                    NodeUtil.undeploy(this.deployer, DEPLOYMENT_1);
                    undeployedApp = DEPLOYMENT_1;
                } else {
                    NodeUtil.undeploy(this.deployer, DEPLOYMENT_2);
                    undeployedApp = DEPLOYMENT_2;
                }

                /* The second HTTP request */
                response = httpClient.execute(new HttpGet(uri));

                Assert.assertEquals(HttpServletResponse.SC_OK, response.getStatusLine().getStatusCode());
                entity = response.getEntity();
                Assert.assertNotNull(entity);
                worker2 = EntityUtils.toString(entity);

                /* Checks that the second node responded the second request */
                if (worker1.equals("worker-1"))
                    Assert.assertEquals("worker-2", worker2);
                else
                    Assert.assertEquals("worker-1", worker2);

            } finally {
                HttpClientUtils.closeQuietly(response);
            }
        }
    }
}