pact_broker 2.4.2 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (156) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.travis.yml +4 -2
  4. data/CHANGELOG.md +54 -0
  5. data/DEVELOPER_DOCUMENTATION.md +11 -7
  6. data/README.md +5 -1
  7. data/UPGRADING.md +18 -0
  8. data/db/migrations/19_make_pact_version_content_sha_not_nullable.rb +9 -1
  9. data/db/migrations/25_make_pv_pacticipants_mandatory.rb +8 -0
  10. data/db/migrations/38_create_triggered_webhooks_table.rb +19 -0
  11. data/db/migrations/39_add_triggered_webhooks_fk_to_execution.rb +24 -0
  12. data/db/migrations/40_create_latest_triggered_webhooks_view.rb +24 -0
  13. data/db/migrations/41_migrate_execution_data.rb +47 -0
  14. data/db/test/backwards_compatibility/.rspec +3 -0
  15. data/db/test/backwards_compatibility/Appraisals +49 -0
  16. data/db/test/backwards_compatibility/Gemfile +11 -0
  17. data/db/test/backwards_compatibility/Rakefile +55 -0
  18. data/db/test/backwards_compatibility/config.ru +18 -0
  19. data/db/test/backwards_compatibility/gemfiles/1.18.0.gemfile +14 -0
  20. data/db/test/backwards_compatibility/gemfiles/1.18.0.gemfile.lock +210 -0
  21. data/db/test/backwards_compatibility/gemfiles/2.0.0.gemfile +14 -0
  22. data/db/test/backwards_compatibility/gemfiles/2.0.0.gemfile.lock +208 -0
  23. data/db/test/backwards_compatibility/gemfiles/2.1.0.gemfile +14 -0
  24. data/db/test/backwards_compatibility/gemfiles/2.1.0.gemfile.lock +209 -0
  25. data/db/test/backwards_compatibility/gemfiles/2.2.0.gemfile +14 -0
  26. data/db/test/backwards_compatibility/gemfiles/2.2.0.gemfile.lock +197 -0
  27. data/db/test/backwards_compatibility/gemfiles/2.3.0.gemfile +13 -0
  28. data/db/test/backwards_compatibility/gemfiles/2.3.0.gemfile.lock +196 -0
  29. data/db/test/backwards_compatibility/gemfiles/2.4.2.gemfile +13 -0
  30. data/db/test/backwards_compatibility/gemfiles/2.4.2.gemfile.lock +196 -0
  31. data/db/test/backwards_compatibility/gemfiles/head.gemfile +13 -0
  32. data/db/test/backwards_compatibility/gemfiles/head.gemfile.lock +200 -0
  33. data/db/test/backwards_compatibility/spec/fixtures/foo-bar.json +22 -0
  34. data/db/test/backwards_compatibility/spec/publish_pact_spec.rb +72 -0
  35. data/db/test/backwards_compatibility/spec/spec_helper.rb +20 -0
  36. data/db/test/backwards_compatibility/spec/support/fixture_helpers.rb +12 -0
  37. data/db/test/backwards_compatibility/spec/support/request_helpers.rb +20 -0
  38. data/example/Gemfile +2 -2
  39. data/example/pact_broker_database.sqlite3 +0 -0
  40. data/lib/pact_broker/api/decorators/pact_collection_decorator.rb +1 -2
  41. data/lib/pact_broker/api/decorators/pact_decorator.rb +12 -10
  42. data/lib/pact_broker/api/decorators/pact_versions_decorator.rb +1 -2
  43. data/lib/pact_broker/api/decorators/pact_webhooks_status_decorator.rb +123 -0
  44. data/lib/pact_broker/api/decorators/versions_decorator.rb +17 -6
  45. data/lib/pact_broker/api/decorators/webhook_decorator.rb +8 -10
  46. data/lib/pact_broker/api/decorators/webhooks_decorator.rb +0 -1
  47. data/lib/pact_broker/api/pact_broker_urls.rb +13 -1
  48. data/lib/pact_broker/api/renderers/html_pact_renderer.rb +47 -3
  49. data/lib/pact_broker/api/resources/badge.rb +3 -3
  50. data/lib/pact_broker/api/resources/base_resource.rb +1 -1
  51. data/lib/pact_broker/api/resources/latest_pact.rb +5 -1
  52. data/lib/pact_broker/api/resources/pact.rb +5 -1
  53. data/lib/pact_broker/api/resources/pact_webhooks_status.rb +61 -0
  54. data/lib/pact_broker/api/resources/triggered_webhook_logs.rb +36 -0
  55. data/lib/pact_broker/api/resources/webhook.rb +31 -3
  56. data/lib/pact_broker/api/resources/webhook_execution.rb +12 -2
  57. data/lib/pact_broker/api.rb +3 -0
  58. data/lib/pact_broker/app.rb +11 -3
  59. data/lib/pact_broker/badges/service.rb +26 -5
  60. data/lib/pact_broker/configuration.rb +12 -5
  61. data/lib/pact_broker/constants.rb +1 -1
  62. data/lib/pact_broker/diagnostic/resources/heartbeat.rb +1 -2
  63. data/lib/pact_broker/doc/views/pact-webhooks.markdown +1 -1
  64. data/lib/pact_broker/doc/views/webhooks-webhooks.markdown +1 -1
  65. data/lib/pact_broker/doc/views/webhooks.markdown +1 -1
  66. data/lib/pact_broker/domain/relationship.rb +13 -4
  67. data/lib/pact_broker/domain/verification.rb +0 -4
  68. data/lib/pact_broker/domain/webhook.rb +2 -6
  69. data/lib/pact_broker/domain/webhook_execution_result.rb +1 -2
  70. data/lib/pact_broker/domain/webhook_request.rb +59 -40
  71. data/lib/pact_broker/pacticipants/service.rb +4 -3
  72. data/lib/pact_broker/pacts/repository.rb +8 -0
  73. data/lib/pact_broker/pacts/service.rb +2 -0
  74. data/lib/pact_broker/services.rb +1 -1
  75. data/lib/pact_broker/ui/view_models/relationship.rb +29 -2
  76. data/lib/pact_broker/ui/views/relationships/show.haml +7 -10
  77. data/lib/pact_broker/verifications/repository.rb +8 -1
  78. data/lib/pact_broker/version.rb +1 -1
  79. data/lib/pact_broker/webhooks/execution.rb +25 -4
  80. data/lib/pact_broker/webhooks/job.rb +55 -13
  81. data/lib/pact_broker/webhooks/latest_triggered_webhook.rb +9 -0
  82. data/lib/pact_broker/webhooks/redact_logs.rb +10 -0
  83. data/lib/pact_broker/webhooks/repository.rb +76 -8
  84. data/lib/pact_broker/webhooks/service.rb +48 -8
  85. data/lib/pact_broker/webhooks/status.rb +29 -0
  86. data/lib/pact_broker/webhooks/triggered_webhook.rb +96 -0
  87. data/lib/pact_broker/webhooks/webhook.rb +19 -8
  88. data/lib/rack/pact_broker/database_transaction.rb +9 -3
  89. data/pact_broker.gemspec +3 -3
  90. data/public/javascripts/pact.js +5 -0
  91. data/public/stylesheets/pact.css +14 -1
  92. data/public/stylesheets/relationships.css +0 -1
  93. data/script/db-spec.sh +7 -0
  94. data/script/seed.rb +13 -8
  95. data/spec/features/create_webhook_spec.rb +1 -1
  96. data/spec/features/delete_pact_spec.rb +5 -1
  97. data/spec/features/delete_webhook_spec.rb +2 -1
  98. data/spec/features/edit_webhook_spec.rb +61 -0
  99. data/spec/features/execute_webhook_spec.rb +73 -0
  100. data/spec/features/get_latest_pact_badge_spec.rb +1 -1
  101. data/spec/features/get_latest_tagged_pact_badge_spec.rb +1 -1
  102. data/spec/features/get_latest_untagged_pact_badge_spec.rb +1 -1
  103. data/spec/features/get_pact_spec.rb +1 -1
  104. data/spec/features/merge_pact_spec.rb +1 -1
  105. data/spec/features/publish_pact_spec.rb +1 -1
  106. data/spec/integration/app_spec.rb +1 -1
  107. data/spec/integration/endpoints/group.rb +1 -1
  108. data/spec/lib/pact_broker/api/decorators/latest_pact_decorator_spec.rb +2 -1
  109. data/spec/lib/pact_broker/api/decorators/pact_decorator_spec.rb +8 -6
  110. data/spec/lib/pact_broker/api/decorators/pact_webhooks_status_decorator_spec.rb +134 -0
  111. data/spec/lib/pact_broker/api/decorators/relationships_csv_decorator_spec.rb +1 -1
  112. data/spec/lib/pact_broker/api/decorators/representable_pact_spec.rb +1 -1
  113. data/spec/lib/pact_broker/api/renderers/html_pact_renderer_spec.rb +27 -1
  114. data/spec/lib/pact_broker/api/resources/badge_spec.rb +32 -15
  115. data/spec/lib/pact_broker/api/resources/base_resource_spec.rb +17 -0
  116. data/spec/lib/pact_broker/api/resources/latest_pact_spec.rb +5 -3
  117. data/spec/lib/pact_broker/api/resources/pact_spec.rb +9 -2
  118. data/spec/lib/pact_broker/api/resources/triggered_webhook_logs_spec.rb +28 -0
  119. data/spec/lib/pact_broker/api/resources/webhook_execution_spec.rb +15 -5
  120. data/spec/lib/pact_broker/api/resources/webhook_spec.rb +43 -31
  121. data/spec/lib/pact_broker/app_spec.rb +12 -8
  122. data/spec/lib/pact_broker/badges/service_spec.rb +15 -1
  123. data/spec/lib/pact_broker/configuration_spec.rb +3 -2
  124. data/spec/lib/pact_broker/domain/relationship_spec.rb +24 -0
  125. data/spec/lib/pact_broker/domain/webhook_request_spec.rb +47 -31
  126. data/spec/lib/pact_broker/domain/webhook_spec.rb +4 -6
  127. data/spec/lib/pact_broker/pacticipants/service_spec.rb +16 -1
  128. data/spec/lib/pact_broker/pacts/repository_spec.rb +22 -1
  129. data/spec/lib/pact_broker/pacts/service_spec.rb +32 -1
  130. data/spec/lib/pact_broker/ui/view_models/relationship_spec.rb +44 -0
  131. data/spec/lib/pact_broker/verifications/repository_spec.rb +19 -0
  132. data/spec/lib/pact_broker/verifications/service_spec.rb +1 -1
  133. data/spec/lib/pact_broker/webhooks/job_spec.rb +80 -19
  134. data/spec/lib/pact_broker/webhooks/redact_logs_spec.rb +49 -0
  135. data/spec/lib/pact_broker/webhooks/repository_spec.rb +271 -21
  136. data/spec/lib/pact_broker/webhooks/service_spec.rb +70 -3
  137. data/spec/lib/pact_broker/webhooks/status_spec.rb +48 -0
  138. data/spec/lib/pact_broker/webhooks/triggered_webhook_spec.rb +40 -0
  139. data/spec/lib/rack/pact_broker/database_transaction_spec.rb +14 -4
  140. data/spec/migrations/23_pact_versions_spec.rb +8 -30
  141. data/spec/migrations/24_populate_pact_contents_spec.rb +3 -21
  142. data/spec/migrations/34_latest_tagged_pacts_spec.rb +1 -17
  143. data/spec/migrations/34_pact_revisions_spec.rb +7 -23
  144. data/spec/migrations/41_migrate_execution_data_spec.rb +109 -0
  145. data/spec/service_consumers/pact_helper.rb +5 -1
  146. data/spec/spec_helper.rb +15 -7
  147. data/spec/support/database_cleaner.rb +15 -2
  148. data/spec/support/migration_helpers.rb +16 -0
  149. data/spec/support/test_data_builder.rb +41 -9
  150. data/tasks/database.rb +7 -2
  151. data/tasks/db.rake +10 -0
  152. data/tasks/rspec.rake +1 -1
  153. data/vendor/hal-browser/browser.html +3 -2
  154. data/vendor/hal-browser/js/hal/resource.js +16 -2
  155. metadata +72 -13
  156. data/script/record_verification.sh +0 -4
