Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Structure timestamps #8

Merged
merged 43 commits into from
Mar 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
a73143a
WIP: include h2 database for logging of timestamps
florianluediger Mar 6, 2018
10d250b
updated jpa and ref<actoring
silasmahler Mar 6, 2018
f3e6da2
update h2 and data jpa dependencies
silasmahler Mar 10, 2018
88d544f
Merge branch 'update-jpa-and-h2' into structure_timestamps
silasmahler Mar 10, 2018
d6aaf2c
Merge branch 'update-jpa-and-h2'
silasmahler Mar 10, 2018
f5f41c5
update repositoryname and eventtype
silasmahler Mar 11, 2018
d192a33
remove testcode
silasmahler Mar 11, 2018
ff3e428
rename classes
silasmahler Mar 11, 2018
b8ab6a5
add service and adjust extension to use service
silasmahler Mar 11, 2018
1b63ee8
add more output and use for service
silasmahler Mar 11, 2018
250ee65
move injection to constructor
silasmahler Mar 11, 2018
0319447
remove componentscan
silasmahler Mar 11, 2018
94b08e6
add annotation for extension
silasmahler Mar 11, 2018
759eeb6
remove imports
silasmahler Mar 12, 2018
2f8736a
asjust to jpa repository
silasmahler Mar 12, 2018
9fe3e9f
adjust build gradle
silasmahler Mar 12, 2018
6672d74
add springextension to male mockmvc working with junit5
silasmahler Mar 12, 2018
413a1cd
add new test
silasmahler Mar 12, 2018
3965c88
add more targets
silasmahler Mar 12, 2018
9ae6591
refactore extension and logger
silasmahler Mar 12, 2018
1338092
update readme
silasmahler Mar 12, 2018
6fa175b
refactored folders and code
silasmahler Mar 12, 2018
c8edecd
replaced controller
silasmahler Mar 12, 2018
4dee8d4
refactored timestampevent
silasmahler Mar 12, 2018
e5c8627
refactoring timestampevent #2
silasmahler Mar 12, 2018
163d23c
refactor event #3
silasmahler Mar 12, 2018
98588af
refactoring so noarg-constructor for jpa is generated
silasmahler Mar 12, 2018
146bdb1
add nobenchmark if needed
silasmahler Mar 12, 2018
25b69cc
Reformat code
florianluediger Mar 15, 2018
303aed6
Fix typos
florianluediger Mar 15, 2018
447f993
Add jaxb dependency which in some cases is not included in the other …
florianluediger Mar 15, 2018
e54c410
Add # symbol to log output
florianluediger Mar 15, 2018
c16e9ac
Delete obsolte JUnit extension
florianluediger Mar 15, 2018
47d56fe
Merge branch 'master' into structure_timestamps
florianluediger Mar 15, 2018
2408a77
Remove all database interactions and write the timestamps directly to…
florianluediger Mar 16, 2018
54f5460
Remove obsolete gradle dependencies
florianluediger Mar 16, 2018
6ff8b84
Fix minor code style warnings
florianluediger Mar 16, 2018
83c3aab
Add test containing a delay
florianluediger Mar 16, 2018
3774502
Add delta mode and log output to the timestamp writer class
florianluediger Mar 16, 2018
f060a2b
Fix order of first line in csv output file
florianluediger Mar 16, 2018
277bc70
Remove unnecessary class keyword in the csv file
florianluediger Mar 21, 2018
5e7e42d
Flush file after each test class, so tests that don't use the spring …
florianluediger Mar 22, 2018
3e47851
Remove class name from method name in the csv file
florianluediger Mar 23, 2018
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.gradle
/build/
!gradle/wrapper/gradle-wrapper.jar
*.csv

### Java ###
.class
Expand Down
35 changes: 26 additions & 9 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,23 @@ buildscript {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
classpath "org.jetbrains.kotlin:kotlin-noarg:${kotlinVersion}"
}
}

ext.junit4Version = '4.12'
ext.junitVintageVersion = '4.12.0'
ext.junitPlatformVersion = '1.1.0'
ext.junitJupiterVersion = '5.1.0'
ext.log4jVersion = '2.6.2'

apply plugin: 'kotlin'
apply plugin: 'kotlin-spring'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'maven-publish'
apply plugin: "kotlin-jpa"

