pact_broker 2.43.0 → 2.44.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 (30) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -1
  3. data/DEVELOPER_DOCUMENTATION.md +10 -6
  4. data/README.md +1 -1
  5. data/lib/pact_broker/api.rb +2 -2
  6. data/lib/pact_broker/api/decorators/version_decorator.rb +8 -0
  7. data/lib/pact_broker/db/models.rb +1 -1
  8. data/lib/pact_broker/doc/views/matrix.markdown +92 -2
  9. data/lib/pact_broker/matrix/deployment_status_summary.rb +11 -2
  10. data/lib/pact_broker/matrix/every_row.rb +43 -0
  11. data/lib/pact_broker/matrix/query_builder.rb +5 -5
  12. data/lib/pact_broker/matrix/quick_row.rb +96 -28
  13. data/lib/pact_broker/matrix/reason.rb +3 -0
  14. data/lib/pact_broker/matrix/repository.rb +33 -35
  15. data/lib/pact_broker/pacticipants/repository.rb +9 -1
  16. data/lib/pact_broker/pacts/{latest_pact_publication_id_by_consumer_version.rb → latest_pact_publication_id_for_consumer_version.rb} +0 -0
  17. data/lib/pact_broker/pacts/repository.rb +1 -1
  18. data/lib/pact_broker/repositories/helpers.rb +12 -5
  19. data/lib/pact_broker/version.rb +1 -1
  20. data/pact_broker.gemspec +1 -1
  21. data/spec/lib/pact_broker/integrations/service_spec.rb +1 -0
  22. data/spec/lib/pact_broker/matrix/deployment_status_summary_spec.rb +38 -33
  23. data/spec/lib/pact_broker/matrix/every_row_spec.rb +136 -0
  24. data/spec/lib/pact_broker/matrix/integration_spec.rb +149 -30
  25. data/spec/lib/pact_broker/matrix/repository_dependency_spec.rb +3 -3
  26. data/spec/lib/pact_broker/matrix/repository_spec.rb +5 -4
  27. data/spec/lib/pact_broker/pacticipants/repository_spec.rb +37 -3
  28. data/spec/service_consumers/provider_states_for_pact_ruby.rb +12 -0
  29. data/spec/support/shared_examples_for_responses.rb +7 -0
  30. metadata +14 -5
@@ -25,7 +25,7 @@ module PactBroker
25
25
  end
26
26
 
27
27
  let(:options) do
28
- { latest: true, tag: "prod" }
28
+ { latest: true, tag: "prod", latestby: "cvp" }
29
29
  end
30
30
 
31
31
  before do
@@ -54,10 +54,10 @@ module PactBroker
54
54
  end
55
55
 
56
56
  let(:selectors) { [{ pacticipant_name: "Bar", latest: true, tag: "test" }]}
57
- let(:options) { { tag: "prod" } }
57
+ let(:options) { { tag: "prod", latestby: "cvp" } }
58
58
 
59
59
  it "does not allow the consumer to be deployed" do
60
- expect(subject.deployment_status_summary.deployable?).to_not be true
60
+ expect(subject.deployment_status_summary).to_not be_deployable
61
61
  end
62
62
  end
63
63
 
@@ -80,7 +80,7 @@ module PactBroker
80
80
  end
81
81
 
82
82
  it "does not allow the consumer to be deployed" do
83
- expect(subject.deployment_status_summary.deployable?).to_not be true
83
+ expect(subject.deployment_status_summary).to_not be_deployable
84
84
  end
85
85
  end
86
86
 
@@ -101,18 +101,22 @@ module PactBroker
101
101
  [ { pacticipant_name: "Foo", pacticipant_version_number: "3.0.0" } ]
102
102
  end
103
103
 
104
- let(:options) { {latest: true, tag: "prod"} }
104
+ let(:options) { {latest: true, tag: "prod", latestby: "cvp"} }
105
105
 
106
106
  it "returns 2 integrations" do
107
107
  expect(subject.integrations.size).to eq 2
108
108
  end
109
109
 
