Skip to content

Commit

Permalink
chore(pact-jvm-server): Converted Create to kotlin
Browse files Browse the repository at this point in the history
  • Loading branch information
rholshausen committed Nov 18, 2024
1 parent 36cf032 commit de37b5e
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 115 deletions.
123 changes: 123 additions & 0 deletions pact-jvm-server/src/main/kotlin/au/com/dius/pact/server/Create.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package au.com.dius.pact.server

import au.com.dius.pact.consumer.model.MockHttpsProviderConfig
import au.com.dius.pact.consumer.model.MockProviderConfig
import au.com.dius.pact.core.model.DefaultPactReader
import au.com.dius.pact.core.model.OptionalBody
import au.com.dius.pact.core.model.PactSpecVersion
import au.com.dius.pact.core.model.Request
import au.com.dius.pact.core.model.Response
import au.com.dius.pact.core.support.isNotEmpty
import io.github.oshai.kotlinlogging.KotlinLogging
import org.apache.commons.lang3.RandomUtils
import java.io.File
import java.io.IOException
import java.net.ServerSocket
import java.security.KeyStore

private val logger = KotlinLogging.logger {}

object Create {

private val CrossSiteHeaders = mapOf("Access-Control-Allow-Origin" to listOf("*"))

@JvmStatic
fun create(_state: String, path: List<String?>?, requestBody: String, oldState: ServerState, config: Config): Result {
val pact = DefaultPactReader.loadPact(requestBody)

val mockConfig : MockProviderConfig = if (config.keystorePath.isNotEmpty()) {
val ks = KeyStore.getInstance(File(config.keystorePath), config.keystorePassword.toCharArray())
MockHttpsProviderConfig(
config.host,
config.sslPort,
PactSpecVersion.fromInt(config.pactVersion),
ks,
"localhost",
config.keystorePassword,
config.keystorePassword
)
}
else {
MockProviderConfig(config.host, randomPort(config.portLowerBound, config.portUpperBound),
PactSpecVersion.fromInt(config.pactVersion))
}
val server = DefaultMockProvider.apply(mockConfig)

val port = server.config.port
val portEntry = port.toString() to server

val newState = (oldState.state.entries.map { it.toPair() } + portEntry).toMutableSet()
if (path != null) {
for (p in path) {
if (p != null) {
newState += (p to server)
}
}
}

val body = OptionalBody.body(("{\"port\": $port}").toByteArray())

server.start(pact)

val headers = CrossSiteHeaders + mapOf("Content-Type" to listOf("application/json"))
return Result(Response(201, headers.toMutableMap(), body), ServerState(newState.associate { it }))
}

@JvmStatic
fun apply(request: Request, oldState: ServerState, config: Config): Result {
logger.debug { "path=${request.path}" }
logger.debug { "query=${request.query}" }
logger.debug { "body=${request.body}" }

if (request.query.isNotEmpty()) {
val stateList = request.query["state"]
if (stateList != null) {
val state = stateList.first()
if (state != null) {
val paths = request.query["path"]
if (request.body.isPresent()) {
return create(state, paths, request.body.valueAsString(), oldState, config)
}
}
}
}

val errorJson = OptionalBody.body("{\"error\": \"please provide state param and path param and pact body\"}".toByteArray())
return Result(Response(400, CrossSiteHeaders.toMutableMap(), errorJson), oldState)
}

private fun randomPort(lower: Int, upper: Int): Int {
var port: Int? = null
var count = 0
while (port == null && count < 20) {
val randomPort = RandomUtils.nextInt(lower, upper)
if (portAvailable(randomPort)) {
port = randomPort
}
count += 1
}

if (port == null) {
port = 0
}

return port
}

private fun portAvailable(p: Int): Boolean {
var socket: ServerSocket? = null
return try {
socket = ServerSocket(p)
true
} catch (_: IOException) {
false
} finally {
if (socket != null) {
try {
socket.close()
} catch (_: IOException) {
}
}
}
}
}
110 changes: 0 additions & 110 deletions pact-jvm-server/src/main/scala/au/com/dius/pact/server/Create.scala

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ object RequestRouter extends StrictLogging {
val urlPattern ="/(\\w*)\\?{0,1}.*".r
val urlPattern(action) = request.getPath
action match {
case "create" => Create(request, oldState, config)
case "create" => Create.apply(request, oldState, config)
case "complete" => Complete(request, oldState)
case "publish" => Publish(request, oldState, config)
case "" => ListServers(oldState)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package au.com.dius.pact.server

import scala.collection.JavaConverters
import au.com.dius.pact.core.model.OptionalBody
import au.com.dius.pact.core.model.Request
import spock.lang.Specification

import java.nio.file.Paths
Expand All @@ -15,7 +16,7 @@ class CreateSpec extends Specification {
when:
def result = Create.create(
'test state',
JavaConverters.asScalaBuffer(['/data']).toList(),
['/data'],
pact,
new ServerState(),
new Config(4444, 'localhost', false, 20000, 40000, true,
Expand Down Expand Up @@ -43,10 +44,10 @@ class CreateSpec extends Specification {

when:
def result = Create.create('test state',
JavaConverters.asScalaBuffer([]).toList(),
[],
pact,
new ServerState(),
new au.com.dius.pact.server.Config(4444, 'localhost', false, 20000, 40000, true,
new Config(4444, 'localhost', false, 20000, 40000, true,
2, keystorePath, password, 8444, '', ''))

then:
Expand All @@ -60,4 +61,69 @@ class CreateSpec extends Specification {
}
}
}

def 'apply returns an error if there is no query parameters'() {
given:
def request = new Request()
def serverState = new ServerState()
def config = new Config()

when:
def result = Create.apply(request, serverState, config)

then:
result.response.status == 400
}

def 'apply returns an error if there is no state query parameter'() {
given:
def request = new Request('GET', '/path', [qp: ['some value']])
def serverState = new ServerState()
def config = new Config()

when:
def result = Create.apply(request, serverState, config)

then:
result.response.status == 400
}

def 'apply returns an error if the state query parameter is empty'() {
given:
def request = new Request('GET', '/path', [qp: []])
def serverState = new ServerState()
def config = new Config()

when:
def result = Create.apply(request, serverState, config)

then:
result.response.status == 400
}

def 'apply returns an error if there is no path query parameter'() {
given:
def request = new Request('GET', '/path', [state: ['test']])
def serverState = new ServerState()
def config = new Config()

when:
def result = Create.apply(request, serverState, config)

then:
result.response.status == 400
}

def 'apply returns an error if the request body is empty'() {
given:
def request = new Request('GET', '/path', [state: ['test'], path: ['/test']], [:], OptionalBody.empty())
def serverState = new ServerState()
def config = new Config()

when:
def result = Create.apply(request, serverState, config)

then:
result.response.status == 400
}
}

0 comments on commit de37b5e

Please sign in to comment.