diff --git a/.travis.yml b/.travis.yml index 7437b33..528c4b7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,4 +7,9 @@ script: branches: only: - master - - develop \ No newline at end of file + - develop +cache: + directories: + - '$HOME/.m2/repository' + - '$HOME/.gradle' + - '.gradle' \ No newline at end of file diff --git a/changelog.md b/changelog.md index 066444f..ab618e7 100644 --- a/changelog.md +++ b/changelog.md @@ -1,30 +1,20 @@ # Change Log All notable changes to this project will be documented in this file. -## [1.6.3] - 2017-08-28 +## [1.7.0] - 2017-08-31 ### Changes - Create mechanism for request recording - Refactoring. - Increase performance - -## [1.6.2] - 2017-08-06 -### Changes -- Refactoring. -- Increase performance +- Documentation - Improve builders for java code configuration - Improve data structures -- Remove unused functionality - Add gradle wrapper - Add ktlint - -## [1.6.1] - 2017-07-11 -### Changes - Add variables for log request/response - Add request counter - Add delay for response -- Add documentation and unit tests - Remove kotlinx package -- Refactoring ## [1.6] - 2017-04-02 ### Changes diff --git a/gradle.properties b/gradle.properties index 36e9060..6fc7c56 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=1.6.3 \ No newline at end of file +version=1.7 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 303ef0a..a4c5526 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-bin.zip diff --git a/komock-core/mock_example.yml b/komock-core/mock_example.yml index 64f4e83..aa92feb 100644 --- a/komock-core/mock_example.yml +++ b/komock-core/mock_example.yml @@ -28,6 +28,13 @@ springConfig: enabled: true keyStoreLocation: mock_keystore.jks keyStorePassword: mockpassword + routes: + - + httpMethod: GET + url: /testNoContent + contentType: text/plain + responseBody: This content will be ignored + code: 204 httpServers: - diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/VariableResolver.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/VariableResolver.kt index 6cee37d..383c4fa 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/VariableResolver.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/VariableResolver.kt @@ -6,6 +6,7 @@ import java.util.regex.Pattern * Replace input line by parameters map * Created by Oleksandr Loushkin on 10.07.2017. */ + object VariableResolver { private val parameterRegexp = Pattern.compile("\\$\\{(.+?)}") diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/after/EmptyAfterResponseHandlerImpl.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/after/EmptyAfterResponseHandlerImpl.kt index 41e2c9a..3504e81 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/after/EmptyAfterResponseHandlerImpl.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/after/EmptyAfterResponseHandlerImpl.kt @@ -3,6 +3,10 @@ package ua.com.lavi.komock.engine.handler.after import ua.com.lavi.komock.engine.model.Request import ua.com.lavi.komock.engine.model.Response +/** + * Created by Oleksandr Loushkin + */ + class EmptyAfterResponseHandlerImpl : AfterResponseHandler { override fun handle(request: Request, response: Response) { // nothing to do diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/after/LogAfterResponseHandlerImpl.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/after/LogAfterResponseHandlerImpl.kt index 957923a..1fbd229 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/after/LogAfterResponseHandlerImpl.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/after/LogAfterResponseHandlerImpl.kt @@ -9,6 +9,7 @@ import ua.com.lavi.komock.engine.model.config.http.RouteProperties /** * Created by Oleksandr Loushkin on 10.07.17. */ + class LogAfterResponseHandlerImpl(private val routeProperties: RouteProperties) : AfterResponseHandler { private val log = LoggerFactory.getLogger(this.javaClass) diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/before/EmptyBeforeResponseHandlerImpl.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/before/EmptyBeforeResponseHandlerImpl.kt index aab48cd..9784a8a 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/before/EmptyBeforeResponseHandlerImpl.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/before/EmptyBeforeResponseHandlerImpl.kt @@ -3,6 +3,10 @@ package ua.com.lavi.komock.engine.handler.before import ua.com.lavi.komock.engine.model.Request import ua.com.lavi.komock.engine.model.Response +/** + * Created by Oleksandr Loushkin + */ + class EmptyBeforeResponseHandlerImpl : BeforeResponseHandler { override fun handle(request: Request, response: Response) { diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/before/LogBeforeResponseHandlerImpl.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/before/LogBeforeResponseHandlerImpl.kt index 11494a9..c2bd2cf 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/before/LogBeforeResponseHandlerImpl.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/before/LogBeforeResponseHandlerImpl.kt @@ -10,6 +10,7 @@ import java.util.concurrent.atomic.AtomicInteger /** * Created by Oleksandr Loushkin on 10.07.17. */ + class LogBeforeResponseHandlerImpl(private val routeProperties: RouteProperties) : BeforeResponseHandler { private val log = LoggerFactory.getLogger(this.javaClass) diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/callback/CallbackHandler.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/callback/CallbackHandler.kt index 1deb383..3f76ced 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/callback/CallbackHandler.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/callback/CallbackHandler.kt @@ -6,6 +6,7 @@ import ua.com.lavi.komock.engine.model.Response /** * Created by Oleksandr Loushkin on 30.03.17. */ + interface CallbackHandler { fun handle(request: Request, response: Response) } \ No newline at end of file diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/callback/CallbackHandlerImpl.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/callback/CallbackHandlerImpl.kt index 3dfa616..7de3e8a 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/callback/CallbackHandlerImpl.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/callback/CallbackHandlerImpl.kt @@ -17,6 +17,7 @@ import kotlin.concurrent.thread /** * Created by Oleksandr Loushkin on 10.07.17. */ + class CallbackHandlerImpl(private val callbackProperties: CallbackProperties) : CallbackHandler { private val log = LoggerFactory.getLogger(this.javaClass) diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/callback/EmptyCallbackHandlerImpl.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/callback/EmptyCallbackHandlerImpl.kt index fa59c8c..a99bbcf 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/callback/EmptyCallbackHandlerImpl.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/callback/EmptyCallbackHandlerImpl.kt @@ -3,6 +3,10 @@ package ua.com.lavi.komock.engine.handler.callback import ua.com.lavi.komock.engine.model.Request import ua.com.lavi.komock.engine.model.Response +/** + * Created by Oleksandr Loushkin + */ + class EmptyCallbackHandlerImpl : CallbackHandler { override fun handle(request: Request, response: Response) { diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/response/EmptyResponseHandler.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/response/EmptyResponseHandler.kt index bcc653e..2daad62 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/response/EmptyResponseHandler.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/response/EmptyResponseHandler.kt @@ -3,6 +3,10 @@ package ua.com.lavi.komock.engine.handler.response import ua.com.lavi.komock.engine.model.Request import ua.com.lavi.komock.engine.model.Response +/** + * Created by Oleksandr Loushkin + */ + class EmptyResponseHandler : ResponseHandler { override fun handle(request: Request, response: Response) { diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/response/RoutedResponseHandlerImpl.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/response/RoutedResponseHandlerImpl.kt index be31cab..b602aac 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/response/RoutedResponseHandlerImpl.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/handler/response/RoutedResponseHandlerImpl.kt @@ -8,6 +8,7 @@ import ua.com.lavi.komock.engine.model.config.http.RouteProperties /** * Created by Oleksandr Loushkin on 10.07.17. */ + open class RoutedResponseHandlerImpl(private val routeProperties: RouteProperties) : ResponseHandler { override fun handle(request: Request, response: Response) { diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/SpringConfigResponse.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/SpringConfigResponse.kt index a79760b..445f158 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/SpringConfigResponse.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/SpringConfigResponse.kt @@ -10,7 +10,10 @@ data class SpringConfigResponse(val name: String, val profiles: List = ArrayList(), val label: String?, val version: String?, - val propertySources: List = ArrayList()) + val propertySources: List = ArrayList()) { + + constructor(name: String, profiles: List, propertySources: List) : this(name, profiles, null, null, propertySources) +} data class PropertySource(val name: String, val source: Any) \ No newline at end of file diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/consul/ConsulAgentProperties.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/consul/ConsulAgentProperties.kt index 49c9f30..613d492 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/consul/ConsulAgentProperties.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/consul/ConsulAgentProperties.kt @@ -10,5 +10,6 @@ open class ConsulAgentProperties { var enabled: Boolean = false var consulHost = "localhost" var consulPort = 8500 + var daemon: Boolean = false var services: List = ArrayList() } \ No newline at end of file diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/http/CallbackProperties.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/http/CallbackProperties.kt index c3d886d..44e2f54 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/http/CallbackProperties.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/http/CallbackProperties.kt @@ -3,6 +3,7 @@ package ua.com.lavi.komock.engine.model.config.http /** * Created by Oleksandr Loushkin on 30.03.17. */ + open class CallbackProperties { var enabled: Boolean = false var httpMethod: String = "" diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/http/CallbackRequest.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/http/CallbackRequest.kt index d87d1fd..985dace 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/http/CallbackRequest.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/http/CallbackRequest.kt @@ -6,6 +6,7 @@ import java.net.URI /** * Created by Oleksandr Loushkin on 30.03.17. */ + open class CallbackRequest(private val methodName: String, private val uri: String) : HttpEntityEnclosingRequestBase() { diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/http/CaptureProperties.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/http/CaptureProperties.kt index 40bc7eb..29e63f1 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/http/CaptureProperties.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/http/CaptureProperties.kt @@ -3,6 +3,7 @@ package ua.com.lavi.komock.engine.model.config.http /** * Created by Oleksandr Loushkin on 20.08.17. */ + open class CaptureProperties { var enabled: Boolean = false var bufferSize: Long = 10000 diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/http/CapturedData.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/http/CapturedData.kt index 9a1f1c3..828e189 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/http/CapturedData.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/http/CapturedData.kt @@ -6,6 +6,7 @@ import ua.com.lavi.komock.engine.model.Response /** * Created by Oleksandr Loushkin on 20.08.17. */ + data class CapturedData(private val request: Request, private val response: Response) { val requestBody: String = request.getRequestBody() diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/http/HttpServerProperties.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/http/HttpServerProperties.kt index c715987..0b5fe3a 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/http/HttpServerProperties.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/http/HttpServerProperties.kt @@ -44,6 +44,11 @@ open class HttpServerProperties { return this } + fun withRoutes(routes: List): HttpServerProperties { + this.routes = routes + return this + } + fun hasRoutes(): Boolean { if (routes.isEmpty()) { return false diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/spring/SpringConfigProperties.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/spring/SpringConfigProperties.kt index 0f6c0a6..d236fa1 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/spring/SpringConfigProperties.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/model/config/spring/SpringConfigProperties.kt @@ -18,6 +18,10 @@ open class SpringConfigProperties { var sourceFolder: String = "/" var httpServer: HttpServerProperties = HttpServerProperties() + fun doRefresh(): Boolean { + return refreshPeriod > 0 + } + fun fileList() : List { return Files.walk(Paths.get(sourceFolder)) .filter { it.toFile().isFile } diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/AbstractMockServer.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/AbstractMockServer.kt index 09146a7..a834664 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/AbstractMockServer.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/AbstractMockServer.kt @@ -63,6 +63,9 @@ abstract class AbstractMockServer(val serverProps: HttpServerProperties) : MockS serverConnector.host = serverProps.host serverConnector.port = serverProps.port jettyServer.connectors = arrayOf(serverConnector) + + //register only enabled routes + serverProps.routes.filter { it.enabled }.forEach { addRoute(it) } } override fun start() { @@ -91,26 +94,16 @@ abstract class AbstractMockServer(val serverProps: HttpServerProperties) : MockS } } - /** - * Add virtual hosts to the running server - */ override fun addVirtualHosts(virtualHosts: List) { getContextHandler().addVirtualHosts(virtualHosts.toTypedArray()) log.info("Added virtual hosts: $virtualHosts") } - /** - * Remove virtual host from the running server - */ override fun deleteVirtualHosts(virtualHosts: List) { getContextHandler().removeVirtualHosts(virtualHosts.toTypedArray()) log.info("Removed virtual hosts: $virtualHosts") } - - /** - * Add route by route properties configuration. It will create before, after, callback handlers - */ override fun addRoute(routeProperties: RouteProperties) { val beforeRouteHandler = if (routeProperties.logRequest) { @@ -133,9 +126,6 @@ abstract class AbstractMockServer(val serverProps: HttpServerProperties) : MockS addRoute(url, httpMethod, responseHandler, beforeRouteHandler, afterRouteHandler, callbackHandler) } - /** - * Add route with empty before, after and callback handlers. - */ override fun addRoute(url: String, httpMethod: HttpMethod, responseHandler: ResponseHandler) { @@ -148,6 +138,19 @@ abstract class AbstractMockServer(val serverProps: HttpServerProperties) : MockS EmptyCallbackHandlerImpl()) } + override fun addRoute(url: String, + httpMethod: HttpMethod, + responseHandler: ResponseHandler, + callbackHandler: CallbackHandler) { + + addRoute(url, + httpMethod, + responseHandler, + EmptyBeforeResponseHandlerImpl(), + EmptyAfterResponseHandlerImpl(), + callbackHandler) + } + override fun addRoute(url: String, httpMethod: HttpMethod, responseHandler: ResponseHandler, diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/MockServer.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/MockServer.kt index c7b032b..f94fb58 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/MockServer.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/MockServer.kt @@ -11,59 +11,86 @@ import ua.com.lavi.komock.engine.model.config.http.RouteProperties /** * Created by Oleksandr Loushkin on 19.08.17. */ + interface MockServer { /** - * Start http server + * Start http server. */ fun start() /** - * Stop http server + * Stop http server. */ fun stop() /** - * Add virtual host in runtime + * Add virtual hosts. + * @param virtualHosts - List of the virtual hosts (domains) */ fun addVirtualHosts(virtualHosts: List) /** - * Delete virtual host in runtime + * Delete virtual hosts. + * @param virtualHosts - List of the virtual hosts (domains) */ fun deleteVirtualHosts(virtualHosts: List) /** - * Add route in runtime + * Add route by route properties configuration. It will create before, after, callback handlers according to properties. + * @param routeProperties - Route properties */ fun addRoute(routeProperties: RouteProperties) /** - * Add route in runtime + * Add route with empty before, after and callback handlers. + * @param url - URL + * @param httpMethod - Http Method + * @param responseHandler - Response handler */ fun addRoute(url: String, httpMethod: HttpMethod, responseHandler: ResponseHandler) /** - * Add route in runtime + * Add route with empty before and after handlers. + * @param url - URL + * @param httpMethod - Http Method + * @param responseHandler - Response handler + * @param callbackHandler - Callback handler + */ + fun addRoute(url: String, httpMethod: HttpMethod, responseHandler: ResponseHandler, callbackHandler: CallbackHandler) + + /** + * Add route with custom handlers. + * @param url - URL + * @param httpMethod - Http Method + * @param responseHandler - Response handler + * @param beforeRouteHandler - Before response handler + * @param afterRouteHandler - After response handler + * @param callbackHandler - Callback handler */ fun addRoute(url: String, httpMethod: HttpMethod, responseHandler: ResponseHandler, beforeRouteHandler: BeforeResponseHandler, afterRouteHandler: AfterResponseHandler, callbackHandler: CallbackHandler) /** - * Delete route in runtime + * Delete existed route. + * @param url - URL + * @param httpMethod - Http Method */ fun deleteRoute(url: String, httpMethod: HttpMethod) /** - * Delete route in runtime + * Delete virtual host from the running server + * @param routeProperties - Route properties */ fun deleteRoute(routeProperties: RouteProperties) /** * Get captured data. If capture option has enable state. It is not in runtime switch option + * @return List of the captured data */ fun getCapturedData(): List /** - * Get configured server's name + * Get configured mock server's name + * @return Name of the mocked server */ fun getName() : String } \ No newline at end of file diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/SecuredMockServer.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/SecuredMockServer.kt index 9a97768..ca414a5 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/SecuredMockServer.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/SecuredMockServer.kt @@ -8,6 +8,7 @@ import ua.com.lavi.komock.engine.model.config.http.HttpServerProperties /** * Created by Oleksandr Loushkin on 19.08.17. */ + class SecuredMockServer(serverProps: HttpServerProperties) : AbstractMockServer(serverProps) { override fun buildServerConnector(): ServerConnector { diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/UnsecuredMockServer.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/UnsecuredMockServer.kt index 0bdeac9..25f3745 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/UnsecuredMockServer.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/UnsecuredMockServer.kt @@ -7,6 +7,7 @@ import ua.com.lavi.komock.engine.model.config.http.HttpServerProperties /** * Created by Oleksandr Loushkin on 19.08.17. */ + class UnsecuredMockServer(serverProps: HttpServerProperties) : AbstractMockServer(serverProps) { override fun buildServerConnector(): ServerConnector { diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/handler/AbstractHttpHandler.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/handler/AbstractHttpHandler.kt index 0375ce7..c27ec03 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/handler/AbstractHttpHandler.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/handler/AbstractHttpHandler.kt @@ -16,6 +16,7 @@ import javax.servlet.http.HttpServletResponse * This is an entry point of the request * Serialize route properties content to the http response */ + abstract class AbstractHttpHandler(private val routingTable: RoutingTable) : SessionHandler() { private val log = LoggerFactory.getLogger(this.javaClass) diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/handler/CaptureHttpHandler.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/handler/CaptureHttpHandler.kt index 752512f..a5552d6 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/handler/CaptureHttpHandler.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/handler/CaptureHttpHandler.kt @@ -12,6 +12,7 @@ import javax.servlet.http.HttpServletResponse * Class decorator capture all requests and processed responses * Created by Oleksandr Loushkin on 20.08.17. */ + class CaptureHttpHandler(private val captureProperties: CaptureProperties, routingTable: RoutingTable) : AbstractHttpHandler(routingTable) { diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/handler/HttpHandler.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/handler/HttpHandler.kt index 2340244..9e00a24 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/handler/HttpHandler.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/handler/HttpHandler.kt @@ -6,6 +6,7 @@ import javax.servlet.http.HttpServletResponse /** * Default http handler */ + open class HttpHandler(routingTable: RoutingTable) : AbstractHttpHandler(routingTable) { override fun doHandle( diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/handler/HttpRequestWrapper.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/handler/HttpRequestWrapper.kt index 83da8f0..49f71ce 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/handler/HttpRequestWrapper.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/engine/server/handler/HttpRequestWrapper.kt @@ -9,6 +9,7 @@ import javax.servlet.http.HttpServletRequestWrapper /** * Created by Oleksandr Loushkin on 20.08.17. */ + class HttpRequestWrapper(request: HttpServletRequest) : HttpServletRequestWrapper(request) { private var cachedBytes: ByteArray? = null diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/registrar/FileChangeHandler.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/registrar/FileChangeHandler.kt index 0cf116d..c7bdc15 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/registrar/FileChangeHandler.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/registrar/FileChangeHandler.kt @@ -5,6 +5,7 @@ import java.nio.file.Path /** * Created by Oleksandr Loushkin on 01.04.17. */ + interface FileChangeHandler { fun onFileChange(filePath: Path) } \ No newline at end of file diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/registrar/FileChangeWatcher.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/registrar/FileChangeWatcher.kt index 127f66b..78afbe2 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/registrar/FileChangeWatcher.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/registrar/FileChangeWatcher.kt @@ -2,14 +2,15 @@ package ua.com.lavi.komock.registrar import org.apache.commons.codec.digest.DigestUtils import org.slf4j.LoggerFactory -import java.nio.file.Files import java.nio.file.Path import java.util.* import kotlin.concurrent.scheduleAtFixedRate /** * Created by Oleksandr Loushkin on 01.04.17. + * Instant watch on files and invoke handler when file changes */ + class FileChangeWatcher(private val fileChangeHandler: FileChangeHandler, private val files: List, private val period: Long) { @@ -24,7 +25,7 @@ class FileChangeWatcher(private val fileChangeHandler: FileChangeHandler, timer.scheduleAtFixedRate(0, period) { for (file in files) { - val currentHash = DigestUtils.md5Hex(String(Files.readAllBytes(file), Charsets.UTF_8)) + val currentHash = DigestUtils.md5Hex(file.toFile().readText()) val oldHash = fileHashes[file] fileHashes.put(file, currentHash) if (oldHash != null && oldHash != currentHash) { diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/registrar/consul/ConsulRegistrar.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/registrar/consul/ConsulRegistrar.kt index c6fb307..7feb164 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/registrar/consul/ConsulRegistrar.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/registrar/consul/ConsulRegistrar.kt @@ -34,16 +34,13 @@ class ConsulRegistrar { log.info("Registered consul service: ${consulService.serviceId} - ${consulService.serviceAddress}:${consulService.servicePort}") } } - daemonMode() - } - - private fun daemonMode() { - try { - log.info("Consul registration is running in daemon mode") - Thread.currentThread().join() - } catch (e: InterruptedException) { - log.warn("Error: {}", e) + if (consulAgentProperties.daemon) { + try { + log.info("Consul registration is running in daemon mode") + Thread.currentThread().join() + } catch (e: InterruptedException) { + log.warn("Error: {}", e) + } } } - } diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/registrar/http/HttpServerRegistrar.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/registrar/http/HttpServerRegistrar.kt index d0ec613..e74c64f 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/registrar/http/HttpServerRegistrar.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/registrar/http/HttpServerRegistrar.kt @@ -37,22 +37,19 @@ class HttpServerRegistrar { fun register(httpServerProperties: HttpServerProperties) { //SSL SecuredHttpRouter or not - val router = if (httpServerProperties.ssl.enabled) { + val mockServer = if (httpServerProperties.ssl.enabled) { SecuredMockServer(httpServerProperties) } else { UnsecuredMockServer(httpServerProperties) } - mockServers.add(router) + mockServers.add(mockServer) try { - router.start() + mockServer.start() } catch (e: BindException) { log.warn(e.message + ": ${httpServerProperties.host}, port: ${httpServerProperties.port}", e) return } - - //register only enabled routes - httpServerProperties.routes.filter { it.enabled }.forEach { router.addRoute(it) } } } diff --git a/komock-core/src/main/kotlin/ua/com/lavi/komock/registrar/spring/SpringConfigRegistrar.kt b/komock-core/src/main/kotlin/ua/com/lavi/komock/registrar/spring/SpringConfigRegistrar.kt index 100614a..30fc094 100644 --- a/komock-core/src/main/kotlin/ua/com/lavi/komock/registrar/spring/SpringConfigRegistrar.kt +++ b/komock-core/src/main/kotlin/ua/com/lavi/komock/registrar/spring/SpringConfigRegistrar.kt @@ -15,14 +15,12 @@ import ua.com.lavi.komock.engine.server.UnsecuredMockServer import ua.com.lavi.komock.registrar.FileChangeHandler import ua.com.lavi.komock.registrar.FileChangeWatcher import java.net.BindException -import java.nio.file.Files import java.nio.file.Path import java.util.* -import kotlin.collections.ArrayList /** * Created by Oleksandr Loushkin - * Register Spring configuration files as a separate server instance + * Register Spring configuration files as a separate http server instance */ class SpringConfigRegistrar { @@ -47,70 +45,56 @@ class SpringConfigRegistrar { return } - log.info("Started httpServer: ${httpServerProp.name} on port: ${httpServerProp.port}. virtualHosts: ${httpServerProp.virtualHosts}") - val profiles = springConfigProperties.profiles val fileList = springConfigProperties.fileList() fileList.forEach({ configFilePath -> registerPath(configFilePath, profiles, router) }) - if (springConfigProperties.refreshPeriod > 0) { - - val fileListener = object : FileChangeHandler { + if (springConfigProperties.doRefresh()) { + val fileChangeHandler = object : FileChangeHandler { override fun onFileChange(filePath: Path) { unregisterPath(filePath, profiles, router) registerPath(filePath, profiles, router) } } - FileChangeWatcher(fileListener, fileList, springConfigProperties.refreshPeriod).start() - } - - //register only enabled routeHolders - if (httpServerProp.hasRoutes()) { - httpServerProp.routes.filter { it.enabled }.forEach { router.addRoute(it) } + FileChangeWatcher(fileChangeHandler, fileList, springConfigProperties.refreshPeriod).start() } + } + private fun unregisterPath(configFilePath: Path, profiles: List, server: MockServer) { + profiles.forEach({ + val serviceName = extractFilenameFromPath(configFilePath) + val url = "/$serviceName/$it" + server.deleteRoute(url, HttpMethod.GET) + }) + log.info("Unregistered spring config file: $configFilePath") } private fun registerPath(configFilePath: Path, profiles: List, server: MockServer) { val serviceName = extractFilenameFromPath(configFilePath) - val textData = String(Files.readAllBytes(configFilePath), Charsets.UTF_8) - val content: Map = buildFlatMap(textData) - val propertySources = buildPropertySources(configFilePath, content) - val springConfigResponse = SpringConfigResponse(serviceName, profiles, null, null, propertySources) + val springConfigResponse = SpringConfigResponse(serviceName, profiles, buildPropertySources(configFilePath)) - val jsonConfigResponse = gson.toJson(springConfigResponse) - - for (profile in profiles) { - - val routeServerProperties = RouteProperties() - routeServerProperties.code = 200 - routeServerProperties.httpMethod = "GET" - routeServerProperties.responseBody = jsonConfigResponse - routeServerProperties.contentType = "application/json" - routeServerProperties.url = "/$serviceName/$profile" - - server.addRoute(routeServerProperties) - } + profiles.forEach { profile -> server.addRoute(buildRouteProperties(springConfigResponse, serviceName, profile)) } log.info("Registered spring config file: $configFilePath") } - private fun unregisterPath(springConfigFilePath: Path, profiles: List, server: MockServer) { - profiles.forEach({ - val serviceName = extractFilenameFromPath(springConfigFilePath) - val url = "/$serviceName/$it" - server.deleteRoute(url, HttpMethod.GET) - }) + private fun buildRouteProperties(springConfigResponse: SpringConfigResponse, serviceName: String, profile: String): RouteProperties { + val routeServerProperties = RouteProperties() + routeServerProperties.code = 200 + routeServerProperties.httpMethod = HttpMethod.GET.name + routeServerProperties.responseBody = gson.toJson(springConfigResponse) + routeServerProperties.contentType = "application/json" + routeServerProperties.url = "/$serviceName/$profile" + return routeServerProperties } - private fun buildPropertySources(springConfigFile: Path, propertySourceBody: Map): ArrayList { - val propertySources = ArrayList() + private fun buildPropertySources(springConfigFile: Path): ArrayList { val propertySourceName = "file:" + springConfigFile.toString().replace("\\\\".toRegex(), "/") - propertySources.add(PropertySource(propertySourceName, propertySourceBody)) - return propertySources + val propertySourceBody = buildFlatMap(springConfigFile.toFile().readText()) + return arrayListOf(PropertySource(propertySourceName, propertySourceBody)) } private fun buildFlatMap(textData: String): Map { diff --git a/komock-core/src/test/kotlin/ua/com/lavi/komock/MockServerJavaCallbackCaptureTest.java b/komock-core/src/test/kotlin/ua/com/lavi/komock/MockServerJavaCallbackCaptureTest.java index 14d9dc6..a6e07ce 100644 --- a/komock-core/src/test/kotlin/ua/com/lavi/komock/MockServerJavaCallbackCaptureTest.java +++ b/komock-core/src/test/kotlin/ua/com/lavi/komock/MockServerJavaCallbackCaptureTest.java @@ -11,6 +11,7 @@ import ua.com.lavi.komock.engine.server.MockServer; import ua.com.lavi.komock.engine.server.UnsecuredMockServer; +import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -20,6 +21,7 @@ /** * Created by Oleksandr Loushkin on 20.08.17. */ + public class MockServerJavaCallbackCaptureTest { private static final String TEST_CALLBACK_BODY = "{'testCallbackBody': true}"; @@ -28,32 +30,30 @@ public class MockServerJavaCallbackCaptureTest { private static final String TEST_REQUEST_KEY = "testRequestKey"; private static final String TEST_RESPONSE_VALUE = "testResponseValue"; private static final String TEST_RESPONSE_KEY = "testResponseKey"; - private final String host = "localhost"; - private final int port_8080 = 8080; - private final int port_8081 = 8081; + private static final String host = "localhost"; + private static final int port_8080 = 8080; + private static final int port_8081 = 8081; private static final String VERIFY_URL = "/verify"; private static final String APPLICATION_JSON = "application/json"; private final MockServer firstServer = new UnsecuredMockServer(new HttpServerProperties() .withName("FirstServer") .withHost(host) - .withPort(port_8080)); + .withPort(port_8080) + .withRoutes(Collections.singletonList(buildRoute()))); private final MockServer captureServer = new UnsecuredMockServer(new HttpServerProperties() .withName("SecondServer") .withHost(host) .withPort(port_8081) .withCapture(new CaptureProperties().enabled()) - ); + .withRoutes(Collections.singletonList(buildCallbackRoute()))); @Before public void setUp() { firstServer.start(); captureServer.start(); Unirest.setObjectMapper(GsonObjectMapper.INSTANCE); - - firstServer.addRoute(routeProperties()); - captureServer.addRoute(callbackRouteProperties()); } @After @@ -66,10 +66,11 @@ public void tearDown() { public void should_return_ok_with_captured_data() throws UnirestException, InterruptedException { HttpResponse response = Unirest.post(String.format("http://%s:%s%s", host, port_8080, VERIFY_URL)) .asString(); - assertTrue(response.getStatus() == 200); - assertTrue(response.getHeaders().get("Content-Type").get(0).equals(APPLICATION_JSON)); - Thread.sleep(100L); //wait for callback + assertEquals(200, response.getStatus()); + assertEquals(APPLICATION_JSON, response.getHeaders().get("Content-Type").get(0)); + List capturedDataList = captureServer.getCapturedData(); + Waiter.INSTANCE.untilNotEmpty(capturedDataList, 1000); assertTrue(capturedDataList.size() == 1); CapturedData capturedData = capturedDataList.get(0); assertEquals(TEST_CALLBACK_BODY, capturedData.getRequestBody()); @@ -79,18 +80,27 @@ public void should_return_ok_with_captured_data() throws UnirestException, Inter assertEquals(TEST_RESPONSE_VALUE, capturedData.getResponseHeaders().get(TEST_RESPONSE_KEY)); } - private RouteProperties routeProperties() { + private RouteProperties buildRoute() { RouteProperties routeProperties = new RouteProperties(); routeProperties.setHttpMethod(HttpMethod.POST.name()); routeProperties.setCode(200); routeProperties.setContentType(APPLICATION_JSON); routeProperties.setUrl(VERIFY_URL); - routeProperties.setCallback(callbackProperties()); + CallbackProperties callbackProperties = new CallbackProperties(); + callbackProperties.setEnabled(true); + callbackProperties.setUrl(String.format("http://%s:%s%s", host, port_8081, VERIFY_URL)); + callbackProperties.setHttpMethod(HttpMethod.POST.name()); + callbackProperties.setRequestBody(TEST_CALLBACK_BODY); + callbackProperties.setRequestHeaders(new HashMap() {{ + put(TEST_REQUEST_KEY, TEST_REQUEST_VALUE); + }}); + + routeProperties.setCallback(callbackProperties); return routeProperties; } - private RouteProperties callbackRouteProperties() { + private RouteProperties buildCallbackRoute() { RouteProperties routeProperties = new RouteProperties(); routeProperties.setHttpMethod(HttpMethod.POST.name()); routeProperties.setCode(200); @@ -102,16 +112,4 @@ private RouteProperties callbackRouteProperties() { }}); return routeProperties; } - - private CallbackProperties callbackProperties() { - CallbackProperties callbackProperties = new CallbackProperties(); - callbackProperties.setEnabled(true); - callbackProperties.setUrl(String.format("http://%s:%s%s", host, port_8081, VERIFY_URL)); - callbackProperties.setHttpMethod(HttpMethod.POST.name()); - callbackProperties.setRequestBody(TEST_CALLBACK_BODY); - callbackProperties.setRequestHeaders(new HashMap() {{ - put(TEST_REQUEST_KEY, TEST_REQUEST_VALUE); - }}); - return callbackProperties; - } } diff --git a/komock-core/src/test/kotlin/ua/com/lavi/komock/MockServerKotlinConfigTest.kt b/komock-core/src/test/kotlin/ua/com/lavi/komock/MockServerKotlinConfigTest.kt index be29e14..ab83185 100644 --- a/komock-core/src/test/kotlin/ua/com/lavi/komock/MockServerKotlinConfigTest.kt +++ b/komock-core/src/test/kotlin/ua/com/lavi/komock/MockServerKotlinConfigTest.kt @@ -14,6 +14,10 @@ import ua.com.lavi.komock.engine.model.config.http.HttpServerProperties import ua.com.lavi.komock.engine.server.MockServer import ua.com.lavi.komock.engine.server.UnsecuredMockServer +/** + * Created by Oleksandr Loushkin + */ + class MockServerKotlinConfigTest { private val host = "localhost" @@ -28,10 +32,15 @@ class MockServerKotlinConfigTest { httpRouter.start() } + @After + fun tearDown() { + httpRouter.stop() + } + @Test fun should_run_kotlin_config() { - httpRouter.addRoute("/testNoContent", HttpMethod.GET, responseHandler = customHandler()) + httpRouter.addRoute("/testNoContent", HttpMethod.GET, customHandler()) val response = Unirest.get("http://$host:$port/testNoContent").asString() @@ -40,11 +49,6 @@ class MockServerKotlinConfigTest { } - @After - fun tearDown() { - httpRouter.stop() - } - private fun customHandler(): ResponseHandler { val responseHandler: ResponseHandler = object : ResponseHandler { override fun handle(request: Request, response: Response) { diff --git a/komock-core/src/test/kotlin/ua/com/lavi/komock/RoutingTest.kt b/komock-core/src/test/kotlin/ua/com/lavi/komock/RoutingTest.kt index 86c456c..6b4930b 100644 --- a/komock-core/src/test/kotlin/ua/com/lavi/komock/RoutingTest.kt +++ b/komock-core/src/test/kotlin/ua/com/lavi/komock/RoutingTest.kt @@ -58,7 +58,8 @@ class RoutingTest { Unirest.get("http://127.0.0.1:8081/testcallback").asJson() val capturedDataList = HttpServerRegistrar.getServers().filter { it.getName() == "callbackserver" }[0].getCapturedData() - Thread.sleep(100L) + Waiter.untilNotEmpty(capturedDataList) + val capturedData = capturedDataList[0] assertEquals("{yo}", capturedData.requestBody) @@ -129,8 +130,7 @@ class RoutingTest { @Test fun should_forbidden_get_secured_area() { - val response = Unirest.get("http://127.0.0.1:8081/testGetTextSecuredRoute") - .asString() + val response = Unirest.get("http://127.0.0.1:8081/testGetTextSecuredRoute").asString() assertTrue(response.status == 401) assertEquals(response.body, "") @@ -259,7 +259,8 @@ class RoutingTest { fun should_ok_get_plaintext_with_content_on_second_secured_server() { val sslHttpClient = HttpClients.custom() .setSSLContext(SSLContextBuilder() - .loadTrustMaterial(null) { _, _ -> true }.build()) + .loadTrustMaterial(null) { _, _ -> true } + .build()) .setSSLHostnameVerifier(NoopHostnameVerifier()) .build() @@ -281,7 +282,7 @@ class RoutingTest { fun should_ok_get_plaintext_with_content_on_third_secured_server() { val sslHttpClient = HttpClients.custom() .setSSLContext(SSLContextBuilder() - .loadTrustMaterial(null) { _, _ -> true }.build()) + .loadTrustMaterial(null) { _, _ -> true }.build()) .setSSLHostnameVerifier(NoopHostnameVerifier()) .build() @@ -345,7 +346,8 @@ class RoutingTest { val sslHttpClient = HttpClients.custom() .setSSLContext(SSLContextBuilder() - .loadTrustMaterial(null) { _, _ -> true }.build()) + .loadTrustMaterial(null) { _, _ -> true } + .build()) .setSSLHostnameVerifier(NoopHostnameVerifier()) .build() @@ -374,4 +376,22 @@ class RoutingTest { } + @Test + fun should_ok_get_noContent_spring_config() { + val sslHttpClient = HttpClients.custom() + .setSSLContext(SSLContextBuilder() + .loadTrustMaterial(null) { _, _ -> true } + .build()) + .setSSLHostnameVerifier(NoopHostnameVerifier()) + .build() + + Unirest.setHttpClient(sslHttpClient) + + val response = Unirest.get("https://127.0.0.1:8888/testNoContent").asJson() + + assertEquals("text/plain", response.headers["Content-Type"]!![0]) + assertEquals(204, response.status) + assertEquals(response.body, null) + } + } diff --git a/komock-core/src/test/kotlin/ua/com/lavi/komock/Waiter.kt b/komock-core/src/test/kotlin/ua/com/lavi/komock/Waiter.kt new file mode 100644 index 0000000..f422e1f --- /dev/null +++ b/komock-core/src/test/kotlin/ua/com/lavi/komock/Waiter.kt @@ -0,0 +1,22 @@ +package ua.com.lavi.komock + +import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit +import kotlin.concurrent.thread + +/** + * Created by Oleksandr Loushkin + */ + +object Waiter { + + fun untilNotEmpty(data: Collection, waitTime: Long = 1000) { + val latch = CountDownLatch(1) + thread { + while (data.isEmpty()) { + } + latch.countDown() + } + latch.await(waitTime, TimeUnit.MILLISECONDS) + } +} \ No newline at end of file diff --git a/komock-core/src/test/kotlin/ua/com/lavi/komock/engine/VariableResolverTest.kt b/komock-core/src/test/kotlin/ua/com/lavi/komock/engine/VariableResolverTest.kt index 3766a43..0ca8c6d 100644 --- a/komock-core/src/test/kotlin/ua/com/lavi/komock/engine/VariableResolverTest.kt +++ b/komock-core/src/test/kotlin/ua/com/lavi/komock/engine/VariableResolverTest.kt @@ -6,6 +6,7 @@ import kotlin.test.assertEquals /** * Created by Oleksandr Loushkin on 01.07.17. */ + class VariableResolverTest { @Test diff --git a/komock-core/src/test/resources/logback.xml b/komock-core/src/test/resources/logback.xml index 42b9241..49a4262 100644 --- a/komock-core/src/test/resources/logback.xml +++ b/komock-core/src/test/resources/logback.xml @@ -16,7 +16,7 @@ - +