diff --git a/buildSrc/src/main/kotlin/io.github.nstdio.http.ext.library-conventions.gradle.kts b/buildSrc/src/main/kotlin/io.github.nstdio.http.ext.library-conventions.gradle.kts index b813e3c..348e31b 100644 --- a/buildSrc/src/main/kotlin/io.github.nstdio.http.ext.library-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/io.github.nstdio.http.ext.library-conventions.gradle.kts @@ -53,10 +53,8 @@ mapOf( configurations.getByName(t) { extendsFrom(configurations.getByName(u)) } } -val notModularConfigurations = - setOf("testRuntimeClasspath", "testCompileClasspath", "spiTestRuntimeClasspath", "spiTestCompileClasspath") configurations.names - .filter { notModularConfigurations.contains(it) } + .filter { !setOf("compileClasspath", "runtimeClasspath").contains(it) } .map { configurations.getByName(it) } .forEach { configure(listOf(it)) { diff --git a/buildSrc/src/main/kotlin/io.github.nstdio.http.ext.quality-conventions.gradle.kts b/buildSrc/src/main/kotlin/io.github.nstdio.http.ext.quality-conventions.gradle.kts index 5e73025..1f7e9e0 100644 --- a/buildSrc/src/main/kotlin/io.github.nstdio.http.ext.quality-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/io.github.nstdio.http.ext.quality-conventions.gradle.kts @@ -14,15 +14,11 @@ * limitations under the License. */ -import gradle.kotlin.dsl.accessors._d03f5c1f48338c7d05c8fd3014919501.jacoco - plugins { jacoco id("org.sonarqube") } - - sonarqube { properties { property("sonar.projectKey", "nstdio_http-client-ext") diff --git a/src/main/java/io/github/nstdio/http/ext/CachingInterceptor.java b/src/main/java/io/github/nstdio/http/ext/CachingInterceptor.java index 07a5ea6..14cecd3 100644 --- a/src/main/java/io/github/nstdio/http/ext/CachingInterceptor.java +++ b/src/main/java/io/github/nstdio/http/ext/CachingInterceptor.java @@ -22,7 +22,6 @@ import static io.github.nstdio.http.ext.Responses.gatewayTimeoutResponse; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.stream.Collectors.toList; -import static lombok.Lombok.sneakyThrow; import io.github.nstdio.http.ext.Cache.CacheEntry; import lombok.RequiredArgsConstructor; @@ -92,15 +91,7 @@ public Chain intercept(Chain in) { return sendAndCache(in, entry); } } else { - FutureHandler fn = (r, th) -> { - if (r != null) { - if (shouldInvalidate(r)) { - invalidate(r); - } - return r; - } - throw sneakyThrow(th); - }; + FutureHandler fn = FutureHandler.of(r -> shouldInvalidate(r) ? invalidate(r) : r); return Chain.of(ctx, in.futureHandler().andThen(fn)); } @@ -165,7 +156,7 @@ private BodyHandler cacheAware(RequestContext ctx) { }; } - private void invalidate(HttpResponse response) { + private HttpResponse invalidate(HttpResponse response) { List toEvict = Stream.of("Location", "Content-Location") .flatMap(s -> Headers.effectiveUri(response.headers(), s, response.uri()).stream()) .filter(uri -> response.uri().getHost().equals(uri.getHost())) @@ -174,6 +165,8 @@ private void invalidate(HttpResponse response) { toEvict.add(response.request()); toEvict.forEach(cache::evictAll); + + return response; } private boolean shouldInvalidate(HttpResponse response) { diff --git a/src/main/java/io/github/nstdio/http/ext/DiskCache.java b/src/main/java/io/github/nstdio/http/ext/DiskCache.java index 6a6b031..b704ec8 100644 --- a/src/main/java/io/github/nstdio/http/ext/DiskCache.java +++ b/src/main/java/io/github/nstdio/http/ext/DiskCache.java @@ -16,11 +16,12 @@ package io.github.nstdio.http.ext; +import static io.github.nstdio.http.ext.IOUtils.createFile; import static io.github.nstdio.http.ext.IOUtils.delete; import static io.github.nstdio.http.ext.IOUtils.size; import lombok.Getter; -import lombok.Value; +import lombok.RequiredArgsConstructor; import lombok.experimental.Accessors; import java.io.IOException; @@ -112,6 +113,10 @@ private EntryPaths pathsFor() { @SuppressWarnings("unchecked") public Writer writer(CacheEntryMetadata metadata) { EntryPaths entryPaths = pathsFor(); + if (!createFile(entryPaths.body())) { + return NullCache.writer(); + } + return new Writer<>() { @Override public BodySubscriber subscriber() { @@ -125,11 +130,12 @@ public Consumer finisher() { }; } - @Value(staticConstructor = "of") + @Getter @Accessors(fluent = true) + @RequiredArgsConstructor(staticName = "of") private static class EntryPaths { - Path body; - Path metadata; + private final Path body; + private final Path metadata; } @Getter diff --git a/src/main/java/io/github/nstdio/http/ext/FutureHandler.java b/src/main/java/io/github/nstdio/http/ext/FutureHandler.java index e24db15..004ffc7 100644 --- a/src/main/java/io/github/nstdio/http/ext/FutureHandler.java +++ b/src/main/java/io/github/nstdio/http/ext/FutureHandler.java @@ -42,12 +42,14 @@ static FutureHandler of(UnaryOperator> op) { default FutureHandler andThen(FutureHandler other) { return (r, th) -> { + HttpResponse result; try { - HttpResponse result = apply(r, th); - return other.apply(result, th); + result = apply(r, th); } catch (Exception e) { return other.apply(null, e); } + + return other.apply(result, th); }; } } diff --git a/src/main/java/io/github/nstdio/http/ext/IOUtils.java b/src/main/java/io/github/nstdio/http/ext/IOUtils.java index 035e224..44ef1f5 100644 --- a/src/main/java/io/github/nstdio/http/ext/IOUtils.java +++ b/src/main/java/io/github/nstdio/http/ext/IOUtils.java @@ -18,6 +18,7 @@ import java.io.Closeable; import java.io.IOException; +import java.nio.file.FileAlreadyExistsException; import java.nio.file.Files; import java.nio.file.Path; @@ -46,4 +47,15 @@ static long size(Path path) { return -1; } } + + static boolean createFile(Path path) { + try { + Files.createFile(path); + return true; + } catch (FileAlreadyExistsException e) { + return true; + } catch (IOException e) { + return false; + } + } } diff --git a/src/main/java/io/github/nstdio/http/ext/PathSubscriber.java b/src/main/java/io/github/nstdio/http/ext/PathSubscriber.java index 05c36ce..1cfc9f4 100644 --- a/src/main/java/io/github/nstdio/http/ext/PathSubscriber.java +++ b/src/main/java/io/github/nstdio/http/ext/PathSubscriber.java @@ -17,13 +17,14 @@ package io.github.nstdio.http.ext; import static io.github.nstdio.http.ext.IOUtils.closeQuietly; -import static java.nio.file.StandardOpenOption.CREATE; +import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; import static java.nio.file.StandardOpenOption.WRITE; import java.io.IOException; import java.net.http.HttpResponse; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; +import java.nio.channels.GatheringByteChannel; import java.nio.file.Path; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -34,7 +35,7 @@ class PathSubscriber implements HttpResponse.BodySubscriber { private static final ByteBuffer[] EMPTY = new ByteBuffer[0]; private final Path path; private final CompletableFuture future = new CompletableFuture<>(); - private volatile FileChannel out; + private GatheringByteChannel out; PathSubscriber(Path path) { this.path = path; @@ -56,7 +57,7 @@ private synchronized void createChannel() { } try { - out = FileChannel.open(path, CREATE, WRITE); + out = FileChannel.open(path, WRITE, TRUNCATE_EXISTING); } catch (IOException e) { future.completeExceptionally(e); } @@ -64,22 +65,21 @@ private synchronized void createChannel() { @Override public void onNext(List item) { - createChannel(); - try { out.write(item.toArray(EMPTY)); } catch (IOException ex) { - close(); - future.completeExceptionally(ex); + onError(ex); } } - private void close() { + private synchronized void close() { closeQuietly(out); + out = null; } @Override public void onError(Throwable throwable) { + close(); future.completeExceptionally(throwable); } diff --git a/src/main/java/io/github/nstdio/http/ext/RequestContext.java b/src/main/java/io/github/nstdio/http/ext/RequestContext.java index 0fab46b..e7a7090 100644 --- a/src/main/java/io/github/nstdio/http/ext/RequestContext.java +++ b/src/main/java/io/github/nstdio/http/ext/RequestContext.java @@ -18,7 +18,6 @@ import lombok.AllArgsConstructor; import lombok.Getter; -import lombok.With; import lombok.experimental.Accessors; import java.net.http.HttpRequest; @@ -29,9 +28,7 @@ @Accessors(fluent = true) @AllArgsConstructor final class RequestContext { - @With private final HttpRequest request; - @With private final BodyHandler bodyHandler; private final CacheControl cacheControl; private final AtomicLong requestTime = new AtomicLong(); @@ -59,4 +56,12 @@ long responseTimeLong() { BodyHandler bodyHandler() { return (BodyHandler) bodyHandler; } + + RequestContext withRequest(HttpRequest request) { + return new RequestContext(request, this.bodyHandler, this.cacheControl); + } + + RequestContext withBodyHandler(BodyHandler bodyHandler) { + return new RequestContext(this.request, bodyHandler, this.cacheControl); + } } diff --git a/src/test/java/io/github/nstdio/http/ext/BodyHandlersTest.java b/src/test/java/io/github/nstdio/http/ext/BodyHandlersTest.java new file mode 100644 index 0000000..f6fdaea --- /dev/null +++ b/src/test/java/io/github/nstdio/http/ext/BodyHandlersTest.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2022 Edgar Asatryan + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.github.nstdio.http.ext; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.fasterxml.jackson.core.type.TypeReference; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.Map; + +class BodyHandlersTest { + + @Nested + class OfJsonTest { + private final HttpClient client = HttpClient.newHttpClient(); + + @Test + void shouldProperlyReadJson() { + //given + var request = HttpRequest.newBuilder(URI.create("https://httpbin.org/get")).build(); + TypeReference> typeReference = new TypeReference<>() { + }; + + //when + var body1 = client.sendAsync(request, BodyHandlers.ofJson(typeReference)) + .thenApply(HttpResponse::body) + .join(); + var body2 = client.sendAsync(request, BodyHandlers.ofJson(Object.class)) + .thenApply(HttpResponse::body) + .join(); + + //then + assertThat(body1).isNotEmpty(); + assertThat(body2).isNotNull(); + } + } +} \ No newline at end of file diff --git a/src/test/java/io/github/nstdio/http/ext/CachingBodySubscriberTest.java b/src/test/java/io/github/nstdio/http/ext/CachingBodySubscriberTest.java index ba49f58..c91c864 100644 --- a/src/test/java/io/github/nstdio/http/ext/CachingBodySubscriberTest.java +++ b/src/test/java/io/github/nstdio/http/ext/CachingBodySubscriberTest.java @@ -16,6 +16,8 @@ package io.github.nstdio.http.ext; +import static java.nio.file.StandardOpenOption.CREATE; +import static java.nio.file.StandardOpenOption.WRITE; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.inOrder; @@ -25,9 +27,11 @@ import org.junit.jupiter.api.io.TempDir; import org.mockito.InOrder; +import java.io.IOException; import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodySubscriber; import java.nio.ByteBuffer; +import java.nio.file.Files; import java.nio.file.Path; import java.util.List; import java.util.function.Consumer; @@ -35,11 +39,29 @@ class CachingBodySubscriberTest { @Test - void shouldResetInputBuffers(@TempDir Path dir) { + void shouldWriteAndReadFromEmptyFile(@TempDir Path dir) throws IOException { //given Path p1 = dir.resolve("p1"); Path p2 = dir.resolve("p2"); + Files.createFile(p2); + assertThat(p2).isEmptyFile(); + assertShouldReadAndWriteResponse(p1, p2); + } + + @Test + void shouldWriteAndReadFromNotEmptyFile(@TempDir Path dir) throws IOException { + //given + Path p1 = dir.resolve("p1"); + Path p2 = dir.resolve("p2"); + Files.write(p2, "random-stuff".repeat(300).getBytes(), CREATE, WRITE); + + assertThat(p2).isNotEmptyFile(); + assertShouldReadAndWriteResponse(p1, p2); + } + + private void assertShouldReadAndWriteResponse(Path p1, Path p2) { + //given String body = Helpers.randomString(32, 128); var original = HttpResponse.BodySubscribers.ofFile(p1); var other = new PathSubscriber(p2); @@ -52,7 +74,7 @@ void shouldResetInputBuffers(@TempDir Path dir) { List buffers = Helpers.toBuffers(body); var subscription = new PlainSubscription(subscriber, buffers, false); subscriber.onSubscribe(subscription); - subscription.cancel(); + var actual1 = subscriber.getBody().toCompletableFuture().join(); var actual2 = other.getBody().toCompletableFuture().join(); diff --git a/src/test/java/io/github/nstdio/http/ext/ExtendedHttpClientContract.java b/src/test/java/io/github/nstdio/http/ext/ExtendedHttpClientContract.java index 59d27b6..f6b6b9d 100644 --- a/src/test/java/io/github/nstdio/http/ext/ExtendedHttpClientContract.java +++ b/src/test/java/io/github/nstdio/http/ext/ExtendedHttpClientContract.java @@ -297,7 +297,7 @@ default void shouldNotRespondWithCacheWhenNoCacheProvided(String cacheControl) t "no-store", "no-store, no-cache" }) - default void shouldNotCacheWhenNoStoreProvided(String cacheControl) throws IOException, InterruptedException { + default void shouldNotCacheWhenRequestNoStoreProvided(String cacheControl) throws IOException, InterruptedException { //given var urlPattern = urlEqualTo(path()); stubFor(get(urlPattern) @@ -329,6 +329,33 @@ default void shouldNotCacheWhenNoStoreProvided(String cacheControl) throws IOExc verify(1, getRequestedFor(urlPattern).withoutHeader(HEADER_CACHE_CONTROL)); } + @ParameterizedTest + @ValueSource(strings = { + "no-store", + "no-store, no-cache" + }) + default void shouldNotCacheWhenResponseNoStoreProvided(String cacheControl) throws IOException, InterruptedException { + //given + var urlPattern = urlEqualTo(path()); + stubFor(get(urlPattern) + .willReturn(ok() + .withHeader(HEADER_CACHE_CONTROL, cacheControl) + .withHeader("Content-Type", "text/plain") + .withBody("abc") + ) + ); + + var count = 5; + for (int i = 0; i < count; i++) { + + //when + then + var r1 = send(requestBuilder().build()); + assertThat(r1).isNotCached().hasBody("abc"); + } + + verify(count, getRequestedFor(urlPattern)); + } + @Test default void shouldCacheWhenHeadersDifferWithoutVary() throws IOException, InterruptedException { //given diff --git a/src/test/java/io/github/nstdio/http/ext/FutureHandlerTest.java b/src/test/java/io/github/nstdio/http/ext/FutureHandlerTest.java new file mode 100644 index 0000000..41a64fa --- /dev/null +++ b/src/test/java/io/github/nstdio/http/ext/FutureHandlerTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2022 Edgar Asatryan + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.github.nstdio.http.ext; + +import static org.assertj.core.api.Assertions.assertThatIOException; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.net.http.HttpResponse; +import java.util.function.UnaryOperator; + +class FutureHandlerTest { + + @Test + void shouldThrowIfThrowableNotNull() { + //given + UnaryOperator> op = UnaryOperator.identity(); + FutureHandler handler = FutureHandler.of(op); + + //when + then + assertThatIOException() + .isThrownBy(() -> handler.apply(null, new IOException())); + } + + @Test + void shouldProperlyChain() { + //given + FutureHandler> handler = (r, t) -> r; + FutureHandler> other = FutureHandler.of(UnaryOperator.identity()); + + //when + then + assertThatIOException() + .isThrownBy(() -> handler.andThen(other).apply(null, new IOException())); + } +} \ No newline at end of file diff --git a/src/test/java/io/github/nstdio/http/ext/IOUtilsTest.java b/src/test/java/io/github/nstdio/http/ext/IOUtilsTest.java new file mode 100644 index 0000000..7190e8c --- /dev/null +++ b/src/test/java/io/github/nstdio/http/ext/IOUtilsTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2022 Edgar Asatryan + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.github.nstdio.http.ext; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.Closeable; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +class IOUtilsTest { + + @Test + void shouldNotRethrowClosingException() { + //given + Closeable c = () -> { + throw new IOException(); + }; + + //when + then + IOUtils.closeQuietly(c); + } + + @Test + void shouldReturnNegativeWhenFileNotExists() { + //given + Path path = Path.of("abc"); + + //when + long size = IOUtils.size(path); + + //then + assertEquals(-1, size); + } + + @Test + void shouldReturnTrueIfFileExists(@TempDir Path temp) throws IOException { + //given + Path path = temp.resolve("abc"); + Files.createFile(path); + + //when + boolean created = IOUtils.createFile(path); + + //then + assertTrue(created); + } +} \ No newline at end of file diff --git a/src/test/java/io/github/nstdio/http/ext/JsonMetadataSerializerTest.java b/src/test/java/io/github/nstdio/http/ext/JsonMetadataSerializerTest.java index d6d2e52..03e7d2a 100644 --- a/src/test/java/io/github/nstdio/http/ext/JsonMetadataSerializerTest.java +++ b/src/test/java/io/github/nstdio/http/ext/JsonMetadataSerializerTest.java @@ -18,6 +18,7 @@ import static io.github.nstdio.http.ext.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertNull; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -27,11 +28,25 @@ import java.net.http.HttpRequest; import java.nio.file.Path; import java.time.Clock; +import java.time.Duration; class JsonMetadataSerializerTest { @TempDir private Path dir; + @Test + void shouldReturnNullWhenCannotRead() { + //given + var file = dir.resolve("abc"); + var ser = new JsonMetadataSerializer(); + + //when + CacheEntryMetadata metadata = ser.read(file); + + //then + assertNull(metadata); + } + @Test void shouldWriteAndRead() { //given @@ -50,6 +65,7 @@ void shouldWriteAndRead() { .header("abcd", "11") .header("abcd", "22") .version(HttpClient.Version.HTTP_2) + .timeout(Duration.ofSeconds(30)) .build(); var metadata = new CacheEntryMetadata(10, 15, responseInfo, request, Clock.systemUTC()); diff --git a/src/test/java/io/github/nstdio/http/ext/LruMultimapTest.java b/src/test/java/io/github/nstdio/http/ext/LruMultimapTest.java index f88f827..b916bf6 100644 --- a/src/test/java/io/github/nstdio/http/ext/LruMultimapTest.java +++ b/src/test/java/io/github/nstdio/http/ext/LruMultimapTest.java @@ -33,9 +33,6 @@ import java.util.function.ToIntFunction; class LruMultimapTest { - - private static final Consumer NOOP = s -> { - }; private static final ToIntFunction> ADD_FN = s -> -1; private static final ToIntFunction> THROWING_FN = s -> { throw new IllegalStateException("Should not be invoked!"); @@ -69,8 +66,7 @@ void shouldReplaceAndNotify() { @Test void shouldMaintainLruForLists() { //given - var map = new LruMultimap(512, s -> { - }); + var map = new LruMultimap(512, null); //when + then map.putSingle("a", "1", ADD_FN); @@ -87,7 +83,7 @@ void shouldMaintainLruForLists() { @Test void shouldNotEvictEldestWhenEmpty() { //given - var map = new LruMultimap(512, NOOP); + var map = new LruMultimap(512, null); //when + then for (int i = 0; i < 32; i++) { @@ -125,7 +121,8 @@ void shouldRemoveMapEntryWhenLastRemoved() { //given @SuppressWarnings("unchecked") Consumer mockEvictionListener = Mockito.mock(Consumer.class); - var map = new LruMultimap(512, mockEvictionListener); + var map = new LruMultimap(512, null); + map.addEvictionListener(mockEvictionListener); //when map.putSingle("a", "1", ADD_FN); @@ -209,7 +206,7 @@ void shouldClearWhenEmpty() { @Test void shouldNotGetWhenIndexIncorrect() { - var map = new LruMultimap(23, NOOP); + var map = new LruMultimap(23, null); //when map.putSingle("a", "2", ADD_FN); diff --git a/src/test/java/io/github/nstdio/http/ext/PathSubscriberTest.java b/src/test/java/io/github/nstdio/http/ext/PathSubscriberTest.java index 1120d3f..5d3ab23 100644 --- a/src/test/java/io/github/nstdio/http/ext/PathSubscriberTest.java +++ b/src/test/java/io/github/nstdio/http/ext/PathSubscriberTest.java @@ -22,6 +22,8 @@ import java.io.IOException; import java.nio.file.Path; +import java.util.List; +import java.util.concurrent.CompletionStage; class PathSubscriberTest { @@ -38,4 +40,18 @@ void shouldBeCompletedWhenOnError() { assertThat(subscriber.getBody()) .isCompletedExceptionally(); } + + @Test + void shouldCompleteExceptionallyWhenPathDoesNotExist() { + //given + PathSubscriber subscriber = new PathSubscriber(Path.of("abc")); + + //when + subscriber.onSubscribe(new PlainSubscription(subscriber, List.of(), false)); + CompletionStage body = subscriber.getBody(); + + //then + assertThat(body) + .isCompletedExceptionally(); + } } \ No newline at end of file diff --git a/src/test/java/io/github/nstdio/http/ext/PredicatesTest.java b/src/test/java/io/github/nstdio/http/ext/PredicatesTest.java new file mode 100644 index 0000000..de7cb8b --- /dev/null +++ b/src/test/java/io/github/nstdio/http/ext/PredicatesTest.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2022 Edgar Asatryan + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.github.nstdio.http.ext; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +import java.net.URI; +import java.net.http.HttpRequest; + +class PredicatesTest { + @Test + void shouldMatchGivenUri() { + //given + URI uri = URI.create("http://example.com"); + HttpRequest r1 = HttpRequest.newBuilder(uri).build(); + HttpRequest r2 = HttpRequest.newBuilder(uri.resolve("/path")).build(); + + //when + then + assertThat(Predicates.uri(uri)) + .accepts(r1) + .rejects(r2); + } +} \ No newline at end of file