NSClientV3PluginTest

This commit is contained in:
Milos Kozak 2023-01-04 15:41:04 +01:00
parent d190b53713
commit eb1fff54f1
7 changed files with 137 additions and 33 deletions

View file

@ -46,6 +46,6 @@ interface NsClient : Sync {
fun resetToFullSync()
fun dbAdd(collection: String, dataPair: DataSyncSelector.DataPair, progress: String)
fun dbUpdate(collection: String, dataPair: DataSyncSelector.DataPair, progress: String)
fun nsAdd(collection: String, dataPair: DataSyncSelector.DataPair, progress: String)
fun nsUpdate(collection: String, dataPair: DataSyncSelector.DataPair, progress: String)
}

View file

@ -26,6 +26,7 @@ dependencies {
implementation project(':core:utils')
implementation project(':core:validators')
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version"
testImplementation "androidx.work:work-testing:$work_version"
testImplementation project(':implementation')
testImplementation project(':plugins:aps')

View file

@ -135,14 +135,14 @@ class DataSyncSelectorImplementation @Inject constructor(
}
// without nsId = create new
bolus.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.dbAdd(
activePlugin.activeNsClient?.nsAdd(
"treatments",
DataSyncSelector.PairBolus(bolus.first, bolus.second.id),
" $startId/$lastDbId"
)
// with nsId = update if it's modified record
bolus.first.interfaceIDs.nightscoutId != null && bolus.first.id != bolus.second.id ->
activePlugin.activeNsClient?.dbUpdate(
activePlugin.activeNsClient?.nsUpdate(
"treatments",
DataSyncSelector.PairBolus(bolus.first, bolus.second.id),
"$startId/$lastDbId"
@ -188,10 +188,10 @@ class DataSyncSelectorImplementation @Inject constructor(
}
// without nsId = create new
carb.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.dbAdd("treatments", DataSyncSelector.PairCarbs(carb.first, carb.second.id), "$startId/$lastDbId")
activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairCarbs(carb.first, carb.second.id), "$startId/$lastDbId")
// with nsId = update if it's modified record
carb.first.interfaceIDs.nightscoutId != null && carb.first.id != carb.second.id ->
activePlugin.activeNsClient?.dbUpdate(
activePlugin.activeNsClient?.nsUpdate(
"treatments",
DataSyncSelector.PairCarbs(carb.first, carb.second.id),
"$startId/$lastDbId"
@ -237,14 +237,14 @@ class DataSyncSelectorImplementation @Inject constructor(
}
// without nsId = create new
bolusCalculatorResult.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.dbAdd(
activePlugin.activeNsClient?.nsAdd(
"treatments",
DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second.id),
"$startId/$lastDbId"
)
// with nsId = update if it's modified record
bolusCalculatorResult.first.interfaceIDs.nightscoutId != null && bolusCalculatorResult.first.id != bolusCalculatorResult.second.id ->
activePlugin.activeNsClient?.dbUpdate(
activePlugin.activeNsClient?.nsUpdate(
"treatments",
DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second.id), "$startId/$lastDbId"
)
@ -289,14 +289,14 @@ class DataSyncSelectorImplementation @Inject constructor(
}
// without nsId = create new
tt.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.dbAdd(
activePlugin.activeNsClient?.nsAdd(
"treatments",
DataSyncSelector.PairTemporaryTarget(tt.first, tt.second.id),
"$startId/$lastDbId"
)
// existing with nsId = update
tt.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.dbUpdate(
activePlugin.activeNsClient?.nsUpdate(
"treatments",
DataSyncSelector.PairTemporaryTarget(tt.first, tt.second.id),
"$startId/$lastDbId"
@ -342,10 +342,10 @@ class DataSyncSelectorImplementation @Inject constructor(
}
// without nsId = create new
food.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.dbAdd("food", DataSyncSelector.PairFood(food.first, food.second.id), "$startId/$lastDbId")
activePlugin.activeNsClient?.nsAdd("food", DataSyncSelector.PairFood(food.first, food.second.id), "$startId/$lastDbId")
// with nsId = update
food.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.dbUpdate(
activePlugin.activeNsClient?.nsUpdate(
"food",
DataSyncSelector.PairFood(food.first, food.second.id),
"$startId/$lastDbId"
@ -392,10 +392,10 @@ class DataSyncSelectorImplementation @Inject constructor(
}
// without nsId = create new
gv.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.dbAdd("entries", DataSyncSelector.PairGlucoseValue(gv.first, gv.second.id), "$startId/$lastDbId")
activePlugin.activeNsClient?.nsAdd("entries", DataSyncSelector.PairGlucoseValue(gv.first, gv.second.id), "$startId/$lastDbId")
// with nsId = update
else -> // gv.first.interfaceIDs.nightscoutId != null
activePlugin.activeNsClient?.dbUpdate(
activePlugin.activeNsClient?.nsUpdate(
"entries",
DataSyncSelector.PairGlucoseValue(gv.first, gv.second.id),
"$startId/$lastDbId"
@ -445,10 +445,10 @@ class DataSyncSelectorImplementation @Inject constructor(
}
// without nsId = create new
te.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.dbAdd("treatments", DataSyncSelector.PairTherapyEvent(te.first, te.second.id), "$startId/$lastDbId")
activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairTherapyEvent(te.first, te.second.id), "$startId/$lastDbId")
// nsId = update
te.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.dbUpdate(
activePlugin.activeNsClient?.nsUpdate(
"treatments",
DataSyncSelector.PairTherapyEvent(te.first, te.second.id),
"$startId/$lastDbId"
@ -480,7 +480,7 @@ class DataSyncSelectorImplementation @Inject constructor(
when {
// without nsId = create new
deviceStatus.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.dbAdd("devicestatus", DataSyncSelector.PairDeviceStatus(deviceStatus, 0), "$startId/$lastDbId")
activePlugin.activeNsClient?.nsAdd("devicestatus", DataSyncSelector.PairDeviceStatus(deviceStatus, 0), "$startId/$lastDbId")
// with nsId = ignore
deviceStatus.interfaceIDs.nightscoutId != null -> Any()
}
@ -524,14 +524,14 @@ class DataSyncSelectorImplementation @Inject constructor(
}
// without nsId = create new
tb.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.dbAdd(
activePlugin.activeNsClient?.nsAdd(
"treatments",
DataSyncSelector.PairTemporaryBasal(tb.first, tb.second.id),
"$startId/$lastDbId"
)
// with nsId = update
tb.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.dbUpdate(
activePlugin.activeNsClient?.nsUpdate(
"treatments",
DataSyncSelector.PairTemporaryBasal(tb.first, tb.second.id),
"$startId/$lastDbId"
@ -579,14 +579,14 @@ class DataSyncSelectorImplementation @Inject constructor(
}
// without nsId = create new
eb.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.dbAdd(
activePlugin.activeNsClient?.nsAdd(
"treatments",
DataSyncSelector.PairExtendedBolus(eb.first, eb.second.id),
"$startId/$lastDbId"
)
// with nsId = update
eb.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.dbUpdate(
activePlugin.activeNsClient?.nsUpdate(
"treatments",
DataSyncSelector.PairExtendedBolus(eb.first, eb.second.id),
"$startId/$lastDbId"
@ -638,10 +638,10 @@ class DataSyncSelectorImplementation @Inject constructor(
}
// without nsId = create new
ps.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.dbAdd("treatments", DataSyncSelector.PairProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId")
activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId")
// with nsId = update
ps.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.dbUpdate(
activePlugin.activeNsClient?.nsUpdate(
"treatments",
DataSyncSelector.PairProfileSwitch(ps.first, ps.second.id),
"$startId/$lastDbId"
@ -687,14 +687,14 @@ class DataSyncSelectorImplementation @Inject constructor(
}
// without nsId = create new
ps.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.dbAdd(
activePlugin.activeNsClient?.nsAdd(
"treatments",
DataSyncSelector.PairEffectiveProfileSwitch(ps.first, ps.second.id),
"$startId/$lastDbId"
)
// with nsId = update
ps.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.dbUpdate(
activePlugin.activeNsClient?.nsUpdate(
"treatments",
DataSyncSelector.PairEffectiveProfileSwitch(ps.first, ps.second.id),
"$startId/$lastDbId"
@ -740,10 +740,10 @@ class DataSyncSelectorImplementation @Inject constructor(
}
// without nsId = create new
oe.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.dbAdd("treatments", DataSyncSelector.PairOfflineEvent(oe.first, oe.second.id), "$startId/$lastDbId")
activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairOfflineEvent(oe.first, oe.second.id), "$startId/$lastDbId")
// existing with nsId = update
oe.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.dbUpdate(
activePlugin.activeNsClient?.nsUpdate(
"treatments",
DataSyncSelector.PairOfflineEvent(oe.first, oe.second.id),
"$startId/$lastDbId"
@ -765,7 +765,7 @@ class DataSyncSelectorImplementation @Inject constructor(
if (lastChange > lastSync) {
if (activePlugin.activeProfileSource.profile?.allProfilesValid != true) return
val profileJson = activePlugin.activeProfileSource.profile?.data ?: return
activePlugin.activeNsClient?.dbAdd("profile", DataSyncSelector.PairProfileStore(profileJson, dateUtil.now()), "")
activePlugin.activeNsClient?.nsAdd("profile", DataSyncSelector.PairProfileStore(profileJson, dateUtil.now()), "")
}
}
}

View file

@ -244,7 +244,7 @@ class NSClientPlugin @Inject constructor(
dataSyncSelector.resetToNextFullSync()
}
override fun dbAdd(collection: String, dataPair: DataSyncSelector.DataPair, progress: String) {
override fun nsAdd(collection: String, dataPair: DataSyncSelector.DataPair, progress: String) {
when (dataPair) {
is DataSyncSelector.PairBolus -> dataPair.value.toJson(true, dateUtil)
is DataSyncSelector.PairCarbs -> dataPair.value.toJson(true, dateUtil)
@ -266,7 +266,7 @@ class NSClientPlugin @Inject constructor(
}
}
override fun dbUpdate(collection: String, dataPair: DataSyncSelector.DataPair, progress: String) {
override fun nsUpdate(collection: String, dataPair: DataSyncSelector.DataPair, progress: String) {
val id = when (dataPair) {
is DataSyncSelector.PairBolus -> dataPair.value.interfaceIDs.nightscoutId
is DataSyncSelector.PairCarbs -> dataPair.value.interfaceIDs.nightscoutId

View file

@ -1,5 +1,6 @@
package info.nightscout.plugins.sync.nsclient
import info.nightscout.androidaps.annotations.OpenForTesting
import info.nightscout.interfaces.receivers.ReceiverStatusStore
import info.nightscout.plugins.sync.R
import info.nightscout.rx.bus.RxBus
@ -11,6 +12,7 @@ import info.nightscout.shared.sharedPreferences.SP
import javax.inject.Inject
import javax.inject.Singleton
@OpenForTesting
@Singleton
class NsClientReceiverDelegate @Inject constructor(
private val rxBus: RxBus,

View file

@ -120,7 +120,7 @@ class NSClientV3Plugin @Inject constructor(
}
private val disposable = CompositeDisposable()
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
var scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
private lateinit var runLoop: Runnable
private val handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
private val listLog: MutableList<EventNSClientNewLog> = ArrayList()
@ -320,11 +320,11 @@ class NSClientV3Plugin @Inject constructor(
storeLastLoadedSrvModified()
}
override fun dbAdd(collection: String, dataPair: DataSyncSelector.DataPair, progress: String) {
override fun nsAdd(collection: String, dataPair: DataSyncSelector.DataPair, progress: String) {
dbOperation(collection, dataPair, progress, Operation.CREATE)
}
override fun dbUpdate(collection: String, dataPair: DataSyncSelector.DataPair, progress: String) {
override fun nsUpdate(collection: String, dataPair: DataSyncSelector.DataPair, progress: String) {
dbOperation(collection, dataPair, progress, Operation.UPDATE)
}

View file

@ -0,0 +1,101 @@
package info.nightscout.plugins.sync.nsclientV3
import android.content.Context
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.TestBase
import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.database.entities.DeviceStatus
import info.nightscout.database.impl.AppRepository
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.XDripBroadcast
import info.nightscout.interfaces.logging.UserEntryLogger
import info.nightscout.interfaces.nsclient.StoreDataForDb
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.pump.VirtualPump
import info.nightscout.interfaces.source.NSClientSource
import info.nightscout.interfaces.sync.DataSyncSelector
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.plugins.sync.nsShared.StoreDataForDbImpl
import info.nightscout.plugins.sync.nsclient.NsClientReceiverDelegate
import info.nightscout.rx.bus.RxBus
import info.nightscout.sdk.interfaces.NSAndroidClient
import info.nightscout.sdk.localmodel.treatment.CreateUpdateResponse
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.internal.verification.Times
@Suppress("SpellCheckingInspection")
internal class NSClientV3PluginTest : TestBase() {
@Mock lateinit var rxBus: RxBus
@Mock lateinit var rh: ResourceHelper
@Mock lateinit var context: Context
@Mock lateinit var fabricPrivacy: FabricPrivacy
@Mock lateinit var sp: SP
@Mock lateinit var nsClientReceiverDelegate: NsClientReceiverDelegate
@Mock lateinit var config: Config
@Mock lateinit var dateUtil: DateUtil
@Mock lateinit var uiInteraction: UiInteraction
@Mock lateinit var dataSyncSelector: DataSyncSelector
@Mock lateinit var profileFunction: ProfileFunction
@Mock lateinit var nsAndroidClient: NSAndroidClient
@Mock lateinit var repository: AppRepository
@Mock lateinit var uel: UserEntryLogger
@Mock lateinit var nsClientSource: NSClientSource
@Mock lateinit var xDripBroadcast: XDripBroadcast
@Mock lateinit var virtualPump: VirtualPump
private lateinit var storeDataForDb: StoreDataForDb
private lateinit var sut: NSClientV3Plugin
private val injector = HasAndroidInjector {
AndroidInjector {
}
}
@BeforeEach
fun prepare() {
storeDataForDb = StoreDataForDbImpl(aapsLogger, rxBus, repository, sp, uel, dateUtil, config, nsClientSource, xDripBroadcast, virtualPump, uiInteraction)
sut =
NSClientV3Plugin(
injector, aapsLogger, aapsSchedulers, rxBus, rh, context, fabricPrivacy,
sp, nsClientReceiverDelegate, config, dateUtil, uiInteraction, storeDataForDb, dataSyncSelector, profileFunction
)
sut.nsAndroidClient = nsAndroidClient
}
@Test
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
fun nsAddDeviceStatus() = runTest {
sut.scope = CoroutineScope(UnconfinedTestDispatcher(testScheduler))
val deviceStatus = DeviceStatus(
timestamp = 10000,
suggested = "{\"temp\":\"absolute\",\"bg\":133,\"tick\":-6,\"eventualBG\":67,\"targetBG\":99,\"insulinReq\":0,\"deliverAt\":\"2023-01-02T15:29:33.374Z\",\"sensitivityRatio\":1,\"variable_sens\":97.5,\"predBGs\":{\"IOB\":[133,127,121,116,111,106,101,97,93,89,85,81,78,75,72,69,67,65,62,60,58,57,55,54,52,51,50,49,48,47,46,45,45,44,43,43,42,42,41,41,41,41,40,40,40,40,39],\"ZT\":[133,127,121,115,110,105,101,96,92,88,84,81,77,74,71,69,66,64,62,59,58,56,54,53,51,50,49,48,47,46,45,44,44,43,42,42,41,41,40,40,40,39,39,39,39,39,39,39],\"UAM\":[133,127,121,115,110,105,101,96,92,88,84,81,77,74,71,69,66,64,62,59,58,56,54,53,51,50,49,48,47,46,45,44,44,43,42,42,41,41,40,40,40,39]},\"reason\":\"COB: 0, Dev: 0.1, BGI: -0.3, ISF: 5.4, CR: 13, Target: 5.5, minPredBG 2.2, minGuardBG 2.1, IOBpredBG 2.2, UAMpredBG 2.2; minGuardBG 2.1<4.0\",\"COB\":0,\"IOB\":0.692,\"duration\":90,\"rate\":0,\"timestamp\":\"2023-01-02T15:29:39.460Z\"}",
iob = "{\"iob\":0.692,\"basaliob\":-0.411,\"activity\":0.0126,\"time\":\"2023-01-02T15:29:39.460Z\"}",
enacted = "{\"temp\":\"absolute\",\"bg\":133,\"tick\":-6,\"eventualBG\":67,\"targetBG\":99,\"insulinReq\":0,\"deliverAt\":\"2023-01-02T15:29:33.374Z\",\"sensitivityRatio\":1,\"variable_sens\":97.5,\"predBGs\":{\"IOB\":[133,127,121,116,111,106,101,97,93,89,85,81,78,75,72,69,67,65,62,60,58,57,55,54,52,51,50,49,48,47,46,45,45,44,43,43,42,42,41,41,41,41,40,40,40,40,39],\"ZT\":[133,127,121,115,110,105,101,96,92,88,84,81,77,74,71,69,66,64,62,59,58,56,54,53,51,50,49,48,47,46,45,44,44,43,42,42,41,41,40,40,40,39,39,39,39,39,39,39],\"UAM\":[133,127,121,115,110,105,101,96,92,88,84,81,77,74,71,69,66,64,62,59,58,56,54,53,51,50,49,48,47,46,45,44,44,43,42,42,41,41,40,40,40,39]},\"reason\":\"COB: 0, Dev: 0.1, BGI: -0.3, ISF: 5.4, CR: 13, Target: 5.5, minPredBG 2.2, minGuardBG 2.1, IOBpredBG 2.2, UAMpredBG 2.2; minGuardBG 2.1<4.0\",\"COB\":0,\"IOB\":0.692,\"duration\":90,\"rate\":0,\"timestamp\":\"2023-01-02T15:29:39.460Z\"}",
device = "openaps://samsung SM-G970F",
pump = "{\"battery\":{\"percent\":75},\"status\":{\"status\":\"normal\",\"timestamp\":\"2023-01-02T15:20:20.656Z\"},\"extended\":{\"Version\":\"3.1.0.3-dev-e-295e1ad18f-2022.12.24\"," +
"\"LastBolus\":\"02.01.23 15:24\",\"LastBolusAmount\":\"1\",\"TempBasalAbsoluteRate\":\"0\",\"TempBasalStart\":\"02.01.23 16:20\",\"TempBasalRemaining\":\"55\",\"BaseBasalRate\":\"0" +
".41\",\"ActiveProfile\":\"L29_U200 IC\"},\"reservoir\":\"133\",\"clock\":\"2023-01-02T15:25:05.826Z\"}",
uploaderBattery = 60,
configuration = "{\"insulin\":5,\"insulinConfiguration\":{},\"sensitivity\":2,\"sensitivityConfiguration\":{\"openapsama_min_5m_carbimpact\":8,\"absorption_cutoff\":4,\"autosens_max\":1.2,\"autosens_min\":0.7},\"overviewConfiguration\":{\"units\":\"mmol\",\"QuickWizard\":\"[]\",\"eatingsoon_duration\":60,\"eatingsoon_target\":4,\"activity_duration\":180,\"activity_target\":7.5,\"hypo_duration\":90,\"hypo_target\":8,\"low_mark\":3.9,\"high_mark\":10,\"statuslights_cage_warning\":72,\"statuslights_cage_critical\":96,\"statuslights_iage_warning\":120,\"statuslights_iage_critical\":150,\"statuslights_sage_warning\":168,\"statuslights_sage_critical\":336,\"statuslights_sbat_warning\":25,\"statuslights_sbat_critical\":5,\"statuslights_bage_warning\":720,\"statuslights_bage_critical\":800,\"statuslights_res_warning\":30,\"statuslights_res_critical\":10,\"statuslights_bat_warning\":50,\"statuslights_bat_critical\":25,\"boluswizard_percentage\":70},\"safetyConfiguration\":{\"age\":\"resistantadult\",\"treatmentssafety_maxbolus\":10,\"treatmentssafety_maxcarbs\":70}}"
)
val dataPair = DataSyncSelector.PairDeviceStatus(deviceStatus, 1000)
`when`(nsAndroidClient.createDeviceStatus(anyObject())).thenReturn(CreateUpdateResponse(201, null))
sut.nsAdd("devicestatus", dataPair, "1/3")
Assertions.assertEquals(1, storeDataForDb.nsIdDeviceStatuses.size)
verify(dataSyncSelector, Times(1)).confirmLastDeviceStatusIdIfGreater(1000)
verify(dataSyncSelector, Times(1)).processChangedDeviceStatusesCompat()
}
}