Skip to content

Commit

Permalink
Add tests for OcTranspoClient
Browse files Browse the repository at this point in the history
  • Loading branch information
dellisd committed Oct 5, 2023
1 parent 23dc1a6 commit 663f29e
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 1 deletion.
7 changes: 6 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[versions]
coroutines = "1.6.4"
kotlin = "1.8.10"
kotlinx-serialization = "1.5.0"
sqldelight = "2.0.0"
Expand All @@ -12,7 +13,8 @@ sqljs = "1.6.7"
absurdSql = "0.0.53"

[libraries]
kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version = "1.6.4" }
kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines"}
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines" }
kotlinx-serialization-yaml = "com.charleskorn.kaml:kaml:0.49.0"
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" }
kotlinx-serialization-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "kotlinx-serialization" }
Expand All @@ -27,6 +29,7 @@ ktor-server-webSockets = { module = "io.ktor:ktor-server-websockets", version.re
# Ktor Client
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
ktor-client-js = { module = "io.ktor:ktor-client-js", version.ref = "ktor" }
ktor-client-mock = { module = "io.ktor:ktor-client-mock", version.ref = "ktor" }
ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" }
ktor-client-contentNegotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" }
ktor-client-webSockets = { module = "io.ktor:ktor-client-websockets", version.ref = "ktor" }
Expand All @@ -43,13 +46,15 @@ inject-runtime = { module = "me.tatarka.inject:kotlin-inject-runtime", version.r

molecule-runtime = { module = "app.cash.molecule:molecule-runtime", version = "0.7.1" }

assertk = { module = "com.willowtreeapps.assertk:assertk", version = "0.27.0" }
compose-mapbox = { module = "ca.derekellis.mapbox:compose-web-mapbox", version = "0.1.0-SNAPSHOT" }
spatialk-geojson = "io.github.dellisd.spatialk:geojson:0.3.0-SNAPSHOT"
kgtfs-gtfs = "ca.derekellis.kgtfs:gtfs:0.2.0-SNAPSHOT"
logback = "ch.qos.logback:logback-classic:1.2.11"
klock = "com.soywiz.korlibs.klock:klock:2.2.0"
clikt = "com.github.ajalt.clikt:clikt:3.5.0"
jgrapht = "org.jgrapht:jgrapht-core:1.5.1"
junit = "junit:junit:4.13.2"

[plugins]
kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
Expand Down
5 changes: 5 additions & 0 deletions server/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ dependencies {
implementation(project(":shared"))

ksp(libs.inject.compiler)

testImplementation(libs.assertk)
testImplementation(libs.junit)
testImplementation(libs.kotlinx.coroutines.test)
testImplementation(libs.ktor.client.mock)
}

kotlin {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import ca.derekellis.reroute.server.config.LoadedServerConfig
import ca.derekellis.reroute.server.di.RerouteScope
import io.github.dellisd.spatialk.geojson.dsl.lngLat
import io.ktor.client.HttpClient
import io.ktor.client.plugins.ServerResponseException
import io.ktor.client.request.get
import io.ktor.client.statement.readBytes
import io.ktor.http.isSuccess
import kotlinx.datetime.toKotlinLocalTime
import me.tatarka.inject.annotations.Inject
import org.w3c.dom.Element
Expand Down Expand Up @@ -38,6 +40,10 @@ class OcTranspoClient(
httpClient.get("https://api.octranspo1.com/v2.0/GetNextTripsForStopAllRoutes?appID=${credentials.appId}&apiKey=${credentials.apiKey}&stopNo=$code&format=xml")
val responseTime = LocalTime.now(ZoneId.of("America/Montreal"))

if (!response.status.isSuccess()) {
throw ServerResponseException(response, response.readBytes().toString(Charsets.UTF_8))
}

return buildResultFromResponse(code, response.readBytes(), responseTime)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package ca.derekellis.reroute.server.realtime

import assertk.assertFailure
import assertk.assertThat
import assertk.assertions.hasSize
import assertk.assertions.isEqualTo
import assertk.assertions.isInstanceOf
import assertk.assertions.messageContains
import ca.derekellis.reroute.server.config.LoadedServerConfig
import ca.derekellis.reroute.server.config.OcTranspoCredentials
import io.ktor.client.HttpClient
import io.ktor.client.engine.mock.MockEngine
import io.ktor.client.engine.mock.respond
import io.ktor.client.plugins.ServerResponseException
import io.ktor.http.HttpHeaders
import io.ktor.http.HttpStatusCode
import io.ktor.http.headersOf
import kotlinx.coroutines.test.runTest
import kotlinx.datetime.LocalTime
import org.junit.Test
import kotlin.io.path.Path
import kotlin.time.Duration.Companion.minutes

class OcTranspoClientTest {
private val config = LoadedServerConfig(
dataPath = Path(""),
ocTranspo = OcTranspoCredentials("", "")
)

private fun makeClient(engine: MockEngine): OcTranspoClient = OcTranspoClient(config, HttpClient(engine))

@Test
fun `basic endpoint response is parsed correctly`() = runTest {
val engine = MockEngine {
respond(
DEFAULT,
status = HttpStatusCode.OK,
headers = headersOf(HttpHeaders.ContentType, "text/html")
)
}

val client = makeClient(engine)
val result = client.get("4106")

assertThat(result.stop).isEqualTo("4106")

val route = result.routes.first()
assertThat(route.number).isEqualTo("6")
assertThat(route.heading).isEqualTo("Rockcliffe")
assertThat(route.directionId).isEqualTo(1)
assertThat(route.trips).hasSize(2)

val trip = route.trips.first()
assertThat(trip.destination).isEqualTo("Rockcliffe")
assertThat(trip.startTime).isEqualTo(LocalTime(22, 49))
// TODO: Test adjusted schedule time conversion with a custom clock
assertThat(trip.adjustmentAge).isEqualTo((-1).minutes)
}

@Test
fun `http error throws error`() = runTest {
val engine = MockEngine {
respond("", HttpStatusCode.BadGateway)
}

val client = makeClient(engine)
assertFailure { client.get("0000") }
.isInstanceOf<ServerResponseException>()
.messageContains("502 Bad Gateway")
}

companion object {
private val DEFAULT = """
<?xml
version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Body>
<GetRouteSummaryForStopResponse xmlns="http://octranspo.com">
<GetRouteSummaryForStopResult>
<StopNo>4106</StopNo>
<StopDescription>BANK / ERIE</StopDescription>
<Error/>
<Routes>
<Route>
<RouteNo>6</RouteNo>
<RouteHeading>Rockcliffe</RouteHeading>
<DirectionID>1</DirectionID>
<Direction/>
<Error/>
<Trips>
<Trip>
<TripDestination>Rockcliffe</TripDestination>
<TripStartTime>22:49</TripStartTime>
<AdjustedScheduleTime>13</AdjustedScheduleTime>
<AdjustmentAge>-1</AdjustmentAge>
<LastTripOfSchedule>false</LastTripOfSchedule>
<BusType/>
<Longitude/>
<Latitude/>
<GPSSpeed/>
</Trip>
<Trip>
<TripDestination>Rockcliffe</TripDestination>
<TripStartTime>23:18</TripStartTime>
<AdjustedScheduleTime>42</AdjustedScheduleTime>
<AdjustmentAge>-1</AdjustmentAge>
<LastTripOfSchedule>false</LastTripOfSchedule>
<BusType/>
<Longitude/>
<Latitude/>
<GPSSpeed/>
</Trip>
</Trips>
</Route>
</Routes>
</GetRouteSummaryForStopResult>
</GetRouteSummaryForStopResponse>
</soap:Body>
</soap:Envelope>
""".trimIndent()
}
}

0 comments on commit 663f29e

Please sign in to comment.