dsl

package
v1.10.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 2, 2024 License: MIT Imports: 26 Imported by: 19

Documentation

Overview

Package dsl contains the main Pact DSL used in the Consumer collaboration test cases, and Provider contract test verification.

Index

Examples

Constants

This section is empty.

Variables

View Source
var IPv4Address = IPAddress

IPv4Address matches valid IPv4 addresses.

View Source
var Integer = Identifier

Integer defines a matcher that accepts ints. Identical to Identifier.

View Source
var Regex = Term

Regex is a more appropriately named alias for the "Term" matcher

Functions

func AfterEachMiddleware added in v1.0.0

func AfterEachMiddleware(afterEach types.Hook) proxy.Middleware

AfterEachMiddleware is invoked after any other, and is the last function to be called prior to returning to the test suite. It is therefore not invoked on __setup

func BeforeEachMiddleware added in v1.0.0

func BeforeEachMiddleware(beforeEach types.Hook) proxy.Middleware

BeforeEachMiddleware is invoked before any other, only on the __setup request (to avoid duplication)

Types

type Client

type Client interface {
	// StartServer starts a remote Pact Mock Server.
	StartServer(args []string, port int) *types.MockServer

	// ListServers lists all known Mock Servers
	ListServers() []*types.MockServer

	// StopServer stops a remote Pact Mock Server.
	StopServer(server *types.MockServer) (*types.MockServer, error)

	// RemoveAllServers stops all remote Pact Mock Servers.
	RemoveAllServers(server *types.MockServer) []*types.MockServer

	// VerifyProvider runs the verification process against a running Provider.
	VerifyProvider(request types.VerifyRequest) ([]types.ProviderVerifierResponse, error)

	// UpdateMessagePact adds a pact message to a contract file
	UpdateMessagePact(request types.PactMessageRequest) error

	// ReifyMessage takes a structured object, potentially containing nested Matchers
	// and returns an object with just the example (generated) content
	// The object may be a simple JSON primitive e.g. string or number or a complex object
	ReifyMessage(request *types.PactReificationRequest) (res *types.ReificationResponse, err error)

	// PublishPacts publishes pact files to a Pact Broker
	PublishPacts(request types.PublishRequest) error
}

Client is the interface

type Interaction

type Interaction struct {
	// Request
	Request Request `json:"request"`

	// Response
	Response Response `json:"response"`

	// Description to be written into the Pact file
	Description string `json:"description"`

	// Provider state to be written into the Pact file
	State string `json:"providerState,omitempty"`
}

Interaction is the main implementation of the Pact interface.

func (*Interaction) Given

func (i *Interaction) Given(state string) *Interaction

Given specifies a provider state. Optional.

func (*Interaction) UponReceiving

func (i *Interaction) UponReceiving(description string) *Interaction

UponReceiving specifies the name of the test case. This becomes the name of the consumer/provider pair in the Pact file. Mandatory.

func (*Interaction) WillRespondWith

func (i *Interaction) WillRespondWith(response Response) *Interaction

WillRespondWith specifies the details of the HTTP response that will be used to confirm that the Provider must satisfy. Mandatory.

func (*Interaction) WithRequest

func (i *Interaction) WithRequest(request Request) *Interaction

WithRequest specifies the details of the HTTP request that will be used to confirm that the Provider provides an API listening on the given interface. Mandatory.

type MapMatcher added in v1.0.0

type MapMatcher map[string]Matcher

MapMatcher allows a map[string]string-like object to also contain complex matchers

func (*MapMatcher) UnmarshalJSON added in v1.0.0

func (m *MapMatcher) UnmarshalJSON(bytes []byte) (err error)

UnmarshalJSON is a custom JSON parser for MapMatcher It treats the matchers as strings

type Matcher added in v1.0.0

type Matcher interface {

	// GetValue returns the raw generated value for the matcher
	// without any of the matching detail context
	GetValue() interface{}
	// contains filtered or unexported methods
}

Matcher allows various implementations such String or StructMatcher to be provided in when matching with the DSL We use the strategy outlined at http://www.jerf.org/iri/post/2917 to create a "sum" or "union" type.

func Date added in v1.0.0

func Date() Matcher

Date matches a pattern corresponding to the ISO_DATE_FORMAT, which is "yyyy-MM-dd". The current date is used as the eaxmple.

