NSCLIENT: upload only valid profiles

This commit is contained in:
Milos Kozak 2022-09-16 21:08:37 +02:00
parent 5d1699e0da
commit 867302dd29
5 changed files with 108 additions and 9 deletions

View file

@ -940,6 +940,7 @@ class DataSyncSelectorImplementation @Inject constructor(
val lastChange = sp.getLong(R.string.key_local_profile_last_change, 0) val lastChange = sp.getLong(R.string.key_local_profile_last_change, 0)
if (lastChange == 0L) return if (lastChange == 0L) return
if (lastChange > lastSync) { if (lastChange > lastSync) {
if (localProfilePlugin.profile?.allProfilesValid != true) return
val profileJson = localProfilePlugin.profile?.data ?: return val profileJson = localProfilePlugin.profile?.data ?: return
nsClientPlugin.nsClientService?.dbAdd("profile", profileJson, DataSyncSelector.PairProfileStore(profileJson, dateUtil.now()), "") nsClientPlugin.nsClientService?.dbAdd("profile", profileJson, DataSyncSelector.PairProfileStore(profileJson, dateUtil.now()), "")
} }

View file

@ -2,19 +2,26 @@ package info.nightscout.androidaps.interfaces
import androidx.collection.ArrayMap import androidx.collection.ArrayMap
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.data.ProfileSealed
import info.nightscout.androidaps.data.PureProfile import info.nightscout.androidaps.data.PureProfile
import info.nightscout.androidaps.extensions.pureProfileFromJson 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.DateUtil
import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.JsonHelper import info.nightscout.androidaps.utils.JsonHelper
import info.nightscout.shared.logging.AAPSLogger
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
import java.util.*
import javax.inject.Inject import javax.inject.Inject
class ProfileStore(val injector: HasAndroidInjector, val data: JSONObject, val dateUtil: DateUtil) { class ProfileStore(val injector: HasAndroidInjector, val data: JSONObject, val dateUtil: DateUtil) {
@Inject lateinit var aapsLogger: AAPSLogger @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 { init {
injector.androidInjector().inject(this) injector.androidInjector().inject(this)
@ -86,4 +93,11 @@ class ProfileStore(val injector: HasAndroidInjector, val data: JSONObject, val d
} }
return null 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}
} }

View file

@ -1,22 +1,27 @@
package info.nightscout.androidaps package info.nightscout.androidaps
import android.content.Context
import dagger.android.AndroidInjector import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.data.ProfileSealed import info.nightscout.androidaps.data.ProfileSealed
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.extensions.pureProfileFromJson import info.nightscout.androidaps.extensions.pureProfileFromJson
import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.interfaces.Profile import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.ProfileStore import info.nightscout.androidaps.interfaces.ProfileStore
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DefaultValueHelper import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.FabricPrivacy 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.json.JSONObject
import org.junit.Before import org.junit.Before
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito
@Suppress("SpellCheckingInspection") @Suppress("SpellCheckingInspection")
open class TestBaseWithProfile : TestBase() { open class TestBaseWithProfile : TestBase() {
@ -28,24 +33,44 @@ open class TestBaseWithProfile : TestBase() {
@Mock lateinit var defaultValueHelper: DefaultValueHelper @Mock lateinit var defaultValueHelper: DefaultValueHelper
@Mock lateinit var dateUtil: DateUtil @Mock lateinit var dateUtil: DateUtil
@Mock lateinit var config: Config @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 rxBus = RxBus(aapsSchedulers, aapsLogger)
val profileInjector = HasAndroidInjector { val profileInjector = HasAndroidInjector {
AndroidInjector { 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 private lateinit var validProfileJSON: String
lateinit var validProfile: Profile lateinit var validProfile: Profile
lateinit var invalidProfile: Profile
@Suppress("PropertyName") val TESTPROFILENAME = "someProfile" @Suppress("PropertyName") val TESTPROFILENAME = "someProfile"
@Before @Before
fun prepareMock() { 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\"}," + 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\"}]," + "{\"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\"}" "\"target_high\":[{\"time\":\"00:00\",\"value\":\"7\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
validProfile = ProfileSealed.Pure(pureProfileFromJson(JSONObject(validProfileJSON), dateUtil)!!) validProfile = ProfileSealed.Pure(pureProfileFromJson(JSONObject(validProfileJSON), dateUtil)!!)
testPumpPlugin = TestPumpPlugin(profileInjector)
Mockito.`when`(activePluginProvider.activePump).thenReturn(testPumpPlugin)
} }
fun getValidProfileStore(): ProfileStore { fun getValidProfileStore(): ProfileStore {
@ -56,4 +81,22 @@ open class TestBaseWithProfile : TestBase() {
json.put("store", store) json.put("store", store)
return ProfileStore(profileInjector, json, dateUtil) 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)
}
} }

View file

@ -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)
}
}

View file

@ -3,14 +3,12 @@ package info.nightscout.androidaps.plugins.aps.loop
import dagger.android.AndroidInjector import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.androidaps.TestBaseWithProfile
import info.nightscout.androidaps.TestPumpPlugin
import info.nightscout.androidaps.database.entities.TemporaryBasal import info.nightscout.androidaps.database.entities.TemporaryBasal
import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.IobCobCalculator
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
import info.nightscout.androidaps.utils.JsonHelper.safeGetDouble import info.nightscout.androidaps.utils.JsonHelper.safeGetDouble
import info.nightscout.shared.sharedPreferences.SP
import org.junit.Assert import org.junit.Assert
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@ -21,10 +19,8 @@ import org.mockito.Mockito.`when`
class APSResultTest : TestBaseWithProfile() { class APSResultTest : TestBaseWithProfile() {
@Mock lateinit var constraintChecker: ConstraintChecker @Mock lateinit var constraintChecker: ConstraintChecker
@Mock lateinit var sp: SP
@Mock lateinit var iobCobCalculator: IobCobCalculator @Mock lateinit var iobCobCalculator: IobCobCalculator
private lateinit var testPumpPlugin: TestPumpPlugin
private val injector = HasAndroidInjector { AndroidInjector { } } private val injector = HasAndroidInjector { AndroidInjector { } }
private var closedLoopEnabled = Constraint(false) private var closedLoopEnabled = Constraint(false)
@ -188,7 +184,6 @@ class APSResultTest : TestBaseWithProfile() {
@Before @Before
fun prepare() { fun prepare() {
testPumpPlugin = TestPumpPlugin(profileInjector)
`when`(constraintChecker.isClosedLoopAllowed()).thenReturn(closedLoopEnabled) `when`(constraintChecker.isClosedLoopAllowed()).thenReturn(closedLoopEnabled)
`when`(activePluginProvider.activePump).thenReturn(testPumpPlugin) `when`(activePluginProvider.activePump).thenReturn(testPumpPlugin)
`when`(sp.getDouble(ArgumentMatchers.anyInt(), ArgumentMatchers.anyDouble())).thenReturn(30.0) `when`(sp.getDouble(ArgumentMatchers.anyInt(), ArgumentMatchers.anyDouble())).thenReturn(30.0)