blob: 7afa9d90538a723c968bc118cc5d6ecf7471b5ca [file] [log] [blame]
// Copyright 2011 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.enterprise.adaptor;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import com.sun.net.httpserver.HttpExchange;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.List;
/**
* Tests for {@link RpcHandler}.
*/
public class RpcHandlerTest {
@Rule
public ExpectedException thrown = ExpectedException.none();
private static final String SESSION_COOKIE_NAME = "testSess";
private SessionManager.ClientStore<HttpExchange> clientStore
= new SessionManager.HttpExchangeClientStore(SESSION_COOKIE_NAME);
private SessionManager<HttpExchange> sessionManager
= new SessionManager<HttpExchange>(new MockTimeProvider(),
clientStore, 10000, 1000);
private RpcHandler handler = new RpcHandler(sessionManager);
private Charset charset = Charset.forName("UTF-8");
private String sessionId;
private String xsrfToken;
@Before
public void loadXsrfToken() throws Exception {
MockHttpExchange ex = makeExchange("POST", "/r", "/r");
handler.handle(ex);
assertEquals(409, ex.getResponseCode());
xsrfToken = (String) ex.getResponseHeaders().getFirst(
RpcHandler.XSRF_TOKEN_HEADER_NAME);
assertNotNull(xsrfToken);
sessionId = clientStore.retrieve(ex);
assertNotNull(sessionId);
}
@Test
public void testGet() throws Exception {
MockHttpExchange ex = makeExchange("GET", "/r", "/r");
handler.handle(ex);
assertEquals(405, ex.getResponseCode());
}
@Test
public void testWrongPath() throws Exception {
MockHttpExchange ex = makeExchange("POST", "/rwrong", "/r");
handler.handle(ex);
assertEquals(404, ex.getResponseCode());
}
@Test
public void testUnknownMethod() throws Exception {
MockHttpExchange ex = makeExchange("POST", "/r", "/r");
ex.setRequestBody(stringToStream(
"{\"method\": \"wrong\",\"params\":null,\"id\":null}"));
handler.handle(ex);
assertEquals(200, ex.getResponseCode());
String response = new String(ex.getResponseBytes(), charset);
JSONObject obj = (JSONObject) JSONValue.parse(response);
assertTrue(obj.get("error") != null);
assertTrue(obj.get("result") == null);
}
@Test
public void testInvalidXsrfToken() throws Exception {
MockHttpExchange ex = new MockHttpExchange("POST", "/r",
new MockHttpContext(handler, "/r"));
ex.getRequestHeaders().set("Cookie", SESSION_COOKIE_NAME + "=" + sessionId);
handler.handle(ex);
assertEquals(409, ex.getResponseCode());
assertNotNull(ex.getResponseHeaders().get(
RpcHandler.XSRF_TOKEN_HEADER_NAME));
}
@Test
public void testInvalidJson() throws Exception {
MockHttpExchange ex = makeExchange("POST", "/r", "/r");
ex.setRequestBody(stringToStream("{"));
handler.handle(ex);
assertEquals(400, ex.getResponseCode());
}
@Test
public void testNoInput() throws Exception {
MockHttpExchange ex = makeExchange("POST", "/r", "/r");
handler.handle(ex);
assertEquals(400, ex.getResponseCode());
}
@Test
public void testInvalidInput() throws Exception {
MockHttpExchange ex = makeExchange("POST", "/r", "/r");
ex.setRequestBody(stringToStream("[]"));
handler.handle(ex);
assertEquals(200, ex.getResponseCode());
String response = new String(ex.getResponseBytes(), charset);
JSONObject obj = (JSONObject) JSONValue.parse(response);
assertTrue(obj.get("error") != null);
assertTrue(obj.get("result") == null);
}
@Test
public void testValidCallWithResponse() throws Exception {
handler.registerRpcMethod("someName", new RpcHandler.RpcMethod() {
@Override
public Object run(List request) throws Exception {
if (request.size() == 1 && request.get(0).equals("input")) {
return "some response";
} else {
throw new RuntimeException("Wrong input");
}
}
});
MockHttpExchange ex = makeExchange("POST", "/r", "/r");
ex.setRequestBody(stringToStream(
"{\"id\": null, \"method\": \"someName\", \"params\": [\"input\"]}"));
handler.handle(ex);
assertEquals(200, ex.getResponseCode());
String response = new String(ex.getResponseBytes(), charset);
JSONObject obj = (JSONObject) JSONValue.parse(response);
assertNull(obj.get("error"));
assertEquals("some response", obj.get("result"));
// Make sure that the method can be unregistered.
handler.unregisterRpcMethod("someName");
ex = makeExchange("POST", "/r", "/r");
ex.setRequestBody(stringToStream(
"{\"id\": null, \"method\": \"someName\", \"params\": [\"input\"]}"));
handler.handle(ex);
assertEquals(200, ex.getResponseCode());
response = new String(ex.getResponseBytes(), charset);
obj = (JSONObject) JSONValue.parse(response);
assertNotNull(obj.get("error"));
assertNull(obj.get("result"));
}
@Test
public void testValidCallWithBrokenResponse() throws Exception {
handler.registerRpcMethod("someName", new RpcHandler.RpcMethod() {
@Override
public Object run(List request) throws Exception {
return null;
}
});
MockHttpExchange ex = makeExchange("POST", "/r", "/r");
ex.setRequestBody(stringToStream(
"{\"id\": null, \"method\": \"someName\", \"params\": null}"));
handler.handle(ex);
assertEquals(200, ex.getResponseCode());
String response = new String(ex.getResponseBytes(), charset);
JSONObject obj = (JSONObject) JSONValue.parse(response);
assertNotNull(obj.get("error"));
assertNull(obj.get("result"));
}
@Test
public void testExceptionWithMessage() throws Exception {
handler.registerRpcMethod("someName", new RpcHandler.RpcMethod() {
@Override
public Object run(List request) throws Exception {
throw new RuntimeException("some error");
}
});
MockHttpExchange ex = makeExchange("POST", "/r", "/r");
ex.setRequestBody(stringToStream(
"{\"id\": null, \"method\": \"someName\", \"params\": null}"));
handler.handle(ex);
assertEquals(200, ex.getResponseCode());
String response = new String(ex.getResponseBytes(), charset);
JSONObject obj = (JSONObject) JSONValue.parse(response);
assertEquals("some error", obj.get("error"));
assertNull(obj.get("result"));
}
@Test
public void testExceptionWithoutMessage() throws Exception {
handler.registerRpcMethod("someName", new RpcHandler.RpcMethod() {
@Override
public Object run(List request) throws Exception {
throw new RuntimeException();
}
});
MockHttpExchange ex = makeExchange("POST", "/r", "/r");
ex.setRequestBody(stringToStream(
"{\"id\": null, \"method\": \"someName\", \"params\": null}"));
handler.handle(ex);
assertEquals(200, ex.getResponseCode());
String response = new String(ex.getResponseBytes(), charset);
JSONObject obj = (JSONObject) JSONValue.parse(response);
assertNotNull(obj.get("error"));
assertNull(obj.get("result"));
}
@Test
public void testDoubleRegisterRpcMethod() {
RpcHandler.RpcMethod method = new ErroringRpcMethod();
handler.registerRpcMethod("someName", method);
thrown.expect(IllegalStateException.class);
handler.registerRpcMethod("someName", method);
}
@Test
public void testDoubleUnregisterRpcMethod() {
RpcHandler.RpcMethod method = new ErroringRpcMethod();
handler.registerRpcMethod("someName", method);
handler.unregisterRpcMethod("someName");
thrown.expect(IllegalStateException.class);
handler.unregisterRpcMethod("someName");
}
private MockHttpExchange makeExchange(String method, String path,
String contextPath) throws Exception {
MockHttpExchange ex = new MockHttpExchange(method, path,
new MockHttpContext(handler, contextPath));
ex.getRequestHeaders().set(RpcHandler.XSRF_TOKEN_HEADER_NAME, xsrfToken);
ex.getRequestHeaders().set("Cookie", SESSION_COOKIE_NAME + "=" + sessionId);
return ex;
}
private InputStream stringToStream(String str) {
return new ByteArrayInputStream(str.getBytes(charset));
}
private static class ErroringRpcMethod implements RpcHandler.RpcMethod {
@Override
public Object run(List request) throws Exception {
throw new RuntimeException();
}
}
}