func Decimal added in v1.0.0

func Decimal() Matcher

Decimal defines a matcher that accepts any decimal value.

func EachLike

func EachLike(content interface{}, minRequired int) Matcher

EachLike specifies that a given element in a JSON body can be repeated "minRequired" times. Number needs to be 1 or greater

Example
match := EachLike([]int{1, 2, 3}, 1)
fmt.Println(formatJSON(match))
Output:

{
	"json_class": "Pact::ArrayLike",
	"contents": [
		1,
		2,
		3
	],
	"min": 1
}

func HexValue added in v1.0.0

func HexValue() Matcher

HexValue defines a matcher that accepts hexadecimal values.

func IPAddress added in v1.0.0

func IPAddress() Matcher

IPAddress defines a matcher that accepts valid IPv4 addresses.

func IPv6Address added in v1.0.0

func IPv6Address() Matcher

IPv6Address defines a matcher that accepts IP addresses.

func Identifier added in v1.0.0

func Identifier() Matcher

Identifier defines a matcher that accepts integer values.

func Like

func Like(content interface{}) Matcher

Like specifies that the given content type should be matched based on type (int, string etc.) instead of a verbatim match.

Example (Number)
match := Like(42)
fmt.Println(formatJSON(match))
Output:

{
	"json_class": "Pact::SomethingLike",
	"contents": 42
}
Example (Object)
match := Like(map[string]string{"baz": "bat"})
fmt.Println(formatJSON(match))
Output:

{
	"json_class": "Pact::SomethingLike",
	"contents": {
		"baz": "bat"
	}
}
Example (String)
match := Like("myspecialvalue")
fmt.Println(formatJSON(match))
Output:

{
	"json_class": "Pact::SomethingLike",
	"contents": "myspecialvalue"
}

func Match added in v0.0.13

func Match(src interface{}) Matcher

Match recursively traverses the provided type and outputs a matcher string for it that is compatible with the Pact dsl. By default, it requires slices to have a minimum of 1 element. For concrete types, it uses `dsl.Like` to assert that types match. Optionally, you may override these defaults by supplying custom pact tags on your structs.

Supported Tag Formats Minimum Slice Size: `pact:"min=2"` String RegEx: `pact:"example=2000-01-01,regex=^\\d{4}-\\d{2}-\\d{2}$"`

func Term

func Term(generate string, matcher string) Matcher

Term specifies that the matching should generate a value and also match using a regular expression.

Example
match := Term("myawesomeword", `\w+`)
fmt.Println(formatJSON(match))
Output:

{
	"json_class": "Pact::Term",
	"data": {
		"generate": "myawesomeword",
		"matcher": {
			"json_class": "Regexp",
			"o": 0,
			"s": "\\w+"
		}
	}
}

func Time added in v1.0.0

func Time() Matcher

Time matches a pattern corresponding to the ISO_DATE_FORMAT, which is "'T'HH:mm:ss". The current tem is used as the eaxmple.

func Timestamp added in v1.0.0

func Timestamp() Matcher

Timestamp matches a pattern corresponding to the ISO_DATETIME_FORMAT, which is "yyyy-MM-dd'T'HH:mm:ss". The current date and time is used as the eaxmple.

func UUID added in v1.0.0

func UUID() Matcher

UUID defines a matcher that accepts UUIDs. Produces a v4 UUID as the example.

type Message added in v1.0.0

type Message struct {
	// Message Body
	Content interface{} `json:"contents,omitempty"`

	// Message Body as a Raw JSON string
	ContentRaw interface{} `json:"-"`

	// Provider state to be written into the Pact file
	States []State `json:"providerStates,omitempty"`

	// Message metadata
	Metadata MapMatcher `json:"metadata,omitempty"`

	// Description to be written into the Pact file
	Description string `json:"description"`

	// Type to Marshall content into when sending back to the consumer
	// Defaults to interface{}
	Type interface{}

	Args []string `json:"-"`
}

Message is a representation of a single, unidirectional message e.g. MQ, pub/sub, Websocket, Lambda Message is the main implementation of the Pact Message interface.

func (*Message) AsType added in v1.0.0

func (p *Message) AsType(t interface{}) *Message

