Skip to content

Commit

Permalink
#42 - Introduce wrapper DTO and return duration of the run
Browse files Browse the repository at this point in the history
Needs more work, however start to decouple the persisted results model from the returned model.
  • Loading branch information
chadlwilson committed Oct 25, 2021
1 parent 2d4a77c commit 3377e61
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 33 deletions.
29 changes: 27 additions & 2 deletions src/main/kotlin/recce/server/api/DatasetRecRunController.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package recce.server.api

import com.fasterxml.jackson.annotation.JsonProperty
import io.micronaut.core.annotation.Introspected
import io.micronaut.http.annotation.Body
import io.micronaut.http.annotation.Controller
Expand All @@ -10,6 +11,9 @@ import mu.KotlinLogging
import reactor.core.publisher.Mono
import recce.server.dataset.DatasetRecRunner
import recce.server.dataset.RecRun
import recce.server.dataset.RecRunResults
import java.time.Duration
import java.time.Instant
import javax.validation.Valid
import javax.validation.constraints.NotBlank

Expand All @@ -19,11 +23,32 @@ private val logger = KotlinLogging.logger {}
@Controller("/runs")
class DatasetRecRunController(@Inject private val runner: DatasetRecRunner) {
@Post
fun create(@Body @Valid params: RunCreationParams): Mono<RecRun> {
fun create(@Body @Valid params: RunCreationParams): Mono<CompletedRun> {
logger.info { "Received request to create run for $params" }
return runner.runFor(params.datasetId)
return runner.runFor(params.datasetId).map { CompletedRun(it) }
}

@Introspected
data class RunCreationParams(@field:NotBlank val datasetId: String)

@Introspected
data class CompletedRun(
val id: Int,
val datasetId: String,
val createdTime: Instant,
val completedTime: Instant,
val results: RecRunResults,
) {
constructor(run: RecRun) : this(
id = run.id!!,
datasetId = run.datasetId,
createdTime = run.createdTime!!,
completedTime = run.completedTime!!,
results = run.results!!
)

@get:JsonProperty("completedDurationSeconds")
val completedDuration: Duration
get() = Duration.between(createdTime, completedTime)
}
}
28 changes: 28 additions & 0 deletions src/test/kotlin/recce/server/TestConfig.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package recce.server

import io.micronaut.context.annotation.Factory
import io.micronaut.runtime.server.EmbeddedServer
import io.restassured.RestAssured
import io.restassured.builder.RequestSpecBuilder
import io.restassured.config.JsonConfig
import io.restassured.filter.log.ResponseLoggingFilter
import io.restassured.http.ContentType
import io.restassured.path.json.config.JsonPathConfig
import io.restassured.specification.RequestSpecification
import jakarta.inject.Singleton

@Factory
class TestConfig {
@Singleton
fun restAssuredSpec(server: EmbeddedServer): RequestSpecification {
// Yes, this is static configuration; seems no other way to do it with RestAssured
RestAssured.config = RestAssured.config()
.jsonConfig(JsonConfig.jsonConfig().numberReturnType(JsonPathConfig.NumberReturnType.DOUBLE))

return RequestSpecBuilder()
.setContentType(ContentType.JSON)
.setBaseUri(server.uri)
.addFilter(ResponseLoggingFilter())
.build()
}
}
55 changes: 24 additions & 31 deletions src/test/kotlin/recce/server/api/DatasetRecRunControllerTest.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
package recce.server.api

import io.micronaut.runtime.server.EmbeddedServer
import io.micronaut.test.annotation.MockBean
import io.micronaut.test.extensions.junit5.annotation.MicronautTest
import io.restassured.builder.RequestSpecBuilder
import io.restassured.filter.log.ResponseLoggingFilter
import io.restassured.http.ContentType
import io.restassured.module.kotlin.extensions.Extract
import io.restassured.module.kotlin.extensions.Given
import io.restassured.module.kotlin.extensions.Then
Expand All @@ -14,8 +10,8 @@ import io.restassured.specification.RequestSpecification
import jakarta.inject.Inject
import org.apache.http.HttpStatus
import org.assertj.core.api.Assertions.assertThat
import org.hamcrest.Matchers.closeTo
import org.hamcrest.Matchers.equalTo
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.eq
Expand All @@ -26,54 +22,51 @@ import recce.server.dataset.DatasetRecRunner
import recce.server.dataset.DatasetRecService
import recce.server.dataset.RecRun
import recce.server.dataset.RecRunResults
import java.time.Duration
import java.time.LocalDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter

internal class DatasetRecRunControllerTest {

private val testDataset = "testDataset"
private val testDataset = "testDataset"
private val testCompletedDuration = Duration.ofMinutes(3).plusNanos(234)
private val testResults = RecRun(
id = 12,
datasetId = testDataset,
createdTime = LocalDateTime.of(2021, 10, 25, 16, 16, 16).toInstant(ZoneOffset.UTC),
).apply {
completedTime = createdTime?.plusNanos(testCompletedDuration.toNanos())
updatedTime = completedTime?.plusSeconds(10)
results = RecRunResults(2000, 3000)
}

internal class DatasetRecRunControllerTest {
private val service = mock<DatasetRecService> {
on { runFor(eq(testDataset)) } doReturn Mono.just(RecRun(testDataset))
on { runFor(eq(testDataset)) } doReturn Mono.just(testResults)
}

private val controller = DatasetRecRunController(service)

@Test
fun `controller should delegate to service`() {
StepVerifier.create(controller.create(DatasetRecRunController.RunCreationParams(eq(testDataset))))
.expectNext(RecRun(testDataset))
.assertNext {
assertThat(it.id).isEqualTo(testResults.id)
assertThat(it.datasetId).isEqualTo(testResults.datasetId)
assertThat(it.createdTime).isEqualTo(testResults.createdTime)
assertThat(it.completedTime).isEqualTo(testResults.completedTime)
assertThat(it.completedDuration).isEqualTo(testCompletedDuration)
assertThat(it.results).isEqualTo(testResults.results)
}
.verifyComplete()
}
}

@MicronautTest
internal class DatasetRecRunControllerApiTest {
private val testDataset = "testDataset"
private val testResults = RecRun(
id = 12,
datasetId = testDataset,
createdTime = LocalDateTime.of(2021, 10, 25, 16, 16, 16).toInstant(ZoneOffset.UTC),
).apply {
completedTime = createdTime?.plusSeconds(180)
updatedTime = completedTime?.plusSeconds(10)
results = RecRunResults(2000, 3000)
}

@Inject
lateinit var server: EmbeddedServer
lateinit var spec: RequestSpecification

@BeforeEach
fun setUp() {
spec = RequestSpecBuilder()
.setContentType(ContentType.JSON)
.setBaseUri(server.uri)
.addFilter(ResponseLoggingFilter())
.build()
}

@Test
fun `controller should delegate to service`() {
Given {
Expand All @@ -87,7 +80,7 @@ internal class DatasetRecRunControllerApiTest {
body("id", equalTo(testResults.id))
body("createdTime", equalTo(DateTimeFormatter.ISO_INSTANT.format(testResults.createdTime)))
body("completedTime", equalTo(DateTimeFormatter.ISO_INSTANT.format(testResults.completedTime)))
body("updatedTime", equalTo(DateTimeFormatter.ISO_INSTANT.format(testResults.updatedTime)))
body("completedDurationSeconds", closeTo(testCompletedDuration.toSeconds().toDouble(), 0.00001))
body("results.sourceRows", equalTo(testResults.results?.sourceRows?.toInt()))
body("results.targetRows", equalTo(testResults.results?.targetRows?.toInt()))
}
Expand Down

0 comments on commit 3377e61

Please sign in to comment.