2 * Created on Jul 20, 2007
4 package org
.spirit
.loadtest
;
6 import java
.net
.HttpURLConnection
;
8 import java
.util
.ArrayList
;
9 import java
.util
.HashMap
;
10 import java
.util
.Iterator
;
11 import java
.util
.List
;
13 import java
.util
.Random
;
16 * Sequence Format File should contain the following format:
18 * METHOD_TYPE, URL, <DATA if POST enabled, separated by ';' semicolon [key=value]>
21 public class LoadTestSequenceParser
{
23 private List sequenceData
= new ArrayList();
25 private static final String REQUEST_GET
= "GET";
26 private static final String REQUEST_POST
= "POST";
28 private static final String COMMAND_SLEEP
= "SLEEP";
30 private static final String TEMPLATE_COMMAND_RAND
= "100";
32 public static final String
[][] TEMPLATE_COMMANDS
= {
33 { "RAND", TEMPLATE_COMMAND_RAND
}
36 private final String START_TOKEN
= "{";
37 private final String END_TOKEN
= "}";
39 private Random randObj
= new Random();
40 private final int MAX_RAND_INT
= 10000;
42 public List
getSequenceData() {
47 * When certain template parameters are found within sequence scripts,
48 * parse them accordingly.
50 * For example; http://www.yahoo{RAND#100}.com
52 * Will replace the variable with a random integer number between 0 and 100.
56 public String
processTemplateVars(final String var
) {
57 int startIndex
= var
.indexOf(START_TOKEN
);
58 int endIndex
= var
.indexOf(END_TOKEN
);
59 if ((endIndex
> startIndex
) && (startIndex
>= 0)) {
60 String templateVals
= var
.substring(startIndex
, endIndex
);
61 String res
= parseTemplateVars(templateVals
);
62 // Replace the template variable with a value.
64 return var
.substring(0, startIndex
) + res
+ var
.substring(endIndex
+ 1);
71 * Return the system command code based on the input template variable.
73 * For example, RAND = system code 100 return value.
78 public String
parseTemplateVars(final String var
) {
79 for (int i
= 0; i
< TEMPLATE_COMMANDS
.length
; i
++) {
80 String systemCommand
= TEMPLATE_COMMANDS
[i
][0];
81 String systemCode
= TEMPLATE_COMMANDS
[i
][1];
82 String templateCommand
= var
.substring(1, var
.length());
83 if (systemCommand
.equalsIgnoreCase(templateCommand
)) {
84 if (TEMPLATE_COMMAND_RAND
.equalsIgnoreCase(systemCode
)) {
85 return "" + randObj
.nextInt(MAX_RAND_INT
);
87 } // End of if - system command / template command
92 public void parse(final String sequence_file
) {
93 Object data
[] = LoadTestManager
.loadDataFile(sequence_file
);
94 for (int i
= 0; i
< data
.length
; i
++) {
95 String
[] tokens
= ((String
) data
[i
]).split(",");
96 if ((tokens
.length
== 2) || (tokens
.length
== 3)) {
97 SequenceModel model
= new SequenceModel();
98 String action
= tokens
[0].trim();
99 model
.setActionMethod(tokens
[0].trim());
100 model
.setRequestUrl(tokens
[1].trim());
101 if (action
.equalsIgnoreCase(REQUEST_POST
)) {
102 // Load the POST content
103 String postDataStr
= tokens
[2].trim();
104 String postData
[] = postDataStr
.split(";");
105 for (int k
= 0; k
< postData
.length
; k
++) {
106 String key_val
= postData
[k
];
107 int eq_idx
= key_val
.indexOf("=");
108 String key
= key_val
.substring(0, eq_idx
).trim();
109 String val
= key_val
.substring(eq_idx
+ 1).trim();
111 // Template (variable replace) the key and/or value string values
112 String parseKey
= processTemplateVars(key
);
113 String parseVal
= processTemplateVars(val
);
114 key
= (parseKey
!= null) ? parseKey
: key
;
115 val
= (parseVal
!= null) ? parseVal
: val
;
116 model
.putPostData(key
, val
);
119 // Add the sequence model to the current set of data
120 sequenceData
.add(model
);
122 throw new RuntimeException("Invalid Sequence Data Format, format tokens=" + tokens
.length
);
126 System
.out
.println("INFO: " + sequenceData
.size() + " requests found in sequence");
128 public void printSummary() {
129 for (Iterator it
= sequenceData
.iterator(); it
.hasNext();) {
130 SequenceModel statement
= (SequenceModel
) it
.next();
131 System
.out
.println(statement
);
135 private String
[] handleGETRequest(SequenceModel statement
, final boolean loadExistingCookies
) {
136 String responseTuple
[] = { "" , "", "" };
137 String url
= statement
.getRequestUrl();
138 if (url
!= null && url
.toLowerCase().startsWith("https")) {
139 // Connect with SSL connection
140 System
.out
.println("INFO: attempting connect with SSL connection");
141 responseTuple
= LoadTestManager
.connectURLSSL(url
, loadExistingCookies
);
143 responseTuple
= LoadTestManager
.connectURL(url
, loadExistingCookies
);
145 return responseTuple
;
148 private String
[] handlePOSTRequest(SequenceModel statement
, final boolean loadExistingCookies
) throws Exception
{
149 String responseTuple
[] = { "" , "", "" };
150 String str_url
= statement
.getRequestUrl();
152 URL url
= LoadTestManager
.getSSLURL(str_url
);
153 HttpURLConnection
.setFollowRedirects(false);
154 HttpURLConnection conn
= (HttpURLConnection
) url
.openConnection();
155 LoadTestManager
.postDataSSL(statement
.getPostData(), conn
, url
, str_url
, false, loadExistingCookies
);
156 System
.out
.println("done posting SSL data");
158 return responseTuple
;
161 private void handleSleepCommand(SequenceModel statement
) {
162 String time_ms
= statement
.getRequestUrl();
163 int sleepTime
= Integer
.parseInt(time_ms
);
165 Thread
.sleep(sleepTime
);
166 } catch (InterruptedException e
) {
171 * Handle all of the sequence statements and perform the according requests.
173 public void handleSequence() {
175 for (Iterator it
= this.sequenceData
.iterator(); it
.hasNext();) {
176 boolean loadExistingCookies
= (sequenceNo
== 0) ?
false : true;
177 String responseTuple
[] = { "", "", "" };
178 SequenceModel statement
= (SequenceModel
) it
.next();
179 long tStart
= System
.currentTimeMillis();
180 if (statement
.getActionMethod().equalsIgnoreCase(REQUEST_GET
)) {
181 System
.out
.println("seq=[" + sequenceNo
+ "] attempting GET request to=" + statement
.getRequestUrl());
182 responseTuple
= handleGETRequest(statement
, loadExistingCookies
);
183 LoadTestManager
.getTestClient().incNumberOfRequests();
184 } else if (statement
.getActionMethod().equalsIgnoreCase(REQUEST_POST
)) {
185 System
.out
.println("seq=[" + sequenceNo
+ "] attempting POST request to=" + statement
.getRequestUrl());
187 responseTuple
= handlePOSTRequest(statement
, loadExistingCookies
);
188 } catch(Exception e
) {
191 LoadTestManager
.getTestClient().incNumberOfRequests();
192 } else if (statement
.getActionMethod().equalsIgnoreCase(COMMAND_SLEEP
)) {
193 // Delay for X number of milliseconds when a sleep command is found
194 handleSleepCommand(statement
);
196 throw new RuntimeException("Action method not supported=" + statement
.getActionMethod());
199 long tEnd
= System
.currentTimeMillis();
200 long diff
= tEnd
- tStart
;
202 // For data keeping, increment total requests
203 LoadTestManager
.getTestClient().incTotalTime(diff
);
205 System
.out
.println("single request time=" + diff
+ " ms -- from thread:" + Thread
.currentThread().getName());
206 LoadTestManager
.log(diff
, responseTuple
, statement
.getRequestUrl());
208 // The following code buildRequestSection, clearRequest are needed after writing the HTML content
209 LoadTestManager
.getTestClient().getHtmlOutput().buildRequestSection(diff
+ " ms, requests=" + sequenceNo
);
210 LoadTestManager
.getTestClient().getHtmlOutput().clearRequest();
215 public class SequenceModel
{
216 private String actionMethod
= "GET";
217 private String requestUrl
= "http://localhost";
218 private Map postData
= new HashMap();
219 public String
getActionMethod() {
223 public Map
getPostData() {
227 public String
getRequestUrl() {
230 public void setActionMethod(String string
) {
231 actionMethod
= string
;
233 public void putPostData(final String key
, final String val
) {
234 this.postData
.put(key
, val
);
236 public void setRequestUrl(String string
) {
239 public String
toString() {
240 return "SequenceModel: action=[" + actionMethod
+ "], url=[" + requestUrl
+ "], data=[" + postData
+ "]";