pact_broker-client 0.0.6 → 1.0.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 (31) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +12 -0
  3. data/Gemfile.lock +57 -32
  4. data/README.md +47 -0
  5. data/doc/markdown/Pact Broker Client - Pact Broker.md +582 -0
  6. data/doc/markdown/README.md +3 -0
  7. data/lib/pact_broker/client/base_client.rb +3 -1
  8. data/lib/pact_broker/client/pact_broker_client.rb +4 -3
  9. data/lib/pact_broker/client/pacticipants.rb +1 -1
  10. data/lib/pact_broker/client/pacts.rb +22 -6
  11. data/lib/pact_broker/client/publish_pacts.rb +16 -6
  12. data/lib/pact_broker/client/retry.rb +26 -0
  13. data/lib/pact_broker/client/tasks/publication_task.rb +3 -2
  14. data/lib/pact_broker/client/version.rb +1 -1
  15. data/lib/pact_broker/client/versions.rb +1 -1
  16. data/spec/lib/pact_broker/client/base_client_spec.rb +51 -0
  17. data/spec/lib/pact_broker/client/pact_broker_client_spec.rb +28 -1
  18. data/spec/lib/pact_broker/client/pacticipants_spec.rb +18 -0
  19. data/spec/lib/pact_broker/client/publish_pacts_spec.rb +67 -5
  20. data/spec/lib/pact_broker/client/tasks/publication_task_spec.rb +4 -2
  21. data/spec/lib/pact_broker/client/versions_spec.rb +18 -0
  22. data/spec/pacts/pact_broker_client-pact_broker.json +87 -91
  23. data/spec/service_providers/pact_broker_client_pacticipant_version_spec.rb +56 -0
  24. data/spec/service_providers/pact_broker_client_publish_spec.rb +34 -12
  25. data/spec/service_providers/pact_broker_client_register_repository_spec.rb +2 -2
  26. data/spec/service_providers/pact_broker_client_retrive_pact_spec.rb +4 -47
  27. data/spec/service_providers/pact_broker_client_tags_spec.rb +3 -3
  28. data/spec/support/pacticipant_get.json +3 -3
  29. data/spec/support/pacticipants_list.json +1 -1
  30. data/spec/support/pacts_latest_list.json +2 -2
  31. metadata +34 -45
@@ -0,0 +1,3 @@
1
+ ### Pacts for Pact Broker Client
2
+
3
+ * [Pact Broker Client](Pact Broker Client - Pact Broker.md)
@@ -26,11 +26,13 @@ module PactBroker
26
26
  include HTTParty
27
27
  include StringToSymbol
28
28
 
29
- attr_reader :base_url
29
+ attr_reader :base_url, :client_options
30
30
 
31
31
  def initialize options
32
32
  @base_url = options[:base_url]
33
+ @client_options = options[:client_options] || {}
33
34
  self.class.base_uri base_url
35
+ self.class.basic_auth(client_options[:basic_auth][:username], client_options[:basic_auth][:password]) if client_options[:basic_auth]
34
36
  end
35
37
 
36
38
  def default_request_headers
@@ -14,19 +14,20 @@ module PactBroker
14
14
 
15
15
  DEFAULT_OPTIONS = {base_url: DEFAULT_PACT_BROKER_BASE_URL}
16
16
 
17
- attr_reader :base_url
17
+ attr_reader :base_url, :client_options
18
18
 
19
19
  def initialize options = {}
20
20
  merged_options = DEFAULT_OPTIONS.merge(options)
21
21
  @base_url = merged_options[:base_url]
22
+ @client_options = merged_options[:client_options] || {}
22
23
  end
23
24
 
24
25
  def pacticipants
25
- PactBroker::Client::Pacticipants.new base_url: base_url
26
+ PactBroker::Client::Pacticipants.new base_url: base_url, client_options: client_options
26
27
  end
27
28
 
28
29
  def pacts
29
- PactBroker::Client::Pacts.new base_url: base_url
30
+ PactBroker::Client::Pacts.new base_url: base_url, client_options: client_options
30
31
  end
31
32
 
32
33
  end
@@ -5,7 +5,7 @@ module PactBroker
5
5
  class Pacticipants < BaseClient
6
6
 
7
7
  def versions
8
- Versions.new base_url: base_url
8
+ Versions.new base_url: base_url, client_options: client_options
9
9
  end
