Package com.kurento.kmf.test.base

Source Code of com.kurento.kmf.test.base.GridBrowserMediaApiTest

/*
* (C) Copyright 2014 Kurento (http://kurento.org/)
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-2.1.html
*
* This library 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.
*
*/
package com.kurento.kmf.test.base;

import static com.kurento.kmf.common.PropertiesManager.getProperty;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import org.apache.commons.httpclient.HttpStatus;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.experimental.categories.Category;

import com.google.common.base.Charsets;
import com.google.common.io.CharStreams;
import com.kurento.kmf.commons.tests.SystemMediaApiTests;
import com.kurento.kmf.media.factory.KmfMediaApiProperties;
import com.kurento.kmf.test.Shell;
import com.kurento.kmf.test.client.Browser;
import com.kurento.kmf.test.services.Node;
import com.kurento.kmf.test.services.Randomizer;
import com.kurento.kmf.test.services.RemoteHost;
import com.kurento.kmf.test.services.SeleniumGridHub;

import freemarker.template.Configuration;
import freemarker.template.Template;

/**
* Base for tests using kmf-media-api, Jetty Http Server and Selenium Grid.
*
* @author Boni Garcia (bgarcia@gsyc.es)
* @since 4.2.5
*/
@Category(SystemMediaApiTests.class)
public class GridBrowserMediaApiTest extends BrowserMediaApiTest {

  public static final int DEFAULT_HUB_PORT = 4444;

  private static final int TIMEOUT_NODE = 120; // seconds
  private static final String LAUNCH_SH = "launch-node.sh";

  private SeleniumGridHub seleniumGridHub;
  private String hubAddress;
  private int hubPort;
  private CountDownLatch countDownLatch;

  public List<Node> nodes;

  @Before
  public void startGrid() throws Exception {
    startHub();
    startNodes();
  }

  private void startHub() throws Exception {
    hubAddress = KmfMediaApiProperties.getThriftKmfAddress().getHost();
    hubPort = getProperty("test.hub.port", DEFAULT_HUB_PORT);

    seleniumGridHub = new SeleniumGridHub(hubAddress, hubPort);
    seleniumGridHub.start();
  }

  private void startNodes() throws InterruptedException {
    countDownLatch = new CountDownLatch(nodes.size());

    for (final Node n : nodes) {
      Thread t = new Thread() {
        public void run() {
          try {
            startNode(n);
          } catch (IOException e) {
            log.error("Exception starting node {} : {}",
                n.getAddress(), e.getClass());
          }
        }
      };
      t.start();
    }

    if (!countDownLatch.await(TIMEOUT_NODE, TimeUnit.SECONDS)) {
      Assert.fail("Timeout waiting nodes (" + TIMEOUT_NODE + " seconds)");
    }
  }

  private void startNode(Node node) throws IOException {
    log.info("Launching node {}", node.getAddress());

    final String chromeDriverName = "/chromedriver";
    final String chromeDriverSource = getPathTestFiles()
        + "/bin/chromedriver/2.9/linux64" + chromeDriverName;
    final String seleniumJarName = "/selenium-server-standalone-2.42.2.jar";
    final String seleniumJarSource = getPathTestFiles()
        + "/bin/selenium-server" + seleniumJarName;

    // OverThere SCP need absolute path, so home path must be known
    String remoteHome = node.getHome();

    final String remoteFolder = remoteHome + "/" + node.REMOTE_FOLDER;
    final String remoteChromeDriver = remoteFolder + chromeDriverName;
    final String remoteSeleniumJar = remoteFolder + seleniumJarName;
    final String remoteScript = node.getTmpFolder() + "/" + LAUNCH_SH;
    final String remotePort = String.valueOf(node.getRemoteHost()
        .getFreePort());

    if (!node.getRemoteHost().exists(remoteFolder) || node.isOverwrite()) {
      node.getRemoteHost()
          .execAndWaitCommand("mkdir", "-p", remoteFolder);
    }
    if (!node.getRemoteHost().exists(remoteChromeDriver)
        || node.isOverwrite()) {
      node.getRemoteHost().scp(chromeDriverSource, remoteChromeDriver);
      node.getRemoteHost().execAndWaitCommand("chmod", "+x",
          remoteChromeDriver);
    }
    if (!node.getRemoteHost().exists(remoteSeleniumJar)
        || node.isOverwrite()) {
      node.getRemoteHost().scp(seleniumJarSource, remoteSeleniumJar);
    }

    // Script is always overwritten
    createRemoteScript(node, remotePort, remoteScript, remoteFolder,
        remoteChromeDriver, remoteSeleniumJar, node.getBrowser(),
        node.getMaxInstances());

    // Copy video in remote host if necessary
    if (node.getVideo() != null) {
      node.getRemoteHost().scp(node.getVideo(), node.getRemoteVideo());
    }

    // Launch node
    node.getRemoteHost().execCommand(remoteScript);

    // Wait to be available for Hub
    waitForNode(node.getAddress(), remotePort);
  }

