pact_broker 2.58.0 → 2.58.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/release_gem.yml +25 -0
  3. data/.travis.yml +5 -3
  4. data/CHANGELOG.md +8 -0
  5. data/DEVELOPER_SETUP.md +46 -16
  6. data/Dockerfile +23 -2
  7. data/Gemfile +29 -2
  8. data/config.ru +32 -12
  9. data/config/database.yml +7 -0
  10. data/docker-compose-dev-postgres.yml +35 -0
  11. data/docker-compose-test.yml +100 -0
  12. data/lib/pact_broker/api/decorators/decorator_context.rb +1 -1
  13. data/lib/pact_broker/api/pact_broker_urls.rb +4 -4
  14. data/lib/pact_broker/api/paths.rb +15 -0
  15. data/lib/pact_broker/api/resources/all_webhooks.rb +3 -3
  16. data/lib/pact_broker/api/resources/base_resource.rb +2 -174
  17. data/lib/pact_broker/api/resources/default_base_resource.rb +211 -0
  18. data/lib/pact_broker/api/resources/error_handler.rb +1 -1
  19. data/lib/pact_broker/api/resources/group.rb +1 -13
  20. data/lib/pact_broker/api/resources/label.rb +5 -2
  21. data/lib/pact_broker/api/resources/latest_pact.rb +4 -0
  22. data/lib/pact_broker/api/resources/latest_pacts.rb +1 -4
  23. data/lib/pact_broker/api/resources/latest_verifications_for_consumer_version.rb +8 -2
  24. data/lib/pact_broker/api/resources/matrix.rb +2 -2
  25. data/lib/pact_broker/api/resources/matrix_for_consumer_and_provider.rb +1 -1
  26. data/lib/pact_broker/api/resources/pact.rb +5 -1
  27. data/lib/pact_broker/api/resources/pact_content_diff.rb +1 -2
  28. data/lib/pact_broker/api/resources/pact_triggered_webhooks.rb +1 -7
  29. data/lib/pact_broker/api/resources/pact_versions.rb +1 -3
  30. data/lib/pact_broker/api/resources/pact_webhooks.rb +2 -5
  31. data/lib/pact_broker/api/resources/pact_webhooks_status.rb +1 -17
  32. data/lib/pact_broker/api/resources/pacticipant.rb +7 -14
  33. data/lib/pact_broker/api/resources/pacticipants.rb +1 -1
  34. data/lib/pact_broker/api/resources/pacticipants_for_label.rb +1 -1
  35. data/lib/pact_broker/api/resources/previous_distinct_pact_version.rb +4 -0
  36. data/lib/pact_broker/api/resources/provider_pacts.rb +5 -1
  37. data/lib/pact_broker/api/resources/provider_pacts_for_verification.rb +1 -1
  38. data/lib/pact_broker/api/resources/tag.rb +5 -1
  39. data/lib/pact_broker/api/resources/tagged_pact_versions.rb +1 -2
  40. data/lib/pact_broker/api/resources/triggered_webhook_logs.rb +4 -0
  41. data/lib/pact_broker/api/resources/verification.rb +7 -3
  42. data/lib/pact_broker/api/resources/verification_triggered_webhooks.rb +5 -1
  43. data/lib/pact_broker/api/resources/verifications.rb +7 -3
  44. data/lib/pact_broker/api/resources/version.rb +4 -1
  45. data/lib/pact_broker/api/resources/versions.rb +1 -3
  46. data/lib/pact_broker/api/resources/webhook.rb +6 -2
  47. data/lib/pact_broker/api/resources/webhook_execution.rb +4 -0
  48. data/lib/pact_broker/api/resources/webhooks.rb +3 -18
  49. data/lib/pact_broker/app.rb +1 -0
  50. data/lib/pact_broker/configuration.rb +8 -1
  51. data/lib/pact_broker/db/clean.rb +0 -6
  52. data/lib/pact_broker/domain/pacticipant.rb +7 -2
  53. data/lib/pact_broker/domain/version.rb +3 -0
  54. data/lib/pact_broker/index/service.rb +5 -45
  55. data/lib/pact_broker/pacticipants/repository.rb +2 -2
  56. data/lib/pact_broker/pacts/latest_pact_publication_id_for_consumer_version.rb +2 -5
  57. data/lib/pact_broker/pacts/pact_publication.rb +11 -9
  58. data/lib/pact_broker/pacts/pact_version.rb +3 -4
  59. data/lib/pact_broker/pacts/repository.rb +53 -39
  60. data/lib/pact_broker/pacts/verifiable_pact.rb +8 -0
  61. data/lib/pact_broker/policies.rb +53 -0
  62. data/lib/pact_broker/repositories/helpers.rb +3 -20
  63. data/lib/pact_broker/ui/controllers/index.rb +0 -2
  64. data/lib/pact_broker/verifications/latest_verification_id_for_pact_version_and_provider_version.rb +3 -5
  65. data/lib/pact_broker/version.rb +1 -1
  66. data/lib/pact_broker/versions/repository.rb +2 -4
  67. data/lib/rack/pact_broker/request_target.rb +6 -1
  68. data/lib/sequel/plugins/insert_ignore.rb +69 -0
  69. data/lib/sequel/plugins/upsert.rb +103 -0
  70. data/pact_broker.gemspec +22 -41
  71. data/script/docker/db-execute-sql-file.sh +2 -0
  72. data/script/issues/consumer-version-selectors-docs/issue-text.txt +11 -0
  73. data/script/issues/consumer-version-selectors-docs/issues.txt +6 -0
  74. data/script/issues/consumer-version-selectors-docs/raise-issue-in-client-repos.sh +10 -0
  75. data/script/prod/redact-data.sql +1 -0
  76. data/script/release-via-github-action.sh +7 -0
  77. data/script/trigger-release.sh +30 -0
  78. data/spec/features/get_versions_spec.rb +1 -6
  79. data/spec/lib/pact_broker/api/pact_broker_urls_spec.rb +2 -2
  80. data/spec/lib/pact_broker/api/resources/all_webhooks_spec.rb +1 -1
  81. data/spec/lib/pact_broker/api/resources/default_base_resource_spec.rb +158 -0
  82. data/spec/lib/pact_broker/api/resources/tag_spec.rb +2 -2
  83. data/spec/lib/pact_broker/api/resources/webhook_spec.rb +1 -1
  84. data/spec/lib/pact_broker/api/resources/webhooks_spec.rb +1 -1
  85. data/spec/lib/pact_broker/db/clean_old_spec.rb +125 -0
  86. data/spec/lib/pact_broker/db/clean_spec.rb +45 -11
  87. data/spec/lib/pact_broker/index/service_spec.rb +2 -3
  88. data/spec/lib/pact_broker/pacts/repository_find_wip_pact_versions_for_provider_spec.rb +36 -0
  89. data/spec/lib/pact_broker/versions/repository_spec.rb +8 -0
  90. data/spec/lib/rack/pact_broker/request_target_spec.rb +7 -0
  91. data/spec/lib/sequel/plugins/insert_ignore_spec.rb +82 -0
  92. data/spec/lib/sequel/plugins/upsert_spec.rb +125 -0
  93. data/spec/spec_helper.rb +1 -0
  94. data/tasks/audit.rake +6 -2
  95. data/tasks/development.rake +2 -2
  96. metadata +46 -284
  97. data/spec/lib/pact_broker/api/resources/base_resource_spec.rb +0 -78
