Skip to content

Commit

Permalink
Merge pull request #40 from platan/mark-previous
Browse files Browse the repository at this point in the history
Allow to add mark showing total time of all tests
  • Loading branch information
platan committed Jun 1, 2023
2 parents 149c3db + d4da5ef commit 5036976
Show file tree
Hide file tree
Showing 23 changed files with 520 additions and 98 deletions.
32 changes: 27 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,11 @@ rendered: ([info](https://github.blog/2022-02-14-include-diagrams-markdown-files

```mermaid
gantt
dateFormat YYYY-MM-DDTHH:mm:ss.SSSZZ
axisFormat %H:%M:%S.%L
section Test1Spec
test 2 - 120 ms :active, 2022-11-08T20:46:17.854+0100, 2022-11-08T20:46:17.974+0100
test 1 - 213 ms :active, 2022-11-08T20:46:17.854+0100, 2022-11-08T20:46:18.067+0100
dateFormat YYYY-MM-DDTHH:mm:ss.SSSZZ
axisFormat %H:%M:%S.%L
section Test1Spec
test 2 - 120 ms: active, 2022-11-08T20:46:17.854+0100, 2022-11-08T20:46:17.974+0100
test 1 - 213 ms: active, 2022-11-08T20:46:17.854+0100, 2022-11-08T20:46:18.067+0100
```

# Configuration
Expand All @@ -125,6 +125,8 @@ Options:
| `formats.json.enabled` | boolean | Generate report in json format | `true` |
| `formats.mermaid.enabled` | boolean | Generate report in mermaid text format | `true` |
| `shiftTimestampsToStartOfDay` | boolean | Adjust the earliest timestamp to the start of the day | `false` |
| `marks.totalTimeOfAllTests.enabled` | boolean | Enable mark showing total time of all tests | `false` |
| `marks.totalTimeOfAllTests.name` | string | Label used for mark | `total time of all tests` |

`build.gradle.kts`:

Expand All @@ -149,6 +151,12 @@ configure<io.github.platan.tests_execution_chart.CreateTestsExecutionReportExten
}
}
shiftTimestampsToStartOfDay.set(true)
marks {
totalTimeOfAllTests {
enabled.set(true)
name.set("total time of all tests")
}
}
}
```

Expand All @@ -175,6 +183,12 @@ createTestsExecutionReport {
}
}
shiftTimestampsToStartOfDay = true
marks {
totalTimeOfAllTests {
enabled = true
name = 'total time of all tests'
}
}
}
```

Expand Down Expand Up @@ -238,6 +252,14 @@ Gradle can generate reports in JUnit XML format. But such reports cannot be used

## Unreleased

### Added

- A new option `marks.totalTimeOfAllTests` allows to add mark showing total time of all tests

### Changed

- Do not remove `#` character from names of tasks/sections

## 0.3.1 (29 March 2023)

