pact_broker-client 1.14.1 → 1.15.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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +21 -0
  4. data/README.md +27 -1
  5. data/Rakefile +9 -0
  6. data/doc/pacts/markdown/Pact Broker Client - Pact Broker.md +521 -10
  7. data/lib/pact_broker/client/base_client.rb +1 -1
  8. data/lib/pact_broker/client/cli/broker.rb +63 -0
  9. data/lib/pact_broker/client/cli/can_i_deploy_long_desc.txt +1 -1
  10. data/lib/pact_broker/client/cli/create_webhook_long_desc.txt +1 -0
  11. data/lib/pact_broker/client/command_result.rb +12 -0
  12. data/lib/pact_broker/client/hal.rb +4 -0
  13. data/lib/pact_broker/client/hal/entity.rb +78 -0
  14. data/lib/pact_broker/client/hal/entry_point.rb +13 -0
  15. data/lib/pact_broker/client/hal/http_client.rb +82 -0
  16. data/lib/pact_broker/client/hal/link.rb +79 -0
  17. data/lib/pact_broker/client/pacts.rb +7 -1
  18. data/lib/pact_broker/client/version.rb +1 -1
  19. data/lib/pact_broker/client/versions.rb +0 -1
  20. data/lib/pact_broker/client/webhooks/create.rb +114 -0
  21. data/spec/integration/can_i_deploy_spec.rb +1 -3
  22. data/spec/integration/create_version_tag_spec.rb +1 -3
  23. data/spec/lib/pact_broker/client/can_i_deploy_spec.rb +1 -1
  24. data/spec/lib/pact_broker/client/cli/broker_create_webhook_spec.rb +190 -0
  25. data/spec/lib/pact_broker/client/hal/entity_spec.rb +93 -0
  26. data/spec/lib/pact_broker/client/hal/http_client_spec.rb +105 -0
  27. data/spec/lib/pact_broker/client/hal/link_spec.rb +108 -0
  28. data/spec/lib/pact_broker/client/webhooks/create_spec.rb +61 -0
  29. data/spec/pacts/pact_broker_client-pact_broker.json +499 -9
  30. data/spec/service_providers/pact_broker_client_publish_spec.rb +6 -1
  31. data/spec/service_providers/pact_broker_client_retrieve_all_pacts_for_provider_spec.rb +1 -1
  32. data/spec/service_providers/{pact_broker_client_retrive_pact_spec.rb → pact_broker_client_retrieve_pact_spec.rb} +2 -3
  33. data/spec/service_providers/pact_broker_client_versions_spec.rb +1 -1
  34. data/spec/service_providers/pact_helper.rb +46 -0
  35. data/spec/service_providers/webhooks_create_spec.rb +255 -0
  36. data/spec/spec_helper.rb +32 -0
  37. data/spec/support/latest_pacts_for_provider.json +1 -1
  38. data/spec/support/shared_context.rb +6 -3
  39. metadata +24 -4
@@ -1,6 +1,4 @@
1
- is_windows = !!RbConfig::CONFIG['host_os'] =~ /bccwin|cygwin|djgpp|mingw|mswin|wince/
2
-
3
- describe "pact-broker can-i-deploy", pending: is_windows do
1
+ describe "pact-broker can-i-deploy", skip_windows: true do
4
2
  before(:all) do
5
3
  @pipe = IO.popen("bundle exec pact-stub-service spec/pacts/pact_broker_client-pact_broker.json -p 5000")
6
4
  sleep 2
@@ -1,6 +1,4 @@
1
- is_windows = !!RbConfig::CONFIG['host_os'] =~ /bccwin|cygwin|djgpp|mingw|mswin|wince/
2
-
3
- describe "pact-broker create-version-tag", pending: is_windows do
1
+ describe "pact-broker create-version-tag", skip_windows: true do
4
2
  before(:all) do
5
3
  @pipe = IO.popen("bundle exec pact-stub-service spec/pacts/pact_broker_client-pact_broker.json -p 5001")
6
4
  sleep 2
@@ -76,7 +76,7 @@ module PactBroker
76
76
 
77
77
  context "when a StandardError is raised" do
78
78
  before do
