pact_broker 2.18.0 → 2.19.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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +7 -0
  3. data/CHANGELOG.md +21 -0
  4. data/README.md +5 -2
  5. data/example/example_data.sql +2 -0
  6. data/lib/pact_broker/api.rb +5 -0
  7. data/lib/pact_broker/api/decorators/pacticipant_decorator.rb +8 -0
  8. data/lib/pact_broker/api/decorators/provider_pacts_decorator.rb +12 -7
  9. data/lib/pact_broker/api/pact_broker_urls.rb +4 -0
  10. data/lib/pact_broker/api/resources/badge.rb +3 -1
  11. data/lib/pact_broker/api/resources/error_handler.rb +5 -1
  12. data/lib/pact_broker/api/resources/error_test.rb +2 -2
  13. data/lib/pact_broker/api/resources/index.rb +13 -1
  14. data/lib/pact_broker/api/resources/latest_provider_pacts.rb +7 -19
  15. data/lib/pact_broker/api/resources/pact_content_diff.rb +14 -2
  16. data/lib/pact_broker/api/resources/pact_version.rb +13 -0
  17. data/lib/pact_broker/api/resources/provider_pacts.rb +45 -0
  18. data/lib/pact_broker/api/resources/version.rb +1 -1
  19. data/lib/pact_broker/domain/verification.rb +1 -2
  20. data/lib/pact_broker/error.rb +1 -0
  21. data/lib/pact_broker/matrix/repository.rb +39 -28
  22. data/lib/pact_broker/matrix/service.rb +2 -6
  23. data/lib/pact_broker/pacts/diff.rb +24 -13
  24. data/lib/pact_broker/pacts/pact_params.rb +10 -0
  25. data/lib/pact_broker/pacts/repository.rb +18 -0
  26. data/lib/pact_broker/pacts/service.rb +4 -0
  27. data/lib/pact_broker/pacts/sort_verifiable_content.rb +41 -0
  28. data/lib/pact_broker/ui/controllers/error_test.rb +1 -1
  29. data/lib/pact_broker/ui/controllers/matrix.rb +5 -6
  30. data/lib/pact_broker/ui/views/matrix/show.haml +15 -17
  31. data/lib/pact_broker/verifications/repository.rb +3 -3
  32. data/lib/pact_broker/version.rb +1 -1
  33. data/lib/pact_broker/versions/repository.rb +11 -1
  34. data/lib/pact_broker/versions/service.rb +2 -2
  35. data/public/javascripts/matrix.js +40 -33
  36. data/spec/features/get_pact_version.rb +13 -0
  37. data/spec/features/get_provider_pacts_spec.rb +33 -12
  38. data/spec/lib/pact_broker/api/decorators/pacticipant_decorator_spec.rb +12 -1
  39. data/spec/lib/pact_broker/api/decorators/provider_pacts_decorator_spec.rb +57 -0
  40. data/spec/lib/pact_broker/api/pact_broker_urls_spec.rb +16 -0
  41. data/spec/lib/pact_broker/api/resources/badge_spec.rb +3 -3
  42. data/spec/lib/pact_broker/api/resources/error_handler_spec.rb +19 -1
  43. data/spec/lib/pact_broker/api/resources/latest_provider_pacts_spec.rb +52 -0
  44. data/spec/lib/pact_broker/api/resources/provider_pacts_spec.rb +75 -0
  45. data/spec/lib/pact_broker/matrix/repository_spec.rb +52 -0
  46. data/spec/lib/pact_broker/matrix/service_spec.rb +1 -17
  47. data/spec/lib/pact_broker/pacts/diff_spec.rb +34 -7
  48. data/spec/lib/pact_broker/pacts/pact_params_spec.rb +33 -8
  49. data/spec/lib/pact_broker/pacts/repository_spec.rb +65 -1
  50. data/spec/lib/pact_broker/pacts/sort_verifiable_content_spec.rb +25 -0
  51. data/spec/lib/pact_broker/verifications/repository_spec.rb +44 -17
  52. data/spec/lib/pact_broker/versions/repository_spec.rb +2 -2
  53. data/spec/support/test_data_builder.rb +4 -0
  54. data/tasks/rspec.rake +6 -4
  55. metadata +17 -2
