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

EachKeyLike matcher generates wrong rules and wrong example #285

Open
nsfrias opened this issue Apr 5, 2023 · 6 comments
Open

EachKeyLike matcher generates wrong rules and wrong example #285

nsfrias opened this issue Apr 5, 2023 · 6 comments

Comments

@nsfrias
Copy link

nsfrias commented Apr 5, 2023

Software versions

  • OS: Mac OSX 13.0.1
  • Consumer Pact library: Pact go v2.0.0-beta.18
  • libpact_ffi: 0.3.2
  • Golang Version: go version go1.18.3 darwin/arm64
  • Golang environment: Provide output of go env

Expected behaviour

Given a request body like:

{
    "author": "Mark Twain",
    "book": "The Adventures of Tom Sawyer",
    "extraInfo": {
        "genre": "folk"
    }
}

I expect a contract with the following rules for the request body to match (all else being OK):

req.JSONBody(matchers.StructMatcher{
    "book": matchers.Like("The Adventures of Tom Sawyer"),
    "author": matchers.Like("Mark Twain"),
    "extraInfo": matchers.EachKeyLike("genre",
    matchers.Like("folk")),
})

Actual behaviour

Given the previous request body and contract rules I get the following error:

2023/04/05 10:37:28 [INFO] pact validation failed, errors: 
			Expected 'folk' to be equal to '{"genre":"folk"}'
			expected:	 "folk"
			actual:		 {"genre":"folk"}
			Expected 'folk' to be the same type as '{"genre":"folk"}'
			expected:	 "folk"
			actual:		 {"genre":"folk"}

Looking at the log I see the pact expected request is also wrong:

2023-04-05T09:37:28.595060Z DEBUG tokio-runtime-worker pact_matching:      body: '{"author":"Mark Twain","book":"The Adventures of Tom Sawyer","extraInfo":"folk"}'

Steps to reproduce

You can run this test to reproduce the issue:

import (
	"net/http"
	"testing"

	"github.com/go-resty/resty/v2"
	"github.com/pact-foundation/pact-go/v2/consumer"
	pactLog "github.com/pact-foundation/pact-go/v2/log"
	"github.com/pact-foundation/pact-go/v2/matchers"
	"github.com/stretchr/testify/assert"
)

func TestMockConsumer(t *testing.T) {
	_ = pactLog.SetLogLevel("DEBUG")

	mockProvider, err := consumer.NewV4Pact(consumer.MockHTTPProviderConfig{
		Consumer: "mock-consumer",
		Provider: "mock-provider",
		Host:     "127.0.0.1",
		Port:     8080,
		TLS:      false,
	})

	if err != nil {
		t.Fatal(err)
	}

	request := map[string]any{
		"book":   "The Adventures of Tom Sawyer",
		"author": "Mark Twain",
		"extraInfo": map[string]string{
			"genre": "folk",
		},
	}

	test := func(config consumer.MockServerConfig) (err error) {
		_, err = resty.New().R().
			SetBody(request).
			SetHeader("content-type", "application/json").
			Post("http://127.0.0.1:8080/books")
		return err
	}

	mockProvider.AddInteraction().
		WithRequest("POST", "/books", func(req *consumer.V4RequestBuilder) {
			req.JSONBody(matchers.StructMatcher{
				"book":      matchers.Like("The Adventures of Tom Sawyer"),
				"author":    matchers.Like("Mark Twain"),
				"extraInfo": matchers.EachKeyLike("genre", matchers.Like("folk")),
			})
		}).
		WillRespondWith(http.StatusOK)

	assert.NoError(t, mockProvider.ExecuteTest(t, test))
}

Relevent log files

eachkeylike_issue.log

@nsfrias
Copy link
Author

nsfrias commented Apr 5, 2023

I also attempted to change the type on the pact-go library (matcher_v3.go) to eachValue as other comments on related issues suggested was the correct approach.

// Object where the key itself is ignored, but the value template must match.
//
// key - Example key to use (which will be ignored)
// template - Example value template to base the comparison on
func EachKeyLike(key string, template interface{}) Matcher {
	return eachKeyLike{
		Specification: models.V3,
		Type:          "eachValue",
		Contents:      template,
	}
}

This is the rule generated

DocPath { path_tokens: [Root, Field("extraInfo")], expr: "$.extraInfo" }: RuleList { rules: [EachValue(MatchingRuleDefinition { value: "{\"pact:matcher:type\":\"type\",\"specification\":\"2.0.0\",\"value\":\"folk\"}", value_type: Unknown, rules: [], generator: None }), Type], rule_logic: And, cascaded: false }

However the test also failed, albeit with a different error:

2023/04/05 11:28:44 [INFO] pact validation failed, errors: 
			Expected 'folk' to be the same type as '{"genre":"folk"}'
			expected:	 "folk"
			actual:		 {"genre":"folk"}

The example was also wrong:

2023-04-05T10:28:44.196839Z DEBUG tokio-runtime-worker pact_matching:      body: '{"author":"Mark Twain","book":"The Adventures of Tom Sawyer","extraInfo":"folk"}'

@mefellows
Copy link
Member

I think it's a matter of changing the value of this attribute on the matcher to eachKey.

If you wanted to attempt a PR and check if it resolves, that would be super helpful!

@nsfrias
Copy link
Author

nsfrias commented May 5, 2023

Thanks @mefellows I'll try your suggested fix and create a PR for it.

@mefellows
Copy link
Member

Thank you!

@github-actions
Copy link

github-actions bot commented Jun 5, 2023

👋 Hi! The 'smartbear-supported' label has just been added to this issue, which will create an internal tracking ticket in PactFlow's Jira (PACT-1056). We will use this to prioritise and assign a team member to this task. All activity will be public on this ticket. For now, sit tight and we'll update this ticket once we have more information on the next steps.

See our documentation for more information.

@mefellows
Copy link
Member

Waiting on upstream clarification: pact-foundation/pact-reference#299

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants