diff --git a/app/build.gradle b/app/build.gradle index 69ae9369cb..7d622ed56f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -343,6 +343,36 @@ task full_clean(type: Delete) { delete file("src/main/jniLibs") } +// Run 'adb' shell command to clear application data of main app for 'debug' variant +task clearMainAppData(type: Exec) { + // we have to iterate to find the 'debug' variant to obtain a variant reference + android.applicationVariants.all { variant -> + if (variant.name == "fullDebug") { + def applicationId = [variant.mergedFlavor.applicationId, variant.buildType.applicationIdSuffix].findAll().join() + def clearDataCommand = ['adb', 'shell', 'pm', 'clear', applicationId] + println "Clearing application data of ${variant.name} variant: [${clearDataCommand}]" + def stdout = new ByteArrayOutputStream() + exec { + commandLine clearDataCommand + standardOutput = stdout + } + String result = stdout.toString().trim() + if (!result.startsWith("Success")) { + println result + throw new GradleException(clearDataCommand.join(" ")) + } + } + } +} +// Clear Application Data (once) before running instrumentation test +tasks.whenTaskAdded { task -> + // Both of these targets are equivalent today, although in future connectedCheck + // will also include connectedUiAutomatorTest (not implemented yet) + if(task.name == "connectedAndroidTest" || task.name == "connectedCheck"){ + task.dependsOn(clearMainAppData) + } +} + clean.dependsOn full_clean preBuild.dependsOn copyLibs diff --git a/app/src/androidTest/java/info/nightscout/androidaps/RealPumpTest.kt b/app/src/androidTest/java/info/nightscout/androidaps/RealPumpTest.kt new file mode 100644 index 0000000000..5463fbcd26 --- /dev/null +++ b/app/src/androidTest/java/info/nightscout/androidaps/RealPumpTest.kt @@ -0,0 +1,116 @@ +package info.nightscout.androidaps + +import android.os.SystemClock +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.LargeTest +import androidx.test.rule.ActivityTestRule +import androidx.test.rule.GrantPermissionRule +import info.nightscout.androidaps.data.Profile +import info.nightscout.androidaps.interfaces.PluginBase +import info.nightscout.androidaps.interfaces.PluginType +import info.nightscout.androidaps.interfaces.PumpInterface +import info.nightscout.androidaps.logging.L +import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin +import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin +import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions +import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin +import info.nightscout.androidaps.plugins.general.actions.ActionsPlugin +import info.nightscout.androidaps.plugins.insulin.InsulinOrefUltraRapidActingPlugin +import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin +import info.nightscout.androidaps.plugins.pump.danaRv2.DanaRv2Plugin +import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin +import info.nightscout.androidaps.plugins.source.RandomBgPlugin +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.SP +import info.nightscout.androidaps.utils.isRunningTest +import org.json.JSONObject +import org.junit.Assert +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.slf4j.LoggerFactory + +@LargeTest +@RunWith(AndroidJUnit4::class) +class RealPumpTest { + + private val log = LoggerFactory.getLogger(L.CORE) + + companion object { + val pump: PumpInterface = DanaRv2Plugin.getPlugin() + const val R_PASSWORD = 1234 + const val R_SERIAL = "PBB00013LR_P" + } + + private val validProfile = "{\"dia\":\"6\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"10\"},{\"time\":\"2:00\",\"value\":\"11\"}],\"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\"}" + + @Rule + @JvmField + var mActivityTestRule = ActivityTestRule(MainActivity::class.java) + + @Rule + @JvmField + var mGrantPermissionRule: GrantPermissionRule = + GrantPermissionRule.grant( + android.Manifest.permission.ACCESS_FINE_LOCATION, + android.Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, + android.Manifest.permission.WRITE_EXTERNAL_STORAGE + ) + + @Before + fun clear() { + SP.clear() + SP.putBoolean(R.string.key_setupwizard_processed, true) + SP.putString(R.string.key_aps_mode, "closed") + MainApp.getDbHelper().resetDatabases() + MainApp.devBranch = false + } + + private fun preparePlugins() { + // Source + RandomBgPlugin.performPluginSwitch(true, PluginType.BGSOURCE) + // Profile + LocalProfilePlugin.performPluginSwitch(true, PluginType.PROFILE) + val profile = Profile(JSONObject(validProfile), Constants.MGDL) + Assert.assertTrue(profile.isValid("Test")) + LocalProfilePlugin.profiles.clear() + LocalProfilePlugin.numOfProfiles = 0 + val singleProfile = LocalProfilePlugin.SingleProfile().copyFrom(profile, "TestProfile") + LocalProfilePlugin.addProfile(singleProfile) + ProfileFunctions.doProfileSwitch(LocalProfilePlugin.createProfileStore(), "TestProfile", 0, 100, 0, DateUtil.now()) + // Insulin + InsulinOrefUltraRapidActingPlugin.getPlugin().performPluginSwitch(true, PluginType.INSULIN) + // Pump + SP.putInt(R.string.key_danar_password, R_PASSWORD) + SP.putString(R.string.key_danar_bt_name, R_SERIAL) + (pump as PluginBase).performPluginSwitch(true, PluginType.PUMP) + // Sensitivity + SensitivityOref1Plugin.getPlugin().performPluginSwitch(true, PluginType.SENSITIVITY) + // APS + OpenAPSSMBPlugin.getPlugin().performPluginSwitch(true, PluginType.APS) + LoopPlugin.getPlugin().performPluginSwitch(true, PluginType.LOOP) + + // Enable common + ActionsPlugin.performPluginSwitch(true, PluginType.GENERAL) + + // Disable unneeded + MainApp.getPluginsList().remove(ObjectivesPlugin) + } + + @Test + fun doTest() { + Assert.assertTrue(isRunningTest()) + preparePlugins() + + while (!pump.isInitialized) { + log.debug("Waiting for initialization") + SystemClock.sleep(1000) + } + + while (true) { + log.debug("Tick") + SystemClock.sleep(1000) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/MainActivity.java b/app/src/main/java/info/nightscout/androidaps/MainActivity.java index f74a58856f..c152c415cb 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/MainActivity.java @@ -63,6 +63,8 @@ import info.nightscout.androidaps.utils.SP; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; +import static info.nightscout.androidaps.utils.EspressoTestHelperKt.isRunningRealPumpTest; + public class MainActivity extends NoSplashAppCompatActivity { private static Logger log = LoggerFactory.getLogger(L.CORE); private CompositeDisposable disposable = new CompositeDisposable(); @@ -137,7 +139,7 @@ public class MainActivity extends NoSplashAppCompatActivity { .subscribe(this::processPreferenceChange, FabricPrivacy::logException) ); - if (!SP.getBoolean(R.string.key_setupwizard_processed, false)) { + if (!SP.getBoolean(R.string.key_setupwizard_processed, false) && !isRunningRealPumpTest()) { Intent intent = new Intent(this, SetupWizardActivity.class); startActivity(intent); } diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/PluginBase.java b/app/src/main/java/info/nightscout/androidaps/interfaces/PluginBase.java index e236125255..5d4ec01fd9 100644 --- a/app/src/main/java/info/nightscout/androidaps/interfaces/PluginBase.java +++ b/app/src/main/java/info/nightscout/androidaps/interfaces/PluginBase.java @@ -74,7 +74,7 @@ public abstract class PluginBase { } } - private void performPluginSwitch(boolean enabled, PluginType type) { + public void performPluginSwitch(boolean enabled, PluginType type) { setPluginEnabled(type, enabled); setFragmentVisible(type, enabled); ConfigBuilderPlugin.getPlugin().processOnEnabledCategoryChanged(this, getType()); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/RandomBgPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/RandomBgPlugin.kt index ea6731ca60..1f79b82bc6 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/RandomBgPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/RandomBgPlugin.kt @@ -31,7 +31,7 @@ object RandomBgPlugin : PluginBase(PluginDescription() private val loopHandler = Handler() private lateinit var refreshLoop: Runnable - const val interval = 5L // minutes + const val interval = 1L // minutes init { refreshLoop = Runnable { @@ -55,7 +55,7 @@ object RandomBgPlugin : PluginBase(PluginDescription() } override fun specialEnableCondition(): Boolean { - return VirtualPumpPlugin.getPlugin().isEnabled(PluginType.PUMP) && (MainApp.engineeringMode || isRunningTest()) + return isRunningTest() || VirtualPumpPlugin.getPlugin().isEnabled(PluginType.PUMP) && MainApp.engineeringMode } override fun handleNewData(intent: Intent) { @@ -65,7 +65,7 @@ object RandomBgPlugin : PluginBase(PluginDescription() val cal = GregorianCalendar() val currentMinute = cal.get(Calendar.MINUTE) + (cal.get(Calendar.HOUR_OF_DAY) % 2) * 60 - val bgMgdl = min + (max - min) * sin(currentMinute / 120.0 * 2 * PI) + val bgMgdl = min + (max - min) + (max - min) * sin(currentMinute / 120.0 * 2 * PI) val bgReading = BgReading() bgReading.value = bgMgdl diff --git a/app/src/main/java/info/nightscout/androidaps/utils/EspressoTestHelper.kt b/app/src/main/java/info/nightscout/androidaps/utils/EspressoTestHelper.kt index 7288e6679f..0cddcc0792 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/EspressoTestHelper.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/EspressoTestHelper.kt @@ -9,3 +9,13 @@ fun isRunningTest(): Boolean { false } } + +@Synchronized +fun isRunningRealPumpTest(): Boolean { + return try { + Class.forName("info.nightscout.androidaps.RealPumpTest") + true + } catch (e: ClassNotFoundException) { + false + } +}