@@ -5,50 +5,107 @@ module PactBroker
5
5
  describe Job do
6
6
 
7
7
  before do
8
- allow(PactBroker::Webhooks::Service).to receive(:execute_webhook_now)
8
+ PactBroker.configuration.webhook_retry_schedule = [10, 60, 120, 300, 600, 1200]
9
+ allow(PactBroker::Webhooks::Service).to receive(:execute_triggered_webhook_now).and_return(result)
10
+ allow(PactBroker::Webhooks::Service).to receive(:update_triggered_webhook_status)
9
11
  end
10
12
 
11
- let(:webhook) { double("webhook", uuid: '1234') }
13
+ let(:triggered_webhook) { instance_double("PactBroker::Webhooks::TriggeredWebhook", webhook_uuid: '1234') }
14
+ let(:result) { instance_double("PactBroker::Domain::WebhookExecutionResult", success?: success)}
15
+ let(:success) { true }
16
+
17
+ context "when the job succeeds" do
18
+ subject { Job.new.perform(triggered_webhook: triggered_webhook) }
19
+
20
+ it "does not reschedule the job" do
21
+ expect(Job).to_not receive(:perform_in)
22
+ subject
23
+ end
24
+
25
+ it "updates the triggered_webhook status to 'success'" do
26
+ expect(PactBroker::Webhooks::Service).to receive(:update_triggered_webhook_status)
27
+ .with(triggered_webhook, TriggeredWebhook::STATUS_SUCCESS)
28
+ subject
29
+ end
30
+ end
12
31
 
