defra_ruby_mocks 4.2.2 → 5.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6394eef6671bf7402ae9086113fa641729b149df46d6f1fcb6a1d3281c19b742
4
- data.tar.gz: 5e0606b7bb200a849cea22cd1abbee314cbbf0449fb7003de05b85be7ef57136
3
+ metadata.gz: f12b1df78280f62fd050fc87d169a323a5596e170a3f4908d6e98eac105bbd35
4
+ data.tar.gz: c01fdde1d3574ad5c12fc89256ae31af9fb326a96d505410f5b3d3189b62f003
5
5
  SHA512:
6
- metadata.gz: 1dea451c6e0c2e98c913b8d8c5d0c67915a7548a0d3a648f1d891df3c0b4ca40b7c47d8c82ecc2a8b8d9e3a9ec290e07bb628452dfa37fea9e8fa940d381ef5e
7
- data.tar.gz: 762b4407b39d0538f7386a3733b915a217dd810c787ca0080b4be8684ed4857349e6b26258e3eb4a7cf74eddf90cfa3c385a3b3df5235fe72dc9d100a9e8540a
6
+ metadata.gz: fe25184586116d837320be07f712f56c47c9728c906b6d7a43ceddd908614fffae27fd5a408181633f90c20a50818fa2cee11f0c6e3a6c6dac19707dced20a76
7
+ data.tar.gz: 1d54bd00a0bca62769bc1b91c27a2521b27de9cce062905787e7cec8c72d58297805a48700de041a287db7aebc21a77bd305484cbfca617eb43860a900de83dd
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DefraRubyMocks
4
+ class GovpayTestHelpersController < ::DefraRubyMocks::ApplicationController
5
+
6
+ skip_before_action :verify_authenticity_token
7
+
8
+ # These are helpers for the automated acceptance tests.
9
+
10
+ # The mock will use the value passed in to populate the status field on all future payments.
11
+ def set_test_payment_response_status
12
+ Rails.logger.info "MOCKS: Setting payment response status to #{params[:status]}"
13
+
14
+ AwsBucketService.write(s3_bucket_name, "test_payment_response_status", params[:status])
15
+
16
+ head 200
17
+ end
18
+
19
+ # The mock will use the value passed in to populate the status field on all future refunds.
20
+ def set_test_refund_response_status
21
+ Rails.logger.info "MOCKS: Setting refund response status to #{params[:status]}"
22
+
23
+ AwsBucketService.write(s3_bucket_name, "test_refund_response_status", params[:status])
24
+
25
+ head 200
26
+ end
27
+
28
+ # This schedules a job to send a mock payment webhook.
29
+ def send_payment_webhook
30
+ Rails.logger.warn "MOCKS: Sending payment webhook for #{params[:govpay_id]}, status #{params[:payment_status]}"
31
+ %w[govpay_id payment_status callback_url signing_secret].each do |p|
32
+ raise StandardError, "Missing parameter: '#{p}'" unless params[p].present?
33
+ end
34
+
35
+ SendPaymentWebhookJob.perform_later(
36
+ govpay_id: params[:govpay_id],
37
+ status: params[:payment_status],
38
+ callback_url: params[:callback_url],
39
+ signing_secret: params[:signing_secret]
40
+ )
41
+
42
+ head 200
43
+ end
44
+
45
+ # This schedules a job to send a mock refund webhook.
46
+ def send_refund_webhook
47
+ Rails.logger.warn "MOCKS: Sending refund webhook for #{params[:govpay_id]}, status #{params[:refund_status]}"
48
+ %w[govpay_id refund_status callback_url signing_secret].each do |p|
49
+ raise StandardError, "Missing parameter: '#{p}'" unless params[p].present?
50
+ end
51
+
52
+ SendRefundWebhookJob.perform_later(
53
+ govpay_id: params[:govpay_id],
54
+ status: params[:refund_status],
55
+ callback_url: params[:callback_url],
56
+ signing_secret: params[:signing_secret]
57
+ )
58
+
59
+ head 200
60
+ end
61
+
62
+ private
63
+
64
+ def s3_bucket_name
65
+ @s3_bucket_name = ENV.fetch("AWS_DEFRA_RUBY_MOCKS_BUCKET", nil)
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ApplicationJob < ActiveJob::Base
4
+ queue_as :default
5
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ class BaseSendWebhookJob < ApplicationJob
4
+ def perform(govpay_id:, status:, callback_url:, signing_secret:)
5
+ body = webhook_body(govpay_id:, status:)
6
+ Rails.logger.warn "MOCKS: sending #{webhook_type} webhook for #{govpay_id}, status \"#{status}\" to #{callback_url}"
7
+ RestClient::Request.execute(
8
+ method: :get,
9
+ url: callback_url,
10
+ body: body,
11
+ headers: { "Pay-Signature": webhook_signature(body, signing_secret) }
12
+ )
13
+ rescue StandardError => e
14
+ Rails.logger.error "MOCKS: error sending #{webhook_type} webhook to #{callback_url}: #{e}\n#{e.backtrace}"
15
+ end
16
+
17
+ private
18
+
19
+ def webhook_type
20
+ raise NotImplementedError
21
+ end
22
+
23
+ def webhook_body(govpay_id:, status:)
24
+ raise NotImplementedError
25
+ end
26
+
27
+ def webhook_signature(webhook_body, signing_secret)
28
+ OpenSSL::HMAC.hexdigest("sha256", signing_secret.encode("utf-8"), webhook_body.to_json.encode("utf-8"))
29
+ end
30
+
31
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SendPaymentWebhookJob < BaseSendWebhookJob
4
+
5
+ private
6
+
7
+ def webhook_type
8
+ "payment"
9
+ end
10
+
11
+ def webhook_body(govpay_id:, status:)
12
+ webhook_body ||= JSON.parse(File.read("lib/fixtures/files/govpay/webhook_payment_update_body.json"))
13
+
14
+ webhook_body["resource"]["payment_id"] = govpay_id
15
+ webhook_body["resource"]["state"]["status"] = status
16
+
17
+ webhook_body
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SendRefundWebhookJob < BaseSendWebhookJob
4
+
5
+ private
6
+
7
+ def webhook_type
8
+ "refund"
9
+ end
10
+
11
+ def webhook_body(govpay_id:, status:)
12
+ webhook_body ||= JSON.parse(File.read("lib/fixtures/files/govpay/webhook_refund_update_body.json"))
13
+
14
+ webhook_body["payment_id"] = govpay_id
15
+ webhook_body["status"] = status
16
+
17
+ webhook_body
18
+ end
19
+ end
@@ -16,10 +16,15 @@ module DefraRubyMocks
16
16
  new.read(bucket_name, file_name)
17
17
  end
18
18
 
19
+ def self.remove(bucket_name, file_name)
20
+ Rails.logger.debug ":::::: mocks removing #{file_name} on S3"
21
+ new.remove(bucket_name, file_name)
22
+ end
23
+
19
24
  def write(bucket_name, file_name, content)
20
25
  @bucket_name = bucket_name
21
26
  @file_name = file_name
22
- Rails.logger.debug ":::::: mocks writing to S3"
27
+ Rails.logger.debug ":::::: mocks writing #{file_name} to S3"
23
28
 
24
29
  write_temp_file(content)
25
30
 
@@ -31,20 +36,30 @@ module DefraRubyMocks
31
36
  def read(bucket_name, file_name)
32
37
  @bucket_name = bucket_name
33
38
  @file_name = file_name
34
- Rails.logger.debug ":::::: mocks reading from S3"
39
+ Rails.logger.debug ":::::: mocks reading #{file_name} from S3"
40
+
41
+ s3.get_object(bucket: bucket_name, key: file_name).body.read
42
+ end
43
+
44
+ def remove(bucket_name, file_name)
45
+ @bucket_name = bucket_name
46
+ Rails.logger.debug ":::::: mocks removing #{file_name} from S3"
35
47
 
36
- s3 = Aws::S3::Client.new(
48
+ bucket.delete(file_name)
49
+ end
50
+
51
+ private
52
+
53
+ def s3
54
+ @s3 ||= Aws::S3::Client.new(
37
55
  region: ENV.fetch("AWS_REGION", nil),
38
56
  credentials: Aws::Credentials.new(
39
57
  ENV.fetch("AWS_DEFRA_RUBY_MOCKS_ACCESS_KEY_ID", nil),
40
58
  ENV.fetch("AWS_DEFRA_RUBY_MOCKS_SECRET_ACCESS_KEY", nil)
41
59
  )
42
60
  )
43
- s3.get_object(bucket: bucket_name, key: file_name).body.read
44
61
  end
45
62
 
46
- private
47
-
48
63
  def temp_filepath
49
64
  "#{Dir.tmpdir}/#{file_name}"
50
65
  end
@@ -21,6 +21,19 @@ module DefraRubyMocks
21
21
 
22
22
  private
23
23
 
24
+ def s3_bucket_name
25
+ @s3_bucket_name = ENV.fetch("AWS_DEFRA_RUBY_MOCKS_BUCKET", nil)
26
+ end
27
+
28
+ # Check if a non-default status value has been requested
29
+ def test_payment_response_status
30
+ AwsBucketService.read(s3_bucket_name, "test_payment_response_status") || "created"
31
+ rescue StandardError => e
32
+ # This is expected behaviour when the payment status default override file is not present.
33
+ Rails.logger.warn ":::::: mocks failed to read test_payment_response_status: #{e}"
34
+ "created"
35
+ end
36
+
24
37
  def base_url
25
38
  File.join(DefraRubyMocks.configuration.govpay_domain, "/payments")
26
39
  end
@@ -34,7 +47,7 @@ module DefraRubyMocks
34
47
  {
35
48
  created_date: "2020-03-03T16:17:19.554Z",
36
49
  state: {
37
- status: "created",
50
+ status: test_payment_response_status,
38
51
  finished: false
39
52
  },
40
53
  _links: {
@@ -19,6 +19,15 @@ module DefraRubyMocks
19
19
 
20
20
  private
21
21
 
22
+ # Check if a non-default status value has been requested
23
+ def test_payment_response_status
24
+ AwsBucketService.read(s3_bucket_name, "test_payment_response_status") || "success"
25
+ rescue StandardError => e
26
+ # This is expected behaviour when the payment status default override file is not present.
27
+ Rails.logger.warn ":::::: mocks failed to read test_payment_response_status: #{e}"
28
+ "success"
29
+ end
30
+
22
31
  # rubocop:disable Metrics/MethodLength
23
32
  def response_success
24
33
  {
@@ -32,7 +41,7 @@ module DefraRubyMocks
32
41
  },
33
42
  email: "sherlock.holmes@example.com",
34
43
  state: {
35
- status: "success",
44
+ status: test_payment_response_status,
36
45
  finished: true
37
46
  },
38
47
  payment_id: "cnnffa1e6s3u9a6n24u2cp527d",
@@ -19,14 +19,24 @@ module DefraRubyMocks
19
19
 
20
20
  private
21
21
 
22
- # "submitted" for up to GOVPAY_REFUND_SUBMITTED_SUCCESS_LAG seconds after the last refund request, then "success"
22
+ # Check if a non-default status value has been requested
23
+ def test_refund_response_status
24
+ AwsBucketService.read(s3_bucket_name, "test_refund_response_status") || "submitted"
25
+ rescue StandardError => e
26
+ # This is expected behaviour when the refund status default override file is not present.
27
+ Rails.logger.warn ":::::: mocks failed to read test_refund_response_status: #{e}"
28
+ "submitted"
29
+ end
30
+
31
+ # "submitted" (or other, if default override is in place) for up to GOVPAY_REFUND_SUBMITTED_SUCCESS_LAG
32
+ # seconds after the last refund request, then "success"
23
33
  def status
24
34
  last_refund_time = refund_request_timestamp
25
35
  submitted_success_lag = ENV.fetch("GOVPAY_REFUND_SUBMITTED_SUCCESS_LAG", 0).to_i
26
36
  cutoff_time = (last_refund_time + submitted_success_lag.seconds).to_time
27
37
  return "success" if submitted_success_lag.zero?
28
38
 
29
- Time.zone.now < cutoff_time ? "submitted" : "success"
39
+ Time.zone.now < cutoff_time ? test_refund_response_status : "success"
30
40
  rescue Errno::ENOENT
31
41
  write_timestamp_file
32
42
 
@@ -40,7 +50,7 @@ module DefraRubyMocks
40
50
  end
41
51
 
42
52
  def s3_bucket_name
43
- @s3_bucket_name = ENV.fetch("GOVPAY_MOCKS_BUCKET", "defra-ruby-mocks-s3bkt001")
53
+ @s3_bucket_name = ENV.fetch("AWS_DEFRA_RUBY_MOCKS_BUCKET", nil)
44
54
  end
45
55
 
46
56
  def timestamp_file_name
@@ -6,17 +6,25 @@ module DefraRubyMocks
6
6
  def run(payment_id:, amount:, refund_amount_available:) # rubocop:disable Lint/UnusedMethodArgument
7
7
  write_timestamp
8
8
 
9
- # This currently supports only "submitted" status:
10
9
  {
11
10
  amount: amount,
12
11
  created_date: "2019-09-19T16:53:03.213Z",
13
12
  refund_id: SecureRandom.hex(22),
14
- status: "submitted"
13
+ status: test_refund_response_status
15
14
  }
16
15
  end
17
16
 
18
17
  private
19
18
 
19
+ # Check if a non-default status value has been requested
20
+ def test_refund_response_status
21
+ AwsBucketService.read(s3_bucket_name, "test_refund_response_status") || "submitted"
22
+ rescue StandardError => e
23
+ # This is expected behaviour when the refund status default override file is not present.
24
+ Rails.logger.warn ":::::: mocks failed to read test_refund_response_status: #{e}"
25
+ "submitted"
26
+ end
27
+
20
28
  # let the refund details service know how long since the refund was requested
21
29
  def write_timestamp
22
30
  Rails.logger.warn ":::::: storing refund request timestamp"
@@ -24,7 +32,7 @@ module DefraRubyMocks
24
32
  end
25
33
 
26
34
  def s3_bucket_name
27
- @s3_bucket_name = ENV.fetch("GOVPAY_MOCKS_BUCKET", "defra-ruby-mocks-s3bkt001")
35
+ @s3_bucket_name = ENV.fetch("AWS_DEFRA_RUBY_MOCKS_BUCKET", nil)
28
36
  end
29
37
 
30
38
  def timestamp_file_name
data/config/routes.rb CHANGED
@@ -35,4 +35,25 @@ DefraRubyMocks::Engine.routes.draw do # rubocop:disable Metrics/BlockLength
35
35
  to: "govpay#refund_details",
36
36
  as: "govpay_refund_details",
37
37
  constraints: ->(_request) { DefraRubyMocks.configuration.enabled? }
38
+
39
+ # test helpers, not mocks:
40
+ get "/govpay/v1/payments/set_test_payment_response_status/:status",
41
+ to: "govpay_test_helpers#set_test_payment_response_status",
42
+ as: "govpay_set_test_payment_response_status",
43
+ constraints: ->(_request) { DefraRubyMocks.configuration.enabled? }
44
+
45
+ get "/govpay/v1/payments/set_test_refund_response_status/:status",
46
+ to: "govpay_test_helpers#set_test_refund_response_status",
47
+ as: "govpay_set_test_refund_response_status",
48
+ constraints: ->(_request) { DefraRubyMocks.configuration.enabled? }
49
+
50
+ post "/govpay/v1/payments/:govpay_id/send_payment_webhook",
51
+ to: "govpay_test_helpers#send_payment_webhook",
52
+ as: "send_payment_webhook",
53
+ constraints: ->(_request) { DefraRubyMocks.configuration.enabled? }
54
+
55
+ post "/govpay/v1/payments/:govpay_id/send_refund_webhook",
56
+ to: "govpay_test_helpers#send_refund_webhook",
57
+ as: "send_refund_webhook",
58
+ constraints: ->(_request) { DefraRubyMocks.configuration.enabled? }
38
59
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DefraRubyMocks
4
- VERSION = "4.2.2"
4
+ VERSION = "5.1.0"
5
5
  end
@@ -0,0 +1,48 @@
1
+ {
2
+ "webhook_message_id": "123abc",
3
+ "api_version": 1,
4
+ "created_date": "2019-07-11T10:36:26.988Z",
5
+ "resource_id": "hu20sqlact5260q2nanm0q8u93",
6
+ "resource_type": "payment",
7
+ "event_type": "card_payment_captured",
8
+ "resource": {
9
+ "amount": 5000,
10
+ "description": "Pay your council tax",
11
+ "reference": "12345",
12
+ "language": "en",
13
+ "email": "sherlock.holmes@example.com",
14
+ "state": {
15
+ "status": "success",
16
+ "finished": false
17
+ },
18
+ "payment_id": "hu20sqlact5260q2nanm0q8u93",
19
+ "payment_provider": "stripe",
20
+ "created_date": "2021-10-19T10:05:45.454Z",
21
+ "refund_summary": {
22
+ "status": "pending",
23
+ "amount_available": 5000,
24
+ "amount_submitted": 0
25
+ },
26
+ "settlement_summary": {},
27
+ "card_details": {
28
+ "last_digits_card_number": "1234",
29
+ "first_digits_card_number": "123456",
30
+ "cardholder_name": "Sherlock Holmes",
31
+ "expiry_date": "04/24",
32
+ "billing_address": {
33
+ "line1": "221 Baker Street",
34
+ "line2": "Flat b",
35
+ "postcode": "NW1 6XE",
36
+ "city": "London",
37
+ "country": "GB"
38
+ },
39
+ "card_brand": "Visa",
40
+ "card_type": "debit"
41
+ },
42
+ "delayed_capture": false,
43
+ "moto": false,
44
+ "provider_id": "10987654321",
45
+ "return_url": "https://your.service.gov.uk/completed"
46
+ }
47
+ }
48
+
@@ -0,0 +1,8 @@
1
+ {
2
+ "refund_id": "345",
3
+ "created_date": "2022-01-26T16:52:41.178Z",
4
+ "amount": 2000,
5
+ "status": "success",
6
+ "settlement_summary": {},
7
+ "payment_id": "789"
8
+ }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: defra_ruby_mocks
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.2.2
4
+ version: 5.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Defra
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-29 00:00:00.000000000 Z
11
+ date: 2025-05-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0.5'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rest-client
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.0'
69
83
  description: A Rails engine which can be used to mock external services when loaded
70
84
  into an application
71
85
  email:
@@ -80,6 +94,11 @@ files:
80
94
  - app/controllers/defra_ruby_mocks/application_controller.rb
81
95
  - app/controllers/defra_ruby_mocks/company_controller.rb
82
96
  - app/controllers/defra_ruby_mocks/govpay_controller.rb
97
+ - app/controllers/defra_ruby_mocks/govpay_test_helpers_controller.rb
98
+ - app/jobs/application_job.rb
99
+ - app/jobs/base_send_webhook_job.rb
100
+ - app/jobs/send_payment_webhook_job.rb
101
+ - app/jobs/send_refund_webhook_job.rb
83
102
  - app/services/defra_ruby_mocks/aws_bucket_service.rb
84
103
  - app/services/defra_ruby_mocks/base_service.rb
85
104
  - app/services/defra_ruby_mocks/companies_house_service.rb
@@ -97,6 +116,8 @@ files:
97
116
  - lib/defra_ruby_mocks/invalid_config_error.rb
98
117
  - lib/defra_ruby_mocks/missing_resource_error.rb
99
118
  - lib/defra_ruby_mocks/version.rb
119
+ - lib/fixtures/files/govpay/webhook_payment_update_body.json
120
+ - lib/fixtures/files/govpay/webhook_refund_update_body.json
100
121
  - lib/tasks/changelog.rake
101
122
  - lib/tasks/defra_ruby_mocks_tasks.rake
102
123
  homepage: https://github.com/DEFRA/defra-ruby-mocks