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

Match.Regex returning 500 when used in WithHeader #420

Open
facusantillo opened this issue Oct 18, 2022 · 10 comments
Open

Match.Regex returning 500 when used in WithHeader #420

facusantillo opened this issue Oct 18, 2022 · 10 comments
Labels
bug Indicates an unexpected problem or unintended behavior upstream Indicates that an issue relates to an upstream problem (such as in pact-reference)

Comments

@facusantillo
Copy link

Following the tutorial for implementing V3, I found that the client returns an internal server error when trying to use a regex matcher in the header. Seems like it's not working as expected (based in what I've seen from the guide)

Here is the code example

Test implementation:

public async void GetProduct()
        {
            // Arange
            pact.UponReceiving("A valid request for a product")
                    .Given("product with ID 10 exists")
                    .WithRequest(HttpMethod.Get, "/api/products/10")
                    .WithHeader("Authorization", Match.Regex("Bearer 2019-01-14T11:34:18.045Z", "Bearer \\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z"))
                .WillRespond()
                    .WithStatus(HttpStatusCode.OK)
                    .WithHeader("Content-Type", "application/json; charset=utf-8")
                    .WithJsonBody(new TypeMatcher(products[1]));

            await pact.VerifyAsync(async ctx =>
            {
                var response = await ApiClient.GetProduct(10);
                Assert.Equal(HttpStatusCode.OK, response.StatusCode);
            });
        }

Client:

 public async Task<HttpResponseMessage> GetProduct(int id)
        {
            using (var client = new HttpClient { BaseAddress = BaseUri })
            {
                try
                {
                    client.DefaultRequestHeaders.Add("Authorization", $"Bearer {DateTime.Now:yyyy-MM-ddTHH:mm:ss.fffZ}");
                    var response = await client.GetAsync($"/api/products/{id}");
                    return response;
                }
                catch (Exception ex)
                {
                    throw new Exception("There was a problem connecting to Provider API.", ex);
                }
            }
        }

Error:

Message: 
Assert.Equal() Failure
Expected: OK
Actual:   InternalServerError

  Stack Trace: 
