pact_broker 2.59.2 → 2.60.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +1 -1
- data/lib/pact_broker/api/contracts/verifiable_pacts_json_query_schema.rb +10 -3
- data/lib/pact_broker/api/resources/index.rb +11 -8
- data/lib/pact_broker/api/resources/provider_pacts_for_verification.rb +3 -8
- data/lib/pact_broker/doc/views/provider-pacts-for-verification.markdown +78 -0
- data/lib/pact_broker/domain/pact.rb +9 -0
- data/lib/pact_broker/pacts/content.rb +28 -4
- data/lib/pact_broker/pacts/repository.rb +25 -31
- data/lib/pact_broker/pacts/selector.rb +8 -0
- data/lib/pact_broker/version.rb +1 -1
- data/lib/pact_broker/webhooks/job.rb +8 -2
- data/spec/features/get_provider_pacts_for_verification_spec.rb +0 -18
- data/spec/lib/pact_broker/api/contracts/verifiable_pacts_json_query_schema_spec.rb +23 -4
- data/spec/lib/pact_broker/api/resources/provider_pacts_for_verification_spec.rb +8 -38
- data/spec/lib/pact_broker/pacts/content_spec.rb +82 -0
- data/spec/lib/pact_broker/pacts/repository_find_for_verification_fallback_spec.rb +14 -0
- data/spec/lib/pact_broker/pacts/repository_find_for_verification_spec.rb +62 -0
- data/spec/lib/pact_broker/webhooks/job_spec.rb +19 -1
- data/spec/support/database_cleaner.rb +1 -5
- metadata +3 -5
- data/lib/pact_broker/api/contracts/verifiable_pacts_query_schema.rb +0 -36
- data/spec/lib/pact_broker/api/contracts/verifiable_pacts_query_schema_spec.rb +0 -97
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dbaaee53f1641458eb110582a96bf0be98d7078ef1fa681ffee934c6e8007347
|
4
|
+
data.tar.gz: 84a2f6e6785acc85cf7053b86a54574746cb06de917bd11a0dff23403046aff5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: de93223c0a1d52af6563bf31b2ae733c41b6cec65afb4a61be741d78f47cf18484ee2fa292c9660b8db09cb3a1a66c549decb145a0b7a036477a9ac73b70f8c6
|
7
|
+
data.tar.gz: 04d3a59551f4fe9f46af8b65cd6c0dc3326ac86a594298eb22d529e33f6a98e39cdf6f9c682bd69bd9bbb85f4f290fe3e2f706d71cfa766b61def28c0dbd7bfc
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
<a name="v2.60.0"></a>
|
2
|
+
### v2.60.0 (2020-09-08)
|
3
|
+
|
4
|
+
#### Features
|
5
|
+
|
6
|
+
* **pacts for verification**
|
7
|
+
* add deprecation title to beta:provider-pacts-for-verification relation ([47a61f69](/../../commit/47a61f69))
|
8
|
+
* do not require environment variable feature toggle to enable feature ([7d0fe1ea](/../../commit/7d0fe1ea))
|
9
|
+
* allow consumer to be specified with fallback tags, and overall latest to be specified with or without a consumer ([2d52d173](/../../commit/2d52d173))
|
10
|
+
|
11
|
+
#### Bug Fixes
|
12
|
+
|
13
|
+
* correctly handle new test results format when merging test results with pact contents ([b35ab71b](/../../commit/b35ab71b))
|
14
|
+
|
1
15
|
<a name="v2.59.2"></a>
|
2
16
|
### v2.59.2 (2020-08-06)
|
3
17
|
|
data/README.md
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
[![Code Climate](https://codeclimate.com/github/pact-foundation/pact_broker/badges/gpa.svg)](https://codeclimate.com/github/pact-foundation/pact_broker)
|
7
7
|
[![Test Coverage](https://codeclimate.com/github/pact-foundation/pact_broker/badges/coverage.svg)](https://codeclimate.com/github/pact-foundation/pact_broker/coverage)
|
8
8
|
|
9
|
-
The Pact Broker is an application for sharing
|
9
|
+
The Pact Broker is an application for sharing of consumer driven contracts and verification results. It is optimised for use with "pacts" (contracts created by the [Pact][pact-docs] framework), but can be used for any type of contract that can be serialized to JSON.
|
10
10
|
|
11
11
|
<br/>
|
12
12
|
<a href="https:/pactflow.io/?utm_source=github&utm_campaign=pact_broker_intro"><img src="docs/images/Pactflow logo - black small.png"></a>
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'dry-validation'
|
2
2
|
require 'pact_broker/hash_refinements'
|
3
|
+
require 'pact_broker/string_refinements'
|
3
4
|
require 'pact_broker/api/contracts/dry_validation_workarounds'
|
4
5
|
require 'pact_broker/api/contracts/dry_validation_predicates'
|
5
6
|
|
@@ -9,6 +10,7 @@ module PactBroker
|
|
9
10
|
class VerifiablePactsJSONQuerySchema
|
10
11
|
extend DryValidationWorkarounds
|
11
12
|
using PactBroker::HashRefinements
|
13
|
+
using PactBroker::StringRefinements
|
12
14
|
|
13
15
|
SCHEMA = Dry::Validation.Schema do
|
14
16
|
configure do
|
@@ -24,7 +26,7 @@ module PactBroker
|
|
24
26
|
# end
|
25
27
|
# end
|
26
28
|
|
27
|
-
|
29
|
+
optional(:tag).filled(:str?)
|
28
30
|
optional(:latest).filled(included_in?: [true, false])
|
29
31
|
optional(:fallbackTag).filled(:str?)
|
30
32
|
optional(:consumer).filled(:str?, :not_blank?)
|
@@ -54,8 +56,9 @@ module PactBroker
|
|
54
56
|
errors << "fallbackTag can only be set if latest is true (at index #{index})"
|
55
57
|
end
|
56
58
|
|
57
|
-
|
58
|
-
|
59
|
+
|
60
|
+
if not_provided?(selector[:tag]) && selector[:latest] != true
|
61
|
+
errors << "latest must be true, or a tag must be provided (at index #{index})"
|
59
62
|
end
|
60
63
|
end
|
61
64
|
if errors.any?
|
@@ -64,6 +67,10 @@ module PactBroker
|
|
64
67
|
end
|
65
68
|
end
|
66
69
|
end
|
70
|
+
|
71
|
+
def self.not_provided?(value)
|
72
|
+
value.nil? || value.blank?
|
73
|
+
end
|
67
74
|
end
|
68
75
|
end
|
69
76
|
end
|
@@ -121,6 +121,17 @@ module PactBroker
|
|
121
121
|
title: "Determine if an application can be safely deployed to an environment identified by the given tag",
|
122
122
|
templated: true
|
123
123
|
},
|
124
|
+
'pb:provider-pacts-for-verification' => {
|
125
|
+
href: base_url + '/pacts/provider/{provider}/for-verification',
|
126
|
+
title: 'Pact versions to be verified for the specified provider',
|
127
|
+
templated: true
|
128
|
+
},
|
129
|
+
'beta:provider-pacts-for-verification' => {
|
130
|
+
name: 'beta',
|
131
|
+
href: base_url + '/doc/{rel}?context=index',
|
132
|
+
title: 'DEPRECATED - please use pb:provider-pacts-for-verification',
|
133
|
+
templated: true
|
134
|
+
},
|
124
135
|
'curies' =>
|
125
136
|
[{
|
126
137
|
name: 'pb',
|
@@ -133,14 +144,6 @@ module PactBroker
|
|
133
144
|
}]
|
134
145
|
}
|
135
146
|
|
136
|
-
if PactBroker.feature_enabled?(:pacts_for_verification)
|
137
|
-
links_hash['beta:provider-pacts-for-verification'] = {
|
138
|
-
href: base_url + '/pacts/provider/{provider}/for-verification',
|
139
|
-
title: 'Pact versions to be verified for the specified provider',
|
140
|
-
templated: true
|
141
|
-
}
|
142
|
-
end
|
143
|
-
|
144
147
|
links_hash
|
145
148
|
end
|
146
149
|
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'pact_broker/api/resources/provider_pacts'
|
2
2
|
require 'pact_broker/api/decorators/verifiable_pacts_decorator'
|
3
|
-
require 'pact_broker/api/contracts/verifiable_pacts_query_schema'
|
4
3
|
require 'pact_broker/api/decorators/verifiable_pacts_query_decorator'
|
5
4
|
require 'pact_broker/api/contracts/verifiable_pacts_json_query_schema'
|
6
5
|
require 'pact_broker/hash_refinements'
|
@@ -12,7 +11,7 @@ module PactBroker
|
|
12
11
|
using PactBroker::HashRefinements
|
13
12
|
|
14
13
|
def allowed_methods
|
15
|
-
["
|
14
|
+
["POST", "OPTIONS"]
|
16
15
|
end
|
17
16
|
|
18
17
|
def content_types_accepted
|
@@ -36,7 +35,7 @@ module PactBroker
|
|
36
35
|
private
|
37
36
|
|
38
37
|
def pacts
|
39
|
-
pact_service.find_for_verification(
|
38
|
+
@pacts ||= pact_service.find_for_verification(
|
40
39
|
provider_name,
|
41
40
|
parsed_query_params.provider_version_tags,
|
42
41
|
parsed_query_params.consumer_version_selectors,
|
@@ -56,11 +55,7 @@ module PactBroker
|
|
56
55
|
end
|
57
56
|
|
58
57
|
def query_schema
|
59
|
-
|
60
|
-
PactBroker::Api::Contracts::VerifiablePactsQuerySchema
|
61
|
-
else
|
62
|
-
PactBroker::Api::Contracts::VerifiablePactsJSONQuerySchema
|
63
|
-
end
|
58
|
+
PactBroker::Api::Contracts::VerifiablePactsJSONQuerySchema
|
64
59
|
end
|
65
60
|
|
66
61
|
def parsed_query_params
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# Provider pacts for verification
|
2
|
+
|
3
|
+
Path: `/pacts/provider/{provider}/for-verification`
|
4
|
+
|
5
|
+
Allowed methods: `POST`
|
6
|
+
|
7
|
+
Content type: `application/hal+json`
|
8
|
+
|
9
|
+
Returns a deduplicated list of pacts to be verified by the specified provider.
|
10
|
+
|
11
|
+
### Body
|
12
|
+
|
13
|
+
Example: This data structure represents the way a user might specify "I want to verify the latest 'master' pact, all 'prod' pacts, and when I publish the verification results, I'm going to tag the provider version with 'master'"
|
14
|
+
|
15
|
+
{
|
16
|
+
"consumerVersionSelectors": [
|
17
|
+
{
|
18
|
+
"tag": "master",
|
19
|
+
"latest": true
|
20
|
+
},{
|
21
|
+
"tag": "prod"
|
22
|
+
}
|
23
|
+
],
|
24
|
+
"providerVersionTags": ["master"],
|
25
|
+
"includePendingStatus": true,
|
26
|
+
"includeWipPactsSince": "2020-01-01"
|
27
|
+
}
|
28
|
+
|
29
|
+
|
30
|
+
`consumerVersionSelectors.tag`: the tag name(s) of the consumer versions to get the pacts for.
|
31
|
+
|
32
|
+
`consumerVersionSelectors.fallbackTag`: the name of the tag to fallback to if the specified `tag` does not exist. This is useful when the consumer and provider use matching branch names to coordinate the development of new features.
|
33
|
+
|
34
|
+
`consumerVersionSelectors.latest`: true. If the latest flag is omitted, *all* the pacts with the specified tag will be returned. (This might seem a bit weird, but it's done this way to match the syntax used for the matrix query params. See https://docs.pact.io/selectors)
|
35
|
+
|
36
|
+
`consumerVersionSelectors.consumer`: allows a selector to only be applied to a certain consumer. This is used when there is an API that has multiple consumers, one of which is a deployed service, and one of which is a mobile consumer. The deployed service only needs the latest production pact verified, where as the mobile consumer may want all the production pacts verified.
|
37
|
+
|
38
|
+
`providerVersionTags`: the tag name(s) for the provider application version that will be published with the verification results. This is used by the Broker to determine whether or not a particular pact is in pending state or not. This parameter can be specified multiple times.
|
39
|
+
|
40
|
+
`includePendingStatus`: true|false (default false). When true, a pending boolean will be added to the verificationProperties in the response, and an extra message will appear in the notices array to indicate why this pact is/is not in pending state. This will allow your code to handle the response based on only what is present in the response, and not have to do ifs based on the user's options together with the response. As requested in the "pacts for verification" issue, please print out these messages in the tests if possible. If not possible, perhaps create a separate task which will list the pact URLs and messages for debugging purposes.
|
41
|
+
|
42
|
+
`includeWipPactsSince`: Date string. The date from which to include the "work in progress" pacts. See https://docs.pact.io/wip for more information on work in progress pacts.
|
43
|
+
|
44
|
+
### Response body
|
45
|
+
|
46
|
+
`pending` flag and the "pending reason" notice will only be included if `includePendingStatus` is set to true.
|
47
|
+
|
48
|
+
|
49
|
+
{
|
50
|
+
"_embedded": {
|
51
|
+
"pacts": [
|
52
|
+
{
|
53
|
+
"verificationProperties": {
|
54
|
+
"notices": [
|
55
|
+
{
|
56
|
+
"text": "This pact is being verified because it is the pact for the latest version of Foo tagged with 'dev'",
|
57
|
+
"when": "before_verification"
|
58
|
+
}
|
59
|
+
],
|
60
|
+
"pending": false
|
61
|
+
},
|
62
|
+
"_links": {
|
63
|
+
"self": {
|
64
|
+
"href": "http://localhost:9292/pacts/provider/Bar/consumer/Foo/pact-version/0e3369199f4008231946e0245474537443ccda2a",
|
65
|
+
"name": "Pact between Foo (v1.0.0) and Bar"
|
66
|
+
}
|
67
|
+
}
|
68
|
+
}
|
69
|
+
]
|
70
|
+
},
|
71
|
+
"_links": {
|
72
|
+
"self": {
|
73
|
+
"href": "http://localhost:9292/pacts/provider/Bar/for-verification",
|
74
|
+
"title": "Pacts to be verified"
|
75
|
+
}
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'pact_broker/db'
|
2
2
|
require 'pact_broker/json'
|
3
|
+
require 'pact_broker/pacts/content'
|
3
4
|
|
4
5
|
=begin
|
5
6
|
This class most accurately represents a PactPublication
|
@@ -76,6 +77,14 @@ module PactBroker
|
|
76
77
|
JSON.parse(json_content, PACT_PARSING_OPTIONS)
|
77
78
|
end
|
78
79
|
|
80
|
+
def content_object
|
81
|
+
@content_object ||= begin
|
82
|
+
PactBroker::Pacts::Content.from_json(json_content)
|
83
|
+
rescue
|
84
|
+
PactBroker::Pacts::Content.new
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
79
88
|
def pact_publication_id
|
80
89
|
id
|
81
90
|
end
|
@@ -39,9 +39,15 @@ module PactBroker
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def with_test_results(test_results)
|
42
|
-
|
43
|
-
if
|
44
|
-
tests =
|
42
|
+
# new format
|
43
|
+
if test_results.is_a?(Array)
|
44
|
+
tests = test_results
|
45
|
+
else
|
46
|
+
# old format
|
47
|
+
tests = test_results && test_results['tests']
|
48
|
+
if tests.nil? || !tests.is_a?(Array) || tests.empty?
|
49
|
+
tests = []
|
50
|
+
end
|
45
51
|
end
|
46
52
|
|
47
53
|
new_pact_hash = pact_hash.dup
|
@@ -67,6 +73,12 @@ module PactBroker
|
|
67
73
|
Content.from_hash(new_pact_hash)
|
68
74
|
end
|
69
75
|
|
76
|
+
def interaction_ids
|
77
|
+
messages_or_interaction_or_empty_array.collect do | interaction |
|
78
|
+
interaction['_id']
|
79
|
+
end.compact
|
80
|
+
end
|
81
|
+
|
70
82
|
# Half thinking this belongs in GenerateSha
|
71
83
|
def content_that_affects_verification_results
|
72
84
|
if interactions || messages
|
@@ -92,6 +104,10 @@ module PactBroker
|
|
92
104
|
messages || interactions
|
93
105
|
end
|
94
106
|
|
107
|
+
def messages_or_interaction_or_empty_array
|
108
|
+
messages_or_interactions || []
|
109
|
+
end
|
110
|
+
|
95
111
|
def pact_specification_version
|
96
112
|
maybe_pact_specification_version_1 = pact_hash['metadata']['pactSpecification']['version'] rescue nil
|
97
113
|
maybe_pact_specification_version_2 = pact_hash['metadata']['pact-specification']['version'] rescue nil
|
@@ -130,7 +146,15 @@ module PactBroker
|
|
130
146
|
end
|
131
147
|
|
132
148
|
def test_is_for_interaction(interaction, test)
|
133
|
-
test.is_a?(Hash) && interaction.is_a?(Hash) &&
|
149
|
+
test.is_a?(Hash) && interaction.is_a?(Hash) && ( interaction_ids_match(interaction, test) || description_and_state_match(interaction, test))
|
150
|
+
end
|
151
|
+
|
152
|
+
def interaction_ids_match(interaction, test)
|
153
|
+
interaction['_id'] && interaction['_id'] == test['interactionId']
|
154
|
+
end
|
155
|
+
|
156
|
+
def description_and_state_match(interaction, test)
|
157
|
+
test['interactionDescription'] && test['interactionDescription'] == interaction['description'] && test['interactionProviderState'] == interaction['providerState']
|
134
158
|
end
|
135
159
|
end
|
136
160
|
end
|
@@ -405,42 +405,37 @@ module PactBroker
|
|
405
405
|
SelectedPact.new(pact_publication.to_domain, Selectors.create_for_overall_latest)
|
406
406
|
end
|
407
407
|
else
|
408
|
-
|
408
|
+
selectors_for_overall_latest = consumer_version_selectors.select(&:overall_latest?)
|
409
|
+
selectors_for_overall_latest.flat_map do | selector |
|
410
|
+
query = scope_for(LatestPactPublications).provider(provider_name)
|
411
|
+
query = query.consumer(selector.consumer) if selector.consumer
|
412
|
+
query.collect do | latest_pact_publication |
|
413
|
+
pact_publication = PactPublication.find(id: latest_pact_publication.id)
|
414
|
+
resolved_selector = selector.consumer ? Selector.latest_for_consumer(selector.consumer) : Selector.overall_latest
|
415
|
+
SelectedPact.new(pact_publication.to_domain, Selectors.new(resolved_selector))
|
416
|
+
end
|
417
|
+
end
|
409
418
|
end
|
410
419
|
end
|
411
420
|
|
412
421
|
def find_pacts_for_which_the_latest_version_for_the_tag_is_required(provider_name, consumer_version_selectors)
|
413
422
|
# The tags for which only the latest version is specified
|
414
|
-
|
423
|
+
selectors = consumer_version_selectors.select(&:latest_for_tag?)
|
415
424
|
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
.
|
421
|
-
.
|
422
|
-
.
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
end
|
428
|
-
else
|
429
|
-
[]
|
425
|
+
selectors.flat_map do | selector |
|
426
|
+
query = scope_for(LatestTaggedPactPublications).where(tag_name: selector.tag).provider(provider_name)
|
427
|
+
query = query.consumer(selector.consumer) if selector.consumer
|
428
|
+
query.all.collect do | latest_tagged_pact_publication |
|
429
|
+
pact_publication = PactPublication.find(id: latest_tagged_pact_publication.id)
|
430
|
+
resolved_pact = selector.consumer ? Selector.latest_for_tag_and_consumer(selector.tag, selector.consumer) : Selector.latest_for_tag(selector.tag)
|
431
|
+
SelectedPact.new(
|
432
|
+
pact_publication.to_domain,
|
433
|
+
Selectors.new(resolved_pact)
|
434
|
+
)
|
435
|
+
end
|
430
436
|
end
|
431
437
|
end
|
432
438
|
|
433
|
-
def create_selected_pact(pact_publications)
|
434
|
-
selector_tag_names = pact_publications.collect(&:tag_name)
|
435
|
-
selectors = Selectors.create_for_latest_of_each_tag(selector_tag_names)
|
436
|
-
last_pact_publication = pact_publications.sort_by(&:consumer_version_order).last
|
437
|
-
pact_publication = scope_for(PactPublication).find(id: last_pact_publication.id)
|
438
|
-
SelectedPact.new(
|
439
|
-
pact_publication.to_domain,
|
440
|
-
selectors
|
441
|
-
)
|
442
|
-
end
|
443
|
-
|
444
439
|
def create_fallback_selected_pact(pact_publications, consumer_version_selectors)
|
445
440
|
selector_tag_names = pact_publications.collect(&:tag_name)
|
446
441
|
selectors = Selectors.create_for_latest_fallback_of_each_tag(selector_tag_names)
|
@@ -454,10 +449,9 @@ module PactBroker
|
|
454
449
|
|
455
450
|
def find_pacts_for_which_the_latest_version_for_the_fallback_tag_is_required(provider_name, selectors)
|
456
451
|
selectors.collect do | selector |
|
457
|
-
scope_for(LatestTaggedPactPublications)
|
458
|
-
|
459
|
-
|
460
|
-
.all
|
452
|
+
query = scope_for(LatestTaggedPactPublications).provider(provider_name).where(tag_name: selector.fallback_tag)
|
453
|
+
query = query.consumer(selector.consumer) if selector.consumer
|
454
|
+
query.all
|
461
455
|
.collect do | latest_tagged_pact_publication |
|
462
456
|
pact_publication = unscoped(PactPublication).find(id: latest_tagged_pact_publication.id)
|
463
457
|
SelectedPact.new(
|
@@ -53,6 +53,14 @@ module PactBroker
|
|
53
53
|
Selector.new(tag: tag, consumer: consumer)
|
54
54
|
end
|
55
55
|
|
56
|
+
def self.latest_for_tag_and_consumer(tag, consumer)
|
57
|
+
Selector.new(latest: true, tag: tag, consumer: consumer)
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.latest_for_consumer(consumer)
|
61
|
+
Selector.new(latest: true, consumer: consumer)
|
62
|
+
end
|
63
|
+
|
56
64
|
def self.from_hash hash
|
57
65
|
Selector.new(hash)
|
58
66
|
end
|
data/lib/pact_broker/version.rb
CHANGED
@@ -7,9 +7,10 @@ module PactBroker
|
|
7
7
|
module Webhooks
|
8
8
|
class Job
|
9
9
|
|
10
|
+
INFO_ERROR_PREFIXES = %w{Errno:: Timeout:: Net:: OpenSSL:: EOFError SocketError}
|
11
|
+
|
10
12
|
include SuckerPunch::Job
|
11
13
|
include PactBroker::Logging
|
12
|
-
include PactBroker::Logging
|
13
14
|
|
14
15
|
def perform data
|
15
16
|
data.fetch(:database_connector).call do
|
@@ -62,7 +63,12 @@ module PactBroker
|
|
62
63
|
end
|
63
64
|
|
64
65
|
def handle_error e
|
65
|
-
|
66
|
+
message = "Error executing triggered webhook with ID #{triggered_webhook ? triggered_webhook.id : nil}"
|
67
|
+
if e.class.name.start_with?(*INFO_ERROR_PREFIXES)
|
68
|
+
logger.info(message, e)
|
69
|
+
else
|
70
|
+
logger.warn(message, e)
|
71
|
+
end
|
66
72
|
handle_failure
|
67
73
|
end
|
68
74
|
|
@@ -24,24 +24,6 @@ describe "Get provider pacts for verification" do
|
|
24
24
|
|
25
25
|
let(:path) { "/pacts/provider/Provider/for-verification" }
|
26
26
|
|
27
|
-
context "when using GET" do
|
28
|
-
it "returns a 200 HAL JSON response" do
|
29
|
-
expect(subject).to be_a_hal_json_success_response
|
30
|
-
end
|
31
|
-
|
32
|
-
it "returns a list of links to the pacts" do
|
33
|
-
expect(pacts.size).to eq 1
|
34
|
-
end
|
35
|
-
|
36
|
-
context "when the provider does not exist" do
|
37
|
-
let(:path) { "/pacts/provider/ProviderThatDoesNotExist/for-verification" }
|
38
|
-
|
39
|
-
it "returns a 404 response" do
|
40
|
-
expect(subject).to be_a_404_response
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
27
|
context "when using POST" do
|
46
28
|
let(:request_body) do
|
47
29
|
{
|
@@ -71,6 +71,27 @@ module PactBroker
|
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
+
context "when the latest version for a particular consumer is requested" do
|
75
|
+
let(:consumer_version_selectors) do
|
76
|
+
[{
|
77
|
+
consumer: "Foo",
|
78
|
+
latest: true
|
79
|
+
}]
|
80
|
+
end
|
81
|
+
|
82
|
+
it { is_expected.to be_empty }
|
83
|
+
end
|
84
|
+
|
85
|
+
context "when the latest version for all is requested" do
|
86
|
+
let(:consumer_version_selectors) do
|
87
|
+
[{
|
88
|
+
latest: true
|
89
|
+
}]
|
90
|
+
end
|
91
|
+
|
92
|
+
it { is_expected.to be_empty }
|
93
|
+
end
|
94
|
+
|
74
95
|
context "when providerVersionTags is not an array" do
|
75
96
|
let(:provider_version_tags) { true }
|
76
97
|
|
@@ -89,7 +110,7 @@ module PactBroker
|
|
89
110
|
end
|
90
111
|
|
91
112
|
it "flattens the messages" do
|
92
|
-
expect(subject[:consumerVersionSelectors].first).to eq "tag
|
113
|
+
expect(subject[:consumerVersionSelectors].first).to eq "latest must be true, or a tag must be provided (at index 0)"
|
93
114
|
end
|
94
115
|
end
|
95
116
|
|
@@ -150,9 +171,7 @@ module PactBroker
|
|
150
171
|
}]
|
151
172
|
end
|
152
173
|
|
153
|
-
it
|
154
|
-
expect(subject[:consumerVersionSelectors].first).to include "not yet supported"
|
155
|
-
end
|
174
|
+
it { is_expected.to be_empty }
|
156
175
|
end
|
157
176
|
end
|
158
177
|
end
|
@@ -11,7 +11,7 @@ module PactBroker
|
|
11
11
|
end
|
12
12
|
|
13
13
|
let(:provider) { double('provider') }
|
14
|
-
let(:pacts) {
|
14
|
+
let(:pacts) { [] }
|
15
15
|
let(:path) { '/pacts/provider/Bar/for-verification' }
|
16
16
|
let(:decorator) { instance_double('PactBroker::Api::Decorators::VerifiablePactsDecorator') }
|
17
17
|
let(:query) do
|
@@ -23,35 +23,7 @@ module PactBroker
|
|
23
23
|
}
|
24
24
|
end
|
25
25
|
|
26
|
-
subject {
|
27
|
-
|
28
|
-
describe "GET" do
|
29
|
-
it "finds the pacts for verification by the provider" do
|
30
|
-
# Naughty not mocking out the query parsing...
|
31
|
-
expect(PactBroker::Pacts::Service).to receive(:find_for_verification).with(
|
32
|
-
"Bar",
|
33
|
-
["master"],
|
34
|
-
PactBroker::Pacts::Selectors.new([PactBroker::Pacts::Selector.latest_for_tag("dev")]),
|
35
|
-
{
|
36
|
-
include_wip_pacts_since: DateTime.parse('2018-01-01'),
|
37
|
-
include_pending_status: true
|
38
|
-
}
|
39
|
-
)
|
40
|
-
subject
|
41
|
-
end
|
42
|
-
|
43
|
-
context "when there are validation errors" do
|
44
|
-
let(:query) do
|
45
|
-
{
|
46
|
-
provider_version_tags: true,
|
47
|
-
}
|
48
|
-
end
|
49
|
-
|
50
|
-
it "returns the keys with the right case" do
|
51
|
-
expect(JSON.parse(subject.body)['errors']).to have_key('provider_version_tags')
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
26
|
+
subject { post(path, request_body.to_json, request_headers) }
|
55
27
|
|
56
28
|
describe "POST" do
|
57
29
|
let(:request_body) do
|
@@ -70,8 +42,6 @@ module PactBroker
|
|
70
42
|
}
|
71
43
|
end
|
72
44
|
|
73
|
-
subject { post(path, request_body.to_json, request_headers) }
|
74
|
-
|
75
45
|
it "finds the pacts for verification by the provider" do
|
76
46
|
# Naughty not mocking out the query parsing...
|
77
47
|
expect(PactBroker::Pacts::Service).to receive(:find_for_verification).with(
|
@@ -97,14 +67,14 @@ module PactBroker
|
|
97
67
|
expect(JSON.parse(subject.body)['errors']).to have_key('providerVersionTags')
|
98
68
|
end
|
99
69
|
end
|
100
|
-
end
|
101
70
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
71
|
+
it "uses the correct options for the decorator" do
|
72
|
+
expect(decorator).to receive(:to_json) do | options |
|
73
|
+
expect(options[:user_options][:title]).to eq "Pacts to be verified by provider Bar"
|
74
|
+
expect(options[:user_options][:include_pending_status]).to eq true
|
75
|
+
end
|
76
|
+
subject
|
106
77
|
end
|
107
|
-
subject
|
108
78
|
end
|
109
79
|
end
|
110
80
|
end
|
@@ -359,6 +359,88 @@ module PactBroker
|
|
359
359
|
expect(subject.to_hash).to eq merged_with_empty_tests
|
360
360
|
end
|
361
361
|
end
|
362
|
+
|
363
|
+
context "with the new format" do
|
364
|
+
let(:test_results) do
|
365
|
+
[
|
366
|
+
{
|
367
|
+
"interactionId" => "1",
|
368
|
+
"success "=> false
|
369
|
+
},{
|
370
|
+
"foo" => "bar"
|
371
|
+
}
|
372
|
+
]
|
373
|
+
end
|
374
|
+
|
375
|
+
let(:pact_content) do
|
376
|
+
{
|
377
|
+
"interactions" => [
|
378
|
+
{
|
379
|
+
"_id" => "1"
|
380
|
+
},
|
381
|
+
{
|
382
|
+
"_id" => "2"
|
383
|
+
}
|
384
|
+
]
|
385
|
+
}
|
386
|
+
end
|
387
|
+
|
388
|
+
let(:merged) do
|
389
|
+
{
|
390
|
+
"interactions" => [
|
391
|
+
{
|
392
|
+
"_id" => "1",
|
393
|
+
"tests" => [{
|
394
|
+
"interactionId" => "1",
|
395
|
+
"success "=> false
|
396
|
+
}]
|
397
|
+
},{
|
398
|
+
"_id" => "2",
|
399
|
+
"tests" => []
|
400
|
+
}
|
401
|
+
]
|
402
|
+
}
|
403
|
+
end
|
404
|
+
|
405
|
+
it "merges the tests into the pact content" do
|
406
|
+
expect(subject.to_hash).to eq merged
|
407
|
+
end
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
411
|
+
describe "interaction_ids" do
|
412
|
+
let(:interaction_1) do
|
413
|
+
{
|
414
|
+
_id: '1'
|
415
|
+
}
|
416
|
+
end
|
417
|
+
|
418
|
+
let(:interaction_2) do
|
419
|
+
{
|
420
|
+
_id: '2'
|
421
|
+
}
|
422
|
+
end
|
423
|
+
|
424
|
+
let(:interaction_3) do
|
425
|
+
{
|
426
|
+
}
|
427
|
+
end
|
428
|
+
|
429
|
+
let(:content_hash) do
|
430
|
+
{
|
431
|
+
interactions: [interaction_1, interaction_2, interaction_3]
|
432
|
+
}
|
433
|
+
end
|
434
|
+
|
435
|
+
subject { Content.from_json(content_hash.to_json) }
|
436
|
+
|
437
|
+
its(:interaction_ids) { is_expected.to eq ['1', '2'] }
|
438
|
+
|
439
|
+
context "when there are no interactions" do
|
440
|
+
let(:content_hash) { {} }
|
441
|
+
|
442
|
+
its(:interaction_ids) { is_expected.to eq [] }
|
443
|
+
end
|
362
444
|
end
|
363
445
|
end
|
364
446
|
end
|
@@ -56,6 +56,20 @@ module PactBroker
|
|
56
56
|
it "sets the latest flag on the selector" do
|
57
57
|
expect(find_by_consumer_version_number("1").selectors.first.latest).to be true
|
58
58
|
end
|
59
|
+
|
60
|
+
context "when a consumer is specified" do
|
61
|
+
before do
|
62
|
+
td.create_pact_with_consumer_version_tag("Foo2", "3", "master", "Bar")
|
63
|
+
end
|
64
|
+
|
65
|
+
let(:selector) { Selector.new(tag: tag, fallback_tag: fallback_tag, latest: true, consumer: "Foo") }
|
66
|
+
|
67
|
+
it "only returns the pacts for the consumer" do
|
68
|
+
expect(subject.size).to eq 1
|
69
|
+
expect(subject.first.consumer.name).to eq "Foo"
|
70
|
+
expect(subject.first.selectors.first).to eq selector
|
71
|
+
end
|
72
|
+
end
|
59
73
|
end
|
60
74
|
|
61
75
|
context "when a pact does not exist for either tag or fallback_tag" do
|
@@ -40,6 +40,68 @@ module PactBroker
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
+
context "when the selector is latest: true" do
|
44
|
+
let(:pact_selector_1) { Selector.overall_latest }
|
45
|
+
let(:consumer_version_selectors) do
|
46
|
+
Selectors.new(pact_selector_1)
|
47
|
+
end
|
48
|
+
|
49
|
+
before do
|
50
|
+
td.create_pact_with_hierarchy("Foo1", "1", "Bar")
|
51
|
+
.create_pact_with_hierarchy("Foo1", "2", "Bar")
|
52
|
+
.create_pact_with_hierarchy("Foo2", "3", "Bar")
|
53
|
+
.create_pact_with_hierarchy("Foo2", "4", "Bar2")
|
54
|
+
end
|
55
|
+
|
56
|
+
it "returns the latest pact for each consumer" do
|
57
|
+
expect(subject.size).to eq 2
|
58
|
+
expect(find_by_consumer_name_and_consumer_version_number("Foo1", "2").selectors).to eq [Selector.overall_latest]
|
59
|
+
expect(find_by_consumer_name_and_consumer_version_number("Foo2", "3").selectors).to eq [Selector.overall_latest]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "when the selector is latest: true for a particular consumer" do
|
64
|
+
let(:pact_selector_1) { Selector.latest_for_consumer("Foo1") }
|
65
|
+
|
66
|
+
let(:consumer_version_selectors) do
|
67
|
+
Selectors.new(pact_selector_1)
|
68
|
+
end
|
69
|
+
|
70
|
+
before do
|
71
|
+
td.create_pact_with_hierarchy("Foo1", "1", "Bar")
|
72
|
+
.create_pact_with_hierarchy("Foo1", "2", "Bar")
|
73
|
+
.create_pact_with_hierarchy("Foo2", "2", "Bar")
|
74
|
+
.create_pact_with_hierarchy("Foo2", "2", "Bar2")
|
75
|
+
end
|
76
|
+
|
77
|
+
it "returns the latest pact for each consumer" do
|
78
|
+
expect(subject.size).to eq 1
|
79
|
+
expect(find_by_consumer_name_and_consumer_version_number("Foo1", "2").selectors).to eq [pact_selector_1]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "when the selector is latest: true, with a tag, for a particular consumer" do
|
84
|
+
let(:pact_selector_1) { Selector.latest_for_tag_and_consumer("prod", "Foo1") }
|
85
|
+
|
86
|
+
let(:consumer_version_selectors) do
|
87
|
+
Selectors.new(pact_selector_1)
|
88
|
+
end
|
89
|
+
|
90
|
+
before do
|
91
|
+
td.create_pact_with_hierarchy("Foo1", "1", "Bar")
|
92
|
+
.create_consumer_version_tag("prod")
|
93
|
+
.create_pact_with_hierarchy("Foo1", "2", "Bar")
|
94
|
+
.create_pact_with_hierarchy("Foo2", "2", "Bar")
|
95
|
+
.create_consumer_version_tag("prod")
|
96
|
+
.create_pact_with_hierarchy("Foo2", "2", "Bar2")
|
97
|
+
end
|
98
|
+
|
99
|
+
it "returns the latest pact for each consumer" do
|
100
|
+
expect(subject.size).to eq 1
|
101
|
+
expect(find_by_consumer_name_and_consumer_version_number("Foo1", "1").selectors).to eq [pact_selector_1]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
43
105
|
context "when the latest consumer tag names are specified" do
|
44
106
|
before do
|
45
107
|
td.create_pact_with_hierarchy("Foo", "foo-latest-prod-version", "Bar")
|
@@ -53,7 +53,25 @@ module PactBroker
|
|
53
53
|
|
54
54
|
context "when an error occurs for the first time" do
|
55
55
|
before do
|
56
|
-
allow(PactBroker::Webhooks::Service).to receive(:execute_triggered_webhook_now).and_raise(
|
56
|
+
allow(PactBroker::Webhooks::Service).to receive(:execute_triggered_webhook_now).and_raise(error)
|
57
|
+
end
|
58
|
+
|
59
|
+
let(:error) { "an error" }
|
60
|
+
|
61
|
+
context "when the error is HTTP related (most likely caused by a problem with the webhook or request itself)" do
|
62
|
+
let(:error) { Errno::ECONNREFUSED.new }
|
63
|
+
|
64
|
+
it "logs a message at info" do
|
65
|
+
expect(logger).to receive(:info).with(/Error executing/, error)
|
66
|
+
subject
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context "when the error is not HTTP related (most likely caused by a code, platform or environment issue)" do
|
71
|
+
it "logs a message at warn" do
|
72
|
+
expect(logger).to receive(:warn).with(/Error executing/, instance_of(RuntimeError))
|
73
|
+
subject
|
74
|
+
end
|
57
75
|
end
|
58
76
|
|
59
77
|
it "reschedules the job in 10 seconds" do
|
@@ -8,11 +8,7 @@ RSpec.configure do |config|
|
|
8
8
|
config.before(:suite) do
|
9
9
|
if defined?(::DB)
|
10
10
|
DatabaseCleaner.strategy = :transaction
|
11
|
-
|
12
|
-
DatabaseCleaner.clean_with :deletion
|
13
|
-
else
|
14
|
-
DatabaseCleaner.clean_with :truncation
|
15
|
-
end
|
11
|
+
PactBroker::Database.truncate
|
16
12
|
end
|
17
13
|
end
|
18
14
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pact_broker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.60.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bethany Skurrie
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2020-08
|
13
|
+
date: 2020-09-08 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: httparty
|
@@ -581,7 +581,6 @@ files:
|
|
581
581
|
- lib/pact_broker/api/contracts/put_pact_params_contract.rb
|
582
582
|
- lib/pact_broker/api/contracts/request_validations.rb
|
583
583
|
- lib/pact_broker/api/contracts/verifiable_pacts_json_query_schema.rb
|
584
|
-
- lib/pact_broker/api/contracts/verifiable_pacts_query_schema.rb
|
585
584
|
- lib/pact_broker/api/contracts/verification_contract.rb
|
586
585
|
- lib/pact_broker/api/contracts/webhook_contract.rb
|
587
586
|
- lib/pact_broker/api/decorators.rb
|
@@ -760,6 +759,7 @@ files:
|
|
760
759
|
- lib/pact_broker/doc/views/pact/tag-prod-version.markdown
|
761
760
|
- lib/pact_broker/doc/views/pact/tag-version.markdown
|
762
761
|
- lib/pact_broker/doc/views/pending-provider-pacts.markdown
|
762
|
+
- lib/pact_broker/doc/views/provider-pacts-for-verification.markdown
|
763
763
|
- lib/pact_broker/doc/views/provider.markdown
|
764
764
|
- lib/pact_broker/doc/views/version/latest-verification-results-where-pacticipant-is-consumer.markdown
|
765
765
|
- lib/pact_broker/doc/views/webhooks.markdown
|
@@ -1120,7 +1120,6 @@ files:
|
|
1120
1120
|
- spec/lib/pact/doc/markdown/index_renderer_spec.rb
|
1121
1121
|
- spec/lib/pact_broker/api/contracts/put_pact_params_contract_spec.rb
|
1122
1122
|
- spec/lib/pact_broker/api/contracts/verifiable_pacts_json_query_schema_spec.rb
|
1123
|
-
- spec/lib/pact_broker/api/contracts/verifiable_pacts_query_schema_spec.rb
|
1124
1123
|
- spec/lib/pact_broker/api/contracts/verification_contract_spec.rb
|
1125
1124
|
- spec/lib/pact_broker/api/contracts/webhook_contract_spec.rb
|
1126
1125
|
- spec/lib/pact_broker/api/decorators/dashboard_decorator_spec.rb
|
@@ -1506,7 +1505,6 @@ test_files:
|
|
1506
1505
|
- spec/lib/pact/doc/markdown/index_renderer_spec.rb
|
1507
1506
|
- spec/lib/pact_broker/api/contracts/put_pact_params_contract_spec.rb
|
1508
1507
|
- spec/lib/pact_broker/api/contracts/verifiable_pacts_json_query_schema_spec.rb
|
1509
|
-
- spec/lib/pact_broker/api/contracts/verifiable_pacts_query_schema_spec.rb
|
1510
1508
|
- spec/lib/pact_broker/api/contracts/verification_contract_spec.rb
|
1511
1509
|
- spec/lib/pact_broker/api/contracts/webhook_contract_spec.rb
|
1512
1510
|
- spec/lib/pact_broker/api/decorators/dashboard_decorator_spec.rb
|
@@ -1,36 +0,0 @@
|
|
1
|
-
require 'dry-validation'
|
2
|
-
require 'pact_broker/api/contracts/dry_validation_workarounds'
|
3
|
-
require 'pact_broker/api/contracts/dry_validation_predicates'
|
4
|
-
|
5
|
-
module PactBroker
|
6
|
-
module Api
|
7
|
-
module Contracts
|
8
|
-
class VerifiablePactsQuerySchema
|
9
|
-
extend DryValidationWorkarounds
|
10
|
-
using PactBroker::HashRefinements
|
11
|
-
|
12
|
-
SCHEMA = Dry::Validation.Schema do
|
13
|
-
configure do
|
14
|
-
predicates(DryValidationPredicates)
|
15
|
-
config.messages_file = File.expand_path("../../../locale/en.yml", __FILE__)
|
16
|
-
end
|
17
|
-
optional(:provider_version_tags).maybe(:array?)
|
18
|
-
optional(:consumer_version_selectors).each do
|
19
|
-
schema do
|
20
|
-
required(:tag).filled(:str?)
|
21
|
-
optional(:latest).filled(included_in?: ["true", "false"])
|
22
|
-
optional(:fallback_tag).filled(:str?)
|
23
|
-
optional(:consumer).filled(:str?, :not_blank?)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
optional(:include_pending_status).filled(included_in?: ["true", "false"])
|
27
|
-
optional(:include_wip_pacts_since).filled(:date?)
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.call(params)
|
31
|
-
select_first_message(flatten_indexed_messages(SCHEMA.call(params&.symbolize_keys).messages(full: true)))
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,97 +0,0 @@
|
|
1
|
-
require 'pact_broker/api/contracts/verifiable_pacts_query_schema'
|
2
|
-
|
3
|
-
module PactBroker
|
4
|
-
module Api
|
5
|
-
module Contracts
|
6
|
-
describe VerifiablePactsQuerySchema do
|
7
|
-
let(:params) do
|
8
|
-
{
|
9
|
-
provider_version_tags: provider_version_tags,
|
10
|
-
consumer_version_selectors: consumer_version_selectors
|
11
|
-
}
|
12
|
-
end
|
13
|
-
|
14
|
-
let(:provider_version_tags) { %w[master] }
|
15
|
-
|
16
|
-
let(:consumer_version_selectors) do
|
17
|
-
[{
|
18
|
-
tag: "master",
|
19
|
-
latest: "true"
|
20
|
-
}]
|
21
|
-
end
|
22
|
-
|
23
|
-
subject { VerifiablePactsQuerySchema.(params) }
|
24
|
-
|
25
|
-
context "when the params are valid" do
|
26
|
-
it "has no errors" do
|
27
|
-
expect(subject).to eq({})
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
context "when provider_version_tags is not an array" do
|
32
|
-
let(:provider_version_tags) { "foo" }
|
33
|
-
|
34
|
-
it { is_expected.to have_key(:provider_version_tags) }
|
35
|
-
end
|
36
|
-
|
37
|
-
context "when the consumer_version_selector is missing a tag" do
|
38
|
-
let(:consumer_version_selectors) do
|
39
|
-
[{}]
|
40
|
-
end
|
41
|
-
|
42
|
-
it "flattens the messages" do
|
43
|
-
expect(subject[:consumer_version_selectors].first).to eq "tag is missing at index 0"
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
context "when the consumer_version_selectors is missing the latest" do
|
48
|
-
let(:consumer_version_selectors) do
|
49
|
-
[{
|
50
|
-
tag: "master"
|
51
|
-
}]
|
52
|
-
end
|
53
|
-
|
54
|
-
it { is_expected.to be_empty }
|
55
|
-
end
|
56
|
-
|
57
|
-
context "when include_wip_pacts_since key exists" do
|
58
|
-
let(:include_wip_pacts_since) { nil }
|
59
|
-
let(:params) do
|
60
|
-
{
|
61
|
-
include_wip_pacts_since: include_wip_pacts_since
|
62
|
-
}
|
63
|
-
end
|
64
|
-
|
65
|
-
context "when it is nil" do
|
66
|
-
it { is_expected.to have_key(:include_wip_pacts_since) }
|
67
|
-
end
|
68
|
-
|
69
|
-
context "when it is not a date" do
|
70
|
-
let(:include_wip_pacts_since) { "foo" }
|
71
|
-
|
72
|
-
it { is_expected.to have_key(:include_wip_pacts_since) }
|
73
|
-
end
|
74
|
-
|
75
|
-
context "when it is a valid date" do
|
76
|
-
let(:include_wip_pacts_since) { "2013-02-13T20:04:45.000+11:00" }
|
77
|
-
|
78
|
-
it { is_expected.to_not have_key(:include_wip_pacts_since) }
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
context "when a blank consumer name is specified" do
|
83
|
-
let(:consumer_version_selectors) do
|
84
|
-
[{
|
85
|
-
tag: "feat-x",
|
86
|
-
consumer: ""
|
87
|
-
}]
|
88
|
-
end
|
89
|
-
|
90
|
-
it "has an error" do
|
91
|
-
expect(subject[:consumer_version_selectors].first).to include "blank"
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|