  private void createRemoteScript(Node node, String remotePort,
      String remoteScript, String remoteFolder,
      String remoteChromeDriver, String remoteSeleniumJar,
      Browser browser, int maxInstances) throws IOException {

    // Create script for Node
    Configuration cfg = new Configuration();

    Map<String, Object> data = new HashMap<String, Object>();
    data.put("remotePort", String.valueOf(remotePort));
    data.put("maxInstances", String.valueOf(maxInstances));
    data.put("hubIp", hubAddress);
    data.put("hubPort", String.valueOf(hubPort));
    data.put("tmpFolder", node.getTmpFolder());
    data.put("remoteChromeDriver", remoteChromeDriver);
    data.put("remoteSeleniumJar", remoteSeleniumJar);
    data.put("pidFile", node.REMOTE_PID_FILE);
    data.put("browser", browser);

    cfg.setClassForTemplateLoading(GridBrowserMediaApiTest.class,
        "/templates/");

    String tmpScript = node.getTmpFolder() + LAUNCH_SH;
    try {
      Template template = cfg.getTemplate(LAUNCH_SH + ".ftl");
      Writer writer = new FileWriter(new File(tmpScript));
      template.process(data, writer);
      writer.flush();
      writer.close();

    } catch (Exception e) {
      throw new RuntimeException(
          "Exception while creating file from template", e);
    }

    // Copy script to remote node
    node.getRemoteHost().scp(tmpScript, remoteScript);
    node.getRemoteHost().execAndWaitCommand("chmod", "+x", remoteScript);
    Shell.run("rm", tmpScript);
  }

  private synchronized void waitForNode(String node, String port) {
    log.info("Waiting for node {} to be ready...", node);
    int responseStatusCode = 0;
    HttpClient client = HttpClientBuilder.create().build();
    HttpGet httpGet = new HttpGet("http://" + node + ":" + port
        + "/wd/hub/static/resource/hub.html");

    // Wait for a max of TIMEOUT_NODE seconds
    long maxSystemTime = System.currentTimeMillis() + TIMEOUT_NODE * 1000;
    do {
      try {
        HttpResponse response = client.execute(httpGet);
        responseStatusCode = response.getStatusLine().getStatusCode();
      } catch (Exception e) {
        try {
          Thread.sleep(100);
        } catch (InterruptedException ie) {
        }
        if (System.currentTimeMillis() > maxSystemTime) {
          log.error("Timeout ({} sec) waiting for node {}",
              TIMEOUT_NODE, node);
        }
      }
    } while (responseStatusCode != HttpStatus.SC_OK);

    if (responseStatusCode == HttpStatus.SC_OK) {
      log.info("Node {} ready (responseStatus {})", node,
          responseStatusCode);
      countDownLatch.countDown();
    }
  }

  protected static List<Node> getRandomNodes(int numNodes, Browser browser) {
    return getRandomNodes(numNodes, browser, null, null);
  }

  protected static List<Node> getRandomNodes(int numNodes, Browser browser,
      String video, String audio) {
    List<Node> nodes = new ArrayList<Node>();

    InputStream inputStream = GridBrowserMediaApiTest.class
        .getClassLoader().getResourceAsStream("node-list.txt");
    List<String> nodeList = null;
    try {
      nodeList = CharStreams.readLines(new InputStreamReader(inputStream,
          Charsets.UTF_8));
    } catch (IOException e) {
      Assert.fail("Exception reading node-list.txt: " + e.getMessage());
    }

    String nodeCandidate;
    long maxSystemTime = System.currentTimeMillis() + 2 * TIMEOUT_NODE
        * 1000;

    do {
      nodeCandidate = nodeList.get(Randomizer.getInt(0, nodeList.size()));
      log.debug("Node candidate {}", nodeCandidate);

      if (RemoteHost.ping(nodeCandidate)) {
        RemoteHost remoteHost = new RemoteHost(nodeCandidate,
            getProperty("test.node.login"),
            getProperty("test.node.passwd"));
        try {
          remoteHost.start();
          int xvfb = remoteHost.runAndWaitCommand("xvfb-run");
          if (xvfb != 2) {
            log.debug("Node {} has no Xvfb", nodeCandidate);
          } else {
            nodes.add(new Node(nodeCandidate, browser, video, audio));
          }
        } catch (Exception e) {
          log.debug("Invalid credentials to access node {} ",
              nodeCandidate);
        } finally {
          remoteHost.stop();
        }

      } else {
        log.debug("Node {} seems to be down", nodeCandidate);
      }
      nodeList.remove(nodeCandidate);

      if (System.currentTimeMillis() > maxSystemTime) {
        Assert.fail("Timeout (" + 2 * TIMEOUT_NODE + " sec) selecting "
            + numNodes + " nodes");
      }

    } while (nodes.size() < numNodes);

    return nodes;
  }

  @After
  public void stopGrid() throws Exception {
    // Stop Hub
    seleniumGridHub.stop();

    // Stop Nodes
    for (Node n : nodes) {
      String remotePid = n.getRemoteHost().execAndWaitCommandNoBr("cat",
          n.getTmpFolder() + "/" + n.REMOTE_PID_FILE);
      n.getRemoteHost().execCommand("pkill", "-KILL", "-P", remotePid);
      n.stopRemoteHost();
    }
  }

  public void runParallel(List<Node> nodeList, Runnable myFunc)
      throws InterruptedException, ExecutionException {
    ExecutorService exec = Executors.newFixedThreadPool(nodes.size());
    List<Future<?>> results = new ArrayList<>();
    for (int i = 0; i < nodes.size(); i++) {
      results.add(exec.submit(myFunc));
    }
    for (Future<?> r : results) {
      r.get();
    }
  }
}
TOP

Related Classes of com.kurento.kmf.test.base.GridBrowserMediaApiTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.