Added Cucumber tests setup

This commit is contained in:
Sylvain Berfini 2025-06-03 12:14:22 +02:00
parent 89458ed826
commit b01e5491b7
10 changed files with 316 additions and 4 deletions

View file

@ -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

View file

@ -11,9 +11,11 @@
include: include:
- '.gitlab-ci-files/job-android.yml' - '.gitlab-ci-files/job-android.yml'
- '.gitlab-ci-files/job-tester.yml'
- '.gitlab-ci-files/job-upload.yml' - '.gitlab-ci-files/job-upload.yml'
stages: stages:
- build - build
- deploy - test
- deploy

View file

@ -1,5 +1,40 @@
<component name="ProjectCodeStyleConfiguration"> <component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173"> <code_scheme name="Project" version="173">
<JavaCodeStyleSettings>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="" withSubpackages="true" static="false" module="true" />
<package name="android" withSubpackages="true" static="true" />
<package name="androidx" withSubpackages="true" static="true" />
<package name="com" withSubpackages="true" static="true" />
<package name="junit" withSubpackages="true" static="true" />
<package name="net" withSubpackages="true" static="true" />
<package name="org" withSubpackages="true" static="true" />
<package name="java" withSubpackages="true" static="true" />
<package name="javax" withSubpackages="true" static="true" />
<package name="" withSubpackages="true" static="true" />
<emptyLine />
<package name="android" withSubpackages="true" static="false" />
<emptyLine />
<package name="androidx" withSubpackages="true" static="false" />
<emptyLine />
<package name="com" withSubpackages="true" static="false" />
<emptyLine />
<package name="junit" withSubpackages="true" static="false" />
<emptyLine />
<package name="net" withSubpackages="true" static="false" />
<emptyLine />
<package name="org" withSubpackages="true" static="false" />
<emptyLine />
<package name="java" withSubpackages="true" static="false" />
<emptyLine />
<package name="javax" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
<emptyLine />
</value>
</option>
</JavaCodeStyleSettings>
<JetCodeStyleSettings> <JetCodeStyleSettings>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings> </JetCodeStyleSettings>

View file

@ -78,9 +78,6 @@ task("getGitVersion") {
} }
project.tasks.preBuild.dependsOn("getGitVersion") project.tasks.preBuild.dependsOn("getGitVersion")
configurations {
implementation { isCanBeResolved = true }
}
task("linphoneSdkSource") { task("linphoneSdkSource") {
doLast { doLast {
configurations.implementation.get().incoming.resolutionResult.allComponents.forEach { configurations.implementation.get().incoming.resolutionResult.allComponents.forEach {
@ -92,6 +89,10 @@ task("linphoneSdkSource") {
} }
project.tasks.preBuild.dependsOn("linphoneSdkSource") project.tasks.preBuild.dependsOn("linphoneSdkSource")
configurations {
implementation { isCanBeResolved = true }
}
android { android {
namespace = "org.linphone" namespace = "org.linphone"
compileSdk = 36 compileSdk = 36
@ -109,6 +110,9 @@ android {
//noinspection ChromeOsAbiSupport //noinspection ChromeOsAbiSupport
abiFilters += listOf("armeabi-v7a", "arm64-v8a") abiFilters += listOf("armeabi-v7a", "arm64-v8a")
} }
testApplicationId = "$packageName.test"
testInstrumentationRunner = "org.linphone.test.CucumberTestInstrumentation"
} }
applicationVariants.all { applicationVariants.all {
@ -208,9 +212,38 @@ android {
lint { lint {
abortOnError = false 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 { 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.annotations)
implementation(libs.androidx.activity) implementation(libs.androidx.activity)
implementation(libs.androidx.appcompat) implementation(libs.androidx.appcompat)

View file

@ -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

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
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)
}
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
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<WelcomeActivity> = 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() {
}
}

View file

@ -0,0 +1,56 @@
FROM debian:bullseye
MAINTAINER Sylvain BERFINI <sylvain.berfini@belledonne-communications.com>
# 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

View file

@ -34,6 +34,12 @@ photoview = "2.3.0"
openidAppauth = "0.11.1" openidAppauth = "0.11.1"
linphone = "5.5.+" linphone = "5.5.+"
cucumber = "7.18.1"
test = "1.7.0"
monitor = "1.8.0"
junit = "1.3.0"
espresso = "3.7.0"
[libraries] [libraries]
androidx-annotations = { group = "androidx.annotation", name = "annotation", version.ref = "annotations" } androidx-annotations = { group = "androidx.annotation", name = "annotation", version.ref = "annotations" }
androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" } 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" } 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] [plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" } androidApplication = { id = "com.android.application", version.ref = "agp" }
jetbrainsKotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } jetbrainsKotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }

8
tests.md Normal file
View file

@ -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