AsType specifies that the content sent through to the consumer handler should be sent as the given type

func (*Message) ExpectsToReceive added in v1.0.0

func (p *Message) ExpectsToReceive(description string) *Message

ExpectsToReceive specifies the content it is expecting to be given from the Provider. The function must be able to handle this message for the interaction to succeed.

func (*Message) Given added in v1.0.0

func (p *Message) Given(state string) *Message

Given specifies a provider state. Optional.

func (*Message) WithContent added in v1.0.0

func (p *Message) WithContent(content interface{}) *Message

WithContent specifies the details of the HTTP request that will be used to confirm that the Provider provides an API listening on the given interface. Mandatory.

func (*Message) WithMetadata added in v1.0.0

func (p *Message) WithMetadata(metadata MapMatcher) *Message

WithMetadata specifies message-implementation specific metadata to go with the content

type MessageConsumer added in v1.0.0

type MessageConsumer func(Message) error

MessageConsumer receives a message and must be able to parse the content

type MessageHandler added in v1.0.0

type MessageHandler func(Message) (interface{}, error)

MessageHandler is a provider function that generates a message for a Consumer given a Message context (state, description etc.)

type MessageHandlers added in v1.0.0

type MessageHandlers map[string]MessageHandler

MessageHandlers is a list of handlers ordered by description

type MockService added in v0.0.2

type MockService struct {
	// BaseURL is the base host for the Pact Mock Service.
	BaseURL string

	// Consumer name.
	Consumer string

	// Provider name.
	Provider string

	// PactFileWriteMode specifies how to write to the Pact file, for the life
	// of a Mock Service.
	// "overwrite" will always truncate and replace the pact after each run
	// "update" will append to the pact file, which is useful if your tests
	// are split over multiple files and instantiations of a Mock Server
	// See https://github.com/pact-foundation/pact-ruby/blob/master/documentation/configuration.md#pactfile_write_mode
	PactFileWriteMode string
}

MockService is the HTTP interface to setup the Pact Mock Service See https://github.com/bethesque/pact-mock_service and https://gist.github.com/bethesque/9d81f21d6f77650811f4.

func (*MockService) AddInteraction added in v0.0.2

func (m *MockService) AddInteraction(interaction *Interaction) error

AddInteraction adds a new Pact Mock Service interaction.

func (*MockService) DeleteInteractions added in v0.0.2

func (m *MockService) DeleteInteractions() error

DeleteInteractions removes any previous Mock Service Interactions.

func (*MockService) Verify added in v0.0.2

func (m *MockService) Verify() error

Verify confirms that all interactions were called.

func (*MockService) WritePact added in v0.0.2

func (m *MockService) WritePact() error

WritePact writes the pact file to disk.

type Pact

type Pact struct {
	// Current server for the consumer.
	Server *types.MockServer

	// Directory of Pactflow standalone CLI (blank if CLI is installed on system)
	PactCLIDir string

	// Consumer is the name of the Consumer/Client.
	Consumer string

	// Provider is the name of the Providing service.
	Provider string

	// Interactions contains all of the Mock Service Interactions to be setup.
	Interactions []*Interaction

	// MessageInteractions contains all of the Message based interactions to be setup.
	MessageInteractions []*Message

	// Log levels.
	LogLevel string

	// Location of Pact external service invocation output logging.
	// Defaults to `<cwd>/logs`.
	LogDir string

	// Pact files will be saved in this folder.
	// Defaults to `<cwd>/pacts`.
	PactDir string

	// PactFileWriteMode specifies how to write to the Pact file, for the life
	// of a Mock Service.
	// "overwrite" will always truncate and replace the pact after each run
	// "merge" will append to the pact file, which is useful if your tests
	// are split over multiple files and instantiations of a Mock Server
	PactFileWriteMode string

	// Specify which version of the Pact Specification should be used (1 or 2).
	// Defaults to 2.
	SpecificationVersion int

	// Host is the address of the Mock and Verification Service runs on
	// Examples include 'localhost', '127.0.0.1', '[::1]'
	// Defaults to 'localhost'
	Host string

	// Network is the network of the Mock and Verification Service
	// Examples include 'tcp', 'tcp4', 'tcp6'
	// Defaults to 'tcp'
	Network string

	// Ports MockServer can be deployed to, can be CSV or Range with a dash
	// Example "1234", "12324,5667", "1234-5667"
	AllowedMockServerPorts string

	// DisableToolValidityCheck prevents CLI version checking - use this carefully!
	// The ideal situation is to check the tool installation with  before running
	// the tests, which should speed up large test suites significantly
	DisableToolValidityCheck bool

	// ClientTimeout specifies how long to wait for Pact CLI to start
	// Can be increased to reduce likelihood of intermittent failure
	// Defaults to 10s
	ClientTimeout time.Duration
	// contains filtered or unexported fields
}

