Skip to content

Commit

Permalink
Fixes #73 One http client
Browse files Browse the repository at this point in the history
Demonstrates:
- GET and PUT
- using body and not
- custom headers
  • Loading branch information
Jim Scarborough committed Oct 8, 2019
1 parent f4e4e09 commit ea0382b
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 60 deletions.
34 changes: 0 additions & 34 deletions src/main/java/com/redhat/vertx/pipeline/steps/GetUrl.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,25 +1,33 @@
package com.redhat.vertx.pipeline.steps;

import java.io.IOException;
import java.net.URI;
import java.util.Collections;
import java.util.Map;
import java.util.function.Function;
import java.util.logging.Logger;

import com.redhat.vertx.Engine;
import com.redhat.vertx.pipeline.AbstractStep;
import com.redhat.vertx.pipeline.Step;
import com.redhat.vertx.pipeline.templates.MissingParameterException;
import io.reactivex.Completable;
import io.reactivex.Maybe;
import io.reactivex.Single;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.impl.headers.VertxHttpHeaders;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.client.WebClientOptions;
import io.vertx.reactivex.core.MultiMap;
import io.vertx.reactivex.core.buffer.Buffer;
import io.vertx.reactivex.ext.web.client.HttpRequest;
import io.vertx.reactivex.ext.web.client.HttpResponse;
import io.vertx.reactivex.ext.web.client.WebClient;
import org.kohsuke.MetaInfServices;

