-
-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathplugin_v2.proto
More file actions
626 lines (567 loc) Β· 24.2 KB
/
Copy pathplugin_v2.proto
File metadata and controls
626 lines (567 loc) Β· 24.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
// Proto file for Pact plugin interface V2
//
// NOTE: This initial V2 proto intentionally mirrors V1 while the
// capability-negotiation changes are introduced incrementally.
syntax = "proto3";
import "google/protobuf/struct.proto";
import "google/protobuf/wrappers.proto";
import "google/protobuf/empty.proto";
package io.pact.plugin.v2;
option go_package = "io.pact.plugin.v2";
// Request to verify the plugin has loaded OK
message InitPluginRequest {
// Implementation calling the plugin
string implementation = 1;
// Version of the implementation
string version = 2;
// Host capabilities provided by the driver and available to the plugin
repeated string hostCapabilities = 3;
// UUID assigned by the driver at process start; the plugin includes this in every log record it emits
string pluginInstanceId = 4;
}
// Entry to be added to the core catalogue. Each entry describes one of the features the plugin provides.
// Entries will be stored in the catalogue under the key "plugin/$name/$type/$key".
message CatalogueEntry {
enum EntryType {
// Matcher for contents of messages, requests or response bodies
CONTENT_MATCHER = 0;
// Generator for contents of messages, requests or response bodies
CONTENT_GENERATOR = 1;
// Transport for a network protocol
TRANSPORT = 2;
// Matching rule for content field/values
MATCHER = 3;
// Type of interaction
INTERACTION = 4;
// Generator for a content field/value. See proposal 006 (Field-level matchers and generators).
GENERATOR = 5;
}
// Entry type
EntryType type = 1;
// Entry key
string key = 2;
// Associated data required for the entry. For CONTENT_MATCHER and CONTENT_GENERATOR types, a "content-types"
// value (separated by semi-colons) is required for all the content types the plugin supports.
map<string, string> values = 3;
}
// Successful result of initialising the plugin
message InitPluginSuccess {
// List of entries the plugin supports
repeated CatalogueEntry catalogue = 1;
// Optional capabilities negotiated for this plugin instance
repeated string pluginCapabilities = 2;
}
// Failure result of initialising the plugin
message InitPluginFailure {
// Error explaining why initialisation failed
string error = 1;
// Host capabilities the plugin requires but were not provided by the driver
repeated string missingHostCapabilities = 2;
}
// Response to init plugin, providing either the negotiated success response or a structured failure
message InitPluginResponse {
oneof response {
InitPluginSuccess success = 1;
InitPluginFailure failure = 2;
}
}
// Catalogue of Core Pact + Plugin features
message Catalogue {
// List of entries from the core catalogue
repeated CatalogueEntry catalogue = 1;
}
// Message representing a request, response or message body
message Body {
// The content type of the body in MIME format (i.e. application/json)
string contentType = 1;
// Bytes of the actual content
google.protobuf.BytesValue content = 2;
// Enum of content type override. This is a hint on how the content type should be treated.
enum ContentTypeHint {
// Determine the form of the content using the default rules of the Pact implementation
DEFAULT = 0;
// Contents must always be treated as a text form
TEXT = 1;
// Contents must always be treated as a binary form
BINARY = 2;
}
// Content type override to apply (if required). If omitted, the default rules of the Pact implementation
// will be used
ContentTypeHint contentTypeHint = 3;
}
// Request to preform a comparison on an actual body given the expected one
message CompareContentsRequest {
// Expected body from the Pact interaction
Body expected = 1;
// Actual received body
Body actual = 2;
// If unexpected keys or attributes should be allowed. Setting this to false results in additional keys or fields
// will cause a mismatch
bool allow_unexpected_keys = 3;
// Map of expressions to matching rules. The expressions follow the documented Pact matching rule expressions
map<string, MatchingRules> rules = 4;
// Additional data added to the Pact/Interaction by the plugin
PluginConfiguration pluginConfiguration = 5;
// Context data provided by the test framework (carries testRunId for log correlation)
google.protobuf.Struct testContext = 6;
}
// Indicates that there was a mismatch with the content type
message ContentTypeMismatch {
// Expected content type (MIME format)
string expected = 1;
// Actual content type received (MIME format)
string actual = 2;
}
// A mismatch for an particular item of content
message ContentMismatch {
// Expected data bytes
google.protobuf.BytesValue expected = 1;
// Actual data bytes
google.protobuf.BytesValue actual = 2;
// Description of the mismatch
string mismatch = 3;
// Path to the item that was matched. This is the value as per the documented Pact matching rule expressions.
string path = 4;
// Optional diff of the contents
string diff = 5;
// Part of the interaction that the mismatch is for: body, headers, metadata, etc.
string mismatchType = 6;
}
// List of content mismatches
message ContentMismatches {
repeated ContentMismatch mismatches = 1;
}
// Response to the CompareContentsRequest with the results of the comparison
message CompareContentsResponse {
// Error message if an error occurred. If this field is set, the remaining fields will be ignored and the
// verification marked as failed
string error = 1;
// There was a mismatch with the types of content. If this is set, the results may not be set.
ContentTypeMismatch typeMismatch = 2;
// Results of the match, keyed by matching rule expression
map<string, ContentMismatches> results = 3;
}
// Request to configure/setup an interaction so that it can be verified later
message ConfigureInteractionRequest {
// Content type of the interaction (MIME format)
string contentType = 1;
// This is data specified by the user in the consumer test
google.protobuf.Struct contentsConfig = 2;
// Context data provided by the test framework (carries testRunId for log correlation)
google.protobuf.Struct testContext = 3;
}
// Represents a matching rule
message MatchingRule {
// Type of the matching rule
string type = 1;
// Associated data for the matching rule
google.protobuf.Struct values = 2;
}
// List of matching rules
message MatchingRules {
repeated MatchingRule rule = 1;
}
// Example generator
message Generator {
// Type of generator
string type = 1;
// Associated data for the generator
google.protobuf.Struct values = 2;
}
// Plugin configuration added to the pact file by the ConfigureInteraction step
message PluginConfiguration {
// Data to be persisted against the interaction
google.protobuf.Struct interactionConfiguration = 1;
// Data to be persisted in the Pact file metadata (Global data)
google.protobuf.Struct pactConfiguration = 2;
}
// Structured interaction data sent to V2 plugins in place of raw pact JSON.
// Contains only the data the plugin needs, eliminating the need for plugins
// to parse full Pact documents.
message InteractionContents {
// The V4 interaction type (e.g. "Synchronous/HTTP", "Synchronous/Messages")
string interactionType = 1;
// Plugin configuration stored by the plugin during the consumer test
PluginConfiguration pluginConfiguration = 2;
// Consumer name, for result reporting and log correlation
string consumer = 3;
// Provider name, for result reporting and log correlation
string provider = 4;
}
// Response to the configure/setup an interaction request
message InteractionResponse {
// Contents for the interaction
Body contents = 1;
// All matching rules to apply
map<string, MatchingRules> rules = 2;
// Generators to apply
map<string, Generator> generators = 3;
// For message interactions, any metadata to be applied
google.protobuf.Struct messageMetadata = 4;
// Plugin specific data to be persisted in the pact file
PluginConfiguration pluginConfiguration = 5;
// Markdown/HTML formatted text representation of the interaction
string interactionMarkup = 6;
// Type of markup used
enum MarkupType {
// CommonMark format
COMMON_MARK = 0;
// HTML format
HTML = 1;
}
MarkupType interactionMarkupType = 7;
// Description of what part this interaction belongs to (in the case of there being more than one, for instance,
// request/response messages)
string partName = 8;
// All matching rules to apply to any message metadata
map<string, MatchingRules> metadata_rules = 9;
// Generators to apply to any message metadata
map<string, Generator> metadata_generators = 10;
}
// Response to the configure/setup an interaction request
message ConfigureInteractionResponse {
// If an error occurred. In this case, the other fields will be ignored/not set
string error = 1;
// The actual response if no error occurred.
repeated InteractionResponse interaction = 2;
// Plugin specific data to be persisted in the pact file
PluginConfiguration pluginConfiguration = 3;
}
// Request to generate the contents using any defined generators
message GenerateContentRequest {
// Original contents
Body contents = 1;
// Generators to apply
map<string, Generator> generators = 2;
// Additional data added to the Pact/Interaction by the plugin
PluginConfiguration pluginConfiguration = 3;
// Context data provided by the test framework
google.protobuf.Struct testContext = 4;
// The mode of the generation, if running from a consumer test or during provider verification
enum TestMode {
Unknown = 0;
// Running on the consumer side
Consumer = 1;
// Running on the provider side
Provider = 2;
}
TestMode testMode = 5;
// Which part the content is for
enum ContentFor {
Request = 0;
Response = 1;
}
ContentFor contentFor = 6;
}
// Generated body/message response
message GenerateContentResponse {
Body contents = 1;
}
// A single value being matched or generated at the field/element level.
//
// Each type Pact's matching rules discriminate has its own arm, rather than everything
// JSON-representable sharing a google.protobuf.Value. That type carries a single number type (a
// double), which would make `integer` and `decimal` indistinguishable and `type` wrong between a
// whole number and a decimal - and these are exactly the rules whose job is to check the runtime
// type of a value. Binary data has its own arm for the same reason: so it never has to be
// stringified into a form it does not fit.
//
// See proposal 006 (Field-level matchers and generators).
message FieldValue {
oneof value {
// A null value
google.protobuf.NullValue nullValue = 1;
// A boolean
bool booleanValue = 2;
// A string
string stringValue = 3;
// A whole number
int64 integerValue = 4;
// A number with a fractional part
double decimalValue = 5;
// Raw bytes, for a value that is not representable as text
bytes binaryValue = 6;
// A map or list, for a rule applied to a collection rather than a scalar. Numbers nested
// inside follow JSON semantics (every number is a double) - a collection rule only needs the
// shape and size of the collection, and the values inside it are matched by their own
// field-level calls, at their own paths, where they arrive under the arms above.
google.protobuf.Value structuredValue = 7;
}
}
// Request to apply a plugin-provided matching rule to a single value. The plugin sees the value,
// its path and the rule's own configuration, but not the document that contains it - a rule that
// needs the surrounding document is a content matcher. See proposal 006.
message MatchFieldRequest {
// Catalogue entry key of the rule being applied, e.g. "creditcard" for matcher/creditcard
string key = 1;
// The rule as stored in the Pact file: its name and configured values
MatchingRule rule = 2;
// Path to the value being matched. This is the value as per the documented Pact matching rule expressions.
string path = 3;
// Part of the interaction the value came from: body, headers, metadata, query, path, status
string mismatchType = 4;
// Expected value from the Pact interaction
FieldValue expected = 5;
// Actual value received
FieldValue actual = 6;
// Additional data added to the Pact/Interaction by the plugin
PluginConfiguration pluginConfiguration = 7;
// Context data provided by the test framework (carries testRunId for log correlation)
google.protobuf.Struct testContext = 8;
}
// Response to the MatchFieldRequest with the result of applying the rule
message MatchFieldResponse {
// Error message if the rule could not be applied at all. If this field is set, the remaining
// fields will be ignored and the verification marked as failed
string error = 1;
// Mismatches found. An empty list means the value matched. A mismatch with an empty path is
// reported against the path from the request
repeated ContentMismatch mismatches = 2;
}
// Request to generate a single value using a plugin-provided generator. Generators are pure
// functions of this request: anything from the host they need arrives in testContext or is
// fetched with an explicit callback. See proposal 006.
message GenerateFieldRequest {
// Catalogue entry key of the generator being applied, e.g. "creditcard" for generator/creditcard
string key = 1;
// The generator as stored in the Pact file: its name and configured values
Generator generator = 2;
// Path to the value being generated. This is the value as per the documented Pact matching rule expressions.
string path = 3;
// The example value from the Pact interaction that the generated value replaces
FieldValue exampleValue = 4;
// Additional data added to the Pact/Interaction by the plugin
PluginConfiguration pluginConfiguration = 5;
// Context data provided by the test framework
google.protobuf.Struct testContext = 6;
// The mode of the generation, if running from a consumer test or during provider verification
GenerateContentRequest.TestMode testMode = 7;
}
// Response to the GenerateFieldRequest with the generated value
message GenerateFieldResponse {
// Error message if the value could not be generated. If this field is set, the value will be
// ignored
string error = 1;
// The generated value
FieldValue value = 2;
}
// Request to start a mock server
message StartMockServerRequest {
// Interface to bind to. Will default to the loopback adapter
string hostInterface = 1;
// Port to bind to. Default (or a value of 0) get the OS to open a random port
uint32 port = 2;
// If TLS should be used (if supported by the mock server)
bool tls = 3;
// Structured interaction data (replaces the pact JSON string from V1)
repeated InteractionContents interactions = 4;
// Context data provided by the test framework
google.protobuf.Struct testContext = 5;
}
// Response to the start mock server request
message StartMockServerResponse {
oneof response {
// If an error occurred
string error = 1;
// Mock server details
MockServerDetails details = 2;
}
}
// Details on a running mock server
message MockServerDetails {
// Mock server unique ID
string key = 1;
// Port the mock server is running on
uint32 port = 2;
// IP address the mock server is bound to. Probably an IP6 address, but may be IP4
string address = 3;
}
// Request for a running mock server by ID
message MockServerRequest {
// The server ID to shutdown
string serverKey = 1;
}
// Result of a request that the mock server received
message MockServerResult {
// service + method that was requested
string path = 1;
// If an error occurred trying to handle the request
string error = 2;
// Any mismatches that occurred
repeated ContentMismatch mismatches = 3;
}
// Matching results of the mock server.
message MockServerResults {
// If the mock status is all ok
bool ok = 1;
// The results of the test run, will contain an entry for each request received by the mock server
repeated MockServerResult results = 2;
}
// Request to prepare an interaction for verification
message VerificationPreparationRequest {
// Structured interaction data (replaces pact JSON + interactionKey from V1)
InteractionContents interactionContents = 1;
// Any data supplied by the user to verify the interaction
google.protobuf.Struct config = 2;
// Context data provided by the test framework
google.protobuf.Struct testContext = 3;
}
// Request metadata value. Will either be a JSON-like value, or binary data
message MetadataValue {
oneof value {
google.protobuf.Value nonBinaryValue = 1;
bytes binaryValue = 2;
}
}
// Interaction request data to be sent or received for verification
message InteractionData {
// Request/Response body as bytes
Body body = 1;
// Metadata associated with the request/response
map<string, MetadataValue> metadata = 2;
}
// Response for the prepare an interaction for verification request
message VerificationPreparationResponse {
oneof response {
// If an error occurred
string error = 1;
// Interaction data required to construct any request
InteractionData interactionData = 2;
}
}
// Request data to verify an interaction
message VerifyInteractionRequest {
// Interaction data required to construct the request
InteractionData interactionData = 1;
// Any data supplied by the user to verify the interaction
google.protobuf.Struct config = 2;
// Structured interaction data (replaces pact JSON + interactionKey from V1)
InteractionContents interactionContents = 3;
// Context data provided by the test framework
google.protobuf.Struct testContext = 4;
}
message VerificationResultItem {
oneof result {
string error = 1;
ContentMismatch mismatch = 2;
}
}
// Result of running the verification
message VerificationResult {
// Was the verification successful?
bool success = 1;
// Interaction data retrieved from the provider (optional)
InteractionData responseData = 2;
// Any mismatches that occurred
repeated VerificationResultItem mismatches = 3;
// Output for the verification to display to the user
repeated string output = 4;
}
// Result of running the verification
message VerifyInteractionResponse {
oneof response {
// If an error occurred trying to run the verification
string error = 1;
VerificationResult result = 2;
}
}
// Structured log record emitted by a plugin and forwarded to the driver via the Log RPC
message LogMessage {
// Plugin instance UUID (from InitPluginRequest.pluginInstanceId)
string pluginInstanceId = 1;
// Test run UUID (from testContext["testRunId"], if available)
string testRunId = 2;
// Log level: TRACE, DEBUG, INFO, WARN, ERROR
string level = 3;
// Human-readable log message
string message = 4;
// Logger name / module path (e.g. "pact_csv_plugin::matching")
string target = 5;
// Unix epoch milliseconds
int64 timestampMs = 6;
}
// Callback request from a plugin to invoke a content matcher capability - host-provided or
// owned by another plugin - resolved by catalogue entry key. See proposal 007 (Driver-plugin
// callback model).
message HostCompareContentsRequest {
// Catalogue entry key identifying the capability to invoke, e.g. "xml" for content-matcher/xml
string entryKey = 1;
// The comparison request, in the same shape as PactPlugin.CompareContents
CompareContentsRequest request = 2;
}
// Callback request from a plugin to invoke a content generator capability - host-provided or
// owned by another plugin - resolved by catalogue entry key. See proposal 007 (Driver-plugin
// callback model).
message HostGenerateContentRequest {
// Catalogue entry key identifying the capability to invoke, e.g. "xml" for content-generator/xml
string entryKey = 1;
// The generation request, in the same shape as PactPlugin.GenerateContent
GenerateContentRequest request = 2;
}
// Callback request from a plugin to invoke a field-level matching rule - host-provided (one of the
// standard Pact rules) or owned by another plugin - resolved by catalogue entry key. See proposals
// 006 (Field-level matchers and generators) and 007 (Driver-plugin callback model).
message HostMatchFieldRequest {
// Catalogue entry key identifying the rule to invoke. Either the rule name on its own ("type",
// "content-type" - the same string MatchFieldRequest.rule.type carries), or more of the
// catalogue key to disambiguate it ("matcher/type", "core/matcher/type").
string entryKey = 1;
// The match request, in the same shape as PactPlugin.MatchField
MatchFieldRequest request = 2;
}
// Callback request from a plugin to invoke a field-level generator - host-provided or owned by
// another plugin - resolved by catalogue entry key. See proposals 006 and 007.
message HostGenerateFieldRequest {
// Catalogue entry key identifying the generator to invoke, e.g. "date" or "generator/date".
// See HostMatchFieldRequest.entryKey.
string entryKey = 1;
// The generation request, in the same shape as PactPlugin.GenerateField
GenerateFieldRequest request = 2;
}
// Driver-side service implemented by the driver and called by plugins
service PluginHost {
// Forward a structured log record from the plugin to the driver's logging framework
rpc Log(LogMessage) returns (google.protobuf.Empty);
// Invoke a content matcher capability by catalogue entry key. The driver resolves the key to
// either a host-registered core handler or another running plugin. See proposal 007.
rpc CompareContents(HostCompareContentsRequest) returns (CompareContentsResponse);
// Invoke a content generator capability by catalogue entry key. The driver resolves the key to
// either a host-registered core handler or another running plugin. See proposal 007.
rpc GenerateContent(HostGenerateContentRequest) returns (GenerateContentResponse);
// Invoke a field-level matching rule by catalogue entry key, resolved the same way. This is how
// a plugin delegates one field of a document it owns to a standard Pact rule instead of
// reimplementing it. See proposals 006 and 009.
rpc MatchField(HostMatchFieldRequest) returns (MatchFieldResponse);
// Invoke a field-level generator by catalogue entry key, resolved the same way.
// See proposals 006 and 009.
rpc GenerateField(HostGenerateFieldRequest) returns (GenerateFieldResponse);
}
service PactPlugin {
// Check that the plugin loaded OK. Returns the catalogue entries describing what the plugin provides
rpc InitPlugin(InitPluginRequest) returns (InitPluginResponse);
// Updated catalogue. This will be sent when the core catalogue has been updated (probably by a plugin loading).
rpc UpdateCatalogue(Catalogue) returns (google.protobuf.Empty);
// Request to perform a comparison of some contents (matching request)
rpc CompareContents(CompareContentsRequest) returns (CompareContentsResponse);
// Request to configure/setup the interaction for later verification. Data returned will be persisted in the pact file.
rpc ConfigureInteraction(ConfigureInteractionRequest) returns (ConfigureInteractionResponse);
// Request to generate the content using any defined generators
rpc GenerateContent(GenerateContentRequest) returns (GenerateContentResponse);
// Apply a plugin-provided matching rule to a single value. Required for any plugin that
// registers a MATCHER catalogue entry. See proposal 006 (Field-level matchers and generators).
rpc MatchField(MatchFieldRequest) returns (MatchFieldResponse);
// Apply a plugin-provided generator to a single value. Required for any plugin that registers
// a GENERATOR catalogue entry. See proposal 006.
rpc GenerateField(GenerateFieldRequest) returns (GenerateFieldResponse);
// Start a mock server
rpc StartMockServer(StartMockServerRequest) returns (StartMockServerResponse);
// Shutdown a running mock server
rpc ShutdownMockServer(MockServerRequest) returns (MockServerResults);
// Get the matching results from a running mock server
rpc GetMockServerResults(MockServerRequest) returns (MockServerResults);
// Prepare an interaction for verification. This should return any data required to construct any request
// so that it can be amended before the verification is run
rpc PrepareInteractionForVerification(VerificationPreparationRequest) returns (VerificationPreparationResponse);
// Execute the verification for the interaction.
rpc VerifyInteraction(VerifyInteractionRequest) returns (VerifyInteractionResponse);
}