From 64c77ac1bb8eb8c810e7923ac1d2e145d7e7c2d9 Mon Sep 17 00:00:00 2001 From: Nicky <31034418+nickybondarenko@users.noreply.github.com> Date: Wed, 13 Nov 2024 14:57:21 +0100 Subject: [PATCH] fix: guard possible changes in serialization (#182) * fix: guard possible changes in serialization --- .../confidence/cache/FileDiskStorage.kt | 16 ++++- .../spotify/confidence/FileDiskStorageTest.kt | 67 +++++++++++++++++++ 2 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 Confidence/src/test/java/com/spotify/confidence/FileDiskStorageTest.kt diff --git a/Confidence/src/main/java/com/spotify/confidence/cache/FileDiskStorage.kt b/Confidence/src/main/java/com/spotify/confidence/cache/FileDiskStorage.kt index 1afc5d90..5218d1b6 100644 --- a/Confidence/src/main/java/com/spotify/confidence/cache/FileDiskStorage.kt +++ b/Confidence/src/main/java/com/spotify/confidence/cache/FileDiskStorage.kt @@ -10,7 +10,7 @@ import java.io.File internal const val FLAGS_FILE_NAME = "confidence_flags_cache.json" internal const val APPLY_FILE_NAME = "confidence_apply_cache.json" -internal class FileDiskStorage private constructor( +internal class FileDiskStorage internal constructor( private val flagsFile: File, private val applyFile: File ) : DiskStorage { @@ -33,7 +33,12 @@ internal class FileDiskStorage private constructor( return if (fileText.isEmpty()) { mutableMapOf() } else { - Json.decodeFromString(fileText) + try { + Json.decodeFromString(fileText) + } catch (e: Throwable) { + applyFile.delete() + mutableMapOf() + } } } @@ -47,7 +52,12 @@ internal class FileDiskStorage private constructor( return if (fileText.isEmpty()) { FlagResolution.EMPTY } else { - Json.decodeFromString(fileText) + try { + Json.decodeFromString(fileText) + } catch (e: Throwable) { + flagsFile.delete() + FlagResolution.EMPTY + } } } diff --git a/Confidence/src/test/java/com/spotify/confidence/FileDiskStorageTest.kt b/Confidence/src/test/java/com/spotify/confidence/FileDiskStorageTest.kt new file mode 100644 index 00000000..d1827644 --- /dev/null +++ b/Confidence/src/test/java/com/spotify/confidence/FileDiskStorageTest.kt @@ -0,0 +1,67 @@ +package com.spotify.confidence + +import com.spotify.confidence.apply.ApplyInstance +import com.spotify.confidence.apply.EventStatus +import com.spotify.confidence.cache.FileDiskStorage +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import java.io.File +import java.nio.file.Files +import java.util.Date + +class FileDiskStorageTest { + private lateinit var diskStorage: FileDiskStorage + private lateinit var flagsFile: File + private lateinit var applyFile: File + + val badFile = "{\"context\":{\"name\":\"emu64a\",\"version\":\"1.0\",\"density\":2.625,\"height\":1857.0,\"width\":1080,\"namespace\":\"com.example.confidencedemoapp\",\"build\":\"1\",\"manufacturer\":\"Google\",\"model\":\"sdk_gphone64_arm64\",\"type\":\"android\",\"targeting_key\":\"a98a4291-53b0-49d9-bae8-73d3f5da2070\"},\"flags\":[{\"flag\":\"hatten\",\"variant\":\"\",\"reason\":\"RESOLVE_REASON_NO_SEGMENT_MATCH\"}],\"resolveToken\":\"meh\"}" + val badApply = "{\"apply\":{\"apply\":\"apply\"}" + + @Before + fun setup() { + flagsFile = Files.createTempFile("flags", ".txt").toFile() + applyFile = Files.createTempFile("apply", ".txt").toFile() + diskStorage = FileDiskStorage(flagsFile, applyFile) + } + + @Test + fun handleCrashingDeserializationForFlags() { + flagsFile.writeText(badFile) + val read = diskStorage.read() + Assert.assertEquals(FlagResolution.EMPTY, read) + Assert.assertFalse(flagsFile.exists()) + + diskStorage.store(FlagResolution(mapOf("name" to ConfidenceValue.String("emu64a")), listOf(), "abcd")) + Assert.assertTrue(flagsFile.exists()) + } + + @Test + fun handleCrashingDeserializationForApplyData() { + applyFile.writeText(badApply) + val read = diskStorage.readApplyData() + Assert.assertEquals(emptyMap>(), read) + + diskStorage.writeApplyData(mutableMapOf("apply" to mutableMapOf("apply" to ApplyInstance(Date(), EventStatus.CREATED)))) + Assert.assertTrue(applyFile.exists()) + } + + @Test + fun readEmptyFlagsFile() { + val read = diskStorage.read() + Assert.assertEquals(FlagResolution.EMPTY, read) + } + + @Test + fun readEmptyApplyFile() { + val read = diskStorage.readApplyData() + Assert.assertEquals(emptyMap>(), read) + } + + @Test + fun testStoreFlagResolution() { + diskStorage.store(FlagResolution.EMPTY) + val read = diskStorage.read() + Assert.assertEquals(FlagResolution.EMPTY, read) + } +} \ No newline at end of file