Skip to content

Commit 04b4905

Browse files
author
Robert Winkler
committed
Deleted old files
1 parent 3d47367 commit 04b4905

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+2273
-1365
lines changed

kotlin-wot-binding-http/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@ dependencies {
2020
//implementation("io.insert-koin:koin-ktor:4.0.0")
2121
testImplementation("io.ktor:ktor-server-test-host")
2222
testImplementation("ch.qos.logback:logback-classic:1.5.12")
23+
testImplementation("com.marcinziolo:kotlin-wiremock:2.1.1")
2324
}

kotlin-wot-binding-http/src/main/kotlin/http/HttpProtocolClient.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class HttpProtocolClient(
4242
return resolveRequestToContent(form, HttpMethod.Post, content)
4343
}
4444

45-
override suspend fun observeResource(form: Form) = flow {
45+
override suspend fun subscribeResource(form: Form) = flow {
4646
// Long-polling logic using Ktor client
4747
while (true) {
4848
try {

kotlin-wot-binding-http/src/main/kotlin/http/HttpProtocolServer.kt

Lines changed: 84 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import ai.ancf.lmos.wot.thing.ExposedThing
88
import ai.ancf.lmos.wot.thing.ThingDescription
99
import ai.ancf.lmos.wot.thing.form.Form
1010
import ai.ancf.lmos.wot.thing.form.Operation
11+
import ai.ancf.lmos.wot.thing.schema.ContentListener
12+
import ai.ancf.lmos.wot.thing.schema.DataSchemaValue
1113
import ai.ancf.lmos.wot.thing.schema.InteractionAffordance
1214
import ai.ancf.lmos.wot.thing.schema.WoTExposedThing
1315
import ai.anfc.lmos.wot.binding.ProtocolServer
@@ -219,31 +221,77 @@ fun Application.setupRouting(servient: Servient) {
219221
call.response.status(HttpStatusCode.NotFound)
220222
}
221223
}
224+
route("/properties") {
225+
get {
226+
val id = call.parameters["id"] ?: return@get call.response.status(HttpStatusCode.BadRequest)
227+
val thing = servient.things[id] ?: return@get call.response.status(HttpStatusCode.NotFound)
228+
val properties : Map<String, Content> = thing.handleReadAllProperties()
229+
val response: MutableMap<String, Any?> = mutableMapOf()
230+
for ((key, value) in properties) {
231+
// Assuming content is not null as it's checked earlier
232+
when (val schemaValue: DataSchemaValue = ContentManager.contentToValue(value, null)) {
233+
is DataSchemaValue.BooleanValue -> {
234+
response[key] = schemaValue.value
235+
}
236+
is DataSchemaValue.IntegerValue -> {
237+
response[key] = schemaValue.value
238+
}
239+
is DataSchemaValue.NumberValue -> {
240+
response[key] = schemaValue.value
241+
}
242+
is DataSchemaValue.StringValue -> {
243+
response[key] = schemaValue.value
244+
}
245+
is DataSchemaValue.ObjectValue -> {
246+
response[key] = schemaValue.value
247+
}
248+
is DataSchemaValue.ArrayValue -> {
249+
response[key] = schemaValue.value
250+
}
251+
is DataSchemaValue.NullValue -> {
252+
response[key] = null
253+
}
254+
}
255+
}
256+
call.respond(response)
257+
}
258+
}
222259
route("/properties/{name}") {
223-
/*
224260
get("/observable") {
225-
call.respond("Observing property", typeInfo<String>())
261+
val id = call.parameters["id"] ?: return@get call.response.status(HttpStatusCode.BadRequest)
262+
val propertyName = call.parameters["name"] ?: return@get call.response.status(HttpStatusCode.BadRequest)
263+
val thing = servient.things[id] ?: return@get call.response.status(HttpStatusCode.NotFound)
264+
val property = thing.properties[propertyName] ?: return@get call.response.status(HttpStatusCode.NotFound)
265+
val contentListener = ContentListener { content: Content ->
266+
call.respondBytes { content.body }
267+
}
268+
thing.handleObserveProperty(propertyName, contentListener)
269+
}
270+
delete("/observable") {
271+
val id = call.parameters["id"] ?: return@delete call.response.status(HttpStatusCode.BadRequest)
272+
val propertyName = call.parameters["name"] ?: return@delete call.response.status(HttpStatusCode.BadRequest)
273+
val thing = servient.things[id] ?: return@delete call.response.status(HttpStatusCode.NotFound)
274+
val property = thing.properties[propertyName] ?: return@delete call.response.status(HttpStatusCode.NotFound)
275+
val contentListener = ContentListener { content: Content ->
276+
call.respondBytes { content.body }
277+
}
278+
thing.handleUnobserveProperty(propertyName, contentListener)
226279
}
227-
*/
228280
get {
229281
val id = call.parameters["id"] ?: return@get call.response.status(HttpStatusCode.BadRequest)
230282
val propertyName = call.parameters["name"] ?: return@get call.response.status(HttpStatusCode.BadRequest)
231283
val thing = servient.things[id] ?: return@get call.response.status(HttpStatusCode.NotFound)
232-
val property = thing.properties[propertyName]
233-
if (property != null) {
234-
if (!property.writeOnly) {
235-
try {
236-
val content = thing.handleReadProperty(propertyName)
237-
call.respondBytes { content.body }
238-
}
239-
catch (e: ContentCodecException) {
240-
call.response.status(HttpStatusCode.InternalServerError)
241-
}
242-
} else {
243-
call.response.status(HttpStatusCode.BadRequest)
284+
val property = thing.properties[propertyName] ?: return@get call.response.status(HttpStatusCode.NotFound)
285+
if (!property.writeOnly) {
286+
try {
287+
val content = thing.handleReadProperty(propertyName)
288+
call.respondBytes { content.body }
289+
}
290+
catch (e: ContentCodecException) {
291+
call.response.status(HttpStatusCode.InternalServerError)
244292
}
245293
} else {
246-
call.response.status(HttpStatusCode.NotFound)
294+
call.response.status(HttpStatusCode.BadRequest)
247295
}
248296
}
249297
put {
@@ -271,7 +319,7 @@ fun Application.setupRouting(servient: Servient) {
271319
call.response.status(HttpStatusCode.BadRequest)
272320
}else{
273321
val actionResult = thing.handleInvokeAction(actionName, content)
274-
if(actionResult != null && actionResult.body.isNotEmpty()) {
322+
if(actionResult.body.isNotEmpty()) {
275323
call.respondBytes { actionResult.body }
276324
} else{
277325
call.response.status(HttpStatusCode.NoContent)
@@ -280,6 +328,25 @@ fun Application.setupRouting(servient: Servient) {
280328

281329
}
282330
get("/events/{name}") {
331+
val id = call.parameters["id"] ?: return@get call.response.status(HttpStatusCode.BadRequest)
332+
val eventName = call.parameters["name"] ?: return@get call.response.status(HttpStatusCode.BadRequest)
333+
val thing = servient.things[id] ?: return@get call.response.status(HttpStatusCode.NotFound)
334+
val event = thing.events[eventName] ?: return@get call.response.status(HttpStatusCode.NotFound)
335+
val contentListener = ContentListener { content: Content ->
336+
call.respondBytes { content.body }
337+
}
338+
thing.handleSubscribeEvent(eventName, contentListener)
339+
call.response.status(HttpStatusCode.OK)
340+
}
341+
delete("/events/{name}") {
342+
val id = call.parameters["id"] ?: return@delete call.response.status(HttpStatusCode.BadRequest)
343+
val eventName = call.parameters["name"] ?: return@delete call.response.status(HttpStatusCode.BadRequest)
344+
val thing = servient.things[id] ?: return@delete call.response.status(HttpStatusCode.NotFound)
345+
val event = thing.events[eventName] ?: return@delete call.response.status(HttpStatusCode.NotFound)
346+
val contentListener = ContentListener { content: Content ->
347+
call.respondBytes { content.body }
348+
}
349+
thing.handleUnsubscribeEvent(eventName, contentListener)
283350
call.response.status(HttpStatusCode.OK)
284351
}
285352
}
Lines changed: 148 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,175 @@
11
package ai.ancf.lmos.wot.binding.http
2+
import ai.ancf.lmos.wot.content.Content
3+
import ai.ancf.lmos.wot.security.BasicSecurityScheme
4+
import ai.ancf.lmos.wot.security.BearerSecurityScheme
5+
import ai.ancf.lmos.wot.security.NoSecurityScheme
26
import ai.ancf.lmos.wot.security.SecurityScheme
37
import ai.ancf.lmos.wot.thing.form.Form
4-
import io.ktor.client.*
5-
import io.ktor.client.request.*
6-
import io.ktor.client.statement.*
7-
import io.mockk.coEvery
8+
import ai.anfc.lmos.wot.binding.ProtocolClientException
9+
import com.github.tomakehurst.wiremock.WireMockServer
10+
import com.marcinziolo.kotlin.wiremock.*
811
import io.mockk.every
912
import io.mockk.mockk
1013
import kotlinx.coroutines.test.runTest
11-
import org.apache.http.StatusLine
14+
import org.junit.jupiter.api.AfterEach
1215
import kotlin.test.BeforeTest
1316
import kotlin.test.Test
17+
import kotlin.test.assertFailsWith
1418

1519
class HttpProtocolClientTest {
1620

1721
private lateinit var form: Form
18-
private lateinit var statusLine: StatusLine
1922
private lateinit var securityScheme: SecurityScheme
20-
private lateinit var httpClient: HttpClient
2123

24+
private val wiremock: WireMockServer = WireMockServer(8080)
2225

2326
@BeforeTest
2427
fun setUp() {
28+
wiremock.start()
2529
form = mockk()
26-
statusLine = mockk()
2730
securityScheme = mockk()
28-
httpClient = mockk()
2931
}
3032

31-
@Test
32-
fun `readResource should create proper request`(): Unit = runTest {
33-
every { form.href ?: "" } returns "http://localhost/foo"
34-
every { statusLine.statusCode } returns 200 // HTTP Status OK
33+
@AfterEach
34+
fun afterEach() {
35+
wiremock.resetAll()
36+
wiremock.stop()
37+
}
3538

36-
val response : HttpResponse = mockk()
39+
@Test
40+
fun readResourceCreatesProperRequest() = runTest {
41+
wiremock.get {
42+
url equalTo "/foo"
43+
} returns {
44+
statusCode = 200
45+
}
3746

38-
coEvery { httpClient.request("http://localhost/foo", any()) } returns response
47+
every { form.href } returns "${wiremock.baseUrl()}/foo"
3948

40-
val client = HttpProtocolClient(httpClient)
49+
val client = HttpProtocolClient()
4150
client.readResource(form)
51+
52+
wiremock.verify {
53+
url equalTo "/foo"
54+
exactly = 1
55+
}
56+
}
57+
58+
@Test
59+
fun writeResourceCreatesProperRequest() = runTest {
60+
wiremock.put {
61+
url equalTo "/foo"
62+
body equalTo """{"key": "value"}"""
63+
} returns {
64+
statusCode = 200
65+
}
66+
67+
every { form.href } returns "${wiremock.baseUrl()}/foo"
68+
val jsonContent = """{"key": "value"}"""
69+
val content = Content("application/json", jsonContent.toByteArray())
70+
71+
val client = HttpProtocolClient()
72+
client.writeResource(form, content)
73+
74+
wiremock.verify {
75+
url equalTo "/foo"
76+
exactly = 1
77+
}
78+
}
79+
80+
@Test
81+
fun invokeResourceCreatesProperRequest() = runTest {
82+
wiremock.post {
83+
url equalTo "/foo"
84+
body equalTo """{"key": "value"}"""
85+
} returns {
86+
statusCode = 200
87+
}
88+
89+
every { form.href } returns "${wiremock.baseUrl()}/foo"
90+
val jsonContent = """{"key": "value"}"""
91+
val content = Content("application/json", jsonContent.toByteArray())
92+
93+
val client = HttpProtocolClient()
94+
client.invokeResource(form, content)
95+
96+
wiremock.verify {
97+
url equalTo "/foo"
98+
exactly = 1
99+
}
100+
}
101+
102+
@Test
103+
fun subscribeResourceHandlesLongPolling() = runTest {
104+
wiremock.get {
105+
url equalTo "/foo"
106+
} returns {
107+
statusCode = 200
108+
}
109+
110+
every { form.href } returns "${wiremock.baseUrl()}/foo"
111+
112+
val client = HttpProtocolClient()
113+
client.subscribeResource(form)
114+
115+
}
116+
117+
@Test
118+
fun setSecurityHandlesBasicSecurityScheme() {
119+
val client = HttpProtocolClient()
120+
val credentials = mapOf("username" to "user", "password" to "pass")
121+
val securityScheme = BasicSecurityScheme()
122+
123+
val result = client.setSecurity(listOf(securityScheme), credentials)
124+
125+
assert(result)
126+
}
127+
128+
@Test
129+
fun setSecurityHandlesBearerSecurityScheme() {
130+
val client = HttpProtocolClient()
131+
val credentials = mapOf("token" to "token123")
132+
val securityScheme = BearerSecurityScheme()
133+
134+
val result = client.setSecurity(listOf(securityScheme), credentials)
135+
136+
assert(result)
137+
}
138+
139+
@Test
140+
fun setSecurityHandlesNoSecurityScheme() {
141+
val client = HttpProtocolClient()
142+
val securityScheme = NoSecurityScheme()
143+
144+
val result = client.setSecurity(listOf(securityScheme), emptyMap())
145+
146+
assert(result)
147+
}
148+
149+
@Test
150+
fun setSecurityThrowsExceptionForUnknownScheme() {
151+
val client = HttpProtocolClient()
152+
val securityScheme = mockk<SecurityScheme>()
153+
154+
val result = client.setSecurity(listOf(securityScheme), emptyMap())
155+
156+
assert(!result)
157+
}
158+
159+
@Test
160+
fun resolveRequestToContentThrowsExceptionForInvalidResponse() = runTest {
161+
wiremock.get {
162+
url equalTo "/foo"
163+
} returns {
164+
statusCode = 500
165+
}
166+
167+
every { form.href } returns "${wiremock.baseUrl()}/foo"
168+
169+
val client = HttpProtocolClient()
170+
171+
assertFailsWith<ProtocolClientException> {
172+
client.readResource(form)
173+
}
42174
}
43175
}

0 commit comments

Comments
 (0)