-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Stefan Niedermann <[email protected]> Signed-off-by: Andy Scherzinger <[email protected]>
- Loading branch information
1 parent
e6e9d27
commit 9377094
Showing
5 changed files
with
283 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
on: [push] | ||
|
||
jobs: | ||
setup_nextcloud: | ||
runs-on: ubuntu-latest | ||
name: Run e2e test | ||
strategy: | ||
matrix: | ||
api-level: [ 24 ] #, 25, 26, 27, 28, 29 ] | ||
nextcloud-version: [ 'nextcloud:latest' ] #, 'nextcloud:stable', 'nextcloud:production' ] | ||
services: | ||
nextcloud: | ||
image: ${{ matrix.nextcloud-version }} | ||
env: | ||
SQLITE_DATABASE: db.sqlite | ||
NEXTCLOUD_ADMIN_USER: Test | ||
NEXTCLOUD_ADMIN_PASSWORD: Test | ||
ports: | ||
- 8080:80 | ||
options: >- | ||
--health-cmd "curl GET 'http://Test:Test@localhost:80/ocs/v2.php/apps/serverinfo/api/v1/info' -f -H 'OCS-APIRequest: true' || exit 1" | ||
--health-interval 1s | ||
--health-timeout 2s | ||
--health-retries 10 | ||
--health-start-period 3s | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v2 | ||
|
||
- name: Make Nextcloud accessible from AVD | ||
run: | | ||
docker exec `docker ps -f 'name=_nextcloud' -l -q` bash -c 'runuser -u www-data -- php occ config:system:set trusted_domains 2 --value=172.17.0.1' | ||
# TODO 172.17.0.1 is the hard coded IP address of the docker container. Make this more generic. | ||
- name: Verify Nextcloud being present on 172.17.0.1 | ||
run: | | ||
curl -v -X GET 'http://Test:[email protected]:8080/ocs/v2.php/cloud/capabilities?format=json' -H 'OCS-APIRequest: true' | jq | ||
########################## | ||
# AVD CACHING START # | ||
########################## | ||
|
||
- name: Gradle cache | ||
uses: actions/cache@v2 | ||
with: | ||
path: | | ||
~/.gradle/caches | ||
~/.gradle/wrapper | ||
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }}-${{ hashFiles('**/buildSrc/**/*.kt') }} | ||
|
||
- name: AVD cache | ||
uses: actions/cache@v2 | ||
id: avd-cache | ||
with: | ||
path: | | ||
~/.android/avd/* | ||
~/.android/adb* | ||
key: avd-${{ matrix.api-level }} | ||
|
||
- name: Create AVD and generate snapshot for caching | ||
if: steps.avd-cache.outputs.cache-hit != 'true' | ||
uses: reactivecircus/android-emulator-runner@v2 | ||
with: | ||
api-level: ${{ matrix.api-level }} | ||
force-avd-creation: false | ||
sdcard-path-or-size: sdcard | ||
emulator-options: -gpu swiftshader_indirect -no-window -noaudio -no-boot-anim -camera-back none | ||
disable-animations: true | ||
script: echo "Generated AVD snapshot for caching." | ||
|
||
########################## | ||
# AVD CACHING END # | ||
########################## | ||
|
||
- name: Run e2e tests | ||
uses: reactivecircus/android-emulator-runner@v2 | ||
with: | ||
api-level: ${{ matrix.api-level }} | ||
force-avd-creation: false | ||
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none | ||
disable-animations: true | ||
# FIXME Execution of connectedDebugAndroidTest fails | ||
# TODO latest.apk should be cached when matrix testing is used | ||
script: | | ||
adb shell pm uninstall -k --user 0 com.nextcloud.android.beta || true | ||
wget -q https://download.nextcloud.com/android/dev/latest.apk | ||
adb install latest.apk | ||
adb shell pm grant com.nextcloud.android.beta android.permission.READ_EXTERNAL_STORAGE | ||
adb logcat -c || true | ||
adb logcat *:I -v color & | ||
./gradlew connectedDebugAndroidTest || true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
190 changes: 190 additions & 0 deletions
190
sample/src/androidTest/java/com/nextcloud/android/sso/sample/E2ETest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
package com.nextcloud.android.sso.sample; | ||
|
||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; | ||
import static androidx.test.uiautomator.Until.findObject; | ||
import static androidx.test.uiautomator.Until.hasObject; | ||
|
||
import android.content.Intent; | ||
import android.util.Log; | ||
import android.webkit.WebView; | ||
import android.widget.Button; | ||
import android.widget.EditText; | ||
|
||
import androidx.annotation.NonNull; | ||
import androidx.test.uiautomator.By; | ||
import androidx.test.uiautomator.UiDevice; | ||
import androidx.test.uiautomator.UiObjectNotFoundException; | ||
import androidx.test.uiautomator.UiSelector; | ||
|
||
import org.junit.After; | ||
import org.junit.Before; | ||
import org.junit.FixMethodOrder; | ||
import org.junit.Test; | ||
import org.junit.runners.MethodSorters; | ||
|
||
/** | ||
* FIXME This does not yet work | ||
*/ | ||
@FixMethodOrder(MethodSorters.NAME_ASCENDING) | ||
public class E2ETest { | ||
|
||
private static final String TAG = E2ETest.class.getSimpleName(); | ||
|
||
private UiDevice mDevice; | ||
|
||
private static final int TIMEOUT = 60_000; | ||
|
||
private static final String APP_NEXTCLOUD = "com.nextcloud.android.beta"; | ||
// TODO This should be passed as argument | ||
private static final String APP_SAMPLE = BuildConfig.APPLICATION_ID; | ||
private static final String SERVER_URL = "http://172.17.0.1:8080"; | ||
private static final String SERVER_USERNAME = "Test"; | ||
private static final String SERVER_PASSWORD = "Test"; | ||
|
||
@Before | ||
public void before() { | ||
mDevice = UiDevice.getInstance(getInstrumentation()); | ||
mDevice.pressHome(); | ||
} | ||
|
||
@After | ||
public void after() { | ||
mDevice.pressHome(); | ||
} | ||
|
||
@Test | ||
public void test_00_configureNextcloudAccount() throws UiObjectNotFoundException { | ||
launch(APP_NEXTCLOUD); | ||
|
||
final var loginButton = mDevice.findObject(new UiSelector().textContains("Log in")); | ||
loginButton.waitForExists(TIMEOUT); | ||
log("Login Button exists. Clicking on it..."); | ||
loginButton.click(); | ||
log("Login Button clicked."); | ||
|
||
final var urlInput = mDevice.findObject(new UiSelector().focused(true)); | ||
urlInput.waitForExists(TIMEOUT); | ||
log("URL input exists."); | ||
log("Entering URL..."); | ||
urlInput.setText(SERVER_URL); | ||
log("URL entered."); | ||
|
||
log("Pressing enter..."); | ||
mDevice.pressEnter(); | ||
log("Enter pressed."); | ||
|
||
log("Waiting for WebView..."); | ||
mDevice.wait(findObject(By.clazz(WebView.class)), TIMEOUT); | ||
log("WebView exists."); | ||
|
||
final var webViewLoginButton = mDevice.findObject(new UiSelector() | ||
.instance(0) | ||
.className(Button.class)); | ||
log("Waiting for WebView Login Button..."); | ||
webViewLoginButton.waitForExists(TIMEOUT); | ||
log("WebView Login Button exists. Clicking on it..."); | ||
webViewLoginButton.click(); | ||
|
||
final var usernameInput = mDevice.findObject(new UiSelector() | ||
.instance(0) | ||
.className(EditText.class)); | ||
log("Waiting for Username Input..."); | ||
usernameInput.waitForExists(TIMEOUT); | ||
log("Username Input exists. Setting text..."); | ||
usernameInput.setText(SERVER_USERNAME); | ||
log("Username has been set."); | ||
|
||
final var passwordInput = mDevice.findObject(new UiSelector() | ||
.instance(1) | ||
.className(EditText.class)); | ||
log("Waiting for Password Input..."); | ||
passwordInput.waitForExists(TIMEOUT); | ||
log("Password Input exists. Setting text..."); | ||
passwordInput.setText(SERVER_PASSWORD); | ||
|
||
final var webViewSubmitButton = mDevice.findObject(new UiSelector() | ||
.instance(0) | ||
.className(Button.class)); | ||
log("Waiting for WebView Submit Button..."); | ||
webViewSubmitButton.waitForExists(TIMEOUT); | ||
log("WebView Submit Button exists. Clicking on it..."); | ||
webViewSubmitButton.click(); | ||
|
||
final var webViewGrantAccessButton = mDevice.findObject(new UiSelector() | ||
.instance(0) | ||
.className(Button.class)); | ||
log("Waiting for WebView Grant Access Button..."); | ||
webViewGrantAccessButton.waitForExists(TIMEOUT); | ||
log("WebView Grant Access Button exists. Clicking on it..."); | ||
webViewGrantAccessButton.click(); | ||
} | ||
|
||
@Test | ||
public void test_01_importAccountIntoSampleApp() throws UiObjectNotFoundException, InterruptedException { | ||
launch(APP_SAMPLE); | ||
|
||
final var accountButton = mDevice.findObject(new UiSelector() | ||
.instance(0) | ||
.className(Button.class)); | ||
accountButton.waitForExists(TIMEOUT); | ||
accountButton.click(); | ||
|
||
mDevice.waitForWindowUpdate(null, TIMEOUT); | ||
|
||
final var radioAccount = mDevice.findObject(new UiSelector() | ||
.clickable(true) | ||
.instance(0)); | ||
radioAccount.waitForExists(TIMEOUT); | ||
radioAccount.click(); | ||
|
||
mDevice.waitForWindowUpdate(null, TIMEOUT); | ||
|
||
Thread.sleep(10_000); | ||
final var okButton = mDevice.findObject(new UiSelector() | ||
.textContains("OK")); | ||
log("Waiting for OK Button..."); | ||
okButton.waitForExists(TIMEOUT); | ||
log("OK Button exists. Clicking on it..."); | ||
okButton.click(); | ||
log("OK Button clicked"); | ||
|
||
mDevice.waitForWindowUpdate(null, TIMEOUT); | ||
|
||
final var allowButton = mDevice.findObject(new UiSelector() | ||
.instance(1) | ||
.className(Button.class)); | ||
log("Waiting for Allow Button..."); | ||
allowButton.waitForExists(TIMEOUT); | ||
log("Allow Button exists. Clicking on it..."); | ||
allowButton.click(); | ||
log("Allow Button clicked"); | ||
|
||
log("Waiting for finished import..."); | ||
final var welcomeText = mDevice.findObject(new UiSelector().description("Filter")); | ||
welcomeText.waitForExists(TIMEOUT); | ||
log("Import finished."); | ||
} | ||
|
||
@Test | ||
public void test_02_verifyResult() throws UiObjectNotFoundException { | ||
launch(APP_SAMPLE); | ||
|
||
final var taskCard = mDevice.findObject(new UiSelector() | ||
.textContains("Test on Nextcloud")); | ||
taskCard.waitForExists(TIMEOUT); | ||
System.out.println("Found: " + taskCard.getText()); | ||
} | ||
|
||
private void log(@NonNull String message) { | ||
Log.i(TAG, message); | ||
} | ||
|
||
private void launch(@NonNull String packageName) { | ||
final var context = getInstrumentation().getContext(); | ||
context.startActivity(context | ||
.getPackageManager() | ||
.getLaunchIntentForPackage(packageName) | ||
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)); | ||
mDevice.wait(hasObject(By.pkg(packageName).depth(0)), TIMEOUT); | ||
} | ||
} |
26 changes: 0 additions & 26 deletions
26
sample/src/androidTest/java/com/nextcloud/android/sso/sample/ExampleInstrumentedTest.java
This file was deleted.
Oops, something went wrong.
17 changes: 0 additions & 17 deletions
17
sample/src/test/java/com/nextcloud/android/sso/sample/ExampleUnitTest.java
This file was deleted.
Oops, something went wrong.