13
32
  context "when an error occurs for the first time" do
14
33
  before do
15
- allow(PactBroker::Webhooks::Service).to receive(:execute_webhook_now).and_raise("an error")
34
+ allow(PactBroker::Webhooks::Service).to receive(:execute_triggered_webhook_now).and_raise("an error")
16
35
  end
17
36
 
37
+ subject { Job.new.perform(triggered_webhook: triggered_webhook) }
38
+
18
39
  it "reschedules the job in 10 seconds" do
19
- expect(Job).to receive(:perform_in).with(10, {webhook: webhook, error_count: 1})
20
- Job.new.perform(webhook: webhook)
40
+ expect(Job).to receive(:perform_in).with(10, {triggered_webhook: triggered_webhook, error_count: 1})
41
+ subject
42
+ end
43
+
44
+ it "updates the triggered_webhook status to 'retrying'" do
45
+ expect(PactBroker::Webhooks::Service).to receive(:update_triggered_webhook_status)
46
+ .with(triggered_webhook, TriggeredWebhook::STATUS_RETRYING)
47
+ subject
21
48
  end
22
49
  end
23
50
 
24
51
  context "when the webhook execution result is not successful for the first time" do
25
- before do
26
- allow(PactBroker::Webhooks::Service).to receive(:execute_webhook_now).and_return(instance_double("PactBroker::Domain::WebhookExecutionResult", success?: false))
27
- end
52
+ let(:success) { false }
53
+
54
+ subject { Job.new.perform(triggered_webhook: triggered_webhook) }
28
55
 
