diff --git a/.cirrus.yml b/.cirrus.yml index 5ab30bfb4..e164bf404 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -10,8 +10,17 @@ check_android_30_task: kvm: true cpu: 8 memory: 24G - start_adb_server_background_script: - java -jar artifacts/adbserver-desktop.jar || true + # xfce4 somehow helps to pass "Geolocation" test + install_de_script: | + export DEBIAN_FRONTEND=noninteractive + apt-get update + apt-get install xfce4 -y + apt-get purge -y pm-utils xscreensaver* + apt-get install xvfb -y + start_de_background_script: | + Xvfb :99 -screen 0 1000x1000x16 & + sleep 5 + startxfce4 accept_licenses_script: echo yes | sdkmanager --licenses install_emulator_script: @@ -33,7 +42,7 @@ check_android_30_task: -no-snapshot -no-window assemble_instrumented_tests_script: - ./gradlew -PCI=true assembleDebugAndroidTest + cd samples && ./gradlew assembleDebugAndroidTest wait_for_avd_script: adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 3; done; input keyevent 82' configure_avd_script: | @@ -45,7 +54,9 @@ check_android_30_task: start_logcat_background_script: adb logcat > log.log run_tests_script: - ./gradlew -PCI=true connectedDebugAndroidTest + cd samples && ./gradlew connectedDebugAndroidTest + # After we do "adb root" connection is closed for a moment. So first attempt to pull screenshots usually fails + # That's why we make 5 attempts to pull folders always: stop_logcat_script: | if [[ $(adb devices | awk 'NR>1 {print $1}') =~ "emulator.*" ]]; then diff --git a/adb-server/adb-server-common/src/main/java/com/kaspersky/adbserver/common/log/LoggerFactory.kt b/adb-server/adb-server-common/src/main/java/com/kaspersky/adbserver/common/log/LoggerFactory.kt index 36b1b5417..086907ea8 100644 --- a/adb-server/adb-server-common/src/main/java/com/kaspersky/adbserver/common/log/LoggerFactory.kt +++ b/adb-server/adb-server-common/src/main/java/com/kaspersky/adbserver/common/log/LoggerFactory.kt @@ -1,6 +1,7 @@ package com.kaspersky.adbserver.common.log import com.kaspersky.adbserver.common.log.filterlog.FullLoggerOptimiser +import com.kaspersky.adbserver.common.log.fulllogger.FullLogger import com.kaspersky.adbserver.common.log.fulllogger.FullLoggerSystemImpl import com.kaspersky.adbserver.common.log.logger.DesktopLogger import com.kaspersky.adbserver.common.log.logger.LogLevel @@ -12,8 +13,12 @@ import com.kaspersky.adbserver.common.log.logger.LoggerImpl */ object LoggerFactory { - fun getDesktopLogger(logLevel: LogLevel, desktopName: String): DesktopLogger { - val logger = getCommonLogger(logLevel, desktopName) + fun getDesktopLogger( + logLevel: LogLevel, + desktopName: String, + fullLogger: FullLogger = FullLoggerSystemImpl(logLevel, desktopName, null) + ): DesktopLogger { + val logger = getCommonLogger(logLevel, desktopName, fullLogger = fullLogger) return DesktopLogger(logger, logLevel, desktopName) } @@ -26,8 +31,12 @@ object LoggerFactory { fun getDeviceLogger(logLevel: LogLevel): Logger = getCommonLogger(logLevel) - private fun getCommonLogger(logLevel: LogLevel, desktopName: String? = null, deviceName: String? = null): Logger { - val fullLogger = FullLoggerSystemImpl(logLevel, desktopName, deviceName) + private fun getCommonLogger( + logLevel: LogLevel, + desktopName: String? = null, + deviceName: String? = null, + fullLogger: FullLogger = FullLoggerSystemImpl(logLevel, desktopName, deviceName) + ): Logger { val fullLoggerWrapper = if (logLevel == LogLevel.DEBUG) FullLoggerOptimiser(originalFullLogger = fullLogger, generateLogs = true) else fullLogger return LoggerImpl(fullLoggerWrapper) diff --git a/adb-server/adb-server-common/src/main/java/com/kaspersky/adbserver/common/log/fulllogger/FullLogger.kt b/adb-server/adb-server-common/src/main/java/com/kaspersky/adbserver/common/log/fulllogger/FullLogger.kt index 0be93c523..0efb9d7a6 100644 --- a/adb-server/adb-server-common/src/main/java/com/kaspersky/adbserver/common/log/fulllogger/FullLogger.kt +++ b/adb-server/adb-server-common/src/main/java/com/kaspersky/adbserver/common/log/fulllogger/FullLogger.kt @@ -2,7 +2,7 @@ package com.kaspersky.adbserver.common.log.fulllogger import com.kaspersky.adbserver.common.log.logger.LogLevel -internal interface FullLogger { +interface FullLogger { fun log( logLevel: LogLevel? = null, diff --git a/adb-server/adbserver-desktop/src/main/java/com/kaspersky/adbserver/desktop/AdbCommandPerformer.kt b/adb-server/adbserver-desktop/src/main/java/com/kaspersky/adbserver/desktop/AdbCommandPerformer.kt new file mode 100644 index 000000000..e9767b75f --- /dev/null +++ b/adb-server/adbserver-desktop/src/main/java/com/kaspersky/adbserver/desktop/AdbCommandPerformer.kt @@ -0,0 +1,21 @@ +package com.kaspersky.adbserver.desktop + +import com.kaspersky.adbserver.common.api.CommandResult +import java.nio.file.Path + +/** + * @param adbPath - path to adb binary + */ +class AdbCommandPerformer( + private val adbPath: Path, + private val cmdCommandPerformer: CmdCommandPerformer, +) { + + /** + * Be aware it's a synchronous method + * @param command - adb command without path to adb binaries + */ + fun perform(command: String): CommandResult { + return cmdCommandPerformer.perform("$adbPath $command") + } +} diff --git a/adb-server/adbserver-desktop/src/main/java/com/kaspersky/adbserver/desktop/CmdCommandPerformer.kt b/adb-server/adbserver-desktop/src/main/java/com/kaspersky/adbserver/desktop/CmdCommandPerformer.kt index 287b8c12f..1b328385f 100644 --- a/adb-server/adbserver-desktop/src/main/java/com/kaspersky/adbserver/desktop/CmdCommandPerformer.kt +++ b/adb-server/adbserver-desktop/src/main/java/com/kaspersky/adbserver/desktop/CmdCommandPerformer.kt @@ -2,10 +2,16 @@ package com.kaspersky.adbserver.desktop import com.kaspersky.adbserver.common.api.CommandResult import com.kaspersky.adbserver.common.api.ExecutorResultStatus +import java.io.File +import java.nio.file.Path import java.util.concurrent.TimeUnit -internal class CmdCommandPerformer( - private val desktopName: String +/** + * @param workingDir - working directory used to execute any cmd command if null when use default process working directory + */ +class CmdCommandPerformer( + private val desktopName: String, + private val workingDir: Path? = null ) { companion object { @@ -17,7 +23,8 @@ internal class CmdCommandPerformer( */ fun perform(command: String): CommandResult { val serviceInfo = "The command was executed on desktop=$desktopName" - val process = Runtime.getRuntime().exec(command) + val workingDir = workingDir?.toFile() ?: File(".") + val process = Runtime.getRuntime().exec(command, emptyArray(), workingDir) try { if (process.waitFor(EXECUTION_TIMEOUT_SECONDS, TimeUnit.SECONDS)) { val exitCode = process.exitValue() diff --git a/adb-server/adbserver-desktop/src/main/java/com/kaspersky/adbserver/desktop/CommandExecutorImpl.kt b/adb-server/adbserver-desktop/src/main/java/com/kaspersky/adbserver/desktop/CommandExecutorImpl.kt index 982aecf62..e3b6d1f58 100644 --- a/adb-server/adbserver-desktop/src/main/java/com/kaspersky/adbserver/desktop/CommandExecutorImpl.kt +++ b/adb-server/adbserver-desktop/src/main/java/com/kaspersky/adbserver/desktop/CommandExecutorImpl.kt @@ -10,6 +10,7 @@ import java.lang.UnsupportedOperationException internal class CommandExecutorImpl( private val cmdCommandPerformer: CmdCommandPerformer, + private val adbCommandPerformer: AdbCommandPerformer, private val deviceName: String, private val adbServerPort: String?, private val logger: Logger, @@ -20,9 +21,9 @@ internal class CommandExecutorImpl( return when (command) { is CmdCommand -> cmdCommandPerformer.perform(command.body) is AdbCommand -> { - val adbCommand = "$adbPath ${ adbServerPort?.let { "-P $adbServerPort " } ?: "" }-s $deviceName ${command.body}" - logger.d("The created adbCommand=$adbCommand") - cmdCommandPerformer.perform(adbCommand) + val adbCommand = "${ adbServerPort?.let { "-P $adbServerPort " } ?: "" }-s $deviceName ${command.body}" + logger.d("The created adbCommand=adb $adbCommand") + adbCommandPerformer.perform(adbCommand) } else -> throw UnsupportedOperationException("The command=$command is unsupported command") } diff --git a/adb-server/adbserver-desktop/src/main/java/com/kaspersky/adbserver/desktop/Desktop.kt b/adb-server/adbserver-desktop/src/main/java/com/kaspersky/adbserver/desktop/Desktop.kt index 84009fbb4..304205c2b 100644 --- a/adb-server/adbserver-desktop/src/main/java/com/kaspersky/adbserver/desktop/Desktop.kt +++ b/adb-server/adbserver-desktop/src/main/java/com/kaspersky/adbserver/desktop/Desktop.kt @@ -3,10 +3,13 @@ package com.kaspersky.adbserver.desktop import com.kaspersky.adbserver.common.api.ExecutorResultStatus import com.kaspersky.adbserver.common.log.LoggerFactory import com.kaspersky.adbserver.common.log.logger.DesktopLogger +import java.util.concurrent.atomic.AtomicBoolean import java.util.regex.Pattern +import kotlin.concurrent.thread -internal class Desktop( +class Desktop( private val cmdCommandPerformer: CmdCommandPerformer, + private val adbCommandPerformer: AdbCommandPerformer, private val presetEmulators: List, private val adbServerPort: String?, private val logger: DesktopLogger, @@ -15,13 +18,44 @@ internal class Desktop( companion object { private const val PAUSE_MS = 500L + private val DEVICE_PATTERN = Pattern.compile("^([a-zA-Z0-9\\-:.]+)(\\s+)(device)") } private val devices: MutableCollection = mutableListOf() + private var isRunning = AtomicBoolean(false) - fun startDevicesObserving() { + /** + * Start Desktop server. + * Blocking current thread while server working + * @throws IllegalStateException - if server already running + */ + fun startDevicesObservingSync() { + if (!isRunning.compareAndSet(false, true)) error("Desktop already running") + startDevicesObservingInternal() + } + + /** + * Start Desktop server asynchronously + * @throws IllegalStateException - if server already running + */ + fun startDevicesObservingAsync() { + if (!isRunning.compareAndSet(false, true)) error("Desktop already running") + thread { + startDevicesObservingInternal() + } + } + + /** + * Stop Desktop server + * @throws IllegalStateException - if server already stopped + */ + fun stopDevicesObserving() { + if (!isRunning.compareAndSet(true, false)) error("Desktop already stopped") + } + + private fun startDevicesObservingInternal() { logger.d("start") - while (true) { + while (isRunning.get()) { val namesOfAttachedDevicesByAdb = getAttachedDevicesByAdb() namesOfAttachedDevicesByAdb.forEach { deviceName -> if (devices.find { client -> client.deviceName == deviceName } == null) { @@ -29,6 +63,7 @@ internal class Desktop( val deviceMirror = DeviceMirror.create( cmdCommandPerformer, + adbCommandPerformer, deviceName, adbServerPort, LoggerFactory.getDesktopLoggerReflectingDevice(logger, deviceName), @@ -49,18 +84,22 @@ internal class Desktop( } Thread.sleep(PAUSE_MS) } + + devices.forEach { client -> + client.stopConnectionToDevice() + } + devices.clear() } private fun getAttachedDevicesByAdb(): List { - val pattern = Pattern.compile("^([a-zA-Z0-9\\-:.]+)(\\s+)(device)") - val commandResult = cmdCommandPerformer.perform("$adbPath devices") + val commandResult = adbCommandPerformer.perform("devices") if (commandResult.status != ExecutorResultStatus.SUCCESS) { return emptyList() } val adbDevicesCommandResult: String = commandResult.description return adbDevicesCommandResult.lines() .asSequence() - .map { pattern.matcher(it) } + .map { DEVICE_PATTERN.matcher(it) } .filter { matcher -> matcher.find() } .map { matcher -> matcher.group(1) } .filter { foundEmulator -> presetEmulators.isEmpty() || presetEmulators.contains(foundEmulator) } diff --git a/adb-server/adbserver-desktop/src/main/java/com/kaspersky/adbserver/desktop/DeviceMirror.kt b/adb-server/adbserver-desktop/src/main/java/com/kaspersky/adbserver/desktop/DeviceMirror.kt index a1bf608a3..15fb248d6 100644 --- a/adb-server/adbserver-desktop/src/main/java/com/kaspersky/adbserver/desktop/DeviceMirror.kt +++ b/adb-server/adbserver-desktop/src/main/java/com/kaspersky/adbserver/desktop/DeviceMirror.kt @@ -22,6 +22,7 @@ internal class DeviceMirror private constructor( fun create( cmdCommandPerformer: CmdCommandPerformer, + adbCommandPerformer: AdbCommandPerformer, deviceName: String, adbServerPort: String?, logger: Logger, @@ -31,6 +32,7 @@ internal class DeviceMirror private constructor( DesktopDeviceSocketConnectionFactory.getSockets(DesktopDeviceSocketConnectionType.FORWARD) val commandExecutor = CommandExecutorImpl( cmdCommandPerformer, + adbCommandPerformer, deviceName, adbServerPort, logger, diff --git a/adb-server/adbserver-desktop/src/main/java/com/kaspersky/adbserver/desktop/Main.kt b/adb-server/adbserver-desktop/src/main/java/com/kaspersky/adbserver/desktop/Main.kt index 3c5982ae4..bf55ad0a4 100644 --- a/adb-server/adbserver-desktop/src/main/java/com/kaspersky/adbserver/desktop/Main.kt +++ b/adb-server/adbserver-desktop/src/main/java/com/kaspersky/adbserver/desktop/Main.kt @@ -7,8 +7,11 @@ import kotlinx.cli.ArgType import kotlinx.cli.default import kotlinx.cli.delimiter import java.lang.management.ManagementFactory +import java.nio.file.Path private const val DESKTOP = "Desktop-" +private const val ERROR_EXIT_CODE = -1 + // It is assumed that adb is preinstall and available by "adb" keyword private const val DEFAULT_ADB_PATH = "adb" @@ -51,14 +54,16 @@ internal fun main(args: Array) { desktopLogger.i("Desktop started with arguments: emulators=$emulators, adbServerPort=$port, adbPath=$adbPath") val cmdCommandPerformer = CmdCommandPerformer(desktopName) + val adbCommandPerformer = AdbCommandPerformer(Path.of(adbPath), cmdCommandPerformer) val desktop = Desktop( cmdCommandPerformer = cmdCommandPerformer, + adbCommandPerformer = adbCommandPerformer, presetEmulators = emulators, adbServerPort = port, logger = desktopLogger, adbPath = adbPath ) - desktop.startDevicesObserving() + desktop.startDevicesObservingSync() } private fun getDesktopName(): String { diff --git a/build-logic/settings.gradle.kts b/build-logic/settings.gradle.kts index 9606505a4..b884978f2 100644 --- a/build-logic/settings.gradle.kts +++ b/build-logic/settings.gradle.kts @@ -1,5 +1,3 @@ -enableFeaturePreview("VERSION_CATALOGS") - rootProject.name = "build-logic" include("android") diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ae04661ee..774fae876 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/allure-support/NOTICE.txt b/kaspresso-allure-support/NOTICE.txt similarity index 100% rename from allure-support/NOTICE.txt rename to kaspresso-allure-support/NOTICE.txt diff --git a/allure-support/build.gradle.kts b/kaspresso-allure-support/build.gradle.kts similarity index 100% rename from allure-support/build.gradle.kts rename to kaspresso-allure-support/build.gradle.kts diff --git a/allure-support/src/main/AndroidManifest.xml b/kaspresso-allure-support/src/main/AndroidManifest.xml similarity index 100% rename from allure-support/src/main/AndroidManifest.xml rename to kaspresso-allure-support/src/main/AndroidManifest.xml diff --git a/allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/AllureSupportKaspressoBuilder.kt b/kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/AllureSupportKaspressoBuilder.kt similarity index 100% rename from allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/AllureSupportKaspressoBuilder.kt rename to kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/AllureSupportKaspressoBuilder.kt diff --git a/allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/files/AttachToReport.kt b/kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/files/AttachToReport.kt similarity index 100% rename from allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/files/AttachToReport.kt rename to kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/files/AttachToReport.kt diff --git a/allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/files/dirs/AllureDirsProvider.kt b/kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/files/dirs/AllureDirsProvider.kt similarity index 100% rename from allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/files/dirs/AllureDirsProvider.kt rename to kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/files/dirs/AllureDirsProvider.kt diff --git a/allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/files/resources/AllureResourcesRootDirsProvider.kt b/kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/files/resources/AllureResourcesRootDirsProvider.kt similarity index 100% rename from allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/files/resources/AllureResourcesRootDirsProvider.kt rename to kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/files/resources/AllureResourcesRootDirsProvider.kt diff --git a/allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/files/resources/impl/AllureResourceFilesProvider.kt b/kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/files/resources/impl/AllureResourceFilesProvider.kt similarity index 100% rename from allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/files/resources/impl/AllureResourceFilesProvider.kt rename to kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/files/resources/impl/AllureResourceFilesProvider.kt diff --git a/allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/files/resources/impl/DefaultAllureResourcesRootDirsProvider.kt b/kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/files/resources/impl/DefaultAllureResourcesRootDirsProvider.kt similarity index 100% rename from allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/files/resources/impl/DefaultAllureResourcesRootDirsProvider.kt rename to kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/files/resources/impl/DefaultAllureResourcesRootDirsProvider.kt diff --git a/allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/step/AllureMapperStepInterceptor.kt b/kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/step/AllureMapperStepInterceptor.kt similarity index 100% rename from allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/step/AllureMapperStepInterceptor.kt rename to kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/step/AllureMapperStepInterceptor.kt diff --git a/allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/step/ScreenshotStepInterceptor.kt b/kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/step/ScreenshotStepInterceptor.kt similarity index 100% rename from allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/step/ScreenshotStepInterceptor.kt rename to kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/step/ScreenshotStepInterceptor.kt diff --git a/allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/testrun/DumpLogcatTestInterceptor.kt b/kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/testrun/DumpLogcatTestInterceptor.kt similarity index 100% rename from allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/testrun/DumpLogcatTestInterceptor.kt rename to kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/testrun/DumpLogcatTestInterceptor.kt diff --git a/allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/testrun/DumpViewsTestInterceptor.kt b/kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/testrun/DumpViewsTestInterceptor.kt similarity index 100% rename from allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/testrun/DumpViewsTestInterceptor.kt rename to kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/testrun/DumpViewsTestInterceptor.kt diff --git a/allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/testrun/HackyVideoRecordingTestInterceptor.kt b/kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/testrun/HackyVideoRecordingTestInterceptor.kt similarity index 100% rename from allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/testrun/HackyVideoRecordingTestInterceptor.kt rename to kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/testrun/HackyVideoRecordingTestInterceptor.kt diff --git a/allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/testrun/ScreenshotTestInterceptor.kt b/kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/testrun/ScreenshotTestInterceptor.kt similarity index 100% rename from allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/testrun/ScreenshotTestInterceptor.kt rename to kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/testrun/ScreenshotTestInterceptor.kt diff --git a/allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/testrun/VideoRecordingTestInterceptor.kt b/kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/testrun/VideoRecordingTestInterceptor.kt similarity index 100% rename from allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/testrun/VideoRecordingTestInterceptor.kt rename to kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/interceptors/testrun/VideoRecordingTestInterceptor.kt diff --git a/allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/results/AllureResultInjector.kt b/kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/results/AllureResultInjector.kt similarity index 100% rename from allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/results/AllureResultInjector.kt rename to kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/results/AllureResultInjector.kt diff --git a/allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/results/AllureResultJsonParser.kt b/kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/results/AllureResultJsonParser.kt similarity index 100% rename from allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/results/AllureResultJsonParser.kt rename to kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/results/AllureResultJsonParser.kt diff --git a/allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/results/AllureResultsHack.kt b/kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/results/AllureResultsHack.kt similarity index 100% rename from allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/results/AllureResultsHack.kt rename to kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/results/AllureResultsHack.kt diff --git a/allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/runlisteners/AllureRunListener.kt b/kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/runlisteners/AllureRunListener.kt similarity index 100% rename from allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/runlisteners/AllureRunListener.kt rename to kaspresso-allure-support/src/main/kotlin/com/kaspersky/components/alluresupport/runlisteners/AllureRunListener.kt diff --git a/compose-support/NOTICE.txt b/kaspresso-compose-support/NOTICE.txt similarity index 100% rename from compose-support/NOTICE.txt rename to kaspresso-compose-support/NOTICE.txt diff --git a/compose-support/build.gradle.kts b/kaspresso-compose-support/build.gradle.kts similarity index 100% rename from compose-support/build.gradle.kts rename to kaspresso-compose-support/build.gradle.kts diff --git a/compose-support/src/main/AndroidManifest.xml b/kaspresso-compose-support/src/main/AndroidManifest.xml similarity index 100% rename from compose-support/src/main/AndroidManifest.xml rename to kaspresso-compose-support/src/main/AndroidManifest.xml diff --git a/compose-support/src/main/java/com/kaspersky/components/composesupport/autoscroll/SemanticsAutoScrollProviderImpl.kt b/kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/autoscroll/SemanticsAutoScrollProviderImpl.kt similarity index 100% rename from compose-support/src/main/java/com/kaspersky/components/composesupport/autoscroll/SemanticsAutoScrollProviderImpl.kt rename to kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/autoscroll/SemanticsAutoScrollProviderImpl.kt diff --git a/compose-support/src/main/java/com/kaspersky/components/composesupport/config/ComposeConfig.kt b/kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/config/ComposeConfig.kt similarity index 100% rename from compose-support/src/main/java/com/kaspersky/components/composesupport/config/ComposeConfig.kt rename to kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/config/ComposeConfig.kt diff --git a/compose-support/src/main/java/com/kaspersky/components/composesupport/config/ComposeInterceptorsInjector.kt b/kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/config/ComposeInterceptorsInjector.kt similarity index 100% rename from compose-support/src/main/java/com/kaspersky/components/composesupport/config/ComposeInterceptorsInjector.kt rename to kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/config/ComposeInterceptorsInjector.kt diff --git a/compose-support/src/main/java/com/kaspersky/components/composesupport/config/ComposeSupportKaspressoBuilder.kt b/kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/config/ComposeSupportKaspressoBuilder.kt similarity index 100% rename from compose-support/src/main/java/com/kaspersky/components/composesupport/config/ComposeSupportKaspressoBuilder.kt rename to kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/config/ComposeSupportKaspressoBuilder.kt diff --git a/compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/ComposeBehaviorInterceptor.kt b/kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/ComposeBehaviorInterceptor.kt similarity index 100% rename from compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/ComposeBehaviorInterceptor.kt rename to kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/ComposeBehaviorInterceptor.kt diff --git a/compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/SemanticsBehaviorInterceptor.kt b/kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/SemanticsBehaviorInterceptor.kt similarity index 100% rename from compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/SemanticsBehaviorInterceptor.kt rename to kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/SemanticsBehaviorInterceptor.kt diff --git a/compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/impl/autoscroll/AutoScrollSemanticsBehaviorInterceptor.kt b/kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/impl/autoscroll/AutoScrollSemanticsBehaviorInterceptor.kt similarity index 100% rename from compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/impl/autoscroll/AutoScrollSemanticsBehaviorInterceptor.kt rename to kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/impl/autoscroll/AutoScrollSemanticsBehaviorInterceptor.kt diff --git a/compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/impl/elementloader/ElementLoaderSemanticsBehaviorInterceptor.kt b/kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/impl/elementloader/ElementLoaderSemanticsBehaviorInterceptor.kt similarity index 100% rename from compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/impl/elementloader/ElementLoaderSemanticsBehaviorInterceptor.kt rename to kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/impl/elementloader/ElementLoaderSemanticsBehaviorInterceptor.kt diff --git a/compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/impl/failure/FailureLoggingSemanticsBehaviorInterceptor.kt b/kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/impl/failure/FailureLoggingSemanticsBehaviorInterceptor.kt similarity index 100% rename from compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/impl/failure/FailureLoggingSemanticsBehaviorInterceptor.kt rename to kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/impl/failure/FailureLoggingSemanticsBehaviorInterceptor.kt diff --git a/compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/impl/flakysafety/FlakySafeSemanticsBehaviorInterceptor.kt b/kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/impl/flakysafety/FlakySafeSemanticsBehaviorInterceptor.kt similarity index 100% rename from compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/impl/flakysafety/FlakySafeSemanticsBehaviorInterceptor.kt rename to kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/impl/flakysafety/FlakySafeSemanticsBehaviorInterceptor.kt diff --git a/compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/impl/systemsafety/SystemDialogSafetySemanticsBehaviorInterceptor.kt b/kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/impl/systemsafety/SystemDialogSafetySemanticsBehaviorInterceptor.kt similarity index 100% rename from compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/impl/systemsafety/SystemDialogSafetySemanticsBehaviorInterceptor.kt rename to kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/impl/systemsafety/SystemDialogSafetySemanticsBehaviorInterceptor.kt diff --git a/compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/tolibrary/ComposeSemanticsInterceptor.kt b/kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/tolibrary/ComposeSemanticsInterceptor.kt similarity index 100% rename from compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/tolibrary/ComposeSemanticsInterceptor.kt rename to kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/tolibrary/ComposeSemanticsInterceptor.kt diff --git a/compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/watcher/ComposeWatcherInterceptor.kt b/kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/watcher/ComposeWatcherInterceptor.kt similarity index 100% rename from compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/watcher/ComposeWatcherInterceptor.kt rename to kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/watcher/ComposeWatcherInterceptor.kt diff --git a/compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/watcher/SemanticsWatcherInterceptor.kt b/kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/watcher/SemanticsWatcherInterceptor.kt similarity index 100% rename from compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/watcher/SemanticsWatcherInterceptor.kt rename to kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/watcher/SemanticsWatcherInterceptor.kt diff --git a/compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/watcher/impl/LoggingSemanticsWatcherInterceptor.kt b/kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/watcher/impl/LoggingSemanticsWatcherInterceptor.kt similarity index 100% rename from compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/watcher/impl/LoggingSemanticsWatcherInterceptor.kt rename to kaspresso-compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/watcher/impl/LoggingSemanticsWatcherInterceptor.kt diff --git a/kaspresso-plugin/build.gradle.kts b/kaspresso-plugin/build.gradle.kts new file mode 100644 index 000000000..05576c741 --- /dev/null +++ b/kaspresso-plugin/build.gradle.kts @@ -0,0 +1,38 @@ +plugins { + `kotlin-dsl` + `java-gradle-plugin` + id("com.gradle.plugin-publish") version "1.2.1" +} + +dependencies { + implementation(libs.androidPlugin) + implementation(projects.adbServer.adbServerCommon) + implementation(projects.adbServer.adbserverDesktop) +} + +group = "com.kaspersky.kaspresso" +version = "1.0" +gradlePlugin { + // TODO: fix for tests on API 30 and uncomment + // website.set("https://kasperskylab.github.io/Kaspresso/en/") + // vcsUrl.set("https://github.com/KasperskyLab/Kaspresso/") + + plugins { + create("AdbServerPlugin") { + id = "com.kaspersky.kaspresso-adb-server-plugin" + displayName = "Kaspresso ADB-server plugin" + description = "Run Kaspresso ADB server for Android UI tests" + // tags.set(listOf("testing", "UI tests", "test automation", "android", "kasresso", "adb server")) + implementationClass = "com.kaspersky.kaspresso.plugin.KaspressoPlugin" + } + } +} + +publishing { + repositories { + maven { + name = "localPluginRepository" + url = uri("../local-plugin-repository") + } + } +} diff --git a/kaspresso-plugin/src/main/kotlin/com/kaspersky/kaspresso/plugin/DesktopServerHolder.kt b/kaspresso-plugin/src/main/kotlin/com/kaspersky/kaspresso/plugin/DesktopServerHolder.kt new file mode 100644 index 000000000..6066f5884 --- /dev/null +++ b/kaspresso-plugin/src/main/kotlin/com/kaspersky/kaspresso/plugin/DesktopServerHolder.kt @@ -0,0 +1,44 @@ +package com.kaspersky.kaspresso.plugin + +import com.kaspersky.adbserver.common.log.LoggerFactory +import com.kaspersky.adbserver.common.log.logger.LogLevel +import com.kaspersky.adbserver.desktop.AdbCommandPerformer +import com.kaspersky.adbserver.desktop.CmdCommandPerformer +import com.kaspersky.adbserver.desktop.Desktop +import org.gradle.api.logging.Logger +import java.nio.file.Path + +internal class DesktopServerHolder(private val logger: Logger) { + companion object { + private const val DESKTOP_NAME = "kaspresso-plugin-adb-server" + } + + private var desktop: Desktop? = null + + @Synchronized + fun start(workingDirectory: Path, adbPath: Path) { + check(desktop == null) { "Desktop already started" } + + logger.debug("Starting Desktop server. workingDir=$workingDirectory, adbPath=$adbPath") + + val cmdCommandPerformer = CmdCommandPerformer(DESKTOP_NAME, workingDirectory) + val adbCommandPerformer = AdbCommandPerformer(adbPath, cmdCommandPerformer) + val logger = LoggerFactory.getDesktopLogger(LogLevel.VERBOSE, DESKTOP_NAME, GradleFullLogger(logger)) + desktop = Desktop( + cmdCommandPerformer = cmdCommandPerformer, + adbCommandPerformer = adbCommandPerformer, + presetEmulators = emptyList(), + adbServerPort = null, + logger = logger, + adbPath = adbPath.toString() + ) + .apply { startDevicesObservingAsync() } + } + + @Synchronized + fun stop() { + check(desktop != null) { "Desktop not started" } + desktop!!.stopDevicesObserving() + desktop = null + } +} diff --git a/kaspresso-plugin/src/main/kotlin/com/kaspersky/kaspresso/plugin/GradleFullLogger.kt b/kaspresso-plugin/src/main/kotlin/com/kaspersky/kaspresso/plugin/GradleFullLogger.kt new file mode 100644 index 000000000..66ab8bf03 --- /dev/null +++ b/kaspresso-plugin/src/main/kotlin/com/kaspersky/kaspresso/plugin/GradleFullLogger.kt @@ -0,0 +1,21 @@ +package com.kaspersky.kaspresso.plugin + +import com.kaspersky.adbserver.common.log.fulllogger.FullLogger +import com.kaspersky.adbserver.common.log.logger.LogLevel +import org.gradle.api.logging.Logger +import org.gradle.api.logging.LogLevel as GradleLogLevel + +class GradleFullLogger(private val logger: Logger) : FullLogger { + override fun log(logLevel: LogLevel?, tag: String?, method: String?, text: String?) { + logger.log(logLevel.toGradleLogLevel(), "[$tag][$method]$text") + } +} + +private fun LogLevel?.toGradleLogLevel(): GradleLogLevel = when (this) { + null -> GradleLogLevel.LIFECYCLE + LogLevel.VERBOSE -> GradleLogLevel.LIFECYCLE + LogLevel.DEBUG -> GradleLogLevel.DEBUG + LogLevel.INFO -> GradleLogLevel.INFO + LogLevel.WARN -> GradleLogLevel.WARN + LogLevel.ERROR -> GradleLogLevel.ERROR +} diff --git a/kaspresso-plugin/src/main/kotlin/com/kaspersky/kaspresso/plugin/KaspressoExtension.kt b/kaspresso-plugin/src/main/kotlin/com/kaspersky/kaspresso/plugin/KaspressoExtension.kt new file mode 100644 index 000000000..d966f4d12 --- /dev/null +++ b/kaspresso-plugin/src/main/kotlin/com/kaspersky/kaspresso/plugin/KaspressoExtension.kt @@ -0,0 +1,13 @@ +package com.kaspersky.kaspresso.plugin + +import org.gradle.api.provider.Property +import java.nio.file.Path + +@Suppress("UnnecessaryAbstractClass") // gradle extensions can't be a interface +abstract class KaspressoExtension { + // by default using rootProject directory + abstract val workingDirectory: Property + + // by default use project.android.sdkDirectory/platform-tools/adb + abstract val adbPath: Property +} diff --git a/kaspresso-plugin/src/main/kotlin/com/kaspersky/kaspresso/plugin/KaspressoPlugin.kt b/kaspresso-plugin/src/main/kotlin/com/kaspersky/kaspresso/plugin/KaspressoPlugin.kt new file mode 100644 index 000000000..96c8bddaa --- /dev/null +++ b/kaspresso-plugin/src/main/kotlin/com/kaspersky/kaspresso/plugin/KaspressoPlugin.kt @@ -0,0 +1,72 @@ +package com.kaspersky.kaspresso.plugin + +import com.android.build.gradle.BasePlugin +import com.android.build.gradle.TestedExtension +import com.android.build.gradle.api.TestVariant +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.tasks.TaskProvider +import org.gradle.internal.os.OperatingSystem +import org.gradle.kotlin.dsl.create +import org.gradle.kotlin.dsl.withType + +class KaspressoPlugin : Plugin { + private lateinit var project: Project + + private lateinit var extension: KaspressoExtension + private lateinit var startServerTaskProvider: TaskProvider + private lateinit var stopServerTaskProvider: TaskProvider + private val desktopServerHolder by lazy { DesktopServerHolder(project.logger) } + + override fun apply(target: Project) { + project = target + + extension = project.extensions.create(EXTENSION_NAME) + extension.workingDirectory.convention(project.rootProject.projectDir.toPath()) + + // wait applying any android plugin + project.plugins.withType { + init() + } + } + + private fun init() { + val android = project.extensions.getByName("android") as TestedExtension + extension.adbPath.convention(project.provider { + val sdkDir = android.sdkDirectory.toPath() + val adbName = if (OperatingSystem.current() == OperatingSystem.WINDOWS) "adb.exe" else "adb" + sdkDir.resolve("platform-tools").resolve(adbName) + }) + + stopServerTaskProvider = project.tasks.register(STOP_ADB_SERVER_TASK_NAME) { + doLast { desktopServerHolder.stop() } + } + + startServerTaskProvider = project.tasks.register(START_ADB_SERVER_TASK_NAME) { + doLast { + desktopServerHolder.start( + workingDirectory = extension.workingDirectory.get(), + adbPath = extension.adbPath.get() + ) + } + finalizedBy(stopServerTaskProvider) + } + + android.testVariants.all(this::configureVariant) + } + + private fun configureVariant(testVariant: TestVariant) { + val connectedTestProvider = testVariant.connectedInstrumentTestProvider + connectedTestProvider.configure { + dependsOn(startServerTaskProvider) + finalizedBy(stopServerTaskProvider) + } + } + + companion object { + const val EXTENSION_NAME = "kaspresso" + const val START_ADB_SERVER_TASK_NAME = "kaspressoStartAdbServer" + const val STOP_ADB_SERVER_TASK_NAME = "kaspressoStopAdbServer" + } +} diff --git a/samples/adbserver-sample/build.gradle.kts b/samples/adbserver-sample/build.gradle.kts index 95453b4bc..708e10894 100644 --- a/samples/adbserver-sample/build.gradle.kts +++ b/samples/adbserver-sample/build.gradle.kts @@ -11,6 +11,6 @@ android { dependencies { implementation(libs.kotlinStdlib) implementation(libs.appcompat) - implementation(projects.adbServer.adbServerDevice) + implementation("com.kaspersky.android-components:adb-server-device") implementation(libs.multidex) } diff --git a/artifacts/hello_world.apk b/samples/artifacts/hello_world.apk similarity index 100% rename from artifacts/hello_world.apk rename to samples/artifacts/hello_world.apk diff --git a/artifacts/upgrade_test_v1.apk b/samples/artifacts/upgrade_test_v1.apk similarity index 100% rename from artifacts/upgrade_test_v1.apk rename to samples/artifacts/upgrade_test_v1.apk diff --git a/artifacts/upgrade_test_v2.apk b/samples/artifacts/upgrade_test_v2.apk similarity index 100% rename from artifacts/upgrade_test_v2.apk rename to samples/artifacts/upgrade_test_v2.apk diff --git a/samples/build.gradle.kts b/samples/build.gradle.kts new file mode 100644 index 000000000..bfe8cb930 --- /dev/null +++ b/samples/build.gradle.kts @@ -0,0 +1,12 @@ +plugins { + base + id("convention.air") +} + +buildscript { + dependencies { + classpath(libs.kotlinPlugin) + classpath(libs.androidPlugin) + classpath("com.kaspersky.kaspresso:kaspresso-plugin") + } +} diff --git a/samples/gradle.properties b/samples/gradle.properties new file mode 100644 index 000000000..bde4c2f88 --- /dev/null +++ b/samples/gradle.properties @@ -0,0 +1,7 @@ +org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 +org.gradle.parallel=true +org.gradle.caching=true + +kotlin.code.style=official + +android.useAndroidX = true diff --git a/samples/gradle/wrapper/gradle-wrapper.jar b/samples/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..249e5832f Binary files /dev/null and b/samples/gradle/wrapper/gradle-wrapper.jar differ diff --git a/samples/gradle/wrapper/gradle-wrapper.properties b/samples/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..ae04661ee --- /dev/null +++ b/samples/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/samples/gradlew b/samples/gradlew new file mode 100755 index 000000000..a69d9cb6c --- /dev/null +++ b/samples/gradlew @@ -0,0 +1,240 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/samples/gradlew.bat b/samples/gradlew.bat new file mode 100644 index 000000000..f127cfd49 --- /dev/null +++ b/samples/gradlew.bat @@ -0,0 +1,91 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/samples/kaspresso-allure-support-sample/build.gradle.kts b/samples/kaspresso-allure-support-sample/build.gradle.kts index 007cb3e9e..1622d2866 100644 --- a/samples/kaspresso-allure-support-sample/build.gradle.kts +++ b/samples/kaspresso-allure-support-sample/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("convention.android-app") + id("com.kaspersky.kaspresso-adb-server-plugin") } android { @@ -26,8 +27,8 @@ dependencies { androidTestImplementation("com.kaspersky.android-components:kaspresso:$kaspressoVersion") androidTestImplementation("com.kaspersky.android-components:kaspresso-allure-support:$kaspressoVersion") } else { - androidTestImplementation(projects.kaspresso) - androidTestImplementation(projects.allureSupport) + androidTestImplementation("com.kaspersky.android-components:kaspresso") + androidTestImplementation("com.kaspersky.android-components:kaspresso-allure-support") } androidTestImplementation(libs.androidXTestExtJunitKtx) diff --git a/samples/kaspresso-compose-support-sample/build.gradle.kts b/samples/kaspresso-compose-support-sample/build.gradle.kts index 6469c4b2d..09578181c 100644 --- a/samples/kaspresso-compose-support-sample/build.gradle.kts +++ b/samples/kaspresso-compose-support-sample/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("convention.android-app") + id("com.kaspersky.kaspresso-adb-server-plugin") } android { @@ -60,10 +61,10 @@ dependencies { androidTestImplementation("com.kaspersky.android-components:kaspresso:$kaspressoVersion") androidTestImplementation("com.kaspersky.android-components:kaspresso-compose-support:$kaspressoVersion") } else { - testImplementation(projects.kaspresso) - testImplementation(projects.composeSupport) - androidTestImplementation(projects.kaspresso) - androidTestImplementation(projects.composeSupport) + testImplementation("com.kaspersky.android-components:kaspresso") + testImplementation("com.kaspersky.android-components:kaspresso-compose-support") + androidTestImplementation("com.kaspersky.android-components:kaspresso") + androidTestImplementation("com.kaspersky.android-components:kaspresso-compose-support") } androidTestImplementation(libs.androidXTestRunner) diff --git a/samples/kaspresso-sample/build.gradle.kts b/samples/kaspresso-sample/build.gradle.kts index a41e8c880..7beea3ac8 100644 --- a/samples/kaspresso-sample/build.gradle.kts +++ b/samples/kaspresso-sample/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("convention.android-app") + id("com.kaspersky.kaspresso-adb-server-plugin") } android { @@ -47,8 +48,8 @@ dependencies { testImplementation("com.kaspersky.android-components:kaspresso:$kaspressoVersion") androidTestImplementation("com.kaspersky.android-components:kaspresso:$kaspressoVersion") } else { - androidTestImplementation(projects.kaspresso) - testImplementation(projects.kaspresso) + androidTestImplementation("com.kaspersky.android-components:kaspresso") + testImplementation("com.kaspersky.android-components:kaspresso") } androidTestImplementation(libs.androidXTestRunner) diff --git a/samples/kautomator-sample-app-upgrade/build.gradle.kts b/samples/kautomator-sample-app-upgrade/build.gradle.kts index fe0c2d170..21e5fb185 100644 --- a/samples/kautomator-sample-app-upgrade/build.gradle.kts +++ b/samples/kautomator-sample-app-upgrade/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("convention.android-app") + id("com.kaspersky.kaspresso-adb-server-plugin") } android { @@ -14,5 +15,5 @@ dependencies { implementation(libs.material) implementation(libs.multidex) - androidTestImplementation(projects.kaspresso) + androidTestImplementation("com.kaspersky.android-components:kaspresso") } diff --git a/samples/kautomator-sample/build.gradle.kts b/samples/kautomator-sample/build.gradle.kts index 603d32972..dd03d1794 100644 --- a/samples/kautomator-sample/build.gradle.kts +++ b/samples/kautomator-sample/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("convention.android-app") + id("com.kaspersky.kaspresso-adb-server-plugin") } android { @@ -20,7 +21,7 @@ dependencies { implementation(libs.constraint) implementation(libs.multidex) - androidTestImplementation(projects.kaspresso) + androidTestImplementation("com.kaspersky.android-components:kaspresso") androidTestImplementation(libs.androidXTestExtJunitKtx) androidTestImplementation(libs.androidXTestExtJunit) diff --git a/samples/settings.gradle.kts b/samples/settings.gradle.kts new file mode 100644 index 000000000..afb35f01f --- /dev/null +++ b/samples/settings.gradle.kts @@ -0,0 +1,35 @@ +enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") + +pluginManagement { + repositories { + gradlePluginPortal() + google() + } +} + +@Suppress("UnstableApiUsage") +dependencyResolutionManagement { + versionCatalogs { + create("libs") { + from(files("../gradle/libs.versions.toml")) + } + } + + repositories { + mavenCentral() + mavenLocal() + google() + maven { url = uri("https://kotlin.bintray.com/kotlinx") } + } +} + +includeBuild("../") + +include( + ":adbserver-sample", + ":kaspresso-sample", + ":kautomator-sample", + ":kautomator-sample-app-upgrade", + ":kaspresso-allure-support-sample", + ":kaspresso-compose-support-sample", +) diff --git a/settings.gradle.kts b/settings.gradle.kts index f334765f9..4878372b0 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,6 +1,5 @@ rootProject.name = "kaspresso-framework" -enableFeaturePreview("VERSION_CATALOGS") enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") pluginManagement { @@ -35,15 +34,9 @@ include( ":kaspresso", ":kautomator", - ":allure-support", - ":compose-support", - - ":samples:adbserver-sample", - ":samples:kaspresso-sample", - ":samples:kautomator-sample", - ":samples:kautomator-sample-app-upgrade", - ":samples:kaspresso-allure-support-sample", - ":samples:kaspresso-compose-support-sample", + ":kaspresso-allure-support", + ":kaspresso-compose-support", + ":kaspresso-plugin", ":tutorial" )