Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: support V4 Pact interface (beta)
Creates a unified ConsumerPact interface for consumer tests and provider verification. It also supports plugins. This means you can create messages and HTTP interactions in the same test through the same entrypoint, and conversely verify interactions for multiple interaction types, including custom transports. NOTE: this feature is currently in beta and is only usable behind a feature toggle. It can be enabled by setting the environment variable ENABLE_FEATURE_V4 to any value.
- Loading branch information
Showing
25 changed files
with
2,899 additions
and
4,273 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import logger from '../../../common/logger'; | ||
import { | ||
MessageDescriptor, | ||
MessageFromProviderWithMetadata, | ||
MessageProvider, | ||
} from '../../message'; | ||
import express from 'express'; | ||
import bodyParser from 'body-parser'; | ||
import { encode as encodeBase64 } from 'js-base64'; | ||
import { ProxyOptions } from './types'; | ||
|
||
// Find a provider message handler, and invoke it | ||
export const findMessageHandler = ( | ||
message: MessageDescriptor, | ||
config: ProxyOptions | ||
): Promise<MessageProvider> => { | ||
const handler = config.messageProviders | ||
? config.messageProviders[message.description] | ||
: undefined; | ||
|
||
if (!handler) { | ||
logger.error(`no handler found for message ${message.description}`); | ||
|
||
return Promise.reject( | ||
new Error( | ||
`No handler found for message "${message.description}". | ||
Check your "handlers" configuration` | ||
) | ||
); | ||
} | ||
|
||
return Promise.resolve(handler); | ||
}; | ||
|
||
// Get the Express app that will run on the HTTP Proxy | ||
export const setupMessageProxyApplication = ( | ||
config: ProxyOptions | ||
): express.Express => { | ||
const app = express(); | ||
|
||
app.use(bodyParser.json()); | ||
app.use(bodyParser.urlencoded({ extended: true })); | ||
app.use((_, res, next) => { | ||
// TODO: this seems to override the metadata for content-type | ||
res.header('Content-Type', 'application/json; charset=utf-8'); | ||
next(); | ||
}); | ||
|
||
// Proxy server will respond to Verifier process | ||
app.all('/*', createProxyMessageHandler(config)); | ||
|
||
return app; | ||
}; | ||
|
||
// Get the API handler for the verification CLI process to invoke on POST /* | ||
export const createProxyMessageHandler = ( | ||
config: ProxyOptions | ||
): ((req: express.Request, res: express.Response) => void) => { | ||
return (req, res) => { | ||
const message: MessageDescriptor = req.body; | ||
|
||
// Invoke the handler, and return the JSON response body | ||
// wrapped in a Message | ||
findMessageHandler(message, config) | ||
.then((handler) => handler(message)) | ||
.then((messageFromHandler) => { | ||
if (hasMetadata(messageFromHandler)) { | ||
const metadata = encodeBase64( | ||
JSON.stringify(messageFromHandler.__pactMessageMetadata) | ||
); | ||
res.header('Pact-Message-Metadata', metadata); | ||
res.header('PACT_MESSAGE_METADATA', metadata); | ||
|
||
return res.json(messageFromHandler.message); | ||
} | ||
return res.json(messageFromHandler); | ||
}) | ||
.catch((e) => res.status(500).send(e)); | ||
}; | ||
}; | ||
|
||
// // Get the Proxy we'll pass to the CLI for verification | ||
// export const setupProxyServer = ( | ||
// app: (request: http.IncomingMessage, response: http.ServerResponse) => void | ||
// ): http.Server => http.createServer(app).listen(); | ||
|
||
const hasMetadata = ( | ||
o: unknown | MessageFromProviderWithMetadata | ||
): o is MessageFromProviderWithMetadata => | ||
Boolean((o as MessageFromProviderWithMetadata).__pactMessageMetadata); | ||
|
||
export const providerWithMetadata = | ||
( | ||
provider: MessageProvider, | ||
metadata: Record<string, string> | ||
): MessageProvider => | ||
(descriptor: MessageDescriptor) => | ||
Promise.resolve(provider(descriptor)).then((message) => | ||
hasMetadata(message) | ||
? { | ||
__pactMessageMetadata: { | ||
...message.__pactMessageMetadata, | ||
...metadata, | ||
}, | ||
message, | ||
} | ||
: { __pactMessageMetadata: metadata, message } | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,18 @@ | ||
import { VerifierOptions as PactCoreVerifierOptions } from '@pact-foundation/pact-core'; | ||
import { MessageProviderOptions } from 'dsl/options'; | ||
|
||
import { ProxyOptions } from './proxy/types'; | ||
|
||
export type VerifierOptions = PactCoreVerifierOptions & ProxyOptions; | ||
type ExcludedPactNodeVerifierKeys = Exclude< | ||
keyof PactCoreVerifierOptions, | ||
'providerBaseUrl' | ||
>; | ||
|
||
export type PactNodeVerificationExcludedOptions = Pick< | ||
PactCoreVerifierOptions, | ||
ExcludedPactNodeVerifierKeys | ||
>; | ||
|
||
export type VerifierOptions = PactNodeVerificationExcludedOptions & | ||
ProxyOptions & | ||
Partial<MessageProviderOptions>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.