package testapp.endpoint;
import com.alibaba.fastjson.JSON;
import okhttp3.*;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.osgl.$;
import org.osgl.http.H;
import org.osgl.mvc.result.*;
import org.osgl.storage.ISObject;
import org.osgl.util.C;
import org.osgl.util.Codec;
import org.osgl.util.E;
import org.osgl.util.S;
import testapp.TestBase;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
public class EndpointTester extends TestBase {
public static final String END_POINT = "http://localhost:6111";
private OkHttpClient http;
private Request.Builder req;
private Response resp;
protected ReqBuilder reqBuilder;
private static Process process;
@BeforeClass
public static void bootup() throws Exception {
if (ping()) {
return;
}
process = new ProcessBuilder(
"mvn","exec:exec").start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
if (line.contains("to start the app")) {
break;
}
}
}
@AfterClass
public static void shutdown() throws Exception {
if (null != process) {
shutdownApp();
process.destroy();
}
}
@Before
public void setup() throws IOException {
reset();
_setup();
}
protected final void reset() {
http = new OkHttpClient.Builder()
.connectTimeout(60 * 10, TimeUnit.SECONDS)
.readTimeout(60 * 10, TimeUnit.SECONDS)
.writeTimeout(60 * 10, TimeUnit.SECONDS).build();
req = null;
resp = null;
reqBuilder = null;
}
protected void _setup() throws IOException {}
private void execute() throws IOException {
resp = http.newCall(req().build()).execute();
}
protected Request.Builder req() {
if (null == req) {
E.illegalStateIf(null == reqBuilder, "Please make sure url(String, Object...) method called first");
req = reqBuilder.build();
}
return req;
}
protected Response resp() throws IOException {
if (null == resp) {
execute();
}
return resp;
}
protected List<Cookie> cookies() throws IOException {
return Cookie.parseAll(HttpUrl.parse("http://localhost:6111"), resp().headers());
}
protected void verify(EndPointTestContext context) throws Exception {
context.applyTo(this);
}
protected void verifyAllMethods(String expected, String url, String key, Object val, Object ... otherPairs) throws Exception {
verifyGet(expected, url, key, val, otherPairs);
verifyPostFormData(expected, url, key, val, otherPairs);
verifyPostJsonBody(expected, url, key, val, otherPairs);
}
protected void verifyGet(String expected, String url, String key, Object val, Object ... otherPairs) throws Exception {
setup();
url(url).get(key, val, otherPairs);
bodyEq(expected);
}
protected void verifyPostFormData(String expected, String url, String key, Object val, Object ... otherPairs) throws Exception {
setup();
url(url).post(key, val, otherPairs);
bodyEq(expected);
}
protected void verifyPostJsonBody(String expected, String url, String key, Object val, Object ... otherPairs) throws Exception {
setup();
Map<String, Object> params = prepareJsonData(key, val, otherPairs);
url(url).postJSON(params);
bodyEq(expected);
}
protected ReqBuilder url(String pathTmpl, Object ... args) {
reqBuilder = new ReqBuilder(pathTmpl, args);
return reqBuilder;
}
protected void assertNoHeader(String header) throws IOException {
assertNull(resp().header(header));
}
protected void checkHeader(String header, String expected) throws IOException {
checkHeaderStr(expected, resp().header(header));
}
private void checkHeaderStr(String s1, String s0) {
eq(C.setOf(S.string(s1).split("[,\\s+]")), C.setOf(S.string(s0).split("[,\\s+]")));
}
protected void bodyContains(String s) throws IOException {
yes(resp().body().string().contains(s));
}
protected void bodyEq(String s) throws IOException {
final Response resp = resp();
checkResponseCode(resp);
eq(s, S.string(resp.body().string()));
}
protected void bodyEq(String s1, String s2, String s3) throws IOException {
final Response resp = resp();
checkResponseCode(resp);
String found = resp.body().string();
if (S.neq(s3, found)) {
if (S.neq(s2, found)) {
eq(s1, found);
}
}
}
protected void bodyEqIgnoreSpace(String s) throws IOException {
final Response resp = resp();
eq(200, resp.code());
eq(s.trim(), S.string(resp.body().string()).trim());
}
protected void bodyEq(Object obj) throws IOException {
bodyEq(JSON.toJSONString(obj));
}
protected void bodyEqIgnoreSpace(Object obj) throws IOException {
bodyEqIgnoreSpace(JSON.toJSONString(obj));
}
protected void checkRespCode() throws IOException {
checkResponseCode(resp());
}
protected Map<String, Object> prepareJsonData(String key, Object val, Object ... otherPairs) {
Map<String, Object> params = C.newMap(key, val);
Map<String, Object> otherParams = C.map(otherPairs);
params.putAll(otherParams);
return params;
}
protected Map<String, Object> prepareJsonData(List<$.T2<String, Object>> params) {
Map<String, Object> map = C.newMap();
if (null != params) {
for ($.T2<String, Object> pair : params) {
String key = pair._1;
Object val = pair._2;
if (map.containsKey(key)) {
List list;
Object x = map.get(key);
if (x instanceof List) {
list = $.cast(x);
} else {
list = C.newList(x);
map.put(key, list);
}
list.add(val);
} else {
map.put(key, val);
}
}
}
return map;
}
private static void shutdownApp() throws Exception {
try {
OkHttpClient http = new OkHttpClient();
Request req = new ReqBuilder("/shutdown").build().build();
Response resp = http.newCall(req).execute();
System.out.println(resp.code());
} catch (Exception e) {
// ignore
}
}
private static boolean ping() {
if (true) {
return true;
}
try {
OkHttpClient http = new OkHttpClient();
Request req = new ReqBuilder("/ping").build().build();
Response resp = http.newCall(req).execute();
return resp.code() == 200;
} catch (Exception e) {
return false;
}
}
private static String fullUrl(String pathTmpl, Object ... args) {
String tmpl0 = pathTmpl.startsWith("/") ? pathTmpl : "/" + pathTmpl;
return S.fmt(END_POINT + tmpl0, args);
}
private void checkResponseCode(Response resp) {
if (resp.code() < 300 && resp.code() > 199) {
return;
}
switch (resp.code()) {
case HttpURLConnection.HTTP_NOT_FOUND:
throw NotFound.INSTANCE;
case HttpURLConnection.HTTP_BAD_REQUEST:
throw BadRequest.INSTANCE;
case HttpURLConnection.HTTP_FORBIDDEN:
throw Forbidden.INSTANCE;
case HttpURLConnection.HTTP_UNAUTHORIZED:
throw Unauthorized.INSTANCE;
case HttpURLConnection.HTTP_NOT_MODIFIED:
throw NotModified.INSTANCE;
case HttpURLConnection.HTTP_CONFLICT:
throw Conflict.INSTANCE;
default:
H.Status status = H.Status.of(resp.code());
if (status.isError()) {
throw new ErrorResult(status);
}
}
}
protected static class ReqBuilder {
StringBuilder sb;
boolean paramAttached;
private H.Method method = H.Method.GET;
private H.Format format;
private H.Format accept;
private RequestBody body;
private String postStr;
private String session;
private String csrf;
private byte[] postBytes;
private ISObject postAttachment;
private List<Cookie> cookies = C.newList();
private Map<String, String> headers = C.newMap();
private List<$.T2<String, Object>> postParams = C.newList();
public ReqBuilder(String pathTmpl, Object ... args) {
String s = fullUrl(pathTmpl, args);
sb = S.builder(s);
paramAttached = s.contains("?");
}
public ReqBuilder cookies(List<Cookie> cookies) {
this.cookies.addAll(cookies);
return this;
}
public ReqBuilder header(String name, String value) {
this.headers.put(name, value);
return this;
}
public ReqBuilder get() {
return method(H.Method.GET);
}
public ReqBuilder getJSON() {
return method(H.Method.GET).format(H.Format.JSON).accept(H.Format.JSON);
}
public ReqBuilder get(String key, Object val, Object ... morePairs) {
params(key, val, morePairs);
return get();
}
public ReqBuilder get(List<$.T2<String, Object>> pairs) {
params(pairs);
return get();
}
public ReqBuilder post() {
return method(H.Method.POST);
}
public ReqBuilder post(String key, Object val, Object... morePairs) {
format(H.Format.FORM_URL_ENCODED);
post();
return params(key, val, morePairs);
}
public ReqBuilder post(List<$.T2<String, Object>> pairs) {
format(H.Format.FORM_URL_ENCODED);
post();
return params(pairs);
}
public ReqBuilder put() {
return method(H.Method.PUT);
}
public ReqBuilder delete() {
return method(H.Method.DELETE);
}
public ReqBuilder options() {
return method(H.Method.OPTIONS);
}
public ReqBuilder method(H.Method method) {
this.method = method;
return this;
}
public H.Method method() {
return this.method;
}
public ReqBuilder format(H.Format format) {
this.format = format;
return this;
}
public ReqBuilder accept(H.Format format) {
this.accept = format;
return this;
}
public ReqBuilder body(RequestBody body) {
this.body = body;
return this;
}
public ReqBuilder param(String key, Object val) {
E.illegalArgumentIf(S.blank(key));
if (method == H.Method.GET) {
sb.append(paramAttached ? "&" : "?");
paramAttached = true;
sb.append(key).append("=").append(Codec.encodeUrl(S.string(val)));
} else {
postParams.add($.T2(key, val));
}
return this;
}
public ReqBuilder params(String key, Object val, Object ... otherPairs) {
E.illegalArgumentIf(otherPairs.length % 2 != 0);
param(key, val);
int len = otherPairs.length;
for (int i = 0; i < len - 1; i += 2) {
String key0 = S.string(otherPairs[i]);
param(key0, otherPairs[i + 1]);
}
return this;
}
public ReqBuilder params(List<$.T2<String, Object>> pairs) {
if (null != pairs) {
for ($.T2<String, Object> pair : pairs) {
param(pair._1, pair._2);
}
}
return this;
}
public ReqBuilder post(String content) {
this.post();
this.postStr = content;
return this;
}
public ReqBuilder postJSON(Object content) {
this.postParams.clear();
this.postBytes = null;
this.format = H.Format.JSON;
this.post();
post(JSON.toJSONString(content));
return this;
}
public ReqBuilder post(byte[] content) {
this.post();
this.postBytes = content;
return this;
}
public ReqBuilder post(ISObject content) {
this.post();
this.postAttachment = content;
return this;
}
public Request.Builder build() {
Request.Builder builder = new Request.Builder().url(sb.toString());
if (this.format == H.Format.JSON) {
builder.addHeader("Content-Type", "application/json");
}
if (this.accept == H.Format.JSON) {
builder.addHeader("Accept", "application/json");
}
if (!this.headers.isEmpty()) {
for (Map.Entry<String, String> entry : headers.entrySet()) {
builder.addHeader(entry.getKey(), entry.getValue());
}
}
if (!this.cookies.isEmpty()) {
builder.header("Cookie", cookieHeader());
}
switch (method) {
case GET:
return builder.get();
case POST:
return builder.post(body());
case PUT:
return builder.put(body());
case DELETE:
return builder.delete(body());
case PATCH:
return builder.patch(body());
case OPTIONS:
return builder.method("OPTIONS", null);
default:
return builder;
}
}
private String cookieHeader() {
StringBuilder cookieHeader = new StringBuilder();
for (int i = 0, size = cookies.size(); i < size; i++) {
if (i > 0) {
cookieHeader.append("; ");
}
Cookie cookie = cookies.get(i);
cookieHeader.append(cookie.name()).append('=').append(cookie.value());
}
return cookieHeader.toString();
}
private RequestBody body() {
if (null == body) {
body = buildBody();
}
return body;
}
private MediaType mediaType() {
return MediaType.parse(format.contentType());
}
private RequestBody buildBody() {
if (format == H.Format.JSON) {
return buildJsonBody();
} else {
return buildFormEncoded();
}
}
private RequestBody buildJsonBody() {
if (S.notBlank(postStr)) {
return RequestBody.create(mediaType(), postStr);
} else {
Map<String, Object> map = new HashMap<String, Object>();
for ($.T2<String, Object> entry : postParams) {
map.put(entry._1, entry._2);
}
return RequestBody.create(mediaType(), JSON.toJSONString(map));
}
}
private RequestBody buildFormEncoded() {
FormBody.Builder builder = new FormBody.Builder();
for ($.T2<String, Object> entry : postParams) {
String val = S.string(entry._2);
if (this.method == H.Method.GET) {
val = Codec.encodeUrl(val);
}
builder.add(entry._1, val);
}
return builder.build();
}
}
}