Skip to content
Merged
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
10 changes: 10 additions & 0 deletions admin-app/src/main/resources/openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,16 @@ paths:
in: query
schema:
type: string
- name: testSessionId
in: query
description: Filter coverage by test session ID. When specified, only coverage data from the given test session is included.
schema:
type: string
- name: testDefinitionId
in: query
description: Filter coverage by test definition ID. Requires testSessionId to be specified. When provided, only coverage data from the specific test definition is included.
schema:
type: string
responses:
'200':
description: Coverage treemap data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ open class MethodCriteria(
object NONE : MethodCriteria()

open val packageNamePattern: String?
get() = packageName?.let { it.removeSuffix("/") + "/" + "%" }
get() = packageName?.let { "$it%" }

open val signaturePattern: String?
get() = listOf(
className ?: "%",
methodName ?: "%",
methodParams ?: "%",
returnType ?: "%"
className?.takeIf { it.isNotEmpty() } ?: "%",
methodName?.takeIf { it.isNotEmpty() } ?: "%",
methodParams?.takeIf { it.isNotEmpty() } ?: "%",
returnType?.takeIf { it.isNotEmpty() } ?: "%"
).joinToString(":").takeIf { it != "%:%:%:%" }
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,25 @@ interface MetricsRepository {
offset: Int? = null, limit: Int? = null
): List<Map<String, Any?>>

suspend fun getMethodsWithCoverageByTestSession(
buildId: String,
testSessionId: String,
testTags: List<String> = emptyList(),
packageNamePattern: String? = null,
methodSignaturePattern: String? = null,
coverageAppEnvIds: List<String> = emptyList(),
): List<Map<String, Any?>>

suspend fun getMethodsWithCoverageByTestDefinition(
buildId: String,
testSessionId: String,
testDefinitionId: String,
packageNamePattern: String? = null,
methodSignaturePattern: String? = null,
coverageAppEnvIds: List<String> = emptyList(),
): List<Map<String, Any?>>


suspend fun getMethodsCount(
buildId: String,
packageNamePattern: String? = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,20 +130,101 @@
)
appendOptional(", input_package_name_pattern => ?", packageName) { "$it%" }
appendOptional(", input_class_name_pattern => ?", className) { "%$it" }
appendOptional(", input_coverage_test_tags => ?", coverageTestTag) { listOf(it) }

Check failure on line 133 in admin-metrics/src/main/kotlin/com/epam/drill/admin/metrics/repository/impl/MetricsRepositoryImpl.kt

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal ", input_coverage_test_tags => ?" 3 times.

See more on https://sonarcloud.io/project/issues?id=Drill4J_admin&issues=AZ2VPVQ0lbRe63qrm8Is&open=AZ2VPVQ0lbRe63qrm8Is&pullRequest=470
appendOptional(", input_coverage_app_env_ids => ?", coverageEnvId) { listOf(it) }
appendOptional(", input_coverage_branches => ?", coverageBranch) { listOf(it) }
append(
"""
)
ORDER BY signature
""".trimIndent()

Check failure on line 140 in admin-metrics/src/main/kotlin/com/epam/drill/admin/metrics/repository/impl/MetricsRepositoryImpl.kt

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal " ) ORDER BY signature " 4 times.

See more on https://sonarcloud.io/project/issues?id=Drill4J_admin&issues=AZ2VPVQ0lbRe63qrm8It&open=AZ2VPVQ0lbRe63qrm8It&pullRequest=470
)
appendOptional(" OFFSET ?", offset)
appendOptional(" LIMIT ?", limit)
}
}

