package org.radargun.stages;
import java.util.Collections;
import java.util.List;
import javax.ws.rs.core.Cookie;
import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.Response;
import org.radargun.Operation;
import org.radargun.RESTOperationInvocations;
import org.radargun.Version;
import org.radargun.config.Namespace;
import org.radargun.config.Property;
import org.radargun.config.Stage;
import org.radargun.stages.test.Invocation;
import org.radargun.stages.test.OperationLogic;
import org.radargun.stages.test.OperationSelector;
import org.radargun.stages.test.RatioOperationSelector;
import org.radargun.stages.test.Stressor;
import org.radargun.stages.test.TestStage;
import org.radargun.traits.InjectTrait;
import org.radargun.traits.RESTOperations;
/**
* A test stage for REST operations on a Web application running in a remote
* web container. Performing only Get operations.
*
* @author Martin Gencur
*/
@Namespace(name = RESTOperationsTestStage.NAMESPACE)
@Stage(doc = "Test using RESTOperations with specific URL")
public class RESTOperationsTestStage extends TestStage {
public static final String NAMESPACE = "urn:radargun:stages:rest:" + Version.SCHEMA_VERSION;
@Property(doc = "Ratio of GET requests. Default is 1 (100%).")
protected int getRatio = 1;
/**
* Context path is the part of URL after the port. It is appended to http://host:port
* in order to create the full URL.
*/
@Property(doc = "The context path for this REST stage. Defaults to empty string.")
private String contextPath = "";
@InjectTrait
protected RESTOperations restOperations;
@Override
protected OperationSelector createOperationSelector() {
return new RatioOperationSelector.Builder()
.add(RESTOperations.GET, getRatio)
.build();
}
@Override
public OperationLogic getLogic() {
return new StickySessionLogic();
}
/**
* The logic sends GET requests to a predefined URL and keeps track of
* a session cookie (JSESSIONID). If the logic receives a new session
* from the remote Web server, it logs an error unless it is a first request.
* The new session is expected on the first request.
*/
protected class StickySessionLogic extends OperationLogic {
private static final String JSESSIONID = "JSESSIONID";
protected RESTOperations.RESTOperationInvoker restInvoker;
private boolean isFirstRequest = true;
private Cookie jsessionid;
@Override
public void init(Stressor stressor) {
super.init(stressor);
this.restInvoker = restOperations.getRESTInvoker(contextPath);
stressor.setUseTransactions(false);//transactions for HTTP ops do not make sense
}
@Override
public void run(Operation operation) throws RequestException {
Response response;
Invocation invocation;
if (operation == RESTOperations.GET) {
List<Cookie> cookies = jsessionid == null ? Collections.EMPTY_LIST : Collections.singletonList(jsessionid);
invocation = new RESTOperationInvocations.Get(restInvoker, cookies, null);
} else {
throw new IllegalArgumentException(operation.name);
}
response = stressor.<Response>makeRequest(invocation);
validateSession(response);
isFirstRequest = false;
}
private void validateSession(Response response) throws RequestException {
NewCookie newSessionId = response.getCookies().get(JSESSIONID);
if (newSessionId != null) {
jsessionid = newSessionId.toCookie();
if (!isFirstRequest) {
throw new IllegalStateException("Session lost!");
}
log.info("New session: " + jsessionid);
}
}
}
}