pact_broker 2.16.1 → 2.17.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE.md +22 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +9 -0
- data/CHANGELOG.md +28 -0
- data/DEVELOPER_DOCUMENTATION.md +5 -0
- data/db/migrations/000046_recreate_latest_verifications.rb +2 -2
- data/db/migrations/20180311_optimise_head_matrix.rb +80 -0
- data/db/migrations/20180315_create_verification_sequence.rb +14 -0
- data/db/migrations/migration_helper.rb +1 -1
- data/lib/db.rb +3 -2
- data/lib/pact_broker/api/resources/base_resource.rb +10 -13
- data/lib/pact_broker/api/resources/error_handler.rb +30 -0
- data/lib/pact_broker/api/resources/pact.rb +6 -1
- data/lib/pact_broker/api/resources/pacticipant.rb +8 -2
- data/lib/pact_broker/api/resources/tag.rb +4 -2
- data/lib/pact_broker/api/resources/verifications.rb +5 -1
- data/lib/pact_broker/api/resources/version.rb +3 -1
- data/lib/pact_broker/api.rb +1 -1
- data/lib/pact_broker/config/load.rb +1 -0
- data/lib/pact_broker/configuration.rb +16 -0
- data/lib/pact_broker/matrix/head_row.rb +19 -0
- data/lib/pact_broker/matrix/repository.rb +39 -2
- data/lib/pact_broker/matrix/row.rb +16 -28
- data/lib/pact_broker/matrix/service.rb +6 -2
- data/lib/pact_broker/pacticipants/service.rb +1 -0
- data/lib/pact_broker/ui/controllers/base_controller.rb +2 -1
- data/lib/pact_broker/ui/controllers/error_test.rb +0 -1
- data/lib/pact_broker/ui/controllers/matrix.rb +3 -4
- data/lib/pact_broker/ui/view_models/matrix_line.rb +6 -0
- data/lib/pact_broker/ui/views/matrix/show.haml +14 -10
- data/lib/pact_broker/ui.rb +6 -6
- data/lib/pact_broker/verifications/repository.rb +9 -4
- data/lib/pact_broker/verifications/sequence.rb +34 -0
- data/lib/pact_broker/verifications/service.rb +2 -2
- data/lib/pact_broker/version.rb +1 -1
- data/lib/webmachine/convert_request_to_rack_env.rb +37 -0
- data/script/publish.sh +13 -2
- data/script/recreate-mysql-db.sh +2 -1
- data/script/seed-matrix.rb +1 -1
- data/spec/features/publish_verification_spec.rb +0 -1
- data/spec/features/update_matrix_spec.rb +146 -0
- data/spec/fixtures/foo-bar.json +22 -0
- data/spec/lib/pact_broker/api/resources/error_handler_spec.rb +55 -0
- data/spec/lib/pact_broker/api/resources/verifications_spec.rb +1 -1
- data/spec/lib/pact_broker/configuration_spec.rb +19 -1
- data/spec/lib/pact_broker/matrix/head_row_spec.rb +52 -0
- data/spec/lib/pact_broker/matrix/repository_spec.rb +20 -0
- data/spec/lib/pact_broker/matrix/row_spec.rb +10 -10
- data/spec/lib/pact_broker/pacticipants/service_spec.rb +1 -0
- data/spec/lib/pact_broker/verifications/repository_spec.rb +0 -29
- data/spec/lib/pact_broker/verifications/sequence_spec.rb +47 -0
- data/spec/lib/pact_broker/verifications/service_spec.rb +0 -13
- data/spec/lib/webmachine/convert_request_to_rack_env_spec.rb +68 -0
- data/spec/support/test_data_builder.rb +2 -0
- data/tasks/development.rake +10 -0
- metadata +22 -2
@@ -10,11 +10,10 @@ module PactBroker
|
|
10
10
|
class Matrix < Base
|
11
11
|
|
12
12
|
include PactBroker::Services
|
13
|
-
include PactBroker::Logging
|
14
13
|
|
15
14
|
get "/" do
|
16
15
|
selectors = [OpenStruct.new, OpenStruct.new]
|
17
|
-
options = { limit: 100, latestby:
|
16
|
+
options = { limit: 100, latestby: nil }
|
18
17
|
locals = {
|
19
18
|
lines: [],
|
20
19
|
title: "The Matrix",
|
@@ -35,7 +34,7 @@ module PactBroker
|
|
35
34
|
end
|
36
35
|
end
|
37
36
|
rescue StandardError => e
|
38
|
-
|
37
|
+
Padrino.logger.exception(e) unless e.is_a?(PactBroker::Error)
|
39
38
|
locals[:errors] = [e.message]
|
40
39
|
end
|
41
40
|
haml :'matrix/show', {locals: locals, layout: :'layouts/main'}
|
@@ -43,7 +42,7 @@ module PactBroker
|
|
43
42
|
|
44
43
|
get "/provider/:provider_name/consumer/:consumer_name" do
|
45
44
|
selectors = [{ pacticipant_name: params[:consumer_name] }, { pacticipant_name: params[:provider_name] } ]
|
46
|
-
options = {latestby:
|
45
|
+
options = {latestby: nil, limit: 100}
|
47
46
|
lines = matrix_service.find(selectors, options)
|
48
47
|
lines = PactBroker::UI::ViewDomain::MatrixLines.new(lines)
|
49
48
|
locals = {
|
@@ -175,6 +175,12 @@ module PactBroker
|
|
175
175
|
def overwritten= overwritten
|
176
176
|
@overwritten = overwritten
|
177
177
|
end
|
178
|
+
|
179
|
+
def inherited_verification_message
|
180
|
+
if @line[:verification_executed_at] && @line[:pact_created_at] > @line[:verification_executed_at]
|
181
|
+
"The verification date is before the pact publication date because this verification has been inherited from a previously verified pact with identical content."
|
182
|
+
end
|
183
|
+
end
|
178
184
|
end
|
179
185
|
end
|
180
186
|
end
|
@@ -53,6 +53,11 @@
|
|
53
53
|
%input{name: 'q[]latest', value: 'true', hidden: true, class: 'latest-flag'}
|
54
54
|
|
55
55
|
%div.top-of-group
|
56
|
+
.input-group
|
57
|
+
%input{type: 'radio', name: "latestby", class: '', value: '', id: 'all_rows', checked: options.all_rows_checked}
|
58
|
+
%label{for: 'all_rows'}
|
59
|
+
Show all results
|
60
|
+
%div
|
56
61
|
.input-group
|
57
62
|
%input{type: 'radio', name: "latestby", class: '', value: 'cvpv', id: 'cvpv', checked: options.cvpv_checked}
|
58
63
|
%label{for: 'cvpv'}
|
@@ -62,14 +67,10 @@
|
|
62
67
|
%input{type: 'radio', name: "latestby", class: '', value: 'cvp', id: 'cvp', checked: options.cvp_checked}
|
63
68
|
%label{for: 'cvp'}
|
64
69
|
Show latest result for each consumer version/provider
|
65
|
-
%div
|
66
|
-
.input-group
|
67
|
-
%input{type: 'radio', name: "latestby", class: '', value: '', id: 'all_rows', checked: options.all_rows_checked}
|
68
|
-
%label{for: 'all_rows'}
|
69
|
-
Show all results
|
70
70
|
%div.top-of-group
|
71
|
-
|
72
|
-
|
71
|
+
- limit_text = "Note that the 'Show latest...' options are summaries of the 'Show all results' query, and that the limit applies to the underlying query, rather than the number of rows returned in the summary."
|
72
|
+
%label{for: "limit", "title": limit_text, "data-toggle": "tooltip", "data-placement": "right"}
|
73
|
+
Limit*
|
73
74
|
%input{name: 'limit', id: "limit", value: options.limit}
|
74
75
|
%div.top-of-group
|
75
76
|
%input{type: 'submit'}
|
@@ -117,7 +118,7 @@
|
|
117
118
|
%a{href: tag.url}
|
118
119
|
.tag.label.label-default
|
119
120
|
= tag.name
|
120
|
-
%td.pact-published{'data-sort-value' => line.pact_published_order}
|
121
|
+
%td.pact-published{'data-sort-value' => line.pact_published_order, "title": line.inherited_verification_message, "data-toggle": "tooltip"}
|
121
122
|
%a{href: line.pact_publication_date_url}
|
122
123
|
- if options.all_rows_checked
|
123
124
|
= "#{line.pact_publication_date} (revision #{line.pact_revision_number})"
|
@@ -141,6 +142,9 @@
|
|
141
142
|
%a{href: tag.url}
|
142
143
|
.tag.label.label-default
|
143
144
|
= tag.name
|
144
|
-
%td.verification-result{class: line.verification_status_class}
|
145
|
+
%td.verification-result{class: line.verification_status_class, "title": line.inherited_verification_message, "data-toggle": "tooltip"}
|
145
146
|
%a{href: line.verification_status_url}
|
146
|
-
|
147
|
+
- if options.all_rows_checked
|
148
|
+
= "#{line.verification_status} (number #{line.number})"
|
149
|
+
- else
|
150
|
+
= line.verification_status
|
data/lib/pact_broker/ui.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
|
-
|
1
|
+
require 'pact_broker/configuration'
|
2
2
|
# Stop Padrino creating a log file, as it will try to create it in the gems directory
|
3
3
|
# http://www.padrinorb.com/api/Padrino/Logger.html
|
4
4
|
unless defined? PADRINO_LOGGER
|
5
|
+
log_path = File.join(PactBroker.configuration.log_dir, 'ui.log')
|
5
6
|
PADRINO_LOGGER = {
|
6
|
-
production: { log_level: :error, stream: :
|
7
|
-
staging: { log_level: :error, stream: :
|
8
|
-
test: { log_level: :warn, stream: :
|
9
|
-
development: { log_level: :warn, stream: :
|
7
|
+
production: { log_level: :error, stream: :to_file, log_path: log_path },
|
8
|
+
staging: { log_level: :error, stream: :to_file, log_path: log_path },
|
9
|
+
test: { log_level: :warn, stream: :to_file, log_path: log_path },
|
10
|
+
development: { log_level: :warn, stream: :to_file, log_path: log_path }
|
10
11
|
}
|
11
12
|
end
|
12
13
|
|
13
14
|
require 'pact_broker/ui/app'
|
14
|
-
|
@@ -2,6 +2,7 @@ require 'sequel'
|
|
2
2
|
require 'pact_broker/domain/verification'
|
3
3
|
require 'pact_broker/verifications/latest_verifications_by_consumer_version'
|
4
4
|
require 'pact_broker/verifications/all_verifications'
|
5
|
+
require 'pact_broker/verifications/sequence'
|
5
6
|
|
6
7
|
module PactBroker
|
7
8
|
module Verifications
|
@@ -10,6 +11,14 @@ module PactBroker
|
|
10
11
|
include PactBroker::Repositories::Helpers
|
11
12
|
include PactBroker::Repositories
|
12
13
|
|
14
|
+
# Ideally this would just be a sequence, but Sqlite and MySQL don't support sequences
|
15
|
+
# in the way we need to use them ie. determining what the next number will be before we
|
16
|
+
# create the record, because Webmachine wants to set the URL of the resource that is about
|
17
|
+
# to be created *before* we actually create it.
|
18
|
+
def next_number
|
19
|
+
Sequence.next_val
|
20
|
+
end
|
21
|
+
|
13
22
|
def create verification, provider_version_number, pact
|
14
23
|
provider = pacticipant_repository.find_by_name(pact.provider_name)
|
15
24
|
version = version_repository.find_by_pacticipant_id_and_number_or_create(provider.id, provider_version_number)
|
@@ -18,10 +27,6 @@ module PactBroker
|
|
18
27
|
verification.save
|
19
28
|
end
|
20
29
|
|
21
|
-
def verification_count_for_pact pact
|
22
|
-
PactBroker::Domain::Verification.where(pact_version_id: pact_version_id_for(pact)).count
|
23
|
-
end
|
24
|
-
|
25
30
|
def find consumer_name, provider_name, pact_version_sha, verification_number
|
26
31
|
PactBroker::Domain::Verification
|
27
32
|
.select_all_qualified
|
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
require 'sequel'
|
3
|
+
|
4
|
+
module PactBroker
|
5
|
+
module Verifications
|
6
|
+
class Sequence < Sequel::Model(:verification_sequence_number)
|
7
|
+
|
8
|
+
dataset_module do
|
9
|
+
# The easiest way to implement a cross database compatible sequence.
|
10
|
+
# Sad, I know.
|
11
|
+
def next_val
|
12
|
+
db.transaction do
|
13
|
+
for_update.first
|
14
|
+
select_all.update(value: Sequel[:value]+1)
|
15
|
+
row = first
|
16
|
+
if row
|
17
|
+
row.value
|
18
|
+
else
|
19
|
+
# The first row should have been created in the migration, so this code
|
20
|
+
# should only ever be executed in a test context.
|
21
|
+
# There would be a risk of a race condition creating two rows if this
|
22
|
+
# code executed in prod, as I don't think you can lock an empty table
|
23
|
+
# to prevent another record being inserted.
|
24
|
+
max_verification_number = PactBroker::Domain::Verification.max(:number)
|
25
|
+
value = max_verification_number ? max_verification_number + 100 : 1
|
26
|
+
insert(value: value)
|
27
|
+
value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -12,8 +12,8 @@ module PactBroker
|
|
12
12
|
extend PactBroker::Repositories
|
13
13
|
extend PactBroker::Services
|
14
14
|
|
15
|
-
def
|
16
|
-
verification_repository.
|
15
|
+
def next_number
|
16
|
+
verification_repository.next_number
|
17
17
|
end
|
18
18
|
|
19
19
|
def create next_verification_number, params, pact
|
data/lib/pact_broker/version.rb
CHANGED
@@ -0,0 +1,37 @@
|
|
1
|
+
module Webmachine
|
2
|
+
class ConvertRequestToRackEnv
|
3
|
+
def self.call(request)
|
4
|
+
env = {
|
5
|
+
'REQUEST_METHOD' => request.method.upcase,
|
6
|
+
'CONTENT_TYPE' => request.headers['Content-Type'],
|
7
|
+
'PATH_INFO' => request.uri.path,
|
8
|
+
'QUERY_STRING' => request.uri.query || "",
|
9
|
+
'SERVER_NAME' => request.uri.host,
|
10
|
+
'SERVER_PORT' => request.uri.port.to_s,
|
11
|
+
'SCRIPT_NAME' => '',
|
12
|
+
'rack.url_scheme' => request.uri.scheme,
|
13
|
+
'rack.input' => request.body.to_io ? StringIO.new(request.body.to_s) : nil
|
14
|
+
}.merge(convert_headers(request))
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.convert_headers(request)
|
18
|
+
request.headers.each_with_object({}) do | (key, value), env |
|
19
|
+
v = redact?(key) ? '[Filtered]' : value
|
20
|
+
env[convert_http_header_name_to_rack_header_name(key)] = v
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.redact?(http_header_name)
|
25
|
+
lower = http_header_name.downcase
|
26
|
+
lower == 'authorization' || lower.include?('token')
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.convert_http_header_name_to_rack_header_name(http_header_name)
|
30
|
+
if http_header_name.downcase == 'content-type' || http_header_name.downcase == 'content-length'
|
31
|
+
http_header_name.upcase.gsub('-', '_')
|
32
|
+
else
|
33
|
+
"HTTP_" + http_header_name.upcase.gsub('-', '_')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/script/publish.sh
CHANGED
@@ -1,4 +1,15 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
function finish {
|
3
|
+
rm -rf tmp/pact.json
|
4
|
+
}
|
5
|
+
trap finish EXIT
|
6
|
+
|
7
|
+
consumer=${1:-Foo}
|
8
|
+
provider=${2:-Bar}
|
9
|
+
echo $consumer $provider
|
10
|
+
body=$(cat script/foo-bar.json | sed "s/Foo/${consumer}/" | sed "s/Bar/${provider}/")
|
11
|
+
echo $body > tmp/pact.json
|
1
12
|
curl -v -XPUT \-H "Content-Type: application/json" \
|
2
|
-
-d@
|
3
|
-
http://127.0.0.1:9292/pacts/provider/
|
13
|
+
-d@tmp/pact.json \
|
14
|
+
http://127.0.0.1:9292/pacts/provider/${provider}/consumer/${consumer}/version/1.0.0
|
4
15
|
echo ""
|
data/script/recreate-mysql-db.sh
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
SCHEMA="pact_broker"
|
2
2
|
set -e
|
3
|
-
mysql mysql -h localhost -u root -e "select 'drop table "' || tablename || '" cascade;' from pg_tables;'"
|
3
|
+
# mysql mysql -h localhost -u root -e "select 'drop table "' || tablename || '" cascade;' from pg_tables;'"
|
4
|
+
mysql mysql -h localhost -u root -e 'DROP DATABASE pact_broker;'
|
4
5
|
mysql mysql -h localhost -u root -e 'CREATE DATABASE pact_broker;'
|
5
6
|
mysql mysql -h localhost -u root -e "GRANT ALL ON pact_broker.* TO 'pact_broker'@'%' identified by 'pact_broker';"
|
6
7
|
|
data/script/seed-matrix.rb
CHANGED
@@ -41,7 +41,7 @@ A -> B -> C
|
|
41
41
|
TestDataBuilder.new
|
42
42
|
.create_pact_with_hierarchy("A", "1", "B")
|
43
43
|
.create_consumer_version_tag("master")
|
44
|
-
.create_verification(provider_version: '1', success: false)
|
44
|
+
.create_verification(provider_version: '1', success: false, execution_date: Date.today - 1 )
|
45
45
|
.create_verification(provider_version: '1', number: 2, success: true)
|
46
46
|
.create_verification(provider_version: '2', number: 3)
|
47
47
|
.create_verification(provider_version: '4', number: 4)
|
@@ -0,0 +1,146 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
Things that should update the matrix (ignoring tags):
|
4
|
+
* pact created
|
5
|
+
* pact content updated
|
6
|
+
* pact deleted
|
7
|
+
* verification created
|
8
|
+
* verification deleted (not yet implemented)
|
9
|
+
|
10
|
+
It's easier to update the matrix at the resource level, so we actually update the matrix when:
|
11
|
+
* pacticipant deleted
|
12
|
+
* version deleted
|
13
|
+
* pact deleted
|
14
|
+
|
15
|
+
Things that should update the head matrix
|
16
|
+
* All of the above
|
17
|
+
* tag created
|
18
|
+
* tag deleted
|
19
|
+
|
20
|
+
=end
|
21
|
+
|
22
|
+
describe "Deleting a resource that affects the matrix" do
|
23
|
+
|
24
|
+
let(:td) { TestDataBuilder.new }
|
25
|
+
let(:response_body_json) { JSON.parse(subject.body) }
|
26
|
+
|
27
|
+
subject { delete path; last_response }
|
28
|
+
|
29
|
+
before do
|
30
|
+
td.create_pact_with_hierarchy("Foo", "1", "Bar")
|
31
|
+
.create_verification(provider_version: "2")
|
32
|
+
end
|
33
|
+
|
34
|
+
context "deleting a pact" do
|
35
|
+
let(:path) { "/pacts/provider/Bar/consumer/Foo/version/1" }
|
36
|
+
|
37
|
+
it "deletes the relevant lines from the matrix" do
|
38
|
+
expect{ subject }.to change{ PactBroker::Matrix::Row.count }.by(-1)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "deletes the relevant lines from the head matrix" do
|
42
|
+
expect{ subject }.to change{ PactBroker::Matrix::HeadRow.count }.by(-1)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "deleting a pacticipant" do
|
47
|
+
let(:path) { "/pacticipants/Bar" }
|
48
|
+
|
49
|
+
it "deletes the relevant lines from the matrix" do
|
50
|
+
expect{ subject }.to change{ PactBroker::Matrix::Row.count }.by(-1)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "deletes the relevant lines from the head matrix" do
|
54
|
+
expect{ subject }.to change{ PactBroker::Matrix::HeadRow.count }.by(-1)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context "deleting a version" do
|
59
|
+
let(:path) { "/pacticipants/Foo/versions/1" }
|
60
|
+
|
61
|
+
it "deletes the relevant lines from the matrix" do
|
62
|
+
expect{ subject }.to change{ PactBroker::Matrix::Row.count }.by(-1)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "deletes the relevant lines from the head matrix" do
|
66
|
+
expect{ subject }.to change{ PactBroker::Matrix::HeadRow.count }.by(-1)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context "deleting a tag" do
|
71
|
+
before do
|
72
|
+
td.create_consumer_version_tag("prod")
|
73
|
+
end
|
74
|
+
|
75
|
+
let(:path) { "/pacticipants/Foo/versions/1/tags/prod" }
|
76
|
+
|
77
|
+
it "does not delete any lines from the matrix" do
|
78
|
+
expect{ subject }.to change{ PactBroker::Matrix::Row.count }.by(0)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "deletes the relevant lines from the head matrix" do
|
82
|
+
expect{ subject }.to change{ PactBroker::Matrix::HeadRow.count }.by(-1)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "Creating a resource that affects the matrix" do
|
88
|
+
|
89
|
+
let(:td) { TestDataBuilder.new }
|
90
|
+
let(:response_body_json) { JSON.parse(subject.body) }
|
91
|
+
|
92
|
+
subject { put(path, nil, {'CONTENT_TYPE' => 'application/json'}); last_response }
|
93
|
+
|
94
|
+
context "creating a tag" do
|
95
|
+
before do
|
96
|
+
td.create_pact_with_hierarchy("Foo", "1", "Bar")
|
97
|
+
end
|
98
|
+
|
99
|
+
let(:path) { "/pacticipants/Foo/versions/1/tags/prod" }
|
100
|
+
|
101
|
+
it "adds the relevant lines to the head matrix" do
|
102
|
+
expect{ subject }.to change{ PactBroker::Matrix::HeadRow.count }.by(1)
|
103
|
+
end
|
104
|
+
|
105
|
+
it "does not add any lines to the matrix" do
|
106
|
+
expect{ subject }.to change{ PactBroker::Matrix::Row.count }.by(0)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context "creating a pact" do
|
111
|
+
let(:pact_content) { load_fixture('foo-bar.json') }
|
112
|
+
let(:path) { "/pacts/provider/Bar/consumer/Foo/versions/1.2.3" }
|
113
|
+
|
114
|
+
subject { put path, pact_content, {'CONTENT_TYPE' => 'application/json'}; last_response }
|
115
|
+
|
116
|
+
it "adds the relevant lines to the matrix" do
|
117
|
+
expect{ subject }.to change{ PactBroker::Matrix::Row.count }.by(1)
|
118
|
+
end
|
119
|
+
|
120
|
+
it "adds the relevant lines to the head matrix" do
|
121
|
+
expect{ subject }.to change{ PactBroker::Matrix::HeadRow.count }.by(1)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
context "creating a verification" do
|
126
|
+
let(:td) { TestDataBuilder.new }
|
127
|
+
let(:path) { "/pacts/provider/Bar/consumer/Foo/pact-version/#{pact.pact_version_sha}/verification-results" }
|
128
|
+
let(:verification_content) { load_fixture('verification.json') }
|
129
|
+
let(:parsed_response_body) { JSON.parse(subject.body) }
|
130
|
+
let(:pact) { td.pact }
|
131
|
+
|
132
|
+
subject { post path, verification_content, {'CONTENT_TYPE' => 'application/json' }; last_response }
|
133
|
+
|
134
|
+
before do
|
135
|
+
td.create_pact_with_hierarchy("Foo", "1", "Bar")
|
136
|
+
end
|
137
|
+
|
138
|
+
it "updates the relevant lines in the matrix" do
|
139
|
+
expect{ subject }.to change{ PactBroker::Matrix::Row.first.provider_version_number }.from(nil).to("4.5.6")
|
140
|
+
end
|
141
|
+
|
142
|
+
it "updates the relevant lines in the head matrix" do
|
143
|
+
expect{ subject }.to change{ PactBroker::Matrix::HeadRow.first.provider_version_number }.from(nil).to("4.5.6")
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
{
|
2
|
+
"consumer": {
|
3
|
+
"name": "Foo"
|
4
|
+
},
|
5
|
+
"provider": {
|
6
|
+
"name": "Bar"
|
7
|
+
},
|
8
|
+
"interactions": [
|
9
|
+
{
|
10
|
+
"description" : "a request for something",
|
11
|
+
"providerState": null,
|
12
|
+
"request": {
|
13
|
+
"method": "get",
|
14
|
+
"path" : "/something"
|
15
|
+
},
|
16
|
+
"response": {
|
17
|
+
"status": 200,
|
18
|
+
"body" : "something"
|
19
|
+
}
|
20
|
+
}
|
21
|
+
]
|
22
|
+
}
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'pact_broker/api/resources/error_handler'
|
2
|
+
|
3
|
+
module PactBroker
|
4
|
+
module Api
|
5
|
+
module Resources
|
6
|
+
describe ErrorHandler do
|
7
|
+
describe "call" do
|
8
|
+
let(:error) { PactBroker::Error.new('test error') }
|
9
|
+
let(:thing) { double('thing', call: nil, another_call: nil) }
|
10
|
+
let(:options) { { env: env } }
|
11
|
+
let(:request) { double('request' ) }
|
12
|
+
let(:response) { double('response', :body= => nil) }
|
13
|
+
let(:env) { double('env') }
|
14
|
+
|
15
|
+
subject { ErrorHandler.call(error, request, response) }
|
16
|
+
|
17
|
+
before do
|
18
|
+
allow(Webmachine::ConvertRequestToRackEnv).to receive(:call).and_return(env)
|
19
|
+
PactBroker.configuration.add_api_error_reporter do | error, options |
|
20
|
+
thing.call(error, options)
|
21
|
+
end
|
22
|
+
|
23
|
+
PactBroker.configuration.add_api_error_reporter do | error, options |
|
24
|
+
thing.another_call(error, options)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it "invokes the api error reporters" do
|
29
|
+
expect(thing).to receive(:call).with(error, options)
|
30
|
+
expect(thing).to receive(:another_call).with(error, options)
|
31
|
+
subject
|
32
|
+
end
|
33
|
+
|
34
|
+
context "when the error reporter raises an error itself" do
|
35
|
+
class TestError < StandardError; end
|
36
|
+
|
37
|
+
before do
|
38
|
+
expect(thing).to receive(:call).and_raise(TestError.new)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "logs the error" do
|
42
|
+
expect(PactBroker.logger).to receive(:error).at_least(1).times
|
43
|
+
subject
|
44
|
+
end
|
45
|
+
|
46
|
+
it "does not propagate the error" do
|
47
|
+
expect(thing).to receive(:another_call)
|
48
|
+
subject
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -46,7 +46,7 @@ module PactBroker
|
|
46
46
|
|
47
47
|
before do
|
48
48
|
allow(Pacts::Service).to receive(:find_pact).and_return(pact)
|
49
|
-
allow(PactBroker::Verifications::Service).to receive(:
|
49
|
+
allow(PactBroker::Verifications::Service).to receive(:next_number).and_return(next_verification_number)
|
50
50
|
allow(PactBroker::Api::Decorators::VerificationDecorator).to receive(:new).and_return(decorator)
|
51
51
|
end
|
52
52
|
|
@@ -40,7 +40,7 @@ module PactBroker
|
|
40
40
|
end
|
41
41
|
|
42
42
|
describe "load_from_database!" do
|
43
|
-
let(:configuration) { PactBroker::Configuration.new}
|
43
|
+
let(:configuration) { PactBroker::Configuration.new }
|
44
44
|
|
45
45
|
before do
|
46
46
|
PactBroker::Config::Setting.create(name: 'use_case_sensitive_resource_names', type: 'string', value: 'foo')
|
@@ -51,6 +51,24 @@ module PactBroker
|
|
51
51
|
expect(configuration.use_case_sensitive_resource_names).to eq "foo"
|
52
52
|
end
|
53
53
|
end
|
54
|
+
|
55
|
+
describe "add_api_error_reporter" do
|
56
|
+
let(:configuration) { PactBroker::Configuration.new }
|
57
|
+
let(:block) { Proc.new{ | error, options | } }
|
58
|
+
|
59
|
+
it "should add the error notifier " do
|
60
|
+
configuration.add_api_error_reporter(&block)
|
61
|
+
expect(configuration.api_error_reporters.first).to eq block
|
62
|
+
end
|
63
|
+
|
64
|
+
context "with a proc with the wrong number of arguments" do
|
65
|
+
let(:block) { Proc.new{ | error | } }
|
66
|
+
|
67
|
+
it "raises an error" do
|
68
|
+
expect { configuration.add_api_error_reporter(&block) }.to raise_error PactBroker::ConfigurationError
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
54
72
|
end
|
55
73
|
end
|
56
74
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'pact_broker/matrix/head_row'
|
2
|
+
|
3
|
+
module PactBroker
|
4
|
+
module Matrix
|
5
|
+
describe HeadRow do
|
6
|
+
describe "refresh", migration: true do
|
7
|
+
before do
|
8
|
+
PactBroker::Database.migrate
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:td) { TestDataBuilder.new(auto_refresh_matrix: false) }
|
12
|
+
|
13
|
+
before do
|
14
|
+
td.create_pact_with_hierarchy("Foo", "1", "Bar")
|
15
|
+
end
|
16
|
+
|
17
|
+
context "with a consumer pacticipant_id and a consumer tag_name" do
|
18
|
+
before do
|
19
|
+
td.create_consumer_version_tag("prod")
|
20
|
+
Row.refresh(ids)
|
21
|
+
end
|
22
|
+
let(:ids) { { pacticipant_id: td.consumer.id, tag_name: "prod"} }
|
23
|
+
|
24
|
+
subject { HeadRow.refresh(ids) }
|
25
|
+
|
26
|
+
it "refreshes the data for the consumer and consumer tag in the head matrix" do
|
27
|
+
subject
|
28
|
+
expect(HeadRow.all.collect(&:values)).to contain_hash(provider_name: "Bar", consumer_name: "Foo", consumer_version_tag_name: "prod")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "with a provider pacticipant_id and a provider tag_name" do
|
33
|
+
before do
|
34
|
+
td.create_verification(provider_version: "2")
|
35
|
+
.use_provider_version("2")
|
36
|
+
.create_provider_version_tag("prod")
|
37
|
+
Row.refresh(ids)
|
38
|
+
end
|
39
|
+
|
40
|
+
let(:ids) { { pacticipant_id: td.consumer.id, tag_name: "prod" } }
|
41
|
+
|
42
|
+
subject { HeadRow.refresh(ids) }
|
43
|
+
|
44
|
+
it "does not update the head matrix as the head matrix only contains consumer tags" do
|
45
|
+
subject
|
46
|
+
expect(HeadRow.count).to eq 0
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -19,6 +19,26 @@ module PactBroker
|
|
19
19
|
rows.collect{ |r| shorten_row(r) }
|
20
20
|
end
|
21
21
|
|
22
|
+
describe "refresh" do
|
23
|
+
before do
|
24
|
+
td.create_pact_with_hierarchy("Foo", "1", "Bar")
|
25
|
+
Row.refresh(pacticipant_id: td.provider.id)
|
26
|
+
end
|
27
|
+
|
28
|
+
context "when deleting an object in the block" do
|
29
|
+
it "removes the relevant lines from the matrix" do
|
30
|
+
expect(Row.count).to_not eq 0
|
31
|
+
Repository.new.refresh(pacticipant_name: "Bar") { PactBroker::Pacticipants::Service.delete("Bar") }
|
32
|
+
expect(Row.count).to eq 0
|
33
|
+
end
|
34
|
+
|
35
|
+
it "yields the block" do
|
36
|
+
Repository.new.refresh(pacticipant_name: "Bar") { PactBroker::Pacticipants::Service.delete("Bar") }
|
37
|
+
expect(PactBroker::Domain::Pacticipant.where(name: "Bar").count).to eq 0
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
22
42
|
describe "find" do
|
23
43
|
before do
|
24
44
|
# A1 - B1
|