110
- it "returns 1 row" do
111
- expect(subject.rows.size).to eq 1
110
+ it "returns 1 row with a verification" do
111
+ expect(subject.rows.select(&:has_verification?).size).to eq 1
112
+ end
113
+
114
+ it "returns 1 row without a verification" do
115
+ expect(subject.rows.reject(&:has_verification?).size).to eq 1
112
116
  end
113
117
 
114
118
  it "does not allow the consumer to be deployed" do
115
- expect(subject.deployment_status_summary.deployable?).to_not be true
119
+ expect(subject.deployment_status_summary).to_not be_deployable
116
120
  end
117
121
  end
118
122
 
@@ -133,7 +137,7 @@ module PactBroker
133
137
  end
134
138
 
135
139
  it "allows the old version of the consumer to be deployed" do
136
- expect(subject.deployment_status_summary.deployable?).to be true
140
+ expect(subject.deployment_status_summary).to be_deployable
137
141
  end
138
142
  end
139
143
 
@@ -146,8 +150,8 @@ module PactBroker
146
150
  [ { pacticipant_name: "Bar", pacticipant_version_number: "5" } ]
147
151
  end
148
152
 
149
- it "does not allow the provider to be deployed" do
150
- expect(subject.deployment_status_summary.deployable?).to_not be true
153
+ it "does not allow the app to be deployed" do
154
+ expect(subject.deployment_status_summary).to_not be_deployable
151
155
  end
152
156
  end
153
157
 
@@ -162,20 +166,19 @@ module PactBroker
162
166
  end
163
167
 
164
168
  let(:options) do
165
- { latest: true, tag: "prod" }
169
+ { latest: true, tag: "prod", latestby: "cvp" }
166
170
  end
167
171
 
168
172
  subject { Service.find(selectors, options) }
169
173
 
170
- it "allows the provider to be deployed" do
171
- expect(subject.deployment_status_summary.deployable?).to be true
174
+ it "allows the app to be deployed" do
175
+ expect(subject.deployment_status_summary).to be_deployable
172
176
  end
173
177
  end
174
178
 
175
179
  describe "when deploying a consumer to prod for the first time and the provider is not yet deployed" do
176
180
  before do
177
- td.create_pact_with_hierarchy("Foo", "1", "Bar")
178
- .create_verification(provider_version: "2")
181
+ td.create_pact_with_verification("Foo", "1", "Bar", "2")
179
182
  end
180
183
 
181
184
  let(:selectors) do
@@ -183,18 +186,17 @@ module PactBroker
183
186
  end
184
187
 
185
188
  let(:options) do
186
- { latest: true, tag: "prod" }
189
+ { latest: true, tag: "prod", latestby: "cvp" }
187
190
  end
188
191
 
189
- it "does not allow the consumer to be deployed" do
190
- expect(subject.deployment_status_summary.deployable?).to_not be true
192
+ it "does not allow the app to be deployed" do
193
+ expect(subject.deployment_status_summary).to_not be_deployable
191
194
  end
192
195
  end
193
196
 
194
197
  describe "when deploying an app that is both a consumer and a provider to prod for the first time and the downstream provider is not yet deployed" do
195
198
  before do
196
- td.create_pact_with_hierarchy("Foo", "1", "Bar")
197
- .create_verification(provider_version: "2")
199
+ td.create_pact_with_verification("Foo", "1", "Bar", "2")
198
200
  .use_consumer("Bar")
199
201
  .use_consumer_version("2")
200
202
  .create_provider("Baz")
@@ -206,18 +208,19 @@ module PactBroker
206
208
  end
207
209
 
208
210
  let(:options) do
209
- { latest: true, tag: "prod" }
211
+ { latest: true, tag: "prod", latestby: "cvp" }
210
212
  end
211
213
 
212
214
  it "does not allow the app to be deployed" do
213
- expect(subject.deployment_status_summary.deployable?).to_not be true
215
+ expect(subject.deployment_status_summary).to_not be_deployable
214
216
  end
215
217
  end
216
218
 
217
219
  describe "when deploying an app that is both a consumer and a provider to prod for the first time and the downstream provider has been deployed" do