Pact is the container structure to run the Consumer Pact test cases.

func (*Pact) AddInteraction

func (p *Pact) AddInteraction() *Interaction

AddInteraction creates a new Pact interaction, initialising all required things. Will automatically start a Mock Service if none running.

func (*Pact) AddMessage added in v1.0.0

func (p *Pact) AddMessage() *Message

AddMessage creates a new asynchronous consumer expectation

func (*Pact) Setup

func (p *Pact) Setup(startMockServer bool) *Pact

Setup starts the Pact Mock Server. This is usually called before each test suite begins. AddInteraction() will automatically call this if no Mock Server has been started.

func (*Pact) Teardown

func (p *Pact) Teardown() *Pact

Teardown stops the Pact Mock Server. This usually is called on completion of each test suite.

func (*Pact) Verify

func (p *Pact) Verify(integrationTest func() error) error

Verify runs the current test case against a Mock Service. Will cleanup interactions between tests within a suite.

func (*Pact) VerifyMessageConsumer added in v1.0.0

func (p *Pact) VerifyMessageConsumer(t *testing.T, message *Message, handler MessageConsumer) error

VerifyMessageConsumer is a test convenience function for VerifyMessageConsumerRaw, accepting an instance of `*testing.T`

func (*Pact) VerifyMessageConsumerRaw added in v1.0.0

func (p *Pact) VerifyMessageConsumerRaw(message *Message, handler MessageConsumer) error

VerifyMessageConsumerRaw creates a new Pact _message_ interaction to build a testable interaction.

A Message Consumer is analogous to a Provider in the HTTP Interaction model. It is the receiver of an interaction, and needs to be able to handle whatever request was provided.

func (*Pact) VerifyMessageProvider added in v1.0.0

func (p *Pact) VerifyMessageProvider(t *testing.T, request VerifyMessageRequest) (res []types.ProviderVerifierResponse, err error)

VerifyMessageProvider accepts an instance of `*testing.T` running provider message verification with granular test reporting and automatic failure reporting for nice, simple tests.

A Message Producer is analogous to Consumer in the HTTP Interaction model. It is the initiator of an interaction, and expects something on the other end of the interaction to respond - just in this case, not immediately.

func (*Pact) VerifyMessageProviderRaw added in v1.0.0

func (p *Pact) VerifyMessageProviderRaw(request VerifyMessageRequest) ([]types.ProviderVerifierResponse, error)

VerifyMessageProviderRaw runs provider message verification.

A Message Producer is analogous to Consumer in the HTTP Interaction model. It is the initiator of an interaction, and expects something on the other end of the interaction to respond - just in this case, not immediately.

func (*Pact) VerifyProvider

func (p *Pact) VerifyProvider(t *testing.T, request types.VerifyRequest) ([]types.ProviderVerifierResponse, error)

VerifyProvider accepts an instance of `*testing.T` running the provider verification with granular test reporting and automatic failure reporting for nice, simple tests.

func (*Pact) VerifyProviderRaw added in v0.0.10

func (p *Pact) VerifyProviderRaw(request types.VerifyRequest) ([]types.ProviderVerifierResponse, error)

VerifyProviderRaw reads the provided pact files and runs verification against a running Provider API, providing raw response from the Verification process.

Order of events: BeforeEach, stateHandlers, requestFilter(pre <execute provider> post), AfterEach

func (*Pact) WritePact added in v0.0.2

func (p *Pact) WritePact() error

WritePact should be called writes when all tests have been performed for a given Consumer <-> Provider pair. It will write out the Pact to the configured file.

type PactClient

