vcr-xml 0.0.1
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 +7 -0
- checksums.yaml.gz.asc +12 -0
- data.tar.gz.asc +12 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/lib/vcr-xml.rb +63 -0
- data/lib/vcr/cassette/serializers/xsyck.rb +38 -0
- data/lib/vcr/errors/unhandled_xml_request_error.rb +63 -0
- data/lib/vcr/errors/unhandled_xml_request_error/bodies.rb +9 -0
- data/lib/vcr/errors/unhandled_xml_request_error/diffs.rb +41 -0
- data/lib/vcr/errors/unhandled_xml_request_error/headers.rb +19 -0
- data/lib/vcr/errors/unhandled_xml_request_error/matchers.rb +34 -0
- data/lib/vcr/errors/unhandled_xml_request_error/suggestions.rb +45 -0
- data/lib/vcr/locales/en.yml +59 -0
- data/lib/vcr/locales/ru.yml +49 -0
- data/lib/vcr/not_xpath_matcher.rb +23 -0
- data/lib/vcr/xml.rb +1 -0
- data/lib/vcr/xml/version.rb +5 -0
- data/lib/vcr/xml_request_handler.rb +15 -0
- data/lib/vcr/xpath_matcher.rb +25 -0
- data/vcr-xml.gemspec +32 -0
- metadata +206 -0
- metadata.gz.asc +12 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5e437a8869b6388c90a90658481670e37cd4c3c5
|
4
|
+
data.tar.gz: bf4875d00c8d07af6188f57bd580e826935f9425
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 92a9a81425942d64888cc699f3a7cb01faa3e97e7d765ca32dd53d1a049c7ad37eb8dcc1a63f43ba01e475c6a3b3aefc5ad21d9a83e742016afcc3cc37a6654c
|
7
|
+
data.tar.gz: 5d08c3ec19e09cf091d7e61890d49674d00ca6a93c72f64cb202922376e95ef69914a05dce8a9cb3a34eef5a6f2917b73b41d5b290711d8d7a455fc7048054ff
|
checksums.yaml.gz.asc
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
-----BEGIN PGP SIGNATURE-----
|
2
|
+
Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
|
3
|
+
Comment: GPGTools - http://gpgtools.org
|
4
|
+
|
5
|
+
iQEcBAABCgAGBQJRwThDAAoJENcoxKfNVdjbXZcH/2klyOywZblFv7ZvwMybZowk
|
6
|
+
tKnOf5Jztm3NAa5ppJ/nfQsPQhoLM2Nza2s5oE44arB2mv2fAvK2xAKziLjDrb0u
|
7
|
+
DzVnWIoudNqRHIaXdbiIO4E1ZysxfmghM4yeS/U6NY6Ah+YSL2ak/Od2xCx6jb82
|
8
|
+
RxCP7mmcbcRwk0F+Ignp68sEjYdN63+ggqiO6ShaskAGA3A1UUfK+RI6+l7vvG6j
|
9
|
+
/eJ0RM7/3dnKWMeg3viu5QYjWm7u0yY2qp6hbkCpw0li5PGOZ1YvxO6smi+FqkoE
|
10
|
+
UcbbpMWGF2Xch9y8eDXoRfy6IyD435HVveV2R63LUtDhStjUmwRmdp+ljB1lrz0=
|
11
|
+
=nh51
|
12
|
+
-----END PGP SIGNATURE-----
|
data.tar.gz.asc
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
-----BEGIN PGP SIGNATURE-----
|
2
|
+
Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
|
3
|
+
Comment: GPGTools - http://gpgtools.org
|
4
|
+
|
5
|
+
iQEcBAABCgAGBQJRwThDAAoJENcoxKfNVdjbMjMH/2UQ7Xl22ESfw4EsDEdlN+OD
|
6
|
+
N4ar1AWK1QkPcqgcdfBNck+JWJ5UzcehpVPk2ikUB9vNpJCx0uXQU58d2Pl5LdVZ
|
7
|
+
nIQWrR3OZsDdC8yJtTnm5Ak2FS9CYEbfKhIRBtoDkOW7kXCJ0rF5sRpUnCs0OrSZ
|
8
|
+
ELcqZmXtSIF5iMhvV80x9xjBgv5pEMdNSuLhq10c3nBwT+bRKVfj3oa9mMLzpNuj
|
9
|
+
Hnh6+bBY4DA99THcaJ7BLpAUmx6OMpp++17Q272CJMR/Wq//oockLA0X/xnF0PML
|
10
|
+
plzc82KTqhyfgMLOl9g00mx9vR8in0NRUIZXRc2c/7ei226e9NHnBMakQS0+Ed8=
|
11
|
+
=eApB
|
12
|
+
-----END PGP SIGNATURE-----
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Vlad Bokov
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Vcr::Xml
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'vcr-xml'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install vcr-xml
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/vcr-xml.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'vcr/cassette/serializers/xsyck'
|
2
|
+
require 'vcr/errors/unhandled_xml_request_error'
|
3
|
+
require 'vcr/request_handler'
|
4
|
+
require 'vcr/xml_request_handler'
|
5
|
+
require 'vcr/xpath_matcher'
|
6
|
+
require 'vcr/header_matcher'
|
7
|
+
require 'vcr/not_xpath_matcher'
|
8
|
+
|
9
|
+
module XsyckSerializer
|
10
|
+
def new(*args, &blk)
|
11
|
+
super(*args, &blk).extend(InstanceMethods)
|
12
|
+
end
|
13
|
+
|
14
|
+
module InstanceMethods
|
15
|
+
def [](name)
|
16
|
+
@serializers.fetch(name) do
|
17
|
+
return @serializers[name] = VCR::Cassette::Serializers::Xsyck if name == :xsyck
|
18
|
+
end
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module ExtendedMatcherRegistry
|
25
|
+
def new(*args, &blk)
|
26
|
+
super(*args, &blk).extend(InstanceMethods)
|
27
|
+
end
|
28
|
+
|
29
|
+
module InstanceMethods
|
30
|
+
def [](matcher)
|
31
|
+
@registry.fetch(matcher) do
|
32
|
+
marker, xpath = matcher.to_s.split(/^xpath:/)
|
33
|
+
return VCR::XpathMatcher.new(xpath) if xpath
|
34
|
+
|
35
|
+
marker, notxpath = matcher.to_s.split(/^notxpath:/)
|
36
|
+
return VCR::NotXpathMatcher.new(notxpath) if notxpath
|
37
|
+
|
38
|
+
marker, keys = matcher.to_s.split(/^headers:\/\//)
|
39
|
+
return VCR::HeaderMatcher.new(keys.split(',')) if keys.split(',').present?
|
40
|
+
|
41
|
+
super
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
module ExtendedConfiguration
|
48
|
+
extend ActiveSupport::Concern
|
49
|
+
included do
|
50
|
+
attr_writer :locale
|
51
|
+
end
|
52
|
+
|
53
|
+
def locale
|
54
|
+
@locale ||= :en
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
VCR::Cassette::Serializers.send :extend, XsyckSerializer
|
59
|
+
VCR::RequestHandler.send :extend, XmlRequestHandler
|
60
|
+
VCR::RequestMatcherRegistry.send :extend, ExtendedMatcherRegistry
|
61
|
+
VCR::Configuration.send :include, ExtendedConfiguration
|
62
|
+
VCR::RequestMatcherRegistry.const_set :DEFAULT_MATCHERS, [:"headers://^Accept-Encoding", :"xpath://Body"]
|
63
|
+
I18n.load_path.unshift(*Dir[File.expand_path('../vcr/locales/*.yml', __FILE__)])
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module VCR
|
2
|
+
class Cassette
|
3
|
+
class Serializers
|
4
|
+
module Xsyck
|
5
|
+
extend EncodingErrorHandling
|
6
|
+
extend self
|
7
|
+
|
8
|
+
ENCODING_ERRORS = [ArgumentError]
|
9
|
+
|
10
|
+
def file_extension
|
11
|
+
"yml"
|
12
|
+
end
|
13
|
+
|
14
|
+
def deserialize(string)
|
15
|
+
handle_encoding_errors do
|
16
|
+
::Syck.load(string)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def serialize(hash)
|
21
|
+
hash['http_interactions'].each do |i|
|
22
|
+
pretty_xml i['request']['body']['string'] if /<\?xml/.match i['request']['body']['string']
|
23
|
+
pretty_xml i['response']['body']['string'] if /<\?xml/.match i['response']['body']['string']
|
24
|
+
end
|
25
|
+
handle_encoding_errors do
|
26
|
+
::Syck.dump(hash)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def pretty_xml(string)
|
33
|
+
string.replace Nokogiri::XML(string).to_xml.encode!('utf-8')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module VCR
|
2
|
+
module Errors
|
3
|
+
class UnhandledXmlRequestError < UnhandledHTTPRequestError
|
4
|
+
|
5
|
+
autoload :Matchers, 'vcr/errors/unhandled_xml_request_error/matchers'
|
6
|
+
autoload :Headers, 'vcr/errors/unhandled_xml_request_error/headers'
|
7
|
+
autoload :Bodies, 'vcr/errors/unhandled_xml_request_error/bodies'
|
8
|
+
autoload :Diffs, 'vcr/errors/unhandled_xml_request_error/diffs'
|
9
|
+
autoload :Suggestions, 'vcr/errors/unhandled_xml_request_error/suggestions'
|
10
|
+
|
11
|
+
include Matchers
|
12
|
+
include Headers
|
13
|
+
include Bodies
|
14
|
+
include Diffs
|
15
|
+
include Suggestions
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def construct_message
|
20
|
+
header = "\n" + "=" * 80 + "\n"
|
21
|
+
body = [
|
22
|
+
header_diff,
|
23
|
+
body_matchers,
|
24
|
+
body_diff,
|
25
|
+
translated_cassette_description,
|
26
|
+
translated_suggestions,
|
27
|
+
].join("\n\n")
|
28
|
+
footer = "\n" + "=" * 80 + "\n"
|
29
|
+
|
30
|
+
header + body + footer
|
31
|
+
end
|
32
|
+
|
33
|
+
def cassette_description
|
34
|
+
if cassette = VCR.current_cassette
|
35
|
+
["VCR is currently using the following cassette:",
|
36
|
+
" - #{cassette.file}",
|
37
|
+
" - :record => #{cassette.record_mode.inspect}",
|
38
|
+
" - :match_requests_on => #{cassette.match_requests_on.inspect}\n",
|
39
|
+
"Under the current configuration VCR can not find a suitable HTTP interaction",
|
40
|
+
"to replay and is prevented from recording new requests. There are a few ways",
|
41
|
+
"you can deal with this:\n"].join("\n")
|
42
|
+
else
|
43
|
+
["There is currently no cassette in use. There are a few ways",
|
44
|
+
"you can configure VCR to handle this request:\n"].join("\n")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def expected_request
|
49
|
+
@expected_request ||= VCR.http_interactions.interactions.first.try(:request)
|
50
|
+
end
|
51
|
+
|
52
|
+
def nokogirify(smth)
|
53
|
+
if smth.is_a? String
|
54
|
+
Nokogiri::XML(smth).tap { |x| x.remove_namespaces! }
|
55
|
+
elsif smth.respond_to? :body
|
56
|
+
Nokogiri::XML(smth.body).tap { |x| x.remove_namespaces! }
|
57
|
+
else
|
58
|
+
smth
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'diffy'
|
2
|
+
|
3
|
+
module VCR::Errors::UnhandledXmlRequestError::Diffs
|
4
|
+
def header_diff
|
5
|
+
return if !matched_by_headers? || header_diff_keys.empty?
|
6
|
+
@header_diff ||= begin
|
7
|
+
Hirb::Helpers::AutoTable.render header_diff_keys, fields: [:key, :expected, :got]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def body_diff
|
12
|
+
return if !matched_by_body? && !matched_by_xpath?
|
13
|
+
if expected_request
|
14
|
+
diff expected_body, received_body
|
15
|
+
else
|
16
|
+
diff '', format(request)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def diff(xml1, xml2)
|
21
|
+
::Diffy::Diff.new(xml1, xml2, context: 2).to_s(:color)
|
22
|
+
end
|
23
|
+
|
24
|
+
def format(nodes)
|
25
|
+
nokogirify(nodes).tap do |xml|
|
26
|
+
xml.xpath('//text()').each do |node|
|
27
|
+
if node.content=~/\S/
|
28
|
+
node.content = node.content.strip
|
29
|
+
else
|
30
|
+
node.remove
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end.to_xml
|
34
|
+
end
|
35
|
+
|
36
|
+
def filtred_xpaths(request)
|
37
|
+
xpath_matchers.reduce(nokogirify request) do |memo, matcher|
|
38
|
+
matcher.extract_xpath(memo)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module VCR::Errors::UnhandledXmlRequestError::Headers
|
2
|
+
def received_headers
|
3
|
+
@received_headers ||= request.headers
|
4
|
+
end
|
5
|
+
|
6
|
+
def expected_headers
|
7
|
+
@expected_headers ||= expected_request.try(:headers) || {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def header_diff_keys
|
11
|
+
expected_headers.diff(received_headers).map do |k,v|
|
12
|
+
{
|
13
|
+
key: k,
|
14
|
+
expected: "#{expected_headers[k]}:<#{expected_headers[k].class}>",
|
15
|
+
got: "#{received_headers[k]}:<#{received_headers[k].class}>"
|
16
|
+
}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module VCR::Errors::UnhandledXmlRequestError::Matchers
|
2
|
+
def body_matchers
|
3
|
+
xpath_matchers.map do |m|
|
4
|
+
"#{m.human_type}: #{m.xpath}"
|
5
|
+
end.join('\n')
|
6
|
+
end
|
7
|
+
|
8
|
+
def xpath_matchers
|
9
|
+
@xpath_matchers ||= VCR.http_interactions.request_matchers.map do |m|
|
10
|
+
matcher = VCR.request_matchers[m]
|
11
|
+
if matcher.is_a?(VCR::XpathMatcher) || matcher.is_a?(VCR::NotXpathMatcher)
|
12
|
+
matcher
|
13
|
+
else
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
end.compact
|
17
|
+
end
|
18
|
+
|
19
|
+
def matched_by_body?
|
20
|
+
matchers.empty? || matchers.include?(:body)
|
21
|
+
end
|
22
|
+
|
23
|
+
def matched_by_xpath?
|
24
|
+
matchers.empty? || matchers.any? { |m| /xpath:/.match m }
|
25
|
+
end
|
26
|
+
|
27
|
+
def matched_by_headers?
|
28
|
+
matchers.empty? || matchers.include?(:headers)
|
29
|
+
end
|
30
|
+
|
31
|
+
def matchers
|
32
|
+
@matchers ||= VCR.http_interactions.request_matchers - [:method, :uri] # always POST to endpoint
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module VCR::Errors::UnhandledXmlRequestError::Suggestions
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
def suggestion_for(k)
|
5
|
+
k
|
6
|
+
end
|
7
|
+
|
8
|
+
def match_requests_on_suggestion
|
9
|
+
:match_requests_on
|
10
|
+
end
|
11
|
+
|
12
|
+
def translated_suggestions
|
13
|
+
translating do
|
14
|
+
suggestions.map do |suggestion|
|
15
|
+
I18n.t("vcr.suggestions.#{suggestion}")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def translated_cassette_description
|
21
|
+
translating do
|
22
|
+
if cassette = VCR.current_cassette
|
23
|
+
I18n.t(
|
24
|
+
"vcr.cassette",
|
25
|
+
file: cassette.file,
|
26
|
+
mode: cassette.record_mode.inspect,
|
27
|
+
matchers: cassette.match_requests_on.inspect
|
28
|
+
)
|
29
|
+
else
|
30
|
+
I18n.t("vcr.no_cassette")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def translating
|
38
|
+
locale = I18n.locale
|
39
|
+
I18n.locale = VCR.configuration.locale
|
40
|
+
ret = yield
|
41
|
+
I18n.locale = locale
|
42
|
+
ret
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
@@ -0,0 +1,59 @@
|
|
1
|
+
en:
|
2
|
+
vcr:
|
3
|
+
cassette: |
|
4
|
+
VCR is currently using the following cassette:
|
5
|
+
- %{file}
|
6
|
+
- :record => %{mode}
|
7
|
+
- :match_requests_on => %{matchers}\n
|
8
|
+
Under the current configuration VCR can not find a suitable HTTP interaction
|
9
|
+
to replay and is prevented from recording new requests. There are a few ways
|
10
|
+
you can deal with this:
|
11
|
+
no_cassette: |
|
12
|
+
There is currently no cassette in use. There are a few ways
|
13
|
+
you can configure VCR to handle this request:
|
14
|
+
suggestions:
|
15
|
+
use_new_episodes: |
|
16
|
+
You can use the :new_episodes record mode to allow VCR to
|
17
|
+
record this new request to the existing cassette
|
18
|
+
|
19
|
+
delete_cassette_for_once: |
|
20
|
+
The current record mode (:once) does not allow new requests to be recorded
|
21
|
+
to a previously recorded cassette. You can delete the cassette file and re-run
|
22
|
+
your tests to allow the cassette to be recorded with this request
|
23
|
+
|
24
|
+
deal_with_none: |
|
25
|
+
The current record mode (:none) does not allow requests to be recorded. You
|
26
|
+
can temporarily change the record mode to :once, delete the cassette file
|
27
|
+
and re-run your tests to allow the cassette to be recorded with this request
|
28
|
+
|
29
|
+
use_a_cassette: |
|
30
|
+
If you want VCR to record this request and play it back during future test
|
31
|
+
runs, you should wrap your test (or this portion of your test) in a
|
32
|
+
`VCR.use_cassette` block
|
33
|
+
|
34
|
+
allow_http_connections_when_no_cassette: |
|
35
|
+
If you only want VCR to handle requests made while a cassette is in use,
|
36
|
+
configure `allow_http_connections_when_no_cassette = true`. VCR will
|
37
|
+
ignore this request since it is made when there is no cassette
|
38
|
+
|
39
|
+
ignore_request: |
|
40
|
+
If you want VCR to ignore this request (and others like it), you can
|
41
|
+
set an `ignore_request` callback
|
42
|
+
|
43
|
+
allow_playback_repeats: |
|
44
|
+
The cassette contains an HTTP interaction that matches this request,
|
45
|
+
but it has already been played back. If you wish to allow a single HTTP
|
46
|
+
interaction to be played back multiple times, set the `:allow_playback_repeats`
|
47
|
+
cassette option
|
48
|
+
|
49
|
+
match_requests_on: |
|
50
|
+
Some interractions haven't played back.
|
51
|
+
If your request is non-deterministic, you may need to
|
52
|
+
change your :match_requests_on cassette option to be more lenient
|
53
|
+
or use a custom request matcher to allow it to match
|
54
|
+
|
55
|
+
try_debug_logger: |
|
56
|
+
If you're surprised VCR is raising this error
|
57
|
+
and want insight about how VCR attempted to handle the request,
|
58
|
+
you can use the debug_logger configuration option to log more details
|
59
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
ru:
|
2
|
+
vcr:
|
3
|
+
cassette: |
|
4
|
+
VCR использует следующую кассету:
|
5
|
+
- %{file}
|
6
|
+
- :record => %{mode}
|
7
|
+
- :match_requests_on => %{matchers}\n
|
8
|
+
Что-то пошло не так и записанное не соответствует дейстительности
|
9
|
+
Решить проблему можно так:
|
10
|
+
no_cassette: |
|
11
|
+
VCR не использует кассету
|
12
|
+
Решить проблему можно так:
|
13
|
+
suggestions:
|
14
|
+
use_new_episodes: |
|
15
|
+
Используйте режим :new_episodes чтобы записывать новые запросы
|
16
|
+
в существующую кассету
|
17
|
+
|
18
|
+
delete_cassette_for_once: |
|
19
|
+
Текущий режим (:once) не позволяет записывать новые запросы к существующей кассете
|
20
|
+
Можно удалить файл кассеты и перепрогнать тесты с этим запросом
|
21
|
+
|
22
|
+
deal_with_none: |
|
23
|
+
Текущий режим (:none) не позволяет записывать запросы
|
24
|
+
можно временно сменить режим на :once, удалить кассету и перепрогнать тесты
|
25
|
+
|
26
|
+
use_a_cassette: |
|
27
|
+
Необходимо либо использовать VCR.use_cassette в before блоке
|
28
|
+
Либо пометить тест меткой :vcr
|
29
|
+
|
30
|
+
allow_http_connections_when_no_cassette: |
|
31
|
+
Если нужно использовать VCR без текущей кассеты - пропишите в настройки
|
32
|
+
`allow_http_connections_when_no_cassette = true`
|
33
|
+
|
34
|
+
ignore_request: |
|
35
|
+
Если надо проигнорировать этот запрос, можно использовать коллбек `ignore_request`
|
36
|
+
|
37
|
+
allow_playback_repeats: |
|
38
|
+
Если кассета содержит запросы, ответы на которые были уже воспроизведены
|
39
|
+
можно использовать опцию `:allow_playback_repeats` для повторного использования ответа от запроса
|
40
|
+
|
41
|
+
match_requests_on: |
|
42
|
+
Несколько запросов не совпали с записанными
|
43
|
+
Поменяйте настройку сравнивания запросов :match_requests_on
|
44
|
+
Напримeр :match_requests_on => [:"xpath://Body"] для сравнивания только <Body>
|
45
|
+
Напримeр :match_requests_on => [:"notxpath://Header"] для НЕсравнивания заголовков
|
46
|
+
|
47
|
+
try_debug_logger: |
|
48
|
+
Попробуйте включить debug_logger
|
49
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module VCR
|
2
|
+
class NotXpathMatcher < Struct.new(:xpath)
|
3
|
+
def matches?(request, expected_request)
|
4
|
+
node = extract_xpath(request.body)
|
5
|
+
expected_node = extract_xpath(expected_request.body)
|
6
|
+
|
7
|
+
EquivalentXml.equivalent? node, expected_node
|
8
|
+
end
|
9
|
+
|
10
|
+
def human_type
|
11
|
+
"exclude"
|
12
|
+
end
|
13
|
+
|
14
|
+
def extract_xpath(xml)
|
15
|
+
if xml.is_a? String
|
16
|
+
xml = Nokogiri::XML(xml)
|
17
|
+
xml.remove_namespaces!
|
18
|
+
end
|
19
|
+
xml.search(xpath).remove
|
20
|
+
xml
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/vcr/xml.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'vcr/xml/version'
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module XmlRequestHandler
|
2
|
+
def new(*args, &blk)
|
3
|
+
super(*args, &blk).extend(InstanceMethods)
|
4
|
+
end
|
5
|
+
|
6
|
+
module InstanceMethods
|
7
|
+
def on_unhandled_request
|
8
|
+
if /<xml/.match vcr_request.body
|
9
|
+
raise VCR::Errors::UnhandledXmlRequestError.new(vcr_request)
|
10
|
+
else
|
11
|
+
super
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module VCR
|
2
|
+
class XpathMatcher < Struct.new(:xpath)
|
3
|
+
def matches?(request, expected_request)
|
4
|
+
node = extract_xpath(request.body)
|
5
|
+
return false if node.blank?
|
6
|
+
|
7
|
+
expected_node = extract_xpath(expected_request.body)
|
8
|
+
return false if expected_node.blank?
|
9
|
+
|
10
|
+
EquivalentXml.equivalent? node, expected_node
|
11
|
+
end
|
12
|
+
|
13
|
+
def human_type
|
14
|
+
"only"
|
15
|
+
end
|
16
|
+
|
17
|
+
def extract_xpath(xml)
|
18
|
+
if xml.is_a? String
|
19
|
+
xml = Nokogiri::XML(xml)
|
20
|
+
xml.remove_namespaces!
|
21
|
+
end
|
22
|
+
xml.xpath(xpath)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/vcr-xml.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'vcr/xml/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "vcr-xml"
|
8
|
+
spec.version = Vcr::Xml::VERSION
|
9
|
+
spec.authors = ["Vlad Bokov"]
|
10
|
+
spec.email = ["razum2um@mail.ru"]
|
11
|
+
spec.description = %q{Easier SOAP with VCR}
|
12
|
+
spec.summary = %q{Easier SOAP with VCR - better formatted failed expectation while comparing XML}
|
13
|
+
spec.homepage = "http://github.com/razum2um/vcr-xml"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
|
24
|
+
spec.add_dependency "vcr", "~> 2.3"
|
25
|
+
spec.add_dependency "nokogiri", "~> 1.5"
|
26
|
+
spec.add_dependency "diffy", "~> 2.1.4"
|
27
|
+
spec.add_dependency "hirb", "~> 0.5"
|
28
|
+
spec.add_dependency "equivalent-xml", "~> 0.3.0"
|
29
|
+
spec.add_dependency "activesupport", ">= 3.2.0"
|
30
|
+
spec.add_dependency "i18n", ">= 0.5.0"
|
31
|
+
spec.add_dependency "syck" if RUBY_VERSION >= "2.0.0"
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,206 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vcr-xml
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Vlad Bokov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-06-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: vcr
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.3'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: nokogiri
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.5'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.5'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: diffy
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 2.1.4
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.1.4
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: hirb
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.5'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ~>
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.5'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: equivalent-xml
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ~>
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.3.0
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.3.0
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: activesupport
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 3.2.0
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 3.2.0
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: i18n
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 0.5.0
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 0.5.0
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: syck
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - '>='
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :runtime
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - '>='
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
description: Easier SOAP with VCR
|
154
|
+
email:
|
155
|
+
- razum2um@mail.ru
|
156
|
+
executables: []
|
157
|
+
extensions: []
|
158
|
+
extra_rdoc_files: []
|
159
|
+
files:
|
160
|
+
- .gitignore
|
161
|
+
- Gemfile
|
162
|
+
- LICENSE.txt
|
163
|
+
- README.md
|
164
|
+
- Rakefile
|
165
|
+
- lib/vcr-xml.rb
|
166
|
+
- lib/vcr/cassette/serializers/xsyck.rb
|
167
|
+
- lib/vcr/errors/unhandled_xml_request_error.rb
|
168
|
+
- lib/vcr/errors/unhandled_xml_request_error/bodies.rb
|
169
|
+
- lib/vcr/errors/unhandled_xml_request_error/diffs.rb
|
170
|
+
- lib/vcr/errors/unhandled_xml_request_error/headers.rb
|
171
|
+
- lib/vcr/errors/unhandled_xml_request_error/matchers.rb
|
172
|
+
- lib/vcr/errors/unhandled_xml_request_error/suggestions.rb
|
173
|
+
- lib/vcr/locales/en.yml
|
174
|
+
- lib/vcr/locales/ru.yml
|
175
|
+
- lib/vcr/not_xpath_matcher.rb
|
176
|
+
- lib/vcr/xml.rb
|
177
|
+
- lib/vcr/xml/version.rb
|
178
|
+
- lib/vcr/xml_request_handler.rb
|
179
|
+
- lib/vcr/xpath_matcher.rb
|
180
|
+
- vcr-xml.gemspec
|
181
|
+
homepage: http://github.com/razum2um/vcr-xml
|
182
|
+
licenses:
|
183
|
+
- MIT
|
184
|
+
metadata: {}
|
185
|
+
post_install_message:
|
186
|
+
rdoc_options: []
|
187
|
+
require_paths:
|
188
|
+
- lib
|
189
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - '>='
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: '0'
|
194
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
195
|
+
requirements:
|
196
|
+
- - '>='
|
197
|
+
- !ruby/object:Gem::Version
|
198
|
+
version: '0'
|
199
|
+
requirements: []
|
200
|
+
rubyforge_project:
|
201
|
+
rubygems_version: 2.0.3
|
202
|
+
signing_key:
|
203
|
+
specification_version: 4
|
204
|
+
summary: Easier SOAP with VCR - better formatted failed expectation while comparing
|
205
|
+
XML
|
206
|
+
test_files: []
|
metadata.gz.asc
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
-----BEGIN PGP SIGNATURE-----
|
2
|
+
Version: GnuPG/MacGPG2 v2.0.19 (Darwin)
|
3
|
+
Comment: GPGTools - http://gpgtools.org
|
4
|
+
|
5
|
+
iQEcBAABCgAGBQJRwThDAAoJENcoxKfNVdjbRgIH/RGHhj4fQekEwRQd5ZHEenWh
|
6
|
+
NxL4LQ8fBoozye349txdqmMChkT4lE87XXvF0aKOIyt6QdxOMNfJ8N13kd5ZQkhD
|
7
|
+
FONq/C//pjSAA7n60N+h4sGc+9aOAcUMa/zCebkKwWRHeRgeClARuTpIv+mVnlHr
|
8
|
+
RlFrLNQsaCJ7YwXwZuo/Ha1rPzpFB8rQqx79BXnSobBOjJ59IQAWuRVen3VN3Mgn
|
9
|
+
Zzuat8rsVvTQuy6omFqEkULpRZinJKXvz6jC0HADpNN4uX5laSds5I6MSMTCWdmv
|
10
|
+
jkpbmB51zvhuqSypPwYyobSkt2cJl2+aCwcQvrJy4DsjcgmmbYoDVm00ICnGrnU=
|
11
|
+
=5XRH
|
12
|
+
-----END PGP SIGNATURE-----
|