29
56
  it "reschedules the job in 10 seconds" do
30
- expect(Job).to receive(:perform_in).with(10, {webhook: webhook, error_count: 1})
31
- Job.new.perform(webhook: webhook)
57
+ expect(Job).to receive(:perform_in).with(10, {triggered_webhook: triggered_webhook, error_count: 1})
58
+ subject
59
+ end
60
+
61
+ it "executes the job with an log message indicating that the webhook will be retried" do
62
+ expect(PactBroker::Webhooks::Service).to receive(:execute_triggered_webhook_now)
63
+ .with(triggered_webhook, {
64
+ failure_log_message: "Retrying webhook in 10 seconds",
65
+ success_log_message: "Successfully executed webhook"
66
+ })
67
+ subject
68
+ end
69
+
70
+ it "updates the triggered_webhook status to 'retrying'" do
71
+ expect(PactBroker::Webhooks::Service).to receive(:update_triggered_webhook_status)
72
+ .with(triggered_webhook, TriggeredWebhook::STATUS_RETRYING)
73
+ subject
32
74
  end
33
75
  end
34
76
 
35
77
  context "when an error occurs for the second time" do
36
78
  before do
37
- allow(PactBroker::Webhooks::Service).to receive(:execute_webhook_now).and_raise("an error")
79
+ allow(PactBroker::Webhooks::Service).to receive(:execute_triggered_webhook_now).and_raise("an error")
38
80
  end
39
81
 
82
+ subject { Job.new.perform(triggered_webhook: triggered_webhook, error_count: 1) }
83
+
40
84
  it "reschedules the job in 60 seconds" do
41
- expect(Job).to receive(:perform_in).with(60, {webhook: webhook, error_count: 2 })
42
- Job.new.perform(webhook: webhook, error_count: 1)
85
+ expect(Job).to receive(:perform_in).with(60, {triggered_webhook: triggered_webhook, error_count: 2})
86
+ subject
43
87
  end
44
- end
45
88
 
46
- context "when an error occurs for the last time" do
47
- before do
48
- allow(PactBroker::Webhooks::Service).to receive(:execute_webhook_now).and_raise("an error")
89
+ it "updates the triggered_webhook status to 'retrying'" do
90
+ expect(PactBroker::Webhooks::Service).to receive(:update_triggered_webhook_status)
91
+ .with(triggered_webhook, TriggeredWebhook::STATUS_RETRYING)
92
+ subject
49
93
  end
94
+ end
95
+
96
+ context "when the job is not successful for the last time" do
97
+ let(:success) { false }
98
+
99
+ subject { Job.new.perform(triggered_webhook: triggered_webhook, error_count: 6) }
50
100
 
51
- subject { Job.new.perform(webhook: webhook, error_count: 6) }
101
+ it "executes the job with an log message indicating that the webhook has failed" do
102
+ expect(PactBroker::Webhooks::Service).to receive(:execute_triggered_webhook_now)
103
+ .with(triggered_webhook, {
104
+ failure_log_message: "Webhook execution failed after 7 attempts",
105
+ success_log_message: "Successfully executed webhook"
106
+ })
107
+ subject
108
+ end
52
109
 
53
110
  it "does not reschedule the job" do
54
111
  expect(Job).to_not receive(:perform_in)
@@ -60,8 +117,12 @@ module PactBroker
60
117
  expect(Job.logger).to receive(:error).with(/Failed to execute/)
61
118
  subject
62
119
  end
63
- end
64
120
 
121
+ it "updates the triggered_webhook status to 'failed'" do
122
+ expect(PactBroker::Webhooks::Service).to receive(:update_triggered_webhook_status).with(triggered_webhook, TriggeredWebhook::STATUS_FAILURE)
123
+ subject
124
+ end
125
+ end
65
126
  end
66
127
  end
67
128
  end
