Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(vendor-junit4): initial junit4 version #577

Draft
wants to merge 25 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
5cb3d92
feat(vendor-junit4): initial implementation
Malinskiy Feb 18, 2021
ccbf2f8
feat(vendor-junit4): add sample project + implement test listener via…
Malinskiy Feb 19, 2021
2d686ee
feat(vendor-junit4): rework device to support long living java process
Malinskiy May 30, 2021
a50c814
feat(vendor-junit4): update junit to 4.13.2
Malinskiy Jun 4, 2021
03f0efa
Merge branch 'develop' into feat/vendor-junit4
Malinskiy Jun 4, 2021
ab0be63
feat(junit4): add gradle plugin marathon-junit4 + passing classpath
Malinskiy Jun 4, 2021
7b34520
feat(junit4): junit5 vintage parser + parameterized runners
Malinskiy Jun 13, 2021
f963751
feat(junit4): add debug booter option and require a test package root
Malinskiy Jun 14, 2021
56a16a7
Merge branch 'develop' into feat/vendor-junit4
Malinskiy Aug 3, 2021
e7e3182
feat(all): merge with develop
Malinskiy Aug 3, 2021
cf783eb
fix(junit4): passthrough for deviceInitializationTimeoutMillis
Malinskiy Aug 4, 2021
7de22d8
fix(junit4): multiple fixes
Malinskiy Aug 7, 2021
59438e2
Merge branch 'feature/device-test-parser' into feat/vendor-junit4
Malinskiy Aug 13, 2021
4837181
fix(junit4): paralellize parsing using multiple booter instances
Malinskiy Aug 14, 2021
24c8473
feat(junit4): separate executor from booter
Malinskiy Aug 26, 2021
36e7be4
feat(vendor-junit4): full isolation
Malinskiy Sep 1, 2021
9f04e9d
fix(vendor-junit4): termination fixes
Malinskiy Sep 2, 2021
6b49eac
feat(vendor-junit4): optional workdir support, classpath jar for long…
Malinskiy Sep 3, 2021
c383b31
Merge branch 'develop' into feat/vendor-junit4
Malinskiy Sep 13, 2021
d0c8eff
fix(vendor-junit4): merge with develop
Malinskiy Sep 13, 2021
42bb3c6
feat(vendor-junit4): add tests
Malinskiy Sep 21, 2021
87d83b3
test(vendor-junit4): fix leaking process in test
Malinskiy Sep 21, 2021
2840796
fix(vendor-junit4): remove redundant parameters + cleanup
Malinskiy Sep 21, 2021
3159731
feat(vendor-junit4): added integration test cases
Malinskiy Sep 23, 2021
9457e77
fix(vendor-junit4): collect annotations on tests into test meta prope…
Malinskiy Sep 23, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion buildSrc/src/main/kotlin/Versions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,26 @@ object Versions {
val logbackClassic = "1.2.3"
val axmlParser = "1.0"
val bugsnag = "3.6.2"
val asm = "9.1"
val clikt = "3.1.0"

val grpc = "1.34.1"
val grpcKotlin = "1.0.0"
val protobufGradle = "0.8.14"
val protobuf = "3.14.0"

val junitGradle = "1.2.0"
val androidGradleVersion = "4.0.0"

val junit5 = "5.7.2"
val junit5launcher = "1.7.2"
val kluent = "1.65"

val kakao = "3.0.2"
val espresso = "3.0.1"
val espressoRules = "1.0.1"
val espressoRunner = "1.0.1"
val junit = "4.12"
val junit = "4.13.2"
val gson = "2.8.8"
val apacheCommonsText = "1.9"
val apacheCommonsIO = "2.9.0"
Expand Down Expand Up @@ -92,10 +100,18 @@ object Libraries {
val allureKotlinCommons = "io.qameta.allure:allure-kotlin-commons:${Versions.allureKotlin}"
val koin = "io.insert-koin:koin-core:${Versions.koin}"
val bugsnag = "com.bugsnag:bugsnag:${Versions.bugsnag}"
val asm = "org.ow2.asm:asm:${Versions.asm}"
val clikt = "com.github.ajalt.clikt:clikt:${Versions.clikt}"
val protobufLite = "com.google.protobuf:protobuf-javalite:${Versions.protobuf}"
val grpcKotlinStubLite = "io.grpc:grpc-kotlin-stub-lite:${Versions.grpcKotlin}"
val grpcOkhttp = "io.grpc:grpc-okhttp:${Versions.grpc}"
val grpcNetty = "io.grpc:grpc-netty:${Versions.grpc}"
}

object TestLibraries {
val junit5 = "org.junit.jupiter:junit-jupiter:${Versions.junit5}"
val junit5vintage = "org.junit.vintage:junit-vintage-engine:${Versions.junit5}"
val junit5launcher = "org.junit.platform:junit-platform-launcher:${Versions.junit5launcher}"
val kluent = "org.amshove.kluent:kluent:${Versions.kluent}"
val kakao = "io.github.kakaocup:kakao:${Versions.kakao}"

Expand Down
1 change: 1 addition & 0 deletions cli/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ dependencies {
implementation(project(":vendor:vendor-android:base"))
implementation(project(":vendor:vendor-android:ddmlib"))
implementation(project(":vendor:vendor-android:adam"))
implementation(project(":vendor:vendor-junit4:vendor-junit4-core"))
implementation(project(":analytics:usage"))
implementation(Libraries.kotlinStdLib)
implementation(Libraries.kotlinCoroutines)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ fun main(args: Array<String>): Unit = mainBody(
.registerModule(JavaTimeModule())
val configuration = ConfigFactory(mapper).create(
marathonfile = marathonfile,
environmentReader = SystemEnvironmentReader()
environmentReader = SystemEnvironmentReader(),
)

val application = marathonStartKoin(configuration)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ package com.malinskiy.marathon.cli.args

import java.io.File

data class EnvironmentConfiguration(val androidSdk: File?)
data class EnvironmentConfiguration(val androidSdk: File?, val javaHome: File?)
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.malinskiy.marathon.cli.args

import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import com.malinskiy.marathon.vendor.junit4.configuration.Junit4Configuration
import com.malinskiy.marathon.vendor.junit4.configuration.executor.ExecutorConfiguration
import com.malinskiy.marathon.vendor.junit4.model.JUnit4TestBundle
import java.io.File


class FileJUnit4Configuration(
@JsonProperty("applicationClasspath") val applicationClasspath: List<File>?,
@JsonProperty("testClasspath") val testClasspath: List<File>?,
@JsonProperty("testPackageRoot") val testPackageRoot: String,
@JsonProperty("source") val source: File? = null,
@JsonProperty("forkEvery") val forkEvery: Int = 1000,
@JsonProperty("debugBooter") val debugBooter: Boolean = false,
@JsonProperty("executorConfiguration") val executorConfiguration: ExecutorConfiguration,

) : FileVendorConfiguration {

fun toJUnit4Configuration(
mapper: ObjectMapper,
javaHome: File?
): Junit4Configuration {
val testBundles = mutableListOf<JUnit4TestBundle>()

source?.let { folder ->
for (file in folder.walkTopDown()) {
if (file.isFile) {
val subconfig = mapper.readValue<FileJUnit4ModuleConfiguration>(file.readText())
testBundles.add(
JUnit4TestBundle(
file.name,
applicationClasspath = subconfig.applicationClasspath,
testClasspath = subconfig.testClasspath,
workdir = subconfig.workdir,
)
)
}
}
}

return Junit4Configuration(
applicationClasspath = mutableListOf<File>().apply {
[email protected]?.let { addAll(it) }
applicationClasspath?.let { addAll(it) }
},
testClasspath = mutableListOf<File>().apply {
[email protected]?.let { addAll(it) }
testClasspath?.let { addAll(it) }
},
testPackageRoot = testPackageRoot,
testBundles = testBundles.toList(),
forkEvery = forkEvery,
debugBooter = debugBooter,
executorConfiguration = executorConfiguration,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.malinskiy.marathon.cli.args

import com.fasterxml.jackson.annotation.JsonProperty
import java.io.File

class FileJUnit4ModuleConfiguration(
@JsonProperty("workdir") val workdir: String?,
@JsonProperty("applicationClasspath") val applicationClasspath: List<File>?,
@JsonProperty("testClasspath") val testClasspath: List<File>?,
)
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ import com.malinskiy.marathon.cli.args.EnvironmentConfiguration
import java.io.File

class SystemEnvironmentReader(
private val environment: (String) -> String? = { System.getenv(it) }
private val environment: (String) -> String? = { System.getenv(it) },
) : EnvironmentReader {
override fun read() = EnvironmentConfiguration(
androidSdk = androidSdkPath()?.let { File(it) }
androidSdk = androidSdkPath()?.let { File(it) },
javaHome = javaHomePath()?.let { File(it) },
)

private fun androidSdkPath() =
environment("ANDROID_HOME") ?: environment("ANDROID_SDK_ROOT")

private fun javaHomePath() = environment("JAVA_HOME")
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
import com.malinskiy.marathon.cli.args.FileAndroidConfiguration
import com.malinskiy.marathon.cli.args.FileConfiguration
import com.malinskiy.marathon.cli.args.FileIOSConfiguration
import com.malinskiy.marathon.cli.args.FileJUnit4Configuration
import com.malinskiy.marathon.cli.args.environment.EnvironmentReader
import com.malinskiy.marathon.exceptions.ConfigurationException
import com.malinskiy.marathon.execution.Configuration
Expand All @@ -19,7 +20,10 @@ private val logger = MarathonLogging.logger {}
class ConfigFactory(private val mapper: ObjectMapper) {
private val environmentVariableSubstitutor = StringSubstitutor(StringLookupFactory.INSTANCE.environmentVariableStringLookup())

fun create(marathonfile: File, environmentReader: EnvironmentReader): Configuration {
fun create(
marathonfile: File,
environmentReader: EnvironmentReader,
): Configuration {
logger.info { "Checking $marathonfile config" }

if (!marathonfile.isFile) {
Expand All @@ -37,6 +41,12 @@ class ConfigFactory(private val mapper: ObjectMapper) {
is FileAndroidConfiguration -> {
fileVendorConfiguration.toAndroidConfiguration(environmentReader.read().androidSdk)
}
is FileJUnit4Configuration -> {
fileVendorConfiguration.toJUnit4Configuration(
mapper,
environmentReader.read().javaHome
)
}
else -> throw ConfigurationException("No vendor config present in ${marathonfile.absolutePath}")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.malinskiy.marathon.cli.args.FileVendorConfiguration
import com.malinskiy.marathon.cli.config.deserialize.AnalyticsConfigurationDeserializer
import com.malinskiy.marathon.cli.config.deserialize.BatchingStrategyDeserializer
import com.malinskiy.marathon.cli.config.deserialize.ExecutionTimeSortingStrategyDeserializer
import com.malinskiy.marathon.cli.config.deserialize.FileJUnit4ExecutorConfigurationDeserializer
import com.malinskiy.marathon.cli.config.deserialize.FileVendorConfigurationDeserializer
import com.malinskiy.marathon.cli.config.deserialize.FixedSizeBatchingStrategyDeserializer
import com.malinskiy.marathon.cli.config.deserialize.FlakinessStrategyDeserializer
Expand All @@ -31,6 +32,7 @@ import com.malinskiy.marathon.execution.strategy.SortingStrategy
import com.malinskiy.marathon.execution.strategy.impl.batching.FixedSizeBatchingStrategy
import com.malinskiy.marathon.execution.strategy.impl.flakiness.ProbabilityBasedFlakinessStrategy
import com.malinskiy.marathon.execution.strategy.impl.sorting.ExecutionTimeSortingStrategy
import com.malinskiy.marathon.vendor.junit4.configuration.executor.ExecutorConfiguration

class DeserializeModule(instantTimeProvider: InstantTimeProvider) : SimpleModule() {
init {
Expand Down Expand Up @@ -62,5 +64,6 @@ class DeserializeModule(instantTimeProvider: InstantTimeProvider) : SimpleModule
addDeserializer(TestFilter::class.java, TestFilterDeserializer())
addDeserializer(FileVendorConfiguration::class.java, FileVendorConfigurationDeserializer())
addDeserializer(ScreenRecordingPolicy::class.java, ScreenRecordingPolicyDeserializer())
addDeserializer(ExecutorConfiguration::class.java, FileJUnit4ExecutorConfigurationDeserializer())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.malinskiy.marathon.cli.config.deserialize

import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.deser.std.StdDeserializer
import com.fasterxml.jackson.databind.node.ObjectNode
import com.fasterxml.jackson.module.kotlin.treeToValue
import com.malinskiy.marathon.exceptions.ConfigurationException
import com.malinskiy.marathon.vendor.junit4.configuration.executor.DockerExecutorConfiguration
import com.malinskiy.marathon.vendor.junit4.configuration.executor.ExecutorConfiguration
import com.malinskiy.marathon.vendor.junit4.configuration.executor.KubernetesExecutorConfiguration
import com.malinskiy.marathon.vendor.junit4.configuration.executor.LocalExecutorConfiguration

const val TYPE_LOCAL = "local"
const val TYPE_DOCKER = "docker"
const val TYPE_KUBERNETES = "kubernetes"

class FileJUnit4ExecutorConfigurationDeserializer : StdDeserializer<ExecutorConfiguration>(ExecutorConfiguration::class.java) {
override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): ExecutorConfiguration {
val codec = p?.codec as ObjectMapper
val node: JsonNode = codec.readTree(p) ?: throw ConfigurationException("Missing JUnit4 executor configuration")
val type = node.get("type").asText()

return when (type) {
TYPE_LOCAL -> {
(node as ObjectNode).remove("type")
codec.treeToValue<LocalExecutorConfiguration>(node) ?: throw ConfigurationException("Missing executor configuration")
}
TYPE_DOCKER -> {
(node as ObjectNode).remove("type")
codec.treeToValue<DockerExecutorConfiguration>(node) ?: throw ConfigurationException("Missing executor configuration")
}
TYPE_KUBERNETES -> {
(node as ObjectNode).remove("type")
codec.treeToValue<KubernetesExecutorConfiguration>(node) ?: throw ConfigurationException("Missing executor configuration")
}
else -> throw ConfigurationException(
"Unrecognized executor type $type. " +
"Valid options are $TYPE_LOCAL, $TYPE_DOCKER and $TYPE_KUBERNETES"
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import com.fasterxml.jackson.databind.node.ObjectNode
import com.fasterxml.jackson.module.kotlin.treeToValue
import com.malinskiy.marathon.cli.args.FileAndroidConfiguration
import com.malinskiy.marathon.cli.args.FileIOSConfiguration
import com.malinskiy.marathon.cli.args.FileJUnit4Configuration
import com.malinskiy.marathon.cli.args.FileVendorConfiguration
import com.malinskiy.marathon.exceptions.ConfigurationException

const val TYPE_ANDROID = "Android"
const val TYPE_IOS = "iOS"
const val TYPE_JUnit4 = "JUnit4"

class FileVendorConfigurationDeserializer : StdDeserializer<FileVendorConfiguration>(FileVendorConfiguration::class.java) {
override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): FileVendorConfiguration {
Expand All @@ -30,9 +32,13 @@ class FileVendorConfigurationDeserializer : StdDeserializer<FileVendorConfigurat
(node as ObjectNode).remove("type")
codec.treeToValue<FileAndroidConfiguration>(node) ?: throw ConfigurationException("Missing vendor configuration")
}
TYPE_JUnit4 -> {
(node as ObjectNode).remove("type")
codec.treeToValue<FileJUnit4Configuration>(node) ?: throw ConfigurationException("Missing vendor configuration")
}
else -> throw ConfigurationException(
"Unrecognized vendor type $type. " +
"Valid options are $TYPE_ANDROID and $TYPE_IOS"
"Valid options are $TYPE_ANDROID and $TYPE_IOS"
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package com.malinskiy.marathon.cli.args
import java.io.File

fun environmentConfiguration(
androidSdk: File? = null
androidSdk: File? = null,
javaHome: File? = null,
) = EnvironmentConfiguration(
androidSdk = androidSdk
androidSdk = androidSdk,
javaHome = javaHome,
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ package com.malinskiy.marathon.cli.args.environment

import com.malinskiy.marathon.cli.args.EnvironmentConfiguration
import com.malinskiy.marathon.cli.args.environmentConfiguration
import com.nhaarman.mockitokotlin2.whenever
import com.nhaarman.mockitokotlin2.mock
import org.amshove.kluent.shouldBe
import com.nhaarman.mockitokotlin2.whenever
import org.amshove.kluent.shouldBeEqualTo
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
Expand Down
Loading