79
- allow(Retry).to receive(:sleep).and_return(0)
79
+ allow(Retry).to receive(:until_true) { |&block| block.call }
80
80
  allow($stderr).to receive(:puts)
81
81
  allow(matrix_client).to receive(:get).and_raise(StandardError.new('error text'))
82
82
  end
@@ -0,0 +1,190 @@
1
+ require 'pact_broker/client/cli/broker'
2
+ require 'pact_broker/client/webhooks/create'
3
+
4
+ module PactBroker
5
+ module Client
6
+ module CLI
7
+ describe Broker do
8
+ describe "create_webhook" do
9
+ before do
10
+ allow($stdout).to receive(:puts)
11
+ allow(PactBroker::Client::Webhooks::Create).to receive(:call).and_return(command_result)
12
+ broker.options = OpenStruct.new(options_hash)
13
+ end
14
+
15
+ let(:broker) { Broker.new }
16
+ let(:data) { 'data' }
17
+ let(:user) { "username:password" }
18
+ let(:command_result) { double('command result', success: success, message: 'message') }
19
+ let(:success) { true }
20
+ let(:header) { ["Foo: bar", "Bar: foo"] }
21
+
22
+ let(:options_hash) do
23
+ {
24
+ request: "POST",
25
+ header: header,
26
+ data: data,
27
+ user: user,
28
+ consumer: "consumer",
29
+ provider: "provider",
30
+ broker_base_url: "http://broker",
31
+ broker_username: "username",
32
+ broker_password: "password",
33
+ contract_content_changed: true,
34
+ verbose: true
35
+ }
36
+ end
37
+
38
+ let(:expected_params) do
39
+ {
40
+ http_method: "POST",
41
+ url: "http://webhook",
42
+ headers: { "Foo" => "bar", "Bar" => "foo"},
43
+ username: "username",
44
+ password: "password",
45
+ body: "data",
46
+ consumer: "consumer",
47
+ provider: "provider",
48
+ events: ["contract_content_changed"]
49
+ }.tap { |it| Pact::Fixture.add_fixture(:create_webhook_params, it) }
50
+ end
51
+
52
+ subject { broker.create_webhook "http://webhook" }
53
+
54
+ it "calls PactBroker::Client::Webhooks::Create with the webhook params" do
55
+ expect(PactBroker::Client::Webhooks::Create).to receive(:call) do | params, _, _ |
56
+ expect(params).to eq expected_params
57
+ command_result
58
+ end
59
+ subject
60
+ end
61
+
62
+ it "calls PactBroker::Client::Webhooks::Create with pact broker details" do
63
+ expect(PactBroker::Client::Webhooks::Create).to receive(:call) do | _, broker_base_url, pact_broker_client_options |
64
+ expect(broker_base_url).to eq "http://broker"
65
+ expect(pact_broker_client_options).to eq(basic_auth: { username: "username", password: "password"}, verbose: true)
66
+ command_result
67
+ end
68
+ subject
69
+ end
70
+
71
+ context "when neither event type is selected" do
72
+ before do
73
+ options_hash.delete(:contract_content_changed)
74
+ broker.options = OpenStruct.new(options_hash)
75
+ end
76
+
77
+ it "raises an error" do
78
+ expect { subject }.to raise_error PactBroker::Client::Error, /You must select at least one/
79
+ end
80
+ end
81
+
82
+ context "with no basic auth" do
83
+ before do
84
+ options_hash.delete(:broker_username)
85
+ options_hash.delete(:broker_password)
86
+ broker.options = OpenStruct.new(options_hash)
87
+ end
88
+
89
+ it "calls Webhooks::Create without basic auth" do
90
+ expect(PactBroker::Client::Webhooks::Create).to receive(:call) do | _, _, pact_broker_client_options |
91
+ expect(pact_broker_client_options).to eq(verbose: true)
92
+ command_result
93
+ end
94
+ subject
95
+ end
96
+ end
97
+
98
+ context "when there are no headers specified" do
99
+ let(:header) { nil }
100
+
101
+ it "calls Webhooks::Create with an empty hash of headers" do
102
+ expect(PactBroker::Client::Webhooks::Create).to receive(:call) do | params, _, _ |
103
+ expect(params[:headers]).to eq({})
104
+ command_result
105
+ end
106
+ subject
107
+ end
108
+ end
109
+
110
+ context "when data is nil" do
111
+ let(:data) { nil }
112
+
113
+ it "alls Webhooks::Create with a nil body" do
114
+ expect(PactBroker::Client::Webhooks::Create).to receive(:call) do | params, _, _ |
115
+ expect(params[:body]).to be nil
116
+ command_result
117
+ end
118
+ subject
119
+ end
120
+ end
121
+
122
+ context "when a file reference is passed for the data" do
123
+ before do
124
+ FileUtils.mkdir_p "tmp"
125
+ File.open("tmp/body.json", "w") { |file| file << "file" }
126
+ end
127
+
128
+ let(:data) { "@tmp/body.json" }
129
+
130
+ it "reads the file and passes it in to the Webhooks::Create call" do
131
+ expect(PactBroker::Client::Webhooks::Create).to receive(:call) do | params, _, _ |
132
+ expect(params[:body]).to eq "file"
133
+ command_result
134
+ end
135
+ subject
136
+ end
137
+
138
+ context "when the file is not found" do
139
+
140
+ let(:data) { "@doesnotexist.json" }
141
+
142
+ it "raises a PactBroker::Client::Error" do
143
+ expect { subject }.to raise_error PactBroker::Client::Error, /Couldn't read data from file/
144
+ end
145
+ end
146
+
147
+ context "when successful" do
148
+ it "prints the message to stdout" do
149
+ expect($stdout).to receive(:puts).with('message')
150
+ subject
151
+ end
152
+ end
153
+
154
+ context "when not successful" do
155
+ let(:success) { false }
156
+
157
+ it "prints the message to stderr" do
158
+ expect($stdout).to receive(:puts).with('message')
159
+ begin
160
+ subject
161
+ rescue SystemExit
162
+ end
163
+ end
164
+
165
+ it "exits with code 1" do
166
+ exited_with_error = false
167
+ begin
168
+ subject
169
+ rescue SystemExit
170
+ exited_with_error = true
171
+ end
172
+ expect(exited_with_error).to be true
173
+ end
174
+ end
175
+
176
+ context "when a PactBroker::Client::Error is raised" do
177
+ before do
178
+ allow(PactBroker::Client::Webhooks::Create).to receive(:call).and_raise(PactBroker::Client::Error, "foo")
179
+ end
180
+
181
+ it "raises a WebhookCreationError which does not show an ugly stack trace" do
182
+ expect { subject }.to raise_error(WebhookCreationError, /foo/)
183
+ end
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end
189
+ end
190
+ end
@@ -0,0 +1,93 @@
1
+ require 'pact_broker/client/hal/entity'
2
+ require 'pact_broker/client/hal/http_client'
3
+
4
+ module PactBroker::Client
5
+ module Hal
6
+ describe Entity do
7
+ let(:http_client) do
8
+ instance_double('Pact::Hal::HttpClient', post: provider_response)
9
+ end
10
+
11
+ let(:provider_response) do
12
+ double('response', body: provider_hash, success?: true)
13
+ end
14
+
15
+ let(:provider_hash) do
16
+ {
17
+ "name" => "Provider"
18
+ }
19
+ end
20
+ let(:pact_hash) do
21
+ {
22
+ "name" => "a name",
23
+
24
+ "_links" => {
25
+ "pb:provider" => {
26
+ "href" => "http://provider"
27
+ },
28
+ "pb:version-tag" => {
29
+ "href" => "http://provider/version/{version}/tag/{tag}"
30
+ }
31
+ }
32
+ }
33
+ end
34
+
35
+ subject(:entity) { Entity.new(pact_hash, http_client) }
36
+
37
+ it "delegates to the properties in the data" do
38
+ expect(subject.name).to eq "a name"
39
+ end
40
+
41
+ describe "post" do
42
+ let(:post_provider) { entity.post("pb:provider", {'some' => 'data'} ) }
43
+
44
+ it "executes an http request" do
45
+ expect(http_client).to receive(:post).with("http://provider", '{"some":"data"}', {})
46
+ post_provider
47
+ end
48
+
49
+ it "returns the entity for the relation" do
50
+ expect(post_provider).to be_a(Entity)
51
+ end
52
+
53
+ context "with template params" do
54
+ let(:post_provider) { entity._link("pb:version-tag").expand(version: "1", tag: "prod").post({'some' => 'data'} ) }
55
+
56
+ it "posts to the expanded URL" do
57
+ expect(http_client).to receive(:post).with("http://provider/version/1/tag/prod", '{"some":"data"}', {})
58
+ post_provider
59
+ end
60
+ end
61
+ end
62
+
63
+ describe "can?" do
64
+ context "when the relation exists" do
65
+ it "returns true" do
66
+ expect(subject.can?('pb:provider')).to be true
67
+ end
68
+ end
69
+
70
+ context "when the relation does not exist" do
71
+ it "returns false" do
72
+ expect(subject.can?('pb:consumer')).to be false
73
+ end
74
+ end
75
+ end
76
+
77
+ describe 'fetch' do
78
+ context 'when the key exist' do
79
+ it 'returns fetched value' do
80
+ expect(subject.fetch('pb:provider')).to be do
81
+ {href: 'http://provider'}
82
+ end
83
+ end
84
+ end
85
+ context "when the key doesn't not exist" do
86
+ it 'returns nil' do
87
+ expect(subject.fetch('i-dont-exist')).to be nil
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,105 @@
1
+ require 'pact_broker/client/hal/http_client'
2
+
3
+ module PactBroker::Client
4
+ module Hal
5
+ describe HttpClient do
6
+ before do
7
+ allow(Retry).to receive(:until_true) { |&block| block.call }
8
+ end
9
+
10
+ subject { HttpClient.new(username: 'foo', password: 'bar') }
11
+
12
+ describe "get" do
13
+ let!(:request) do
14
+ stub_request(:get, "http://example.org/").
15
+ with( headers: {
16
+ 'Accept'=>'application/hal+json',
17
+ 'Authorization'=>'Basic Zm9vOmJhcg=='
18
+ }).
19
+ to_return(status: 200, body: response_body, headers: {'Content-Type' => 'application/json'})
20
+ end
21
+
22
+ let(:response_body) { {some: 'json'}.to_json }
23
+ let(:do_get) { subject.get('http://example.org') }
24
+
25
+ it "performs a get request" do
26
+ do_get
27
+ expect(request).to have_been_made
28
+ end
29
+
30
+ context "with get params" do
31
+ let!(:request) do
32
+ stub_request(:get, "http://example.org/?foo=hello+world&bar=wiffle").
33
+ to_return(status: 200)
34
+ end
35
+
36
+ let(:do_get) { subject.get('http://example.org', { 'foo' => 'hello world', 'bar' => 'wiffle' }) }
37
+
38
+ it "correctly converts and encodes get params" do
39
+ do_get
40
+ expect(request).to have_been_made
41
+ end
42
+ end
43
+
44
+
45
+ it "retries on failure" do
46
+ expect(Retry).to receive(:until_true)
47
+ do_get
48
+ end
49
+
50
+ it "returns a response" do
51
+ expect(do_get.body).to eq({"some" => "json"})
52
+ end
53
+ end
54
+
55
+ describe "post" do
56
+ let!(:request) do
57
+ stub_request(:post, "http://example.org/").
58
+ with( headers: {
59
+ 'Accept'=>'application/hal+json',
60
+ 'Authorization'=>'Basic Zm9vOmJhcg==',
61
+ 'Content-Type'=>'application/json'
62
+ },
63
+ body: request_body).
64
+ to_return(status: 200, body: response_body, headers: {'Content-Type' => 'application/json'})
65
+ end
66
+
67
+ let(:request_body) { {some: 'data'}.to_json }
68
+ let(:response_body) { {some: 'json'}.to_json }
69
+
70
+ let(:do_post) { subject.post('http://example.org/', request_body) }
71
+
72
+ it "performs a post request" do
73
+ do_post
74
+ expect(request).to have_been_made
75
+ end
76
+
77
+ it "calls Retry.until_true" do
78
+ expect(Retry).to receive(:until_true)
79
+ do_post
80
+ end
81
+
82
+ it "returns a response" do
83
+ expect(do_post.body).to eq({"some" => "json"})
84
+ end
85
+
86
+ context "with custom headers" do
87
+ let!(:request) do
88
+ stub_request(:post, "http://example.org/").
89
+ with( headers: {
90
+ 'Accept'=>'foo'
91
+ }).
92
+ to_return(status: 200)
93
+ end
94
+
95
+ let(:do_post) { subject.post('http://example.org/', request_body, {"Accept" => "foo"} ) }
96
+
97
+ it "performs a post request with custom headers" do
98
+ do_post
99
+ expect(request).to have_been_made
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,108 @@
1
+ require 'pact_broker/client/hal/link'
2
+ require 'pact_broker/client/hal/entity'
3
+ require 'pact_broker/client/hal/http_client'
4
+
5
+ module PactBroker::Client
6
+ module Hal
7
+ describe Link do
8
+ let(:http_client) do
9
+ instance_double('PactBroker::Client::Hal::HttpClient', post: response)
10
+ end
11
+
12
+ let(:response) do
13
+ instance_double('PactBroker::Client::Hal::HttpClient::Response', success?: success, body: response_body)
14
+ end
15
+
16
+ let(:success) { true }
17
+
18
+ let(:entity) do
19
+ instance_double('PactBroker::Client::Hal::Entity')
20
+ end
21
+
22
+ let(:attrs) do
23
+ {
24
+ 'href' => 'http://foo/{bar}',
25
+ 'title' => 'title',
26
+ method: :post
27
+ }
28
+ end
29
+
30
+ let(:response_body) do
31
+ {
32
+ 'some' => 'body'
33
+ }
34
+ end
35
+
36
+ subject { Link.new(attrs, http_client) }
37
+
38
+ before do
39
+ allow(PactBroker::Client::Hal::Entity).to receive(:new).and_return(entity)
40
+ end
41
+
42
+ describe "#run" do
43
+ let(:do_run) { subject.run('foo' => 'bar') }
44
+
45
+ it "executes the configured http request" do
46
+ expect(http_client).to receive(:post)
47
+ do_run
48
+ end
49
+
50
+ it "creates an Entity" do
51
+ expect(PactBroker::Client::Hal::Entity).to receive(:new).with(response_body, http_client, response)
52
+ do_run
53
+ end
54
+
55
+ it "returns an Entity" do
56
+ expect(do_run).to eq entity
57
+ end
58
+
59
+ context "when an error response is returned" do
60
+ before do
61
+ allow(PactBroker::Client::Hal::ErrorEntity).to receive(:new).and_return(entity)
62
+ end
63
+
64
+ let(:success) { false }
65
+
66
+ it "creates an ErrorEntity" do
67
+ expect(PactBroker::Client::Hal::ErrorEntity).to receive(:new).with(response_body, http_client, response)
68
+ do_run
69
+ end
70
+ end
71
+ end
72
+
73
+ describe "#get" do
74
+ before do
75
+ allow(http_client).to receive(:get).and_return(response)
76
+ end
77
+
78
+ let(:do_get) { subject.get({ 'foo' => 'bar' }) }
79
+
80
+ it "executes an HTTP Get request" do
81
+ expect(http_client).to receive(:get).with('http://foo/{bar}', { 'foo' => 'bar' }, {})
82
+ do_get
83
+ end
84
+ end
85
+
86
+ describe "#post" do
87
+ let(:do_post) { subject.post({ 'foo' => 'bar' }, { 'Accept' => 'foo' }) }
88
+
89
+ context "with custom headers" do
90
+ it "executes an HTTP Post request with the custom headers" do
91
+ expect(http_client).to receive(:post).with('http://foo/{bar}', '{"foo":"bar"}', { 'Accept' => 'foo' })
92
+ do_post
93
+ end
94
+ end
95
+ end
96
+
97
+ describe "#expand" do
98
+ it "returns a duplicate Link with the expanded href" do
99
+ expect(subject.expand(bar: 'wiffle').href).to eq "http://foo/wiffle"
100
+ end
101
+
102
+ it "returns a duplicate Link with the expanded href with URL escaping" do
103
+ expect(subject.expand(bar: 'wiffle meep').href).to eq "http://foo/wiffle%20meep"
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end