Skip to content

Commit

Permalink
Merge pull request #96 from craigatk/info-message
Browse files Browse the repository at this point in the history
(feature) Can display messages on test report dashboard
  • Loading branch information
craigatk authored May 21, 2020
2 parents 0706f71 + c5ff555 commit c3c65a2
Show file tree
Hide file tree
Showing 20 changed files with 400 additions and 115 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package projektor.server.api.messages

data class Messages(val messages: List<String>)
6 changes: 5 additions & 1 deletion server/server-app/src/main/kotlin/projektor/AppModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import projektor.incomingresults.TestResultsProcessingService
import projektor.incomingresults.TestResultsService
import projektor.incomingresults.processing.ResultsProcessingDatabaseRepository
import projektor.incomingresults.processing.ResultsProcessingRepository
import projektor.message.MessageConfig
import projektor.message.MessageService
import projektor.metrics.MetricsService
import projektor.parser.grouped.GroupedResultsParser
import projektor.results.processor.TestResultsProcessor
Expand All @@ -38,7 +40,8 @@ fun createAppModule(
dataSource: HikariDataSource,
authConfig: AuthConfig,
dslContext: DSLContext,
metricRegistry: MeterRegistry
metricRegistry: MeterRegistry,
messageConfig: MessageConfig
) = module {
single { dataSource }
single { TestResultsProcessor() }
Expand All @@ -55,6 +58,7 @@ fun createAppModule(
single { GroupedResultsParser() }
single { GroupedResultsConverter(get(), get()) }
single { GroupedTestResultsService(get(), get(), get(), get(), get()) }
single { MessageService(messageConfig) }
single { TestCaseService(get()) }
single { TestSuiteService(get()) }
single { TestResultsProcessingService(get()) }
Expand Down
8 changes: 7 additions & 1 deletion server/server-app/src/main/kotlin/projektor/Application.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ import projektor.incomingresults.GroupedTestResultsService
import projektor.incomingresults.TestResultsProcessingService
import projektor.incomingresults.TestResultsService
import projektor.incomingresults.processing.ResultsProcessingRepository
import projektor.message.MessageConfig
import projektor.message.MessageService
import projektor.metrics.InfluxMetricsConfig
import projektor.metrics.createRegistry
import projektor.route.*
Expand All @@ -59,7 +61,9 @@ fun Application.main() {

val cleanupConfig = CleanupConfig.createCleanupConfig(applicationConfig)

val appModule = createAppModule(dataSource, authConfig, dslContext, metricRegistry)
val messageConfig = MessageConfig.createMessageConfig(applicationConfig)

val appModule = createAppModule(dataSource, authConfig, dslContext, metricRegistry, messageConfig)

install(CORS) {
anyHost()
Expand Down Expand Up @@ -109,6 +113,7 @@ fun Application.main() {
}

val authService: AuthService by inject()
val messageService: MessageService by inject()
val testResultsService: TestResultsService by inject()
val groupedTestResultsService: GroupedTestResultsService by inject()
val testResultsProcessingService: TestResultsProcessingService by inject()
Expand All @@ -131,6 +136,7 @@ fun Application.main() {
attachments(attachmentService, authService)
config(cleanupConfig)
health()
messages(messageService)
results(testResultsService, groupedTestResultsService, testResultsProcessingService, authService, metricRegistry)
testCases(testCaseService)
testSuites(testSuiteService)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package projektor.message

import io.ktor.config.ApplicationConfig
import io.ktor.util.KtorExperimentalAPI

@KtorExperimentalAPI
data class MessageConfig(val globalMessages: List<String>) {

companion object {
fun createMessageConfig(applicationConfig: ApplicationConfig): MessageConfig {
val messageString = applicationConfig.propertyOrNull("ktor.message.global")?.getString()
val messages = messageString?.let { it.split("|") } ?: listOf()

return MessageConfig(messages)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package projektor.message

import io.ktor.util.KtorExperimentalAPI
import projektor.server.api.PublicId
import projektor.server.api.messages.Messages

@KtorExperimentalAPI
class MessageService(private val messageConfig: MessageConfig) {

fun getTestRunMessages(publicId: PublicId): Messages {
return Messages(messageConfig.globalMessages)
}
}
20 changes: 20 additions & 0 deletions server/server-app/src/main/kotlin/projektor/route/MessageRoutes.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package projektor.route

import io.ktor.application.call
import io.ktor.http.HttpStatusCode
import io.ktor.response.respond
import io.ktor.routing.Route
import io.ktor.routing.get
import io.ktor.util.KtorExperimentalAPI
import io.ktor.util.getOrFail
import projektor.message.MessageService
import projektor.server.api.PublicId

@KtorExperimentalAPI
fun Route.messages(messageService: MessageService) {
get("/run/{publicId}/messages") {
val publicId = call.parameters.getOrFail("publicId")

call.respond(HttpStatusCode.OK, messageService.getTestRunMessages(PublicId(publicId)))
}
}
4 changes: 4 additions & 0 deletions server/server-app/src/main/resources/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,8 @@ ktor {
environment = ${?METRICS_INFLUXDB_ENV}
}
}

message {
global = ${?GLOBAL_MESSAGES}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ open class ApplicationTestCase {
protected var metricsUsername: String? = null
protected var metricsPassword: String? = null

protected var globalMessages: String? = null

fun createTestApplication(application: Application) {
val schema = databaseSchema

Expand Down Expand Up @@ -98,6 +100,8 @@ open class ApplicationTestCase {
metricsUsername?.let { username -> put("ktor.metrics.influxdb.username", username) }
metricsPassword?.let { password -> put("ktor.metrics.influxdb.password", password) }
}

globalMessages?.let { put("ktor.message.global", it) }
}

application.main()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import org.koin.test.KoinTest
import projektor.auth.AuthConfig
import projektor.database.DataSourceConfig
import projektor.database.generated.tables.daos.*
import projektor.message.MessageConfig
import projektor.metrics.InfluxMetricsConfig
import projektor.metrics.createRegistry

Expand Down Expand Up @@ -70,7 +71,8 @@ open class DatabaseRepositoryTestCase : KoinTest {
dataSource,
AuthConfig(null),
dslContext,
createRegistry(metricsConfig)
createRegistry(metricsConfig),
MessageConfig(listOf())
))
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package projektor.message

import io.ktor.http.HttpMethod
import io.ktor.http.HttpStatusCode
import io.ktor.server.testing.handleRequest
import io.ktor.server.testing.withTestApplication
import io.ktor.util.KtorExperimentalAPI
import kotlin.test.assertNotNull
import org.junit.jupiter.api.Test
import projektor.ApplicationTestCase
import projektor.incomingresults.randomPublicId
import projektor.server.api.messages.Messages
import strikt.api.expectThat
import strikt.assertions.contains
import strikt.assertions.hasSize
import strikt.assertions.isEqualTo

@KtorExperimentalAPI
class MessageApplicationTest : ApplicationTestCase() {

@Test
fun `when single global message should return it`() {
val publicId = randomPublicId()

globalMessages = "Here is a global message"

withTestApplication(::createTestApplication) {
handleRequest(HttpMethod.Get, "/run/$publicId/messages")
.apply {
expectThat(response.status()).isEqualTo(HttpStatusCode.OK)

val messagesResponse = objectMapper.readValue(response.content, Messages::class.java)
assertNotNull(messagesResponse)

expectThat(messagesResponse.messages)
.hasSize(1)
.contains("Here is a global message")
}
}
}

@Test
fun `when two global messages should return them`() {
val publicId = randomPublicId()

globalMessages = "First global message|Second global message"

withTestApplication(::createTestApplication) {
handleRequest(HttpMethod.Get, "/run/$publicId/messages")
.apply {
expectThat(response.status()).isEqualTo(HttpStatusCode.OK)

val messagesResponse = objectMapper.readValue(response.content, Messages::class.java)
assertNotNull(messagesResponse)

expectThat(messagesResponse.messages)
.hasSize(2)
.contains("First global message")
.contains("Second global message")
}
}
}

@Test
fun `when no messages should return empty list`() {
val publicId = randomPublicId()

globalMessages = null

withTestApplication(::createTestApplication) {
handleRequest(HttpMethod.Get, "/run/$publicId/messages")
.apply {
expectThat(response.status()).isEqualTo(HttpStatusCode.OK)

val messagesResponse = objectMapper.readValue(response.content, Messages::class.java)
assertNotNull(messagesResponse)

expectThat(messagesResponse.messages)
.hasSize(0)
}
}
}
}
1 change: 1 addition & 0 deletions ui/cypress/fixtures/messages/no_messages.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "messages": [] }
1 change: 1 addition & 0 deletions ui/cypress/fixtures/messages/one_message.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "messages": ["Here is one message"] }
54 changes: 54 additions & 0 deletions ui/cypress/integration/messages.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/// <reference types="Cypress" />

context("test run messages", () => {
it("when one messages should show it on dashboard page", () => {
const publicId = "12345";

cy.server();

cy.route(
"GET",
`run/${publicId}/summary`,
"fixture:one_passing/test_run_summary.json"
);
cy.route("GET", `run/${publicId}`, "fixture:one_passing/test_run.json");

cy.route(
"GET",
`run/${publicId}/messages`,
"fixture:messages/one_message.json"
);

cy.visit(`http://localhost:1234/tests/${publicId}`);

cy.getByTestId("test-run-message-1").should(
"contain",
"Here is one message"
);
});

it("when no messages should not display any dashboard page", () => {
const publicId = "12345";

cy.server();

cy.route(
"GET",
`run/${publicId}/summary`,
"fixture:one_passing/test_run_summary.json"
);
cy.route("GET", `run/${publicId}`, "fixture:one_passing/test_run.json");

cy.route(
"GET",
`run/${publicId}/messages`,
"fixture:messages/no_messages.json"
);

cy.visit(`http://localhost:1234/tests/${publicId}`);

cy.testIdShouldExist("test-run-messages");

cy.testIdShouldNotExist("test-run-message-1");
});
});
3 changes: 2 additions & 1 deletion ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@
"typescript": "3.7.4"
},
"dependencies": {
"@material-ui/core": "4.8.3",
"@material-ui/core": "4.9.14",
"@material-ui/icons": "4.4.3",
"@material-ui/lab": "4.0.0-alpha.53",
"@reach/router": "1.2.1",
"@types/axios-case-converter": "0.3.1",
"@types/node": "12.11.1",
Expand Down
15 changes: 7 additions & 8 deletions ui/src/CodeText/CodeTextLine.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import styled from 'styled-components'
import styled from "styled-components";

interface CodeTextLineProps {
line: String;
Expand All @@ -14,11 +14,12 @@ interface CodeTextLineStyleProps {

const Line = styled.div<CodeTextLineStyleProps>`
cursor: default;
background-color: ${({highlighted}) => (highlighted ? "#F9F9F9": "inherit")};
background-color: ${({ highlighted }) =>
highlighted ? "#F9F9F9" : "inherit"};
&:hover {
background-color: lightgrey;
}
font-size: .9em;
font-size: 0.9em;
display: inline-block;
width: 100%;
padding-right: 10px;
Expand All @@ -29,8 +30,8 @@ const LineNumber = styled.span`
min-width: 40px;
display: inline-block;
text-align: right;
padding-Right: 15px;
`
padding-right: 15px;
`;

const CodeTextLine = ({
line,
Expand All @@ -48,9 +49,7 @@ const CodeTextLine = ({
data-testid={`code-text-line-${idx}-${highlighted}`}
highlighted={highlighted}
>
<LineNumber
data-testid={`code-text-line-number-${idx}`}
>
<LineNumber data-testid={`code-text-line-number-${idx}`}>
{idx}
</LineNumber>
<span data-testid={`code-text-line-content-${idx}`}>{line}</span>
Expand Down
2 changes: 2 additions & 0 deletions ui/src/Dashboard/DashboardSummary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import PageTitle from "../PageTitle";
import TestRunDuration from "./TestRunDuration";
import TestRunDate from "./TestRunDate";
import TestRunCleanupDate from "./TestRunCleanupDate";
import TestRunMessages from "../TestRunMessages/TestRunMessages";

interface DashboardSummaryProps {
publicId: string;
Expand Down Expand Up @@ -36,6 +37,7 @@ const DashboardSummary = ({
return (
<div>
<PageTitle title="Tests" testid="dashboard-summary-title" />
<TestRunMessages publicId={publicId} />
<Grid container>
<Grid item sm={3} xs={12}>
<TestCountList
Expand Down
Loading

0 comments on commit c3c65a2

Please sign in to comment.