Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PactV3Options.Port property value is not respected #1131

Closed
daTooz opened this issue Oct 23, 2023 · 6 comments
Closed

PactV3Options.Port property value is not respected #1131

daTooz opened this issue Oct 23, 2023 · 6 comments
Labels
awaiting feedback Awaiting Feedback from OP

Comments

@daTooz
Copy link

daTooz commented Oct 23, 2023

Software versions

Please provide at least OS and version of pact-js

  • Consumer Pact library: 12.1.0
  • Node Version: 18.18.2

I am attempting to new up a PactV3 using PactV3Options but it appears that the port value in the options is not respected...

const provider = new PactV3({
consumer: "consumer",
provider: "provider",
//log: path.resolve(process.cwd(), "logs", "pact.log"),
//logLevel: "debug",
dir: path.resolve(process.cwd(), "pacts"),
spec: SpecificationVersion.SPECIFICATION_VERSION_V3,
host: "localhost",
port: 9999
});

...whether or not the port value is set, the mockerserver is assigning a random port.

NOTES:

  1. The host value is respected.
  2. OS: Windows 11
  3. I confirmed the port was not in use
@daTooz daTooz added bug Indicates an unexpected problem or unintended behavior triage This issue is yet to be triaged by a maintainer labels Oct 23, 2023
@YOU54F
Copy link
Member

YOU54F commented Nov 8, 2023

Hey,

So just taken a look now. - working branch here

https://github.com/YOU54F/vscode-pact-snippets/blob/issue/pact-js-1131/js/v3.test.js

Testing on MacOSX - Ventura 13.6.1, Node v18.17.1

Working test with random port

const axios = require("axios");
const defaultBaseUrl = "http://your-api.example.com";
const api = (baseUrl = defaultBaseUrl) => ({
  getHealth: () =>
    axios.get(baseUrl + "/health").then((response) => response.data.status),
  /* other endpoints here */
});

const { Pact, Matchers } = require("@pact-foundation/pact");
const provider = new Pact({
  consumer: "consumer-js-v2",
  provider: "provider-js-v2",
  host: "127.0.0.1",
  port: 9999
});

const { regex, like } = Matchers;

describe("Name of the group", () => {
  beforeAll(() => provider.setup());
  afterEach(() => provider.verify());
  afterAll(() => provider.finalize());

  it("should create a v2 js pact", () => {
    provider.addInteraction({
      state: "Server is healthy",
      uponReceiving: "A request for API health",
      withRequest: {
        method: "GET",
        path: "/health",
      },
      willRespondWith: {
        status: 200,
        body: { status: like("up") },
      },
    });

    const client = api(provider.mockService.baseUrl);
    return client.getHealth().then((health) => {
      expect(health).toEqual("up");
    });
  });
});

Log output showing random port being used.

2023-11-08T11:50:21.958837Z DEBUG ThreadId(01) pactffi_create_mock_server_for_pact{pact=PactHandle { pact_ref: 1 } addr_str=0x16f5d4108 tls=false}: pact_mock_server::mock_server: Started mock server on 127.0.0.1:9999
2023-11-08T11:49:29.076520Z DEBUG tokio-runtime-worker pact_mock_server::hyper_server: Test context = {"mockServer": Object {"port": Number(9999), "url": String("http://127.0.0.1:9999")}}
2023-11-08T11:49:29.076527Z TRACE tokio-runtime-worker pact_matching: generate_response response=HttpResponse { status: 200, headers: Some({"Content-Type": ["application/json"]}), body: Present(b"{\"status\":\"up\"}", Some(ContentType { main_type: "application", sub_type: "json", attributes: {}, suffix: None }), None), matching_rules: MatchingRules { rules: {BODY: MatchingRuleCategory { name: BODY, rules: {DocPath { path_tokens: [Root, Field("status")], expr: "$.status" }: RuleList { rules: [Type], rule_logic: And, cascaded: false }} }} }, generators: Generators { categories: {} } } mode=Consumer context={"mockServer": Object {"port": Number(9999), "url": String("http://127.0.0.1:9999")}}