@@ -0,0 +1,13 @@
1
+ describe "retrieving a pact" do
2
+ subject { get path; last_response }
3
+
4
+ context "when differing case is used in the consumer and provider names" do
5
+ let(:td) { TestDataBuilder.new }
6
+ let(:pact) { td.create_pact_with_hierarchy("Foo", "1", "Bar").and_return(:pact) }
7
+ let!(:path) { "/pacts/provider/Bar/consumer/Foo/pact-version/#{pact.pact_version_sha}" }
8
+
9
+ it "returns a 200 Success" do
10
+ expect(subject.status).to be 200
11
+ end
12
+ end
13
+ end
@@ -1,18 +1,16 @@
1
- require 'spec/support/test_data_builder'
2
-
3
1
  describe "Get provider pacts" do
4
-
5
- let(:path) { "/pacts/provider/Provider/latest" }
6
2
  let(:last_response_body) { JSON.parse(subject.body, symbolize_names: true) }
7
-
3
+ let(:pact_links) { last_response_body[:_links][:'pb:pacts'] }
8
4
  subject { get path; last_response }
9
5
 
10
6
  context "when the provider exists" do
11
-
12
7
  before do
13
8
  TestDataBuilder.new
14
9
  .create_provider("Provider")
15
10
  .create_consumer("Consumer")
11
+ .create_consumer_version("0.0.1")
12
+ .create_consumer_version_tag("prod")
13
+ .create_pact
16
14
  .create_consumer_version("1.0.0")
17
15
  .create_consumer_version_tag("prod")
18
16
  .create_pact
@@ -20,22 +18,23 @@ describe "Get provider pacts" do
20
18
  .create_pact
21
19
  .create_consumer("Consumer 2")
22
20
  .create_consumer_version("4.5.6")
21
+ .create_consumer_version_tag("prod")
23
22
  .create_pact
24
23
  end
25
24
 
26
25
  context "with no tag specified" do
26
+ let(:path) { "/pacts/provider/Provider/latest" }
27
27
 
28
28
  it "returns a 200 HAL JSON response" do
29
29
  expect(subject).to be_a_hal_json_success_response
30
30
  end
31
31
 
32
32
  it "returns a list of links to the pacts" do
33
- expect(last_response_body[:_links][:pacts].size).to eq 2
33
+ expect(pact_links.size).to eq 2
34
34
  end
35
35
  end
36
36
 
37
37
  context "with a tag specified" do
38
-
39
38
  let(:path) { "/pacts/provider/Provider/latest/prod" }
40
39
 
41
40
  it "returns a 200 HAL JSON response" do
@@ -43,12 +42,11 @@ describe "Get provider pacts" do
43
42
  end
44
43
 
45
44
  it "returns a list of links to the pacts" do
46
- expect(last_response_body[:_links][:pacts].size).to eq 1
45
+ expect(pact_links.size).to eq 2
47
46
  end
48
47
  end
49
48
 
50
49
  context "with a tag with no pacts" do
51
-
52
50
  let(:path) { "/pacts/provider/Provider/latest/foo" }
53
51
 
54
52
  it "returns a 200 HAL JSON response" do
@@ -56,17 +54,40 @@ describe "Get provider pacts" do
56
54
  end
57
55
 
58
56
  it "returns a list of links to the pacts" do
59
- expect(last_response_body[:_links][:pacts].size).to eq 0
57
+ expect(pact_links.size).to eq 0
60
58
  end
61
59
  end
62
60
 