### Added
Expand Down
50 changes: 45 additions & 5 deletions src/functionalTest/groovy/ReportsFunctionalTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ class ReportsFunctionalTest extends Specification {
json { enabled = true }
mermaid { enabled = true }
}
marks {
totalTimeOfAllTests {
enabled = true
}
}
}
repositories {
mavenCentral()
Expand Down Expand Up @@ -72,6 +77,9 @@ class ReportsFunctionalTest extends Specification {
mermaidFile.exists()
jsonFile.exists()
htmlFile.exists()

and:
mermaidFile.text.contains 'total time of all tests : milestone, '
}

def "should replace special characters in mermaid graph test names"() {
Expand Down Expand Up @@ -121,10 +129,10 @@ class ReportsFunctionalTest extends Specification {

when:
def result = GradleRunner.create()
.withProjectDir(testProjectDir)
.withArguments('test', 'createTestsExecutionReport')
.withPluginClasspath()
.build()
.withProjectDir(testProjectDir)
.withArguments('test', 'createTestsExecutionReport')
.withPluginClasspath()
.build()

then:
result.task(":createTestsExecutionReport").outcome == SUCCESS
Expand All @@ -133,7 +141,7 @@ class ReportsFunctionalTest extends Specification {
def mermaidGraph = new File("$projectDirRealPath/build/reports/tests-execution/mermaid/test.txt").text
!mermaidGraph.contains("test with # character")
!mermaidGraph.contains("test with : character")
mermaidGraph.contains("test with character")
mermaidGraph.contains("test with #35; character")
mermaidGraph.contains("test with #colon; character")
}

Expand Down Expand Up @@ -213,6 +221,38 @@ class ReportsFunctionalTest extends Specification {
!new File("$projectDirRealPath/build/reports/tests-execution/").exists()
}

def "exit with error on empty mark name"() {
given:
settingsFile << "rootProject.name = 'hello-world'"
buildFile << """
plugins {
id 'groovy'
id 'io.github.platan.tests-execution-chart'
}
createTestsExecutionReport {
marks {
totalTimeOfAllTests {
name = ''
}
}
}
"""

when:
def result = GradleRunner.create()
.withProjectDir(testProjectDir)
.withArguments('createTestsExecutionReport')
.withPluginClasspath()
.buildAndFail()

then:
result.output.contains("marks.totalTimeOfAllTests.name cannot be blank")
result.output.contains('BUILD FAILED')

and:
!new File("$projectDirRealPath/build/reports/tests-execution/").exists()
}

// @TempDir creates directories in /var, but on macOS /var is a link to /private/var
// so we have to use toRealPath to get a real path which is logged
private Path getProjectDirRealPath() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package io.github.platan.tests_execution_chart.reporters.mermaid

import io.github.platan.tests_execution_chart.reporters.mermaid.core.MermaidGanttDiagram
import io.github.platan.tests_execution_chart.reporters.mermaid.core.MermaidGanttDiagramFormatter
import spock.lang.Retry
import spock.lang.Specification
import spock.lang.TempDir

class MermaidGanttDiagramFormatterSpec extends Specification {
class MermaidGanttDiagramFormatterToSvgConversionSpec extends Specification {

@TempDir
File tempDir
Expand All @@ -27,7 +29,9 @@ class MermaidGanttDiagramFormatterSpec extends Specification {
def "should produce result parsable by mmdc (mermaid CLI)"() {
given:
def diagramBuilder = new MermaidGanttDiagram.MermaidGanttDiagramBuilder()
diagramBuilder.add("test-section $SPECIAL_CHARS", "test-row $SPECIAL_CHARS", 'active', 1, 2)
diagramBuilder.addSection("test-section $SPECIAL_CHARS")
diagramBuilder.addTask("test-row $SPECIAL_CHARS", 'active', 1, 2)
diagramBuilder.addMilestone("test-milestone $SPECIAL_CHARS", 1)
def diagram = diagramBuilder.build("YYYY-MM-DD\\THH\\:mm\\:ss\\.SSSZ", "%H:%M:%S.%L")
def mermaid = new MermaidGanttDiagramFormatter().format(diagram, "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
inputFile.text = mermaid
Expand Down
6 changes: 6 additions & 0 deletions src/functionalTest/resources/report-visual-regression.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,11 @@
"resultType": "SUCCESS",
"testName": "test 3"
}
],
"marks": [
{
"timestamp": 1679338714982,
"name": "total time of all tests"
}
]
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.github.platan.tests_execution_chart

import io.github.platan.tests_execution_chart.config.Formats
import io.github.platan.tests_execution_chart.config.Marks
import org.gradle.api.Action
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
Expand All @@ -13,10 +14,17 @@ abstract class CreateTestsExecutionReportExtension @Inject constructor(objectFac
@Nested
abstract fun getFormats(): Formats

@Nested
abstract fun getMarks(): Marks

@get:Input
val shiftTimestampsToStartOfDay: Property<Boolean> = objectFactory.property(Boolean::class.java).convention(false)

open fun formats(action: Action<in Formats>) {
action.execute(getFormats())
}

open fun marks(action: Action<in Marks>) {
action.execute(getMarks())
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.github.platan.tests_execution_chart

import io.github.platan.tests_execution_chart.config.Formats
import io.github.platan.tests_execution_chart.config.Marks
import io.github.platan.tests_execution_chart.report.TestExecutionScheduleReport
import io.github.platan.tests_execution_chart.reporters.Logger
import io.github.platan.tests_execution_chart.reporters.html.HtmlGanttDiagramReporter
Expand Down Expand Up @@ -37,6 +38,9 @@ abstract class CreateTestsExecutionReportTask @Inject constructor(objectFactory:
@Nested
abstract fun getFormats(): Formats

@Nested
abstract fun getMarks(): Marks

@get:Input
val shiftTimestampsToStartOfDay: Property<Boolean> = objectFactory.property(Boolean::class.java).convention(false)

Expand All @@ -57,7 +61,11 @@ abstract class CreateTestsExecutionReportTask @Inject constructor(objectFactory:
)
}
if (getFormats().getJson().enabled.get()) {
JsonReporter(getFormats().getJson(), customLogger).report(adjustedResults, task.project.buildDir, task.name)
JsonReporter(getFormats().getJson(), customLogger).report(
adjustedResults,
task.project.buildDir,
task.name
)
}
if (getFormats().getHtml().enabled.get()) {
HtmlGanttDiagramReporter(getFormats().getHtml().toHtmlConfig(), customLogger).report(
Expand All @@ -71,10 +79,13 @@ abstract class CreateTestsExecutionReportTask @Inject constructor(objectFactory:
}

private fun adjustResults(results: TestExecutionScheduleReport): TestExecutionScheduleReport {
return if (shiftTimestampsToStartOfDay.get()) {
results.timestampsShiftedToStartOfDay(ZoneId.systemDefault())
} else {
results
var adjusted = results
if (shiftTimestampsToStartOfDay.get()) {
adjusted = results.timestampsShiftedToStartOfDay(ZoneId.systemDefault())
}
if (getMarks().getTotalTimeOfAllTests().enabled.get()) {
adjusted = adjusted.addTotalTimeOfAllTestsMark(getMarks().getTotalTimeOfAllTests().name.get())
}
return adjusted
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,11 @@ class TestsExecutionReportPlugin : Plugin<Project> {
.set(createTestsExecutionReportExtension.getFormats().getMermaid().outputLocation)

task.shiftTimestampsToStartOfDay.set(createTestsExecutionReportExtension.shiftTimestampsToStartOfDay)
task.getMarks().getTotalTimeOfAllTests().enabled.set(
createTestsExecutionReportExtension.getMarks().getTotalTimeOfAllTests().enabled
)
val name = createTestsExecutionReportExtension.getMarks().getTotalTimeOfAllTests().name.get()
require(name.isNotBlank()) { "marks.totalTimeOfAllTests.name cannot be blank" }
task.getMarks().getTotalTimeOfAllTests().name.set(name)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package io.github.platan.tests_execution_chart.config

import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import javax.inject.Inject

abstract class Mark @Inject constructor(objectFactory: ObjectFactory, name: String) {

@get:Input
val enabled: Property<Boolean> = objectFactory.property(Boolean::class.java).convention(false)

@get:Input
val name: Property<String> = objectFactory.property(String::class.java).convention(name)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.github.platan.tests_execution_chart.config

import org.gradle.api.Action
import org.gradle.api.tasks.Nested

abstract class Marks {

@Nested
abstract fun getTotalTimeOfAllTests(): TotalTimeOfAllTestsMark

open fun totalTimeOfAllTests(action: Action<in Mark>) {
action.execute(getTotalTimeOfAllTests())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.github.platan.tests_execution_chart.config

import org.gradle.api.model.ObjectFactory
import javax.inject.Inject

abstract class TotalTimeOfAllTestsMark @Inject constructor(objectFactory: ObjectFactory) :
Mark(objectFactory, "total time of all tests")
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.github.platan.tests_execution_chart.report

import kotlinx.serialization.Serializable
import java.time.Duration

@Serializable
data class Mark(
var name: String,
var timestamp: Long
) {
fun shiftTimestamps(timeShift: Duration): Mark {
return this.copy(timestamp = this.timestamp + timeShift.toMillis())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,29 @@ import java.time.ZoneId
import java.time.temporal.ChronoUnit

@Serializable
data class TestExecutionScheduleReport(val results: List<TimedTestResult>) {
data class TestExecutionScheduleReport(val results: List<TimedTestResult>, val marks: List<Mark>) {

constructor(results: List<TimedTestResult>) : this(results, emptyList())

fun timestampsShiftedToStartOfDay(zoneId: ZoneId): TestExecutionScheduleReport {
return when {
results.isEmpty() -> this
else -> {
val minStartTime = Instant.ofEpochMilli(results.minBy { it.startTime }.startTime)
val targetMinStartTime = minStartTime.atZone(zoneId).truncatedTo(ChronoUnit.DAYS).toInstant()
val timeShift = Duration.between(minStartTime, targetMinStartTime)
return TestExecutionScheduleReport(results.map { it.shiftTimestamps(timeShift) })
return TestExecutionScheduleReport(
results.map { it.shiftTimestamps(timeShift) },
marks.map { it.shiftTimestamps(timeShift) }
)
}
}
}

fun addTotalTimeOfAllTestsMark(markName: String): TestExecutionScheduleReport {
val minStartTime = results.minBy { it.startTime }.startTime
val totalDurationOfAllTestsMs = results.sumOf { it.durationMs }
val totalTimeOfAllTestsMark = minStartTime + totalDurationOfAllTestsMs
return this.copy(marks = listOf(Mark(markName, totalTimeOfAllTestsMark)))
}
}

This file was deleted.

Loading

0 comments on commit 5036976

Please sign in to comment.