diff options
2 files changed, 30 insertions, 2 deletions
diff --git a/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/converter/RomanjiConverter.kt b/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/converter/RomanjiConverter.kt index b502d63..e1a11f8 100644 --- a/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/converter/RomanjiConverter.kt +++ b/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/converter/RomanjiConverter.kt @@ -93,6 +93,13 @@ class RomanjiConverter( // pin every word of the message to its unconverted form for good, because the words // are converted concurrently and the timeout cancels all of them at once. throw e + } catch (e: ConversionTimeoutException) { + // Returned without caching: a timeout says the request was slow, not that the word + // has no conversion, so recording the hiragana would pin it for the life of the + // cache over one slow reply. A hard API failure is different - the fallback is + // cached there deliberately. + logger.warning("Timed out converting $hiragana, leaving it uncached: ${e.message}") + return hiragana } catch (e: Exception) { logger.warning("Failed to convert $hiragana: ${e.message}") hiragana // Use hiragana if API fails diff --git a/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/converter/RomanjiConverterTest.kt b/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/converter/RomanjiConverterTest.kt index 69baa32..c8314d7 100644 --- a/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/converter/RomanjiConverterTest.kt +++ b/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/converter/RomanjiConverterTest.kt @@ -302,7 +302,7 @@ class RomanjiConverterTest { } @Test - fun `an API timeout degrades to hiragana like any other failure`() = + fun `an API timeout degrades to hiragana without caching it`() = runBlocking { val (converter, cache, apiClient) = createConverter() coEvery { apiClient.convert("おはよう") } throws ConversionTimeoutException(1.seconds) @@ -310,7 +310,28 @@ class RomanjiConverterTest { val result = converter.convert("ohayou") assertEquals("おはよう", result) - verify(exactly = 1) { cache.put("ohayou", "おはよう") } + // A slow reply says nothing about the word, so caching the hiragana would pin it to its + // unconverted form for the life of the cache. + verify(exactly = 0) { cache.put(any(), any()) } + } + + @Test + fun `a word that timed out is converted on the next attempt`() = + runBlocking { + // A cache that actually remembers, unlike the shared fixture whose get() always returns + // null - which would let this pass even if the timeout had been cached. + val entries = mutableMapOf<String, String>() + val cache = mockk<ConversionCache>(relaxed = true) + every { cache.get(any()) } answers { entries[firstArg()] } + every { cache.put(any(), any()) } answers { entries[firstArg()] = secondArg() } + val apiClient = mockk<GoogleIMEClient>(relaxed = true) + val converter = RomanjiConverter(cache, apiClient, TestUtils.TestLogger()) + + coEvery { apiClient.convert("おはよう") } throws ConversionTimeoutException(1.seconds) + converter.convert("ohayou") + coEvery { apiClient.convert("おはよう") } returns "おはよう御座います" + + assertEquals("おはよう御座います", converter.convert("ohayou")) } @Test |