@@ -125,7 +125,7 @@ module PactBroker
125
125
  end
126
126
 
127
127
  it "renders the tag" do
128
- expect(tag_decorator).to receive(:to_json).with(user_options: { base_url: "http://example.org" })
128
+ expect(tag_decorator).to receive(:to_json).with(user_options: hash_including(base_url: "http://example.org"))
129
129
  subject
130
130
  expect(last_response.body).to eq tag_json
131
131
  end
@@ -149,7 +149,7 @@ module PactBroker
149
149
  end
150
150
 
151
151
  it "renders the tag" do
152
- expect(tag_decorator).to receive(:to_json).with(user_options: { base_url: "http://example.org" })
152
+ expect(tag_decorator).to receive(:to_json).with(user_options: hash_including(base_url: "http://example.org"))
153
153
  subject
154
154
  expect(last_response.body).to eq tag_json
155
155
  end
@@ -40,7 +40,7 @@ module PactBroker::Api
40
40
 
41
41
  it "generates a JSON representation of the webhook" do
42
42
  expect(Decorators::WebhookDecorator).to receive(:new).with(webhook)
43
- expect(decorator).to receive(:to_json).with(user_options: { base_url: 'http://example.org'})
43
+ expect(decorator).to receive(:to_json).with(user_options: hash_including(base_url: 'http://example.org'))
44
44
  subject