218
220
  before do
219
- td.create_pact_with_hierarchy("Foo", "1", "Bar")
220
- .create_verification(provider_version: "2")
221
+ # Foo v1 => Bar v2
222
+ # Bar v2 => Baz v4 (prod)
223
+ td.create_pact_with_verification("Foo", "1", "Bar", "2")
221
224
  .use_consumer("Bar")
222
225
  .use_consumer_version("2")
223
226
  .create_provider("Baz")
@@ -229,12 +232,64 @@ module PactBroker
229
232
  [ { pacticipant_name: "Bar", pacticipant_version_number: "2" } ]
230
233
  end
231
234
 
235
+ # Deploy Bar v2 to prod
232
236
  let(:options) do
233
- { latest: true, tag: "prod" }
237
+ { latest: true, tag: "prod", latestby: "cvp" }
234
238
  end
235
239
 
236
240
  it "allows the app to be deployed" do
237
- expect(subject.deployment_status_summary.deployable?).to be true
241
+ expect(subject.deployment_status_summary).to be_deployable
242
+ end
243
+ end
244
+
245
+ describe "when deploying a provider where the pact has not been verified" do
246
+ before do
247
+ # Foo v1 => Bar ?
248
+ td.create_pact_with_hierarchy("Foo", "1", "Bar")
249
+ .create_provider_version("2")
250
+ end
251
+
252
+ let(:selectors) do
253
+ [ { pacticipant_name: "Bar", pacticipant_version_number: "2" } ]
254
+ end
255
+
256
+ # Deploy Bar v2 to prod
257
+ let(:options) do
258
+ { latest: true, tag: "prod", latestby: "cvp" }
259
+ end
260
+
261
+ it "allows the app to be deployed" do
262
+ # no integrations and no matrix rows
263
+ expect(subject.deployment_status_summary).to be_deployable
264
+ end
265
+ end
266
+
267
+ describe "when deploying a consumer where the pact has been verified, but not by the required provider version" do
268
+ before do
269
+ # Foo v1 => Bar v2
270
+ td.create_pact_with_hierarchy("Foo", "1", "Bar")
271
+ .create_provider_version("2")
272
+ .create_provider_version_tag("prod")
273
+ .create_provider_version("3")
274
+ .create_verification(comment: "the verification is not from the required provider version")
275
+ end
276
+
277
+ let(:selectors) do
278
+ [ { pacticipant_name: "Foo", pacticipant_version_number: "1" } ]
279
+ end
280
+
281
+ # Deploy Foo v1 to prod
282
+ let(:options) do
283
+ { latest: true, tag: "prod", latestby: "cvp" }
284
+ end
285
+
286
+ # Currently returning PactNotEverVerifiedByProvider because the matrix response has changed from 'no row' to
287
+ # 'one row with no verification details' (left outer join stuff).
288
+ # Not sure if the 'no row' usecase can ever happen now.
289
+ # The messages shown to the user for 'not ever verified' and 'verified by the wrong provider version'
290
+ # are the same however, so the code does not need to be updated straight away.
291
+ it "returns a reason indicating that the pact has not been verified by the required provider version", pending: true do
292
+ expect(subject.deployment_status_summary.reasons.first).to be_a(PactBroker::Matrix::PactNotVerifiedByRequiredProviderVersion)
238
293
  end
239
294
  end
240
295
 
@@ -258,7 +313,7 @@ module PactBroker
258
313
  let(:options) { { latestby: "cvpv" } }
259
314
 
260
315
  it "does not allow the two apps to be deployed together" do
261
- expect(subject.deployment_status_summary.deployable?).to_not be true
316
+ expect(subject.deployment_status_summary).to_not be_deployable
262
317
  end
263
318
  end
264
319
 
@@ -272,11 +327,75 @@ module PactBroker
272
327
  let(:options) { { latestby: "cvp", latest: true } }
273
328
 
274
329
  it "does not allow the two apps to be deployed together" do