ApiTest.<GetProduct>b__6_0(IConsumerContext ctx) line 80
PactBuilder.VerifyAsync(Func`2 interact)
ApiTest.GetProduct() line 77
<>c.<ThrowAsync>b__139_0(Object state)

  Standard Output: 
Mock driver logs:

2022-10-18T11:47:49.732152Z  INFO tokio-runtime-worker pact_mock_server::hyper_server: Received request HTTP Request ( method: GET, path: /api/products/10, query: None, headers: Some({"host": ["localhost:9000"], "authorization": ["Bearer 2022-10-18T13:47:47.628Z"]}), body: Empty )
2022-10-18T11:47:49.732290Z  INFO tokio-runtime-worker pact_matching: comparing to expected HTTP Request ( method: GET, path: /api/products/10, query: None, headers: Some({"Authorization": ["Bearer 2019-01-14T11:34:18.045Z"]}), body: Missing )
@mefellows
Copy link
Member

Can you please share the full DEBUG level logs for this?

@facusantillo
Copy link
Author

Standard Output: 
Mock driver logs:

2022-10-18T12:15:25.022211Z DEBUG tokio-runtime-worker pact_mock_server::hyper_server: Creating pact request from hyper request
2022-10-18T12:15:25.022217Z DEBUG tokio-runtime-worker pact_mock_server::hyper_server: Extracting query from uri /api/products/10
2022-10-18T12:15:25.022255Z  INFO tokio-runtime-worker pact_mock_server::hyper_server: Received request HTTP Request ( method: GET, path: /api/products/10, query: None, headers: Some({"host": ["localhost:9000"], "authorization": ["Bearer 2022-10-18T14:15:22.953Z"]}), body: Empty )
2022-10-18T12:15:25.022313Z  INFO tokio-runtime-worker pact_matching: comparing to expected HTTP Request ( method: GET, path: /api/products/10, query: None, headers: Some({"Authorization": ["Bearer 2019-01-14T11:34:18.045Z"]}), body: Missing )
2022-10-18T12:15:25.022316Z DEBUG tokio-runtime-worker pact_matching:      body: ''
2022-10-18T12:15:25.022318Z DEBUG tokio-runtime-worker pact_matching:      matching_rules: MatchingRules { rules: {PATH: MatchingRuleCategory { name: PATH, rules: {} }, HEADER: MatchingRuleCategory { name: HEADER, rules: {DocPath { path_tokens: [Root, Field("Authorization"), Index(0)], expr: "$.Authorization[0]" }: RuleList { rules: [Regex("Bearer \\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z")], rule_logic: And, cascaded: false }} }} }
2022-10-18T12:15:25.022330Z DEBUG tokio-runtime-worker pact_matching:      generators: Generators { categories: {} }
2022-10-18T12:15:25.022357Z DEBUG tokio-runtime-worker pact_matching::matchers: String -> String: comparing '/api/products/10' to '/api/products/10' ==> true cascaded=false matcher=Equality
2022-10-18T12:15:25.022371Z DEBUG tokio-runtime-worker pact_matching: expected content type = '*/*', actual content type = '*/*'
2022-10-18T12:15:25.022387Z DEBUG tokio-runtime-worker pact_matching: content type header matcher = 'RuleList { rules: [], rule_logic: And, cascaded: false }'
2022-10-18T12:15:25.022401Z DEBUG tokio-runtime-worker pact_matching::matchers: String -> String: comparing 'Bearer 2019-01-14T11:34:18.045Z' to 'Bearer 2022-10-18T14:15:22.953Z' ==> false cascaded=false matcher=Equality
2022-10-18T12:15:25.022417Z DEBUG tokio-runtime-worker pact_matching: --> Mismatches: [HeaderMismatch { key: "Authorization", expected: "Bearer 2019-01-14T11:34:18.045Z", actual: "Bearer 2022-10-18T14:15:22.953Z", mismatch: "Mismatch with header 'Authorization': Expected 'Bearer 2019-01-14T11:34:18.045Z' to be equal to 'Bearer 2022-10-18T14:15:22.953Z'" }]
2022-10-18T12:15:25.022452Z DEBUG tokio-runtime-worker pact_mock_server::hyper_server: Request did not match: Request did not match - HTTP Request ( method: GET, path: /api/products/10, query: None, headers: Some({"Authorization": ["Bearer 2019-01-14T11:34:18.045Z"]}), body: Missing )    0) Mismatch with header 'Authorization': Expected 'Bearer 2019-01-14T11:34:18.045Z' to be equal to 'Bearer 2022-10-18T14:15:22.953Z'

@adamrodger
Copy link
Contributor

So the error is that the actual header doesn't match the expected one (it has a different date).

Since you've used a Matcher instead of a literal value then you'd expect that to work, but looks like it's matching literally.

@adamrodger
Copy link
Contributor

PactNer serialises the Matcher properly and submits it to pactffi, so it looks like this is a bug in pactffi to me

internal RequestBuilder WithHeader(string key, IMatcher matcher)

@adamrodger
Copy link
Contributor

I wonder if this is caused by pact-foundation/pact-reference#214

The regex library on pactffi is known to be a bit quirky with inputs with partial overlaps, which all ISO dates are very likely to have since they start with the year.

@adamrodger adamrodger added bug Indicates an unexpected problem or unintended behavior upstream labels Oct 18, 2022
@Danae-Planit
Copy link

Danae-Planit commented Oct 27, 2022

I can confirm I have reproduced this exact same issue on pactnet 4.2.0+. Match.Type also fails for request headers, and for simple strings such as host - does not have to be using date time regex.

*This issue does not occur in pactnet 4.1.0

SUCCESSFUL:
.WithRequest(HttpMethod.Get, "/api/products") .WithHeader("host", "localhost:9000")

FAILS:
.WithHeader("host", Match.Type("localhost:8000"))

Response (Failure clue from debug log):
2022-10-27T00:36:38.640811Z DEBUG tokio-runtime-worker pact_matching::matchers: String -> String: comparing 'localhost:8000' to 'localhost:9000' ==> false cascaded=false matcher=Equality 2022-10-27T00:36:38.640828Z DEBUG tokio-runtime-worker pact_matching: --> Mismatches: [HeaderMismatch { key: "host", expected: "localhost:8000", actual: "localhost:9000", mismatch: "Mismatch with header 'host': Expected 'localhost:8000' to be equal to 'localhost:9000'" }]

@lehmamic
Copy link

I experienced the same issue. It worked for me with pactnet 4.1.0 as well.

@mefellows
Copy link
Member

Raised upstream issue: pact-foundation/pact-reference#238

@mefellows mefellows added the upstream Indicates that an issue relates to an upstream problem (such as in pact-reference) label Aug 18, 2023
@vcalatayud
Copy link

Could be that this is already fixed? At least my test is not failing anymore. #433

@adamrodger
Copy link
Contributor

adamrodger commented Sep 2, 2023 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Indicates an unexpected problem or unintended behavior upstream Indicates that an issue relates to an upstream problem (such as in pact-reference)
Projects
Status: New Issue
Development

No branches or pull requests

6 participants