vcr.rb 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. # Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
  2. VCR_IGNORE_MATCHING_HOSTS = %w[elasticsearch selenium zammad.org zammad.com znuny.com google.com login.microsoftonline.com github.com].freeze
  3. VCR_IGNORE_MATCHING_REGEXPS = [%r{^192\.168\.\d+\.\d+$}].freeze
  4. VCR.configure do |config|
  5. config.cassette_library_dir = 'test/data/vcr_cassettes'
  6. config.hook_into :webmock
  7. config.allow_http_connections_when_no_cassette = false
  8. config.ignore_localhost = true
  9. config.ignore_request do |request|
  10. uri = URI(request.uri)
  11. next true if VCR_IGNORE_MATCHING_HOSTS.any? { |elem| uri.host.include? elem }
  12. next true if VCR_IGNORE_MATCHING_REGEXPS.any? { |elem| uri.host.match? elem }
  13. end
  14. config.register_request_matcher(:oauth_headers) do |r1, r2|
  15. without_onetime_oauth_params = ->(params) { params.gsub(%r{oauth_(nonce|signature|timestamp)="[^"]+", }, '') }
  16. r1.headers.except('Authorization') == r2.headers.except('Authorization') &&
  17. r1.headers['Authorization']&.map(&without_onetime_oauth_params) ==
  18. r2.headers['Authorization']&.map(&without_onetime_oauth_params)
  19. end
  20. end
  21. module RSpec
  22. VCR_ADVISORY = <<~MSG.freeze
  23. If this test is failing unexpectedly, the VCR cassette may be to blame.
  24. This can happen when changing `describe`/`context` labels on some specs;
  25. see commit message 1ebddff95 for details.
  26. Check `git status` to see if a new VCR cassette has been generated.
  27. If so, rename the old cassette to replace the new one and try again.
  28. MSG
  29. module Support
  30. module VCRHelper
  31. def self.inject_advisory(example)
  32. # block argument is an #<RSpec::Expectations::ExpectationNotMetError>
  33. define_method(:notify_failure) do |e, options = {}|
  34. super(e.exception(VCR_ADVISORY + e.message), options)
  35. end
  36. example.run
  37. ensure
  38. remove_method(:notify_failure)
  39. end
  40. end
  41. singleton_class.send(:prepend, VCRHelper)
  42. end
  43. module Expectations
  44. module VCRHelper
  45. def self.inject_advisory(example)
  46. define_method(:handle_matcher) do |*args|
  47. super(*args)
  48. rescue => e
  49. raise e.exception(VCR_ADVISORY + e.message)
  50. end
  51. example.run
  52. ensure
  53. remove_method(:handle_matcher)
  54. end
  55. end
  56. PositiveExpectationHandler.singleton_class.send(:prepend, VCRHelper)
  57. NegativeExpectationHandler.singleton_class.send(:prepend, VCRHelper)
  58. end
  59. end
  60. RSpec.configure do |config|
  61. config.around(:each, use_vcr: true) do |example|
  62. vcr_options = Array(example.metadata[:use_vcr])
  63. spec_path = Pathname.new(example.file_path).realpath
  64. cassette_path = spec_path.relative_path_from(Rails.root.join('spec')).sub(%r{_spec\.rb$}, '')
  65. cassette_name = "#{example.metadata[:example_group][:full_description]}/#{example.description}".gsub(%r{[^0-9A-Za-z\-]+}, '_').downcase
  66. # handle file name limit of 255 chars
  67. if cassette_name.length > 253
  68. hexdigest_cassette_name = Digest::SHA256.hexdigest(cassette_name)
  69. shortened_casset_name = "#{cassette_name.first(30)}-#{cassette_name.last(30)}-#{hexdigest_cassette_name}"
  70. Rails.logger.info "Detected too long VCR filename '#{cassette_name}' (#{cassette_name.length}) and therefore converted it to '#{shortened_casset_name}'"
  71. cassette_name = shortened_casset_name
  72. end
  73. request_profile = [
  74. :method,
  75. :uri,
  76. vcr_options.include?(:with_oauth_headers) ? :oauth_headers : nil
  77. ].compact
  78. VCR.use_cassette(cassette_path.join(cassette_name), match_requests_on: request_profile) do |cassette|
  79. if vcr_options.include?(:time_sensitive) && !cassette.recording?
  80. travel_to(cassette.http_interactions.interactions.first.recorded_at)
  81. end
  82. example.run
  83. end
  84. end
  85. config.around(:each, use_vcr: true) do |example|
  86. RSpec::Support::VCRHelper.inject_advisory(example)
  87. end
  88. config.around(:each, use_vcr: true) do |example|
  89. RSpec::Expectations::VCRHelper.inject_advisory(example)
  90. end
  91. end