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; } }