public abstract class BaseHttpClient extends AbstractStep {
private static Logger logger = Logger.getLogger(BaseHttpClient.class.getName());
@MetaInfServices(Step.class)
public class HttpClient extends AbstractStep {
private static Logger logger = Logger.getLogger(HttpClient.class.getName());
private WebClient http;

public String getUrl(JsonObject env) {
Expand All @@ -36,7 +44,42 @@ public Completable init(Engine engine, JsonObject config) {
return super.init(engine, config);
}

public abstract HttpRequest<Buffer> request(JsonObject env);
public HttpMethod getMethod(JsonObject env) {
try {
return (HttpMethod)HttpMethod.class.getDeclaredField(env.getString("method","GET")).get(null);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException("Invalid HTTP method", e);
}
}

private MultiMap getHeaders(JsonObject env) {
MultiMap mm = new MultiMap(new VertxHttpHeaders());
env.getJsonObject("headers",new JsonObject().put("Accept","application/json"))
.forEach(e -> mm.add(e.getKey(),e.getValue().toString()));
return mm;

}


public HttpRequest<Buffer> request(JsonObject env) {
String url = getUrl(env);
logger.fine(() -> "requesting " + url);
URI uri = URI.create(url);
String pqf = uri.getPath();

if (uri.getQuery() != null) {
pqf += "?" + uri.getQuery();
}
if (uri.getFragment() != null) {
pqf += "#" + uri.getFragment();
}

return webClient()
.request(getMethod(env), uri.getPort(), uri.getHost(), pqf)
.putHeaders(getHeaders(env));
}



public Object processResponse(HttpResponse<Buffer> response) throws HttpResponseStatusException {
switch (response.statusCode()) {
Expand All @@ -52,6 +95,7 @@ public Object processResponse(HttpResponse<Buffer> response) throws HttpResponse
public static final Map<String, Function<HttpResponse<Buffer>,Object>> decodings;
static {
Map<String, Function<HttpResponse<Buffer>,Object>> d = Map.of(
"application/octet-stream", HttpResponse::bodyAsBuffer,
"text/plain",HttpResponse::bodyAsString,
"text/html",HttpResponse::bodyAsString,
"application/json", HttpResponse::bodyAsJsonObject, // TODO manage JsonArray and String as appropriate
Expand Down Expand Up @@ -86,7 +130,15 @@ public Maybe<Object> execute(JsonObject env) {
return Maybe.error(e);
}

return request.rxSend().flatMapMaybe(this::rxProcessResponse);
return send(request, env).flatMapMaybe(this::rxProcessResponse);
}

public Single<HttpResponse<Buffer>> send(HttpRequest<Buffer> request, JsonObject env) {
if (env.containsKey("body")) {
return request.rxSendJson(env.getValue("body"));
} else {
return request.rxSend();
}
}

protected WebClient webClient() {
Expand Down
11 changes: 5 additions & 6 deletions src/test/java/com/redhat/vertx/pipeline/step/GetUrlTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

import com.redhat.vertx.Engine;
import com.redhat.vertx.pipeline.json.TemplatedJsonObject;
import com.redhat.vertx.pipeline.steps.BaseHttpClient;
import com.redhat.vertx.pipeline.steps.GetUrl;
import com.redhat.vertx.pipeline.steps.HttpClient;
import com.redhat.vertx.pipeline.templates.JinjaTemplateProcessor;
import com.redhat.vertx.pipeline.templates.MissingParameterException;
import io.vertx.core.json.JsonObject;
Expand All @@ -28,7 +27,7 @@ public void testGetUrl(Vertx vertx, VertxTestContext testContext) throws Excepti
JsonObject env = new JsonObject();
String url = "http://www.example.com/";
env.put("url",url);
BaseHttpClient client = new GetUrl();
HttpClient client = new HttpClient();
assertThat(client.getUrl(env)).isEqualTo(url);

env = new TemplatedJsonObject(new JsonObject(), new JinjaTemplateProcessor());
Expand All @@ -46,7 +45,7 @@ public void testGetRequest(Vertx vertx, VertxTestContext testContext) throws Exc
JsonObject env = new JsonObject();
String url = "http://www.example.com/";
env.put("url",url);
BaseHttpClient client = new GetUrl();
HttpClient client = new HttpClient();

Engine engine = mock(Engine.class);
when(engine.getRxVertx()).thenReturn(vertx);
Expand All @@ -69,7 +68,7 @@ public void testProcessResponse(Vertx vertx, VertxTestContext testContext) throw
JsonObject env = new JsonObject();
String url = "http://www.example.com/";
env.put("url",url);
BaseHttpClient client = new GetUrl();
HttpClient client = new HttpClient();

Engine engine = mock(Engine.class);
when(engine.getRxVertx()).thenReturn(vertx);
Expand Down Expand Up @@ -97,7 +96,7 @@ public void testProcessResponse(Vertx vertx, VertxTestContext testContext) throw
try {
body = client.processResponse(response);
fail();
} catch (BaseHttpClient.HttpResponseStatusException e) {
} catch (HttpClient.HttpResponseStatusException e) {
// expected
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.junit.WireMockRule;
import com.github.tomakehurst.wiremock.matching.ContentPattern;
import com.github.tomakehurst.wiremock.matching.EqualToPattern;
import com.github.tomakehurst.wiremock.matching.MatchResult;
import com.github.tomakehurst.wiremock.matching.StringValuePattern;
import com.redhat.ResourceUtils;
import com.redhat.vertx.Engine;
import com.redhat.vertx.pipeline.steps.BaseHttpClient;
import com.redhat.vertx.pipeline.steps.HttpClient;
import io.reactivex.disposables.Disposable;
import io.reactivex.internal.disposables.DisposableHelper;
import io.vertx.core.json.JsonObject;
Expand All @@ -23,18 +27,12 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
import static com.github.tomakehurst.wiremock.client.WireMock.matching;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching;
import static com.github.tomakehurst.wiremock.client.WireMock.verify;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
import static org.assertj.core.api.Assertions.assertThat;

@ExtendWith(VertxExtension.class)
public class GetUrlIntegrationTest {
public class HttpClientIntegrationTest {
private WireMockServer wireMockServer;

@BeforeEach
Expand Down Expand Up @@ -82,15 +80,14 @@ public void happyPath200(Vertx vertx, VertxTestContext testContext) throws Excep
@Test
public void happyPath204(Vertx vertx, VertxTestContext testContext) throws Exception {
int port = wireMockServer.port();
wireMockServer.stubFor(get(urlEqualTo("/my/resource"))
.withHeader("Accept", matching("application/json"))
wireMockServer.stubFor(post(urlEqualTo("/my/resource"))
.willReturn(aResponse().withStatus(204)));

String url = "http://localhost:" + port + "/my/resource";

Engine engine = new Engine(
ResourceUtils.fileContentsFromResource(
"com/redhat/vertx/pipeline/step/httpClientIntegrationTest.yaml"
"com/redhat/vertx/pipeline/step/httpPostTest.yaml"
));
JsonObject doc = new JsonObject().put("url",url);
vertx.rxDeployVerticle(engine).timeout(1, TimeUnit.SECONDS).blockingGet();
Expand All @@ -113,8 +110,10 @@ private void validate204(Object r, VertxTestContext testContext) {
JsonObject jo = (JsonObject)r;
assertThat(jo.containsKey("response")).isFalse(); // This could well be false because the result is empty
assertThat(jo.getJsonObject("response")).isNull();
verify(getRequestedFor(urlMatching("/my/resource"))
.withHeader("Accept", matching("application/json")));
verify(postRequestedFor(urlMatching("/my/resource"))
.withHeader("Accept", matching("application/json"))
.withRequestBody(new EqualToPattern("Shall I compare thee to a summer's day?")));

testContext.completeNow();
}

Expand Down Expand Up @@ -145,7 +144,7 @@ public void serverError500(Vertx vertx, VertxTestContext testContext) throws Exc
engine.execute(doc)
.doOnError(t -> {
logger.info("Evaluating exception " + t.toString());
assertThat(t).isNotInstanceOf(BaseHttpClient.HttpResponseStatusException.class);
assertThat(t).isNotInstanceOf(HttpClient.HttpResponseStatusException.class);
})
.doAfterTerminate(() -> {
logger.info("Disposing after terminate");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
steps:
- name: Fetch
get_url:
http_client:
url: "{{doc.url}}"
register: response
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
steps:
- name: Post
http_client:
url: "{{doc.url}}"
method: POST
headers:
Content-type: "text/plain"
body: "Shall I compare thee to a summer's day?"
register: response

0 comments on commit ea0382b

Please sign in to comment.