61
+ context "with a tag for all pacts" do
62
+ let(:path) { "/pacts/provider/Provider/tag/prod" }
63
+
64
+ it "returns a 200 HAL JSON response" do
65
+ expect(subject).to be_a_hal_json_success_response
66
+ end
67
+
68
+ it "returns a list of links to the pacts" do
69
+ expect(pact_links.size).to eq 3
70
+ end
71
+ end
72
+
73
+ context "with no tag for all pacts" do
74
+ let(:path) { "/pacts/provider/Provider" }
75
+
76
+ it "returns a 200 HAL JSON response" do
77
+ expect(subject).to be_a_hal_json_success_response
78
+ end
79
+
80
+ it "returns a list of links to the pacts" do
81
+ expect(last_response_body[:_links][:'pb:pacts'].size).to eq 4
82
+ end
83
+ end
63
84
  end
64
85
 
65
86
  context "when the provider does not exist" do
87
+ let(:path) { "/pacts/provider/Provider" }
66
88
 
67
89
  it "returns a 404 response" do
68
90
  expect(subject).to be_a_404_response
69
91
  end
70
-
71
92
  end
72
93
  end
@@ -20,13 +20,15 @@ module PactBroker
20
20
 
21
21
  let(:created_at) { Time.new(2014, 3, 4) }
22
22
  let(:updated_at) { Time.new(2014, 3, 5) }
23
+ let(:base_url) { 'http://example.org' }
23
24
 
24
25
  before do
25
26
  pacticipant.created_at = created_at
26
27
  pacticipant.updated_at = updated_at
28
+ allow_any_instance_of(PacticipantDecorator).to receive(:templated_tag_url_for_pacticipant).and_return('version_tag_url')
27
29
  end
28
30
 
29
- subject { JSON.parse PacticipantDecorator.new(pacticipant).to_json(user_options: {base_url: 'http://example.org'}), symbolize_names: true }
31
+ subject { JSON.parse PacticipantDecorator.new(pacticipant).to_json(user_options: {base_url: base_url}), symbolize_names: true }
30
32
 
31
33
  it "includes timestamps" do
32
34
  expect(subject[:createdAt]).to eq created_at.xmlschema