Note following combinations also worked.

Just port, host defaults to 127.0.0.1

const provider = new PactV3({
  consumer: "consumer-js-v3",
  provider: "provider-js-v3",
  port: 9999
});

port & host set

const provider = new PactV3({
  consumer: "consumer-js-v3",
  provider: "provider-js-v3",
  host: "127.0.0.1",
  port: 9999
});

Setting the host value to localhost was no good, either with port defined, or undefined.

const provider = new PactV3({
  consumer: "consumer-js-v3",
  provider: "provider-js-v3",
  logLevel: "trace",
  host: "localhost",
  port: 9999
});

This actually resulted in an error where the mock server failed to start.

2023-11-08T12:01:07.789321Z TRACE ThreadId(01) pact_ffi::mock_server::handles: with_pact - ref = 1, keys = [1]
2023-11-08T12:01:07.789341Z TRACE ThreadId(01) pact_ffi::mock_server::handles: with_pact before - ref = 1, inner = RefCell { value: PactHandleInner { pact: V4Pact { consumer: Consumer { name: "consumer-js-v3" }, provider: Provider { name: "provider-js-v3" }, interactions: [], metadata: {"pactRust": Object {"ffi": String("0.4.9")}}, plugin_data: [] }, mock_server_started: false, specification_version: V3 } }
2023-11-08T12:01:07.790131Z TRACE ThreadId(01) pact_ffi::mock_server::handles: with_pact after - ref = 1, inner = RefCell { value: PactHandleInner { pact: V4Pact { consumer: Consumer { name: "consumer-js-v3" }, provider: Provider { name: "provider-js-v3" }, interactions: [], metadata: {"pactRust": Object {"ffi": String("0.4.9")}}, plugin_data: [] }, mock_server_started: false, specification_version: V3 } }
2023-11-08T12:01:07.790162Z TRACE ThreadId(01) pact_ffi::mock_server::handles: with_pact - ref = 1, keys = [1]
2023-11-08T12:01:07.790165Z TRACE ThreadId(01) pact_ffi::mock_server::handles: with_pact before - ref = 1, inner = RefCell { value: PactHandleInner { pact: V4Pact { consumer: Consumer { name: "consumer-js-v3" }, provider: Provider { name: "provider-js-v3" }, interactions: [], metadata: {"pactRust": Object {"ffi": String("0.4.9")}}, plugin_data: [] }, mock_server_started: false, specification_version: V3 } }
2023-11-08T12:01:07.790169Z TRACE ThreadId(01) pact_ffi::mock_server::handles: with_pact after - ref = 1, inner = RefCell { value: PactHandleInner { pact: V4Pact { consumer: Consumer { name: "consumer-js-v3" }, provider: Provider { name: "provider-js-v3" }, interactions: [], metadata: {"pact-js": Object {"version": String("12.1.0")}, "pactRust": Object {"ffi": String("0.4.9")}}, plugin_data: [] }, mock_server_started: false, specification_version: V3 } }
2023-11-08T12:01:07.791263Z TRACE ThreadId(01) pact_ffi::mock_server::handles: with_pact - ref = 1, keys = [1]
2023-11-08T12:01:07.791267Z TRACE ThreadId(01) pact_ffi::mock_server::handles: with_pact before - ref = 1, inner = RefCell { value: PactHandleInner { pact: V4Pact { consumer: Consumer { name: "consumer-js-v3" }, provider: Provider { name: "provider-js-v3" }, interactions: [], metadata: {"pact-js": Object {"version": String("12.1.0")}, "pactRust": Object {"ffi": String("0.4.9")}}, plugin_data: [] }, mock_server_started: false, specification_version: V3 } }
2023-11-08T12:01:07.791278Z TRACE ThreadId(01) pact_ffi::mock_server::handles: with_pact after - ref = 1, inner = RefCell { value: PactHandleInner { pact: V4Pact { consumer: Consumer { name: "consumer-js-v3" }, provider: Provider { name: "provider-js-v3" }, interactions: [SynchronousHttp { id: None, key: None, description: "A request for API health", provider_states: [], request: HttpRequest { method: "GET", path: "/", query: None, headers: None, body: Missing, matching_rules: MatchingRules { rules: {} }, generators: Generators { categories: {} } }, response: HttpResponse { status: 200, headers: None, body: Missing, matching_rules: MatchingRules { rules: {} }, generators: Generators { categories: {} } }, comments: {}, pending: false, plugin_config: {}, interaction_markup: InteractionMarkup { markup: "", markup_type: "" }, transport: None }], metadata: {"pact-js": Object {"version": String("12.1.0")}, "pactRust": Object {"ffi": String("0.4.9")}}, plugin_data: [] }, mock_server_started: false, specification_version: V3 } }
2023-11-08T12:01:07.792406Z TRACE ThreadId(01) pact_ffi::mock_server::handles: with_interaction - index = 1, interaction = 1
2023-11-08T12:01:07.792413Z TRACE ThreadId(01) pact_ffi::mock_server::handles: with_interaction - keys = [1]
2023-11-08T12:01:07.792415Z TRACE ThreadId(01) pact_ffi::mock_server::handles: with_interaction - inner = PactHandleInner { pact: V4Pact { consumer: Consumer { name: "consumer-js-v3" }, provider: Provider { name: "provider-js-v3" }, interactions: [SynchronousHttp { id: None, key: None, description: "A request for API health", provider_states: [], request: HttpRequest { method: "GET", path: "/", query: None, headers: None, body: Missing, matching_rules: MatchingRules { rules: {} }, generators: Generators { categories: {} } }, response: HttpResponse { status: 200, headers: None, body: Missing, matching_rules: MatchingRules { rules: {} }, generators: Generators { categories: {} } }, comments: {}, pending: false, plugin_config: {}, interaction_markup: InteractionMarkup { markup: "", markup_type: "" }, transport: None }], metadata: {"pact-js": Object {"version": String("12.1.0")}, "pactRust": Object {"ffi": String("0.4.9")}}, plugin_data: [] }, mock_server_started: false, specification_version: V3 }
2023-11-08T12:01:07.792465Z TRACE ThreadId(01) pact_ffi::mock_server::handles: with_interaction - index = 1, interaction = 1
2023-11-08T12:01:07.792468Z TRACE ThreadId(01) pact_ffi::mock_server::handles: with_interaction - keys = [1]
2023-11-08T12:01:07.792470Z TRACE ThreadId(01) pact_ffi::mock_server::handles: with_interaction - inner = PactHandleInner { pact: V4Pact { consumer: Consumer { name: "consumer-js-v3" }, provider: Provider { name: "provider-js-v3" }, interactions: [SynchronousHttp { id: None, key: None, description: "A request for API health", provider_states: [ProviderState { name: "Server is healthy", params: {} }], request: HttpRequest { method: "GET", path: "/", query: None, headers: None, body: Missing, matching_rules: MatchingRules { rules: {} }, generators: Generators { categories: {} } }, response: HttpResponse { status: 200, headers: None, body: Missing, matching_rules: MatchingRules { rules: {} }, generators: Generators { categories: {} } }, comments: {}, pending: false, plugin_config: {}, interaction_markup: InteractionMarkup { markup: "", markup_type: "" }, transport: None }], metadata: {"pact-js": Object {"version": String("12.1.0")}, "pactRust": Object {"ffi": String("0.4.9")}}, plugin_data: [] }, mock_server_started: false, specification_version: V3 }
2023-11-08T12:01:07.792794Z TRACE ThreadId(01) pact_ffi::mock_server::handles: with_interaction - index = 1, interaction = 1
2023-11-08T12:01:07.792797Z TRACE ThreadId(01) pact_ffi::mock_server::handles: with_interaction - keys = [1]
2023-11-08T12:01:07.792799Z TRACE ThreadId(01) pact_ffi::mock_server::handles: with_interaction - inner = PactHandleInner { pact: V4Pact { consumer: Consumer { name: "consumer-js-v3" }, provider: Provider { name: "provider-js-v3" }, interactions: [SynchronousHttp { id: None, key: None, description: "A request for API health", provider_states: [ProviderState { name: "Server is healthy", params: {} }], request: HttpRequest { method: "GET", path: "/health", query: None, headers: None, body: Missing, matching_rules: MatchingRules { rules: {PATH: MatchingRuleCategory { name: PATH, rules: {} }} }, generators: Generators { categories: {} } }, response: HttpResponse { status: 200, headers: None, body: Missing, matching_rules: MatchingRules { rules: {} }, generators: Generators { categories: {} } }, comments: {}, pending: false, plugin_config: {}, interaction_markup: InteractionMarkup { markup: "", markup_type: "" }, transport: None }], metadata: {"pact-js": Object {"version": String("12.1.0")}, "pactRust": Object {"ffi": String("0.4.9")}}, plugin_data: [] }, mock_server_started: false, specification_version: V3 }
2023-11-08T12:01:07.793015Z TRACE ThreadId(01) pact_ffi::mock_server::handles: >>> pactffi_with_body(InteractionHandle { interaction_ref: 65537 }, Response, 0x16f9ac418, 0x14c740de0)
2023-11-08T12:01:07.793547Z TRACE ThreadId(01) pact_ffi::mock_server::handles: with_interaction - index = 1, interaction = 1
2023-11-08T12:01:07.793549Z TRACE ThreadId(01) pact_ffi::mock_server::handles: with_interaction - keys = [1]
2023-11-08T12:01:07.793550Z TRACE ThreadId(01) pact_ffi::mock_server::handles: with_interaction - inner = PactHandleInner { pact: V4Pact { consumer: Consumer { name: "consumer-js-v3" }, provider: Provider { name: "provider-js-v3" }, interactions: [SynchronousHttp { id: None, key: None, description: "A request for API health", provider_states: [ProviderState { name: "Server is healthy", params: {} }], request: HttpRequest { method: "GET", path: "/health", query: None, headers: None, body: Missing, matching_rules: MatchingRules { rules: {PATH: MatchingRuleCategory { name: PATH, rules: {} }} }, generators: Generators { categories: {} } }, response: HttpResponse { status: 200, headers: None, body: Missing, matching_rules: MatchingRules { rules: {} }, generators: Generators { categories: {} } }, comments: {}, pending: false, plugin_config: {}, interaction_markup: InteractionMarkup { markup: "", markup_type: "" }, transport: None }], metadata: {"pact-js": Object {"version": String("12.1.0")}, "pactRust": Object {"ffi": String("0.4.9")}}, plugin_data: [] }, mock_server_started: false, specification_version: V3 }
2023-11-08T12:01:07.793746Z TRACE ThreadId(01) pact_ffi::mock_server::handles: Setting up the response body
2023-11-08T12:01:07.793763Z TRACE ThreadId(01) pact_ffi::mock_server::bodies: process_json
2023-11-08T12:01:07.793768Z TRACE ThreadId(01) pact_ffi::mock_server::bodies: >>> process_object(obj={"status": Object {"pact:matcher:type": String("type"), "value": String("up")}}, matching_rules=MatchingRuleCategory { name: BODY, rules: {} }, generators=Generators { categories: {} }, path=$, type_matcher=false)
2023-11-08T12:01:07.794321Z DEBUG ThreadId(01) pact_ffi::mock_server::bodies: Path = $
2023-11-08T12:01:07.794324Z DEBUG ThreadId(01) pact_ffi::mock_server::bodies: Configuring a normal object
2023-11-08T12:01:07.794405Z TRACE ThreadId(01) pact_ffi::mock_server::bodies: >>> process_object(obj={"pact:matcher:type": String("type"), "value": String("up")}, matching_rules=MatchingRuleCategory { name: BODY, rules: {} }, generators=Generators { categories: {} }, path=$.status, type_matcher=false)
2023-11-08T12:01:07.794409Z DEBUG ThreadId(01) pact_ffi::mock_server::bodies: Path = $.status
2023-11-08T12:01:07.794410Z DEBUG ThreadId(01) pact_ffi::mock_server::bodies: detected pact:matcher:type, will configure a matcher
2023-11-08T12:01:07.794514Z TRACE ThreadId(01) pact_models::matchingrules: rule_type: type, attributes: {"pact:matcher:type":"type","value":"up"}
2023-11-08T12:01:07.794526Z TRACE ThreadId(01) pact_ffi::mock_server::bodies: matching_rule = Ok((Some(Type), String("up")))
 FAIL  ./v3.test.js.794543Z TRACE ThreadId(01) pact_ffi::mock_server::bodies: -> result = String("up")
  test with pact
    ✕ should setup a test with pact (18 ms)

  ● test with pact › should setup a test with pact

    Error in native callback

      at mockServerMismatches (node_modules/@pact-foundation/pact-core/src/consumer/internals.ts:10:9)
      at Object.mockServerMismatches (node_modules/@pact-foundation/pact-core/src/consumer/index.ts:123:27)
      at PactV3.<anonymous> (node_modules/@pact-foundation/src/v3/pact.ts:206:39)
      at step (node_modules/@pact-foundation/pact/src/v3/pact.js:33:23)
      at Object.throw (node_modules/@pact-foundation/pact/src/v3/pact.js:14:53)
      at rejected (node_modules/@pact-foundation/pact/src/v3/pact.js:6:65)