@@ -0,0 +1,49 @@
1
+ require 'pact_broker/webhooks/redact_logs'
2
+
3
+ module PactBroker
4
+ module Webhooks
5
+ describe RedactLogs do
6
+ describe ".call" do
7
+ let(:string) do
8
+ "Authorization: foo\nX-Thing: bar"
9
+ end
10
+
11
+ let(:x_auth_string) do
12
+ "X-Authorization: bar foo\nX-Thing: bar"
13
+ end
14
+
15
+ let(:x_auth_token) do
16
+ "X-Auth-Token: bar foo\nX-Thing: bar"
17
+ end
18
+
19
+ let(:x_authorization_token) do
20
+ "X-Authorization-Token: bar foo\nX-Thing: bar"
21
+ end
22
+
23
+ let(:string_lower) do
24
+ "authorization: foo\nX-Thing: bar"
25
+ end
26
+
27
+ it "hides the value of the Authorization header" do
28
+ expect(RedactLogs.call(string)).to eq "Authorization: [REDACTED]\nX-Thing: bar"
29
+ end
30
+
31
+ it "hides the value of the X-Authorization header" do
32
+ expect(RedactLogs.call(x_auth_string)).to eq "X-Authorization: [REDACTED]\nX-Thing: bar"
33
+ end
34
+
35
+ it "hides the value of the X-Auth-Token header" do
36
+ expect(RedactLogs.call(x_auth_token)).to eq "X-Auth-Token: [REDACTED]\nX-Thing: bar"
37
+ end
38
+
39
+ it "hides the value of the X-Authorization-Token header" do
40
+ expect(RedactLogs.call(x_authorization_token)).to eq "X-Authorization-Token: [REDACTED]\nX-Thing: bar"
41
+ end
42
+
43
+ it "hides the value of the authorization header" do
44
+ expect(RedactLogs.call(string_lower)).to eq "authorization: [REDACTED]\nX-Thing: bar"
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -5,6 +5,7 @@ module PactBroker
5
5
  module Webhooks
6
6
  describe Repository do
7
7
 
8
+ let(:td) { TestDataBuilder.new }
8
9
  let(:url) { 'http://example.org' }
9
10
  let(:body) { {'some' => 'json' } }
10
11
  let(:headers) { {'Content-Type' => 'application/json', 'Accept' => 'application/json'} }
@@ -187,6 +188,51 @@ module PactBroker
187
188
 
188
189
  end
189
190
 
191
+ describe "update_by_uuid" do
192
+ let(:uuid) { '1234' }
193
+ let(:td) { TestDataBuilder.new }
194
+ let(:old_webhook_params) do
195
+ {
196
+ uuid: uuid,
197
+ method: 'POST',
198
+ url: 'http://example.org',
199
+ body: '{"foo":1}',
200
+ headers: {'Content-Type' => 'application/json'},
201
+ username: 'username',
202
+ password: 'password'
203
+ }
204
+ end
205
+ let(:new_webhook_params) do
206
+ {
207
+ method: 'GET',
208
+ url: 'http://example.com',
209
+ body: 'foo',
210
+ headers: {'Content-Type' => 'text/plain'}
211
+ }
212
+ end
213
+ before do
214
+ td.create_consumer
215
+ .create_provider
216
+ .create_webhook(old_webhook_params)
217
+ end
218
+ let(:new_webhook) do
219
+ PactBroker::Domain::Webhook.new(request: PactBroker::Domain::WebhookRequest.new(new_webhook_params))
220
+ end
221
+
222
+ subject { Repository.new.update_by_uuid uuid, new_webhook }
223
+
224
+ it "updates the webhook" do
225
+ updated_webhook = subject
226
+ expect(updated_webhook.uuid).to eq uuid
227
+ expect(updated_webhook.request.method).to eq 'GET'
228
+ expect(updated_webhook.request.url).to eq 'http://example.com'
229
+ expect(updated_webhook.request.body).to eq 'foo'
230
+ expect(updated_webhook.request.headers).to eq 'Content-Type' => 'text/plain'
231
+ expect(updated_webhook.request.username).to eq nil
232
+ expect(updated_webhook.request.password).to eq nil
233
+ end
234
+ end
235
+
190
236
  describe "find_all" do
191
237
  before do
192
238
  Repository.new.create uuid, webhook, consumer, provider
@@ -240,20 +286,65 @@ module PactBroker
240
286
  end
241
287
  end
242
288
 
289
+ describe "create_triggered_webhook" do
290
+ before do
291
+ td.create_consumer
292
+ .create_provider
293
+ .create_webhook
294
+ .create_consumer_version
295
+ .create_pact
296
+ end
297
+
298
+ subject { Repository.new.create_triggered_webhook '1234', td.webhook, td.pact, 'pact_publication' }
299
+
300
+ it "creates a TriggeredWebhook" do
301
+ expect(subject.webhook_uuid ).to eq td.webhook.uuid
302
+ expect(subject.consumer).to eq td.consumer
303
+ expect(subject.provider).to eq td.provider
304
+ expect(subject.trigger_uuid).to eq '1234'
305
+ expect(subject.trigger_type).to eq 'pact_publication'
306
+ end
307
+
308
+ it "sets the webhook" do
309
+ expect(subject.webhook.uuid).to eq td.webhook.uuid
310
+ end
311
+
312
+ it "sets the webhook_uuid" do
313
+ expect(subject.webhook_uuid).to eq td.webhook.uuid
314
+ end
315
+
316
+ it "sets the consumer" do
317
+ expect(subject.consumer).to eq td.consumer
318
+ end
319
+
320
+ it "sets the provider" do
321
+ expect(subject.provider).to eq td.provider
322
+ end
323
+
324
+ it "sets the PactPublication" do
325
+ expect(subject.pact_publication.id).to eq td.pact.id
326
+ end
327
+ end
328
+
243
329
  describe "create_execution" do
