Skip to content

Commit

Permalink
fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Stefano Sonzogni committed Jan 31, 2024
1 parent aeaa29b commit f848de1
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 37 deletions.
2 changes: 1 addition & 1 deletion .idea/runConfigurations/run_Service.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package eu.miaplatform.commons
import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.PropertyNamingStrategies.SNAKE_CASE
import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import com.fasterxml.jackson.module.kotlin.registerKotlinModule

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ kotlin.code.style=official
kotlin_version=1.9.22
ktor_version=2.3.7
retrofit_version=2.9.0
jackson_version=2.12.4
jackson_version=2.16.1
junit_version=5.7.2
100 changes: 68 additions & 32 deletions service/src/main/kotlin/eu/miaplatform/service/ServiceApplication.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package eu.miaplatform.service

import ch.qos.logback.classic.ClassicConstants
import ch.qos.logback.classic.util.ContextInitializer
import com.fasterxml.jackson.databind.exc.InvalidFormatException
import com.fasterxml.jackson.databind.exc.MismatchedInputException
import com.papsign.ktor.openapigen.OpenAPIGen
import com.papsign.ktor.openapigen.interop.withAPI
import com.papsign.ktor.openapigen.schema.builder.provider.DefaultObjectSchemaProvider
import com.papsign.ktor.openapigen.schema.namer.DefaultSchemaNamer
import com.papsign.ktor.openapigen.schema.namer.SchemaNamer
Expand All @@ -10,23 +14,31 @@ import eu.miaplatform.commons.StatusService
import eu.miaplatform.commons.client.CrudClientInterface
import eu.miaplatform.commons.client.RetrofitClient
import eu.miaplatform.commons.ktor.install
import eu.miaplatform.commons.model.BadRequestException
import eu.miaplatform.commons.model.InternalServerErrorException
import eu.miaplatform.commons.model.NotFoundException
import eu.miaplatform.commons.model.UnauthorizedException
import eu.miaplatform.service.applications.DocumentationApplication
import eu.miaplatform.service.applications.HealthApplication
import eu.miaplatform.service.applications.helloworld.HelloWorldApplication
import eu.miaplatform.service.core.openapi.CustomJacksonObjectSchemaProvider
import eu.miaplatform.service.model.ErrorResponse
import eu.miaplatform.service.services.HelloWorldService
import io.ktor.http.*
import io.ktor.serialization.jackson.*
import io.ktor.server.application.*
import io.ktor.server.logging.*
import io.ktor.server.netty.*
import io.ktor.server.plugins.callloging.*
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.server.plugins.statuspages.*
import io.ktor.server.request.*
import okhttp3.logging.HttpLoggingInterceptor
import org.slf4j.event.Level
import java.lang.reflect.InvocationTargetException
import kotlin.reflect.KType

fun main(args: Array<String>) {
System.setProperty(ContextInitializer.CONFIG_FILE_PROPERTY, System.getenv("LOG_CONFIG_FILE"))
System.setProperty(ClassicConstants.CONFIG_FILE_PROPERTY, System.getenv("LOG_CONFIG_FILE"))
EngineMain.main(args)
}

Expand All @@ -53,14 +65,26 @@ fun Application.module() {
install(HealthApplication())
}

/**
* Default implementation of Ktor of a log formatter. You can change this however you like to fit your needs.
*/
private fun customCallFormat(call: ApplicationCall): String =
when (val status = call.response.status() ?: "Unhandled") {
HttpStatusCode.Found -> "${status as HttpStatusCode}: " +
"${call.request.toLogString()} -> ${call.response.headers[HttpHeaders.Location]}"

"Unhandled" -> "${status}: ${call.request.toLogString()}"
else -> "${status as HttpStatusCode}: ${call.request.toLogString()}"
}

/**
* Install common functionalities like open api, logging, metrics, serialization, etc. for this application.
*/
fun Application.baseModule() {
install(CallLogging) {
level = Level.INFO
disableDefaultColors()
format {
customCallFormat(it)
}
// don't log calls to health
filter { call -> !call.request.path().startsWith("/-/") }
}
Expand Down Expand Up @@ -100,32 +124,44 @@ fun Application.baseModule() {
}
}

// install() {
// withAPI(api) {
// exception<UnauthorizedException, ErrorResponse>(HttpStatusCode.Unauthorized) {
// ErrorResponse(it.code, it.errorMessage)
// }
// exception<NotFoundException, ErrorResponse>(HttpStatusCode.NotFound) {
// ErrorResponse(it.code, it.errorMessage)
// }
// exception<BadRequestException, ErrorResponse>(HttpStatusCode.BadRequest) {
// ErrorResponse(it.code, it.errorMessage)
// }
// exception<MissingKotlinParameterException, ErrorResponse>(HttpStatusCode.BadRequest) {
// ErrorResponse(1000, it.localizedMessage)
// }
// exception<InvocationTargetException, ErrorResponse>(HttpStatusCode.BadRequest) {
// ErrorResponse(1000, it.targetException.localizedMessage)
// }
// exception<InvalidFormatException, ErrorResponse>(HttpStatusCode.BadRequest) {
// ErrorResponse(1000, it.localizedMessage)
// }
// exception<InternalServerErrorException, ErrorResponse>(HttpStatusCode.InternalServerError) {
// ErrorResponse(it.code, it.errorMessage)
// }
// exception<Exception, ErrorResponse>(HttpStatusCode.InternalServerError) {
// ErrorResponse(1000, it.localizedMessage ?: "Generic error")
// }
// }
// }
/**
* Intercept thrown exceptions and convert them to http responses
*
* note: the following statuses will be included as possible return values of all endpoints in the openapi doc
*/
install(StatusPages) {
withAPI(api) {
exception<UnauthorizedException, ErrorResponse>(HttpStatusCode.Unauthorized) {
ErrorResponse(it.code, it.errorMessage)
}
exception<NotFoundException, ErrorResponse>(HttpStatusCode.NotFound) {
ErrorResponse(it.code, it.errorMessage)
}
exception<io.ktor.server.plugins.NotFoundException, ErrorResponse>(HttpStatusCode.NotFound) {
ErrorResponse(1000, it.localizedMessage)
}
exception<BadRequestException, ErrorResponse>(HttpStatusCode.BadRequest) {
ErrorResponse(it.code, it.errorMessage)
}
exception<io.ktor.server.plugins.BadRequestException, ErrorResponse>(HttpStatusCode.BadRequest) {
ErrorResponse(1000, it.localizedMessage)
}
exception<MismatchedInputException, ErrorResponse>(HttpStatusCode.BadRequest) {
ErrorResponse(1000, it.localizedMessage)
}
exception<InvocationTargetException, ErrorResponse>(HttpStatusCode.BadRequest) {
ErrorResponse(1000, it.targetException.localizedMessage)
}
exception<InvalidFormatException, ErrorResponse>(HttpStatusCode.BadRequest) {
ErrorResponse(1000, it.localizedMessage)
}
exception<InternalServerErrorException, ErrorResponse>(HttpStatusCode.InternalServerError) {
ErrorResponse(it.code, it.errorMessage)
}
// generic interceptor
exception<Exception, ErrorResponse>(HttpStatusCode.InternalServerError) {
ErrorResponse(1000, it.localizedMessage ?: "Generic error")
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ class HelloWorldApplicationTest : DescribeSpec({
val servicePackage = "eu.miaplatform.service"
val expectedBody = objectMapper.writeValueAsString(
// if you change the package name, remember to update it in the following error or the test will fail
ErrorResponse(1000, "Instantiation of [simple type, class $servicePackage.model.request.HelloWorldRequestBody] value failed for JSON property surname due to missing (therefore NULL) value for creator parameter surname which is a non-nullable type\n at [Source: (InputStreamReader); line: 1, column: 15] (through reference chain: $servicePackage.model.request.HelloWorldRequestBody[\"surname\"])")
ErrorResponse(1000, "Failed to convert request body to class $servicePackage.model.request.HelloWorldRequestBody")
)
assertThat(response.content).isEqualTo(expectedBody)
}
Expand Down
5 changes: 3 additions & 2 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ enableFeaturePreview("VERSION_CATALOGS")
dependencyResolutionManagement {
repositories {
mavenCentral()
// maven { url 'https://jitpack.io' } // for papsign ktor open api generator
}

versionCatalogs {
Expand All @@ -17,7 +16,7 @@ dependencyResolutionManagement {
version('junit-jupiter', junit_version.toString())
alias('mockk').to('io.mockk','mockk').version('1.12.0')
alias('assertk').to('com.willowtreeapps.assertk','assertk-jvm').version('0.24')
alias('kotest').to('io.kotest','kotest-runner-junit5').version('5.0.0.M3')
alias('kotest').to('io.kotest','kotest-runner-junit5').version('5.8.0')
alias('junit-jupiter-api').to('org.junit.jupiter','junit-jupiter-api').versionRef('junit-jupiter')
alias('junit-jupiter-engine').to('org.junit.jupiter','junit-jupiter-engine').versionRef('junit-jupiter')
alias('junit-jupiter-params').to('org.junit.jupiter','junit-jupiter-params').versionRef('junit-jupiter')
Expand All @@ -31,6 +30,7 @@ dependencyResolutionManagement {
alias('ktor-logging').to('io.ktor','ktor-server-call-logging').versionRef('ktor')
alias('ktor-content-negotiation').to('io.ktor','ktor-server-content-negotiation').versionRef('ktor')
alias('ktor-jackson').to('io.ktor','ktor-serialization-jackson').versionRef('ktor')
alias('ktor-status-pages').to('io.ktor','ktor-server-status-pages').versionRef('ktor')
alias('ktor-openapi').to('dev.forst','ktor-openapi-generator').version('0.6.1')
bundle(
'impl-ktor',
Expand All @@ -41,6 +41,7 @@ dependencyResolutionManagement {
'ktor-logging',
'ktor-content-negotiation',
'ktor-jackson',
'ktor-status-pages',
'ktor-openapi'
]
)
Expand Down

0 comments on commit f848de1

Please sign in to comment.