pact_broker 1.18.0.beta.1 → 1.18.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 +4 -2
- data/README.md +12 -12
- data/example/{heroku → basic_auth}/Gemfile +0 -0
- data/example/{heroku → basic_auth}/Procfile +0 -0
- data/example/{heroku → basic_auth}/README.md +1 -1
- data/example/basic_auth/config.ru +19 -0
- data/example/config.ru +0 -2
- data/lib/pact_broker/api/decorators/versions_decorator.rb +1 -1
- data/lib/pact_broker/api/resources/versions.rb +1 -1
- data/lib/pact_broker/app.rb +7 -6
- data/lib/pact_broker/configuration.rb +4 -42
- data/lib/pact_broker/domain/order_versions.rb +15 -5
- data/lib/pact_broker/domain/webhook.rb +0 -1
- data/lib/pact_broker/domain/webhook_request.rb +6 -4
- data/lib/pact_broker/logging.rb +4 -0
- data/lib/pact_broker/pacticipants/repository.rb +2 -1
- data/lib/pact_broker/pacticipants/service.rb +2 -2
- data/lib/pact_broker/version.rb +1 -1
- data/lib/pact_broker/webhooks/job.rb +46 -0
- data/lib/pact_broker/webhooks/service.rb +9 -8
- data/lib/pact_broker/webhooks/webhook.rb +1 -1
- data/pact_broker.gemspec +2 -1
- data/pact_broker_client-pact_broker.json +4 -4
- data/script/foo-bar.json +22 -0
- data/script/publish-new.sh +7 -0
- data/script/publish.sh +2 -2
- data/script/recreate-pg-db.sh +7 -0
- data/spec/fixtures/a_consumer-a_provider-2.json +1 -1
- data/spec/fixtures/a_consumer-a_provider-3.json +1 -1
- data/spec/fixtures/a_consumer-a_provider-conflict.json +1 -1
- data/spec/fixtures/a_consumer-a_provider-merged.json +2 -2
- data/spec/fixtures/a_consumer-a_provider.json +1 -1
- data/spec/fixtures/consumer-provider.json +1 -1
- data/spec/fixtures/renderer_pact.json +1 -1
- data/spec/lib/pact_broker/configuration_spec.rb +2 -22
- data/spec/lib/pact_broker/domain/order_versions_spec.rb +30 -10
- data/spec/lib/pact_broker/domain/webhook_request_spec.rb +3 -1
- data/spec/lib/pact_broker/pacticipants/repository_spec.rb +16 -0
- data/spec/lib/pact_broker/webhooks/job_spec.rb +67 -0
- data/spec/lib/pact_broker/webhooks/service_spec.rb +40 -3
- data/spec/support/provider_state_builder.rb +36 -8
- metadata +29 -12
- data/example/heroku/config.ru +0 -12
- data/lib/pact_broker/configuration/configure_basic_auth.rb +0 -83
- data/spec/lib/pact_broker/configuration/configure_basic_auth_spec.rb +0 -267
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'pact_broker/repositories'
|
2
2
|
require 'pact_broker/logging'
|
3
|
+
require 'pact_broker/webhooks/job'
|
3
4
|
require 'base64'
|
5
|
+
require 'securerandom'
|
4
6
|
|
5
7
|
module PactBroker
|
6
8
|
|
@@ -50,6 +52,7 @@ module PactBroker
|
|
50
52
|
|
51
53
|
def self.execute_webhooks pact
|
52
54
|
webhooks = webhook_repository.find_by_consumer_and_provider pact.consumer, pact.provider
|
55
|
+
|
53
56
|
if webhooks.any?
|
54
57
|
run_later(webhooks)
|
55
58
|
else
|
@@ -57,15 +60,13 @@ module PactBroker
|
|
57
60
|
end
|
58
61
|
end
|
59
62
|
|
60
|
-
# TODO background job?
|
61
63
|
def self.run_later webhooks
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
end
|
64
|
+
webhooks.each do | webhook |
|
65
|
+
begin
|
66
|
+
logger.info "Scheduling job for #{webhook.description} with uuid #{webhook.uuid}"
|
67
|
+
Job.perform_async webhook: webhook
|
68
|
+
rescue StandardError => e
|
69
|
+
log_error e
|
69
70
|
end
|
70
71
|
end
|
71
72
|
end
|
@@ -46,7 +46,7 @@ module PactBroker
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def request_attributes
|
49
|
-
values.merge(headers: parsed_headers, body: parsed_body, password: plain_text_password)
|
49
|
+
values.merge(headers: parsed_headers, body: parsed_body, password: plain_text_password, uuid: uuid)
|
50
50
|
end
|
51
51
|
|
52
52
|
def plain_text_password
|
data/pact_broker.gemspec
CHANGED
@@ -35,9 +35,10 @@ Gem::Specification.new do |gem|
|
|
35
35
|
gem.add_runtime_dependency 'pact-support', '~>0.4', '>=0.4.2'
|
36
36
|
gem.add_runtime_dependency 'padrino-core', '~>0.12.4'
|
37
37
|
gem.add_runtime_dependency 'haml', '~>4.0'
|
38
|
+
gem.add_runtime_dependency 'sucker_punch', '~>2.0'
|
38
39
|
|
39
40
|
gem.add_development_dependency 'sqlite3'
|
40
|
-
gem.add_development_dependency 'pry'
|
41
|
+
gem.add_development_dependency 'pry-byebug'
|
41
42
|
gem.add_development_dependency 'rake', '~>10.0'
|
42
43
|
gem.add_development_dependency 'fakefs', '~>0.4'
|
43
44
|
gem.add_development_dependency 'mysql2', '~>0.3.15'
|
@@ -35,7 +35,7 @@
|
|
35
35
|
},
|
36
36
|
{
|
37
37
|
"description": "a request to publish a pact",
|
38
|
-
"
|
38
|
+
"providerState": "an error occurs while publishing a pact",
|
39
39
|
"request": {
|
40
40
|
"method": "put",
|
41
41
|
"path": "/pacticipant/Condor/versions/1.3.0/pacts/Pricing%20Service",
|
@@ -72,7 +72,7 @@
|
|
72
72
|
},
|
73
73
|
{
|
74
74
|
"description": "a request to retrieve the repository URL of the 'Pricing Service'",
|
75
|
-
"
|
75
|
+
"providerState": "the 'Pricing Service' does not exist in the pact-broker",
|
76
76
|
"request": {
|
77
77
|
"method": "get",
|
78
78
|
"path": "/pacticipant/Pricing%20Service/repository_url",
|
@@ -90,7 +90,7 @@
|
|
90
90
|
|
91
91
|
{
|
92
92
|
"description": "a request to register the repository URL of a pacticipant",
|
93
|
-
"
|
93
|
+
"providerState": "the 'Pricing Service' does not exist in the pact-broker",
|
94
94
|
"request": {
|
95
95
|
"method": "patch",
|
96
96
|
"path": "/pacticipant/Pricing%20Service",
|
@@ -108,7 +108,7 @@
|
|
108
108
|
},
|
109
109
|
{
|
110
110
|
"description": "a request to retrieve the repository URL of the 'Pricing Service'",
|
111
|
-
"
|
111
|
+
"providerState": "the 'Pricing Service' already exists in the pact-broker",
|
112
112
|
"request": {
|
113
113
|
"method": "get",
|
114
114
|
"path": "/pacticipant/Pricing%20Service/repository_url",
|
data/script/foo-bar.json
ADDED
@@ -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,7 @@
|
|
1
|
+
# set -x
|
2
|
+
BODY=$(ruby -e "require 'json'; j = JSON.parse(File.read('script/foo-bar.json')); j['interactions'][0]['providerState'] = 'it is ' + Time.now.to_s; puts j.to_json")
|
3
|
+
echo ${BODY} >> tmp.json
|
4
|
+
curl -v -XPUT \-H "Content-Type: application/json" \
|
5
|
+
-d@tmp.json \
|
6
|
+
http://127.0.0.1:9292/pacts/provider/Bar/consumer/Foo/version/1.0.0
|
7
|
+
rm tmp.json
|
data/script/publish.sh
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
curl -v -XPUT \-H "Content-Type: application/json" \
|
2
|
-
-d@
|
3
|
-
http://
|
2
|
+
-d@script/foo-bar.json \
|
3
|
+
http://127.0.0.1:9292/pacts/provider/Bar/consumer/Foo/version/1.0.0
|
@@ -0,0 +1,7 @@
|
|
1
|
+
psql postgres -c "drop database pact_broker;"
|
2
|
+
psql postgres -c "create database pact_broker;"
|
3
|
+
psql postgres -c "GRANT ALL PRIVILEGES ON DATABASE pact_broker to pact_broker;"
|
4
|
+
ip=$(ifconfig en0 | sed -n -e '/inet/s/.*inet \([0-9.]*\) netmask .*/\1/p')
|
5
|
+
echo ""
|
6
|
+
echo "run the following command to set your environment variables:"
|
7
|
+
echo "export PACT_BROKER_DATABASE_HOST=${ip}"
|
@@ -8,7 +8,7 @@
|
|
8
8
|
"interactions": [
|
9
9
|
{
|
10
10
|
"description" : "a request for something",
|
11
|
-
"
|
11
|
+
"providerState": null,
|
12
12
|
"request": {
|
13
13
|
"method": "get",
|
14
14
|
"path" : "/something"
|
@@ -20,7 +20,7 @@
|
|
20
20
|
},
|
21
21
|
{
|
22
22
|
"description" : "another request for something",
|
23
|
-
"
|
23
|
+
"providerState": null,
|
24
24
|
"request": {
|
25
25
|
"method": "get",
|
26
26
|
"path" : "/something_else"
|
@@ -7,35 +7,15 @@ module PactBroker
|
|
7
7
|
|
8
8
|
context "default configuration" do
|
9
9
|
describe ".html_pact_renderer" do
|
10
|
+
|
10
11
|
let(:pact) { double('pact') }
|
11
12
|
|
12
13
|
it "calls the inbuilt HtmlPactRenderer" do
|
13
14
|
expect(PactBroker::Api::Renderers::HtmlPactRenderer).to receive(:call).with(pact)
|
14
15
|
PactBroker.configuration.html_pact_renderer.call pact
|
15
16
|
end
|
16
|
-
end
|
17
|
-
|
18
|
-
describe "protect_with_basic_auth" do
|
19
|
-
let(:config) do
|
20
|
-
config = Configuration.new
|
21
|
-
config.protect_with_basic_auth [:foo, :bar], {some: 'credentials'}
|
22
|
-
config.protect_with_basic_auth :foo, {some: 'othercredentials'}
|
23
|
-
config
|
24
|
-
end
|
25
17
|
|
26
|
-
it "groups credentials by scope" do
|
27
|
-
expect(config.basic_auth_credentials_list_for(:foo)).to eq([{some: 'credentials'},{some: 'othercredentials'}])
|
28
|
-
expect(config.basic_auth_credentials_list_for(:bar)).to eq([{some: 'credentials'}])
|
29
|
-
end
|
30
|
-
|
31
|
-
describe "protect_with_basic_auth?" do
|
32
|
-
it "indicates whether a scope is protected" do
|
33
|
-
expect(config.protect_with_basic_auth?(:foo)).to be true
|
34
|
-
expect(config.protect_with_basic_auth?(:bar)).to be true
|
35
|
-
expect(config.protect_with_basic_auth?(:wiffle)).to be false
|
36
|
-
end
|
37
|
-
end
|
38
18
|
end
|
39
19
|
end
|
40
20
|
end
|
41
|
-
end
|
21
|
+
end
|
@@ -4,20 +4,40 @@ require 'pact_broker/domain/order_versions.rb'
|
|
4
4
|
|
5
5
|
describe PactBroker::Domain::OrderVersions do
|
6
6
|
|
7
|
+
context "when order_versions_by_date is false (the default)" do
|
8
|
+
before do
|
9
|
+
ProviderStateBuilder.new
|
10
|
+
.create_condor
|
11
|
+
.create_condor_version('1.3.0')
|
12
|
+
.create_condor_version('1.5.0')
|
13
|
+
.create_condor_version('1.4.0')
|
14
|
+
.create_condor_version('1.6.0')
|
15
|
+
end
|
7
16
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
.
|
13
|
-
|
17
|
+
let(:ordered_versions) { PactBroker::Domain::Version.order(:order).all.collect(&:number) }
|
18
|
+
let(:condor) { PactBroker::Domain::Pacticipant.where(name: 'Condor').single_record }
|
19
|
+
|
20
|
+
it "orders the versions so they can be loaded from the database in order" do
|
21
|
+
expect(ordered_versions).to eq(['1.3.0', '1.4.0', '1.5.0', '1.6.0'])
|
22
|
+
end
|
14
23
|
end
|
15
24
|
|
16
|
-
|
17
|
-
|
25
|
+
context "when order_versions_by_date is true (not recommended)" do
|
26
|
+
before do
|
27
|
+
allow(PactBroker.configuration).to receive(:order_versions_by_date).and_return(true)
|
28
|
+
end
|
29
|
+
let(:consumer) { ProviderStateBuilder.new.create_consumer.and_return(:consumer) }
|
30
|
+
let!(:version_1) { PactBroker::Domain::Version.create(pacticipant_id: consumer.id, number: '2', created_at: DateTime.new(2017)) }
|
31
|
+
let!(:version_2) { PactBroker::Domain::Version.create(pacticipant_id: consumer.id, number: '1', created_at: DateTime.new(2017)) }
|
32
|
+
let!(:version_3) { PactBroker::Domain::Version.create(pacticipant_id: consumer.id, number: '3', created_at: DateTime.new(2016)) }
|
33
|
+
let!(:version_4) { PactBroker::Domain::Version.create(pacticipant_id: consumer.id, number: '4', created_at: DateTime.new(2018)) }
|
34
|
+
|
35
|
+
let(:ordered_versions) { PactBroker::Domain::Version.order(:order).all.collect(&:number) }
|
36
|
+
|
37
|
+
it "orders by date, then id" do
|
38
|
+
expect(ordered_versions).to eq(['3', '2', '1', '4'])
|
39
|
+
end
|
18
40
|
|
19
|
-
it "orders the versions so they can be loaded from the database in order" do
|
20
|
-
expect(ordered_versions).to eq(['1.3.0','1.4.0', '1.5.0'])
|
21
41
|
end
|
22
42
|
|
23
43
|
end
|
@@ -64,7 +64,9 @@ module PactBroker
|
|
64
64
|
|
65
65
|
it "logs the response" do
|
66
66
|
allow(PactBroker.logger).to receive(:info)
|
67
|
-
|
67
|
+
allow(PactBroker.logger).to receive(:debug)
|
68
|
+
expect(PactBroker.logger).to receive(:info).with(/response.*302/)
|
69
|
+
expect(PactBroker.logger).to receive(:debug).with(/respbod/)
|
68
70
|
subject.execute
|
69
71
|
end
|
70
72
|
|
@@ -53,6 +53,22 @@ module PactBroker
|
|
53
53
|
|
54
54
|
end
|
55
55
|
|
56
|
+
describe "#find_all_pacticipant_versions_in_reverse_order" do
|
57
|
+
before do
|
58
|
+
ProviderStateBuilder.new
|
59
|
+
.create_consumer("Foo")
|
60
|
+
.create_consumer_version("1.2.3")
|
61
|
+
.create_consumer_version("4.5.6")
|
62
|
+
.create_consumer("Bar")
|
63
|
+
.create_consumer_version("8.9.0")
|
64
|
+
end
|
65
|
+
|
66
|
+
subject { Repository.new.find_all_pacticipant_versions_in_reverse_order "Foo" }
|
67
|
+
|
68
|
+
it "returns all the application versions for the given consumer" do
|
69
|
+
expect(subject.collect(&:number)).to eq ["4.5.6", "1.2.3"]
|
70
|
+
end
|
71
|
+
end
|
56
72
|
|
57
73
|
end
|
58
74
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'pact_broker/webhooks/job'
|
2
|
+
|
3
|
+
module PactBroker
|
4
|
+
module Webhooks
|
5
|
+
describe Job do
|
6
|
+
|
7
|
+
before do
|
8
|
+
allow(PactBroker::Webhooks::Service).to receive(:execute_webhook_now)
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:webhook) { double("webhook", uuid: '1234') }
|
12
|
+
|
13
|
+
context "when an error occurs for the first time" do
|
14
|
+
before do
|
15
|
+
allow(PactBroker::Webhooks::Service).to receive(:execute_webhook_now).and_raise("an error")
|
16
|
+
end
|
17
|
+
|
18
|
+
it "reschedules the job in 10 seconds" do
|
19
|
+
expect(Job).to receive(:perform_in).with(10, {webhook: webhook, error_count: 1})
|
20
|
+
Job.new.perform(webhook: webhook)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "when the webhook execution result is not successful for the first time" do
|
25
|
+
before do
|
26
|
+
allow(PactBroker::Webhooks::Service).to receive(:execute_webhook_now).and_return(instance_double("PactBroker::Domain::WebhookExecutionResult", success?: false))
|
27
|
+
end
|
28
|
+
|
29
|
+
it "reschedules the job in 10 seconds" do
|
30
|
+
expect(Job).to receive(:perform_in).with(10, {webhook: webhook, error_count: 1})
|
31
|
+
Job.new.perform(webhook: webhook)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "when an error occurs for the second time" do
|
36
|
+
before do
|
37
|
+
allow(PactBroker::Webhooks::Service).to receive(:execute_webhook_now).and_raise("an error")
|
38
|
+
end
|
39
|
+
|
40
|
+
it "reschedules the job in 60 seconds" do
|
41
|
+
expect(Job).to receive(:perform_in).with(60, {webhook: webhook, error_count: 2 })
|
42
|
+
Job.new.perform(webhook: webhook, error_count: 1)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "when an error occurs for the last time" do
|
47
|
+
before do
|
48
|
+
allow(PactBroker::Webhooks::Service).to receive(:execute_webhook_now).and_raise("an error")
|
49
|
+
end
|
50
|
+
|
51
|
+
subject { Job.new.perform(webhook: webhook, error_count: 6) }
|
52
|
+
|
53
|
+
it "does not reschedule the job" do
|
54
|
+
expect(Job).to_not receive(:perform_in)
|
55
|
+
subject
|
56
|
+
end
|
57
|
+
|
58
|
+
it "logs that it has failed" do
|
59
|
+
allow(Job.logger).to receive(:error)
|
60
|
+
expect(Job.logger).to receive(:error).with(/Failed to execute/)
|
61
|
+
subject
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'pact_broker/webhooks/service'
|
3
|
+
require 'webmock/rspec'
|
4
|
+
require 'sucker_punch/testing/inline'
|
3
5
|
|
4
6
|
module PactBroker
|
5
7
|
|
@@ -12,11 +14,11 @@ module PactBroker
|
|
12
14
|
let(:consumer_version) { PactBroker::Domain::Version.new(number: '1.2.3') }
|
13
15
|
let(:consumer) { PactBroker::Domain::Pacticipant.new(name: 'Consumer') }
|
14
16
|
let(:provider) { PactBroker::Domain::Pacticipant.new(name: 'Provider') }
|
15
|
-
let(:webhooks) { [instance_double(PactBroker::Domain::Webhook)]}
|
17
|
+
let(:webhooks) { [instance_double(PactBroker::Domain::Webhook, description: 'description', uuid: '1244')]}
|
16
18
|
|
17
19
|
before do
|
18
20
|
allow_any_instance_of(PactBroker::Webhooks::Repository).to receive(:find_by_consumer_and_provider).and_return(webhooks)
|
19
|
-
allow(
|
21
|
+
allow(Job).to receive(:perform_async)
|
20
22
|
end
|
21
23
|
|
22
24
|
subject { Service.execute_webhooks pact }
|
@@ -45,7 +47,42 @@ module PactBroker
|
|
45
47
|
subject
|
46
48
|
end
|
47
49
|
end
|
50
|
+
|
51
|
+
context "when there is a scheduling error" do
|
52
|
+
before do
|
53
|
+
allow(Job).to receive(:perform_async).and_raise("an error")
|
54
|
+
end
|
55
|
+
|
56
|
+
it "logs the error" do
|
57
|
+
allow(Service.logger).to receive(:error)
|
58
|
+
expect(Service.logger).to receive(:error).with(/an error/)
|
59
|
+
subject
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe ".execute_webhooks integration test" do
|
65
|
+
let!(:http_request) do
|
66
|
+
stub_request(:get, "http://example.org").
|
67
|
+
to_return(:status => 200)
|
68
|
+
end
|
69
|
+
|
70
|
+
let(:pact) do
|
71
|
+
ProviderStateBuilder.new
|
72
|
+
.create_consumer
|
73
|
+
.create_provider
|
74
|
+
.create_consumer_version
|
75
|
+
.create_pact
|
76
|
+
.create_webhook(method: 'GET', url: 'http://example.org')
|
77
|
+
.and_return(:pact)
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
it "executes the HTTP request of the webhook" do
|
82
|
+
PactBroker::Webhooks::Service.execute_webhooks pact
|
83
|
+
expect(http_request).to have_been_made
|
84
|
+
end
|
48
85
|
end
|
49
86
|
end
|
50
87
|
end
|
51
|
-
end
|
88
|
+
end
|