244
- let(:webhook_domain) { Repository.new.create uuid, webhook, consumer, provider }
330
+ before do
331
+ td.create_consumer
332
+ .create_provider
333
+ .create_consumer_version
334
+ .create_pact
335
+ .create_webhook
336
+ .create_triggered_webhook
337
+ end
338
+
339
+ let(:webhook_domain) { Repository.new.find_by_uuid td.webhook.uuid }
245
340
  let(:webhook_execution_result) { instance_double("PactBroker::Domain::WebhookExecutionResult", success?: true, logs: "logs") }
246
341
 
247
- subject { Repository.new.create_execution webhook_domain, webhook_execution_result }
342
+ subject { Repository.new.create_execution td.triggered_webhook, webhook_execution_result }
248
343
 
249
344
  it "saves a new webhook execution " do
250
345
  expect { subject }.to change { Execution.count }.by(1)
251
346
  end
252
347
 
253
- it "sets the webhook" do
254
- expect(subject.webhook.uuid).to eq webhook_domain.uuid
255
- end
256
-
257
348
  it "sets the success" do
258
349
  expect(subject.success).to be true
259
350
  end
@@ -261,32 +352,191 @@ module PactBroker
261
352
  it "sets the logs" do
262
353
  expect(subject.logs).to eq "logs"
263
354
  end
355
+ end
264
356
 
265
- it "sets the consumer" do
266
- expect(subject.consumer).to eq consumer
357
+ describe "unlink_triggered_webhooks_by_webhook_uuid" do
358
+ let(:td) { TestDataBuilder.new }
359
+
360
+ before do
361
+ td.create_consumer
362
+ .create_provider
363
+ .create_consumer_version
364
+ .create_pact
365
+ .create_webhook
366
+ .create_triggered_webhook
367
+ .create_deprecated_webhook_execution
267
368
  end
268
369
 
269
- it "sets the provider" do
270
- expect(subject.provider).to eq provider
370
+ subject { Repository.new.unlink_triggered_webhooks_by_webhook_uuid td.webhook.uuid }
371
+
372
+ it "sets the webhook id to nil" do
373
+ webhook_id = Webhook.find(uuid: td.webhook.uuid).id
374
+ expect { subject }.to change {
375
+ TriggeredWebhook.find(id: td.triggered_webhook.id).webhook_id
376
+ }.from(webhook_id).to(nil)
271
377
  end
272
378
 
273
- it "sets the PactPublication" do
274
- expect(subject.pact_publication)
379
+ it "sets the webhook id to nil for the deprecated webhook execution field" do
380
+ webhook_id = Webhook.find(uuid: td.webhook.uuid).id
381
+ expect { subject }.to change {
382
+ DeprecatedExecution.find(id: td.webhook_execution.id).webhook_id
383
+ }.from(webhook_id).to(nil)
275
384
  end
276
385
  end
277
386
 
278
- describe "unlink_executions_by_webhook_uuid" do
279
- let!(:webhook_domain) { Repository.new.create uuid, webhook, consumer, provider }
280
- let!(:webhook_execution_result) { instance_double("PactBroker::Domain::WebhookExecutionResult", success?: true, logs: "logs") }
281
- let!(:webhook_execution) { Repository.new.create_execution webhook_domain, webhook_execution_result }
387
+ describe "delete_executions_by_pacticipant" do
388
+ before do
389
+ td.create_consumer
390
+ .create_provider
391
+ .create_webhook
392
+ .create_consumer_version
393
+ .create_pact
394
+ .create_triggered_webhook
395
+ .create_webhook_execution
396
+ # Replicate the old way of doing it
397
+ end
282
398
 
283
- subject { Repository.new.unlink_executions_by_webhook_uuid uuid }
399
+ context "with triggered webhooks" do
400
+ it "deletes the execution by consumer" do
401
+ expect { Repository.new.delete_executions_by_pacticipant td.consumer }
402
+ .to change { Execution.count }.by(-1)
403
+ end
284
404
 
