package com.github.dreamhead.moco;
import com.google.common.io.Files;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.fluent.Request;
import org.apache.http.entity.ContentType;
import org.hamcrest.Matcher;
import org.hamcrest.core.SubstringMatcher;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import static com.github.dreamhead.moco.HttpProtocolVersion.VERSION_0_9;
import static com.github.dreamhead.moco.HttpProtocolVersion.VERSION_1_0;
import static com.github.dreamhead.moco.HttpProtocolVersion.VERSION_1_1;
import static com.github.dreamhead.moco.Moco.and;
import static com.github.dreamhead.moco.Moco.by;
import static com.github.dreamhead.moco.Moco.context;
import static com.github.dreamhead.moco.Moco.eq;
import static com.github.dreamhead.moco.Moco.failover;
import static com.github.dreamhead.moco.Moco.file;
import static com.github.dreamhead.moco.Moco.from;
import static com.github.dreamhead.moco.Moco.header;
import static com.github.dreamhead.moco.Moco.httpServer;
import static com.github.dreamhead.moco.Moco.log;
import static com.github.dreamhead.moco.Moco.match;
import static com.github.dreamhead.moco.Moco.method;
import static com.github.dreamhead.moco.Moco.playback;
import static com.github.dreamhead.moco.Moco.proxy;
import static com.github.dreamhead.moco.Moco.query;
import static com.github.dreamhead.moco.Moco.status;
import static com.github.dreamhead.moco.Moco.template;
import static com.github.dreamhead.moco.Moco.uri;
import static com.github.dreamhead.moco.Moco.version;
import static com.github.dreamhead.moco.Moco.with;
import static com.github.dreamhead.moco.MocoRequestHit.once;
import static com.github.dreamhead.moco.MocoRequestHit.requestHit;
import static com.github.dreamhead.moco.Runner.running;
import static com.github.dreamhead.moco.helper.RemoteTestUtils.port;
import static com.github.dreamhead.moco.helper.RemoteTestUtils.remoteUrl;
import static com.github.dreamhead.moco.helper.RemoteTestUtils.root;
import static com.google.common.collect.ImmutableMultimap.of;
import static java.lang.String.format;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
public class MocoProxyTest extends AbstractMocoHttpTest {
@Rule
public TemporaryFolder tempFolder = new TemporaryFolder();
@Test
public void should_fetch_remote_url() throws Exception {
server.response(proxy("https://github.com/"));
running(server, new Runnable() {
@Override
public void run() throws IOException {
assertThat(helper.getForStatus(root()), is(200));
}
});
}
@Test
public void should_proxy_with_request_method() throws Exception {
server.get(by(uri("/target"))).response("get_proxy");
server.post(and(by(uri("/target")), by("proxy"))).response("post_proxy");
server.request(and(by(uri("/target")), by(method("put")), by("proxy"))).response("put_proxy");
server.request(and(by(uri("/target")), by(method("delete")))).response("delete_proxy");
server.request(and(by(uri("/target")), by(method("head")))).response(status(200));
server.request(and(by(uri("/target")), by(method("options")))).response("options_proxy");
server.request(and(by(uri("/target")), by(method("trace")))).response("trace_proxy");
server.request(by(uri("/proxy"))).response(proxy(remoteUrl("/target")));
running(server, new Runnable() {
@Override
public void run() throws IOException {
assertThat(helper.get(remoteUrl("/proxy")), is("get_proxy"));
assertThat(helper.postContent(remoteUrl("/proxy"), "proxy"), is("post_proxy"));
Request putRequest = Request.Put(remoteUrl("/proxy")).bodyString("proxy", ContentType.DEFAULT_TEXT);
assertThat(helper.executeAsString(putRequest), is("put_proxy"));
Request deleteRequest = Request.Delete(remoteUrl("/proxy"));
assertThat(helper.executeAsString(deleteRequest), is("delete_proxy"));
Request headRequest = Request.Head(remoteUrl("/proxy"));
StatusLine headStatusLine = helper.execute(headRequest).getStatusLine();
assertThat(headStatusLine.getStatusCode(), is(200));
Request optionsRequest = Request.Options(remoteUrl("/proxy"));
assertThat(helper.executeAsString(optionsRequest), is("options_proxy"));
Request traceRequest = Request.Trace(remoteUrl("/proxy"));
assertThat(helper.executeAsString(traceRequest), is("trace_proxy"));
}
});
}
@Test
public void should_proxy_with_request_header() throws Exception {
server.request(and(by(uri("/target")), eq(header("foo"), "foo"))).response("foo_proxy");
server.request(and(by(uri("/target")), eq(header("bar"), "bar"))).response("bar_proxy");
server.request(by(uri("/proxy"))).response(proxy(remoteUrl("/target")));
running(server, new Runnable() {
@Override
public void run() throws IOException {
assertThat(helper.getWithHeader(remoteUrl("/proxy"), of("foo", "foo")), is("foo_proxy"));
}
});
}
@Test
public void should_proxy_with_request_query_parameters() throws Exception {
server.request(and(by(uri("/target")), eq(query("foo"), "foo"))).response("foo_proxy");
server.request(and(by(uri("/target")), eq(query("bar"), "bar"))).response("bar_proxy");
server.request(by(uri("/proxy"))).response(proxy(remoteUrl("/target")));
running(server, new Runnable() {
@Override
public void run() throws IOException {
assertThat(helper.get(remoteUrl("/proxy?foo=foo")), is("foo_proxy"));
assertThat(helper.get(remoteUrl("/proxy?bar=bar")), is("bar_proxy"));
}
});
}
@Test
public void should_proxy_with_response_headers() throws Exception {
server.request(and(by(uri("/target")), eq(header("foo"), "foo"))).response(header("foo", "foo_header"));
server.request(and(by(uri("/target")), eq(header("bar"), "bar"))).response(header("bar", "bar_header"));
server.request(by(uri("/proxy"))).response(proxy(remoteUrl("/target")));
running(server, new Runnable() {
@Override
public void run() throws IOException {
Request request = Request.Get(remoteUrl("/proxy")).addHeader("foo", "foo");
String fooHeader = helper.execute(request).getFirstHeader("foo").getValue();
assertThat(fooHeader, is("foo_header"));
}
});
}
@Test
public void should_proxy_with_request_version() throws Exception {
server.request(and(by(uri("/target")), by(version(VERSION_1_0)))).response("1.0");
server.request(and(by(uri("/target")), by(version(VERSION_1_1)))).response("1.1");
server.request(by(uri("/proxy"))).response(proxy(remoteUrl("/target")));
running(server, new Runnable() {
@Override
public void run() throws IOException {
assertThat(helper.getWithVersion(remoteUrl("/proxy"), HttpVersion.HTTP_1_0), is("1.0"));
assertThat(helper.getWithVersion(remoteUrl("/proxy"), HttpVersion.HTTP_1_1), is("1.1"));
}
});
}
@Test
public void should_proxy_with_response_version() throws Exception {
server.request(and(by(uri("/target")), by(version(VERSION_1_0)))).response(version(VERSION_1_0));
server.request(and(by(uri("/target")), by(version(VERSION_1_1)))).response(version(VERSION_1_1));
server.request(and(by(uri("/target")), by(version(VERSION_0_9)))).response(version(VERSION_1_0));
server.request(by(uri("/proxy"))).response(proxy(remoteUrl("/target")));
running(server, new Runnable() {
@Override
public void run() throws IOException {
HttpResponse response10 = helper.execute(Request.Get(remoteUrl("/proxy"))
.version(HttpVersion.HTTP_1_0));
assertThat(response10.getProtocolVersion().toString(), is(HttpVersion.HTTP_1_0.toString()));
HttpResponse response11 = helper.execute(Request.Get(remoteUrl("/proxy"))
.version(HttpVersion.HTTP_1_1));
assertThat(response11.getProtocolVersion().toString(), is(HttpVersion.HTTP_1_1.toString()));
HttpResponse response09 = helper.execute(Request.Get(remoteUrl("/proxy"))
.version(HttpVersion.HTTP_0_9));
assertThat(response09.getProtocolVersion().toString(), is(HttpVersion.HTTP_1_0.toString()));
}
});
}
@Test
public void should_failover_with_response_content() throws Exception {
server.post(and(by(uri("/target")), by("proxy"))).response("proxy");
final File tempFile = tempFolder.newFile();
server.request(by(uri("/proxy"))).response(proxy(remoteUrl("/target"), failover(tempFile.getAbsolutePath())));
running(server, new Runnable() {
@Override
public void run() throws IOException {
assertThat(helper.postContent(remoteUrl("/proxy"), "proxy"), is("proxy"));
assertThat(Files.toString(tempFile, Charset.defaultCharset()), containsString("proxy"));
}
});
}
@Test
public void should_failover_with_many_response_content() throws Exception {
server.get(by(uri("/target"))).response("get_proxy");
server.post(and(by(uri("/target")), by("proxy"))).response("post_proxy");
final File tempFile = tempFolder.newFile();
server.request(by(uri("/proxy"))).response(proxy(remoteUrl("/target"), failover(tempFile.getAbsolutePath())));
running(server, new Runnable() {
@Override
public void run() throws IOException {
assertThat(helper.get(remoteUrl("/proxy")), is("get_proxy"));
assertThat(helper.postContent(remoteUrl("/proxy"), "proxy"), is("post_proxy"));
String failoverContent = Files.toString(tempFile, Charset.defaultCharset());
assertThat(failoverContent, containsString("get_proxy"));
assertThat(failoverContent, containsString("post_proxy"));
}
});
}
@Test
public void should_failover_with_same_response_once() throws Exception {
server = httpServer(port(), log());
server.post(and(by(uri("/target")), by("proxy"))).response("0XCAFEBABE");
final File tempFile = tempFolder.newFile();
server.request(by(uri("/proxy"))).response(proxy(remoteUrl("/target"), failover(tempFile.getAbsolutePath())));
running(server, new Runnable() {
@Override
public void run() throws IOException {
assertThat(helper.postContent(remoteUrl("/proxy"), "proxy"), is("0XCAFEBABE"));
assertThat(helper.postContent(remoteUrl("/proxy"), "proxy"), is("0XCAFEBABE"));
assertThat(Files.toString(tempFile, Charset.defaultCharset()), countString("/proxy", 1));
}
});
}
private Matcher<String> countString(final String substring, final int targetCount) {
return new SubstringMatcher(substring) {
@Override
protected boolean evalSubstringOf(final String string) {
int count = 0;
int current = 0;
while (current < string.length()) {
int index = string.indexOf(substring, current);
if (index > 0) {
count++;
current = index + substring.length();
} else {
break;
}
}
return count == targetCount;
}
@Override
protected String relationship() {
return format("count %d string", targetCount);
}
};
}
@Test
public void should_failover_for_unreachable_remote_server() throws Exception {
server.request(by(uri("/proxy"))).response(proxy(remoteUrl("/target"), failover("src/test/resources/failover.response")));
running(server, new Runnable() {
@Override
public void run() throws IOException {
assertThat(helper.postContent(remoteUrl("/proxy"), "proxy"), is("proxy"));
}
});
}
@Test
public void should_failover_for_unreachable_remote_server_with_many_content() throws Exception {
server.request(by(uri("/proxy"))).response(proxy(remoteUrl("/target"), failover("src/test/resources/many_content_failover.response")));
running(server, new Runnable() {
@Override
public void run() throws IOException {
assertThat(helper.get(remoteUrl("/proxy")), is("get_proxy"));
assertThat(helper.postContent(remoteUrl("/proxy"), "proxy"), is("post_proxy"));
}
});
}
// @Test
// public void should_be_able_to_connect_to_external_website_successfully() throws Exception {
// server.response(proxy("http://www.baidu.com/"));
//
// running(server, new Runnable() {
// @Override
// public void run() throws IOException {
// assertThat(helper.getForStatus(root()), is(200));
// }
// });
// }
@Test
public void should_proxy_a_batch_of_urls() throws Exception {
server.get(by(uri("/target/1"))).response("target_1");
server.get(by(uri("/target/2"))).response("target_2");
server.get(match(uri("/proxy/.*"))).response(proxy(from("/proxy").to(remoteUrl("/target"))));
running(server, new Runnable() {
@Override
public void run() throws Exception {
assertThat(helper.get(remoteUrl("/proxy/1")), is("target_1"));
assertThat(helper.get(remoteUrl("/proxy/2")), is("target_2"));
}
});
}
@Test
public void should_proxy_a_batch_of_urls_with_failover() throws Exception {
server.request(match(uri("/proxy/.*"))).response(proxy(from("/proxy").to(remoteUrl("/target")), failover("src/test/resources/failover.response")));
running(server, new Runnable() {
@Override
public void run() throws Exception {
assertThat(helper.postContent(remoteUrl("/proxy/1"), "proxy"), is("proxy"));
}
});
}
@Test
public void should_batch_proxy_from_server() throws Exception {
server.get(by(uri("/target/1"))).response("target_1");
server.get(by(uri("/target/2"))).response("target_2");
server.proxy(from("/proxy").to(remoteUrl("/target")));
running(server, new Runnable() {
@Override
public void run() throws Exception {
assertThat(helper.get(remoteUrl("/proxy/1")), is("target_1"));
assertThat(helper.get(remoteUrl("/proxy/2")), is("target_2"));
}
});
}
@Test(expected = HttpResponseException.class)
public void should_not_proxy_url_for_unmatching_url_for_batch_proxy_from_server() throws Exception {
server.proxy(from("/proxy").to(remoteUrl("/target")));
running(server, new Runnable() {
@Override
public void run() throws Exception {
helper.get(remoteUrl("/proxy1/1"));
}
});
}
@Test
public void should_batch_proxy_from_server_with_context_server() throws Exception {
server = httpServer(port(), context("/proxy"));
server.get(by(uri("/target/1"))).response("target_1");
server.get(by(uri("/target/2"))).response("target_2");
server.proxy(from("/proxy").to(remoteUrl("/proxy/target")));
running(server, new Runnable() {
@Override
public void run() throws Exception {
assertThat(helper.get(remoteUrl("/proxy/proxy/1")), is("target_1"));
assertThat(helper.get(remoteUrl("/proxy/proxy/2")), is("target_2"));
}
});
}
@Test
public void should_proxy_a_batch_of_urls_with_failover_from_server() throws Exception {
server.proxy(from("/proxy").to(remoteUrl("/target")), failover("src/test/resources/failover.response"));
running(server, new Runnable() {
@Override
public void run() throws Exception {
assertThat(helper.postContent(remoteUrl("/proxy/1"), "proxy"), is("proxy"));
}
});
}
@Test
public void should_proxy_with_playback() throws Exception {
server.request(by(uri("/target"))).response("proxy");
final File file = tempFolder.newFile();
server.request(by(uri("/proxy_playback"))).response(proxy(remoteUrl("/target"), playback(file.getAbsolutePath())));
running(server, new Runnable() {
@Override
public void run() throws Exception {
assertThat(helper.get(remoteUrl("/proxy_playback")), is("proxy"));
}
});
}
@Test
public void should_proxy_with_playback_to_access_remote_only_once() throws Exception {
RequestHit hit = requestHit();
server = httpServer(port(), hit);
server.request(by(uri("/target"))).response("proxy");
final File file = tempFolder.newFile();
server.request(by(uri("/proxy_playback"))).response(proxy(remoteUrl("/target"), playback(file.getAbsolutePath())));
running(server, new Runnable() {
@Override
public void run() throws Exception {
assertThat(helper.get(remoteUrl("/proxy_playback")), is("proxy"));
assertThat(helper.get(remoteUrl("/proxy_playback")), is("proxy"));
}
});
hit.verify(by(uri("/target")), once());
}
@Test
public void should_ignore_some_header_from_remote_server() throws Exception {
server.request(by(uri("/target"))).response(with("proxy"), header("Date", "2014-5-1"), header("Server", "moco"));
server.request(by(uri("/proxy"))).response(proxy(remoteUrl("/target")));
running(server, new Runnable() {
@Override
public void run() throws Exception {
HttpResponse response = helper.execute(Request.Get(remoteUrl("/proxy")));
assertThat(response.getFirstHeader("Date"), nullValue());
assertThat(response.getFirstHeader("Server"), nullValue());
}
});
}
@Test
public void should_work_well_for_chunk_response() throws Exception {
final File file = tempFolder.newFile();
HttpServer server = httpServer(12306, context("/"));
server.get(match(uri("/repos/.*")))
.response(proxy(from("/repos").to("https://api.github.com/repos"), playback(file.getAbsolutePath())));
running(server, new Runnable() {
@Override
public void run() throws Exception {
String result = helper.get("http://localhost:12306/repos/HipByte/RubyMotion/contributors");
assertThat(result.isEmpty(), is(false));
}
});
}
@Test
public void should_work_with_file_resource_url() throws Exception {
server.get(by(uri("/target"))).response("get_proxy");
server.request(by(uri("/proxy"))).response(proxy(file("src/test/resources/remote_url.resource")));
running(server, new Runnable() {
@Override
public void run() throws IOException {
assertThat(helper.get(remoteUrl("/proxy")), is("get_proxy"));
}
});
}
@Test
public void should_work_with_template() throws Exception {
server.get(by(uri("/target"))).response("get_proxy");
server.request(by(uri("/proxy"))).response(proxy(template("http://localhost:12306/${var}", "var", "target")));
running(server, new Runnable() {
@Override
public void run() throws IOException {
assertThat(helper.get(remoteUrl("/proxy")), is("get_proxy"));
}
});
}
}