/**
* Copyright 2010-2016 Ralph Schaer <ralphschaer@gmail.com>
*
* 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 ch.ralscha.extdirectspring_itest;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.databene.contiperf.PerfTest;
import org.databene.contiperf.junit.ContiPerfRule;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.junit.Rule;
import org.junit.Test;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import ch.ralscha.extdirectspring.bean.api.Action;
import ch.ralscha.extdirectspring.bean.api.PollingProvider;
import ch.ralscha.extdirectspring.bean.api.RemotingApi;
import ch.ralscha.extdirectspring.controller.ApiControllerTest;
import ch.ralscha.extdirectspring.controller.ApiRequestParams;
public class SimpleServiceTest extends JettyTest2 {
@Rule
public ContiPerfRule i = new ContiPerfRule();
private final static AtomicInteger id = new AtomicInteger();
private final static ObjectMapper mapper = new ObjectMapper();
private static RemotingApi api() {
RemotingApi remotingApi = new RemotingApi("remoting", "/controller/router", null);
remotingApi.addAction("simpleService", Action.create("toUpperCase", 1));
remotingApi.addAction("simpleService", Action.createNamed("echo",
Arrays.asList("userId", "logLevel"), null, null));
PollingProvider pollingProvider = new PollingProvider("simpleService", "poll",
"poll");
remotingApi.addPollingProvider(pollingProvider);
return remotingApi;
}
@Test
@PerfTest(invocations = 150, threads = 5)
public void testSimpleApiDebug() throws IllegalStateException, IOException {
CloseableHttpClient client = HttpClientBuilder.create().build();
try {
HttpGet get = new HttpGet(
"http://localhost:9998/controller/api-debug.js?group=itest_simple");
handleApi(client, get, false);
}
finally {
IOUtils.closeQuietly(client);
}
}
@Test
@PerfTest(invocations = 150, threads = 5)
public void testSimpleApi() throws IllegalStateException, IOException {
CloseableHttpClient client = HttpClientBuilder.create().build();
try {
HttpGet get = new HttpGet(
"http://localhost:9998/controller/api.js?group=itest_simple");
handleApi(client, get, false);
}
finally {
IOUtils.closeQuietly(client);
}
}
@Test
@PerfTest(invocations = 150, threads = 5)
public void testSimpleApiFingerprinted() throws IllegalStateException, IOException {
CloseableHttpClient client = HttpClientBuilder.create().build();
try {
HttpGet get = new HttpGet(
"http://localhost:9998/controller/api-1.0.0.js?group=itest_simple");
handleApi(client, get, true);
}
finally {
IOUtils.closeQuietly(client);
}
}
private static void handleApi(HttpClient client, HttpGet get, boolean fingerprinted)
throws IOException, JsonParseException, JsonMappingException {
HttpResponse response = client.execute(get);
HttpEntity entity = response.getEntity();
assertThat(entity).isNotNull();
String responseString = EntityUtils.toString(entity);
String contentType = response.getFirstHeader("Content-Type").getValue();
ApiControllerTest.compare(responseString, contentType, api(),
ApiRequestParams.builder().build());
assertCacheHeaders(response, fingerprinted);
}
public static void assertCacheHeaders(HttpResponse response, boolean fingerprinted) {
if (fingerprinted) {
assertThat(response.getFirstHeader("Content-Type").getValue())
.isEqualTo("application/javascript;charset=UTF-8");
assertThat(response.getFirstHeader("Content-Length")).isNotNull();
String expiresString = response.getFirstHeader("Expires").getValue();
DateTimeFormatter fmt = DateTimeFormat
.forPattern("E, dd MMM yyyy HH:mm:ss ZZZ").withLocale(Locale.ENGLISH);
DateTime expires = DateTime.parse(expiresString, fmt);
DateTime inSixMonths = DateTime.now(DateTimeZone.UTC)
.plusSeconds(6 * 30 * 24 * 60 * 60);
assertThat(expires.getYear()).isEqualTo(inSixMonths.getYear());
assertThat(expires.getMonthOfYear()).isEqualTo(inSixMonths.getMonthOfYear());
assertThat(expires.getDayOfMonth()).isEqualTo(inSixMonths.getDayOfMonth());
assertThat(expires.getHourOfDay()).isEqualTo(inSixMonths.getHourOfDay());
assertThat(expires.getMinuteOfDay()).isEqualTo(inSixMonths.getMinuteOfDay());
assertThat(response.getFirstHeader("ETag").getValue()).isNotNull();
assertThat(response.getFirstHeader("Cache-Control").getValue())
.isEqualTo("public, max-age=15552000");
}
else {
assertThat(response.getFirstHeader("Content-Type").getValue())
.isEqualTo("application/javascript;charset=UTF-8");
assertThat(response.getFirstHeader("Content-Length")).isNotNull();
assertThat(response.getFirstHeader("Expires")).isNull();
assertThat(response.getFirstHeader("ETag")).isNull();
assertThat(response.getFirstHeader("Cache-Control")).isNull();
}
}
@Test
@PerfTest(invocations = 150, threads = 5)
public void testSimpleCall() throws IllegalStateException, IOException {
CloseableHttpClient client = HttpClientBuilder.create().build();
try {
postToUpperCase("ralph", client);
postToUpperCase("renee", client);
postToUpperCase("andrea", client);
}
finally {
IOUtils.closeQuietly(client);
}
}
@Test
@PerfTest(invocations = 150, threads = 5)
public void testPoll() throws IOException {
String _id = String.valueOf(id.incrementAndGet());
CloseableHttpClient client = HttpClientBuilder.create().build();
CloseableHttpResponse response = null;
try {
HttpGet get = new HttpGet(
"http://localhost:9998/controller/poll/simpleService/poll/poll?id="
+ _id);
response = client.execute(get);
assertThat(response.getFirstHeader("Content-Type").getValue())
.isEqualTo("application/json;charset=UTF-8");
String responseString = EntityUtils.toString(response.getEntity());
Map<String, Object> rootAsMap = mapper.readValue(responseString, Map.class);
assertThat(rootAsMap).hasSize(3);
assertThat(rootAsMap.get("type")).isEqualTo("event");
assertThat(rootAsMap.get("name")).isEqualTo("poll");
assertThat(rootAsMap.get("data")).isEqualTo(_id);
}
finally {
IOUtils.closeQuietly(response);
IOUtils.closeQuietly(client);
}
}
private static void postToUpperCase(String text, HttpClient client)
throws IOException, JsonParseException, JsonMappingException {
HttpPost post = new HttpPost("http://localhost:9998/controller/router");
StringEntity postEntity = new StringEntity(
"{\"action\":\"simpleService\",\"method\":\"toUpperCase\",\"data\":[\""
+ text + "\"],\"type\":\"rpc\",\"tid\":1}",
"UTF-8");
post.setEntity(postEntity);
post.setHeader("Content-Type", "application/json; charset=UTF-8");
HttpResponse response = client.execute(post);
HttpEntity entity = response.getEntity();
assertThat(entity).isNotNull();
String responseString = EntityUtils.toString(entity);
assertThat(response.getFirstHeader("Content-Length").getValue())
.isEqualTo("" + responseString.length());
assertThat(responseString).isNotNull();
assertThat(responseString).startsWith("[").endsWith("]");
Map<String, Object> rootAsMap = mapper.readValue(
responseString.substring(1, responseString.length() - 1), Map.class);
assertThat(rootAsMap).hasSize(5);
assertThat(rootAsMap.get("result")).isEqualTo(text.toUpperCase());
assertThat(rootAsMap.get("method")).isEqualTo("toUpperCase");
assertThat(rootAsMap.get("type")).isEqualTo("rpc");
assertThat(rootAsMap.get("action")).isEqualTo("simpleService");
assertThat(rootAsMap.get("tid")).isEqualTo(1);
}
@Test
@PerfTest(invocations = 150, threads = 5)
public void testSimpleNamedCall() throws IllegalStateException, IOException {
CloseableHttpClient client = HttpClientBuilder.create().build();
try {
postToEcho(
Collections.singletonList("\"userId\":\"ralph\", \"logLevel\": 100"),
Collections.singletonList("UserId: ralph LogLevel: 100"), client);
postToEcho(Collections.singletonList("\"userId\":\"tom\""),
Collections.singletonList("UserId: tom LogLevel: 10"), client);
postToEcho(Collections.singletonList("\"userId\":\"renee\", \"logLevel\": 1"),
Collections.singletonList("UserId: renee LogLevel: 1"), client);
postToEcho(Collections.singletonList("\"userId\":\"andrea\""),
Collections.singletonList("UserId: andrea LogLevel: 10"), client);
}
finally {
IOUtils.closeQuietly(client);
}
}
@Test
@PerfTest(invocations = 150, threads = 5)
public void testSimpleNamedCallBatched() throws IllegalStateException, IOException {
CloseableHttpClient client = HttpClientBuilder.create().build();
try {
postToEcho(
Arrays.asList("\"userId\":\"Ralph\", \"logLevel\": 100",
"\"userId\":\"Tom\"", "\"userId\":\"Renee\", \"logLevel\": 1",
"\"userId\":\"Andrea\""),
Arrays.asList("UserId: Ralph LogLevel: 100",
"UserId: Tom LogLevel: 10", "UserId: Renee LogLevel: 1",
"UserId: Andrea LogLevel: 10"),
client);
}
finally {
IOUtils.closeQuietly(client);
}
}
private static void postToEcho(List<String> datas, List<String> expectedResult,
HttpClient client)
throws IOException, JsonParseException, JsonMappingException {
HttpPost post = new HttpPost("http://localhost:9998/controller/router");
StringBuilder postData = new StringBuilder();
if (datas.size() > 1) {
postData.append("[");
}
for (int i = 0; i < datas.size(); i++) {
postData.append(
"{\"action\":\"simpleService\",\"method\":\"echo\",\"data\":{");
postData.append(datas.get(i));
postData.append("},\"type\":\"rpc\",\"tid\":");
postData.append(i + 1);
postData.append("}");
if (i < datas.size() - 1) {
postData.append(",");
}
}
if (datas.size() > 1) {
postData.append("]");
}
StringEntity postEntity = new StringEntity(postData.toString(), "UTF-8");
post.setEntity(postEntity);
post.setHeader("Content-Type", "application/json; charset=UTF-8");
HttpResponse response = client.execute(post);
HttpEntity entity = response.getEntity();
assertThat(entity).isNotNull();
String responseString = EntityUtils.toString(entity);
assertThat(response.getFirstHeader("Content-Length")).isNull();
assertThat(responseString).isNotNull();
assertThat(responseString).startsWith("[").endsWith("]");
List<Map<String, Object>> results = mapper.readValue(responseString, List.class);
assertThat(results).hasSize(expectedResult.size());
int tid = 1;
for (Map<String, Object> map : results) {
assertThat(map).hasSize(5);
assertThat(map.get("result")).isEqualTo(expectedResult.get(tid - 1));
assertThat(map.get("method")).isEqualTo("echo");
assertThat(map.get("type")).isEqualTo("rpc");
assertThat(map.get("action")).isEqualTo("simpleService");
assertThat(map.get("tid")).isEqualTo(tid++);
}
}
}