@mefellows mefellows added the awaiting feedback Awaiting Feedback from OP label Nov 8, 2023
@daTooz
Copy link
Author

daTooz commented Nov 16, 2023

@YOU54F @mefellows hey gang, I don't mind checking/confirming the fix but I am a Pact newbie and may need a little direction.

@mefellows
Copy link
Member

The port doesn't seem to be random here, it's 9999 as specified in the test. Did you mean to say something else Yousaf?

Screenshot 2023-11-17 at 7 19 38 am

@daTooz
Copy link
Author

daTooz commented Jan 10, 2024

@YOU54F @mefellows I just wanted to see what I can do to help move this forward?

@mefellows
Copy link
Member

I'm not sure there is a bug here, perhaps it's only a problem on Windows. This code starts a mock service on port 9999 running on host 127.0.0.1 (default):

index.js:

const axios = require("axios");
const defaultBaseUrl = "http://your-api.example.com";
const api = (baseUrl = defaultBaseUrl) => ({
  getHealth: () =>
    axios.get(baseUrl + "/health").then((response) => response.data.status),
  /* other endpoints here */
});

(async () => {
  const { PactV3, Matchers } = require("@pact-foundation/pact");
  const provider = new PactV3({
    consumer: "consumer-js-v2",
    provider: "provider-js-v2",
    host: "127.0.0.1",
    port: 9999,
  });

  const { regex, like } = Matchers;

  await provider.setup();

  provider.addInteraction({
    state: "Server is healthy",
    uponReceiving: "A request for API health",
    withRequest: {
      method: "GET",
      path: "/health",
    },
    willRespondWith: {
      status: 200,
      body: { status: like("up") },
    },
  });

  await provider.executeTest(async (mockServer) => {
    console.log(mockServer.url)
    const client = api("http://127.0.0.1:9999");
    const health = await client.getHealth();
    // expect(health).toEqual("up");
    console.log(health)

  })
})();

I just wanted to see what I can do to help move this forward?
Provide a reproducible example. As per the bug template, there a JS project you could fork and clone to demonstrate the issue: https://github.com/mefellows/pact-js-repro-template

The build includes a windows runner, so it should cover your use case.

@mefellows mefellows removed bug Indicates an unexpected problem or unintended behavior triage This issue is yet to be triaged by a maintainer labels Jan 14, 2024
@mefellows
Copy link
Member

Closing due to inactivity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting feedback Awaiting Feedback from OP
Projects
None yet
Development

No branches or pull requests

3 participants