From 39993466e7dfefee72d18da1f9e230d96ba2edc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20W=C3=BCrl?= Date: Fri, 29 Mar 2024 07:26:16 +0100 Subject: [PATCH] simplified cache size calculation and tests for cache --- .github/workflows/build.yml | 2 +- .../app/controller/HistoryController.kt | 1 - .../android/data/MainDataHandler.kt | 5 +- .../android/data/cache/DataCache.kt | 28 +++--- .../blitzortung/android/dialogs/LogDialog.kt | 5 +- .../android/data/cache/DataCacheTest.kt | 87 +++++++++++++++++++ 6 files changed, 105 insertions(+), 23 deletions(-) create mode 100644 app/src/test/java/org/blitzortung/android/data/cache/DataCacheTest.kt diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c359b0d1..e2a24f0d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -45,7 +45,7 @@ jobs: uses: actions/upload-artifact@v3 with: name: build - path: app/build + path: app/build/outputs if-no-files-found: "error" - name: Generate app bundle. run: ./gradlew build app:bundleRelease --stacktrace diff --git a/app/src/main/java/org/blitzortung/android/app/controller/HistoryController.kt b/app/src/main/java/org/blitzortung/android/app/controller/HistoryController.kt index f0ac8982..7d704d7b 100644 --- a/app/src/main/java/org/blitzortung/android/app/controller/HistoryController.kt +++ b/app/src/main/java/org/blitzortung/android/app/controller/HistoryController.kt @@ -22,7 +22,6 @@ import android.view.View import android.widget.ImageButton import org.blitzortung.android.app.ButtonGroup import org.blitzortung.android.app.databinding.MainBinding -import org.blitzortung.android.data.DataChannel import org.blitzortung.android.data.MainDataHandler import org.blitzortung.android.data.Mode import org.blitzortung.android.data.provider.result.ResultEvent diff --git a/app/src/main/java/org/blitzortung/android/data/MainDataHandler.kt b/app/src/main/java/org/blitzortung/android/data/MainDataHandler.kt index 448a773d..b568c700 100644 --- a/app/src/main/java/org/blitzortung/android/data/MainDataHandler.kt +++ b/app/src/main/java/org/blitzortung/android/data/MainDataHandler.kt @@ -32,6 +32,7 @@ import org.blitzortung.android.app.R import org.blitzortung.android.app.view.OnSharedPreferenceChangeListener import org.blitzortung.android.app.view.PreferenceKey import org.blitzortung.android.app.view.get +import org.blitzortung.android.data.cache.CacheSize import org.blitzortung.android.data.cache.DataCache import org.blitzortung.android.data.provider.DataProviderFactory import org.blitzortung.android.data.provider.DataProviderType @@ -443,9 +444,7 @@ class MainDataHandler @Inject constructor( } } - fun calculateTotalCacheSize(): Int = cache.calculateTotalSize() - - + fun calculateTotalCacheSize(): CacheSize = cache.calculateTotalSize() } internal const val DEFAULT_RASTER_BASELENGTH = 10000 diff --git a/app/src/main/java/org/blitzortung/android/data/cache/DataCache.kt b/app/src/main/java/org/blitzortung/android/data/cache/DataCache.kt index c4dcec41..3a55d28e 100644 --- a/app/src/main/java/org/blitzortung/android/data/cache/DataCache.kt +++ b/app/src/main/java/org/blitzortung/android/data/cache/DataCache.kt @@ -4,8 +4,6 @@ import android.util.Log import org.blitzortung.android.app.Main.Companion.LOG_TAG import org.blitzortung.android.data.Parameters import org.blitzortung.android.data.provider.result.ResultEvent -import java.io.ByteArrayOutputStream -import java.io.ObjectOutputStream import java.io.Serializable import javax.inject.Inject import javax.inject.Singleton @@ -13,7 +11,7 @@ import javax.inject.Singleton @Singleton class DataCache @Inject constructor() { - private val cache = hashMapOf>() + val cache = hashMapOf>() fun get(parameters: Parameters, expiryTime: Long = DEFAULT_EXPIRY_TIME): ResultEvent? { val entry = cache[parameters] ?: return null @@ -28,18 +26,11 @@ class DataCache @Inject constructor() { cache[parameters] = Timestamped(dataEvent) } - fun calculateTotalSize(): Int = cache.entries.fold(0) { acc, entry -> - val size = determineObjectSize(entry.value) - Log.v(LOG_TAG, "${entry.key} -> ${size}") - acc + size - } - - private fun determineObjectSize(obj: Any): Int { - val baos = ByteArrayOutputStream() - val oos = ObjectOutputStream(baos) - oos.writeObject(obj) - oos.close() - return baos.size() + fun calculateTotalSize(): CacheSize = cache.entries.fold(CacheSize(0, 0)) { acc, entry -> + val resultEvent = entry.value.value + val strikeCount = resultEvent.strikes?.size ?: 0 + Log.v(LOG_TAG, "${entry.key} -> ${strikeCount}") + CacheSize(acc.entries + 1, acc.strikes + strikeCount) } fun clear() { @@ -51,4 +42,9 @@ class DataCache @Inject constructor() { } } -data class Timestamped(val value: T, val timestamp: Long = System.currentTimeMillis()) : Serializable \ No newline at end of file +data class Timestamped(val value: T, val timestamp: Long = System.currentTimeMillis()) : Serializable + +data class CacheSize( + val entries: Int, + val strikes: Int, +) \ No newline at end of file diff --git a/app/src/main/java/org/blitzortung/android/dialogs/LogDialog.kt b/app/src/main/java/org/blitzortung/android/dialogs/LogDialog.kt index 7b1b9d13..b098c4ec 100644 --- a/app/src/main/java/org/blitzortung/android/dialogs/LogDialog.kt +++ b/app/src/main/java/org/blitzortung/android/dialogs/LogDialog.kt @@ -29,11 +29,12 @@ import android.widget.TextView import android.widget.Toast import org.blitzortung.android.app.R import org.blitzortung.android.app.components.BuildVersion +import org.blitzortung.android.data.cache.CacheSize import org.blitzortung.android.dialogs.log.LogProvider class LogDialog( context: Context, - private val cacheSize: Int, + private val cacheSize: CacheSize, private val buildVersion: BuildVersion, private val logProvider: LogProvider = LogProvider() ) : android.app.AlertDialog(context) { @@ -65,7 +66,7 @@ class LogDialog( } private fun getCacheString(): String { - return "Cache size: %.3f MB".format(cacheSize/1024f/1024f) + return "Cache size: %d entries, %d strikes".format(cacheSize.entries, cacheSize.strikes) } private fun getDeviceString(): String { diff --git a/app/src/test/java/org/blitzortung/android/data/cache/DataCacheTest.kt b/app/src/test/java/org/blitzortung/android/data/cache/DataCacheTest.kt new file mode 100644 index 00000000..1aaeb140 --- /dev/null +++ b/app/src/test/java/org/blitzortung/android/data/cache/DataCacheTest.kt @@ -0,0 +1,87 @@ +package org.blitzortung.android.data.cache + +import io.mockk.MockKAnnotations +import org.assertj.core.api.Assertions.assertThat +import org.blitzortung.android.data.Flags +import org.blitzortung.android.data.Parameters +import org.blitzortung.android.data.TimeInterval +import org.blitzortung.android.data.beans.RasterElement +import org.blitzortung.android.data.provider.result.ResultEvent +import org.junit.Before +import org.junit.Test + +class DataCacheTest { + + private val parameters = Parameters(interval = TimeInterval(offset = 30)) + + private lateinit var uut: DataCache + + @Before + fun setUp() { + MockKAnnotations.init(this, relaxed = true) + + uut = DataCache() + } + + @Test + fun cacheMiss() { + val result = uut.get(parameters) + + assertThat(result).isNull() + } + + @Test + fun emptySize() { + val result = uut.calculateTotalSize() + + assertThat(result).isEqualTo(CacheSize(0, 0)) + } + + @Test + fun cachePut() { + val dataEvent = ResultEvent(parameters = parameters, flags = Flags()) + uut.put(parameters, dataEvent) + + val result = uut.get(parameters) + + assertThat(result).isEqualTo(dataEvent) + } + + @Test + fun cacheClear() { + val dataEvent = ResultEvent(parameters = parameters, flags = Flags()) + uut.put(parameters, dataEvent) + uut.clear() + + val result = uut.get(parameters) + + assertThat(result).isNull() + } + + @Test + fun cachePutOutdated() { + val dataEvent = ResultEvent(parameters = parameters, flags = Flags()) + uut.cache[parameters] = Timestamped(dataEvent, System.currentTimeMillis() - DataCache.DEFAULT_EXPIRY_TIME - 1) + + val result = uut.get(parameters) + + assertThat(result).isNull() + } + + @Test + fun cacheSizeSimple() { + val strikes = listOf( + RasterElement(0, 1.0, 2.0, 3), + RasterElement(2, 3.0, 4.0, 2), + RasterElement(4, -3.0, -4.0, 1), + ) + val dataEvent = ResultEvent(parameters = parameters, flags = Flags(), strikes = strikes) + + uut.put(parameters, dataEvent) + uut.put(parameters.copy(interval = TimeInterval(offset = 60)), ResultEvent(parameters = parameters, flags = Flags())) + + val result = uut.calculateTotalSize() + + assertThat(result).isEqualTo(CacheSize(2, 3)) + } +} \ No newline at end of file