Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hoist up Node Gradle plugin, set TestTomcat baseDir, add hasContentType matcher, HTTP status consts #7

Merged
merged 3 commits into from
Nov 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
plugins {
// Apply the foojay-resolver plugin to allow automatic download of JDKs
id("org.gradle.toolchains.foojay-resolver-convention") version "0.7.0"
id("com.github.node-gradle.node") version "7.0.1" apply false
id("com.github.ben-manes.versions") version "0.50.0" apply false
}

Expand Down
2 changes: 1 addition & 1 deletion strcalc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask
plugins {
war
jacoco
id("com.github.node-gradle.node") version "7.0.1"
id("com.github.node-gradle.node")
id("com.github.ben-manes.versions")
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.mike_bland.training.testing.matchers;

import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;

import java.net.http.HttpResponse;

// Custom Hamcrest matcher validating the Content-Type header of a HttpResponse.
//
// This could be generalized to check any HTTP header, or collection thereof.
// However, since this is a teaching example, we'll keep it straightforward.
class HasContentType<T> extends TypeSafeMatcher<HttpResponse<T>> {
private final String expected;

// Constructor to register the expected Content-Type value.
HasContentType(String contentType) {
this.expected = contentType;
}

// Helper method to extract the Content-Type value from an HttpResponse.
private String getContentType(HttpResponse<T> resp) {
return resp.headers().firstValue("Content-Type").orElse("");
}

// Performs the actual assertion.
@Override public boolean matchesSafely(HttpResponse<T> resp) {
return getContentType(resp).equals(expected);
}

// Describes the "Expected:" value in assertion failure messages.
@Override public void describeTo(Description description) {
description.appendText(expected);
}

// Describes the actual ("but:") value in assertion failure messages.
@Override public void describeMismatchSafely(
HttpResponse<T> resp, Description description) {
description.appendText(getContentType(resp));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.mike_bland.training.testing.matchers;

import org.hamcrest.Matcher;

import java.net.http.HttpResponse;

// Collection of custom Hamcrest Matcher<T> classes for assertThat() statements.
//
// These tutorials describe how to write Matchers:
//
// - https://hamcrest.org/JavaHamcrest/tutorial
// - https://www.baeldung.com/hamcrest-custom-matchers
//
// Note that these tutorials show the static factory functions defined on the
// same class as the Matcher. However, Hamcrest itself collects these factories
// into its own org.hamcrest.Matchers class for convenience, instead of
// importing one class per Matcher.
public class Matchers {
public static <T> Matcher<HttpResponse<T>> hasContentType(
String contentType) {
return new HasContentType<>(contentType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.mike_bland.training.testing.annotations.MediumTest;
import com.mike_bland.training.testing.utils.PortPicker;
import com.mike_bland.training.testing.utils.TestTomcat;
import jakarta.servlet.http.HttpServletResponse;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;

Expand All @@ -20,6 +21,7 @@
import java.net.http.HttpResponse.BodyHandlers;
import java.util.Optional;

import static com.mike_bland.training.testing.matchers.Matchers.hasContentType;
import static com.mike_bland.training.testing.stringcalculator.Servlet.DEFAULT_ROOT;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
Expand Down Expand Up @@ -65,11 +67,8 @@ void servesCorrectLandingPage() throws Exception {

var resp = sendRequest(req);

assertEquals(200, resp.statusCode());
assertEquals(
Optional.of("text/html"),
resp.headers().firstValue("Content-Type")
);
assertEquals(HttpServletResponse.SC_OK, resp.statusCode());
assertThat(resp, hasContentType("text/html"));
assertThat(
resp.body(),
containsString("<title>String Calculator - ")
Expand All @@ -86,11 +85,8 @@ void addEndpointPlaceholder() throws Exception {

var resp = sendRequest(req);

assertEquals(200, resp.statusCode());
assertEquals(
Optional.of("text/plain;charset=UTF-8"),
resp.headers().firstValue("Content-Type")
);
assertEquals(HttpServletResponse.SC_OK, resp.statusCode());
assertThat(resp, hasContentType("text/plain;charset=UTF-8"));
assertEquals("placeholder for /add API endpoint", resp.body());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public class TestTomcat {
private final int port;
private final String contextPath;
private final URI uri;
private final File baseDir;
private Tomcat tomcat;
private boolean running;

Expand All @@ -52,12 +53,14 @@ public TestTomcat(int port, String contextPath)
this.uri = URI.create(
String.format("http://localhost:%d%s", port, contextPath)
);
this.baseDir = new File("build/test-tomcat-basedir");
}

public synchronized void start() throws LifecycleException {
if (running) return;
running = true;
tomcat = new Tomcat();
tomcat.setBaseDir(this.baseDir.getAbsolutePath());
tomcat.setPort(port);
tomcat.setSilent(true);

Expand Down Expand Up @@ -127,7 +130,7 @@ public synchronized void stop() throws LifecycleException, IOException {
if (!running) return;
running = false;
tomcat.stop();
deleteBaseDir(port);
deleteBaseDir(this.baseDir);
}

private static String validateContextPath(String contextPath)
Expand All @@ -141,10 +144,7 @@ private static String validateContextPath(String contextPath)
return contextPath;
}

private static void deleteBaseDir(int port) throws IOException {
// The Tomcat.setBaseDir() documentation explains the base dir schema:
// - https://tomcat.apache.org/tomcat-10.1-doc/api/org/apache/catalina/startup/Tomcat.html#setBaseDir(java.lang.String)
final var baseDir = new File("tomcat.%d".formatted(port));
private static void deleteBaseDir(File baseDir) throws IOException {
List<String> failed;

try (var fileStream = Files.walk(baseDir.toPath())) {
Expand Down
Loading