From b3e3dfb3f3349a828a35e405f633866a900c6137 Mon Sep 17 00:00:00 2001 From: Dominik Adam Przybysz Date: Wed, 10 Dec 2014 20:40:09 +0100 Subject: [PATCH] Add setting status code in mock --- .../mockserver/server/ContextExecutor.groovy | 3 +- .../mockserver/server/HttpMockServer.groovy | 25 +++++-- .../pl/touk/mockserver/server/Mock.groovy | 19 +++--- .../client/AddMockRequestData.groovy | 1 + .../client/ControlServerClient.groovy | 32 +++++---- .../InvalidMockDefinitionException.groovy | 7 ++ .../server/MockServerIntegrationTest.groovy | 66 +++++++++++++++++-- 7 files changed, 118 insertions(+), 35 deletions(-) create mode 100644 src/test/groovy/pl/touk/mockserver/client/InvalidMockDefinitionException.groovy diff --git a/src/main/groovy/pl/touk/mockserver/server/ContextExecutor.groovy b/src/main/groovy/pl/touk/mockserver/server/ContextExecutor.groovy index 63dff2b..5c3af82 100644 --- a/src/main/groovy/pl/touk/mockserver/server/ContextExecutor.groovy +++ b/src/main/groovy/pl/touk/mockserver/server/ContextExecutor.groovy @@ -16,7 +16,6 @@ class ContextExecutor { this.mocks = new CopyOnWriteArrayList<>([initialMock]) httpServerWraper.createContext(path,{ HttpExchange ex -> - ex.sendResponseHeaders(200, 0) String input = ex.requestBody.text println "Mock received input" GPathResult inputXml = new XmlSlurper().parseText(input) @@ -31,6 +30,7 @@ class ContextExecutor { } } if (xml != null && mock.predicate(xml)) { + ex.sendResponseHeaders(mock.statusCode, 0) println "Mock ${mock.name} invoked" ++mock.counter String response = mock.responseOk(xml) @@ -42,6 +42,7 @@ class ContextExecutor { e.printStackTrace() } } + ex.sendResponseHeaders(404, 0) ex.responseBody << "" ex.responseBody.close() }) diff --git a/src/main/groovy/pl/touk/mockserver/server/HttpMockServer.groovy b/src/main/groovy/pl/touk/mockserver/server/HttpMockServer.groovy index f79c0e0..a2d6245 100644 --- a/src/main/groovy/pl/touk/mockserver/server/HttpMockServer.groovy +++ b/src/main/groovy/pl/touk/mockserver/server/HttpMockServer.groovy @@ -17,7 +17,6 @@ class HttpMockServer { httpServerWraper.createContext('/serverControl', { HttpExchange ex -> - ex.sendResponseHeaders(200, 0) try{ GPathResult request = new XmlSlurper().parse(ex.requestBody) if(ex.requestMethod== 'POST' && request.name() == 'addMock'){ @@ -41,10 +40,23 @@ class HttpMockServer { println "Adding $name" String mockPath = request.path int mockPort = Integer.valueOf(request.port as String) - Closure predicate = Eval.me(request.predicate as String) as Closure - Closure okResponse = Eval.me(request.response as String) as Closure - boolean soap = Boolean.valueOf(request.soap as String) - Mock mock = new Mock(name, mockPath, mockPort, predicate, okResponse, soap) + Mock mock = new Mock(name, mockPath, mockPort) + String predicate = request.predicate + if(predicate){ + mock.predicate = Eval.me(predicate) as Closure + } + String okResponse = request.response + if(okResponse){ + mock.responseOk = Eval.me(okResponse) as Closure + } + String soap = request.soap + if(soap){ + mock.soap = Boolean.valueOf(soap) + } + String statusCode = request.statusCode + if(statusCode){ + mock.statusCode = Integer.valueOf(statusCode) + } HttpServerWraper child = childServers.find { it.port == mockPort } if (!child) { child = new HttpServerWraper(mockPort) @@ -52,6 +64,7 @@ class HttpMockServer { } child.addMock(mockPath, mock) mockNames << name + ex.sendResponseHeaders(200, 0) ex.responseBody << '' ex.responseBody.close() } @@ -64,11 +77,13 @@ class HttpMockServer { println "Removing $name" int used = childServers.inject(0) { int res, HttpServerWraper server-> server.removeMock(name) + res} mockNames.remove(name) + ex.sendResponseHeaders(200, 0) ex.responseBody << "$used" ex.responseBody.close() } private static void createErrorResponse(HttpExchange ex, Exception e) { + ex.sendResponseHeaders(400, 0) ex.responseBody << """${e.message}""" ex.responseBody.close() } diff --git a/src/main/groovy/pl/touk/mockserver/server/Mock.groovy b/src/main/groovy/pl/touk/mockserver/server/Mock.groovy index c36e567..e250616 100644 --- a/src/main/groovy/pl/touk/mockserver/server/Mock.groovy +++ b/src/main/groovy/pl/touk/mockserver/server/Mock.groovy @@ -7,21 +7,18 @@ class Mock { final String name final String path final int port - final Closure predicate - final Closure responseOk - final boolean soap - //TODO add http method - //TODO add http code - //TODO add request headers - //TODO add response headers + Closure predicate = { xml -> true } + Closure responseOk = { xml -> '' } + boolean soap = false + int statusCode = 200 + //TODO add http method - default POST + //TODO add request headers - default [:] + //TODO add response headers - default [:] int counter = 0 //TODO add historical invocations - Mock(String name, String path, int port, Closure predicate, Closure responseOk, boolean soap) { + Mock(String name, String path, int port) { this.name = name - this.predicate = predicate - this.responseOk = responseOk - this.soap = soap this.path = path this.port = port } diff --git a/src/test/groovy/pl/touk/mockserver/client/AddMockRequestData.groovy b/src/test/groovy/pl/touk/mockserver/client/AddMockRequestData.groovy index 893332f..3cf3c02 100644 --- a/src/test/groovy/pl/touk/mockserver/client/AddMockRequestData.groovy +++ b/src/test/groovy/pl/touk/mockserver/client/AddMockRequestData.groovy @@ -9,6 +9,7 @@ class AddMockRequestData { String predicate String response Boolean soap + Integer statusCode void setPredicate(String predicate){ this.predicate = StringEscapeUtils.escapeXml11(predicate) diff --git a/src/test/groovy/pl/touk/mockserver/client/ControlServerClient.groovy b/src/test/groovy/pl/touk/mockserver/client/ControlServerClient.groovy index 994f829..3b56c38 100644 --- a/src/test/groovy/pl/touk/mockserver/client/ControlServerClient.groovy +++ b/src/test/groovy/pl/touk/mockserver/client/ControlServerClient.groovy @@ -16,46 +16,50 @@ class ControlServerClient { address = "http://$host:$port/serverControl" } - void addMock(AddMockRequestData addMockRequestData){ + void addMock(AddMockRequestData addMockRequestData) { HttpPost addMockPost = new HttpPost(address) addMockPost.entity = buildAddMockRequest(addMockRequestData) CloseableHttpResponse response = client.execute(addMockPost) GPathResult responseXml = Util.extractXmlResponse(response) - if(responseXml.name() != 'mockAdded'){ - throw new MockAlreadyExists() + if (responseXml.name() != 'mockAdded') { + if (responseXml.text() == 'mock already registered') { + throw new MockAlreadyExists() + + } + throw new InvalidMockDefinitionException(responseXml.text()) } } - int removeMock(String name){ + int removeMock(String name) { HttpPost removeMockPost = new HttpPost(address) - removeMockPost.entity = buildRemoveMockRequest(new RemoveMockRequestData(name:name)) + removeMockPost.entity = buildRemoveMockRequest(new RemoveMockRequestData(name: name)) CloseableHttpResponse response = client.execute(removeMockPost) GPathResult responseXml = Util.extractXmlResponse(response) - if(responseXml.name() == 'mockRemoved'){ + if (responseXml.name() == 'mockRemoved') { return responseXml.text() as int } throw new MockDoesNotExist() } - - private StringEntity buildRemoveMockRequest(RemoveMockRequestData data){ + private static StringEntity buildRemoveMockRequest(RemoveMockRequestData data) { return new StringEntity("""\ ${data.name} - """,ContentType.create("text/xml", "UTF-8")) + """, ContentType.create("text/xml", "UTF-8")) } - private StringEntity buildAddMockRequest(AddMockRequestData data){ + private static StringEntity buildAddMockRequest(AddMockRequestData data) { return new StringEntity("""\ ${data.name} ${data.path} ${data.port} - ${data.predicate} - ${data.response} - ${data.soap} + ${data.predicate != null ? "${data.predicate}" : ''} + ${data.response != null ? "${data.response}" : ''} + ${data.soap != null ? "${data.soap}" : ''} + ${data.statusCode != null ? "${data.statusCode}" : ''} - """,ContentType.create("text/xml", "UTF-8")) + """, ContentType.create("text/xml", "UTF-8")) } } diff --git a/src/test/groovy/pl/touk/mockserver/client/InvalidMockDefinitionException.groovy b/src/test/groovy/pl/touk/mockserver/client/InvalidMockDefinitionException.groovy new file mode 100644 index 0000000..96156a1 --- /dev/null +++ b/src/test/groovy/pl/touk/mockserver/client/InvalidMockDefinitionException.groovy @@ -0,0 +1,7 @@ +package pl.touk.mockserver.client + +class InvalidMockDefinitionException extends RuntimeException{ + InvalidMockDefinitionException(String s) { + super(s) + } +} diff --git a/src/test/groovy/pl/touk/mockserver/server/MockServerIntegrationTest.groovy b/src/test/groovy/pl/touk/mockserver/server/MockServerIntegrationTest.groovy index 5738ce3..63e2538 100644 --- a/src/test/groovy/pl/touk/mockserver/server/MockServerIntegrationTest.groovy +++ b/src/test/groovy/pl/touk/mockserver/server/MockServerIntegrationTest.groovy @@ -7,6 +7,7 @@ import org.apache.http.entity.ContentType import org.apache.http.entity.StringEntity import org.apache.http.impl.client.CloseableHttpClient import org.apache.http.impl.client.HttpClients +import org.apache.http.util.EntityUtils import pl.touk.mockserver.client.* import spock.lang.Shared import spock.lang.Specification @@ -73,7 +74,7 @@ class MockServerIntegrationTest extends Specification { controlServerClient.removeMock('testSoap') == 1 } - def "should not remove when it does not exist"() { + def "should not remove mock when it does not exist"() { when: controlServerClient.removeMock('testSoap') then: @@ -214,9 +215,62 @@ class MockServerIntegrationTest extends Specification { 9998 | '/test2' | 'another port and path' } - //TODO def "should get mock report"(){} - //TODO def "should get list mocks"(){} - //TODO def "should dispatch rest mock with response code"(){} + @Unroll + def "should dispatch rest mock with response code"() { + given: + controlServerClient.addMock(new AddMockRequestData( + name: 'testRest1', + path: '/test1', + port: 9999, + statusCode: statusCode + )) + HttpPost request = new HttpPost('http://localhost:9999/test1') + request.entity = new StringEntity('', ContentType.create("text/xml", "UTF-8")) + when: + CloseableHttpResponse response = client.execute(request) + then: + response.statusLine.statusCode == expectedStatusCode + EntityUtils.consumeQuietly(response.entity) + where: + statusCode | expectedStatusCode + null | 200 + 300 | 300 + 204 | 204 + } + + def "should return response code 404 and error body when mocks does not apply"() { + given: + controlServerClient.addMock(new AddMockRequestData( + name: 'testRest1', + path: '/test1', + port: 9999, + predicate: '''{xml -> xml.name() == 'request2'}''', + response: '''{xml -> ""}''' + )) + HttpPost request = new HttpPost('http://localhost:9999/test1') + request.entity = new StringEntity('', ContentType.create("text/xml", "UTF-8")) + when: + CloseableHttpResponse response = client.execute(request) + then: + response.statusLine.statusCode == 404 + GPathResult secondXmlResponse = Util.extractXmlResponse(response) + secondXmlResponse.name() == 'invalidInput' + } + + def "should inform that there was problem during adding mock - invalid port"(){ + when: + controlServerClient.addMock(new AddMockRequestData( + name: 'testSoap', + path: '/testEndpoint2', + port: -1, + predicate: '''{xml -> true}''', + response: '''{xml -> ""}''', + soap: true + )) + then: + thrown(InvalidMockDefinitionException) + } + //TODO def "should dispatch rest mock with post method"(){} //TODO def "should dispatch rest mock with post method and request headers"(){} //TODO def "should dispatch rest mock with post method and response headers"(){} @@ -230,4 +284,8 @@ class MockServerIntegrationTest extends Specification { //TODO def "should dispatch rest mock with delete method and request headers"(){} //TODO def "should dispatch rest mock with delete method and response headers"(){} //TODO def "should dispatch rest mocks with all methods"(){} + + //TODO def "should get mock report"(){} + //TODO def "should get list mocks"(){} + //TODO def "should validate mock when creating" }