45
45
  end
46
46
 
@@ -223,7 +223,7 @@ module PactBroker::Api
223
223
 
224
224
  it "generates the JSON response body" do
225
225
  expect(Decorators::WebhookDecorator).to receive(:new).with(saved_webhook).and_return(webhook_decorator)
226
- expect(webhook_decorator).to receive(:to_json).with(user_options: { base_url: 'http://example.org' })
226
+ expect(webhook_decorator).to receive(:to_json).with(user_options: hash_including(base_url: 'http://example.org'))
227
227
  subject
228
228
  end
229
229
 
@@ -0,0 +1,125 @@
1
+ require 'pact_broker/db/clean'
2
+
3
+ IS_MYSQL = !!DB.mysql?
4
+
5
+ module PactBroker
6
+ module DB
7
+ # Inner queries don't work on MySQL. Seriously, MySQL???
8
+ describe Clean, skip: true, pending: IS_MYSQL do
9
+ let(:options) { {} }
10
+ let(:db) { PactBroker::DB.connection }
11
+
12
+ subject { Clean.call(PactBroker::DB.connection, options) }
13
+
14
+ describe ".call"do
15
+
16
+ before do
17
+ td.create_pact_with_hierarchy("Foo", "0", "Bar")
18
+ .create_consumer_version_tag("prod")
19
+ .create_consumer_version("1")
20
+ .create_pact
21
+ .create_consumer_version_tag("prod")
22
+ .comment("keep")
23
+ .create_verification(provider_version: "20")
24
+ .create_consumer_version("2")
25
+ .create_pact
26
+ .comment("don't keep")
27
+ .create_webhook
28
+ .create_triggered_webhook
29
+ .create_webhook_execution
30
+ .create_verification(provider_version: "30")
31
+ .create_verification_webhook
32
+ .create_triggered_webhook
33
+ .create_webhook_execution
34
+ .create_consumer_version("3")
35
+ .create_pact
36
+ .comment("keep")
37
+ .create_verification(provider_version: "40")
38
+ .create_verification(provider_version: "40", number: 2)
39
+ .create_verification(provider_version: "50", number: 3)
40
+ end
41
+
42
+
43
+ it "does not delete any rows in the head matrix" do
44
+ head_matrix_before = db[:head_matrix].select_all
45
+ subject
46
+ head_matrix_after = db[:head_matrix].select_all
47
+ expect(head_matrix_before).to eq head_matrix_after
48
+ end
49
+
50
+ it "deletes rows that aren't the latest or latest tagged" do
51
+ subject
52
+ expect(db[:matrix].where(consumer_version_number: "2").count).to eq 0
53
+ end
54
+
55
+ it "deletes orphan pact_versions" do
56
+ subject
57
+ expect(db[:pact_versions].count).to eq 2
58
+ end
59
+
60
+ it "deletes orphan versions" do
61
+ subject
62
+ expect(db[:versions].where(number: "20").count).to be 1
63
+ expect(db[:versions].where(number: "30").count).to be 0
64
+ expect(db[:versions].where(number: "40").count).to be 1
65
+ expect(db[:versions].where(number: "50").count).to be 1
66
+ end
67
+
68
+ it "deletes overwritten verifications" do
69
+ expect(db[:matrix].where(provider_version_number: "40").count).to eq 2
70
+ subject
71
+ expect(db[:matrix].where(provider_version_number: "40", verification_number: 2).count).to eq 1
72
+ end
73
+ end
74
+
75
+ describe ".call with a date" do
76
+ before do
77
+ td.set_now(DateTime.new(2019, 1, 1))
78
+ .create_pact_with_hierarchy
79
+ .create_verification
80
+ end
81
+ let(:options) { { date: date } }
82
+
83
+ context "when the data is older than the given date" do
84
+ let(:date) { DateTime.new(2019, 1, 2) }
85
+ let(:expected_report) do
86
+ {
87
+ kept: { pact_publications: 0, verification_results: 0 },
88
+ deleted: { pact_publications: 1, verification_results: 1 }
89
+ }
90
+ end
91
+
92
+ it "is deleted" do
93
+ subject
94
+ expect(db[:head_matrix].count).to be 0
95
+ end
96
+
97
+ it "returns a report" do
98
+ expect(subject).to include(expected_report)
99
+ end
100
+ end
101
+
102
+ context "when the data is not older than the given date" do
103
+ let(:date) { DateTime.new(2019, 1, 1) }
104
+ let(:expected_report) do
105
+ {
106
+ kept: { pact_publications: 1, verification_results: 1 },
107
+ deleted: { pact_publications: 0, verification_results: 0 }
108
+ }
109
+ end
110
+
111
+ it "is not deleted" do
112
+ subject
113
+ expect(db[:head_matrix].count).to be 1
114
+ expect(db[:pact_publications].count).to be 1
115
+ expect(db[:verifications].count).to be 1
116
+ end
117
+
118
+ it "returns a report" do
119
+ expect(subject).to include(expected_report)
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -11,31 +11,26 @@ module PactBroker
11
11
  let(:db) { PactBroker::DB.connection }