275
- expect(subject.deployment_status_summary.deployable?).to_not be true
330
+ expect(subject.deployment_status_summary).to_not be_deployable
331
+ end
332
+ end
333
+ end
334
+
335
+ describe "specifying a provider which has multiple prod versions of one consumer (explicit) and a single version of another (inferred)" do
336
+ before do
337
+ # Foo 1 (prod) -> Bar 2 [explicit]
338
+ # Foo 2 (prod) -> Bar 2 [explicit]
339
+ # Foo 3 -> Bar 2 failed [explicit]
340
+ # Cat 20 (prod) -> Bar ? [inferred, missing verification]
341
+ # Dog 40 -> Bar 2 failed [inferred, but not in prod]
342
+
343
+ td.create_pact_with_verification("Foo", "1", "Bar", "2")
344
+ .create_consumer_version_tag("prod")
345
+ .create_consumer_version("2")
346
+ .create_consumer_version_tag("prod")
347
+ .create_pact
348
+ .create_verification(provider_version: "2")
349
+ .create_consumer_version("3")
350
+ .create_pact
351
+ .create_verification(provider_version: "2", success: false, comment: "not prod, doesn't matter")
352
+ .create_consumer("Cat")
353
+ .create_consumer_version("20")
354
+ .create_consumer_version_tag("prod")
355
+ .create_pact
356
+ .comment("missing verification")
357
+ .create_consumer("Dog")
358
+ .create_consumer_version("40")
359
+ .create_pact
360
+ .create_verification(provider_version: "2")
361
+ end
362
+
363
+ let(:selector_1) { { pacticipant_name: "Bar", pacticipant_version_number: "2" } }
364
+ let(:selector_2) { { pacticipant_name: "Foo", tag: "prod" } }
365
+ let(:selectors) { [ selector_1, selector_2 ] }
366
+
367
+ subject { Service.find(selectors, options) }
368
+
369
+ context "with inferred selectors" do
370
+ let(:options) { { latest: true, tag: "prod"} }
371
+
372
+ it "determines the number of integrations" do
373
+ expect(subject.integrations.size).to eq 3
374
+ end
375
+
376
+ it "finds all prod versions of Foo" do
377
+ expect(subject.select { |row| row.consumer_name == "Foo"}.size).to eq 2
378
+ end
379
+
380
+ it "finds the single prod version of Cat" do
381
+ expect(subject.select { |row| row.consumer_name == "Cat"}.size).to eq 1
382
+ end
383
+
384
+ it "is not deployable because of the missing verification for Cat v20" do
385
+ expect(subject.deployment_status_summary.reasons.size).to eq 1
386
+ expect(subject.deployment_status_summary.reasons.first).to be_a_pact_never_verified_for_consumer "Cat"
387
+ end
388
+ end
389
+
390
+ context "without inferred selectors" do
391
+ let(:options) { {} }
392
+
393
+ it "is deployable" do
394
+ expect(subject.deployment_status_summary).to be_deployable
276
395
  end
277
396
  end
278
397
  end
279
398
  end
280
399
  end
281
400
  end
282
- end
401
+ end
@@ -48,9 +48,9 @@ module PactBroker
48
48
  subject { shorten_rows(rows) }
49
49
  let(:results) { Repository.new.find(selectors, options) }
50
50
 
51
- it "returns an empty array" do
52
- expect(results).to eq []
53
- expect(results.resolved_selectors.find{ |s | s[:pacticipant_name] == "Bar"}[:pacticipant_version_id]).to eq -1
51
+ it "returns an array with one row that does not have a verification" do
52
+ expect(results.first).to_not have_verification
53
+ expect(results.resolved_selectors.find{ |s | s[:pacticipant_name] == "Bar"}.pacticipant_version_id).to eq -1
54
54
  end
55
55
  end
56
56
  end
@@ -54,7 +54,7 @@ module PactBroker
54
54
 
55
55
  context "when a limit is specified" do
56
56
  let(:selectors) { build_selectors('A' => nil) }
57
- let(:options) { {limit: 1} }
57
+ let(:options) { { limit: 1 } }
58
58
 
59
59
  it "returns fewer rows than the limit (because some of the logic is done in the code, there may be fewer than the limit - need to fix this)" do
