From 79f192040c59d56f08b155c629e45d6e0b6bc056 Mon Sep 17 00:00:00 2001 From: zoff99 Date: Wed, 17 Apr 2024 17:42:05 +0200 Subject: [PATCH] tweak tests and add new bob test --- .github/workflows/bobtests.yml | 128 ++++++ .../applications/trifa/JavaFriendTester.java | 400 ++++++++++++++++++ .../applications/trifa/MainActivity.java | 6 +- 3 files changed, 531 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/bobtests.yml create mode 100644 android-refimpl-app/app/src/androidTest/java/com/zoffcc/applications/trifa/JavaFriendTester.java diff --git a/.github/workflows/bobtests.yml b/.github/workflows/bobtests.yml new file mode 100644 index 000000000..4699f28ae --- /dev/null +++ b/.github/workflows/bobtests.yml @@ -0,0 +1,128 @@ +name: Bob Tests +on: + push: + paths-ignore: + - 'README.md' + - '.github/workflows/android.yml' + pull_request: + paths-ignore: + - 'README.md' + - '.github/workflows/android.yml' + workflow_dispatch: + inputs: + version: + description: dummy + default: dummy + +jobs: + android-test_bob: + runs-on: macos-latest + permissions: + contents: write + if: ${{ true }} + steps: + - uses: actions/checkout@v4 + + - name: Install Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: | + 11 + + - name: test java1 + run: | + type java + echo "===========1=========" + java -version || exit 0 + echo "===========2=========" + + - name: install cliclick + run: brew install cliclick + + - name: macos-version1 + run: sw_vers -productVersion + + - name: macos-version2 + run: system_profiler SPSoftwareDataType + + - name: download tester + shell: bash + run: | + curl -L https://github.com/zoff99/java_tox_tester/archive/refs/heads/master.zip -o master.zip + unzip master.zip + ls -al java_tox_tester-master/ + java -version + javac -version + + - name: start tester + shell: bash + run: | + cd java_tox_tester-master/ ; ls -al ; ./do_wait_for_app.sh & + + - name: android test + timeout-minutes: 120 + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: 31 + profile: Nexus 6 + arch: x86_64 + ndk: 21.0.6113669 + cmake: 3.10.2.4988404 + emulator-options: -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim -camera-back none + disable-animations: true + disable-spellchecker: true + script: | + rm -f /Users/runner/work/ToxAndroidRefImpl/ToxAndroidRefImpl/android-refimpl-app/app/witness.gradle + sed -i -e 's#a.getWindow().addFlags#//a.getWindow().addFlagsXXYY#' /Users/runner/work/ToxAndroidRefImpl/ToxAndroidRefImpl/android-refimpl-app/app/src/main/java/com/zoffcc/applications/trifa/CallingActivity.java + printf 'dependencyVerification {\nverify = [\n]\n}\n' > /Users/runner/work/ToxAndroidRefImpl/ToxAndroidRefImpl/android-refimpl-app/app/witness.gradle + java -version + cd android-refimpl-app ; ./gradlew assemble + cliclick -m verbose m:12,34 + adb logcat -c || echo "NOERR" + adb logcat > /Users/runner/work/ToxAndroidRefImpl/ToxAndroidRefImpl/android-refimpl-app/logcat.txt & + echo 'sleep 100' > /Users/runner/a.sh + echo 'sleep 40' >> /Users/runner/a.sh + echo 'sleep 10' >> /Users/runner/a.sh + echo 'sleep 10' >> /Users/runner/a.sh + echo 'sleep 10' >> /Users/runner/a.sh + echo 'adb pull "/storage/emulated/0/screen4.png" /Users/runner/screen_adb_04.png' >> /Users/runner/a.sh + cat /Users/runner/a.sh + ls -al /Users/runner/a.sh + chmod u+rx /Users/runner/a.sh + bash /Users/runner/a.sh & + cd android-refimpl-app ; ./gradlew app:connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=com.zoffcc.applications.trifa.StartMainActivityWrapperTest || echo "NOERR" + pwd + adb pull /sdcard/googletest/test_outputfiles . + ls -al test_outputfiles/ + echo "---------------" + ls -al test_outputfiles/*.png + + - name: upload screenshots + uses: actions/upload-artifact@v4 + with: + name: macscreen + path: | + /Users/runner/screen*.png + /Users/runner/test_outputfiles/*.png + + - name: upload logcat output + continue-on-error: true + uses: actions/upload-artifact@v4 + with: + name: logcat + path: | + /Users/runner/work/ToxAndroidRefImpl/ToxAndroidRefImpl/android-refimpl-app/logcat.txt + + - name: Upload to nightly release + uses: ncipollo/release-action@v1 + if: github.event_name == 'push' && github.ref == 'refs/heads/zoff99/dev003' + with: + allowUpdates: true + tag: nightly + omitBodyDuringUpdate: true + omitNameDuringUpdate: true + prerelease: true + replacesArtifacts: true + token: ${{ secrets.GITHUB_TOKEN }} + artifacts: "screen_shot_android.png" diff --git a/android-refimpl-app/app/src/androidTest/java/com/zoffcc/applications/trifa/JavaFriendTester.java b/android-refimpl-app/app/src/androidTest/java/com/zoffcc/applications/trifa/JavaFriendTester.java new file mode 100644 index 000000000..726ece1d9 --- /dev/null +++ b/android-refimpl-app/app/src/androidTest/java/com/zoffcc/applications/trifa/JavaFriendTester.java @@ -0,0 +1,400 @@ +package com.zoffcc.applications.trifa; + +import android.Manifest; +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.os.SystemClock; +import android.preference.PreferenceManager; +import android.util.Log; +import android.view.View; +import android.widget.TextView; + +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; + +import androidx.test.core.app.ActivityScenario; +import androidx.test.espresso.Espresso; +import androidx.test.espresso.NoMatchingViewException; +import androidx.test.espresso.UiController; +import androidx.test.espresso.ViewAction; +import androidx.test.espresso.ViewInteraction; +import androidx.test.ext.junit.rules.ActivityScenarioRule; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.LargeTest; +import androidx.test.rule.GrantPermissionRule; +import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry; + +import static androidx.test.InstrumentationRegistry.getTargetContext; +import static androidx.test.core.graphics.BitmapStorage.writeToTestStorage; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.Espresso.openContextualActionModeOverflowMenu; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.action.ViewActions.longClick; +import static androidx.test.espresso.action.ViewActions.replaceText; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.RootMatchers.isDialog; +import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.isRoot; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withParent; +import static androidx.test.espresso.matcher.ViewMatchers.withText; +import static androidx.test.espresso.screenshot.ViewInteractionCapture.captureToBitmap; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static androidx.test.runner.lifecycle.Stage.RESUMED; +import static com.zoffcc.applications.trifa.MainActivity.PREF__window_security; +import static com.zoffcc.applications.trifa.TrifaToxService.orma; +import static org.hamcrest.CoreMatchers.allOf; + +@RunWith(AndroidJUnit4.class) +@LargeTest +public class JavaFriendTester +{ + private static final String TAG = "TEST003"; + // + private static final String MOCK_PASSWORD = "öWOIA>C9iq2v rule = new ActivityScenarioRule<>( + StartMainActivityWrapper.class); + // + @Rule + public GrantPermissionRule grantPermissionRule = GrantPermissionRule.grant(Manifest.permission.CAMERA, + Manifest.permission.RECORD_AUDIO, + Manifest.permission.WRITE_EXTERNAL_STORAGE); + private static Activity currentActivity = null; + + @Test + public void Test_Startup() + { + Log.i(TAG, "Test_Startup"); + ActivityScenario scenario = rule.getScenario(); + + String cur_act = getActivityInstance().getLocalClassName(); + Log.i(TAG, "ACT:" + cur_act); + + boolean showing_app = false; + int app_showing_cycles = 0; + while (!showing_app) + { + if (app_showing_cycles > 120) + { + Log.i(TAG, "App did not load"); + cause_error(1); + } + cur_act = getActivityInstance().getLocalClassName(); + if (cur_act.equals("CheckPasswordActivity")) + { + showing_app = true; + } + else if (cur_act.equals("SetPasswordActivity")) + { + showing_app = true; + } + else + { + app_showing_cycles++; + } + wait_(1, "until app is showing"); + } + + setSharedPrefs(); + PREF__window_security = false; + Log.i(TAG, "PREF__window_security:002=" + PREF__window_security); + + screenshot("001"); + + if (cur_act.equals("CheckPasswordActivity")) + { + onView(withId(R.id.password_1_c)).perform(replaceText(MOCK_PASSWORD)); + screenshot("002a"); + onView(withId(R.id.set_button_2)).perform(click()); + } + else if (cur_act.equals("SetPasswordActivity")) + { + onView(withId(R.id.password_1)).perform(replaceText(MOCK_PASSWORD)); + onView(withId(R.id.password_2)).perform(replaceText(MOCK_PASSWORD)); + screenshot("002b"); + onView(withId(R.id.set_button)).perform(click()); + } + else + { + cause_error(2); + } + + Log.i(TAG, "checking for AlertDialog"); + + try + { + onView(withId(android.R.id.button2)).check(matches(isDisplayed())); + + /* + For an AlertDialog, the id assigned for each button is: + POSITIVE: android.R.id.button1 + NEGATIVE: android.R.id.button2 + NEUTRAL: android.R.id.button3 + */ + // click NO on Dialog asking to disable battery optimisations for app + onView(withId(android.R.id.button2)).inRoot(isDialog()).check(matches(isDisplayed())).perform(click()); + Log.i(TAG, "AlertDialog: \"NO\" button clicked"); + + } + catch (NoMatchingViewException e) + { + //view not displayed logic + Log.i(TAG, "checking for AlertDialog:View does not show, that is ok"); + } + + boolean tox_online = false; + while (!tox_online) + { + tox_online = MainActivity.tox_self_get_connection_status() != 0; + // HINT: wait for tox to get online + wait_(1, "for tox to get online"); + } + + setSharedPrefs(); + PREF__window_security = false; + Log.i(TAG, "PREF__window_security:001=" + PREF__window_security); + + // HINT: after we are online give it another 5 seconds + wait_(5); + + // HINT: we are online here ---------------------- + final String mytoxid = MainActivity.get_my_toxid(); + Log.i(TAG, "my_toxid:" + mytoxid); + testwrite("001", mytoxid); + + long loops = 0; + final long max_loops = 30; + int count_friends = orma.selectFromFriendList().count(); + while (count_friends < 2) + { + wait_(2); + loops++; + if (loops > max_loops) + { + Log.i(TAG, "ERROR: waiting to long for friend"); + break; + } + count_friends = orma.selectFromFriendList().count(); + } + + screenshot("004a"); + wait_(12); + screenshot("004b"); + onView( + getElementFromMatchAtPosition( + allOf(withId(R.id.f_avatar_icon), withParent(withId(R.id.friend_line_container))) + ,0 + ) + ).perform(click()); + + wait_(1); + Espresso.closeSoftKeyboard(); + screenshot("005"); + wait_(120); + screenshot("099"); + } + + private static void testwrite(final String num, final String text) + { + final String file_with_path = currentActivity.getExternalFilesDir(null).getAbsolutePath() + "/" + num + ".txt"; + try + { + java.io.File file = new java.io.File(file_with_path); + java.io.FileOutputStream fileOutput = new java.io.FileOutputStream(file); + java.io.OutputStreamWriter outputStreamWriter = new java.io.OutputStreamWriter(fileOutput); + outputStreamWriter.write(text); + outputStreamWriter.flush(); + fileOutput.getFD().sync(); + outputStreamWriter.close(); + Log.i(TAG, "testwrite:write text: "+ file_with_path); + } + catch (Exception e) + { + Log.i(TAG, "testwrite:ERROR writing text: "+ file_with_path + " E:" + e.getMessage()); + e.printStackTrace(); + } + } + + private static void screenshot(final String num) + { + try + { + writeToTestStorage(captureToBitmap(onView(isRoot())), "test_" + num); + Log.i(TAG, "capture screenshot: "+ "test_" + num + ".png"); + } + catch (Exception e) + { + Log.i(TAG, "ERROR on ca pturing screenshot: "+ "test_" + num + ".png" + " E:" + e.getMessage()); + e.printStackTrace(); + } + } + + private static void wait_(final long seconds) + { + wait_(seconds, null); + } + + private static void wait_(final long seconds, String custom_message_addon) + { + if (custom_message_addon != null) + { + Log.i(TAG, "sleeping " + seconds + " seconds " + custom_message_addon); + } + else + { + Log.i(TAG, "sleeping " + seconds + " seconds"); + } + SystemClock.sleep(seconds * 1000); + Log.i(TAG, "sleeping ended"); + } + + private static Matcher getElementFromMatchAtPosition(final Matcher matcher, final int position) + { + return new BaseMatcher() + { + int counter = 0; + + @Override + public boolean matches(final Object item) + { + if (matcher.matches(item)) + { + if (counter == position) + { + counter++; + return true; + } + counter++; + } + return false; + } + + @Override + public void describeTo(final Description description) + { + description.appendText("Element at hierarchy position " + position); + } + }; + } + + private static void cause_error(int errnum) + { + Log.i(TAG, "___ERROR_at_TESTS___:" + errnum); + if (errnum == 1) + { + onView(withId(R.id.bugButton1)).perform(replaceText(MOCK_PASSWORD)); + } + else if (errnum == 2) + { + onView(withId(R.id.bugButton2)).perform(replaceText(MOCK_PASSWORD)); + } + else if (errnum == 3) + { + onView(withId(R.id.bugButton3)).perform(replaceText(MOCK_PASSWORD)); + } + else + { + onView(withId(R.id.bugButton)).perform(replaceText(MOCK_PASSWORD)); + } + } + + public void setSharedPrefs() + { + SharedPreferences sharedPreferences = + PreferenceManager.getDefaultSharedPreferences(getInstrumentation().getContext()); + SharedPreferences.Editor editor = sharedPreferences.edit() ; + editor.putBoolean("window_security", false) ; + editor.apply(); + editor.commit(); + Log.i(TAG ,"Setting up shared prefs"); + } + + @Before + public void setUp() throws Exception + { + Log.i(TAG, "setUp"); + } + + @After + public void tearDown() throws Exception + { + Log.i(TAG, "tearDown"); + } + + public Activity getActivityInstance() + { + getInstrumentation().runOnMainSync(new Runnable() + { + public void run() + { + Collection resumedActivities = ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage( + RESUMED); + if (resumedActivities.iterator().hasNext()) + { + currentActivity = (Activity) resumedActivities.iterator().next(); + } + } + }); + + return currentActivity; + } + + public void grant_permissions() + { + // ----- persmission ----- + ArrayList permissions = new ArrayList<>(); + permissions.add(Manifest.permission.CAMERA); + permissions.add(Manifest.permission.RECORD_AUDIO); + permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); + for (int i = 0; i < permissions.size(); i++) + { + String command = String.format("pm grant %s %s", getTargetContext().getPackageName(), permissions.get(i)); + getInstrumentation().getUiAutomation().executeShellCommand(command); + // wait a bit until the command is finished + SystemClock.sleep(2000); + } + // ----- persmission ----- + } + + public String getViewInteractionText(ViewInteraction matcher) + { + final String[] text = new String[1]; + ViewAction va = new ViewAction() + { + @Override + public Matcher getConstraints() + { + return isAssignableFrom(TextView.class); + } + + @Override + public String getDescription() + { + return "Text of the view"; + } + + @Override + public void perform(UiController uiController, View view) + { + TextView tv = (TextView) view; + text[0] = tv.getText().toString(); + } + }; + + matcher.perform(va); + return text[0]; + } +} \ No newline at end of file diff --git a/android-refimpl-app/app/src/main/java/com/zoffcc/applications/trifa/MainActivity.java b/android-refimpl-app/app/src/main/java/com/zoffcc/applications/trifa/MainActivity.java index 8c0e8eef4..5e34badc4 100644 --- a/android-refimpl-app/app/src/main/java/com/zoffcc/applications/trifa/MainActivity.java +++ b/android-refimpl-app/app/src/main/java/com/zoffcc/applications/trifa/MainActivity.java @@ -6382,9 +6382,9 @@ static void android_tox_callback_file_recv_chunk_cb_method(long friend_number, l global_last_activity_for_battery_savings_ts = System.currentTimeMillis(); global_last_activity_outgoung_ft_ts = System.currentTimeMillis(); - // Log.i(TAG, "file_recv_chunk:" + friend_number + ":fn==" + file_number + ":position=" + position + ":length=" + length + ":data len=" + data.length + ":data=" + data); - // Log.i(TAG, "file_recv_chunk:--START--"); - // Log.i(TAG, "file_recv_chunk:" + friend_number + ":" + file_number + ":" + position + ":" + length); + Log.i(TAG, "file_recv_chunk:" + friend_number + ":fn==" + file_number + ":position=" + position + ":length=" + length + ":data len=" + data.length + ":data=" + data); + Log.i(TAG, "file_recv_chunk:--START--"); + Log.i(TAG, "file_recv_chunk:" + friend_number + ":" + file_number + ":" + position + ":" + length); Filetransfer f = null; try