22
33package com.trendyol.stove.testing.e2e.http
44
5- import arrow.core.None
6- import arrow.core.Option
7- import arrow.core.getOrElse
5+ import arrow.core.*
86import com.fasterxml.jackson.databind.ObjectMapper
97import com.trendyol.stove.testing.e2e.serialization.StoveObjectMapper
10- import com.trendyol.stove.testing.e2e.system.TestSystem
11- import com.trendyol.stove.testing.e2e.system.ValidationDsl
12- import com.trendyol.stove.testing.e2e.system.WithDsl
13- import com.trendyol.stove.testing.e2e.system.abstractions.PluggedSystem
14- import com.trendyol.stove.testing.e2e.system.abstractions.SystemNotRegisteredException
15- import com.trendyol.stove.testing.e2e.system.abstractions.SystemOptions
8+ import com.trendyol.stove.testing.e2e.system.*
9+ import com.trendyol.stove.testing.e2e.system.abstractions.*
1610import kotlinx.coroutines.future.await
17- import java.net.URI
18- import java.net.URLEncoder
19- import java.net.http.HttpClient
11+ import java.net.*
12+ import java.net.http.*
2013import java.net.http.HttpClient.Redirect.ALWAYS
2114import java.net.http.HttpClient.Version.HTTP_2
22- import java.net.http.HttpRequest
2315import java.net.http.HttpRequest.BodyPublishers
24- import java.net.http.HttpResponse
2516import java.net.http.HttpResponse.BodyHandlers
2617import java.time.Duration
2718import kotlin.reflect.KClass
@@ -50,142 +41,158 @@ class HttpSystem(
5041 @PublishedApi
5142 internal val httpClient: HttpClient = httpClient()
5243
53- @Suppress(" unused" )
5444 suspend fun getResponse (
5545 uri : String ,
5646 queryParams : Map <String , String > = mapOf(),
5747 headers : Map <String , String > = mapOf(),
5848 token : Option <String > = None ,
5949 expect : suspend (StoveHttpResponse ) -> Unit
60- ): HttpSystem =
61- httpClient.send(uri, headers = headers, queryParams = queryParams) { request ->
62- token.map { request.setHeader(Headers .AUTHORIZATION , Headers .bearer(it)) }
63- request
64- }.let {
65- expect(StoveHttpResponse (it.statusCode(), it.headers().map()))
66- this
67- }
68-
69- suspend fun postAndExpectBodilessResponse (
70- uri : String ,
71- body : Option <Any >,
72- token : Option <String > = None ,
73- headers : Map <String , String > = mapOf(),
74- expect : suspend (StoveHttpResponse ) -> Unit
75- ): HttpSystem =
76- httpClient.send(uri, headers = headers) { request ->
77- token.map { request.setHeader(Headers .AUTHORIZATION , Headers .bearer(it)) }
78- body.fold(
79- ifEmpty = { request.POST (BodyPublishers .noBody()) },
80- ifSome = { request.POST (BodyPublishers .ofString(objectMapper.writeValueAsString(it))) }
50+ ): HttpSystem = httpClient.send(uri, headers = headers, queryParams = queryParams) { request ->
51+ token.map { request.setHeader(Headers .AUTHORIZATION , Headers .bearer(it)) }
52+ request
53+ }.let {
54+ expect(
55+ StoveHttpResponse .Bodiless (
56+ it.statusCode(),
57+ it.headers().map()
8158 )
82- }.let {
83- expect(StoveHttpResponse (it.statusCode(), it.headers().map()))
84- this
85- }
59+ )
60+ this
61+ }
8662
87- suspend fun putAndExpectBodilessResponse (
63+ suspend inline fun < reified T : Any > getResponse (
8864 uri : String ,
89- body : Option <Any >,
90- token : Option <String > = None ,
65+ queryParams : Map <String , String > = mapOf(),
9166 headers : Map <String , String > = mapOf(),
92- expect : suspend (StoveHttpResponse ) -> Unit
93- ): HttpSystem =
94- httpClient.send(uri, headers = headers) { request ->
95- token.map { request.setHeader(Headers .AUTHORIZATION , Headers .bearer(it)) }
96- body.fold(
97- ifEmpty = { request.PUT (BodyPublishers .noBody()) },
98- ifSome = { request.PUT (BodyPublishers .ofString(objectMapper.writeValueAsString(it))) }
99- )
100- }.let {
101- expect(StoveHttpResponse (it.statusCode(), it.headers().map()))
102- this
103- }
104-
105- suspend fun deleteAndExpectBodilessResponse (
106- uri : String ,
10767 token : Option <String > = None ,
108- headers : Map <String , String > = mapOf(),
109- expect : suspend (StoveHttpResponse ) -> Unit
110- ): HttpSystem =
111- httpClient.send(uri, headers = headers) { request ->
112- token.map { request.setHeader(Headers .AUTHORIZATION , Headers .bearer(it)) }
113- request.DELETE ()
114- }.let {
115- expect(StoveHttpResponse (it.statusCode(), it.headers().map()))
116- this
117- }
68+ expect : (StoveHttpResponse .WithBody <T >) -> Unit
69+ ): HttpSystem = httpClient.send(uri, headers = headers, queryParams = queryParams) { request ->
70+ token.map { request.setHeader(Headers .AUTHORIZATION , Headers .bearer(it)) }
71+ request
72+ }.let {
73+ expect(
74+ StoveHttpResponse .WithBody (
75+ it.statusCode(),
76+ it.headers().map()
77+ ) { deserialize(it, T ::class ) }
78+ )
79+ this
80+ }
11881
11982 suspend inline fun <reified TExpected : Any > get (
12083 uri : String ,
12184 queryParams : Map <String , String > = mapOf(),
12285 headers : Map <String , String > = mapOf(),
12386 token : Option <String > = None ,
12487 expect : (TExpected ) -> Unit
125- ): HttpSystem =
126- httpClient.send(uri, headers = headers, queryParams = queryParams) { request ->
127- token.map { request.setHeader(Headers .AUTHORIZATION , Headers .bearer(it)) }
128- request.GET ()
129- }.let {
130- expect(deserialize(it, TExpected ::class ))
131- this
132- }
88+ ): HttpSystem = httpClient.send(uri, headers = headers, queryParams = queryParams) { request ->
89+ token.map { request.setHeader(Headers .AUTHORIZATION , Headers .bearer(it)) }
90+ request.GET ()
91+ }.let {
92+ expect(deserialize(it, TExpected ::class ))
93+ this
94+ }
13395
13496 suspend inline fun <reified TExpected : Any > getMany (
13597 uri : String ,
13698 queryParams : Map <String , String > = mapOf(),
13799 headers : Map <String , String > = mapOf(),
138100 token : Option <String > = None ,
139101 expect : (List <TExpected >) -> Unit
140- ): HttpSystem =
141- httpClient.send(uri, headers = headers, queryParams = queryParams) { request ->
142- token.map { request.setHeader(Headers .AUTHORIZATION , Headers .bearer(it)) }
143- request.GET ()
144- }.let {
145- expect(
146- objectMapper.readValue(
147- it.body(),
148- objectMapper.typeFactory.constructCollectionType(List ::class .java, TExpected ::class .javaObjectType)
149- )
102+ ): HttpSystem = httpClient.send(uri, headers = headers, queryParams = queryParams) { request ->
103+ token.map { request.setHeader(Headers .AUTHORIZATION , Headers .bearer(it)) }
104+ request.GET ()
105+ }.let {
106+ expect(
107+ objectMapper.readValue(
108+ it.body(),
109+ objectMapper.typeFactory.constructCollectionType(List ::class .java, TExpected ::class .javaObjectType)
150110 )
151- this
152- }
111+ )
112+ this
113+ }
114+
115+ suspend fun postAndExpectBodilessResponse (
116+ uri : String ,
117+ body : Option <Any >,
118+ token : Option <String > = None ,
119+ headers : Map <String , String > = mapOf(),
120+ expect : suspend (StoveHttpResponse ) -> Unit
121+ ): HttpSystem = doPostReq(uri, headers, token, body).let {
122+ expect(StoveHttpResponse .Bodiless (it.statusCode(), it.headers().map()))
123+ this
124+ }
153125
154126 suspend inline fun <reified TExpected : Any > postAndExpectJson (
155127 uri : String ,
156128 body : Option <Any > = None ,
157129 headers : Map <String , String > = mapOf(),
158130 token : Option <String > = None ,
159131 expect : (actual: TExpected ) -> Unit
160- ): HttpSystem =
161- httpClient.send(uri, headers = headers) { request ->
162- token.map { request.setHeader(Headers .AUTHORIZATION , Headers .bearer(it)) }
163- body.fold(
164- ifEmpty = { request.POST (BodyPublishers .noBody()) },
165- ifSome = { request.POST (BodyPublishers .ofString(objectMapper.writeValueAsString(it))) }
166- )
167- }.let {
168- expect(deserialize(it, TExpected ::class ))
169- this
170- }
132+ ): HttpSystem = doPostReq(uri, headers, token, body).let {
133+ expect(deserialize(it, TExpected ::class ))
134+ this
135+ }
136+
137+ /* *
138+ * Posts the given [body] to the given [uri] and expects the response to have a body.
139+ */
140+ suspend inline fun <reified TExpected : Any > postAndExpectBody (
141+ uri : String ,
142+ body : Option <Any > = None ,
143+ headers : Map <String , String > = mapOf(),
144+ token : Option <String > = None ,
145+ expect : (actual: StoveHttpResponse .WithBody <TExpected >) -> Unit
146+ ): HttpSystem = doPostReq(uri, headers, token, body).let {
147+ expect(StoveHttpResponse .WithBody (it.statusCode(), it.headers().map()) { deserialize(it, TExpected ::class ) })
148+ this
149+ }
150+
151+ suspend fun putAndExpectBodilessResponse (
152+ uri : String ,
153+ body : Option <Any >,
154+ token : Option <String > = None ,
155+ headers : Map <String , String > = mapOf(),
156+ expect : suspend (StoveHttpResponse ) -> Unit
157+ ): HttpSystem = doPUTReq(uri, headers, token, body).let {
158+ expect(StoveHttpResponse .Bodiless (it.statusCode(), it.headers().map()))
159+ this
160+ }
171161
172162 suspend inline fun <reified TExpected : Any > putAndExpectJson (
173163 uri : String ,
174164 body : Option <Any > = None ,
175165 headers : Map <String , String > = mapOf(),
176166 token : Option <String > = None ,
177167 expect : (actual: TExpected ) -> Unit
178- ): HttpSystem =
179- httpClient.send(uri, headers = headers) { request ->
180- token.map { request.setHeader(Headers .AUTHORIZATION , Headers .bearer(it)) }
181- body.fold(
182- ifEmpty = { request.PUT (BodyPublishers .noBody()) },
183- ifSome = { request.PUT (BodyPublishers .ofString(objectMapper.writeValueAsString(it))) }
184- )
185- }.let {
186- expect(deserialize(it, TExpected ::class ))
187- this
188- }
168+ ): HttpSystem = doPUTReq(uri, headers, token, body).let {
169+ expect(deserialize(it, TExpected ::class ))
170+ this
171+ }
172+
173+ suspend inline fun <reified TExpected : Any > putAndExpectBody (
174+ uri : String ,
175+ body : Option <Any > = None ,
176+ headers : Map <String , String > = mapOf(),
177+ token : Option <String > = None ,
178+ expect : (actual: StoveHttpResponse .WithBody <TExpected >) -> Unit
179+ ): HttpSystem = doPUTReq(uri, headers, token, body).let {
180+ expect(StoveHttpResponse .WithBody (it.statusCode(), it.headers().map()) { deserialize(it, TExpected ::class ) })
181+ this
182+ }
183+
184+ suspend fun deleteAndExpectBodilessResponse (
185+ uri : String ,
186+ token : Option <String > = None ,
187+ headers : Map <String , String > = mapOf(),
188+ expect : suspend (StoveHttpResponse ) -> Unit
189+ ): HttpSystem = httpClient.send(uri, headers = headers) { request ->
190+ token.map { request.setHeader(Headers .AUTHORIZATION , Headers .bearer(it)) }
191+ request.DELETE ()
192+ }.let {
193+ expect(StoveHttpResponse .Bodiless (it.statusCode(), it.headers().map()))
194+ this
195+ }
189196
190197 override fun then (): TestSystem = testSystem
191198
@@ -196,32 +203,58 @@ class HttpSystem(
196203 queryParams : Map <String , String > = mapOf(),
197204 configureRequest : (request: HttpRequest .Builder ) -> HttpRequest .Builder
198205 ): HttpResponse <ByteArray > {
199- val requestBuilder =
200- HttpRequest .newBuilder()
201- .uri(relative(uri, queryParams))
202- .addHeaders(headers)
206+ val requestBuilder = HttpRequest .newBuilder()
207+ .uri(relative(uri, queryParams))
208+ .addHeaders(headers)
203209 return sendAsync(configureRequest(requestBuilder).build(), BodyHandlers .ofByteArray()).await()
204210 }
205211
206- private fun HttpRequest.Builder.addHeaders (headers : Map <String , String >): HttpRequest .Builder =
207- headers
208- .toMutableMap()
209- .apply { this [Headers .CONTENT_TYPE ] = MediaType .APPLICATION_JSON }
210- .forEach { (key, value) -> setHeader(key, value) }
211- .let { this }
212+ @PublishedApi
213+ internal suspend fun doPUTReq (
214+ uri : String ,
215+ headers : Map <String , String >,
216+ token : Option <String >,
217+ body : Option <Any >
218+ ): HttpResponse <ByteArray > = httpClient.send(uri, headers = headers) { request ->
219+ token.map { request.setHeader(Headers .AUTHORIZATION , Headers .bearer(it)) }
220+ body.fold(
221+ ifEmpty = { request.PUT (BodyPublishers .noBody()) },
222+ ifSome = { request.PUT (BodyPublishers .ofString(objectMapper.writeValueAsString(it))) }
223+ )
224+ }
225+
226+ @PublishedApi
227+ internal suspend fun doPostReq (
228+ uri : String ,
229+ headers : Map <String , String >,
230+ token : Option <String >,
231+ body : Option <Any >
232+ ): HttpResponse <ByteArray > = httpClient.send(uri, headers = headers) { request ->
233+ token.map { request.setHeader(Headers .AUTHORIZATION , Headers .bearer(it)) }
234+ body.fold(
235+ ifEmpty = { request.POST (BodyPublishers .noBody()) },
236+ ifSome = { request.POST (BodyPublishers .ofString(objectMapper.writeValueAsString(it))) }
237+ )
238+ }
239+
240+ private fun HttpRequest.Builder.addHeaders (
241+ headers : Map <String , String >
242+ ): HttpRequest .Builder = headers
243+ .toMutableMap()
244+ .apply { this [Headers .CONTENT_TYPE ] = MediaType .APPLICATION_JSON }
245+ .forEach { (key, value) -> setHeader(key, value) }
246+ .let { this }
212247
213248 private fun relative (
214249 uri : String ,
215250 queryParams : Map <String , String > = mapOf()
216- ): URI =
217- URI .create(testSystem.baseUrl)
218- .resolve(uri + queryParams.toParamsString())
219-
220- private fun Map <String , String >.toParamsString (): String =
221- when {
222- this .any() -> " ?${this .map { " ${it.key} =${URLEncoder .encode(it.value, Charsets .UTF_8 )} " }.joinToString(" &" )} "
223- else -> " "
224- }
251+ ): URI = URI .create(testSystem.baseUrl)
252+ .resolve(uri + queryParams.toParamsString())
253+
254+ private fun Map <String , String >.toParamsString (): String = when {
255+ this .any() -> " ?${this .map { " ${it.key} =${URLEncoder .encode(it.value, Charsets .UTF_8 )} " }.joinToString(" &" )} "
256+ else -> " "
257+ }
225258
226259 private fun httpClient (): HttpClient {
227260 val builder = HttpClient .newBuilder()
@@ -235,11 +268,10 @@ class HttpSystem(
235268 internal fun <TExpected : Any > deserialize (
236269 it : HttpResponse <ByteArray >,
237270 clazz : KClass <TExpected >
238- ): TExpected =
239- when {
240- clazz.java.isAssignableFrom(String ::class .java) -> String (it.body()) as TExpected
241- else -> objectMapper.readValue(it.body(), clazz.java)
242- }
271+ ): TExpected = when {
272+ clazz.java.isAssignableFrom(String ::class .java) -> String (it.body()) as TExpected
273+ else -> objectMapper.readValue(it.body(), clazz.java)
274+ }
243275
244276 override fun close () {}
245277
0 commit comments