lib/vcr/cassette/migrator.rb
require 'vcr'
module VCR
class Cassette
# @private
class Migrator
def initialize(dir, out = $stdout)
@dir, @out = dir, out
@yaml_load_errors = yaml_load_errors
end
def migrate!
@out.puts "Migrating VCR cassettes in #{@dir}..."
Dir["#{@dir}/**/*.yml"].each do |cassette|
migrate_cassette(cassette)
end
end
private
def migrate_cassette(cassette)
unless http_interactions = load_yaml(cassette)
@out.puts " - Ignored #{relative_casssette_name(cassette)} since it could not be parsed as YAML (does it have some ERB?)"
return
end
unless valid_vcr_1_cassette?(http_interactions)
@out.puts " - Ignored #{relative_casssette_name(cassette)} since it does not appear to be a valid VCR 1.x cassette"
return
end
http_interactions.map! do |interaction|
interaction.response.adapter_metadata = {}
interaction.recorded_at = File.mtime(cassette)
remove_unnecessary_standard_port(interaction)
denormalize_http_header_keys(interaction.request)
denormalize_http_header_keys(interaction.response)
normalize_body(interaction.request)
normalize_body(interaction.response)
interaction.to_hash
end
hash = {
"http_interactions" => http_interactions,
"recorded_with" => "VCR #{VCR.version}"
}
File.open(cassette, 'w') { |f| f.write ::YAML.dump(hash) }
@out.puts " - Migrated #{relative_casssette_name(cassette)}"
end
def load_yaml(cassette)
if ::YAML.respond_to?(:unsafe_load_file)
::YAML.unsafe_load_file(cassette)
else
::YAML.load_file(cassette)
end
rescue *@yaml_load_errors
return nil
end
def yaml_load_errors
[ArgumentError].tap do |errors|
errors << Psych::SyntaxError if defined?(Psych::SyntaxError)
end
end
def relative_casssette_name(cassette)
cassette.gsub(%r|\A#{Regexp.escape(@dir)}/?|, '')
end
def valid_vcr_1_cassette?(content)
content.is_a?(Array) &&
content.map(&:class).uniq == [HTTPInteraction]
end
def remove_unnecessary_standard_port(interaction)
uri = VCR.configuration.uri_parser.parse(interaction.request.uri)
if uri.scheme == 'http' && uri.port == 80 ||
uri.scheme == 'https' && uri.port == 443
uri.port = nil
interaction.request.uri = uri.to_s
end
rescue URI::InvalidURIError
# ignore this URI.
# This can occur when the user uses the filter_sensitive_data option
# to put a substitution string in their URI
end
def denormalize_http_header_keys(object)
object.headers = {}.tap do |denormalized|
object.headers.each do |k, v|
denormalized[denormalize_header_key(k)] = v
end if object.headers
end
end
def denormalize_header_key(key)
key.split('-'). # 'user-agent' => %w(user agent)
each { |w| w.capitalize! }. # => %w(User Agent)
join('-')
end
EMPTY_STRING = if String.method_defined?(:force_encoding)
''.force_encoding("US-ASCII")
else
''
end
def normalize_body(object)
object.body = EMPTY_STRING if object.body.nil?
end
end
end
end