blob: f1336b307f8e6723f6808ba361bd43192999d824 [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 adaptorlib;
import static org.junit.Assert.*;
import org.junit.*;
import org.junit.rules.ExpectedException;
import java.io.*;
import java.util.*;
import java.net.URI;
import java.nio.charset.Charset;
/**
* Tests for {@link DocumentHandlerTest}.
*/
public class DocumentHandlerTest {
@Rule
public ExpectedException thrown = ExpectedException.none();
private DocumentHandler handler = new DocumentHandler("localhost",
Charset.forName("UTF-8"), new MockDocIdDecoder(),
new Journal(new MockTimeProvider()), new MockAdaptor(), false,
"localhost", new String[0], null, null);
private MockHttpExchange ex = new MockHttpExchange("http", "GET", "/",
new MockHttpContext(handler, "/"));
@Test
public void testSecurity() throws Exception {
handler = new DocumentHandler("localhost", Charset.forName("UTF-8"),
new MockDocIdDecoder(), new Journal(new MockTimeProvider()),
new PrivateMockAdaptor(), false, "localhost", new String[0], null,
null);
handler.handle(ex);
assertEquals(403, ex.getResponseCode());
}
@Test
public void testSecurityFromGsa() throws Exception {
// 127.0.0.3 is the address hard-coded in MockHttpExchange
handler = new DocumentHandler("localhost", Charset.forName("UTF-8"),
new MockDocIdDecoder(), new Journal(new MockTimeProvider()),
new PrivateMockAdaptor(), false, "localhost",
new String[] {"127.0.0.3", " "}, null, null);
handler.handle(ex);
assertEquals(200, ex.getResponseCode());
assertArrayEquals(new byte[] {1, 2, 3}, ex.getResponseBytes());
}
@Test
public void testSecurityFromGsaNoWhitelist() throws Exception {
// 127.0.0.3 is the address hard-coded in MockHttpExchange
handler = new DocumentHandler("localhost", Charset.forName("UTF-8"),
new MockDocIdDecoder(), new Journal(new MockTimeProvider()),
new PrivateMockAdaptor(), false, "127.0.0.3",
new String[0], null, null);
handler.handle(ex);
assertEquals(403, ex.getResponseCode());
}
@Test
public void testSecurityFromGsaAutoAddWhitelist() throws Exception {
// 127.0.0.3 is the address hard-coded in MockHttpExchange
handler = new DocumentHandler("localhost", Charset.forName("UTF-8"),
new MockDocIdDecoder(), new Journal(new MockTimeProvider()),
new PrivateMockAdaptor(), true, "127.0.0.3",
new String[0], null, null);
handler.handle(ex);
assertEquals(200, ex.getResponseCode());
assertArrayEquals(new byte[] {1, 2, 3}, ex.getResponseBytes());
}
@Test
public void testNoSuchHost() throws Exception {
thrown.expect(RuntimeException.class);
handler = new DocumentHandler("localhost", Charset.forName("UTF-8"),
new MockDocIdDecoder(), new Journal(new MockTimeProvider()),
new PrivateMockAdaptor(), false, "localhost",
new String[] {"-no-such-host-"}, null, null);
}
@Test
public void testNoSuchGsaHost() throws Exception {
thrown.expect(RuntimeException.class);
handler = new DocumentHandler("localhost", Charset.forName("UTF-8"),
new MockDocIdDecoder(), new Journal(new MockTimeProvider()),
new PrivateMockAdaptor(), true, "-no-such-host-",
new String[0], null, null);
}
@Test
public void testNormal() throws Exception {
handler.handle(ex);
assertEquals(200, ex.getResponseCode());
assertArrayEquals(new byte[] {1, 2, 3}, ex.getResponseBytes());
}
@Test
public void testNormalHead() throws Exception {
MockHttpExchange ex = new MockHttpExchange("http", "HEAD", "/",
new MockHttpContext(handler, "/"));
handler.handle(ex);
assertEquals(200, ex.getResponseCode());
assertArrayEquals(new byte[] {}, ex.getResponseBytes());
}
@Test
public void testNormalPost() throws Exception {
MockHttpExchange ex = new MockHttpExchange("http", "POST", "/",
new MockHttpContext(handler, "/"));
handler.handle(ex);
assertEquals(405, ex.getResponseCode());
}
@Test
public void testNullAuthzResponse() throws Exception {
MockAdaptor adaptor = new MockAdaptor() {
@Override
public Map<DocId, AuthzStatus> isUserAuthorized(String userIdentifier,
Set<String> groups, Collection<DocId> ids) {
return null;
}
};
handler = createDefaultHandlerForAdaptor(adaptor);
handler.handle(ex);
assertEquals(403, ex.getResponseCode());
}
@Test
public void testFileNotFound() throws Exception {
MockAdaptor adaptor = new MockAdaptor() {
@Override
public void getDocContent(Request request, Response response)
throws IOException {
throw new FileNotFoundException();
}
};
handler = createDefaultHandlerForAdaptor(adaptor);
handler.handle(ex);
assertEquals(404, ex.getResponseCode());
}
@Test
public void testIOException() throws Exception {
MockAdaptor adaptor = new MockAdaptor() {
@Override
public void getDocContent(Request request, Response response)
throws IOException {
throw new IOException();
}
};
handler = createDefaultHandlerForAdaptor(adaptor);
handler.handle(ex);
assertEquals(500, ex.getResponseCode());
}
@Test
public void testRuntimeException() throws Exception {
MockAdaptor adaptor = new MockAdaptor() {
@Override
public void getDocContent(Request request, Response response)
throws IOException {
throw new RuntimeException();
}
};
handler = createDefaultHandlerForAdaptor(adaptor);
handler.handle(ex);
assertEquals(500, ex.getResponseCode());
}
@Test
public void testNoOutput() throws Exception {
MockAdaptor adaptor = new MockAdaptor() {
@Override
public void getDocContent(Request request, Response response)
throws IOException {
}
};
handler = createDefaultHandlerForAdaptor(adaptor);
handler.handle(ex);
assertEquals(500, ex.getResponseCode());
}
@Test
public void testNotModified() throws Exception {
MockAdaptor adaptor = new MockAdaptor() {
@Override
public void getDocContent(Request request, Response response)
throws IOException {
response.respondNotModified();
}
};
handler = createDefaultHandlerForAdaptor(adaptor);
handler.handle(ex);
assertEquals(304, ex.getResponseCode());
}
@Test
public void testNotModifiedThenOutputStream() throws Exception {
MockAdaptor adaptor = new MockAdaptor() {
@Override
public void getDocContent(Request request, Response response)
throws IOException {
response.respondNotModified();
response.getOutputStream();
}
};
handler = createDefaultHandlerForAdaptor(adaptor);
handler.handle(ex);
assertEquals(500, ex.getResponseCode());
}
@Test
public void testOutputStreamThenNotModified() throws Exception {
MockAdaptor adaptor = new MockAdaptor() {
@Override
public void getDocContent(Request request, Response response)
throws IOException {
response.getOutputStream();
response.respondNotModified();
}
};
handler = createDefaultHandlerForAdaptor(adaptor);
handler.handle(ex);
assertEquals(500, ex.getResponseCode());
}
@Test
public void testOutputStreamTwice() throws Exception {
MockAdaptor adaptor = new MockAdaptor() {
@Override
public void getDocContent(Request request, Response response)
throws IOException {
response.getOutputStream();
response.getOutputStream();
}
};
handler = createDefaultHandlerForAdaptor(adaptor);
handler.handle(ex);
assertEquals(200, ex.getResponseCode());
}
@Test
public void testSetContentTypeLate() throws Exception {
MockAdaptor adaptor = new MockAdaptor() {
@Override
public void getDocContent(Request request, Response response)
throws IOException {
response.getOutputStream();
response.setContentType("text/plain");
}
};
handler = createDefaultHandlerForAdaptor(adaptor);
handler.handle(ex);
assertEquals(500, ex.getResponseCode());
}
@Test
public void testSetMetadataLate() throws Exception {
MockAdaptor adaptor = new MockAdaptor() {
@Override
public void getDocContent(Request request, Response response)
throws IOException {
response.getOutputStream();
response.setMetadata(Metadata.EMPTY);
}
};
handler = createDefaultHandlerForAdaptor(adaptor);
handler.handle(ex);
assertEquals(500, ex.getResponseCode());
}
@Test
public void testSmartAdaptor() throws Exception {
MockAdaptor adaptor = new MockAdaptor() {
@Override
public void getDocContent(Request request, Response response)
throws IOException {
if (!request.getDocId().equals(new DocId("http://localhost/"))) {
throw new FileNotFoundException();
}
if (!request.hasChangedSinceLastAccess(new Date(1 * 1000))) {
response.respondNotModified();
return;
}
response.setContentType("text/plain");
response.setMetadata(Metadata.EMPTY);
response.getOutputStream();
// It is free to get it multiple times
response.getOutputStream();
}
};
handler = createDefaultHandlerForAdaptor(adaptor);
ex.getRequestHeaders().set("If-Modified-Since",
"Thu, 1 Jan 1970 00:00:01 GMT");
handler.handle(ex);
assertEquals(304, ex.getResponseCode());
ex = new MockHttpExchange("http", "GET", "/",
new MockHttpContext(handler, "/"));
ex.getRequestHeaders().set("If-Modified-Since",
"Thu, 1 Jan 1970 00:00:00 GMT");
handler.handle(ex);
assertEquals(200, ex.getResponseCode());
assertEquals("text/plain",
ex.getResponseHeaders().getFirst("Content-Type"));
ex = new MockHttpExchange("http", "HEAD", "/",
new MockHttpContext(handler, "/"));
handler.handle(ex);
assertEquals(200, ex.getResponseCode());
}
@Test
public void testMetadataNonGsa() throws Exception {
MockAdaptor adaptor = new MockAdaptor() {
@Override
public void getDocContent(Request request, Response response)
throws IOException {
response.setMetadata(new Metadata(Collections.singleton(
MetaItem.raw("test", "ing"))));
response.getOutputStream();
}
};
handler = new DocumentHandler("localhost", Charset.forName("UTF-8"),
new MockDocIdDecoder(), new Journal(new MockTimeProvider()),
adaptor, false, "localhost", new String[0], null, null);
handler.handle(ex);
assertEquals(200, ex.getResponseCode());
assertNull(ex.getResponseHeaders().getFirst("X-Gsa-External-Metadata"));
}
private DocumentHandler createDefaultHandlerForAdaptor(Adaptor adaptor) {
return new DocumentHandler("localhost", Charset.forName("UTF-8"),
new MockDocIdDecoder(), new Journal(new MockTimeProvider()),
adaptor, false, "localhost", new String[0], null, null);
}
@Test
public void testFormMetadataHeader() {
Set<MetaItem> items = new HashSet<MetaItem>();
items.add(MetaItem.isPublic());
items.add(MetaItem.raw("test", "ing"));
items.add(MetaItem.raw("another", "item"));
items.add(MetaItem.raw("equals=", "=="));
String result = DocumentHandler.formMetadataHeader(new Metadata(items));
assertEquals("another=item,equals%3D=%3D%3D,google%3Aispublic=true,"
+ "test=ing", result);
}
@Test
public void testFormMetadataHeaderEmpty() {
String header = DocumentHandler.formMetadataHeader(
new Metadata(new HashSet<MetaItem>()));
assertEquals("", header);
}
@Test
public void testPercentEncoding() {
String encoded = DocumentHandler.percentEncode(
"AaZz-_.~`=/?+';\\/\"!@#$%^&*()[]{}ë\u0001");
assertEquals("AaZz-_.~%60%3D%2F%3F%2B%27%3B%5C%2F%22%21%40%23%24%25%5E%26"
+ "%2A%28%29%5B%5D%7B%7D%C3%AB%01", encoded);
}
private static class MockAdaptor extends AbstractAdaptor {
@Override
public void getDocIds(DocIdPusher pusher) {
throw new UnsupportedOperationException();
}
@Override
public void getDocContent(Request request, Response response)
throws IOException {
response.getOutputStream().write(new byte[] {1, 2, 3});
}
}
private static class PrivateMockAdaptor extends MockAdaptor {
@Override
public Map<DocId, AuthzStatus> isUserAuthorized(String userIdentifier,
Set<String> groups,
Collection<DocId> ids) {
Map<DocId, AuthzStatus> result
= new HashMap<DocId, AuthzStatus>(ids.size() * 2);
for (DocId id : ids) {
result.put(id, AuthzStatus.DENY);
}
return Collections.unmodifiableMap(result);
}
}
private static class MockDocIdDecoder implements DocIdDecoder {
public DocId decodeDocId(URI uri) {
return new DocId(uri.toString());
}
}
}