12
12
 
13
13
  subject { Clean.call(PactBroker::DB.connection, options) }
14
+ let(:latest_dev_selector) { PactBroker::Matrix::UnresolvedSelector.new(tag: "dev", latest: true) }
15
+ let(:all_prod_selector) { PactBroker::Matrix::UnresolvedSelector.new(tag: "prod") }
14
16
 
15
17
  describe ".call"do
16
18
  context "when there are specified versions to keep" do
17
19
  before do
18
20
  td.create_pact_with_hierarchy("Foo", "1", "Bar")
19
21
  .create_consumer_version_tag("prod")
20
- .create_consumer_version_tag("master")
22
+ .create_consumer_version_tag("dev")
21
23
  .create_consumer_version("3", tag_names: %w{prod})
22
24
  .create_pact
23
- .create_consumer_version("4", tag_names: %w{master})
25
+ .create_consumer_version("4", tag_names: %w{dev})
24
26
  .create_pact
25
- .create_consumer_version("5", tag_names: %w{master})
27
+ .create_consumer_version("5", tag_names: %w{dev})
26
28
  .create_pact
27
29
  .create_consumer_version("6", tag_names: %w{foo})
28
30
  .create_pact
29
31
  end
30
32
 
31
- let(:options) do
32
- {
33
- keep: [
34
- PactBroker::Matrix::UnresolvedSelector.new(tag: "prod"),
35
- PactBroker::Matrix::UnresolvedSelector.new(tag: "master", latest: true)
36
- ]
37
- }
38
- end
33
+ let(:options) { { keep: [all_prod_selector, latest_dev_selector] } }
39
34
 
40
35
  it "does not delete the consumer versions specified" do
41
36
  expect(PactBroker::Domain::Version.where(number: "1").count).to be 1
@@ -51,6 +46,45 @@ module PactBroker
51
46
  expect(PactBroker::Domain::Version.where(number: "6").count).to be 0
52
47
  end
53
48
  end
49
+
50
+ context "with orphan pact versions" do
51
+ before do
52
+ # Create a pact that will not be deleted
53
+ td.create_pact_with_hierarchy("Foo", "0", "Bar", json_content_1)
54
+ .create_consumer_version_tag("dev")
55
+ # Create an orphan pact version
56
+ pact_version_params = PactBroker::Pacts::PactVersion.first.to_hash
57
+ pact_version_params.delete(:id)
58
+ pact_version_params[:sha] = "1234"
59
+ PactBroker::Pacts::PactVersion.create(pact_version_params)
60
+ end
61
+
62
+ let(:json_content_1) { { interactions: ['a', 'b']}.to_json }
63
+ let(:json_content_2) { { interactions: ['a', 'c']}.to_json }
64
+
65
+ let(:options) { { keep: [latest_dev_selector] } }
66
+
67
+ it "deletes them" do
68
+ expect { subject }.to change { PactBroker::Pacts::PactVersion.count }.by(-1)
69
+ end
70
+ end
71
+
72
+ context "with triggered and executed" do
73
+ before do
74
+ td.create_pact_with_hierarchy("Foo", "1", "Bar")
75
+ .create_consumer_version_tag("dev").comment("keep")
76
+ .create_webhook
77
+ .create_triggered_webhook
78
+ .create_webhook_execution
79
+ .add_day
80
+ .create_triggered_webhook
81
+ .create_webhook_execution
82
+ end
83
+
84
+ xit "deletes all but the most recent triggered webhook" do
85
+
86
+ end
87
+ end
54
88
  end
