Skip to content

Commit

Permalink
Adding API endpoint to fetch latest test run summaries for a repo (#1263
Browse files Browse the repository at this point in the history
)
  • Loading branch information
craigatk committed Apr 9, 2024
1 parent 2272d83 commit 4f8b1ad
Show file tree
Hide file tree
Showing 13 changed files with 235 additions and 21 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ retrofitVersion=2.9.0

auth0_version=4.4.0
jacksonDatabindVersion=2.15.3
jacksonVersion=2.15.3
jacksonVersion=2.16.2

postgresDriverVersion=42.7.3

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package projektor.server.api.repository

import projektor.server.api.TestRunSummary

data class RepositoryTestRunSummaries(val testRuns: List<TestRunSummary>)
2 changes: 1 addition & 1 deletion server/server-app/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ ktor_version=2.3.9
koin_version=3.5.1
koin_test_version=3.5.4

opentelemetry_version=1.28.0
opentelemetry_version=1.36.0
2 changes: 1 addition & 1 deletion server/server-app/opentelemetry/.version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.21.0
2.2.0
Binary file modified server/server-app/opentelemetry/opentelemetry-javaagent.jar
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package projektor.repository.testrun

import io.opentelemetry.api.GlobalOpenTelemetry
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.jooq.Condition
Expand All @@ -14,14 +15,18 @@ import projektor.database.generated.Tables.TEST_CASE
import projektor.database.generated.Tables.TEST_RUN
import projektor.server.api.PublicId
import projektor.server.api.TestCase
import projektor.server.api.TestRunSummary
import projektor.server.api.repository.BranchType
import projektor.server.api.repository.RepositoryTestRunTimeline
import projektor.server.api.repository.RepositoryTestRunTimelineEntry
import projektor.telemetry.startSpanWithParent
import projektor.testcase.TestCaseDatabaseRepository
import projektor.testcase.TestCaseDatabaseRepository.Companion.selectTestCase
import kotlin.streams.toList

class RepositoryTestRunDatabaseRepository(private val dslContext: DSLContext) : RepositoryTestRunRepository {
private val tracer = GlobalOpenTelemetry.getTracer("projektor.RepositoryTestRunDatabaseRepository")

private val timelineEntryMapper = JdbcMapperFactory.newInstance()
.addKeys("public_id")
.ignorePropertyNotFound()
Expand Down Expand Up @@ -51,6 +56,29 @@ class RepositoryTestRunDatabaseRepository(private val dslContext: DSLContext) :
if (timelineEntries.isNotEmpty()) RepositoryTestRunTimeline(timelineEntries) else null
}

override suspend fun fetchRepositoryTestRunSummaries(repoName: String, projectName: String?, limit: Int): List<TestRunSummary> =
withContext(Dispatchers.IO) {
val span = tracer.startSpanWithParent("projektor.fetchRepositoryTestRunSummaries")

val testRunSummaries = dslContext
.select(TEST_RUN.PUBLIC_ID.`as`("id"))
.select(TEST_RUN.fields().filterNot { it.name == "id" }.toList())
.from(TEST_RUN)
.innerJoin(RESULTS_METADATA).on(TEST_RUN.ID.eq(RESULTS_METADATA.TEST_RUN_ID))
.innerJoin(GIT_METADATA).on(TEST_RUN.ID.eq(GIT_METADATA.TEST_RUN_ID))
.where(
runInCIFromRepo(repoName, projectName)
.and(withBranchType(BranchType.MAINLINE))
)
.orderBy(TEST_RUN.CREATED_TIMESTAMP.desc())
.limit(limit)
.fetchInto(TestRunSummary::class.java)

span.end()

testRunSummaries
}