override suspend fun getMethodsWithCoverageByTestSession(
buildId: String,
testSessionId: String,
testTags: List<String>,
packageNamePattern: String?,
methodSignaturePattern: String?,
coverageAppEnvIds: List<String>,
): List<Map<String, Any?>> = transaction {
executeQueryReturnMap {
append(
"""
SELECT
signature,
class_name,
method_name,
method_params,
return_type,
probes_count,
covered_probes AS isolated_covered_probes,
covered_probes AS aggregated_covered_probes,
probes_coverage_ratio AS isolated_probes_coverage_ratio,
probes_coverage_ratio AS aggregated_probes_coverage_ratio
FROM metrics.get_methods_with_coverage_by_test_session(
input_build_id => ?,
input_test_session_id => ?
""".trimIndent(), buildId, testSessionId
)
appendOptional(", input_coverage_test_tags => ?", testTags)
appendOptional(", input_package_name_pattern => ?", packageNamePattern) { "$it%" }
appendOptional(", input_signature_pattern => ?", methodSignaturePattern)
appendOptional(", input_coverage_app_env_ids => ?", coverageAppEnvIds)
append(
"""
)
ORDER BY signature
""".trimIndent()
)
}
}

override suspend fun getMethodsWithCoverageByTestDefinition(
buildId: String,
testSessionId: String,
testDefinitionId: String,
packageNamePattern: String?,
methodSignaturePattern: String?,
coverageAppEnvIds: List<String>,
): List<Map<String, Any?>> = transaction {
executeQueryReturnMap {
append(
"""
SELECT
signature,
class_name,
method_name,
method_params,
return_type,
probes_count,
covered_probes AS isolated_covered_probes,
covered_probes AS aggregated_covered_probes,
probes_coverage_ratio AS isolated_probes_coverage_ratio,
probes_coverage_ratio AS aggregated_probes_coverage_ratio
FROM metrics.get_methods_with_coverage_by_test_definition(
input_build_id => ?,
input_test_session_id => ?,
input_test_definition_id => ?
""".trimIndent(), buildId, testSessionId, testDefinitionId
)
appendOptional(", input_package_name_pattern => ?", packageNamePattern) { "$it%" }
appendOptional(", input_signature_pattern => ?", methodSignaturePattern)
appendOptional(", input_coverage_app_env_ids => ?", coverageAppEnvIds)
append(
"""
)
ORDER BY signature
""".trimIndent()
)
}
}


override suspend fun getChangesWithCoverage(
buildId: String,
baselineBuildId: String?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,9 @@ class Metrics {
val branch: String? = null,
val packageNamePattern: String? = null,
val classNamePattern: String? = null,
val rootId: String? = null
val rootId: String? = null,
val testSessionId: String? = null,
val testDefinitionId: String? = null
)

@Resource("/changes-coverage-treemap")
Expand Down Expand Up @@ -327,7 +329,9 @@ fun Route.getCoverageTreemap() {
params.branch,
params.packageNamePattern,
params.classNamePattern,
params.rootId
params.rootId,
params.testSessionId,
params.testDefinitionId
)
this.call.respond(HttpStatusCode.OK, ApiResponse(treemap))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
pageSize: Int?
): PagedList<BuildView>

suspend fun getCoverageTreemap(

Check warning on line 40 in admin-metrics/src/main/kotlin/com/epam/drill/admin/metrics/service/MetricsService.kt

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

This function has 9 parameters, which is greater than the 7 authorized.

See more on https://sonarcloud.io/project/issues?id=Drill4J_admin&issues=AZ2VPVUglbRe63qrm8Iu&open=AZ2VPVUglbRe63qrm8Iu&pullRequest=470
buildId: String,
testTag: String?,
envId: String?,
Expand All @@ -45,6 +45,8 @@
packageNamePattern: String?,
classNamePattern: String?,
rootId: String?,
testSessionId: String? = null,
testDefinitionId: String? = null,
): List<Any>

