pact_broker-client 0.0.6 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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