Permalink
Browse files

Fix http4k setup files, and add undertow server backend, database and…

… fortunes tests (#2822)

* adding undertow implementation

* fixes to setup scripts

* fixes to setup scripts

* fixes to setup scripts

* fixes to setup scripts

* fixes to setup scripts

* fixes to setup scripts

* upgrade version of http4k

* adding fortunes and worlds tests

* some fixes for database driver

* fix number of records returned

* set content type on view

* set content type on json

* fix max and min

* adding new fortune to list and sorting result
  • Loading branch information...
daviddenton authored and nbrady-techempower committed May 29, 2017
1 parent 40a6222 commit 169900b62b3b63cb6c45ab4a301efe4e30bfde8d
@@ -1,3 +1,3 @@
FROM mysql
FROM postgres
ADD create.sql /docker-entrypoint-initdb.d/
@@ -11,6 +11,11 @@ The tests were run with:
- JSON Encoding: http://localhost:9000/json
- Plaintext: http://localhost:9000/plaintext
## Supported backends
- Jetty
- Netty
- Undertow
## How to run
```bash
./gradlew clean build jetty
@@ -3,18 +3,22 @@
"tests": [
{
"default": {
"setup_file": "setup_jetty",
"orm": "Raw",
"database_os": "Linux",
"setup_file": "setup_jetty",
"db_url": "/db",
"fortune_url": "/fortunes",
"query_url": "/queries?queries=",
"update_url": "/updates?queries=",
"database": "postgres",
"json_url": "/json",
"plaintext_url": "/plaintext",
"port": 9000,
"approach": "Realistic",
"classification": "Micro",
"database": "None",
"framework": "http4k",
"language": "Kotlin",
"platform": "Servlet",
"platform": "servlet",
"webserver": "None",
"os": "Linux",
"display_name": "http4k-jetty",
@@ -23,25 +27,54 @@
}
},
{
"default": {
"netty": {
"setup_file": "setup_netty",
"orm": "Raw",
"database_os": "Linux",
"setup_file": "setup_netty",
"db_url": "/db",
"fortune_url": "/fortunes",
"query_url": "/queries?queries=",
"update_url": "/updates?queries=",
"database": "postgres",
"json_url": "/json",
"plaintext_url": "/plaintext",
"port": 9000,
"approach": "Realistic",
"classification": "Micro",
"database": "None",
"framework": "http4k",
"language": "Kotlin",
"platform": "Netty",
"platform": "netty",
"webserver": "None",
"os": "Linux",
"display_name": "http4k-netty",
"notes": "",
"versus": "netty"
}
},
{
"undertow": {
"setup_file": "setup_undertow",
"orm": "Raw",
"database_os": "Linux",
"db_url": "/db",
"fortune_url": "/fortunes",
"query_url": "/queries?queries=",
"update_url": "/updates?queries=",
"database": "postgres",
"json_url": "/json",
"plaintext_url": "/plaintext",
"port": 9000,
"approach": "Realistic",
"classification": "Micro",
"framework": "http4k",
"language": "Kotlin",
"platform": "undertow",
"webserver": "None",
"os": "Linux",
"display_name": "http4k-undertow",
"notes": "",
"versus": "undertow"
}
}
]
}
@@ -1,6 +1,6 @@
buildscript {
ext.kotlin_version = "1.1.2"
ext.http4k_version = "0.20.0"
ext.kotlin_version = "1.1.2-4"
ext.http4k_version = "1.23.0"
repositories {
mavenCentral()
jcenter()
@@ -24,13 +24,16 @@ sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
dependencies {
compile "org.apache.commons:commons-lang3:3.5"
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compile "org.http4k:http4k-core:$http4k_version"
compile "org.http4k:http4k-contract:$http4k_version"
compile "org.http4k:http4k-format-jackson:$http4k_version"
compile "org.http4k:http4k-server-jetty:$http4k_version"
compile "org.http4k:http4k-server-netty:$http4k_version"
compile "org.http4k:http4k-server-undertow:$http4k_version"
compile "org.http4k:http4k-template-handlebars:$http4k_version"
compile "org.apache.commons:commons-lang3:3.5"
compile "com.zaxxer:HikariCP:2.6.1"
compile "org.postgresql:postgresql:42.0.0"
}
task jetty(type: OneJar) {
@@ -39,4 +42,7 @@ task jetty(type: OneJar) {
task netty(type: OneJar) {
mainClass = 'Http4kNettyServerKt'
}
task undertow(type: OneJar) {
mainClass = 'Http4kUndertowServerKt'
}
@@ -1,8 +1,7 @@
#!/bin/bash
fw_depends mysql java
fw_depends postgresql java
gradle wrapper
./gradlew clean build jetty
gradle clean build jetty
java -server -XX:+UseNUMA -XX:+UseParallelGC -XX:+AggressiveOpts -XX:+AlwaysPreTouch -jar build/libs/http4k-standalone.jar &
@@ -1,8 +1,7 @@
#!/bin/bash
fw_depends mysql java
fw_depends postgresql java
gradle wrapper
./gradlew clean build netty
gradle clean build netty
java -server -XX:+UseNUMA -XX:+UseParallelGC -XX:+AggressiveOpts -XX:+AlwaysPreTouch -jar build/libs/http4k-standalone.jar &
@@ -0,0 +1,7 @@
#!/bin/bash
fw_depends postgresql java
./gradlew clean build undertow
java -server -XX:+UseNUMA -XX:+UseParallelGC -XX:+AggressiveOpts -XX:+AlwaysPreTouch -jar build/libs/http4k-standalone.jar &
@@ -1,4 +1,9 @@
http4k/src/main/scala/
http4k/src/main/scala/Http4kBenchmarkServer.kt
http4k/src/main/scala/Http4kJettyServer.kt
http4k/src/main/scala/Http4kNettyServer.kt
http4k/src/main/kotlin/Database.kt
http4k/src/main/kotlin/FortunesRoute.kt
http4k/src/main/kotlin/JsonRoute.kt
http4k/src/main/kotlin/PlainTextRoute.kt
http4k/src/main/kotlin/WorldRoutes.kt
http4k/src/main/kotlin/Http4kBenchmarkServer.kt
http4k/src/main/kotlin/Http4kJettyServer.kt
http4k/src/main/kotlin/Http4kNettyServer.kt
http4k/src/main/kotlin/Http4kUndertowServer.kt
@@ -0,0 +1,50 @@
import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource
import java.sql.Connection
import java.sql.ResultSet
class Database(private val dataSource: javax.sql.DataSource) {
companion object {
operator fun invoke(host: String): Database {
val postgresqlUrl = "jdbc:postgresql://$host/hello_world?" +
"jdbcCompliantTruncation=false&" +
"elideSetAutoCommits=true&" +
"useLocalSessionState=true&" +
"cachePrepStmts=true&" +
"cacheCallableStmts=true&" +
"alwaysSendSetIsolation=false&" +
"prepStmtCacheSize=4096&" +
"cacheServerConfiguration=true&" +
"prepStmtCacheSqlLimit=2048&" +
"traceProtocol=false&" +
"useUnbufferedInput=false&" +
"useReadAheadInput=false&" +
"maintainTimeStats=false&" +
"useServerPrepStmts=true&" +
"cacheRSMetadata=true"
val config = HikariConfig()
config.jdbcUrl = postgresqlUrl
config.maximumPoolSize = 256
config.username = "benchmarkdbuser"
config.password = "benchmarkdbpass"
return Database(HikariDataSource(config))
}
}
fun <T> withConnection(fn: (Connection) -> T): T =
try {
fn(dataSource.connection)
} finally {
dataSource.connection.close()
}
}
fun <T> ResultSet.toList(fn: (ResultSet) -> T): List<T> {
val t = mutableListOf<T>()
while (this.next()) {
t.add(fn(this))
}
return t
}
@@ -0,0 +1,31 @@
import org.http4k.core.Body
import org.http4k.core.ContentType.Companion.TEXT_HTML
import org.http4k.core.Method.GET
import org.http4k.core.Response
import org.http4k.core.Status.Companion.OK
import org.http4k.core.with
import org.http4k.routing.Route
import org.http4k.routing.by
import org.http4k.template.HandlebarsTemplates
import org.http4k.template.ViewModel
import org.http4k.template.view
data class Fortune(val id: Int, val message: String)
data class FortunesList(val items: List<Fortune>) : ViewModel
object FortunesRoute {
private val viewBody = Body.view(HandlebarsTemplates().CachingClasspath(), TEXT_HTML)
operator fun invoke(database: Database): Route = GET to "fortunes" by {
val items = database.withConnection {
it.prepareStatement("select * from fortune").executeQuery().toList {
Fortune(it.getInt(1), it.getString(2))
}
}
.plus(Fortune(0, "Additional fortune added at request time."))
.sortedBy { it.message }
Response(OK).with(viewBody of FortunesList(items))
}
}
@@ -1,26 +1,12 @@
import org.apache.commons.lang3.time.FastDateFormat.getInstance
import org.http4k.asByteBuffer
import org.http4k.contract.Root
import org.http4k.contract.Route
import org.http4k.contract.RouteModule
import org.http4k.contract.SimpleJson
import org.http4k.core.ContentType
import org.http4k.core.Filter
import org.http4k.core.Method.GET
import org.http4k.core.Response
import org.http4k.core.Status.Companion.OK
import org.http4k.core.with
import org.http4k.format.Jackson
import org.http4k.format.Jackson.json
import org.http4k.lens.Body
import org.http4k.core.then
import org.http4k.routing.routes
import org.http4k.server.ServerConfig
import org.http4k.server.asServer
import java.util.TimeZone.getTimeZone
object Http4kBenchmarkServer {
private val json = Jackson
private val preAllocatedHelloWorldText = "Hello, World!".asByteBuffer()
private val dateFormat = getInstance("EEE, d MMM yyyy HH:mm:ss 'GMT'", getTimeZone("GMT"))
private val dateAndServer = Filter {
@@ -32,16 +18,12 @@ object Http4kBenchmarkServer {
}
}
private val jsonBody = Body.json().required()
private val plainTextBody = Body.binary(ContentType.TEXT_PLAIN).required()
private val database = Database(System.getenv("DBHOST") ?: "localhost")
private val module = RouteModule(Root, SimpleJson(json), dateAndServer)
.withRoute(Route("plaintext").at(GET) / "plaintext" bind {
Response(OK).with(plainTextBody to preAllocatedHelloWorldText)
})
.withRoute(Route("json").at(GET) / "json" bind {
Response(OK).with(jsonBody to json.obj("message" to json.string("Hello, World!")))
})
val routes = listOf(PlainTextRoute(),
JsonRoute(),
FortunesRoute(database)
).plus(WorldRoutes(database))
fun start(config: ServerConfig) = module.toHttpHandler().asServer(config).start().block()
fun start(config: ServerConfig) = dateAndServer.then(routes(*routes.toTypedArray())).asServer(config).start().block()
}
@@ -0,0 +1,5 @@
import org.http4k.server.Undertow
fun main(args: Array<String>) {
Http4kBenchmarkServer.start(Undertow(9000))
}
@@ -0,0 +1,15 @@
import org.http4k.core.Body
import org.http4k.core.Method.GET
import org.http4k.core.Response
import org.http4k.core.Status.Companion.OK
import org.http4k.core.with
import org.http4k.format.Jackson.json
import org.http4k.format.Jackson.obj
import org.http4k.format.Jackson.string
import org.http4k.routing.by
object JsonRoute {
private val jsonBody = Body.json().toLens()
operator fun invoke() = GET to "/json" by { Response(OK).with(jsonBody of obj("message" to string("Hello, World!"))) }
}
@@ -0,0 +1,18 @@
import org.http4k.asByteBuffer
import org.http4k.core.Body
import org.http4k.core.ContentType.Companion.TEXT_PLAIN
import org.http4k.core.Method.GET
import org.http4k.core.Response
import org.http4k.core.Status.Companion.OK
import org.http4k.core.with
import org.http4k.lens.binary
import org.http4k.routing.by
object PlainTextRoute {
private val preAllocatedHelloWorldText = "Hello, World!".asByteBuffer()
private val plainTextBody = Body.binary(TEXT_PLAIN).toLens()
operator fun invoke() = GET to "/plaintext" by { Response(OK).with(plainTextBody of preAllocatedHelloWorldText) }
}
Oops, something went wrong.

0 comments on commit 169900b

Please sign in to comment.