defra_ruby_mocks 4.0.0 → 4.2.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: c648dae3e678030c2d132615c0d148b673bedacde6d9d0e653dd2f20710fe4f9
4
- data.tar.gz: '0948298e72ee7c2adb8e5cd98ff71eaf0f72de6fe9a9faf0aa0e6ae1e3699c3b'
3
+ metadata.gz: fbc211a8e66923ea6517dd55d0f327c43b8b67e74981e8e49600a46eeb5ddd80
4
+ data.tar.gz: e28bfc2b91cfac3f76e8cf19dcee4cb00a2eb6e598826663f60d7e1ece4d2902
5
5
  SHA512:
6
- metadata.gz: 1cdb1d9e9b0f434ef1b7bcc58de8f5ec79c07bb10621772cd705ef33bad0a66a7767b764df299a8b506af750b296429b814a5b4575385b66d08cf8f985853778
7
- data.tar.gz: 4ca9a9935239757a5af2874392c85de2df9e9a1c93ee504610a8430b6179004de218b2ef9fb06ef20ffdc4e9edcc1f0d812d9ee14ed06a024ed14c46279dd50c
6
+ metadata.gz: b80a0af3f9ddd3711de5cac260152d2d7f503b74aece65788f6d96a805638501cb662ecec5a5c3572555a7972ab376ebf866b986ec1b56d8737763e6b571991e
7
+ data.tar.gz: c2036eb0aa7586a4d41c61ae7575b626f328e7900b5bc1318ea8c1c8b8648c84aab82d2826b8d29e81b7e75dca3ff6f67b07a90411bd7eb3cfcbe3b3cc98abc9
data/README.md CHANGED
@@ -178,7 +178,7 @@ In order to use the govpay mock you'll need to provide additional configuration
178
178
  require "defra_ruby_mocks"
179
179
 
180
180
  DefraRubyMocks.configure do |config|
181
- config.govpay_domain = File.join(ENV["WCRS_GOVPAY_DOMAIN"] || "http://localhost:3002", "/fo/mocks/govpay/v1")
181
+ config.govpay_domain = File.join(ENV["WCRS_GOVPAY_MOCK_DOMAIN"] || "http://localhost:3002", "/fo/mocks/govpay/v1")
182
182
  end
