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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +22 -0
  3. data/.github/PULL_REQUEST_TEMPLATE.md +9 -0
  4. data/CHANGELOG.md +28 -0
  5. data/DEVELOPER_DOCUMENTATION.md +5 -0
  6. data/db/migrations/000046_recreate_latest_verifications.rb +2 -2
  7. data/db/migrations/20180311_optimise_head_matrix.rb +80 -0
  8. data/db/migrations/20180315_create_verification_sequence.rb +14 -0
  9. data/db/migrations/migration_helper.rb +1 -1
  10. data/lib/db.rb +3 -2
  11. data/lib/pact_broker/api/resources/base_resource.rb +10 -13
  12. data/lib/pact_broker/api/resources/error_handler.rb +30 -0
  13. data/lib/pact_broker/api/resources/pact.rb +6 -1
  14. data/lib/pact_broker/api/resources/pacticipant.rb +8 -2
  15. data/lib/pact_broker/api/resources/tag.rb +4 -2
  16. data/lib/pact_broker/api/resources/verifications.rb +5 -1
  17. data/lib/pact_broker/api/resources/version.rb +3 -1
  18. data/lib/pact_broker/api.rb +1 -1
  19. data/lib/pact_broker/config/load.rb +1 -0
  20. data/lib/pact_broker/configuration.rb +16 -0
  21. data/lib/pact_broker/matrix/head_row.rb +19 -0
  22. data/lib/pact_broker/matrix/repository.rb +39 -2
  23. data/lib/pact_broker/matrix/row.rb +16 -28
  24. data/lib/pact_broker/matrix/service.rb +6 -2
  25. data/lib/pact_broker/pacticipants/service.rb +1 -0
  26. data/lib/pact_broker/ui/controllers/base_controller.rb +2 -1
  27. data/lib/pact_broker/ui/controllers/error_test.rb +0 -1
  28. data/lib/pact_broker/ui/controllers/matrix.rb +3 -4
  29. data/lib/pact_broker/ui/view_models/matrix_line.rb +6 -0
  30. data/lib/pact_broker/ui/views/matrix/show.haml +14 -10
  31. data/lib/pact_broker/ui.rb +6 -6
  32. data/lib/pact_broker/verifications/repository.rb +9 -4
  33. data/lib/pact_broker/verifications/sequence.rb +34 -0
  34. data/lib/pact_broker/verifications/service.rb +2 -2
  35. data/lib/pact_broker/version.rb +1 -1
  36. data/lib/webmachine/convert_request_to_rack_env.rb +37 -0
  37. data/script/publish.sh +13 -2
  38. data/script/recreate-mysql-db.sh +2 -1
  39. data/script/seed-matrix.rb +1 -1
  40. data/spec/features/publish_verification_spec.rb +0 -1
  41. data/spec/features/update_matrix_spec.rb +146 -0
  42. data/spec/fixtures/foo-bar.json +22 -0
  43. data/spec/lib/pact_broker/api/resources/error_handler_spec.rb +55 -0
  44. data/spec/lib/pact_broker/api/resources/verifications_spec.rb +1 -1
  45. data/spec/lib/pact_broker/configuration_spec.rb +19 -1
  46. data/spec/lib/pact_broker/matrix/head_row_spec.rb +52 -0
  47. data/spec/lib/pact_broker/matrix/repository_spec.rb +20 -0
  48. data/spec/lib/pact_broker/matrix/row_spec.rb +10 -10
  49. data/spec/lib/pact_broker/pacticipants/service_spec.rb +1 -0
  50. data/spec/lib/pact_broker/verifications/repository_spec.rb +0 -29
  51. data/spec/lib/pact_broker/verifications/sequence_spec.rb +47 -0
  52. data/spec/lib/pact_broker/verifications/service_spec.rb +0 -13
  53. data/spec/lib/webmachine/convert_request_to_rack_env_spec.rb +68 -0
  54. data/spec/support/test_data_builder.rb +2 -0
  55. data/tasks/development.rake +10 -0
  56. 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: 'cvpv' }
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
- log_error(e) unless e.is_a?(PactBroker::Error)
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: 'cvpv', limit: 100}
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
- %label{for: "limit"}
72
- Limit
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
- = line.verification_status
147
+ - if options.all_rows_checked
148
+ = "#{line.verification_status} (number #{line.number})"
149
+ - else
150
+ = line.verification_status
@@ -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: :stderr },
7
- staging: { log_level: :error, stream: :stderr },
8
- test: { log_level: :warn, stream: :stdout },
9
- development: { log_level: :warn, stream: :stdout }
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 next_number_for pact
16
- verification_repository.verification_count_for_pact(pact) + 1
15
+ def next_number
16
+ verification_repository.next_number
17
17
  end
18
18
 
19
19
  def create next_verification_number, params, pact
@@ -1,3 +1,3 @@
1
1
  module PactBroker
2
- VERSION = '2.16.1'
2
+ VERSION = '2.17.0'
3
3
  end
@@ -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@script/foo-bar.json \
3
- http://127.0.0.1:9292/pacts/provider/Bar/consumer/Foo/version/1.0.0
13
+ -d@tmp/pact.json \
14
+ http://127.0.0.1:9292/pacts/provider/${provider}/consumer/${consumer}/version/1.0.0
4
15
  echo ""
@@ -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
 
@@ -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)
@@ -10,7 +10,6 @@ describe "Recording a pact verification" do
10
10
 
11
11
  subject { post path, verification_content, {'CONTENT_TYPE' => 'application/json' }; last_response }
12
12
 
13
-
14
13
  before do
15
14
  td.create_provider("Provider")
16
15
  .create_consumer("Consumer")
@@ -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(:next_number_for).and_return(next_verification_number)
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