chore: migriere ping-feature Modul auf Module Structure Blueprint, füge Fake-Repository und neue Integrationstests hinzu, dokumentiere Änderungen
This commit is contained in:
+173
@@ -0,0 +1,173 @@
|
||||
package at.mocode.frontend.features.ping.data
|
||||
|
||||
import at.mocode.ping.api.EnhancedPingResponse
|
||||
import at.mocode.ping.api.HealthResponse
|
||||
import at.mocode.ping.api.PingResponse
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.engine.mock.*
|
||||
import io.ktor.client.plugins.contentnegotiation.*
|
||||
import io.ktor.http.*
|
||||
import io.ktor.serialization.kotlinx.json.*
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class PingApiKoinClientTest {
|
||||
|
||||
// Hilfe zur Erstellung eines testbaren Clients mithilfe der neuen DI-freundlichen Implementierung
|
||||
private fun createTestClient(mockEngine: MockEngine): PingApiKoinClient {
|
||||
val client = HttpClient(mockEngine) {
|
||||
install(ContentNegotiation) {
|
||||
json(Json {
|
||||
prettyPrint = true
|
||||
isLenient = true
|
||||
ignoreUnknownKeys = true
|
||||
})
|
||||
}
|
||||
}
|
||||
return PingApiKoinClient(client)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `simplePing should return correct response`() = runTest {
|
||||
// Given
|
||||
val expectedResponse = PingResponse(
|
||||
status = "OK",
|
||||
timestamp = "2025-09-27T21:27:00Z",
|
||||
service = "ping-service"
|
||||
)
|
||||
|
||||
val mockEngine = MockEngine { request ->
|
||||
assertEquals("/api/ping/simple", request.url.encodedPath)
|
||||
assertEquals(HttpMethod.Get, request.method)
|
||||
|
||||
respond(
|
||||
content = Json.encodeToString(PingResponse.serializer(), expectedResponse),
|
||||
status = HttpStatusCode.OK,
|
||||
headers = headersOf(HttpHeaders.ContentType, "application/json")
|
||||
)
|
||||
}
|
||||
|
||||
// When
|
||||
val apiClient = createTestClient(mockEngine)
|
||||
val response = apiClient.simplePing()
|
||||
|
||||
// Then
|
||||
assertEquals(expectedResponse, response)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `enhancedPing should include simulate parameter`() = runTest {
|
||||
// Given
|
||||
val expectedResponse = EnhancedPingResponse(
|
||||
status = "OK",
|
||||
timestamp = "2025-09-27T21:27:00Z",
|
||||
service = "ping-service",
|
||||
circuitBreakerState = "CLOSED",
|
||||
responseTime = 42L
|
||||
)
|
||||
|
||||
val mockEngine = MockEngine { request ->
|
||||
assertEquals("/api/ping/enhanced", request.url.encodedPath)
|
||||
assertEquals("true", request.url.parameters["simulate"])
|
||||
assertEquals(HttpMethod.Get, request.method)
|
||||
|
||||
respond(
|
||||
content = Json.encodeToString(EnhancedPingResponse.serializer(), expectedResponse),
|
||||
status = HttpStatusCode.OK,
|
||||
headers = headersOf(HttpHeaders.ContentType, "application/json")
|
||||
)
|
||||
}
|
||||
|
||||
// When
|
||||
val apiClient = createTestClient(mockEngine)
|
||||
val response = apiClient.enhancedPing(simulate = true)
|
||||
|
||||
// Then
|
||||
assertEquals(expectedResponse, response)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `healthCheck should return health response`() = runTest {
|
||||
// Given
|
||||
val expectedResponse = HealthResponse(
|
||||
status = "UP",
|
||||
timestamp = "2025-09-27T21:27:00Z",
|
||||
service = "ping-service",
|
||||
healthy = true
|
||||
)
|
||||
|
||||
val mockEngine = MockEngine { request ->
|
||||
assertEquals("/api/ping/health", request.url.encodedPath)
|
||||
assertEquals(HttpMethod.Get, request.method)
|
||||
|
||||
respond(
|
||||
content = Json.encodeToString(HealthResponse.serializer(), expectedResponse),
|
||||
status = HttpStatusCode.OK,
|
||||
headers = headersOf(HttpHeaders.ContentType, "application/json")
|
||||
)
|
||||
}
|
||||
|
||||
// When
|
||||
val apiClient = createTestClient(mockEngine)
|
||||
val response = apiClient.healthCheck()
|
||||
|
||||
// Then
|
||||
assertEquals(expectedResponse, response)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `JSON serialization should work correctly`() {
|
||||
// Given
|
||||
val pingResponse = PingResponse(
|
||||
status = "OK",
|
||||
timestamp = "2025-09-27T21:27:00Z",
|
||||
service = "test-service"
|
||||
)
|
||||
|
||||
// When
|
||||
val json = Json.encodeToString(PingResponse.serializer(), pingResponse)
|
||||
val deserializedResponse = Json.decodeFromString(PingResponse.serializer(), json)
|
||||
|
||||
// Then
|
||||
assertEquals(pingResponse, deserializedResponse)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Enhanced ping response serialization should work correctly`() {
|
||||
// Given
|
||||
val enhancedResponse = EnhancedPingResponse(
|
||||
status = "OK",
|
||||
timestamp = "2025-09-27T21:27:00Z",
|
||||
service = "test-service",
|
||||
circuitBreakerState = "CLOSED",
|
||||
responseTime = 123L
|
||||
)
|
||||
|
||||
// When
|
||||
val json = Json.encodeToString(EnhancedPingResponse.serializer(), enhancedResponse)
|
||||
val deserializedResponse = Json.decodeFromString(EnhancedPingResponse.serializer(), json)
|
||||
|
||||
// Then
|
||||
assertEquals(enhancedResponse, deserializedResponse)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Health response serialization should work correctly`() {
|
||||
// Given
|
||||
val healthResponse = HealthResponse(
|
||||
status = "UP",
|
||||
timestamp = "2025-09-27T21:27:00Z",
|
||||
service = "test-service",
|
||||
healthy = true
|
||||
)
|
||||
|
||||
// When
|
||||
val json = Json.encodeToString(HealthResponse.serializer(), healthResponse)
|
||||
val deserializedResponse = Json.decodeFromString(HealthResponse.serializer(), json)
|
||||
|
||||
// Then
|
||||
assertEquals(healthResponse, deserializedResponse)
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package at.mocode.frontend.features.ping.integration
|
||||
|
||||
import at.mocode.frontend.core.sync.SyncableRepository
|
||||
import at.mocode.ping.api.PingEvent
|
||||
|
||||
class FakePingEventRepository : SyncableRepository<PingEvent> {
|
||||
val storedEvents = mutableListOf<PingEvent>()
|
||||
var latestSince: String? = null
|
||||
|
||||
override suspend fun getLatestSince(): String? = latestSince
|
||||
|
||||
override suspend fun upsert(items: List<PingEvent>) {
|
||||
storedEvents.addAll(items)
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
package at.mocode.frontend.features.ping.integration
|
||||
|
||||
import at.mocode.frontend.core.sync.SyncManager
|
||||
import at.mocode.frontend.features.ping.domain.PingSyncServiceImpl
|
||||
import at.mocode.ping.api.PingEvent
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.engine.mock.*
|
||||
import io.ktor.client.plugins.contentnegotiation.*
|
||||
import io.ktor.http.*
|
||||
import io.ktor.serialization.kotlinx.json.*
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class PingSyncIntegrationTest {
|
||||
|
||||
@Test
|
||||
fun `syncPings should fetch data from API and store in repository`() = runTest {
|
||||
// Given
|
||||
val fakeRepo = FakePingEventRepository()
|
||||
|
||||
// Mock API Response
|
||||
val mockEngine = MockEngine { request ->
|
||||
assertEquals("/api/ping/sync", request.url.encodedPath)
|
||||
|
||||
val responseBody = """
|
||||
[
|
||||
{
|
||||
"id": "event-1",
|
||||
"message": "Ping 1",
|
||||
"lastModified": 1000
|
||||
},
|
||||
{
|
||||
"id": "event-2",
|
||||
"message": "Ping 2",
|
||||
"lastModified": 2000
|
||||
}
|
||||
]
|
||||
""".trimIndent()
|
||||
|
||||
respond(
|
||||
content = responseBody,
|
||||
status = HttpStatusCode.OK,
|
||||
headers = headersOf(HttpHeaders.ContentType, "application/json")
|
||||
)
|
||||
}
|
||||
|
||||
val httpClient = HttpClient(mockEngine) {
|
||||
install(ContentNegotiation) {
|
||||
json(Json {
|
||||
ignoreUnknownKeys = true
|
||||
isLenient = true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
val syncManager = SyncManager(httpClient)
|
||||
val syncService = PingSyncServiceImpl(syncManager, fakeRepo)
|
||||
|
||||
// When
|
||||
syncService.syncPings()
|
||||
|
||||
// Then
|
||||
assertEquals(2, fakeRepo.storedEvents.size)
|
||||
assertTrue(fakeRepo.storedEvents.any { it.id == "event-1" && it.message == "Ping 1" })
|
||||
assertTrue(fakeRepo.storedEvents.any { it.id == "event-2" && it.message == "Ping 2" })
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user