Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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 build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
/*
* Copyright 2025 Exactpro (Exactpro Systems Limited)
*
* 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
*
* http://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.
*/

import org.jlleitschuh.gradle.ktlint.reporter.ReporterType

plugins {
Expand Down Expand Up @@ -79,7 +95,7 @@ kotlin {
}

ktlint {
version.set("0.50.0")
version.set("1.6.0")
reporters {
reporter(ReporterType.HTML)
}
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ testcontainers-bom = { group = "org.testcontainers", name = "testcontainers-bom"
[plugins]
th2-publish = { id = "com.exactpro.th2.gradle.publish", version = "0.3.5" }
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
ktlint = { id = "org.jlleitschuh.gradle.ktlint", version = "12.3.0" }
ktlint = { id = "org.jlleitschuh.gradle.ktlint", version = "13.0.0" }
compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version = "0.18.1" }
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ import org.junit.jupiter.api.extension.ParameterResolver
import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils
import java.util.LinkedList

public class CleanupExtension : BeforeEachCallback, BeforeAllCallback, AfterEachCallback, ParameterResolver {
public class CleanupExtension :
BeforeEachCallback,
BeforeAllCallback,
AfterEachCallback,
ParameterResolver {
override fun beforeEach(context: ExtensionContext) {
context.getStore(NAMESPACE).put(AFTER_TEST_KEY, ClosableRegistry(Registry()))
}
Expand All @@ -48,7 +52,11 @@ public class CleanupExtension : BeforeEachCallback, BeforeAllCallback, AfterEach
public fun add(resource: AutoCloseable) {
add(RandomStringUtils.randomAlphabetic(10), resource)
}
public fun add(name: String, resource: AutoCloseable) {

public fun add(
name: String,
resource: AutoCloseable,
) {
check(resources.find { it.first == name } == null) {
"duplicated resource $name"
}
Expand All @@ -59,7 +67,6 @@ public class CleanupExtension : BeforeEachCallback, BeforeAllCallback, AfterEach
private class ClosableRegistry(
val registry: Registry,
) : ExtensionContext.Store.CloseableResource {

override fun close() {
registry.resources.descendingIterator().forEach { (name, resource) ->
runCatching {
Expand All @@ -72,18 +79,22 @@ public class CleanupExtension : BeforeEachCallback, BeforeAllCallback, AfterEach
}
}

override fun supportsParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): Boolean {
return parameterContext.parameter.type == Registry::class.java
}
override fun supportsParameter(
parameterContext: ParameterContext,
extensionContext: ExtensionContext,
): Boolean = parameterContext.parameter.type == Registry::class.java

override fun resolveParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): Any {
override fun resolveParameter(
parameterContext: ParameterContext,
extensionContext: ExtensionContext,
): Any {
val store = extensionContext.getStore(NAMESPACE)
// if we have registry for AFTER_TEST_KEY key it means the parameter is resolved for test method
// or in before
val autoClosableRegistry = (
store.get(AFTER_TEST_KEY, ClosableRegistry::class.java)
?: store.get(AFTER_ALL_KEY, ClosableRegistry::class.java)
)
)
return autoClosableRegistry?.registry ?: error("registry is not created")
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 Exactpro (Exactpro Systems Limited)
* Copyright 2023-2025 Exactpro (Exactpro Systems Limited)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -21,11 +21,10 @@ import org.junit.platform.commons.support.ReflectionSupport
import java.lang.reflect.Field
import kotlin.reflect.KClass

private fun List<Field>.definitions(): String {
return joinToString {
private fun List<Field>.definitions(): String =
joinToString {
"${it.name} in ${it.declaringClass}"
}
}

internal inline fun <reified T> Any.getSingle(fields: List<Field>): T {
require(fields.size == 1) {
Expand Down Expand Up @@ -53,10 +52,9 @@ internal inline fun <reified T> Any.getFieldOrDefault(default: () -> T): T {
?: default()
}

internal inline fun <reified T> KClass<*>.findFields(): List<Field> {
return ReflectionSupport.findFields(
internal inline fun <reified T> KClass<*>.findFields(): List<Field> =
ReflectionSupport.findFields(
java,
{ field -> field.type == T::class.java },
HierarchyTraversalMode.TOP_DOWN,
)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 Exactpro (Exactpro Systems Limited)
* Copyright 2023-2025 Exactpro (Exactpro Systems Limited)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -18,8 +18,7 @@ package com.exactpro.th2.test.extension

import org.junit.jupiter.api.extension.ExtensionContext.Store

internal inline fun <reified T> Store.getRequired(key: Any): T {
return checkNotNull(get(key, T::class.java)) {
internal inline fun <reified T> Store.getRequired(key: Any): T =
checkNotNull(get(key, T::class.java)) {
"no value of type ${T::class} by key $key"
}
}
8 changes: 3 additions & 5 deletions src/main/kotlin/com/exactpro/th2/test/extension/Th2.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 Exactpro (Exactpro Systems Limited)
* Copyright 2023-2025 Exactpro (Exactpro Systems Limited)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -24,9 +24,7 @@ internal object Th2 {
@JvmField
val NAMESPACE: Namespace = Namespace.create(Th2::class)

fun getAppConfigFolder(context: ExtensionContext): Path =
context.getStore(NAMESPACE).getRequired(Th2ConfigExtension.APP_CONFIG)
fun getAppConfigFolder(context: ExtensionContext): Path = context.getStore(NAMESPACE).getRequired(Th2ConfigExtension.APP_CONFIG)

fun getTestConfigFolder(context: ExtensionContext): Path =
context.getStore(NAMESPACE).getRequired(Th2ConfigExtension.TEST_CONFIG)
fun getTestConfigFolder(context: ExtensionContext): Path = context.getStore(NAMESPACE).getRequired(Th2ConfigExtension.TEST_CONFIG)
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,19 @@ import org.junit.jupiter.api.extension.ParameterResolver
import java.nio.file.Path
import kotlin.io.path.outputStream

public class Th2CommonFactoryExtension : BeforeAllCallback, BeforeEachCallback, AfterEachCallback, ParameterResolver {
public class Th2CommonFactoryExtension :
BeforeAllCallback,
BeforeEachCallback,
AfterEachCallback,
ParameterResolver {
private class FactoryHolder(
folder: Path,
) {
val factory: CommonFactory = CommonFactory.createFromArguments(
"-c",
folder.toAbsolutePath().toString(),
)
val factory: CommonFactory =
CommonFactory.createFromArguments(
"-c",
folder.toAbsolutePath().toString(),
)
}

private lateinit var appCommonFactory: FactoryHolder
Expand Down Expand Up @@ -72,7 +77,10 @@ public class Th2CommonFactoryExtension : BeforeAllCallback, BeforeEachCallback,
}
}

private fun cleanUp(holder: FactoryHolder, name: String) {
private fun cleanUp(
holder: FactoryHolder,
name: String,
) {
LOGGER.info { "Cleaning factory $name" }
runCatching {
holder.factory.close()
Expand All @@ -82,15 +90,16 @@ public class Th2CommonFactoryExtension : BeforeAllCallback, BeforeEachCallback,
LOGGER.info { "Cleaning factory $name done" }
}

override fun supportsParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): Boolean {
return parameterContext.parameter.type == CommonFactory::class.java
}
override fun supportsParameter(
parameterContext: ParameterContext,
extensionContext: ExtensionContext,
): Boolean = parameterContext.parameter.type == CommonFactory::class.java

override fun resolveParameter(
parameterContext: ParameterContext,
extensionContext: ExtensionContext,
): CommonFactory {
return when {
): CommonFactory =
when {
parameterContext.isAnnotated(Th2AppFactory::class.java) -> {
check(::appCommonFactory.isInitialized) { "app factory is not initialized" }
appCommonFactory.factory
Expand All @@ -103,7 +112,6 @@ public class Th2CommonFactoryExtension : BeforeAllCallback, BeforeEachCallback,

else -> error("parameter must be annotated with ${Th2AppFactory::class} or ${Th2TestFactory::class} annotation")
}
}

private fun Path.writeConfiguration(name: String) {
resolve(ConfigurationWriter.PROMETHEUS_CONFIG).outputStream().use {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ import kotlin.io.path.ExperimentalPathApi
import kotlin.io.path.createDirectory
import kotlin.io.path.deleteRecursively

public class Th2ConfigExtension : BeforeAllCallback, AfterAllCallback {
public class Th2ConfigExtension :
BeforeAllCallback,
AfterAllCallback {
override fun beforeAll(context: ExtensionContext) {
val store = context.getStore(Th2.NAMESPACE)
val root = Files.createTempDirectory("th2")
Expand All @@ -38,7 +40,9 @@ public class Th2ConfigExtension : BeforeAllCallback, AfterAllCallback {

@OptIn(ExperimentalPathApi::class)
override fun afterAll(context: ExtensionContext) {
context.getStore(Th2.NAMESPACE).get(ROOT_CONFIG, Path::class.java)
context
.getStore(Th2.NAMESPACE)
.get(ROOT_CONFIG, Path::class.java)
?.also {
LOGGER.info { "Cleaning config dirs $it" }
it.deleteRecursively()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ public class Th2CradleExtension :
private var cradleSpec: CradleSpec? = null
private lateinit var cradle: CradleIntegration

override fun postProcessTestInstance(testInstance: Any, context: ExtensionContext) {
override fun postProcessTestInstance(
testInstance: Any,
context: ExtensionContext,
) {
val fields = testInstance::class.findFields<CradleSpec>().ifEmpty { return }
cradleSpec = testInstance.getSingle(fields)
}
Expand Down Expand Up @@ -109,17 +112,24 @@ public class Th2CradleExtension :
}
}

override fun supportsParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): Boolean {
return parameterContext.parameter.type == CradleManager::class.java
}
override fun supportsParameter(
parameterContext: ParameterContext,
extensionContext: ExtensionContext,
): Boolean = parameterContext.parameter.type == CradleManager::class.java

override fun resolveParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): Any {
override fun resolveParameter(
parameterContext: ParameterContext,
extensionContext: ExtensionContext,
): Any {
val spec = checkNotNull(cradleSpec) { "cannot create Cradle manager without spec specified" }
val resource = extensionContext.getStore(Th2.NAMESPACE).getOrComputeIfAbsent(
Th2CradleExtension::class,
) {
ClosableCradleResource(createManager(spec))
}.let(ClosableCradleResource::class::cast)
val resource =
extensionContext
.getStore(Th2.NAMESPACE)
.getOrComputeIfAbsent(
Th2CradleExtension::class,
) {
ClosableCradleResource(createManager(spec))
}.let(ClosableCradleResource::class::cast)
return resource.manager
}

Expand All @@ -137,7 +147,10 @@ public class Th2CradleExtension :
}
}

private fun startCradle(spec: CradleSpec, testInstance: Any) {
private fun startCradle(
spec: CradleSpec,
testInstance: Any,
) {
cradle = testInstance.getFieldOrDefault { CradleIntegration.defaultImage() }
cradle.start()
if (spec.reuseKeyspace) {
Expand All @@ -153,9 +166,7 @@ public class Th2CradleExtension :
}
}

private fun createManager(
spec: CradleSpec,
): CassandraCradleManager {
private fun createManager(spec: CradleSpec): CassandraCradleManager {
val contactPoint = cradle.container.contactPoint
return CassandraCradleManager(
CassandraConnectionSettings(
Expand All @@ -182,14 +193,19 @@ public class Th2CradleExtension :
}
}

private fun CradleStorage.createPages(bookName: String, spec: CradleSpec, minDistanceBetweenPages: Long) {
private fun CradleStorage.createPages(
bookName: String,
spec: CradleSpec,
minDistanceBetweenPages: Long,
) {
val bookStart = Instant.now()
val bookInfo: BookInfo = addBook(
BookToAdd(
bookName,
bookStart,
),
)
val bookInfo: BookInfo =
addBook(
BookToAdd(
bookName,
bookStart,
),
)
var pageStart: Instant = bookStart
val pageEnd: Instant = pageStart + spec.autoPageInterval
var index = 1
Expand Down
Loading
Loading