10
10
 
11
11
  def update options
@@ -13,7 +13,11 @@ module PactBroker
13
13
  url = save_consumer_contract_url consumer_contract, consumer_version
14
14
  response = self.class.put(url, body: pact_string, headers: default_put_headers)
15
15
  handle_response(response) do
16
- true
16
+ latest_link = find_latest_link JSON.parse(response.body)
17
+ if latest_link.nil?
18
+ "Please upgrade to the latest version of the pact broker to see the URL of the latest pact!"
19
+ end
20
+ latest_link
17
21
  end
18
22
  end
19
23
 
@@ -28,7 +32,7 @@ module PactBroker
28
32
  def list_latest
29
33
  response = self.class.get("/pacts/latest", headers: default_get_headers)
30
34
  handle_response(response) do
31
- map_pact_list_do_hash JSON.parse(response.body)["pacts"]
35
+ map_pact_list_to_hash JSON.parse(response.body)["pacts"]
32
36
  end
33
37
  end
34
38
 
@@ -43,7 +47,7 @@ module PactBroker
43
47
  private
44
48
 
45
49
  #TODO Move into mapper class
46
- def map_pact_list_do_hash pacts_list
50
+ def map_pact_list_to_hash pacts_list
47
51
  pacts_list.collect do | pact_hash |