55
89
  end
56
90
  end
@@ -8,17 +8,16 @@ module PactBroker
8
8
  describe Service do
9
9
  let(:td) { TestDataBuilder.new }
10
10
  let(:tags) { ['prod', 'production'] }
11
- let(:options) { { tags: tags, optimised: optimised, page_size: page_size, page_number: page_number } }
11
+ let(:options) { { tags: tags, page_size: page_size, page_number: page_number } }
12
12
  let(:page_number) { nil }
13
13
  let(:page_size) { nil }
14
14
  let(:rows) { subject.find_index_items(options) }
15
- let(:optimised) { true }
16
15
 
17
16
  before do
18
17
  td.create_global_webhook
19
18
  end
20
19
 
21
- subject{ Service }
20
+ subject { Service }
22
21
 
23
22
  describe "find_relationships integration test" do
24
23
  context "when a prod pact exists and is not the latest version" do
@@ -20,6 +20,42 @@ module PactBroker
20
20
  end
21
21
  end
22
22
 
23
+ context "when there are multiple wip pacts" do
24
+ before do
25
+ td.create_provider("bar")
26
+ .create_provider_version("333")
27
+ .create_provider_version_tag("dev")
28
+ .add_day
29
+ .create_pact_with_hierarchy("foo", "1", "bar")
30
+ .create_consumer_version_tag("feat-1")
31
+ .add_day
32
+ .create_pact_with_hierarchy("meep", "2", "bar")
33
+ .create_consumer_version_tag("feat-2")
34
+ .add_day
35
+ .create_pact_with_hierarchy("foo", "2", "bar")
36
+ .create_consumer_version_tag("feat-2")
37
+ .add_day
38
+ .create_pact_with_hierarchy("meep", "1", "bar")
39
+ .create_consumer_version_tag("feat-1")
40
+ end
41
+
42
+ let(:provider_tags) { %w[dev] }
43
+
44
+ it "sorts them" do
45
+ expect(subject[0].consumer_name).to eq "foo"
46
+ expect(subject[0].consumer_version_number).to eq "1"
47
+
48
+ expect(subject[1].consumer_name).to eq "foo"
49
+ expect(subject[1].consumer_version_number).to eq "2"
50
+
51
+ expect(subject[2].consumer_name).to eq "meep"
52
+ expect(subject[2].consumer_version_number).to eq "2"
53
+
54
+ expect(subject[3].consumer_name).to eq "meep"
55
+ expect(subject[3].consumer_version_number).to eq "1"
56
+ end
57
+ end
58
+
23
59
  context "when the latest pact for a tag has been successfully verified by the given provider tag" do
24
60
  before do
25
61
  td.create_pact_with_hierarchy("foo", "1", "bar")
@@ -39,6 +39,10 @@ module PactBroker
39
39
 
40
40
  subject { Repository.new.create pacticipant_id: existing_version.pacticipant_id, number: "1.2.4" }
41
41
 
42
+ it "creates a new version" do
43
+ expect { subject }.to change { PactBroker::Domain::Version.count }.by(1)
44
+ end
45
+
42
46
  it "sets the order to the previous version's order plus one" do
43
47
  expect(subject.order).to eq existing_version.order + 1
44
48
  end
@@ -49,6 +53,10 @@ module PactBroker
49
53
 
50
54
  subject { Repository.new.create pacticipant_id: existing_version.pacticipant_id, number: version_number }
51
55
 