type PactClient struct {

	// Track mock servers
	Servers []MockService

	// Network Daemon is listening on
	Network string

	// Address the Daemon is listening on
	Address string

	// TimeoutDuration specifies how long to wait for Pact CLI to start
	TimeoutDuration time.Duration
	// contains filtered or unexported fields
}

PactClient is the main interface into starting/stopping the underlying Pact CLI subsystem

func NewClient added in v1.0.0

func NewClient(pactCLIDir string) *PactClient

NewClient creates a new Pact client manager with defaults

func (*PactClient) ListServers

func (p *PactClient) ListServers() []*types.MockServer

ListServers lists all known Mock Servers

func (*PactClient) PublishPacts added in v1.0.0

func (p *PactClient) PublishPacts(request types.PublishRequest) error

PublishPacts publishes a set of pacts to a pact broker

func (*PactClient) ReifyMessage added in v1.0.0

func (p *PactClient) ReifyMessage(request *types.PactReificationRequest) (res *types.ReificationResponse, err error)

ReifyMessage takes a structured object, potentially containing nested Matchers and returns an object with just the example (generated) content The object may be a simple JSON primitive e.g. string or number or a complex object

func (*PactClient) RemoveAllServers added in v1.0.0

func (p *PactClient) RemoveAllServers(_ *types.MockServer) []*types.MockServer

RemoveAllServers stops all remote Pact Mock Servers.

func (*PactClient) StartServer

func (p *PactClient) StartServer(args []string, port int) *types.MockServer

StartServer starts a remote Pact Mock Server.

func (*PactClient) StopServer

func (p *PactClient) StopServer(server *types.MockServer) (*types.MockServer, error)

StopServer stops a remote Pact Mock Server.

func (*PactClient) UpdateMessagePact added in v1.0.0

func (p *PactClient) UpdateMessagePact(request types.PactMessageRequest) error

UpdateMessagePact adds a pact message to a contract file

func (*PactClient) VerifyProvider

func (p *PactClient) VerifyProvider(request types.VerifyRequest) ([]types.ProviderVerifierResponse, error)

VerifyProvider runs the verification process against a running Provider. TODO: extract/refactor the stdout/error streaems from these functions

type PactFile added in v0.0.2

type PactFile struct {
	// The API Consumer name
	Consumer PactName `json:"consumer"`

	// The API Provider name
	Provider PactName `json:"provider"`
}

PactFile is a simple representation of a Pact file to be able to parse Consumer/Provider from the file.

type PactName added in v0.0.2

type PactName struct {
	Name string `json:"name"`
}

PactName represents the name fields in the PactFile.

type Publisher added in v0.0.2

type Publisher struct {
	// Directory of Pactflow standalone CLI (blank if CLI is installed on system)
	PactCLIDir string

	// Log levels.
	LogLevel string
	// contains filtered or unexported fields
}

Publisher is the API to send Pact files to a Pact Broker.

func (*Publisher) Publish added in v0.0.2

func (p *Publisher) Publish(request types.PublishRequest) error

Publish sends the Pacts to a broker, optionally tagging them

type Request

type Request struct {
	Method  string      `json:"method"`
	Path    Matcher     `json:"path"`
	Query   MapMatcher  `json:"query,omitempty"`
	Headers MapMatcher  `json:"headers,omitempty"`
	Body    interface{} `json:"body,omitempty"`
}

Request is the default implementation of the Request interface.

type Response

type Response struct {
	Status  int         `json:"status"`
	Headers MapMatcher  `json:"headers,omitempty"`
	Body    interface{} `json:"body,omitempty"`
}

Response is the default implementation of the Response interface.

type S added in v1.0.0

type S string

S is the string primitive wrapper (alias) for the Matcher type, it allows plain strings to be matched To keep backwards compatible with previous versions we aren't using an alias here

func (S) GetValue added in v1.0.0

func (s S) GetValue() interface{}

GetValue returns the raw generated value for the matcher without any of the matching detail context

type ServiceMock added in v1.0.0

type ServiceMock struct {
	Cmd string

	Args                []string
	ServiceStopResult   bool
	ServiceStopError    error
	ServiceList         map[int]*exec.Cmd
	ServiceStartCmd     *exec.Cmd
	ServiceStartCount   int
	ServicePort         int
	ServiceStopCount    int
	ServicesSetupCalled bool

	// ExecFunc sets the function to run when starting commands
	ExecFunc func() *exec.Cmd
	// contains filtered or unexported fields
}