285
- it "sets the webhook id to nil" do
286
- webhook_id = Webhook.find(uuid: uuid).id
405
+ it "deletes the execution by provider" do
406
+ expect { Repository.new.delete_executions_by_pacticipant td.provider }
407
+ .to change { Execution.count }.by(-1)
408
+ end
409
+
410
+ it "does not delete executions for non related pacticipants" do
411
+ another_consumer = td.create_consumer.and_return(:consumer)
412
+ expect { Repository.new.delete_executions_by_pacticipant another_consumer }
413
+ .to change { Execution.count }.by(0)
414
+ end
415
+ end
416
+
417
+ context "with deprecated executions (before the triggered webhook table was introduced)" do
418
+ before do
419
+ Sequel::Model.db[:webhook_executions].update(triggered_webhook_id: nil, consumer_id: td.consumer.id, provider_id: td.provider.id)
420
+ TriggeredWebhook.select_all.delete
421
+ end
422
+
423
+ it "deletes the execution by consumer" do
424
+ expect { Repository.new.delete_executions_by_pacticipant td.consumer }
425
+ .to change { Execution.count }.by(-1)
426
+ end
427
+
428
+ it "deletes the execution by provider" do
429
+ expect { Repository.new.delete_executions_by_pacticipant td.provider }
430
+ .to change { Execution.count }.by(-1)
431
+ end
432
+
433
+ it "does not delete executions for non related pacticipants" do
434
+ another_consumer = td.create_consumer.and_return(:consumer)
435
+ expect { Repository.new.delete_executions_by_pacticipant another_consumer }
436
+ .to change { Execution.count }.by(0)
437
+ end
438
+ end
439
+ end
440
+
441
+ describe "find_latest_triggered_webhooks" do
442
+ before do
443
+ td
444
+ .create_pact_with_hierarchy("Foo", "1.0.0", "Bar")
445
+ .create_webhook
446
+ .create_triggered_webhook
447
+ .create_webhook_execution
448
+ .create_pact_with_hierarchy
449
+ .create_webhook(uuid: '123')
450
+ .create_triggered_webhook(trigger_uuid: '256', created_at: DateTime.new(2016))
451
+ .create_webhook_execution
452
+ .create_triggered_webhook(trigger_uuid: '332', created_at: DateTime.new(2017))
453
+ .create_webhook_execution
454
+ .create_webhook(uuid: '987')
455
+ .create_triggered_webhook(trigger_uuid: '876', created_at: DateTime.new(2017))
456
+ .create_webhook_execution
457
+ .create_triggered_webhook(trigger_uuid: '638', created_at: DateTime.new(2018))
458
+ .create_webhook_execution
459
+ end
460
+
461
+ subject { Repository.new.find_latest_triggered_webhooks(td.consumer, td.provider) }
462
+
463
+ it "finds the latest triggered webhooks" do
464
+ expect(subject.collect(&:trigger_uuid).sort).to eq ['332', '638']
465
+ end
466
+
467
+ context "when there are two 'latest' triggered webhooks at the same time" do
468
+ before do
469
+ td.create_triggered_webhook(trigger_uuid: '888', created_at: DateTime.new(2018))
470
+ .create_webhook_execution
471
+ end
472
+
473
+ it "returns the one with the bigger ID" do
474
+ expect(subject.collect(&:trigger_uuid).sort).to eq ['332', '888']
475
+ end
476
+ end
477
+
478
+ context "when there are no triggered webhooks for the given consumer and provider" do
479
+ before do
480
+ td.create_consumer
481
+ .create_provider
482
+ end
483
+
484
+ it "returns an empty list" do
485
+ expect(subject).to be_empty
486
+ end
487
+ end
488
+ end
489
+
490
+ describe "fail_retrying_triggered_webhooks" do
491
+ before do
492
+ td.create_pact_with_hierarchy
493
+ .create_webhook
494
+ .create_triggered_webhook(status: TriggeredWebhook::STATUS_RETRYING)
495
+ .create_triggered_webhook(status: TriggeredWebhook::STATUS_SUCCESS)
496
+ .create_triggered_webhook(status: TriggeredWebhook::STATUS_NOT_RUN)
497
+ .create_triggered_webhook(status: TriggeredWebhook::STATUS_FAILURE)
498
+ end
499
+
500
+ it "sets the triggered_webhooks with retrying status to failed" do
501
+ Repository.new.fail_retrying_triggered_webhooks
502
+ expect(TriggeredWebhook.failed.count).to eq 2
503
+ expect(TriggeredWebhook.retrying.count).to eq 0
504
+ expect(TriggeredWebhook.successful.count).to eq 1
505
+ expect(TriggeredWebhook.not_run.count).to eq 1
506
+ end
507
+ end
508
+
509
+ describe "delete_triggered_webhooks_by_pact_publication_id" do
510
+ before do
511
+ td.create_pact_with_hierarchy
512
+ .create_webhook
513
+ .create_triggered_webhook
514
+ .create_webhook_execution
515
+ .create_pact_with_hierarchy("A Consumer", "1.2.3", "A Provider")
516
+ .create_webhook
517
+ .create_triggered_webhook
518
+ .create_webhook_execution
519
+ .create_deprecated_webhook_execution
520
+ end
521
+
522
+ subject { Repository.new.delete_triggered_webhooks_by_pact_publication_ids [td.pact.id] }
523
+
524
+ it "deletes the triggered webhook" do
287
525
  expect { subject }.to change {
288
- Execution.find(id: webhook_execution.id).webhook_id
289
- }.from(webhook_id).to(nil)
526
+ TriggeredWebhook.count
527
+ }.by(-1)
528
+ end
529
+
530
+ it "deletes the webhook_execution" do
531
+ expect { subject }.to change {
532
+ Execution.exclude(triggered_webhook_id: nil).count
533
+ }.by(-1)
534
+ end
535
+
536
+ it "deletes the deprecated webhook_execution" do
537
+ expect { subject }.to change {
538
+ Execution.exclude(consumer_id: nil).count
539
+ }.by(-1)
290
540
  end
