Add imports support in closures

This commit is contained in:
Dominik Przybysz 2015-12-22 15:24:06 +01:00
parent 261126d58b
commit 493bb8fd91
6 changed files with 237 additions and 171 deletions

View file

@ -13,5 +13,10 @@
<xs:enumeration value="PATCH"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="importAlias">
<xs:attribute name="alias" type="xs:string"/>
<xs:attribute name="fullClassName" type="xs:string"/>
</xs:complexType>
</xs:schema>

View file

@ -22,6 +22,7 @@
<xs:element name="method" type="common:method" minOccurs="0"/>
<xs:element name="responseHeaders" type="xs:string" minOccurs="0"/>
<xs:element name="schema" type="xs:string" minOccurs="0"/>
<xs:element name="imports" type="common:importAlias" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>

View file

@ -109,6 +109,7 @@
<xs:element name="method" type="common:method"/>
<xs:element name="statusCode" type="xs:int"/>
<xs:element name="schema" type="xs:string" minOccurs="0"/>
<xs:element name="imports" type="common:importAlias" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>

View file

@ -1,17 +1,31 @@
package pl.touk.mockserver.tests
import groovy.util.slurpersupport.GPathResult
import org.apache.http.client.methods.*
import org.apache.http.client.methods.CloseableHttpResponse
import org.apache.http.client.methods.HttpDelete
import org.apache.http.client.methods.HttpGet
import org.apache.http.client.methods.HttpHead
import org.apache.http.client.methods.HttpOptions
import org.apache.http.client.methods.HttpPatch
import org.apache.http.client.methods.HttpPost
import org.apache.http.client.methods.HttpPut
import org.apache.http.client.methods.HttpTrace
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.api.common.ImportAlias
import pl.touk.mockserver.api.common.Method
import pl.touk.mockserver.api.request.AddMock
import pl.touk.mockserver.api.response.MockEventReport
import pl.touk.mockserver.api.response.MockReport
import pl.touk.mockserver.client.*
import pl.touk.mockserver.client.InvalidMockDefinition
import pl.touk.mockserver.client.InvalidMockRequestSchema
import pl.touk.mockserver.client.MockAlreadyExists
import pl.touk.mockserver.client.MockDoesNotExist
import pl.touk.mockserver.client.RemoteMockServer
import pl.touk.mockserver.client.Util
import pl.touk.mockserver.server.HttpMockServer
import spock.lang.Shared
import spock.lang.Specification
@ -611,7 +625,7 @@ class MockServerIntegrationTest extends Specification {
restPostResponse.name == 'goodResponse-1'
}
def "should get list mocks"() {
def "should get list of mocks"() {
given:
remoteMockServer.addMock(new AddMock(
name: 'testRest2',
@ -648,7 +662,8 @@ class MockServerIntegrationTest extends Specification {
name: 'testRest',
path: 'testEndpoint',
port: 9999,
schema: 'schema2.xsd'
schema: 'schema2.xsd',
imports: [new ImportAlias(alias: 'aaa', fullClassName: 'bbb')]
))
remoteMockServer.removeMock('testRest5')
when:
@ -660,6 +675,7 @@ class MockServerIntegrationTest extends Specification {
assertMockReport(mockReport[2], [name: 'testRest3', path: 'testEndpoint2', port: 9999, predicate: '{ _ -> true }', response: '''{ _ -> '' }''', responseHeaders: '{ _ -> [:] }', soap: false, statusCode: 200, method: Method.POST])
assertMockReport(mockReport[3], [name: 'testRest4', path: 'testEndpoint', port: 9999, predicate: '{ _ -> true }', response: '''{ _ -> '' }''', responseHeaders: '{ _ -> [:] }', soap: true, statusCode: 204, method: Method.PUT])
assertMockReport(mockReport[4], [name: 'testRest6', path: 'testEndpoint2', port: 9999, predicate: '{ _ -> true }', response: '''{ _ -> '' }''', responseHeaders: '{ _ -> [:] }', soap: false, statusCode: 200, method: Method.POST])
mockReport[0].imports.find { it.alias == 'aaa' }?.fullClassName == 'bbb'
}
private static void assertMockReport(MockReport mockReport, Map<String, Object> props) {
@ -991,4 +1007,26 @@ class MockServerIntegrationTest extends Specification {
expect:
remoteMockServer.removeMock('testSoap')?.size() == 2
}
def "should add mock with alias"() {
expect:
remoteMockServer.addMock(new AddMock(
name: 'testRest',
path: 'testEndpoint',
port: 9999,
predicate: '''{req -> req.xml.name() == 'request'}''',
response: '''{req -> "<goodResponseRest-${AAA.XMLNS_ATTRIBUTE}/>"}''',
soap: false,
imports: [new ImportAlias(alias: 'AAA', fullClassName: 'javax.xml.XMLConstants')]
))
when:
HttpPost restPost = new HttpPost('http://localhost:9999/testEndpoint')
restPost.entity = new StringEntity('<request/>', ContentType.create("text/xml", "UTF-8"))
CloseableHttpResponse response = client.execute(restPost)
then:
GPathResult restPostResponse = Util.extractXmlResponse(response)
restPostResponse.name() == 'goodResponseRest-xmlns'
expect:
remoteMockServer.removeMock('testRest')?.size() == 1
}
}

View file

@ -2,11 +2,21 @@ package pl.touk.mockserver.server
import com.sun.net.httpserver.HttpExchange
import groovy.util.logging.Slf4j
import pl.touk.mockserver.api.common.ImportAlias
import pl.touk.mockserver.api.request.AddMock
import pl.touk.mockserver.api.request.MockServerRequest
import pl.touk.mockserver.api.request.PeekMock
import pl.touk.mockserver.api.request.RemoveMock
import pl.touk.mockserver.api.response.*
import pl.touk.mockserver.api.response.ExceptionOccured
import pl.touk.mockserver.api.response.MockAdded
import pl.touk.mockserver.api.response.MockEventReport
import pl.touk.mockserver.api.response.MockPeeked
import pl.touk.mockserver.api.response.MockRemoved
import pl.touk.mockserver.api.response.MockReport
import pl.touk.mockserver.api.response.MockRequestReport
import pl.touk.mockserver.api.response.MockResponseReport
import pl.touk.mockserver.api.response.Mocks
import pl.touk.mockserver.api.response.Parameter
import javax.xml.bind.JAXBContext
import java.util.concurrent.ConcurrentHashMap
@ -65,7 +75,8 @@ class HttpMockServer {
soap: it.soap,
method: it.method,
statusCode: it.statusCode as int,
schema: it.schema
schema: it.schema,
imports: it.imports.collect { new ImportAlias(alias: it.key, fullClassName: it.value) }
)
}
)
@ -90,6 +101,7 @@ class HttpMockServer {
private static Mock mockFromRequest(AddMock request) {
Mock mock = new Mock(request.name, request.path, request.port)
mock.imports = request.imports?.collectEntries { [(it.alias): it.fullClassName] } ?: [:]
mock.predicate = request.predicate
mock.response = request.response
mock.soap = request.soap

View file

@ -3,6 +3,8 @@ package pl.touk.mockserver.server
import groovy.transform.EqualsAndHashCode
import groovy.transform.PackageScope
import groovy.util.logging.Slf4j
import org.codehaus.groovy.control.CompilerConfiguration
import org.codehaus.groovy.control.customizers.ImportCustomizer
import pl.touk.mockserver.api.common.Method
import javax.xml.XMLConstants
@ -31,6 +33,7 @@ class Mock implements Comparable<Mock> {
final List<MockEvent> history = new CopyOnWriteArrayList<>()
String schema
private Validator validator
Map<String, String> imports = [:]
Mock(String name, String path, int port) {
if (!(name)) {
@ -88,7 +91,13 @@ class Mock implements Comparable<Mock> {
if (predicate ==~ /(?m).*System\s*\.\s*exit\s*\(.*/) {
throw new RuntimeException('System.exit is forbidden')
}
GroovyShell sh = new GroovyShell(this.class.classLoader);
CompilerConfiguration compilerConfiguration = new CompilerConfiguration()
ImportCustomizer customizer = new ImportCustomizer()
imports.each {
customizer.addImport(it.key, it.value)
}
compilerConfiguration.addCompilationCustomizers(customizer)
GroovyShell sh = new GroovyShell(this.class.classLoader, compilerConfiguration);
return sh.evaluate(predicate) as Closure
}