pact_broker 2.18.0 → 2.19.0

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