Pact-jvm: [pact-jvm-consumer-junit], PactProviderRule with random port (set via 0), get that port after Netty-launch

Created on 11 Apr 2017  路  10Comments  路  Source: pact-foundation/pact-jvm

This feature-request is about PactProviderRule.java.

In my use-case, I want to bind the PactProvider to a specific IP, but with a random port. This is possible, using

rule = new PactProviderRule("a name" <some-ip>, 0, target)

a Netty will be launched, having a random port. So far, so fine.

But, I cannot access the random port.

int port = rule.getConfig().getPort()

will always return 0. Well, somehow this is correct ...

Please provide a way, in which I can access the random port of the launched Netty in this use-case.

bug

All 10 comments

As a work around, if you leave the host and port out (or set them to null), you will get a random port accessible via rule.getConfig().getPort().

I could not find a way to get the port from Netty, so I have implemented a new mock server that can return the bound port. I still have to update PactProviderRule to use the new mock server.

Released 3.4.0 with the new mock server.

This happened for me with 3.5.0 today

@SchulteMarkus Are you using PactProviderRuleMk2?

Yes.

@Rule
public BaseProviderRule mockProvider = new PactProviderRuleMk2("some-name", this);

Assert.assertEquals(0, mockProvider.getConfig().getPort()); // works fine

mockProvider.getPort() will only return the port while the mock server is running, which is during the execution of the test method. Calling it outside of the test method just returns null.

mockProvider.getConfig().getPort() will return the configured port number, which will be zero.

Ah, I see, this totally make sense!
In my use-case, I am doing integration-testing with the help of Pact. My microservice is packaged into a docker-image. When integration-testing, I am running this docker-image. I am starting the container using an environment variable, which should contain the URL of a service my microservice uses. From the docker-containers point-of-view, just as in a productive-system, it got an address to send it's requests to, but the "Pact-server" will handle those requests while testing. This setup happens before the integration-test runs.

I guess there are two options at this point:

  • I will have to rewrite the application, so I can pass in the required "Pact-server"-URL after the application has been started
  • Maybe, in this case (mockProvider.getConfig().getPort() == 0 and server is not running), this method-call will throw an exception (or return an Optional in general, or ...), so as a user, it would be more easy to see my mistake.

I was also thinking of throwing an exception to let the user know that the port is not available yet.

Using it in the way you are is not what it was designed for. Maybe something like a standalone mock server is what you need, so you can start it before you start your container (or use something like docker compose).

See

pact-jvm-consumer-junit fits my needs (almost) perfectly, but thanks for your effort of showing me some alternatives.
I will stay by detecting a free port myself as part of the test-setup (in my case I am using Spring) :-)

  @Rule
  public BaseProviderRule mockProvider = new PactProviderRuleMk2("a name", "127.0.0.1", org.springframework.util.SocketUtils.findAvailableTcpPort(), this);

But I would appreciate the "exception"-solution, instead of getPort() returning 0, if the server has not yet started.

Was this page helpful?
0 / 5 - 0 ratings