Compare commits

...
Author SHA1 Message Date
atsunatsu a082abb72c build: bump version to 4.4.7-ba7opf.15.7 (504) 2026-09-24 11:11:31 +08:00
atsunatsu a2e41a0c1a fix: don't crash the AMSAT list update on unknown satellite names
resolvePerName crashed with NoSuchElementException (all.first()) when an
AMSAT live-page name had no matching local entry (TEVEL2-1..9, RS95S, any
brand-new sat not yet in the local TLE). The exception was swallowed by
updateAmSatLiveLists' runCatching, so the FM/Linear lists were NEVER
rewritten — they stayed at the stale pre-whitelist snapshot containing
all five ISS modules, which is why ISS kept showing as DESTINY despite the
15.4/15.5/15.6 disambiguation fixes.

Fix: return an empty set for names with no local match (correct skip
semantics) so the rest of the page still resolves and the ISS module
collapse runs. Regression test covers the real AMSAT page mix (ISS +
unknown names).
2026-09-24 11:11:04 +08:00
3 changed files with 45 additions and 2 deletions

No files matched your search

@@ -158,6 +158,12 @@ class DatabaseRepo(
val all = nameToCatnum.filter { (localName, _) ->
dataParser.matchesAmSatName(localName, keys)
}.values.toSet()
// No local entry matches this AMSAT name (e.g. a brand-new
// satellite not yet in the local TLE, like TEVEL2/RS95S):
// skip it. Returning empty is correct — crashing here (via
// all.first()) aborted the WHOLE list update and kept the
// stale pre-whitelist FM list with all five ISS modules.
if (all.isEmpty()) return emptySet()
if (all.size <= 1) return all
val preferred = all.intersect(activeCatnums)
if (preferred.isNotEmpty()) return preferred
@@ -244,6 +244,43 @@ class DatabaseRepoTest {
assertEquals(setOf(25544), settingsRepo.amSatFm)
}
@Test
fun `amsat fm list survives unknown satellite names and still disambiguates ISS`() = runTest(dispatcher) {
// Regression: AMSAT pages list satellites absent from the local TLE
// (TEVEL2-1..9, RS95S). resolvePerName used to crash on the empty
// match set (all.first()), aborting the WHOLE list update and keeping
// the stale pre-whitelist FM list with all five ISS modules.
val satnogsUrl = Sources.satelliteDataUrls.getValue("SatNOGS")
val localSource = FakeLocalSource()
val remoteSource = FakeRemoteSource().apply {
networkStreams[satnogsUrl] = { issModulesCsvStream() }
networkStreams[Sources.amSatLiveUrls.getValue("FM")] = { amsatFmPageWithUnknownStream() }
}
val settingsRepo = FakeSettingsRepo(
dataSources = DataSourcesSettings(
satelliteUrls = listOf(satnogsUrl),
transceiversUrls = emptyList()
)
).apply { amSatActive = setOf(25544) }
val repository = DatabaseRepo(dispatcher, dataParser, localSource, remoteSource, settingsRepo)
repository.updateFromRemote()
// No crash; ISS still collapses to the primary ZARYA (25544).
assertEquals(setOf(25544), settingsRepo.amSatFm)
}
private fun amsatFmPageWithUnknownStream(): InputStream = """
<table>
<thead><tr><th>Satellite</th><th>Uplink</th><th>Downlink</th><th>Comment</th></tr></thead>
<tbody>
<tr><td>ISS</td><td>145.990 MHz</td><td>437.800 MHz</td><td></td></tr>
<tr><td>TEVEL2-1 thru TEVEL2-9</td><td>145.970 MHz</td><td>436.400 MHz</td><td></td></tr>
<tr><td>RS95S(QMR-KWT-2)</td><td>145.920 MHz</td><td>436.950 MHz</td><td></td></tr>
</tbody>
</table>
""".trimIndent().byteInputStream()
private fun issModulesCsvStream(): InputStream = """
OBJECT_NAME,OBJECT_ID,EPOCH,MEAN_MOTION,ECCENTRICITY,INCLINATION,RA_OF_ASC_NODE,ARG_OF_PERICENTER,MEAN_ANOMALY,EPHEMERIS_TYPE,CLASSIFICATION_TYPE,NORAD_CAT_ID,ELEMENT_SET_NO,REV_AT_EPOCH,BSTAR,MEAN_MOTION_DOT,MEAN_MOTION_DDOT
ISS (ZARYA),1998-067A,2021-11-16T12:28:09.322176,15.48582035,.0004694,51.6447,309.4881,203.6966,299.8876,0,U,25544,999,31220,.31985E-4,.1288E-4,0
+2 -2
View File
@@ -1,8 +1,8 @@
[versions]
#noinspection UnusedVersionCatalogEntry
appVersionCode = "503"
appVersionCode = "504"
#noinspection UnusedVersionCatalogEntry
appVersionName = "4.4.7-ba7opf.15.6"
appVersionName = "4.4.7-ba7opf.15.7"
#noinspection UnusedVersionCatalogEntry
compileSdk = "37"
#noinspection UnusedVersionCatalogEntry