suspend fun getChangesCoverageTreemap(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,21 +114,53 @@ class MetricsServiceImpl(
branch: String?,
packageNamePattern: String?,
classNamePattern: String?,
rootId: String?
rootId: String?,
testSessionId: String?,
testDefinitionId: String?,
): List<Any> {
if (!metricsRepository.buildExists(buildId)) {
throw BuildNotFound("Build info not found for $buildId")
}

val data = metricsRepository.getMethodsWithCoverage(
buildId = buildId,
coverageTestTag = testTag?.takeIf { it.isNotBlank() },
coverageEnvId = envId?.takeIf { it.isNotBlank() },
coverageBranch = branch?.takeIf { it.isNotBlank() },
packageName = packageNamePattern?.takeIf { it.isNotBlank() },
className = classNamePattern?.takeIf { it.isNotBlank() }
val methodCriteria = MethodCriteria(
packageName = packageNamePattern,
className = classNamePattern
)

val data = when {
testDefinitionId != null -> {
val resolvedTestSessionId = testSessionId
?: throw IllegalArgumentException("testSessionId is required when testDefinitionId is specified")
metricsRepository.getMethodsWithCoverageByTestDefinition(
buildId = buildId,
testSessionId = resolvedTestSessionId,
testDefinitionId = testDefinitionId,
packageNamePattern = methodCriteria.packageNamePattern,
methodSignaturePattern = methodCriteria.signaturePattern,
coverageAppEnvIds = envId?.takeIf { it.isNotBlank() }?.let { listOf(it) } ?: emptyList(),
)
}
testSessionId != null -> {
metricsRepository.getMethodsWithCoverageByTestSession(
buildId = buildId,
testSessionId = testSessionId,
packageNamePattern = methodCriteria.packageNamePattern,
methodSignaturePattern = methodCriteria.signaturePattern,
coverageAppEnvIds = envId?.takeIf { it.isNotBlank() }?.let { listOf(it) } ?: emptyList(),
testTags = testTag?.takeIf { it.isNotBlank() }?.let { listOf(it) } ?: emptyList(),
)
}
else -> {
metricsRepository.getMethodsWithCoverage(
buildId = buildId,
coverageTestTag = testTag?.takeIf { it.isNotBlank() },
coverageEnvId = envId?.takeIf { it.isNotBlank() },
coverageBranch = branch?.takeIf { it.isNotBlank() },
packageName = packageNamePattern?.takeIf { it.isNotBlank() },
className = classNamePattern?.takeIf { it.isNotBlank() }
)
}
}

return buildTree(data, rootId)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,34 @@ SELECT
FROM metrics.test_definitions td
LEFT JOIN metrics.test_launches tl ON tl.group_id = td.group_id AND tl.test_definition_id = td.test_definition_id
GROUP BY td.group_id, td.test_path, tl.test_session_id;

-------------------------------------------------------------------
-- Create a view of test session definitions with information about
-- the number of test launches, total duration, and overall results
-------------------------------------------------------------------
DROP VIEW IF EXISTS metrics.test_session_definitions CASCADE;
CREATE OR REPLACE VIEW metrics.test_session_definitions AS
SELECT
ts.test_session_id,
td.test_definition_id,
COUNT(*) AS test_launches,
SUM(tl.test_duration) AS test_duration_sum,
raw_data.format_duration(SUM(tl.test_duration)::bigint) AS test_duration_sum_formatted,
CASE
WHEN SUM(tl.failed) > 0 THEN 'FAILED'
WHEN SUM(tl.passed) > 0 THEN 'PASSED'
WHEN SUM(tl.smart_skipped) > 0 THEN 'SMART_SKIPPED'
WHEN SUM(tl.skipped) > 0 THEN 'SKIPPED'
ELSE 'UNKNOWN'
END AS test_result,
MIN(td.test_name) AS test_name,
MIN(td.test_path) AS test_path,
MIN(td.test_runner) AS test_runner,
MIN(td.test_tags) AS test_tags,
array_to_string(MIN(td.test_tags), ', ') AS test_tags_formatted
FROM metrics.test_sessions ts
JOIN metrics.test_launches tl ON tl.test_session_id = ts.test_session_id AND tl.group_id = ts.group_id
JOIN metrics.test_definitions td ON td.group_id = tl.group_id AND td.test_definition_id = tl.test_definition_id
GROUP BY
ts.test_session_id,
td.test_definition_id;
Loading
Loading