@@ -2,34 +2,24 @@ package name.valery1707.problem
22
33import name.valery1707.problem.LinkChecker.Companion.HTTP_DATE_FORMAT
44import name.valery1707.problem.LinkChecker.Companion.toURI
5+ import okhttp3.Headers.Companion.toHeaders
6+ import okhttp3.OkHttpClient
7+ import okhttp3.mock.MockInterceptor
8+ import okhttp3.mock.body
59import org.assertj.core.api.Assertions.assertThat
610import org.assertj.core.api.Assertions.fail
711import org.assertj.core.api.Assumptions.assumeThat
812import org.junit.jupiter.api.Test
913import org.junit.jupiter.params.ParameterizedTest
1014import org.junit.jupiter.params.provider.ValueSource
11- import java.net.Authenticator
12- import java.net.CookieHandler
1315import java.net.InetSocketAddress
1416import java.net.ProxySelector
15- import java.net.URI
16- import java.net.http.HttpClient
17- import java.net.http.HttpHeaders
18- import java.net.http.HttpRequest
19- import java.net.http.HttpResponse
2017import java.nio.file.Path
21- import java.time.Duration
2218import java.time.Instant
2319import java.time.ZoneId
2420import java.util.*
25- import java.util.concurrent.CompletableFuture
26- import java.util.concurrent.Executor
27- import javax.net.ssl.SSLContext
28- import javax.net.ssl.SSLParameters
29- import javax.net.ssl.SSLSession
3021import kotlin.io.path.toPath
3122
32- typealias ResponseBuilder <T > = (HttpRequest ) -> HttpResponse <T >
3323typealias ResponseMeta = () -> Pair <Int , Map <String , String >>
3424
3525internal class LinkCheckerTest {
@@ -42,10 +32,9 @@ internal class LinkCheckerTest {
4232 )
4333 internal fun checkReal (path : Path ) {
4434 assumeThat(path).isDirectory.isReadable
45- val client = HttpClient
46- .newBuilder()
47- .followRedirects(HttpClient .Redirect .NEVER )
48- .proxy(proxy)
35+ val client = OkHttpClient .Builder ()
36+ .followRedirects(false ).followSslRedirects(false )
37+ .proxySelector(proxy)
4938 .build()
5039 val checker = LinkChecker (path)
5140 assertThat(checker.findInvalid(client)).isEmpty()
@@ -67,18 +56,18 @@ internal class LinkCheckerTest {
6756 }
6857
6958 // Check links via: curl --silent -X GET --head 'URL'
70- val client = MockedHttpClient .fromMeta (
59+ val client = mockHttpClient (
7160 mapOf (
72- " https://ya.ru " to listOf (
73- redirect(302 , " https://ya.ru /" ),
61+ " https://habr.com/ru/company/otus/blog/707724/comments " to mutableListOf (
62+ redirect(302 , " https://habr.com/ru/company/otus/blog/707724/comments /" ),
7463 ),
75- " https://ya. ru/" to listOf (
64+ " https://habr.com/ ru/company/otus/blog/707724/comments/ " to mutableListOf (
7665 ok(),
7766 ),
78- " http://schema.org" to listOf (
67+ " http://schema.org/ " to mutableListOf (
7968 redirect(301 , " https://schema.org/" ),
8069 ),
81- " https://github.com/androidx/androidx/blob/androidx-main/build.gradle" to listOf (
70+ " https://github.com/androidx/androidx/blob/androidx-main/build.gradle" to mutableListOf (
8271 // Will wait some time
8372 rateLimitGH(2111 ),
8473 // Will wait zero time
@@ -87,14 +76,14 @@ internal class LinkCheckerTest {
8776 rateLimitGH(- 1500 ),
8877 ok(),
8978 ),
90- " https://www.bearer.com/" to listOf (
79+ " https://www.bearer.com/" to mutableListOf (
9180 // Use variant with "delay-seconds"
9281 rateLimitSpecSec(1 ),
9382 // Use variant with "http-date"
9483 rateLimitSpecDate(100 ),
9584 ok(),
9685 ),
97- " https://github.com/androidx/androidx/blob/androidx-main/buildSrc/public/src/main/kotlin/androidx/build/LibraryGroups.kt" to listOf (
86+ " https://github.com/androidx/androidx/blob/androidx-main/buildSrc/public/src/main/kotlin/androidx/build/LibraryGroups.kt" to mutableListOf (
9887 notFound(),
9988 ),
10089 ),
@@ -104,7 +93,7 @@ internal class LinkCheckerTest {
10493
10594 assertThat(checker.findInvalid(client)).containsExactlyInAnyOrderEntriesOf(
10695 mapOf (
107- " Demo.md:1:25" to " https://ya.ru -> 302 -> https://ya.ru /" ,
96+ " Demo.md:1:25" to " https://habr.com/ru/company/otus/blog/707724/comments -> 302 -> https://habr.com/ru/company/otus/blog/707724/comments /" ,
10897 " Demo.md:3:14" to " http://schema.org -> 301 -> https://schema.org/" ,
10998 " Demo.md:7:14" to " https://github.com/androidx/androidx/blob/androidx-main/buildSrc/public/src/main/kotlin/androidx/build/LibraryGroups.kt -> 404" ,
11099 ),
@@ -132,72 +121,24 @@ internal class LinkCheckerTest {
132121 ? : ProxySelector .getDefault()
133122 }
134123
135- private class MockedHttpClient (
136- private val worker : ResponseBuilder <Any ?>,
137- ) : HttpClient() {
138- override fun cookieHandler (): Optional <CookieHandler > = Optional .empty()
139- override fun connectTimeout (): Optional <Duration > = Optional .empty()
140- override fun followRedirects (): Redirect = Redirect .NEVER
141- override fun proxy (): Optional <ProxySelector > = Optional .empty()
142- override fun sslContext (): SSLContext = SSLContext .getDefault()
143- override fun sslParameters (): SSLParameters = sslContext().defaultSSLParameters
144- override fun authenticator (): Optional <Authenticator > = Optional .empty()
145- override fun version (): Version = Version .HTTP_1_1
146- override fun executor (): Optional <Executor > = Optional .empty()
147-
148- override fun <T : Any ?> sendAsync (
149- request : HttpRequest ,
150- responseBodyHandler : HttpResponse .BodyHandler <T >,
151- pushPromiseHandler : HttpResponse .PushPromiseHandler <T >? ,
152- ): CompletableFuture <HttpResponse <T >> = sendAsync(request, responseBodyHandler)
153-
154- override fun <T : Any ?> sendAsync (
155- request : HttpRequest ,
156- responseBodyHandler : HttpResponse .BodyHandler <T >,
157- ): CompletableFuture <HttpResponse <T >> = CompletableFuture .supplyAsync { send(request, responseBodyHandler) }
158-
159- @Suppress(" UNCHECKED_CAST" )
160- override fun <T : Any ?> send (request : HttpRequest , responseBodyHandler : HttpResponse .BodyHandler <T >): HttpResponse <T > =
161- worker(request) as HttpResponse <T >
162-
163- companion object {
164- fun fromMeta (responses : Map <String , List <ResponseMeta >>): HttpClient = fromBuilders(
165- responses.mapValues {
166- it.value
167- .map<ResponseMeta , ResponseBuilder <Any ?>> { metaBuilder ->
168- { req ->
169- val meta = metaBuilder()
170- MockedHttpResponse .fromRequest(req, meta.first, meta.second.mapValues { h -> listOf (h.value) })
171- }
172- }
173- .toMutableList()
174- },
175- )
176-
177- fun fromBuilders (responses : Map <String , MutableList <ResponseBuilder <Any ?>>>): HttpClient = MockedHttpClient { req ->
178- responses[req.uri().toString()]?.removeFirst()?.invoke(req) ? : fail(" Unknown response builders for ${req.uri()} " )
179- }
180- }
181- }
182-
183- private class MockedHttpResponse <T : Any ?>(
184- private val request : HttpRequest ,
185- private val statusCode : Int ,
186- private val headers : HttpHeaders ,
187- ) : HttpResponse<T> {
188- override fun statusCode (): Int = statusCode
189- override fun request (): HttpRequest = request
190- override fun previousResponse (): Optional <HttpResponse <T >> = Optional .empty()
191- override fun headers (): HttpHeaders = headers
192- override fun body (): T ? = null
193- override fun sslSession (): Optional <SSLSession > = Optional .empty()
194- override fun uri (): URI = request().uri()
195- override fun version (): HttpClient .Version = request().version().orElse(HttpClient .Version .HTTP_1_1 )
196-
197- companion object {
198- fun <T : Any ?> fromRequest (request : HttpRequest , statusCode : Int , headers : Map <String , List <String >>): HttpResponse <T > = MockedHttpResponse (
199- request, statusCode, HttpHeaders .of(headers) { _, _ -> true },
200- )
124+ private companion object {
125+ fun mockHttpClient (responses : Map <String , MutableList <ResponseMeta >>): OkHttpClient {
126+ val interceptor = MockInterceptor ()
127+
128+ interceptor.addRule()
129+ .anyTimes()
130+ .answer { req ->
131+ val uri = req.url.toUri()
132+ val meta = ((responses[uri.toString()] ? : fail(" Unknown URI: $uri " )).removeFirstOrNull() ? : fail(" Too many requests for URI: $uri " ))()
133+ okhttp3.Response .Builder ()
134+ .code(meta.first)
135+ .headers(meta.second.toHeaders())
136+ .body(" " )
137+ }
138+
139+ return OkHttpClient .Builder ()
140+ .addInterceptor(interceptor)
141+ .build();
201142 }
202143 }
203144
0 commit comments