From b01e5491b7489b6d573eb71f0eb604a9c5be94e0 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 3 Jun 2025 12:14:22 +0200 Subject: [PATCH] Added Cucumber tests setup --- .gitlab-ci-files/job-tester.yml | 37 ++++++++++ .gitlab-ci.yml | 4 +- .idea/codeStyles/Project.xml | 35 +++++++++ app/build.gradle.kts | 39 +++++++++- .../assets/features/welcome.feature | 7 ++ .../test/CucumberTestInstrumentation.kt | 48 +++++++++++++ .../org/linphone/test/WelcomeActivityTest.kt | 71 +++++++++++++++++++ docker-files/bc-dev-android-35 | 56 +++++++++++++++ gradle/libs.versions.toml | 15 ++++ tests.md | 8 +++ 10 files changed, 316 insertions(+), 4 deletions(-) create mode 100644 .gitlab-ci-files/job-tester.yml create mode 100644 app/src/androidTest/assets/features/welcome.feature create mode 100644 app/src/androidTest/java/org/linphone/test/CucumberTestInstrumentation.kt create mode 100644 app/src/androidTest/java/org/linphone/test/WelcomeActivityTest.kt create mode 100644 docker-files/bc-dev-android-35 create mode 100644 tests.md diff --git a/.gitlab-ci-files/job-tester.yml b/.gitlab-ci-files/job-tester.yml new file mode 100644 index 000000000..1d45c7e84 --- /dev/null +++ b/.gitlab-ci-files/job-tester.yml @@ -0,0 +1,37 @@ +job-android-tester: + + stage: test + tags: [ "docker-test-liblinphone-lenovo-2-sdk " ] + image: gitlab.linphone.org:4567/bc/public/linphone-android/bc-dev-android:20230414_bullseye_jdk_17_cleaned + + #only: + # - schedules + dependencies: + - job-android + allow_failure: true + + before_script: + - if ! [ -z ${SCP_PRIVATE_KEY+x} ]; then eval $(ssh-agent -s); fi + - if ! [ -z ${SCP_PRIVATE_KEY+x} ]; then echo "$SCP_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null; fi + - if ! [ -z ${ANDROID_SETTINGS_GRADLE+x} ]; then echo "$ANDROID_SETTINGS_GRADLE" > settings.gradle.kts; fi + - git config --global --add safe.directory /builds/BC/public/linphone-android + + script: + - scp -oStrictHostKeyChecking=no $DEPLOY_SERVER:$ANDROID_KEYSTORE_PATH app/ + - scp -oStrictHostKeyChecking=no $DEPLOY_SERVER:$ANDROID_GOOGLE_SERVICES_PATH app/ + - echo storePassword=$ANDROID_KEYSTORE_PASSWORD > keystore.properties + - echo keyPassword=$ANDROID_KEYSTORE_KEY_PASSWORD >> keystore.properties + - echo keyAlias=$ANDROID_KEYSTORE_KEY_ALIAS >> keystore.properties + - echo storeFile=$ANDROID_KEYSTORE_FILE >> keystore.properties + - ./gradlew app:dependencies | grep org.linphone + - ./gradlew clean + - ./gradlew assembleDebug + - ./gradlew assembleDebugAndroidTest -x test +# - ./gradlew connectAndroidTest + - ./gradlew pixel9api35arm64DebugAndroidTest --full-stacktrace + + artifacts: + paths: + - app/build/outputs/androidTest-results/connected/debug/ + when: always + expire_in: 1 day diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0e65baf26..36d603c62 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,9 +11,11 @@ include: - '.gitlab-ci-files/job-android.yml' + - '.gitlab-ci-files/job-tester.yml' - '.gitlab-ci-files/job-upload.yml' stages: - build - - deploy + - test + - deploy \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 7643783a8..7f70f7ef8 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,5 +1,40 @@ + + + diff --git a/app/build.gradle.kts b/app/build.gradle.kts index d77c8ed36..af2b454ba 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -78,9 +78,6 @@ task("getGitVersion") { } project.tasks.preBuild.dependsOn("getGitVersion") -configurations { - implementation { isCanBeResolved = true } -} task("linphoneSdkSource") { doLast { configurations.implementation.get().incoming.resolutionResult.allComponents.forEach { @@ -92,6 +89,10 @@ task("linphoneSdkSource") { } project.tasks.preBuild.dependsOn("linphoneSdkSource") +configurations { + implementation { isCanBeResolved = true } +} + android { namespace = "org.linphone" compileSdk = 36 @@ -109,6 +110,9 @@ android { //noinspection ChromeOsAbiSupport abiFilters += listOf("armeabi-v7a", "arm64-v8a") } + + testApplicationId = "$packageName.test" + testInstrumentationRunner = "org.linphone.test.CucumberTestInstrumentation" } applicationVariants.all { @@ -208,9 +212,38 @@ android { lint { abortOnError = false } + + sourceSets { + getByName("androidTest").assets.srcDirs("src/androidTest/assets") + } + + testOptions { + managedDevices { + localDevices { + // Use ./gradlew pixel9api35arm64DebugAndroidTest to execute tests on this device + create("pixel9api35arm64") { + device = "Pixel 9" + apiLevel = 35 + // systemImageSource = "aosp", "google-atd", "aosp-atd" + systemImageSource = "google" + // testedAbi = "x86_64" + testedAbi = "arm64-v8a" + } + } + } + } } dependencies { + androidTestImplementation(libs.androidx.monitor) + androidTestImplementation(libs.androidx.test.core) + androidTestImplementation(libs.androidx.test.rules) + androidTestImplementation(libs.androidx.test.runner) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso) + androidTestImplementation(libs.cucumber.android) + androidTestImplementation(libs.cucumber.junit) + implementation(libs.androidx.annotations) implementation(libs.androidx.activity) implementation(libs.androidx.appcompat) diff --git a/app/src/androidTest/assets/features/welcome.feature b/app/src/androidTest/assets/features/welcome.feature new file mode 100644 index 000000000..75e56533d --- /dev/null +++ b/app/src/androidTest/assets/features/welcome.feature @@ -0,0 +1,7 @@ +Feature:Welcome + When app starts the first time, it must display the welcome screens + + Scenario Outline:Welcome screens displayed at first start + Given I have a welcome Activity + When I press skip + Then I should be sent to the assistant Activity diff --git a/app/src/androidTest/java/org/linphone/test/CucumberTestInstrumentation.kt b/app/src/androidTest/java/org/linphone/test/CucumberTestInstrumentation.kt new file mode 100644 index 000000000..bb6235112 --- /dev/null +++ b/app/src/androidTest/java/org/linphone/test/CucumberTestInstrumentation.kt @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2010-2025 Belledonne Communications SARL. + * + * This file is part of linphone-android + * (see https://www.linphone.org). + * + * 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 org.linphone.test + +import android.app.Application +import android.content.Context +import io.cucumber.android.runner.CucumberAndroidJUnitRunner +import io.cucumber.junit.CucumberOptions +import org.linphone.LinphoneApplication + +/** + * The CucumberOptions annotation is mandatory for exactly one of the classes in the test project. + * Only the first annotated class that is found will be used, others are ignored. If no class is + * annotated, an exception is thrown. This annotation does not have to placed in runner class + */ +@CucumberOptions(features = ["features"]) +class CucumberTestInstrumentation : CucumberAndroidJUnitRunner() { + @Throws( + ClassNotFoundException::class, + IllegalAccessException::class, + InstantiationException::class + ) + @Override + override fun newApplication( + cl: ClassLoader, + className: String, + context: Context + ): Application { + return super.newApplication(cl, LinphoneApplication::class.java.getName(), context) + } +} diff --git a/app/src/androidTest/java/org/linphone/test/WelcomeActivityTest.kt b/app/src/androidTest/java/org/linphone/test/WelcomeActivityTest.kt new file mode 100644 index 000000000..c31ddc41d --- /dev/null +++ b/app/src/androidTest/java/org/linphone/test/WelcomeActivityTest.kt @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2010-2025 Belledonne Communications SARL. + * + * This file is part of linphone-android + * (see https://www.linphone.org). + * + * 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 org.linphone.test + +import android.content.Intent +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import androidx.test.rule.ActivityTestRule +import io.cucumber.java.After +import io.cucumber.java.Before +import io.cucumber.java.en.Given +import io.cucumber.java.en.Then +import io.cucumber.java.en.When +import junit.framework.TestCase.assertNotNull +import org.junit.Rule +import org.junit.runner.RunWith +import org.linphone.ui.welcome.WelcomeActivity + +@SmallTest +@RunWith(AndroidJUnit4::class) +class WelcomeActivityTest { + @JvmField + @Rule + var activityTestRule: ActivityTestRule = ActivityTestRule(WelcomeActivity::class.java) + + @Rule + lateinit var activity: WelcomeActivity + + @Before() + fun setup() { + activityTestRule.launchActivity(Intent()) + activity = activityTestRule.activity + } + + @After() + fun finish() { + activityTestRule.finishActivity() + } + + @Given("^I have a welcome Activity") + fun I_have_a_login_activity() { + assertNotNull(activity) + } + + @When("^I press skip") + fun I_press_skip() { + + } + + @Then("^I should be sent to the assistant Activity") + fun I_should_be_sent_to_the_assistant_activity() { + + } +} diff --git a/docker-files/bc-dev-android-35 b/docker-files/bc-dev-android-35 new file mode 100644 index 000000000..48f861f94 --- /dev/null +++ b/docker-files/bc-dev-android-35 @@ -0,0 +1,56 @@ +FROM debian:bullseye + +MAINTAINER Sylvain BERFINI + +# Configure locale +RUN apt-get update && \ + apt-get install -y locales && \ + apt-get clean && \ + echo "en_US.UTF-8 UTF-8" > /etc/locale.gen && \ + locale-gen +ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' LC_ALL='en_US.UTF-8' + +ENV SHELL=/bin/bash + +# Define environment +ENV ANDROID_HOME /opt/android-sdk-linux + +# Install common general tools +RUN apt-get update && \ + apt-get install -y curl nano sudo unzip vim wget rsync ssh git openjdk-17-jdk-headless && \ + apt-get install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils cpu-checker libxkbfile1 libxkbcommon-x11-0 libxcb-cursor0 && \ + apt-get clean + +# Get latest Android command line tools, otherwise won't work with JDK 17 +RUN mkdir -p $ANDROID_HOME/cmdline-tools/latest +RUN wget https://dl.google.com/android/repository/commandlinetools-linux-9477386_latest.zip && \ + unzip commandlinetools-linux-9477386_latest.zip && \ + cp -R ./cmdline-tools/* $ANDROID_HOME/cmdline-tools/latest/ && \ + rm -rf ./cmdline-tools && \ + rm -rf commandlinetools-linux-9477386_latest.zip + +# Update path to include all Android SDK tools +ENV PATH $ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/tools:$ANDROID_HOME/tools/bin:$ANDROID_HOME/platform-tools:$PATH + +# Get the Android SDK +RUN echo "y" | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "platform-tools" "tools" "platforms;android-35" "platforms;android-36" "system-images;android-35;google_atd;x86_64" "build-tools;35.0.0" + +# Accept Android SDK licenses +RUN yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses + +# Give write rights +RUN chmod -R ugo+rwx $ANDROID_HOME + +# Consider all git repositories as safe +RUN git --version +RUN git config --global --add safe.directory '*' + +# Configure user bc +RUN useradd -ms /bin/bash bc && \ + echo 'bc:cotcot' | chpasswd && \ + echo 'bc ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers + +USER bc +WORKDIR /home/bc +ENV PS1='\[\e[34m\]\u@bc-dev-android>\[\e[0m\] ' +CMD bash diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 41edf105b..c8a574301 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -34,6 +34,12 @@ photoview = "2.3.0" openidAppauth = "0.11.1" linphone = "5.5.+" +cucumber = "7.18.1" +test = "1.7.0" +monitor = "1.8.0" +junit = "1.3.0" +espresso = "3.7.0" + [libraries] androidx-annotations = { group = "androidx.annotation", name = "annotation", version.ref = "annotations" } androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" } @@ -71,6 +77,15 @@ openid-appauth = { group = "net.openid", name = "appauth", version.ref = "openid linphone = { group = "org.linphone", name = "linphone-sdk-android", version.ref = "linphone" } +cucumber-android = { group = "io.cucumber", name = "cucumber-android", version.ref = "cucumber" } +cucumber-junit = { group = "io.cucumber", name = "cucumber-junit", version.ref = "cucumber" } +androidx-test-core = { group = "androidx.test", name = "core", version.ref = "test" } +androidx-test-rules = { group = "androidx.test", name = "rules", version.ref = "test" } +androidx-test-runner = { group = "androidx.test", name = "runner", version.ref = "test" } +androidx-monitor = { group = "androidx.test", name = "monitor", version.ref = "monitor" } +androidx-junit = { group = "androidx.test.ext", name = "junit-ktx", version.ref = "junit" } +androidx-espresso = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso" } + [plugins] androidApplication = { id = "com.android.application", version.ref = "agp" } jetbrainsKotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } diff --git a/tests.md b/tests.md new file mode 100644 index 000000000..213785fe9 --- /dev/null +++ b/tests.md @@ -0,0 +1,8 @@ +sudo docker run -it --device /dev/kvm --net=host --privileged --env="DISPLAY" gitlab.linphone.org:4567/bc/public/linphone-android/bc-dev-android-35:20251103_tests + + +git clone https://gitlab.linphone.org/BC/public/linphone-android.git -b feature/cucumber_tests && cd linphone-android/ && ./gradlew assembleDebug && ./gradlew assembleDebugAndroidTest -x test && ./gradlew pixel9api35arm64DebugAndroidTest --full-stacktrace + +echo "no" | avdmanager --verbose create avd --force --name "pixel_6_api35_google_atd_emulator" --package "system-images;android-35;google_atd;x86_64" --tag "google_atd" --abi "x86_64" --device "pixel_6" +cd /opt/android-sdk-linux/tools/ +QT_QPA_PLATFORM=xcb emulator -avd pixel_6_api35_google_atd_emulator -no-audio -no-boot-anim -no-window -accel on -gpu off -no-skin \ No newline at end of file