summaryrefslogtreecommitdiff
path: root/android-app/app/src/test/kotlin/com/example
diff options
context:
space:
mode:
Diffstat (limited to 'android-app/app/src/test/kotlin/com/example')
-rw-r--r--android-app/app/src/test/kotlin/com/example/androidapp/data/weather/SatelliteGribDownloaderTest.kt180
1 files changed, 180 insertions, 0 deletions
diff --git a/android-app/app/src/test/kotlin/com/example/androidapp/data/weather/SatelliteGribDownloaderTest.kt b/android-app/app/src/test/kotlin/com/example/androidapp/data/weather/SatelliteGribDownloaderTest.kt
new file mode 100644
index 0000000..4bf7985
--- /dev/null
+++ b/android-app/app/src/test/kotlin/com/example/androidapp/data/weather/SatelliteGribDownloaderTest.kt
@@ -0,0 +1,180 @@
+package com.example.androidapp.data.weather
+
+import com.example.androidapp.data.model.GribParameter
+import com.example.androidapp.data.model.GribRegion
+import com.example.androidapp.data.model.SatelliteDownloadRequest
+import com.example.androidapp.data.storage.InMemoryGribFileManager
+import org.junit.Assert.*
+import org.junit.Before
+import org.junit.Test
+import java.time.Instant
+
+class SatelliteGribDownloaderTest {
+
+ private lateinit var manager: InMemoryGribFileManager
+ private lateinit var downloader: SatelliteGribDownloader
+
+ // 10°×10° region at 1°: 11×11 = 121 grid points
+ private val region10x10 = GribRegion("atlantic", 30.0, 40.0, -70.0, -60.0)
+
+ @Before
+ fun setUp() {
+ manager = InMemoryGribFileManager()
+ downloader = SatelliteGribDownloader(manager)
+ }
+
+ // ------------------------------------------------------------------ size estimation
+
+ @Test
+ fun `estimateSizeBytes_scalesWithRegionArea`() {
+ // 10°×10° region: 11×11 = 121 grid points
+ val req10 = SatelliteDownloadRequest(
+ region = region10x10,
+ parameters = GribParameter.SATELLITE_MINIMAL,
+ forecastHours = 24
+ )
+ // 20°×20° region: 21×21 = 441 grid points — roughly 3.6× more grid points
+ val region20x20 = GribRegion("bigger", 20.0, 40.0, -80.0, -60.0)
+ val req20 = SatelliteDownloadRequest(
+ region = region20x20,
+ parameters = GribParameter.SATELLITE_MINIMAL,
+ forecastHours = 24
+ )
+
+ val size10 = downloader.estimateSizeBytes(req10)
+ val size20 = downloader.estimateSizeBytes(req20)
+
+ assertTrue("Larger region must produce larger estimate", size20 > size10)
+ }
+
+ @Test
+ fun `estimateSizeBytes_scalesWithParameterCount`() {
+ val minimalReq = SatelliteDownloadRequest(
+ region = region10x10,
+ parameters = GribParameter.SATELLITE_MINIMAL, // 3 params
+ forecastHours = 24
+ )
+ val fullReq = SatelliteDownloadRequest(
+ region = region10x10,
+ parameters = GribParameter.values().toSet(), // all 7 params
+ forecastHours = 24
+ )
+
+ val sizeMinimal = downloader.estimateSizeBytes(minimalReq)
+ val sizeFull = downloader.estimateSizeBytes(fullReq)
+
+ assertTrue("More parameters must produce larger estimate", sizeFull > sizeMinimal)
+ }
+
+ @Test
+ fun `estimateSizeBytes_coarserResolutionProducesSmallerFile`() {
+ val finReq = SatelliteDownloadRequest(
+ region = region10x10,
+ parameters = GribParameter.SATELLITE_MINIMAL,
+ forecastHours = 24,
+ resolutionDeg = 1.0
+ )
+ val coarseReq = SatelliteDownloadRequest(
+ region = region10x10,
+ parameters = GribParameter.SATELLITE_MINIMAL,
+ forecastHours = 24,
+ resolutionDeg = 2.0
+ )
+
+ val sizeFine = downloader.estimateSizeBytes(finReq)
+ val sizeCoarse = downloader.estimateSizeBytes(coarseReq)
+
+ assertTrue("Coarser resolution must produce smaller estimate", sizeCoarse < sizeFine)
+ }
+
+ @Test
+ fun `estimatedDownloadSeconds_atIridiumBandwidth`() {
+ // 10°×10°, 3 params, 24h at 1° → known estimate
+ val req = SatelliteDownloadRequest(
+ region = region10x10,
+ parameters = GribParameter.SATELLITE_MINIMAL,
+ forecastHours = 24
+ )
+ val estBytes = downloader.estimateSizeBytes(req)
+ val expectedSeconds = Math.ceil(estBytes * 8.0 / SatelliteGribDownloader.SATELLITE_BANDWIDTH_BPS).toLong()
+
+ val actualSeconds = downloader.estimatedDownloadSeconds(req)
+
+ assertEquals(expectedSeconds, actualSeconds)
+ // Sanity: should be > 0 seconds and less than 10 minutes for a small region
+ assertTrue("Download estimate must be positive", actualSeconds > 0)
+ assertTrue("Small 10°×10° should complete in under 10 min at 2.4kbps", actualSeconds < 600)
+ }
+
+ // ------------------------------------------------------------------ buildMinimalRequest
+
+ @Test
+ fun `buildMinimalRequest_containsOnlyWindAndPressure`() {
+ val req = downloader.buildMinimalRequest(region10x10, 48)
+
+ assertEquals(GribParameter.SATELLITE_MINIMAL, req.parameters)
+ assertTrue(req.parameters.contains(GribParameter.WIND_SPEED))
+ assertTrue(req.parameters.contains(GribParameter.WIND_DIRECTION))
+ assertTrue(req.parameters.contains(GribParameter.SURFACE_PRESSURE))
+ assertFalse(req.parameters.contains(GribParameter.TEMPERATURE_2M))
+ assertFalse(req.parameters.contains(GribParameter.PRECIPITATION))
+ assertEquals(region10x10, req.region)
+ assertEquals(48, req.forecastHours)
+ }
+
+ // ------------------------------------------------------------------ download()
+
+ @Test
+ fun `download_abortsWhenEstimatedSizeExceedsLimit`() {
+ val req = downloader.buildMinimalRequest(region10x10, 24)
+ var fetcherCalled = false
+
+ val result = downloader.download(
+ request = req,
+ fetcher = { fetcherCalled = true; ByteArray(100) },
+ outputPath = "/tmp/test.grib",
+ sizeLimitBytes = 1L // ridiculously small limit
+ )
+
+ assertTrue("Should abort without calling fetcher", result is SatelliteGribDownloader.DownloadResult.Aborted)
+ assertFalse("Fetcher must not be called when aborting", fetcherCalled)
+ val aborted = result as SatelliteGribDownloader.DownloadResult.Aborted
+ assertTrue("Should report estimated bytes", aborted.estimatedBytes > 0)
+ }
+
+ @Test
+ fun `download_returnsFailedWhenFetcherReturnsNull`() {
+ val req = downloader.buildMinimalRequest(region10x10, 24)
+
+ val result = downloader.download(
+ request = req,
+ fetcher = { null },
+ outputPath = "/tmp/test.grib"
+ )
+
+ assertTrue("Should fail when fetcher returns null", result is SatelliteGribDownloader.DownloadResult.Failed)
+ }
+
+ @Test
+ fun `download_savesMetadataAndReturnsSuccessOnValidFetch`() {
+ val req = downloader.buildMinimalRequest(region10x10, 24)
+ val fakeBytes = ByteArray(8208) { 0x00 }
+ val now = Instant.parse("2026-03-16T12:00:00Z")
+
+ val result = downloader.download(
+ request = req,
+ fetcher = { fakeBytes },
+ outputPath = "/tmp/atlantic.grib",
+ now = now
+ )
+
+ assertTrue("Should succeed", result is SatelliteGribDownloader.DownloadResult.Success)
+ val success = result as SatelliteGribDownloader.DownloadResult.Success
+ assertEquals(region10x10, success.file.region)
+ assertEquals(24, success.file.forecastHours)
+ assertEquals(fakeBytes.size.toLong(), success.file.sizeBytes)
+ assertEquals("/tmp/atlantic.grib", success.file.filePath)
+ // Metadata must be persisted in the manager
+ assertNotNull(manager.latestFile(region10x10))
+ }
+}