AndroidAPS/app/src/test/java/info/nightscout/androidaps/queue/CommandQueueImplementationTest.kt
2022-04-19 13:32:22 +02:00

506 lines
18 KiB
Kotlin

package info.nightscout.androidaps.queue
import android.content.Context
import android.os.PowerManager
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.TestBaseWithProfile
import info.nightscout.androidaps.TestPumpPlugin
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.data.PumpEnactResult
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.database.entities.Bolus
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.PumpSync
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.general.maintenance.PrefFileListProvider
import info.nightscout.androidaps.queue.commands.*
import info.nightscout.androidaps.utils.AndroidPermission
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.buildHelper.BuildHelperImpl
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.sharedPreferences.SP
import io.reactivex.rxjava3.core.Single
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.Mockito.anyLong
import java.util.*
class CommandQueueImplementationTest : TestBaseWithProfile() {
@Mock lateinit var constraintChecker: ConstraintChecker
@Mock lateinit var activePlugin: ActivePlugin
@Mock lateinit var sp: SP
@Mock lateinit var powerManager: PowerManager
@Mock lateinit var repository: AppRepository
@Mock lateinit var fileListProvider: PrefFileListProvider
@Mock lateinit var androidPermission: AndroidPermission
class CommandQueueMocked(
injector: HasAndroidInjector,
aapsLogger: AAPSLogger,
rxBus: RxBus,
aapsSchedulers: AapsSchedulers,
rh: ResourceHelper,
constraintChecker: ConstraintChecker,
profileFunction: ProfileFunction,
activePlugin: ActivePlugin,
context: Context,
sp: SP,
buildHelper: BuildHelper,
dateUtil: DateUtil,
repository: AppRepository,
fabricPrivacy: FabricPrivacy,
config: Config,
androidPermission: AndroidPermission
) : CommandQueueImplementation(injector, aapsLogger, rxBus, aapsSchedulers, rh, constraintChecker, profileFunction,
activePlugin, context, sp, buildHelper, dateUtil, repository, fabricPrivacy, config, androidPermission) {
override fun notifyAboutNewCommand() {}
}
val injector = HasAndroidInjector {
AndroidInjector {
if (it is Command) {
it.aapsLogger = aapsLogger
it.rh = rh
}
if (it is CommandTempBasalPercent) {
it.activePlugin = activePlugin
}
if (it is CommandBolus) {
it.activePlugin = activePlugin
it.rxBus = rxBus
}
if (it is CommandCustomCommand) {
it.activePlugin = activePlugin
}
if (it is CommandExtendedBolus) {
it.activePlugin = activePlugin
}
if (it is CommandLoadHistory) {
it.activePlugin = activePlugin
}
if (it is PumpEnactResult) {
it.rh = rh
}
}
}
private lateinit var commandQueue: CommandQueueImplementation
private lateinit var testPumpPlugin: TestPumpPlugin
@Before
fun prepare() {
commandQueue = CommandQueueMocked(injector, aapsLogger, rxBus, aapsSchedulers, rh,
constraintChecker, profileFunction, activePlugin, context, sp,
BuildHelperImpl(config, fileListProvider), dateUtil,
repository,
fabricPrivacy, config, androidPermission)
testPumpPlugin = TestPumpPlugin(injector)
testPumpPlugin.pumpDescription.basalMinimumRate = 0.1
`when`(context.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager)
`when`(activePlugin.activePump).thenReturn(testPumpPlugin)
`when`(repository.getEffectiveProfileSwitchActiveAt(anyLong())).thenReturn(Single.just(ValueWrapper.Existing(effectiveProfileSwitch)))
`when`(repository.getLastBolusRecord()).thenReturn(
Bolus(
timestamp = Calendar.getInstance().also { it.set(2000, 0, 1) }.timeInMillis,
type = Bolus.Type.NORMAL,
amount = 0.0
)
)
`when`(profileFunction.getProfile()).thenReturn(validProfile)
val bolusConstraint = Constraint(0.0)
`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(bolusConstraint)
`when`(constraintChecker.applyExtendedBolusConstraints(anyObject())).thenReturn(bolusConstraint)
val carbsConstraint = Constraint(0)
`when`(constraintChecker.applyCarbsConstraints(anyObject())).thenReturn(carbsConstraint)
val rateConstraint = Constraint(0.0)
`when`(constraintChecker.applyBasalConstraints(anyObject(), anyObject())).thenReturn(rateConstraint)
val percentageConstraint = Constraint(0)
`when`(constraintChecker.applyBasalPercentConstraints(anyObject(), anyObject())).thenReturn(percentageConstraint)
`when`(rh.gs(R.string.connectiontimedout)).thenReturn("Connection timed out")
`when`(rh.gs(R.string.formatinsulinunits)).thenReturn("%1\$.2f U")
}
@Test
fun commandIsPickedUp() {
val commandQueue = CommandQueueImplementation(injector, aapsLogger, rxBus, aapsSchedulers, rh,
constraintChecker, profileFunction, activePlugin, context, sp,
BuildHelperImpl(config, fileListProvider),
dateUtil, repository,
fabricPrivacy, config, androidPermission)
// start with empty queue
Assert.assertEquals(0, commandQueue.size())
// add bolus command
commandQueue.bolus(DetailedBolusInfo(), null)
Assert.assertEquals(1, commandQueue.size())
commandQueue.waitForFinishedThread()
Thread.sleep(1000)
Assert.assertEquals(0, commandQueue.size())
}
@Test
fun doTests() {
// start with empty queue
Assert.assertEquals(0, commandQueue.size())
// add bolus command
commandQueue.bolus(DetailedBolusInfo(), null)
Assert.assertEquals(1, commandQueue.size())
// add READSTATUS
commandQueue.readStatus("anyString", null)
Assert.assertEquals(2, commandQueue.size())
// adding another bolus should remove the first one (size still == 2)
commandQueue.bolus(DetailedBolusInfo(), null)
Assert.assertEquals(2, commandQueue.size())
// clear the queue should reset size
commandQueue.clear()
Assert.assertEquals(0, commandQueue.size())
// add tempbasal
commandQueue.tempBasalAbsolute(0.0, 30, true, validProfile, PumpSync.TemporaryBasalType.NORMAL, null)
Assert.assertEquals(1, commandQueue.size())
// add tempbasal percent. it should replace previous TEMPBASAL
commandQueue.tempBasalPercent(0, 30, true, validProfile, PumpSync.TemporaryBasalType.NORMAL, null)
Assert.assertEquals(1, commandQueue.size())
// cancel tempbasal it should replace previous TEMPBASAL
commandQueue.cancelTempBasal(false, null)
Assert.assertEquals(1, commandQueue.size())
// add extended bolus
commandQueue.extendedBolus(1.0, 30, null)
Assert.assertEquals(2, commandQueue.size())
// add extended should remove previous extended setting
commandQueue.extendedBolus(1.0, 30, null)
Assert.assertEquals(2, commandQueue.size())
// cancel extended bolus should replace previous extended
commandQueue.cancelExtended(null)
Assert.assertEquals(2, commandQueue.size())
// add setProfile
// TODO: this crash the test
// commandQueue.setProfile(validProfile, null)
// Assert.assertEquals(3, commandQueue.size())
// add loadHistory
commandQueue.loadHistory(0.toByte(), null)
Assert.assertEquals(3, commandQueue.size())
// add loadEvents
commandQueue.loadEvents(null)
Assert.assertEquals(4, commandQueue.size())
commandQueue.clear()
commandQueue.tempBasalAbsolute(0.0, 30, true, validProfile, PumpSync.TemporaryBasalType.NORMAL, null)
commandQueue.pickup()
Assert.assertEquals(0, commandQueue.size())
Assert.assertNotNull(commandQueue.performing)
Assert.assertEquals(Command.CommandType.TEMPBASAL, commandQueue.performing?.commandType)
commandQueue.resetPerforming()
Assert.assertNull(commandQueue.performing)
}
@Test
fun callingCancelAllBolusesClearsQueue() {
// given
Assert.assertEquals(0, commandQueue.size())
val smb = DetailedBolusInfo()
smb.lastKnownBolusTime = System.currentTimeMillis()
smb.bolusType = DetailedBolusInfo.BolusType.SMB
commandQueue.bolus(smb, null)
commandQueue.bolus(DetailedBolusInfo(), null)
Assert.assertEquals(2, commandQueue.size())
// when
commandQueue.cancelAllBoluses()
// then
Assert.assertEquals(0, commandQueue.size())
}
@Test
fun smbIsRejectedIfABolusIsQueued() {
// given
Assert.assertEquals(0, commandQueue.size())
// when
commandQueue.bolus(DetailedBolusInfo(), null)
val smb = DetailedBolusInfo()
smb.bolusType = DetailedBolusInfo.BolusType.SMB
val queued: Boolean = commandQueue.bolus(smb, null)
// then
Assert.assertFalse(queued)
Assert.assertEquals(commandQueue.size(), 1)
}
@Test
fun smbIsRejectedIfLastKnownBolusIsOutdated() {
// given
Assert.assertEquals(0, commandQueue.size())
// when
val bolus = DetailedBolusInfo()
bolus.bolusType = DetailedBolusInfo.BolusType.SMB
bolus.lastKnownBolusTime = 0
val queued: Boolean = commandQueue.bolus(bolus, null)
// then
Assert.assertFalse(queued)
Assert.assertEquals(commandQueue.size(), 0)
}
@Test
fun isCustomCommandRunning() {
// given
Assert.assertEquals(0, commandQueue.size())
// when
val queued1 = commandQueue.customCommand(CustomCommand1(), null)
val queued2 = commandQueue.customCommand(CustomCommand2(), null)
commandQueue.pickup()
// then
Assert.assertTrue(queued1)
Assert.assertTrue(queued2)
Assert.assertTrue(commandQueue.isCustomCommandInQueue(CustomCommand1::class.java))
Assert.assertTrue(commandQueue.isCustomCommandInQueue(CustomCommand2::class.java))
Assert.assertFalse(commandQueue.isCustomCommandInQueue(CustomCommand3::class.java))
Assert.assertTrue(commandQueue.isCustomCommandRunning(CustomCommand1::class.java))
Assert.assertFalse(commandQueue.isCustomCommandRunning(CustomCommand2::class.java))
Assert.assertFalse(commandQueue.isCustomCommandRunning(CustomCommand3::class.java))
Assert.assertEquals(1, commandQueue.size())
}
@Test
fun isSetUserOptionsCommandInQueue() {
// given
Assert.assertEquals(0, commandQueue.size())
// when
commandQueue.setUserOptions(null)
// then
Assert.assertTrue(commandQueue.isLastScheduled(Command.CommandType.SET_USER_SETTINGS))
Assert.assertEquals(1, commandQueue.size())
// next should be ignored
commandQueue.setUserOptions(null)
Assert.assertEquals(1, commandQueue.size())
}
@Test
fun isLoadEventsCommandInQueue() {
// given
Assert.assertEquals(0, commandQueue.size())
// when
commandQueue.loadEvents(null)
// then
Assert.assertTrue(commandQueue.isLastScheduled(Command.CommandType.LOAD_EVENTS))
Assert.assertEquals(1, commandQueue.size())
// next should be ignored
commandQueue.loadEvents(null)
Assert.assertEquals(1, commandQueue.size())
}
@Test
fun isLoadTDDsCommandInQueue() {
// given
Assert.assertEquals(0, commandQueue.size())
// when
commandQueue.loadTDDs(null)
// then
Assert.assertEquals(1, commandQueue.size())
// next should be ignored
commandQueue.loadTDDs(null)
Assert.assertEquals(1, commandQueue.size())
}
@Test
fun isLoadHistoryCommandInQueue() {
// given
Assert.assertEquals(0, commandQueue.size())
// when
commandQueue.loadHistory(0, null)
// then
Assert.assertTrue(commandQueue.isLastScheduled(Command.CommandType.LOAD_HISTORY))
Assert.assertEquals(1, commandQueue.size())
// next should be ignored
commandQueue.loadHistory(0, null)
Assert.assertEquals(1, commandQueue.size())
}
@Test
fun isProfileSetCommandInQueue() {
// given
Assert.assertEquals(0, commandQueue.size())
// when
testPumpPlugin.isProfileSet = true
commandQueue.setProfile(validProfile, false, object : Callback() {
override fun run() {
Assert.assertTrue(result.success)
Assert.assertFalse(result.enacted)
}
})
// then
// the same profile -> ignore
Assert.assertEquals(0, commandQueue.size())
// different should be added
testPumpPlugin.isProfileSet = false
commandQueue.setProfile(validProfile, false, object : Callback() {
override fun run() {
Assert.assertTrue(result.success)
Assert.assertTrue(result.enacted)
}
})
Assert.assertEquals(1, commandQueue.size())
// next should be ignored
commandQueue.setProfile(validProfile, false, object : Callback() {
override fun run() {
Assert.assertTrue(result.success)
}
})
Assert.assertEquals(1, commandQueue.size())
testPumpPlugin.isProfileSet = true
}
@Test
fun isStopCommandInQueue() {
// given
Assert.assertEquals(0, commandQueue.size())
// when
commandQueue.stopPump(null)
// then
Assert.assertTrue(commandQueue.isLastScheduled(Command.CommandType.STOP_PUMP))
Assert.assertEquals(1, commandQueue.size())
}
@Test
fun isStarCommandInQueue() {
// given
Assert.assertEquals(0, commandQueue.size())
// when
commandQueue.startPump(null)
// then
Assert.assertTrue(commandQueue.isLastScheduled(Command.CommandType.START_PUMP))
Assert.assertEquals(1, commandQueue.size())
}
@Test
fun isSetTbrNotificationCommandInQueue() {
// given
Assert.assertEquals(0, commandQueue.size())
// when
commandQueue.setTBROverNotification(null, true)
// then
Assert.assertTrue(commandQueue.isLastScheduled(Command.CommandType.INSIGHT_SET_TBR_OVER_ALARM))
Assert.assertEquals(1, commandQueue.size())
}
@Test
fun differentCustomCommandsAllowed() {
// given
Assert.assertEquals(0, commandQueue.size())
// when
val queued1 = commandQueue.customCommand(CustomCommand1(), null)
val queued2 = commandQueue.customCommand(CustomCommand2(), null)
// then
Assert.assertTrue(queued1)
Assert.assertTrue(queued2)
Assert.assertEquals(2, commandQueue.size())
}
@Test
fun sameCustomCommandNotAllowed() {
// given
Assert.assertEquals(0, commandQueue.size())
// when
val queued1 = commandQueue.customCommand(CustomCommand1(), null)
val queued2 = commandQueue.customCommand(CustomCommand1(), null)
// then
Assert.assertTrue(queued1)
Assert.assertFalse(queued2)
Assert.assertEquals(1, commandQueue.size())
}
@Test
fun readStatusTwiceIsNotAllowed() {
// given
Assert.assertEquals(0, commandQueue.size())
// when
val queued1 = commandQueue.readStatus("1", null)
val queued2 = commandQueue.readStatus("2", null)
// then
Assert.assertTrue(queued1)
Assert.assertFalse(queued2)
Assert.assertEquals(1, commandQueue.size())
Assert.assertTrue(commandQueue.statusInQueue())
}
private class CustomCommand1 : CustomCommand {
override val statusDescription: String
get() = "CUSTOM COMMAND 1"
}
private class CustomCommand2 : CustomCommand {
override val statusDescription: String
get() = "CUSTOM COMMAND 2"
}
private class CustomCommand3 : CustomCommand {
override val statusDescription: String
get() = "CUSTOM COMMAND 3"
}
}