Skip to content

Commit 032a78e

Browse files
committed
refactor: improve error handling in ConfigurationService and ActivityService; add unit tests for ActivityService
1 parent 6fc10fb commit 032a78e

4 files changed

Lines changed: 155 additions & 17 deletions

File tree

boot/src/main/kotlin/io/github/costaalex/workoutrelay/app/activity/ActivityService.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,10 @@ class ActivityService(
3434
return CopyActivitiesResponse(activitiesToSave.size, filteredOut, request.startDate, request.endDate)
3535
}
3636

37-
private fun getRepository(platform: Platform) = repositoryMap[platform]!!
37+
private fun getRepository(
38+
platform: Platform,
39+
): ActivityRepository =
40+
checkNotNull(repositoryMap[platform]) {
41+
"No ActivityRepository registered for platform $platform"
42+
}
3843
}

boot/src/main/kotlin/io/github/costaalex/workoutrelay/app/configuration/ConfigurationService.kt

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -42,23 +42,19 @@ class ConfigurationService(
4242
val info = try {
4343
repository.platformInfo()
4444
} catch (exception: Exception) {
45-
log.warn(
46-
"Unable to validate connection to {}",
47-
platform.title,
48-
exception
49-
)
45+
log.warn("Unable to validate connection to {}", platform.title, exception)
5046

51-
PlatformInfo(
52-
mapOf("isValid" to false)
53-
)
47+
PlatformInfo(mapOf("isValid" to false))
5448
}
5549

5650
platform to info
5751
}
5852

59-
fun platformInfo(platform: Platform): PlatformInfo {
60-
return platformInfoRepositoryMap[platform]!!.platformInfo()
61-
}
53+
fun platformInfo(
54+
platform: Platform,
55+
): PlatformInfo =
56+
getPlatformInfoRepository(platform)
57+
.platformInfo()
6258

6359
fun refreshPlatformInfo(): Map<Platform, PlatformInfo> {
6460
cacheManager
@@ -68,21 +64,40 @@ class ConfigurationService(
6864
return platformInfo()
6965
}
7066

67+
private fun getPlatformInfoRepository(
68+
platform: Platform,
69+
): PlatformInfoRepository =
70+
checkNotNull(
71+
platformInfoRepositoryMap[platform]
72+
) {
73+
"No PlatformInfoRepository registered for platform $platform"
74+
}
75+
7176
private fun handleDebugModeIfNecessary(request: UpdateConfigurationRequest) {
7277
debugModeService.handleDebugMode(request.configMap)
7378
}
7479

7580
private fun updateConfiguration(
7681
request: UpdateConfigurationRequest,
77-
repository: PlatformConfigurationRepository
82+
repository: PlatformConfigurationRepository,
7883
): String? {
7984
return try {
8085
repository.updateConfig(request)
8186
null
82-
} catch (e: PlatformException) {
83-
"${e.platform.title}: ${e.message}"
84-
} catch (e: Exception) {
85-
e.message
87+
} catch (exception: PlatformException) {
88+
"${exception.platform.title}: " +
89+
(
90+
exception.message ?: "Unable to update configuration"
91+
)
92+
} catch (exception: Exception) {
93+
val platform = repository.platform()
94+
95+
log.error("Unexpected error while updating configuration for {}", platform.title, exception)
96+
97+
"${platform.title}: " +
98+
(
99+
exception.message ?: "Unexpected configuration error"
100+
)
86101
}
87102
}
88103
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package io.github.costaalex.workoutrelay.app.activity
2+
3+
import io.github.costaalex.workoutrelay.domain.Platform
4+
import org.junit.jupiter.api.Assertions.assertEquals
5+
import org.junit.jupiter.api.Test
6+
import org.junit.jupiter.api.assertThrows
7+
8+
class ActivityServiceTest {
9+
10+
@Test
11+
fun `should fail with clear error when repository is missing`() {
12+
val activityService =
13+
ActivityService(emptyList())
14+
15+
val request =
16+
CopyActivitiesRequest(
17+
sourcePlatform =
18+
Platform.INTERVALS,
19+
targetPlatform =
20+
Platform.TRAINING_PEAKS,
21+
startDate =
22+
java.time.LocalDate.of(
23+
2026,
24+
7,
25+
1,
26+
),
27+
endDate =
28+
java.time.LocalDate.of(
29+
2026,
30+
7,
31+
2,
32+
),
33+
types = emptyList(),
34+
)
35+
36+
val exception =
37+
assertThrows<IllegalStateException> {
38+
activityService.syncActivities(request)
39+
}
40+
41+
assertEquals(
42+
"No ActivityRepository registered " +
43+
"for platform INTERVALS",
44+
exception.message,
45+
)
46+
}
47+
}

boot/src/test/kotlin/io/github/costaalex/workoutrelay/app/configuration/ConfigurationServiceTest.kt

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import org.mockito.Mockito.verify
2020
import org.mockito.Mockito.`when`
2121
import org.springframework.cache.Cache
2222
import org.springframework.cache.CacheManager
23+
import org.junit.jupiter.api.assertThrows
2324

2425
class ConfigurationServiceTest {
2526

@@ -212,4 +213,74 @@ class ConfigurationServiceTest {
212213

213214
verify(cache).clear()
214215
}
216+
217+
@Test
218+
fun `should return unexpected error when configuration update fails`() {
219+
val request =
220+
UpdateConfigurationRequest(
221+
mapOf(
222+
"intervals.api-key" to "invalid-key",
223+
)
224+
)
225+
226+
doThrow(
227+
RuntimeException("Database unavailable")
228+
)
229+
.`when`(platformConfigurationRepository)
230+
.updateConfig(request)
231+
232+
val errors =
233+
configurationService.updateConfiguration(request)
234+
235+
assertEquals(
236+
listOf(
237+
"Intervals.icu: Database unavailable"
238+
),
239+
errors,
240+
)
241+
242+
verify(debugModeService)
243+
.handleDebugMode(request.configMap)
244+
}
245+
246+
@Test
247+
fun `should return fallback error when exception has no message`() {
248+
val request =
249+
UpdateConfigurationRequest(
250+
mapOf(
251+
"intervals.api-key" to "invalid-key",
252+
)
253+
)
254+
255+
doThrow(
256+
RuntimeException()
257+
)
258+
.`when`(platformConfigurationRepository)
259+
.updateConfig(request)
260+
261+
val errors =
262+
configurationService.updateConfiguration(request)
263+
264+
assertEquals(
265+
listOf(
266+
"Intervals.icu: Unexpected configuration error"
267+
),
268+
errors,
269+
)
270+
271+
verify(debugModeService)
272+
.handleDebugMode(request.configMap)
273+
}
274+
275+
@Test
276+
fun `should fail with clear error when platform repository is missing`() {
277+
val exception =
278+
assertThrows<IllegalStateException> {
279+
configurationService.platformInfo(
280+
Platform.TRAINING_PEAKS
281+
)
282+
}
283+
284+
assertEquals("No PlatformInfoRepository registered for platform TRAINING_PEAKS", exception.message)
285+
}
215286
}

0 commit comments

Comments
 (0)