@@ -38,6 +40,15 @@ module PactBroker
38
40
  expect(subject[:_embedded][:labels].first[:_links][:self][:href]).to match %r{http://example.org/.*foo}
39
41
  end
40
42
 
43
+ it "creates the URL for a version tag" do
44
+ expect_any_instance_of(PacticipantDecorator).to receive(:templated_tag_url_for_pacticipant).with("Name", base_url)
45
+ subject
46
+ end
47
+
48
+ it "includes a relation for a version tag" do
49
+ expect(subject[:_links][:'pb:version-tag'][:href]).to eq "version_tag_url"
50
+ end
51
+
41
52
  context "when there is a latest_version" do
42
53
  before { test_data_builder.create_version("1.2.107") }
43
54
  it "includes an embedded latestVersion" do
@@ -0,0 +1,57 @@
1
+ require 'pact_broker/api/decorators/provider_pacts_decorator'
2
+
3
+ module PactBroker
4
+ module Api
5
+ module Decorators
6
+ describe ProviderPactsDecorator do
7
+
8
+ let(:pacts) { [pact]}
9
+ let(:pact) do
10
+ double('pact', name: 'Pact name', consumer_name: 'Foo')
11
+ end
12
+ let(:user_options) do
13
+ {
14
+ base_url: 'http://example.org',
15
+ resource_url: 'http://example.org/provider-pacts',
16
+ title: 'title'
17
+ }
18
+ end
19
+
20
+ before do
21
+ allow_any_instance_of(ProviderPactsDecorator).to receive(:pact_url).and_return('pact_url')
22
+ end
23
+
24
+ subject { JSON.parse ProviderPactsDecorator.new(pacts).to_json(user_options: user_options), symbolize_names: true }
25
+
26
+ let(:expected) do
27
+ {
28
+ :_links => {
29
+ :self=> {
30
+ :href=> "http://example.org/provider-pacts",
31
+ :title => "title"
32
+ },
33
+ :provider => {
34
+ :href => "http://example.org/pacticipants/",
35
+ :title => nil
36
+ },
37
+ :"pb:pacts" =>[{
38
+ :href => "pact_url",
39
+ :title => "Pact name",
40
+ :name => "Foo" }],
41
+ :pacts => [{
42
+ :href => "pact_url",
43
+ :title => "DEPRECATED - please use the pb:pacts relation",
44
+ :name => "Foo"
45
+ }
46
+ ]
47
+ }
48
+ }
49
+ end
50
+
51
+ it "matches the expected JSON" do
52
+ expect(subject).to match_pact(expected)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,16 @@
1
+ require 'pact_broker/api/pact_broker_urls'
2
+
3
+ module PactBroker
4
+ module Api
5
+ describe PactBrokerUrls do
6
+
7
+ let(:base_url) { "http://example.org" }
8
+
9
+ describe "templated_tag_url_for_pacticipant" do
10
+ subject { PactBrokerUrls.templated_tag_url_for_pacticipant("Bar", base_url) }
11
+
12
+ it { is_expected.to eq "http://example.org/pacticipants/Bar/versions/{version}/tags/{tag}" }
13
+ end
14
+ end
15
+ end
16
+ end
@@ -16,10 +16,10 @@ module PactBroker
16
16
  allow(PactBroker::Verifications::Status).to receive(:new).and_return(verification_status)
17
17
  end
18
18
 
19
- let(:pact) { instance_double("PactBroker::Domain::Pact", consumer: consumer, provider: provider, consumer_version_number: "2") }
19
+ let(:pact) { instance_double("PactBroker::Domain::Pact", consumer: consumer, provider: provider, consumer_version_number: "2", revision_number: "1") }
20
20
  let(:consumer) { double('consumer') }
21
21
  let(:provider) { double('provider') }
22
- let(:verification) { double("verification", provider_version_number: "3") }
22
+ let(:verification) { double("verification", provider_version_number: "3", number: "7") }
23
23
  let(:verification_status) { instance_double("PactBroker::Verifications::Status", to_sym: :verified) }
24
24
 
25
25
 
@@ -86,7 +86,7 @@ module PactBroker
86
86
  end
87
87
 
88
88
  it "returns a comment with the consumer and provider numbers" do
89
- expect(subject.body).to include "<!-- consumer version 2 provider version 3 -->"
89
+ expect(subject.body).to include "<!-- consumer version 2 revision 1 provider version 3 number 7 -->"
90
90
  end
91
91
 
92
92
  context "when the label param is specified" do
@@ -5,7 +5,7 @@ module PactBroker
5
5
  module Resources
6
6
  describe ErrorHandler do
7
7
  describe "call" do
8
- let(:error) { PactBroker::Error.new('test error') }
8
+ let(:error) { StandardError.new('test error') }
9
9
  let(:thing) { double('thing', call: nil, another_call: nil) }
10
10
  let(:options) { { env: env } }
11
11
  let(:request) { double('request' ) }
@@ -31,6 +31,24 @@ module PactBroker
31
31
  subject
32
32
  end
33
33
 
34
+ context "when the error is a PactBroker::Error or subclass" do
35
+ let(:error) { Class.new(PactBroker::Error).new('test error') }
36
+
37
+ it "does not invoke the api error reporters" do
38
+ expect(thing).to_not receive(:call).with(error, options)
39
+ subject
40
+ end
41
+ end
42
+
43
+ context "when the error is a PactBroker::TestError" do
44
+ let(:error) { PactBroker::TestError.new('test error') }
45
+
46
+ it "invokes the api error reporters" do
47
+ expect(thing).to receive(:call).with(error, options)
48
+ subject
49
+ end
50
+ end
51
+
34
52
  context "when the error reporter raises an error itself" do
35
53
  class TestError < StandardError; end
36
54
 
@@ -0,0 +1,52 @@
1
+ require 'pact_broker/api/resources/latest_provider_pacts'
2
+
3
+ module PactBroker
4
+ module Api
5
+ module Resources
6
+ describe LatestProviderPacts do
7
+ before do
8
+ allow(PactBroker::Pacts::Service).to receive(:find_latest_pact_versions_for_provider).and_return(pacts)
9
+ allow(PactBroker::Api::Decorators::ProviderPactsDecorator).to receive(:new).and_return(decorator)
10
+ allow_any_instance_of(LatestProviderPacts).to receive(:resource_exists?).and_return(provider)
11
+ end
12
+
13
+ let(:provider) { double('provider') }
14
+ let(:pacts) { double('pacts') }
15
+ let(:path) { '/pacts/provider/Bar/latest' }
16
+ let(:decorator) { instance_double('PactBroker::Api::Decorators::ProviderPactsDecorator') }
17
+
18
+ subject { get path; last_response }
19
+
20
+ context "with no tag" do
21
+ it "finds the pacts" do
22
+ expect(PactBroker::Pacts::Service).to receive(:find_latest_pact_versions_for_provider).with("Bar", tag: nil)
23
+ subject
24
+ end
25
+
26
+ it "sets the correct resource title" do
27
+ expect(decorator).to receive(:to_json) do | options |
28
+ expect(options[:user_options][:title]).to eq "Latest pact versions for the provider Bar"
29
+ end
30
+ subject
31
+ end
32
+ end
33
+
34
+ context "with a tag" do
35
+ let(:path) { '/pacts/provider/Bar/latest/prod' }
36
+
37
+ it "finds the pacts with a tag" do
38
+ expect(PactBroker::Pacts::Service).to receive(:find_latest_pact_versions_for_provider).with("Bar", tag: "prod")
39
+ subject
40
+ end
41
+
42
+ it "sets the correct resource title" do
43
+ expect(decorator).to receive(:to_json) do | options |
44
+ expect(options[:user_options][:title]).to eq "Latest pact versions for the provider Bar with consumer version tag 'prod'"
45
+ end
46
+ subject
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,75 @@
1
+ require 'pact_broker/api/resources/provider_pacts'
2
+
3
+ module PactBroker
4
+ module Api
5
+ module Resources
6
+ describe ProviderPacts do
7
+ before do
8
+ allow(PactBroker::Pacts::Service).to receive(:find_latest_pact_versions_for_provider).and_return(pacts)
9
+ allow(PactBroker::Api::Decorators::ProviderPactsDecorator).to receive(:new).and_return(decorator)
10
+ allow(PactBroker::Pacticipants::Service).to receive(:find_pacticipant_by_name).and_return(provider)
11
+ end
12
+
13
+ let(:provider) { double('provider') }
14
+ let(:pacts) { double('pacts') }
15
+ let(:decorator) { instance_double('PactBroker::Api::Decorators::ProviderPactsDecorator', to_json: json) }
16
+ let(:json) { {some: 'json'}.to_json }
17
+ let(:path) { '/pacts/provider/Bar' }
18
+
19
+ subject { get path; last_response }
20
+
21
+ it "finds the pacticipant" do
22
+ expect(PactBroker::Pacticipants::Service).to receive(:find_pacticipant_by_name).with("Bar")
23
+ subject
24
+ end
25
+
26
+ it "returns a 200 response status" do
27
+ expect(subject.status).to eq 200
28
+ end
29
+
30
+ it "returns a json response" do
31
+ expect(subject.headers['Content-Type']).to eq "application/hal+json;charset=utf-8"
32
+ expect(subject.body).to eq json
33
+ end
34
+
35
+ context "with no tag" do
36
+ it "finds all the pacts for the given provider" do
37
+ expect(PactBroker::Pacts::Service).to receive(:find_pact_versions_for_provider).with("Bar", tag: nil)
38
+ subject
39
+ end
40
+
41
+ it "sets the correct resource title" do
42
+ expect(decorator).to receive(:to_json) do | options |
43
+ expect(options[:user_options][:title]).to eq "All pact versions for the provider Bar"
44
+ end
45
+ subject
46
+ end
47
+ end
48
+
49
+ context "with a tag" do
50
+ let(:path) { '/pacts/provider/Bar/tag/prod' }
51
+
52
+ it "finds all the pacts with the given tag for the provider" do
53
+ expect(PactBroker::Pacts::Service).to receive(:find_pact_versions_for_provider).with("Bar", tag: "prod")
54
+ subject
55
+ end
56
+
57
+ it "sets the correct resource title" do
58
+ expect(decorator).to receive(:to_json) do | options |
59
+ expect(options[:user_options][:title]).to eq "All pact versions for the provider Bar with consumer version tag 'prod'"
60
+ end
61
+ subject
62
+ end
63
+ end
64
+
65
+ context "with the pacticipant does not exist" do
66
+ let(:provider) { nil }
67
+
68
+ it "returns a 404" do
69
+ expect(subject.status).to eq 404
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -479,6 +479,58 @@ module PactBroker
479
479
  end
480
480
  end
481
481
 
482
+ context "when compability is required with all versions with a given tag" do
483
+ before do
484
+ td.create_pact_with_hierarchy("android app", "1", "BFF")
485
+ .create_consumer_version_tag("prod")
486
+ .create_verification(provider_version: "5", comment: "included")
487
+ .create_consumer_version("2", tag_name: "prod")
488
+ .create_pact
489
+ .create_verification(provider_version: "5", comment: "included")
490
+ .create_consumer_version("3")
491
+ .create_pact
492
+ .create_verification(provider_version: "5", comment: "not included")
493
+ .create_consumer("ios app")
494
+ .create_consumer_version("20", tag_name: "prod")
495
+ .create_pact
496
+ .create_verification(provider_version: "5", comment: "not included")
497
+ end
498
+
499
+ context "when the other service is specifically named" do
500
+ let(:selectors) do
501
+ [
502
+ { pacticipant_name: "android app", tag: "prod" },
503
+ { pacticipant_name: "BFF", pacticipant_version_number: "5" }
504
+ ]
505
+ end
506
+
507
+ let(:options) { {} }
508
+
509
+ it "returns the matrix for all of the versions for the specified pacticipants with the given tag" do
510
+ expect(subject).to include_hash_matching(consumer_version_number: "1")
511
+ expect(subject).to include_hash_matching(consumer_version_number: "2")
512
+ expect(subject).to_not include_hash_matching(consumer_version_number: "3")
513
+ expect(subject).to_not include_hash_matching(consumer_name: "ios app")
514
+ end
515
+ end
516
+
517
+ context "when the other service is not specifically named" do
518
+ let(:selectors) do
519
+ [
520
+ { pacticipant_name: "BFF", pacticipant_version_number: "5" }
521
+ ]
522
+ end
523
+
524
+ let(:options) { { tag: "prod" } }
525
+
526
+ it "returns the matrix for all of the versions with the given tag" do
527
+ expect(subject).to include_hash_matching(consumer_name: "android app", consumer_version_number: "1")
528
+ expect(subject).to include_hash_matching(consumer_name: "android app", consumer_version_number: "2")
529
+ expect(subject).to include_hash_matching(consumer_name: "ios app", consumer_version_number: "20")
530
+ end
531
+ end
532
+ end
533
+
482
534
  context "using the success option" do
483
535
  before do
484
536
  td.create_pact_with_hierarchy("A", "1.2.3", "B")