pact_broker 2.55.0 → 2.56.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|