56
+ it "does not create a new version" do
57
+ expect { subject }.to_not change { PactBroker::Domain::Version.count }
58
+ end
59
+
52
60
  it "returns the pre-existing version" do
53
61
  expect(subject.id).to eq existing_version.id
54
62
  end
@@ -56,6 +56,13 @@ module Rack
56
56
 
57
57
  it { is_expected.to be false }
58
58
  end
59
+
60
+ context "when the request is for a badge resource with a svg content type" do
61
+ let(:accept) { "image/svg+xml;charset=utf-8" }
62
+ let(:path) { "/pacts/provider/foo/consumer/bar/latest/badge" }
63
+
64
+ it { is_expected.to be false }
65
+ end
59
66
  end
60
67
  end
61
68
  end
@@ -0,0 +1,82 @@
1
+ require 'sequel/plugins/insert_ignore'
2
+ require 'sequel'
3
+
4
+ module Sequel
5
+ module Plugins
6
+ module InsertIgnore
7
+ class PacticipantNoInsertIgnore < Sequel::Model(:pacticipants)
8
+ plugin :timestamps, update_on_create: true
9
+ end
10
+
11
+ class Pacticipant < Sequel::Model
12
+ plugin :insert_ignore, identifying_columns: [:name]
13
+ plugin :timestamps, update_on_create: true
14
+ end
15
+
16
+ class Version < Sequel::Model
17
+ plugin :insert_ignore, identifying_columns: [:pacticipant_id, :number]
18
+ plugin :timestamps, update_on_create: true
19
+ end
20
+
21
+ context "when a duplicate is inserted with no insert_ignore" do
22
+ before do
23
+ PacticipantNoInsertIgnore.new(name: "Foo").save
24
+ end
25
+
26
+ subject do
27
+ PacticipantNoInsertIgnore.new(name: "Foo").save
28
+ end
29
+
30
+ it "raises an error" do
31
+ expect { subject }.to raise_error Sequel::UniqueConstraintViolation
32
+ end
33
+ end
34
+
35
+ # This doesn't work on MSQL because the _insert_raw method
36
+ # does not return the row ID of the duplicated row when insert_ignore is used
37
+ # May have to go back to the old method of doing this
38
+ context "when a duplicate Pacticipant is inserted with insert_ignore" do
39
+ before do
40
+ Pacticipant.new(name: "Foo", repository_url: "http://foo").insert_ignore
41
+ end
42
+
43
+ subject do
44
+ Pacticipant.new(name: "Foo").insert_ignore
45
+ end
46
+
47
+ it "does not raise an error" do
48
+ expect { subject }.to_not raise_error
49
+ end
50
+
51
+ it "sets the values on the object" do
52
+ expect(subject.repository_url).to eq "http://foo"
53
+ end
54
+
55
+ it "does not insert another row" do
56
+ expect { subject }.to_not change { Pacticipant.count }
57
+ end
58
+ end
59
+
60
+ context "when a duplicate Version is inserted with insert_ignore" do
61
+ let!(:pacticipant) { Pacticipant.new(name: "Foo").save }
62
+ let!(:original_version) { Version.new(number: "1", pacticipant_id: pacticipant.id).insert_ignore }
63
+
64
+ subject do
65
+ Version.new(number: "1", pacticipant_id: pacticipant.id).insert_ignore
66
+ end
67
+
68
+ it "does not raise an error" do
69
+ expect { subject }.to_not raise_error
70
+ end
71
+
72
+ it "sets the values on the object" do
73
+ expect(subject.id).to eq original_version.id
74
+ end
75
+
76
+ it "does not insert another row" do
77
+ expect { subject }.to_not change { Version.count }
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,125 @@
1
+ require 'sequel/plugins/upsert'
2
+ require 'sequel'
3
+
4
+ module Sequel
5
+ module Plugins
6
+ module Upsert
7
+ class PacticipantNoUpsert < Sequel::Model(:pacticipants)
8
+ plugin :timestamps, update_on_create: true
9
+ end
10
+
11
+ class Pacticipant < Sequel::Model
12
+ plugin :upsert, identifying_columns: [:name]
13
+ plugin :timestamps, update_on_create: true
14
+ end
15
+
16
+ class Version < Sequel::Model
17
+ plugin :upsert, identifying_columns: [:pacticipant_id, :number]
18
+ plugin :timestamps, update_on_create: true
19
+ end
20
+
21
+ class LatestPactPublicationIdForConsumerVersion < Sequel::Model(:latest_pact_publication_ids_for_consumer_versions)
22
+ set_primary_key [:provider_id, :consumer_version_id]
23
+ unrestrict_primary_key
24
+ plugin :upsert, identifying_columns: [:provider_id, :consumer_version_id]
25
+ end
26
+
27
+ describe "LatestPactPublicationIdForConsumerVersion" do
28
+ before do
29
+ td.create_pact_with_hierarchy("Foo", "1", "Bar")
30
+ .create_consumer_version("2")
31
+ end
32
+
33
+ let!(:new_pact_publication) do
34
+ pact_publication_values = PactBroker::Pacts::PactPublication.first.values.dup
35
+ pact_publication_values.delete(:id)
36
+ pact_publication_values.delete(:created_at)
37
+ pact_publication_values.delete(:updated_at)
38
+ pact_publication_values[:revision_number] = 2
39
+ PactBroker::Pacts::PactPublication.new(pact_publication_values).save
40
+ end
41
+
42
+ let(:new_latest_pact_publication_id_for_consumer_version) do
43
+ values = LatestPactPublicationIdForConsumerVersion.first.values
44
+ LatestPactPublicationIdForConsumerVersion.new(values.merge(pact_publication_id: new_pact_publication.id))
45
+ end
46
+
47
+ describe "save" do
48
+ subject { new_latest_pact_publication_id_for_consumer_version.save }
49
+
50
+ it "raises an error" do
51
+ expect { subject }.to raise_error Sequel::UniqueConstraintViolation
52
+ end
53
+ end
54
+
55
+ describe "upsert" do
56
+ subject { new_latest_pact_publication_id_for_consumer_version.upsert }
57
+
58
+ it "updates the new object with the values from the existing object" do
59
+ expect(subject.pact_publication_id).to eq new_pact_publication.id
60
+ end
61
+ end
62
+ end
63
+
64
+ context "when a duplicate is inserted with no upsert" do
65
+ before do
66
+ PacticipantNoUpsert.new(name: "Foo").save
67
+ end
68
+
69
+ subject do
70
+ PacticipantNoUpsert.new(name: "Foo").save
71
+ end
72
+
73
+ it "raises an error" do
74
+ expect { subject }.to raise_error Sequel::UniqueConstraintViolation
75
+ end
76
+ end
77
+
78
+ # This doesn't work on MSQL because the _insert_raw method
79
+ # does not return the row ID of the duplicated row when upsert is used
80
+ # May have to go back to the old method of doing this
81
+ context "when a duplicate Pacticipant is inserted with upsert" do
82
+ before do
83
+ Pacticipant.new(name: "Foo", repository_url: "http://foo").upsert
84
+ end
85
+
86
+ subject do
87
+ Pacticipant.new(name: "Foo", repository_url: "http://bar").upsert
88
+ end
89
+
90
+ it "does not raise an error" do
91
+ expect { subject }.to_not raise_error
92
+ end
93
+
94
+ it "sets the values on the object" do
95
+ expect(subject.repository_url).to eq "http://bar"
96
+ end
97
+
98
+ it "does not insert another row" do
99
+ expect { subject }.to_not change { Pacticipant.count }
100
+ end
101
+ end
102
+
103
+ context "when a duplicate Version is inserted with upsert" do
104
+ let!(:pacticipant) { Pacticipant.new(name: "Foo").save }
105
+ let!(:original_version) { Version.new(number: "1", pacticipant_id: pacticipant.id).upsert }
106
+
107
+ subject do
108
+ Version.new(number: "1", pacticipant_id: pacticipant.id).upsert
109
+ end
110
+
111
+ it "does not raise an error" do
112
+ expect { subject }.to_not raise_error
113
+ end
114
+
115
+ it "sets the values on the object" do
116
+ expect(subject.id).to eq original_version.id
117
+ end
118
+
119
+ it "does not insert another row" do
120
+ expect { subject }.to_not change { Version.count }
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end