Skip to content

Commit

Permalink
Modernise DSL
Browse files Browse the repository at this point in the history
  • Loading branch information
Sergey Chelombitko committed Jul 31, 2024
1 parent 7a28dee commit 69fe63b
Show file tree
Hide file tree
Showing 28 changed files with 478 additions and 350 deletions.
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ allprojects {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_17)
freeCompilerArgs.addAll(
"-Xjvm-default=all",
"-opt-in=kotlin.RequiresOptIn"
)
}
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/kotlin/com/malinskiy/marathon/Marathon.kt
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class Marathon(
private val logger = MarathonLogging.logger("Marathon")

private val configurationValidator = LogicalConfigurationValidator()
private val strictRunProcessor = StrictRunProcessor(configuration.strictRunFilterConfiguration)
private val strictRunProcessor = StrictRunProcessor(configuration.strictRunConfiguration)

private lateinit var scheduler: Scheduler
private lateinit var hook: ShutdownHook
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ internal class TrackerFactory(

track + mappingTracker
track + cacheTestResultsTracker
configuration.customAnalyticsTracker?.let { track + it }
configuration.analyticsTracker?.let { track + it }

return delegatingTrackerInternal
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class TestCacheLoader(
if (configuration.cache.isEnabled) {
val testCacheBlackList: MutableList<Test> = arrayListOf()
tests.tests.forEach { test ->
if (configuration.strictRunFilterConfiguration.filter.matches(test)) {
if (configuration.strictRunConfiguration.filter.matches(test)) {
testCacheBlackList.add(test)
} else {
testsToCheck.send(TestToCheck(poolId, test, isStrictRun = false))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,117 +19,117 @@ import java.io.File
private const val DEFAULT_NO_DEVICES_TIMEOUT_MILLIS: Long = 300_000
private const val DEFAULT_OUTPUT_TIMEOUT_MILLIS: Long = 60_000

data class Configuration constructor(
data class Configuration(
val outputDir: File,

val customAnalyticsTracker: Tracker?,
val cache: CacheConfiguration,
val poolingStrategy: PoolingStrategy,
val shardingStrategy: ShardingStrategy,
val sortingStrategy: SortingStrategy,
val batchingStrategy: BatchingStrategy,
val flakinessStrategy: FlakinessStrategy,
val retryStrategy: RetryStrategy,
val filteringConfiguration: FilteringConfiguration,
val strictRunFilterConfiguration: StrictRunFilterConfiguration,
val listener: MarathonListener?,
val strictRunConfiguration: StrictRunConfiguration,

val cache: CacheConfiguration,
val debug: Boolean,
val ignoreFailures: Boolean,
val strictMode: Boolean,
val uncompletedTestRetryQuota: Int,

val testClassRegexes: Collection<Regex>,
val includeSerialRegexes: Collection<Regex>,
val excludeSerialRegexes: Collection<Regex>,
val testClassRegexes: Collection<Regex>,
val ignoreFailureRegexes: Collection<Regex>,
val failFastFailureRegexes: Collection<Regex>,

val testOutputTimeoutMillis: Long,
val noDevicesTimeoutMillis: Long,
val debug: Boolean,

val analyticsTracker: Tracker?,
val listener: MarathonListener?,
val vendorConfiguration: VendorConfiguration
) {

constructor(
outputDir: File,

customAnalyticsTracker: Tracker?,
cache: CacheConfiguration?,
poolingStrategy: PoolingStrategy?,
shardingStrategy: ShardingStrategy?,
sortingStrategy: SortingStrategy?,
batchingStrategy: BatchingStrategy?,
flakinessStrategy: FlakinessStrategy?,
retryStrategy: RetryStrategy?,
filteringConfiguration: FilteringConfiguration?,
strictRunFilterConfiguration: StrictRunFilterConfiguration?,
listener: MarathonListener?,
strictRunConfiguration: StrictRunConfiguration?,

cache: CacheConfiguration?,
debug: Boolean?,
ignoreFailures: Boolean?,
strictMode: Boolean?,
uncompletedTestRetryQuota: Int?,

testClassRegexes: Collection<Regex>?,
includeSerialRegexes: Collection<Regex>?,
excludeSerialRegexes: Collection<Regex>?,
testClassRegexes: Collection<Regex>?,
ignoreFailureRegexes: Collection<Regex>?,
failFastFailureRegexes: Collection<Regex>?,

testOutputTimeoutMillis: Long?,
noDevicesTimeoutMillis: Long?,
debug: Boolean?,

analyticsTracker: Tracker?,
listener: MarathonListener?,
vendorConfiguration: VendorConfiguration
) :

this(
outputDir = outputDir,
customAnalyticsTracker = customAnalyticsTracker,
cache = cache ?: CacheConfiguration(),
poolingStrategy = poolingStrategy ?: OmniPoolingStrategy(),
shardingStrategy = shardingStrategy ?: ParallelShardingStrategy(),
sortingStrategy = sortingStrategy ?: NoSortingStrategy(),
batchingStrategy = batchingStrategy ?: IsolateBatchingStrategy(),
flakinessStrategy = flakinessStrategy ?: IgnoreFlakinessStrategy(),
retryStrategy = retryStrategy ?: NoRetryStrategy(),
filteringConfiguration = filteringConfiguration ?: FilteringConfiguration(emptyList(), emptyList()),
strictRunFilterConfiguration = strictRunFilterConfiguration ?: StrictRunFilterConfiguration(emptyList()),
cache = cache ?: CacheConfiguration(),
filteringConfiguration = filteringConfiguration ?: FilteringConfiguration(),
strictRunConfiguration = strictRunConfiguration ?: StrictRunConfiguration(),
debug = debug ?: true,
ignoreFailures = ignoreFailures ?: false,
strictMode = strictMode ?: false,
listener = listener,
uncompletedTestRetryQuota = uncompletedTestRetryQuota ?: Integer.MAX_VALUE,
testClassRegexes = testClassRegexes ?: listOf(Regex("^((?!Abstract).)*Test$")),
includeSerialRegexes = includeSerialRegexes ?: emptyList(),
excludeSerialRegexes = excludeSerialRegexes ?: emptyList(),
testClassRegexes = testClassRegexes ?: listOf(Regex("^((?!Abstract).)*Test$")),
ignoreFailureRegexes = ignoreFailureRegexes ?: emptyList(),
failFastFailureRegexes = failFastFailureRegexes ?: emptyList(),
testOutputTimeoutMillis = testOutputTimeoutMillis ?: DEFAULT_OUTPUT_TIMEOUT_MILLIS,
noDevicesTimeoutMillis = noDevicesTimeoutMillis ?: DEFAULT_NO_DEVICES_TIMEOUT_MILLIS,
debug = debug ?: true,
analyticsTracker = analyticsTracker,
listener = listener,
vendorConfiguration = vendorConfiguration
)

fun toMap() =
mapOf<String, String>(
"outputDir" to outputDir.absolutePath,
"cache" to cache.toString(),
"pooling" to poolingStrategy.toString(),
"sharding" to shardingStrategy.toString(),
"sorting" to sortingStrategy.toString(),
"batching" to batchingStrategy.toString(),
"flakiness" to flakinessStrategy.toString(),
"retry" to retryStrategy.toString(),
"filtering" to filteringConfiguration.toString(),
"strictRunFilter" to strictRunFilterConfiguration.toString(),
"cache" to cache.toString(),
"strictRun" to strictRunConfiguration.toString(),
"debug" to debug.toString(),
"ignoreFailures" to ignoreFailures.toString(),
"strictMode" to strictMode.toString(),
"testClassRegexes" to testClassRegexes.toString(),
"includeSerialRegexes" to includeSerialRegexes.toString(),
"excludeSerialRegexes" to excludeSerialRegexes.toString(),
"testClassRegexes" to testClassRegexes.toString(),
"testOutputTimeoutMillis" to testOutputTimeoutMillis.toString(),
"noDevicesTimeoutMillis" to noDevicesTimeoutMillis.toString(),
"debug" to debug.toString(),
"vendorConfiguration" to vendorConfiguration.toString()
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface StrictRunChecker {
class ConfigurationStrictRunChecker(private val configuration: Configuration) : StrictRunChecker {

override fun isStrictRun(test: Test): Boolean =
configuration.strictMode || configuration.strictRunFilterConfiguration.filter.matches(test)
configuration.strictMode || configuration.strictRunConfiguration.filter.matches(test)

override fun hasFailFastFailures(stackTrace: String?): Boolean =
stackTrace?.let { configuration.failFastFailureRegexes.any { it.matches(stackTrace) } } == true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.malinskiy.marathon.execution

import com.fasterxml.jackson.annotation.JsonProperty

data class StrictRunFilterConfiguration(
data class StrictRunConfiguration(
@JsonProperty("filter", required = false) val filter: Collection<TestFilter> = emptyList(),
@JsonProperty("runs", required = false) val runs: Int = 1
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.malinskiy.marathon.execution

import com.malinskiy.marathon.test.Test

class StrictRunProcessor(private val configuration: StrictRunFilterConfiguration) {
class StrictRunProcessor(private val configuration: StrictRunConfiguration) {

fun processShard(shard: TestShard): TestShard {
var testsForStrictRun = if (configuration.filter.isEmpty()) emptyList() else shard.tests.toList()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class TestResultReporter(
}

private fun Test.isStrictRun(): Boolean =
configuration.strictMode || configuration.strictRunFilterConfiguration.filter.matches(this)
configuration.strictMode || configuration.strictRunConfiguration.filter.matches(this)

fun addShard(shard: TestShard) {
val allTests = shard.tests + shard.flakyTests
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import com.malinskiy.marathon.analytics.internal.pub.Track
import com.malinskiy.marathon.createDeviceInfo
import com.malinskiy.marathon.device.DevicePoolId
import com.malinskiy.marathon.execution.SimpleClassnameFilter
import com.malinskiy.marathon.execution.StrictRunFilterConfiguration
import com.malinskiy.marathon.execution.StrictRunConfiguration
import com.malinskiy.marathon.execution.TestFilter
import com.malinskiy.marathon.execution.TestResult
import com.malinskiy.marathon.execution.TestShard
Expand Down Expand Up @@ -46,7 +46,7 @@ object TestResultReporterSpec : Spek(
fun strictFilterReporter(filter: TestFilter) = TestResultReporter(
poolId,
analytics,
defaultConfig.copy(strictRunFilterConfiguration = StrictRunFilterConfiguration(filter = listOf(filter), runs = 3)),
defaultConfig.copy(strictRunConfiguration = StrictRunConfiguration(filter = listOf(filter), runs = 3)),
track
).apply {
addShard(TestShard(listOf(test, test, test)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,42 @@ import com.malinskiy.marathon.execution.strategy.BatchingStrategy
import com.malinskiy.marathon.execution.strategy.impl.batching.FixedSizeBatchingStrategy
import com.malinskiy.marathon.execution.strategy.impl.batching.IsolateBatchingStrategy
import org.gradle.api.Action
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Nested
import java.time.Duration
import java.time.Instant

class BatchingStrategyConfiguration {
var fixedSize: FixedSizeBatchingStrategyConfiguration? = null
interface BatchingStrategyConfiguration {
@get:Nested
val fixedSize: FixedSizeBatchingStrategyConfiguration

fun fixedSize(action: Action<FixedSizeBatchingStrategyConfiguration>) {
fixedSize = (fixedSize ?: FixedSizeBatchingStrategyConfiguration()).also { action.execute(it) }
fixedSize.initDefaults()
action.execute(fixedSize)
}
}

class FixedSizeBatchingStrategyConfiguration {
var size = 1
var durationMillis: Long? = null
var percentile: Double? = null
var timeLimit: Instant? = null
var lastMileLength: Int = 0
interface FixedSizeBatchingStrategyConfiguration {
val size: Property<Int>
val durationMillis: Property<Long>
val percentile: Property<Double>
val timeLimit: Property<Duration>
val lastMileLength: Property<Int>

fun initDefaults() {
size.convention(1)
lastMileLength.convention(0)
}
}

fun BatchingStrategyConfiguration.toStrategy(): BatchingStrategy = fixedSize?.let {
FixedSizeBatchingStrategy(it.size, it.durationMillis, it.percentile, it.timeLimit, it.lastMileLength)
} ?: IsolateBatchingStrategy()
internal fun BatchingStrategyConfiguration.toStrategy(): BatchingStrategy =
if (fixedSize.size.isPresent) fixedSize.toStrategy() else IsolateBatchingStrategy()

private fun FixedSizeBatchingStrategyConfiguration.toStrategy(): FixedSizeBatchingStrategy =
FixedSizeBatchingStrategy(
size = size.get(),
durationMillis = durationMillis.orNull,
percentile = percentile.orNull,
timeLimit = timeLimit.orNull?.let { Instant.now().minus(it) },
lastMileLength = lastMileLength.get()
)
Original file line number Diff line number Diff line change
Expand Up @@ -5,51 +5,65 @@ import com.malinskiy.marathon.cache.config.LocalCacheConfiguration
import com.malinskiy.marathon.cache.config.RemoteCacheConfiguration
import com.malinskiy.marathon.execution.CacheConfiguration
import org.gradle.api.Action
import java.io.File
import org.gradle.api.credentials.PasswordCredentials
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Nested
import java.net.URI

open class CachePluginConfiguration {
interface CachePluginConfiguration {
@get:Nested
val local: LocalCacheExtension

var localExtension: LocalCacheExtension? = null
var remoteExtension: RemoteCacheExtension? = null
@get:Nested
val remote: RemoteCacheExtension

fun local(action: Action<LocalCacheExtension>) {
localExtension = (localExtension ?: LocalCacheExtension()).also { action.execute(it) }
local.initDefaults()
action.execute(local)
}

fun remote(action: Action<RemoteCacheExtension>) {
remoteExtension = (remoteExtension ?: RemoteCacheExtension()).also { action.execute(it) }
action.execute(remote)
}
}

private val DEFAULT_LOCAL_CACHE_DIRECTORY = File("~/cache/marathon")
private const val DEFAULT_LOCAL_UNUSED_ENTRIES_DELETE_AFTER_DAYS = 7
interface LocalCacheExtension {
val directory: DirectoryProperty
val removeUnusedEntriesAfterDays: Property<Int>

open class LocalCacheExtension {
var directory: File = DEFAULT_LOCAL_CACHE_DIRECTORY
var removeUnusedEntriesAfterDays: Int = DEFAULT_LOCAL_UNUSED_ENTRIES_DELETE_AFTER_DAYS
fun initDefaults() {
removeUnusedEntriesAfterDays.convention(7)
}
}

private fun LocalCacheExtension?.toConfig(): LocalCacheConfiguration =
this?.let {
LocalCacheConfiguration.Enabled(it.directory, it.removeUnusedEntriesAfterDays)
} ?: LocalCacheConfiguration.Disabled

open class RemoteCacheExtension {
var url: URI? = null
var credentials: Credentials? = null
interface RemoteCacheExtension {
val url: Property<URI>
val credentials: Property<PasswordCredentials>
}

private fun RemoteCacheExtension?.toConfig(): RemoteCacheConfiguration =
this?.let {
val url = it.url ?: throw IllegalArgumentException("Remote cache URL is required for remote cache configuration")
RemoteCacheConfiguration.Enabled(url, it.credentials)
} ?: RemoteCacheConfiguration.Disabled
internal fun CachePluginConfiguration.toCacheConfiguration(): CacheConfiguration =
CacheConfiguration(
local = local.toConfig(),
remote = remote.toConfig()
)

private fun LocalCacheExtension.toConfig(): LocalCacheConfiguration =
if (directory.isPresent) {
LocalCacheConfiguration.Enabled(directory.get().asFile, removeUnusedEntriesAfterDays.get())
} else {
LocalCacheConfiguration.Disabled
}

fun CachePluginConfiguration.toCacheConfiguration(): CacheConfiguration {
return CacheConfiguration(
local = localExtension.toConfig(),
remote = remoteExtension.toConfig()
private fun RemoteCacheExtension.toConfig(): RemoteCacheConfiguration =
if (url.isPresent) {
RemoteCacheConfiguration.Enabled(url.get(), credentials.orNull?.toCredentials())
} else {
RemoteCacheConfiguration.Disabled
}

private fun PasswordCredentials.toCredentials(): Credentials =
Credentials(
userName = requireNotNull(username) { "Username is required" },
password = requireNotNull(password) { "Password is required" }
)
}
Loading

0 comments on commit 69fe63b

Please sign in to comment.