pact_broker 2.55.0 → 2.56.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 +22 -0
- data/lib/pact_broker/api/decorators/reason_decorator.rb +17 -0
- data/lib/pact_broker/app.rb +13 -4
- data/lib/pact_broker/db.rb +9 -1
- data/lib/pact_broker/doc/controllers/app.rb +5 -1
- data/lib/pact_broker/domain/verification.rb +13 -0
- data/lib/pact_broker/integrations/service.rb +2 -2
- data/lib/pact_broker/logging.rb +3 -1
- data/lib/pact_broker/matrix/deployment_status_summary.rb +23 -1
- data/lib/pact_broker/matrix/reason.rb +9 -0
- data/lib/pact_broker/pacts/content.rb +26 -2
- data/lib/pact_broker/pacts/repository.rb +2 -2
- data/lib/pact_broker/tasks/migration_task.rb +20 -1
- data/lib/pact_broker/ui/controllers/base_controller.rb +1 -1
- data/lib/pact_broker/ui/views/index/_navbar.haml +1 -1
- data/lib/pact_broker/verifications/repository.rb +2 -2
- data/lib/pact_broker/version.rb +1 -1
- data/script/foo-bar-verification.json +3 -1
- data/script/foo-bar.json +11 -0
- data/spec/features/delete_integration_spec.rb +2 -2
- data/spec/integration/ui/index_spec.rb +16 -0
- data/spec/integration/ui/matrix_spec.rb +1 -1
- data/spec/lib/pact_broker/api/decorators/reason_decorator_spec.rb +18 -1
- data/spec/lib/pact_broker/doc/controllers/app_spec.rb +16 -0
- data/spec/lib/pact_broker/integrations/service_spec.rb +6 -0
- data/spec/lib/pact_broker/matrix/deployment_status_summary_spec.rb +6 -2
- data/spec/lib/pact_broker/matrix/integration_spec.rb +43 -0
- data/spec/lib/pact_broker/pacts/content_spec.rb +125 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f4391656ae9cddad910749af5c6bb4c3c94644cf605122e31a40ce8891feb49d
|
4
|
+
data.tar.gz: db46a7cdf21674996ed6271dac6c13e2238771004d76693fea6bc11e18fdd146
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 77ebcb58e85910f527b5750b4a484d856cb7a84369e4d6dc89097e3cc706c8077e1f2cc83ff8f7c5e1e079eb55b686680cacccb52c79a20a6b42b903d98e8784
|
7
|
+
data.tar.gz: c151197191dab0a0b35dd08f7ec0df10a280f28f372a5d72365052a813b67265a2cd1e3d602927641169b5e72fd9e1b6547c0e04a260895693c6a65415fcace0
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
<a name="v2.56.0"></a>
|
2
|
+
### v2.56.0 (2020-06-01)
|
3
|
+
|
4
|
+
|
5
|
+
#### Features
|
6
|
+
|
7
|
+
* **database**
|
8
|
+
* log schema versions and migration info on startup ([b385e535](/../../commit/b385e535))
|
9
|
+
* allow options to be passed to Sequel migrate via the MigrationTask ([143613e7](/../../commit/143613e7))
|
10
|
+
|
11
|
+
* allow Pactflow messages in logs to be hidden by setting PACT_BROKER_HIDE_PACTFLOW_MESSAGES=true ([a7550105](/../../commit/a7550105))
|
12
|
+
|
13
|
+
* **can-i-deploy**
|
14
|
+
* experimental - add a warning message if there are interactions missing verification test results. ([f7ab8cc5](/../../commit/f7ab8cc5))
|
15
|
+
|
16
|
+
|
17
|
+
#### Bug Fixes
|
18
|
+
|
19
|
+
* use relative URLs when base_url not explictly set to ensure app is not vulnerable to host header attacks ([92c45a0a](/../../commit/92c45a0a))
|
20
|
+
* raise PactBroker::Error when either pacticipant is not found in the business layer while attempting to delete an integration ([3c209a46](/../../commit/3c209a46))
|
21
|
+
|
22
|
+
|
1
23
|
<a name="v2.55.0"></a>
|
2
24
|
### v2.55.0 (2020-05-22)
|
3
25
|
|
@@ -22,6 +22,11 @@ module PactBroker
|
|
22
22
|
"There are no missing dependencies"
|
23
23
|
when PactBroker::Matrix::Successful
|
24
24
|
"All required verification results are published and successful"
|
25
|
+
when PactBroker::Matrix::InteractionsMissingVerifications
|
26
|
+
descriptions = reason.interactions.collect do | interaction |
|
27
|
+
interaction_description(interaction)
|
28
|
+
end.join('; ')
|
29
|
+
"WARNING: Although the verification was reported as successful, the results for #{reason.consumer_selector.description} and #{reason.provider_selector.description} may be missing tests for the following interactions: #{descriptions}"
|
25
30
|
else
|
26
31
|
reason
|
27
32
|
end
|
@@ -44,6 +49,18 @@ module PactBroker
|
|
44
49
|
""
|
45
50
|
end
|
46
51
|
end
|
52
|
+
|
53
|
+
# TODO move this somewhere else
|
54
|
+
def interaction_description(interaction)
|
55
|
+
if interaction['providerState'] && interaction['providerState'] != ''
|
56
|
+
"#{interaction['description']} given #{interaction['providerState']}"
|
57
|
+
elsif interaction['providerStates'] && interaction['providerStates'].is_a?(Array) && interaction['providerStates'].any?
|
58
|
+
provider_states = interaction['providerStates'].collect{ |ps| ps['name'] }.compact.join(', ')
|
59
|
+
"#{interaction['description']} given #{provider_states}"
|
60
|
+
else
|
61
|
+
interaction['description']
|
62
|
+
end
|
63
|
+
end
|
47
64
|
end
|
48
65
|
end
|
49
66
|
end
|
data/lib/pact_broker/app.rb
CHANGED
@@ -81,11 +81,18 @@ module PactBroker
|
|
81
81
|
end
|
82
82
|
|
83
83
|
def prepare_database
|
84
|
+
logger.info "Database schema version is #{PactBroker::DB.version(configuration.database_connection)}"
|
84
85
|
if configuration.auto_migrate_db
|
85
|
-
|
86
|
-
PactBroker::DB.
|
86
|
+
migration_options = { allow_missing_migration_files: configuration.allow_missing_migration_files }
|
87
|
+
if PactBroker::DB.is_current?(configuration.database_connection, migration_options)
|
88
|
+
logger.info "Skipping database migrations as the latest migration has already been applied"
|
89
|
+
else
|
90
|
+
logger.info "Migrating database schema"
|
91
|
+
PactBroker::DB.run_migrations configuration.database_connection, migration_options
|
92
|
+
logger.info "Database schema version is now #{PactBroker::DB.version(configuration.database_connection)}"
|
93
|
+
end
|
87
94
|
else
|
88
|
-
logger.info "Skipping database migrations"
|
95
|
+
logger.info "Skipping database schema migrations as database auto migrate is disabled"
|
89
96
|
end
|
90
97
|
|
91
98
|
if configuration.auto_migrate_db_data
|
@@ -232,7 +239,9 @@ module PactBroker
|
|
232
239
|
end
|
233
240
|
|
234
241
|
def print_startup_message
|
235
|
-
|
242
|
+
if ENV['PACT_BROKER_HIDE_PACTFLOW_MESSAGES'] != 'true'
|
243
|
+
logger.info "\n\n#{'*' * 80}\n\nWant someone to manage your Pact Broker for you? Check out https://pactflow.io/oss for a hardened, fully supported SaaS version of the Pact Broker with an improved UI + more.\n\n#{'*' * 80}\n"
|
244
|
+
end
|
236
245
|
end
|
237
246
|
end
|
238
247
|
end
|
data/lib/pact_broker/db.rb
CHANGED
@@ -2,12 +2,12 @@ require 'sequel'
|
|
2
2
|
require 'pact_broker/db/validate_encoding'
|
3
3
|
require 'pact_broker/db/migrate'
|
4
4
|
require 'pact_broker/db/migrate_data'
|
5
|
+
require 'pact_broker/db/version'
|
5
6
|
|
6
7
|
Sequel.datetime_class = DateTime
|
7
8
|
|
8
9
|
module PactBroker
|
9
10
|
module DB
|
10
|
-
|
11
11
|
MIGRATIONS_DIR = File.expand_path("../../../db/migrations", __FILE__)
|
12
12
|
|
13
13
|
def self.connection= connection
|
@@ -27,6 +27,14 @@ module PactBroker
|
|
27
27
|
PactBroker::DB::MigrateData.(database_connection)
|
28
28
|
end
|
29
29
|
|
30
|
+
def self.is_current? database_connection, options = {}
|
31
|
+
Sequel::TimestampMigrator.is_current?(database_connection, PactBroker::DB::MIGRATIONS_DIR, options)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.version database_connection
|
35
|
+
PactBroker::DB::Version.call(database_connection)
|
36
|
+
end
|
37
|
+
|
30
38
|
def self.validate_connection_config
|
31
39
|
PactBroker::DB::ValidateEncoding.(connection)
|
32
40
|
end
|
@@ -46,7 +46,11 @@ module PactBroker
|
|
46
46
|
private
|
47
47
|
|
48
48
|
def base_url
|
49
|
-
|
49
|
+
# Using the X-Forwarded headers in the UI can leave the app vulnerable
|
50
|
+
# https://www.acunetix.com/blog/articles/automated-detection-of-host-header-attacks/
|
51
|
+
# Either use the explicitly configured base url or an empty string,
|
52
|
+
# rather than request.base_url, which uses the X-Forwarded headers.
|
53
|
+
PactBroker.configuration.base_url || ''
|
50
54
|
end
|
51
55
|
end
|
52
56
|
end
|
@@ -2,6 +2,7 @@ require 'json'
|
|
2
2
|
require 'sequel'
|
3
3
|
require 'pact_broker/repositories/helpers'
|
4
4
|
require 'pact_broker/tags/tag_with_latest_flag'
|
5
|
+
require 'pact_broker/pacts/content'
|
5
6
|
|
6
7
|
|
7
8
|
module PactBroker
|
@@ -83,6 +84,18 @@ module PactBroker
|
|
83
84
|
def latest_pact_publication
|
84
85
|
pact_version.latest_pact_publication
|
85
86
|
end
|
87
|
+
|
88
|
+
def interactions_missing_test_results
|
89
|
+
@interactions_missing_test_results ||= pact_content_with_test_results.interactions_missing_test_results
|
90
|
+
end
|
91
|
+
|
92
|
+
def all_interactions_missing_test_results?
|
93
|
+
pact_content_with_test_results.interactions.count == pact_content_with_test_results.interactions_missing_test_results.count
|
94
|
+
end
|
95
|
+
|
96
|
+
def pact_content_with_test_results
|
97
|
+
@pact_content_with_test_results = PactBroker::Pacts::Content.from_json(pact_version.content).with_test_results(test_results)
|
98
|
+
end
|
86
99
|
end
|
87
100
|
|
88
101
|
Verification.plugin :timestamps
|
@@ -31,8 +31,8 @@ module PactBroker
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def self.delete(consumer_name, provider_name)
|
34
|
-
consumer = pacticipant_service.find_pacticipant_by_name(consumer_name)
|
35
|
-
provider = pacticipant_service.find_pacticipant_by_name(provider_name)
|
34
|
+
consumer = pacticipant_service.find_pacticipant_by_name!(consumer_name)
|
35
|
+
provider = pacticipant_service.find_pacticipant_by_name!(provider_name)
|
36
36
|
# this takes care of the triggered webhooks and webhook executions
|
37
37
|
pact_service.delete_all_pact_publications_between(consumer_name, and: provider_name)
|
38
38
|
verification_service.delete_all_verifications_between(consumer_name, and: provider_name)
|
data/lib/pact_broker/logging.rb
CHANGED
@@ -34,7 +34,9 @@ module PactBroker
|
|
34
34
|
message = "#{e.class} #{e.message}\n#{e.backtrace.join("\n")}"
|
35
35
|
message = "#{description} - #{message}" if description
|
36
36
|
logger.error message
|
37
|
-
|
37
|
+
if ENV['PACT_BROKER_HIDE_PACTFLOW_MESSAGES'] != 'true'
|
38
|
+
logger.info "\n\n#{'*' * 80}\n\nPrefer it was someone else's job to deal with this error? Check out https://pactflow.io/oss for a hardened, fully supported SaaS version of the Pact Broker with an improved UI + more.\n\n#{'*' * 80}\n"
|
39
|
+
end
|
38
40
|
end
|
39
41
|
end
|
40
42
|
|
@@ -31,7 +31,7 @@ module PactBroker
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def reasons
|
34
|
-
error_messages.any? ? error_messages : success_messages
|
34
|
+
error_messages.any? ? error_messages + warning_messages : success_messages + warning_messages
|
35
35
|
end
|
36
36
|
|
37
37
|
private
|
@@ -51,6 +51,10 @@ module PactBroker
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
+
def warning_messages
|
55
|
+
warnings_for_missing_interactions
|
56
|
+
end
|
57
|
+
|
54
58
|
def specified_selectors_that_do_not_exist
|
55
59
|
resolved_selectors.select(&:specified_version_that_does_not_exist?)
|
56
60
|
end
|
@@ -182,6 +186,24 @@ module PactBroker
|
|
182
186
|
[dummy_consumer_selector, dummy_provider_selector]
|
183
187
|
end.flatten
|
184
188
|
end
|
189
|
+
|
190
|
+
# experimental
|
191
|
+
def warnings_for_missing_interactions
|
192
|
+
rows.select(&:success).collect do | row |
|
193
|
+
begin
|
194
|
+
if row.verification.interactions_missing_test_results.any? && !row.verification.all_interactions_missing_test_results?
|
195
|
+
InteractionsMissingVerifications.new(selector_for(row.consumer_name), selector_for(row.provider_name), row.verification.interactions_missing_test_results)
|
196
|
+
end
|
197
|
+
rescue StandardError => e
|
198
|
+
log_error(e, "Error determining if there were missing interaction verifications")
|
199
|
+
nil
|
200
|
+
end
|
201
|
+
end.compact.tap { |it| report_missing_interaction_verifications(it) if it.any? }
|
202
|
+
end
|
203
|
+
|
204
|
+
def report_missing_interaction_verifications(messages)
|
205
|
+
logger.warn("Interactions missing verifications", messages)
|
206
|
+
end
|
185
207
|
end
|
186
208
|
end
|
187
209
|
end
|
@@ -73,5 +73,14 @@ module PactBroker
|
|
73
73
|
# provider verifications.
|
74
74
|
class NoDependenciesMissing < Reason
|
75
75
|
end
|
76
|
+
|
77
|
+
class InteractionsMissingVerifications < ErrorReasonWithTwoSelectors
|
78
|
+
attr_reader :interactions
|
79
|
+
|
80
|
+
def initialize(consumer_selector, provider_selector, interactions)
|
81
|
+
super(consumer_selector, provider_selector)
|
82
|
+
@interactions = interactions
|
83
|
+
end
|
84
|
+
end
|
76
85
|
end
|
77
86
|
end
|
@@ -31,14 +31,25 @@ module PactBroker
|
|
31
31
|
Content.from_hash(SortContent.call(pact_hash))
|
32
32
|
end
|
33
33
|
|
34
|
+
def interactions_missing_test_results
|
35
|
+
interactions.reject do | interaction |
|
36
|
+
interaction['tests']&.any?
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
34
40
|
def with_test_results(test_results)
|
41
|
+
tests = test_results && test_results['tests']
|
42
|
+
if tests.nil? || !tests.is_a?(Array) || tests.empty?
|
43
|
+
tests = []
|
44
|
+
end
|
45
|
+
|
35
46
|
new_pact_hash = pact_hash.dup
|
36
47
|
if interactions && interactions.is_a?(Array)
|
37
|
-
new_pact_hash['interactions'] = merge_verification_results(interactions,
|
48
|
+
new_pact_hash['interactions'] = merge_verification_results(interactions, tests)
|
38
49
|
end
|
39
50
|
|
40
51
|
if messages && messages.is_a?(Array)
|
41
|
-
new_pact_hash['messages'] = merge_verification_results(messages,
|
52
|
+
new_pact_hash['messages'] = merge_verification_results(messages, tests)
|
42
53
|
end
|
43
54
|
Content.from_hash(new_pact_hash)
|
44
55
|
end
|
@@ -107,6 +118,19 @@ module PactBroker
|
|
107
118
|
end
|
108
119
|
end
|
109
120
|
end
|
121
|
+
|
122
|
+
def merge_verification_results(interactions, tests)
|
123
|
+
interactions.collect(&:dup).collect do | interaction |
|
124
|
+
interaction['tests'] = tests.select do | test |
|
125
|
+
test_is_for_interaction(interaction, test)
|
126
|
+
end
|
127
|
+
interaction
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_is_for_interaction(interaction, test)
|
132
|
+
test.is_a?(Hash) && interaction.is_a?(Hash) && test['interactionDescription'] == interaction['description'] && test['interactionProviderState'] == interaction['providerState']
|
133
|
+
end
|
110
134
|
end
|
111
135
|
end
|
112
136
|
end
|
@@ -107,8 +107,8 @@ module PactBroker
|
|
107
107
|
end
|
108
108
|
|
109
109
|
def delete_all_pact_publications_between consumer_name, options
|
110
|
-
consumer = pacticipant_repository.find_by_name(consumer_name)
|
111
|
-
provider = pacticipant_repository.find_by_name(options.fetch(:and))
|
110
|
+
consumer = pacticipant_repository.find_by_name!(consumer_name)
|
111
|
+
provider = pacticipant_repository.find_by_name!(options.fetch(:and))
|
112
112
|
query = PactPublication.where(consumer: consumer, provider: provider)
|
113
113
|
query = query.tag(options[:tag]) if options[:tag]
|
114
114
|
|
@@ -16,8 +16,10 @@ module PactBroker
|
|
16
16
|
class MigrationTask < ::Rake::TaskLib
|
17
17
|
|
18
18
|
attr_accessor :database_connection
|
19
|
+
attr_accessor :options
|
19
20
|
|
20
21
|
def initialize &block
|
22
|
+
@options = {}
|
21
23
|
rake_task &block
|
22
24
|
end
|
23
25
|
|
@@ -27,12 +29,29 @@ module PactBroker
|
|
27
29
|
desc "Run sequel migrations for pact broker database"
|
28
30
|
task :migrate, [:target] do | t, args |
|
29
31
|
require 'pact_broker/db/migrate'
|
32
|
+
require 'pact_broker/db/version'
|
33
|
+
|
30
34
|
instance_eval(&block)
|
31
|
-
|
35
|
+
|
32
36
|
if args[:target]
|
33
37
|
options[:target] = args[:target].to_i
|
34
38
|
end
|
39
|
+
|
40
|
+
if (logger = database_connection.loggers.first)
|
41
|
+
current_version = PactBroker::DB::Version.call(database_connection)
|
42
|
+
if options[:target]
|
43
|
+
logger.info "Migrating from schema version #{current_version} to #{options[:target]}"
|
44
|
+
else
|
45
|
+
logger.info "Migrating from schema version #{current_version} to latest"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
35
49
|
PactBroker::DB::Migrate.call(database_connection, options)
|
50
|
+
|
51
|
+
if logger
|
52
|
+
current_version = PactBroker::DB::Version.call(database_connection)
|
53
|
+
logger.info "Current schema version is now #{current_version}"
|
54
|
+
end
|
36
55
|
end
|
37
56
|
end
|
38
57
|
end
|
@@ -12,7 +12,7 @@ module PactBroker
|
|
12
12
|
set :dump_errors, false # The padrino logger logs these for us. If this is enabled we get duplicate logging.
|
13
13
|
|
14
14
|
def base_url
|
15
|
-
PactBroker.configuration.base_url ||
|
15
|
+
PactBroker.configuration.base_url || ''
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
@@ -136,8 +136,8 @@ module PactBroker
|
|
136
136
|
end
|
137
137
|
|
138
138
|
def delete_all_verifications_between(consumer_name, options)
|
139
|
-
consumer = pacticipant_repository.find_by_name(consumer_name)
|
140
|
-
provider = pacticipant_repository.find_by_name(options.fetch(:and))
|
139
|
+
consumer = pacticipant_repository.find_by_name!(consumer_name)
|
140
|
+
provider = pacticipant_repository.find_by_name!(options.fetch(:and))
|
141
141
|
PactBroker::Domain::Verification.where(provider: provider, consumer: consumer).delete
|
142
142
|
end
|
143
143
|
|
data/lib/pact_broker/version.rb
CHANGED
@@ -2,8 +2,10 @@
|
|
2
2
|
"success": true,
|
3
3
|
"providerApplicationVersion": "1.0.0",
|
4
4
|
"testResults": {
|
5
|
-
"
|
5
|
+
"tests": [
|
6
6
|
{
|
7
|
+
"interactionDescription": "a request for something",
|
8
|
+
"interactionProviderState": null,
|
7
9
|
"description": "has status code 200",
|
8
10
|
"file_path": "/redacted/.gem/ruby/2.4.1/gems/pact-1.17.0/lib/pact/provider/rspec.rb",
|
9
11
|
"full_description": "Verifying a pact between me and they Greeting with GET / returns a response which has status code 200",
|
data/script/foo-bar.json
CHANGED
@@ -17,6 +17,17 @@
|
|
17
17
|
"status": 200,
|
18
18
|
"body" : "something"
|
19
19
|
}
|
20
|
+
},{
|
21
|
+
"description" : "a request for something else",
|
22
|
+
"providerState": null,
|
23
|
+
"request": {
|
24
|
+
"method": "get",
|
25
|
+
"path" : "/something"
|
26
|
+
},
|
27
|
+
"response": {
|
28
|
+
"status": 200,
|
29
|
+
"body" : "something"
|
30
|
+
}
|
20
31
|
}
|
21
32
|
]
|
22
33
|
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
describe "Deleting
|
1
|
+
describe "Deleting an integration" do
|
2
2
|
|
3
3
|
let(:path) { "/integrations/provider/Bar/consumer/Foo" }
|
4
4
|
|
@@ -19,7 +19,7 @@ describe "Deleting pact versions" do
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
context "when the
|
22
|
+
context "when the integration does not exist" do
|
23
23
|
it "returns a 404 Not Found" do
|
24
24
|
expect(subject.status).to be 404
|
25
25
|
end
|
@@ -32,5 +32,21 @@ describe "UI index" do
|
|
32
32
|
expect(subject.body.scan('<tr').to_a.count).to eq 3
|
33
33
|
end
|
34
34
|
end
|
35
|
+
|
36
|
+
context "with the base_url not set" do
|
37
|
+
it "returns relative links" do
|
38
|
+
expect(subject.body).to include "href='/stylesheets"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "with the base_url set" do
|
43
|
+
before do
|
44
|
+
allow(PactBroker.configuration).to receive(:base_url).and_return('http://example.org/pact-broker')
|
45
|
+
end
|
46
|
+
|
47
|
+
it "returns absolute links" do
|
48
|
+
expect(subject.body).to include "href='http://example.org/pact-broker/stylesheets"
|
49
|
+
end
|
50
|
+
end
|
35
51
|
end
|
36
52
|
end
|
@@ -31,7 +31,7 @@ describe "UI matrix" do
|
|
31
31
|
subject { get("/matrix?q%5B%5Dpacticipant=Foo&q%5B%5Dtag=ctag&q%5B%5Dlatest=true&q%5B%5Dpacticipant=Bar&q%5B%5Dtag=ptag&q%5B%5Dlatest=true&latestby=cvpv&limit=100") }
|
32
32
|
|
33
33
|
it "returns a page with a badge" do
|
34
|
-
expect(subject.body).to include "
|
34
|
+
expect(subject.body).to include "/matrix/provider/Bar/latest/ptag/consumer/Foo/latest/ctag/badge.svg"
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
@@ -10,7 +10,7 @@ module PactBroker
|
|
10
10
|
|
11
11
|
describe "the number of Reason classes" do
|
12
12
|
it "is 9 - add another spec here if a new Reason is added" do
|
13
|
-
expect(REASON_CLASSES.size).to eq
|
13
|
+
expect(REASON_CLASSES.size).to eq 10
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -52,6 +52,23 @@ module PactBroker
|
|
52
52
|
|
53
53
|
its(:to_s) { is_expected.to eq "All required verification results are published and successful" }
|
54
54
|
end
|
55
|
+
|
56
|
+
context "when the reason is PactBroker::Matrix::InteractionsMissingVerifications" do
|
57
|
+
let(:reason) { PactBroker::Matrix::InteractionsMissingVerifications.new(consumer_selector, provider_selector, interactions) }
|
58
|
+
let(:interactions) do
|
59
|
+
[
|
60
|
+
{
|
61
|
+
"description" => "desc1",
|
62
|
+
"providerState" => "p2"
|
63
|
+
},{
|
64
|
+
"description" => "desc1",
|
65
|
+
"providerStates" => [ { "name" => "desc3"}, { "name" => "desc4"} ]
|
66
|
+
}
|
67
|
+
]
|
68
|
+
end
|
69
|
+
|
70
|
+
its(:to_s) { is_expected.to eq "WARNING: Although the verification was reported as successful, the results for version 2 of Foo and version 6 of Bar may be missing tests for the following interactions: desc1 given p2; desc1 given desc3, desc4" }
|
71
|
+
end
|
55
72
|
end
|
56
73
|
end
|
57
74
|
end
|
@@ -26,6 +26,22 @@ module PactBroker
|
|
26
26
|
subject
|
27
27
|
expect(last_response.body).to include "<html>"
|
28
28
|
end
|
29
|
+
|
30
|
+
context "with the base_url not set" do
|
31
|
+
it "returns relative links" do
|
32
|
+
expect(subject.body).to include "href='/css"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "with the base_url set" do
|
37
|
+
before do
|
38
|
+
allow(PactBroker.configuration).to receive(:base_url).and_return('http://example.org/pact-broker')
|
39
|
+
end
|
40
|
+
|
41
|
+
it "returns absolute links" do
|
42
|
+
expect(subject.body).to include "href='http://example.org/pact-broker/css"
|
43
|
+
end
|
44
|
+
end
|
29
45
|
end
|
30
46
|
|
31
47
|
context "when the resource does not exist" do
|
@@ -248,6 +248,12 @@ module PactBroker
|
|
248
248
|
Service.delete("Foo", "Foo")
|
249
249
|
end
|
250
250
|
end
|
251
|
+
|
252
|
+
context "when the pacticipants are not found for some bizarre reason (I can't see how this can happen, but it has)" do
|
253
|
+
it "raises an error" do
|
254
|
+
expect { Service.delete("Foo", "Bar") }.to raise_error(PactBroker::Error, /found/)
|
255
|
+
end
|
256
|
+
end
|
251
257
|
end
|
252
258
|
|
253
259
|
describe "delete_all" do
|
@@ -29,7 +29,8 @@ module PactBroker
|
|
29
29
|
provider_name: bar.name,
|
30
30
|
provider_id: bar.id,
|
31
31
|
success: row_1_success,
|
32
|
-
pacticipant_names: [foo.name, bar.name]
|
32
|
+
pacticipant_names: [foo.name, bar.name],
|
33
|
+
verification: verification_1
|
33
34
|
)
|
34
35
|
end
|
35
36
|
|
@@ -46,7 +47,8 @@ module PactBroker
|
|
46
47
|
provider_name: baz.name,
|
47
48
|
provider_id: baz.id,
|
48
49
|
success: true,
|
49
|
-
pacticipant_names: [foo.name, baz.name]
|
50
|
+
pacticipant_names: [foo.name, baz.name],
|
51
|
+
verification: verification_2
|
50
52
|
)
|
51
53
|
end
|
52
54
|
|
@@ -65,6 +67,8 @@ module PactBroker
|
|
65
67
|
let(:foo_version) { double('foo version', number: "ddec8101dabf4edf9125a69f9a161f0f294af43c", id: 10)}
|
66
68
|
let(:bar_version) { double('bar version', number: "14131c5da3abf323ccf410b1b619edac76231243", id: 11)}
|
67
69
|
let(:baz_version) { double('baz version', number: "4ee06460f10e8207ad904fa9fa6c4842e462ab59", id: 12)}
|
70
|
+
let(:verification_1) { double('verification 1', interactions_missing_test_results: []) }
|
71
|
+
let(:verification_2) { double('verification 2', interactions_missing_test_results: []) }
|
68
72
|
|
69
73
|
let(:resolved_selectors) do
|
70
74
|
[
|
@@ -416,6 +416,49 @@ module PactBroker
|
|
416
416
|
expect(subject.deployment_status_summary).to be_deployable
|
417
417
|
end
|
418
418
|
end
|
419
|
+
|
420
|
+
describe "when verification results are published missing tests for some interactions" do
|
421
|
+
let(:pact_content) do
|
422
|
+
{
|
423
|
+
"interactions" => [
|
424
|
+
{
|
425
|
+
"description" => "desc1"
|
426
|
+
},{
|
427
|
+
"description" => "desc2"
|
428
|
+
}
|
429
|
+
]
|
430
|
+
}
|
431
|
+
end
|
432
|
+
|
433
|
+
let(:verification_tests) do
|
434
|
+
[
|
435
|
+
{
|
436
|
+
"interactionDescription" => "desc1"
|
437
|
+
}
|
438
|
+
]
|
439
|
+
end
|
440
|
+
|
441
|
+
before do
|
442
|
+
td.create_consumer("Foo")
|
443
|
+
.create_provider("Bar")
|
444
|
+
.create_consumer_version
|
445
|
+
.create_pact(json_content: pact_content.to_json)
|
446
|
+
.create_verification(provider_version: "1", test_results: { tests: verification_tests })
|
447
|
+
end
|
448
|
+
|
449
|
+
let(:selectors) do
|
450
|
+
[
|
451
|
+
UnresolvedSelector.new(pacticipant_name: "Foo", latest: true),
|
452
|
+
UnresolvedSelector.new(pacticipant_name: "Bar", latest: true)
|
453
|
+
]
|
454
|
+
end
|
455
|
+
|
456
|
+
let(:options) { { latestby: "cvpv"} }
|
457
|
+
|
458
|
+
it "should include a warning" do
|
459
|
+
expect(subject.deployment_status_summary.reasons.last).to be_a(PactBroker::Matrix::InteractionsMissingVerifications)
|
460
|
+
end
|
461
|
+
end
|
419
462
|
end
|
420
463
|
end
|
421
464
|
end
|
@@ -227,6 +227,131 @@ module PactBroker
|
|
227
227
|
its(:pact_specification_version) { is_expected.to eq nil }
|
228
228
|
end
|
229
229
|
end
|
230
|
+
|
231
|
+
describe "with_test_results" do
|
232
|
+
let(:test_results) do
|
233
|
+
{
|
234
|
+
"tests" => [
|
235
|
+
{
|
236
|
+
"interactionProviderState" => "ps1",
|
237
|
+
"interactionDescription" => "desc1"
|
238
|
+
},{
|
239
|
+
"interactionProviderState" => "ps1",
|
240
|
+
"interactionDescription" => "desc1"
|
241
|
+
}
|
242
|
+
]
|
243
|
+
}
|
244
|
+
end
|
245
|
+
|
246
|
+
let(:pact_content) do
|
247
|
+
{
|
248
|
+
"interactions" => [
|
249
|
+
{
|
250
|
+
"providerState" => "ps1",
|
251
|
+
"description" => "desc1",
|
252
|
+
},
|
253
|
+
{
|
254
|
+
"providerState" => "ps2",
|
255
|
+
"description" => "desc2",
|
256
|
+
}
|
257
|
+
]
|
258
|
+
}
|
259
|
+
end
|
260
|
+
|
261
|
+
subject { Content.from_hash(pact_content).with_test_results(test_results) }
|
262
|
+
|
263
|
+
let(:merged) do
|
264
|
+
{
|
265
|
+
"interactions" => [
|
266
|
+
{
|
267
|
+
"providerState" => "ps1",
|
268
|
+
"description" => "desc1",
|
269
|
+
"tests" => [
|
270
|
+
{
|
271
|
+
"interactionProviderState" => "ps1",
|
272
|
+
"interactionDescription" => "desc1",
|
273
|
+
},{
|
274
|
+
"interactionProviderState" => "ps1",
|
275
|
+
"interactionDescription" => "desc1",
|
276
|
+
}
|
277
|
+
]
|
278
|
+
},{
|
279
|
+
"providerState" => "ps2",
|
280
|
+
"description" => "desc2",
|
281
|
+
"tests" => []
|
282
|
+
}
|
283
|
+
]
|
284
|
+
}
|
285
|
+
end
|
286
|
+
|
287
|
+
let(:merged_with_empty_tests) do
|
288
|
+
{
|
289
|
+
"interactions" => [
|
290
|
+
{
|
291
|
+
"providerState" => "ps1",
|
292
|
+
"description" => "desc1",
|
293
|
+
"tests" => []
|
294
|
+
},{
|
295
|
+
"providerState" => "ps2",
|
296
|
+
"description" => "desc2",
|
297
|
+
"tests" => []
|
298
|
+
}
|
299
|
+
]
|
300
|
+
}
|
301
|
+
end
|
302
|
+
|
303
|
+
it "merges the contents with the results" do
|
304
|
+
expect(subject.to_hash).to eq merged
|
305
|
+
end
|
306
|
+
|
307
|
+
it "returns interactions without test results" do
|
308
|
+
expect(subject.interactions_missing_test_results.count).to eq 1
|
309
|
+
end
|
310
|
+
|
311
|
+
context "with nil test results" do
|
312
|
+
let(:test_results) { nil }
|
313
|
+
|
314
|
+
it "does not blow up" do
|
315
|
+
expect(subject.to_hash).to eq merged_with_empty_tests
|
316
|
+
end
|
317
|
+
|
318
|
+
it "returns interactions without test results" do
|
319
|
+
expect(subject.interactions_missing_test_results.count).to eq 2
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
context "with nil tests" do
|
324
|
+
let(:test_results) { {} }
|
325
|
+
|
326
|
+
it "does not blow up" do
|
327
|
+
expect(subject.to_hash).to eq merged_with_empty_tests
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
context "with empty tests" do
|
332
|
+
let(:test_results) { { "tests" => [] } }
|
333
|
+
|
334
|
+
it "does not blow up" do
|
335
|
+
expect(subject.to_hash).to eq merged_with_empty_tests
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
context "with tests not an array" do
|
340
|
+
let(:test_results) { { "tests" => {} } }
|
341
|
+
|
342
|
+
it "does not blow up" do
|
343
|
+
expect(subject.to_hash).to eq merged_with_empty_tests
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
context "with tests an array of not hashes" do
|
348
|
+
let(:test_results) { { "tests" => [1] } }
|
349
|
+
|
350
|
+
it "does not blow up" do
|
351
|
+
expect(subject.to_hash).to eq merged_with_empty_tests
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
230
355
|
end
|
231
356
|
end
|
232
357
|
end
|
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.56.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-
|
13
|
+
date: 2020-06-01 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: httparty
|