Skip to content

Commit

Permalink
(jcabi#254) Introduce integration tests based on HttpBin
Browse files Browse the repository at this point in the history
  • Loading branch information
andreoss committed Jun 27, 2021
1 parent 357ce43 commit a91450c
Show file tree
Hide file tree
Showing 4 changed files with 382 additions and 4 deletions.
24 changes: 24 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,16 @@ OF THE POSSIBILITY OF SUCH DAMAGE.
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
Expand All @@ -263,6 +273,20 @@ OF THE POSSIBILITY OF SUCH DAMAGE.
<scope>import</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>1.15.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.7.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
Expand Down
252 changes: 252 additions & 0 deletions src/test/java/com/jcabi/http/RequestITCaseTemplate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
/*
* Copyright (c) 2011-2017, jcabi.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met: 1) Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer. 2) Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution. 3) Neither the name of the jcabi.com nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jcabi.http;

import com.jcabi.aspects.Tv;
import com.jcabi.http.request.JdkRequest;
import com.jcabi.http.response.JsonResponse;
import com.jcabi.http.response.RestResponse;
import com.jcabi.http.response.XmlResponse;
import com.jcabi.http.wire.AutoRedirectingWire;
import com.jcabi.http.wire.BasicAuthWire;
import com.jcabi.http.wire.CookieOptimizingWire;
import com.jcabi.xml.XML;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.util.Locale;
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonValue;
import javax.ws.rs.core.HttpHeaders;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledIf;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

/**
* Tests for any implementation of {@link Request}.
*
* @checkstyle JavadocMethodCheck (500 lines)
* @since 1.17.8
*/
@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
@SuppressWarnings({"PMD.AbstractClassWithoutAbstractMethod", "PMD.TooManyMethods"})
public abstract class RequestITCaseTemplate {

/**
* Type of Request.
*/
private final Class<? extends Request> type;

/**
* Base URI.
*/
private final URI uri;

/**
* Make request for a specific path.
* @param path Path.
* @return Request.
*/
protected final Request request(final String path) {
return RequestTestTemplate.request(
this.uri.resolve(path),
this.type
);
}

@ParameterizedTest
@ValueSource(ints = {
HttpURLConnection.HTTP_NOT_FOUND,
HttpURLConnection.HTTP_OK,
HttpURLConnection.HTTP_UNAVAILABLE
})
final void readsReturnStatusCode(final int code) throws IOException {
this.request(String.format("/status/%d", code))
.fetch()
.as(RestResponse.class)
.assertStatus(code);
}

@ParameterizedTest
@ValueSource(
strings = {
Request.DELETE,
Request.GET,
Request.POST,
Request.PUT
}
)
final void readsReturnStatusCode(final String method) throws IOException {
this.request(String.format("/%s", method.toLowerCase(Locale.ENGLISH)))
.method(method)
.fetch()
.as(RestResponse.class)
.assertStatus(HttpURLConnection.HTTP_OK);
}

@Test
final void sendsCookies() throws IOException {
MatcherAssert.assertThat(
"Must send cookies",
this.request("/cookies")
.header(HttpHeaders.COOKIE, "foo=bar")
.header(HttpHeaders.COOKIE, "baz=foz")
.through(CookieOptimizingWire.class)
.fetch()
.as(JsonResponse.class)
.json()
.readObject()
.getJsonObject("cookies"),
Matchers.allOf(
Matchers.hasEntry(
Matchers.is("foo"),
Matchers.is(Json.createValue("bar"))
),
Matchers.hasEntry(
Matchers.is("baz"),
Matchers.is(Json.createValue("foz"))
)
)
);
}

@Test
final void followsLocationHeader() throws IOException {
this.request("/absolute-redirect/5")
.through(AutoRedirectingWire.class, Tv.SIX)
.fetch()
.as(RestResponse.class)
.assertStatus(HttpURLConnection.HTTP_OK);
}

@Test
final void failsOnTimeout() {
Assertions.assertThrows(
IOException.class,
() ->
this.request("/delay/3")
.timeout(Tv.THOUSAND, Tv.THOUSAND)
.fetch()
);
}

@Test
final void readsJsonResponse() throws Exception {
MatcherAssert.assertThat(
"Must parse Json response",
this.request("/json")
.fetch()
.as(JsonResponse.class)
.json()
.readObject(),
Matchers.notNullValue(JsonObject.class)
);
}

@Test
@DisabledIf("isJdkRequest")
final void readsDeflatedJsonResponse() throws Exception {
MatcherAssert.assertThat(
"Must undeflate & parse Json response",
this.request("/deflate")
.fetch()
.as(JsonResponse.class)
.json()
.readObject(),
Matchers.hasEntry(
Matchers.is("deflated"),
Matchers.is(JsonValue.TRUE)
)
);
}

@Test
@DisabledIf("isJdkRequest")
final void readsGzippedJsonResponse() throws Exception {
MatcherAssert.assertThat(
"Must unzip & parse Json response",
this.request("/gzip")
.fetch()
.as(JsonResponse.class)
.json()
.readObject(),
Matchers.hasEntry(
Matchers.is("gzipped"),
Matchers.is(JsonValue.TRUE)
)
);
}

@Test
final void handlesBasicAuth() throws Exception {
MatcherAssert.assertThat(
"Must authenticate with userInfo",
this.request("/basic-auth/jeff/secret")
.uri()
.userInfo("jeff:secret")
.back()
.through(BasicAuthWire.class)
.fetch()
.as(JsonResponse.class)
.status(),
Matchers.is(
HttpURLConnection.HTTP_OK
)
);
}

@Test
final void readsXmlResponse() throws Exception {
MatcherAssert.assertThat(
"Must parse XML response",
this.request("/xml")
.fetch()
.as(XmlResponse.class)
.xml(),
Matchers.notNullValue(XML.class)
);
}

/**
* Is JdkRequest being tested?
* @return True if so.
*/
@SuppressWarnings("PMD.UnusedPrivateMethod")
private boolean isJdkRequest() {
return JdkRequest.class.equals(this.type);
}
}
103 changes: 103 additions & 0 deletions src/test/java/com/jcabi/http/RequestSecondITCase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright (c) 2011-2017, jcabi.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met: 1) Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer. 2) Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution. 3) Neither the name of the jcabi.com nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jcabi.http;

