Akke Luukkonen
07/12/2022, 9:18 AM/var/lib
? I have a simpler version where I just mount it directly to root as /pacts
. For comparison, I'm publishing contracts using Docker in ADO with:
steps:
- task: DownloadPipelineArtifact@2
displayName: Download artifact containing pacts
inputs:
artifactName: ${{ parameters.pactsArtifactName }}
targetPath: $(Agent.TempDirectory)/pacts
- script: >
docker run
-e PACT_BROKER_TOKEN
-v $(Agent.TempDirectory)/pacts:/pacts
pactfoundation/pact-cli@sha256:ddefe0e43c3706884635a2642f2be366274679d7055f300ed92c4e384639ba0a
broker publish
/pacts
--consumer-app-version ${{ parameters.version }}
--branch ${{ parameters.branch }}
--broker-base-url https://<company>.<http://pactflow.io|pactflow.io>
displayName: Publish to Pactflow
env:
PACT_BROKER_TOKEN: $(SecretPactBrokerToken)
Gerard van Engelen
07/14/2022, 4:22 AMstring version = Environment.GetEnvironmentVariable("VERSION");
string branch = Environment.GetEnvironmentVariable("BRANCH");
string buildUri = Environment.GetEnvironmentVariable("BUILD_URL");
verifier.ServiceProvider("My Provider", _fixture.ServerUri)
.WithPactBrokerSource(new Uri("<https://broker.example.org>"), options =>
{
options.ConsumerVersionSelectors(new ConsumerVersionSelector { MainBranch = true, Latest = true })
.PublishResults(version, results =>
{
results.ProviderBranch(branch)
.BuildUri(new Uri(buildUri));
});
.PublishResults(version, results => { results.ProviderBranch(branch);});
})
.Verify();
This was my latest error:
Failures:
1) Failed to load pact - Could not load pacts from the pact broker '<https://broker.pact.engineering.crxt.io/>' - ContentError("Request to pact broker URL '<https://broker.pact.engineering.crxt.io/pacts/provider/Vehicle%20Financing/for-verification>' failed - HTTP status server error (500 Internal Server Error) for url (<https://broker.pact.engineering.crxt.io/pacts/provider/Vehicle%20Financing/for-verification>)")
There were 1 pact failures
[91m[<http://xUnit.net|xUnit.net> 00:00:02.82] Financing.Api.ContractTests.FinanceOptionsContractTests.EnsureSomethingApiHonoursPactWithConsumer [FAIL][0m[91m
[0m Failed Financing.Api.ContractTests.FinanceOptionsContractTests.EnsureSomethingApiHonoursPactWithConsumer [1 s]
Error Message:
PactNet.Exceptions.PactFailureException : Pact verification failed
Stack Trace:
at PactNet.Verifier.InteropVerifierProvider.Execute()
at PactNet.Verifier.PactVerifierSource.Verify()
at Financing.Api.ContractTests.FinanceOptionsContractTests.EnsureSomethingApiHonoursPactWithConsumer() in /src/test/Financing.Api.ContractTests/FinanceContractTests.cs:line 43
Standard Output Messages:
Starting verification...
Pact verification failed
Ganesh
07/18/2022, 11:22 AMvar exposureRequest = new ExposuresRequest
{
PortfolioId = "10000000-0000-0000-0000-000000000000",
PortfolioNamespace = "MaceConsumerTests/GBP Holdings portfolio",
PortfolioClassificationNamespace = "namespace_PortfolioA",
EffectDate = new DateTime(2021, 05, 05),
Currency = "USD",
PortfolioDataDates = new Dictionary<string, DateTime> { { "10000000-0000-0000-0000-000000000000", new DateTime(2021, 05, 06) } },
UseStorage = true,
ClassificationHierarchy = new string[][] { new string[] { "industry" } },
OutputType = ExposuresOutputType.GroupLevel,
Path = null
};
and here is my Pact consumer request:
pact.UponReceiving("A valid request")
.Given("A valid request for get exposures")
.WithRequest(<http://HttpMethod.Post|HttpMethod.Post>, "/api/exposures")
.WithHeader("content-type", "application/json; charset=utf-8")
.WithJsonBody(exposureRequest,new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() })
.WillRespond()
.WithStatus(HttpStatusCode.OK)
.WithHeader("content-type", "application/json")
.WithJsonBody(new TypeMatcher(new ExposuresResponse()));
await pact.VerifyAsync(async ctx =>
{
var response = await ApiClient.GetExposures(exposureRequest);
Assert.NotNull(response);
});
and this the ApiClient that is actually making http request
public async Task<ExposuresResponse> GetExposures(ExposuresRequest request)
{
var requestContent = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json");
var httpResponse = await httpClient.PostAsync("api/exposures", requestContent);
var exposuresResponse = await TryGetResponse<ExposuresResponse>(httpResponse);
return exposuresResponse;
}
I am getting HTTP Status code 500, Internal server error because the actual request does not meet expected request. Here is the Log output
Standard Output Messages:
Mock server logs:
[DEBUG][pact_mock_server::hyper_server] Creating pact request from hyper request
[DEBUG][pact_mock_server::hyper_server] Extracting query from uri /api/exposures
[INFO][pact_mock_server::hyper_server] Received request Request ( method: POST, path: /api/exposures, query: None, headers: Some({"host": ["localhost:8197"], "content-type": ["application/json; charset=utf-8"], "content-length": ["501"]}), body: Present(501 bytes, application/json;charset=utf-8) )
[DEBUG][pact_mock_server::hyper_server] body: '{"ClassificationHierarchy":[["industry"]],"UseStorage":true,"OutputType":1,"Path":null,"EffectDate":"2021-05-05T00:00:00","PortfolioDataDates":{"10000000-0000-0000-0000-000000000000":"2021-05-06T00:00:00"},"Currency":"USD","PortfolioId":"10000000-0000-0000-0000-000000000000","PortfolioNamespace":"MaceConsumerTests/GBP Holdings portfolio","PortfolioClassificationNamespace":"namespace_PortfolioA","BenchmarkPortfolioId":null,"BenchmarkPortfolioNamespace":null,"BenchmarkClassificationNamespace":null}'
[INFO][pact_matching] comparing to expected Request ( method: POST, path: /api/exposures, query: None, headers: Some({"content-type": ["application/json; charset=utf-8"]}), body: Present(501 bytes) )
[DEBUG][pact_matching] body: '{"benchmarkClassificationNamespace":null,"benchmarkPortfolioId":null,"benchmarkPortfolioNamespace":null,"classificationHierarchy":[["industry"]],"currency":"USD","effectDate":"2021-05-05T00:00:00","outputType":1,"path":null,"portfolioClassificationNamespace":"namespace_PortfolioA","portfolioDataDates":{"10000000-0000-0000-0000-000000000000":"2021-05-06T00:00:00"},"portfolioId":"10000000-0000-0000-0000-000000000000","portfolioNamespace":"MaceConsumerTests/GBP Holdings portfolio","useStorage":true}'
[DEBUG][pact_matching] matching_rules: MatchingRules { rules: {HEADER: MatchingRuleCategory { name: HEADER, rules: {} }, PATH: MatchingRuleCategory { name: PATH, rules: {} }, BODY: MatchingRuleCategory { name: BODY, rules: {} }} }
[DEBUG][pact_matching] generators: Generators { categories: {} }
[DEBUG][pact_matching::matchers] String -> String: comparing '/api/exposures' to '/api/exposures' using Equality
[DEBUG][pact_matching] expected content type = 'application/json;charset=utf-8', actual content type = 'application/json;charset=utf-8'
[DEBUG][pact_matching] content type header matcher = 'None'
[DEBUG][pact_matching] Using body matcher for content type 'application/json;charset=utf-8'
[DEBUG][pact_matching::json] compare: Comparing path $
[DEBUG][pact_matching::json] compare_maps: Comparing maps at $: {"benchmarkClassificationNamespace": Null, "benchmarkPortfolioId": Null, "benchmarkPortfolioNamespace": Null, "classificationHierarchy": Array([Array([String("industry")])]), "currency": String("USD"), "effectDate": String("2021-05-05T00:00:00"), "outputType": Number(1), "path": Null, "portfolioClassificationNamespace": String("namespace_PortfolioA"), "portfolioDataDates": Object({"10000000-0000-0000-0000-000000000000": String("2021-05-06T00:00:00")}), "portfolioId": String("10000000-0000-0000-0000-000000000000"), "portfolioNamespace": String("MaceConsumerTests/GBP Holdings portfolio"), "useStorage": Bool(true)} -> {"BenchmarkClassificationNamespace": Null, "BenchmarkPortfolioId": Null, "BenchmarkPortfolioNamespace": Null, "ClassificationHierarchy": Array([Array([String("industry")])]), "Currency": String("USD"), "EffectDate": String("2021-05-05T00:00:00"), "OutputType": Number(1), "Path": Null, "PortfolioClassificationNamespace": String("namespace_PortfolioA"), "PortfolioDataDates": Object({"10000000-0000-0000-0000-000000000000": String("2021-05-06T00:00:00")}), "PortfolioId": String("10000000-0000-0000-0000-000000000000"), "PortfolioNamespace": String("MaceConsumerTests/GBP Holdings portfolio"), "UseStorage": Bool(true)}
[DEBUG][pact_matching] --> Mismatches: [BodyMismatch { path: "$", expected: Some(b"{\"benchmarkClassificationNamespace\":\"null\",\"benchmarkPortfolioId\":\"null\",\"benchmarkPortfolioNamespace\":\"null\",\"classificationHierarchy\":\"[[\\\"industry\\\"]]\",\"currency\":\"\\\"USD\\\"\",\"effectDate\":\"\\\"2021-05-05T00:00:00\\\"\",\"outputType\":\"1\",\"path\":\"null\",\"portfolioClassificationNamespace\":\"\\\"namespace_PortfolioA\\\"\",\"portfolioDataDates\":\"{\\\"10000000-0000-0000-0000-000000000000\\\":\\\"2021-05-06T00:00:00\\\"}\",\"portfolioId\":\"\\\"10000000-0000-0000-0000-000000000000\\\"\",\"portfolioNamespace\":\"\\\"MaceConsumerTests/GBP Holdings portfolio\\\"\",\"useStorage\":\"true\"}"), actual: Some(b"{\"BenchmarkClassificationNamespace\":\"null\",\"BenchmarkPortfolioId\":\"null\",\"BenchmarkPortfolioNamespace\":\"null\",\"ClassificationHierarchy\":\"[[\\\"industry\\\"]]\",\"Currency\":\"\\\"USD\\\"\",\"EffectDate\":\"\\\"2021-05-05T00:00:00\\\"\",\"OutputType\":\"1\",\"Path\":\"null\",\"PortfolioClassificationNamespace\":\"\\\"namespace_PortfolioA\\\"\",\"PortfolioDataDates\":\"{\\\"10000000-0000-0000-0000-000000000000\\\":\\\"2021-05-06T00:00:00\\\"}\",\"PortfolioId\":\"\\\"10000000-0000-0000-0000-000000000000\\\"\",\"PortfolioNamespace\":\"\\\"MaceConsumerTests/GBP Holdings portfolio\\\"\",\"UseStorage\":\"true\"}"), mismatch: "Expected a Map with keys benchmarkClassificationNamespace, benchmarkPortfolioId, benchmarkPortfolioNamespace, classificationHierarchy, currency, effectDate, outputType, path, portfolioClassificationNamespace, portfolioDataDates, portfolioId, portfolioNamespace, useStorage but received one with keys BenchmarkClassificationNamespace, BenchmarkPortfolioId, BenchmarkPortfolioNamespace, ClassificationHierarchy, Currency, EffectDate, OutputType, Path, PortfolioClassificationNamespace, PortfolioDataDates, PortfolioId, PortfolioNamespace, UseStorage" }]
[DEBUG][pact_mock_server::hyper_server] Request did not match: Request did not match - Request ( method: POST, path: /api/exposures, query: None, headers: Some({"content-type": ["application/json; charset=utf-8"]}), body: Present(501 bytes) ) 0) $ -> Expected a Map with keys benchmarkClassificationNamespace, benchmarkPortfolioId, benchmarkPortfolioNamespace, classificationHierarchy, currency, effectDate, outputType, path, portfolioClassificationNamespace, portfolioDataDates, portfolioId, portfolioNamespace, useStorage but received one with keys BenchmarkClassificationNamespace, BenchmarkPortfolioId, BenchmarkPortfolioNamespace, ClassificationHierarchy, Currency, EffectDate, OutputType, Path, PortfolioClassificationNamespace, PortfolioDataDates, PortfolioId, PortfolioNamespace, UseStorage
I am not able to find out why Pact complains request did not match. Can someone please help here. I have already spent 1 day on this and blocked here.
Thank youMatt (pactflow.io / pact-js / pact-go)
Matt (pactflow.io / pact-js / pact-go)
Ganesh
07/18/2022, 1:18 PM.WithJsonBody(product,new JsonSerializerSettings { ContractResolver=new CamelCasePropertyNamesContractResolver()})
It's still complaining about case mismatch. how do I tell Pact to send the json in CamcelcaseMatt (pactflow.io / pact-js / pact-go)
Alasdair
07/25/2022, 11:00 AMJay Espiritu
07/27/2022, 11:50 AMAndre Rodrigues
08/05/2022, 4:59 PMSarunas Kavaliauskas
08/16/2022, 7:33 PMSarunas Kavaliauskas
08/20/2022, 3:40 AMSiddharth Gupta
08/29/2022, 9:15 AMSiddharth Gupta
08/29/2022, 9:15 AMSiddharth Gupta
08/29/2022, 9:16 AMSiddharth Gupta
08/29/2022, 9:57 AMJay Li
08/31/2022, 9:17 AMSiddharth Gupta
09/02/2022, 6:56 AMSiddharth Gupta
09/02/2022, 6:56 AMSiddharth Gupta
09/02/2022, 6:56 AMSiddharth Gupta
09/02/2022, 6:57 AMSiddharth Gupta
09/02/2022, 6:57 AMDavid Hvilava
09/02/2022, 7:53 AMPublishing of verification results failed with an error: Link/Resource was not found - Request to pact broker path '/pacticipants/Provider1' failed: 404 Not Found. URL: '<https://outsystems-cfl.pactflow.io/pacts/provider/Provider1/consumer/Consumer2/version/1.0.1>'
Although a pact is available by that url.
This problem was described several months ago in this PR. But it didn't get any attention. Back then I just explored a new functionality. But now it becomes critical for our team, since we move forward to can-i-deploy and add webhooks in PactFlow. Maybe someone can help me with thatSiddharth Gupta
09/02/2022, 8:12 AMMaksym Liannoi
09/02/2022, 9:49 AMtask-api-consumer-task-api-provider.json
) for checking responses to all features from the provider side or better split generating pact files depending on provider features (e.g. task-api-consumer-task-api-provider-crud.json
and task-api-consumer-task-api-provider-filter.json
) and after that writing two verification test methods on the provider side for each coming pact files?
2. Where should I save the pact file path? Is reading from a configuration file (such as launchSettings.json) for a test project better than C# constant?
3. If a consumer has many providers, which algorithm is better to use if I need to publish one pact file to a specific provider? Depend on the pact file prefix, or save the pact file in a particular folder during generation on the consumer side on passing tests?
Thanks,
MaksymJay Li
09/05/2022, 2:44 AMAndre Rodrigues
09/07/2022, 1:20 PMАлександр Аврамчик
09/07/2022, 1:44 PMFábio Rodrigues
09/13/2022, 5:10 PM[INFO][pact_verifier::pact_broker] Fetching path '/pacts/provider/publish-service/consumer/alm-app/pact-version/6bc3dee5de1ea718ef23d4dab94fa32536ecf014/metadata/c1tdW2N2XT0xMTI2MiZwPXRydWU' from pact broker
[DEBUG][hyper::client::pool] reuse idle connection for ("https", <http://outsystems.pactflow.io|outsystems.pactflow.io>)
[DEBUG][reqwest::async_impl::client] response '200 OK' for <https://outsystems.pactflow.io/pacts/provider/publish-service/consumer/alm-app/pact-version/6bc3dee5de1ea718ef23d4dab94fa32536ecf014/metadata/c1tdW2N2XT0xMTI2MiZwPXRydWU>
[ERROR][pact_verifier] Failed to load pact - Failed to load pact from '<https://outsystems.pactflow.io/>' - ContentError("Expected a \".\" or \"[\" instead of \"r\" in path expression \"$results[*].deploymentOperations[*].applicationKey\" at index 1")
[WARN][pact_matching::metrics]
The part i'm not understanding is why it's failing on parsing the matcher locator:
"matchingRules": {
"body": {
"$results[*].deploymentOperations[*].applicationKey": {
"combine": "AND",
"matchers": [
{
"match": "regex",
"regex": "^$|[0-9A-Fa-f]{8}(?:-[0-9A-Fa-f]{4}){3}-[0-9A-Fa-f]{12}$"
}
]
},
Andre Rodrigues
09/21/2022, 9:04 AM