48
52
  {
49
53
  consumer: {
@@ -59,6 +63,18 @@ module PactBroker
59
63
  end
60
64
  end
61
65
 
66
+ def find_latest_link response
67
+ links = response['_links']
68
+ return nil unless links
69
+ key = links.keys.find{ | key | key =~ /latest/ && key =~ /pact/ && key =~ /version/ }
70
+ return links[key]['href'] if key
71
+ key = links.keys.find{ | key | key =~ /latest/ && key =~ /pact/ }
72
+ return links[key]['href'] if key
73
+ nil
74
+ end
75
+
76
+
77
+
62
78
  def find_latest_consumer_contract_query options
63
79
  query = {:consumer => options[:consumer], :provider => options[:provider]}
64
80
  query[:tag] = options[:tag] if options[:tag]
@@ -69,21 +85,21 @@ module PactBroker
69
85
  consumer_name = encode_param(options[:consumer])
70
86
  provider_name = encode_param(options[:provider])
71
87
  tag = options[:tag] ? "/#{options[:tag]}" : ""
72
- "/pact/provider/#{provider_name}/consumer/#{consumer_name}/latest#{tag}"
88
+ "/pacts/provider/#{provider_name}/consumer/#{consumer_name}/latest#{tag}"
73
89
  end
74
90
 
75
91
  def get_consumer_contract_url options
76
92
  consumer_name = encode_param(options[:consumer])
77
93
  provider_name = encode_param(options[:provider])
78
94
  consumer_version = encode_param(options[:consumer_version])
79
- "/pact/provider/#{provider_name}/consumer/#{consumer_name}/version/#{consumer_version}"
95
+ "/pacts/provider/#{provider_name}/consumer/#{consumer_name}/version/#{consumer_version}"
80
96
  end
81
97
 
82
98
  def save_consumer_contract_url consumer_contract, consumer_version
83
99
  consumer_name = encode_param(consumer_contract.consumer.name)
84
100
  provider_name = encode_param(consumer_contract.provider.name)
85
101
  version = encode_param(consumer_version)
86
- "/pact/provider/#{provider_name}/consumer/#{consumer_name}/version/#{version}"
102
+ "/pacts/provider/#{provider_name}/consumer/#{consumer_name}/version/#{version}"
87
103
  end
88
104
  end
89
105
  end
@@ -1,39 +1,49 @@
1
1
  require 'pact_broker/client'
2
+ require 'pact_broker/client/retry'
2
3
 
3
4
  module PactBroker
4
5
  module Client
5
6
  class PublishPacts
6
7
 
7
- def initialize pact_broker_base_url, pact_files, consumer_version
8
+ def initialize pact_broker_base_url, pact_files, consumer_version, pact_broker_client_options={}
8
9
  @pact_broker_base_url = pact_broker_base_url
9
10
  @pact_files = pact_files
10
11
  @consumer_version = consumer_version
12
+ @pact_broker_client_options = pact_broker_client_options
11
13
  end
12
14
 
13
15
  def call
14
16
  validate
17
+ $stdout.puts("")
15
18
  pact_files.collect{ | pact_file | publish_pact pact_file }.all?
16
19
  end
17
20
 
18
21
  private
19
22
 
20
- attr_reader :pact_broker_base_url, :pact_files, :consumer_version
23
+ attr_reader :pact_broker_base_url, :pact_files, :consumer_version, :pact_broker_client_options
21
24
 
22
25
  def pact_broker_client
23
- @pact_broker_client ||= PactBroker::Client::PactBrokerClient.new(base_url: pact_broker_base_url)
26
+ @pact_broker_client ||= PactBroker::Client::PactBrokerClient.new(base_url: pact_broker_base_url, client_options: pact_broker_client_options)
24
27
  end
25
28
 
26
29
  def publish_pact pact_file
27
30
  begin
28
- puts "Publishing #{pact_file} to pact broker at #{pact_broker_base_url}"
29
- pact_broker_client.pacticipants.versions.pacts.publish(pact_json: File.read(pact_file), consumer_version: consumer_version)
30
- true
31
+ $stdout.puts ">> Publishing #{pact_file} to pact broker at #{pact_broker_base_url}"
32
+ publish_pact_contents File.read(pact_file)
31
33
  rescue => e
32
34
  $stderr.puts "Failed to publish pact: #{pact_file} due to error: #{e.to_s}\n#{e.backtrace.join("\n")}"
33
35
  false
34
36
  end
35
37
  end
36
38
 
39
+ def publish_pact_contents pact_file_contents
40
+ Retry.until_true do
41
+ latest_pact_url = pact_broker_client.pacticipants.versions.pacts.publish(pact_json: pact_file_contents, consumer_version: consumer_version)
42
+ $stdout.puts "The latest version of this pact can be accessed at the following URL (use this to configure the provider verification):\n#{latest_pact_url}\n\n"
43
+ true
44
+ end
45
+ end
46
+
37
47
  def validate
38
48
  raise "Please specify the consumer_version" unless (consumer_version && consumer_version.to_s.strip.size > 0)
39
49
  raise "Please specify the pact_broker_base_url" unless (pact_broker_base_url && pact_broker_base_url.to_s.strip.size > 0)
@@ -0,0 +1,26 @@
1
+ module PactBroker
2
+ module Client
3
+ class Retry
4
+
5
+ def self.until_true options = {}
6
+ max_tries = options.fetch(:times, 3)
7
+ tries = 0
8
+ while true
9
+ begin
10
+ return yield
11
+ rescue StandardError => e
12
+ tries += 1
13
+ $stderr.puts "Error publishing pact - #{e.message}, attempt #{tries} of #{max_tries}"
14
+ sleep options
15
+ raise e if max_tries == tries
16
+ end
17
+ end
18
+ end
19
+
20
+ def self.sleep options
21
+ Kernel.sleep options.fetch(:sleep, 5)
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -15,7 +15,7 @@ module PactBroker
15
15
  module Client
16
16
  class PublicationTask < ::Rake::TaskLib
17
17
 
18
- attr_accessor :pattern, :pact_broker_base_url, :consumer_version
18
+ attr_accessor :pattern, :pact_broker_base_url, :consumer_version, :pact_broker_basic_auth
19
19
 
20
20
  def initialize name = nil, &block
21
21
  @name = name
@@ -32,7 +32,8 @@ module PactBroker
32
32
  task task_name do
33
33
  block.call(self)
34
34
  require 'pact_broker/client/publish_pacts'
35
- success = PactBroker::Client::PublishPacts.new(pact_broker_base_url, FileList[pattern], consumer_version).call
35
+ pact_broker_client_options = pact_broker_basic_auth ? {basic_auth: pact_broker_basic_auth} :{}
36
+ success = PactBroker::Client::PublishPacts.new(pact_broker_base_url, FileList[pattern], consumer_version, pact_broker_client_options).call
36
37
  raise "One or more pacts failed to be published" unless success
37
38
  end
38
39
  end
@@ -1,5 +1,5 @@
1
1
  module PactBroker
2
2
  module Client
3
- VERSION = '0.0.6'
3
+ VERSION = '1.0.0'
4
4
  end
5
5
  end
@@ -32,7 +32,7 @@ module PactBroker
32
32
  end
33
33
 
34
34
  def pacts
35
- Pacts.new base_url: base_url
35
+ Pacts.new base_url: base_url, client_options: client_options
36
36
  end
37
37
 
38
38
  private
@@ -0,0 +1,51 @@
1
+ require 'pact_broker/client/base_client'
2
+ module PactBroker
3
+ module Client
4
+ describe BaseClient do
5
+ describe '#initialize' do
6
+ let(:base_url) { 'http://pact_broker_base_url'}
7
+ let(:username) { 'pact_repo_username'}
8
+ let(:password) { 'pact_repo_password'}
9
+ let(:client_options) do
10
+ {
11
+ basic_auth: {
12
+ username: username,
13
+ password: password
14
+ }
15
+ }
16
+ end
17
+ context 'with basic url' do
18
+ it 'should set base url' do
19
+ base_client = BaseClient.new(base_url: base_url)
20
+ expect(base_client.base_url).to eq(base_url)
21
+ expect(BaseClient.base_uri).to eq(base_url)
22
+ end
23
+ end
24
+
25
+ context 'with client options' do
26
+ subject { BaseClient.new(base_url: base_url, client_options: client_options) }
27
+ it 'should set client options ' do
28
+ expect(subject.client_options).to eq(client_options)
29
+ end
30
+
31
+ it 'should set httpparty basic auth when client options contains basic auth' do
32
+ expect(BaseClient).to receive(:basic_auth).with(username, password)
33
+ subject
34
+ end
35
+ end
36
+
37
+ context 'without client options' do
38
+ subject { BaseClient.new(base_url: base_url) }
39
+ it 'should set client options to empty hash ' do
40
+ expect(subject.client_options).to eq({})
41
+ end
42
+
43
+ it 'should not set httpparty basic auth' do
44
+ expect(BaseClient).to_not receive(:basic_auth).with(username, password)
45
+ subject
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -5,14 +5,41 @@ require 'pact_broker/client'
5
5
  module PactBroker::Client
6
6
  describe PactBrokerClient do
7
7
 
8
+ let(:client_options) do
9
+ { some_option: 'option value'}
10
+ end
11
+ let(:base_url) { 'https://blah' }
12
+
8
13
  describe 'initialize' do
9
14
  subject { PactBrokerClient.new }
10
15
  it 'sets the base_uri to http://pact-broker by default' do
11
16
  expect(subject.base_url).to eq('http://pact-broker')
12
17
  end
13
18
 
19
+ it 'sets the client options to empty hash by default' do
20
+ expect(subject.client_options).to eq({})
21
+ end
22
+
14
23
  it 'allows configuration of the base_uri' do
15
- expect(PactBrokerClient.new(base_url: 'https://blah').base_url).to eq('https://blah')
24
+ expect(PactBrokerClient.new(base_url: base_url).base_url).to eq(base_url)
25
+ end
26
+
27
+ it 'allows configuration of the client options' do
28
+ expect(PactBrokerClient.new(client_options: client_options).client_options).to eq(client_options)
29
+ end
30
+ end
31
+
32
+ describe 'pacticipants' do
33
+ it 'initializes pacticipants with base url and client options' do
34
+ expect(PactBroker::Client::Pacticipants).to receive(:new).with(base_url: base_url, client_options: client_options)
35
+ PactBrokerClient.new(base_url: base_url, client_options: client_options).pacticipants
36
+ end
37
+ end
38
+
39
+ describe 'pacts' do
40
+ it 'initializes [act] with base url and client options' do
41
+ expect(PactBroker::Client::Pacts).to receive(:new).with(base_url: base_url, client_options: client_options)
42
+ PactBrokerClient.new(base_url: base_url, client_options: client_options).pacts
16
43
  end
17
44
  end
18
45
  end
@@ -0,0 +1,18 @@
1
+ require 'pact_broker/client/pacticipants'
2
+ module PactBroker
3
+ module Client
4
+ describe Pacticipants do
5
+ let(:client_options) do
6
+ { some_option: 'option value'}
7
+ end
8
+ let(:base_url) { 'https://blah' }
9
+
10
+ describe 'versions' do
11
+ it 'initializes versions with base url and client options' do
12
+ expect(PactBroker::Client::Versions).to receive(:new).with(base_url: base_url, client_options: client_options)
13
+ Pacticipants.new(base_url: base_url, client_options: client_options).versions
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -9,22 +9,31 @@ module PactBroker
9
9
 
10
10
  before do
11
11
  FakeFS.activate!
12
- pacts_client.stub(:publish)
13
- PactBroker::Client::PactBrokerClient.stub(:new).with(base_url: pact_broker_base_url).and_return(pact_broker_client)
12
+ pacts_client.stub(:publish).and_return(latest_pact_url)
13
+ PactBroker::Client::PactBrokerClient.stub(:new).with(base_url: pact_broker_base_url, client_options: pact_broker_client_options).and_return(pact_broker_client)
14
14
  end
15
15
 
16
16
  after do
17
17
  FakeFS.deactivate!
18
18
  end
19
19
 
20
+ let(:latest_pact_url) { 'http://example.org/latest/pact' }
20
21
  let(:pact_broker_client) { double("PactBroker::Client")}
21
22
  let(:pact_files) { ['spec/pacts/consumer-provider.json']}
22
23
  let(:consumer_version) { "1.2.3" }
23
24
  let(:pact_hash) { {consumer: {name: 'Consumer'}, provider: {name: 'Provider'} } }
24
25
  let(:pacts_client) { instance_double("PactBroker::ClientSupport::Pacts")}
25
26
  let(:pact_broker_base_url) { 'http://some-host'}
27
+ let(:pact_broker_client_options) do
28
+ {
29
+ basic_auth: {
30
+ username: 'user',
31
+ password: 'pass'
32
+ }
33
+ }
34
+ end
26
35
 
27
- subject { PublishPacts.new(pact_broker_base_url, pact_files, consumer_version) }
36
+ subject { PublishPacts.new(pact_broker_base_url, pact_files, consumer_version, pact_broker_client_options) }
28
37
 
29
38
  before do
30
39
  FileUtils.mkdir_p "spec/pacts"
@@ -40,13 +49,20 @@ module PactBroker
40
49
  end
41
50
 
42
51
  context "when publishing is successful" do
52
+
53
+ it "puts the location of the latest pact" do
54
+ allow($stdout).to receive(:puts)
55
+ expect($stdout).to receive(:puts).with(/#{latest_pact_url}/)
56
+ subject.call
57
+ end
43
58
  it "returns true" do
44
- expect(subject.call).to be_true
59
+ expect(subject.call).to be true
45
60
  end
46
61
  end
47
62
 
48
63
  context "when publishing one or more pacts fails" do
49
64
  let(:pact_files) { ['spec/pacts/doesnotexist.json','spec/pacts/consumer-provider.json']}
65
+
50
66
  before do
51
67
  $stderr.stub(:puts)
52
68
  end
@@ -62,7 +78,7 @@ module PactBroker
62
78
  end
63
79
 
64
80
  it "returns false" do
65
- expect(subject.call).to be_false
81
+ expect(subject.call).to be false
66
82
  end
67
83
  end
68
84
 
@@ -86,6 +102,52 @@ module PactBroker
86
102
  expect { subject.call }.to raise_error(/Please specify the pact_broker_base_url/)
87
103
  end
88
104
  end
105
+
106
+ context "when an error occurs every time while publishing a pact" do
107
+
108
+ before do
109
+ allow(Retry).to receive(:sleep)
110
+ allow(pacts_client).to receive(:publish).and_raise("an error")
111
+ allow($stderr).to receive(:puts)
112
+ end
113
+
114
+ it "retries multiple times" do
115
+ expect(pacts_client).to receive(:publish).exactly(3).times
116
+ subject.call
117
+ end
118
+
119
+ it "returns false" do
120
+ expect(subject.call).to eq false
121
+ end
122
+ end
123
+
124
+ context "when an error occurs less than the maximum number of retries" do
125
+
126
+ before do
127
+ allow(Retry).to receive(:sleep)
128
+ tries = 0
129
+ allow(pacts_client).to receive(:publish) do
130
+ if tries == 0
131
+ tries += 1
132
+ raise "an error"
133
+ else
134
+ latest_pact_url
135
+ end
136
+ end
137
+ allow($stderr).to receive(:puts)
138
+ end
139
+
140
+ it "retries multiple times" do
141
+ expect(pacts_client).to receive(:publish).exactly(2).times
142
+ subject.call
143
+ end
144
+
145
+ it "returns true" do
146
+ expect(subject.call).to eq true
147
+ end
148
+
149
+ end
150
+
89
151
  end
90
152
  end
91
153
  end