60
60
  expect(subject).to eq ["A2 B? n?"]
@@ -606,7 +606,7 @@ module PactBroker
606
606
  end
607
607
 
608
608
  it "returns the tag information" do
609
- expect(subject.first[:provider_version_tags]).to include_hash_matching name: 'prod', latest: 1
609
+ expect(subject.first.provider_version_tags).to include_hash_matching name: 'prod', latest: 1
610
610
  end
611
611
  end
612
612
 
@@ -647,8 +647,9 @@ module PactBroker
647
647
  ]
648
648
  end
649
649
 
650
- it "returns no data" do
651
- expect(subject.size).to eq 0
650
+ it "returns a row with no verification" do
651
+ expect(subject.size).to eq 1
652
+ expect(subject.first).to_not have_verification
652
653
  end
653
654
  end
654
655
  end
@@ -60,10 +60,10 @@ module PactBroker
60
60
  end
61
61
  describe "#find_by_name" do
62
62
  before do
63
- TestDataBuilder.new.create_pacticipant("Foo Bar")
63
+ td.create_pacticipant("Foo-Bar")
64
64
  end
65
65
 
66
- subject { Repository.new.find_by_name('foo bar') }
66
+ subject { Repository.new.find_by_name('foo-bar') }
67
67
 
68
68
  context "when the name is a different case" do
69
69
  context "with case sensitivity turned on" do
@@ -83,9 +83,43 @@ module PactBroker
83
83
 
84
84
  it "returns the pacticipant" do
85
85
  expect(subject).to_not be nil
86
- expect(subject.name).to eq "Foo Bar"
86
+ expect(subject.name).to eq "Foo-Bar"
87
87
  end
88
88
  end
89
+
90
+ context "with case sensitivity turned off and multiple records found", skip: DB.mysql? do
91
+ # Can't be created in MySQL - duplicate record
92
+ before do
93
+ td.create_pacticipant("Foo-bar")
94
+ allow(PactBroker.configuration).to receive(:use_case_sensitive_resource_names).and_return(false)
95
+ end
96
+
97
+ it "raises an error" do
98
+ expect { subject }.to raise_error PactBroker::Error, /Found multiple pacticipants.*foo-bar/
99
+ end
100
+ end
101
+
102
+ context "with case sensitivity turned off and searching for a name with an underscore" do
103
+ before do
104
+ allow(PactBroker.configuration).to receive(:use_case_sensitive_resource_names).and_return(false)
105
+ end
106
+
107
+ subject { Repository.new.find_by_name('foo_bar') }
108
+
109
+ it { is_expected.to be nil }
110
+ end
111
+
112
+ context "with case sensitivity turned on and searching for a name with an underscore" do
113
+ subject { Repository.new.find_by_name('foo_bar') }
114
+
115
+ it { is_expected.to be nil }
116
+ end
117
+
118
+ context "with case sensitivity turned off no record found" do
119
+ subject { Repository.new.find_by_name('blah') }
120
+
121
+ it { is_expected.to be nil }
122
+ end
89
123
  end
90
124
  end
91
125
 
@@ -143,4 +143,16 @@ Pact.provider_states_for "Pact Ruby" do
143
143
  .create_pact
144
144
  end
145
145
  end
146
+
147
+ provider_state "the relation for retrieving pacts for verifications exists in the index resource" do
148
+ no_op
149
+ end
150
+
151
+ provider_state "Foo has a pact tagged cdev with provider Bar" do
152
+ set_up do
153
+ TestDataBuilder.new
154
+ .create_pact_with_hierarchy("Foo", "1", "Bar")
155
+ .create_consumer_version_tag("cdev")
156
+ end
157
+ end
146
158
  end
@@ -76,3 +76,10 @@ RSpec::Matchers.define :include_hash_matching do |expected|
76
76
  end
77
77
  end
78
78
  end
