From 41795d6c1893adb06a3851bcf2330a2975ed8dfe 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 +++++++++++++++++++ gradle/libs.versions.toml | 15 ++++ 8 files changed, 252 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 diff --git a/.gitlab-ci-files/job-tester.yml b/.gitlab-ci-files/job-tester.yml new file mode 100644 index 000000000..5cde7f8cb --- /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 pixel9api36DebugAndroidTest --full-stacktrace + + artifacts: + paths: + - app/build/outputs/androidTest-results/connected/debug/ + when: always + expire_in: 1 day \ No newline at end of file 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 e64ad64a3..2613df028 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 pixel9api36DebugAndroidTest to execute tests on this device + create("pixel9api36") { + device = "Pixel 9" + apiLevel = 36 + // systemImageSource = "aosp" + 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/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2e13313e1..8d392105d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -33,6 +33,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" } @@ -69,6 +75,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" }