override suspend fun fetchRepositoryFailingTestCases(
repoName: String,
projectName: String?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ package projektor.repository.testrun

import projektor.server.api.PublicId
import projektor.server.api.TestCase
import projektor.server.api.TestRunSummary
import projektor.server.api.repository.BranchType
import projektor.server.api.repository.RepositoryTestRunTimeline

interface RepositoryTestRunRepository {
suspend fun fetchRepositoryTestRunTimeline(repoName: String, projectName: String?): RepositoryTestRunTimeline?

suspend fun fetchRepositoryTestRunSummaries(repoName: String, projectName: String?, limit: Int): List<TestRunSummary>

suspend fun fetchRepositoryFailingTestCases(repoName: String, projectName: String?, maxRuns: Int, branchType: BranchType): List<TestCase>

suspend fun fetchRecentTestRunPublicIds(repoName: String, projectName: String?, maxRuns: Int): List<PublicId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package projektor.repository.testrun

import projektor.server.api.TestRunSummary
import projektor.server.api.repository.BranchType
import projektor.server.api.repository.RepositoryFlakyTest
import kotlin.math.min
Expand All @@ -23,4 +24,7 @@ class RepositoryTestRunService(private val repositoryTestRunRepository: Reposito

return flakyTestCalculator.calculateFlakyTests(failingTestCases, flakyFailureThreshold, testRunCount)
}

suspend fun fetchRepositoryTestRunSummaries(repoName: String, projectName: String?, limit: Int): List<TestRunSummary> =
repositoryTestRunRepository.fetchRepositoryTestRunSummaries(repoName, projectName, limit)
}
15 changes: 15 additions & 0 deletions server/server-app/src/main/kotlin/projektor/route/ApiRoutes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import projektor.repository.testrun.RepositoryTestRunService
import projektor.server.api.repository.BranchSearch
import projektor.server.api.repository.BranchType
import projektor.server.api.repository.RepositoryFlakyTests
import projektor.server.api.repository.RepositoryTestRunSummaries
import kotlin.math.min

fun Route.api(
organizationCoverageService: OrganizationCoverageService,
Expand Down Expand Up @@ -84,4 +86,17 @@ fun Route.api(
call.respond(HttpStatusCode.NoContent)
}
}

get("/api/v1/repo/{orgPart}/{repoPart}/tests/runs/summaries") {
val orgPart = call.parameters.getOrFail("orgPart")
val repoPart = call.parameters.getOrFail("repoPart")
val projectName = call.request.queryParameters["project"]
val limit = min(call.request.queryParameters["limit"]?.toInt() ?: 10, 100) // Defaults to 10 with a max of 100

val fullRepoName = "$orgPart/$repoPart"

val testRunSummaries = repositoryTestRunService.fetchRepositoryTestRunSummaries(fullRepoName, projectName, limit)

call.respond(HttpStatusCode.OK, RepositoryTestRunSummaries(testRuns = testRunSummaries))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ package projektor.api
import com.fasterxml.jackson.module.kotlin.readValue
import io.ktor.http.*
import io.ktor.server.testing.*
import org.apache.commons.lang3.RandomStringUtils
import org.junit.jupiter.api.Test
import projektor.ApplicationTestCase
import projektor.incomingresults.randomPublicId
import projektor.server.api.repository.coverage.RepositoryCurrentCoverage
import projektor.server.example.coverage.JacocoXmlLoader
import projektor.util.randomFullRepoName
import strikt.api.expectThat
import strikt.assertions.isEqualTo
import java.time.ZoneOffset
Expand All @@ -17,8 +17,7 @@ import kotlin.test.assertNotNull
class ApiRepositoryApplicationTest : ApplicationTestCase() {
@Test
fun `should fetch current coverage for repository without project name`() {
val orgName = RandomStringUtils.randomAlphabetic(12)
val repoName = "$orgName/repo"
val repoName = randomFullRepoName()

val firstRunPublicId = randomPublicId()
val secondRunPublicId = randomPublicId()
Expand Down Expand Up @@ -85,8 +84,7 @@ class ApiRepositoryApplicationTest : ApplicationTestCase() {

@Test
fun `should fetch current coverage for repository with project name`() {
val orgName = RandomStringUtils.randomAlphabetic(12)
val repoName = "$orgName/repo"
val repoName = randomFullRepoName()

val firstRunPublicId = randomPublicId()
val secondRunPublicId = randomPublicId()
Expand Down Expand Up @@ -154,8 +152,7 @@ class ApiRepositoryApplicationTest : ApplicationTestCase() {

@Test
fun `should fetch current coverage for repository with branch name`() {
val orgName = RandomStringUtils.randomAlphabetic(12)
val repoName = "$orgName/repo"
val repoName = randomFullRepoName()

val firstRunPublicId = randomPublicId()
val secondRunPublicId = randomPublicId()
Expand Down Expand Up @@ -224,8 +221,7 @@ class ApiRepositoryApplicationTest : ApplicationTestCase() {

@Test
fun `when no branch specific should fetch current coverage from mainline branch`() {
val orgName = RandomStringUtils.randomAlphabetic(12)
val repoName = "$orgName/repo"
val repoName = randomFullRepoName()

val otherBranchRunPublicId1 = randomPublicId()
val mainRunPublicId = randomPublicId()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ package projektor.api

import io.ktor.http.*
import io.ktor.server.testing.*
import org.apache.commons.lang3.RandomStringUtils
import org.junit.jupiter.api.Test
import projektor.ApplicationTestCase
import projektor.TestSuiteData
import projektor.incomingresults.randomPublicId
import projektor.server.api.repository.RepositoryFlakyTests
import projektor.util.randomFullRepoName
import strikt.api.expectThat
import strikt.assertions.any
import strikt.assertions.contains
Expand All @@ -18,8 +18,7 @@ import kotlin.test.assertNotNull
class ApiRepositoryFlakyTestsApplicationTest : ApplicationTestCase() {
@Test
fun `when flaky tests without a project name should return them`() {
val orgName = RandomStringUtils.randomAlphabetic(12)
val repoName = "$orgName/repo"
val repoName = randomFullRepoName()
val projectName = null

val publicIds = (1..5).map { randomPublicId() }
Expand Down Expand Up @@ -60,8 +59,7 @@ class ApiRepositoryFlakyTestsApplicationTest : ApplicationTestCase() {

@Test
fun `when flaky tests within specified max runs and threshold should find them`() {
val orgName = RandomStringUtils.randomAlphabetic(12)
val repoName = "$orgName/repo"
val repoName = randomFullRepoName()
val projectName = null

val failingPublicIds = (1..3).map { randomPublicId() }
Expand Down Expand Up @@ -111,8 +109,7 @@ class ApiRepositoryFlakyTestsApplicationTest : ApplicationTestCase() {

@Test
fun `when flaky tests with a project name should return them`() {
val orgName = RandomStringUtils.randomAlphabetic(12)
val repoName = "$orgName/repo"
val repoName = randomFullRepoName()
val projectName = "my-project"

val publicIds = (1..5).map { randomPublicId() }
Expand Down Expand Up @@ -153,8 +150,7 @@ class ApiRepositoryFlakyTestsApplicationTest : ApplicationTestCase() {

@Test
fun `should find flaky tests in mainline only`() {
val orgName = RandomStringUtils.randomAlphabetic(12)
val repoName = "$orgName/repo"
val repoName = randomFullRepoName()
val projectName = null

val failingMainlinePublicIds = (1..3).map { randomPublicId() }
Expand Down
Loading

0 comments on commit 4f8b1ad

Please sign in to comment.