-
-
Notifications
You must be signed in to change notification settings - Fork 99
/
FiltersTest.kt
139 lines (120 loc) · 4.92 KB
/
FiltersTest.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package com.hexagonkt.http.test.examples
import com.hexagonkt.core.text.decodeBase64
import com.hexagonkt.http.basicAuth
import com.hexagonkt.http.client.HttpClient
import com.hexagonkt.http.client.HttpClientPort
import com.hexagonkt.http.client.HttpClientSettings
import com.hexagonkt.http.model.FORBIDDEN_403
import com.hexagonkt.http.model.UNAUTHORIZED_401
import com.hexagonkt.http.model.Header
import com.hexagonkt.http.model.HttpMethod.PUT
import com.hexagonkt.http.model.*
import com.hexagonkt.http.server.HttpServerPort
import com.hexagonkt.http.server.HttpServerSettings
import com.hexagonkt.http.handlers.PathHandler
import com.hexagonkt.http.handlers.HttpHandler
import com.hexagonkt.http.handlers.path
import com.hexagonkt.http.test.BaseTest
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
@Suppress("FunctionName") // This class's functions are intended to be used only in tests
abstract class FiltersTest(
final override val clientAdapter: () -> HttpClientPort,
final override val serverAdapter: () -> HttpServerPort,
final override val serverSettings: HttpServerSettings = HttpServerSettings(),
) : BaseTest() {
// filters
private val users: Map<String, String> = mapOf(
"Turing" to "London",
"Dijkstra" to "Rotterdam"
)
private val path: PathHandler = path {
filter("*") {
val start = System.nanoTime()
// Call next and store result to chain it
val next = next()
val time = (System.nanoTime() - start).toString()
// Copies result from chain with the extra data
next.send(headers = response.headers + Header("time", time))
}
filter("/protected/*") {
val authorization = request.authorization ?: return@filter unauthorized("Unauthorized")
val credentials = authorization.value
val userPassword = String(credentials.decodeBase64()).split(":")
// Parameters set in call attributes are accessible in other filters and routes
send(attributes = attributes
+ ("username" to userPassword[0])
+ ("password" to userPassword[1])
).next()
}
// All matching filters are run in order unless call is halted
filter("/protected/*") {
if(users[attributes["username"]] != attributes["password"])
send(FORBIDDEN_403, "Forbidden")
else
next()
}
get("/protected/hi") {
ok("Hello ${attributes["username"]}!")
}
path("/after") {
after(PUT) {
send(ALREADY_REPORTED_208)
}
after(PUT, "/second") {
send(NO_CONTENT_204)
}
after("/second") {
send(CREATED_201)
}
after {
send(ACCEPTED_202)
}
}
}
// filters
override val handler: HttpHandler = path
@Test fun `After handlers can be chained`() {
assertEquals(ACCEPTED_202, client.get("/after").status)
assertEquals(CREATED_201, client.get("/after/second").status)
assertEquals(NO_CONTENT_204, client.put("/after/second").status)
assertEquals(ALREADY_REPORTED_208, client.put("/after").status)
}
@Test fun `Request without authorization returns 401`() {
val response = client.get("/protected/hi")
val time = response.headers["time"]?.string()?.toLong() ?: 0
assertResponseEquals(response, UNAUTHORIZED_401, "Unauthorized")
assert(time > 0)
}
@Test fun `HTTP request with valid credentials returns valid response`() {
authorizedClient("Turing", "London").use {
val response = it.get("/protected/hi")
val time = response.headers["time"]?.string()?.toLong() ?: 0
assertResponseEquals(response, OK_200, "Hello Turing!")
assert(time > 0)
}
}
@Test fun `Request with invalid password returns 403`() {
authorizedClient("Turing", "Millis").use {
val response = it.get("/protected/hi")
val time = response.headers["time"]?.string()?.toLong() ?: 0
assertResponseEquals(response, FORBIDDEN_403, "Forbidden")
assert(time > 0)
}
}
@Test fun `Request with invalid user returns 403`() {
authorizedClient("Curry", "Millis").use {
val response = it.get("/protected/hi")
val time = response.headers["time"]?.string()?.toLong() ?: 0
assertResponseEquals(response, FORBIDDEN_403, "Forbidden")
assert(time > 0)
}
}
private fun authorizedClient(user: String, password: String): HttpClient {
val settings = HttpClientSettings(
baseUrl = server.binding,
authorization = Authorization("basic", basicAuth(user, password))
)
return HttpClient(clientAdapter(), settings).apply { start() }
}
}