@@ -2,34 +2,24 @@ package name.valery1707.problem
2
2
3
3
import name.valery1707.problem.LinkChecker.Companion.HTTP_DATE_FORMAT
4
4
import 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
5
9
import org.assertj.core.api.Assertions.assertThat
6
10
import org.assertj.core.api.Assertions.fail
7
11
import org.assertj.core.api.Assumptions.assumeThat
8
12
import org.junit.jupiter.api.Test
9
13
import org.junit.jupiter.params.ParameterizedTest
10
14
import org.junit.jupiter.params.provider.ValueSource
11
- import java.net.Authenticator
12
- import java.net.CookieHandler
13
15
import java.net.InetSocketAddress
14
16
import 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
20
17
import java.nio.file.Path
21
- import java.time.Duration
22
18
import java.time.Instant
23
19
import java.time.ZoneId
24
20
import 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
30
21
import kotlin.io.path.toPath
31
22
32
- typealias ResponseBuilder <T > = (HttpRequest ) -> HttpResponse <T >
33
23
typealias ResponseMeta = () -> Pair <Int , Map <String , String >>
34
24
35
25
internal class LinkCheckerTest {
@@ -42,10 +32,9 @@ internal class LinkCheckerTest {
42
32
)
43
33
internal fun checkReal (path : Path ) {
44
34
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)
49
38
.build()
50
39
val checker = LinkChecker (path)
51
40
assertThat(checker.findInvalid(client)).isEmpty()
@@ -67,18 +56,18 @@ internal class LinkCheckerTest {
67
56
}
68
57
69
58
// Check links via: curl --silent -X GET --head 'URL'
70
- val client = MockedHttpClient .fromMeta (
59
+ val client = mockHttpClient (
71
60
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 /" ),
74
63
),
75
- " https://ya. ru/" to listOf (
64
+ " https://habr.com/ ru/company/otus/blog/707724/comments/ " to mutableListOf (
76
65
ok(),
77
66
),
78
- " http://schema.org" to listOf (
67
+ " http://schema.org/ " to mutableListOf (
79
68
redirect(301 , " https://schema.org/" ),
80
69
),
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 (
82
71
// Will wait some time
83
72
rateLimitGH(2111 ),
84
73
// Will wait zero time
@@ -87,14 +76,14 @@ internal class LinkCheckerTest {
87
76
rateLimitGH(- 1500 ),
88
77
ok(),
89
78
),
90
- " https://www.bearer.com/" to listOf (
79
+ " https://www.bearer.com/" to mutableListOf (
91
80
// Use variant with "delay-seconds"
92
81
rateLimitSpecSec(1 ),
93
82
// Use variant with "http-date"
94
83
rateLimitSpecDate(100 ),
95
84
ok(),
96
85
),
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 (
98
87
notFound(),
99
88
),
100
89
),
@@ -104,7 +93,7 @@ internal class LinkCheckerTest {
104
93
105
94
assertThat(checker.findInvalid(client)).containsExactlyInAnyOrderEntriesOf(
106
95
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 /" ,
108
97
" Demo.md:3:14" to " http://schema.org -> 301 -> https://schema.org/" ,
109
98
" Demo.md:7:14" to " https://github.com/androidx/androidx/blob/androidx-main/buildSrc/public/src/main/kotlin/androidx/build/LibraryGroups.kt -> 404" ,
110
99
),
@@ -132,72 +121,24 @@ internal class LinkCheckerTest {
132
121
? : ProxySelector .getDefault()
133
122
}
134
123
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();
201
142
}
202
143
}
203
144
0 commit comments