diff --git a/app/src/main/java/info/nightscout/androidaps/data/DetailedBolusInfo.java b/app/src/main/java/info/nightscout/androidaps/data/DetailedBolusInfo.java index c2f9d16dc3..6e65e6d6d3 100644 --- a/app/src/main/java/info/nightscout/androidaps/data/DetailedBolusInfo.java +++ b/app/src/main/java/info/nightscout/androidaps/data/DetailedBolusInfo.java @@ -10,6 +10,7 @@ import java.util.Date; import info.nightscout.androidaps.db.CareportalEvent; import info.nightscout.androidaps.db.Source; +import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin; /** * Created by mike on 29.05.2017. @@ -17,6 +18,7 @@ import info.nightscout.androidaps.db.Source; public class DetailedBolusInfo { public long date = System.currentTimeMillis(); + public long lastKnownBolusTime; public String eventType = CareportalEvent.MEALBOLUS; public double insulin = 0; public double carbs = 0; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java index 1911f588b1..5bb810274e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java @@ -520,6 +520,7 @@ public class ConfigBuilderPlugin extends PluginBase { // deliver SMB DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo(); + detailedBolusInfo.lastKnownBolusTime = activeTreatments.getLastBolusTime(); detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS; detailedBolusInfo.insulin = request.smb; detailedBolusInfo.isSMB = true; diff --git a/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.java b/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.java index 9f2fdf7eee..47fe4acd6a 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.java +++ b/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.java @@ -26,6 +26,7 @@ import info.nightscout.androidaps.plugins.Overview.Dialogs.BolusProgressHelperAc import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.Overview.notifications.Notification; +import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin; import info.nightscout.androidaps.queue.commands.Command; import info.nightscout.androidaps.queue.commands.CommandBolus; import info.nightscout.androidaps.queue.commands.CommandCancelExtendedBolus; @@ -177,6 +178,18 @@ public class CommandQueue { public synchronized boolean bolus(DetailedBolusInfo detailedBolusInfo, Callback callback) { Command.CommandType type = detailedBolusInfo.isSMB ? Command.CommandType.SMB_BOLUS : Command.CommandType.BOLUS; + if (type == Command.CommandType.SMB_BOLUS) { + if (isRunning(Command.CommandType.BOLUS) || bolusInQueue()) { + log.debug("Rejecting SMB since a bolus is queue/running"); + return false; + } + if (detailedBolusInfo.lastKnownBolusTime < TreatmentsPlugin.getPlugin().getLastBolusTime()) { + log.debug("Rejecting bolus, another bolus was issued since request time"); + return false; + } + } + + if(type.equals(Command.CommandType.BOLUS) && detailedBolusInfo.carbs > 0 && detailedBolusInfo.insulin == 0){ type = Command.CommandType.CARBS_ONLY_TREATMENT; //Carbs only can be added in parallel as they can be "in the future". diff --git a/app/src/test/java/info/nightscout/androidaps/queue/CommandQueueTest.java b/app/src/test/java/info/nightscout/androidaps/queue/CommandQueueTest.java index dd6493fd66..29c9128186 100644 --- a/app/src/test/java/info/nightscout/androidaps/queue/CommandQueueTest.java +++ b/app/src/test/java/info/nightscout/androidaps/queue/CommandQueueTest.java @@ -15,6 +15,8 @@ import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; +import java.util.Date; + import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.data.ConstraintChecker; @@ -24,9 +26,11 @@ import info.nightscout.androidaps.interfaces.Constraint; import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.PumpMDI.MDIPlugin; +import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin; import info.nightscout.androidaps.queue.commands.Command; import info.nightscout.utils.ToastUtils; +import static info.nightscout.utils.DateUtil.now; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -36,7 +40,7 @@ import static org.mockito.Mockito.when; */ @RunWith(PowerMockRunner.class) -@PrepareForTest({MainApp.class, ConfigBuilderPlugin.class, ToastUtils.class, Context.class}) +@PrepareForTest({MainApp.class, ConfigBuilderPlugin.class, ToastUtils.class, Context.class, TreatmentsPlugin.class}) public class CommandQueueTest extends CommandQueue { String validProfile = "{\"dia\":\"3\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"100\"},{\"time\":\"2:00\",\"value\":\"110\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"0.1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"; @@ -142,6 +146,11 @@ public class CommandQueueTest extends CommandQueue { when(MainApp.bus()).thenReturn(bus); when(MainApp.gs(0)).thenReturn(""); + + PowerMockito.mockStatic(TreatmentsPlugin.class); + TreatmentsPlugin treatmentsPlugin = mock(TreatmentsPlugin.class); + when(TreatmentsPlugin.getPlugin()).thenReturn(treatmentsPlugin); + when(treatmentsPlugin.getLastBolusTime()).thenReturn(new Date(100, 0,1 ).getTime()); } @Override @@ -159,21 +168,57 @@ public class CommandQueueTest extends CommandQueue { @Test public void callingCancelAllBolusesClearsQueue() throws Exception { + // given prepareMock(0d, 0); - - // add normal and SMB-bolus to queue Assert.assertEquals(0, size()); + DetailedBolusInfo smb = new DetailedBolusInfo(); + smb.lastKnownBolusTime = now(); + smb.isSMB = true; + bolus(smb, null); + + bolus(new DetailedBolusInfo(), null); + Assert.assertEquals(2, size()); + + // when + cancelAllBoluses(); + + // then + Assert.assertEquals(0, size()); + } + + @Test + public void smbIsRejectedIfABolusIsQueued() throws Exception { + // given + prepareMock(0d, 0); + Assert.assertEquals(0, size()); + + // when bolus(new DetailedBolusInfo(), null); DetailedBolusInfo smb = new DetailedBolusInfo(); smb.isSMB = true; - bolus(smb, null); + boolean queued = bolus(smb, null); - Assert.assertEquals(2, size()); + // then + Assert.assertFalse(queued); + Assert.assertEquals(size(), 1); + } - // cancelling all boluses clear all boluses from the queue - cancelAllBoluses(); + @Test + public void smbIsRejectedIfLastKnownBolusIsOutdated() throws Exception { + // given + prepareMock(0d, 0); Assert.assertEquals(0, size()); + + // when + DetailedBolusInfo bolus = new DetailedBolusInfo(); + bolus.isSMB = true; + bolus.lastKnownBolusTime = 0; + boolean queued = bolus(bolus, null); + + // then + Assert.assertFalse(queued); + Assert.assertEquals(size(), 0); } }