/*
* Copyright (C) 2015 SoftIndex LLC.
*
* 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 io.datakernel.http;
import io.datakernel.async.ResultCallback;
import io.datakernel.bytebuf.ByteBuf;
import io.datakernel.bytebuf.ByteBufStrings;
import io.datakernel.exception.ParseException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import static io.datakernel.bytebuf.ByteBufPool.*;
import static io.datakernel.http.HttpMethod.*;
import static org.junit.Assert.assertEquals;
public class MiddlewareServletTest {
private static final String TEMPLATE = "http://www.site.org";
private static final String DELIM = "*****************************************************************************";
@Rule
public ExpectedException expectedException = ExpectedException.none();
private static ResultCallback<HttpResponse> callback(final String expectedBody, final int expectedCode) {
return new ResultCallback<HttpResponse>() {
@Override
public void onResult(HttpResponse result) {
assertEquals(expectedBody, result.getBody() == null ? "" : result.getBody().toString());
assertEquals(expectedCode, result.getCode());
System.out.println(result + " " + result.getBody());
result.recycleBufs();
}
@Override
protected void onException(Exception e) {
assertEquals(expectedCode, ((HttpException) e).getCode());
}
};
}
@Test
public void testBase() {
MiddlewareServlet servlet1 = MiddlewareServlet.create();
servlet1.with(HttpMethod.GET, "/a/b/c", new AsyncServlet() {
@Override
public void serve(HttpRequest request, ResultCallback<HttpResponse> callback) {
callback.setResult(HttpResponse.ofCode(200));
}
});
servlet1.serve(HttpRequest.get("http://some-test.com/a/b/c"), callback("", 200));
servlet1.serve(HttpRequest.get("http://some-test.com/a/b/c/d"), callback("", 404));
servlet1.serve(HttpRequest.post("http://some-test.com/a/b/c"), callback("", 405));
MiddlewareServlet servlet2 = MiddlewareServlet.create();
servlet2.with(HttpMethod.HEAD, "/a/b/c", new AsyncServlet() {
@Override
public void serve(HttpRequest request, ResultCallback<HttpResponse> callback) {
callback.setResult(HttpResponse.ofCode(200));
}
});
servlet2.serve(HttpRequest.post("http://some-test.com/a/b/c"), callback("", 405));
servlet2.serve(HttpRequest.post("http://some-test.com/a/b/c/d"), callback("", 404));
servlet2.serve(HttpRequest.of(HttpMethod.HEAD, "http://some-test.com/a/b/c"), callback("", 200));
}
@Test
public void testProcessWildCardRequest() {
MiddlewareServlet servlet = MiddlewareServlet.create();
servlet.with("/a/b/c/d", new AsyncServlet() {
@Override
public void serve(HttpRequest request, ResultCallback<HttpResponse> callback) {
callback.setResult(HttpResponse.ofCode(200));
}
});
servlet.serve(HttpRequest.get("http://some-test.com/a/b/c/d"), callback("", 200));
servlet.serve(HttpRequest.post("http://some-test.com/a/b/c/d"), callback("", 200));
servlet.serve(HttpRequest.of(HttpMethod.OPTIONS, "http://some-test.com/a/b/c/d"), callback("", 200));
}
@Test
public void testMicroMapping() throws ParseException {
HttpRequest request1 = HttpRequest.get(TEMPLATE + "/"); // ok
HttpRequest request2 = HttpRequest.get(TEMPLATE + "/a"); // ok
HttpRequest request3 = HttpRequest.get(TEMPLATE + "/a/c"); // ok
HttpRequest request4 = HttpRequest.get(TEMPLATE + "/a/d"); // ok
HttpRequest request5 = HttpRequest.get(TEMPLATE + "/a/e"); // 404
HttpRequest request6 = HttpRequest.get(TEMPLATE + "/b"); // 404
HttpRequest request7 = HttpRequest.get(TEMPLATE + "/b/f"); // ok
HttpRequest request8 = HttpRequest.get(TEMPLATE + "/b/g"); // ok
AsyncServlet action = new AsyncServlet() {
@Override
public void serve(HttpRequest request, ResultCallback<HttpResponse> callback) {
ByteBuf msg = ByteBufStrings.wrapUtf8("Executed: " + request.getPath());
callback.setResult(HttpResponse.ofCode(200).withBody(msg));
}
};
MiddlewareServlet a = MiddlewareServlet.create()
.with(GET, "/c", action)
.with(GET, "/d", action)
.with(GET, "/", action);
MiddlewareServlet b = MiddlewareServlet.create()
.with(GET, "/f", action)
.with(GET, "/g", action);
MiddlewareServlet main = MiddlewareServlet.create()
.with(GET, "/", action)
.with(GET, "/a", a)
.with(GET, "/b", b);
System.out.println("Micro mapping" + DELIM);
main.serve(request1, callback("Executed: /", 200));
main.serve(request2, callback("Executed: /a", 200));
main.serve(request3, callback("Executed: /a/c", 200));
main.serve(request4, callback("Executed: /a/d", 200));
main.serve(request5, callback("", 404));
main.serve(request6, callback("", 404));
main.serve(request7, callback("Executed: /b/f", 200));
main.serve(request8, callback("Executed: /b/g", 200));
System.out.println();
assertEquals(getPoolItemsString(), getCreatedItems(), getPoolItems());
}
@Test
public void testLongMapping() throws ParseException {
HttpRequest request1 = HttpRequest.get(TEMPLATE + "/"); // ok
HttpRequest request2 = HttpRequest.get(TEMPLATE + "/a"); // ok
HttpRequest request3 = HttpRequest.get(TEMPLATE + "/a/c"); // ok
HttpRequest request4 = HttpRequest.get(TEMPLATE + "/a/d"); // ok
HttpRequest request5 = HttpRequest.get(TEMPLATE + "/a/e"); // 404
HttpRequest request6 = HttpRequest.get(TEMPLATE + "/b"); // 404
HttpRequest request7 = HttpRequest.get(TEMPLATE + "/b/f"); // ok
HttpRequest request8 = HttpRequest.get(TEMPLATE + "/b/g"); // ok
AsyncServlet action = new AsyncServlet() {
@Override
public void serve(HttpRequest request, ResultCallback<HttpResponse> callback) {
ByteBuf msg = ByteBufStrings.wrapUtf8("Executed: " + request.getPath());
callback.setResult(HttpResponse.ofCode(200).withBody(msg));
}
};
MiddlewareServlet main = MiddlewareServlet.create()
.with(GET, "/", action)
.with(GET, "/a", action)
.with(GET, "/a/c", action)
.with(GET, "/a/d", action)
.with(GET, "/b/f", action)
.with(GET, "/b/g", action);
System.out.println("Long mapping " + DELIM);
main.serve(request1, callback("Executed: /", 200));
main.serve(request2, callback("Executed: /a", 200));
main.serve(request3, callback("Executed: /a/c", 200));
main.serve(request4, callback("Executed: /a/d", 200));
main.serve(request5, callback("", 404));
main.serve(request6, callback("", 404));
main.serve(request7, callback("Executed: /b/f", 200));
main.serve(request8, callback("Executed: /b/g", 200));
System.out.println();
assertEquals(getPoolItemsString(), getCreatedItems(), getPoolItems());
}
@Test
public void testOverrideHandler() {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Can't map. Servlet already exists");
MiddlewareServlet s1 = MiddlewareServlet.create()
.with(GET, "/", new AsyncServlet() {
@Override
public void serve(HttpRequest request, ResultCallback<HttpResponse> callback) {
}
})
.with(GET, "/", new AsyncServlet() {
@Override
public void serve(HttpRequest request, ResultCallback<HttpResponse> callback) {
}
});
assertEquals(getPoolItemsString(), getCreatedItems(), getPoolItems());
}
@Test
public void testMerge() throws ParseException {
HttpRequest request1 = HttpRequest.get(TEMPLATE + "/"); // ok
HttpRequest request2 = HttpRequest.get(TEMPLATE + "/a"); // ok
HttpRequest request3 = HttpRequest.get(TEMPLATE + "/b"); // ok
HttpRequest request4 = HttpRequest.get(TEMPLATE + "/a/c"); // ok
HttpRequest request5 = HttpRequest.get(TEMPLATE + "/a/d"); // ok
HttpRequest request6 = HttpRequest.get(TEMPLATE + "/a/e"); // ok
HttpRequest request7 = HttpRequest.get(TEMPLATE + "/a/c/f"); // ok
AsyncServlet action = new AsyncServlet() {
@Override
public void serve(HttpRequest request, ResultCallback<HttpResponse> callback) {
ByteBuf msg = ByteBufStrings.wrapUtf8("Executed: " + request.getPath());
callback.setResult(HttpResponse.ofCode(200).withBody(msg));
}
};
MiddlewareServlet main = MiddlewareServlet.create()
.with(GET, "/a", action)
.with(GET, "/a/c", action)
.with(GET, "/a/d", action)
.with(GET, "/b", action)
.with(GET, "/", MiddlewareServlet.create()
.with(GET, "/", action)
.with(GET, "/a/e", action)
.with(GET, "/a/c/f", action));
System.out.println("Merge " + DELIM);
main.serve(request1, callback("Executed: /", 200));
main.serve(request2, callback("Executed: /a", 200));
main.serve(request3, callback("Executed: /b", 200));
main.serve(request4, callback("Executed: /a/c", 200));
main.serve(request5, callback("Executed: /a/d", 200));
main.serve(request6, callback("Executed: /a/e", 200));
main.serve(request7, callback("Executed: /a/c/f", 200));
System.out.println();
assertEquals(getPoolItemsString(), getCreatedItems(), getPoolItems());
}
@Test
public void testFailMerge() throws ParseException {
HttpRequest request = HttpRequest.get(TEMPLATE + "/a/c/f"); // fail
AsyncServlet action = new AsyncServlet() {
@Override
public void serve(HttpRequest request, ResultCallback<HttpResponse> callback) {
ByteBuf msg = ByteBufStrings.wrapUtf8("Executed: " + request.getPath());
callback.setResult(HttpResponse.ofCode(200).withBody(msg));
}
};
AsyncServlet anotherAction = new AsyncServlet() {
@Override
public void serve(HttpRequest request, ResultCallback<HttpResponse> callback) {
ByteBuf msg = ByteBufStrings.wrapUtf8("Shall not be executed: " + request.getPath());
callback.setResult(HttpResponse.ofCode(200).withBody(msg));
}
};
// /a/c/f already mapped
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Can't map. Servlet for this method already exists");
MiddlewareServlet main = MiddlewareServlet.create()
.with(GET, "/", action)
.with(GET, "/a/e", action)
.with(GET, "/a/c/f", action)
.with(GET, "/", MiddlewareServlet.create()
.with(GET, "/a/c/f", anotherAction));
main.serve(request, callback("SHALL NOT BE EXECUTED", 500));
assertEquals(getPoolItemsString(), getCreatedItems(), getPoolItems());
}
@Test
public void testParameter() throws ParseException {
AsyncServlet printParameters = new AsyncServlet() {
@Override
public void serve(HttpRequest request, ResultCallback<HttpResponse> callback) {
String body = request.getUrlParameter("id")
+ " " + request.getUrlParameter("uid")
+ " " + request.getUrlParameter("eid");
ByteBuf bodyByteBuf = ByteBufStrings.wrapUtf8(body);
callback.setResult(HttpResponse.ofCode(200).withBody(bodyByteBuf));
request.recycleBufs();
}
};
MiddlewareServlet main = MiddlewareServlet.create()
.with(GET, "/:id/a/:uid/b/:eid", printParameters)
.with(GET, "/:id/a/:uid", printParameters);
System.out.println("Parameter test " + DELIM);
main.serve(HttpRequest.get("http://www.coursera.org/123/a/456/b/789"), callback("123 456 789", 200));
main.serve(HttpRequest.get("http://www.coursera.org/555/a/777"), callback("555 777 null", 200));
main.serve(HttpRequest.get("http://www.coursera.org"), callback("", 404));
System.out.println();
assertEquals(getPoolItemsString(), getCreatedItems(), getPoolItems());
}
@Test
public void testMultiParameters() throws ParseException {
AsyncServlet serveCar = new AsyncServlet() {
@Override
public void serve(HttpRequest request, ResultCallback<HttpResponse> callback) {
ByteBuf body = ByteBufStrings.wrapUtf8("served car: " + request.getUrlParameter("cid"));
callback.setResult(HttpResponse.ofCode(200).withBody(body));
}
};
AsyncServlet serveMan = new AsyncServlet() {
@Override
public void serve(HttpRequest request, ResultCallback<HttpResponse> callback) {
ByteBuf body = ByteBufStrings.wrapUtf8("served man: " + request.getUrlParameter("mid"));
callback.setResult(HttpResponse.ofCode(200).withBody(body));
}
};
MiddlewareServlet ms = MiddlewareServlet.create()
.with(GET, "/serve/:cid/wash", serveCar)
.with(GET, "/serve/:mid/feed", serveMan);
System.out.println("Multi parameters " + DELIM);
ms.serve(HttpRequest.get(TEMPLATE + "/serve/1/wash"), callback("served car: 1", 200));
ms.serve(HttpRequest.get(TEMPLATE + "/serve/2/feed"), callback("served man: 2", 200));
System.out.println();
assertEquals(getPoolItemsString(), getCreatedItems(), getPoolItems());
}
@Test
public void testDifferentMethods() throws ParseException {
HttpRequest request1 = HttpRequest.get(TEMPLATE + "/a/b/c/action");
HttpRequest request2 = HttpRequest.post(TEMPLATE + "/a/b/c/action");
HttpRequest request3 = HttpRequest.of(CONNECT, TEMPLATE + "/a/b/c/action");
AsyncServlet post = new AsyncServlet() {
@Override
public void serve(HttpRequest request, ResultCallback<HttpResponse> callback) {
callback.setResult(HttpResponse.ofCode(200).withBody(ByteBufStrings.wrapUtf8("POST")));
}
};
AsyncServlet get = new AsyncServlet() {
@Override
public void serve(HttpRequest request, ResultCallback<HttpResponse> callback) {
callback.setResult(HttpResponse.ofCode(200).withBody(ByteBufStrings.wrapUtf8("GET")));
}
};
AsyncServlet wildcard = new AsyncServlet() {
@Override
public void serve(HttpRequest request, ResultCallback<HttpResponse> callback) {
callback.setResult(HttpResponse.ofCode(200).withBody(ByteBufStrings.wrapUtf8("WILDCARD")));
}
};
MiddlewareServlet servlet = MiddlewareServlet.create()
.with("/a/b/c/action", wildcard)
.with(POST, "/a/b/c/action", post)
.with(GET, "/a/b/c/action", get);
System.out.println("Different methods " + DELIM);
servlet.serve(request1, callback("GET", 200));
servlet.serve(request2, callback("POST", 200));
servlet.serve(request3, callback("WILDCARD", 200));
System.out.println();
assertEquals(getPoolItemsString(), getCreatedItems(), getPoolItems());
}
@Test
public void testDefault() throws ParseException {
AsyncServlet def = new AsyncServlet() {
@Override
public void serve(HttpRequest request, ResultCallback<HttpResponse> callback) {
callback.setResult(HttpResponse.ofCode(200).withBody(ByteBufStrings.wrapUtf8("Stopped at admin: " + request.getRelativePath())));
}
};
AsyncServlet action = new AsyncServlet() {
@Override
public void serve(HttpRequest request, ResultCallback<HttpResponse> callback) {
callback.setResult(HttpResponse.ofCode(200).withBody(ByteBufStrings.wrapUtf8("Action executed")));
}
};
HttpRequest request1 = HttpRequest.get(TEMPLATE + "/html/admin/action");
HttpRequest request2 = HttpRequest.get(TEMPLATE + "/html/admin/action/ban");
MiddlewareServlet main = MiddlewareServlet.create()
.with(GET, "/html/admin/action", action)
.withFallback("/html/admin", def);
System.out.println("Default stop " + DELIM);
main.serve(request1, callback("Action executed", 200));
main.serve(request2, callback("Stopped at admin: /action/ban", 200));
System.out.println();
assertEquals(getPoolItemsString(), getCreatedItems(), getPoolItems());
}
@Test
public void test404() throws ParseException {
AsyncServlet servlet = new AsyncServlet() {
@Override
public void serve(HttpRequest request, ResultCallback<HttpResponse> callback) {
callback.setResult(HttpResponse.ofCode(200).withBody(ByteBufStrings.wrapUtf8("All OK")));
}
};
MiddlewareServlet main = MiddlewareServlet.create()
.with("/a/:id/b/d", servlet);
System.out.println("404 " + DELIM);
main.serve(HttpRequest.get(TEMPLATE + "/a/123/b/c"), callback("", 404));
System.out.println();
assertEquals(getPoolItemsString(), getCreatedItems(), getPoolItems());
}
@Test
public void test405() throws ParseException {
AsyncServlet servlet = new AsyncServlet() {
@Override
public void serve(HttpRequest request, ResultCallback<HttpResponse> callback) {
callback.setResult(HttpResponse.ofCode(200).withBody(ByteBufStrings.wrapUtf8("Should not execute")));
}
};
MiddlewareServlet main = MiddlewareServlet.create()
.with(GET, "/a/:id/b/d", servlet);
main.serve(HttpRequest.post(TEMPLATE + "/a/123/b/d"), callback("", 405));
assertEquals(getPoolItemsString(), getCreatedItems(), getPoolItems());
}
@Test
public void test405WithFallback() {
AsyncServlet servlet = new AsyncServlet() {
@Override
public void serve(HttpRequest request, ResultCallback<HttpResponse> callback) {
callback.setResult(HttpResponse.ofCode(200).withBody(ByteBufStrings.wrapUtf8("Should not execute")));
}
};
AsyncServlet fallback = new AsyncServlet() {
@Override
public void serve(HttpRequest request, ResultCallback<HttpResponse> callback) {
callback.setResult(HttpResponse.ofCode(200).withBody(ByteBufStrings.wrapUtf8("Fallback executed")));
}
};
MiddlewareServlet main = MiddlewareServlet.create()
.with(GET, "/a/:id/b/d", servlet)
.withFallback("/a/:id/b/d", fallback);
main.serve(HttpRequest.post(TEMPLATE + "/a/123/b/d"), callback("Fallback executed", 200));
assertEquals(getPoolItemsString(), getCreatedItems(), getPoolItems());
}
}