publishing {
publications {
Expand Down Expand Up @@ -69,13 +77,22 @@ dependencies {
compile('com.fasterxml.jackson.module:jackson-module-kotlin')
compile('org.jetbrains.kotlin:kotlin-stdlib-jdk8')
compile('org.jetbrains.kotlin:kotlin-reflect')
compile('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'junit', module: 'junit'
}
compile('org.junit.jupiter:junit-jupiter-api')
runtime('org.springframework.boot:spring-boot-devtools')
testCompile('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'junit', module: 'junit'
}
testCompile('org.junit.jupiter:junit-jupiter-api')

compile('org.springframework.boot:spring-boot-starter-test') { exclude group: 'junit', module: 'junit' }
testCompile('org.springframework.boot:spring-boot-starter-test') { exclude group: 'junit', module: 'junit' }

// JUnit Jupiter API and TestEngine implementation
compile("org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}")
testCompile("org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}")
testRuntime("org.junit.jupiter:junit-jupiter-engine:${junitJupiterVersion}")

// If you also want to support JUnit 3 and JUnit 4 tests
//testCompile("junit:junit:${junit4Version}")
//testRuntime("org.junit.vintage:junit-vintage-engine:${junitVintageVersion}")

testRuntime("org.apache.logging.log4j:log4j-core:${log4jVersion}")
testRuntime("org.apache.logging.log4j:log4j-jul:${log4jVersion}")

// Only needed to run tests in an IDE that bundles an older version (e.g. IntelliJ)
testRuntime("org.junit.platform:junit-platform-launcher:${junitPlatformVersion}")
}
8 changes: 7 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,10 @@ For the user of the test classes, it looks like some tests take a long time to e
To make this behavior transparent, a report is created.

# How to use
ToDo

Add the dependency to your project.

`//TODO`

Add @JUnitInsights to the test-classes you want to benchmark.
Be aware that ExtendsWith(SpringExtension::class) needs to be used as Runner-class.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication

@SpringBootApplication
open class JunitInsightsApplication
class JunitInsightsApplication

fun main(args: Array<String>) {
runApplication<JunitInsightsApplication>(*args)
Expand Down
29 changes: 0 additions & 29 deletions src/main/kotlin/de/adesso/junitinsights/SpringContextListeners.kt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package de.adesso.junitinsights.annotations

import de.adesso.junitinsights.tests.TestBenchmarkExtension
import org.junit.jupiter.api.extension.ExtendWith

/**
* Annotate your test classes with this method to activate JUnit-insights.
*/
@Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS)
@Retention(value = AnnotationRetention.RUNTIME)
@ExtendWith(TestBenchmarkExtension::class)
annotation class JUnitInsights
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package de.adesso.junitinsights.annotations

/**
* Annotate the functions you don't want to have insights about with this and they won't be benchmarked.
*/
@Target(AnnotationTarget.FUNCTION)
@Retention(value = AnnotationRetention.RUNTIME)
annotation class NoJUnitInsights
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package de.adesso.junitinsights
package de.adesso.junitinsights.example

import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
Expand All @@ -7,7 +7,7 @@ import org.springframework.web.bind.annotation.RestController
class HelloController {

@RequestMapping("/")
fun index() : String {
fun index(): String {
return "Greetings from Spring Boot!"
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package de.adesso.junitinsights.listener

import de.adesso.junitinsights.tools.TimestampWriter
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.context.event.ContextClosedEvent
import org.springframework.context.event.ContextRefreshedEvent
import org.springframework.context.event.EventListener
import org.springframework.stereotype.Component

@Component
class SpringContextListener {

companion object {
val log: Logger = LoggerFactory.getLogger(this::class.java)
}

private val timestampWriter = TimestampWriter

@EventListener(ContextRefreshedEvent::class)
fun catchContextStart(event: ContextRefreshedEvent) {
//log.info("### AppContextId: ${event.applicationContext.id}")
//TODO Check if first init before closing initial, so that its not a refresh
timestampWriter.writeTimestamp(System.currentTimeMillis(),
"context refreshed",
"", "")
}

@EventListener(ContextClosedEvent::class)
fun catchContextEnd(event: ContextClosedEvent) {
//log.info("### AppContextId: ${event.applicationContext.id}")
timestampWriter.writeTimestamp(System.currentTimeMillis(),
"context closed",
"", "")
//TODO: Is this method really called only once at the end?
timestampWriter.flush()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package de.adesso.junitinsights.tests

import de.adesso.junitinsights.annotations.NoJUnitInsights
import de.adesso.junitinsights.tools.TimestampWriter
import org.junit.jupiter.api.extension.*
import org.junit.platform.commons.support.AnnotationSupport.isAnnotated


/**
* Extension that measures the execution time of each test class and method
*
*/
class TestBenchmarkExtension :
BeforeAllCallback, AfterAllCallback,
BeforeEachCallback, AfterEachCallback,
BeforeTestExecutionCallback, AfterTestExecutionCallback {

private val timestampWriter = TimestampWriter

override fun beforeAll(context: ExtensionContext) {
if (shouldNotBeBenchmarked(context)) {
return
}
timestampWriter.writeTimestamp(System.currentTimeMillis(),
"before all",
trimClassName(context),
trimMethodName(context))
}

override fun afterAll(context: ExtensionContext) {
if (shouldNotBeBenchmarked(context)) {
return
}
timestampWriter.writeTimestamp(System.currentTimeMillis(),
"after all",
trimClassName(context),
trimMethodName(context))
timestampWriter.flush()
}

override fun beforeEach(context: ExtensionContext) {
if (shouldNotBeBenchmarked(context)) {
return
}
timestampWriter.writeTimestamp(System.currentTimeMillis(),
"before each",
trimClassName(context),
trimMethodName(context))
}

override fun afterEach(context: ExtensionContext) {
if (shouldNotBeBenchmarked(context)) {
return
}
timestampWriter.writeTimestamp(System.currentTimeMillis(),
"after each",
trimClassName(context),
trimMethodName(context))
}

@Throws(Exception::class)
override fun beforeTestExecution(context: ExtensionContext) {
if (shouldNotBeBenchmarked(context)) {
return
}
timestampWriter.writeTimestamp(System.currentTimeMillis(),
"before test execution",
trimClassName(context),
trimMethodName(context))
}

@Throws(Exception::class)
override fun afterTestExecution(context: ExtensionContext) {
if (shouldNotBeBenchmarked(context)) {
return
}
timestampWriter.writeTimestamp(System.currentTimeMillis(),
"after test execution",
trimClassName(context),
trimMethodName(context))
}

private fun shouldNotBeBenchmarked(context: ExtensionContext): Boolean {
return context.element
.map<Boolean> { el -> isAnnotated(el, NoJUnitInsights::class.java) }
.orElse(false)
}

private fun trimClassName(testContext: ExtensionContext): String {
return testContext.testClass.toString().replace("class", "")
}

private fun trimMethodName(testContext: ExtensionContext): String {
val splitName = testContext.testMethod.toString().split(".")
return if (splitName.isEmpty()) "" else splitName.last()
}
}
47 changes: 47 additions & 0 deletions src/main/kotlin/de/adesso/junitinsights/tools/TimestampWriter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package de.adesso.junitinsights.tools

import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.io.File

var deltaMode = false
var logOutput = false

object TimestampWriter {
private var file = File("timestamps.csv").bufferedWriter()
private var lastTimestamp: Long = 0

private var logger: Logger = LoggerFactory.getLogger(this::class.java)

init {
file.write("timestamp;event;test class;test function")
file.newLine()
}

fun writeTimestamp(timestamp: Long, event: String, testClass: String, testFunction: String) {
var tstamp: Long = timestamp
if (deltaMode) {
if (lastTimestamp == 0.toLong()) {
lastTimestamp = timestamp
} else {
tstamp = timestamp - lastTimestamp
lastTimestamp = timestamp
}
}
file.write(tstamp.toString() + ";" + event + ";" + trimObjectString(testClass) + ";" + trimObjectString(testFunction))
file.newLine()
if (logOutput)
logger.info("########" + tstamp.toString() + ";" + event + ";" + trimObjectString(testClass) + ";" + trimObjectString(testFunction) + "\n")
}

fun flush() {
file.flush()
}

private fun trimObjectString(string: String): String {
return string.replace("Optional.empty", "")
.replace("Optional", "")
.replace("[", "")
.replace("]", "")
}
}
Loading