diff --git a/app/build.gradle b/app/build.gradle index c8e5f2c0b..63a9e3fe6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,13 +13,15 @@ android { applicationId 'org.openobservatory.ooniprobe' minSdk libs.versions.minSdk.get().toInteger() targetSdk libs.versions.targetSdk.get().toInteger() - versionName '3.9.0-beta' - versionCode 119 + versionName '4.0.0' + versionCode 122 testInstrumentationRunner "org.openobservatory.ooniprobe.TestAndroidJUnitRunner" - buildConfigField 'String', 'OONI_API_BASE_URL', '"https://api.ooni.io/"' + buildConfigField 'String', 'OONI_API_BASE_URL', '"https://api.ooni.org"' buildConfigField 'String', 'NOTIFICATION_SERVER', '"https://countly.ooni.io"' + buildConfigField 'String', 'OONI_RUN_DASHBOARD_URL', '"https://run.ooni.org"' resValue "string", "APP_ID", 'org.openobservatory.ooniprobe' resValue "string", "APP_NAME", "OONI Probe" + resValue "string", "RUN_V2_DOMAIN", "run.ooni.org" buildConfigField 'String', 'SOFTWARE_NAME', 'BASE_SOFTWARE_NAME+IS_DEBUG' buildConfigField 'String', 'COUNTLY_KEY', '"146836f41172f9e3287cab6f2cc347de3f5ddf3b"' buildConfigField "boolean", "RUN_AUTOMATION", "false" @@ -120,6 +122,10 @@ android { viewBinding = true buildConfig = true } + dataBinding { + enabled = true + enabledForTests = true + } namespace 'org.openobservatory.ooniprobe' } @@ -136,6 +142,7 @@ dependencies { implementation libs.androidx.preference implementation libs.androidx.localbroadcastmanager implementation libs.androidx.legacy.support.v4 + implementation libs.androidx.work.runtime // Google implementation libs.google.material @@ -177,7 +184,7 @@ dependencies { // Unit Testing testImplementation project(':shared-test') testImplementation libs.junit4 - testImplementation libs.androidx.core + testImplementation libs.androidx.test.core testImplementation libs.androidx.runner testImplementation libs.androidx.rules testImplementation libs.mockito.core diff --git a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/MainActivityWebsitesTest.java b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/MainActivityWebsitesTest.java index 1e7eb3d9b..3aea016cf 100644 --- a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/MainActivityWebsitesTest.java +++ b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/MainActivityWebsitesTest.java @@ -1,47 +1,44 @@ package org.openobservatory.ooniprobe.ui; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.action.ViewActions.typeText; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.contrib.RecyclerViewActions.scrollToPosition; +import static androidx.test.espresso.intent.Intents.intending; +import static androidx.test.espresso.intent.matcher.IntentMatchers.anyIntent; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withText; +import static org.openobservatory.ooniprobe.ui.utils.RecyclerViewMatcher.withRecyclerView; +import static org.openobservatory.ooniprobe.ui.utils.ViewMatchers.withIndex; + import android.app.Activity; import android.app.Instrumentation; import android.content.Intent; +import android.view.View; import androidx.test.core.app.ActivityScenario; import androidx.test.core.app.ApplicationProvider; +import androidx.test.espresso.UiController; +import androidx.test.espresso.ViewAction; +import androidx.test.espresso.contrib.RecyclerViewActions; import androidx.test.espresso.intent.Intents; -import androidx.test.espresso.matcher.ViewMatchers; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.adevinta.android.barista.rule.flaky.AllowFlaky; import com.adevinta.android.barista.rule.flaky.FlakyTestRule; +import org.hamcrest.Matcher; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.openobservatory.ooniprobe.AbstractTest; import org.openobservatory.ooniprobe.R; import org.openobservatory.ooniprobe.activity.MainActivity; -import org.openobservatory.ooniprobe.activity.RunningActivity; -import org.openobservatory.ooniprobe.fragment.ProgressFragment; import io.bloco.faker.Faker; -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.action.ViewActions.click; -import static androidx.test.espresso.action.ViewActions.typeText; -import static androidx.test.espresso.assertion.ViewAssertions.matches; -import static androidx.test.espresso.contrib.RecyclerViewActions.scrollToPosition; -import static androidx.test.espresso.intent.Intents.intended; -import static androidx.test.espresso.intent.Intents.intending; -import static androidx.test.espresso.intent.matcher.ComponentNameMatchers.hasClassName; -import static androidx.test.espresso.intent.matcher.IntentMatchers.anyIntent; -import static androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent; -import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; -import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility; -import static androidx.test.espresso.matcher.ViewMatchers.withId; -import static androidx.test.espresso.matcher.ViewMatchers.withText; -import static org.hamcrest.Matchers.not; -import static org.openobservatory.ooniprobe.ui.utils.RecyclerViewMatcher.withRecyclerView; -import static org.openobservatory.ooniprobe.ui.utils.ViewMatchers.withIndex; - @RunWith(AndroidJUnit4.class) public class MainActivityWebsitesTest extends AbstractTest { @@ -50,6 +47,26 @@ public class MainActivityWebsitesTest extends AbstractTest { @Rule public FlakyTestRule flakyRule = new FlakyTestRule(); + public static ViewAction clickChildViewWithId(final int id) { + return new ViewAction() { + @Override + public Matcher getConstraints() { + return null; + } + + @Override + public String getDescription() { + return "Click on a child view with specified id."; + } + + @Override + public void perform(UiController uiController, View view) { + View v = view.findViewById(id); + v.performClick(); + } + }; + } + @Test @AllowFlaky(attempts = 3) public void addCustomWebsiteTest() { @@ -62,22 +79,17 @@ public void addCustomWebsiteTest() { // Act launchDashboard(); - onView(withId(R.id.recycler)) - .perform(scrollToPosition(0)); + onView(withId(R.id.recycler)).perform(scrollToPosition(1)); - onView(withRecyclerView(R.id.recycler) - .atPositionOnView(0, R.id.title)) - .perform(click()); + onView(withRecyclerView(R.id.recycler).atPositionOnView(1, R.id.title)).perform(click()); onView(withId(R.id.customUrl)).perform(click()); - onView(withIndex(withId(R.id.editText), 0)) - .perform(typeText(url1)); + onView(withIndex(withId(R.id.editText), 0)).perform(typeText(url1)); onView(withId(R.id.add)).perform(click()); - onView(withIndex(withId(R.id.editText), 1)) - .perform(typeText(url2)); + onView(withIndex(withId(R.id.editText), 1)).perform(typeText(url2)); // Assert onView(withText(totalUrls)).check(matches(isDisplayed())); @@ -90,32 +102,32 @@ public void deleteCustomWebsiteTest() { Faker faker = new Faker(); String url1 = faker.internet.domainName() + faker.internet.domainSuffix(); String url2 = faker.internet.domainName() + faker.internet.domainSuffix(); - String totalUrls = String.format(getResourceString(R.string.OONIRun_URLs), 1); + String totalUrls = String.format("Test %s URLs", 1); // Act launchDashboard(); - onView(withId(R.id.recycler)) - .perform(scrollToPosition(0)); + onView(withId(R.id.recycler)).perform(scrollToPosition(1)); - onView(withRecyclerView(R.id.recycler) - .atPositionOnView(0, R.id.title)) - .perform(click()); + onView(withRecyclerView(R.id.recycler).atPositionOnView(1, R.id.title)).perform(click()); onView(withId(R.id.customUrl)).perform(click()); - onView(withIndex(withId(R.id.editText), 0)) - .perform(typeText(url1)); + onView(withIndex(withId(R.id.editText), 0)).perform(typeText(url1)); + + onView(withId(R.id.urlContainer)).perform(scrollToPosition(0)); - onView(withIndex(withId(R.id.delete), 0)) - .check(matches(not(isDisplayed()))); + onView(withRecyclerView(R.id.urlContainer).atPositionOnView(0, R.id.delete)).check(matches(isDisplayed())); onView(withId(R.id.add)).perform(click()); - onView(withIndex(withId(R.id.editText), 1)) - .perform(typeText(url2)); + onView(withIndex(withId(R.id.editText), 1)).perform(typeText(url2)); - onView(withIndex(withId(R.id.delete), 1)) - .perform(click()); + onView(withIndex(withId(R.id.delete), 1)).perform(click()); + + onView(withId(R.id.urlContainer)).perform(scrollToPosition(1)); + + // TODO: fix click action + onView(withRecyclerView(R.id.urlContainer).atPosition(1)).perform(RecyclerViewActions.actionOnItemAtPosition(1, clickChildViewWithId(R.id.delete))); // Assert onView(withText(totalUrls)).check(matches(isDisplayed())); @@ -126,29 +138,18 @@ public void deleteCustomWebsiteTest() { public void lunchCustomWebsiteIntentTest() { // Act launchDashboard(); - onView(withId(R.id.recycler)) - .perform(scrollToPosition(0)); + onView(withId(R.id.recycler)).perform(scrollToPosition(1)); - onView(withRecyclerView(R.id.recycler) - .atPositionOnView(0, R.id.title)) - .perform(click()); + onView(withRecyclerView(R.id.recycler).atPositionOnView(1, R.id.title)).perform(click()); onView(withId(R.id.customUrl)).perform(click()); Intents.init(); Intent emptyIntent = new Intent(); - Instrumentation.ActivityResult result = - new Instrumentation.ActivityResult(Activity.RESULT_OK, emptyIntent); + Instrumentation.ActivityResult result = new Instrumentation.ActivityResult(Activity.RESULT_OK, emptyIntent); intending(anyIntent()).respondWith(result); - - onView(withId(R.id.runButton)).perform(click()); - // TODO(aanorbel): resolve issue. Running activity no longer available. - // ```intended(hasComponent(hasClassName(RunningActivity.class.getName())));``` - // progress display is dismissed before its availability is checked - // ```onView(withId(R.id.progress_layout)).check(matches(isDisplayed()));``` - Intents.release(); } diff --git a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/RunningActivityTest.java b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/RunningActivityTest.java index 9bd23c078..b4bb217c7 100644 --- a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/RunningActivityTest.java +++ b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/RunningActivityTest.java @@ -6,9 +6,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.rule.ServiceTestRule; -import com.adevinta.android.barista.rule.flaky.AllowFlaky; -import com.adevinta.android.barista.rule.flaky.FlakyTestRule; - import org.junit.After; import org.junit.Rule; import org.junit.Test; @@ -17,12 +14,12 @@ import org.openobservatory.ooniprobe.AbstractTest; import org.openobservatory.ooniprobe.activity.MainActivity; import org.openobservatory.ooniprobe.activity.RunningActivity; +import org.openobservatory.ooniprobe.common.OONITests; import org.openobservatory.ooniprobe.common.service.RunTestService; import org.openobservatory.ooniprobe.engine.TestEngineInterface; import org.openobservatory.ooniprobe.model.jsonresult.EventResult; import org.openobservatory.ooniprobe.test.EngineProvider; import org.openobservatory.ooniprobe.test.suite.AbstractSuite; -import org.openobservatory.ooniprobe.test.suite.InstantMessagingSuite; import org.openobservatory.ooniprobe.utils.DatabaseUtils; import java.util.ArrayList; @@ -31,6 +28,9 @@ import static org.openobservatory.ooniprobe.testing.ActivityAssertions.assertCurrentActivity; import static org.openobservatory.ooniprobe.testing.ActivityAssertions.waitForCurrentActivity; +import com.adevinta.android.barista.rule.flaky.AllowFlaky; +import com.adevinta.android.barista.rule.flaky.FlakyTestRule; + @RunWith(AndroidJUnit4.class) public class RunningActivityTest extends AbstractTest { @@ -87,7 +87,7 @@ private void startRunTestService() { serviceRule.startService( new Intent(c, RunTestService.class) .putExtra("testSuites", new ArrayList() {{ - add(new InstantMessagingSuite()); + add(OONITests.WEBSITES.toOONIDescriptor(c).getTest(c)); }}) ); } catch (TimeoutException e) { diff --git a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/CircumventionTest.java b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/CircumventionTest.java index 17bdb976a..ea5bbcae1 100644 --- a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/CircumventionTest.java +++ b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/CircumventionTest.java @@ -1,26 +1,23 @@ package org.openobservatory.ooniprobe.ui.resultdetails; import androidx.test.ext.junit.runners.AndroidJUnit4; - -import com.adevinta.android.barista.rule.flaky.AllowFlaky; -import com.adevinta.android.barista.rule.flaky.FlakyTestRule; - import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.common.OONITests; import org.openobservatory.ooniprobe.factory.ResultFactory; import org.openobservatory.ooniprobe.model.database.Measurement; import org.openobservatory.ooniprobe.model.database.Result; -import org.openobservatory.ooniprobe.test.suite.CircumventionSuite; import org.openobservatory.ooniprobe.utils.FormattingUtils; import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; import static androidx.test.espresso.assertion.ViewAssertions.matches; -import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; -import static androidx.test.espresso.matcher.ViewMatchers.withId; -import static androidx.test.espresso.matcher.ViewMatchers.withText; +import static androidx.test.espresso.matcher.ViewMatchers.*; + +import com.adevinta.android.barista.rule.flaky.AllowFlaky; +import com.adevinta.android.barista.rule.flaky.FlakyTestRule; @RunWith(AndroidJUnit4.class) public class CircumventionTest extends MeasurementAbstractTest { @@ -32,7 +29,7 @@ public class CircumventionTest extends MeasurementAbstractTest { @AllowFlaky(attempts = 3) public void testHeaderData() { // Arrange - Result testResult = ResultFactory.createAndSave(new CircumventionSuite(), 3, 0); + Result testResult = ResultFactory.createAndSave(OONITests.CIRCUMVENTION.toOONIDescriptor(c), 3, 0); // Act launchDetails(testResult.id); @@ -44,7 +41,7 @@ public void testHeaderData() { @Test public void testSuccessPsiphon() { // Arrange - Result testResult = ResultFactory.createAndSave(new CircumventionSuite(), 3, 0); + Result testResult = ResultFactory.createAndSave(OONITests.CIRCUMVENTION.toOONIDescriptor(c), 3, 0); Measurement measurement = testResult.getMeasurement("psiphon"); String formattedBootstrap = FormattingUtils.formatBootstrap(measurement.getTestKeys().bootstrap_time); @@ -61,7 +58,7 @@ public void testSuccessPsiphon() { @Test public void testBlockedPsiphon() { // Arrange - Result testResult = ResultFactory.createAndSave(new CircumventionSuite(), 0, 3); + Result testResult = ResultFactory.createAndSave(OONITests.CIRCUMVENTION.toOONIDescriptor(c), 0, 3); Measurement measurement = testResult.getMeasurement("psiphon"); // Act @@ -77,7 +74,7 @@ public void testBlockedPsiphon() { @Test public void testSuccessTor() { // Arrange - Result testResult = ResultFactory.createAndSave(new CircumventionSuite(), 3, 0); + Result testResult = ResultFactory.createAndSave(OONITests.CIRCUMVENTION.toOONIDescriptor(c), 3, 0); Measurement measurement = testResult.getMeasurement("tor"); String formattedBridges = FormattingUtils.getFormattedBridges(measurement); @@ -97,7 +94,7 @@ public void testSuccessTor() { @Test public void testBlockedTor() { // Arrange - Result testResult = ResultFactory.createAndSave(new CircumventionSuite(), 0, 3); + Result testResult = ResultFactory.createAndSave(OONITests.CIRCUMVENTION.toOONIDescriptor(c), 0, 3); Measurement measurement = testResult.getMeasurement("tor"); String formattedBridges = FormattingUtils.getFormattedBridges(measurement); diff --git a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/InstantMessagingTest.java b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/InstantMessagingTest.java index 45214d59a..35b8a086c 100644 --- a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/InstantMessagingTest.java +++ b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/InstantMessagingTest.java @@ -9,9 +9,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.common.OONITests; import org.openobservatory.ooniprobe.factory.ResultFactory; import org.openobservatory.ooniprobe.model.database.Result; -import org.openobservatory.ooniprobe.test.suite.InstantMessagingSuite; import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; @@ -30,7 +30,7 @@ public class InstantMessagingTest extends MeasurementAbstractTest { @AllowFlaky(attempts = 3) public void testHeaderData() { // Arrange - Result testResult = ResultFactory.createAndSave(new InstantMessagingSuite()); + Result testResult = ResultFactory.createAndSave(OONITests.INSTANT_MESSAGING.toOONIDescriptor(c)); // Act launchDetails(testResult.id); @@ -43,7 +43,7 @@ public void testHeaderData() { @AllowFlaky(attempts = 2) public void testSuccessWhatsApp() { // Arrange - Result testResult = ResultFactory.createAndSave(new InstantMessagingSuite()); + Result testResult = ResultFactory.createAndSave(OONITests.INSTANT_MESSAGING.toOONIDescriptor(c)); // Act launchDetails(testResult.id); @@ -57,7 +57,7 @@ public void testSuccessWhatsApp() { @Test public void testBlockedWhatsApp() { // Arrange - Result testResult = ResultFactory.createAndSave(new InstantMessagingSuite(), 0, 4); + Result testResult = ResultFactory.createAndSave(OONITests.INSTANT_MESSAGING.toOONIDescriptor(c), 0, 4); // Act launchDetails(testResult.id); @@ -72,7 +72,7 @@ public void testBlockedWhatsApp() { @Test public void testSuccessTelegram() { // Arrange - Result testResult = ResultFactory.createAndSave(new InstantMessagingSuite()); + Result testResult = ResultFactory.createAndSave(OONITests.INSTANT_MESSAGING.toOONIDescriptor(c)); // Act launchDetails(testResult.id); @@ -87,7 +87,7 @@ public void testSuccessTelegram() { @Test public void testBlockedTelegram() { // Arrange - Result testResult = ResultFactory.createAndSave(new InstantMessagingSuite(), 0, 4); + Result testResult = ResultFactory.createAndSave(OONITests.INSTANT_MESSAGING.toOONIDescriptor(c), 0, 4); // Act launchDetails(testResult.id); @@ -102,7 +102,7 @@ public void testBlockedTelegram() { @Test public void testSuccessFacebookMessenger() { // Arrange - Result testResult = ResultFactory.createAndSave(new InstantMessagingSuite()); + Result testResult = ResultFactory.createAndSave(OONITests.INSTANT_MESSAGING.toOONIDescriptor(c)); // Act launchDetails(testResult.id); @@ -117,7 +117,7 @@ public void testSuccessFacebookMessenger() { @Test public void testBlockedFacebookMessenger() { // Arrange - Result testResult = ResultFactory.createAndSave(new InstantMessagingSuite(), 0, 4); + Result testResult = ResultFactory.createAndSave(OONITests.INSTANT_MESSAGING.toOONIDescriptor(c), 0, 4); // Act launchDetails(testResult.id); @@ -132,7 +132,7 @@ public void testBlockedFacebookMessenger() { @Test public void testSuccessSignal() { // Arrange - Result testResult = ResultFactory.createAndSave(new InstantMessagingSuite()); + Result testResult = ResultFactory.createAndSave(OONITests.INSTANT_MESSAGING.toOONIDescriptor(c)); // Act launchDetails(testResult.id); @@ -146,7 +146,7 @@ public void testSuccessSignal() { @Test public void testBlockedSignal() { // Arrange - Result testResult = ResultFactory.createAndSave(new InstantMessagingSuite(), 0, 4); + Result testResult = ResultFactory.createAndSave(OONITests.INSTANT_MESSAGING.toOONIDescriptor(c), 0, 4); // Act launchDetails(testResult.id); diff --git a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/PerformanceTest.java b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/PerformanceTest.java index 867ba6199..7cfa4b67f 100644 --- a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/PerformanceTest.java +++ b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/PerformanceTest.java @@ -22,11 +22,11 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.common.OONITests; import org.openobservatory.ooniprobe.factory.ResultFactory; import org.openobservatory.ooniprobe.model.database.Measurement; import org.openobservatory.ooniprobe.model.database.Result; import org.openobservatory.ooniprobe.model.jsonresult.TestKeys; -import org.openobservatory.ooniprobe.test.suite.PerformanceSuite; import org.openobservatory.ooniprobe.test.test.Dash; import org.openobservatory.ooniprobe.test.test.HttpHeaderFieldManipulation; import org.openobservatory.ooniprobe.test.test.HttpInvalidRequestLine; @@ -43,7 +43,7 @@ public class PerformanceTest extends MeasurementAbstractTest { @AllowFlaky(attempts = 3) public void testHeaderData() { // Arrange - Result testResult = ResultFactory.createAndSave(new PerformanceSuite()); + Result testResult = ResultFactory.createAndSave(OONITests.PERFORMANCE.toOONIDescriptor(c)); Measurement dashMeasurement = testResult.getMeasurement(Dash.NAME); String videoQuality = getResourceString(dashMeasurement.getTestKeys().getVideoQuality(false)); @@ -90,7 +90,7 @@ public void testHeaderData() { @Test public void testListOfMeasurements() { // Arrange - Result testResult = ResultFactory.createAndSave(new PerformanceSuite()); + Result testResult = ResultFactory.createAndSave(OONITests.PERFORMANCE.toOONIDescriptor(c)); Measurement dashMeasurement = testResult.getMeasurement(Dash.NAME); String videoQuality = getResourceString(dashMeasurement.getTestKeys().getVideoQuality(true)); String notDetected = getResourceString(R.string.TestResults_Overview_MiddleBoxes_NotFound); @@ -146,7 +146,7 @@ public void testListOfMeasurements() { @Test public void testNDT() { // Arrange - Result testResult = ResultFactory.createAndSave(new PerformanceSuite()); + Result testResult = ResultFactory.createAndSave(OONITests.PERFORMANCE.toOONIDescriptor(c)); Measurement ndtMeasurement = testResult.getMeasurement(Ndt.NAME); Integer ndtProtocol = ndtMeasurement.getTestKeys().protocol; TestKeys.Summary ndtSummary = ndtMeasurement.getTestKeys().summary; @@ -192,7 +192,7 @@ public void testNDT() { @Test public void testStreaming() { // Arrange - Result testResult = ResultFactory.createAndSave(new PerformanceSuite()); + Result testResult = ResultFactory.createAndSave(OONITests.PERFORMANCE.toOONIDescriptor(c)); Measurement dashMeasurement = testResult.getMeasurement(Dash.NAME); String videoQuality = getResourceString(dashMeasurement.getTestKeys().getVideoQuality(true)); String bitrateUnit = getResourceString(dashMeasurement.getTestKeys().getMedianBitrateUnit()); @@ -213,7 +213,7 @@ public void testStreaming() { @Test public void testRequestLine() { // Arrange - Result testResult = ResultFactory.createAndSave(new PerformanceSuite()); + Result testResult = ResultFactory.createAndSave(OONITests.PERFORMANCE.toOONIDescriptor(c)); Measurement invalidRequest = testResult.getMeasurement(HttpInvalidRequestLine.NAME); // Act @@ -228,7 +228,7 @@ public void testRequestLine() { @Test public void testRequestLineDetection() { // Arrange - Result testResult = ResultFactory.createAndSave(new PerformanceSuite(), 2, 2); + Result testResult = ResultFactory.createAndSave(OONITests.PERFORMANCE.toOONIDescriptor(c), 2, 2); Measurement invalidRequest = testResult.getMeasurement(HttpInvalidRequestLine.NAME); // Act @@ -243,7 +243,7 @@ public void testRequestLineDetection() { @Test public void testFieldManipulation() { // Arrange - Result testResult = ResultFactory.createAndSave(new PerformanceSuite()); + Result testResult = ResultFactory.createAndSave(OONITests.PERFORMANCE.toOONIDescriptor(c)); Measurement fieldManipulation = testResult.getMeasurement(HttpHeaderFieldManipulation.NAME); // Act @@ -258,7 +258,7 @@ public void testFieldManipulation() { @Test public void testFieldManipulationDetection() { // Arrange - Result testResult = ResultFactory.createAndSave(new PerformanceSuite(), 2, 2); + Result testResult = ResultFactory.createAndSave(OONITests.PERFORMANCE.toOONIDescriptor(c), 2, 2); Measurement fieldManipulation = testResult.getMeasurement(HttpHeaderFieldManipulation.NAME); // Act diff --git a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/TestResultsMainScreenTest.java b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/TestResultsMainScreenTest.java index ccac85cc7..838113cee 100644 --- a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/TestResultsMainScreenTest.java +++ b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/TestResultsMainScreenTest.java @@ -9,13 +9,10 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.common.OONITests; import org.openobservatory.ooniprobe.factory.ResultFactory; import org.openobservatory.ooniprobe.model.database.Result; import org.openobservatory.ooniprobe.model.jsonresult.TestKeys; -import org.openobservatory.ooniprobe.test.suite.CircumventionSuite; -import org.openobservatory.ooniprobe.test.suite.InstantMessagingSuite; -import org.openobservatory.ooniprobe.test.suite.PerformanceSuite; -import org.openobservatory.ooniprobe.test.suite.WebsitesSuite; import org.openobservatory.ooniprobe.test.test.Dash; import org.openobservatory.ooniprobe.test.test.Ndt; import org.openobservatory.ooniprobe.utils.FormattingUtils; @@ -49,10 +46,10 @@ public class TestResultsMainScreenTest extends MeasurementAbstractTest { @AllowFlaky(attempts = 3) public void testHeaderData() { // Arrange - Result websites = ResultFactory.createAndSave(new WebsitesSuite()); - Result messaging = ResultFactory.createAndSave(new InstantMessagingSuite()); - Result circumvention = ResultFactory.createAndSave(new CircumventionSuite(), 1, 2); - Result performance = ResultFactory.createAndSave(new PerformanceSuite()); + Result websites = ResultFactory.createAndSave(OONITests.WEBSITES.toOONIDescriptor(c)); + Result messaging = ResultFactory.createAndSave(OONITests.INSTANT_MESSAGING.toOONIDescriptor(c)); + Result circumvention = ResultFactory.createAndSave(OONITests.CIRCUMVENTION.toOONIDescriptor(c), 1, 2); + Result performance = ResultFactory.createAndSave(OONITests.PERFORMANCE.toOONIDescriptor(c)); long totalDownload = websites.data_usage_down + messaging.data_usage_down + @@ -78,19 +75,19 @@ public void testHeaderData() { @AllowFlaky(attempts = 3) public void testListOfResults() { // Arrange - Result websites = ResultFactory.createAndSave(new WebsitesSuite()); + Result websites = ResultFactory.createAndSave(OONITests.WEBSITES.toOONIDescriptor(c)); websites.start_time = getDateFrom(1, Calendar.JANUARY, 2020); websites.save(); - Result messaging = ResultFactory.createAndSave(new InstantMessagingSuite()); + Result messaging = ResultFactory.createAndSave(OONITests.INSTANT_MESSAGING.toOONIDescriptor(c)); messaging.start_time = getDateFrom(1, Calendar.FEBRUARY, 2020); messaging.save(); - Result circumvention = ResultFactory.createAndSave(new CircumventionSuite(), 1, 2); + Result circumvention = ResultFactory.createAndSave(OONITests.CIRCUMVENTION.toOONIDescriptor(c), 1, 2); circumvention.start_time = getDateFrom(1, Calendar.MARCH, 2020); circumvention.save(); - Result performance = ResultFactory.createAndSave(new PerformanceSuite()); + Result performance = ResultFactory.createAndSave(OONITests.PERFORMANCE.toOONIDescriptor(c)); performance.start_time = getDateFrom(1, Calendar.APRIL, 2020); performance.save(); @@ -189,8 +186,8 @@ public void testListOfResults() { @AllowFlaky(attempts = 3) public void deleteResultsTest() { // Arrange - ResultFactory.createAndSave(new WebsitesSuite()); - ResultFactory.createAndSave(new PerformanceSuite()); + ResultFactory.createAndSave(OONITests.WEBSITES.toOONIDescriptor(c)); + ResultFactory.createAndSave(OONITests.PERFORMANCE.toOONIDescriptor(c)); // Act launchResults(); @@ -208,19 +205,19 @@ public void deleteResultsTest() { @AllowFlaky(attempts = 3) public void filterTest() { // Arrange - Result websites = ResultFactory.createAndSave(new WebsitesSuite()); + Result websites = ResultFactory.createAndSave(OONITests.WEBSITES.toOONIDescriptor(c)); websites.start_time = getDateFrom(1, Calendar.JANUARY, 2020); websites.save(); - Result messaging = ResultFactory.createAndSave(new InstantMessagingSuite()); + Result messaging = ResultFactory.createAndSave(OONITests.INSTANT_MESSAGING.toOONIDescriptor(c)); messaging.start_time = getDateFrom(1, Calendar.FEBRUARY, 2020); messaging.save(); - Result circumvention = ResultFactory.createAndSave(new CircumventionSuite(), 1, 2); + Result circumvention = ResultFactory.createAndSave(OONITests.CIRCUMVENTION.toOONIDescriptor(c), 1, 2); circumvention.start_time = getDateFrom(1, Calendar.MARCH, 2020); circumvention.save(); - Result performance = ResultFactory.createAndSave(new PerformanceSuite()); + Result performance = ResultFactory.createAndSave(OONITests.PERFORMANCE.toOONIDescriptor(c)); performance.start_time = getDateFrom(1, Calendar.APRIL, 2020); performance.save(); diff --git a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/WebsitesTest.java b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/WebsitesTest.java index 31752d31f..05a4268c7 100644 --- a/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/WebsitesTest.java +++ b/app/src/androidTest/java/org/openobservatory/ooniprobe/ui/resultdetails/WebsitesTest.java @@ -1,5 +1,19 @@ package org.openobservatory.ooniprobe.ui.resultdetails; +import static androidx.test.espresso.Espresso.onData; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.contrib.RecyclerViewActions.scrollToPosition; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.isRoot; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withText; +import static org.hamcrest.Matchers.anything; +import static org.hamcrest.Matchers.containsString; +import static org.openobservatory.ooniprobe.ui.utils.RecyclerViewMatcher.withRecyclerView; +import static org.openobservatory.ooniprobe.ui.utils.ViewMatchers.waitPartialText; + import androidx.test.ext.junit.runners.AndroidJUnit4; import com.adevinta.android.barista.rule.flaky.AllowFlaky; @@ -10,29 +24,14 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.openobservatory.ooniprobe.R; +import org.openobservatory.ooniprobe.common.OONITests; import org.openobservatory.ooniprobe.factory.ResultFactory; import org.openobservatory.ooniprobe.model.database.Measurement; import org.openobservatory.ooniprobe.model.database.Result; -import org.openobservatory.ooniprobe.test.suite.WebsitesSuite; import java.util.List; import java.util.concurrent.TimeUnit; -import static androidx.test.espresso.Espresso.onData; -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.action.ViewActions.click; -import static androidx.test.espresso.assertion.ViewAssertions.matches; -import static androidx.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition; -import static androidx.test.espresso.contrib.RecyclerViewActions.scrollToPosition; -import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; -import static androidx.test.espresso.matcher.ViewMatchers.isRoot; -import static androidx.test.espresso.matcher.ViewMatchers.withId; -import static androidx.test.espresso.matcher.ViewMatchers.withText; -import static org.hamcrest.Matchers.anything; -import static org.hamcrest.Matchers.containsString; -import static org.openobservatory.ooniprobe.ui.utils.RecyclerViewMatcher.withRecyclerView; -import static org.openobservatory.ooniprobe.ui.utils.ViewMatchers.waitPartialText; - @RunWith(AndroidJUnit4.class) public class WebsitesTest extends MeasurementAbstractTest { @@ -43,7 +42,7 @@ public class WebsitesTest extends MeasurementAbstractTest { @AllowFlaky(attempts = 3) public void testHeaderData() { // Arrange - Result testResult = ResultFactory.createAndSave(new WebsitesSuite(), 10, 2); + Result testResult = ResultFactory.createAndSave(OONITests.WEBSITES.toOONIDescriptor(c), 10, 2); // Act launchDetails(testResult.id); @@ -58,7 +57,7 @@ public void checkListOfMeasurementsTest() { int successfulMeasurements = 10; int failedMeasurement = 2; - Result testResult = ResultFactory.createAndSave(new WebsitesSuite(), successfulMeasurements, failedMeasurement); + Result testResult = ResultFactory.createAndSave(OONITests.WEBSITES.toOONIDescriptor(c), successfulMeasurements, failedMeasurement); List measurements = testResult.getMeasurementsSorted(); // Act @@ -78,7 +77,7 @@ public void checkListOfMeasurementsTest() { @Test public void testSucceed() { // Arrange - Result testResult = ResultFactory.createAndSave(new WebsitesSuite()); + Result testResult = ResultFactory.createAndSave(OONITests.WEBSITES.toOONIDescriptor(c)); Measurement measurement = testResult.getMeasurementsSorted().get(0); String headerOutcome = measurement.getUrlString() + "\n" + getResourceString(R.string.TestResults_Details_Websites_Reachable_Hero_Title); @@ -94,7 +93,7 @@ public void testSucceed() { @Test public void testBlocked() { // Arrange - Result testResult = ResultFactory.createAndSave(new WebsitesSuite(), 0, 3); + Result testResult = ResultFactory.createAndSave(OONITests.WEBSITES.toOONIDescriptor(c), 0, 3); Measurement measurement = testResult.getMeasurementsSorted().get(0); String headerOutcome = measurement.getUrlString() + "\n" + BLOCKED_OUTCOME; @@ -115,7 +114,7 @@ public void canRerunTest() { int failedMeasurement = 2; int totalNumberOfMeasurements = successfulMeasurements + failedMeasurement; - Result testResult = ResultFactory.createAndSave(new WebsitesSuite(), successfulMeasurements, failedMeasurement); + Result testResult = ResultFactory.createAndSave(OONITests.WEBSITES.toOONIDescriptor(c), successfulMeasurements, failedMeasurement); String websites = totalNumberOfMeasurements + " " + getResourceString(R.string.websites); List measurements = testResult.getMeasurementsSorted(); diff --git a/app/src/dw/assets/descriptors.json b/app/src/dw/assets/descriptors.json new file mode 100644 index 000000000..837ad582c --- /dev/null +++ b/app/src/dw/assets/descriptors.json @@ -0,0 +1,312 @@ +[ + { + "name": "Trusted International Media", + "short_description": "The most reliable international media outlets.", + "description": "In this list you will find the largest, most reliable international media outlets in the world.", + "author": "internet-freedom@dw.com", + "nettests": [ + { + "test_name": "web_connectivity", + "inputs": [ + "https://www.dw.com", + "https://www.francemediasmonde.com/", + "https://www.mc-doualiya.com/", + "https://www.dw.com/", + "https://www.bbc.com/", + "http://www.lemonde.fr/", + "https://www.rferl.org/", + "http://www.rfi.fr/", + "http://www.voanews.com/", + "https://ici.radio-canada.ca/rci/en", + "https://www.rfa.org/english/", + "https://www.france24.com/en/", + "https://www3.nhk.or.jp/nhkworld/", + "https://www.abc.net.au/news", + "https://www.swissinfo.ch/eng/", + "https://www.srgssr.ch/en/home/" + ], + "options": {}, + "backend_options": {}, + "is_background_run_enabled_default": false, + "is_manual_run_enabled_default": false + } + ], + "name_intl": { + "de": "Vertrauenswürdige Internationale Medien", + "en": "Trusted international media", + "ru": "Доверенные международные СМИ" + }, + "short_description_intl": {}, + "description_intl": {}, + "icon": "FaShield", + "color": "#68bc00", + "expiration_date": "2027-07-24T00:00:00.000000Z", + "oonirun_link_id": "10004", + "date_created": "2024-06-06T14:35:13.000000Z", + "date_updated": "2024-06-06T14:56:44.000000Z", + "revision": "2", + "is_mine": false, + "is_expired": false + }, + { + "name": "Selected (inter)national media", + "short_description": "Selected national and international media outlets.", + "description": "Selected national and international media outlets. \nWarning: This could also include biased and/or propagandistic media.", + "author": "internet-freedom@dw.com", + "nettests": [ + { + "test_name": "web_connectivity", + "inputs": [ + "https://dartcenter.org/", + "https://ourworldindata.org/", + "https://www.propublica.org/", + "http://www.1tv.ru/", + "http://www.vesti.ru/", + "https://sputnikglobe.com/", + "https://rtr-planeta.com/", + "https://www.ntv.ru/", + "https://www.rtarabic.com/", + "https://vgtrk.ru/", + "https://www.currenttime.tv/", + "https://www.dailywire.com/", + "https://timcast.com/", + "https://www.projectveritas.com/", + "https://www.francemediasmonde.com/", + "https://www.france24.com/ar/", + "https://www.mc-doualiya.com/", + "https://www.washingtonpost.com/", + "https://www.spiegel.de/", + "https://www.icij.org/", + "https://foreignpolicy.com/", + "https://www.reuters.com/", + "https://sputniknews.com/", + "https://www.sbs.com.au/language/coronavirus?cid=infocus", + "http://www.ftchinese.com/", + "http://www.sputniknews.cn/", + "http://www.dailymail.co.uk/", + "https://www.theatlantic.com/", + "https://www.nbcnews.com/", + "https://www.aljazeera.com/", + "https://www.urduvoa.com/", + "https://www.dw.com/", + "https://www.nbc.com/", + "http://abc.go.com/", + "https://theintercept.com/", + "https://www.bbc.com/", + "https://www.bbc.co.uk/", + "https://www.chinadaily.com.cn/", + "https://news.google.com/", + "https://nypost.com/", + "https://www.wsj.com/", + "https://timesofindia.indiatimes.com/", + "https://wikileaks.org/", + "https://www.afp.com/", + "https://www.alarabiya.net/", + "https://www.aljazeera.net/", + "https://www.cbc.ca/", + "https://www.cbsnews.com/", + "https://www.chinatimes.com/", + "https://edition.cnn.com/", + "https://www.foxnews.com/", + "https://www.ft.com/", + "http://www.granma.cu/", + "https://www.haaretz.com/", + "http://www.indiatimes.com/", + "http://www.irna.ir/", + "http://www.kcna.kp/", + "http://www.lemonde.fr/", + "http://www.mainichi.co.jp/", + "http://www.mizzima.com/", + "https://www.nytimes.com/", + "http://www.people.com.cn/", + "http://www.pravda.ru/", + "https://www.rambler.ru/", + "https://www.reddit.com/", + "http://www.repubblica.com/", + "https://www.rferl.org/", + "http://www.rfi.fr/", + "https://www.rt.com/", + "https://www.telegraph.co.uk/", + "http://www.theepochtimes.com/", + "https://www.theguardian.com/", + "http://www.voanews.com/", + "http://www.washingtontimes.com/", + "http://www.xinhuanet.com/", + "http://www.zeit.de/" + ], + "options": {}, + "backend_options": {}, + "is_background_run_enabled_default": false, + "is_manual_run_enabled_default": false + } + ], + "name_intl": {}, + "short_description_intl": {}, + "description_intl": {}, + "icon": "FaBookOpenReader", + "color": "#000000", + "expiration_date": "2027-07-24T00:00:00.000000Z", + "oonirun_link_id": "10005", + "date_created": "2024-06-06T14:37:53.000000Z", + "date_updated": "2024-06-06T14:37:53.000000Z", + "revision": "2", + "is_mine": false, + "is_expired": false + }, + { + "name": "Global media ", + "short_description": "A wide range of global media.", + "description": "This is the largest collection of media worldwide.\n\nAttention: This list will most likely contain propagandistic and influenced media outlets.", + "author": "internet-freedom@dw.com", + "nettests": [ + { + "test_name": "web_connectivity", + "inputs": [ + "https://dartcenter.org/", + "https://ourworldindata.org/", + "https://www.propublica.org/", + "https://www.vesti.ru/", + "http://ren.tv/", + "http://smotrim.ru/", + "http://www.1tv.ru/", + "http://www.tvc.ru/", + "http://www.vesti.ru/", + "https://sputnikglobe.com/", + "https://rtr-planeta.com/", + "https://www.ntv.ru/", + "https://www.rtarabic.com/", + "https://vgtrk.ru/", + "https://www.currenttime.tv/", + "http://www.freeexpression.org/", + "https://www.dailywire.com/", + "https://timcast.com/", + "https://wearechange.org/", + "https://reclaimthenet.org/", + "https://www.muckrock.com/", + "https://www.projectveritas.com/", + "https://substack.com/", + "https://www.infowars.com/", + "https://banthis.tv/", + "http://ria.ru/", + "https://www.francemediasmonde.com/", + "https://www.france24.com/ar/", + "https://www.mc-doualiya.com/", + "https://www.usatoday.com/", + "https://www.washingtonpost.com/", + "https://www.spiegel.de/", + "https://www.icij.org/", + "http://www.qhtyzx.com/", + "http://www.qhnews.com/", + "https://liveuamap.com/", + "https://foreignpolicy.com/", + "https://www.reuters.com/", + "https://sputniknews.com/", + "https://www.sbs.com.au/language/coronavirus?cid=infocus", + "http://www.ftchinese.com/", + "http://www.sputniknews.cn/", + "https://www.dailysabah.com/", + "http://www.dailymail.co.uk/", + "https://www.economist.com/", + "https://www.theatlantic.com/", + "https://www.nbcnews.com/", + "https://slate.com/", + "https://www.aljazeera.com/", + "https://globalpressjournal.com/", + "https://www.urduvoa.com/", + "https://www.dw.com/", + "https://www.vice.com/", + "https://tyt.com/", + "https://www.nbc.com/", + "http://abc.go.com/", + "https://theintercept.com/", + "https://www.bbc.com/", + "https://www.bbc.co.uk/", + "https://asiatimes.com/", + "https://boingboing.net/", + "https://www.chinadaily.com.cn/", + "https://creativecommons.org/", + "https://indymedia.org/", + "https://ipi.media/", + "https://jezebel.com/", + "http://www.kabobfest.com/", + "https://news.google.com/", + "https://nypost.com/", + "https://www.wsj.com/", + "http://russia.tv/", + "https://slashdot.org/", + "https://timesofindia.indiatimes.com/", + "https://wikileaks.org/", + "https://www.advocate.com/", + "https://www.afp.com/", + "https://www.ahram.org.eg/", + "https://www.alarabiya.net/", + "https://www.aljazeera.net/", + "https://www.almanar.com.lb/", + "https://www.arabnews.com/", + "https://www.benedelman.org/", + "https://www.cbc.ca/", + "https://www.cbsnews.com/", + "https://www.chinatimes.com/", + "https://edition.cnn.com/", + "https://www.csmonitor.com/", + "https://www.democracynow.org/", + "https://www.dopplr.com/", + "http://www.drudgereport.com/", + "https://www.eluniversal.com/", + "https://www.foxnews.com/", + "https://www.ft.com/", + "https://www.gearthblog.com/", + "http://www.granma.cu/", + "https://www.haaretz.com/", + "https://www.huffpost.com/", + "http://www.indiatimes.com/", + "http://www.irna.ir/", + "http://www.kcna.kp/", + "http://www.lanacion.com.ar/", + "http://www.latimes.com/", + "http://www.lemonde.fr/", + "http://www.mainichi.co.jp/", + "https://www.mideastyouth.com/", + "http://www.mizzima.com/", + "https://www.nytimes.com/", + "http://www.ohmynews.com/", + "http://www.osce.org/", + "http://www.people.com.cn/", + "http://www.pravda.ru/", + "https://www.rambler.ru/", + "https://www.reddit.com/", + "http://www.repubblica.com/", + "https://www.rferl.org/", + "http://www.rfi.fr/", + "https://www.rt.com/", + "https://www.telegraph.co.uk/", + "http://www.theepochtimes.com/", + "https://www.theguardian.com/", + "http://www.theregister.co.uk/", + "http://www.voanews.com/", + "http://www.washingtontimes.com/", + "http://www.wnd.com/", + "http://www.xinhuanet.com/", + "http://www.zeit.de/", + "http://xxx.lanl.gov/" + ], + "options": {}, + "backend_options": {}, + "is_background_run_enabled_default": false, + "is_manual_run_enabled_default": false + } + ], + "name_intl": {}, + "short_description_intl": {}, + "description_intl": {}, + "icon": "FaEarthAmericas", + "color": "#000000", + "expiration_date": "2027-07-24T00:00:00.000000Z", + "oonirun_link_id": "10006", + "date_created": "2024-06-06T14:39:02.000000Z", + "date_updated": "2024-06-06T14:39:02.000000Z", + "revision": "2", + "is_mine": false, + "is_expired": false + } +] \ No newline at end of file diff --git a/app/src/dw/kotlin/org/openobservatory/ooniprobe/activity/runtests/adapter/RunTestsExpandableListViewAdapter.kt b/app/src/dw/kotlin/org/openobservatory/ooniprobe/activity/runtests/adapter/RunTestsExpandableListViewAdapter.kt new file mode 100644 index 000000000..0e44b4ad1 --- /dev/null +++ b/app/src/dw/kotlin/org/openobservatory/ooniprobe/activity/runtests/adapter/RunTestsExpandableListViewAdapter.kt @@ -0,0 +1,67 @@ +package org.openobservatory.ooniprobe.activity.runtests.adapter + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import org.openobservatory.ooniprobe.R +import org.openobservatory.ooniprobe.activity.runtests.RunTestsViewModel +import org.openobservatory.ooniprobe.activity.runtests.models.ChildItem +import org.openobservatory.ooniprobe.activity.runtests.models.GroupItem +import org.openobservatory.ooniprobe.test.test.AbstractTest + + +class RunTestsExpandableListViewAdapter( + private val groupedListData: List, + private val viewModel: RunTestsViewModel +) : AbstractRunTestsExpandableListViewAdapter(groupedListData, viewModel) { + + override fun getChildrenCount(groupPosition: Int): Int { + val group = groupedListData[groupPosition] + return if (group is GroupItem && group.nettests.isNotEmpty()) { + group.nettests[0].inputs?.size ?: 0 + } else { + 0 + } + } + + + override fun getChild(groupPosition: Int, childPosition: Int): ChildItem { + + return when (val group = groupedListData[groupPosition]) { + is GroupItem -> { + ChildItem( + name = group.nettests[0].inputs?.get(childPosition) + ?: "", + selected = false, + inputs = null + ) + } + + else -> ChildItem(name = "", selected = false, inputs = null) + } + } + + override fun getChildView( + groupPosition: Int, + childPosition: Int, + isLastChild: Boolean, + convertView: View?, + parent: ViewGroup + ): View? { + var convertView = + convertView + ?: LayoutInflater.from(parent.context) + .inflate(R.layout.run_tests_child_list_item, parent, false) + val childItem = getChild(groupPosition, childPosition) + convertView.findViewById(R.id.child_name)?.apply { + text = childItem.name + } + convertView.findViewById(R.id.child_select).apply { + visibility = View.GONE + } + convertView.setPadding(parent.context.resources.getDimensionPixelOffset(R.dimen.item_padding_prefix), 0, 0, 0) + return convertView + } +} \ No newline at end of file diff --git a/app/src/dw/kotlin/org/openobservatory/ooniprobe/common/DefaultDescriptors.kt b/app/src/dw/kotlin/org/openobservatory/ooniprobe/common/DefaultDescriptors.kt new file mode 100644 index 000000000..df9384b30 --- /dev/null +++ b/app/src/dw/kotlin/org/openobservatory/ooniprobe/common/DefaultDescriptors.kt @@ -0,0 +1,77 @@ +package org.openobservatory.ooniprobe.common + +import android.annotation.SuppressLint +import android.content.Context +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken +import com.google.gson.stream.JsonReader +import com.raizlabs.android.dbflow.sql.language.SQLite +import org.openobservatory.engine.BaseNettest +import org.openobservatory.engine.OONIRunDescriptor +import org.openobservatory.ooniprobe.model.database.TestDescriptor +import org.openobservatory.ooniprobe.model.database.TestDescriptor_Table +import org.openobservatory.ooniprobe.model.database.Url +import org.openobservatory.ooniprobe.test.suite.DynamicTestSuite + +class DefaultDescriptors { + companion object { + + @SuppressLint("StringFormatInvalid") + @JvmStatic + fun getAll(context: Context): List> { + // NOTE: Performance hit since json is read and database checked every time this method is called. + context.assets.open("descriptors.json").use { inputStream -> + JsonReader(inputStream.reader()).use { jsonReader -> + // Read the json file and convert it to a list of OONIRunDescriptor. + val descriptorType = object : TypeToken>() {}.type + val descriptorList: List = + Gson().fromJson(jsonReader, descriptorType) + // Save the descriptors to the database. + descriptorList.forEach { ooniRunDescriptor -> + + // Check if the descriptor is already in the database. + ooniRunDescriptor.nettests.forEach { nettest -> + nettest.inputs?.forEach { input -> + Url.checkExistingUrl(input) + } + } + // Check if the descriptor is already in the database. + val testDescriptor = SQLite.select().from(TestDescriptor::class.java) + .where(TestDescriptor_Table.runId.eq(ooniRunDescriptor.oonirunLinkId.toLong())) + .querySingle() + // Save the descriptor if it is not in the database. + if (testDescriptor == null) { + ooniRunDescriptor.toTestDescriptor().apply { + + ooniRunDescriptor.nettests.forEach { nettest -> + (context as? Application)?.preferenceManager?.let { + it.enableTest(nettest.name, preferencePrefix()) + it.enableTest(nettest.name, preferencePrefix(),true) + } + } + + isAutoUpdate = true + }.save() + } + } + return emptyList() + } + } + } + + @JvmStatic + fun autoRunTests( + context: Context, + preferenceManager: PreferenceManager, + testDescriptorManager: TestDescriptorManager + ): MutableList { + return testDescriptorManager.getRunV2Descriptors(expired = false) + .map { testDescriptor -> + testDescriptor.toDynamicTestSuite(context).apply { + autoRun = true + } + }.toMutableList() + } + + } +} diff --git a/app/src/dw/res/drawable/ooni_phone.xml b/app/src/dw/res/drawable/ooni_phone.xml new file mode 100644 index 000000000..43a08e8d8 --- /dev/null +++ b/app/src/dw/res/drawable/ooni_phone.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/dw/res/layout/activity_prompt.xml b/app/src/dw/res/layout/activity_prompt.xml new file mode 100644 index 000000000..e4e37fb79 --- /dev/null +++ b/app/src/dw/res/layout/activity_prompt.xml @@ -0,0 +1,85 @@ + + + + + + + + + +