79
+
80
+ RSpec::Matchers.define :be_a_pact_never_verified_for_consumer do | expected_consumer_name |
81
+ match do | actual_reason |
82
+ expect(actual_reason).to be_a(PactBroker::Matrix::PactNotEverVerifiedByProvider)
83
+ expect(actual_reason.consumer_selector.pacticipant_name).to eq expected_consumer_name
84
+ end
85
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pact_broker
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.43.0
4
+ version: 2.44.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bethany Skurrie
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2020-01-05 00:00:00.000000000 Z
13
+ date: 2020-01-22 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: httparty
@@ -174,16 +174,22 @@ dependencies:
174
174
  name: pact-support
175
175
  requirement: !ruby/object:Gem::Requirement
176
176
  requirements:
177
+ - - "~>"
178
+ - !ruby/object:Gem::Version
179
+ version: '1.12'
177
180
  - - ">="
178
181
  - !ruby/object:Gem::Version
179
- version: '0'
182
+ version: 1.12.1
180
183
  type: :runtime
181
184
  prerelease: false
182
185
  version_requirements: !ruby/object:Gem::Requirement
183
186
  requirements:
187
+ - - "~>"
188
+ - !ruby/object:Gem::Version
189
+ version: '1.12'
184
190
  - - ">="
185
191
  - !ruby/object:Gem::Version
186
- version: '0'
192
+ version: 1.12.1
187
193
  - !ruby/object:Gem::Dependency
188
194
  name: padrino-core
189
195
  requirement: !ruby/object:Gem::Requirement
@@ -1006,6 +1012,7 @@ files:
1006
1012
  - lib/pact_broker/matrix/aggregated_row.rb
1007
1013
  - lib/pact_broker/matrix/can_i_deploy_query_schema.rb
1008
1014
  - lib/pact_broker/matrix/deployment_status_summary.rb
1015
+ - lib/pact_broker/matrix/every_row.rb
1009
1016
  - lib/pact_broker/matrix/head_row.rb
1010
1017
  - lib/pact_broker/matrix/integration.rb
1011
1018
  - lib/pact_broker/matrix/parse_can_i_deploy_query.rb
@@ -1032,7 +1039,7 @@ files:
1032
1039
  - lib/pact_broker/pacts/generate_interaction_sha.rb
1033
1040
  - lib/pact_broker/pacts/generate_sha.rb
1034
1041
  - lib/pact_broker/pacts/head_pact.rb
1035
- - lib/pact_broker/pacts/latest_pact_publication_id_by_consumer_version.rb
1042
+ - lib/pact_broker/pacts/latest_pact_publication_id_for_consumer_version.rb
1036
1043
  - lib/pact_broker/pacts/latest_pact_publications.rb
1037
1044
  - lib/pact_broker/pacts/latest_pact_publications_by_consumer_version.rb
1038
1045
  - lib/pact_broker/pacts/latest_tagged_pact_publications.rb
@@ -1417,6 +1424,7 @@ files:
1417
1424
  - spec/lib/pact_broker/labels/service_spec.rb
1418
1425
  - spec/lib/pact_broker/matrix/aggregated_row_spec.rb
1419
1426
  - spec/lib/pact_broker/matrix/deployment_status_summary_spec.rb
1427
+ - spec/lib/pact_broker/matrix/every_row_spec.rb
1420
1428
  - spec/lib/pact_broker/matrix/head_row_spec.rb
1421
1429
  - spec/lib/pact_broker/matrix/integration_spec.rb
1422
1430
  - spec/lib/pact_broker/matrix/parse_query_spec.rb
@@ -1789,6 +1797,7 @@ test_files:
1789
1797
  - spec/lib/pact_broker/labels/service_spec.rb
1790
1798
  - spec/lib/pact_broker/matrix/aggregated_row_spec.rb
1791
1799
  - spec/lib/pact_broker/matrix/deployment_status_summary_spec.rb
1800
+ - spec/lib/pact_broker/matrix/every_row_spec.rb
1792
1801
  - spec/lib/pact_broker/matrix/head_row_spec.rb
1793
1802
  - spec/lib/pact_broker/matrix/integration_spec.rb
1794
1803
  - spec/lib/pact_broker/matrix/parse_query_spec.rb