183
183
  ```
184
184
 
@@ -8,17 +8,30 @@ module DefraRubyMocks
8
8
  def create_payment
9
9
  valid_create_params
10
10
 
11
- # Enqueue the payment callback to run after the controller responds
12
- DefraRubyMocks::GovpayPaymentCallbackJob.perform_later(params[:return_url])
11
+ store_return_url(params[:return_url])
13
12
 
14
13
  render json: GovpayCreatePaymentService.new.run(
15
- amount: params[:amount], description: params[:description], return_url: params[:return_url]
14
+ amount: params[:amount], description: params[:description]
16
15
  )
17
16
  rescue StandardError => e
18
17
  Rails.logger.error("MOCKS: Govpay payment creation error: #{e.message}")
19
18
  head 500
20
19
  end
21
20
 
21
+ # This mocks the Govpay route which presents the payment details page to the user.
22
+ # We don't mock the actual payment details and payment confirmation pages - we go
23
+ # straight to the application callback route.
24
+ def next_url
25
+ response_url = retrieve_return_url
26
+ Rails.logger.warn "Govpay mock calling response URL #{response_url}"
27
+ redirect_to response_url, allow_other_host: true
28
+ rescue RestClient::ExceptionWithResponse => e
29
+ Rails.logger.warn "Govpay mock: RestClient received response: #{e}"
30
+ rescue StandardError => e
31
+ Rails.logger.error("Govpay mock: Error sending request to govpay: #{e}")
32
+ Airbrake.notify(e, message: "Error on govpay request")
33
+ end
34
+
22
35
  def payment_details
23
36
  valid_payment_id
24
37
  render json: GovpayGetPaymentService.new.run(payment_id: params[:payment_id])
@@ -44,6 +57,27 @@ module DefraRubyMocks
44
57
  head 500
45
58
  end
46
59
 
60
+ private
61
+
62
+ def s3_bucket_name
63
+ @s3_bucket_name = ENV.fetch("GOVPAY_MOCKS_BUCKET", "defra-ruby-mocks-s3bkt001")
64
+ end
65
+
66
+ def return_url_file_name
67
+ @return_url_file_name = "return_url_file"
68
+ end
69
+
70
+ # We need to persist the return_url between the initial payment creation request and the execution of next_url.
71
+ # We can't use tmp for multi-server environments so we load the temp file to AWS S3.
72
+ def store_return_url(return_url)
73
+ Rails.logger.warn ":::::: storing return_url #{return_url}"
74
+ AwsBucketService.write(s3_bucket_name, return_url_file_name, return_url)
75
+ end
76
+
77
+ def retrieve_return_url
78
+ AwsBucketService.read(s3_bucket_name, return_url_file_name)
79
+ end
80
+
47
81
  def valid_create_params
48
82
  params.require(%i[amount description return_url])
49
83
  end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DefraRubyMocks
4
+ class AwsBucketService
5
+
6
+ attr_accessor :bucket_name, :file_name
7
+
8
+ def self.write(bucket_name, file_name, content)
9
+ new.write(bucket_name, file_name, content)
10
+ end
11
+
12
+ def self.read(bucket_name, file_name)
13
+ new.read(bucket_name, file_name)
14
+ end
15
+
16
+ def write(bucket_name, file_name, content)
17
+ @bucket_name = bucket_name
18
+ @file_name = file_name
19
+
20
+ write_temp_file(content)
21
+
22
+ load_temp_file_to_s3
23
+
24
+ true
25
+ end
26
+
27
+ def read(bucket_name, file_name)
28
+ Rails.logger.warn ":::::: reading from S3"
29
+
30
+ s3 = Aws::S3::Client.new
31
+ s3.get_object(bucket: bucket_name, key: file_name)
32
+ rescue Aws::S3::NoSuchBucket => e
33
+ raise StandardError, e
34
+ end
35
+
36
+ private
37
+
38
+ def temp_filepath
39
+ "#{Dir.tmpdir}/#{file_name}"
40
+ end
41
+
42
+ def write_temp_file(content)
43
+ Rails.logger.warn ":::::: creating temp file for #{content}"
44
+ File.write(temp_filepath, content)
45
+ end
46
+
47
+ def load_temp_file_to_s3
48
+ Rails.logger.warn ":::::: loading temp file to S3"
49
+
50
+ result = nil
51
+
52
+ 3.times do
53
+ result = bucket.load(File.new(temp_filepath, "r"))
54
+
55
+ break if result.successful?
56
+ end
57
+
58
+ raise(result&.error) unless result&.successful?
59
+ end
60
+
61
+ def bucket
62
+ @bucket ||= DefraRuby::Aws.get_bucket(bucket_name)
63
+ end
64
+ end
65
+ end
@@ -5,12 +5,12 @@ require "securerandom"
5
5
  module DefraRubyMocks
6
6
  class GovpayCreatePaymentService < BaseService
7
7
 
8
- def run(amount:, description:, return_url:)
8
+ def run(amount:, description:)
9
9
  success_response.merge(
10
10
  {
11
11
  _links: {
12
12
  self: { href: "#{base_url}/#{payment_id}", method: "GET" },
13
- next_url: { href: return_url, method: "GET" }
13
+ next_url: { href: "#{base_url}/secure/next-url-uuid-abc123", method: "GET" }
14
14
  },
15
15
  amount: amount.to_i,
16
16
  description: description,
@@ -3,6 +3,8 @@
3
3
  module DefraRubyMocks
4
4
  class GovpayRefundDetailsService < BaseService
5
5
 
6
+ DEFAULT_LAST_REFUND_REQUEST_TIME = 1.day.ago.freeze
7
+
6
8
  def run(payment_id:, refund_id:) # rubocop:disable Lint/UnusedMethodArgument
7
9
  {
8
10
  amount: 2000,
@@ -19,24 +21,37 @@ module DefraRubyMocks
19
21
 
20
22
  # "submitted" for up to GOVPAY_REFUND_SUBMITTED_SUCCESS_LAG seconds after the last refund request, then "success"
21
23
  def status
22
- timestamp = File.read("#{Dir.tmpdir}/govpay_request_refund_service_last_run_time")
23
- last_refund_time = timestamp ? Time.parse(timestamp) : 1.day.ago
24
+ last_refund_time = refund_request_timestamp
24
25
  submitted_success_lag = ENV.fetch("GOVPAY_REFUND_SUBMITTED_SUCCESS_LAG", 0).to_i
25
26
  cutoff_time = (last_refund_time + submitted_success_lag.seconds).to_time
26
27
  return "success" if submitted_success_lag.zero?
27
28
 
28
29
  Time.zone.now < cutoff_time ? "submitted" : "success"
29
30
  rescue Errno::ENOENT
30
- write_timestamp_file("govpay_request_refund_service_last_run_time")
31
+ write_timestamp_file
31
32
 
32
33
  "success"
33
34
  end
34
35
 
35
- def write_timestamp_file(filename)
36
- filepath = "#{Dir.tmpdir}/#{filename}"
36
+ def write_timestamp_file
37
+ timestamp = Time.zone.now
38
+ Rails.logger.warn ":::::: writing timestamp file: #{timestamp}"
39
+ AwsBucketService.write(s3_bucket_name, timestamp_file_name, timestamp)
40
+ end
41
+
42
+ def s3_bucket_name
43
+ @s3_bucket_name = ENV.fetch("GOVPAY_MOCKS_BUCKET", "defra-ruby-mocks-s3bkt001")
44
+ end
45
+
46
+ def timestamp_file_name
47
+ @govpay_request_refund_service_last_run_time = "govpay_request_refund_service_last_run_time"
48
+ end
37
49
 
38
- # FileUtils.touch seems unreliable in VM so need to write/read the actual time
39
- File.write(filepath, Time.zone.now)
50
+ def refund_request_timestamp
51
+ timestamp = AwsBucketService.read(s3_bucket_name, timestamp_file_name)
52
+ timestamp ? Time.parse(timestamp) : DEFAULT_LAST_REFUND_REQUEST_TIME
53
+ rescue StandardError
54
+ DEFAULT_LAST_REFUND_REQUEST_TIME
40
55
  end
41
56
 
42
57
  end
@@ -19,9 +19,16 @@ module DefraRubyMocks
19
19
 
20
20
  # let the refund details service know how long since the refund was requested
21
21
  def write_timestamp
22
- filepath = "#{Dir.tmpdir}/govpay_request_refund_service_last_run_time"
23
- # FileUtils.touch seems unreliable in VM so need to write/read the actual time
24
- File.write(filepath, Time.zone.now)
22
+ Rails.logger.warn ":::::: storing refund request timestamp"
23
+ AwsBucketService.write(s3_bucket_name, timestamp_file_name, Time.zone.now.to_s)
24
+ end
25
+
26
+ def s3_bucket_name
27
+ @s3_bucket_name = ENV.fetch("GOVPAY_MOCKS_BUCKET", "defra-ruby-mocks-s3bkt001")
28
+ end
29
+
30
+ def timestamp_file_name
31
+ @timestamp_file_name = "govpay_request_refund_service_last_run_time"
25
32
  end
26
33
  end
27
34
  end
data/config/routes.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- DefraRubyMocks::Engine.routes.draw do
3
+ DefraRubyMocks::Engine.routes.draw do # rubocop:disable Metrics/BlockLength
4
4
  get "/company/:id",
5
5
  to: "company#show",
6
6
  as: "company",
@@ -16,6 +16,11 @@ DefraRubyMocks::Engine.routes.draw do
16
16
  as: "govpay_create_payment",
17
17
  constraints: ->(_request) { DefraRubyMocks.configuration.enabled? }
18
18
 
19
+ get "/govpay/v1/payments/secure/:uuid",
20
+ to: "govpay#next_url",
21
+ as: "govpay_next_url",
22
+ constraints: ->(_request) { DefraRubyMocks.configuration.enabled? }
23
+
19
24
  get "/govpay/v1/payments/:payment_id",
20
25
  to: "govpay#payment_details",
21
26
  as: "govpay_payment_details",
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DefraRubyMocks
4
- VERSION = "4.0.0"
4
+ VERSION = "4.2.0"
5
5
  end
@@ -12,12 +12,6 @@ module DefraRubyMocks
12
12
  def configuration
13
13
  @configuration ||= Configuration.new
14
14
  end
15
-
16
- # Added for testing. Without we cannot test both a config object with and
17
- # with set values in the same rspec session
18
- def reset_configuration
19
- @configuration = nil
20
- end
21
15
  end
22
16
 
23
17
  def self.configure
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.0.0
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Defra
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-10-05 00:00:00.000000000 Z
11
+ date: 2024-05-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -28,30 +28,44 @@ dependencies:
28
28
  name: sprockets
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '4.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: '4.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: sprockets-rails
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: '3.0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: defra_ruby_aws
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.5'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
53
67
  - !ruby/object:Gem::Version
54
- version: '0'
68
+ version: '0.5'
55
69
  description: A Rails engine which can be used to mock external services when loaded
56
70
  into an application
57
71
  email:
@@ -66,8 +80,7 @@ files:
66
80
  - app/controllers/defra_ruby_mocks/application_controller.rb
67
81
  - app/controllers/defra_ruby_mocks/company_controller.rb
68
82
  - app/controllers/defra_ruby_mocks/govpay_controller.rb
69
- - app/jobs/defra_ruby_mocks/application_job.rb
70
- - app/jobs/defra_ruby_mocks/govpay_payment_callback_job.rb
83
+ - app/services/defra_ruby_mocks/aws_bucket_service.rb
71
84
  - app/services/defra_ruby_mocks/base_service.rb
72
85
  - app/services/defra_ruby_mocks/companies_house_service.rb
73
86
  - app/services/defra_ruby_mocks/govpay_create_payment_service.rb
@@ -1,6 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module DefraRubyMocks
4
- class ApplicationJob < ActiveJob::Base
5
- end
6
- end
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module DefraRubyMocks
4
- class GovpayPaymentCallbackJob < DefraRubyMocks::ApplicationJob
5
- queue_as :default
6
-
7
- def perform(*response_url)
8
- Rails.logger.debug "GovpayPaymentCallbackJob calling response URL #{response_url}"
9
- RestClient::Request.execute(method: :GET, url: response_url[0])
10
- rescue RestClient::ExceptionWithResponse => e
11
- Rails.logger.debug "GovpayPaymentCallbackJob: RestClient received response: #{e}"
12
- rescue StandardError => e
13
- Rails.logger.error("GovpayPaymentCallbackJob: Error sending request to govpay: #{e}")
14
- Airbrake.notify(e, message: "Error on govpay request")
15
- end
16
- end
17
- end