From 256bf71832d266da62fdf8b3143308da00e7459b Mon Sep 17 00:00:00 2001 From: cyberta Date: Sun, 1 Jan 2023 23:41:59 +0100 Subject: add fastline basics --- Gemfile | 3 + Gemfile.lock | 218 ++++++++++++++++++++++++++++++++++++++++++++++++++++ fastlane/Appfile | 2 + fastlane/Fastfile | 38 +++++++++ fastlane/README.md | 48 ++++++++++++ fastlane/report.xml | 20 +++++ 6 files changed, 329 insertions(+) create mode 100644 Gemfile create mode 100644 Gemfile.lock create mode 100644 fastlane/Appfile create mode 100644 fastlane/Fastfile create mode 100644 fastlane/README.md create mode 100644 fastlane/report.xml diff --git a/Gemfile b/Gemfile new file mode 100644 index 00000000..7a118b49 --- /dev/null +++ b/Gemfile @@ -0,0 +1,3 @@ +source "https://rubygems.org" + +gem "fastlane" diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 00000000..0fdb16b0 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,218 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.5) + rexml + addressable (2.8.1) + public_suffix (>= 2.0.2, < 6.0) + artifactory (3.0.15) + atomos (0.1.3) + aws-eventstream (1.2.0) + aws-partitions (1.686.0) + aws-sdk-core (3.168.4) + aws-eventstream (~> 1, >= 1.0.2) + aws-partitions (~> 1, >= 1.651.0) + aws-sigv4 (~> 1.5) + jmespath (~> 1, >= 1.6.1) + aws-sdk-kms (1.61.0) + aws-sdk-core (~> 3, >= 3.165.0) + aws-sigv4 (~> 1.1) + aws-sdk-s3 (1.117.2) + aws-sdk-core (~> 3, >= 3.165.0) + aws-sdk-kms (~> 1) + aws-sigv4 (~> 1.4) + aws-sigv4 (1.5.2) + aws-eventstream (~> 1, >= 1.0.2) + babosa (1.0.4) + claide (1.1.0) + colored (1.2) + colored2 (3.1.2) + commander (4.6.0) + highline (~> 2.0.0) + declarative (0.0.20) + digest-crc (0.6.4) + rake (>= 12.0.0, < 14.0.0) + domain_name (0.5.20190701) + unf (>= 0.0.5, < 1.0.0) + dotenv (2.8.1) + emoji_regex (3.2.3) + excon (0.95.0) + faraday (1.10.2) + faraday-em_http (~> 1.0) + faraday-em_synchrony (~> 1.0) + faraday-excon (~> 1.1) + faraday-httpclient (~> 1.0) + faraday-multipart (~> 1.0) + faraday-net_http (~> 1.0) + faraday-net_http_persistent (~> 1.0) + faraday-patron (~> 1.0) + faraday-rack (~> 1.0) + faraday-retry (~> 1.0) + ruby2_keywords (>= 0.0.4) + faraday-cookie_jar (0.0.7) + faraday (>= 0.8.0) + http-cookie (~> 1.0.0) + faraday-em_http (1.0.0) + faraday-em_synchrony (1.0.0) + faraday-excon (1.1.0) + faraday-httpclient (1.0.1) + faraday-multipart (1.0.4) + multipart-post (~> 2) + faraday-net_http (1.0.1) + faraday-net_http_persistent (1.2.0) + faraday-patron (1.0.0) + faraday-rack (1.0.0) + faraday-retry (1.0.3) + faraday_middleware (1.2.0) + faraday (~> 1.0) + fastimage (2.2.6) + fastlane (2.211.0) + CFPropertyList (>= 2.3, < 4.0.0) + addressable (>= 2.8, < 3.0.0) + artifactory (~> 3.0) + aws-sdk-s3 (~> 1.0) + babosa (>= 1.0.3, < 2.0.0) + bundler (>= 1.12.0, < 3.0.0) + colored + commander (~> 4.6) + dotenv (>= 2.1.1, < 3.0.0) + emoji_regex (>= 0.1, < 4.0) + excon (>= 0.71.0, < 1.0.0) + faraday (~> 1.0) + faraday-cookie_jar (~> 0.0.6) + faraday_middleware (~> 1.0) + fastimage (>= 2.1.0, < 3.0.0) + gh_inspector (>= 1.1.2, < 2.0.0) + google-apis-androidpublisher_v3 (~> 0.3) + google-apis-playcustomapp_v1 (~> 0.1) + google-cloud-storage (~> 1.31) + highline (~> 2.0) + json (< 3.0.0) + jwt (>= 2.1.0, < 3) + mini_magick (>= 4.9.4, < 5.0.0) + multipart-post (~> 2.0.0) + naturally (~> 2.2) + optparse (~> 0.1.1) + plist (>= 3.1.0, < 4.0.0) + rubyzip (>= 2.0.0, < 3.0.0) + security (= 0.1.3) + simctl (~> 1.6.3) + terminal-notifier (>= 2.0.0, < 3.0.0) + terminal-table (>= 1.4.5, < 2.0.0) + tty-screen (>= 0.6.3, < 1.0.0) + tty-spinner (>= 0.8.0, < 1.0.0) + word_wrap (~> 1.0.0) + xcodeproj (>= 1.13.0, < 2.0.0) + xcpretty (~> 0.3.0) + xcpretty-travis-formatter (>= 0.0.3) + gh_inspector (1.1.3) + google-apis-androidpublisher_v3 (0.32.0) + google-apis-core (>= 0.9.1, < 2.a) + google-apis-core (0.9.2) + addressable (~> 2.5, >= 2.5.1) + googleauth (>= 0.16.2, < 2.a) + httpclient (>= 2.8.1, < 3.a) + mini_mime (~> 1.0) + representable (~> 3.0) + retriable (>= 2.0, < 4.a) + rexml + webrick + google-apis-iamcredentials_v1 (0.16.0) + google-apis-core (>= 0.9.1, < 2.a) + google-apis-playcustomapp_v1 (0.12.0) + google-apis-core (>= 0.9.1, < 2.a) + google-apis-storage_v1 (0.19.0) + google-apis-core (>= 0.9.0, < 2.a) + google-cloud-core (1.6.0) + google-cloud-env (~> 1.0) + google-cloud-errors (~> 1.0) + google-cloud-env (1.6.0) + faraday (>= 0.17.3, < 3.0) + google-cloud-errors (1.3.0) + google-cloud-storage (1.44.0) + addressable (~> 2.8) + digest-crc (~> 0.4) + google-apis-iamcredentials_v1 (~> 0.1) + google-apis-storage_v1 (~> 0.19.0) + google-cloud-core (~> 1.6) + googleauth (>= 0.16.2, < 2.a) + mini_mime (~> 1.0) + googleauth (1.3.0) + faraday (>= 0.17.3, < 3.a) + jwt (>= 1.4, < 3.0) + memoist (~> 0.16) + multi_json (~> 1.11) + os (>= 0.9, < 2.0) + signet (>= 0.16, < 2.a) + highline (2.0.3) + http-cookie (1.0.5) + domain_name (~> 0.5) + httpclient (2.8.3) + jmespath (1.6.2) + json (2.6.3) + jwt (2.6.0) + memoist (0.16.2) + mini_magick (4.12.0) + mini_mime (1.1.2) + multi_json (1.15.0) + multipart-post (2.0.0) + nanaimo (0.3.0) + naturally (2.2.1) + optparse (0.1.1) + os (1.1.4) + plist (3.6.0) + public_suffix (5.0.1) + rake (13.0.6) + representable (3.2.0) + declarative (< 0.1.0) + trailblazer-option (>= 0.1.1, < 0.2.0) + uber (< 0.2.0) + retriable (3.1.2) + rexml (3.2.5) + rouge (2.0.7) + ruby2_keywords (0.0.5) + rubyzip (2.3.2) + security (0.1.3) + signet (0.17.0) + addressable (~> 2.8) + faraday (>= 0.17.5, < 3.a) + jwt (>= 1.5, < 3.0) + multi_json (~> 1.10) + simctl (1.6.8) + CFPropertyList + naturally + terminal-notifier (2.0.0) + terminal-table (1.8.0) + unicode-display_width (~> 1.1, >= 1.1.1) + trailblazer-option (0.1.2) + tty-cursor (0.7.1) + tty-screen (0.8.1) + tty-spinner (0.9.3) + tty-cursor (~> 0.7) + uber (0.1.0) + unf (0.1.4) + unf_ext + unf_ext (0.0.8.2) + unicode-display_width (1.8.0) + webrick (1.7.0) + word_wrap (1.0.0) + xcodeproj (1.22.0) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.3.0) + rexml (~> 3.2.4) + xcpretty (0.3.0) + rouge (~> 2.0.7) + xcpretty-travis-formatter (1.0.1) + xcpretty (~> 0.2, >= 0.0.7) + +PLATFORMS + x86_64-darwin-21 + +DEPENDENCIES + fastlane + +BUNDLED WITH + 2.3.26 diff --git a/fastlane/Appfile b/fastlane/Appfile new file mode 100644 index 00000000..97be5207 --- /dev/null +++ b/fastlane/Appfile @@ -0,0 +1,2 @@ +json_key_file("") # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one +package_name("se.leap.bitmaskclient") # e.g. com.krausefx.app diff --git a/fastlane/Fastfile b/fastlane/Fastfile new file mode 100644 index 00000000..19c557cc --- /dev/null +++ b/fastlane/Fastfile @@ -0,0 +1,38 @@ +# This file contains the fastlane.tools configuration +# You can find the documentation at https://docs.fastlane.tools +# +# For a list of all available actions, check out +# +# https://docs.fastlane.tools/actions +# +# For a list of all available plugins, check out +# +# https://docs.fastlane.tools/plugins/available-plugins +# + +# Uncomment the line if you want fastlane to automatically update itself +# update_fastlane + +default_platform(:android) + +platform :android do + desc "Runs all the tests" + lane :test do + gradle(task: "test") + end + + desc "Submit a new Beta Build to Crashlytics Beta" + lane :beta do + gradle(task: "clean assembleRelease") + crashlytics + + # sh "your_script.sh" + # You can also use other beta testing services here + end + + desc "Deploy a new version to the Google Play" + lane :deploy do + gradle(task: "clean assembleRelease") + upload_to_play_store + end +end diff --git a/fastlane/README.md b/fastlane/README.md new file mode 100644 index 00000000..7ec1207f --- /dev/null +++ b/fastlane/README.md @@ -0,0 +1,48 @@ +fastlane documentation +---- + +# Installation + +Make sure you have the latest version of the Xcode command line tools installed: + +```sh +xcode-select --install +``` + +For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane) + +# Available Actions + +## Android + +### android test + +```sh +[bundle exec] fastlane android test +``` + +Runs all the tests + +### android beta + +```sh +[bundle exec] fastlane android beta +``` + +Submit a new Beta Build to Crashlytics Beta + +### android deploy + +```sh +[bundle exec] fastlane android deploy +``` + +Deploy a new version to the Google Play + +---- + +This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run. + +More information about _fastlane_ can be found on [fastlane.tools](https://fastlane.tools). + +The documentation of _fastlane_ can be found on [docs.fastlane.tools](https://docs.fastlane.tools). diff --git a/fastlane/report.xml b/fastlane/report.xml new file mode 100644 index 00000000..071e9c62 --- /dev/null +++ b/fastlane/report.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3 From e201e92acf17e3a71e2bffb73419fdd3726b0569 Mon Sep 17 00:00:00 2001 From: cyberta Date: Mon, 2 Jan 2023 21:08:29 +0100 Subject: simple example setup for fastlane, doing some screenshots in different languages, including screenshots with phone frames for use in an app store --- .gitignore | 3 + app/build.gradle | 19 +++--- .../androidTest/java/base/ProviderSetupTest.java | 68 ++++++++++++++++++++++ app/src/debug/AndroidManifest.xml | 43 ++++++++++++++ fastlane/Fastfile | 6 ++ fastlane/README.md | 8 +++ fastlane/Screengrabfile | 20 +++++++ fastlane/report.xml | 20 ------- 8 files changed, 160 insertions(+), 27 deletions(-) create mode 100644 app/src/androidTest/java/base/ProviderSetupTest.java create mode 100644 app/src/debug/AndroidManifest.xml create mode 100644 fastlane/Screengrabfile delete mode 100644 fastlane/report.xml diff --git a/.gitignore b/.gitignore index fb10e3e2..3997ee6d 100644 --- a/.gitignore +++ b/.gitignore @@ -106,3 +106,6 @@ lib-bitmask-core-x86_64/bitmaskcore_x86_64-sources.jar lib-bitmask-core-x86_64/bitmaskcore_x86_64.aar lib-bitmask-core/bitmaskcore-sources.jar lib-bitmask-core/bitmaskcore.aar + + +fastlane/report.xml diff --git a/app/build.gradle b/app/build.gradle index 92120f88..359597a4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -276,12 +276,13 @@ android { applicationIdSuffix ".beta" appSuffix = " Beta" buildConfigField "Boolean", "DEBUG_MODE", "true" + testCoverageEnabled = false // tor-android doesn't know this build-type, fallback to release in that case matchingFallbacks = ['release'] } debug { - testCoverageEnabled = true + testCoverageEnabled = false buildConfigField "Boolean", "DEBUG_MODE", "true" } } @@ -410,13 +411,17 @@ dependencies { testImplementation 'org.powermock:powermock-module-junit4-rule:2.0.9' testImplementation group: 'com.tngtech.java', name: 'junit-dataprovider', version: '1.10.0' - androidTestImplementation 'org.mockito:mockito-core:3.6.0' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' - androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.4.0' - androidTestImplementation 'androidx.test.espresso:espresso-intents:3.4.0' - //TODO: remove that library - androidTestImplementation 'com.jayway.android.robotium:robotium-solo:5.6.3' + androidTestImplementation 'org.mockito:mockito-core:3.9.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0' + androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.5.0' + androidTestImplementation 'androidx.test.espresso:espresso-intents:3.5.0' + + androidTestImplementation 'tools.fastlane:screengrab:2.1.1' + testImplementation 'tools.fastlane:screengrab:2.1.1' + + testImplementation 'org.json:json:20180813' + androidTestImplementation 'androidx.test.ext:junit:1.1.4' debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1' annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3' annotationProcessor 'com.squareup.dagger:dagger-compiler:1.2.2' diff --git a/app/src/androidTest/java/base/ProviderSetupTest.java b/app/src/androidTest/java/base/ProviderSetupTest.java new file mode 100644 index 00000000..fd46a093 --- /dev/null +++ b/app/src/androidTest/java/base/ProviderSetupTest.java @@ -0,0 +1,68 @@ +package base; + + +import static android.content.Context.MODE_PRIVATE; +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; +import static androidx.test.espresso.Espresso.onData; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static org.hamcrest.Matchers.anything; + +import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; + +import android.content.SharedPreferences; + +import androidx.test.ext.junit.rules.ActivityScenarioRule; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.LargeTest; + +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Locale; + +import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.base.StartActivity; +import se.leap.bitmaskclient.base.utils.PreferenceHelper; +import se.leap.bitmaskclient.providersetup.ProviderListActivity; +import se.leap.bitmaskclient.providersetup.activities.ProviderSetupBaseActivity; +import se.leap.bitmaskclient.testutils.ForceLocaleRule; +import tools.fastlane.screengrab.Screengrab; +import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy; +import tools.fastlane.screengrab.locale.LocaleTestRule; + +@LargeTest +@RunWith(AndroidJUnit4.class) +public class ProviderSetupTest { + + @ClassRule + public static final LocaleTestRule localeTestRule = new LocaleTestRule(); + + @Rule + public ActivityScenarioRule mActivityScenarioRule = + new ActivityScenarioRule<>(ProviderListActivity.class); + + @Before + public void setup() { + Screengrab.setDefaultScreenshotStrategy(new UiAutomatorScreenshotStrategy()); + SharedPreferences preferences = getApplicationContext().getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); + preferences.edit().clear().commit(); + } + + @Test + public void testConfigureRiseupVPNScreenshot() { + Screengrab.screenshot("configureRiseupVPN_before_button_click"); + onData(anything()).inAdapterView(withId(R.id.provider_list)).atPosition(2).perform(click()); + Screengrab.screenshot("configureRiseupVPN_after_button_click"); + } + + @Test + public void testaddManuallyNewProviderScreenshot() { + Screengrab.screenshot("addManuallyNewProvider_before_button_click"); + onData(anything()).inAdapterView(withId(R.id.provider_list)).atPosition(3).perform(click()); + Screengrab.screenshot("addManuallyNewProvider_after_button_click"); + } +} diff --git a/app/src/debug/AndroidManifest.xml b/app/src/debug/AndroidManifest.xml new file mode 100644 index 00000000..51e17015 --- /dev/null +++ b/app/src/debug/AndroidManifest.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 19c557cc..d985984d 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -21,6 +21,12 @@ platform :android do gradle(task: "test") end + lane :screenshots do + capture_android_screenshots + frameit(white: true) + # deliver + end + desc "Submit a new Beta Build to Crashlytics Beta" lane :beta do gradle(task: "clean assembleRelease") diff --git a/fastlane/README.md b/fastlane/README.md index 7ec1207f..96002ac1 100644 --- a/fastlane/README.md +++ b/fastlane/README.md @@ -23,6 +23,14 @@ For _fastlane_ installation instructions, see [Installing _fastlane_](https://do Runs all the tests +### android screenshots + +```sh +[bundle exec] fastlane android screenshots +``` + + + ### android beta ```sh diff --git a/fastlane/Screengrabfile b/fastlane/Screengrabfile new file mode 100644 index 00000000..4c46de1a --- /dev/null +++ b/fastlane/Screengrabfile @@ -0,0 +1,20 @@ +# remove the leading '#' to uncomment lines + +# app_package_name('your.app.package') +# use_tests_in_packages(['your.screenshot.tests.package']) + +app_apk_path('app/build/outputs/apk/normalProductionFat/debug/Bitmask_debug.apk') +# tests_apk_path('app/build/intermediates/apk/androidTest/normalProductionFat/debug/app-normal-production-fat-debug-androidTest.apk') + +# all locales +# locales(['ar', 'az', 'bg', 'bn', 'br', 'ca', 'cs', 'de', 'el', 'es', 'es-AR', 'et', 'eu', 'fa-IR', 'fi', 'fr', 'gl', 'he', 'hr', 'hu', 'id', 'it', 'ja', 'my', 'nl', 'no', 'pl', 'pt-BR', 'pt-PT', 'ro', 'ru', 'tr', 'ug', 'uk', 'vi', 'zh-CN', 'zh-TW']) +# prioritized locales +# locales(['ar', 'bn', 'de', 'es', 'fa-IR', 'fr', 'he', 'hu', 'id', 'it', 'ja', 'my', 'nl', 'pt-BR', 'pt-PT', 'ru', 'tr', 'ug', 'uk', 'zh-CN', 'zh-TW']) +# development locales +locales(['ar', 'de', 'ru']) + +# clear all previously generated screenshots in your local output directory before creating new ones +clear_previous_screenshots(true) + +# For more information about all available options run +# fastlane screengrab --help diff --git a/fastlane/report.xml b/fastlane/report.xml deleted file mode 100644 index 071e9c62..00000000 --- a/fastlane/report.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - -- cgit v1.2.3 From b0f96ee9ca2c612836f1a59222b1148b763fbedd Mon Sep 17 00:00:00 2001 From: cyberta Date: Mon, 2 Jan 2023 21:55:17 +0100 Subject: remove unused imports --- app/src/androidTest/java/base/ProviderSetupTest.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/app/src/androidTest/java/base/ProviderSetupTest.java b/app/src/androidTest/java/base/ProviderSetupTest.java index fd46a093..d5a363aa 100644 --- a/app/src/androidTest/java/base/ProviderSetupTest.java +++ b/app/src/androidTest/java/base/ProviderSetupTest.java @@ -7,7 +7,6 @@ import static androidx.test.espresso.Espresso.onData; import static androidx.test.espresso.action.ViewActions.click; import static androidx.test.espresso.matcher.ViewMatchers.withId; import static org.hamcrest.Matchers.anything; - import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; import android.content.SharedPreferences; @@ -22,14 +21,8 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import java.util.Locale; - import se.leap.bitmaskclient.R; -import se.leap.bitmaskclient.base.StartActivity; -import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.providersetup.ProviderListActivity; -import se.leap.bitmaskclient.providersetup.activities.ProviderSetupBaseActivity; -import se.leap.bitmaskclient.testutils.ForceLocaleRule; import tools.fastlane.screengrab.Screengrab; import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy; import tools.fastlane.screengrab.locale.LocaleTestRule; -- cgit v1.2.3 From 108b886f43feeb861807deddfcb1ab241330e242 Mon Sep 17 00:00:00 2001 From: cyberta Date: Thu, 19 Jan 2023 18:47:14 +0100 Subject: improve screenshot tests, run in different languages, test more Fragments/Activities --- app/build.gradle | 5 - .../androidTest/java/base/ProviderSetupTest.java | 61 ------- .../leap/bitmaskclient/base/ProviderSetupTest.java | 68 ++++++++ .../se/leap/bitmaskclient/base/VpnStartTest.java | 176 +++++++++++++++++++++ .../leap/bitmaskclient/suite/ScreenshotTest.java | 19 +++ .../androidTest/java/utils/CustomInteractions.java | 81 ++++++++++ app/src/androidTest/java/utils/CustomMatchers.java | 31 ++++ .../androidTest/java/utils/CustomViewActions.java | 89 +++++++++++ .../leap/bitmaskclient/base/views/MainButton.java | 2 + .../testutils/TestSetupHelper.java | 108 ------------- .../bitmaskclient/testutils/TestSetupHelper.java | 108 +++++++++++++ fastlane/Screengrabfile | 6 +- 12 files changed, 577 insertions(+), 177 deletions(-) delete mode 100644 app/src/androidTest/java/base/ProviderSetupTest.java create mode 100644 app/src/androidTest/java/se/leap/bitmaskclient/base/ProviderSetupTest.java create mode 100644 app/src/androidTest/java/se/leap/bitmaskclient/base/VpnStartTest.java create mode 100644 app/src/androidTest/java/se/leap/bitmaskclient/suite/ScreenshotTest.java create mode 100644 app/src/androidTest/java/utils/CustomInteractions.java create mode 100644 app/src/androidTest/java/utils/CustomMatchers.java create mode 100644 app/src/androidTest/java/utils/CustomViewActions.java delete mode 100644 app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java create mode 100644 app/src/test/java/se/leap/bitmaskclient/testutils/TestSetupHelper.java diff --git a/app/build.gradle b/app/build.gradle index 359597a4..3034b062 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -307,11 +307,6 @@ android { test { resources.srcDirs += ['src/test/resources'] - java.srcDirs += ['src/sharedTest/java'] - } - - androidTest { - java.srcDirs += ['src/sharedTest/java'] } fatweb { diff --git a/app/src/androidTest/java/base/ProviderSetupTest.java b/app/src/androidTest/java/base/ProviderSetupTest.java deleted file mode 100644 index d5a363aa..00000000 --- a/app/src/androidTest/java/base/ProviderSetupTest.java +++ /dev/null @@ -1,61 +0,0 @@ -package base; - - -import static android.content.Context.MODE_PRIVATE; -import static androidx.test.core.app.ApplicationProvider.getApplicationContext; -import static androidx.test.espresso.Espresso.onData; -import static androidx.test.espresso.action.ViewActions.click; -import static androidx.test.espresso.matcher.ViewMatchers.withId; -import static org.hamcrest.Matchers.anything; -import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; - -import android.content.SharedPreferences; - -import androidx.test.ext.junit.rules.ActivityScenarioRule; -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.filters.LargeTest; - -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import se.leap.bitmaskclient.R; -import se.leap.bitmaskclient.providersetup.ProviderListActivity; -import tools.fastlane.screengrab.Screengrab; -import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy; -import tools.fastlane.screengrab.locale.LocaleTestRule; - -@LargeTest -@RunWith(AndroidJUnit4.class) -public class ProviderSetupTest { - - @ClassRule - public static final LocaleTestRule localeTestRule = new LocaleTestRule(); - - @Rule - public ActivityScenarioRule mActivityScenarioRule = - new ActivityScenarioRule<>(ProviderListActivity.class); - - @Before - public void setup() { - Screengrab.setDefaultScreenshotStrategy(new UiAutomatorScreenshotStrategy()); - SharedPreferences preferences = getApplicationContext().getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); - preferences.edit().clear().commit(); - } - - @Test - public void testConfigureRiseupVPNScreenshot() { - Screengrab.screenshot("configureRiseupVPN_before_button_click"); - onData(anything()).inAdapterView(withId(R.id.provider_list)).atPosition(2).perform(click()); - Screengrab.screenshot("configureRiseupVPN_after_button_click"); - } - - @Test - public void testaddManuallyNewProviderScreenshot() { - Screengrab.screenshot("addManuallyNewProvider_before_button_click"); - onData(anything()).inAdapterView(withId(R.id.provider_list)).atPosition(3).perform(click()); - Screengrab.screenshot("addManuallyNewProvider_after_button_click"); - } -} diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/base/ProviderSetupTest.java b/app/src/androidTest/java/se/leap/bitmaskclient/base/ProviderSetupTest.java new file mode 100644 index 00000000..23db8582 --- /dev/null +++ b/app/src/androidTest/java/se/leap/bitmaskclient/base/ProviderSetupTest.java @@ -0,0 +1,68 @@ +package se.leap.bitmaskclient.base; + + +import static android.content.Context.MODE_PRIVATE; +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; +import static androidx.test.espresso.Espresso.onData; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static org.hamcrest.Matchers.anything; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.hasToString; +import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; +import static utils.CustomInteractions.tryResolve; + +import android.content.SharedPreferences; + +import androidx.test.espresso.DataInteraction; +import androidx.test.espresso.NoMatchingViewException; +import androidx.test.ext.junit.rules.ActivityScenarioRule; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.LargeTest; + +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.providersetup.ProviderListActivity; +import tools.fastlane.screengrab.Screengrab; +import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy; +import tools.fastlane.screengrab.locale.LocaleTestRule; + +@LargeTest +@RunWith(AndroidJUnit4.class) +public class ProviderSetupTest { + + @ClassRule + public static final LocaleTestRule localeTestRule = new LocaleTestRule(); + + @Rule + public ActivityScenarioRule mActivityScenarioRule = + new ActivityScenarioRule<>(ProviderListActivity.class); + + @Before + public void setup() { + Screengrab.setDefaultScreenshotStrategy(new UiAutomatorScreenshotStrategy()); + SharedPreferences preferences = getApplicationContext().getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); + preferences.edit().clear().commit(); + } + + @Test + public void testConfigureRiseupVPNScreenshot() { + DataInteraction linearLayout = tryResolve(onData(hasToString(containsString("riseup.net"))) + .inAdapterView(withId(R.id.provider_list)), + 2); + Screengrab.screenshot("ProviderListActivity"); + linearLayout.perform(click()); + Screengrab.screenshot("ProviderListActivity_configureRiseup"); + } + + @Test + public void testaddManuallyNewProviderScreenshot() { + onData(anything()).inAdapterView(withId(R.id.provider_list)).atPosition(3).perform(click()); + Screengrab.screenshot("ProviderListActivity_addManuallyNewProvider"); + } +} diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/base/VpnStartTest.java b/app/src/androidTest/java/se/leap/bitmaskclient/base/VpnStartTest.java new file mode 100644 index 00000000..6c99b90e --- /dev/null +++ b/app/src/androidTest/java/se/leap/bitmaskclient/base/VpnStartTest.java @@ -0,0 +1,176 @@ +package se.leap.bitmaskclient.base; + + +import static android.content.Context.MODE_PRIVATE; +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; +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.DrawerMatchers.isClosed; +import static androidx.test.espresso.matcher.RootMatchers.isDialog; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withTagValue; +import static androidx.test.espresso.matcher.ViewMatchers.withText; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.anything; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.hasToString; +import static org.hamcrest.Matchers.is; +import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; +import static utils.CustomInteractions.tryResolve; + +import android.content.SharedPreferences; +import android.view.Gravity; + +import androidx.test.espresso.DataInteraction; +import androidx.test.espresso.NoMatchingViewException; +import androidx.test.espresso.ViewInteraction; +import androidx.test.espresso.contrib.DrawerActions; +import androidx.test.ext.junit.rules.ActivityScenarioRule; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.LargeTest; + +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.FixMethodOrder; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; + +import se.leap.bitmaskclient.R; +import tools.fastlane.screengrab.Screengrab; +import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy; +import tools.fastlane.screengrab.locale.LocaleTestRule; + +@LargeTest +@RunWith(AndroidJUnit4.class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class VpnStartTest { + + @ClassRule + public static final LocaleTestRule localeTestRule = new LocaleTestRule(); + + @Rule + public ActivityScenarioRule mActivityScenarioRule = + new ActivityScenarioRule<>(StartActivity.class); + + @Before + public void setup() { + Screengrab.setDefaultScreenshotStrategy(new UiAutomatorScreenshotStrategy()); + SharedPreferences preferences = getApplicationContext().getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); + preferences.edit().clear().commit(); + } + + @Test + public void test01_vpnStartTest() { + boolean configurationNeeded = configureProviderIfNeeded(); + + ViewInteraction mainButtonStop; + if (!configurationNeeded) { + // click on Main on/off button and start VPN + ViewInteraction mainButton = tryResolve( + onView(withId(R.id.main_button)), + matches(isDisplayed()) + ); + + mainButton.perform(click()); + tryResolve( + onView(allOf( + withId(R.id.button), + withTagValue(is("button_circle_cancel")))), + matches(isDisplayed()), + 2); + Screengrab.screenshot("VPN_connecting"); + + mainButtonStop = tryResolve( + onView(allOf( + withId(R.id.button), + withTagValue(is("button_circle_stop")))), + matches(isDisplayed()), + 20); + Screengrab.screenshot("VPN_connected"); + } else { + // on new configurations the VPN is automatically started + Screengrab.screenshot("VPN_connecting"); + mainButtonStop = tryResolve( + onView(allOf( + withId(R.id.button), + withTagValue(is("button_circle_stop")))), + matches(isDisplayed()), + 20); + Screengrab.screenshot("VPN_connected"); + } + + mainButtonStop.perform(click()); + Screengrab.screenshot("VPN_ask_disconnect"); + + onView(withText(android.R.string.yes)) + .inRoot(isDialog()) + .check(matches(isDisplayed())) + .perform(click()); + Screengrab.screenshot("VPN_disconnected"); + } + + @Test + public void test02_SettingsFragmentScreenshots() { + onView(withId(R.id.drawer_layout)) + .check(matches(isClosed(Gravity.LEFT))) // Left Drawer should be closed. + .perform(DrawerActions.open()); // Open Drawer + + Screengrab.screenshot("navigationDrawer"); + + // Start the screen of your activity. + onView(withId(R.id.advancedSettings)) + .perform(click()); + + Screengrab.screenshot("settingsFragment"); + } + + @Test + public void test03_LocationSelectionFragmentScreenshots() { + onView(withId(R.id.drawer_layout)) + .check(matches(isClosed(Gravity.LEFT))) // Left Drawer should be closed. + .perform(DrawerActions.open()); // Open Drawer + + onView(withId(R.id.manualGatewaySelection)) + .perform(click()); + + Screengrab.screenshot("GatewaySelectionFragment"); + } + + @Test + public void test04_AppExclusionFragmentScreenshots() { + onView(withId(R.id.drawer_layout)) + .check(matches(isClosed(Gravity.LEFT))) // Left Drawer should be closed. + .perform(DrawerActions.open()); // Open Drawer + + onView(withId(R.id.advancedSettings)).perform(click()); + + onView(withId(R.id.exclude_apps)).perform(click()); + + tryResolve( + onData(anything()).inAdapterView(withId(android.R.id.list)).atPosition(2), + matches(isDisplayed()), + 5); + + Screengrab.screenshot("App_Exclusion_Fragment"); + } + + public boolean configureProviderIfNeeded() { + try { + DataInteraction linearLayout = tryResolve(onData(hasToString(containsString("riseup.net"))) + .inAdapterView(withId(R.id.provider_list)), + 2); + linearLayout.perform(click()); + return true; + } catch (NoMatchingViewException e) { + // it might be that the provider was already configured, so we print the stack + // trace here and try to continue + e.printStackTrace(); + } + return false; + } +} diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/suite/ScreenshotTest.java b/app/src/androidTest/java/se/leap/bitmaskclient/suite/ScreenshotTest.java new file mode 100644 index 00000000..186a50d1 --- /dev/null +++ b/app/src/androidTest/java/se/leap/bitmaskclient/suite/ScreenshotTest.java @@ -0,0 +1,19 @@ +package se.leap.bitmaskclient.suite; + + +import androidx.test.filters.LargeTest; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +import se.leap.bitmaskclient.base.ProviderSetupTest; +import se.leap.bitmaskclient.base.VpnStartTest; + +@LargeTest +@RunWith(Suite.class) +@Suite.SuiteClasses({ + ProviderSetupTest.class, + VpnStartTest.class, +}) +public class ScreenshotTest { +} diff --git a/app/src/androidTest/java/utils/CustomInteractions.java b/app/src/androidTest/java/utils/CustomInteractions.java new file mode 100644 index 00000000..896e8d9b --- /dev/null +++ b/app/src/androidTest/java/utils/CustomInteractions.java @@ -0,0 +1,81 @@ +package utils; + +import androidx.annotation.Nullable; +import androidx.test.espresso.DataInteraction; +import androidx.test.espresso.NoMatchingViewException; +import androidx.test.espresso.ViewAssertion; +import androidx.test.espresso.ViewInteraction; + +public class CustomInteractions { + + public static @Nullable + ViewInteraction tryResolve(ViewInteraction viewInteraction, int maxTries) { + return tryResolve(viewInteraction, null, maxTries); + } + + public static @Nullable + ViewInteraction tryResolve(ViewInteraction viewInteraction, ViewAssertion assertion) { + return tryResolve(viewInteraction, assertion, 10); + } + + public static @Nullable ViewInteraction tryResolve(ViewInteraction viewInteraction, ViewAssertion assertion, int maxTries) { + ViewInteraction resolvedViewInteraction = null; + int attempt = 0; + boolean hasFound = false; + while (!hasFound && attempt < maxTries) { + try { + resolvedViewInteraction = viewInteraction; + if (assertion != null) { + resolvedViewInteraction.check(assertion); + } + hasFound = true; + } catch (NoMatchingViewException exception) { + System.out.println("NoMatchingViewException attempt: " + attempt); + attempt++; + if (attempt == maxTries) { + throw exception; + } + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + break; + } + } + } + return resolvedViewInteraction; + } + + public static @Nullable + DataInteraction tryResolve(DataInteraction dataInteraction, ViewAssertion assertion, int maxTries) { + DataInteraction resolvedDataInteraction = null; + int attempt = 0; + boolean hasFound = false; + while (!hasFound && attempt < maxTries) { + try { + resolvedDataInteraction = dataInteraction; + if (assertion != null) { + resolvedDataInteraction.check(assertion); + } + hasFound = true; + } catch (Exception exception) { + // TODO: specify expected exception + attempt++; + if (attempt == maxTries) { + throw exception; + } + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + break; + } + } + } + return resolvedDataInteraction; + } + public static @Nullable + DataInteraction tryResolve(DataInteraction dataInteraction, int maxTries) { + return tryResolve(dataInteraction, null, maxTries); + } +} diff --git a/app/src/androidTest/java/utils/CustomMatchers.java b/app/src/androidTest/java/utils/CustomMatchers.java new file mode 100644 index 00000000..5fe11cd2 --- /dev/null +++ b/app/src/androidTest/java/utils/CustomMatchers.java @@ -0,0 +1,31 @@ +package utils; + +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewParent; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; + +public class CustomMatchers { + + public static Matcher childAtPosition( + final Matcher parentMatcher, final int position) { + + return new TypeSafeMatcher() { + @Override + public void describeTo(Description description) { + description.appendText("Child at position " + position + " in parent "); + parentMatcher.describeTo(description); + } + + @Override + public boolean matchesSafely(View view) { + ViewParent parent = view.getParent(); + return parent instanceof ViewGroup && parentMatcher.matches(parent) + && view.equals(((ViewGroup) parent).getChildAt(position)); + } + }; + } +} diff --git a/app/src/androidTest/java/utils/CustomViewActions.java b/app/src/androidTest/java/utils/CustomViewActions.java new file mode 100644 index 00000000..fb0dcc27 --- /dev/null +++ b/app/src/androidTest/java/utils/CustomViewActions.java @@ -0,0 +1,89 @@ +package utils; + +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 android.view.View; + +import androidx.annotation.StringRes; +import androidx.test.espresso.UiController; +import androidx.test.espresso.ViewAction; +import androidx.test.espresso.util.TreeIterables; + +import org.hamcrest.Matcher; + +public class CustomViewActions { + + public static ViewAction waitForView(int viewId, long timeout) { + return new ViewAction() { + + @Override + public String getDescription() { + return "Wait for view with specific id \n@param viewId: resource ID \n@param timeout: timeout in milli seconds."; + } + + @Override + public Matcher getConstraints() { + return isRoot(); + } + + @Override + public void perform(UiController uiController, View view) { + uiController.loopMainThreadUntilIdle(); + long startTime = System.currentTimeMillis(); + long endTime = startTime + timeout; + Matcher viewMatcher = withId(viewId); + + while (System.currentTimeMillis() < endTime) { + // Iterate through all views on the screen and see if the view we are looking for is there already + for (View child : TreeIterables.breadthFirstViewTraversal(view)) { + // found view with required ID + if (viewMatcher.matches(child)) { + return; + } + } + // Loops the main thread for a specified period of time. + // Control may not return immediately, instead it'll return after the provided delay has passed and the queue is in an idle state again. + uiController.loopMainThreadForAtLeast(100); + } + } + }; + } + + public static ViewAction waitForText(@StringRes int textId, long timeout) { + return new ViewAction() { + + @Override + public String getDescription() { + return "Wait for view with specific id \n@param viewId: resource ID \n@param timeout: timeout in milli seconds."; + } + + @Override + public Matcher getConstraints() { + return isRoot(); + } + + @Override + public void perform(UiController uiController, View view) { + uiController.loopMainThreadUntilIdle(); + long startTime = System.currentTimeMillis(); + long endTime = startTime + timeout; + Matcher viewMatcher = withText(textId); + + while (System.currentTimeMillis() < endTime) { + // Iterate through all views on the screen and see if the view we are looking for is there already + for (View child : TreeIterables.breadthFirstViewTraversal(view)) { + // found view with required ID + if (viewMatcher.matches(child)) { + return; + } + } + // Loops the main thread for a specified period of time. + // Control may not return immediately, instead it'll return after the provided delay has passed and the queue is in an idle state again. + uiController.loopMainThreadForAtLeast(100); + } + } + }; + } +} \ No newline at end of file diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java b/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java index fc86fc0b..c7273613 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java @@ -48,10 +48,12 @@ public class MainButton extends RelativeLayout { public void updateState(boolean isOn, boolean isProcessing) { if (isProcessing) { button.setImageDrawable(ContextCompat.getDrawable(getContext(), R.drawable.button_circle_cancel)); + button.setTag("button_circle_cancel"); } else { button.setImageDrawable( ContextCompat.getDrawable(getContext(), isOn ? R.drawable.button_circle_stop : R.drawable.button_circle_start)); + button.setTag(isOn ? "button_circle_stop" : "button_circle_start"); } } } diff --git a/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java b/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java deleted file mode 100644 index 72791ba6..00000000 --- a/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java +++ /dev/null @@ -1,108 +0,0 @@ -/** - * Copyright (c) 2018 LEAP Encryption Access Project and contributers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package se.leap.bitmaskclient.testutils; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; - -import se.leap.bitmaskclient.base.models.Provider; - -/** - * Created by cyberta on 08.10.17. - */ - -public class TestSetupHelper { - - public static String getInputAsString(InputStream fileAsInputStream) throws IOException { - BufferedReader br = new BufferedReader(new InputStreamReader(fileAsInputStream)); - StringBuilder sb = new StringBuilder(); - String line = br.readLine(); - while (line != null) { - sb.append(line); - line = br.readLine(); - if (line != null) { - sb.append("\n"); - } - } - - return sb.toString(); - } - - - public static Provider getConfiguredProvider() throws IOException, JSONException { - return getProvider(null, null, null, null, null, null, null, null); - } - - public static Provider getConfiguredProviderAPIv4() { - return getProvider(null, null, null, null, null, "v4/riseup.net.json", "v4/riseup.service.json", null); - } - - - public static Provider getProvider(String domain, String geoipUrl, String providerIp, String providerApiIp, String caCertFile, String providerJson, String eipServiceJson, String geoIpJson) { - if (domain == null) - domain = "https://riseup.net"; - if (geoipUrl == null) - geoipUrl = "https://api.black.riseup.net:9001/json"; - if (providerIp == null) { - providerIp = ""; - } - if (providerApiIp == null) { - providerApiIp = ""; - } - if (caCertFile == null) - caCertFile = "riseup.net.pem"; - if (providerJson == null) - providerJson = "riseup.net.json"; - if (eipServiceJson == null) { - eipServiceJson = "riseup.service.json"; - } - if (geoIpJson == null) { - geoIpJson = "riseup.geoip.json"; - } - - try { - Provider p = new Provider( - domain, - geoipUrl, - null, - providerIp, - providerApiIp, - getInputAsString(TestSetupHelper.class.getClassLoader().getResourceAsStream(caCertFile)), - getInputAsString(TestSetupHelper.class.getClassLoader().getResourceAsStream(providerJson)) - - ); - JSONObject eipServiceJsonObject = new JSONObject( - getInputAsString(TestSetupHelper.class.getClassLoader().getResourceAsStream(eipServiceJson))); - p.setEipServiceJson(eipServiceJsonObject); - - JSONObject geoIpJsonObject = new JSONObject( - getInputAsString(TestSetupHelper.class.getClassLoader().getResourceAsStream(geoIpJson))); - p.setGeoIpJson(geoIpJsonObject); - return p; - } catch (IOException | JSONException e) { - e.printStackTrace(); - } - return null; - } - -} diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/TestSetupHelper.java b/app/src/test/java/se/leap/bitmaskclient/testutils/TestSetupHelper.java new file mode 100644 index 00000000..72791ba6 --- /dev/null +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/TestSetupHelper.java @@ -0,0 +1,108 @@ +/** + * Copyright (c) 2018 LEAP Encryption Access Project and contributers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package se.leap.bitmaskclient.testutils; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +import se.leap.bitmaskclient.base.models.Provider; + +/** + * Created by cyberta on 08.10.17. + */ + +public class TestSetupHelper { + + public static String getInputAsString(InputStream fileAsInputStream) throws IOException { + BufferedReader br = new BufferedReader(new InputStreamReader(fileAsInputStream)); + StringBuilder sb = new StringBuilder(); + String line = br.readLine(); + while (line != null) { + sb.append(line); + line = br.readLine(); + if (line != null) { + sb.append("\n"); + } + } + + return sb.toString(); + } + + + public static Provider getConfiguredProvider() throws IOException, JSONException { + return getProvider(null, null, null, null, null, null, null, null); + } + + public static Provider getConfiguredProviderAPIv4() { + return getProvider(null, null, null, null, null, "v4/riseup.net.json", "v4/riseup.service.json", null); + } + + + public static Provider getProvider(String domain, String geoipUrl, String providerIp, String providerApiIp, String caCertFile, String providerJson, String eipServiceJson, String geoIpJson) { + if (domain == null) + domain = "https://riseup.net"; + if (geoipUrl == null) + geoipUrl = "https://api.black.riseup.net:9001/json"; + if (providerIp == null) { + providerIp = ""; + } + if (providerApiIp == null) { + providerApiIp = ""; + } + if (caCertFile == null) + caCertFile = "riseup.net.pem"; + if (providerJson == null) + providerJson = "riseup.net.json"; + if (eipServiceJson == null) { + eipServiceJson = "riseup.service.json"; + } + if (geoIpJson == null) { + geoIpJson = "riseup.geoip.json"; + } + + try { + Provider p = new Provider( + domain, + geoipUrl, + null, + providerIp, + providerApiIp, + getInputAsString(TestSetupHelper.class.getClassLoader().getResourceAsStream(caCertFile)), + getInputAsString(TestSetupHelper.class.getClassLoader().getResourceAsStream(providerJson)) + + ); + JSONObject eipServiceJsonObject = new JSONObject( + getInputAsString(TestSetupHelper.class.getClassLoader().getResourceAsStream(eipServiceJson))); + p.setEipServiceJson(eipServiceJsonObject); + + JSONObject geoIpJsonObject = new JSONObject( + getInputAsString(TestSetupHelper.class.getClassLoader().getResourceAsStream(geoIpJson))); + p.setGeoIpJson(geoIpJsonObject); + return p; + } catch (IOException | JSONException e) { + e.printStackTrace(); + } + return null; + } + +} diff --git a/fastlane/Screengrabfile b/fastlane/Screengrabfile index 4c46de1a..8a149163 100644 --- a/fastlane/Screengrabfile +++ b/fastlane/Screengrabfile @@ -1,10 +1,10 @@ # remove the leading '#' to uncomment lines # app_package_name('your.app.package') -# use_tests_in_packages(['your.screenshot.tests.package']) +use_tests_in_packages(['se.leap.bitmaskclient.suite']) -app_apk_path('app/build/outputs/apk/normalProductionFat/debug/Bitmask_debug.apk') -# tests_apk_path('app/build/intermediates/apk/androidTest/normalProductionFat/debug/app-normal-production-fat-debug-androidTest.apk') +app_apk_path('app/build/intermediates/apk/normalProductionFat/debug/Bitmask_debug.apk') +tests_apk_path('app/build/intermediates/apk/androidTest/normalProductionFat/debug/app-normal-production-fat-debug-androidTest.apk') # all locales # locales(['ar', 'az', 'bg', 'bn', 'br', 'ca', 'cs', 'de', 'el', 'es', 'es-AR', 'et', 'eu', 'fa-IR', 'fi', 'fr', 'gl', 'he', 'hr', 'hu', 'id', 'it', 'ja', 'my', 'nl', 'no', 'pl', 'pt-BR', 'pt-PT', 'ro', 'ru', 'tr', 'ug', 'uk', 'vi', 'zh-CN', 'zh-TW']) -- cgit v1.2.3 From a800ef1e82c25207a842c197190b614e43739051 Mon Sep 17 00:00:00 2001 From: cyberta Date: Fri, 20 Jan 2023 11:59:57 +0100 Subject: fixing tests --- app/src/test/resources/v4/riseup.net.cert | 96 +++++++++++++++---------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/app/src/test/resources/v4/riseup.net.cert b/app/src/test/resources/v4/riseup.net.cert index 1beff4bd..2708a8c8 100644 --- a/app/src/test/resources/v4/riseup.net.cert +++ b/app/src/test/resources/v4/riseup.net.cert @@ -1,54 +1,54 @@ -----BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEAqSkd5UbKh+HbWSH603MJNgSkomeBnPooE0dlxYXIOQa/HnTl -5+7CV47JDWjFWSj1h+zeAmXcgkQxDRF1rbZ+oov26SYyGingBQgn9qvoCZwIdesE -N5Xhdvt23FK8edanCMN/tn1CnyaO5xvHdWRvhpmEf9zAsVwo9qfx1vmRsJfzvcnH -rHoCgH3nxzK1VZm5xNGRdAm9jA2odYYIuSKN1hSYgjcnXVvNHm3bWs+B4RzgtrZG -vy+vsSSd6AaYGQ4sCj3DOuKNOWqXZ8yFpfjbi0rYsOmzxEFiZiequxhrafSM+2uy -NbdPsPXKd0veZh1ApDEHW/6I+qP0bnHE6Dtr+wIDAQABAoIBABnwxjbcrj48Mmju -vwoh/+2atKx69vNdoTujnUW3CEdGc5R2FLOGd6L5sHcv8+OCVnSrrDft6uzHDEaW -wNcMv0qp8Ak85D4C4emjoI1BO2oN1XZPvevQPi0Czu1meqSseBzt7e3MM6U4Qn3K -UsH7zuZzMFBzR9Fq8pUwl/OBfgf4ZWF0IeHFx1/T+3A/lCTdki2wZ8M7pN7djED1 -fqmbwXt3KSnhhOAjZm17qhVM6K+kA3EInsijShbeUTtQMyZCifIrtj5EHYf/sr3f -mlXdspIaR5Wh5tKQo9TRrBNgmMxg+GhBz7fwaM2P1uZXVWTAK4L35vz17o0AQR0P -aItWxyECgYEA3fEGWgH53tATZklxiXaEInCve+XNpE2m80g1hNkIS36D676e0Mxm -L1PlgO+YDRgLBAQVbSdUbfQrcc8Zlcn7R2a0X1a12OH/4pKFXNM4doS/3k5wN1TI -Zr7+AqP4vaLVNt8fjYBhRYpOdwpr5PTjJCpP9dh3ItuIOyH/w+2k4iMCgYEAwx6Y -Cjkn7IaBJOr0kK5JORlGx10jfUmMLMiaJATs49vAcgxt7rKTiEUNvS1YArR4Vh/n -hAYmsC76folGTeZjotmzQbUkm/yZ3OMTSrcja85uM7NJbt9CnUPiDkKDEY4Exhuh -K/Ls+Lp6/eIyJ+b4/xpFEzlUQyY4WiZ6UWcEUEkCgYEAxsqVYtd0RQPg7HSKMpMq -RWLje7lZWXqIOE6MSWLQUDaQ2P6TZ/g86tVdswBoFApeC4nQ20UoFZhntXfHtegF -n225z89t8EZ1mS6eL4etglLjPK7LSnQxT/5wrFLMgKcyDQULUQYVmmEIaQ23mItU -TFdt6YmrJFi4jCam3YqlbjsCgYACzTSnqOxu0/uUuR7r2OTKQhenEypIST8PAY5d -CAkSuHwJ5y3I6J1/rmYlGjqSR18W9XxQg/oYO4RzPqtYwP8bPn75aY1uA/F9n3EO -eJS0npEsgt2CDwiY03mydLgHD3/4DDuDMwi+BYdwj8filMlseEcXoJIaKLlUagsF -kjIYqQKBgEDDiM51YU2V1k4rzdzICdfo5mqa7FiQ2JiRs3yG20gNg3nDReQZk0Q4 -poJkZksuojQabDOnHzWc2jfUehll6gC1ijtRzaoSeRH2m8X5JXb3vfAe5/TFZHBg -bErDqPo+En9Y72LIcGG5vlzQHfE0l24C0oQ64cssLHA9+VnYmwhw +MIIEpAIBAAKCAQEA29qrZxVQz0crl9USbBpzZCMfbDno8tZVjI/imqLgdfgmaW2D +5YEmDMPrr3GEqVBKAYT9LHRgmTSi63PW3N8gb9CKMdoQtSL35XcLbXgtdsJEzSSy +CbtXmB4Yrp2NhzMS9qhFAjbLjjnZkaECLmZDka5dy6j6JWjRNlpE4umqGSCzBtaA +IXuUjMF3hyZ9kY2ojdRDSo3I/gebo2vwaUj/lwYbs1lkDf0LVCcwmpLkppxnf+Cg +T8MA9HRvOk8TZJpShAPWWOBNWVjh79OF41MCbIAr9ynrNR8grOTJV57q1V04/Gi+ +Ue0BkvxsGtNGxTrS4lC672a3Z8nW/NCuMnVTHwIDAQABAoIBAQC8jGuFK32zVlkn +jL+Q4JpnncucGIoUgQa7VsbDUb5ozdm7fwWn9Tu5pOji/NsGDep6JSCvWFtj6QV0 +IlN59w2td06ddGPxxLyPGao+RtvOxssUmEzsFbQIrH8EefBfq8iuqx8LyAyIvEpA +H7JsMp3uOXkNaaymGp+aGo6LgFO12YMNq4OzGeyvetqwkFNkowYOLzAXa99MruZA +xl2lJ4Pm3P7sQspUOxaWrSUYImcg0yM9vpDPxn46f1N3voNGXc2v0okizCOIyrk9 +GF8BHZra8v5oinReCD0by7Xg4X2OfMuOV46lN/TlZ5kmNmsPxORMpuu4NkhAyGRj +dPEU/rHxAoGBAPcTKQk3HZoOf+z/ax7OpLvt+qkWuQrKzjKa+AfiE6cqiLG3oN9I +5qhZYI9vFszEw0Ak5Oouc2EWv1/m0Um/w8CQdbeH0AvxQZDKKLdothDwxokVB0fQ +Ish34lZyHrccsF96GzZMmepjYqiaebsv0ptkn1a0Umc87ao90UdDUL6nAoGBAOPL +yNLADh3LlY2FUVztDG4We2d6Wjr+SI9H4SShXZhz6067I+TwWeXl4mtPAUhAr6ex +/TLE+cRvq8SxDPiKSu4h2UKm5h0HMSpCbFQaqOnPgYihwSTm8/C9uKr2e9mqNSsw +VJYyO1Gbrsbb7NOZFmm9uivg9X5aMwF/1wWQGY7JAoGABoDVmq19tPleuqE6c5Qi +1+N6roqvki4mYUSc9LAprkO7V1oq/NWRZKr9lKjq47bmIMEX2WYhmVOc8+xCY/uN +Lnte7dbATiAqhqIbkkBKUoXT4/XOvEApOjeVmIrmbhFuPwUaxEId5wJ4rVFrlNa8 +Z2StoP2cEaWT5+A6qvKFpI8CgYEAx/N6pbM7MOAguAaL8puIy6EkVSJKzXmiy1H2 +yCZ0d3tY0tTlnvFyl5//7N1+bKOLDBHqBIRuEQVMquwWTJtnRjuj7yN83YIQn92K +JRD5r7IbK4mAdhnbijeeP0L4V4lV/kEAHo6dDvcupRMqgFniGJMXNajTFEOsfeZv +IUzpgjECgYAj4L4boXvCmZIkI46MU9JxQk0eHusR2uGwpdrMiokIsz7uN+MogK1U +1ijIZp/tDH9W1K4t2sTrmRXBee8bZ6iIvj5qPFJqmj+uil20UbyCPQvpAxHn+VNt +gUOLvqlGa2uQ9aymKjnG9bmg7Uk8qXIFsQf2DUYLwrmJjsF6cI2xig== -----END RSA PRIVATE KEY----- -----BEGIN CERTIFICATE----- -MIIEmzCCAoOgAwIBAgIQejc1yqfKGehUKDMdybDH+DANBgkqhkiG9w0BAQsFADB1 +MIIEmzCCAoOgAwIBAgIQcAUo8ZeIKRBNyIAyEg7QFDANBgkqhkiG9w0BAQsFADB1 MRgwFgYDVQQKDA9SaXNldXAgTmV0d29ya3MxGzAZBgNVBAsMEmh0dHBzOi8vcmlz ZXVwLm5ldDE8MDoGA1UEAwwzUmlzZXVwIE5ldHdvcmtzIFJvb3QgQ0EgKGNsaWVu -dCBjZXJ0aWZpY2F0ZXMgb25seSEpMB4XDTIyMTAxNDAwMDAwMFoXDTIzMDExNDAw -MDAwMFowLTErMCkGA1UEAwwiVU5MSU1JVEVEMTMxaXF4cHB0cHljYnN3eGRueXRu -aHhiMDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkpHeVGyofh21kh -+tNzCTYEpKJngZz6KBNHZcWFyDkGvx505efuwleOyQ1oxVko9Yfs3gJl3IJEMQ0R -da22fqKL9ukmMhop4AUIJ/ar6AmcCHXrBDeV4Xb7dtxSvHnWpwjDf7Z9Qp8mjucb -x3Vkb4aZhH/cwLFcKPan8db5kbCX873Jx6x6AoB958cytVWZucTRkXQJvYwNqHWG -CLkijdYUmII3J11bzR5t21rPgeEc4La2Rr8vr7EknegGmBkOLAo9wzrijTlql2fM -haX424tK2LDps8RBYmYnqrsYa2n0jPtrsjW3T7D1yndL3mYdQKQxB1v+iPqj9G5x -xOg7a/sCAwEAAaNvMG0wHQYDVR0OBBYEFEFB2IaA9Z5TOAPtMw3vgKvRR+tpMAsG +dCBjZXJ0aWZpY2F0ZXMgb25seSEpMB4XDTIyMTIyMDAwMDAwMFoXDTIzMDMyMDAw +MDAwMFowLTErMCkGA1UEAwwiVU5MSU1JVEVEYnpnMWZicmd3MWdsa29qMWlhZG4w +d2ZiaTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANvaq2cVUM9HK5fV +Emwac2QjH2w56PLWVYyP4pqi4HX4Jmltg+WBJgzD669xhKlQSgGE/Sx0YJk0outz +1tzfIG/QijHaELUi9+V3C214LXbCRM0ksgm7V5geGK6djYczEvaoRQI2y4452ZGh +Ai5mQ5GuXcuo+iVo0TZaROLpqhkgswbWgCF7lIzBd4cmfZGNqI3UQ0qNyP4Hm6Nr +8GlI/5cGG7NZZA39C1QnMJqS5KacZ3/goE/DAPR0bzpPE2SaUoQD1ljgTVlY4e/T +heNTAmyAK/cp6zUfIKzkyVee6tVdOPxovlHtAZL8bBrTRsU60uJQuu9mt2fJ1vzQ +rjJ1Ux8CAwEAAaNvMG0wHQYDVR0OBBYEFF1cHd5fjHXKbGrW0qd4zNg6KquiMAsG A1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAjAJBgNVHRMEAjAAMB8GA1Ud -IwQYMBaAFBf0G9XlKgEBTWuiXTYKKQmWZYBGMA0GCSqGSIb3DQEBCwUAA4ICAQB0 -x+RhbfmWuKQ7clT2oBhLOep1USJ9y98BLMsEmqZ84q0CnG+tI2QLhZvaMiGiMplI -saHhK1lIHbO/UATHOhE+ZbY9vAaGK1JaBdlOTshjo+cijZ2nWwfwa9Qj/Cx64sSO -cee3Lbg5IcsFc/0KGCTw0k9PheD/CudRSnLCxImA8DmJO+1w1NUoBBm48tdD6usD -fLU35FvChvNwW/7GO/q3TGXF/jrreBnrJZMjsffwFOJC8SWZIAScmF/OrqWyruYb -ZS9/0ZXR21TT1mvUFjIs+0uY2crfli/f91ZbB9eRoiyHkck8RtotiH9PrmYt7j02 -5cwos2BqRs+kZ7AgYvZjWErwIyCsXSzrk0WztLa2vslqZSZSt12VlW5iIyKTyx8T -snQLEdHwzRT5C+9daq3PneOvD5KhgyySlwWSoMuJdg2n3cTs/0uMDQE7FIim11XM -Fz8liZf4PcWv8YLFUBHQ367SvbAiyZLzpXZETQyDaYNYGTwYBCGs9Yhq3KM85Kmz -f0rgrBpm61ujLQ/OBSCq6/RA9BN8UYdO+YS0vengYtIdc+aw1PzLhcC9dLLXC4ef -zH25zfe7vkt58UcuG+YCsaIR8Hy3I/yDQWVkbNawEYUboEHHRd8pQmUIkHLaYibt -eq1SXtuulUUDIkyfRATiA/GkPVPPnJImL8XK12WFPQ== ------END CERTIFICATE----- +IwQYMBaAFBf0G9XlKgEBTWuiXTYKKQmWZYBGMA0GCSqGSIb3DQEBCwUAA4ICAQCS +sDwNJmNqgrOeNgEuszIGE5V2wTj89S2TtHggBfWErKGUn7N0+gcIRvxxCHG9X7ne +WjhTS/kEMblR3OcaB/8kfBGCZD6Hc+d0nXv7G5Iqpy5eJuWnv8L4n7QUxIkYiyRr +bp3Mg31MCFKlDVi2RoTbm3rvcWYPsfBARu6tZlvfNb2Q6dP9/zPU1N2b69fyNwXV +IOjF/5KPt4n/abxyFuty6xv1G9B3Bq072wZrUSQbZsOLNUtSyLJVyhHRLBBzOOJ/ +Cw8awAEeXXwF1+qAO4MAq/ILcA/v8hAR6AlZez6nbZOBfk5JvEPumZPdIQN6PQ6J +jODFuJRFFemea3uYyUEnv5MD3BcsApIrM7eRc82Edc9a73CkuMP4ekG68OFl2qHl +h+XzEchQNVG3t+Ka+8FN1RyeXhPRjzf1JG0elP+CIuyHBOd1SJLv4elGK2ZJWk2L +cPfLt+tFATKy3PEuftXasLG9g/K8PVaNh8gmh4en88vM0XxZ7npygPv84Cl5wV4r +LUuR6Cy8quE8QHx01D2EAspkHqk4d/xClyxfT1KCKEQvOk5gOlSrEFsB8TTqtYfr +G1LiVDcwEq+ExmeDwGIW0EY2mOre7yTHva0p0JZ4AcyK4lNIPXpGBOQcyZ++7/jh +vdNyERG7ZAjCsj7YTy72On5cS6DQDEHnKmrAIejLLw== +-----END CERTIFICATE----- \ No newline at end of file -- cgit v1.2.3 From 7d0a1f8d8057faa74035de0cee262a46c6fbbe00 Mon Sep 17 00:00:00 2001 From: cyberta Date: Mon, 23 Jan 2023 19:47:56 +0100 Subject: setup fastlane to create screenshots for Bitmask and custom branded clients, refactor Tests accordingly and create a script and environment variables to run fastlane screenshotting without thinking --- .../leap/bitmaskclient/base/ProviderBaseTest.java | 157 ++++++++++++++++++ .../leap/bitmaskclient/base/ProviderSetupTest.java | 68 -------- .../se/leap/bitmaskclient/base/VpnStartTest.java | 176 --------------------- .../leap/bitmaskclient/suite/ScreenshotTest.java | 19 --- .../androidTest/java/utils/CustomInteractions.java | 1 + .../bitmaskclient/base/CustomProviderTest.java | 49 ++++++ .../leap/bitmaskclient/suite/ScreenshotTest.java | 17 ++ .../se/leap/bitmaskclient/base/BitmaskTest.java | 42 +++++ .../leap/bitmaskclient/base/ProviderSetupTest.java | 68 ++++++++ .../leap/bitmaskclient/suite/ScreenshotTest.java | 19 +++ fastlane/.env.custom | 3 + fastlane/.env.default | 3 + fastlane/Fastfile | 46 +++++- fastlane/README.md | 28 +++- fastlane/Screengrabfile | 4 - scripts/fastlane.sh | 34 ++++ 16 files changed, 464 insertions(+), 270 deletions(-) create mode 100644 app/src/androidTest/java/se/leap/bitmaskclient/base/ProviderBaseTest.java delete mode 100644 app/src/androidTest/java/se/leap/bitmaskclient/base/ProviderSetupTest.java delete mode 100644 app/src/androidTest/java/se/leap/bitmaskclient/base/VpnStartTest.java delete mode 100644 app/src/androidTest/java/se/leap/bitmaskclient/suite/ScreenshotTest.java create mode 100644 app/src/androidTestCustom/java/se/leap/bitmaskclient/base/CustomProviderTest.java create mode 100644 app/src/androidTestCustom/java/se/leap/bitmaskclient/suite/ScreenshotTest.java create mode 100644 app/src/androidTestNormal/java/se/leap/bitmaskclient/base/BitmaskTest.java create mode 100644 app/src/androidTestNormal/java/se/leap/bitmaskclient/base/ProviderSetupTest.java create mode 100644 app/src/androidTestNormal/java/se/leap/bitmaskclient/suite/ScreenshotTest.java create mode 100644 fastlane/.env.custom create mode 100644 fastlane/.env.default create mode 100755 scripts/fastlane.sh diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/base/ProviderBaseTest.java b/app/src/androidTest/java/se/leap/bitmaskclient/base/ProviderBaseTest.java new file mode 100644 index 00000000..bbfcdc8b --- /dev/null +++ b/app/src/androidTest/java/se/leap/bitmaskclient/base/ProviderBaseTest.java @@ -0,0 +1,157 @@ +package se.leap.bitmaskclient.base; + +import static android.content.Context.MODE_PRIVATE; +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; +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.DrawerMatchers.isClosed; +import static androidx.test.espresso.matcher.RootMatchers.isDialog; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withTagValue; +import static androidx.test.espresso.matcher.ViewMatchers.withText; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.anything; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.hasToString; +import static org.hamcrest.Matchers.is; +import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; +import static utils.CustomInteractions.tryResolve; + +import android.content.SharedPreferences; +import android.view.Gravity; + +import androidx.test.espresso.DataInteraction; +import androidx.test.espresso.NoMatchingViewException; +import androidx.test.espresso.ViewInteraction; +import androidx.test.espresso.contrib.DrawerActions; +import androidx.test.ext.junit.rules.ActivityScenarioRule; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.LargeTest; + +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.FixMethodOrder; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; + +import se.leap.bitmaskclient.R; +import tools.fastlane.screengrab.Screengrab; +import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy; +import tools.fastlane.screengrab.locale.LocaleTestRule; + +@LargeTest +@RunWith(AndroidJUnit4.class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public abstract class ProviderBaseTest { + + @ClassRule + public static final LocaleTestRule localeTestRule = new LocaleTestRule(); + + @Rule + public ActivityScenarioRule mActivityScenarioRule = + new ActivityScenarioRule<>(StartActivity.class); + + @Before + public void setup() { + Screengrab.setDefaultScreenshotStrategy(new UiAutomatorScreenshotStrategy()); + SharedPreferences preferences = getApplicationContext().getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); + preferences.edit().clear().commit(); + } + + @Test + public void test01_vpnStartTest() throws InterruptedException { + boolean configurationNeeded = configureProviderIfNeeded(); + + ViewInteraction mainButtonStop; + if (!configurationNeeded) { + // click on Main on/off button and start VPN + ViewInteraction mainButton = tryResolve( + onView(withId(R.id.main_button)), + matches(isDisplayed()) + ); + + mainButton.perform(click()); + Thread.sleep(50); + Screengrab.screenshot("VPN_connecting"); + + mainButtonStop = tryResolve( + onView(allOf( + withId(R.id.button), + withTagValue(is("button_circle_stop")))), + matches(isDisplayed()), + 20); + Screengrab.screenshot("VPN_connected"); + } else { + // on new configurations the VPN is automatically started + Screengrab.screenshot("VPN_connecting"); + mainButtonStop = tryResolve( + onView(allOf( + withId(R.id.button), + withTagValue(is("button_circle_stop")))), + matches(isDisplayed()), + 20); + Screengrab.screenshot("VPN_connected"); + } + + mainButtonStop.perform(click()); + Screengrab.screenshot("VPN_ask_disconnect"); + + onView(withText(android.R.string.yes)) + .inRoot(isDialog()) + .check(matches(isDisplayed())) + .perform(click()); + Screengrab.screenshot("VPN_disconnected"); + } + + @Test + public void test02_SettingsFragmentScreenshots() { + onView(withId(R.id.drawer_layout)) + .check(matches(isClosed(Gravity.LEFT))) // Left Drawer should be closed. + .perform(DrawerActions.open()); // Open Drawer + + Screengrab.screenshot("navigationDrawer"); + + // Start the screen of your activity. + onView(withId(R.id.advancedSettings)) + .perform(click()); + + Screengrab.screenshot("settingsFragment"); + } + + @Test + public void test03_LocationSelectionFragmentScreenshots() { + onView(withId(R.id.drawer_layout)) + .check(matches(isClosed(Gravity.LEFT))) // Left Drawer should be closed. + .perform(DrawerActions.open()); // Open Drawer + + onView(withId(R.id.manualGatewaySelection)) + .perform(click()); + + Screengrab.screenshot("GatewaySelectionFragment"); + } + + @Test + public void test04_AppExclusionFragmentScreenshots() { + onView(withId(R.id.drawer_layout)) + .check(matches(isClosed(Gravity.LEFT))) // Left Drawer should be closed. + .perform(DrawerActions.open()); // Open Drawer + + onView(withId(R.id.advancedSettings)).perform(click()); + + onView(withId(R.id.exclude_apps)).perform(click()); + + tryResolve( + onData(anything()).inAdapterView(withId(android.R.id.list)).atPosition(2), + matches(isDisplayed()), + 5); + + Screengrab.screenshot("App_Exclusion_Fragment"); + } + + public abstract boolean configureProviderIfNeeded(); +} diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/base/ProviderSetupTest.java b/app/src/androidTest/java/se/leap/bitmaskclient/base/ProviderSetupTest.java deleted file mode 100644 index 23db8582..00000000 --- a/app/src/androidTest/java/se/leap/bitmaskclient/base/ProviderSetupTest.java +++ /dev/null @@ -1,68 +0,0 @@ -package se.leap.bitmaskclient.base; - - -import static android.content.Context.MODE_PRIVATE; -import static androidx.test.core.app.ApplicationProvider.getApplicationContext; -import static androidx.test.espresso.Espresso.onData; -import static androidx.test.espresso.action.ViewActions.click; -import static androidx.test.espresso.matcher.ViewMatchers.withId; -import static org.hamcrest.Matchers.anything; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.hasToString; -import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; -import static utils.CustomInteractions.tryResolve; - -import android.content.SharedPreferences; - -import androidx.test.espresso.DataInteraction; -import androidx.test.espresso.NoMatchingViewException; -import androidx.test.ext.junit.rules.ActivityScenarioRule; -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.filters.LargeTest; - -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import se.leap.bitmaskclient.R; -import se.leap.bitmaskclient.providersetup.ProviderListActivity; -import tools.fastlane.screengrab.Screengrab; -import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy; -import tools.fastlane.screengrab.locale.LocaleTestRule; - -@LargeTest -@RunWith(AndroidJUnit4.class) -public class ProviderSetupTest { - - @ClassRule - public static final LocaleTestRule localeTestRule = new LocaleTestRule(); - - @Rule - public ActivityScenarioRule mActivityScenarioRule = - new ActivityScenarioRule<>(ProviderListActivity.class); - - @Before - public void setup() { - Screengrab.setDefaultScreenshotStrategy(new UiAutomatorScreenshotStrategy()); - SharedPreferences preferences = getApplicationContext().getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); - preferences.edit().clear().commit(); - } - - @Test - public void testConfigureRiseupVPNScreenshot() { - DataInteraction linearLayout = tryResolve(onData(hasToString(containsString("riseup.net"))) - .inAdapterView(withId(R.id.provider_list)), - 2); - Screengrab.screenshot("ProviderListActivity"); - linearLayout.perform(click()); - Screengrab.screenshot("ProviderListActivity_configureRiseup"); - } - - @Test - public void testaddManuallyNewProviderScreenshot() { - onData(anything()).inAdapterView(withId(R.id.provider_list)).atPosition(3).perform(click()); - Screengrab.screenshot("ProviderListActivity_addManuallyNewProvider"); - } -} diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/base/VpnStartTest.java b/app/src/androidTest/java/se/leap/bitmaskclient/base/VpnStartTest.java deleted file mode 100644 index 6c99b90e..00000000 --- a/app/src/androidTest/java/se/leap/bitmaskclient/base/VpnStartTest.java +++ /dev/null @@ -1,176 +0,0 @@ -package se.leap.bitmaskclient.base; - - -import static android.content.Context.MODE_PRIVATE; -import static androidx.test.core.app.ApplicationProvider.getApplicationContext; -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.DrawerMatchers.isClosed; -import static androidx.test.espresso.matcher.RootMatchers.isDialog; -import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; -import static androidx.test.espresso.matcher.ViewMatchers.withId; -import static androidx.test.espresso.matcher.ViewMatchers.withTagValue; -import static androidx.test.espresso.matcher.ViewMatchers.withText; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.anything; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.hasToString; -import static org.hamcrest.Matchers.is; -import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; -import static utils.CustomInteractions.tryResolve; - -import android.content.SharedPreferences; -import android.view.Gravity; - -import androidx.test.espresso.DataInteraction; -import androidx.test.espresso.NoMatchingViewException; -import androidx.test.espresso.ViewInteraction; -import androidx.test.espresso.contrib.DrawerActions; -import androidx.test.ext.junit.rules.ActivityScenarioRule; -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.filters.LargeTest; - -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.FixMethodOrder; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.MethodSorters; - -import se.leap.bitmaskclient.R; -import tools.fastlane.screengrab.Screengrab; -import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy; -import tools.fastlane.screengrab.locale.LocaleTestRule; - -@LargeTest -@RunWith(AndroidJUnit4.class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class VpnStartTest { - - @ClassRule - public static final LocaleTestRule localeTestRule = new LocaleTestRule(); - - @Rule - public ActivityScenarioRule mActivityScenarioRule = - new ActivityScenarioRule<>(StartActivity.class); - - @Before - public void setup() { - Screengrab.setDefaultScreenshotStrategy(new UiAutomatorScreenshotStrategy()); - SharedPreferences preferences = getApplicationContext().getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); - preferences.edit().clear().commit(); - } - - @Test - public void test01_vpnStartTest() { - boolean configurationNeeded = configureProviderIfNeeded(); - - ViewInteraction mainButtonStop; - if (!configurationNeeded) { - // click on Main on/off button and start VPN - ViewInteraction mainButton = tryResolve( - onView(withId(R.id.main_button)), - matches(isDisplayed()) - ); - - mainButton.perform(click()); - tryResolve( - onView(allOf( - withId(R.id.button), - withTagValue(is("button_circle_cancel")))), - matches(isDisplayed()), - 2); - Screengrab.screenshot("VPN_connecting"); - - mainButtonStop = tryResolve( - onView(allOf( - withId(R.id.button), - withTagValue(is("button_circle_stop")))), - matches(isDisplayed()), - 20); - Screengrab.screenshot("VPN_connected"); - } else { - // on new configurations the VPN is automatically started - Screengrab.screenshot("VPN_connecting"); - mainButtonStop = tryResolve( - onView(allOf( - withId(R.id.button), - withTagValue(is("button_circle_stop")))), - matches(isDisplayed()), - 20); - Screengrab.screenshot("VPN_connected"); - } - - mainButtonStop.perform(click()); - Screengrab.screenshot("VPN_ask_disconnect"); - - onView(withText(android.R.string.yes)) - .inRoot(isDialog()) - .check(matches(isDisplayed())) - .perform(click()); - Screengrab.screenshot("VPN_disconnected"); - } - - @Test - public void test02_SettingsFragmentScreenshots() { - onView(withId(R.id.drawer_layout)) - .check(matches(isClosed(Gravity.LEFT))) // Left Drawer should be closed. - .perform(DrawerActions.open()); // Open Drawer - - Screengrab.screenshot("navigationDrawer"); - - // Start the screen of your activity. - onView(withId(R.id.advancedSettings)) - .perform(click()); - - Screengrab.screenshot("settingsFragment"); - } - - @Test - public void test03_LocationSelectionFragmentScreenshots() { - onView(withId(R.id.drawer_layout)) - .check(matches(isClosed(Gravity.LEFT))) // Left Drawer should be closed. - .perform(DrawerActions.open()); // Open Drawer - - onView(withId(R.id.manualGatewaySelection)) - .perform(click()); - - Screengrab.screenshot("GatewaySelectionFragment"); - } - - @Test - public void test04_AppExclusionFragmentScreenshots() { - onView(withId(R.id.drawer_layout)) - .check(matches(isClosed(Gravity.LEFT))) // Left Drawer should be closed. - .perform(DrawerActions.open()); // Open Drawer - - onView(withId(R.id.advancedSettings)).perform(click()); - - onView(withId(R.id.exclude_apps)).perform(click()); - - tryResolve( - onData(anything()).inAdapterView(withId(android.R.id.list)).atPosition(2), - matches(isDisplayed()), - 5); - - Screengrab.screenshot("App_Exclusion_Fragment"); - } - - public boolean configureProviderIfNeeded() { - try { - DataInteraction linearLayout = tryResolve(onData(hasToString(containsString("riseup.net"))) - .inAdapterView(withId(R.id.provider_list)), - 2); - linearLayout.perform(click()); - return true; - } catch (NoMatchingViewException e) { - // it might be that the provider was already configured, so we print the stack - // trace here and try to continue - e.printStackTrace(); - } - return false; - } -} diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/suite/ScreenshotTest.java b/app/src/androidTest/java/se/leap/bitmaskclient/suite/ScreenshotTest.java deleted file mode 100644 index 186a50d1..00000000 --- a/app/src/androidTest/java/se/leap/bitmaskclient/suite/ScreenshotTest.java +++ /dev/null @@ -1,19 +0,0 @@ -package se.leap.bitmaskclient.suite; - - -import androidx.test.filters.LargeTest; - -import org.junit.runner.RunWith; -import org.junit.runners.Suite; - -import se.leap.bitmaskclient.base.ProviderSetupTest; -import se.leap.bitmaskclient.base.VpnStartTest; - -@LargeTest -@RunWith(Suite.class) -@Suite.SuiteClasses({ - ProviderSetupTest.class, - VpnStartTest.class, -}) -public class ScreenshotTest { -} diff --git a/app/src/androidTest/java/utils/CustomInteractions.java b/app/src/androidTest/java/utils/CustomInteractions.java index 896e8d9b..9e3a8f9d 100644 --- a/app/src/androidTest/java/utils/CustomInteractions.java +++ b/app/src/androidTest/java/utils/CustomInteractions.java @@ -31,6 +31,7 @@ public class CustomInteractions { hasFound = true; } catch (NoMatchingViewException exception) { System.out.println("NoMatchingViewException attempt: " + attempt); + exception.printStackTrace(); attempt++; if (attempt == maxTries) { throw exception; diff --git a/app/src/androidTestCustom/java/se/leap/bitmaskclient/base/CustomProviderTest.java b/app/src/androidTestCustom/java/se/leap/bitmaskclient/base/CustomProviderTest.java new file mode 100644 index 00000000..1a0814b6 --- /dev/null +++ b/app/src/androidTestCustom/java/se/leap/bitmaskclient/base/CustomProviderTest.java @@ -0,0 +1,49 @@ +package se.leap.bitmaskclient.base; + +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.RootMatchers.isDialog; +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 utils.CustomInteractions.tryResolve; + +import androidx.test.espresso.ViewInteraction; + +import org.junit.Test; + +import se.leap.bitmaskclient.R; +import tools.fastlane.screengrab.Screengrab; + +public class CustomProviderTest extends ProviderBaseTest { + + @Test + @Override + public void test01_vpnStartTest() throws InterruptedException { + ViewInteraction mainButtonStop; + mainButtonStop = tryResolve( + onView(withId(R.id.main_button)), + matches(isDisplayed()), + 30); + Screengrab.screenshot("VPN_connected"); + + mainButtonStop.perform(click()); + Screengrab.screenshot("VPN_ask_disconnect"); + + ViewInteraction alertDialogOKbutton = tryResolve(onView(withText(android.R.string.yes)) + .inRoot(isDialog()), + matches(isDisplayed())); + alertDialogOKbutton.perform(click()); + Screengrab.screenshot("VPN_disconnected"); + + mainButtonStop.perform(click()); + Thread.sleep(50); + Screengrab.screenshot("VPN_connecting"); + } + + @Override + public boolean configureProviderIfNeeded() { + return false; + } +} \ No newline at end of file diff --git a/app/src/androidTestCustom/java/se/leap/bitmaskclient/suite/ScreenshotTest.java b/app/src/androidTestCustom/java/se/leap/bitmaskclient/suite/ScreenshotTest.java new file mode 100644 index 00000000..a19b0ffd --- /dev/null +++ b/app/src/androidTestCustom/java/se/leap/bitmaskclient/suite/ScreenshotTest.java @@ -0,0 +1,17 @@ +package se.leap.bitmaskclient.suite; + + +import androidx.test.filters.LargeTest; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +import se.leap.bitmaskclient.base.CustomProviderTest; + +@LargeTest +@RunWith(Suite.class) +@Suite.SuiteClasses({ + CustomProviderTest.class +}) +public class ScreenshotTest { +} diff --git a/app/src/androidTestNormal/java/se/leap/bitmaskclient/base/BitmaskTest.java b/app/src/androidTestNormal/java/se/leap/bitmaskclient/base/BitmaskTest.java new file mode 100644 index 00000000..aa437c74 --- /dev/null +++ b/app/src/androidTestNormal/java/se/leap/bitmaskclient/base/BitmaskTest.java @@ -0,0 +1,42 @@ +package se.leap.bitmaskclient.base; + + +import static androidx.test.espresso.Espresso.onData; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.hasToString; +import static utils.CustomInteractions.tryResolve; + +import androidx.test.espresso.DataInteraction; +import androidx.test.espresso.NoMatchingViewException; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.LargeTest; + +import org.junit.FixMethodOrder; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; + +import se.leap.bitmaskclient.R; + +@LargeTest +@RunWith(AndroidJUnit4.class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class BitmaskTest extends ProviderBaseTest { + + @Override + public boolean configureProviderIfNeeded() { + try { + DataInteraction linearLayout = tryResolve(onData(hasToString(containsString("riseup.net"))) + .inAdapterView(withId(R.id.provider_list)), + 2); + linearLayout.perform(click()); + return true; + } catch (NoMatchingViewException e) { + // it might be that the provider was already configured, so we print the stack + // trace here and try to continue + e.printStackTrace(); + } + return false; + } +} diff --git a/app/src/androidTestNormal/java/se/leap/bitmaskclient/base/ProviderSetupTest.java b/app/src/androidTestNormal/java/se/leap/bitmaskclient/base/ProviderSetupTest.java new file mode 100644 index 00000000..23db8582 --- /dev/null +++ b/app/src/androidTestNormal/java/se/leap/bitmaskclient/base/ProviderSetupTest.java @@ -0,0 +1,68 @@ +package se.leap.bitmaskclient.base; + + +import static android.content.Context.MODE_PRIVATE; +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; +import static androidx.test.espresso.Espresso.onData; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static org.hamcrest.Matchers.anything; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.hasToString; +import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; +import static utils.CustomInteractions.tryResolve; + +import android.content.SharedPreferences; + +import androidx.test.espresso.DataInteraction; +import androidx.test.espresso.NoMatchingViewException; +import androidx.test.ext.junit.rules.ActivityScenarioRule; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.LargeTest; + +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.providersetup.ProviderListActivity; +import tools.fastlane.screengrab.Screengrab; +import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy; +import tools.fastlane.screengrab.locale.LocaleTestRule; + +@LargeTest +@RunWith(AndroidJUnit4.class) +public class ProviderSetupTest { + + @ClassRule + public static final LocaleTestRule localeTestRule = new LocaleTestRule(); + + @Rule + public ActivityScenarioRule mActivityScenarioRule = + new ActivityScenarioRule<>(ProviderListActivity.class); + + @Before + public void setup() { + Screengrab.setDefaultScreenshotStrategy(new UiAutomatorScreenshotStrategy()); + SharedPreferences preferences = getApplicationContext().getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); + preferences.edit().clear().commit(); + } + + @Test + public void testConfigureRiseupVPNScreenshot() { + DataInteraction linearLayout = tryResolve(onData(hasToString(containsString("riseup.net"))) + .inAdapterView(withId(R.id.provider_list)), + 2); + Screengrab.screenshot("ProviderListActivity"); + linearLayout.perform(click()); + Screengrab.screenshot("ProviderListActivity_configureRiseup"); + } + + @Test + public void testaddManuallyNewProviderScreenshot() { + onData(anything()).inAdapterView(withId(R.id.provider_list)).atPosition(3).perform(click()); + Screengrab.screenshot("ProviderListActivity_addManuallyNewProvider"); + } +} diff --git a/app/src/androidTestNormal/java/se/leap/bitmaskclient/suite/ScreenshotTest.java b/app/src/androidTestNormal/java/se/leap/bitmaskclient/suite/ScreenshotTest.java new file mode 100644 index 00000000..5fa45a95 --- /dev/null +++ b/app/src/androidTestNormal/java/se/leap/bitmaskclient/suite/ScreenshotTest.java @@ -0,0 +1,19 @@ +package se.leap.bitmaskclient.suite; + + +import androidx.test.filters.LargeTest; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +import se.leap.bitmaskclient.base.ProviderSetupTest; +import se.leap.bitmaskclient.base.BitmaskTest; + +@LargeTest +@RunWith(Suite.class) +@Suite.SuiteClasses({ + ProviderSetupTest.class, + BitmaskTest.class, +}) +public class ScreenshotTest { +} diff --git a/fastlane/.env.custom b/fastlane/.env.custom new file mode 100644 index 00000000..9b65f5d4 --- /dev/null +++ b/fastlane/.env.custom @@ -0,0 +1,3 @@ +SCREENGRAB_APP_PACKAGE_NAME="se.leap.riseupvpn" +SCREENGRAB_APP_APK_PATH="app/build/outputs/apk/customProductionFat/debug/RiseupVPN_debug.apk" +SCREENGRAB_TESTS_APK_PATH="app/build/outputs/apk/androidTest/customProductionFat/debug/app-custom-production-fat-debug-androidTest.apk" diff --git a/fastlane/.env.default b/fastlane/.env.default new file mode 100644 index 00000000..bdb771ce --- /dev/null +++ b/fastlane/.env.default @@ -0,0 +1,3 @@ +SCREENGRAB_APP_PACKAGE_NAME="se.leap.bitmaskclient" +SCREENGRAB_APP_APK_PATH="app/build/outputs/apk/normalProductionFat/debug/Bitmask_debug.apk" +SCREENGRAB_TESTS_APK_PATH="app/build/outputs/apk/androidTest/normalProductionFat/debug/app-normal-production-fat-debug-androidTest.apk" diff --git a/fastlane/Fastfile b/fastlane/Fastfile index d985984d..a0e25930 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -21,12 +21,56 @@ platform :android do gradle(task: "test") end - lane :screenshots do + desc "Build debug and test APK for screenshots" + lane :build_bitmask_for_screengrab do + gradle( + task: 'clean' + ) + gradle( + task: 'assemble', + build_type: 'Debug', + flavor: 'NormalProductionFat' + ) + gradle( + task: 'assemble', + build_type: 'DebugAndroidTest', + flavor: 'NormalProductionFat' + ) + end + + desc "Build debug and test APK for screenshots" + lane :build_custom_for_screengrab do + gradle( + task: 'clean' + ) + gradle( + task: 'assemble', + build_type: 'Debug', + flavor: 'CustomProductionFat' + ) + gradle( + task: 'assemble', + build_type: 'DebugAndroidTest', + flavor: 'CustomProductionFat' + ) + end + + lane :bitmask_screenshots do + # Prepare builds for Automatic UI Tests + build_bitmask_for_screengrab capture_android_screenshots frameit(white: true) # deliver end + lane :custom_build_screenshots do + # Prepare builds for Automatic UI Tests + build_custom_for_screengrab + capture_android_screenshots + frameit(white: true) + # deliver + end + desc "Submit a new Beta Build to Crashlytics Beta" lane :beta do gradle(task: "clean assembleRelease") diff --git a/fastlane/README.md b/fastlane/README.md index 96002ac1..a41fc4c9 100644 --- a/fastlane/README.md +++ b/fastlane/README.md @@ -23,10 +23,34 @@ For _fastlane_ installation instructions, see [Installing _fastlane_](https://do Runs all the tests -### android screenshots +### android build_bitmask_for_screengrab ```sh -[bundle exec] fastlane android screenshots +[bundle exec] fastlane android build_bitmask_for_screengrab +``` + +Build debug and test APK for screenshots + +### android build_custom_for_screengrab + +```sh +[bundle exec] fastlane android build_custom_for_screengrab +``` + +Build debug and test APK for screenshots + +### android bitmask_screenshots + +```sh +[bundle exec] fastlane android bitmask_screenshots +``` + + + +### android custom_build_screenshots + +```sh +[bundle exec] fastlane android custom_build_screenshots ``` diff --git a/fastlane/Screengrabfile b/fastlane/Screengrabfile index 8a149163..8534db2a 100644 --- a/fastlane/Screengrabfile +++ b/fastlane/Screengrabfile @@ -1,11 +1,7 @@ # remove the leading '#' to uncomment lines -# app_package_name('your.app.package') use_tests_in_packages(['se.leap.bitmaskclient.suite']) -app_apk_path('app/build/intermediates/apk/normalProductionFat/debug/Bitmask_debug.apk') -tests_apk_path('app/build/intermediates/apk/androidTest/normalProductionFat/debug/app-normal-production-fat-debug-androidTest.apk') - # all locales # locales(['ar', 'az', 'bg', 'bn', 'br', 'ca', 'cs', 'de', 'el', 'es', 'es-AR', 'et', 'eu', 'fa-IR', 'fi', 'fr', 'gl', 'he', 'hr', 'hu', 'id', 'it', 'ja', 'my', 'nl', 'no', 'pl', 'pt-BR', 'pt-PT', 'ro', 'ru', 'tr', 'ug', 'uk', 'vi', 'zh-CN', 'zh-TW']) # prioritized locales diff --git a/scripts/fastlane.sh b/scripts/fastlane.sh new file mode 100755 index 00000000..f039cd24 --- /dev/null +++ b/scripts/fastlane.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +GREEN='\033[0;32m' +RED='\033[0;31m' +NC='\033[0m' + +# init parameters +if [[ ${1} = "custom" ]]; then + BUILD_CUSTOM=true +elif [[ ! -z ${1} ]]; then + echo -e """${RED}Failed due to wrong arguments.${NC} + Usage: + ====== + ${GREEN}create screenshots for Bitmask:${NC} + ./fastlane.sh + + ${GREEN}create screenshots for your custom build${NC} (please adopt the environment variables in './fastlane/.env.custom'): + ./fastlane.sh custom + """ + exit 1 +fi; + +#screengrab related environment variables can be found in ./fastlane/.env.* +SCRIPT_DIR=$(dirname "$0") +BASE_DIR="$SCRIPT_DIR/.." + +cd $BASE_DIR +if [[ -z $BUILD_CUSTOM ]]; then + fastlane android bitmask_screenshots +else + fastlane android custom_build_screenshots --env custom +fi; +cd - + -- cgit v1.2.3 From 2ce81f736c15a431de9c95059f84dea72c9e2556 Mon Sep 17 00:00:00 2001 From: cyberta Date: Tue, 24 Jan 2023 01:01:02 +0100 Subject: specify input directory for frameit (framed images) --- fastlane/.env.custom | 1 + fastlane/.env.default | 1 + fastlane/Fastfile | 15 +++++++++++++-- fastlane/Screengrabfile | 1 + src/README.md | 7 +++++++ src/custom/fastlane/metadata/android/README.md | 0 src/normal/fastlane/metadata/android/README.md | 0 7 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 src/README.md create mode 100644 src/custom/fastlane/metadata/android/README.md create mode 100644 src/normal/fastlane/metadata/android/README.md diff --git a/fastlane/.env.custom b/fastlane/.env.custom index 9b65f5d4..5ec9ffd0 100644 --- a/fastlane/.env.custom +++ b/fastlane/.env.custom @@ -1,3 +1,4 @@ SCREENGRAB_APP_PACKAGE_NAME="se.leap.riseupvpn" SCREENGRAB_APP_APK_PATH="app/build/outputs/apk/customProductionFat/debug/RiseupVPN_debug.apk" SCREENGRAB_TESTS_APK_PATH="app/build/outputs/apk/androidTest/customProductionFat/debug/app-custom-production-fat-debug-androidTest.apk" +SCREENGRAB_OUTPUT_DIRECTORY="src/custom/fastlane/metadata/android" \ No newline at end of file diff --git a/fastlane/.env.default b/fastlane/.env.default index bdb771ce..1362c5f1 100644 --- a/fastlane/.env.default +++ b/fastlane/.env.default @@ -1,3 +1,4 @@ SCREENGRAB_APP_PACKAGE_NAME="se.leap.bitmaskclient" SCREENGRAB_APP_APK_PATH="app/build/outputs/apk/normalProductionFat/debug/Bitmask_debug.apk" SCREENGRAB_TESTS_APK_PATH="app/build/outputs/apk/androidTest/normalProductionFat/debug/app-normal-production-fat-debug-androidTest.apk" +SCREENGRAB_OUTPUT_DIRECTORY="src/normal/fastlane/metadata/android" \ No newline at end of file diff --git a/fastlane/Fastfile b/fastlane/Fastfile index a0e25930..99d540ed 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -59,7 +59,12 @@ platform :android do # Prepare builds for Automatic UI Tests build_bitmask_for_screengrab capture_android_screenshots - frameit(white: true) + Dir.chdir("../src/normal/fastlane/metadata") do + frameit( + white: true, + path: "." + ) + end # deliver end @@ -67,7 +72,13 @@ platform :android do # Prepare builds for Automatic UI Tests build_custom_for_screengrab capture_android_screenshots - frameit(white: true) + Dir.chdir("../src/custom/fastlane/metadata") do + frameit( + white: true, + path: "." + ) + end + # deliver end diff --git a/fastlane/Screengrabfile b/fastlane/Screengrabfile index 8534db2a..317583b0 100644 --- a/fastlane/Screengrabfile +++ b/fastlane/Screengrabfile @@ -1,6 +1,7 @@ # remove the leading '#' to uncomment lines use_tests_in_packages(['se.leap.bitmaskclient.suite']) +use_timestamp_suffix(false) # all locales # locales(['ar', 'az', 'bg', 'bn', 'br', 'ca', 'cs', 'de', 'el', 'es', 'es-AR', 'et', 'eu', 'fa-IR', 'fi', 'fr', 'gl', 'he', 'hr', 'hu', 'id', 'it', 'ja', 'my', 'nl', 'no', 'pl', 'pt-BR', 'pt-PT', 'ro', 'ru', 'tr', 'ug', 'uk', 'vi', 'zh-CN', 'zh-TW']) diff --git a/src/README.md b/src/README.md new file mode 100644 index 00000000..dfdcf286 --- /dev/null +++ b/src/README.md @@ -0,0 +1,7 @@ +# F-Droid compatible fastlane metadata directory + +This source folder only contains the generated metadata for f-droid builds for both Bitmask and a custom flavored client. +Currently neither F-Droid nor Fastlane support metadata dirs directly within build flavor dirs of a module, like +`//src//fastlane/metadata/android/` (which would be preferable). + +Keep an eye on this [issue](https://gitlab.com/fdroid/fdroidserver/-/issues/829) to track the state of the fastlane improvements for F-Droid. diff --git a/src/custom/fastlane/metadata/android/README.md b/src/custom/fastlane/metadata/android/README.md new file mode 100644 index 00000000..e69de29b diff --git a/src/normal/fastlane/metadata/android/README.md b/src/normal/fastlane/metadata/android/README.md new file mode 100644 index 00000000..e69de29b -- cgit v1.2.3 From f756c4e3027838e54b177695619ef5460aca2fd6 Mon Sep 17 00:00:00 2001 From: cyberta Date: Tue, 24 Jan 2023 16:21:19 +0100 Subject: ignore ruby vendor directory, needed for fastlane --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3997ee6d..58b37fff 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ obj bin gen libs +vendor .settings openvpn/.git openvpn/autom4te.cache -- cgit v1.2.3 From 3e9b1d2d30080939257ec382c49a6294bae3f65a Mon Sep 17 00:00:00 2001 From: kwadronaut Date: Thu, 23 Feb 2023 11:31:39 +0100 Subject: Add screengrab docker and ci Still some issues on language change and virtual screens Basics are there. --- .gitlab-ci.yml | 44 ++++++++++++++++++- docker/android-fastlane/Dockerfile | 89 ++++++++++++++++++++++++++++++++++++++ scripts/fastlane.sh | 3 +- scripts/installFastlane.sh | 39 +++++++++++++++++ scripts/prepareForScreenshots.sh | 29 +++++++++++++ scripts/startEmulators.sh | 25 +++++++++-- 6 files changed, 222 insertions(+), 7 deletions(-) create mode 100644 docker/android-fastlane/Dockerfile create mode 100755 scripts/installFastlane.sh create mode 100755 scripts/prepareForScreenshots.sh diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 286e6d45..7c9e8a54 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -14,6 +14,7 @@ variables: image: 0xacab.org:4567/leap/docker/debian:bullseye_amd64 tags: - docker-in-docker + - runner02-sea services: - docker:dind @@ -51,6 +52,15 @@ docker_image:emulator: allow_failure: true <<: *build_docker_image +docker_image:fastlane: + stage: docker_image_other + variables: + DOCKER_IMAGE: android-fastlane +# DEFAULT_IMAGE: "registry.0xacab.org/leap/bitmask_android/android-emulator" + when: manual + <<: *build_docker_image + allow_failure: true + unit_test: image: "0xacab.org:4567/leap/bitmask_android/android-ndk:latest" stage: test @@ -63,6 +73,38 @@ unit_test: when: on_failure expire_in: 3 days +screenshot: + image: "0xacab.org:4567/leap/bitmask_android/android-fastlane:latest" + stage: test + when: always +# needs: ["docker_image:fastlane"] + tags: + - birch + variables: + LC_ALL: "en_US.UTF-8" + LANG: "en_US.UTF-8" + ANDROID_EMULATOR_USE_SYSTEM_LIBS: 1 + DEBIAN_FRONTEN: "noninteractive" +# try to re-use the build artifcats from before, lib building is slow +# dependencies: +# - build + script: + - ./scripts/prepareForScreenshots.sh + - ./scripts/installFastlane.sh + - ./gradlew testCustomProductionFatReleaseUnitTest testNormalProductionFatReleaseUnitTest + - ./scripts/startEmulators.sh + - ./scripts/fastlane.sh + artifacts: + paths: + - app + - app/build/screenshots + - ./source/custom/fastlane/metadata/ + - build/ + - src/normal/ + when: always + expire_in: 3 days + allow_failure: true + #ui_test: # image: "0xacab.org:4567/leap/bitmask_android/android-emulator:latest" # stage: test @@ -106,7 +148,7 @@ build: script: - ./scripts/cleanProject.sh - ./scripts/build_deps.sh >> build_deps.log 2>&1 - - ./gradlew clean assembleNormalProductionFatDebug --stacktrace >> build.log 2>&1 + - ./gradlew clean assembleNormalProductionFatDebug -debug >> build.log 2>&1 artifacts: paths: - app/build/outputs/ diff --git a/docker/android-fastlane/Dockerfile b/docker/android-fastlane/Dockerfile new file mode 100644 index 00000000..07240c21 --- /dev/null +++ b/docker/android-fastlane/Dockerfile @@ -0,0 +1,89 @@ +FROM registry.0xacab.org/leap/bitmask_android/android-sdk:latest + +MAINTAINER LEAP Encryption Access Project +LABEL Description="Android emulator image based on android-sdk" Vendor="LEAP" Version="2" + +# Make sure debconf doesn't complain about lack of interactivity +ENV DEBIAN_FRONTEND noninteractive +# ensure GL compatibility +ENV ANDROID_EMULATOR_USE_SYSTEM_LIBS=1 + +# ------------------------------------------------------ +# --- System Dependencies + +# Need docker package in order to do Docker-in-Docker (DIND) +RUN lsb_release -a + +RUN apt-get update -qq && \ + apt-get -y dist-upgrade && \ + apt-get -y install gnupg apt-transport-https + +# Docker apt details should be inherited from android_sdk +#RUN curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg && \ +# echo \ +# "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \ +# $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + +# JNI build dependencies w/ 32-bit compatible C libs +# fastlane dependencies + +RUN apt-get update -qq && \ + apt-get install -y docker-ce docker-ce-cli make gcc swig file lib32stdc++6 lib32z1 \ + autoconf autogen automake autopoint autotools-dev gettext-base libtool patch pkg-config po4a \ + curl git openjdk-11-jdk openjdk-11-jre-headless imagemagick libpulse0 po4a \ + make build-essential ruby-dev imagemagick docker-ce-cli mesa-utils xvfb \ + libstdc++6 libncurses5 libsdl1.2debian imagemagick libpulse-java libpulse0 libxkbcommon-x11-0 && \ + apt-get clean && \ + apt-get autoclean && \ + rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +# ------------------------------------------------------ +# --- Install Android Emulator + +RUN echo "accept all licenses" +# Accept all licenses +RUN echo y | sdkmanager --licenses +RUN sdkmanager --list + +# Install Android SDK emulator package +RUN echo y | sdkmanager "emulator" + +# Install System Images for emulators +# seems like every version has its own quirks +RUN echo y | sdkmanager "system-images;android-31;google_apis;x86_64" +#RUN echo y | sdkmanager "system-images;android-27;google_apis;x86" +#RUN echo y | sdkmanager "system-images;android-25;google_apis;x86_64" +#RUN echo y | sdkmanager "system-images;android-23;google_apis;x86_64" + +# fastlane wants 2 emulators. Starting happens in the scripts +RUN echo no | avdmanager create avd --force --name testApi31 --abi google_apis/x86_64 --package 'system-images;android-31;google_apis;x86_64' +# TODO: fastlane has been troublesome for newer versions, need to dive deep to update +#RUN echo no | avdmanager create avd --force --name testApi27 --abi google_apis/x86_64 --package 'system-images;android-27;google_apis;x86_64' +#RUN echo no | avdmanager create avd --force --name testApi27-duet --abi google_apis/x86_64 --package 'system-images;android-27;google_apis;x86_64' + +# Install Android cmake +RUN sdkmanager "cmake;3.10.2.4988404" + +# Fastlane: +RUN gem install bundler fastlane + + +############################################### + +# this stuff is all just notes... really, don't call it a mess +# ------------------------------------------------------ +# --- Install Android NDK (for running C code) + +#ENV ANDROID_NDK_VERSION "r21e" +#ENV ANDROID_NDK_HOME ${ANDROID_HOME}/android-ndk-${ANDROID_NDK_VERSION} +#ENV ANDROID_NDK_URL http://dl.google.com/android/repository/android-ndk-${ANDROID_NDK_VERSION}-linux-x86_64.zip +#ENV ANDROID_SDK_ROOT ${ANDROID_HOME}/latest/cmdline-tools +# +#RUN curl -L $ANDROID_NDK_URL -o ndk.zip \ +# && unzip ndk.zip -d $ANDROID_HOME/ndk \ +# && rm -rf ndk.zip +#RUN cat $ANDROID_HOME/ndk/android-ndk-${ANDROID_NDK_VERSION}/source.properties | \ +# grep Pkg.Revision | cut -d "=" -f 2 | \ +# xargs -I '{}' mv $ANDROID_HOME/ndk/android-ndk-${ANDROID_NDK_VERSION}/ $ANDROID_HOME/ndk/'{}' +#ENV PATH ${PATH}:${ANDROID_NDK_HOME} + diff --git a/scripts/fastlane.sh b/scripts/fastlane.sh index f039cd24..1ce06ab8 100755 --- a/scripts/fastlane.sh +++ b/scripts/fastlane.sh @@ -26,9 +26,8 @@ BASE_DIR="$SCRIPT_DIR/.." cd $BASE_DIR if [[ -z $BUILD_CUSTOM ]]; then - fastlane android bitmask_screenshots + fastlane --verbose android bitmask_screenshots else fastlane android custom_build_screenshots --env custom fi; cd - - diff --git a/scripts/installFastlane.sh b/scripts/installFastlane.sh new file mode 100755 index 00000000..9abc6211 --- /dev/null +++ b/scripts/installFastlane.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +## --- System Dependencies for fastlane +apt-get update -qq && \ +apt-get -y dist-upgrade && \ +apt-get -y install make build-essential ruby ruby-dev imagemagick xvfb libxcb1 libname-dev + +gem install fastlane + +## ------------------------------------------------------ +## --- Android Emulator + +sdkmanager "platforms;android-30" +# +# Install Android SDK emulator package +echo y | sdkmanager "emulator" + +echo y | sdkmanager "system-images;android-31;google_apis;x86_64" +#echo y | sdkmanager "system-images;android-30;google_apis;x86_64" +#echo y | sdkmanager "system-images;android-28;google_apis;x86_64" +#echo y | sdkmanager "system-images;android-27;google_apis;x86" +#echo y | sdkmanager "system-images;android-25;google_apis;x86_64" + +echo no | avdmanager create avd --force --name testApi31 --abi google_apis/x86_64 --package 'system-images;android-31;google_apis;x86_64' +echo no | avdmanager create avd --force --name testApiduet --abi google_apis/x86_64 --package 'system-images;android-31;google_apis;x86_64' + +#echo no | avdmanager create avd --force --name testApi31 --abi google_apis/x86_64 --package 'system-images;android-30;google_apis;x86_64' +#echo no | avdmanager create avd --force --name testApiduet --abi google_apis/x86_64 --package 'system-images;android-30;google_apis;x86_64' + +#echo no | avdmanager create avd --force --name testApi28 --abi google_apis/x86_64 --package 'system-images;android-28;google_apis;x86_64' +#echo no | avdmanager create avd --force --name testApiduet --abi google_apis/x86_64 --package 'system-images;android-28;google_apis;x86_64' + +#echo no | avdmanager create avd --force --name testApi27 --abi google_apis/x86 --package 'system-images;android-27;google_apis;x86' +#echo no | avdmanager create avd --force --name testApiduet --abi google_apis/x86 --package 'system-images;android-27;google_apis;x86' + +#echo no | avdmanager create avd --force --name testApi25 --abi google_apis/x86_64 --package 'system-images;android-25;google_apis;x86_64' +#echo no | avdmanager create avd --force --name testApiduet --abi google_apis/x86_64 --package 'system-images;android-25;google_apis;x86_64' + +##bundle exec fastlane android bitmask_screenshots diff --git a/scripts/prepareForScreenshots.sh b/scripts/prepareForScreenshots.sh new file mode 100755 index 00000000..c2ae1bd5 --- /dev/null +++ b/scripts/prepareForScreenshots.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# Copyright (c) 2023 LEAP Encryption Access Project and contributors +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +SCRIPT_DIR=$(dirname "$0") +BASE_DIR="$SCRIPT_DIR/.." + +rm -r $BASE_DIR/bitmaskcore/lib/* + +git checkout -- \* +git checkout -- \.\* +git submodule foreach --recursive git reset --hard HEAD +git submodule sync --recursive +git submodule update --init --recursive + +BUILD_TOR=false BUILD_OPENVPN_LIBS=false ./scripts/build_deps.sh diff --git a/scripts/startEmulators.sh b/scripts/startEmulators.sh index d1bc8292..1d73dee7 100755 --- a/scripts/startEmulators.sh +++ b/scripts/startEmulators.sh @@ -1,5 +1,13 @@ #!/bin/bash +PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/Sdk/tools:$ANDROID_HOME/emulator +apt-get update +apt-get install -y libpulse-java libpulse0 imagemagick libxkbcommon-x11-0 xvfb vulkan-tools +# there's a QT thing missing +emulator -accel-check +docker info +export DISPLAY=:99.0 + # init parameters for ((i=1;i<=$#;i++)); do @@ -28,6 +36,13 @@ err() { } sec=0 timeout=30 + +# make sure the emulator is there - and in the PATH +echo y | sdkmanager "emulator" +avdmanager list avd +emulator -version +find /opt -iname emulator -type f + waitForAdbDevices() { while true; do if [[ $sec -ge $timeout ]]; then @@ -37,7 +52,7 @@ waitForAdbDevices() { if [[ "$out" == "$N" ]]; then break fi - let "r = sec % 5" + let "r = sec % 50" if [[ $r -eq 0 ]]; then echo "Waiting for adb devices to start: $out / $N" fi @@ -47,12 +62,14 @@ waitForAdbDevices() { } #start first N avd images -avdmanager list avd | grep Name: | cut -d ':' -f2 | head -n $N | xargs -I{} -P$N -n1 emulator -no-snapshot -avd {} & +Xvfb :0 -screen 0 800x600x16 & +#avdmanager list avd | grep 'Name:' | cut -d ':' -f2 | head -n $N | xargs -I{} -P$N -n1 emulator -no-snapshot -avd {} & +avdmanager list avd | grep 'Name:' | cut -d ':' -f2 | head -n $N | xargs -I{} -P$N -n1 emulator -no-window -no-audio -no-snapshot -avd {} & +#avdmanager list avd | grep 'Name:' | cut -d ':' -f2 | head -n $N | xargs -I{} -P$N -n1 emulator -no-snapshot -no-window -avd {} & +# avdmanager list avd | grep 'Name:' | cut -d ':' -f2 | head -n $N | xargs -I{} -P$N -n1 emulator -no-snapshot -no-window -no-boot-anim -accel on -avd {} & waitForAdbDevices echo "adb found all emulators..." #wait for each emulator that booting completed adb devices | grep -v List | awk '$2{print $1}' | xargs -I{} .gitlab/wait-for-emulator.sh -s {} echo "all emulators successfully booted" - - -- cgit v1.2.3 From 93bb86626e68c9820b7f40eebfc71c959ed0f047 Mon Sep 17 00:00:00 2001 From: kwadronaut Date: Thu, 23 Feb 2023 11:34:34 +0100 Subject: fix city choose test --- .../leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java index 68435fec..aa894cca 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java @@ -424,11 +424,11 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen Provider currentProvider = ProviderObservable.getInstance().getCurrentProvider(); account.setText(currentProvider.getName()); initManualGatewayEntry(); - } + } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if (key.equals(PREFERRED_CITY)) { + if (key != null && key.equals(PREFERRED_CITY)) { initManualGatewayEntry(); } } -- cgit v1.2.3