From 50c2a19743bc772129cb9ce244f72f0403e4ae43 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Fri, 16 Sep 2022 21:08:37 +0200 Subject: [PATCH] NSCLIENT: upload only valid profiles --- .../DataSyncSelectorImplementation.kt | 1 + .../androidaps/interfaces/ProfileStore.kt | 20 ++++++-- .../androidaps/TestBaseWithProfile.kt | 45 +++++++++++++++++- .../androidaps/interfaces/ProfileStoreTest.kt | 46 +++++++++++++++++++ .../plugins/aps/loop/APSResultTest.kt | 5 -- 5 files changed, 108 insertions(+), 9 deletions(-) create mode 100644 core/src/test/java/info/nightscout/androidaps/interfaces/ProfileStoreTest.kt diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/DataSyncSelectorImplementation.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/DataSyncSelectorImplementation.kt index ff88b7e38f..2999ba9d32 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/DataSyncSelectorImplementation.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/DataSyncSelectorImplementation.kt @@ -940,6 +940,7 @@ class DataSyncSelectorImplementation @Inject constructor( val lastChange = sp.getLong(R.string.key_local_profile_last_change, 0) if (lastChange == 0L) return if (lastChange > lastSync) { + if (localProfilePlugin.profile?.allProfilesValid != true) return val profileJson = localProfilePlugin.profile?.data ?: return nsClientPlugin.nsClientService?.dbAdd("profile", profileJson, DataSyncSelector.PairProfileStore(profileJson, dateUtil.now()), "") } diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/ProfileStore.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/ProfileStore.kt index f471b01759..3a39fdb446 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/ProfileStore.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/ProfileStore.kt @@ -2,19 +2,26 @@ package info.nightscout.androidaps.interfaces import androidx.collection.ArrayMap import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.data.ProfileSealed import info.nightscout.androidaps.data.PureProfile import info.nightscout.androidaps.extensions.pureProfileFromJson -import info.nightscout.shared.logging.AAPSLogger +import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.HardLimits import info.nightscout.androidaps.utils.JsonHelper +import info.nightscout.shared.logging.AAPSLogger import org.json.JSONException import org.json.JSONObject -import java.util.* import javax.inject.Inject class ProfileStore(val injector: HasAndroidInjector, val data: JSONObject, val dateUtil: DateUtil) { @Inject lateinit var aapsLogger: AAPSLogger + @Inject lateinit var activePlugin: ActivePlugin + @Inject lateinit var config: Config + @Inject lateinit var rh: ResourceHelper + @Inject lateinit var rxBus: RxBus + @Inject lateinit var hardLimits: HardLimits init { injector.androidInjector().inject(this) @@ -22,7 +29,7 @@ class ProfileStore(val injector: HasAndroidInjector, val data: JSONObject, val d private val cachedObjects = ArrayMap() - private fun storeUnits() : String? = JsonHelper.safeGetStringAllowNull(data, "units", null) + private fun storeUnits(): String? = JsonHelper.safeGetStringAllowNull(data, "units", null) private fun getStore(): JSONObject? { try { @@ -86,4 +93,11 @@ class ProfileStore(val injector: HasAndroidInjector, val data: JSONObject, val d } return null } + + val allProfilesValid: Boolean + get() = getProfileList() + .asSequence() + .map { profileName -> getSpecificProfile(profileName.toString()) } + .map { pureProfile -> pureProfile?.let { ProfileSealed.Pure(pureProfile).isValid("allProfilesValid", activePlugin.activePump, config, rh, rxBus, hardLimits, false) } } + .all { it?.isValid == true} } diff --git a/core/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt b/core/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt index d2b0723d59..8d6807485d 100644 --- a/core/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt +++ b/core/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt @@ -1,22 +1,27 @@ package info.nightscout.androidaps +import android.content.Context import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.data.ProfileSealed +import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.extensions.pureProfileFromJson import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.interfaces.Profile import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileStore +import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DefaultValueHelper import info.nightscout.androidaps.utils.FabricPrivacy -import info.nightscout.androidaps.interfaces.ResourceHelper +import info.nightscout.androidaps.utils.HardLimits +import info.nightscout.shared.sharedPreferences.SP import org.json.JSONObject import org.junit.Before import org.mockito.Mock +import org.mockito.Mockito @Suppress("SpellCheckingInspection") open class TestBaseWithProfile : TestBase() { @@ -28,24 +33,44 @@ open class TestBaseWithProfile : TestBase() { @Mock lateinit var defaultValueHelper: DefaultValueHelper @Mock lateinit var dateUtil: DateUtil @Mock lateinit var config: Config + @Mock lateinit var sp: SP + @Mock lateinit var context: Context + @Mock lateinit var repository: AppRepository + + lateinit var testPumpPlugin: TestPumpPlugin val rxBus = RxBus(aapsSchedulers, aapsLogger) val profileInjector = HasAndroidInjector { AndroidInjector { + if (it is ProfileStore) { + it.aapsLogger = aapsLogger + it.activePlugin = activePluginProvider + it.config = config + it.rh = rh + it.rxBus = rxBus + it.hardLimits = HardLimits(aapsLogger, rxBus, sp, rh, context, repository) + } } } + private lateinit var invalidProfileJSON: String private lateinit var validProfileJSON: String lateinit var validProfile: Profile + lateinit var invalidProfile: Profile @Suppress("PropertyName") val TESTPROFILENAME = "someProfile" @Before fun prepareMock() { + invalidProfileJSON = "{\"dia\":\"1\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"3\"}," + + "{\"time\":\"2:00\",\"value\":\"3.4\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4.5\"}]," + + "\"target_high\":[{\"time\":\"00:00\",\"value\":\"7\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}" validProfileJSON = "{\"dia\":\"5\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"3\"}," + "{\"time\":\"2:00\",\"value\":\"3.4\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4.5\"}]," + "\"target_high\":[{\"time\":\"00:00\",\"value\":\"7\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}" validProfile = ProfileSealed.Pure(pureProfileFromJson(JSONObject(validProfileJSON), dateUtil)!!) + testPumpPlugin = TestPumpPlugin(profileInjector) + Mockito.`when`(activePluginProvider.activePump).thenReturn(testPumpPlugin) } fun getValidProfileStore(): ProfileStore { @@ -56,4 +81,22 @@ open class TestBaseWithProfile : TestBase() { json.put("store", store) return ProfileStore(profileInjector, json, dateUtil) } + + fun getInvalidProfileStore1(): ProfileStore { + val json = JSONObject() + val store = JSONObject() + store.put(TESTPROFILENAME, JSONObject(invalidProfileJSON)) + json.put("defaultProfile", TESTPROFILENAME) + json.put("store", store) + return ProfileStore(profileInjector, json, dateUtil) + } + fun getInvalidProfileStore2(): ProfileStore { + val json = JSONObject() + val store = JSONObject() + store.put(TESTPROFILENAME, JSONObject(validProfileJSON)) + store.put("invalid", JSONObject(invalidProfileJSON)) + json.put("defaultProfile", TESTPROFILENAME) + json.put("store", store) + return ProfileStore(profileInjector, json, dateUtil) + } } diff --git a/core/src/test/java/info/nightscout/androidaps/interfaces/ProfileStoreTest.kt b/core/src/test/java/info/nightscout/androidaps/interfaces/ProfileStoreTest.kt new file mode 100644 index 0000000000..cd5f464d24 --- /dev/null +++ b/core/src/test/java/info/nightscout/androidaps/interfaces/ProfileStoreTest.kt @@ -0,0 +1,46 @@ +package info.nightscout.androidaps.interfaces + +import info.nightscout.androidaps.TestBaseWithProfile +import info.nightscout.androidaps.data.PureProfile +import org.junit.Assert +import org.junit.Test + +internal class ProfileStoreTest : TestBaseWithProfile() { + + @Test + fun getStartDateTest() { + Assert.assertEquals(0, getValidProfileStore().getStartDate()) + } + + @Test + fun getDefaultProfileTest() { + Assert.assertTrue(getValidProfileStore().getDefaultProfile() is PureProfile) + } + + @Test + fun getDefaultProfileJsonTest() { + Assert.assertTrue(getValidProfileStore().getDefaultProfileJson()?.has("dia") ?: false) + } + + @Test + fun getDefaultProfileNameTest() { + Assert.assertEquals(TESTPROFILENAME, getValidProfileStore().getDefaultProfileName()) + } + + @Test + fun getProfileListTest() { + Assert.assertEquals(1, getValidProfileStore().getProfileList().size) + } + + @Test + fun getSpecificProfileTest() { + Assert.assertTrue(getValidProfileStore().getSpecificProfile(TESTPROFILENAME) is PureProfile) + } + + @Test + fun allProfilesValidTest() { + Assert.assertTrue(getValidProfileStore().allProfilesValid) + Assert.assertFalse(getInvalidProfileStore1().allProfilesValid) + Assert.assertFalse(getInvalidProfileStore2().allProfilesValid) + } +} \ No newline at end of file diff --git a/core/src/test/java/info/nightscout/androidaps/plugins/aps/loop/APSResultTest.kt b/core/src/test/java/info/nightscout/androidaps/plugins/aps/loop/APSResultTest.kt index 8ae8a2a2b3..b2ed11b65e 100644 --- a/core/src/test/java/info/nightscout/androidaps/plugins/aps/loop/APSResultTest.kt +++ b/core/src/test/java/info/nightscout/androidaps/plugins/aps/loop/APSResultTest.kt @@ -3,14 +3,12 @@ package info.nightscout.androidaps.plugins.aps.loop import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.TestBaseWithProfile -import info.nightscout.androidaps.TestPumpPlugin import info.nightscout.androidaps.database.entities.TemporaryBasal import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.pump.common.defs.PumpType import info.nightscout.androidaps.utils.JsonHelper.safeGetDouble -import info.nightscout.shared.sharedPreferences.SP import org.junit.Assert import org.junit.Before import org.junit.Test @@ -21,10 +19,8 @@ import org.mockito.Mockito.`when` class APSResultTest : TestBaseWithProfile() { @Mock lateinit var constraintChecker: ConstraintChecker - @Mock lateinit var sp: SP @Mock lateinit var iobCobCalculator: IobCobCalculator - private lateinit var testPumpPlugin: TestPumpPlugin private val injector = HasAndroidInjector { AndroidInjector { } } private var closedLoopEnabled = Constraint(false) @@ -188,7 +184,6 @@ class APSResultTest : TestBaseWithProfile() { @Before fun prepare() { - testPumpPlugin = TestPumpPlugin(profileInjector) `when`(constraintChecker.isClosedLoopAllowed()).thenReturn(closedLoopEnabled) `when`(activePluginProvider.activePump).thenReturn(testPumpPlugin) `when`(sp.getDouble(ArgumentMatchers.anyInt(), ArgumentMatchers.anyDouble())).thenReturn(30.0)