import com.jcabi.http.request.ApacheRequest;
import com.jcabi.http.request.JdkRequest;
import java.net.URI;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.TestInstance;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.utility.DockerImageName;

/**
* Integration test for {@link Request}.
*
* @since 1.17.8
*/
@SuppressWarnings("PMD.AbstractClassWithoutAbstractMethod")
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public final class RequestSecondITCase {

/**
* Container with HttpBin.
*/
private final GenericContainer<?> container = new GenericContainer<>(
DockerImageName.parse("kennethreitz/httpbin")
).withExposedPorts(80);

@BeforeAll
void beforeAll() {
this.container.start();
}

@AfterAll
void tearDown() {
this.container.stop();
}

/**
* URI of the container.
* @return URI.
*/
private URI uri() {
return URI.create(
String.format(
"http://%s:%d",
this.container.getHost(),
this.container.getFirstMappedPort()
)
);
}

/**
* Test for {@link JdkRequest}.
* @since 1.17.8
*/
@Nested
final class JdkRequestITCase extends RequestITCaseTemplate {
JdkRequestITCase() {
super(JdkRequest.class, RequestSecondITCase.this.uri());
}
}

/**
* Test for {@link ApacheRequest}.
* @since 1.17.8
*/
@Nested
final class ApacheRequestITCase extends RequestITCaseTemplate {
ApacheRequestITCase() {
super(ApacheRequest.class, RequestSecondITCase.this.uri());
}
}
}
Loading

0 comments on commit a91450c

Please sign in to comment.