package com.robonobo.test; import static com.robonobo.common.util.TextUtil.*; import java.io.*; import java.util.*; import org.apache.commons.httpclient.*; import org.apache.commons.httpclient.auth.AuthScope; import org.apache.commons.httpclient.methods.*; import org.apache.commons.httpclient.params.HttpConnectionManagerParams; import com.google.protobuf.AbstractMessage; import com.google.protobuf.GeneratedMessage; import com.robonobo.common.serialization.*; import com.robonobo.common.util.TextUtil; import com.robonobo.core.api.proto.CoreApi.PlaylistMsg; import com.robonobo.core.api.proto.CoreApi.StreamMsg; import com.robonobo.core.api.proto.CoreApi.UserMsg; public class MidasSoakTester { static final int MAX_HTTP_CONNECTIONS_PER_CLIENT = 4; /** percentage */ static final int PLAYLIST_CHANGE_CHANCE = 10; String midasUrl; List<Long> userIds; int numThreads; Random rand = new Random(); List<String> sids; static void printUsage() { System.err.println("Usage: MidasSoakTester <sid file> <midas url> <minUserId> <maxUserId> <num threads>"); } public static void main(String[] args) throws Exception { if (args.length < 5) { printUsage(); return; } File sidFile = new File(args[0]); BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(sidFile))); List<String> sids = new ArrayList<String>(); String line; while ((line = in.readLine()) != null) { sids.add(line); } in.close(); String midasUrl = args[1]; long minUserId = Long.parseLong(args[2]); long maxUserId = Long.parseLong(args[3]); int numThreads = Integer.parseInt(args[4]); List<Long> userIds = new ArrayList<Long>(); for (long i = minUserId; i <= maxUserId; i++) { userIds.add(i); } MidasSoakTester mst = new MidasSoakTester(midasUrl, userIds, sids, numThreads); mst.run(); } public MidasSoakTester(String midasUrl, List<Long> userIds, List<String> sids, int numThreads) { this.midasUrl = midasUrl; this.userIds = userIds; this.numThreads = numThreads; this.sids = sids; } public void run() throws Exception { for(int i=0;i<numThreads;i++) { Thread t = new SoakTestThread(i); t.start(); } } class SoakTestThread extends Thread { int num; HttpClient client; public SoakTestThread(int num) { this.num = num; HttpConnectionManagerParams httpParams = new HttpConnectionManagerParams(); httpParams.setDefaultMaxConnectionsPerHost(MAX_HTTP_CONNECTIONS_PER_CLIENT); HttpConnectionManager connMgr = new MultiThreadedHttpConnectionManager(); connMgr.setParams(httpParams); client = new HttpClient(connMgr); } @Override public void run() { while (true) { long userId = userIds.get(rand.nextInt(userIds.size())); String userEmail = "testuser-"+userId+"@robonobo.com"; String pwd = "password"; UserMsg.Builder ub = UserMsg.newBuilder(); String userUrl = midasUrl + "users/byemail/"+urlEncode(userEmail); try { System.out.println(num+": fetching user "+userId); getObjectFromUrl(ub, userUrl, userEmail, pwd); UserMsg um = ub.build(); for (long plId : um.getPlaylistIdList()) { String playlistUrl = midasUrl + "playlists/" + Long.toHexString(plId); PlaylistMsg.Builder pb = PlaylistMsg.newBuilder(); System.out.println(num+": fetching playlist "+plId); getObjectFromUrl(pb, playlistUrl, userEmail, pwd); PlaylistMsg pm = pb.build(); for (String sid : pm.getStreamIdList()) { String streamUrl = midasUrl + "streams/"+sid; StreamMsg.Builder sb = StreamMsg.newBuilder(); System.out.println(num+": fetching stream "+sid); getObjectFromUrl(sb, streamUrl, userEmail, pwd); StreamMsg sm = sb.build(); } // Change this playlist, maybe int babyNeedsANewPairOfShoes = rand.nextInt(100); if(babyNeedsANewPairOfShoes < PLAYLIST_CHANGE_CHANCE) { pb = PlaylistMsg.newBuilder(pm); pb.clearStreamId(); Set<String> newSids = new HashSet<String>(); while(newSids.size() < pm.getStreamIdCount()) { newSids.add(sids.get(rand.nextInt(sids.size()))); } pb.addAllStreamId(newSids); System.out.println(num+": updating playlist "+plId); putObjectToUrl(pb.build(), playlistUrl, null, userEmail, pwd); } } } catch (Exception e) { e.printStackTrace(); System.exit(1); } } } public void getObjectFromUrl(AbstractMessage.Builder bldr, String url, String username, String password) throws IOException, SerializationException { GetMethod get = new GetMethod(url); try { if (username != null) { client.getState().setAuthenticationPreemptive(true); client.getState().setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password)); } int statusCode = client.executeMethod(get); switch (statusCode) { case 200: bldr.mergeFrom(get.getResponseBodyAsStream()); break; case 404: throw new ResourceNotFoundException("Server could not find resource for " + url); case 401: throw new UnauthorizedException("Server did not allow us to access url " + url + " with supplied credentials"); case 500: throw new IOException("Unable to get object from url '" + url + "', server said: " + get.getResponseBodyAsString()); default: throw new IOException("Url '" + url + "' replied with status " + statusCode); } } finally { get.releaseConnection(); } } public void putObjectToUrl(GeneratedMessage msg, String url, AbstractMessage.Builder bldr, String username, String password) throws IOException { PutMethod put = new PutMethod(url); try { put.setRequestEntity(new ByteArrayRequestEntity(msg.toByteArray())); // set auth client.getState().setAuthenticationPreemptive(true); client.getState().setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password)); int statusCode = client.executeMethod(put); switch (statusCode) { case 200: if(bldr != null) { byte[] bodBytes = put.getResponseBody(); bldr.mergeFrom(bodBytes); } return; default: throw new IOException("Server replied with status " + statusCode + ": " + put.getResponseBodyAsString()); } } finally { put.releaseConnection(); } } } }