AuthRequestTest

This commit is contained in:
Milos Kozak 2020-03-09 23:49:00 +01:00
parent 3da0defcd7
commit 5d745a2d9b
6 changed files with 138 additions and 122 deletions

View file

@ -20,6 +20,7 @@ import info.nightscout.androidaps.plugins.general.automation.actions.*
import info.nightscout.androidaps.plugins.general.automation.elements.*
import info.nightscout.androidaps.plugins.general.automation.triggers.*
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationWithAction
import info.nightscout.androidaps.plugins.general.smsCommunicator.AuthRequest
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensData
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobOref1Thread
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobThread
@ -143,6 +144,8 @@ interface AppComponent : AndroidInjector<MainApp> {
fun injectBolusWizard(bolusWizard: BolusWizard)
fun injectQuickWizardEntry(quickWizardEntry: QuickWizardEntry)
fun injectAuthRequest(authRequest: AuthRequest)
@Component.Builder
interface Builder {

View file

@ -30,6 +30,7 @@ import info.nightscout.androidaps.plugins.general.automation.actions.*
import info.nightscout.androidaps.plugins.general.automation.elements.*
import info.nightscout.androidaps.plugins.general.automation.triggers.*
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationWithAction
import info.nightscout.androidaps.plugins.general.smsCommunicator.AuthRequest
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensData
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobOref1Thread
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobThread
@ -194,6 +195,8 @@ open class AppModule {
@ContributesAndroidInjector fun loggerBolusWizard(): BolusWizard
@ContributesAndroidInjector fun loggerQuickWizardEntry(): QuickWizardEntry
@ContributesAndroidInjector fun authRequestInjector(): AuthRequest
@Binds fun bindContext(mainApp: MainApp): Context
@Binds fun bindInjector(mainApp: MainApp): HasAndroidInjector

View file

@ -1,40 +1,50 @@
package info.nightscout.androidaps.plugins.general.smsCommunicator
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.logging.L
import info.nightscout.androidaps.logging.StacktraceLoggerWrapper
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.resources.ResourceHelper
import org.slf4j.LoggerFactory
import javax.inject.Inject
class AuthRequest internal constructor(val plugin: SmsCommunicatorPlugin, val resourceHelper: ResourceHelper, var requester: Sms, requestText: String, var confirmCode: String, val action: SmsAction) {
private val log = StacktraceLoggerWrapper.getLogger(L.SMS)
class AuthRequest internal constructor(
injector: HasAndroidInjector,
var requester: Sms,
requestText: String,
var confirmCode: String,
val action: SmsAction) {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin
@Inject lateinit var resourceHelper: ResourceHelper
private val date = DateUtil.now()
private var processed = false
init {
plugin.sendSMS(Sms(requester.phoneNumber, requestText))
injector.androidInjector().inject(this)
smsCommunicatorPlugin.sendSMS(Sms(requester.phoneNumber, requestText))
}
fun action(codeReceived: String) {
if (processed) {
if (L.isEnabled(L.SMS)) log.debug("Already processed")
aapsLogger.debug(LTag.SMS, "Already processed")
return
}
if (confirmCode != codeReceived) {
processed = true
if (L.isEnabled(L.SMS)) log.debug("Wrong code")
plugin.sendSMS(Sms(requester.phoneNumber, resourceHelper.gs(R.string.sms_wrongcode)))
aapsLogger.debug(LTag.SMS, "Wrong code")
smsCommunicatorPlugin.sendSMS(Sms(requester.phoneNumber, resourceHelper.gs(R.string.sms_wrongcode)))
return
}
if (DateUtil.now() - date < Constants.SMS_CONFIRM_TIMEOUT) {
processed = true
if (L.isEnabled(L.SMS)) log.debug("Processing confirmed SMS: " + requester.text)
aapsLogger.debug(LTag.SMS, "Processing confirmed SMS: " + requester.text)
action.run()
return
}
if (L.isEnabled(L.SMS)) log.debug("Timed out SMS: " + requester.text)
aapsLogger.debug(LTag.SMS, "Timed out SMS: " + requester.text)
}
}

View file

@ -70,8 +70,8 @@ class SmsCommunicatorPlugin @Inject constructor(
) {
private val disposable = CompositeDisposable()
var allowedNumbers: MutableList<String> = ArrayList()
var messageToConfirm: AuthRequest? = null
private var allowedNumbers: MutableList<String> = ArrayList()
private var messageToConfirm: AuthRequest? = null
var lastRemoteBolusTime: Long = 0
var messages = ArrayList<Sms>()
@ -159,7 +159,7 @@ class SmsCommunicatorPlugin @Inject constructor(
}
}
fun isCommand(command: String, number: String): Boolean {
private fun isCommand(command: String, number: String): Boolean {
var found = false
commands.forEach { (k, _) ->
if (k == command) found = true
@ -167,7 +167,7 @@ class SmsCommunicatorPlugin @Inject constructor(
return found || messageToConfirm?.requester?.phoneNumber == number
}
fun isAllowedNumber(number: String): Boolean {
private fun isAllowedNumber(number: String): Boolean {
for (num in allowedNumbers) {
if (num == number) return true
}
@ -184,7 +184,7 @@ class SmsCommunicatorPlugin @Inject constructor(
}
}
fun processSms(receivedSms: Sms) {
private fun processSms(receivedSms: Sms) {
if (!isEnabled(PluginType.GENERAL)) {
aapsLogger.debug(LTag.SMS, "Ignoring SMS. Plugin disabled.")
return
@ -356,7 +356,7 @@ class SmsCommunicatorPlugin @Inject constructor(
val passCode = generatePasscode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_suspendreplywithcode), duration, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(this, resourceHelper, receivedSms, reply, passCode, object : SmsAction(duration) {
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(duration) {
override fun run() {
commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() {
@ -471,7 +471,7 @@ class SmsCommunicatorPlugin @Inject constructor(
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_profilereplywithcode), list[pindex - 1], percentage, passCode)
receivedSms.processed = true
val finalPercentage = percentage
messageToConfirm = AuthRequest(this, resourceHelper, receivedSms, reply, passCode, object : SmsAction(list[pindex - 1] as String, finalPercentage) {
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(list[pindex - 1] as String, finalPercentage) {
override fun run() {
activePlugin.activeTreatments.doProfileSwitch(store, list[pindex - 1] as String, 0, finalPercentage, 0, DateUtil.now())
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.profileswitchcreated)))
@ -488,7 +488,7 @@ class SmsCommunicatorPlugin @Inject constructor(
val passCode = generatePasscode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_basalstopreplywithcode), passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(this, resourceHelper, receivedSms, reply, passCode, object : SmsAction() {
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() {
@ -518,7 +518,7 @@ class SmsCommunicatorPlugin @Inject constructor(
val passCode = generatePasscode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_basalpctreplywithcode), tempBasalPct, duration, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(this, resourceHelper, receivedSms, reply, passCode, object : SmsAction(tempBasalPct, duration) {
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(tempBasalPct, duration) {
override fun run() {
commandQueue.tempBasalPercent(anInteger(), secondInteger(), true, profile, object : Callback() {
override fun run() {
@ -550,7 +550,7 @@ class SmsCommunicatorPlugin @Inject constructor(
val passCode = generatePasscode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_basalreplywithcode), tempBasal, duration, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(this, resourceHelper, receivedSms, reply, passCode, object : SmsAction(tempBasal, duration) {
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(tempBasal, duration) {
override fun run() {
commandQueue.tempBasalAbsolute(aDouble(), secondInteger(), true, profile, object : Callback() {
override fun run() {
@ -577,7 +577,7 @@ class SmsCommunicatorPlugin @Inject constructor(
val passCode = generatePasscode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_extendedstopreplywithcode), passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(this, resourceHelper, receivedSms, reply, passCode, object : SmsAction() {
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
commandQueue.cancelExtended(object : Callback() {
override fun run() {
@ -605,7 +605,7 @@ class SmsCommunicatorPlugin @Inject constructor(
val passCode = generatePasscode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_extendedreplywithcode), extended, duration, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(this, resourceHelper, receivedSms, reply, passCode, object : SmsAction(extended, duration) {
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(extended, duration) {
override fun run() {
commandQueue.extendedBolus(aDouble(), secondInteger(), object : Callback() {
override fun run() {
@ -640,7 +640,7 @@ class SmsCommunicatorPlugin @Inject constructor(
else
String.format(resourceHelper.gs(R.string.smscommunicator_bolusreplywithcode), bolus, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(this, resourceHelper, receivedSms, reply, passCode, object : SmsAction(bolus) {
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(bolus) {
override fun run() {
val detailedBolusInfo = DetailedBolusInfo()
detailedBolusInfo.insulin = aDouble()
@ -716,7 +716,7 @@ class SmsCommunicatorPlugin @Inject constructor(
val passCode = generatePasscode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_carbsreplywithcode), grams, DateUtil.timeString(time), passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(this, resourceHelper, receivedSms, reply, passCode, object : SmsAction(grams, time) {
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(grams, time) {
override fun run() {
val detailedBolusInfo = DetailedBolusInfo()
detailedBolusInfo.carbs = anInteger().toDouble()
@ -748,7 +748,7 @@ class SmsCommunicatorPlugin @Inject constructor(
val passCode = generatePasscode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_temptargetwithcode), splitted[1].toUpperCase(Locale.getDefault()), passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(this, resourceHelper, receivedSms, reply, passCode, object : SmsAction() {
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
val units = profileFunction.getUnits()
var keyDuration = 0
@ -803,7 +803,7 @@ class SmsCommunicatorPlugin @Inject constructor(
val passCode = generatePasscode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_temptargetcancel), passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(this, resourceHelper, receivedSms, reply, passCode, object : SmsAction() {
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
val tempTarget = TempTarget()
.source(Source.USER)
@ -827,7 +827,7 @@ class SmsCommunicatorPlugin @Inject constructor(
val passCode = generatePasscode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_stopsmswithcode), passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(this, resourceHelper, receivedSms, reply, passCode, object : SmsAction() {
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
sp.putBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)
val replyText = String.format(resourceHelper.gs(R.string.smscommunicator_stoppedsms))
@ -843,7 +843,7 @@ class SmsCommunicatorPlugin @Inject constructor(
val passCode = generatePasscode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_calibrationreplywithcode), cal, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(this, resourceHelper, receivedSms, reply, passCode, object : SmsAction(cal) {
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(cal) {
override fun run() {
val result = XdripCalibrations.sendIntent(aDouble)
if (result) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_calibrationsent))) else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_calibrationfailed)))

View file

@ -1,93 +0,0 @@
package info.nightscout.androidaps.plugins.general.smsCommunicator;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.stubbing.Answer;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import info.AAPSMocker;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.SP;
import info.nightscout.androidaps.utils.T;
import static org.mockito.ArgumentMatchers.any;
import static org.powermock.api.mockito.PowerMockito.doAnswer;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.when;
@RunWith(PowerMockRunner.class)
@PrepareForTest({SmsCommunicatorPlugin.class, L.class, SP.class, MainApp.class, DateUtil.class})
public class AuthRequestTest {
private SmsCommunicatorPlugin smsCommunicatorPlugin;
private Sms sentSms;
private boolean actionCalled = false;
@Test
public void doTests() {
Sms requester = new Sms("aNumber", "aText");
SmsAction action = new SmsAction() {
@Override
public void run() {
actionCalled = true;
}
};
// Check if SMS requesting code is sent
AuthRequest authRequest = new AuthRequest(smsCommunicatorPlugin, requester, "Request text", "ABC", action);
Assert.assertEquals(sentSms.getPhoneNumber(), "aNumber");
Assert.assertEquals(sentSms.getText(), "Request text");
// wrong reply
actionCalled = false;
authRequest.action("EFG");
Assert.assertEquals(sentSms.getPhoneNumber(), "aNumber");
Assert.assertEquals(sentSms.getText(), "Wrong code. Command cancelled.");
Assert.assertFalse(actionCalled);
// correct reply
authRequest = new AuthRequest(smsCommunicatorPlugin, requester, "Request text", "ABC", action);
actionCalled = false;
authRequest.action("ABC");
Assert.assertTrue(actionCalled);
// second time action should not be called
actionCalled = false;
authRequest.action("ABC");
Assert.assertFalse(actionCalled);
// test timed out message
long now = 10000;
when(DateUtil.now()).thenReturn(now);
authRequest = new AuthRequest(smsCommunicatorPlugin, requester, "Request text", "ABC", action);
actionCalled = false;
when(DateUtil.now()).thenReturn(now + T.mins(Constants.SMS_CONFIRM_TIMEOUT).msecs() + 1);
authRequest.action("ABC");
Assert.assertFalse(actionCalled);
}
@Before
public void prepareTests() {
AAPSMocker.mockMainApp();
AAPSMocker.mockApplicationContext();
AAPSMocker.mockSP();
AAPSMocker.mockL();
AAPSMocker.mockStrings();
mockStatic(DateUtil.class);
smsCommunicatorPlugin = mock(SmsCommunicatorPlugin.class);
doAnswer((Answer) invocation -> {
sentSms = invocation.getArgument(0);
return null;
}).when(smsCommunicatorPlugin).sendSMS(any(Sms.class));
}
}

View file

@ -0,0 +1,93 @@
package info.nightscout.androidaps.plugins.general.smsCommunicator
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.TestBase
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.resources.ResourceHelper
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.invocation.InvocationOnMock
import org.mockito.stubbing.Answer
import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner
@RunWith(PowerMockRunner::class)
@PrepareForTest(SmsCommunicatorPlugin::class, DateUtil::class)
class AuthRequestTest : TestBase() {
@Mock lateinit var aapsLogger: AAPSLogger
@Mock lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin
@Mock lateinit var resourceHelper: ResourceHelper
var injector: HasAndroidInjector = HasAndroidInjector {
AndroidInjector {
if (it is AuthRequest) {
it.aapsLogger = aapsLogger
it.resourceHelper = resourceHelper
it.smsCommunicatorPlugin = smsCommunicatorPlugin
}
}
}
private var sentSms: Sms? = null
private var actionCalled = false
@Before fun prepareTests() {
`when`(resourceHelper.gs(R.string.sms_wrongcode)).thenReturn("Wrong code. Command cancelled.")
PowerMockito.doAnswer(Answer { invocation: InvocationOnMock ->
sentSms = invocation.getArgument(0)
null
} as Answer<*>).`when`(smsCommunicatorPlugin).sendSMS(anyObject())
}
@Test fun doTests() {
val requester = Sms("aNumber", "aText")
val action: SmsAction = object : SmsAction() {
override fun run() {
actionCalled = true
}
}
// Check if SMS requesting code is sent
var authRequest = AuthRequest(injector, requester, "Request text", "ABC", action)
Assert.assertEquals(sentSms!!.phoneNumber, "aNumber")
Assert.assertEquals(sentSms!!.text, "Request text")
// wrong reply
actionCalled = false
authRequest.action("EFG")
Assert.assertEquals(sentSms!!.phoneNumber, "aNumber")
Assert.assertEquals(sentSms!!.text, "Wrong code. Command cancelled.")
Assert.assertFalse(actionCalled)
// correct reply
authRequest = AuthRequest(injector, requester, "Request text", "ABC", action)
actionCalled = false
authRequest.action("ABC")
Assert.assertTrue(actionCalled)
// second time action should not be called
actionCalled = false
authRequest.action("ABC")
Assert.assertFalse(actionCalled)
// test timed out message
val now: Long = 10000
PowerMockito.mockStatic(DateUtil::class.java)
PowerMockito.`when`(DateUtil.now()).thenReturn(now)
authRequest = AuthRequest(injector, requester, "Request text", "ABC", action)
actionCalled = false
PowerMockito.`when`(DateUtil.now()).thenReturn(now + T.mins(Constants.SMS_CONFIRM_TIMEOUT).msecs() + 1)
authRequest.action("ABC")
Assert.assertFalse(actionCalled)
}
}