291
541
  end
292
542
  end
@@ -1,5 +1,6 @@
1
1
  require 'spec_helper'
2
2
  require 'pact_broker/webhooks/service'
3
+ require 'pact_broker/webhooks/triggered_webhook'
3
4
  require 'webmock/rspec'
4
5
  require 'sucker_punch/testing/inline'
5
6
 
@@ -7,6 +8,24 @@ module PactBroker
7
8
 
8
9
  module Webhooks
9
10
  describe Service do
11
+ let(:td) { TestDataBuilder.new }
12
+
13
+ describe ".delete_by_uuid" do
14
+ before do
15
+ td.create_pact_with_hierarchy
16
+ .create_webhook
17
+ .create_triggered_webhook
18
+ .create_deprecated_webhook_execution
19
+ end
20
+
21
+ subject { Service.delete_by_uuid td.webhook.uuid }
22
+
23
+ it "deletes the webhook" do
24
+ expect { subject }.to change {
25
+ Webhook.count
26
+ }.by(-1)
27
+ end
28
+ end
10
29
 
11
30
  describe ".execute_webhooks" do
12
31
 
@@ -15,9 +34,11 @@ module PactBroker
15
34
  let(:consumer) { PactBroker::Domain::Pacticipant.new(name: 'Consumer') }
16
35
  let(:provider) { PactBroker::Domain::Pacticipant.new(name: 'Provider') }
17
36
  let(:webhooks) { [instance_double(PactBroker::Domain::Webhook, description: 'description', uuid: '1244')]}
37
+ let(:triggered_webhook) { instance_double(PactBroker::Webhooks::TriggeredWebhook) }
18
38
 
19
39
  before do
20
40
  allow_any_instance_of(PactBroker::Webhooks::Repository).to receive(:find_by_consumer_and_provider).and_return(webhooks)
41
+ allow_any_instance_of(PactBroker::Webhooks::Repository).to receive(:create_triggered_webhook).and_return(triggered_webhook)
21
42
  allow(Job).to receive(:perform_async)
22
43
  end
23
44
 
@@ -30,7 +51,7 @@ module PactBroker
30
51
 
31
52
  context "when webhooks are found" do
32
53
  it "executes the webhook" do
33
- expect(Service).to receive(:run_later).with(webhooks)
54
+ expect(Service).to receive(:run_later).with(webhooks, pact)
34
55
  subject
35
56
  end
36
57
  end
@@ -61,6 +82,44 @@ module PactBroker
61
82
  end
62
83
  end
63
84
 
85
+ describe ".execute_webhook_now integration test" do
86
+ let(:td) { TestDataBuilder.new }
87
+
88
+ let!(:http_request) do
89
+ stub_request(:get, "http://example.org").
90
+ to_return(:status => 200)
91
+ end
92
+
93
+ let!(:pact) do
94
+ td.create_consumer
95
+ .create_provider
96
+ .create_consumer_version
97
+ .create_pact
98
+ .create_webhook(method: 'GET', url: 'http://example.org')
99
+ .and_return(:pact)
100
+ end
101
+
102
+ subject { PactBroker::Webhooks::Service.execute_webhook_now td.webhook, pact }
103
+
104
+ it "executes the HTTP request of the webhook" do
105
+ subject
106
+ expect(http_request).to have_been_made
107
+ end
108
+
109
+ it "saves the triggered webhook" do
110
+ expect { subject }.to change { PactBroker::Webhooks::TriggeredWebhook.count }.by(1)
111
+ end
112
+
113
+ it "saves the execution" do
114
+ expect { subject }.to change { PactBroker::Webhooks::Execution.count }.by(1)
115
+ end
116
+
117
+ it "marks the triggered webhook as a success" do
118
+ subject
119
+ expect(TriggeredWebhook.first.status).to eq TriggeredWebhook::STATUS_SUCCESS
120
+ end
121
+ end
122
+
64
123
  describe ".execute_webhooks integration test" do
65
124
  let!(:http_request) do
66
125
  stub_request(:get, "http://example.org").
@@ -68,8 +127,7 @@ module PactBroker
68
127
  end
69
128
 
70
129
  let(:pact) do
71
- TestDataBuilder.new
72
- .create_consumer
130
+ td.create_consumer
73
131
  .create_provider
74
132
  .create_consumer_version
75
133
  .create_pact
@@ -84,9 +142,18 @@ module PactBroker
84
142
  expect(http_request).to have_been_made
85
143
  end
86
144
 
145
+ it "saves the triggered webhook" do
146
+ expect { subject }.to change { PactBroker::Webhooks::TriggeredWebhook.count }.by(1)
147
+ end
148
+
87
149
  it "saves the execution" do
88
150
  expect { subject }.to change { PactBroker::Webhooks::Execution.count }.by(1)
89
151
  end
152
+
153
+ it "marks the triggered webhook as a success" do
154
+ subject
155
+ expect(TriggeredWebhook.first.status).to eq TriggeredWebhook::STATUS_SUCCESS
156
+ end
90
157
  end
91
158
  end
92
159
  end