Skip to content

Commit

Permalink
fix: Support IP6 hosts #405
Browse files Browse the repository at this point in the history
  • Loading branch information
rholshausen committed Jan 18, 2023
1 parent 51c89df commit 21b06cf
Show file tree
Hide file tree
Showing 8 changed files with 211 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package au.com.dius.pact.consumer.model

import spock.lang.Specification

class MockProviderConfigSpec extends Specification {
def 'url test'() {
expect:
new MockProviderConfig(hostname, port).url() == url

where:

hostname | port | url
'127.0.0.1' | 0 | 'http://localhost:0'
'localhost' | 1234 | 'http://localhost:1234'
'[::1]' | 1234 | 'http://ip6-localhost:1234'
'ip6-localhost' | 1234 | 'http://ip6-localhost:1234'
'::1' | 0 | 'http://ip6-localhost:0'
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package au.com.dius.pact.consumer.junit;

import au.com.dius.pact.consumer.dsl.PactDslWithProvider;
import au.com.dius.pact.core.model.RequestResponsePact;
import au.com.dius.pact.core.model.annotations.Pact;
import org.apache.hc.client5.http.fluent.Request;
import org.junit.Rule;
import org.junit.Test;

import java.io.IOException;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;

public class IP6Test {

@Rule
public PactProviderRule provider = new PactProviderRule("ip6_provider", "::1", 0, this);

@Pact(provider = "ip6_provider", consumer = "test_consumer")
public RequestResponsePact getRequest(PactDslWithProvider builder) {
return builder
.uponReceiving("get request")
.path("/path")
.method("GET")
.willRespondWith()
.status(200)
.body("{}", "application/json")
.toPact();
}

@Test
@PactVerification("ip6_provider")
public void runTest() throws IOException {
assertThat(Request.get(provider.getUrl() + "/path").execute().returnContent().asString(), is(equalTo("{}")));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package au.com.dius.pact.consumer.junit5;

import au.com.dius.pact.consumer.MockServer;
import au.com.dius.pact.consumer.dsl.PactDslWithProvider;
import au.com.dius.pact.consumer.junit.MockServerConfig;
import au.com.dius.pact.consumer.model.MockServerImplementation;
import au.com.dius.pact.core.model.PactSpecVersion;
import au.com.dius.pact.core.model.RequestResponsePact;
import au.com.dius.pact.core.model.annotations.Pact;
import org.apache.hc.client5.http.fluent.Request;
import org.apache.hc.core5.http.ClassicHttpResponse;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import java.io.IOException;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;

@ExtendWith(PactConsumerTestExt.class)
@PactTestFor(providerName = "ip6_provider", pactVersion = PactSpecVersion.V3)
@MockServerConfig(hostInterface = "::1", port = "1234", implementation = MockServerImplementation.KTorServer)
public class Ip6KTorTest {
@Pact(consumer = "ApiConsumer")
public RequestResponsePact articles(PactDslWithProvider builder) {
return builder
.uponReceiving("GET request")
.path("/test")
.method("GET")
.willRespondWith()
.status(200)
.toPact();
}

@Test
@PactTestFor
void testApi(MockServer mockServer) throws IOException {
ClassicHttpResponse httpResponse = (ClassicHttpResponse) Request.get(mockServer.getUrl() + "/test").execute().returnResponse();
assertThat(httpResponse.getCode(), is(equalTo(200)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package au.com.dius.pact.consumer.junit5;

import au.com.dius.pact.consumer.MockServer;
import au.com.dius.pact.consumer.dsl.PactDslWithProvider;
import au.com.dius.pact.consumer.junit.MockServerConfig;
import au.com.dius.pact.core.model.PactSpecVersion;
import au.com.dius.pact.core.model.RequestResponsePact;
import au.com.dius.pact.core.model.annotations.Pact;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.io.IOUtils;
import org.apache.hc.client5.http.fluent.Request;
import org.apache.hc.core5.http.ClassicHttpResponse;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import static au.com.dius.pact.consumer.dsl.LambdaDsl.newJsonArrayMinLike;
import static java.lang.String.format;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;

@ExtendWith(PactConsumerTestExt.class)
@PactTestFor(providerName = "ip6_provider", pactVersion = PactSpecVersion.V3)
@MockServerConfig(hostInterface = "::1", port = "1234")
public class Ip6Test {
@Pact(consumer = "ApiConsumer")
public RequestResponsePact articles(PactDslWithProvider builder) {
return builder
.uponReceiving("GET request")
.path("/test")
.method("GET")
.willRespondWith()
.status(200)
.toPact();
}

@Test
@PactTestFor
void testApi(MockServer mockServer) throws IOException {
ClassicHttpResponse httpResponse = (ClassicHttpResponse) Request.get(mockServer.getUrl() + "/test").execute().returnResponse();
assertThat(httpResponse.getCode(), is(equalTo(200)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,24 @@ import io.ktor.request.receiveStream
import io.ktor.response.header
import io.ktor.response.respond
import io.ktor.response.respondBytes
import io.ktor.server.engine.ApplicationEngineEnvironment
import io.ktor.server.engine.applicationEngineEnvironment
import io.ktor.server.engine.connector
import io.ktor.server.engine.embeddedServer
import io.ktor.server.engine.sslConnector
import io.ktor.server.netty.Netty
import io.ktor.server.netty.NettyApplicationEngine
import io.ktor.util.network.hostname
import io.ktor.util.network.port
import io.netty.channel.Channel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import mu.KLogging
import java.net.SocketAddress
import java.util.zip.DeflaterInputStream
import java.util.zip.GZIPInputStream

class KTorMockServer(
class KTorMockServer @JvmOverloads constructor(
pact: BasePact,
config: MockProviderConfig,
private val stopTimeout: Long = 20000
Expand Down Expand Up @@ -117,10 +122,23 @@ class KTorMockServer(
}

override fun getUrl(): String {
return "${config.scheme}://${server.environment.connectors.first().host}:${this.getPort()}"
val address = socketAddress()
return if (address != null) {
"${config.scheme}://${address.hostname}:${address.port}"
} else {
val connectorConfig = server.environment.connectors.first()
"${config.scheme}://${connectorConfig.host}:${connectorConfig.port}"
}
}

private fun socketAddress(): SocketAddress? {
val field = server.javaClass.getDeclaredField("channels")
field.isAccessible = true
val channels = field.get(server) as List<Channel>?
return channels?.first()?.localAddress()
}

override fun getPort() = server.environment.connectors.first().port
override fun getPort() = socketAddress()?.port ?: server.environment.connectors.first().port

override fun updatePact(pact: Pact): Pact {
return if (pact.isV4Pact()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -334,13 +334,7 @@ abstract class BaseJdkMockServer(
initServer()
}

override fun getUrl(): String {
return if (config.port == 0) {
"${config.scheme}://${server.address.hostName}:${server.address.port}"
} else {
config.url()
}
}
override fun getUrl() = "${config.scheme}://${server.address.hostName}:${server.address.port}"

override fun getPort(): Int = server.address.port

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package au.com.dius.pact.consumer.model

import au.com.dius.pact.consumer.junit.MockServerConfig
import au.com.dius.pact.core.model.PactSpecVersion
import io.ktor.util.network.hostname
import java.net.InetSocketAddress
import java.util.Optional

Expand Down Expand Up @@ -52,7 +53,10 @@ open class MockProviderConfig @JvmOverloads constructor (
open val transportRegistryEntry: String = ""
) {

fun url() = "$scheme://$hostname:$port"
fun url(): String {
val address = address()
return "$scheme://${address.hostname}:${address.port}"
}

fun address() = InetSocketAddress(hostname, port)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,42 @@ class MockHttpServerSpec extends Specification {
then:
request.path == '/endpoint/Some%2FValue'
}

def 'IP6 test'() {
given:
def pact = new RequestResponsePact(new Provider(), new Consumer(), [])
def config = new MockProviderConfig(hostname, port)

when:
def mockServer = mockServerClass.newInstance(pact, config)
mockServer.start()

then:
mockServer.url ==~ url

cleanup:
mockServer.stop()

where:

mockServerClass | hostname | port | url
MockHttpServer | '[::1]' | 0 | /http:\/\/ip6-localhost:\d+/
MockHttpServer | '[::1]' | 1234 | 'http://ip6-localhost:1234'
MockHttpServer | '::1' | 0 | /http:\/\/ip6-localhost:\d+/
MockHttpServer | '::1' | 1235 | 'http://ip6-localhost:1235'
MockHttpServer | 'ip6-localhost' | 0 | /http:\/\/ip6-localhost:\d+/
MockHttpServer | 'ip6-localhost' | 1236 | 'http://ip6-localhost:1236'
MockHttpsServer | '[::1]' | 0 | /http:\/\/ip6-localhost:\d+/
MockHttpsServer | '[::1]' | 1237 | 'http://ip6-localhost:1237'
MockHttpsServer | '::1' | 0 | /http:\/\/ip6-localhost:\d+/
MockHttpsServer | '::1' | 1238 | 'http://ip6-localhost:1238'
MockHttpsServer | 'ip6-localhost' | 0 | /http:\/\/ip6-localhost:\d+/
MockHttpsServer | 'ip6-localhost' | 1239 | 'http://ip6-localhost:1239'
KTorMockServer | '[::1]' | 0 | /http:\/\/ip6-localhost:\d+/
KTorMockServer | '[::1]' | 2234 | 'http://ip6-localhost:2234'
KTorMockServer | '::1' | 0 | /http:\/\/ip6-localhost:\d+/
KTorMockServer | '::1' | 2235 | 'http://ip6-localhost:2235'
KTorMockServer | 'ip6-localhost' | 0 | /http:\/\/ip6-localhost:\d+/
KTorMockServer | 'ip6-localhost' | 2236 | 'http://ip6-localhost:2236'
}
}

0 comments on commit 21b06cf

Please sign in to comment.