package geniusweb.runserver;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import geniusweb.deadline.Deadline;
import geniusweb.deadline.DeadlineTime;
import geniusweb.protocol.session.TeamInfo;
import geniusweb.protocol.session.saop.SAOPSettings;
import geniusweb.references.Parameters;
import geniusweb.references.PartyRef;
import geniusweb.references.PartyWithParameters;
import geniusweb.references.PartyWithProfile;
import geniusweb.references.ProfileRef;
/**
* End to end test starts server, plus partyserver plus profilesserver, and then
* tries to launch large number of parties and keep them busy. Checks and
* reports the average CPU loads. Ensure that you have no other background tasks
* when you run this test, to avoid incorrect CPU measurements (we can't measure
* java-only CPU loads)
*
*
*
Large tests
Tomcat-embed seems very limited in heap space. Best way
* to test this with {@link #NUMBER_SESSIONS}>20 is to run all services on
* standard tomcat (not embed). To achieve this, disable the @Before and @After.
* Additionally, make sure that server.xml has maxThreads="4500" or some large
* number sufficient for your test.
*/
public class MaxLoadTest {
private static final int NUMBER_SESSIONS = 5;
private static final int INTER_LAUNCH_DELAY = 20;
private static final int PARTY_RESPONSETIME = 1;
// HACK can we get it from maven?
private static final String GENIUSWEB_VERSION = "2.0.5";
private static final ObjectMapper jackson = new ObjectMapper();
private static final String HARDLINER = "http://localhost:8080/partiesserver/run/hardliner-"
+ GENIUSWEB_VERSION;
/**
* Test takes average load of last minute. It may take also a minute or two
* to launch all sessions to start with. The average should be taken AFTER
* all sessions were launched.
*/
private static final long TEST_TIME_MS = 3 * 60 * 1000;
private static final EmbeddedTomcat tomcat = new EmbeddedTomcat();
private static final Parameters parameters = new Parameters().with("delay",
PARTY_RESPONSETIME);
private static final String PROFILE1 = "ws://localhost:8080/profilesserver/websocket/get/7issues/7issues1";
private static final String PROFILE2 = "ws://localhost:8080/profilesserver/websocket/get/7issues/7issues2";
private static final Deadline deadline = new DeadlineTime(TEST_TIME_MS);
private final URL url;
private final byte[] startcommand;
public MaxLoadTest() throws MalformedURLException, JsonProcessingException,
URISyntaxException {
url = new URL("http://localhost:8080/runserver/run");
String startsession = jackson.writeValueAsString(getSettings());
startcommand = startsession.toString().getBytes(StandardCharsets.UTF_8);
}
/**
* Start up embedded tomcat servers (all: parties-, profile- and run-server)
*
* @throws InterruptedException
*
* @throws Throwable
*/
@Before
public void before() throws InterruptedException {
tomcat.start();
tomcat.deploy("runserver");
tomcat.deployWar("profilesserver", new File(
"target/jars/profilesserver-" + GENIUSWEB_VERSION + ".war"));
tomcat.deployWar("partiesserver", new File(
"target/jars/partiesserver-" + GENIUSWEB_VERSION + ".war"));
System.out.println("waiting for server start");
Thread.sleep(1500);// HOW do this properly?
System.out.println("server started I hope");
}
@After
public void after() throws InterruptedException {
System.setSecurityManager(null);
tomcat.stop();
Thread.sleep(2000);
}
@Test
public void testRunOneSession()
throws URISyntaxException, IOException, InterruptedException {
for (int n = 0; n < NUMBER_SESSIONS; n++) {
startSession();
Thread.sleep(INTER_LAUNCH_DELAY);
}
System.out.println("Started session. Waiting termination");
// wait at least 1minute, becaues getLoadAver averages over 1 minute.
Thread.sleep(Math.max(TEST_TIME_MS + 100, 60 * 1000));
OperatingSystemMXBean operatingSystemMXBean = ManagementFactory
.getOperatingSystemMXBean();
System.out.println("average load in last minute was "
+ operatingSystemMXBean.getSystemLoadAverage());
}
/**
*
* @return the response received from the startup request
* @throws IOException
* @throws ProtocolException
* @throws IllegalStateException if party can not be launched.
*/
private void startSession() throws IOException, ProtocolException {
URLConnection con = url.openConnection();
HttpURLConnection http = (HttpURLConnection) con;
http.setRequestMethod("POST"); // PUT is another valid option
http.setDoOutput(true);
http.setFixedLengthStreamingMode(startcommand.length);
http.setRequestProperty("Content-Type",
"application/json; charset=UTF-8");
http.setUseCaches(false);
http.setDoOutput(true);
http.connect();
try (OutputStream os = http.getOutputStream()) {
os.write(startcommand);
}
InputStream is = http.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String response = "";
String line;
while ((line = rd.readLine()) != null) {
response += line + "\r";
}
rd.close();
System.out.println("sent request. Response=" + response);
if (!(response.startsWith("SAOP")))
throw new IllegalStateException(
"Failed to start party:" + response);
}
private SAOPSettings getSettings() throws URISyntaxException {
PartyRef partyref = new PartyRef(HARDLINER);
PartyWithParameters party1 = new PartyWithParameters(partyref,
parameters);
PartyWithParameters party2 = new PartyWithParameters(partyref,
parameters);
PartyWithProfile partyprofile1 = new PartyWithProfile(party1,
new ProfileRef(PROFILE1));
PartyWithProfile partyprofile2 = new PartyWithProfile(party2,
new ProfileRef(PROFILE2));
TeamInfo team1 = new TeamInfo(Arrays.asList(partyprofile1));
TeamInfo team2 = new TeamInfo(Arrays.asList(partyprofile2));
List participants = Arrays.asList(team1, team2);
SAOPSettings settings = new SAOPSettings(participants, deadline);
return settings;
}
}