ServiceMock is the mock implementation of the Service interface.

func (*ServiceMock) Command added in v1.0.0

func (s *ServiceMock) Command() *exec.Cmd

Command implements to Command operation

func (*ServiceMock) List added in v1.0.0

func (s *ServiceMock) List() map[int]*exec.Cmd

List all Service PIDs.

func (*ServiceMock) NewService added in v1.0.0

func (s *ServiceMock) NewService(_ []string) client.Service

NewService creates a new MockService with default settings.

func (*ServiceMock) Setup added in v1.0.0

func (s *ServiceMock) Setup(pactCLIDir string)

Setup the Management services.

func (*ServiceMock) Start added in v1.0.0

func (s *ServiceMock) Start() *exec.Cmd

Start a Service and log its output.

func (*ServiceMock) Stop added in v1.0.0

func (s *ServiceMock) Stop(pid int) (bool, error)

Stop a Service and returns the exit status.

type State added in v1.0.0

type State struct {
	Name   string                 `json:"name"`
	Params map[string]interface{} `json:"params,omitempty"`
}

State specifies how the system should be configured when verified. e.g. "user A exists"

type StateHandler added in v1.0.0

type StateHandler func(State) error

StateHandler is a provider function that sets up a given state before the provider interaction is validated

type StateHandlers added in v1.0.0

type StateHandlers map[string]StateHandler

StateHandlers is a list of StateHandler's

type String added in v1.0.0

type String string

String is the longer named form of the string primitive wrapper, it allows plain strings to be matched

func (String) GetValue added in v1.0.0

func (s String) GetValue() interface{}

GetValue returns the raw generated value for the matcher without any of the matching detail context

type StructMatcher added in v1.0.0

type StructMatcher map[string]interface{}

StructMatcher matches a complex object structure, which may itself contain nested Matchers

func (StructMatcher) GetValue added in v1.0.0

func (m StructMatcher) GetValue() interface{}

GetValue returns the raw generated value for the matcher without any of the matching detail context

type VerifyMessageRequest added in v1.0.0

type VerifyMessageRequest struct {
	// Local/HTTP paths to Pact files.
	PactURLs []string

	// Pact Broker URL for broker-based verification
	BrokerURL string

	// Tags to find in Broker for matrix-based testing
	Tags []string

	// Selectors are the way we specify which pacticipants and
	// versions we want to use when configuring verifications
	// See https://docs.pact.io/selectors for more
	ConsumerVersionSelectors []types.ConsumerVersionSelector

	// Username when authenticating to a Pact Broker.
	BrokerUsername string

	// Password when authenticating to a Pact Broker.
	BrokerPassword string

	// BrokerToken is required when authenticating using the Bearer token mechanism
	BrokerToken string

	// PublishVerificationResults to the Pact Broker.
	PublishVerificationResults bool

	// ProviderVersion is the semantical version of the Provider API.
	ProviderVersion string

	// ProviderTags is the set of tags to apply to the provider application version when results are published to the broker
	ProviderTags []string

	// MessageHandlers contains a mapped list of message handlers for a provider
	// that will be rable to produce the correct message format for a given
	// consumer interaction
	MessageHandlers MessageHandlers

	// StateHandlers contain a mapped list of message states to functions
	// that are used to setup a given provider state prior to the message
	// verification step.
	StateHandlers StateHandlers

	// Specify an output directory to log all of the verification request/responses
	// seen by the verification process. Useful to debug issues with your contract
	// and API
	PactLogDir string

	// Specify the log verbosity of the CLI verifier process spawned through verification
	// Useful for debugging issues with the framework itself
	PactLogLevel string

	// Tag the provider with the current git branch in the Pact Broker
	TagWithGitBranch bool

	// Arguments to the VerificationProvider
	// Deprecated: This will be deleted after the native library replaces Ruby deps.
	Args []string
}

VerifyMessageRequest contains the verification logic to send to the Pact Message verifier

func (*VerifyMessageRequest) Validate added in v1.0.0

func (v *VerifyMessageRequest) Validate() error

Validate checks that the minimum fields are provided. Deprecated: This map be deleted after the native library replaces Ruby deps, and should not be used outside of this library.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL