/**
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS-IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.apphosting.vmruntime.jetty9;
import com.google.appengine.api.memcache.MemcacheServicePb.MemcacheGetResponse;
import com.google.appengine.api.memcache.MemcacheServicePb.MemcacheGetResponse.Item;
import com.google.appengine.api.memcache.MemcacheServicePb.MemcacheSetRequest;
import com.google.appengine.api.memcache.MemcacheServicePb.MemcacheSetResponse;
import com.google.appengine.api.memcache.MemcacheServicePb.MemcacheSetResponse.SetStatusCode;
import com.google.apphosting.api.ApiProxy;
import com.google.apphosting.api.DatastorePb.PutResponse;
import com.google.apphosting.vmruntime.VmApiProxyEnvironment;
import com.google.storage.onestore.v3.OnestoreEntity.Path;
import com.google.storage.onestore.v3.OnestoreEntity.Path.Element;
import com.google.storage.onestore.v3.OnestoreEntity.Reference;
import java.io.IOException;
import java.net.HttpURLConnection;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import java.net.URL;
import java.util.Arrays;
import javax.servlet.http.HttpServletResponse;
/**
* Tests for running AppEngine Java apps inside a VM using a Jetty 9 container
* with HTTP servlet sessions enabled.
*
* @author isdal@google.com (Tomas Isdal)
*/
public class VmRuntimeJettySessionTest extends VmRuntimeTestBase {
@Override
protected void setUp() throws Exception {
appengineWebXml = "WEB-INF/sessions-enabled-appengine-web.xml";
super.setUp();
}
protected int fetchResponseCode(URL url) throws IOException {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.connect();
return connection.getResponseCode();
}
public void testSsl_NoSSL() throws Exception {
HttpClient httpClient = new HttpClient();
httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(30000);
GetMethod get = new GetMethod(createUrl("/test-ssl").toString());
int httpCode = httpClient.executeMethod(get);
assertEquals(200, httpCode);
String expected = "false:http:http://localhost:"+port+"/test-ssl";
assertEquals(expected, get.getResponseBodyAsString());
}
public void testSsl_WithSSL() throws Exception {
HttpClient httpClient = new HttpClient();
httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(30000);
URL url = createUrl("/test-ssl");
GetMethod get = new GetMethod(url.toString());
get.addRequestHeader(VmApiProxyEnvironment.HTTPS_HEADER, "on");
int httpCode = httpClient.executeMethod(get);
assertEquals(200, httpCode);
assertEquals("true:https:https://localhost/test-ssl", get.getResponseBodyAsString());
}
public void LUDOTODOtestWithInvalidInboundIp() throws Exception {
HttpClient httpClient = new HttpClient();
httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(30000);
GetMethod get = new GetMethod(createUrlForHostIP("/test-ssl").toString());
int httpCode = httpClient.executeMethod(get);
assertEquals(403, httpCode);
}
/**
* Tests that mapping a servlet to / works.
*
* @throws Exception
*/
public void testWelcomeServlet() throws Exception {
String[] lines = fetchUrl(createUrl("/"));
assertTrue(Arrays.asList(lines).contains("Hello, World!"));
}
// public void testHealthCheckInterval() throws Exception {
// // Test that it was not healthy without IsLastSuccessful query string.
// int code = fetchResponseCode(createUrl("/_ah/health"));
// assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, code);
//
// // Test that it will be healthy if the last IsLastSuccessful query string was less than
// // VmRuntimeWebAppContext.checkIntervalSec ago.
// String[] lines = fetchUrl(createUrl("/_ah/health?IsLastSuccessful=yes"));
// assertEquals(1, lines.length);
// assertEquals("ok", lines[0].trim());
//
// Thread.sleep((VmRuntimeWebAppContext.checkIntervalSec - 1) * 1000);
//
// code = fetchResponseCode(createUrl("/_ah/health"));
// assertEquals(HttpServletResponse.SC_OK, code);
//
// // Test that it will be unhealthy if the last IsLastSuccessful query string was more than
// // VmRuntimeWebAppContext.checkIntervalSec ago.
// lines = fetchUrl(createUrl("/_ah/health?IsLastSuccessful=yes"));
// assertEquals(1, lines.length);
// assertEquals("ok", lines[0].trim());
//
// Thread.sleep(VmRuntimeWebAppContext.checkIntervalSec * 1000);
//
// code = fetchResponseCode(createUrl("/_ah/health"));
// assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, code);
// }
/**
* Create a datastore put response with the minimal fields required to make
* the put succeed.
*
* @return A new PutReponse object.
*/
private PutResponse createDatastorePutResponse() {
PutResponse putResponse = new PutResponse();
Reference key = putResponse.addKey();
key.setApp(VmRuntimeTestBase.PROJECT);
Path path = key.getMutablePath();
Element element = path.addElement();
element.setType("kind");
element.setName("name");
return putResponse;
}
/**
* Test that sessions are persisted in the datastore and memcache, and that
* any data stored is available to subsequent requests.
*
* @throws Exception
*/
public void testSessions() throws Exception {
URL url = createUrl("/count?type=session");
FakeableVmApiProxyDelegate fakeApiProxy = new FakeableVmApiProxyDelegate();
ApiProxy.setDelegate(fakeApiProxy);
// Add responses for session create.
fakeApiProxy.addApiResponse(createDatastorePutResponse());
fakeApiProxy.addApiResponse(
MemcacheSetResponse.newBuilder().addSetStatus(SetStatusCode.STORED).build());
// Add responses for session save.
fakeApiProxy.addApiResponse(createDatastorePutResponse());
fakeApiProxy.addApiResponse(
MemcacheSetResponse.newBuilder().addSetStatus(SetStatusCode.STORED).build());
// Make a call to count and save the session cookie.
HttpClient httpClient = new HttpClient();
httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(30000);
GetMethod firstGet = new GetMethod(url.toString());
int returnCode = httpClient.executeMethod(firstGet);
assertEquals(HttpServletResponse.SC_OK, returnCode);
// Check the count, should be 1 for the first request.
assertEquals("1", firstGet.getResponseBodyAsString().trim());
// Parse the memcache put request so we can respond to the next get request.
MemcacheSetRequest setRequest
= MemcacheSetRequest.parseFrom(fakeApiProxy.getLastRequest().getRequestData());
assertEquals(1, setRequest.getItemCount());
Item responsePayload = Item.newBuilder()
.setKey(setRequest.getItem(0).getKey()).setValue(setRequest.getItem(0).getValue()).build();
MemcacheGetResponse getResponse
= MemcacheGetResponse.newBuilder().addItem(responsePayload).build();
fakeApiProxy.addApiResponse(getResponse);
// Add responses for session save.
fakeApiProxy.addApiResponse(createDatastorePutResponse());
fakeApiProxy.addApiResponse(
MemcacheSetResponse.newBuilder().addSetStatus(SetStatusCode.STORED).build());
// Make a call to count with the session cookie.
GetMethod secondGet = new GetMethod(url.toString());
returnCode = httpClient.executeMethod(secondGet);
assertEquals(HttpServletResponse.SC_OK, returnCode);
// Check the count, should be "2" for the second request.
assertEquals("2", secondGet.getResponseBodyAsString().trim());
}
}