mirror of
https://github.com/kevin1024/vcrpy.git
synced 2025-12-08 16:53:23 +00:00
Format project with black (#467)
Format with line length 110 to match flake8 make black part of linting check Update travis spec for updated black requirements Add diff output for black on failure update changelog
This commit is contained in:
19
.travis.yml
19
.travis.yml
@@ -5,7 +5,6 @@ env:
|
||||
# - secure: AifoKzwhjV94cmcQZrdQmqRu/9rkZZvWpwBv1daeAQpLOKFPGsOm3D+x2cSw9+iCfkgDZDfqQVv1kCaFVxTll8v8jTq5SJdqEY0NmGWbj/UkNtShh609oRDsuzLxAEwtVKYjf/h8K2BRea+bl1tGkwZ2vtmYS6dxNlAijjWOfds=
|
||||
# - secure: LBSEg/gMj4u4Hrpo3zs6Y/1mTpd2RtcN49mZIFgTdbJ9IhpiNPqcEt647Lz94F9Eses2x2WbNuKqZKZZReY7QLbEzU1m0nN5jlaKrjcG5NR5clNABfFFyhgc0jBikyS4abAG8jc2efeaTrFuQwdoF4sE8YiVrkiVj2X5Xoi6sBk=
|
||||
matrix:
|
||||
- TOX_SUFFIX="flakes"
|
||||
- TOX_SUFFIX="requests"
|
||||
- TOX_SUFFIX="httplib2"
|
||||
- TOX_SUFFIX="boto3"
|
||||
@@ -14,7 +13,7 @@ env:
|
||||
- TOX_SUFFIX="aiohttp"
|
||||
matrix:
|
||||
include:
|
||||
- env: TOX_SUFFIX="flakes"
|
||||
- env: TOX_SUFFIX="lint"
|
||||
python: 3.7
|
||||
dist: xenial
|
||||
- env: TOX_SUFFIX="requests"
|
||||
@@ -23,6 +22,9 @@ matrix:
|
||||
- env: TOX_SUFFIX="httplib2"
|
||||
python: 3.7
|
||||
dist: xenial
|
||||
- env: TOX_SUFFIX="boto3"
|
||||
python: 3.7
|
||||
dist: xenial
|
||||
- env: TOX_SUFFIX="urllib3"
|
||||
python: 3.7
|
||||
dist: xenial
|
||||
@@ -36,13 +38,16 @@ matrix:
|
||||
- env: TOX_SUFFIX="aiohttp"
|
||||
python: "pypy3"
|
||||
exclude:
|
||||
# Only run flakes on a single Python 2.x and a single 3.x
|
||||
- env: TOX_SUFFIX="flakes"
|
||||
# Only run lint on a single 3.x
|
||||
- env: TOX_SUFFIX="lint"
|
||||
python: 2.7
|
||||
- env: TOX_SUFFIX="lint"
|
||||
python: 3.5
|
||||
- env: TOX_SUFFIX="flakes"
|
||||
- env: TOX_SUFFIX="lint"
|
||||
python: pypy
|
||||
- env: TOX_SUFFIX="flakes"
|
||||
- env: TOX_SUFFIX="lint"
|
||||
python: "pypy3"
|
||||
# Exclude aiohttp support
|
||||
- env: TOX_SUFFIX="aiohttp"
|
||||
python: 2.7
|
||||
- env: TOX_SUFFIX="aiohttp"
|
||||
@@ -55,7 +60,7 @@ python:
|
||||
- "pypy3"
|
||||
install:
|
||||
- pip install tox-travis codecov
|
||||
- if [[ $TOX_SUFFIX != 'flakes' ]]; then python setup.py install ; fi
|
||||
- if [[ $TOX_SUFFIX != 'lint' ]]; then python setup.py install ; fi
|
||||
script:
|
||||
- tox -e "${TOX_SUFFIX}"
|
||||
after_success:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|PyPI| |Python versions| |Build Status| |CodeCov| |Gitter|
|
||||
|PyPI| |Python versions| |Build Status| |CodeCov| |Gitter| |CodeStyleBlack|
|
||||
|
||||
VCR.py
|
||||
======
|
||||
@@ -59,4 +59,6 @@ more details
|
||||
.. |CodeCov| image:: https://codecov.io/gh/kevin1024/vcrpy/branch/master/graph/badge.svg
|
||||
:target: https://codecov.io/gh/kevin1024/vcrpy
|
||||
:alt: Code Coverage Status
|
||||
|
||||
.. |CodeStyleBlack| image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||
:target: https://github.com/psf/black
|
||||
:alt: Code Style: black
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
Changelog
|
||||
---------
|
||||
- 2.1.1 (UNRELEASED)
|
||||
- Format code with black (@neozenith)
|
||||
- Use latest pypy3 in Travis (@hugovk)
|
||||
- 2.1.0 - Add a `rewind` method to reset a cassette (thanks @khamidou)
|
||||
New error message with more details on why the cassette failed to play a request (thanks @arthurHamon2, @neozenith)
|
||||
Handle connect tunnel URI (thanks @jeking3)
|
||||
|
||||
165
docs/conf.py
165
docs/conf.py
@@ -17,50 +17,45 @@ import os
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.intersphinx',
|
||||
'sphinx.ext.coverage',
|
||||
'sphinx.ext.viewcode',
|
||||
]
|
||||
extensions = ["sphinx.ext.autodoc", "sphinx.ext.intersphinx", "sphinx.ext.coverage", "sphinx.ext.viewcode"]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
templates_path = ["_templates"]
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
# source_suffix = ['.rst', '.md']
|
||||
source_suffix = '.rst'
|
||||
source_suffix = ".rst"
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
# source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
master_doc = "index"
|
||||
|
||||
# General information about the project.
|
||||
project = u'vcrpy'
|
||||
copyright = u'2015, Kevin McCarthy'
|
||||
author = u'Kevin McCarthy'
|
||||
project = u"vcrpy"
|
||||
copyright = u"2015, Kevin McCarthy"
|
||||
author = u"Kevin McCarthy"
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '1.7.4'
|
||||
version = "1.7.4"
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '1.7.4'
|
||||
release = "1.7.4"
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
@@ -71,37 +66,37 @@ language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
# today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build']
|
||||
exclude_patterns = ["_build"]
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all
|
||||
# documents.
|
||||
#default_role = None
|
||||
# default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
# add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
# add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
# show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
pygments_style = "sphinx"
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
# modindex_common_prefix = []
|
||||
|
||||
# If true, keep warnings as "system message" paragraphs in the built documents.
|
||||
#keep_warnings = False
|
||||
# keep_warnings = False
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = False
|
||||
@@ -111,156 +106,148 @@ todo_include_todos = False
|
||||
|
||||
# The theme to use for HTML and HTML Help pages.
|
||||
# https://read-the-docs.readthedocs.io/en/latest/theme.html#how-do-i-use-this-locally-and-on-read-the-docs
|
||||
if 'READTHEDOCS' not in os.environ:
|
||||
if "READTHEDOCS" not in os.environ:
|
||||
import sphinx_rtd_theme
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
html_theme = "sphinx_rtd_theme"
|
||||
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
# html_theme_options = {}
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
# html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
# html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
# html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
# html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
html_static_path = ["_static"]
|
||||
|
||||
# Add any extra paths that contain custom files (such as robots.txt or
|
||||
# .htaccess) here, relative to this directory. These files are copied
|
||||
# directly to the root of the documentation.
|
||||
#html_extra_path = []
|
||||
# html_extra_path = []
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
# html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
# html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
# html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
# html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
# html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
# html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
# html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
# html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
# html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
# html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
# html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
# html_file_suffix = None
|
||||
|
||||
# Language to be used for generating the HTML full-text search index.
|
||||
# Sphinx supports the following languages:
|
||||
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
|
||||
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
|
||||
#html_search_language = 'en'
|
||||
# html_search_language = 'en'
|
||||
|
||||
# A dictionary with options for the search language support, empty by default.
|
||||
# Now only 'ja' uses this config value
|
||||
#html_search_options = {'type': 'default'}
|
||||
# html_search_options = {'type': 'default'}
|
||||
|
||||
# The name of a javascript file (relative to the configuration directory) that
|
||||
# implements a search results scorer. If empty, the default will be used.
|
||||
#html_search_scorer = 'scorer.js'
|
||||
# html_search_scorer = 'scorer.js'
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'vcrpydoc'
|
||||
htmlhelp_basename = "vcrpydoc"
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#'figure_align': 'htbp',
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
# Latex figure (float) alignment
|
||||
#'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'vcrpy.tex', u'vcrpy Documentation',
|
||||
u'Kevin McCarthy', 'manual'),
|
||||
]
|
||||
latex_documents = [(master_doc, "vcrpy.tex", u"vcrpy Documentation", u"Kevin McCarthy", "manual")]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
# latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
# latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
# latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
# latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
# latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
# latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'vcrpy', u'vcrpy Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
man_pages = [(master_doc, "vcrpy", u"vcrpy Documentation", [author], 1)]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
# man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
@@ -269,23 +256,29 @@ man_pages = [
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'vcrpy', u'vcrpy Documentation',
|
||||
author, 'vcrpy', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
(
|
||||
master_doc,
|
||||
"vcrpy",
|
||||
u"vcrpy Documentation",
|
||||
author,
|
||||
"vcrpy",
|
||||
"One line description of project.",
|
||||
"Miscellaneous",
|
||||
)
|
||||
]
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#texinfo_appendices = []
|
||||
# texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#texinfo_domain_indices = True
|
||||
# texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#texinfo_show_urls = 'footnote'
|
||||
# texinfo_show_urls = 'footnote'
|
||||
|
||||
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
||||
#texinfo_no_detailmenu = False
|
||||
# texinfo_no_detailmenu = False
|
||||
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {'https://docs.python.org/': None}
|
||||
intersphinx_mapping = {"https://docs.python.org/": None}
|
||||
|
||||
2
pyproject.toml
Normal file
2
pyproject.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[tool.black]
|
||||
line-length=110
|
||||
63
setup.py
63
setup.py
@@ -5,11 +5,10 @@ import sys
|
||||
from setuptools import setup, find_packages
|
||||
from setuptools.command.test import test as TestCommand
|
||||
|
||||
long_description = open('README.rst', 'r').read()
|
||||
long_description = open("README.rst", "r").read()
|
||||
|
||||
|
||||
class PyTest(TestCommand):
|
||||
|
||||
def finalize_options(self):
|
||||
TestCommand.finalize_options(self)
|
||||
self.test_args = []
|
||||
@@ -18,14 +17,15 @@ class PyTest(TestCommand):
|
||||
def run_tests(self):
|
||||
# import here, cause outside the eggs aren't loaded
|
||||
import pytest
|
||||
|
||||
errno = pytest.main(self.test_args)
|
||||
sys.exit(errno)
|
||||
|
||||
|
||||
install_requires = [
|
||||
'PyYAML',
|
||||
'wrapt',
|
||||
'six>=1.5',
|
||||
"PyYAML",
|
||||
"wrapt",
|
||||
"six>=1.5",
|
||||
'contextlib2; python_version=="2.7"',
|
||||
'mock; python_version=="2.7"',
|
||||
'yarl; python_version>="3.5"',
|
||||
@@ -36,36 +36,33 @@ if sys.version_info[0] == 2:
|
||||
excluded_packages.append("vcr.stubs.aiohttp_stubs")
|
||||
|
||||
setup(
|
||||
name='vcrpy',
|
||||
version='2.1.0',
|
||||
description=(
|
||||
"Automatically mock your HTTP interactions to simplify and "
|
||||
"speed up testing"
|
||||
),
|
||||
name="vcrpy",
|
||||
version="2.1.0",
|
||||
description=("Automatically mock your HTTP interactions to simplify and " "speed up testing"),
|
||||
long_description=long_description,
|
||||
author='Kevin McCarthy',
|
||||
author_email='me@kevinmccarthy.org',
|
||||
url='https://github.com/kevin1024/vcrpy',
|
||||
author="Kevin McCarthy",
|
||||
author_email="me@kevinmccarthy.org",
|
||||
url="https://github.com/kevin1024/vcrpy",
|
||||
packages=find_packages(exclude=excluded_packages),
|
||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*',
|
||||
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*",
|
||||
install_requires=install_requires,
|
||||
license='MIT',
|
||||
tests_require=['pytest', 'mock', 'pytest-httpbin'],
|
||||
license="MIT",
|
||||
tests_require=["pytest", "mock", "pytest-httpbin"],
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Environment :: Console',
|
||||
'Intended Audience :: Developers',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: Implementation :: CPython',
|
||||
'Programming Language :: Python :: Implementation :: PyPy',
|
||||
'Topic :: Software Development :: Testing',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
]
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"Environment :: Console",
|
||||
"Intended Audience :: Developers",
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 2",
|
||||
"Programming Language :: Python :: 2.7",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.5",
|
||||
"Programming Language :: Python :: 3.6",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: Implementation :: CPython",
|
||||
"Programming Language :: Python :: Implementation :: PyPy",
|
||||
"Topic :: Software Development :: Testing",
|
||||
"Topic :: Internet :: WWW/HTTP",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -13,7 +13,7 @@ def assert_cassette_has_one_response(cass):
|
||||
|
||||
def assert_is_json(a_string):
|
||||
try:
|
||||
json.loads(a_string.decode('utf-8'))
|
||||
json.loads(a_string.decode("utf-8"))
|
||||
except Exception:
|
||||
assert False
|
||||
assert True
|
||||
|
||||
@@ -5,19 +5,19 @@ import aiohttp
|
||||
from aiohttp.test_utils import TestClient
|
||||
|
||||
|
||||
async def aiohttp_request(loop, method, url, output='text', encoding='utf-8', content_type=None, **kwargs):
|
||||
async def aiohttp_request(loop, method, url, output="text", encoding="utf-8", content_type=None, **kwargs):
|
||||
session = aiohttp.ClientSession(loop=loop)
|
||||
response_ctx = session.request(method, url, **kwargs)
|
||||
|
||||
response = await response_ctx.__aenter__()
|
||||
if output == 'text':
|
||||
if output == "text":
|
||||
content = await response.text()
|
||||
elif output == 'json':
|
||||
content_type = content_type or 'application/json'
|
||||
elif output == "json":
|
||||
content_type = content_type or "application/json"
|
||||
content = await response.json(encoding=encoding, content_type=content_type)
|
||||
elif output == 'raw':
|
||||
elif output == "raw":
|
||||
content = await response.read()
|
||||
elif output == 'stream':
|
||||
elif output == "stream":
|
||||
content = await response.content.read()
|
||||
|
||||
response_ctx._resp.close()
|
||||
@@ -28,7 +28,7 @@ async def aiohttp_request(loop, method, url, output='text', encoding='utf-8', co
|
||||
|
||||
def aiohttp_app():
|
||||
async def hello(request):
|
||||
return aiohttp.web.Response(text='hello')
|
||||
return aiohttp.web.Response(text="hello")
|
||||
|
||||
async def json(request):
|
||||
return aiohttp.web.json_response({})
|
||||
@@ -37,7 +37,7 @@ def aiohttp_app():
|
||||
return aiohttp.web.json_response()
|
||||
|
||||
app = aiohttp.web.Application()
|
||||
app.router.add_get('/', hello)
|
||||
app.router.add_get('/json', json)
|
||||
app.router.add_get('/json/empty', json_empty_body)
|
||||
app.router.add_get("/", hello)
|
||||
app.router.add_get("/json", json)
|
||||
app.router.add_get("/json/empty", json_empty_body)
|
||||
return app
|
||||
|
||||
@@ -2,6 +2,7 @@ import contextlib
|
||||
import logging
|
||||
|
||||
import pytest
|
||||
|
||||
asyncio = pytest.importorskip("asyncio")
|
||||
aiohttp = pytest.importorskip("aiohttp")
|
||||
|
||||
@@ -16,33 +17,33 @@ def run_in_loop(fn):
|
||||
return loop.run_until_complete(task)
|
||||
|
||||
|
||||
def request(method, url, output='text', **kwargs):
|
||||
def request(method, url, output="text", **kwargs):
|
||||
def run(loop):
|
||||
return aiohttp_request(loop, method, url, output=output, **kwargs)
|
||||
|
||||
return run_in_loop(run)
|
||||
|
||||
|
||||
def get(url, output='text', **kwargs):
|
||||
return request('GET', url, output=output, **kwargs)
|
||||
def get(url, output="text", **kwargs):
|
||||
return request("GET", url, output=output, **kwargs)
|
||||
|
||||
|
||||
def post(url, output='text', **kwargs):
|
||||
return request('POST', url, output='text', **kwargs)
|
||||
def post(url, output="text", **kwargs):
|
||||
return request("POST", url, output="text", **kwargs)
|
||||
|
||||
|
||||
@pytest.fixture(params=["https", "http"])
|
||||
def scheme(request):
|
||||
'''Fixture that returns both http and https.'''
|
||||
"""Fixture that returns both http and https."""
|
||||
return request.param
|
||||
|
||||
|
||||
def test_status(tmpdir, scheme):
|
||||
url = scheme + '://httpbin.org'
|
||||
with vcr.use_cassette(str(tmpdir.join('status.yaml'))):
|
||||
url = scheme + "://httpbin.org"
|
||||
with vcr.use_cassette(str(tmpdir.join("status.yaml"))):
|
||||
response, _ = get(url)
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('status.yaml'))) as cassette:
|
||||
with vcr.use_cassette(str(tmpdir.join("status.yaml"))) as cassette:
|
||||
cassette_response, _ = get(url)
|
||||
assert cassette_response.status == response.status
|
||||
assert cassette.play_count == 1
|
||||
@@ -50,27 +51,27 @@ def test_status(tmpdir, scheme):
|
||||
|
||||
@pytest.mark.parametrize("auth", [None, aiohttp.BasicAuth("vcrpy", "test")])
|
||||
def test_headers(tmpdir, scheme, auth):
|
||||
url = scheme + '://httpbin.org'
|
||||
with vcr.use_cassette(str(tmpdir.join('headers.yaml'))):
|
||||
url = scheme + "://httpbin.org"
|
||||
with vcr.use_cassette(str(tmpdir.join("headers.yaml"))):
|
||||
response, _ = get(url, auth=auth)
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('headers.yaml'))) as cassette:
|
||||
with vcr.use_cassette(str(tmpdir.join("headers.yaml"))) as cassette:
|
||||
if auth is not None:
|
||||
request = cassette.requests[0]
|
||||
assert "AUTHORIZATION" in request.headers
|
||||
cassette_response, _ = get(url, auth=auth)
|
||||
assert dict(cassette_response.headers) == dict(response.headers)
|
||||
assert cassette.play_count == 1
|
||||
assert 'istr' not in cassette.data[0]
|
||||
assert 'yarl.URL' not in cassette.data[0]
|
||||
assert "istr" not in cassette.data[0]
|
||||
assert "yarl.URL" not in cassette.data[0]
|
||||
|
||||
|
||||
def test_case_insensitive_headers(tmpdir, scheme):
|
||||
url = scheme + '://httpbin.org'
|
||||
with vcr.use_cassette(str(tmpdir.join('whatever.yaml'))):
|
||||
url = scheme + "://httpbin.org"
|
||||
with vcr.use_cassette(str(tmpdir.join("whatever.yaml"))):
|
||||
_, _ = get(url)
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('whatever.yaml'))) as cassette:
|
||||
with vcr.use_cassette(str(tmpdir.join("whatever.yaml"))) as cassette:
|
||||
cassette_response, _ = get(url)
|
||||
assert "Content-Type" in cassette_response.headers
|
||||
assert "content-type" in cassette_response.headers
|
||||
@@ -78,61 +79,61 @@ def test_case_insensitive_headers(tmpdir, scheme):
|
||||
|
||||
|
||||
def test_text(tmpdir, scheme):
|
||||
url = scheme + '://httpbin.org'
|
||||
with vcr.use_cassette(str(tmpdir.join('text.yaml'))):
|
||||
url = scheme + "://httpbin.org"
|
||||
with vcr.use_cassette(str(tmpdir.join("text.yaml"))):
|
||||
_, response_text = get(url)
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('text.yaml'))) as cassette:
|
||||
with vcr.use_cassette(str(tmpdir.join("text.yaml"))) as cassette:
|
||||
_, cassette_response_text = get(url)
|
||||
assert cassette_response_text == response_text
|
||||
assert cassette.play_count == 1
|
||||
|
||||
|
||||
def test_json(tmpdir, scheme):
|
||||
url = scheme + '://httpbin.org/get'
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
url = scheme + "://httpbin.org/get"
|
||||
headers = {"Content-Type": "application/json"}
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('json.yaml'))):
|
||||
_, response_json = get(url, output='json', headers=headers)
|
||||
with vcr.use_cassette(str(tmpdir.join("json.yaml"))):
|
||||
_, response_json = get(url, output="json", headers=headers)
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('json.yaml'))) as cassette:
|
||||
_, cassette_response_json = get(url, output='json', headers=headers)
|
||||
with vcr.use_cassette(str(tmpdir.join("json.yaml"))) as cassette:
|
||||
_, cassette_response_json = get(url, output="json", headers=headers)
|
||||
assert cassette_response_json == response_json
|
||||
assert cassette.play_count == 1
|
||||
|
||||
|
||||
def test_binary(tmpdir, scheme):
|
||||
url = scheme + '://httpbin.org/image/png'
|
||||
with vcr.use_cassette(str(tmpdir.join('binary.yaml'))):
|
||||
_, response_binary = get(url, output='raw')
|
||||
url = scheme + "://httpbin.org/image/png"
|
||||
with vcr.use_cassette(str(tmpdir.join("binary.yaml"))):
|
||||
_, response_binary = get(url, output="raw")
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('binary.yaml'))) as cassette:
|
||||
_, cassette_response_binary = get(url, output='raw')
|
||||
with vcr.use_cassette(str(tmpdir.join("binary.yaml"))) as cassette:
|
||||
_, cassette_response_binary = get(url, output="raw")
|
||||
assert cassette_response_binary == response_binary
|
||||
assert cassette.play_count == 1
|
||||
|
||||
|
||||
def test_stream(tmpdir, scheme):
|
||||
url = scheme + '://httpbin.org/get'
|
||||
url = scheme + "://httpbin.org/get"
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('stream.yaml'))):
|
||||
resp, body = get(url, output='raw') # Do not use stream here, as the stream is exhausted by vcr
|
||||
with vcr.use_cassette(str(tmpdir.join("stream.yaml"))):
|
||||
resp, body = get(url, output="raw") # Do not use stream here, as the stream is exhausted by vcr
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('stream.yaml'))) as cassette:
|
||||
cassette_resp, cassette_body = get(url, output='stream')
|
||||
with vcr.use_cassette(str(tmpdir.join("stream.yaml"))) as cassette:
|
||||
cassette_resp, cassette_body = get(url, output="stream")
|
||||
assert cassette_body == body
|
||||
assert cassette.play_count == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize('body', ['data', 'json'])
|
||||
@pytest.mark.parametrize("body", ["data", "json"])
|
||||
def test_post(tmpdir, scheme, body, caplog):
|
||||
caplog.set_level(logging.INFO)
|
||||
data = {'key1': 'value1', 'key2': 'value2'}
|
||||
url = scheme + '://httpbin.org/post'
|
||||
with vcr.use_cassette(str(tmpdir.join('post.yaml'))):
|
||||
data = {"key1": "value1", "key2": "value2"}
|
||||
url = scheme + "://httpbin.org/post"
|
||||
with vcr.use_cassette(str(tmpdir.join("post.yaml"))):
|
||||
_, response_json = post(url, **{body: data})
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('post.yaml'))) as cassette:
|
||||
with vcr.use_cassette(str(tmpdir.join("post.yaml"))) as cassette:
|
||||
request = cassette.requests[0]
|
||||
assert request.body == data
|
||||
_, cassette_response_json = post(url, **{body: data})
|
||||
@@ -143,58 +144,57 @@ def test_post(tmpdir, scheme, body, caplog):
|
||||
(
|
||||
log
|
||||
for log in caplog.records
|
||||
if log.getMessage()
|
||||
== '<Request (POST) {}> not in cassette, sending to real server'.format(url)
|
||||
if log.getMessage() == "<Request (POST) {}> not in cassette, sending to real server".format(url)
|
||||
),
|
||||
None,
|
||||
), 'Log message not found.'
|
||||
), "Log message not found."
|
||||
|
||||
|
||||
def test_params(tmpdir, scheme):
|
||||
url = scheme + '://httpbin.org/get'
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
params = {'a': 1, 'b': False, 'c': 'c'}
|
||||
url = scheme + "://httpbin.org/get"
|
||||
headers = {"Content-Type": "application/json"}
|
||||
params = {"a": 1, "b": False, "c": "c"}
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('get.yaml'))) as cassette:
|
||||
_, response_json = get(url, output='json', params=params, headers=headers)
|
||||
with vcr.use_cassette(str(tmpdir.join("get.yaml"))) as cassette:
|
||||
_, response_json = get(url, output="json", params=params, headers=headers)
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('get.yaml'))) as cassette:
|
||||
_, cassette_response_json = get(url, output='json', params=params, headers=headers)
|
||||
with vcr.use_cassette(str(tmpdir.join("get.yaml"))) as cassette:
|
||||
_, cassette_response_json = get(url, output="json", params=params, headers=headers)
|
||||
assert cassette_response_json == response_json
|
||||
assert cassette.play_count == 1
|
||||
|
||||
|
||||
def test_params_same_url_distinct_params(tmpdir, scheme):
|
||||
url = scheme + '://httpbin.org/get'
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
params = {'a': 1, 'b': False, 'c': 'c'}
|
||||
url = scheme + "://httpbin.org/get"
|
||||
headers = {"Content-Type": "application/json"}
|
||||
params = {"a": 1, "b": False, "c": "c"}
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('get.yaml'))) as cassette:
|
||||
_, response_json = get(url, output='json', params=params, headers=headers)
|
||||
with vcr.use_cassette(str(tmpdir.join("get.yaml"))) as cassette:
|
||||
_, response_json = get(url, output="json", params=params, headers=headers)
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('get.yaml'))) as cassette:
|
||||
_, cassette_response_json = get(url, output='json', params=params, headers=headers)
|
||||
with vcr.use_cassette(str(tmpdir.join("get.yaml"))) as cassette:
|
||||
_, cassette_response_json = get(url, output="json", params=params, headers=headers)
|
||||
assert cassette_response_json == response_json
|
||||
assert cassette.play_count == 1
|
||||
|
||||
other_params = {'other': 'params'}
|
||||
with vcr.use_cassette(str(tmpdir.join('get.yaml'))) as cassette:
|
||||
response, cassette_response_text = get(url, output='text', params=other_params)
|
||||
assert 'No match for the request' in cassette_response_text
|
||||
other_params = {"other": "params"}
|
||||
with vcr.use_cassette(str(tmpdir.join("get.yaml"))) as cassette:
|
||||
response, cassette_response_text = get(url, output="text", params=other_params)
|
||||
assert "No match for the request" in cassette_response_text
|
||||
assert response.status == 599
|
||||
|
||||
|
||||
def test_params_on_url(tmpdir, scheme):
|
||||
url = scheme + '://httpbin.org/get?a=1&b=foo'
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
url = scheme + "://httpbin.org/get?a=1&b=foo"
|
||||
headers = {"Content-Type": "application/json"}
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('get.yaml'))) as cassette:
|
||||
_, response_json = get(url, output='json', headers=headers)
|
||||
with vcr.use_cassette(str(tmpdir.join("get.yaml"))) as cassette:
|
||||
_, response_json = get(url, output="json", headers=headers)
|
||||
request = cassette.requests[0]
|
||||
assert request.url == url
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('get.yaml'))) as cassette:
|
||||
_, cassette_response_json = get(url, output='json', headers=headers)
|
||||
with vcr.use_cassette(str(tmpdir.join("get.yaml"))) as cassette:
|
||||
_, cassette_response_json = get(url, output="json", headers=headers)
|
||||
request = cassette.requests[0]
|
||||
assert request.url == url
|
||||
assert cassette_response_json == response_json
|
||||
@@ -204,42 +204,42 @@ def test_params_on_url(tmpdir, scheme):
|
||||
def test_aiohttp_test_client(aiohttp_client, tmpdir):
|
||||
loop = asyncio.get_event_loop()
|
||||
app = aiohttp_app()
|
||||
url = '/'
|
||||
url = "/"
|
||||
client = loop.run_until_complete(aiohttp_client(app))
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('get.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("get.yaml"))):
|
||||
response = loop.run_until_complete(client.get(url))
|
||||
|
||||
assert response.status == 200
|
||||
response_text = loop.run_until_complete(response.text())
|
||||
assert response_text == 'hello'
|
||||
response_text = loop.run_until_complete(response.text(errors='replace'))
|
||||
assert response_text == 'hello'
|
||||
assert response_text == "hello"
|
||||
response_text = loop.run_until_complete(response.text(errors="replace"))
|
||||
assert response_text == "hello"
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('get.yaml'))) as cassette:
|
||||
with vcr.use_cassette(str(tmpdir.join("get.yaml"))) as cassette:
|
||||
response = loop.run_until_complete(client.get(url))
|
||||
|
||||
request = cassette.requests[0]
|
||||
assert request.url == str(client.make_url(url))
|
||||
response_text = loop.run_until_complete(response.text())
|
||||
assert response_text == 'hello'
|
||||
assert response_text == "hello"
|
||||
assert cassette.play_count == 1
|
||||
|
||||
|
||||
def test_aiohttp_test_client_json(aiohttp_client, tmpdir):
|
||||
loop = asyncio.get_event_loop()
|
||||
app = aiohttp_app()
|
||||
url = '/json/empty'
|
||||
url = "/json/empty"
|
||||
client = loop.run_until_complete(aiohttp_client(app))
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('get.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("get.yaml"))):
|
||||
response = loop.run_until_complete(client.get(url))
|
||||
|
||||
assert response.status == 200
|
||||
response_json = loop.run_until_complete(response.json())
|
||||
assert response_json is None
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('get.yaml'))) as cassette:
|
||||
with vcr.use_cassette(str(tmpdir.join("get.yaml"))) as cassette:
|
||||
response = loop.run_until_complete(client.get(url))
|
||||
|
||||
request = cassette.requests[0]
|
||||
@@ -250,12 +250,12 @@ def test_aiohttp_test_client_json(aiohttp_client, tmpdir):
|
||||
|
||||
|
||||
def test_redirect(aiohttp_client, tmpdir):
|
||||
url = 'https://httpbin.org/redirect/2'
|
||||
url = "https://httpbin.org/redirect/2"
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('redirect.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("redirect.yaml"))):
|
||||
response, _ = get(url)
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('redirect.yaml'))) as cassette:
|
||||
with vcr.use_cassette(str(tmpdir.join("redirect.yaml"))) as cassette:
|
||||
cassette_response, _ = get(url)
|
||||
|
||||
assert cassette_response.status == response.status
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''Basic tests for cassettes'''
|
||||
"""Basic tests for cassettes"""
|
||||
|
||||
# External imports
|
||||
import os
|
||||
@@ -10,21 +10,21 @@ import vcr
|
||||
|
||||
|
||||
def test_nonexistent_directory(tmpdir, httpbin):
|
||||
'''If we load a cassette in a nonexistent directory, it can save ok'''
|
||||
"""If we load a cassette in a nonexistent directory, it can save ok"""
|
||||
# Check to make sure directory doesnt exist
|
||||
assert not os.path.exists(str(tmpdir.join('nonexistent')))
|
||||
assert not os.path.exists(str(tmpdir.join("nonexistent")))
|
||||
|
||||
# Run VCR to create dir and cassette file
|
||||
with vcr.use_cassette(str(tmpdir.join('nonexistent', 'cassette.yml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("nonexistent", "cassette.yml"))):
|
||||
urlopen(httpbin.url).read()
|
||||
|
||||
# This should have made the file and the directory
|
||||
assert os.path.exists(str(tmpdir.join('nonexistent', 'cassette.yml')))
|
||||
assert os.path.exists(str(tmpdir.join("nonexistent", "cassette.yml")))
|
||||
|
||||
|
||||
def test_unpatch(tmpdir, httpbin):
|
||||
'''Ensure that our cassette gets unpatched when we're done'''
|
||||
with vcr.use_cassette(str(tmpdir.join('unpatch.yaml'))) as cass:
|
||||
"""Ensure that our cassette gets unpatched when we're done"""
|
||||
with vcr.use_cassette(str(tmpdir.join("unpatch.yaml"))) as cass:
|
||||
urlopen(httpbin.url).read()
|
||||
|
||||
# Make the same request, and assert that we haven't served any more
|
||||
@@ -34,30 +34,30 @@ def test_unpatch(tmpdir, httpbin):
|
||||
|
||||
|
||||
def test_basic_json_use(tmpdir, httpbin):
|
||||
'''
|
||||
"""
|
||||
Ensure you can load a json serialized cassette
|
||||
'''
|
||||
test_fixture = str(tmpdir.join('synopsis.json'))
|
||||
with vcr.use_cassette(test_fixture, serializer='json'):
|
||||
"""
|
||||
test_fixture = str(tmpdir.join("synopsis.json"))
|
||||
with vcr.use_cassette(test_fixture, serializer="json"):
|
||||
response = urlopen(httpbin.url).read()
|
||||
assert b'difficult sometimes' in response
|
||||
assert b"difficult sometimes" in response
|
||||
|
||||
|
||||
def test_patched_content(tmpdir, httpbin):
|
||||
'''
|
||||
"""
|
||||
Ensure that what you pull from a cassette is what came from the
|
||||
request
|
||||
'''
|
||||
with vcr.use_cassette(str(tmpdir.join('synopsis.yaml'))) as cass:
|
||||
"""
|
||||
with vcr.use_cassette(str(tmpdir.join("synopsis.yaml"))) as cass:
|
||||
response = urlopen(httpbin.url).read()
|
||||
assert cass.play_count == 0
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('synopsis.yaml'))) as cass:
|
||||
with vcr.use_cassette(str(tmpdir.join("synopsis.yaml"))) as cass:
|
||||
response2 = urlopen(httpbin.url).read()
|
||||
assert cass.play_count == 1
|
||||
cass._save(force=True)
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('synopsis.yaml'))) as cass:
|
||||
with vcr.use_cassette(str(tmpdir.join("synopsis.yaml"))) as cass:
|
||||
response3 = urlopen(httpbin.url).read()
|
||||
assert cass.play_count == 1
|
||||
|
||||
@@ -66,12 +66,12 @@ def test_patched_content(tmpdir, httpbin):
|
||||
|
||||
|
||||
def test_patched_content_json(tmpdir, httpbin):
|
||||
'''
|
||||
"""
|
||||
Ensure that what you pull from a json cassette is what came from the
|
||||
request
|
||||
'''
|
||||
"""
|
||||
|
||||
testfile = str(tmpdir.join('synopsis.json'))
|
||||
testfile = str(tmpdir.join("synopsis.json"))
|
||||
|
||||
with vcr.use_cassette(testfile) as cass:
|
||||
response = urlopen(httpbin.url).read()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import pytest
|
||||
|
||||
boto = pytest.importorskip("boto")
|
||||
|
||||
import boto # NOQA
|
||||
@@ -6,6 +7,7 @@ import boto.iam # NOQA
|
||||
from boto.s3.connection import S3Connection # NOQA
|
||||
from boto.s3.key import Key # NOQA
|
||||
import vcr # NOQA
|
||||
|
||||
try: # NOQA
|
||||
from ConfigParser import DuplicateSectionError # NOQA
|
||||
except ImportError: # NOQA
|
||||
@@ -14,68 +16,69 @@ except ImportError: # NOQA
|
||||
|
||||
|
||||
def test_boto_stubs(tmpdir):
|
||||
with vcr.use_cassette(str(tmpdir.join('boto-stubs.yml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("boto-stubs.yml"))):
|
||||
# Perform the imports within the patched context so that
|
||||
# CertValidatingHTTPSConnection refers to the patched version.
|
||||
from boto.https_connection import CertValidatingHTTPSConnection
|
||||
from vcr.stubs.boto_stubs import VCRCertValidatingHTTPSConnection
|
||||
|
||||
# Prove that the class was patched by the stub and that we can instantiate it.
|
||||
assert issubclass(CertValidatingHTTPSConnection, VCRCertValidatingHTTPSConnection)
|
||||
CertValidatingHTTPSConnection('hostname.does.not.matter')
|
||||
CertValidatingHTTPSConnection("hostname.does.not.matter")
|
||||
|
||||
|
||||
def test_boto_without_vcr():
|
||||
s3_conn = S3Connection()
|
||||
s3_bucket = s3_conn.get_bucket('boto-demo-1394171994') # a bucket you can access
|
||||
s3_bucket = s3_conn.get_bucket("boto-demo-1394171994") # a bucket you can access
|
||||
k = Key(s3_bucket)
|
||||
k.key = 'test.txt'
|
||||
k.set_contents_from_string('hello world i am a string')
|
||||
k.key = "test.txt"
|
||||
k.set_contents_from_string("hello world i am a string")
|
||||
|
||||
|
||||
def test_boto_medium_difficulty(tmpdir):
|
||||
s3_conn = S3Connection()
|
||||
s3_bucket = s3_conn.get_bucket('boto-demo-1394171994') # a bucket you can access
|
||||
with vcr.use_cassette(str(tmpdir.join('boto-medium.yml'))):
|
||||
s3_bucket = s3_conn.get_bucket("boto-demo-1394171994") # a bucket you can access
|
||||
with vcr.use_cassette(str(tmpdir.join("boto-medium.yml"))):
|
||||
k = Key(s3_bucket)
|
||||
k.key = 'test.txt'
|
||||
k.set_contents_from_string('hello world i am a string')
|
||||
k.key = "test.txt"
|
||||
k.set_contents_from_string("hello world i am a string")
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('boto-medium.yml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("boto-medium.yml"))):
|
||||
k = Key(s3_bucket)
|
||||
k.key = 'test.txt'
|
||||
k.set_contents_from_string('hello world i am a string')
|
||||
k.key = "test.txt"
|
||||
k.set_contents_from_string("hello world i am a string")
|
||||
|
||||
|
||||
def test_boto_hardcore_mode(tmpdir):
|
||||
with vcr.use_cassette(str(tmpdir.join('boto-hardcore.yml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("boto-hardcore.yml"))):
|
||||
s3_conn = S3Connection()
|
||||
s3_bucket = s3_conn.get_bucket('boto-demo-1394171994') # a bucket you can access
|
||||
s3_bucket = s3_conn.get_bucket("boto-demo-1394171994") # a bucket you can access
|
||||
k = Key(s3_bucket)
|
||||
k.key = 'test.txt'
|
||||
k.set_contents_from_string('hello world i am a string')
|
||||
k.key = "test.txt"
|
||||
k.set_contents_from_string("hello world i am a string")
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('boto-hardcore.yml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("boto-hardcore.yml"))):
|
||||
s3_conn = S3Connection()
|
||||
s3_bucket = s3_conn.get_bucket('boto-demo-1394171994') # a bucket you can access
|
||||
s3_bucket = s3_conn.get_bucket("boto-demo-1394171994") # a bucket you can access
|
||||
k = Key(s3_bucket)
|
||||
k.key = 'test.txt'
|
||||
k.set_contents_from_string('hello world i am a string')
|
||||
k.key = "test.txt"
|
||||
k.set_contents_from_string("hello world i am a string")
|
||||
|
||||
|
||||
def test_boto_iam(tmpdir):
|
||||
try:
|
||||
boto.config.add_section('Boto')
|
||||
boto.config.add_section("Boto")
|
||||
except DuplicateSectionError:
|
||||
pass
|
||||
# Ensure that boto uses HTTPS
|
||||
boto.config.set('Boto', 'is_secure', 'true')
|
||||
boto.config.set("Boto", "is_secure", "true")
|
||||
# Ensure that boto uses CertValidatingHTTPSConnection
|
||||
boto.config.set('Boto', 'https_validate_certificates', 'true')
|
||||
boto.config.set("Boto", "https_validate_certificates", "true")
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('boto-iam.yml'))):
|
||||
iam_conn = boto.iam.connect_to_region('universal')
|
||||
with vcr.use_cassette(str(tmpdir.join("boto-iam.yml"))):
|
||||
iam_conn = boto.iam.connect_to_region("universal")
|
||||
iam_conn.get_all_users()
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('boto-iam.yml'))):
|
||||
iam_conn = boto.iam.connect_to_region('universal')
|
||||
with vcr.use_cassette(str(tmpdir.join("boto-iam.yml"))):
|
||||
iam_conn = boto.iam.connect_to_region("universal")
|
||||
iam_conn.get_all_users()
|
||||
|
||||
@@ -18,13 +18,13 @@ except ImportError:
|
||||
# https://github.com/boto/botocore/pull/1495
|
||||
boto3_skip_vendored_requests = pytest.mark.skipif(
|
||||
botocore_awsrequest,
|
||||
reason='botocore version {ver} does not use vendored requests anymore.'.format(
|
||||
ver=botocore.__version__))
|
||||
reason="botocore version {ver} does not use vendored requests anymore.".format(ver=botocore.__version__),
|
||||
)
|
||||
|
||||
boto3_skip_awsrequest = pytest.mark.skipif(
|
||||
not botocore_awsrequest,
|
||||
reason='botocore version {ver} still uses vendored requests.'.format(
|
||||
ver=botocore.__version__))
|
||||
reason="botocore version {ver} still uses vendored requests.".format(ver=botocore.__version__),
|
||||
)
|
||||
|
||||
IAM_USER_NAME = "vcrpy"
|
||||
|
||||
@@ -34,12 +34,13 @@ def iam_client():
|
||||
def _iam_client(boto3_session=None):
|
||||
if boto3_session is None:
|
||||
boto3_session = boto3.Session(
|
||||
aws_access_key_id=os.environ.get('AWS_ACCESS_KEY_ID', "default"),
|
||||
aws_secret_access_key=os.environ.get('AWS_SECRET_ACCESS_KEY', "default"),
|
||||
aws_access_key_id=os.environ.get("AWS_ACCESS_KEY_ID", "default"),
|
||||
aws_secret_access_key=os.environ.get("AWS_SECRET_ACCESS_KEY", "default"),
|
||||
aws_session_token=None,
|
||||
region_name=os.environ.get('AWS_DEFAULT_REGION', "default"),
|
||||
region_name=os.environ.get("AWS_DEFAULT_REGION", "default"),
|
||||
)
|
||||
return boto3_session.client('iam')
|
||||
return boto3_session.client("iam")
|
||||
|
||||
return _iam_client
|
||||
|
||||
|
||||
@@ -50,39 +51,43 @@ def get_user(iam_client):
|
||||
# Default client set with fixture `iam_client`
|
||||
client = iam_client()
|
||||
return client.get_user(UserName=user_name)
|
||||
|
||||
return _get_user
|
||||
|
||||
|
||||
@boto3_skip_vendored_requests
|
||||
def test_boto_vendored_stubs(tmpdir):
|
||||
with vcr.use_cassette(str(tmpdir.join('boto3-stubs.yml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("boto3-stubs.yml"))):
|
||||
# Perform the imports within the patched context so that
|
||||
# HTTPConnection, VerifiedHTTPSConnection refers to the patched version.
|
||||
from botocore.vendored.requests.packages.urllib3.connectionpool import \
|
||||
HTTPConnection, VerifiedHTTPSConnection
|
||||
from botocore.vendored.requests.packages.urllib3.connectionpool import (
|
||||
HTTPConnection,
|
||||
VerifiedHTTPSConnection,
|
||||
)
|
||||
from vcr.stubs.boto3_stubs import VCRRequestsHTTPConnection, VCRRequestsHTTPSConnection
|
||||
|
||||
# Prove that the class was patched by the stub and that we can instantiate it.
|
||||
assert issubclass(HTTPConnection, VCRRequestsHTTPConnection)
|
||||
assert issubclass(VerifiedHTTPSConnection, VCRRequestsHTTPSConnection)
|
||||
HTTPConnection('hostname.does.not.matter')
|
||||
VerifiedHTTPSConnection('hostname.does.not.matter')
|
||||
HTTPConnection("hostname.does.not.matter")
|
||||
VerifiedHTTPSConnection("hostname.does.not.matter")
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
os.environ.get("TRAVIS_PULL_REQUEST") != "false",
|
||||
reason="Encrypted Environment Variables from Travis Repository Settings"
|
||||
" are disabled on PRs from forks. "
|
||||
"https://docs.travis-ci.com/user/pull-requests/#pull-requests-and-security-restrictions"
|
||||
"https://docs.travis-ci.com/user/pull-requests/#pull-requests-and-security-restrictions",
|
||||
)
|
||||
def test_boto_medium_difficulty(tmpdir, get_user):
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('boto3-medium.yml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("boto3-medium.yml"))):
|
||||
response = get_user()
|
||||
assert response['User']['UserName'] == IAM_USER_NAME
|
||||
assert response["User"]["UserName"] == IAM_USER_NAME
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('boto3-medium.yml'))) as cass:
|
||||
with vcr.use_cassette(str(tmpdir.join("boto3-medium.yml"))) as cass:
|
||||
response = get_user()
|
||||
assert response['User']['UserName'] == IAM_USER_NAME
|
||||
assert response["User"]["UserName"] == IAM_USER_NAME
|
||||
assert cass.all_played
|
||||
|
||||
|
||||
@@ -90,28 +95,28 @@ def test_boto_medium_difficulty(tmpdir, get_user):
|
||||
os.environ.get("TRAVIS_PULL_REQUEST") != "false",
|
||||
reason="Encrypted Environment Variables from Travis Repository Settings"
|
||||
" are disabled on PRs from forks. "
|
||||
"https://docs.travis-ci.com/user/pull-requests/#pull-requests-and-security-restrictions"
|
||||
"https://docs.travis-ci.com/user/pull-requests/#pull-requests-and-security-restrictions",
|
||||
)
|
||||
def test_boto_hardcore_mode(tmpdir, iam_client, get_user):
|
||||
with vcr.use_cassette(str(tmpdir.join('boto3-hardcore.yml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("boto3-hardcore.yml"))):
|
||||
ses = boto3.Session(
|
||||
aws_access_key_id=os.environ.get('AWS_ACCESS_KEY_ID'),
|
||||
aws_secret_access_key=os.environ.get('AWS_SECRET_ACCESS_KEY'),
|
||||
region_name=os.environ.get('AWS_DEFAULT_REGION'),
|
||||
aws_access_key_id=os.environ.get("AWS_ACCESS_KEY_ID"),
|
||||
aws_secret_access_key=os.environ.get("AWS_SECRET_ACCESS_KEY"),
|
||||
region_name=os.environ.get("AWS_DEFAULT_REGION"),
|
||||
)
|
||||
client = iam_client(ses)
|
||||
response = get_user(client=client)
|
||||
assert response['User']['UserName'] == IAM_USER_NAME
|
||||
assert response["User"]["UserName"] == IAM_USER_NAME
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('boto3-hardcore.yml'))) as cass:
|
||||
with vcr.use_cassette(str(tmpdir.join("boto3-hardcore.yml"))) as cass:
|
||||
ses = boto3.Session(
|
||||
aws_access_key_id=os.environ.get('AWS_ACCESS_KEY_ID'),
|
||||
aws_secret_access_key=os.environ.get('AWS_SECRET_ACCESS_KEY'),
|
||||
aws_access_key_id=os.environ.get("AWS_ACCESS_KEY_ID"),
|
||||
aws_secret_access_key=os.environ.get("AWS_SECRET_ACCESS_KEY"),
|
||||
aws_session_token=None,
|
||||
region_name=os.environ.get('AWS_DEFAULT_REGION'),
|
||||
region_name=os.environ.get("AWS_DEFAULT_REGION"),
|
||||
)
|
||||
|
||||
client = iam_client(ses)
|
||||
response = get_user(client=client)
|
||||
assert response['User']['UserName'] == IAM_USER_NAME
|
||||
assert response["User"]["UserName"] == IAM_USER_NAME
|
||||
assert cass.all_played
|
||||
|
||||
@@ -6,45 +6,45 @@ from six.moves.urllib.request import urlopen
|
||||
|
||||
|
||||
def test_set_serializer_default_config(tmpdir, httpbin):
|
||||
my_vcr = vcr.VCR(serializer='json')
|
||||
my_vcr = vcr.VCR(serializer="json")
|
||||
|
||||
with my_vcr.use_cassette(str(tmpdir.join('test.json'))):
|
||||
assert my_vcr.serializer == 'json'
|
||||
urlopen(httpbin.url + '/get')
|
||||
with my_vcr.use_cassette(str(tmpdir.join("test.json"))):
|
||||
assert my_vcr.serializer == "json"
|
||||
urlopen(httpbin.url + "/get")
|
||||
|
||||
with open(str(tmpdir.join('test.json'))) as f:
|
||||
with open(str(tmpdir.join("test.json"))) as f:
|
||||
assert json.loads(f.read())
|
||||
|
||||
|
||||
def test_default_set_cassette_library_dir(tmpdir, httpbin):
|
||||
my_vcr = vcr.VCR(cassette_library_dir=str(tmpdir.join('subdir')))
|
||||
my_vcr = vcr.VCR(cassette_library_dir=str(tmpdir.join("subdir")))
|
||||
|
||||
with my_vcr.use_cassette('test.json'):
|
||||
urlopen(httpbin.url + '/get')
|
||||
with my_vcr.use_cassette("test.json"):
|
||||
urlopen(httpbin.url + "/get")
|
||||
|
||||
assert os.path.exists(str(tmpdir.join('subdir').join('test.json')))
|
||||
assert os.path.exists(str(tmpdir.join("subdir").join("test.json")))
|
||||
|
||||
|
||||
def test_override_set_cassette_library_dir(tmpdir, httpbin):
|
||||
my_vcr = vcr.VCR(cassette_library_dir=str(tmpdir.join('subdir')))
|
||||
my_vcr = vcr.VCR(cassette_library_dir=str(tmpdir.join("subdir")))
|
||||
|
||||
cld = str(tmpdir.join('subdir2'))
|
||||
cld = str(tmpdir.join("subdir2"))
|
||||
|
||||
with my_vcr.use_cassette('test.json', cassette_library_dir=cld):
|
||||
urlopen(httpbin.url + '/get')
|
||||
with my_vcr.use_cassette("test.json", cassette_library_dir=cld):
|
||||
urlopen(httpbin.url + "/get")
|
||||
|
||||
assert os.path.exists(str(tmpdir.join('subdir2').join('test.json')))
|
||||
assert not os.path.exists(str(tmpdir.join('subdir').join('test.json')))
|
||||
assert os.path.exists(str(tmpdir.join("subdir2").join("test.json")))
|
||||
assert not os.path.exists(str(tmpdir.join("subdir").join("test.json")))
|
||||
|
||||
|
||||
def test_override_match_on(tmpdir, httpbin):
|
||||
my_vcr = vcr.VCR(match_on=['method'])
|
||||
my_vcr = vcr.VCR(match_on=["method"])
|
||||
|
||||
with my_vcr.use_cassette(str(tmpdir.join('test.json'))):
|
||||
with my_vcr.use_cassette(str(tmpdir.join("test.json"))):
|
||||
urlopen(httpbin.url)
|
||||
|
||||
with my_vcr.use_cassette(str(tmpdir.join('test.json'))) as cass:
|
||||
urlopen(httpbin.url + '/get')
|
||||
with my_vcr.use_cassette(str(tmpdir.join("test.json"))) as cass:
|
||||
urlopen(httpbin.url + "/get")
|
||||
|
||||
assert len(cass) == 1
|
||||
assert cass.play_count == 1
|
||||
@@ -54,5 +54,5 @@ def test_missing_matcher():
|
||||
my_vcr = vcr.VCR()
|
||||
my_vcr.register_matcher("awesome", object)
|
||||
with pytest.raises(KeyError):
|
||||
with my_vcr.use_cassette("test.yaml", match_on=['notawesome']):
|
||||
with my_vcr.use_cassette("test.yaml", match_on=["notawesome"]):
|
||||
pass
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''Basic tests about save behavior'''
|
||||
"""Basic tests about save behavior"""
|
||||
|
||||
# External imports
|
||||
import os
|
||||
@@ -11,11 +11,11 @@ import vcr
|
||||
|
||||
|
||||
def test_disk_saver_nowrite(tmpdir, httpbin):
|
||||
'''
|
||||
"""
|
||||
Ensure that when you close a cassette without changing it it doesn't
|
||||
rewrite the file
|
||||
'''
|
||||
fname = str(tmpdir.join('synopsis.yaml'))
|
||||
"""
|
||||
fname = str(tmpdir.join("synopsis.yaml"))
|
||||
with vcr.use_cassette(fname) as cass:
|
||||
urlopen(httpbin.url).read()
|
||||
assert cass.play_count == 0
|
||||
@@ -31,11 +31,11 @@ def test_disk_saver_nowrite(tmpdir, httpbin):
|
||||
|
||||
|
||||
def test_disk_saver_write(tmpdir, httpbin):
|
||||
'''
|
||||
"""
|
||||
Ensure that when you close a cassette after changing it it does
|
||||
rewrite the file
|
||||
'''
|
||||
fname = str(tmpdir.join('synopsis.yaml'))
|
||||
"""
|
||||
fname = str(tmpdir.join("synopsis.yaml"))
|
||||
with vcr.use_cassette(fname) as cass:
|
||||
urlopen(httpbin.url).read()
|
||||
assert cass.play_count == 0
|
||||
@@ -45,9 +45,9 @@ def test_disk_saver_write(tmpdir, httpbin):
|
||||
# the mtime doesn't change
|
||||
time.sleep(1)
|
||||
|
||||
with vcr.use_cassette(fname, record_mode='any') as cass:
|
||||
with vcr.use_cassette(fname, record_mode="any") as cass:
|
||||
urlopen(httpbin.url).read()
|
||||
urlopen(httpbin.url + '/get').read()
|
||||
urlopen(httpbin.url + "/get").read()
|
||||
assert cass.play_count == 1
|
||||
assert cass.dirty
|
||||
last_mod2 = os.path.getmtime(fname)
|
||||
|
||||
@@ -10,9 +10,7 @@ from assertions import assert_cassette_has_one_response, assert_is_json
|
||||
|
||||
def _request_with_auth(url, username, password):
|
||||
request = Request(url)
|
||||
base64string = base64.b64encode(
|
||||
username.encode('ascii') + b':' + password.encode('ascii')
|
||||
)
|
||||
base64string = base64.b64encode(username.encode("ascii") + b":" + password.encode("ascii"))
|
||||
request.add_header(b"Authorization", b"Basic " + base64string)
|
||||
return urlopen(request)
|
||||
|
||||
@@ -22,84 +20,84 @@ def _find_header(cassette, header):
|
||||
|
||||
|
||||
def test_filter_basic_auth(tmpdir, httpbin):
|
||||
url = httpbin.url + '/basic-auth/user/passwd'
|
||||
cass_file = str(tmpdir.join('basic_auth_filter.yaml'))
|
||||
my_vcr = vcr.VCR(match_on=['uri', 'method', 'headers'])
|
||||
url = httpbin.url + "/basic-auth/user/passwd"
|
||||
cass_file = str(tmpdir.join("basic_auth_filter.yaml"))
|
||||
my_vcr = vcr.VCR(match_on=["uri", "method", "headers"])
|
||||
# 2 requests, one with auth failure and one with auth success
|
||||
with my_vcr.use_cassette(cass_file, filter_headers=['authorization']):
|
||||
with my_vcr.use_cassette(cass_file, filter_headers=["authorization"]):
|
||||
with pytest.raises(HTTPError):
|
||||
resp = _request_with_auth(url, 'user', 'wrongpasswd')
|
||||
resp = _request_with_auth(url, "user", "wrongpasswd")
|
||||
assert resp.getcode() == 401
|
||||
resp = _request_with_auth(url, 'user', 'passwd')
|
||||
resp = _request_with_auth(url, "user", "passwd")
|
||||
assert resp.getcode() == 200
|
||||
# make same 2 requests, this time both served from cassette.
|
||||
with my_vcr.use_cassette(cass_file, filter_headers=['authorization']) as cass:
|
||||
with my_vcr.use_cassette(cass_file, filter_headers=["authorization"]) as cass:
|
||||
with pytest.raises(HTTPError):
|
||||
resp = _request_with_auth(url, 'user', 'wrongpasswd')
|
||||
resp = _request_with_auth(url, "user", "wrongpasswd")
|
||||
assert resp.getcode() == 401
|
||||
resp = _request_with_auth(url, 'user', 'passwd')
|
||||
resp = _request_with_auth(url, "user", "passwd")
|
||||
assert resp.getcode() == 200
|
||||
# authorization header should not have been recorded
|
||||
assert not _find_header(cass, 'authorization')
|
||||
assert not _find_header(cass, "authorization")
|
||||
assert len(cass) == 2
|
||||
|
||||
|
||||
def test_filter_querystring(tmpdir, httpbin):
|
||||
url = httpbin.url + '/?foo=bar'
|
||||
cass_file = str(tmpdir.join('filter_qs.yaml'))
|
||||
with vcr.use_cassette(cass_file, filter_query_parameters=['foo']):
|
||||
url = httpbin.url + "/?foo=bar"
|
||||
cass_file = str(tmpdir.join("filter_qs.yaml"))
|
||||
with vcr.use_cassette(cass_file, filter_query_parameters=["foo"]):
|
||||
urlopen(url)
|
||||
with vcr.use_cassette(cass_file, filter_query_parameters=['foo']) as cass:
|
||||
with vcr.use_cassette(cass_file, filter_query_parameters=["foo"]) as cass:
|
||||
urlopen(url)
|
||||
assert 'foo' not in cass.requests[0].url
|
||||
assert "foo" not in cass.requests[0].url
|
||||
|
||||
|
||||
def test_filter_post_data(tmpdir, httpbin):
|
||||
url = httpbin.url + '/post'
|
||||
data = urlencode({'id': 'secret', 'foo': 'bar'}).encode('utf-8')
|
||||
cass_file = str(tmpdir.join('filter_pd.yaml'))
|
||||
with vcr.use_cassette(cass_file, filter_post_data_parameters=['id']):
|
||||
url = httpbin.url + "/post"
|
||||
data = urlencode({"id": "secret", "foo": "bar"}).encode("utf-8")
|
||||
cass_file = str(tmpdir.join("filter_pd.yaml"))
|
||||
with vcr.use_cassette(cass_file, filter_post_data_parameters=["id"]):
|
||||
urlopen(url, data)
|
||||
with vcr.use_cassette(cass_file, filter_post_data_parameters=['id']) as cass:
|
||||
assert b'id=secret' not in cass.requests[0].body
|
||||
with vcr.use_cassette(cass_file, filter_post_data_parameters=["id"]) as cass:
|
||||
assert b"id=secret" not in cass.requests[0].body
|
||||
|
||||
|
||||
def test_filter_json_post_data(tmpdir, httpbin):
|
||||
data = json.dumps({'id': 'secret', 'foo': 'bar'}).encode('utf-8')
|
||||
request = Request(httpbin.url + '/post', data=data)
|
||||
request.add_header('Content-Type', 'application/json')
|
||||
data = json.dumps({"id": "secret", "foo": "bar"}).encode("utf-8")
|
||||
request = Request(httpbin.url + "/post", data=data)
|
||||
request.add_header("Content-Type", "application/json")
|
||||
|
||||
cass_file = str(tmpdir.join('filter_jpd.yaml'))
|
||||
with vcr.use_cassette(cass_file, filter_post_data_parameters=['id']):
|
||||
cass_file = str(tmpdir.join("filter_jpd.yaml"))
|
||||
with vcr.use_cassette(cass_file, filter_post_data_parameters=["id"]):
|
||||
urlopen(request)
|
||||
with vcr.use_cassette(cass_file, filter_post_data_parameters=['id']) as cass:
|
||||
with vcr.use_cassette(cass_file, filter_post_data_parameters=["id"]) as cass:
|
||||
assert b'"id": "secret"' not in cass.requests[0].body
|
||||
|
||||
|
||||
def test_filter_callback(tmpdir, httpbin):
|
||||
url = httpbin.url + '/get'
|
||||
cass_file = str(tmpdir.join('basic_auth_filter.yaml'))
|
||||
url = httpbin.url + "/get"
|
||||
cass_file = str(tmpdir.join("basic_auth_filter.yaml"))
|
||||
|
||||
def before_record_cb(request):
|
||||
if request.path != '/get':
|
||||
if request.path != "/get":
|
||||
return request
|
||||
|
||||
# Test the legacy keyword.
|
||||
my_vcr = vcr.VCR(before_record=before_record_cb)
|
||||
with my_vcr.use_cassette(cass_file, filter_headers=['authorization']) as cass:
|
||||
with my_vcr.use_cassette(cass_file, filter_headers=["authorization"]) as cass:
|
||||
urlopen(url)
|
||||
assert len(cass) == 0
|
||||
|
||||
my_vcr = vcr.VCR(before_record_request=before_record_cb)
|
||||
with my_vcr.use_cassette(cass_file, filter_headers=['authorization']) as cass:
|
||||
with my_vcr.use_cassette(cass_file, filter_headers=["authorization"]) as cass:
|
||||
urlopen(url)
|
||||
assert len(cass) == 0
|
||||
|
||||
|
||||
def test_decompress_gzip(tmpdir, httpbin):
|
||||
url = httpbin.url + '/gzip'
|
||||
request = Request(url, headers={'Accept-Encoding': ['gzip, deflate']})
|
||||
cass_file = str(tmpdir.join('gzip_response.yaml'))
|
||||
url = httpbin.url + "/gzip"
|
||||
request = Request(url, headers={"Accept-Encoding": ["gzip, deflate"]})
|
||||
cass_file = str(tmpdir.join("gzip_response.yaml"))
|
||||
with vcr.use_cassette(cass_file, decode_compressed_response=True):
|
||||
urlopen(request)
|
||||
with vcr.use_cassette(cass_file) as cass:
|
||||
@@ -109,9 +107,9 @@ def test_decompress_gzip(tmpdir, httpbin):
|
||||
|
||||
|
||||
def test_decompress_deflate(tmpdir, httpbin):
|
||||
url = httpbin.url + '/deflate'
|
||||
request = Request(url, headers={'Accept-Encoding': ['gzip, deflate']})
|
||||
cass_file = str(tmpdir.join('deflate_response.yaml'))
|
||||
url = httpbin.url + "/deflate"
|
||||
request = Request(url, headers={"Accept-Encoding": ["gzip, deflate"]})
|
||||
cass_file = str(tmpdir.join("deflate_response.yaml"))
|
||||
with vcr.use_cassette(cass_file, decode_compressed_response=True):
|
||||
urlopen(request)
|
||||
with vcr.use_cassette(cass_file) as cass:
|
||||
@@ -122,8 +120,8 @@ def test_decompress_deflate(tmpdir, httpbin):
|
||||
|
||||
def test_decompress_regular(tmpdir, httpbin):
|
||||
"""Test that it doesn't try to decompress content that isn't compressed"""
|
||||
url = httpbin.url + '/get'
|
||||
cass_file = str(tmpdir.join('noncompressed_response.yaml'))
|
||||
url = httpbin.url + "/get"
|
||||
cass_file = str(tmpdir.join("noncompressed_response.yaml"))
|
||||
with vcr.use_cassette(cass_file, decode_compressed_response=True):
|
||||
urlopen(url)
|
||||
with vcr.use_cassette(cass_file) as cass:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''Integration tests with httplib2'''
|
||||
"""Integration tests with httplib2"""
|
||||
|
||||
import sys
|
||||
|
||||
@@ -19,97 +19,90 @@ def http():
|
||||
Returns an httplib2 HTTP instance
|
||||
with the certificate replaced by the httpbin one.
|
||||
"""
|
||||
kwargs = {
|
||||
'ca_certs': pytest_httpbin.certs.where()
|
||||
}
|
||||
kwargs = {"ca_certs": pytest_httpbin.certs.where()}
|
||||
if sys.version_info[:2] in [(2, 7), (3, 7)]:
|
||||
kwargs['disable_ssl_certificate_validation'] = True
|
||||
kwargs["disable_ssl_certificate_validation"] = True
|
||||
return httplib2.Http(**kwargs)
|
||||
|
||||
|
||||
def test_response_code(tmpdir, httpbin_both):
|
||||
'''Ensure we can read a response code from a fetch'''
|
||||
"""Ensure we can read a response code from a fetch"""
|
||||
url = httpbin_both.url
|
||||
with vcr.use_cassette(str(tmpdir.join('atts.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("atts.yaml"))):
|
||||
resp, _ = http().request(url)
|
||||
code = resp.status
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('atts.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("atts.yaml"))):
|
||||
resp, _ = http().request(url)
|
||||
assert code == resp.status
|
||||
|
||||
|
||||
def test_random_body(httpbin_both, tmpdir):
|
||||
'''Ensure we can read the content, and that it's served from cache'''
|
||||
url = httpbin_both.url + '/bytes/1024'
|
||||
with vcr.use_cassette(str(tmpdir.join('body.yaml'))):
|
||||
"""Ensure we can read the content, and that it's served from cache"""
|
||||
url = httpbin_both.url + "/bytes/1024"
|
||||
with vcr.use_cassette(str(tmpdir.join("body.yaml"))):
|
||||
_, content = http().request(url)
|
||||
body = content
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('body.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("body.yaml"))):
|
||||
_, content = http().request(url)
|
||||
assert body == content
|
||||
|
||||
|
||||
def test_response_headers(tmpdir, httpbin_both):
|
||||
'''Ensure we can get information from the response'''
|
||||
"""Ensure we can get information from the response"""
|
||||
url = httpbin_both.url
|
||||
with vcr.use_cassette(str(tmpdir.join('headers.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("headers.yaml"))):
|
||||
resp, _ = http().request(url)
|
||||
headers = resp.items()
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('headers.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("headers.yaml"))):
|
||||
resp, _ = http().request(url)
|
||||
assert set(headers) == set(resp.items())
|
||||
|
||||
|
||||
def test_effective_url(tmpdir, httpbin_both):
|
||||
'''Ensure that the effective_url is captured'''
|
||||
url = httpbin_both.url + '/redirect-to?url=/html'
|
||||
with vcr.use_cassette(str(tmpdir.join('headers.yaml'))):
|
||||
"""Ensure that the effective_url is captured"""
|
||||
url = httpbin_both.url + "/redirect-to?url=/html"
|
||||
with vcr.use_cassette(str(tmpdir.join("headers.yaml"))):
|
||||
resp, _ = http().request(url)
|
||||
effective_url = resp['content-location']
|
||||
assert effective_url == httpbin_both + '/html'
|
||||
effective_url = resp["content-location"]
|
||||
assert effective_url == httpbin_both + "/html"
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('headers.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("headers.yaml"))):
|
||||
resp, _ = http().request(url)
|
||||
assert effective_url == resp['content-location']
|
||||
assert effective_url == resp["content-location"]
|
||||
|
||||
|
||||
def test_multiple_requests(tmpdir, httpbin_both):
|
||||
'''Ensure that we can cache multiple requests'''
|
||||
urls = [
|
||||
httpbin_both.url,
|
||||
httpbin_both.url,
|
||||
httpbin_both.url + '/get',
|
||||
httpbin_both.url + '/bytes/1024',
|
||||
]
|
||||
with vcr.use_cassette(str(tmpdir.join('multiple.yaml'))) as cass:
|
||||
"""Ensure that we can cache multiple requests"""
|
||||
urls = [httpbin_both.url, httpbin_both.url, httpbin_both.url + "/get", httpbin_both.url + "/bytes/1024"]
|
||||
with vcr.use_cassette(str(tmpdir.join("multiple.yaml"))) as cass:
|
||||
[http().request(url) for url in urls]
|
||||
assert len(cass) == len(urls)
|
||||
|
||||
|
||||
def test_get_data(tmpdir, httpbin_both):
|
||||
'''Ensure that it works with query data'''
|
||||
data = urlencode({'some': 1, 'data': 'here'})
|
||||
url = httpbin_both.url + '/get?' + data
|
||||
with vcr.use_cassette(str(tmpdir.join('get_data.yaml'))):
|
||||
"""Ensure that it works with query data"""
|
||||
data = urlencode({"some": 1, "data": "here"})
|
||||
url = httpbin_both.url + "/get?" + data
|
||||
with vcr.use_cassette(str(tmpdir.join("get_data.yaml"))):
|
||||
_, res1 = http().request(url)
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('get_data.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("get_data.yaml"))):
|
||||
_, res2 = http().request(url)
|
||||
|
||||
assert res1 == res2
|
||||
|
||||
|
||||
def test_post_data(tmpdir, httpbin_both):
|
||||
'''Ensure that it works when posting data'''
|
||||
data = urlencode({'some': 1, 'data': 'here'})
|
||||
url = httpbin_both.url + '/post'
|
||||
with vcr.use_cassette(str(tmpdir.join('post_data.yaml'))):
|
||||
"""Ensure that it works when posting data"""
|
||||
data = urlencode({"some": 1, "data": "here"})
|
||||
url = httpbin_both.url + "/post"
|
||||
with vcr.use_cassette(str(tmpdir.join("post_data.yaml"))):
|
||||
_, res1 = http().request(url, "POST", data)
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('post_data.yaml'))) as cass:
|
||||
with vcr.use_cassette(str(tmpdir.join("post_data.yaml"))) as cass:
|
||||
_, res2 = http().request(url, "POST", data)
|
||||
|
||||
assert res1 == res2
|
||||
@@ -117,13 +110,13 @@ def test_post_data(tmpdir, httpbin_both):
|
||||
|
||||
|
||||
def test_post_unicode_data(tmpdir, httpbin_both):
|
||||
'''Ensure that it works when posting unicode data'''
|
||||
data = urlencode({'snowman': u'☃'.encode('utf-8')})
|
||||
url = httpbin_both.url + '/post'
|
||||
with vcr.use_cassette(str(tmpdir.join('post_data.yaml'))):
|
||||
"""Ensure that it works when posting unicode data"""
|
||||
data = urlencode({"snowman": u"☃".encode("utf-8")})
|
||||
url = httpbin_both.url + "/post"
|
||||
with vcr.use_cassette(str(tmpdir.join("post_data.yaml"))):
|
||||
_, res1 = http().request(url, "POST", data)
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('post_data.yaml'))) as cass:
|
||||
with vcr.use_cassette(str(tmpdir.join("post_data.yaml"))) as cass:
|
||||
_, res2 = http().request(url, "POST", data)
|
||||
|
||||
assert res1 == res2
|
||||
@@ -131,11 +124,11 @@ def test_post_unicode_data(tmpdir, httpbin_both):
|
||||
|
||||
|
||||
def test_cross_scheme(tmpdir, httpbin, httpbin_secure):
|
||||
'''Ensure that requests between schemes are treated separately'''
|
||||
"""Ensure that requests between schemes are treated separately"""
|
||||
# First fetch a url under https, and then again under https and then
|
||||
# ensure that we haven't served anything out of cache, and we have two
|
||||
# requests / response pairs in the cassette
|
||||
with vcr.use_cassette(str(tmpdir.join('cross_scheme.yaml'))) as cass:
|
||||
with vcr.use_cassette(str(tmpdir.join("cross_scheme.yaml"))) as cass:
|
||||
http().request(httpbin_secure.url)
|
||||
http().request(httpbin.url)
|
||||
assert len(cass) == 2
|
||||
@@ -143,17 +136,17 @@ def test_cross_scheme(tmpdir, httpbin, httpbin_secure):
|
||||
|
||||
|
||||
def test_decorator(tmpdir, httpbin_both):
|
||||
'''Test the decorator version of VCR.py'''
|
||||
"""Test the decorator version of VCR.py"""
|
||||
url = httpbin_both.url
|
||||
|
||||
@vcr.use_cassette(str(tmpdir.join('atts.yaml')))
|
||||
@vcr.use_cassette(str(tmpdir.join("atts.yaml")))
|
||||
def inner1():
|
||||
resp, _ = http().request(url)
|
||||
return resp['status']
|
||||
return resp["status"]
|
||||
|
||||
@vcr.use_cassette(str(tmpdir.join('atts.yaml')))
|
||||
@vcr.use_cassette(str(tmpdir.join("atts.yaml")))
|
||||
def inner2():
|
||||
resp, _ = http().request(url)
|
||||
return resp['status']
|
||||
return resp["status"]
|
||||
|
||||
assert inner1() == inner2()
|
||||
|
||||
@@ -15,59 +15,53 @@ def overridden_dns(overrides):
|
||||
def fake_getaddrinfo(*args, **kwargs):
|
||||
if args[0] in overrides:
|
||||
address = overrides[args[0]]
|
||||
return [(2, 1, 6, '', (address, args[1]))]
|
||||
return [(2, 1, 6, "", (address, args[1]))]
|
||||
return real_getaddrinfo(*args, **kwargs)
|
||||
|
||||
socket.getaddrinfo = fake_getaddrinfo
|
||||
yield
|
||||
socket.getaddrinfo = real_getaddrinfo
|
||||
|
||||
|
||||
def test_ignore_localhost(tmpdir, httpbin):
|
||||
with overridden_dns({'httpbin.org': '127.0.0.1'}):
|
||||
cass_file = str(tmpdir.join('filter_qs.yaml'))
|
||||
with overridden_dns({"httpbin.org": "127.0.0.1"}):
|
||||
cass_file = str(tmpdir.join("filter_qs.yaml"))
|
||||
with vcr.use_cassette(cass_file, ignore_localhost=True) as cass:
|
||||
urlopen('http://localhost:{}/'.format(httpbin.port))
|
||||
urlopen("http://localhost:{}/".format(httpbin.port))
|
||||
assert len(cass) == 0
|
||||
urlopen('http://httpbin.org:{}/'.format(httpbin.port))
|
||||
urlopen("http://httpbin.org:{}/".format(httpbin.port))
|
||||
assert len(cass) == 1
|
||||
|
||||
|
||||
def test_ignore_httpbin(tmpdir, httpbin):
|
||||
with overridden_dns({'httpbin.org': '127.0.0.1'}):
|
||||
cass_file = str(tmpdir.join('filter_qs.yaml'))
|
||||
with vcr.use_cassette(
|
||||
cass_file,
|
||||
ignore_hosts=['httpbin.org']
|
||||
) as cass:
|
||||
urlopen('http://httpbin.org:{}/'.format(httpbin.port))
|
||||
with overridden_dns({"httpbin.org": "127.0.0.1"}):
|
||||
cass_file = str(tmpdir.join("filter_qs.yaml"))
|
||||
with vcr.use_cassette(cass_file, ignore_hosts=["httpbin.org"]) as cass:
|
||||
urlopen("http://httpbin.org:{}/".format(httpbin.port))
|
||||
assert len(cass) == 0
|
||||
urlopen('http://localhost:{}/'.format(httpbin.port))
|
||||
urlopen("http://localhost:{}/".format(httpbin.port))
|
||||
assert len(cass) == 1
|
||||
|
||||
|
||||
def test_ignore_localhost_and_httpbin(tmpdir, httpbin):
|
||||
with overridden_dns({'httpbin.org': '127.0.0.1'}):
|
||||
cass_file = str(tmpdir.join('filter_qs.yaml'))
|
||||
with vcr.use_cassette(
|
||||
cass_file,
|
||||
ignore_hosts=['httpbin.org'],
|
||||
ignore_localhost=True
|
||||
) as cass:
|
||||
urlopen('http://httpbin.org:{}'.format(httpbin.port))
|
||||
urlopen('http://localhost:{}'.format(httpbin.port))
|
||||
with overridden_dns({"httpbin.org": "127.0.0.1"}):
|
||||
cass_file = str(tmpdir.join("filter_qs.yaml"))
|
||||
with vcr.use_cassette(cass_file, ignore_hosts=["httpbin.org"], ignore_localhost=True) as cass:
|
||||
urlopen("http://httpbin.org:{}".format(httpbin.port))
|
||||
urlopen("http://localhost:{}".format(httpbin.port))
|
||||
assert len(cass) == 0
|
||||
|
||||
|
||||
def test_ignore_localhost_twice(tmpdir, httpbin):
|
||||
with overridden_dns({'httpbin.org': '127.0.0.1'}):
|
||||
cass_file = str(tmpdir.join('filter_qs.yaml'))
|
||||
with overridden_dns({"httpbin.org": "127.0.0.1"}):
|
||||
cass_file = str(tmpdir.join("filter_qs.yaml"))
|
||||
with vcr.use_cassette(cass_file, ignore_localhost=True) as cass:
|
||||
urlopen('http://localhost:{}'.format(httpbin.port))
|
||||
urlopen("http://localhost:{}".format(httpbin.port))
|
||||
assert len(cass) == 0
|
||||
urlopen('http://httpbin.org:{}'.format(httpbin.port))
|
||||
urlopen("http://httpbin.org:{}".format(httpbin.port))
|
||||
assert len(cass) == 1
|
||||
with vcr.use_cassette(cass_file, ignore_localhost=True) as cass:
|
||||
assert len(cass) == 1
|
||||
urlopen('http://localhost:{}'.format(httpbin.port))
|
||||
urlopen('http://httpbin.org:{}'.format(httpbin.port))
|
||||
urlopen("http://localhost:{}".format(httpbin.port))
|
||||
urlopen("http://httpbin.org:{}".format(httpbin.port))
|
||||
assert len(cass) == 1
|
||||
|
||||
@@ -3,11 +3,11 @@ import pytest
|
||||
from six.moves.urllib.request import urlopen
|
||||
|
||||
|
||||
DEFAULT_URI = 'http://httpbin.org/get?p1=q1&p2=q2' # base uri for testing
|
||||
DEFAULT_URI = "http://httpbin.org/get?p1=q1&p2=q2" # base uri for testing
|
||||
|
||||
|
||||
def _replace_httpbin(uri, httpbin, httpbin_secure):
|
||||
return uri.replace('http://httpbin.org', httpbin.url).replace('https://httpbin.org', httpbin_secure.url)
|
||||
return uri.replace("http://httpbin.org", httpbin.url).replace("https://httpbin.org", httpbin_secure.url)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -18,29 +18,22 @@ def cassette(tmpdir, httpbin, httpbin_secure):
|
||||
"""
|
||||
default_uri = _replace_httpbin(DEFAULT_URI, httpbin, httpbin_secure)
|
||||
|
||||
cassette_path = str(tmpdir.join('test.yml'))
|
||||
with vcr.use_cassette(cassette_path, record_mode='all'):
|
||||
cassette_path = str(tmpdir.join("test.yml"))
|
||||
with vcr.use_cassette(cassette_path, record_mode="all"):
|
||||
urlopen(default_uri)
|
||||
return cassette_path
|
||||
|
||||
|
||||
@pytest.mark.parametrize("matcher, matching_uri, not_matching_uri", [
|
||||
('uri',
|
||||
'http://httpbin.org/get?p1=q1&p2=q2',
|
||||
'http://httpbin.org/get?p2=q2&p1=q1'),
|
||||
('scheme',
|
||||
'http://google.com/post?a=b',
|
||||
'https://httpbin.org/get?p1=q1&p2=q2'),
|
||||
('host',
|
||||
'https://httpbin.org/post?a=b',
|
||||
'http://google.com/get?p1=q1&p2=q2'),
|
||||
('path',
|
||||
'https://google.com/get?a=b',
|
||||
'http://httpbin.org/post?p1=q1&p2=q2'),
|
||||
('query',
|
||||
'https://google.com/get?p2=q2&p1=q1',
|
||||
'http://httpbin.org/get?p1=q1&a=b')
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"matcher, matching_uri, not_matching_uri",
|
||||
[
|
||||
("uri", "http://httpbin.org/get?p1=q1&p2=q2", "http://httpbin.org/get?p2=q2&p1=q1"),
|
||||
("scheme", "http://google.com/post?a=b", "https://httpbin.org/get?p1=q1&p2=q2"),
|
||||
("host", "https://httpbin.org/post?a=b", "http://google.com/get?p1=q1&p2=q2"),
|
||||
("path", "https://google.com/get?a=b", "http://httpbin.org/post?p1=q1&p2=q2"),
|
||||
("query", "https://google.com/get?p2=q2&p1=q1", "http://httpbin.org/get?p1=q1&a=b"),
|
||||
],
|
||||
)
|
||||
def test_matchers(httpbin, httpbin_secure, cassette, matcher, matching_uri, not_matching_uri):
|
||||
|
||||
matching_uri = _replace_httpbin(matching_uri, httpbin, httpbin_secure)
|
||||
@@ -67,22 +60,20 @@ def test_method_matcher(cassette, httpbin, httpbin_secure):
|
||||
default_uri = _replace_httpbin(DEFAULT_URI, httpbin, httpbin_secure)
|
||||
|
||||
# play cassette with matching on method
|
||||
with vcr.use_cassette(cassette, match_on=['method']) as cass:
|
||||
urlopen('https://google.com/get?a=b')
|
||||
with vcr.use_cassette(cassette, match_on=["method"]) as cass:
|
||||
urlopen("https://google.com/get?a=b")
|
||||
assert cass.play_count == 1
|
||||
|
||||
# should fail if method does not match
|
||||
with pytest.raises(vcr.errors.CannotOverwriteExistingCassetteException):
|
||||
with vcr.use_cassette(cassette, match_on=['method']) as cass:
|
||||
with vcr.use_cassette(cassette, match_on=["method"]) as cass:
|
||||
# is a POST request
|
||||
urlopen(default_uri, data=b'')
|
||||
urlopen(default_uri, data=b"")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("uri", [
|
||||
DEFAULT_URI,
|
||||
'http://httpbin.org/get?p2=q2&p1=q1',
|
||||
'http://httpbin.org/get?p2=q2&p1=q1',
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"uri", [DEFAULT_URI, "http://httpbin.org/get?p2=q2&p1=q1", "http://httpbin.org/get?p2=q2&p1=q1"]
|
||||
)
|
||||
def test_default_matcher_matches(cassette, uri, httpbin, httpbin_secure):
|
||||
|
||||
uri = _replace_httpbin(uri, httpbin, httpbin_secure)
|
||||
@@ -92,12 +83,15 @@ def test_default_matcher_matches(cassette, uri, httpbin, httpbin_secure):
|
||||
assert cass.play_count == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize("uri", [
|
||||
'https://httpbin.org/get?p1=q1&p2=q2',
|
||||
'http://google.com/get?p1=q1&p2=q2',
|
||||
'http://httpbin.org/post?p1=q1&p2=q2',
|
||||
'http://httpbin.org/get?p1=q1&a=b'
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"uri",
|
||||
[
|
||||
"https://httpbin.org/get?p1=q1&p2=q2",
|
||||
"http://google.com/get?p1=q1&p2=q2",
|
||||
"http://httpbin.org/post?p1=q1&p2=q2",
|
||||
"http://httpbin.org/get?p1=q1&a=b",
|
||||
],
|
||||
)
|
||||
def test_default_matcher_does_not_match(cassette, uri, httpbin, httpbin_secure):
|
||||
uri = _replace_httpbin(uri, httpbin, httpbin_secure)
|
||||
with pytest.raises(vcr.errors.CannotOverwriteExistingCassetteException):
|
||||
@@ -110,4 +104,4 @@ def test_default_matcher_does_not_match_on_method(cassette, httpbin, httpbin_sec
|
||||
with pytest.raises(vcr.errors.CannotOverwriteExistingCassetteException):
|
||||
with vcr.use_cassette(cassette):
|
||||
# is a POST request
|
||||
urlopen(default_uri, data=b'')
|
||||
urlopen(default_uri, data=b"")
|
||||
|
||||
@@ -6,15 +6,15 @@ from six.moves.urllib.request import urlopen
|
||||
def test_making_extra_request_raises_exception(tmpdir, httpbin):
|
||||
# make two requests in the first request that are considered
|
||||
# identical (since the match is based on method)
|
||||
with vcr.use_cassette(str(tmpdir.join('test.json')), match_on=['method']):
|
||||
urlopen(httpbin.url + '/status/200')
|
||||
urlopen(httpbin.url + '/status/201')
|
||||
with vcr.use_cassette(str(tmpdir.join("test.json")), match_on=["method"]):
|
||||
urlopen(httpbin.url + "/status/200")
|
||||
urlopen(httpbin.url + "/status/201")
|
||||
|
||||
# Now, try to make three requests. The first two should return the
|
||||
# correct status codes in order, and the third should raise an
|
||||
# exception.
|
||||
with vcr.use_cassette(str(tmpdir.join('test.json')), match_on=['method']):
|
||||
assert urlopen(httpbin.url + '/status/200').getcode() == 200
|
||||
assert urlopen(httpbin.url + '/status/201').getcode() == 201
|
||||
with vcr.use_cassette(str(tmpdir.join("test.json")), match_on=["method"]):
|
||||
assert urlopen(httpbin.url + "/status/200").getcode() == 200
|
||||
assert urlopen(httpbin.url + "/status/201").getcode() == 201
|
||||
with pytest.raises(Exception):
|
||||
urlopen(httpbin.url + '/status/200')
|
||||
urlopen(httpbin.url + "/status/200")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''Test using a proxy.'''
|
||||
"""Test using a proxy."""
|
||||
|
||||
# External imports
|
||||
import multiprocessing
|
||||
@@ -16,11 +16,12 @@ requests = pytest.importorskip("requests")
|
||||
|
||||
|
||||
class Proxy(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
'''
|
||||
"""
|
||||
Simple proxy server.
|
||||
|
||||
(Inspired by: http://effbot.org/librarybook/simplehttpserver.htm).
|
||||
'''
|
||||
"""
|
||||
|
||||
def do_GET(self):
|
||||
upstream_response = urlopen(self.path)
|
||||
try:
|
||||
@@ -37,24 +38,22 @@ class Proxy(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
self.copyfile(upstream_response, self.wfile)
|
||||
|
||||
|
||||
@pytest.yield_fixture(scope='session')
|
||||
@pytest.yield_fixture(scope="session")
|
||||
def proxy_server():
|
||||
httpd = socketserver.ThreadingTCPServer(('', 0), Proxy)
|
||||
proxy_process = multiprocessing.Process(
|
||||
target=httpd.serve_forever,
|
||||
)
|
||||
httpd = socketserver.ThreadingTCPServer(("", 0), Proxy)
|
||||
proxy_process = multiprocessing.Process(target=httpd.serve_forever)
|
||||
proxy_process.start()
|
||||
yield 'http://{}:{}'.format(*httpd.server_address)
|
||||
yield "http://{}:{}".format(*httpd.server_address)
|
||||
proxy_process.terminate()
|
||||
|
||||
|
||||
def test_use_proxy(tmpdir, httpbin, proxy_server):
|
||||
'''Ensure that it works with a proxy.'''
|
||||
with vcr.use_cassette(str(tmpdir.join('proxy.yaml'))):
|
||||
response = requests.get(httpbin.url, proxies={'http': proxy_server})
|
||||
"""Ensure that it works with a proxy."""
|
||||
with vcr.use_cassette(str(tmpdir.join("proxy.yaml"))):
|
||||
response = requests.get(httpbin.url, proxies={"http": proxy_server})
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('proxy.yaml'))) as cassette:
|
||||
cassette_response = requests.get(httpbin.url, proxies={'http': proxy_server})
|
||||
with vcr.use_cassette(str(tmpdir.join("proxy.yaml"))) as cassette:
|
||||
cassette_response = requests.get(httpbin.url, proxies={"http": proxy_server})
|
||||
|
||||
assert cassette_response.headers == response.headers
|
||||
assert cassette.play_count == 1
|
||||
|
||||
@@ -4,7 +4,7 @@ from six.moves.urllib.request import urlopen
|
||||
|
||||
|
||||
def test_once_record_mode(tmpdir, httpbin):
|
||||
testfile = str(tmpdir.join('recordmode.yml'))
|
||||
testfile = str(tmpdir.join("recordmode.yml"))
|
||||
with vcr.use_cassette(testfile, record_mode="once"):
|
||||
# cassette file doesn't exist, so create.
|
||||
urlopen(httpbin.url).read()
|
||||
@@ -17,11 +17,11 @@ def test_once_record_mode(tmpdir, httpbin):
|
||||
# but, try to access something else from the same cassette, and an
|
||||
# exception is raised.
|
||||
with pytest.raises(Exception):
|
||||
urlopen(httpbin.url + '/get').read()
|
||||
urlopen(httpbin.url + "/get").read()
|
||||
|
||||
|
||||
def test_once_record_mode_two_times(tmpdir, httpbin):
|
||||
testfile = str(tmpdir.join('recordmode.yml'))
|
||||
testfile = str(tmpdir.join("recordmode.yml"))
|
||||
with vcr.use_cassette(testfile, record_mode="once"):
|
||||
# get two of the same file
|
||||
urlopen(httpbin.url).read()
|
||||
@@ -34,7 +34,7 @@ def test_once_record_mode_two_times(tmpdir, httpbin):
|
||||
|
||||
|
||||
def test_once_mode_three_times(tmpdir, httpbin):
|
||||
testfile = str(tmpdir.join('recordmode.yml'))
|
||||
testfile = str(tmpdir.join("recordmode.yml"))
|
||||
with vcr.use_cassette(testfile, record_mode="once"):
|
||||
# get three of the same file
|
||||
urlopen(httpbin.url).read()
|
||||
@@ -43,7 +43,7 @@ def test_once_mode_three_times(tmpdir, httpbin):
|
||||
|
||||
|
||||
def test_new_episodes_record_mode(tmpdir, httpbin):
|
||||
testfile = str(tmpdir.join('recordmode.yml'))
|
||||
testfile = str(tmpdir.join("recordmode.yml"))
|
||||
|
||||
with vcr.use_cassette(testfile, record_mode="new_episodes"):
|
||||
# cassette file doesn't exist, so create.
|
||||
@@ -58,7 +58,7 @@ def test_new_episodes_record_mode(tmpdir, httpbin):
|
||||
|
||||
# in the "new_episodes" record mode, we can add more requests to
|
||||
# a cassette without repurcussions.
|
||||
urlopen(httpbin.url + '/get').read()
|
||||
urlopen(httpbin.url + "/get").read()
|
||||
|
||||
# one of the responses has been played
|
||||
assert cass.play_count == 1
|
||||
@@ -72,8 +72,8 @@ def test_new_episodes_record_mode(tmpdir, httpbin):
|
||||
|
||||
|
||||
def test_new_episodes_record_mode_two_times(tmpdir, httpbin):
|
||||
testfile = str(tmpdir.join('recordmode.yml'))
|
||||
url = httpbin.url + '/bytes/1024'
|
||||
testfile = str(tmpdir.join("recordmode.yml"))
|
||||
url = httpbin.url + "/bytes/1024"
|
||||
with vcr.use_cassette(testfile, record_mode="new_episodes"):
|
||||
# cassette file doesn't exist, so create.
|
||||
original_first_response = urlopen(url).read()
|
||||
@@ -97,7 +97,7 @@ def test_new_episodes_record_mode_two_times(tmpdir, httpbin):
|
||||
|
||||
|
||||
def test_all_record_mode(tmpdir, httpbin):
|
||||
testfile = str(tmpdir.join('recordmode.yml'))
|
||||
testfile = str(tmpdir.join("recordmode.yml"))
|
||||
|
||||
with vcr.use_cassette(testfile, record_mode="all"):
|
||||
# cassette file doesn't exist, so create.
|
||||
@@ -109,7 +109,7 @@ def test_all_record_mode(tmpdir, httpbin):
|
||||
|
||||
# in the "all" record mode, we can add more requests to
|
||||
# a cassette without repurcussions.
|
||||
urlopen(httpbin.url + '/get').read()
|
||||
urlopen(httpbin.url + "/get").read()
|
||||
|
||||
# The cassette was never actually played, even though it existed.
|
||||
# that's because, in "all" mode, the requests all go directly to
|
||||
@@ -120,7 +120,7 @@ def test_all_record_mode(tmpdir, httpbin):
|
||||
def test_none_record_mode(tmpdir, httpbin):
|
||||
# Cassette file doesn't exist, yet we are trying to make a request.
|
||||
# raise hell.
|
||||
testfile = str(tmpdir.join('recordmode.yml'))
|
||||
testfile = str(tmpdir.join("recordmode.yml"))
|
||||
with vcr.use_cassette(testfile, record_mode="none"):
|
||||
with pytest.raises(Exception):
|
||||
urlopen(httpbin.url).read()
|
||||
@@ -128,7 +128,7 @@ def test_none_record_mode(tmpdir, httpbin):
|
||||
|
||||
def test_none_record_mode_with_existing_cassette(tmpdir, httpbin):
|
||||
# create a cassette file
|
||||
testfile = str(tmpdir.join('recordmode.yml'))
|
||||
testfile = str(tmpdir.join("recordmode.yml"))
|
||||
|
||||
with vcr.use_cassette(testfile, record_mode="all"):
|
||||
urlopen(httpbin.url).read()
|
||||
@@ -139,4 +139,4 @@ def test_none_record_mode_with_existing_cassette(tmpdir, httpbin):
|
||||
assert cass.play_count == 1
|
||||
# but if I try to hit the net, raise an exception.
|
||||
with pytest.raises(Exception):
|
||||
urlopen(httpbin.url + '/get').read()
|
||||
urlopen(httpbin.url + "/get").read()
|
||||
|
||||
@@ -12,25 +12,25 @@ def false_matcher(r1, r2):
|
||||
|
||||
def test_registered_true_matcher(tmpdir, httpbin):
|
||||
my_vcr = vcr.VCR()
|
||||
my_vcr.register_matcher('true', true_matcher)
|
||||
testfile = str(tmpdir.join('test.yml'))
|
||||
with my_vcr.use_cassette(testfile, match_on=['true']):
|
||||
my_vcr.register_matcher("true", true_matcher)
|
||||
testfile = str(tmpdir.join("test.yml"))
|
||||
with my_vcr.use_cassette(testfile, match_on=["true"]):
|
||||
# These 2 different urls are stored as the same request
|
||||
urlopen(httpbin.url)
|
||||
urlopen(httpbin.url + '/get')
|
||||
urlopen(httpbin.url + "/get")
|
||||
|
||||
with my_vcr.use_cassette(testfile, match_on=['true']):
|
||||
with my_vcr.use_cassette(testfile, match_on=["true"]):
|
||||
# I can get the response twice even though I only asked for it once
|
||||
urlopen(httpbin.url + '/get')
|
||||
urlopen(httpbin.url + '/get')
|
||||
urlopen(httpbin.url + "/get")
|
||||
urlopen(httpbin.url + "/get")
|
||||
|
||||
|
||||
def test_registered_false_matcher(tmpdir, httpbin):
|
||||
my_vcr = vcr.VCR()
|
||||
my_vcr.register_matcher('false', false_matcher)
|
||||
testfile = str(tmpdir.join('test.yml'))
|
||||
with my_vcr.use_cassette(testfile, match_on=['false']) as cass:
|
||||
my_vcr.register_matcher("false", false_matcher)
|
||||
testfile = str(tmpdir.join("test.yml"))
|
||||
with my_vcr.use_cassette(testfile, match_on=["false"]) as cass:
|
||||
# These 2 different urls are stored as different requests
|
||||
urlopen(httpbin.url)
|
||||
urlopen(httpbin.url + '/get')
|
||||
urlopen(httpbin.url + "/get")
|
||||
assert len(cass) == 2
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''Tests for cassettes with custom persistence'''
|
||||
"""Tests for cassettes with custom persistence"""
|
||||
|
||||
# External imports
|
||||
import os
|
||||
@@ -11,45 +11,45 @@ from vcr.persisters.filesystem import FilesystemPersister
|
||||
|
||||
|
||||
class CustomFilesystemPersister(object):
|
||||
'''Behaves just like default FilesystemPersister but adds .test extension
|
||||
to the cassette file'''
|
||||
"""Behaves just like default FilesystemPersister but adds .test extension
|
||||
to the cassette file"""
|
||||
|
||||
@staticmethod
|
||||
def load_cassette(cassette_path, serializer):
|
||||
cassette_path += '.test'
|
||||
cassette_path += ".test"
|
||||
return FilesystemPersister.load_cassette(cassette_path, serializer)
|
||||
|
||||
@staticmethod
|
||||
def save_cassette(cassette_path, cassette_dict, serializer):
|
||||
cassette_path += '.test'
|
||||
FilesystemPersister.save_cassette(cassette_path, cassette_dict,
|
||||
serializer)
|
||||
cassette_path += ".test"
|
||||
FilesystemPersister.save_cassette(cassette_path, cassette_dict, serializer)
|
||||
|
||||
|
||||
def test_save_cassette_with_custom_persister(tmpdir, httpbin):
|
||||
'''Ensure you can save a cassette using custom persister'''
|
||||
"""Ensure you can save a cassette using custom persister"""
|
||||
my_vcr = vcr.VCR()
|
||||
my_vcr.register_persister(CustomFilesystemPersister)
|
||||
|
||||
# Check to make sure directory doesnt exist
|
||||
assert not os.path.exists(str(tmpdir.join('nonexistent')))
|
||||
assert not os.path.exists(str(tmpdir.join("nonexistent")))
|
||||
|
||||
# Run VCR to create dir and cassette file using new save_cassette callback
|
||||
with my_vcr.use_cassette(str(tmpdir.join('nonexistent', 'cassette.yml'))):
|
||||
with my_vcr.use_cassette(str(tmpdir.join("nonexistent", "cassette.yml"))):
|
||||
urlopen(httpbin.url).read()
|
||||
|
||||
# Callback should have made the file and the directory
|
||||
assert os.path.exists(str(tmpdir.join('nonexistent', 'cassette.yml.test')))
|
||||
assert os.path.exists(str(tmpdir.join("nonexistent", "cassette.yml.test")))
|
||||
|
||||
|
||||
def test_load_cassette_with_custom_persister(tmpdir, httpbin):
|
||||
'''
|
||||
"""
|
||||
Ensure you can load a cassette using custom persister
|
||||
'''
|
||||
"""
|
||||
my_vcr = vcr.VCR()
|
||||
my_vcr.register_persister(CustomFilesystemPersister)
|
||||
|
||||
test_fixture = str(tmpdir.join('synopsis.json.test'))
|
||||
test_fixture = str(tmpdir.join("synopsis.json.test"))
|
||||
|
||||
with my_vcr.use_cassette(test_fixture, serializer='json'):
|
||||
with my_vcr.use_cassette(test_fixture, serializer="json"):
|
||||
response = urlopen(httpbin.url).read()
|
||||
assert b'difficult sometimes' in response
|
||||
assert b"difficult sometimes" in response
|
||||
|
||||
@@ -10,7 +10,7 @@ class MockSerializer(object):
|
||||
def deserialize(self, cassette_string):
|
||||
self.serialize_count += 1
|
||||
self.cassette_string = cassette_string
|
||||
return {'interactions': []}
|
||||
return {"interactions": []}
|
||||
|
||||
def serialize(self, cassette_dict):
|
||||
self.deserialize_count += 1
|
||||
@@ -20,13 +20,13 @@ class MockSerializer(object):
|
||||
def test_registered_serializer(tmpdir):
|
||||
ms = MockSerializer()
|
||||
my_vcr = vcr.VCR()
|
||||
my_vcr.register_serializer('mock', ms)
|
||||
tmpdir.join('test.mock').write('test_data')
|
||||
with my_vcr.use_cassette(str(tmpdir.join('test.mock')), serializer='mock'):
|
||||
my_vcr.register_serializer("mock", ms)
|
||||
tmpdir.join("test.mock").write("test_data")
|
||||
with my_vcr.use_cassette(str(tmpdir.join("test.mock")), serializer="mock"):
|
||||
# Serializer deserialized once
|
||||
assert ms.serialize_count == 1
|
||||
# and serialized the test data string
|
||||
assert ms.cassette_string == 'test_data'
|
||||
assert ms.cassette_string == "test_data"
|
||||
# and hasn't serialized yet
|
||||
assert ms.deserialize_count == 0
|
||||
|
||||
|
||||
@@ -3,17 +3,17 @@ from six.moves.urllib.request import urlopen
|
||||
|
||||
|
||||
def test_recorded_request_uri_with_redirected_request(tmpdir, httpbin):
|
||||
with vcr.use_cassette(str(tmpdir.join('test.yml'))) as cass:
|
||||
with vcr.use_cassette(str(tmpdir.join("test.yml"))) as cass:
|
||||
assert len(cass) == 0
|
||||
urlopen(httpbin.url + '/redirect/3')
|
||||
assert cass.requests[0].uri == httpbin.url + '/redirect/3'
|
||||
assert cass.requests[3].uri == httpbin.url + '/get'
|
||||
urlopen(httpbin.url + "/redirect/3")
|
||||
assert cass.requests[0].uri == httpbin.url + "/redirect/3"
|
||||
assert cass.requests[3].uri == httpbin.url + "/get"
|
||||
assert len(cass) == 4
|
||||
|
||||
|
||||
def test_records_multiple_header_values(tmpdir, httpbin):
|
||||
with vcr.use_cassette(str(tmpdir.join('test.yml'))) as cass:
|
||||
with vcr.use_cassette(str(tmpdir.join("test.yml"))) as cass:
|
||||
assert len(cass) == 0
|
||||
urlopen(httpbin.url + '/response-headers?foo=bar&foo=baz')
|
||||
urlopen(httpbin.url + "/response-headers?foo=bar&foo=baz")
|
||||
assert len(cass) == 1
|
||||
assert cass.responses[0]['headers']['foo'] == ['bar', 'baz']
|
||||
assert cass.responses[0]["headers"]["foo"] == ["bar", "baz"]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''Test requests' interaction with vcr'''
|
||||
"""Test requests' interaction with vcr"""
|
||||
import platform
|
||||
import pytest
|
||||
import sys
|
||||
@@ -11,76 +11,76 @@ from requests.exceptions import ConnectionError # noqa E402
|
||||
|
||||
|
||||
def test_status_code(httpbin_both, tmpdir):
|
||||
'''Ensure that we can read the status code'''
|
||||
url = httpbin_both.url + '/'
|
||||
with vcr.use_cassette(str(tmpdir.join('atts.yaml'))):
|
||||
"""Ensure that we can read the status code"""
|
||||
url = httpbin_both.url + "/"
|
||||
with vcr.use_cassette(str(tmpdir.join("atts.yaml"))):
|
||||
status_code = requests.get(url).status_code
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('atts.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("atts.yaml"))):
|
||||
assert status_code == requests.get(url).status_code
|
||||
|
||||
|
||||
def test_headers(httpbin_both, tmpdir):
|
||||
'''Ensure that we can read the headers back'''
|
||||
url = httpbin_both + '/'
|
||||
with vcr.use_cassette(str(tmpdir.join('headers.yaml'))):
|
||||
"""Ensure that we can read the headers back"""
|
||||
url = httpbin_both + "/"
|
||||
with vcr.use_cassette(str(tmpdir.join("headers.yaml"))):
|
||||
headers = requests.get(url).headers
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('headers.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("headers.yaml"))):
|
||||
assert headers == requests.get(url).headers
|
||||
|
||||
|
||||
def test_body(tmpdir, httpbin_both):
|
||||
'''Ensure the responses are all identical enough'''
|
||||
url = httpbin_both + '/bytes/1024'
|
||||
with vcr.use_cassette(str(tmpdir.join('body.yaml'))):
|
||||
"""Ensure the responses are all identical enough"""
|
||||
url = httpbin_both + "/bytes/1024"
|
||||
with vcr.use_cassette(str(tmpdir.join("body.yaml"))):
|
||||
content = requests.get(url).content
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('body.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("body.yaml"))):
|
||||
assert content == requests.get(url).content
|
||||
|
||||
|
||||
def test_get_empty_content_type_json(tmpdir, httpbin_both):
|
||||
'''Ensure GET with application/json content-type and empty request body doesn't crash'''
|
||||
url = httpbin_both + '/status/200'
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
"""Ensure GET with application/json content-type and empty request body doesn't crash"""
|
||||
url = httpbin_both + "/status/200"
|
||||
headers = {"Content-Type": "application/json"}
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('get_empty_json.yaml')), match_on=('body',)):
|
||||
with vcr.use_cassette(str(tmpdir.join("get_empty_json.yaml")), match_on=("body",)):
|
||||
status = requests.get(url, headers=headers).status_code
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('get_empty_json.yaml')), match_on=('body',)):
|
||||
with vcr.use_cassette(str(tmpdir.join("get_empty_json.yaml")), match_on=("body",)):
|
||||
assert status == requests.get(url, headers=headers).status_code
|
||||
|
||||
|
||||
def test_effective_url(tmpdir, httpbin_both):
|
||||
'''Ensure that the effective_url is captured'''
|
||||
url = httpbin_both.url + '/redirect-to?url=/html'
|
||||
with vcr.use_cassette(str(tmpdir.join('url.yaml'))):
|
||||
"""Ensure that the effective_url is captured"""
|
||||
url = httpbin_both.url + "/redirect-to?url=/html"
|
||||
with vcr.use_cassette(str(tmpdir.join("url.yaml"))):
|
||||
effective_url = requests.get(url).url
|
||||
assert effective_url == httpbin_both.url + '/html'
|
||||
assert effective_url == httpbin_both.url + "/html"
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('url.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("url.yaml"))):
|
||||
assert effective_url == requests.get(url).url
|
||||
|
||||
|
||||
def test_auth(tmpdir, httpbin_both):
|
||||
'''Ensure that we can handle basic auth'''
|
||||
auth = ('user', 'passwd')
|
||||
url = httpbin_both + '/basic-auth/user/passwd'
|
||||
with vcr.use_cassette(str(tmpdir.join('auth.yaml'))):
|
||||
"""Ensure that we can handle basic auth"""
|
||||
auth = ("user", "passwd")
|
||||
url = httpbin_both + "/basic-auth/user/passwd"
|
||||
with vcr.use_cassette(str(tmpdir.join("auth.yaml"))):
|
||||
one = requests.get(url, auth=auth)
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('auth.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("auth.yaml"))):
|
||||
two = requests.get(url, auth=auth)
|
||||
assert one.content == two.content
|
||||
assert one.status_code == two.status_code
|
||||
|
||||
|
||||
def test_auth_failed(tmpdir, httpbin_both):
|
||||
'''Ensure that we can save failed auth statuses'''
|
||||
auth = ('user', 'wrongwrongwrong')
|
||||
url = httpbin_both + '/basic-auth/user/passwd'
|
||||
with vcr.use_cassette(str(tmpdir.join('auth-failed.yaml'))) as cass:
|
||||
"""Ensure that we can save failed auth statuses"""
|
||||
auth = ("user", "wrongwrongwrong")
|
||||
url = httpbin_both + "/basic-auth/user/passwd"
|
||||
with vcr.use_cassette(str(tmpdir.join("auth-failed.yaml"))) as cass:
|
||||
# Ensure that this is empty to begin with
|
||||
assert_cassette_empty(cass)
|
||||
one = requests.get(url, auth=auth)
|
||||
@@ -90,58 +90,59 @@ def test_auth_failed(tmpdir, httpbin_both):
|
||||
|
||||
|
||||
def test_post(tmpdir, httpbin_both):
|
||||
'''Ensure that we can post and cache the results'''
|
||||
data = {'key1': 'value1', 'key2': 'value2'}
|
||||
url = httpbin_both + '/post'
|
||||
with vcr.use_cassette(str(tmpdir.join('requests.yaml'))):
|
||||
"""Ensure that we can post and cache the results"""
|
||||
data = {"key1": "value1", "key2": "value2"}
|
||||
url = httpbin_both + "/post"
|
||||
with vcr.use_cassette(str(tmpdir.join("requests.yaml"))):
|
||||
req1 = requests.post(url, data).content
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('requests.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("requests.yaml"))):
|
||||
req2 = requests.post(url, data).content
|
||||
|
||||
assert req1 == req2
|
||||
|
||||
|
||||
def test_post_chunked_binary(tmpdir, httpbin):
|
||||
'''Ensure that we can send chunked binary without breaking while trying to concatenate bytes with str.'''
|
||||
data1 = iter([b'data', b'to', b'send'])
|
||||
data2 = iter([b'data', b'to', b'send'])
|
||||
url = httpbin.url + '/post'
|
||||
with vcr.use_cassette(str(tmpdir.join('requests.yaml'))):
|
||||
"""Ensure that we can send chunked binary without breaking while trying to concatenate bytes with str."""
|
||||
data1 = iter([b"data", b"to", b"send"])
|
||||
data2 = iter([b"data", b"to", b"send"])
|
||||
url = httpbin.url + "/post"
|
||||
with vcr.use_cassette(str(tmpdir.join("requests.yaml"))):
|
||||
req1 = requests.post(url, data1).content
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('requests.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("requests.yaml"))):
|
||||
req2 = requests.post(url, data2).content
|
||||
|
||||
assert req1 == req2
|
||||
|
||||
|
||||
@pytest.mark.skipif('sys.version_info >= (3, 6)', strict=True, raises=ConnectionError)
|
||||
@pytest.mark.skipif((3, 5) < sys.version_info < (3, 6) and
|
||||
platform.python_implementation() == 'CPython',
|
||||
reason='Fails on CPython 3.5')
|
||||
@pytest.mark.skipif("sys.version_info >= (3, 6)", strict=True, raises=ConnectionError)
|
||||
@pytest.mark.skipif(
|
||||
(3, 5) < sys.version_info < (3, 6) and platform.python_implementation() == "CPython",
|
||||
reason="Fails on CPython 3.5",
|
||||
)
|
||||
def test_post_chunked_binary_secure(tmpdir, httpbin_secure):
|
||||
'''Ensure that we can send chunked binary without breaking while trying to concatenate bytes with str.'''
|
||||
data1 = iter([b'data', b'to', b'send'])
|
||||
data2 = iter([b'data', b'to', b'send'])
|
||||
url = httpbin_secure.url + '/post'
|
||||
with vcr.use_cassette(str(tmpdir.join('requests.yaml'))):
|
||||
"""Ensure that we can send chunked binary without breaking while trying to concatenate bytes with str."""
|
||||
data1 = iter([b"data", b"to", b"send"])
|
||||
data2 = iter([b"data", b"to", b"send"])
|
||||
url = httpbin_secure.url + "/post"
|
||||
with vcr.use_cassette(str(tmpdir.join("requests.yaml"))):
|
||||
req1 = requests.post(url, data1).content
|
||||
print(req1)
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('requests.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("requests.yaml"))):
|
||||
req2 = requests.post(url, data2).content
|
||||
|
||||
assert req1 == req2
|
||||
|
||||
|
||||
def test_redirects(tmpdir, httpbin_both):
|
||||
'''Ensure that we can handle redirects'''
|
||||
url = httpbin_both + '/redirect-to?url=bytes/1024'
|
||||
with vcr.use_cassette(str(tmpdir.join('requests.yaml'))):
|
||||
"""Ensure that we can handle redirects"""
|
||||
url = httpbin_both + "/redirect-to?url=bytes/1024"
|
||||
with vcr.use_cassette(str(tmpdir.join("requests.yaml"))):
|
||||
content = requests.get(url).content
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('requests.yaml'))) as cass:
|
||||
with vcr.use_cassette(str(tmpdir.join("requests.yaml"))) as cass:
|
||||
assert content == requests.get(url).content
|
||||
# Ensure that we've now cached *two* responses. One for the redirect
|
||||
# and one for the final fetch
|
||||
@@ -150,149 +151,151 @@ def test_redirects(tmpdir, httpbin_both):
|
||||
|
||||
|
||||
def test_cross_scheme(tmpdir, httpbin_secure, httpbin):
|
||||
'''Ensure that requests between schemes are treated separately'''
|
||||
"""Ensure that requests between schemes are treated separately"""
|
||||
# First fetch a url under http, and then again under https and then
|
||||
# ensure that we haven't served anything out of cache, and we have two
|
||||
# requests / response pairs in the cassette
|
||||
with vcr.use_cassette(str(tmpdir.join('cross_scheme.yaml'))) as cass:
|
||||
requests.get(httpbin_secure + '/')
|
||||
requests.get(httpbin + '/')
|
||||
with vcr.use_cassette(str(tmpdir.join("cross_scheme.yaml"))) as cass:
|
||||
requests.get(httpbin_secure + "/")
|
||||
requests.get(httpbin + "/")
|
||||
assert cass.play_count == 0
|
||||
assert len(cass) == 2
|
||||
|
||||
|
||||
def test_gzip(tmpdir, httpbin_both):
|
||||
'''
|
||||
"""
|
||||
Ensure that requests (actually urllib3) is able to automatically decompress
|
||||
the response body
|
||||
'''
|
||||
url = httpbin_both + '/gzip'
|
||||
"""
|
||||
url = httpbin_both + "/gzip"
|
||||
response = requests.get(url)
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('gzip.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("gzip.yaml"))):
|
||||
response = requests.get(url)
|
||||
assert_is_json(response.content)
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('gzip.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("gzip.yaml"))):
|
||||
assert_is_json(response.content)
|
||||
|
||||
|
||||
def test_session_and_connection_close(tmpdir, httpbin):
|
||||
'''
|
||||
"""
|
||||
This tests the issue in https://github.com/kevin1024/vcrpy/issues/48
|
||||
|
||||
If you use a requests.session and the connection is closed, then an
|
||||
exception is raised in the urllib3 module vendored into requests:
|
||||
`AttributeError: 'NoneType' object has no attribute 'settimeout'`
|
||||
'''
|
||||
with vcr.use_cassette(str(tmpdir.join('session_connection_closed.yaml'))):
|
||||
"""
|
||||
with vcr.use_cassette(str(tmpdir.join("session_connection_closed.yaml"))):
|
||||
session = requests.session()
|
||||
|
||||
session.get(httpbin + '/get', headers={'Connection': 'close'})
|
||||
session.get(httpbin + '/get', headers={'Connection': 'close'})
|
||||
session.get(httpbin + "/get", headers={"Connection": "close"})
|
||||
session.get(httpbin + "/get", headers={"Connection": "close"})
|
||||
|
||||
|
||||
def test_https_with_cert_validation_disabled(tmpdir, httpbin_secure):
|
||||
with vcr.use_cassette(str(tmpdir.join('cert_validation_disabled.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("cert_validation_disabled.yaml"))):
|
||||
requests.get(httpbin_secure.url, verify=False)
|
||||
|
||||
|
||||
def test_session_can_make_requests_after_requests_unpatched(tmpdir, httpbin):
|
||||
with vcr.use_cassette(str(tmpdir.join('test_session_after_unpatched.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("test_session_after_unpatched.yaml"))):
|
||||
session = requests.session()
|
||||
session.get(httpbin + '/get')
|
||||
session.get(httpbin + "/get")
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('test_session_after_unpatched.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("test_session_after_unpatched.yaml"))):
|
||||
session = requests.session()
|
||||
session.get(httpbin + '/get')
|
||||
session.get(httpbin + "/get")
|
||||
|
||||
session.get(httpbin + '/status/200')
|
||||
session.get(httpbin + "/status/200")
|
||||
|
||||
|
||||
def test_session_created_before_use_cassette_is_patched(tmpdir, httpbin_both):
|
||||
url = httpbin_both + '/bytes/1024'
|
||||
url = httpbin_both + "/bytes/1024"
|
||||
# Record arbitrary, random data to the cassette
|
||||
with vcr.use_cassette(str(tmpdir.join('session_created_outside.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("session_created_outside.yaml"))):
|
||||
session = requests.session()
|
||||
body = session.get(url).content
|
||||
|
||||
# Create a session outside of any cassette context manager
|
||||
session = requests.session()
|
||||
# Make a request to make sure that a connectionpool is instantiated
|
||||
session.get(httpbin_both + '/get')
|
||||
session.get(httpbin_both + "/get")
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('session_created_outside.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("session_created_outside.yaml"))):
|
||||
# These should only be the same if the patching succeeded.
|
||||
assert session.get(url).content == body
|
||||
|
||||
|
||||
def test_nested_cassettes_with_session_created_before_nesting(httpbin_both, tmpdir):
|
||||
'''
|
||||
"""
|
||||
This tests ensures that a session that was created while one cassette was
|
||||
active is patched to the use the responses of a second cassette when it
|
||||
is enabled.
|
||||
'''
|
||||
url = httpbin_both + '/bytes/1024'
|
||||
with vcr.use_cassette(str(tmpdir.join('first_nested.yaml'))):
|
||||
"""
|
||||
url = httpbin_both + "/bytes/1024"
|
||||
with vcr.use_cassette(str(tmpdir.join("first_nested.yaml"))):
|
||||
session = requests.session()
|
||||
first_body = session.get(url).content
|
||||
with vcr.use_cassette(str(tmpdir.join('second_nested.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("second_nested.yaml"))):
|
||||
second_body = session.get(url).content
|
||||
third_body = requests.get(url).content
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('second_nested.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("second_nested.yaml"))):
|
||||
session = requests.session()
|
||||
assert session.get(url).content == second_body
|
||||
with vcr.use_cassette(str(tmpdir.join('first_nested.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("first_nested.yaml"))):
|
||||
assert session.get(url).content == first_body
|
||||
assert session.get(url).content == third_body
|
||||
|
||||
# Make sure that the session can now get content normally.
|
||||
assert 'User-agent' in session.get(httpbin_both.url + '/robots.txt').text
|
||||
assert "User-agent" in session.get(httpbin_both.url + "/robots.txt").text
|
||||
|
||||
|
||||
def test_post_file(tmpdir, httpbin_both):
|
||||
'''Ensure that we handle posting a file.'''
|
||||
url = httpbin_both + '/post'
|
||||
with vcr.use_cassette(str(tmpdir.join('post_file.yaml'))) as cass, open('tox.ini', 'rb') as f:
|
||||
"""Ensure that we handle posting a file."""
|
||||
url = httpbin_both + "/post"
|
||||
with vcr.use_cassette(str(tmpdir.join("post_file.yaml"))) as cass, open("tox.ini", "rb") as f:
|
||||
original_response = requests.post(url, f).content
|
||||
|
||||
# This also tests that we do the right thing with matching the body when they are files.
|
||||
with vcr.use_cassette(str(tmpdir.join('post_file.yaml')),
|
||||
match_on=('method', 'scheme', 'host', 'port', 'path', 'query', 'body')) as cass:
|
||||
with open('tox.ini', 'rb') as f:
|
||||
with vcr.use_cassette(
|
||||
str(tmpdir.join("post_file.yaml")),
|
||||
match_on=("method", "scheme", "host", "port", "path", "query", "body"),
|
||||
) as cass:
|
||||
with open("tox.ini", "rb") as f:
|
||||
tox_content = f.read()
|
||||
assert cass.requests[0].body.read() == tox_content
|
||||
with open('tox.ini', 'rb') as f:
|
||||
with open("tox.ini", "rb") as f:
|
||||
new_response = requests.post(url, f).content
|
||||
assert original_response == new_response
|
||||
|
||||
|
||||
def test_filter_post_params(tmpdir, httpbin_both):
|
||||
'''
|
||||
"""
|
||||
This tests the issue in https://github.com/kevin1024/vcrpy/issues/158
|
||||
|
||||
Ensure that a post request made through requests can still be filtered.
|
||||
with vcr.use_cassette(cass_file, filter_post_data_parameters=['id']) as cass:
|
||||
assert b'id=secret' not in cass.requests[0].body
|
||||
'''
|
||||
url = httpbin_both.url + '/post'
|
||||
cass_loc = str(tmpdir.join('filter_post_params.yaml'))
|
||||
with vcr.use_cassette(cass_loc, filter_post_data_parameters=['key']) as cass:
|
||||
requests.post(url, data={'key': 'value'})
|
||||
with vcr.use_cassette(cass_loc, filter_post_data_parameters=['key']) as cass:
|
||||
assert b'key=value' not in cass.requests[0].body
|
||||
"""
|
||||
url = httpbin_both.url + "/post"
|
||||
cass_loc = str(tmpdir.join("filter_post_params.yaml"))
|
||||
with vcr.use_cassette(cass_loc, filter_post_data_parameters=["key"]) as cass:
|
||||
requests.post(url, data={"key": "value"})
|
||||
with vcr.use_cassette(cass_loc, filter_post_data_parameters=["key"]) as cass:
|
||||
assert b"key=value" not in cass.requests[0].body
|
||||
|
||||
|
||||
def test_post_unicode_match_on_body(tmpdir, httpbin_both):
|
||||
'''Ensure that matching on POST body that contains Unicode characters works.'''
|
||||
data = {'key1': 'value1', '●‿●': '٩(●̮̮̃•̃)۶'}
|
||||
url = httpbin_both + '/post'
|
||||
"""Ensure that matching on POST body that contains Unicode characters works."""
|
||||
data = {"key1": "value1", "●‿●": "٩(●̮̮̃•̃)۶"}
|
||||
url = httpbin_both + "/post"
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('requests.yaml')), additional_matchers=('body',)):
|
||||
with vcr.use_cassette(str(tmpdir.join("requests.yaml")), additional_matchers=("body",)):
|
||||
req1 = requests.post(url, data).content
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('requests.yaml')), additional_matchers=('body',)):
|
||||
with vcr.use_cassette(str(tmpdir.join("requests.yaml")), additional_matchers=("body",)):
|
||||
req2 = requests.post(url, data).content
|
||||
|
||||
assert req1 == req2
|
||||
|
||||
@@ -8,18 +8,18 @@ from assertions import assert_is_json
|
||||
|
||||
def _headers_are_case_insensitive(host, port):
|
||||
conn = httplib.HTTPConnection(host, port)
|
||||
conn.request('GET', "/cookies/set?k1=v1")
|
||||
conn.request("GET", "/cookies/set?k1=v1")
|
||||
r1 = conn.getresponse()
|
||||
cookie_data1 = r1.getheader('set-cookie')
|
||||
cookie_data1 = r1.getheader("set-cookie")
|
||||
conn = httplib.HTTPConnection(host, port)
|
||||
conn.request('GET', "/cookies/set?k1=v1")
|
||||
conn.request("GET", "/cookies/set?k1=v1")
|
||||
r2 = conn.getresponse()
|
||||
cookie_data2 = r2.getheader('Set-Cookie')
|
||||
cookie_data2 = r2.getheader("Set-Cookie")
|
||||
return cookie_data1 == cookie_data2
|
||||
|
||||
|
||||
def test_case_insensitivity(tmpdir, httpbin):
|
||||
testfile = str(tmpdir.join('case_insensitivity.yml'))
|
||||
testfile = str(tmpdir.join("case_insensitivity.yml"))
|
||||
# check if headers are case insensitive outside of vcrpy
|
||||
host, port = httpbin.host, httpbin.port
|
||||
outside = _headers_are_case_insensitive(host, port)
|
||||
@@ -35,13 +35,13 @@ def test_case_insensitivity(tmpdir, httpbin):
|
||||
|
||||
def _multiple_header_value(httpbin):
|
||||
conn = httplib.HTTPConnection(httpbin.host, httpbin.port)
|
||||
conn.request('GET', "/response-headers?foo=bar&foo=baz")
|
||||
conn.request("GET", "/response-headers?foo=bar&foo=baz")
|
||||
r = conn.getresponse()
|
||||
return r.getheader('foo')
|
||||
return r.getheader("foo")
|
||||
|
||||
|
||||
def test_multiple_headers(tmpdir, httpbin):
|
||||
testfile = str(tmpdir.join('multiple_headers.yaml'))
|
||||
testfile = str(tmpdir.join("multiple_headers.yaml"))
|
||||
outside = _multiple_header_value(httpbin)
|
||||
|
||||
with vcr.use_cassette(testfile):
|
||||
@@ -51,83 +51,84 @@ def test_multiple_headers(tmpdir, httpbin):
|
||||
|
||||
|
||||
def test_original_decoded_response_is_not_modified(tmpdir, httpbin):
|
||||
testfile = str(tmpdir.join('decoded_response.yml'))
|
||||
testfile = str(tmpdir.join("decoded_response.yml"))
|
||||
host, port = httpbin.host, httpbin.port
|
||||
|
||||
conn = httplib.HTTPConnection(host, port)
|
||||
conn.request('GET', '/gzip')
|
||||
conn.request("GET", "/gzip")
|
||||
outside = conn.getresponse()
|
||||
|
||||
with vcr.use_cassette(testfile, decode_compressed_response=True):
|
||||
conn = httplib.HTTPConnection(host, port)
|
||||
conn.request('GET', '/gzip')
|
||||
conn.request("GET", "/gzip")
|
||||
inside = conn.getresponse()
|
||||
|
||||
# Assert that we do not modify the original response while appending
|
||||
# to the casssette.
|
||||
assert 'gzip' == inside.headers['content-encoding']
|
||||
assert "gzip" == inside.headers["content-encoding"]
|
||||
|
||||
# They should effectively be the same response.
|
||||
inside_headers = (h for h in inside.headers.items() if h[0].lower() != 'date')
|
||||
outside_headers = (h for h in outside.getheaders() if h[0].lower() != 'date')
|
||||
inside_headers = (h for h in inside.headers.items() if h[0].lower() != "date")
|
||||
outside_headers = (h for h in outside.getheaders() if h[0].lower() != "date")
|
||||
assert set(inside_headers) == set(outside_headers)
|
||||
inside = zlib.decompress(inside.read(), 16+zlib.MAX_WBITS)
|
||||
outside = zlib.decompress(outside.read(), 16+zlib.MAX_WBITS)
|
||||
inside = zlib.decompress(inside.read(), 16 + zlib.MAX_WBITS)
|
||||
outside = zlib.decompress(outside.read(), 16 + zlib.MAX_WBITS)
|
||||
assert inside == outside
|
||||
|
||||
# Even though the above are raw bytes, the JSON data should have been
|
||||
# decoded and saved to the cassette.
|
||||
with vcr.use_cassette(testfile):
|
||||
conn = httplib.HTTPConnection(host, port)
|
||||
conn.request('GET', '/gzip')
|
||||
conn.request("GET", "/gzip")
|
||||
inside = conn.getresponse()
|
||||
|
||||
assert 'content-encoding' not in inside.headers
|
||||
assert "content-encoding" not in inside.headers
|
||||
assert_is_json(inside.read())
|
||||
|
||||
|
||||
def _make_before_record_response(fields, replacement='[REDACTED]'):
|
||||
def _make_before_record_response(fields, replacement="[REDACTED]"):
|
||||
def before_record_response(response):
|
||||
string_body = response['body']['string'].decode('utf8')
|
||||
string_body = response["body"]["string"].decode("utf8")
|
||||
body = json.loads(string_body)
|
||||
|
||||
for field in fields:
|
||||
if field in body:
|
||||
body[field] = replacement
|
||||
|
||||
response['body']['string'] = json.dumps(body).encode()
|
||||
response["body"]["string"] = json.dumps(body).encode()
|
||||
return response
|
||||
|
||||
return before_record_response
|
||||
|
||||
|
||||
def test_original_response_is_not_modified_by_before_filter(tmpdir, httpbin):
|
||||
testfile = str(tmpdir.join('sensitive_data_scrubbed_response.yml'))
|
||||
testfile = str(tmpdir.join("sensitive_data_scrubbed_response.yml"))
|
||||
host, port = httpbin.host, httpbin.port
|
||||
field_to_scrub = 'url'
|
||||
replacement = '[YOU_CANT_HAVE_THE_MANGO]'
|
||||
field_to_scrub = "url"
|
||||
replacement = "[YOU_CANT_HAVE_THE_MANGO]"
|
||||
|
||||
conn = httplib.HTTPConnection(host, port)
|
||||
conn.request('GET', '/get')
|
||||
conn.request("GET", "/get")
|
||||
outside = conn.getresponse()
|
||||
|
||||
callback = _make_before_record_response([field_to_scrub], replacement)
|
||||
with vcr.use_cassette(testfile, before_record_response=callback):
|
||||
conn = httplib.HTTPConnection(host, port)
|
||||
conn.request('GET', '/get')
|
||||
conn.request("GET", "/get")
|
||||
inside = conn.getresponse()
|
||||
|
||||
# The scrubbed field should be the same, because no cassette existed.
|
||||
# Furthermore, the responses should be identical.
|
||||
inside_body = json.loads(inside.read().decode('utf-8'))
|
||||
outside_body = json.loads(outside.read().decode('utf-8'))
|
||||
inside_body = json.loads(inside.read().decode("utf-8"))
|
||||
outside_body = json.loads(outside.read().decode("utf-8"))
|
||||
assert not inside_body[field_to_scrub] == replacement
|
||||
assert inside_body[field_to_scrub] == outside_body[field_to_scrub]
|
||||
|
||||
# Ensure that when a cassette exists, the scrubbed response is returned.
|
||||
with vcr.use_cassette(testfile, before_record_response=callback):
|
||||
conn = httplib.HTTPConnection(host, port)
|
||||
conn.request('GET', '/get')
|
||||
conn.request("GET", "/get")
|
||||
inside = conn.getresponse()
|
||||
|
||||
inside_body = json.loads(inside.read().decode('utf-8'))
|
||||
inside_body = json.loads(inside.read().decode("utf-8"))
|
||||
assert inside_body[field_to_scrub] == replacement
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''Test requests' interaction with vcr'''
|
||||
"""Test requests' interaction with vcr"""
|
||||
|
||||
import json
|
||||
|
||||
@@ -17,105 +17,99 @@ http = pytest.importorskip("tornado.httpclient")
|
||||
supports_raise_error = tornado.version_info >= (4,)
|
||||
|
||||
|
||||
@pytest.fixture(params=['simple', 'curl', 'default'])
|
||||
@pytest.fixture(params=["simple", "curl", "default"])
|
||||
def get_client(request):
|
||||
if request.param == 'simple':
|
||||
if request.param == "simple":
|
||||
from tornado import simple_httpclient as simple
|
||||
return (lambda: simple.SimpleAsyncHTTPClient())
|
||||
elif request.param == 'curl':
|
||||
|
||||
return lambda: simple.SimpleAsyncHTTPClient()
|
||||
elif request.param == "curl":
|
||||
curl = pytest.importorskip("tornado.curl_httpclient")
|
||||
return (lambda: curl.CurlAsyncHTTPClient())
|
||||
return lambda: curl.CurlAsyncHTTPClient()
|
||||
else:
|
||||
return (lambda: http.AsyncHTTPClient())
|
||||
return lambda: http.AsyncHTTPClient()
|
||||
|
||||
|
||||
def get(client, url, **kwargs):
|
||||
fetch_kwargs = {}
|
||||
if supports_raise_error:
|
||||
fetch_kwargs['raise_error'] = kwargs.pop('raise_error', True)
|
||||
fetch_kwargs["raise_error"] = kwargs.pop("raise_error", True)
|
||||
|
||||
return client.fetch(
|
||||
http.HTTPRequest(url, method='GET', **kwargs),
|
||||
**fetch_kwargs
|
||||
)
|
||||
return client.fetch(http.HTTPRequest(url, method="GET", **kwargs), **fetch_kwargs)
|
||||
|
||||
|
||||
def post(client, url, data=None, **kwargs):
|
||||
if data:
|
||||
kwargs['body'] = json.dumps(data)
|
||||
return client.fetch(http.HTTPRequest(url, method='POST', **kwargs))
|
||||
kwargs["body"] = json.dumps(data)
|
||||
return client.fetch(http.HTTPRequest(url, method="POST", **kwargs))
|
||||
|
||||
|
||||
@pytest.fixture(params=["https", "http"])
|
||||
def scheme(request):
|
||||
'''Fixture that returns both http and https.'''
|
||||
"""Fixture that returns both http and https."""
|
||||
return request.param
|
||||
|
||||
|
||||
@pytest.mark.gen_test
|
||||
def test_status_code(get_client, scheme, tmpdir):
|
||||
'''Ensure that we can read the status code'''
|
||||
url = scheme + '://httpbin.org/'
|
||||
with vcr.use_cassette(str(tmpdir.join('atts.yaml'))):
|
||||
"""Ensure that we can read the status code"""
|
||||
url = scheme + "://httpbin.org/"
|
||||
with vcr.use_cassette(str(tmpdir.join("atts.yaml"))):
|
||||
status_code = (yield get(get_client(), url)).code
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('atts.yaml'))) as cass:
|
||||
with vcr.use_cassette(str(tmpdir.join("atts.yaml"))) as cass:
|
||||
assert status_code == (yield get(get_client(), url)).code
|
||||
assert 1 == cass.play_count
|
||||
|
||||
|
||||
@pytest.mark.gen_test
|
||||
def test_headers(get_client, scheme, tmpdir):
|
||||
'''Ensure that we can read the headers back'''
|
||||
url = scheme + '://httpbin.org/'
|
||||
with vcr.use_cassette(str(tmpdir.join('headers.yaml'))):
|
||||
"""Ensure that we can read the headers back"""
|
||||
url = scheme + "://httpbin.org/"
|
||||
with vcr.use_cassette(str(tmpdir.join("headers.yaml"))):
|
||||
headers = (yield get(get_client(), url)).headers
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('headers.yaml'))) as cass:
|
||||
with vcr.use_cassette(str(tmpdir.join("headers.yaml"))) as cass:
|
||||
assert headers == (yield get(get_client(), url)).headers
|
||||
assert 1 == cass.play_count
|
||||
|
||||
|
||||
@pytest.mark.gen_test
|
||||
def test_body(get_client, tmpdir, scheme):
|
||||
'''Ensure the responses are all identical enough'''
|
||||
"""Ensure the responses are all identical enough"""
|
||||
|
||||
url = scheme + '://httpbin.org/bytes/1024'
|
||||
with vcr.use_cassette(str(tmpdir.join('body.yaml'))):
|
||||
url = scheme + "://httpbin.org/bytes/1024"
|
||||
with vcr.use_cassette(str(tmpdir.join("body.yaml"))):
|
||||
content = (yield get(get_client(), url)).body
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('body.yaml'))) as cass:
|
||||
with vcr.use_cassette(str(tmpdir.join("body.yaml"))) as cass:
|
||||
assert content == (yield get(get_client(), url)).body
|
||||
assert 1 == cass.play_count
|
||||
|
||||
|
||||
@pytest.mark.gen_test
|
||||
def test_effective_url(get_client, scheme, tmpdir):
|
||||
'''Ensure that the effective_url is captured'''
|
||||
url = scheme + '://httpbin.org/redirect-to?url=/html'
|
||||
with vcr.use_cassette(str(tmpdir.join('url.yaml'))):
|
||||
"""Ensure that the effective_url is captured"""
|
||||
url = scheme + "://httpbin.org/redirect-to?url=/html"
|
||||
with vcr.use_cassette(str(tmpdir.join("url.yaml"))):
|
||||
effective_url = (yield get(get_client(), url)).effective_url
|
||||
assert effective_url == scheme + '://httpbin.org/html'
|
||||
assert effective_url == scheme + "://httpbin.org/html"
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('url.yaml'))) as cass:
|
||||
with vcr.use_cassette(str(tmpdir.join("url.yaml"))) as cass:
|
||||
assert effective_url == (yield get(get_client(), url)).effective_url
|
||||
assert 1 == cass.play_count
|
||||
|
||||
|
||||
@pytest.mark.gen_test
|
||||
def test_auth(get_client, tmpdir, scheme):
|
||||
'''Ensure that we can handle basic auth'''
|
||||
auth = ('user', 'passwd')
|
||||
url = scheme + '://httpbin.org/basic-auth/user/passwd'
|
||||
with vcr.use_cassette(str(tmpdir.join('auth.yaml'))):
|
||||
one = yield get(
|
||||
get_client(), url, auth_username=auth[0], auth_password=auth[1]
|
||||
)
|
||||
"""Ensure that we can handle basic auth"""
|
||||
auth = ("user", "passwd")
|
||||
url = scheme + "://httpbin.org/basic-auth/user/passwd"
|
||||
with vcr.use_cassette(str(tmpdir.join("auth.yaml"))):
|
||||
one = yield get(get_client(), url, auth_username=auth[0], auth_password=auth[1])
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('auth.yaml'))) as cass:
|
||||
two = yield get(
|
||||
get_client(), url, auth_username=auth[0], auth_password=auth[1]
|
||||
)
|
||||
with vcr.use_cassette(str(tmpdir.join("auth.yaml"))) as cass:
|
||||
two = yield get(get_client(), url, auth_username=auth[0], auth_password=auth[1])
|
||||
assert one.body == two.body
|
||||
assert one.code == two.code
|
||||
assert 1 == cass.play_count
|
||||
@@ -123,30 +117,20 @@ def test_auth(get_client, tmpdir, scheme):
|
||||
|
||||
@pytest.mark.gen_test
|
||||
def test_auth_failed(get_client, tmpdir, scheme):
|
||||
'''Ensure that we can save failed auth statuses'''
|
||||
auth = ('user', 'wrongwrongwrong')
|
||||
url = scheme + '://httpbin.org/basic-auth/user/passwd'
|
||||
with vcr.use_cassette(str(tmpdir.join('auth-failed.yaml'))) as cass:
|
||||
"""Ensure that we can save failed auth statuses"""
|
||||
auth = ("user", "wrongwrongwrong")
|
||||
url = scheme + "://httpbin.org/basic-auth/user/passwd"
|
||||
with vcr.use_cassette(str(tmpdir.join("auth-failed.yaml"))) as cass:
|
||||
# Ensure that this is empty to begin with
|
||||
assert_cassette_empty(cass)
|
||||
with pytest.raises(http.HTTPError) as exc_info:
|
||||
yield get(
|
||||
get_client(),
|
||||
url,
|
||||
auth_username=auth[0],
|
||||
auth_password=auth[1],
|
||||
)
|
||||
yield get(get_client(), url, auth_username=auth[0], auth_password=auth[1])
|
||||
one = exc_info.value.response
|
||||
assert exc_info.value.code == 401
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('auth-failed.yaml'))) as cass:
|
||||
with vcr.use_cassette(str(tmpdir.join("auth-failed.yaml"))) as cass:
|
||||
with pytest.raises(http.HTTPError) as exc_info:
|
||||
two = yield get(
|
||||
get_client(),
|
||||
url,
|
||||
auth_username=auth[0],
|
||||
auth_password=auth[1],
|
||||
)
|
||||
two = yield get(get_client(), url, auth_username=auth[0], auth_password=auth[1])
|
||||
two = exc_info.value.response
|
||||
assert exc_info.value.code == 401
|
||||
assert one.body == two.body
|
||||
@@ -156,13 +140,13 @@ def test_auth_failed(get_client, tmpdir, scheme):
|
||||
|
||||
@pytest.mark.gen_test
|
||||
def test_post(get_client, tmpdir, scheme):
|
||||
'''Ensure that we can post and cache the results'''
|
||||
data = {'key1': 'value1', 'key2': 'value2'}
|
||||
url = scheme + '://httpbin.org/post'
|
||||
with vcr.use_cassette(str(tmpdir.join('requests.yaml'))):
|
||||
"""Ensure that we can post and cache the results"""
|
||||
data = {"key1": "value1", "key2": "value2"}
|
||||
url = scheme + "://httpbin.org/post"
|
||||
with vcr.use_cassette(str(tmpdir.join("requests.yaml"))):
|
||||
req1 = (yield post(get_client(), url, data)).body
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('requests.yaml'))) as cass:
|
||||
with vcr.use_cassette(str(tmpdir.join("requests.yaml"))) as cass:
|
||||
req2 = (yield post(get_client(), url, data)).body
|
||||
|
||||
assert req1 == req2
|
||||
@@ -171,55 +155,55 @@ def test_post(get_client, tmpdir, scheme):
|
||||
|
||||
@pytest.mark.gen_test
|
||||
def test_redirects(get_client, tmpdir, scheme):
|
||||
'''Ensure that we can handle redirects'''
|
||||
url = scheme + '://httpbin.org/redirect-to?url=bytes/1024'
|
||||
with vcr.use_cassette(str(tmpdir.join('requests.yaml'))):
|
||||
"""Ensure that we can handle redirects"""
|
||||
url = scheme + "://httpbin.org/redirect-to?url=bytes/1024"
|
||||
with vcr.use_cassette(str(tmpdir.join("requests.yaml"))):
|
||||
content = (yield get(get_client(), url)).body
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('requests.yaml'))) as cass:
|
||||
with vcr.use_cassette(str(tmpdir.join("requests.yaml"))) as cass:
|
||||
assert content == (yield get(get_client(), url)).body
|
||||
assert cass.play_count == 1
|
||||
|
||||
|
||||
@pytest.mark.gen_test
|
||||
def test_cross_scheme(get_client, tmpdir, scheme):
|
||||
'''Ensure that requests between schemes are treated separately'''
|
||||
"""Ensure that requests between schemes are treated separately"""
|
||||
# First fetch a url under http, and then again under https and then
|
||||
# ensure that we haven't served anything out of cache, and we have two
|
||||
# requests / response pairs in the cassette
|
||||
with vcr.use_cassette(str(tmpdir.join('cross_scheme.yaml'))) as cass:
|
||||
yield get(get_client(), 'https://httpbin.org/')
|
||||
yield get(get_client(), 'http://httpbin.org/')
|
||||
with vcr.use_cassette(str(tmpdir.join("cross_scheme.yaml"))) as cass:
|
||||
yield get(get_client(), "https://httpbin.org/")
|
||||
yield get(get_client(), "http://httpbin.org/")
|
||||
assert cass.play_count == 0
|
||||
assert len(cass) == 2
|
||||
|
||||
# Then repeat the same requests and ensure both were replayed.
|
||||
with vcr.use_cassette(str(tmpdir.join('cross_scheme.yaml'))) as cass:
|
||||
yield get(get_client(), 'https://httpbin.org/')
|
||||
yield get(get_client(), 'http://httpbin.org/')
|
||||
with vcr.use_cassette(str(tmpdir.join("cross_scheme.yaml"))) as cass:
|
||||
yield get(get_client(), "https://httpbin.org/")
|
||||
yield get(get_client(), "http://httpbin.org/")
|
||||
assert cass.play_count == 2
|
||||
|
||||
|
||||
@pytest.mark.gen_test
|
||||
def test_gzip(get_client, tmpdir, scheme):
|
||||
'''
|
||||
"""
|
||||
Ensure that httpclient is able to automatically decompress the response
|
||||
body
|
||||
'''
|
||||
url = scheme + '://httpbin.org/gzip'
|
||||
"""
|
||||
url = scheme + "://httpbin.org/gzip"
|
||||
|
||||
# use_gzip was renamed to decompress_response in 4.0
|
||||
kwargs = {}
|
||||
if tornado.version_info < (4,):
|
||||
kwargs['use_gzip'] = True
|
||||
kwargs["use_gzip"] = True
|
||||
else:
|
||||
kwargs['decompress_response'] = True
|
||||
kwargs["decompress_response"] = True
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('gzip.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("gzip.yaml"))):
|
||||
response = yield get(get_client(), url, **kwargs)
|
||||
assert_is_json(response.body)
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('gzip.yaml'))) as cass:
|
||||
with vcr.use_cassette(str(tmpdir.join("gzip.yaml"))) as cass:
|
||||
response = yield get(get_client(), url, **kwargs)
|
||||
assert_is_json(response.body)
|
||||
assert 1 == cass.play_count
|
||||
@@ -227,28 +211,26 @@ def test_gzip(get_client, tmpdir, scheme):
|
||||
|
||||
@pytest.mark.gen_test
|
||||
def test_https_with_cert_validation_disabled(get_client, tmpdir):
|
||||
cass_path = str(tmpdir.join('cert_validation_disabled.yaml'))
|
||||
cass_path = str(tmpdir.join("cert_validation_disabled.yaml"))
|
||||
|
||||
with vcr.use_cassette(cass_path):
|
||||
yield get(get_client(), 'https://httpbin.org', validate_cert=False)
|
||||
yield get(get_client(), "https://httpbin.org", validate_cert=False)
|
||||
|
||||
with vcr.use_cassette(cass_path) as cass:
|
||||
yield get(get_client(), 'https://httpbin.org', validate_cert=False)
|
||||
yield get(get_client(), "https://httpbin.org", validate_cert=False)
|
||||
assert 1 == cass.play_count
|
||||
|
||||
|
||||
@pytest.mark.gen_test
|
||||
def test_unsupported_features_raises_in_future(get_client, tmpdir):
|
||||
'''Ensure that the exception for an AsyncHTTPClient feature not being
|
||||
supported is raised inside the future.'''
|
||||
"""Ensure that the exception for an AsyncHTTPClient feature not being
|
||||
supported is raised inside the future."""
|
||||
|
||||
def callback(chunk):
|
||||
assert False, "Did not expect to be called."
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('invalid.yaml'))):
|
||||
future = get(
|
||||
get_client(), 'http://httpbin.org', streaming_callback=callback
|
||||
)
|
||||
with vcr.use_cassette(str(tmpdir.join("invalid.yaml"))):
|
||||
future = get(get_client(), "http://httpbin.org", streaming_callback=callback)
|
||||
|
||||
with pytest.raises(Exception) as excinfo:
|
||||
yield future
|
||||
@@ -256,24 +238,18 @@ def test_unsupported_features_raises_in_future(get_client, tmpdir):
|
||||
assert "not yet supported by VCR" in str(excinfo)
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not supports_raise_error,
|
||||
reason='raise_error unavailable in tornado <= 3',
|
||||
)
|
||||
@pytest.mark.skipif(not supports_raise_error, reason="raise_error unavailable in tornado <= 3")
|
||||
@pytest.mark.gen_test
|
||||
def test_unsupported_features_raise_error_disabled(get_client, tmpdir):
|
||||
'''Ensure that the exception for an AsyncHTTPClient feature not being
|
||||
supported is not raised if raise_error=False.'''
|
||||
"""Ensure that the exception for an AsyncHTTPClient feature not being
|
||||
supported is not raised if raise_error=False."""
|
||||
|
||||
def callback(chunk):
|
||||
assert False, "Did not expect to be called."
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('invalid.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("invalid.yaml"))):
|
||||
response = yield get(
|
||||
get_client(),
|
||||
'http://httpbin.org',
|
||||
streaming_callback=callback,
|
||||
raise_error=False,
|
||||
get_client(), "http://httpbin.org", streaming_callback=callback, raise_error=False
|
||||
)
|
||||
|
||||
assert "not yet supported by VCR" in str(response.error)
|
||||
@@ -281,60 +257,51 @@ def test_unsupported_features_raise_error_disabled(get_client, tmpdir):
|
||||
|
||||
@pytest.mark.gen_test
|
||||
def test_cannot_overwrite_cassette_raises_in_future(get_client, tmpdir):
|
||||
'''Ensure that CannotOverwriteExistingCassetteException is raised inside
|
||||
the future.'''
|
||||
"""Ensure that CannotOverwriteExistingCassetteException is raised inside
|
||||
the future."""
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('overwrite.yaml'))):
|
||||
yield get(get_client(), 'http://httpbin.org/get')
|
||||
with vcr.use_cassette(str(tmpdir.join("overwrite.yaml"))):
|
||||
yield get(get_client(), "http://httpbin.org/get")
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('overwrite.yaml'))):
|
||||
future = get(get_client(), 'http://httpbin.org/headers')
|
||||
with vcr.use_cassette(str(tmpdir.join("overwrite.yaml"))):
|
||||
future = get(get_client(), "http://httpbin.org/headers")
|
||||
|
||||
with pytest.raises(CannotOverwriteExistingCassetteException):
|
||||
yield future
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not supports_raise_error,
|
||||
reason='raise_error unavailable in tornado <= 3',
|
||||
)
|
||||
@pytest.mark.skipif(not supports_raise_error, reason="raise_error unavailable in tornado <= 3")
|
||||
@pytest.mark.gen_test
|
||||
def test_cannot_overwrite_cassette_raise_error_disabled(get_client, tmpdir):
|
||||
'''Ensure that CannotOverwriteExistingCassetteException is not raised if
|
||||
raise_error=False in the fetch() call.'''
|
||||
"""Ensure that CannotOverwriteExistingCassetteException is not raised if
|
||||
raise_error=False in the fetch() call."""
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('overwrite.yaml'))):
|
||||
yield get(
|
||||
get_client(), 'http://httpbin.org/get', raise_error=False
|
||||
)
|
||||
with vcr.use_cassette(str(tmpdir.join("overwrite.yaml"))):
|
||||
yield get(get_client(), "http://httpbin.org/get", raise_error=False)
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('overwrite.yaml'))):
|
||||
response = yield get(
|
||||
get_client(), 'http://httpbin.org/headers', raise_error=False
|
||||
)
|
||||
with vcr.use_cassette(str(tmpdir.join("overwrite.yaml"))):
|
||||
response = yield get(get_client(), "http://httpbin.org/headers", raise_error=False)
|
||||
|
||||
assert isinstance(response.error, CannotOverwriteExistingCassetteException)
|
||||
|
||||
|
||||
@pytest.mark.gen_test
|
||||
@vcr.use_cassette(path_transformer=vcr.default_vcr.ensure_suffix('.yaml'))
|
||||
@vcr.use_cassette(path_transformer=vcr.default_vcr.ensure_suffix(".yaml"))
|
||||
def test_tornado_with_decorator_use_cassette(get_client):
|
||||
response = yield get_client().fetch(
|
||||
http.HTTPRequest('http://www.google.com/', method='GET')
|
||||
)
|
||||
assert response.body.decode('utf-8') == "not actually google"
|
||||
response = yield get_client().fetch(http.HTTPRequest("http://www.google.com/", method="GET"))
|
||||
assert response.body.decode("utf-8") == "not actually google"
|
||||
|
||||
|
||||
@pytest.mark.gen_test
|
||||
@vcr.use_cassette(path_transformer=vcr.default_vcr.ensure_suffix('.yaml'))
|
||||
@vcr.use_cassette(path_transformer=vcr.default_vcr.ensure_suffix(".yaml"))
|
||||
def test_tornado_exception_can_be_caught(get_client):
|
||||
try:
|
||||
yield get(get_client(), 'http://httpbin.org/status/500')
|
||||
yield get(get_client(), "http://httpbin.org/status/500")
|
||||
except http.HTTPError as e:
|
||||
assert e.code == 500
|
||||
|
||||
try:
|
||||
yield get(get_client(), 'http://httpbin.org/status/404')
|
||||
yield get(get_client(), "http://httpbin.org/status/404")
|
||||
except http.HTTPError as e:
|
||||
assert e.code == 404
|
||||
|
||||
@@ -343,41 +310,41 @@ def test_tornado_exception_can_be_caught(get_client):
|
||||
def test_existing_references_get_patched(tmpdir):
|
||||
from tornado.httpclient import AsyncHTTPClient
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('data.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("data.yaml"))):
|
||||
client = AsyncHTTPClient()
|
||||
yield get(client, 'http://httpbin.org/get')
|
||||
yield get(client, "http://httpbin.org/get")
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('data.yaml'))) as cass:
|
||||
yield get(client, 'http://httpbin.org/get')
|
||||
with vcr.use_cassette(str(tmpdir.join("data.yaml"))) as cass:
|
||||
yield get(client, "http://httpbin.org/get")
|
||||
assert cass.play_count == 1
|
||||
|
||||
|
||||
@pytest.mark.gen_test
|
||||
def test_existing_instances_get_patched(get_client, tmpdir):
|
||||
'''Ensure that existing instances of AsyncHTTPClient get patched upon
|
||||
entering VCR context.'''
|
||||
"""Ensure that existing instances of AsyncHTTPClient get patched upon
|
||||
entering VCR context."""
|
||||
|
||||
client = get_client()
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('data.yaml'))):
|
||||
yield get(client, 'http://httpbin.org/get')
|
||||
with vcr.use_cassette(str(tmpdir.join("data.yaml"))):
|
||||
yield get(client, "http://httpbin.org/get")
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('data.yaml'))) as cass:
|
||||
yield get(client, 'http://httpbin.org/get')
|
||||
with vcr.use_cassette(str(tmpdir.join("data.yaml"))) as cass:
|
||||
yield get(client, "http://httpbin.org/get")
|
||||
assert cass.play_count == 1
|
||||
|
||||
|
||||
@pytest.mark.gen_test
|
||||
def test_request_time_is_set(get_client, tmpdir):
|
||||
'''Ensures that the request_time on HTTPResponses is set.'''
|
||||
"""Ensures that the request_time on HTTPResponses is set."""
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('data.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("data.yaml"))):
|
||||
client = get_client()
|
||||
response = yield get(client, 'http://httpbin.org/get')
|
||||
response = yield get(client, "http://httpbin.org/get")
|
||||
assert response.request_time is not None
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('data.yaml'))) as cass:
|
||||
with vcr.use_cassette(str(tmpdir.join("data.yaml"))) as cass:
|
||||
client = get_client()
|
||||
response = yield get(client, 'http://httpbin.org/get')
|
||||
response = yield get(client, "http://httpbin.org/get")
|
||||
assert response.request_time is not None
|
||||
assert cass.play_count == 1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''Integration tests with urllib2'''
|
||||
"""Integration tests with urllib2"""
|
||||
|
||||
import ssl
|
||||
from six.moves.urllib.request import urlopen
|
||||
@@ -15,91 +15,86 @@ from assertions import assert_cassette_has_one_response
|
||||
def urlopen_with_cafile(*args, **kwargs):
|
||||
context = ssl.create_default_context(cafile=pytest_httpbin.certs.where())
|
||||
context.check_hostname = False
|
||||
kwargs['context'] = context
|
||||
kwargs["context"] = context
|
||||
try:
|
||||
return urlopen(*args, **kwargs)
|
||||
except TypeError:
|
||||
# python2/pypi don't let us override this
|
||||
del kwargs['cafile']
|
||||
del kwargs["cafile"]
|
||||
return urlopen(*args, **kwargs)
|
||||
|
||||
|
||||
def test_response_code(httpbin_both, tmpdir):
|
||||
'''Ensure we can read a response code from a fetch'''
|
||||
"""Ensure we can read a response code from a fetch"""
|
||||
url = httpbin_both.url
|
||||
with vcr.use_cassette(str(tmpdir.join('atts.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("atts.yaml"))):
|
||||
code = urlopen_with_cafile(url).getcode()
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('atts.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("atts.yaml"))):
|
||||
assert code == urlopen_with_cafile(url).getcode()
|
||||
|
||||
|
||||
def test_random_body(httpbin_both, tmpdir):
|
||||
'''Ensure we can read the content, and that it's served from cache'''
|
||||
url = httpbin_both.url + '/bytes/1024'
|
||||
with vcr.use_cassette(str(tmpdir.join('body.yaml'))):
|
||||
"""Ensure we can read the content, and that it's served from cache"""
|
||||
url = httpbin_both.url + "/bytes/1024"
|
||||
with vcr.use_cassette(str(tmpdir.join("body.yaml"))):
|
||||
body = urlopen_with_cafile(url).read()
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('body.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("body.yaml"))):
|
||||
assert body == urlopen_with_cafile(url).read()
|
||||
|
||||
|
||||
def test_response_headers(httpbin_both, tmpdir):
|
||||
'''Ensure we can get information from the response'''
|
||||
"""Ensure we can get information from the response"""
|
||||
url = httpbin_both.url
|
||||
with vcr.use_cassette(str(tmpdir.join('headers.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("headers.yaml"))):
|
||||
open1 = urlopen_with_cafile(url).info().items()
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('headers.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("headers.yaml"))):
|
||||
open2 = urlopen_with_cafile(url).info().items()
|
||||
|
||||
assert sorted(open1) == sorted(open2)
|
||||
|
||||
|
||||
def test_effective_url(httpbin_both, tmpdir):
|
||||
'''Ensure that the effective_url is captured'''
|
||||
url = httpbin_both.url + '/redirect-to?url=/html'
|
||||
with vcr.use_cassette(str(tmpdir.join('headers.yaml'))):
|
||||
"""Ensure that the effective_url is captured"""
|
||||
url = httpbin_both.url + "/redirect-to?url=/html"
|
||||
with vcr.use_cassette(str(tmpdir.join("headers.yaml"))):
|
||||
effective_url = urlopen_with_cafile(url).geturl()
|
||||
assert effective_url == httpbin_both.url + '/html'
|
||||
assert effective_url == httpbin_both.url + "/html"
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('headers.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("headers.yaml"))):
|
||||
assert effective_url == urlopen_with_cafile(url).geturl()
|
||||
|
||||
|
||||
def test_multiple_requests(httpbin_both, tmpdir):
|
||||
'''Ensure that we can cache multiple requests'''
|
||||
urls = [
|
||||
httpbin_both.url,
|
||||
httpbin_both.url,
|
||||
httpbin_both.url + '/get',
|
||||
httpbin_both.url + '/bytes/1024',
|
||||
]
|
||||
with vcr.use_cassette(str(tmpdir.join('multiple.yaml'))) as cass:
|
||||
"""Ensure that we can cache multiple requests"""
|
||||
urls = [httpbin_both.url, httpbin_both.url, httpbin_both.url + "/get", httpbin_both.url + "/bytes/1024"]
|
||||
with vcr.use_cassette(str(tmpdir.join("multiple.yaml"))) as cass:
|
||||
[urlopen_with_cafile(url) for url in urls]
|
||||
assert len(cass) == len(urls)
|
||||
|
||||
|
||||
def test_get_data(httpbin_both, tmpdir):
|
||||
'''Ensure that it works with query data'''
|
||||
data = urlencode({'some': 1, 'data': 'here'})
|
||||
url = httpbin_both.url + '/get?' + data
|
||||
with vcr.use_cassette(str(tmpdir.join('get_data.yaml'))):
|
||||
"""Ensure that it works with query data"""
|
||||
data = urlencode({"some": 1, "data": "here"})
|
||||
url = httpbin_both.url + "/get?" + data
|
||||
with vcr.use_cassette(str(tmpdir.join("get_data.yaml"))):
|
||||
res1 = urlopen_with_cafile(url).read()
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('get_data.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("get_data.yaml"))):
|
||||
res2 = urlopen_with_cafile(url).read()
|
||||
assert res1 == res2
|
||||
|
||||
|
||||
def test_post_data(httpbin_both, tmpdir):
|
||||
'''Ensure that it works when posting data'''
|
||||
data = urlencode({'some': 1, 'data': 'here'}).encode('utf-8')
|
||||
url = httpbin_both.url + '/post'
|
||||
with vcr.use_cassette(str(tmpdir.join('post_data.yaml'))):
|
||||
"""Ensure that it works when posting data"""
|
||||
data = urlencode({"some": 1, "data": "here"}).encode("utf-8")
|
||||
url = httpbin_both.url + "/post"
|
||||
with vcr.use_cassette(str(tmpdir.join("post_data.yaml"))):
|
||||
res1 = urlopen_with_cafile(url, data).read()
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('post_data.yaml'))) as cass:
|
||||
with vcr.use_cassette(str(tmpdir.join("post_data.yaml"))) as cass:
|
||||
res2 = urlopen_with_cafile(url, data).read()
|
||||
assert len(cass) == 1
|
||||
|
||||
@@ -108,13 +103,13 @@ def test_post_data(httpbin_both, tmpdir):
|
||||
|
||||
|
||||
def test_post_unicode_data(httpbin_both, tmpdir):
|
||||
'''Ensure that it works when posting unicode data'''
|
||||
data = urlencode({'snowman': u'☃'.encode('utf-8')}).encode('utf-8')
|
||||
url = httpbin_both.url + '/post'
|
||||
with vcr.use_cassette(str(tmpdir.join('post_data.yaml'))):
|
||||
"""Ensure that it works when posting unicode data"""
|
||||
data = urlencode({"snowman": u"☃".encode("utf-8")}).encode("utf-8")
|
||||
url = httpbin_both.url + "/post"
|
||||
with vcr.use_cassette(str(tmpdir.join("post_data.yaml"))):
|
||||
res1 = urlopen_with_cafile(url, data).read()
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('post_data.yaml'))) as cass:
|
||||
with vcr.use_cassette(str(tmpdir.join("post_data.yaml"))) as cass:
|
||||
res2 = urlopen_with_cafile(url, data).read()
|
||||
assert len(cass) == 1
|
||||
|
||||
@@ -123,11 +118,11 @@ def test_post_unicode_data(httpbin_both, tmpdir):
|
||||
|
||||
|
||||
def test_cross_scheme(tmpdir, httpbin_secure, httpbin):
|
||||
'''Ensure that requests between schemes are treated separately'''
|
||||
"""Ensure that requests between schemes are treated separately"""
|
||||
# First fetch a url under https, and then again under https and then
|
||||
# ensure that we haven't served anything out of cache, and we have two
|
||||
# requests / response pairs in the cassette
|
||||
with vcr.use_cassette(str(tmpdir.join('cross_scheme.yaml'))) as cass:
|
||||
with vcr.use_cassette(str(tmpdir.join("cross_scheme.yaml"))) as cass:
|
||||
urlopen_with_cafile(httpbin_secure.url)
|
||||
urlopen_with_cafile(httpbin.url)
|
||||
assert len(cass) == 2
|
||||
@@ -135,14 +130,14 @@ def test_cross_scheme(tmpdir, httpbin_secure, httpbin):
|
||||
|
||||
|
||||
def test_decorator(httpbin_both, tmpdir):
|
||||
'''Test the decorator version of VCR.py'''
|
||||
"""Test the decorator version of VCR.py"""
|
||||
url = httpbin_both.url
|
||||
|
||||
@vcr.use_cassette(str(tmpdir.join('atts.yaml')))
|
||||
@vcr.use_cassette(str(tmpdir.join("atts.yaml")))
|
||||
def inner1():
|
||||
return urlopen_with_cafile(url).getcode()
|
||||
|
||||
@vcr.use_cassette(str(tmpdir.join('atts.yaml')))
|
||||
@vcr.use_cassette(str(tmpdir.join("atts.yaml")))
|
||||
def inner2():
|
||||
return urlopen_with_cafile(url).getcode()
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
'''Integration tests with urllib3'''
|
||||
"""Integration tests with urllib3"""
|
||||
|
||||
# coding=utf-8
|
||||
|
||||
@@ -7,101 +7,101 @@ import pytest_httpbin
|
||||
import vcr
|
||||
from vcr.patch import force_reset
|
||||
from assertions import assert_cassette_empty, assert_is_json
|
||||
|
||||
urllib3 = pytest.importorskip("urllib3")
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
@pytest.fixture(scope="module")
|
||||
def verify_pool_mgr():
|
||||
return urllib3.PoolManager(
|
||||
cert_reqs='CERT_REQUIRED', # Force certificate check.
|
||||
ca_certs=pytest_httpbin.certs.where()
|
||||
cert_reqs="CERT_REQUIRED", ca_certs=pytest_httpbin.certs.where() # Force certificate check.
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
@pytest.fixture(scope="module")
|
||||
def pool_mgr():
|
||||
return urllib3.PoolManager(cert_reqs='CERT_NONE')
|
||||
return urllib3.PoolManager(cert_reqs="CERT_NONE")
|
||||
|
||||
|
||||
def test_status_code(httpbin_both, tmpdir, verify_pool_mgr):
|
||||
'''Ensure that we can read the status code'''
|
||||
"""Ensure that we can read the status code"""
|
||||
url = httpbin_both.url
|
||||
with vcr.use_cassette(str(tmpdir.join('atts.yaml'))):
|
||||
status_code = verify_pool_mgr.request('GET', url).status
|
||||
with vcr.use_cassette(str(tmpdir.join("atts.yaml"))):
|
||||
status_code = verify_pool_mgr.request("GET", url).status
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('atts.yaml'))):
|
||||
assert status_code == verify_pool_mgr.request('GET', url).status
|
||||
with vcr.use_cassette(str(tmpdir.join("atts.yaml"))):
|
||||
assert status_code == verify_pool_mgr.request("GET", url).status
|
||||
|
||||
|
||||
def test_headers(tmpdir, httpbin_both, verify_pool_mgr):
|
||||
'''Ensure that we can read the headers back'''
|
||||
"""Ensure that we can read the headers back"""
|
||||
url = httpbin_both.url
|
||||
with vcr.use_cassette(str(tmpdir.join('headers.yaml'))):
|
||||
headers = verify_pool_mgr.request('GET', url).headers
|
||||
with vcr.use_cassette(str(tmpdir.join("headers.yaml"))):
|
||||
headers = verify_pool_mgr.request("GET", url).headers
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('headers.yaml'))):
|
||||
assert headers == verify_pool_mgr.request('GET', url).headers
|
||||
with vcr.use_cassette(str(tmpdir.join("headers.yaml"))):
|
||||
assert headers == verify_pool_mgr.request("GET", url).headers
|
||||
|
||||
|
||||
def test_body(tmpdir, httpbin_both, verify_pool_mgr):
|
||||
'''Ensure the responses are all identical enough'''
|
||||
url = httpbin_both.url + '/bytes/1024'
|
||||
with vcr.use_cassette(str(tmpdir.join('body.yaml'))):
|
||||
content = verify_pool_mgr.request('GET', url).data
|
||||
"""Ensure the responses are all identical enough"""
|
||||
url = httpbin_both.url + "/bytes/1024"
|
||||
with vcr.use_cassette(str(tmpdir.join("body.yaml"))):
|
||||
content = verify_pool_mgr.request("GET", url).data
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('body.yaml'))):
|
||||
assert content == verify_pool_mgr.request('GET', url).data
|
||||
with vcr.use_cassette(str(tmpdir.join("body.yaml"))):
|
||||
assert content == verify_pool_mgr.request("GET", url).data
|
||||
|
||||
|
||||
def test_auth(tmpdir, httpbin_both, verify_pool_mgr):
|
||||
'''Ensure that we can handle basic auth'''
|
||||
auth = ('user', 'passwd')
|
||||
headers = urllib3.util.make_headers(basic_auth='{}:{}'.format(*auth))
|
||||
url = httpbin_both.url + '/basic-auth/user/passwd'
|
||||
with vcr.use_cassette(str(tmpdir.join('auth.yaml'))):
|
||||
one = verify_pool_mgr.request('GET', url, headers=headers)
|
||||
"""Ensure that we can handle basic auth"""
|
||||
auth = ("user", "passwd")
|
||||
headers = urllib3.util.make_headers(basic_auth="{}:{}".format(*auth))
|
||||
url = httpbin_both.url + "/basic-auth/user/passwd"
|
||||
with vcr.use_cassette(str(tmpdir.join("auth.yaml"))):
|
||||
one = verify_pool_mgr.request("GET", url, headers=headers)
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('auth.yaml'))):
|
||||
two = verify_pool_mgr.request('GET', url, headers=headers)
|
||||
with vcr.use_cassette(str(tmpdir.join("auth.yaml"))):
|
||||
two = verify_pool_mgr.request("GET", url, headers=headers)
|
||||
assert one.data == two.data
|
||||
assert one.status == two.status
|
||||
|
||||
|
||||
def test_auth_failed(tmpdir, httpbin_both, verify_pool_mgr):
|
||||
'''Ensure that we can save failed auth statuses'''
|
||||
auth = ('user', 'wrongwrongwrong')
|
||||
headers = urllib3.util.make_headers(basic_auth='{}:{}'.format(*auth))
|
||||
url = httpbin_both.url + '/basic-auth/user/passwd'
|
||||
with vcr.use_cassette(str(tmpdir.join('auth-failed.yaml'))) as cass:
|
||||
"""Ensure that we can save failed auth statuses"""
|
||||
auth = ("user", "wrongwrongwrong")
|
||||
headers = urllib3.util.make_headers(basic_auth="{}:{}".format(*auth))
|
||||
url = httpbin_both.url + "/basic-auth/user/passwd"
|
||||
with vcr.use_cassette(str(tmpdir.join("auth-failed.yaml"))) as cass:
|
||||
# Ensure that this is empty to begin with
|
||||
assert_cassette_empty(cass)
|
||||
one = verify_pool_mgr.request('GET', url, headers=headers)
|
||||
two = verify_pool_mgr.request('GET', url, headers=headers)
|
||||
one = verify_pool_mgr.request("GET", url, headers=headers)
|
||||
two = verify_pool_mgr.request("GET", url, headers=headers)
|
||||
assert one.data == two.data
|
||||
assert one.status == two.status == 401
|
||||
|
||||
|
||||
def test_post(tmpdir, httpbin_both, verify_pool_mgr):
|
||||
'''Ensure that we can post and cache the results'''
|
||||
data = {'key1': 'value1', 'key2': 'value2'}
|
||||
url = httpbin_both.url + '/post'
|
||||
with vcr.use_cassette(str(tmpdir.join('verify_pool_mgr.yaml'))):
|
||||
req1 = verify_pool_mgr.request('POST', url, data).data
|
||||
"""Ensure that we can post and cache the results"""
|
||||
data = {"key1": "value1", "key2": "value2"}
|
||||
url = httpbin_both.url + "/post"
|
||||
with vcr.use_cassette(str(tmpdir.join("verify_pool_mgr.yaml"))):
|
||||
req1 = verify_pool_mgr.request("POST", url, data).data
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('verify_pool_mgr.yaml'))):
|
||||
req2 = verify_pool_mgr.request('POST', url, data).data
|
||||
with vcr.use_cassette(str(tmpdir.join("verify_pool_mgr.yaml"))):
|
||||
req2 = verify_pool_mgr.request("POST", url, data).data
|
||||
|
||||
assert req1 == req2
|
||||
|
||||
|
||||
def test_redirects(tmpdir, httpbin_both, verify_pool_mgr):
|
||||
'''Ensure that we can handle redirects'''
|
||||
url = httpbin_both.url + '/redirect-to?url=bytes/1024'
|
||||
with vcr.use_cassette(str(tmpdir.join('verify_pool_mgr.yaml'))):
|
||||
content = verify_pool_mgr.request('GET', url).data
|
||||
"""Ensure that we can handle redirects"""
|
||||
url = httpbin_both.url + "/redirect-to?url=bytes/1024"
|
||||
with vcr.use_cassette(str(tmpdir.join("verify_pool_mgr.yaml"))):
|
||||
content = verify_pool_mgr.request("GET", url).data
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('verify_pool_mgr.yaml'))) as cass:
|
||||
assert content == verify_pool_mgr.request('GET', url).data
|
||||
with vcr.use_cassette(str(tmpdir.join("verify_pool_mgr.yaml"))) as cass:
|
||||
assert content == verify_pool_mgr.request("GET", url).data
|
||||
# Ensure that we've now cached *two* responses. One for the redirect
|
||||
# and one for the final fetch
|
||||
assert len(cass) == 2
|
||||
@@ -109,36 +109,36 @@ def test_redirects(tmpdir, httpbin_both, verify_pool_mgr):
|
||||
|
||||
|
||||
def test_cross_scheme(tmpdir, httpbin, httpbin_secure, verify_pool_mgr):
|
||||
'''Ensure that requests between schemes are treated separately'''
|
||||
"""Ensure that requests between schemes are treated separately"""
|
||||
# First fetch a url under http, and then again under https and then
|
||||
# ensure that we haven't served anything out of cache, and we have two
|
||||
# requests / response pairs in the cassette
|
||||
with vcr.use_cassette(str(tmpdir.join('cross_scheme.yaml'))) as cass:
|
||||
verify_pool_mgr.request('GET', httpbin_secure.url)
|
||||
verify_pool_mgr.request('GET', httpbin.url)
|
||||
with vcr.use_cassette(str(tmpdir.join("cross_scheme.yaml"))) as cass:
|
||||
verify_pool_mgr.request("GET", httpbin_secure.url)
|
||||
verify_pool_mgr.request("GET", httpbin.url)
|
||||
assert cass.play_count == 0
|
||||
assert len(cass) == 2
|
||||
|
||||
|
||||
def test_gzip(tmpdir, httpbin_both, verify_pool_mgr):
|
||||
'''
|
||||
"""
|
||||
Ensure that requests (actually urllib3) is able to automatically decompress
|
||||
the response body
|
||||
'''
|
||||
url = httpbin_both.url + '/gzip'
|
||||
response = verify_pool_mgr.request('GET', url)
|
||||
"""
|
||||
url = httpbin_both.url + "/gzip"
|
||||
response = verify_pool_mgr.request("GET", url)
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('gzip.yaml'))):
|
||||
response = verify_pool_mgr.request('GET', url)
|
||||
with vcr.use_cassette(str(tmpdir.join("gzip.yaml"))):
|
||||
response = verify_pool_mgr.request("GET", url)
|
||||
assert_is_json(response.data)
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('gzip.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("gzip.yaml"))):
|
||||
assert_is_json(response.data)
|
||||
|
||||
|
||||
def test_https_with_cert_validation_disabled(tmpdir, httpbin_secure, pool_mgr):
|
||||
with vcr.use_cassette(str(tmpdir.join('cert_validation_disabled.yaml'))):
|
||||
pool_mgr.request('GET', httpbin_secure.url)
|
||||
with vcr.use_cassette(str(tmpdir.join("cert_validation_disabled.yaml"))):
|
||||
pool_mgr.request("GET", httpbin_secure.url)
|
||||
|
||||
|
||||
def test_urllib3_force_reset():
|
||||
@@ -146,7 +146,7 @@ def test_urllib3_force_reset():
|
||||
http_original = cpool.HTTPConnection
|
||||
https_original = cpool.HTTPSConnection
|
||||
verified_https_original = cpool.VerifiedHTTPSConnection
|
||||
with vcr.use_cassette(path='test'):
|
||||
with vcr.use_cassette(path="test"):
|
||||
first_cassette_HTTPConnection = cpool.HTTPConnection
|
||||
first_cassette_HTTPSConnection = cpool.HTTPSConnection
|
||||
first_cassette_VerifiedHTTPSConnection = cpool.VerifiedHTTPSConnection
|
||||
|
||||
@@ -13,13 +13,13 @@ except ImportError:
|
||||
|
||||
|
||||
def test_domain_redirect():
|
||||
'''Ensure that redirects across domains are considered unique'''
|
||||
"""Ensure that redirects across domains are considered unique"""
|
||||
# In this example, seomoz.org redirects to moz.com, and if those
|
||||
# requests are considered identical, then we'll be stuck in a redirect
|
||||
# loop.
|
||||
url = 'http://seomoz.org/'
|
||||
with vcr.use_cassette('tests/fixtures/wild/domain_redirect.yaml') as cass:
|
||||
requests.get(url, headers={'User-Agent': 'vcrpy-test'})
|
||||
url = "http://seomoz.org/"
|
||||
with vcr.use_cassette("tests/fixtures/wild/domain_redirect.yaml") as cass:
|
||||
requests.get(url, headers={"User-Agent": "vcrpy-test"})
|
||||
# Ensure that we've now served two responses. One for the original
|
||||
# redirect, and a second for the actual fetch
|
||||
assert len(cass) == 2
|
||||
@@ -30,13 +30,11 @@ def test_flickr_multipart_upload(httpbin, tmpdir):
|
||||
The python-flickr-api project does a multipart
|
||||
upload that confuses vcrpy
|
||||
"""
|
||||
|
||||
def _pretend_to_be_flickr_library():
|
||||
content_type, body = "text/plain", "HELLO WORLD"
|
||||
h = httplib.HTTPConnection(httpbin.host, httpbin.port)
|
||||
headers = {
|
||||
"Content-Type": content_type,
|
||||
"content-length": str(len(body))
|
||||
}
|
||||
headers = {"Content-Type": content_type, "content-length": str(len(body))}
|
||||
h.request("POST", "/post/", headers=headers)
|
||||
h.send(body)
|
||||
r = h.getresponse()
|
||||
@@ -45,7 +43,7 @@ def test_flickr_multipart_upload(httpbin, tmpdir):
|
||||
|
||||
return data
|
||||
|
||||
testfile = str(tmpdir.join('flickr.yml'))
|
||||
testfile = str(tmpdir.join("flickr.yml"))
|
||||
with vcr.use_cassette(testfile) as cass:
|
||||
_pretend_to_be_flickr_library()
|
||||
assert len(cass) == 1
|
||||
@@ -57,44 +55,41 @@ def test_flickr_multipart_upload(httpbin, tmpdir):
|
||||
|
||||
|
||||
def test_flickr_should_respond_with_200(tmpdir):
|
||||
testfile = str(tmpdir.join('flickr.yml'))
|
||||
testfile = str(tmpdir.join("flickr.yml"))
|
||||
with vcr.use_cassette(testfile):
|
||||
r = requests.post("https://api.flickr.com/services/upload", verify=False)
|
||||
assert r.status_code == 200
|
||||
|
||||
|
||||
def test_cookies(tmpdir, httpbin):
|
||||
testfile = str(tmpdir.join('cookies.yml'))
|
||||
testfile = str(tmpdir.join("cookies.yml"))
|
||||
with vcr.use_cassette(testfile):
|
||||
s = requests.Session()
|
||||
s.get(httpbin.url + "/cookies/set?k1=v1&k2=v2")
|
||||
|
||||
r2 = s.get(httpbin.url + "/cookies")
|
||||
assert len(r2.json()['cookies']) == 2
|
||||
assert len(r2.json()["cookies"]) == 2
|
||||
|
||||
|
||||
def test_amazon_doctype(tmpdir):
|
||||
# amazon gzips its homepage. For some reason, in requests 2.7, it's not
|
||||
# getting gunzipped.
|
||||
with vcr.use_cassette(str(tmpdir.join('amz.yml'))):
|
||||
r = requests.get('http://www.amazon.com', verify=False)
|
||||
assert 'html' in r.text
|
||||
with vcr.use_cassette(str(tmpdir.join("amz.yml"))):
|
||||
r = requests.get("http://www.amazon.com", verify=False)
|
||||
assert "html" in r.text
|
||||
|
||||
|
||||
def start_rpc_server(q):
|
||||
httpd = xmlrpc_server.SimpleXMLRPCServer(('127.0.0.1', 0))
|
||||
httpd = xmlrpc_server.SimpleXMLRPCServer(("127.0.0.1", 0))
|
||||
httpd.register_function(pow)
|
||||
q.put('http://{}:{}'.format(*httpd.server_address))
|
||||
q.put("http://{}:{}".format(*httpd.server_address))
|
||||
httpd.serve_forever()
|
||||
|
||||
|
||||
@pytest.yield_fixture(scope='session')
|
||||
@pytest.yield_fixture(scope="session")
|
||||
def rpc_server():
|
||||
q = multiprocessing.Queue()
|
||||
proxy_process = multiprocessing.Process(
|
||||
target=start_rpc_server,
|
||||
args=(q,)
|
||||
)
|
||||
proxy_process = multiprocessing.Process(target=start_rpc_server, args=(q,))
|
||||
try:
|
||||
proxy_process.start()
|
||||
yield q.get()
|
||||
@@ -103,11 +98,11 @@ def rpc_server():
|
||||
|
||||
|
||||
def test_xmlrpclib(tmpdir, rpc_server):
|
||||
with vcr.use_cassette(str(tmpdir.join('xmlrpcvideo.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("xmlrpcvideo.yaml"))):
|
||||
roundup_server = xmlrpc_client.ServerProxy(rpc_server, allow_none=True)
|
||||
original_schema = roundup_server.pow(2, 4)
|
||||
|
||||
with vcr.use_cassette(str(tmpdir.join('xmlrpcvideo.yaml'))):
|
||||
with vcr.use_cassette(str(tmpdir.join("xmlrpcvideo.yaml"))):
|
||||
roundup_server = xmlrpc_client.ServerProxy(rpc_server, allow_none=True)
|
||||
second_schema = roundup_server.pow(2, 4)
|
||||
|
||||
|
||||
@@ -14,31 +14,36 @@ from vcr.stubs import VCRHTTPSConnection
|
||||
|
||||
|
||||
def test_cassette_load(tmpdir):
|
||||
a_file = tmpdir.join('test_cassette.yml')
|
||||
a_file.write(yaml.dump({'interactions': [
|
||||
{'request': {'body': '', 'uri': 'foo', 'method': 'GET', 'headers': {}},
|
||||
'response': 'bar'}
|
||||
]}))
|
||||
a_file = tmpdir.join("test_cassette.yml")
|
||||
a_file.write(
|
||||
yaml.dump(
|
||||
{
|
||||
"interactions": [
|
||||
{"request": {"body": "", "uri": "foo", "method": "GET", "headers": {}}, "response": "bar"}
|
||||
]
|
||||
}
|
||||
)
|
||||
)
|
||||
a_cassette = Cassette.load(path=str(a_file))
|
||||
assert len(a_cassette) == 1
|
||||
|
||||
|
||||
def test_cassette_not_played():
|
||||
a = Cassette('test')
|
||||
a = Cassette("test")
|
||||
assert not a.play_count
|
||||
|
||||
|
||||
def test_cassette_append():
|
||||
a = Cassette('test')
|
||||
a.append('foo', 'bar')
|
||||
assert a.requests == ['foo']
|
||||
assert a.responses == ['bar']
|
||||
a = Cassette("test")
|
||||
a.append("foo", "bar")
|
||||
assert a.requests == ["foo"]
|
||||
assert a.responses == ["bar"]
|
||||
|
||||
|
||||
def test_cassette_len():
|
||||
a = Cassette('test')
|
||||
a.append('foo', 'bar')
|
||||
a.append('foo2', 'bar2')
|
||||
a = Cassette("test")
|
||||
a.append("foo", "bar")
|
||||
a.append("foo2", "bar2")
|
||||
assert len(a) == 2
|
||||
|
||||
|
||||
@@ -46,34 +51,34 @@ def _mock_requests_match(request1, request2, matchers):
|
||||
return request1 == request2
|
||||
|
||||
|
||||
@mock.patch('vcr.cassette.requests_match', _mock_requests_match)
|
||||
@mock.patch("vcr.cassette.requests_match", _mock_requests_match)
|
||||
def test_cassette_contains():
|
||||
a = Cassette('test')
|
||||
a.append('foo', 'bar')
|
||||
assert 'foo' in a
|
||||
a = Cassette("test")
|
||||
a.append("foo", "bar")
|
||||
assert "foo" in a
|
||||
|
||||
|
||||
@mock.patch('vcr.cassette.requests_match', _mock_requests_match)
|
||||
@mock.patch("vcr.cassette.requests_match", _mock_requests_match)
|
||||
def test_cassette_responses_of():
|
||||
a = Cassette('test')
|
||||
a.append('foo', 'bar')
|
||||
assert a.responses_of('foo') == ['bar']
|
||||
a = Cassette("test")
|
||||
a.append("foo", "bar")
|
||||
assert a.responses_of("foo") == ["bar"]
|
||||
|
||||
|
||||
@mock.patch('vcr.cassette.requests_match', _mock_requests_match)
|
||||
@mock.patch("vcr.cassette.requests_match", _mock_requests_match)
|
||||
def test_cassette_get_missing_response():
|
||||
a = Cassette('test')
|
||||
a = Cassette("test")
|
||||
with pytest.raises(UnhandledHTTPRequestError):
|
||||
a.responses_of('foo')
|
||||
a.responses_of("foo")
|
||||
|
||||
|
||||
@mock.patch('vcr.cassette.requests_match', _mock_requests_match)
|
||||
@mock.patch("vcr.cassette.requests_match", _mock_requests_match)
|
||||
def test_cassette_cant_read_same_request_twice():
|
||||
a = Cassette('test')
|
||||
a.append('foo', 'bar')
|
||||
a.play_response('foo')
|
||||
a = Cassette("test")
|
||||
a.append("foo", "bar")
|
||||
a.play_response("foo")
|
||||
with pytest.raises(UnhandledHTTPRequestError):
|
||||
a.play_response('foo')
|
||||
a.play_response("foo")
|
||||
|
||||
|
||||
def make_get_request():
|
||||
@@ -82,62 +87,61 @@ def make_get_request():
|
||||
return conn.getresponse()
|
||||
|
||||
|
||||
@mock.patch('vcr.cassette.requests_match', return_value=True)
|
||||
@mock.patch('vcr.cassette.FilesystemPersister.load_cassette',
|
||||
classmethod(lambda *args, **kwargs: (('foo',), (mock.MagicMock(),))))
|
||||
@mock.patch('vcr.cassette.Cassette.can_play_response_for', return_value=True)
|
||||
@mock.patch('vcr.stubs.VCRHTTPResponse')
|
||||
@mock.patch("vcr.cassette.requests_match", return_value=True)
|
||||
@mock.patch(
|
||||
"vcr.cassette.FilesystemPersister.load_cassette",
|
||||
classmethod(lambda *args, **kwargs: (("foo",), (mock.MagicMock(),))),
|
||||
)
|
||||
@mock.patch("vcr.cassette.Cassette.can_play_response_for", return_value=True)
|
||||
@mock.patch("vcr.stubs.VCRHTTPResponse")
|
||||
def test_function_decorated_with_use_cassette_can_be_invoked_multiple_times(*args):
|
||||
decorated_function = Cassette.use(path='test')(make_get_request)
|
||||
decorated_function = Cassette.use(path="test")(make_get_request)
|
||||
for i in range(4):
|
||||
decorated_function()
|
||||
|
||||
|
||||
def test_arg_getter_functionality():
|
||||
arg_getter = mock.Mock(return_value={'path': 'test'})
|
||||
arg_getter = mock.Mock(return_value={"path": "test"})
|
||||
context_decorator = Cassette.use_arg_getter(arg_getter)
|
||||
|
||||
with context_decorator as cassette:
|
||||
assert cassette._path == 'test'
|
||||
assert cassette._path == "test"
|
||||
|
||||
arg_getter.return_value = {'path': 'other'}
|
||||
arg_getter.return_value = {"path": "other"}
|
||||
|
||||
with context_decorator as cassette:
|
||||
assert cassette._path == 'other'
|
||||
assert cassette._path == "other"
|
||||
|
||||
arg_getter.return_value = {'path': 'other', 'filter_headers': ('header_name',)}
|
||||
arg_getter.return_value = {"path": "other", "filter_headers": ("header_name",)}
|
||||
|
||||
@context_decorator
|
||||
def function():
|
||||
pass
|
||||
|
||||
with mock.patch.object(
|
||||
Cassette, 'load',
|
||||
return_value=mock.MagicMock(inject=False)
|
||||
) as cassette_load:
|
||||
with mock.patch.object(Cassette, "load", return_value=mock.MagicMock(inject=False)) as cassette_load:
|
||||
function()
|
||||
cassette_load.assert_called_once_with(**arg_getter.return_value)
|
||||
|
||||
|
||||
def test_cassette_not_all_played():
|
||||
a = Cassette('test')
|
||||
a.append('foo', 'bar')
|
||||
a = Cassette("test")
|
||||
a.append("foo", "bar")
|
||||
assert not a.all_played
|
||||
|
||||
|
||||
@mock.patch('vcr.cassette.requests_match', _mock_requests_match)
|
||||
@mock.patch("vcr.cassette.requests_match", _mock_requests_match)
|
||||
def test_cassette_all_played():
|
||||
a = Cassette('test')
|
||||
a.append('foo', 'bar')
|
||||
a.play_response('foo')
|
||||
a = Cassette("test")
|
||||
a.append("foo", "bar")
|
||||
a.play_response("foo")
|
||||
assert a.all_played
|
||||
|
||||
|
||||
@mock.patch('vcr.cassette.requests_match', _mock_requests_match)
|
||||
@mock.patch("vcr.cassette.requests_match", _mock_requests_match)
|
||||
def test_cassette_rewound():
|
||||
a = Cassette('test')
|
||||
a.append('foo', 'bar')
|
||||
a.play_response('foo')
|
||||
a = Cassette("test")
|
||||
a.append("foo", "bar")
|
||||
a.play_response("foo")
|
||||
assert a.all_played
|
||||
|
||||
a.rewind()
|
||||
@@ -145,53 +149,57 @@ def test_cassette_rewound():
|
||||
|
||||
|
||||
def test_before_record_response():
|
||||
before_record_response = mock.Mock(return_value='mutated')
|
||||
cassette = Cassette('test', before_record_response=before_record_response)
|
||||
cassette.append('req', 'res')
|
||||
before_record_response = mock.Mock(return_value="mutated")
|
||||
cassette = Cassette("test", before_record_response=before_record_response)
|
||||
cassette.append("req", "res")
|
||||
|
||||
before_record_response.assert_called_once_with('res')
|
||||
assert cassette.responses[0] == 'mutated'
|
||||
before_record_response.assert_called_once_with("res")
|
||||
assert cassette.responses[0] == "mutated"
|
||||
|
||||
|
||||
def assert_get_response_body_is(value):
|
||||
conn = httplib.HTTPConnection("www.python.org")
|
||||
conn.request("GET", "/index.html")
|
||||
assert conn.getresponse().read().decode('utf8') == value
|
||||
assert conn.getresponse().read().decode("utf8") == value
|
||||
|
||||
|
||||
@mock.patch('vcr.cassette.requests_match', _mock_requests_match)
|
||||
@mock.patch('vcr.cassette.Cassette.can_play_response_for', return_value=True)
|
||||
@mock.patch('vcr.cassette.Cassette._save', return_value=True)
|
||||
@mock.patch("vcr.cassette.requests_match", _mock_requests_match)
|
||||
@mock.patch("vcr.cassette.Cassette.can_play_response_for", return_value=True)
|
||||
@mock.patch("vcr.cassette.Cassette._save", return_value=True)
|
||||
def test_nesting_cassette_context_managers(*args):
|
||||
first_response = {'body': {'string': b'first_response'}, 'headers': {},
|
||||
'status': {'message': 'm', 'code': 200}}
|
||||
first_response = {
|
||||
"body": {"string": b"first_response"},
|
||||
"headers": {},
|
||||
"status": {"message": "m", "code": 200},
|
||||
}
|
||||
|
||||
second_response = copy.deepcopy(first_response)
|
||||
second_response['body']['string'] = b'second_response'
|
||||
second_response["body"]["string"] = b"second_response"
|
||||
|
||||
with contextlib.ExitStack() as exit_stack:
|
||||
first_cassette = exit_stack.enter_context(Cassette.use(path='test'))
|
||||
exit_stack.enter_context(mock.patch.object(first_cassette, 'play_response',
|
||||
return_value=first_response))
|
||||
assert_get_response_body_is('first_response')
|
||||
first_cassette = exit_stack.enter_context(Cassette.use(path="test"))
|
||||
exit_stack.enter_context(
|
||||
mock.patch.object(first_cassette, "play_response", return_value=first_response)
|
||||
)
|
||||
assert_get_response_body_is("first_response")
|
||||
|
||||
# Make sure a second cassette can supercede the first
|
||||
with Cassette.use(path='test') as second_cassette:
|
||||
with mock.patch.object(second_cassette, 'play_response', return_value=second_response):
|
||||
assert_get_response_body_is('second_response')
|
||||
with Cassette.use(path="test") as second_cassette:
|
||||
with mock.patch.object(second_cassette, "play_response", return_value=second_response):
|
||||
assert_get_response_body_is("second_response")
|
||||
|
||||
# Now the first cassette should be back in effect
|
||||
assert_get_response_body_is('first_response')
|
||||
assert_get_response_body_is("first_response")
|
||||
|
||||
|
||||
def test_nesting_context_managers_by_checking_references_of_http_connection():
|
||||
original = httplib.HTTPConnection
|
||||
with Cassette.use(path='test'):
|
||||
with Cassette.use(path="test"):
|
||||
first_cassette_HTTPConnection = httplib.HTTPConnection
|
||||
with Cassette.use(path='test'):
|
||||
with Cassette.use(path="test"):
|
||||
second_cassette_HTTPConnection = httplib.HTTPConnection
|
||||
assert second_cassette_HTTPConnection is not first_cassette_HTTPConnection
|
||||
with Cassette.use(path='test'):
|
||||
with Cassette.use(path="test"):
|
||||
assert httplib.HTTPConnection is not second_cassette_HTTPConnection
|
||||
with force_reset():
|
||||
assert httplib.HTTPConnection is original
|
||||
@@ -202,14 +210,13 @@ def test_nesting_context_managers_by_checking_references_of_http_connection():
|
||||
def test_custom_patchers():
|
||||
class Test(object):
|
||||
attribute = None
|
||||
with Cassette.use(path='custom_patches',
|
||||
custom_patches=((Test, 'attribute', VCRHTTPSConnection),)):
|
||||
|
||||
with Cassette.use(path="custom_patches", custom_patches=((Test, "attribute", VCRHTTPSConnection),)):
|
||||
assert issubclass(Test.attribute, VCRHTTPSConnection)
|
||||
assert VCRHTTPSConnection is not Test.attribute
|
||||
old_attribute = Test.attribute
|
||||
|
||||
with Cassette.use(path='custom_patches',
|
||||
custom_patches=((Test, 'attribute', VCRHTTPSConnection),)):
|
||||
with Cassette.use(path="custom_patches", custom_patches=((Test, "attribute", VCRHTTPSConnection),)):
|
||||
assert issubclass(Test.attribute, VCRHTTPSConnection)
|
||||
assert VCRHTTPSConnection is not Test.attribute
|
||||
assert Test.attribute is not old_attribute
|
||||
@@ -223,15 +230,15 @@ def test_decorated_functions_are_reentrant():
|
||||
info = {"second": False}
|
||||
original_conn = httplib.HTTPConnection
|
||||
|
||||
@Cassette.use(path='whatever', inject=True)
|
||||
@Cassette.use(path="whatever", inject=True)
|
||||
def test_function(cassette):
|
||||
if info['second']:
|
||||
assert httplib.HTTPConnection is not info['first_conn']
|
||||
if info["second"]:
|
||||
assert httplib.HTTPConnection is not info["first_conn"]
|
||||
else:
|
||||
info['first_conn'] = httplib.HTTPConnection
|
||||
info['second'] = True
|
||||
info["first_conn"] = httplib.HTTPConnection
|
||||
info["second"] = True
|
||||
test_function()
|
||||
assert httplib.HTTPConnection is info['first_conn']
|
||||
assert httplib.HTTPConnection is info["first_conn"]
|
||||
|
||||
test_function()
|
||||
assert httplib.HTTPConnection is original_conn
|
||||
@@ -240,43 +247,39 @@ def test_decorated_functions_are_reentrant():
|
||||
def test_cassette_use_called_without_path_uses_function_to_generate_path():
|
||||
@Cassette.use(inject=True)
|
||||
def function_name(cassette):
|
||||
assert cassette._path == 'function_name'
|
||||
assert cassette._path == "function_name"
|
||||
|
||||
function_name()
|
||||
|
||||
|
||||
def test_path_transformer_with_function_path():
|
||||
def path_transformer(path):
|
||||
return os.path.join('a', path)
|
||||
return os.path.join("a", path)
|
||||
|
||||
@Cassette.use(inject=True, path_transformer=path_transformer)
|
||||
def function_name(cassette):
|
||||
assert cassette._path == os.path.join('a', 'function_name')
|
||||
assert cassette._path == os.path.join("a", "function_name")
|
||||
|
||||
function_name()
|
||||
|
||||
|
||||
def test_path_transformer_with_context_manager():
|
||||
with Cassette.use(
|
||||
path='b', path_transformer=lambda *args: 'a'
|
||||
) as cassette:
|
||||
assert cassette._path == 'a'
|
||||
with Cassette.use(path="b", path_transformer=lambda *args: "a") as cassette:
|
||||
assert cassette._path == "a"
|
||||
|
||||
|
||||
def test_path_transformer_None():
|
||||
with Cassette.use(
|
||||
path='a', path_transformer=None,
|
||||
) as cassette:
|
||||
assert cassette._path == 'a'
|
||||
with Cassette.use(path="a", path_transformer=None) as cassette:
|
||||
assert cassette._path == "a"
|
||||
|
||||
|
||||
def test_func_path_generator():
|
||||
def generator(function):
|
||||
return os.path.join(os.path.dirname(inspect.getfile(function)),
|
||||
function.__name__)
|
||||
return os.path.join(os.path.dirname(inspect.getfile(function)), function.__name__)
|
||||
|
||||
@Cassette.use(inject=True, func_path_generator=generator)
|
||||
def function_name(cassette):
|
||||
assert cassette._path == os.path.join(os.path.dirname(__file__), 'function_name')
|
||||
assert cassette._path == os.path.join(os.path.dirname(__file__), "function_name")
|
||||
|
||||
function_name()
|
||||
|
||||
@@ -329,7 +332,7 @@ def test_find_requests_with_most_matches_one_similar_request(mock_get_matchers_r
|
||||
|
||||
cassette = Cassette("test")
|
||||
for request in range(1, 4):
|
||||
cassette.append(request, 'response')
|
||||
cassette.append(request, "response")
|
||||
result = cassette.find_requests_with_most_matches("fake request")
|
||||
assert result == [(2, ["method", "path"], [("query", "failed : query")])]
|
||||
|
||||
@@ -344,7 +347,7 @@ def test_find_requests_with_most_matches_no_similar_requests(mock_get_matchers_r
|
||||
|
||||
cassette = Cassette("test")
|
||||
for request in range(1, 4):
|
||||
cassette.append(request, 'response')
|
||||
cassette.append(request, "response")
|
||||
result = cassette.find_requests_with_most_matches("fake request")
|
||||
assert result == []
|
||||
|
||||
@@ -359,9 +362,9 @@ def test_find_requests_with_most_matches_many_similar_requests(mock_get_matchers
|
||||
|
||||
cassette = Cassette("test")
|
||||
for request in range(1, 4):
|
||||
cassette.append(request, 'response')
|
||||
cassette.append(request, "response")
|
||||
result = cassette.find_requests_with_most_matches("fake request")
|
||||
assert result == [
|
||||
(1, ["method", "path"], [("query", "failed : query")]),
|
||||
(3, ["method", "path"], [("query", "failed : query")])
|
||||
(3, ["method", "path"], [("query", "failed : query")]),
|
||||
]
|
||||
|
||||
@@ -10,10 +10,7 @@ from vcr.cassette import Cassette
|
||||
"most_matches, expected_message",
|
||||
[
|
||||
# No request match found
|
||||
(
|
||||
[],
|
||||
"No similar requests, that have not been played, found."
|
||||
),
|
||||
([], "No similar requests, that have not been played, found."),
|
||||
# One matcher failed
|
||||
(
|
||||
[("similar request", ["method", "path"], [("query", "failed : query")])],
|
||||
@@ -22,8 +19,7 @@ from vcr.cassette import Cassette
|
||||
"Matchers succeeded : ['method', 'path']\n"
|
||||
"Matchers failed :\n"
|
||||
"query - assertion failure :\n"
|
||||
"failed : query\n"
|
||||
|
||||
"failed : query\n",
|
||||
),
|
||||
# Multiple failed matchers
|
||||
(
|
||||
@@ -35,14 +31,13 @@ from vcr.cassette import Cassette
|
||||
"query - assertion failure :\n"
|
||||
"failed : query\n"
|
||||
"path - assertion failure :\n"
|
||||
"failed : path\n"
|
||||
|
||||
"failed : path\n",
|
||||
),
|
||||
# Multiple similar requests
|
||||
(
|
||||
[
|
||||
("similar request", ["method"], [("query", "failed : query")]),
|
||||
("similar request 2", ["method"], [("query", "failed : query 2")])
|
||||
("similar request 2", ["method"], [("query", "failed : query 2")]),
|
||||
],
|
||||
"Found 2 similar requests with 1 different matcher(s) :\n"
|
||||
"\n1 - ('similar request').\n"
|
||||
@@ -54,20 +49,20 @@ from vcr.cassette import Cassette
|
||||
"Matchers succeeded : ['method']\n"
|
||||
"Matchers failed :\n"
|
||||
"query - assertion failure :\n"
|
||||
"failed : query 2\n"
|
||||
|
||||
"failed : query 2\n",
|
||||
),
|
||||
]
|
||||
],
|
||||
)
|
||||
def test_CannotOverwriteExistingCassetteException_get_message(
|
||||
mock_find_requests_with_most_matches, most_matches, expected_message):
|
||||
mock_find_requests_with_most_matches, most_matches, expected_message
|
||||
):
|
||||
mock_find_requests_with_most_matches.return_value = most_matches
|
||||
cassette = Cassette("path")
|
||||
failed_request = "request"
|
||||
exception_message = errors.CannotOverwriteExistingCassetteException._get_message(
|
||||
cassette, "request"
|
||||
exception_message = errors.CannotOverwriteExistingCassetteException._get_message(cassette, "request")
|
||||
expected = (
|
||||
"Can't overwrite existing cassette (%r) in your current record mode (%r).\n"
|
||||
"No match for the request (%r) was found.\n"
|
||||
"%s" % (cassette._path, cassette.record_mode, failed_request, expected_message)
|
||||
)
|
||||
expected = "Can't overwrite existing cassette (%r) in your current record mode (%r).\n" \
|
||||
"No match for the request (%r) was found.\n" \
|
||||
"%s" % (cassette._path, cassette.record_mode, failed_request, expected_message)
|
||||
assert exception_message == expected
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
from six import BytesIO
|
||||
from vcr.filters import (
|
||||
remove_headers, replace_headers,
|
||||
remove_query_parameters, replace_query_parameters,
|
||||
remove_post_data_parameters, replace_post_data_parameters,
|
||||
decode_response
|
||||
remove_headers,
|
||||
replace_headers,
|
||||
remove_query_parameters,
|
||||
replace_query_parameters,
|
||||
remove_post_data_parameters,
|
||||
replace_post_data_parameters,
|
||||
decode_response,
|
||||
)
|
||||
from vcr.compat import mock
|
||||
from vcr.request import Request
|
||||
@@ -20,31 +23,24 @@ def test_replace_headers():
|
||||
# 4. replacing a header using a callable
|
||||
# 5. removing a header using a callable
|
||||
# 6. replacing a header that doesn't exist
|
||||
headers = {
|
||||
'one': ['keep'],
|
||||
'two': ['lose'],
|
||||
'three': ['change'],
|
||||
'four': ['shout'],
|
||||
'five': ['whisper'],
|
||||
}
|
||||
request = Request('GET', 'http://google.com', '', headers)
|
||||
replace_headers(request, [
|
||||
('two', None),
|
||||
('three', 'tada'),
|
||||
('four', lambda key, value, request: value.upper()),
|
||||
('five', lambda key, value, request: None),
|
||||
('six', 'doesntexist'),
|
||||
])
|
||||
assert request.headers == {
|
||||
'one': 'keep',
|
||||
'three': 'tada',
|
||||
'four': 'SHOUT',
|
||||
}
|
||||
headers = {"one": ["keep"], "two": ["lose"], "three": ["change"], "four": ["shout"], "five": ["whisper"]}
|
||||
request = Request("GET", "http://google.com", "", headers)
|
||||
replace_headers(
|
||||
request,
|
||||
[
|
||||
("two", None),
|
||||
("three", "tada"),
|
||||
("four", lambda key, value, request: value.upper()),
|
||||
("five", lambda key, value, request: None),
|
||||
("six", "doesntexist"),
|
||||
],
|
||||
)
|
||||
assert request.headers == {"one": "keep", "three": "tada", "four": "SHOUT"}
|
||||
|
||||
|
||||
def test_replace_headers_empty():
|
||||
headers = {'hello': 'goodbye', 'secret': 'header'}
|
||||
request = Request('GET', 'http://google.com', '', headers)
|
||||
headers = {"hello": "goodbye", "secret": "header"}
|
||||
request = Request("GET", "http://google.com", "", headers)
|
||||
replace_headers(request, [])
|
||||
assert request.headers == headers
|
||||
|
||||
@@ -52,22 +48,20 @@ def test_replace_headers_empty():
|
||||
def test_replace_headers_callable():
|
||||
# This goes beyond test_replace_headers() to ensure that the callable
|
||||
# receives the expected arguments.
|
||||
headers = {'hey': 'there'}
|
||||
request = Request('GET', 'http://google.com', '', headers)
|
||||
callme = mock.Mock(return_value='ho')
|
||||
replace_headers(request, [('hey', callme)])
|
||||
assert request.headers == {'hey': 'ho'}
|
||||
assert callme.call_args == ((), {'request': request,
|
||||
'key': 'hey',
|
||||
'value': 'there'})
|
||||
headers = {"hey": "there"}
|
||||
request = Request("GET", "http://google.com", "", headers)
|
||||
callme = mock.Mock(return_value="ho")
|
||||
replace_headers(request, [("hey", callme)])
|
||||
assert request.headers == {"hey": "ho"}
|
||||
assert callme.call_args == ((), {"request": request, "key": "hey", "value": "there"})
|
||||
|
||||
|
||||
def test_remove_headers():
|
||||
# Test the backward-compatible API wrapper.
|
||||
headers = {'hello': ['goodbye'], 'secret': ['header']}
|
||||
request = Request('GET', 'http://google.com', '', headers)
|
||||
remove_headers(request, ['secret'])
|
||||
assert request.headers == {'hello': 'goodbye'}
|
||||
headers = {"hello": ["goodbye"], "secret": ["header"]}
|
||||
request = Request("GET", "http://google.com", "", headers)
|
||||
remove_headers(request, ["secret"])
|
||||
assert request.headers == {"hello": "goodbye"}
|
||||
|
||||
|
||||
def test_replace_query_parameters():
|
||||
@@ -78,48 +72,45 @@ def test_replace_query_parameters():
|
||||
# 4. replacing a parameter using a callable
|
||||
# 5. removing a parameter using a callable
|
||||
# 6. replacing a parameter that doesn't exist
|
||||
uri = 'http://g.com/?one=keep&two=lose&three=change&four=shout&five=whisper'
|
||||
request = Request('GET', uri, '', {})
|
||||
replace_query_parameters(request, [
|
||||
('two', None),
|
||||
('three', 'tada'),
|
||||
('four', lambda key, value, request: value.upper()),
|
||||
('five', lambda key, value, request: None),
|
||||
('six', 'doesntexist'),
|
||||
])
|
||||
assert request.query == [
|
||||
('four', 'SHOUT'),
|
||||
('one', 'keep'),
|
||||
('three', 'tada'),
|
||||
]
|
||||
uri = "http://g.com/?one=keep&two=lose&three=change&four=shout&five=whisper"
|
||||
request = Request("GET", uri, "", {})
|
||||
replace_query_parameters(
|
||||
request,
|
||||
[
|
||||
("two", None),
|
||||
("three", "tada"),
|
||||
("four", lambda key, value, request: value.upper()),
|
||||
("five", lambda key, value, request: None),
|
||||
("six", "doesntexist"),
|
||||
],
|
||||
)
|
||||
assert request.query == [("four", "SHOUT"), ("one", "keep"), ("three", "tada")]
|
||||
|
||||
|
||||
def test_remove_all_query_parameters():
|
||||
uri = 'http://g.com/?q=cowboys&w=1'
|
||||
request = Request('GET', uri, '', {})
|
||||
replace_query_parameters(request, [('w', None), ('q', None)])
|
||||
assert request.uri == 'http://g.com/'
|
||||
uri = "http://g.com/?q=cowboys&w=1"
|
||||
request = Request("GET", uri, "", {})
|
||||
replace_query_parameters(request, [("w", None), ("q", None)])
|
||||
assert request.uri == "http://g.com/"
|
||||
|
||||
|
||||
def test_replace_query_parameters_callable():
|
||||
# This goes beyond test_replace_query_parameters() to ensure that the
|
||||
# callable receives the expected arguments.
|
||||
uri = 'http://g.com/?hey=there'
|
||||
request = Request('GET', uri, '', {})
|
||||
callme = mock.Mock(return_value='ho')
|
||||
replace_query_parameters(request, [('hey', callme)])
|
||||
assert request.uri == 'http://g.com/?hey=ho'
|
||||
assert callme.call_args == ((), {'request': request,
|
||||
'key': 'hey',
|
||||
'value': 'there'})
|
||||
uri = "http://g.com/?hey=there"
|
||||
request = Request("GET", uri, "", {})
|
||||
callme = mock.Mock(return_value="ho")
|
||||
replace_query_parameters(request, [("hey", callme)])
|
||||
assert request.uri == "http://g.com/?hey=ho"
|
||||
assert callme.call_args == ((), {"request": request, "key": "hey", "value": "there"})
|
||||
|
||||
|
||||
def test_remove_query_parameters():
|
||||
# Test the backward-compatible API wrapper.
|
||||
uri = 'http://g.com/?q=cowboys&w=1'
|
||||
request = Request('GET', uri, '', {})
|
||||
remove_query_parameters(request, ['w'])
|
||||
assert request.uri == 'http://g.com/?q=cowboys'
|
||||
uri = "http://g.com/?q=cowboys&w=1"
|
||||
request = Request("GET", uri, "", {})
|
||||
remove_query_parameters(request, ["w"])
|
||||
assert request.uri == "http://g.com/?q=cowboys"
|
||||
|
||||
|
||||
def test_replace_post_data_parameters():
|
||||
@@ -130,38 +121,41 @@ def test_replace_post_data_parameters():
|
||||
# 4. replacing a parameter using a callable
|
||||
# 5. removing a parameter using a callable
|
||||
# 6. replacing a parameter that doesn't exist
|
||||
body = b'one=keep&two=lose&three=change&four=shout&five=whisper'
|
||||
request = Request('POST', 'http://google.com', body, {})
|
||||
replace_post_data_parameters(request, [
|
||||
('two', None),
|
||||
('three', 'tada'),
|
||||
('four', lambda key, value, request: value.upper()),
|
||||
('five', lambda key, value, request: None),
|
||||
('six', 'doesntexist'),
|
||||
])
|
||||
assert request.body == b'one=keep&three=tada&four=SHOUT'
|
||||
body = b"one=keep&two=lose&three=change&four=shout&five=whisper"
|
||||
request = Request("POST", "http://google.com", body, {})
|
||||
replace_post_data_parameters(
|
||||
request,
|
||||
[
|
||||
("two", None),
|
||||
("three", "tada"),
|
||||
("four", lambda key, value, request: value.upper()),
|
||||
("five", lambda key, value, request: None),
|
||||
("six", "doesntexist"),
|
||||
],
|
||||
)
|
||||
assert request.body == b"one=keep&three=tada&four=SHOUT"
|
||||
|
||||
|
||||
def test_remove_post_data_parameters():
|
||||
# Test the backward-compatible API wrapper.
|
||||
body = b'id=secret&foo=bar'
|
||||
request = Request('POST', 'http://google.com', body, {})
|
||||
remove_post_data_parameters(request, ['id'])
|
||||
assert request.body == b'foo=bar'
|
||||
body = b"id=secret&foo=bar"
|
||||
request = Request("POST", "http://google.com", body, {})
|
||||
remove_post_data_parameters(request, ["id"])
|
||||
assert request.body == b"foo=bar"
|
||||
|
||||
|
||||
def test_preserve_multiple_post_data_parameters():
|
||||
body = b'id=secret&foo=bar&foo=baz'
|
||||
request = Request('POST', 'http://google.com', body, {})
|
||||
replace_post_data_parameters(request, [('id', None)])
|
||||
assert request.body == b'foo=bar&foo=baz'
|
||||
body = b"id=secret&foo=bar&foo=baz"
|
||||
request = Request("POST", "http://google.com", body, {})
|
||||
replace_post_data_parameters(request, [("id", None)])
|
||||
assert request.body == b"foo=bar&foo=baz"
|
||||
|
||||
|
||||
def test_remove_all_post_data_parameters():
|
||||
body = b'id=secret&foo=bar'
|
||||
request = Request('POST', 'http://google.com', body, {})
|
||||
replace_post_data_parameters(request, [('id', None), ('foo', None)])
|
||||
assert request.body == b''
|
||||
body = b"id=secret&foo=bar"
|
||||
request = Request("POST", "http://google.com", body, {})
|
||||
replace_post_data_parameters(request, [("id", None), ("foo", None)])
|
||||
assert request.body == b""
|
||||
|
||||
|
||||
def test_replace_json_post_data_parameters():
|
||||
@@ -173,16 +167,19 @@ def test_replace_json_post_data_parameters():
|
||||
# 5. removing a parameter using a callable
|
||||
# 6. replacing a parameter that doesn't exist
|
||||
body = b'{"one": "keep", "two": "lose", "three": "change", "four": "shout", "five": "whisper"}'
|
||||
request = Request('POST', 'http://google.com', body, {})
|
||||
request.headers['Content-Type'] = 'application/json'
|
||||
replace_post_data_parameters(request, [
|
||||
('two', None),
|
||||
('three', 'tada'),
|
||||
('four', lambda key, value, request: value.upper()),
|
||||
('five', lambda key, value, request: None),
|
||||
('six', 'doesntexist'),
|
||||
])
|
||||
request_data = json.loads(request.body.decode('utf-8'))
|
||||
request = Request("POST", "http://google.com", body, {})
|
||||
request.headers["Content-Type"] = "application/json"
|
||||
replace_post_data_parameters(
|
||||
request,
|
||||
[
|
||||
("two", None),
|
||||
("three", "tada"),
|
||||
("four", lambda key, value, request: value.upper()),
|
||||
("five", lambda key, value, request: None),
|
||||
("six", "doesntexist"),
|
||||
],
|
||||
)
|
||||
request_data = json.loads(request.body.decode("utf-8"))
|
||||
expected_data = json.loads('{"one": "keep", "three": "tada", "four": "SHOUT"}')
|
||||
assert request_data == expected_data
|
||||
|
||||
@@ -190,85 +187,80 @@ def test_replace_json_post_data_parameters():
|
||||
def test_remove_json_post_data_parameters():
|
||||
# Test the backward-compatible API wrapper.
|
||||
body = b'{"id": "secret", "foo": "bar", "baz": "qux"}'
|
||||
request = Request('POST', 'http://google.com', body, {})
|
||||
request.headers['Content-Type'] = 'application/json'
|
||||
remove_post_data_parameters(request, ['id'])
|
||||
request_body_json = json.loads(request.body.decode('utf-8'))
|
||||
expected_json = json.loads(b'{"foo": "bar", "baz": "qux"}'.decode('utf-8'))
|
||||
request = Request("POST", "http://google.com", body, {})
|
||||
request.headers["Content-Type"] = "application/json"
|
||||
remove_post_data_parameters(request, ["id"])
|
||||
request_body_json = json.loads(request.body.decode("utf-8"))
|
||||
expected_json = json.loads(b'{"foo": "bar", "baz": "qux"}'.decode("utf-8"))
|
||||
assert request_body_json == expected_json
|
||||
|
||||
|
||||
def test_remove_all_json_post_data_parameters():
|
||||
body = b'{"id": "secret", "foo": "bar"}'
|
||||
request = Request('POST', 'http://google.com', body, {})
|
||||
request.headers['Content-Type'] = 'application/json'
|
||||
replace_post_data_parameters(request, [('id', None), ('foo', None)])
|
||||
assert request.body == b'{}'
|
||||
request = Request("POST", "http://google.com", body, {})
|
||||
request.headers["Content-Type"] = "application/json"
|
||||
replace_post_data_parameters(request, [("id", None), ("foo", None)])
|
||||
assert request.body == b"{}"
|
||||
|
||||
|
||||
def test_decode_response_uncompressed():
|
||||
recorded_response = {
|
||||
"status": {
|
||||
"message": "OK",
|
||||
"code": 200
|
||||
},
|
||||
"status": {"message": "OK", "code": 200},
|
||||
"headers": {
|
||||
"content-length": ["10806"],
|
||||
"date": ["Fri, 24 Oct 2014 18:35:37 GMT"],
|
||||
"content-type": ["text/html; charset=utf-8"],
|
||||
},
|
||||
"body": {
|
||||
"string": b""
|
||||
}
|
||||
"body": {"string": b""},
|
||||
}
|
||||
assert decode_response(recorded_response) == recorded_response
|
||||
|
||||
|
||||
def test_decode_response_deflate():
|
||||
body = b'deflate message'
|
||||
body = b"deflate message"
|
||||
deflate_response = {
|
||||
'body': {'string': zlib.compress(body)},
|
||||
'headers': {
|
||||
'access-control-allow-credentials': ['true'],
|
||||
'access-control-allow-origin': ['*'],
|
||||
'connection': ['keep-alive'],
|
||||
'content-encoding': ['deflate'],
|
||||
'content-length': ['177'],
|
||||
'content-type': ['application/json'],
|
||||
'date': ['Wed, 02 Dec 2015 19:44:32 GMT'],
|
||||
'server': ['nginx']
|
||||
"body": {"string": zlib.compress(body)},
|
||||
"headers": {
|
||||
"access-control-allow-credentials": ["true"],
|
||||
"access-control-allow-origin": ["*"],
|
||||
"connection": ["keep-alive"],
|
||||
"content-encoding": ["deflate"],
|
||||
"content-length": ["177"],
|
||||
"content-type": ["application/json"],
|
||||
"date": ["Wed, 02 Dec 2015 19:44:32 GMT"],
|
||||
"server": ["nginx"],
|
||||
},
|
||||
'status': {'code': 200, 'message': 'OK'}
|
||||
"status": {"code": 200, "message": "OK"},
|
||||
}
|
||||
decoded_response = decode_response(deflate_response)
|
||||
assert decoded_response['body']['string'] == body
|
||||
assert decoded_response['headers']['content-length'] == [str(len(body))]
|
||||
assert decoded_response["body"]["string"] == body
|
||||
assert decoded_response["headers"]["content-length"] == [str(len(body))]
|
||||
|
||||
|
||||
def test_decode_response_gzip():
|
||||
body = b'gzip message'
|
||||
body = b"gzip message"
|
||||
|
||||
buf = BytesIO()
|
||||
f = gzip.GzipFile('a', fileobj=buf, mode='wb')
|
||||
f = gzip.GzipFile("a", fileobj=buf, mode="wb")
|
||||
f.write(body)
|
||||
f.close()
|
||||
|
||||
compressed_body = buf.getvalue()
|
||||
buf.close()
|
||||
gzip_response = {
|
||||
'body': {'string': compressed_body},
|
||||
'headers': {
|
||||
'access-control-allow-credentials': ['true'],
|
||||
'access-control-allow-origin': ['*'],
|
||||
'connection': ['keep-alive'],
|
||||
'content-encoding': ['gzip'],
|
||||
'content-length': ['177'],
|
||||
'content-type': ['application/json'],
|
||||
'date': ['Wed, 02 Dec 2015 19:44:32 GMT'],
|
||||
'server': ['nginx']
|
||||
"body": {"string": compressed_body},
|
||||
"headers": {
|
||||
"access-control-allow-credentials": ["true"],
|
||||
"access-control-allow-origin": ["*"],
|
||||
"connection": ["keep-alive"],
|
||||
"content-encoding": ["gzip"],
|
||||
"content-length": ["177"],
|
||||
"content-type": ["application/json"],
|
||||
"date": ["Wed, 02 Dec 2015 19:44:32 GMT"],
|
||||
"server": ["nginx"],
|
||||
},
|
||||
'status': {'code': 200, 'message': 'OK'}
|
||||
"status": {"code": 200, "message": "OK"},
|
||||
}
|
||||
decoded_response = decode_response(gzip_response)
|
||||
assert decoded_response['body']['string'] == body
|
||||
assert decoded_response['headers']['content-length'] == [str(len(body))]
|
||||
assert decoded_response["body"]["string"] == body
|
||||
assert decoded_response["headers"]["content-length"] == [str(len(body))]
|
||||
|
||||
@@ -4,16 +4,14 @@ from vcr.request import Request
|
||||
|
||||
|
||||
def test_serialize_binary():
|
||||
request = Request(
|
||||
method='GET',
|
||||
uri='http://localhost/',
|
||||
body='',
|
||||
headers={},
|
||||
)
|
||||
cassette = {'requests': [request], 'responses': [{'body': b'\x8c'}]}
|
||||
request = Request(method="GET", uri="http://localhost/", body="", headers={})
|
||||
cassette = {"requests": [request], "responses": [{"body": b"\x8c"}]}
|
||||
|
||||
with pytest.raises(Exception) as e:
|
||||
serialize(cassette)
|
||||
assert e.message == "Error serializing cassette to JSON. Does this \
|
||||
assert (
|
||||
e.message
|
||||
== "Error serializing cassette to JSON. Does this \
|
||||
HTTP interaction contain binary data? If so, use a different \
|
||||
serializer (like the yaml serializer) for this request"
|
||||
)
|
||||
|
||||
@@ -9,13 +9,13 @@ from vcr import request
|
||||
# the dict contains requests with corresponding to its key difference
|
||||
# with 'base' request.
|
||||
REQUESTS = {
|
||||
'base': request.Request('GET', 'http://host.com/p?a=b', '', {}),
|
||||
'method': request.Request('POST', 'http://host.com/p?a=b', '', {}),
|
||||
'scheme': request.Request('GET', 'https://host.com:80/p?a=b', '', {}),
|
||||
'host': request.Request('GET', 'http://another-host.com/p?a=b', '', {}),
|
||||
'port': request.Request('GET', 'http://host.com:90/p?a=b', '', {}),
|
||||
'path': request.Request('GET', 'http://host.com/x?a=b', '', {}),
|
||||
'query': request.Request('GET', 'http://host.com/p?c=d', '', {}),
|
||||
"base": request.Request("GET", "http://host.com/p?a=b", "", {}),
|
||||
"method": request.Request("POST", "http://host.com/p?a=b", "", {}),
|
||||
"scheme": request.Request("GET", "https://host.com:80/p?a=b", "", {}),
|
||||
"host": request.Request("GET", "http://another-host.com/p?a=b", "", {}),
|
||||
"port": request.Request("GET", "http://host.com:90/p?a=b", "", {}),
|
||||
"path": request.Request("GET", "http://host.com/x?a=b", "", {}),
|
||||
"query": request.Request("GET", "http://host.com/p?c=d", "", {}),
|
||||
}
|
||||
|
||||
|
||||
@@ -40,103 +40,103 @@ def test_uri_matcher():
|
||||
assert matchers.uri(REQUESTS[k1], REQUESTS[k2]) is None
|
||||
|
||||
|
||||
req1_body = (b"<?xml version='1.0'?><methodCall><methodName>test</methodName>"
|
||||
b"<params><param><value><array><data><value><struct>"
|
||||
b"<member><name>a</name><value><string>1</string></value></member>"
|
||||
b"<member><name>b</name><value><string>2</string></value></member>"
|
||||
b"</struct></value></data></array></value></param></params></methodCall>")
|
||||
req2_body = (b"<?xml version='1.0'?><methodCall><methodName>test</methodName>"
|
||||
b"<params><param><value><array><data><value><struct>"
|
||||
b"<member><name>b</name><value><string>2</string></value></member>"
|
||||
b"<member><name>a</name><value><string>1</string></value></member>"
|
||||
b"</struct></value></data></array></value></param></params></methodCall>")
|
||||
req1_body = (
|
||||
b"<?xml version='1.0'?><methodCall><methodName>test</methodName>"
|
||||
b"<params><param><value><array><data><value><struct>"
|
||||
b"<member><name>a</name><value><string>1</string></value></member>"
|
||||
b"<member><name>b</name><value><string>2</string></value></member>"
|
||||
b"</struct></value></data></array></value></param></params></methodCall>"
|
||||
)
|
||||
req2_body = (
|
||||
b"<?xml version='1.0'?><methodCall><methodName>test</methodName>"
|
||||
b"<params><param><value><array><data><value><struct>"
|
||||
b"<member><name>b</name><value><string>2</string></value></member>"
|
||||
b"<member><name>a</name><value><string>1</string></value></member>"
|
||||
b"</struct></value></data></array></value></param></params></methodCall>"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("r1, r2", [
|
||||
(
|
||||
request.Request('POST', 'http://host.com/', '123', {}),
|
||||
request.Request('POST', 'http://another-host.com/',
|
||||
'123', {'Some-Header': 'value'})
|
||||
),
|
||||
(
|
||||
request.Request('POST', 'http://host.com/', 'a=1&b=2',
|
||||
{'Content-Type': 'application/x-www-form-urlencoded'}),
|
||||
request.Request('POST', 'http://host.com/', 'b=2&a=1',
|
||||
{'Content-Type': 'application/x-www-form-urlencoded'})
|
||||
),
|
||||
(
|
||||
request.Request('POST', 'http://host.com/', '123', {}),
|
||||
request.Request('POST', 'http://another-host.com/', '123', {'Some-Header': 'value'})
|
||||
),
|
||||
(
|
||||
request.Request(
|
||||
'POST', 'http://host.com/', 'a=1&b=2',
|
||||
{'Content-Type': 'application/x-www-form-urlencoded'}
|
||||
@pytest.mark.parametrize(
|
||||
"r1, r2",
|
||||
[
|
||||
(
|
||||
request.Request("POST", "http://host.com/", "123", {}),
|
||||
request.Request("POST", "http://another-host.com/", "123", {"Some-Header": "value"}),
|
||||
),
|
||||
request.Request(
|
||||
'POST', 'http://host.com/', 'b=2&a=1',
|
||||
{'Content-Type': 'application/x-www-form-urlencoded'}
|
||||
)
|
||||
),
|
||||
(
|
||||
request.Request(
|
||||
'POST', 'http://host.com/', '{"a": 1, "b": 2}',
|
||||
{'Content-Type': 'application/json'}
|
||||
(
|
||||
request.Request(
|
||||
"POST", "http://host.com/", "a=1&b=2", {"Content-Type": "application/x-www-form-urlencoded"}
|
||||
),
|
||||
request.Request(
|
||||
"POST", "http://host.com/", "b=2&a=1", {"Content-Type": "application/x-www-form-urlencoded"}
|
||||
),
|
||||
),
|
||||
request.Request(
|
||||
'POST', 'http://host.com/', '{"b": 2, "a": 1}',
|
||||
{'content-type': 'application/json'}
|
||||
)
|
||||
),
|
||||
(
|
||||
request.Request(
|
||||
'POST', 'http://host.com/', req1_body,
|
||||
{'User-Agent': 'xmlrpclib', 'Content-Type': 'text/xml'}
|
||||
(
|
||||
request.Request("POST", "http://host.com/", "123", {}),
|
||||
request.Request("POST", "http://another-host.com/", "123", {"Some-Header": "value"}),
|
||||
),
|
||||
request.Request(
|
||||
'POST', 'http://host.com/', req2_body,
|
||||
{'user-agent': 'somexmlrpc', 'content-type': 'text/xml'}
|
||||
)
|
||||
),
|
||||
(
|
||||
request.Request(
|
||||
'POST', 'http://host.com/',
|
||||
'{"a": 1, "b": 2}', {'Content-Type': 'application/json'}
|
||||
(
|
||||
request.Request(
|
||||
"POST", "http://host.com/", "a=1&b=2", {"Content-Type": "application/x-www-form-urlencoded"}
|
||||
),
|
||||
request.Request(
|
||||
"POST", "http://host.com/", "b=2&a=1", {"Content-Type": "application/x-www-form-urlencoded"}
|
||||
),
|
||||
),
|
||||
request.Request(
|
||||
'POST', 'http://host.com/',
|
||||
'{"b": 2, "a": 1}', {'content-type': 'application/json'}
|
||||
)
|
||||
)
|
||||
])
|
||||
(
|
||||
request.Request(
|
||||
"POST", "http://host.com/", '{"a": 1, "b": 2}', {"Content-Type": "application/json"}
|
||||
),
|
||||
request.Request(
|
||||
"POST", "http://host.com/", '{"b": 2, "a": 1}', {"content-type": "application/json"}
|
||||
),
|
||||
),
|
||||
(
|
||||
request.Request(
|
||||
"POST", "http://host.com/", req1_body, {"User-Agent": "xmlrpclib", "Content-Type": "text/xml"}
|
||||
),
|
||||
request.Request(
|
||||
"POST",
|
||||
"http://host.com/",
|
||||
req2_body,
|
||||
{"user-agent": "somexmlrpc", "content-type": "text/xml"},
|
||||
),
|
||||
),
|
||||
(
|
||||
request.Request(
|
||||
"POST", "http://host.com/", '{"a": 1, "b": 2}', {"Content-Type": "application/json"}
|
||||
),
|
||||
request.Request(
|
||||
"POST", "http://host.com/", '{"b": 2, "a": 1}', {"content-type": "application/json"}
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_body_matcher_does_match(r1, r2):
|
||||
assert matchers.body(r1, r2) is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize("r1, r2", [
|
||||
(
|
||||
request.Request('POST', 'http://host.com/', '{"a": 1, "b": 2}', {}),
|
||||
request.Request('POST', 'http://host.com/', '{"b": 2, "a": 1}', {}),
|
||||
),
|
||||
(
|
||||
request.Request(
|
||||
'POST', 'http://host.com/',
|
||||
'{"a": 1, "b": 3}', {'Content-Type': 'application/json'}
|
||||
@pytest.mark.parametrize(
|
||||
"r1, r2",
|
||||
[
|
||||
(
|
||||
request.Request("POST", "http://host.com/", '{"a": 1, "b": 2}', {}),
|
||||
request.Request("POST", "http://host.com/", '{"b": 2, "a": 1}', {}),
|
||||
),
|
||||
request.Request(
|
||||
'POST', 'http://host.com/',
|
||||
'{"b": 2, "a": 1}', {'content-type': 'application/json'}
|
||||
)
|
||||
),
|
||||
(
|
||||
request.Request(
|
||||
'POST', 'http://host.com/', req1_body, {'Content-Type': 'text/xml'}
|
||||
(
|
||||
request.Request(
|
||||
"POST", "http://host.com/", '{"a": 1, "b": 3}', {"Content-Type": "application/json"}
|
||||
),
|
||||
request.Request(
|
||||
"POST", "http://host.com/", '{"b": 2, "a": 1}', {"content-type": "application/json"}
|
||||
),
|
||||
),
|
||||
request.Request(
|
||||
'POST', 'http://host.com/', req2_body, {'content-type': 'text/xml'}
|
||||
)
|
||||
)
|
||||
])
|
||||
(
|
||||
request.Request("POST", "http://host.com/", req1_body, {"Content-Type": "text/xml"}),
|
||||
request.Request("POST", "http://host.com/", req2_body, {"content-type": "text/xml"}),
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_body_match_does_not_match(r1, r2):
|
||||
with pytest.raises(AssertionError):
|
||||
matchers.body(r1, r2)
|
||||
@@ -238,9 +238,7 @@ def test_get_assertion_message_with_details():
|
||||
],
|
||||
)
|
||||
def test_get_matchers_results(r1, r2, expected_successes, expected_failures):
|
||||
successes, failures = matchers.get_matchers_results(
|
||||
r1, r2, [matchers.method, matchers.path]
|
||||
)
|
||||
successes, failures = matchers.get_matchers_results(r1, r2, [matchers.method, matchers.path])
|
||||
assert successes == expected_successes
|
||||
assert len(failures) == len(expected_failures)
|
||||
for i, expected_failure in enumerate(expected_failures):
|
||||
@@ -251,11 +249,7 @@ def test_get_matchers_results(r1, r2, expected_successes, expected_failures):
|
||||
@mock.patch("vcr.matchers.get_matchers_results")
|
||||
@pytest.mark.parametrize(
|
||||
"successes, failures, expected_match",
|
||||
[
|
||||
(["method", "path"], [], True),
|
||||
(["method"], ["path"], False),
|
||||
([], ["method", "path"], False),
|
||||
],
|
||||
[(["method", "path"], [], True), (["method"], ["path"], False), ([], ["method", "path"], False)],
|
||||
)
|
||||
def test_requests_match(mock_get_matchers_results, successes, failures, expected_match):
|
||||
mock_get_matchers_results.return_value = (successes, failures)
|
||||
|
||||
@@ -13,33 +13,33 @@ except ImportError:
|
||||
|
||||
|
||||
def test_try_migrate_with_json(tmpdir):
|
||||
cassette = tmpdir.join('cassette.json').strpath
|
||||
shutil.copy('tests/fixtures/migration/old_cassette.json', cassette)
|
||||
cassette = tmpdir.join("cassette.json").strpath
|
||||
shutil.copy("tests/fixtures/migration/old_cassette.json", cassette)
|
||||
assert vcr.migration.try_migrate(cassette)
|
||||
with open('tests/fixtures/migration/new_cassette.json', 'r') as f:
|
||||
with open("tests/fixtures/migration/new_cassette.json", "r") as f:
|
||||
expected_json = json.load(f)
|
||||
with open(cassette, 'r') as f:
|
||||
with open(cassette, "r") as f:
|
||||
actual_json = json.load(f)
|
||||
assert actual_json == expected_json
|
||||
|
||||
|
||||
def test_try_migrate_with_yaml(tmpdir):
|
||||
cassette = tmpdir.join('cassette.yaml').strpath
|
||||
shutil.copy('tests/fixtures/migration/old_cassette.yaml', cassette)
|
||||
cassette = tmpdir.join("cassette.yaml").strpath
|
||||
shutil.copy("tests/fixtures/migration/old_cassette.yaml", cassette)
|
||||
assert vcr.migration.try_migrate(cassette)
|
||||
with open('tests/fixtures/migration/new_cassette.yaml', 'r') as f:
|
||||
with open("tests/fixtures/migration/new_cassette.yaml", "r") as f:
|
||||
expected_yaml = yaml.load(f, Loader=Loader)
|
||||
with open(cassette, 'r') as f:
|
||||
with open(cassette, "r") as f:
|
||||
actual_yaml = yaml.load(f, Loader=Loader)
|
||||
assert actual_yaml == expected_yaml
|
||||
|
||||
|
||||
def test_try_migrate_with_invalid_or_new_cassettes(tmpdir):
|
||||
cassette = tmpdir.join('cassette').strpath
|
||||
cassette = tmpdir.join("cassette").strpath
|
||||
files = [
|
||||
'tests/fixtures/migration/not_cassette.txt',
|
||||
'tests/fixtures/migration/new_cassette.yaml',
|
||||
'tests/fixtures/migration/new_cassette.json',
|
||||
"tests/fixtures/migration/not_cassette.txt",
|
||||
"tests/fixtures/migration/new_cassette.yaml",
|
||||
"tests/fixtures/migration/new_cassette.json",
|
||||
]
|
||||
for file_path in files:
|
||||
shutil.copy(file_path, cassette)
|
||||
|
||||
@@ -4,20 +4,26 @@ from vcr.persisters.filesystem import FilesystemPersister
|
||||
from vcr.serializers import jsonserializer, yamlserializer
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cassette_path, serializer", [
|
||||
('tests/fixtures/migration/old_cassette.json', jsonserializer),
|
||||
('tests/fixtures/migration/old_cassette.yaml', yamlserializer),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"cassette_path, serializer",
|
||||
[
|
||||
("tests/fixtures/migration/old_cassette.json", jsonserializer),
|
||||
("tests/fixtures/migration/old_cassette.yaml", yamlserializer),
|
||||
],
|
||||
)
|
||||
def test_load_cassette_with_old_cassettes(cassette_path, serializer):
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
FilesystemPersister.load_cassette(cassette_path, serializer)
|
||||
assert "run the migration script" in excinfo.exconly()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cassette_path, serializer", [
|
||||
('tests/fixtures/migration/not_cassette.txt', jsonserializer),
|
||||
('tests/fixtures/migration/not_cassette.txt', yamlserializer),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"cassette_path, serializer",
|
||||
[
|
||||
("tests/fixtures/migration/not_cassette.txt", jsonserializer),
|
||||
("tests/fixtures/migration/not_cassette.txt", yamlserializer),
|
||||
],
|
||||
)
|
||||
def test_load_cassette_with_invalid_cassettes(cassette_path, serializer):
|
||||
with pytest.raises(Exception) as excinfo:
|
||||
FilesystemPersister.load_cassette(cassette_path, serializer)
|
||||
|
||||
@@ -3,51 +3,60 @@ import pytest
|
||||
from vcr.request import Request, HeadersDict
|
||||
|
||||
|
||||
@pytest.mark.parametrize("method, uri, expected_str", [
|
||||
('GET', 'http://www.google.com/', '<Request (GET) http://www.google.com/>'),
|
||||
('OPTIONS', '*', '<Request (OPTIONS) *>'),
|
||||
('CONNECT', 'host.some.where:1234', '<Request (CONNECT) host.some.where:1234>')
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"method, uri, expected_str",
|
||||
[
|
||||
("GET", "http://www.google.com/", "<Request (GET) http://www.google.com/>"),
|
||||
("OPTIONS", "*", "<Request (OPTIONS) *>"),
|
||||
("CONNECT", "host.some.where:1234", "<Request (CONNECT) host.some.where:1234>"),
|
||||
],
|
||||
)
|
||||
def test_str(method, uri, expected_str):
|
||||
assert str(Request(method, uri, '', {})) == expected_str
|
||||
assert str(Request(method, uri, "", {})) == expected_str
|
||||
|
||||
|
||||
def test_headers():
|
||||
headers = {'X-Header1': ['h1'], 'X-Header2': 'h2'}
|
||||
req = Request('GET', 'http://go.com/', '', headers)
|
||||
assert req.headers == {'X-Header1': 'h1', 'X-Header2': 'h2'}
|
||||
req.headers['X-Header1'] = 'h11'
|
||||
assert req.headers == {'X-Header1': 'h11', 'X-Header2': 'h2'}
|
||||
headers = {"X-Header1": ["h1"], "X-Header2": "h2"}
|
||||
req = Request("GET", "http://go.com/", "", headers)
|
||||
assert req.headers == {"X-Header1": "h1", "X-Header2": "h2"}
|
||||
req.headers["X-Header1"] = "h11"
|
||||
assert req.headers == {"X-Header1": "h11", "X-Header2": "h2"}
|
||||
|
||||
|
||||
def test_add_header_deprecated():
|
||||
req = Request('GET', 'http://go.com/', '', {})
|
||||
pytest.deprecated_call(req.add_header, 'foo', 'bar')
|
||||
assert req.headers == {'foo': 'bar'}
|
||||
req = Request("GET", "http://go.com/", "", {})
|
||||
pytest.deprecated_call(req.add_header, "foo", "bar")
|
||||
assert req.headers == {"foo": "bar"}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("uri, expected_port", [
|
||||
('http://go.com/', 80),
|
||||
('http://go.com:80/', 80),
|
||||
('http://go.com:3000/', 3000),
|
||||
('https://go.com/', 443),
|
||||
('https://go.com:443/', 443),
|
||||
('https://go.com:3000/', 3000),
|
||||
('*', None)
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"uri, expected_port",
|
||||
[
|
||||
("http://go.com/", 80),
|
||||
("http://go.com:80/", 80),
|
||||
("http://go.com:3000/", 3000),
|
||||
("https://go.com/", 443),
|
||||
("https://go.com:443/", 443),
|
||||
("https://go.com:3000/", 3000),
|
||||
("*", None),
|
||||
],
|
||||
)
|
||||
def test_port(uri, expected_port):
|
||||
req = Request('GET', uri, '', {})
|
||||
req = Request("GET", uri, "", {})
|
||||
assert req.port == expected_port
|
||||
|
||||
|
||||
@pytest.mark.parametrize("method, uri", [
|
||||
('GET', 'http://go.com/'),
|
||||
('GET', 'http://go.com:80/'),
|
||||
('CONNECT', 'localhost:1234'),
|
||||
('OPTIONS', '*')
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"method, uri",
|
||||
[
|
||||
("GET", "http://go.com/"),
|
||||
("GET", "http://go.com:80/"),
|
||||
("CONNECT", "localhost:1234"),
|
||||
("OPTIONS", "*"),
|
||||
],
|
||||
)
|
||||
def test_uri(method, uri):
|
||||
assert Request(method, uri, '', {}).uri == uri
|
||||
assert Request(method, uri, "", {}).uri == uri
|
||||
|
||||
|
||||
def test_HeadersDict():
|
||||
@@ -55,23 +64,23 @@ def test_HeadersDict():
|
||||
# Simple test of CaseInsensitiveDict
|
||||
h = HeadersDict()
|
||||
assert h == {}
|
||||
h['Content-Type'] = 'application/json'
|
||||
assert h == {'Content-Type': 'application/json'}
|
||||
assert h['content-type'] == 'application/json'
|
||||
assert h['CONTENT-TYPE'] == 'application/json'
|
||||
h["Content-Type"] = "application/json"
|
||||
assert h == {"Content-Type": "application/json"}
|
||||
assert h["content-type"] == "application/json"
|
||||
assert h["CONTENT-TYPE"] == "application/json"
|
||||
|
||||
# Test feature of HeadersDict: devolve list to first element
|
||||
h = HeadersDict()
|
||||
assert h == {}
|
||||
h['x'] = ['foo', 'bar']
|
||||
assert h == {'x': 'foo'}
|
||||
h["x"] = ["foo", "bar"]
|
||||
assert h == {"x": "foo"}
|
||||
|
||||
# Test feature of HeadersDict: preserve original key case
|
||||
h = HeadersDict()
|
||||
assert h == {}
|
||||
h['Content-Type'] = 'application/json'
|
||||
assert h == {'Content-Type': 'application/json'}
|
||||
h['content-type'] = 'text/plain'
|
||||
assert h == {'Content-Type': 'text/plain'}
|
||||
h['CONtent-tyPE'] = 'whoa'
|
||||
assert h == {'Content-Type': 'whoa'}
|
||||
h["Content-Type"] = "application/json"
|
||||
assert h == {"Content-Type": "application/json"}
|
||||
h["content-type"] = "text/plain"
|
||||
assert h == {"Content-Type": "text/plain"}
|
||||
h["CONtent-tyPE"] = "whoa"
|
||||
assert h == {"Content-Type": "whoa"}
|
||||
|
||||
@@ -9,10 +9,7 @@ from vcr.stubs import VCRHTTPResponse
|
||||
|
||||
def test_response_should_have_headers_field():
|
||||
recorded_response = {
|
||||
"status": {
|
||||
"message": "OK",
|
||||
"code": 200
|
||||
},
|
||||
"status": {"message": "OK", "code": 200},
|
||||
"headers": {
|
||||
"content-length": ["0"],
|
||||
"server": ["gunicorn/18.0"],
|
||||
@@ -22,9 +19,7 @@ def test_response_should_have_headers_field():
|
||||
"access-control-allow-origin": ["*"],
|
||||
"content-type": ["text/html; charset=utf-8"],
|
||||
},
|
||||
"body": {
|
||||
"string": b""
|
||||
}
|
||||
"body": {"string": b""},
|
||||
}
|
||||
response = VCRHTTPResponse(recorded_response)
|
||||
|
||||
@@ -33,19 +28,14 @@ def test_response_should_have_headers_field():
|
||||
|
||||
def test_response_headers_should_be_equal_to_msg():
|
||||
recorded_response = {
|
||||
"status": {
|
||||
"message": b"OK",
|
||||
"code": 200
|
||||
},
|
||||
"status": {"message": b"OK", "code": 200},
|
||||
"headers": {
|
||||
"content-length": ["0"],
|
||||
"server": ["gunicorn/18.0"],
|
||||
"connection": ["Close"],
|
||||
"content-type": ["text/html; charset=utf-8"],
|
||||
},
|
||||
"body": {
|
||||
"string": b""
|
||||
}
|
||||
"body": {"string": b""},
|
||||
}
|
||||
response = VCRHTTPResponse(recorded_response)
|
||||
|
||||
@@ -54,23 +44,18 @@ def test_response_headers_should_be_equal_to_msg():
|
||||
|
||||
def test_response_headers_should_have_correct_values():
|
||||
recorded_response = {
|
||||
"status": {
|
||||
"message": "OK",
|
||||
"code": 200
|
||||
},
|
||||
"status": {"message": "OK", "code": 200},
|
||||
"headers": {
|
||||
"content-length": ["10806"],
|
||||
"date": ["Fri, 24 Oct 2014 18:35:37 GMT"],
|
||||
"content-type": ["text/html; charset=utf-8"],
|
||||
},
|
||||
"body": {
|
||||
"string": b""
|
||||
}
|
||||
"body": {"string": b""},
|
||||
}
|
||||
response = VCRHTTPResponse(recorded_response)
|
||||
|
||||
assert response.headers.get('content-length') == "10806"
|
||||
assert response.headers.get('date') == "Fri, 24 Oct 2014 18:35:37 GMT"
|
||||
assert response.headers.get("content-length") == "10806"
|
||||
assert response.headers.get("date") == "Fri, 24 Oct 2014 18:35:37 GMT"
|
||||
|
||||
|
||||
@unittest.skipIf(six.PY2, "Regression test for Python3 only")
|
||||
@@ -80,10 +65,7 @@ def test_response_parses_correctly_and_fp_attribute_error_is_not_thrown():
|
||||
:return:
|
||||
"""
|
||||
recorded_response = {
|
||||
"status": {
|
||||
"message": "OK",
|
||||
"code": 200
|
||||
},
|
||||
"status": {"message": "OK", "code": 200},
|
||||
"headers": {
|
||||
"content-length": ["0"],
|
||||
"server": ["gunicorn/18.0"],
|
||||
@@ -95,28 +77,27 @@ def test_response_parses_correctly_and_fp_attribute_error_is_not_thrown():
|
||||
},
|
||||
"body": {
|
||||
"string": b"\nPMID- 19416910\nOWN - NLM\nSTAT- MEDLINE\nDA - 20090513\nDCOM- "
|
||||
b"20090622\nLR - "
|
||||
b"20141209\nIS - 1091-6490 (Electronic)\nIS - 0027-8424 (Linking)\nVI - "
|
||||
b"106\nIP - "
|
||||
b"19\nDP - 2009 May 12\nTI - Genetic dissection of histone deacetylase "
|
||||
b"requirement in "
|
||||
b"tumor cells.\nPG - 7751-5\nLID - 10.1073/pnas.0903139106 [doi]\nAB - "
|
||||
b"Histone "
|
||||
b"deacetylase inhibitors (HDACi) represent a new group of drugs currently\n "
|
||||
b" being "
|
||||
b"tested in a wide variety of clinical applications. They are especially\n "
|
||||
b" effective "
|
||||
b"in preclinical models of cancer where they show antiproliferative\n "
|
||||
b"action in many "
|
||||
b"different types of cancer cells. Recently, the first HDACi was\n "
|
||||
b"approved for the "
|
||||
b"treatment of cutaneous T cell lymphomas. Most HDACi currently in\n "
|
||||
b"clinical "
|
||||
|
||||
}
|
||||
b"20090622\nLR - "
|
||||
b"20141209\nIS - 1091-6490 (Electronic)\nIS - 0027-8424 (Linking)\nVI - "
|
||||
b"106\nIP - "
|
||||
b"19\nDP - 2009 May 12\nTI - Genetic dissection of histone deacetylase "
|
||||
b"requirement in "
|
||||
b"tumor cells.\nPG - 7751-5\nLID - 10.1073/pnas.0903139106 [doi]\nAB - "
|
||||
b"Histone "
|
||||
b"deacetylase inhibitors (HDACi) represent a new group of drugs currently\n "
|
||||
b" being "
|
||||
b"tested in a wide variety of clinical applications. They are especially\n "
|
||||
b" effective "
|
||||
b"in preclinical models of cancer where they show antiproliferative\n "
|
||||
b"action in many "
|
||||
b"different types of cancer cells. Recently, the first HDACi was\n "
|
||||
b"approved for the "
|
||||
b"treatment of cutaneous T cell lymphomas. Most HDACi currently in\n "
|
||||
b"clinical "
|
||||
},
|
||||
}
|
||||
vcr_response = VCRHTTPResponse(recorded_response)
|
||||
handle = io.TextIOWrapper(io.BufferedReader(vcr_response), encoding='utf-8')
|
||||
handle = io.TextIOWrapper(io.BufferedReader(vcr_response), encoding="utf-8")
|
||||
handle = iter(handle)
|
||||
articles = [line for line in handle]
|
||||
assert len(articles) > 1
|
||||
|
||||
@@ -8,28 +8,28 @@ from vcr.serializers import yamlserializer, jsonserializer, compat
|
||||
|
||||
|
||||
def test_deserialize_old_yaml_cassette():
|
||||
with open('tests/fixtures/migration/old_cassette.yaml', 'r') as f:
|
||||
with open("tests/fixtures/migration/old_cassette.yaml", "r") as f:
|
||||
with pytest.raises(ValueError):
|
||||
deserialize(f.read(), yamlserializer)
|
||||
|
||||
|
||||
def test_deserialize_old_json_cassette():
|
||||
with open('tests/fixtures/migration/old_cassette.json', 'r') as f:
|
||||
with open("tests/fixtures/migration/old_cassette.json", "r") as f:
|
||||
with pytest.raises(ValueError):
|
||||
deserialize(f.read(), jsonserializer)
|
||||
|
||||
|
||||
def test_deserialize_new_yaml_cassette():
|
||||
with open('tests/fixtures/migration/new_cassette.yaml', 'r') as f:
|
||||
with open("tests/fixtures/migration/new_cassette.yaml", "r") as f:
|
||||
deserialize(f.read(), yamlserializer)
|
||||
|
||||
|
||||
def test_deserialize_new_json_cassette():
|
||||
with open('tests/fixtures/migration/new_cassette.json', 'r') as f:
|
||||
with open("tests/fixtures/migration/new_cassette.json", "r") as f:
|
||||
deserialize(f.read(), jsonserializer)
|
||||
|
||||
|
||||
REQBODY_TEMPLATE = u'''\
|
||||
REQBODY_TEMPLATE = u"""\
|
||||
interactions:
|
||||
- request:
|
||||
body: {req_body}
|
||||
@@ -44,96 +44,76 @@ interactions:
|
||||
content-length: ['0']
|
||||
content-type: [application/json]
|
||||
status: {{code: 200, message: OK}}
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
# A cassette generated under Python 2 stores the request body as a string,
|
||||
# but the same cassette generated under Python 3 stores it as "!!binary".
|
||||
# Make sure we accept both forms, regardless of whether we're running under
|
||||
# Python 2 or 3.
|
||||
@pytest.mark.parametrize("req_body, expect", [
|
||||
# Cassette written under Python 2 (pure ASCII body)
|
||||
('x=5&y=2', b'x=5&y=2'),
|
||||
# Cassette written under Python 3 (pure ASCII body)
|
||||
('!!binary |\n eD01Jnk9Mg==', b'x=5&y=2'),
|
||||
|
||||
# Request body has non-ASCII chars (x=föo&y=2), encoded in UTF-8.
|
||||
('!!python/str "x=f\\xF6o&y=2"', b'x=f\xc3\xb6o&y=2'),
|
||||
('!!binary |\n eD1mw7ZvJnk9Mg==', b'x=f\xc3\xb6o&y=2'),
|
||||
|
||||
# Same request body, this time encoded in UTF-16. In this case, we
|
||||
# write the same YAML file under both Python 2 and 3, so there's only
|
||||
# one test case here.
|
||||
('!!binary |\n //54AD0AZgD2AG8AJgB5AD0AMgA=',
|
||||
b'\xff\xfex\x00=\x00f\x00\xf6\x00o\x00&\x00y\x00=\x002\x00'),
|
||||
|
||||
# Same again, this time encoded in ISO-8859-1.
|
||||
('!!binary |\n eD1m9m8meT0y', b'x=f\xf6o&y=2'),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"req_body, expect",
|
||||
[
|
||||
# Cassette written under Python 2 (pure ASCII body)
|
||||
("x=5&y=2", b"x=5&y=2"),
|
||||
# Cassette written under Python 3 (pure ASCII body)
|
||||
("!!binary |\n eD01Jnk9Mg==", b"x=5&y=2"),
|
||||
# Request body has non-ASCII chars (x=föo&y=2), encoded in UTF-8.
|
||||
('!!python/str "x=f\\xF6o&y=2"', b"x=f\xc3\xb6o&y=2"),
|
||||
("!!binary |\n eD1mw7ZvJnk9Mg==", b"x=f\xc3\xb6o&y=2"),
|
||||
# Same request body, this time encoded in UTF-16. In this case, we
|
||||
# write the same YAML file under both Python 2 and 3, so there's only
|
||||
# one test case here.
|
||||
(
|
||||
"!!binary |\n //54AD0AZgD2AG8AJgB5AD0AMgA=",
|
||||
b"\xff\xfex\x00=\x00f\x00\xf6\x00o\x00&\x00y\x00=\x002\x00",
|
||||
),
|
||||
# Same again, this time encoded in ISO-8859-1.
|
||||
("!!binary |\n eD1m9m8meT0y", b"x=f\xf6o&y=2"),
|
||||
],
|
||||
)
|
||||
def test_deserialize_py2py3_yaml_cassette(tmpdir, req_body, expect):
|
||||
cfile = tmpdir.join('test_cassette.yaml')
|
||||
cfile = tmpdir.join("test_cassette.yaml")
|
||||
cfile.write(REQBODY_TEMPLATE.format(req_body=req_body))
|
||||
with open(str(cfile)) as f:
|
||||
(requests, responses) = deserialize(f.read(), yamlserializer)
|
||||
assert requests[0].body == expect
|
||||
|
||||
|
||||
@mock.patch.object(jsonserializer.json, 'dumps',
|
||||
side_effect=UnicodeDecodeError('utf-8', b'unicode error in serialization',
|
||||
0, 10, 'blew up'))
|
||||
@mock.patch.object(
|
||||
jsonserializer.json,
|
||||
"dumps",
|
||||
side_effect=UnicodeDecodeError("utf-8", b"unicode error in serialization", 0, 10, "blew up"),
|
||||
)
|
||||
def test_serialize_constructs_UnicodeDecodeError(mock_dumps):
|
||||
with pytest.raises(UnicodeDecodeError):
|
||||
jsonserializer.serialize({})
|
||||
|
||||
|
||||
def test_serialize_empty_request():
|
||||
request = Request(
|
||||
method='POST',
|
||||
uri='http://localhost/',
|
||||
body='',
|
||||
headers={},
|
||||
)
|
||||
request = Request(method="POST", uri="http://localhost/", body="", headers={})
|
||||
|
||||
serialize(
|
||||
{'requests': [request], 'responses': [{}]},
|
||||
jsonserializer
|
||||
)
|
||||
serialize({"requests": [request], "responses": [{}]}, jsonserializer)
|
||||
|
||||
|
||||
def test_serialize_json_request():
|
||||
request = Request(
|
||||
method='POST',
|
||||
uri='http://localhost/',
|
||||
body="{'hello': 'world'}",
|
||||
headers={},
|
||||
)
|
||||
request = Request(method="POST", uri="http://localhost/", body="{'hello': 'world'}", headers={})
|
||||
|
||||
serialize(
|
||||
{'requests': [request], 'responses': [{}]},
|
||||
jsonserializer
|
||||
)
|
||||
serialize({"requests": [request], "responses": [{}]}, jsonserializer)
|
||||
|
||||
|
||||
def test_serialize_binary_request():
|
||||
msg = "Does this HTTP interaction contain binary data?"
|
||||
|
||||
request = Request(
|
||||
method='POST',
|
||||
uri='http://localhost/',
|
||||
body=b'\x8c',
|
||||
headers={},
|
||||
)
|
||||
request = Request(method="POST", uri="http://localhost/", body=b"\x8c", headers={})
|
||||
|
||||
try:
|
||||
serialize(
|
||||
{'requests': [request], 'responses': [{}]},
|
||||
jsonserializer
|
||||
)
|
||||
serialize({"requests": [request], "responses": [{}]}, jsonserializer)
|
||||
except (UnicodeDecodeError, TypeError) as exc:
|
||||
assert msg in str(exc)
|
||||
|
||||
|
||||
def test_deserialize_no_body_string():
|
||||
data = {'body': {'string': None}}
|
||||
data = {"body": {"string": None}}
|
||||
output = compat.convert_to_bytes(data)
|
||||
assert data == output
|
||||
|
||||
@@ -4,15 +4,14 @@ from vcr.cassette import Cassette
|
||||
|
||||
|
||||
class TestVCRConnection(object):
|
||||
|
||||
def test_setting_of_attributes_get_propogated_to_real_connection(self):
|
||||
vcr_connection = VCRHTTPSConnection('www.examplehost.com')
|
||||
vcr_connection.ssl_version = 'example_ssl_version'
|
||||
assert vcr_connection.real_connection.ssl_version == 'example_ssl_version'
|
||||
vcr_connection = VCRHTTPSConnection("www.examplehost.com")
|
||||
vcr_connection.ssl_version = "example_ssl_version"
|
||||
assert vcr_connection.real_connection.ssl_version == "example_ssl_version"
|
||||
|
||||
@mock.patch('vcr.cassette.Cassette.can_play_response_for', return_value=False)
|
||||
@mock.patch("vcr.cassette.Cassette.can_play_response_for", return_value=False)
|
||||
def testing_connect(*args):
|
||||
vcr_connection = VCRHTTPSConnection('www.google.com')
|
||||
vcr_connection.cassette = Cassette('test', record_mode='all')
|
||||
vcr_connection = VCRHTTPSConnection("www.google.com")
|
||||
vcr_connection.cassette = Cassette("test", record_mode="all")
|
||||
vcr_connection.real_connection.connect()
|
||||
assert vcr_connection.real_connection.sock is not None
|
||||
|
||||
@@ -14,75 +14,75 @@ def test_vcr_use_cassette():
|
||||
record_mode = mock.Mock()
|
||||
test_vcr = VCR(record_mode=record_mode)
|
||||
with mock.patch(
|
||||
'vcr.cassette.Cassette.load',
|
||||
return_value=mock.MagicMock(inject=False)
|
||||
"vcr.cassette.Cassette.load", return_value=mock.MagicMock(inject=False)
|
||||
) as mock_cassette_load:
|
||||
|
||||
@test_vcr.use_cassette('test')
|
||||
@test_vcr.use_cassette("test")
|
||||
def function():
|
||||
pass
|
||||
|
||||
assert mock_cassette_load.call_count == 0
|
||||
function()
|
||||
assert mock_cassette_load.call_args[1]['record_mode'] is record_mode
|
||||
assert mock_cassette_load.call_args[1]["record_mode"] is record_mode
|
||||
|
||||
# Make sure that calls to function now use cassettes with the
|
||||
# new filter_header_settings
|
||||
test_vcr.record_mode = mock.Mock()
|
||||
function()
|
||||
assert mock_cassette_load.call_args[1]['record_mode'] == test_vcr.record_mode
|
||||
assert mock_cassette_load.call_args[1]["record_mode"] == test_vcr.record_mode
|
||||
|
||||
# Ensure that explicitly provided arguments still supercede
|
||||
# those on the vcr.
|
||||
new_record_mode = mock.Mock()
|
||||
|
||||
with test_vcr.use_cassette('test', record_mode=new_record_mode) as cassette:
|
||||
with test_vcr.use_cassette("test", record_mode=new_record_mode) as cassette:
|
||||
assert cassette.record_mode == new_record_mode
|
||||
|
||||
|
||||
def test_vcr_before_record_request_params():
|
||||
base_path = 'http://httpbin.org/'
|
||||
base_path = "http://httpbin.org/"
|
||||
|
||||
def before_record_cb(request):
|
||||
if request.path != '/get':
|
||||
if request.path != "/get":
|
||||
return request
|
||||
|
||||
test_vcr = VCR(filter_headers=('cookie', ('bert', 'ernie')),
|
||||
before_record_request=before_record_cb,
|
||||
ignore_hosts=('www.test.com',), ignore_localhost=True,
|
||||
filter_query_parameters=('foo', ('tom', 'jerry')),
|
||||
filter_post_data_parameters=('posted', ('no', 'trespassing')))
|
||||
test_vcr = VCR(
|
||||
filter_headers=("cookie", ("bert", "ernie")),
|
||||
before_record_request=before_record_cb,
|
||||
ignore_hosts=("www.test.com",),
|
||||
ignore_localhost=True,
|
||||
filter_query_parameters=("foo", ("tom", "jerry")),
|
||||
filter_post_data_parameters=("posted", ("no", "trespassing")),
|
||||
)
|
||||
|
||||
with test_vcr.use_cassette('test') as cassette:
|
||||
with test_vcr.use_cassette("test") as cassette:
|
||||
# Test explicit before_record_cb
|
||||
request_get = Request('GET', base_path + 'get', '', {})
|
||||
request_get = Request("GET", base_path + "get", "", {})
|
||||
assert cassette.filter_request(request_get) is None
|
||||
request = Request('GET', base_path + 'get2', '', {})
|
||||
request = Request("GET", base_path + "get2", "", {})
|
||||
assert cassette.filter_request(request) is not None
|
||||
|
||||
# Test filter_query_parameters
|
||||
request = Request('GET', base_path + '?foo=bar', '', {})
|
||||
request = Request("GET", base_path + "?foo=bar", "", {})
|
||||
assert cassette.filter_request(request).query == []
|
||||
request = Request('GET', base_path + '?tom=nobody', '', {})
|
||||
assert cassette.filter_request(request).query == [('tom', 'jerry')]
|
||||
request = Request("GET", base_path + "?tom=nobody", "", {})
|
||||
assert cassette.filter_request(request).query == [("tom", "jerry")]
|
||||
|
||||
# Test filter_headers
|
||||
request = Request('GET', base_path + '?foo=bar', '',
|
||||
{'cookie': 'test', 'other': 'fun', 'bert': 'nobody'})
|
||||
assert (cassette.filter_request(request).headers ==
|
||||
{'other': 'fun', 'bert': 'ernie'})
|
||||
request = Request(
|
||||
"GET", base_path + "?foo=bar", "", {"cookie": "test", "other": "fun", "bert": "nobody"}
|
||||
)
|
||||
assert cassette.filter_request(request).headers == {"other": "fun", "bert": "ernie"}
|
||||
|
||||
# Test ignore_hosts
|
||||
request = Request('GET', 'http://www.test.com' + '?foo=bar', '',
|
||||
{'cookie': 'test', 'other': 'fun'})
|
||||
request = Request("GET", "http://www.test.com" + "?foo=bar", "", {"cookie": "test", "other": "fun"})
|
||||
assert cassette.filter_request(request) is None
|
||||
|
||||
# Test ignore_localhost
|
||||
request = Request('GET', 'http://localhost:8000' + '?foo=bar', '',
|
||||
{'cookie': 'test', 'other': 'fun'})
|
||||
request = Request("GET", "http://localhost:8000" + "?foo=bar", "", {"cookie": "test", "other": "fun"})
|
||||
assert cassette.filter_request(request) is None
|
||||
|
||||
with test_vcr.use_cassette('test', before_record_request=None) as cassette:
|
||||
with test_vcr.use_cassette("test", before_record_request=None) as cassette:
|
||||
# Test that before_record can be overwritten in context manager.
|
||||
assert cassette.filter_request(request_get) is not None
|
||||
|
||||
@@ -90,16 +90,16 @@ def test_vcr_before_record_request_params():
|
||||
def test_vcr_before_record_response_iterable():
|
||||
# Regression test for #191
|
||||
|
||||
request = Request('GET', '/', '', {})
|
||||
request = Request("GET", "/", "", {})
|
||||
response = object() # just can't be None
|
||||
|
||||
# Prevent actually saving the cassette
|
||||
with mock.patch('vcr.cassette.FilesystemPersister.save_cassette'):
|
||||
with mock.patch("vcr.cassette.FilesystemPersister.save_cassette"):
|
||||
|
||||
# Baseline: non-iterable before_record_response should work
|
||||
mock_filter = mock.Mock()
|
||||
vcr = VCR(before_record_response=mock_filter)
|
||||
with vcr.use_cassette('test') as cassette:
|
||||
with vcr.use_cassette("test") as cassette:
|
||||
assert mock_filter.call_count == 0
|
||||
cassette.append(request, response)
|
||||
assert mock_filter.call_count == 1
|
||||
@@ -107,22 +107,22 @@ def test_vcr_before_record_response_iterable():
|
||||
# Regression test: iterable before_record_response should work too
|
||||
mock_filter = mock.Mock()
|
||||
vcr = VCR(before_record_response=(mock_filter,))
|
||||
with vcr.use_cassette('test') as cassette:
|
||||
with vcr.use_cassette("test") as cassette:
|
||||
assert mock_filter.call_count == 0
|
||||
cassette.append(request, response)
|
||||
assert mock_filter.call_count == 1
|
||||
|
||||
|
||||
def test_before_record_response_as_filter():
|
||||
request = Request('GET', '/', '', {})
|
||||
request = Request("GET", "/", "", {})
|
||||
response = object() # just can't be None
|
||||
|
||||
# Prevent actually saving the cassette
|
||||
with mock.patch('vcr.cassette.FilesystemPersister.save_cassette'):
|
||||
with mock.patch("vcr.cassette.FilesystemPersister.save_cassette"):
|
||||
|
||||
filter_all = mock.Mock(return_value=None)
|
||||
vcr = VCR(before_record_response=filter_all)
|
||||
with vcr.use_cassette('test') as cassette:
|
||||
with vcr.use_cassette("test") as cassette:
|
||||
cassette.append(request, response)
|
||||
assert cassette.data == []
|
||||
assert not cassette.dirty
|
||||
@@ -132,22 +132,22 @@ def test_vcr_path_transformer():
|
||||
# Regression test for #199
|
||||
|
||||
# Prevent actually saving the cassette
|
||||
with mock.patch('vcr.cassette.FilesystemPersister.save_cassette'):
|
||||
with mock.patch("vcr.cassette.FilesystemPersister.save_cassette"):
|
||||
|
||||
# Baseline: path should be unchanged
|
||||
vcr = VCR()
|
||||
with vcr.use_cassette('test') as cassette:
|
||||
assert cassette._path == 'test'
|
||||
with vcr.use_cassette("test") as cassette:
|
||||
assert cassette._path == "test"
|
||||
|
||||
# Regression test: path_transformer=None should do the same.
|
||||
vcr = VCR(path_transformer=None)
|
||||
with vcr.use_cassette('test') as cassette:
|
||||
assert cassette._path == 'test'
|
||||
with vcr.use_cassette("test") as cassette:
|
||||
assert cassette._path == "test"
|
||||
|
||||
# and it should still work with cassette_library_dir
|
||||
vcr = VCR(cassette_library_dir='/foo')
|
||||
with vcr.use_cassette('test') as cassette:
|
||||
assert os.path.abspath(cassette._path) == os.path.abspath('/foo/test')
|
||||
vcr = VCR(cassette_library_dir="/foo")
|
||||
with vcr.use_cassette("test") as cassette:
|
||||
assert os.path.abspath(cassette._path) == os.path.abspath("/foo/test")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -155,7 +155,7 @@ def random_fixture():
|
||||
return 1
|
||||
|
||||
|
||||
@use_cassette('test')
|
||||
@use_cassette("test")
|
||||
def test_fixtures_with_use_cassette(random_fixture):
|
||||
# Applying a decorator to a test function that requests features can cause
|
||||
# problems if the decorator does not preserve the signature of the original
|
||||
@@ -173,15 +173,13 @@ def test_custom_patchers():
|
||||
class Test(object):
|
||||
attribute = None
|
||||
attribute2 = None
|
||||
test_vcr = VCR(custom_patches=((Test, 'attribute', VCRHTTPSConnection),))
|
||||
with test_vcr.use_cassette('custom_patches'):
|
||||
|
||||
test_vcr = VCR(custom_patches=((Test, "attribute", VCRHTTPSConnection),))
|
||||
with test_vcr.use_cassette("custom_patches"):
|
||||
assert issubclass(Test.attribute, VCRHTTPSConnection)
|
||||
assert VCRHTTPSConnection is not Test.attribute
|
||||
|
||||
with test_vcr.use_cassette(
|
||||
'custom_patches',
|
||||
custom_patches=((Test, 'attribute2', VCRHTTPSConnection),)
|
||||
):
|
||||
with test_vcr.use_cassette("custom_patches", custom_patches=((Test, "attribute2", VCRHTTPSConnection),)):
|
||||
assert issubclass(Test.attribute, VCRHTTPSConnection)
|
||||
assert VCRHTTPSConnection is not Test.attribute
|
||||
assert Test.attribute is Test.attribute2
|
||||
@@ -190,11 +188,11 @@ def test_custom_patchers():
|
||||
def test_inject_cassette():
|
||||
vcr = VCR(inject_cassette=True)
|
||||
|
||||
@vcr.use_cassette('test', record_mode='once')
|
||||
@vcr.use_cassette("test", record_mode="once")
|
||||
def with_cassette_injected(cassette):
|
||||
assert cassette.record_mode == 'once'
|
||||
assert cassette.record_mode == "once"
|
||||
|
||||
@vcr.use_cassette('test', record_mode='once', inject_cassette=False)
|
||||
@vcr.use_cassette("test", record_mode="once", inject_cassette=False)
|
||||
def without_cassette_injected():
|
||||
pass
|
||||
|
||||
@@ -203,92 +201,92 @@ def test_inject_cassette():
|
||||
|
||||
|
||||
def test_with_current_defaults():
|
||||
vcr = VCR(inject_cassette=True, record_mode='once')
|
||||
vcr = VCR(inject_cassette=True, record_mode="once")
|
||||
|
||||
@vcr.use_cassette('test', with_current_defaults=False)
|
||||
@vcr.use_cassette("test", with_current_defaults=False)
|
||||
def changing_defaults(cassette, checks):
|
||||
checks(cassette)
|
||||
|
||||
@vcr.use_cassette('test', with_current_defaults=True)
|
||||
@vcr.use_cassette("test", with_current_defaults=True)
|
||||
def current_defaults(cassette, checks):
|
||||
checks(cassette)
|
||||
|
||||
def assert_record_mode_once(cassette):
|
||||
assert cassette.record_mode == 'once'
|
||||
assert cassette.record_mode == "once"
|
||||
|
||||
def assert_record_mode_all(cassette):
|
||||
assert cassette.record_mode == 'all'
|
||||
assert cassette.record_mode == "all"
|
||||
|
||||
changing_defaults(assert_record_mode_once)
|
||||
current_defaults(assert_record_mode_once)
|
||||
|
||||
vcr.record_mode = 'all'
|
||||
vcr.record_mode = "all"
|
||||
changing_defaults(assert_record_mode_all)
|
||||
current_defaults(assert_record_mode_once)
|
||||
|
||||
|
||||
def test_cassette_library_dir_with_decoration_and_no_explicit_path():
|
||||
library_dir = '/libary_dir'
|
||||
library_dir = "/libary_dir"
|
||||
vcr = VCR(inject_cassette=True, cassette_library_dir=library_dir)
|
||||
|
||||
@vcr.use_cassette()
|
||||
def function_name(cassette):
|
||||
assert cassette._path == os.path.join(library_dir, 'function_name')
|
||||
assert cassette._path == os.path.join(library_dir, "function_name")
|
||||
|
||||
function_name()
|
||||
|
||||
|
||||
def test_cassette_library_dir_with_decoration_and_explicit_path():
|
||||
library_dir = '/libary_dir'
|
||||
library_dir = "/libary_dir"
|
||||
vcr = VCR(inject_cassette=True, cassette_library_dir=library_dir)
|
||||
|
||||
@vcr.use_cassette(path='custom_name')
|
||||
@vcr.use_cassette(path="custom_name")
|
||||
def function_name(cassette):
|
||||
assert cassette._path == os.path.join(library_dir, 'custom_name')
|
||||
assert cassette._path == os.path.join(library_dir, "custom_name")
|
||||
|
||||
function_name()
|
||||
|
||||
|
||||
def test_cassette_library_dir_with_decoration_and_super_explicit_path():
|
||||
library_dir = '/libary_dir'
|
||||
library_dir = "/libary_dir"
|
||||
vcr = VCR(inject_cassette=True, cassette_library_dir=library_dir)
|
||||
|
||||
@vcr.use_cassette(path=os.path.join(library_dir, 'custom_name'))
|
||||
@vcr.use_cassette(path=os.path.join(library_dir, "custom_name"))
|
||||
def function_name(cassette):
|
||||
assert cassette._path == os.path.join(library_dir, 'custom_name')
|
||||
assert cassette._path == os.path.join(library_dir, "custom_name")
|
||||
|
||||
function_name()
|
||||
|
||||
|
||||
def test_cassette_library_dir_with_path_transformer():
|
||||
library_dir = '/libary_dir'
|
||||
vcr = VCR(inject_cassette=True, cassette_library_dir=library_dir,
|
||||
path_transformer=lambda path: path + '.json')
|
||||
library_dir = "/libary_dir"
|
||||
vcr = VCR(
|
||||
inject_cassette=True, cassette_library_dir=library_dir, path_transformer=lambda path: path + ".json"
|
||||
)
|
||||
|
||||
@vcr.use_cassette()
|
||||
def function_name(cassette):
|
||||
assert cassette._path == os.path.join(library_dir, 'function_name.json')
|
||||
assert cassette._path == os.path.join(library_dir, "function_name.json")
|
||||
|
||||
function_name()
|
||||
|
||||
|
||||
def test_use_cassette_with_no_extra_invocation():
|
||||
vcr = VCR(inject_cassette=True, cassette_library_dir='/')
|
||||
vcr = VCR(inject_cassette=True, cassette_library_dir="/")
|
||||
|
||||
@vcr.use_cassette
|
||||
def function_name(cassette):
|
||||
assert cassette._path == os.path.join('/', 'function_name')
|
||||
assert cassette._path == os.path.join("/", "function_name")
|
||||
|
||||
function_name()
|
||||
|
||||
|
||||
def test_path_transformer():
|
||||
vcr = VCR(inject_cassette=True, cassette_library_dir='/',
|
||||
path_transformer=lambda x: x + '_test')
|
||||
vcr = VCR(inject_cassette=True, cassette_library_dir="/", path_transformer=lambda x: x + "_test")
|
||||
|
||||
@vcr.use_cassette
|
||||
def function_name(cassette):
|
||||
assert cassette._path == os.path.join('/', 'function_name_test')
|
||||
assert cassette._path == os.path.join("/", "function_name_test")
|
||||
|
||||
function_name()
|
||||
|
||||
@@ -298,32 +296,31 @@ def test_cassette_name_generator_defaults_to_using_module_function_defined_in():
|
||||
|
||||
@vcr.use_cassette
|
||||
def function_name(cassette):
|
||||
assert cassette._path == os.path.join(os.path.dirname(__file__),
|
||||
'function_name')
|
||||
assert cassette._path == os.path.join(os.path.dirname(__file__), "function_name")
|
||||
|
||||
function_name()
|
||||
|
||||
|
||||
def test_ensure_suffix():
|
||||
vcr = VCR(inject_cassette=True, path_transformer=VCR.ensure_suffix('.yaml'))
|
||||
vcr = VCR(inject_cassette=True, path_transformer=VCR.ensure_suffix(".yaml"))
|
||||
|
||||
@vcr.use_cassette
|
||||
def function_name(cassette):
|
||||
assert cassette._path == os.path.join(os.path.dirname(__file__),
|
||||
'function_name.yaml')
|
||||
assert cassette._path == os.path.join(os.path.dirname(__file__), "function_name.yaml")
|
||||
|
||||
function_name()
|
||||
|
||||
|
||||
def test_additional_matchers():
|
||||
vcr = VCR(match_on=('uri',), inject_cassette=True)
|
||||
vcr = VCR(match_on=("uri",), inject_cassette=True)
|
||||
|
||||
@vcr.use_cassette
|
||||
def function_defaults(cassette):
|
||||
assert set(cassette._match_on) == {vcr.matchers['uri']}
|
||||
assert set(cassette._match_on) == {vcr.matchers["uri"]}
|
||||
|
||||
@vcr.use_cassette(additional_matchers=('body',))
|
||||
@vcr.use_cassette(additional_matchers=("body",))
|
||||
def function_additional(cassette):
|
||||
assert set(cassette._match_on) == {vcr.matchers['uri'], vcr.matchers['body']}
|
||||
assert set(cassette._match_on) == {vcr.matchers["uri"], vcr.matchers["body"]}
|
||||
|
||||
function_defaults()
|
||||
function_additional()
|
||||
@@ -331,7 +328,7 @@ def test_additional_matchers():
|
||||
|
||||
def test_decoration_should_respect_function_return_value():
|
||||
vcr = VCR()
|
||||
ret = 'a-return-value'
|
||||
ret = "a-return-value"
|
||||
|
||||
@vcr.use_cassette
|
||||
def function_with_return():
|
||||
@@ -341,7 +338,6 @@ def test_decoration_should_respect_function_return_value():
|
||||
|
||||
|
||||
class TestVCRClass(VCR().test_case()):
|
||||
|
||||
def no_decoration(self):
|
||||
assert httplib.HTTPConnection == _HTTPConnection
|
||||
self.test_dynamically_added()
|
||||
|
||||
@@ -3,9 +3,9 @@ import sys
|
||||
|
||||
def test_vcr_import_deprecation(recwarn):
|
||||
|
||||
if 'vcr' in sys.modules:
|
||||
if "vcr" in sys.modules:
|
||||
# Remove imported module entry if already loaded in another test
|
||||
del sys.modules['vcr']
|
||||
del sys.modules["vcr"]
|
||||
|
||||
import vcr # noqa: F401
|
||||
|
||||
|
||||
16
tox.ini
16
tox.ini
@@ -1,6 +1,6 @@
|
||||
[tox]
|
||||
skip_missing_interpreters=true
|
||||
envlist = cov-clean,{py27,py35,py36,py37,pypy}-{flakes,requests,httplib2,urllib3,tornado4,boto3},{py35,py36,py37}-{aiohttp},cov-report
|
||||
envlist = cov-clean,{py27,py35,py36,py37,pypy}-{lint,requests,httplib2,urllib3,tornado4,boto3},{py35,py36,py37}-{aiohttp},cov-report
|
||||
|
||||
|
||||
# Coverage environment tasks: cov-clean and cov-report
|
||||
@@ -15,15 +15,19 @@ deps = coverage
|
||||
skip_install=true
|
||||
commands =
|
||||
coverage html
|
||||
coverage report --fail-under=75
|
||||
coverage report --fail-under=80
|
||||
|
||||
[testenv:flakes]
|
||||
[testenv:lint]
|
||||
skipsdist = True
|
||||
commands =
|
||||
black --version
|
||||
black --check --diff .
|
||||
flake8 --version
|
||||
flake8 --exclude=./docs/conf.py,./.tox/
|
||||
pyflakes ./docs/conf.py
|
||||
deps = flake8
|
||||
deps =
|
||||
flake8
|
||||
black
|
||||
|
||||
[testenv]
|
||||
# Need to use develop install so that paths
|
||||
@@ -51,8 +55,8 @@ deps =
|
||||
aiohttp: pytest-asyncio
|
||||
aiohttp: pytest-aiohttp
|
||||
depends =
|
||||
{py27,py35,py36,py37,pypy}-{flakes,requests,httplib2,urllib3,tornado4,boto3},{py35,py36,py37}-{aiohttp}: cov-clean
|
||||
cov-report: {py27,py35,py36,py37,pypy}-{flakes,requests,httplib2,urllib3,tornado4,boto3},{py35,py36,py37}-{aiohttp}
|
||||
{py27,py35,py36,py37,pypy}-{lint,requests,httplib2,urllib3,tornado4,boto3},{py35,py36,py37}-{aiohttp}: cov-clean
|
||||
cov-report: {py27,py35,py36,py37,pypy}-{lint,requests,httplib2,urllib3,tornado4,boto3},{py35,py36,py37}-{aiohttp}
|
||||
passenv =
|
||||
AWS_ACCESS_KEY_ID
|
||||
AWS_DEFAULT_REGION
|
||||
|
||||
@@ -7,14 +7,16 @@ from .config import VCR
|
||||
try: # Python 2.7+
|
||||
from logging import NullHandler
|
||||
except ImportError:
|
||||
|
||||
class NullHandler(logging.Handler):
|
||||
def emit(self, record):
|
||||
pass
|
||||
|
||||
|
||||
if sys.version_info[0] == 2:
|
||||
warnings.warn(
|
||||
"Python 2.x support of vcrpy is deprecated and will be removed in an upcoming major release.",
|
||||
DeprecationWarning
|
||||
DeprecationWarning,
|
||||
)
|
||||
|
||||
logging.getLogger(__name__).addHandler(NullHandler())
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
async def handle_coroutine(vcr, fn): # noqa: E999
|
||||
with vcr as cassette:
|
||||
return (await fn(cassette)) # noqa: E999
|
||||
return await fn(cassette) # noqa: E999
|
||||
|
||||
@@ -17,14 +17,17 @@ from .util import partition_dict
|
||||
try:
|
||||
from asyncio import iscoroutinefunction
|
||||
except ImportError:
|
||||
|
||||
def iscoroutinefunction(*args, **kwargs):
|
||||
return False
|
||||
|
||||
|
||||
if sys.version_info[:2] >= (3, 5):
|
||||
from ._handle_coroutine import handle_coroutine
|
||||
else:
|
||||
|
||||
def handle_coroutine(*args, **kwags):
|
||||
raise NotImplementedError('Not implemented on Python 2')
|
||||
raise NotImplementedError("Not implemented on Python 2")
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -48,7 +51,7 @@ class CassetteContextDecorator(object):
|
||||
this class as a context manager in ``__exit__``.
|
||||
"""
|
||||
|
||||
_non_cassette_arguments = ('path_transformer', 'func_path_generator')
|
||||
_non_cassette_arguments = ("path_transformer", "func_path_generator")
|
||||
|
||||
@classmethod
|
||||
def from_args(cls, cassette_class, **kwargs):
|
||||
@@ -63,14 +66,10 @@ class CassetteContextDecorator(object):
|
||||
with contextlib.ExitStack() as exit_stack:
|
||||
for patcher in CassettePatcherBuilder(cassette).build():
|
||||
exit_stack.enter_context(patcher)
|
||||
log_format = '{action} context for cassette at {path}.'
|
||||
log.debug(log_format.format(
|
||||
action="Entering", path=cassette._path
|
||||
))
|
||||
log_format = "{action} context for cassette at {path}."
|
||||
log.debug(log_format.format(action="Entering", path=cassette._path))
|
||||
yield cassette
|
||||
log.debug(log_format.format(
|
||||
action="Exiting", path=cassette._path
|
||||
))
|
||||
log.debug(log_format.format(action="Exiting", path=cassette._path))
|
||||
# TODO(@IvanMalison): Hmmm. it kind of feels like this should be
|
||||
# somewhere else.
|
||||
cassette._save()
|
||||
@@ -86,12 +85,11 @@ class CassetteContextDecorator(object):
|
||||
# pass
|
||||
assert self.__finish is None, "Cassette already open."
|
||||
other_kwargs, cassette_kwargs = partition_dict(
|
||||
lambda key, _: key in self._non_cassette_arguments,
|
||||
self._args_getter()
|
||||
lambda key, _: key in self._non_cassette_arguments, self._args_getter()
|
||||
)
|
||||
if other_kwargs.get('path_transformer'):
|
||||
transformer = other_kwargs['path_transformer']
|
||||
cassette_kwargs['path'] = transformer(cassette_kwargs['path'])
|
||||
if other_kwargs.get("path_transformer"):
|
||||
transformer = other_kwargs["path_transformer"]
|
||||
cassette_kwargs["path"] = transformer(cassette_kwargs["path"])
|
||||
self.__finish = self._patch_generator(self.cls.load(**cassette_kwargs))
|
||||
return next(self.__finish)
|
||||
|
||||
@@ -105,9 +103,7 @@ class CassetteContextDecorator(object):
|
||||
# functions are reentrant. This is required for thread
|
||||
# safety and the correct operation of recursive functions.
|
||||
args_getter = self._build_args_getter_for_decorator(function)
|
||||
return type(self)(self.cls, args_getter)._execute_function(
|
||||
function, args, kwargs
|
||||
)
|
||||
return type(self)(self.cls, args_getter)._execute_function(function, args, kwargs)
|
||||
|
||||
def _execute_function(self, function, args, kwargs):
|
||||
def handle_function(cassette):
|
||||
@@ -154,12 +150,12 @@ class CassetteContextDecorator(object):
|
||||
def _build_args_getter_for_decorator(self, function):
|
||||
def new_args_getter():
|
||||
kwargs = self._args_getter()
|
||||
if 'path' not in kwargs:
|
||||
name_generator = (kwargs.get('func_path_generator') or
|
||||
self.get_function_name)
|
||||
if "path" not in kwargs:
|
||||
name_generator = kwargs.get("func_path_generator") or self.get_function_name
|
||||
path = name_generator(function)
|
||||
kwargs['path'] = path
|
||||
kwargs["path"] = path
|
||||
return kwargs
|
||||
|
||||
return new_args_getter
|
||||
|
||||
|
||||
@@ -181,10 +177,18 @@ class Cassette(object):
|
||||
def use(cls, **kwargs):
|
||||
return CassetteContextDecorator.from_args(cls, **kwargs)
|
||||
|
||||
def __init__(self, path, serializer=None, persister=None, record_mode='once',
|
||||
match_on=(uri, method), before_record_request=None,
|
||||
before_record_response=None, custom_patches=(),
|
||||
inject=False):
|
||||
def __init__(
|
||||
self,
|
||||
path,
|
||||
serializer=None,
|
||||
persister=None,
|
||||
record_mode="once",
|
||||
match_on=(uri, method),
|
||||
before_record_request=None,
|
||||
before_record_response=None,
|
||||
custom_patches=(),
|
||||
inject=False,
|
||||
):
|
||||
self._persister = persister or FilesystemPersister
|
||||
self._path = path
|
||||
self._serializer = serializer or yamlserializer
|
||||
@@ -221,8 +225,7 @@ class Cassette(object):
|
||||
|
||||
@property
|
||||
def write_protected(self):
|
||||
return self.rewound and self.record_mode == 'once' or \
|
||||
self.record_mode == 'none'
|
||||
return self.rewound and self.record_mode == "once" or self.record_mode == "none"
|
||||
|
||||
def append(self, request, response):
|
||||
"""Add a request, response pair to this cassette"""
|
||||
@@ -254,9 +257,7 @@ class Cassette(object):
|
||||
|
||||
def can_play_response_for(self, request):
|
||||
request = self._before_record_request(request)
|
||||
return request and request in self and \
|
||||
self.record_mode != 'all' and \
|
||||
self.rewound
|
||||
return request and request in self and self.record_mode != "all" and self.rewound
|
||||
|
||||
def play_response(self, request):
|
||||
"""
|
||||
@@ -269,8 +270,7 @@ class Cassette(object):
|
||||
return response
|
||||
# The cassette doesn't contain the request asked for.
|
||||
raise UnhandledHTTPRequestError(
|
||||
"The cassette (%r) doesn't contain the request (%r) asked for"
|
||||
% (self._path, request)
|
||||
"The cassette (%r) doesn't contain the request (%r) asked for" % (self._path, request)
|
||||
)
|
||||
|
||||
def responses_of(self, request):
|
||||
@@ -285,8 +285,7 @@ class Cassette(object):
|
||||
return responses
|
||||
# The cassette doesn't contain the request asked for.
|
||||
raise UnhandledHTTPRequestError(
|
||||
"The cassette (%r) doesn't contain the request (%r) asked for"
|
||||
% (self._path, request)
|
||||
"The cassette (%r) doesn't contain the request (%r) asked for" % (self._path, request)
|
||||
)
|
||||
|
||||
def rewind(self):
|
||||
@@ -333,19 +332,12 @@ class Cassette(object):
|
||||
|
||||
def _save(self, force=False):
|
||||
if force or self.dirty:
|
||||
self._persister.save_cassette(
|
||||
self._path,
|
||||
self._as_dict(),
|
||||
serializer=self._serializer,
|
||||
)
|
||||
self._persister.save_cassette(self._path, self._as_dict(), serializer=self._serializer)
|
||||
self.dirty = False
|
||||
|
||||
def _load(self):
|
||||
try:
|
||||
requests, responses = self._persister.load_cassette(
|
||||
self._path,
|
||||
serializer=self._serializer,
|
||||
)
|
||||
requests, responses = self._persister.load_cassette(self._path, serializer=self._serializer)
|
||||
for request, response in zip(requests, responses):
|
||||
self.append(request, response)
|
||||
self.dirty = False
|
||||
@@ -354,9 +346,7 @@ class Cassette(object):
|
||||
pass
|
||||
|
||||
def __str__(self):
|
||||
return "<Cassette containing {} recorded response(s)>".format(
|
||||
len(self)
|
||||
)
|
||||
return "<Cassette containing {} recorded response(s)>".format(len(self))
|
||||
|
||||
def __len__(self):
|
||||
"""Return the number of request,response pairs stored in here"""
|
||||
|
||||
@@ -8,7 +8,7 @@ try:
|
||||
except ImportError:
|
||||
import contextlib2 as contextlib
|
||||
else:
|
||||
if not hasattr(contextlib, 'ExitStack'):
|
||||
if not hasattr(contextlib, "ExitStack"):
|
||||
import contextlib2 as contextlib
|
||||
|
||||
__all__ = ['mock', 'contextlib']
|
||||
__all__ = ["mock", "contextlib"]
|
||||
|
||||
193
vcr/config.py
193
vcr/config.py
@@ -1,4 +1,5 @@
|
||||
import copy
|
||||
|
||||
try:
|
||||
from collections import abc as collections_abc # only works on python 3.3+
|
||||
except ImportError:
|
||||
@@ -19,11 +20,9 @@ from . import filters
|
||||
|
||||
|
||||
class VCR(object):
|
||||
|
||||
@staticmethod
|
||||
def is_test_method(method_name, function):
|
||||
return method_name.startswith('test') and \
|
||||
isinstance(function, types.FunctionType)
|
||||
return method_name.startswith("test") and isinstance(function, types.FunctionType)
|
||||
|
||||
@staticmethod
|
||||
def ensure_suffix(suffix):
|
||||
@@ -31,35 +30,45 @@ class VCR(object):
|
||||
if not path.endswith(suffix):
|
||||
return path + suffix
|
||||
return path
|
||||
|
||||
return ensure
|
||||
|
||||
def __init__(self, path_transformer=None, before_record_request=None,
|
||||
custom_patches=(), filter_query_parameters=(), ignore_hosts=(),
|
||||
record_mode="once", ignore_localhost=False, filter_headers=(),
|
||||
before_record_response=None, filter_post_data_parameters=(),
|
||||
match_on=('method', 'scheme', 'host', 'port', 'path', 'query'),
|
||||
before_record=None, inject_cassette=False, serializer='yaml',
|
||||
cassette_library_dir=None, func_path_generator=None,
|
||||
decode_compressed_response=False):
|
||||
def __init__(
|
||||
self,
|
||||
path_transformer=None,
|
||||
before_record_request=None,
|
||||
custom_patches=(),
|
||||
filter_query_parameters=(),
|
||||
ignore_hosts=(),
|
||||
record_mode="once",
|
||||
ignore_localhost=False,
|
||||
filter_headers=(),
|
||||
before_record_response=None,
|
||||
filter_post_data_parameters=(),
|
||||
match_on=("method", "scheme", "host", "port", "path", "query"),
|
||||
before_record=None,
|
||||
inject_cassette=False,
|
||||
serializer="yaml",
|
||||
cassette_library_dir=None,
|
||||
func_path_generator=None,
|
||||
decode_compressed_response=False,
|
||||
):
|
||||
self.serializer = serializer
|
||||
self.match_on = match_on
|
||||
self.cassette_library_dir = cassette_library_dir
|
||||
self.serializers = {
|
||||
'yaml': yamlserializer,
|
||||
'json': jsonserializer,
|
||||
}
|
||||
self.serializers = {"yaml": yamlserializer, "json": jsonserializer}
|
||||
self.matchers = {
|
||||
'method': matchers.method,
|
||||
'uri': matchers.uri,
|
||||
'url': matchers.uri, # matcher for backwards compatibility
|
||||
'scheme': matchers.scheme,
|
||||
'host': matchers.host,
|
||||
'port': matchers.port,
|
||||
'path': matchers.path,
|
||||
'query': matchers.query,
|
||||
'headers': matchers.headers,
|
||||
'raw_body': matchers.raw_body,
|
||||
'body': matchers.body,
|
||||
"method": matchers.method,
|
||||
"uri": matchers.uri,
|
||||
"url": matchers.uri, # matcher for backwards compatibility
|
||||
"scheme": matchers.scheme,
|
||||
"host": matchers.host,
|
||||
"port": matchers.port,
|
||||
"path": matchers.path,
|
||||
"query": matchers.query,
|
||||
"headers": matchers.headers,
|
||||
"raw_body": matchers.raw_body,
|
||||
"body": matchers.body,
|
||||
}
|
||||
self.persister = FilesystemPersister
|
||||
self.record_mode = record_mode
|
||||
@@ -80,11 +89,7 @@ class VCR(object):
|
||||
try:
|
||||
serializer = self.serializers[serializer_name]
|
||||
except KeyError:
|
||||
raise KeyError(
|
||||
"Serializer {} doesn't exist or isn't registered".format(
|
||||
serializer_name
|
||||
)
|
||||
)
|
||||
raise KeyError("Serializer {} doesn't exist or isn't registered".format(serializer_name))
|
||||
return serializer
|
||||
|
||||
def _get_matchers(self, matcher_names):
|
||||
@@ -93,9 +98,7 @@ class VCR(object):
|
||||
for m in matcher_names:
|
||||
matchers.append(self.matchers[m])
|
||||
except KeyError:
|
||||
raise KeyError(
|
||||
"Matcher {} doesn't exist or isn't registered".format(m)
|
||||
)
|
||||
raise KeyError("Matcher {} doesn't exist or isn't registered".format(m))
|
||||
return matchers
|
||||
|
||||
def use_cassette(self, path=None, **kwargs):
|
||||
@@ -117,62 +120,47 @@ class VCR(object):
|
||||
return Cassette.use_arg_getter(args_getter)
|
||||
|
||||
def get_merged_config(self, **kwargs):
|
||||
serializer_name = kwargs.get('serializer', self.serializer)
|
||||
matcher_names = kwargs.get('match_on', self.match_on)
|
||||
path_transformer = kwargs.get(
|
||||
'path_transformer',
|
||||
self.path_transformer
|
||||
)
|
||||
func_path_generator = kwargs.get(
|
||||
'func_path_generator',
|
||||
self.func_path_generator
|
||||
)
|
||||
cassette_library_dir = kwargs.get(
|
||||
'cassette_library_dir',
|
||||
self.cassette_library_dir
|
||||
)
|
||||
additional_matchers = kwargs.get('additional_matchers', ())
|
||||
serializer_name = kwargs.get("serializer", self.serializer)
|
||||
matcher_names = kwargs.get("match_on", self.match_on)
|
||||
path_transformer = kwargs.get("path_transformer", self.path_transformer)
|
||||
func_path_generator = kwargs.get("func_path_generator", self.func_path_generator)
|
||||
cassette_library_dir = kwargs.get("cassette_library_dir", self.cassette_library_dir)
|
||||
additional_matchers = kwargs.get("additional_matchers", ())
|
||||
|
||||
if cassette_library_dir:
|
||||
|
||||
def add_cassette_library_dir(path):
|
||||
if not path.startswith(cassette_library_dir):
|
||||
return os.path.join(cassette_library_dir, path)
|
||||
return path
|
||||
path_transformer = compose(
|
||||
add_cassette_library_dir, path_transformer
|
||||
)
|
||||
|
||||
path_transformer = compose(add_cassette_library_dir, path_transformer)
|
||||
elif not func_path_generator:
|
||||
# If we don't have a library dir, use the functions
|
||||
# location to build a full path for cassettes.
|
||||
func_path_generator = self._build_path_from_func_using_module
|
||||
|
||||
merged_config = {
|
||||
'serializer': self._get_serializer(serializer_name),
|
||||
'persister': self.persister,
|
||||
'match_on': self._get_matchers(
|
||||
tuple(matcher_names) + tuple(additional_matchers)
|
||||
),
|
||||
'record_mode': kwargs.get('record_mode', self.record_mode),
|
||||
'before_record_request': self._build_before_record_request(kwargs),
|
||||
'before_record_response': self._build_before_record_response(kwargs),
|
||||
'custom_patches': self._custom_patches + kwargs.get(
|
||||
'custom_patches', ()
|
||||
),
|
||||
'inject': kwargs.get('inject_cassette', self.inject_cassette),
|
||||
'path_transformer': path_transformer,
|
||||
'func_path_generator': func_path_generator
|
||||
"serializer": self._get_serializer(serializer_name),
|
||||
"persister": self.persister,
|
||||
"match_on": self._get_matchers(tuple(matcher_names) + tuple(additional_matchers)),
|
||||
"record_mode": kwargs.get("record_mode", self.record_mode),
|
||||
"before_record_request": self._build_before_record_request(kwargs),
|
||||
"before_record_response": self._build_before_record_response(kwargs),
|
||||
"custom_patches": self._custom_patches + kwargs.get("custom_patches", ()),
|
||||
"inject": kwargs.get("inject_cassette", self.inject_cassette),
|
||||
"path_transformer": path_transformer,
|
||||
"func_path_generator": func_path_generator,
|
||||
}
|
||||
path = kwargs.get('path')
|
||||
path = kwargs.get("path")
|
||||
if path:
|
||||
merged_config['path'] = path
|
||||
merged_config["path"] = path
|
||||
return merged_config
|
||||
|
||||
def _build_before_record_response(self, options):
|
||||
before_record_response = options.get(
|
||||
'before_record_response', self.before_record_response
|
||||
)
|
||||
before_record_response = options.get("before_record_response", self.before_record_response)
|
||||
decode_compressed_response = options.get(
|
||||
'decode_compressed_response', self.decode_compressed_response
|
||||
"decode_compressed_response", self.decode_compressed_response
|
||||
)
|
||||
filter_functions = []
|
||||
if decode_compressed_response:
|
||||
@@ -188,58 +176,38 @@ class VCR(object):
|
||||
break
|
||||
response = function(response)
|
||||
return response
|
||||
|
||||
return before_record_response
|
||||
|
||||
def _build_before_record_request(self, options):
|
||||
filter_functions = []
|
||||
filter_headers = options.get(
|
||||
'filter_headers', self.filter_headers
|
||||
)
|
||||
filter_query_parameters = options.get(
|
||||
'filter_query_parameters', self.filter_query_parameters
|
||||
)
|
||||
filter_headers = options.get("filter_headers", self.filter_headers)
|
||||
filter_query_parameters = options.get("filter_query_parameters", self.filter_query_parameters)
|
||||
filter_post_data_parameters = options.get(
|
||||
'filter_post_data_parameters', self.filter_post_data_parameters
|
||||
"filter_post_data_parameters", self.filter_post_data_parameters
|
||||
)
|
||||
before_record_request = options.get(
|
||||
"before_record_request",
|
||||
options.get("before_record", self.before_record_request)
|
||||
)
|
||||
ignore_hosts = options.get(
|
||||
'ignore_hosts', self.ignore_hosts
|
||||
)
|
||||
ignore_localhost = options.get(
|
||||
'ignore_localhost', self.ignore_localhost
|
||||
"before_record_request", options.get("before_record", self.before_record_request)
|
||||
)
|
||||
ignore_hosts = options.get("ignore_hosts", self.ignore_hosts)
|
||||
ignore_localhost = options.get("ignore_localhost", self.ignore_localhost)
|
||||
if filter_headers:
|
||||
replacements = [h if isinstance(h, tuple) else (h, None)
|
||||
for h in filter_headers]
|
||||
filter_functions.append(
|
||||
functools.partial(
|
||||
filters.replace_headers,
|
||||
replacements=replacements,
|
||||
)
|
||||
)
|
||||
replacements = [h if isinstance(h, tuple) else (h, None) for h in filter_headers]
|
||||
filter_functions.append(functools.partial(filters.replace_headers, replacements=replacements))
|
||||
if filter_query_parameters:
|
||||
replacements = [p if isinstance(p, tuple) else (p, None)
|
||||
for p in filter_query_parameters]
|
||||
filter_functions.append(functools.partial(
|
||||
filters.replace_query_parameters,
|
||||
replacements=replacements,
|
||||
))
|
||||
if filter_post_data_parameters:
|
||||
replacements = [p if isinstance(p, tuple) else (p, None)
|
||||
for p in filter_post_data_parameters]
|
||||
replacements = [p if isinstance(p, tuple) else (p, None) for p in filter_query_parameters]
|
||||
filter_functions.append(
|
||||
functools.partial(
|
||||
filters.replace_post_data_parameters,
|
||||
replacements=replacements,
|
||||
)
|
||||
functools.partial(filters.replace_query_parameters, replacements=replacements)
|
||||
)
|
||||
if filter_post_data_parameters:
|
||||
replacements = [p if isinstance(p, tuple) else (p, None) for p in filter_post_data_parameters]
|
||||
filter_functions.append(
|
||||
functools.partial(filters.replace_post_data_parameters, replacements=replacements)
|
||||
)
|
||||
|
||||
hosts_to_ignore = set(ignore_hosts)
|
||||
if ignore_localhost:
|
||||
hosts_to_ignore.update(('localhost', '0.0.0.0', '127.0.0.1'))
|
||||
hosts_to_ignore.update(("localhost", "0.0.0.0", "127.0.0.1"))
|
||||
if hosts_to_ignore:
|
||||
filter_functions.append(self._build_ignore_hosts(hosts_to_ignore))
|
||||
|
||||
@@ -255,20 +223,21 @@ class VCR(object):
|
||||
break
|
||||
request = function(request)
|
||||
return request
|
||||
|
||||
return before_record_request
|
||||
|
||||
@staticmethod
|
||||
def _build_ignore_hosts(hosts_to_ignore):
|
||||
def filter_ignored_hosts(request):
|
||||
if hasattr(request, 'host') and request.host in hosts_to_ignore:
|
||||
if hasattr(request, "host") and request.host in hosts_to_ignore:
|
||||
return
|
||||
return request
|
||||
|
||||
return filter_ignored_hosts
|
||||
|
||||
@staticmethod
|
||||
def _build_path_from_func_using_module(function):
|
||||
return os.path.join(os.path.dirname(inspect.getfile(function)),
|
||||
function.__name__)
|
||||
return os.path.join(os.path.dirname(inspect.getfile(function)), function.__name__)
|
||||
|
||||
def register_serializer(self, name, serializer):
|
||||
self.serializers[name] = serializer
|
||||
|
||||
@@ -14,27 +14,29 @@ class CannotOverwriteExistingCassetteException(Exception):
|
||||
if best_matches:
|
||||
# Build a comprehensible message to put in the exception.
|
||||
best_matches_msg = "Found {} similar requests with {} different matcher(s) :\n".format(
|
||||
len(best_matches), len(best_matches[0][2]))
|
||||
len(best_matches), len(best_matches[0][2])
|
||||
)
|
||||
|
||||
for idx, best_match in enumerate(best_matches, start=1):
|
||||
request, succeeded_matchers, failed_matchers_assertion_msgs = best_match
|
||||
best_matches_msg += "\n%s - (%r).\n" \
|
||||
"Matchers succeeded : %s\n" \
|
||||
"Matchers failed :\n" % (idx, request, succeeded_matchers)
|
||||
best_matches_msg += (
|
||||
"\n%s - (%r).\n"
|
||||
"Matchers succeeded : %s\n"
|
||||
"Matchers failed :\n" % (idx, request, succeeded_matchers)
|
||||
)
|
||||
for failed_matcher, assertion_msg in failed_matchers_assertion_msgs:
|
||||
best_matches_msg += "%s - assertion failure :\n" \
|
||||
"%s\n" % (failed_matcher, assertion_msg)
|
||||
best_matches_msg += "%s - assertion failure :\n" "%s\n" % (failed_matcher, assertion_msg)
|
||||
else:
|
||||
best_matches_msg = "No similar requests, that have not been played, found."
|
||||
return (
|
||||
"Can't overwrite existing cassette (%r) in "
|
||||
"your current record mode (%r).\n"
|
||||
"No match for the request (%r) was found.\n"
|
||||
"%s"
|
||||
% (cassette._path, cassette.record_mode, failed_request, best_matches_msg)
|
||||
"%s" % (cassette._path, cassette.record_mode, failed_request, best_matches_msg)
|
||||
)
|
||||
|
||||
|
||||
class UnhandledHTTPRequestError(KeyError):
|
||||
"""Raised when a cassette does not contain the request we want."""
|
||||
|
||||
pass
|
||||
|
||||
@@ -83,9 +83,9 @@ def replace_post_data_parameters(request, replacements):
|
||||
value or None.
|
||||
"""
|
||||
replacements = dict(replacements)
|
||||
if request.method == 'POST' and not isinstance(request.body, BytesIO):
|
||||
if request.headers.get('Content-Type') == 'application/json':
|
||||
json_data = json.loads(request.body.decode('utf-8'))
|
||||
if request.method == "POST" and not isinstance(request.body, BytesIO):
|
||||
if request.headers.get("Content-Type") == "application/json":
|
||||
json_data = json.loads(request.body.decode("utf-8"))
|
||||
for k, rv in replacements.items():
|
||||
if k in json_data:
|
||||
ov = json_data.pop(k)
|
||||
@@ -93,28 +93,26 @@ def replace_post_data_parameters(request, replacements):
|
||||
rv = rv(key=k, value=ov, request=request)
|
||||
if rv is not None:
|
||||
json_data[k] = rv
|
||||
request.body = json.dumps(json_data).encode('utf-8')
|
||||
request.body = json.dumps(json_data).encode("utf-8")
|
||||
else:
|
||||
if isinstance(request.body, text_type):
|
||||
request.body = request.body.encode('utf-8')
|
||||
splits = [p.partition(b'=') for p in request.body.split(b'&')]
|
||||
request.body = request.body.encode("utf-8")
|
||||
splits = [p.partition(b"=") for p in request.body.split(b"&")]
|
||||
new_splits = []
|
||||
for k, sep, ov in splits:
|
||||
if sep is None:
|
||||
new_splits.append((k, sep, ov))
|
||||
else:
|
||||
rk = k.decode('utf-8')
|
||||
rk = k.decode("utf-8")
|
||||
if rk not in replacements:
|
||||
new_splits.append((k, sep, ov))
|
||||
else:
|
||||
rv = replacements[rk]
|
||||
if callable(rv):
|
||||
rv = rv(key=rk, value=ov.decode('utf-8'),
|
||||
request=request)
|
||||
rv = rv(key=rk, value=ov.decode("utf-8"), request=request)
|
||||
if rv is not None:
|
||||
new_splits.append((k, sep, rv.encode('utf-8')))
|
||||
request.body = b'&'.join(k if sep is None else b''.join([k, sep, v])
|
||||
for k, sep, v in new_splits)
|
||||
new_splits.append((k, sep, rv.encode("utf-8")))
|
||||
request.body = b"&".join(k if sep is None else b"".join([k, sep, v]) for k, sep, v in new_splits)
|
||||
return request
|
||||
|
||||
|
||||
@@ -133,15 +131,16 @@ def decode_response(response):
|
||||
2. delete the content-encoding header
|
||||
3. update content-length header to decompressed length
|
||||
"""
|
||||
|
||||
def is_compressed(headers):
|
||||
encoding = headers.get('content-encoding', [])
|
||||
return encoding and encoding[0] in ('gzip', 'deflate')
|
||||
encoding = headers.get("content-encoding", [])
|
||||
return encoding and encoding[0] in ("gzip", "deflate")
|
||||
|
||||
def decompress_body(body, encoding):
|
||||
"""Returns decompressed body according to encoding using zlib.
|
||||
to (de-)compress gzip format, use wbits = zlib.MAX_WBITS | 16
|
||||
"""
|
||||
if encoding == 'gzip':
|
||||
if encoding == "gzip":
|
||||
return zlib.decompress(body, zlib.MAX_WBITS | 16)
|
||||
else: # encoding == 'deflate'
|
||||
return zlib.decompress(body)
|
||||
@@ -149,15 +148,15 @@ def decode_response(response):
|
||||
# Deepcopy here in case `headers` contain objects that could
|
||||
# be mutated by a shallow copy and corrupt the real response.
|
||||
response = copy.deepcopy(response)
|
||||
headers = CaseInsensitiveDict(response['headers'])
|
||||
headers = CaseInsensitiveDict(response["headers"])
|
||||
if is_compressed(headers):
|
||||
encoding = headers['content-encoding'][0]
|
||||
headers['content-encoding'].remove(encoding)
|
||||
if not headers['content-encoding']:
|
||||
del headers['content-encoding']
|
||||
encoding = headers["content-encoding"][0]
|
||||
headers["content-encoding"].remove(encoding)
|
||||
if not headers["content-encoding"]:
|
||||
del headers["content-encoding"]
|
||||
|
||||
new_body = decompress_body(response['body']['string'], encoding)
|
||||
response['body']['string'] = new_body
|
||||
headers['content-length'] = [str(len(new_body))]
|
||||
response['headers'] = dict(headers)
|
||||
new_body = decompress_body(response["body"]["string"], encoding)
|
||||
response["body"]["string"] = new_body
|
||||
headers["content-length"] = [str(len(new_body))]
|
||||
response["headers"] = dict(headers)
|
||||
return response
|
||||
|
||||
@@ -51,9 +51,10 @@ def headers(r1, r2):
|
||||
assert r1.headers == r2.headers, "{} != {}".format(r1.headers, r2.headers)
|
||||
|
||||
|
||||
def _header_checker(value, header='Content-Type'):
|
||||
def _header_checker(value, header="Content-Type"):
|
||||
def checker(headers):
|
||||
return value in headers.get(header, '').lower()
|
||||
return value in headers.get(header, "").lower()
|
||||
|
||||
return checker
|
||||
|
||||
|
||||
@@ -62,18 +63,18 @@ def _transform_json(body):
|
||||
# string. RFC 7159 says the default encoding is UTF-8 (although UTF-16
|
||||
# and UTF-32 are also allowed: hmmmmm).
|
||||
if body:
|
||||
return json.loads(body.decode('utf-8'))
|
||||
return json.loads(body.decode("utf-8"))
|
||||
|
||||
|
||||
_xml_header_checker = _header_checker('text/xml')
|
||||
_xmlrpc_header_checker = _header_checker('xmlrpc', header='User-Agent')
|
||||
_xml_header_checker = _header_checker("text/xml")
|
||||
_xmlrpc_header_checker = _header_checker("xmlrpc", header="User-Agent")
|
||||
_checker_transformer_pairs = (
|
||||
(_header_checker('application/x-www-form-urlencoded'),
|
||||
lambda body: urllib.parse.parse_qs(body.decode('ascii'))),
|
||||
(_header_checker('application/json'),
|
||||
_transform_json),
|
||||
(lambda request: _xml_header_checker(request) and _xmlrpc_header_checker(request),
|
||||
xmlrpc_client.loads),
|
||||
(
|
||||
_header_checker("application/x-www-form-urlencoded"),
|
||||
lambda body: urllib.parse.parse_qs(body.decode("ascii")),
|
||||
),
|
||||
(_header_checker("application/json"), _transform_json),
|
||||
(lambda request: _xml_header_checker(request) and _xmlrpc_header_checker(request), xmlrpc_client.loads),
|
||||
)
|
||||
|
||||
|
||||
@@ -92,11 +93,7 @@ def _get_transformer(request):
|
||||
def requests_match(r1, r2, matchers):
|
||||
successes, failures = get_matchers_results(r1, r2, matchers)
|
||||
if failures:
|
||||
log.debug(
|
||||
"Requests {} and {} differ.\n"
|
||||
"Failure details:\n"
|
||||
"{}".format(r1, r2, failures)
|
||||
)
|
||||
log.debug("Requests {} and {} differ.\n" "Failure details:\n" "{}".format(r1, r2, failures))
|
||||
return len(failures) == 0
|
||||
|
||||
|
||||
|
||||
@@ -38,55 +38,46 @@ def preprocess_yaml(cassette):
|
||||
# versions. So this just strips the tags before deserializing.
|
||||
|
||||
STRINGS_TO_NUKE = [
|
||||
'!!python/object:vcr.request.Request',
|
||||
'!!python/object/apply:__builtin__.frozenset',
|
||||
'!!python/object/apply:builtins.frozenset',
|
||||
"!!python/object:vcr.request.Request",
|
||||
"!!python/object/apply:__builtin__.frozenset",
|
||||
"!!python/object/apply:builtins.frozenset",
|
||||
]
|
||||
for s in STRINGS_TO_NUKE:
|
||||
cassette = cassette.replace(s, '')
|
||||
cassette = cassette.replace(s, "")
|
||||
return cassette
|
||||
|
||||
|
||||
PARTS = [
|
||||
'protocol',
|
||||
'host',
|
||||
'port',
|
||||
'path',
|
||||
]
|
||||
PARTS = ["protocol", "host", "port", "path"]
|
||||
|
||||
|
||||
def build_uri(**parts):
|
||||
port = parts['port']
|
||||
scheme = parts['protocol']
|
||||
default_port = {'https': 443, 'http': 80}[scheme]
|
||||
parts['port'] = ':{}'.format(port) if port != default_port else ''
|
||||
port = parts["port"]
|
||||
scheme = parts["protocol"]
|
||||
default_port = {"https": 443, "http": 80}[scheme]
|
||||
parts["port"] = ":{}".format(port) if port != default_port else ""
|
||||
return "{protocol}://{host}{port}{path}".format(**parts)
|
||||
|
||||
|
||||
def _migrate(data):
|
||||
interactions = []
|
||||
for item in data:
|
||||
req = item['request']
|
||||
res = item['response']
|
||||
req = item["request"]
|
||||
res = item["response"]
|
||||
uri = {k: req.pop(k) for k in PARTS}
|
||||
req['uri'] = build_uri(**uri)
|
||||
req["uri"] = build_uri(**uri)
|
||||
# convert headers to dict of lists
|
||||
headers = req['headers']
|
||||
headers = req["headers"]
|
||||
for k in headers:
|
||||
headers[k] = [headers[k]]
|
||||
response_headers = {}
|
||||
for k, v in get_httpmessage(
|
||||
b"".join(h.encode('utf-8') for h in res['headers'])
|
||||
).items():
|
||||
for k, v in get_httpmessage(b"".join(h.encode("utf-8") for h in res["headers"])).items():
|
||||
response_headers.setdefault(k, [])
|
||||
response_headers[k].append(v)
|
||||
res['headers'] = response_headers
|
||||
interactions.append({'request': req, 'response': res})
|
||||
res["headers"] = response_headers
|
||||
interactions.append({"request": req, "response": res})
|
||||
return {
|
||||
'requests': [
|
||||
request.Request._from_dict(i['request']) for i in interactions
|
||||
],
|
||||
'responses': [i['response'] for i in interactions],
|
||||
"requests": [request.Request._from_dict(i["request"]) for i in interactions],
|
||||
"responses": [i["response"] for i in interactions],
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +96,7 @@ def _list_of_tuples_to_dict(fs):
|
||||
|
||||
def _already_migrated(data):
|
||||
try:
|
||||
if data.get('version') == 1:
|
||||
if data.get("version") == 1:
|
||||
return True
|
||||
except AttributeError:
|
||||
return False
|
||||
@@ -116,9 +107,7 @@ def migrate_yml(in_fp, out_fp):
|
||||
if _already_migrated(data):
|
||||
return False
|
||||
for i in range(len(data)):
|
||||
data[i]['request']['headers'] = _list_of_tuples_to_dict(
|
||||
data[i]['request']['headers']
|
||||
)
|
||||
data[i]["request"]["headers"] = _list_of_tuples_to_dict(data[i]["request"]["headers"])
|
||||
interactions = _migrate(data)
|
||||
out_fp.write(serialize(interactions, yamlserializer))
|
||||
return True
|
||||
@@ -127,43 +116,42 @@ def migrate_yml(in_fp, out_fp):
|
||||
def migrate(file_path, migration_fn):
|
||||
# because we assume that original files can be reverted
|
||||
# we will try to copy the content. (os.rename not needed)
|
||||
with tempfile.TemporaryFile(mode='w+') as out_fp:
|
||||
with open(file_path, 'r') as in_fp:
|
||||
with tempfile.TemporaryFile(mode="w+") as out_fp:
|
||||
with open(file_path, "r") as in_fp:
|
||||
if not migration_fn(in_fp, out_fp):
|
||||
return False
|
||||
with open(file_path, 'w') as in_fp:
|
||||
with open(file_path, "w") as in_fp:
|
||||
out_fp.seek(0)
|
||||
shutil.copyfileobj(out_fp, in_fp)
|
||||
return True
|
||||
|
||||
|
||||
def try_migrate(path):
|
||||
if path.endswith('.json'):
|
||||
if path.endswith(".json"):
|
||||
return migrate(path, migrate_json)
|
||||
elif path.endswith('.yaml') or path.endswith('.yml'):
|
||||
elif path.endswith(".yaml") or path.endswith(".yml"):
|
||||
return migrate(path, migrate_yml)
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2:
|
||||
raise SystemExit("Please provide path to cassettes directory or file. "
|
||||
"Usage: python -m vcr.migration PATH")
|
||||
raise SystemExit(
|
||||
"Please provide path to cassettes directory or file. " "Usage: python -m vcr.migration PATH"
|
||||
)
|
||||
|
||||
path = sys.argv[1]
|
||||
if not os.path.isabs(path):
|
||||
path = os.path.abspath(path)
|
||||
files = [path]
|
||||
if os.path.isdir(path):
|
||||
files = (os.path.join(root, name)
|
||||
for (root, dirs, files) in os.walk(path)
|
||||
for name in files)
|
||||
files = (os.path.join(root, name) for (root, dirs, files) in os.walk(path) for name in files)
|
||||
for file_path in files:
|
||||
migrated = try_migrate(file_path)
|
||||
status = 'OK' if migrated else 'FAIL'
|
||||
status = "OK" if migrated else "FAIL"
|
||||
sys.stderr.write("[{}] {}\n".format(status, file_path))
|
||||
sys.stderr.write("Done.\n")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
230
vcr/patch.py
230
vcr/patch.py
@@ -1,4 +1,4 @@
|
||||
'''Utilities for patching in cassettes'''
|
||||
"""Utilities for patching in cassettes"""
|
||||
import functools
|
||||
import itertools
|
||||
|
||||
@@ -76,16 +76,14 @@ try:
|
||||
except ImportError: # pragma: no cover
|
||||
pass
|
||||
else:
|
||||
_SimpleAsyncHTTPClient_fetch_impl = \
|
||||
tornado.simple_httpclient.SimpleAsyncHTTPClient.fetch_impl
|
||||
_SimpleAsyncHTTPClient_fetch_impl = tornado.simple_httpclient.SimpleAsyncHTTPClient.fetch_impl
|
||||
|
||||
try:
|
||||
import tornado.curl_httpclient
|
||||
except ImportError: # pragma: no cover
|
||||
pass
|
||||
else:
|
||||
_CurlAsyncHTTPClient_fetch_impl = \
|
||||
tornado.curl_httpclient.CurlAsyncHTTPClient.fetch_impl
|
||||
_CurlAsyncHTTPClient_fetch_impl = tornado.curl_httpclient.CurlAsyncHTTPClient.fetch_impl
|
||||
|
||||
try:
|
||||
import aiohttp.client
|
||||
@@ -96,13 +94,10 @@ else:
|
||||
|
||||
|
||||
class CassettePatcherBuilder(object):
|
||||
|
||||
def _build_patchers_from_mock_triples_decorator(function):
|
||||
@functools.wraps(function)
|
||||
def wrapped(self, *args, **kwargs):
|
||||
return self._build_patchers_from_mock_triples(
|
||||
function(self, *args, **kwargs)
|
||||
)
|
||||
return self._build_patchers_from_mock_triples(function(self, *args, **kwargs))
|
||||
|
||||
return wrapped
|
||||
|
||||
@@ -112,11 +107,15 @@ class CassettePatcherBuilder(object):
|
||||
|
||||
def build(self):
|
||||
return itertools.chain(
|
||||
self._httplib(), self._requests(), self._boto3(), self._urllib3(),
|
||||
self._httplib2(), self._boto(), self._tornado(), self._aiohttp(),
|
||||
self._build_patchers_from_mock_triples(
|
||||
self._cassette.custom_patches
|
||||
),
|
||||
self._httplib(),
|
||||
self._requests(),
|
||||
self._boto3(),
|
||||
self._urllib3(),
|
||||
self._httplib2(),
|
||||
self._boto(),
|
||||
self._tornado(),
|
||||
self._aiohttp(),
|
||||
self._build_patchers_from_mock_triples(self._cassette.custom_patches),
|
||||
)
|
||||
|
||||
def _build_patchers_from_mock_triples(self, mock_triples):
|
||||
@@ -129,9 +128,9 @@ class CassettePatcherBuilder(object):
|
||||
if not hasattr(obj, patched_attribute):
|
||||
return
|
||||
|
||||
return mock.patch.object(obj, patched_attribute,
|
||||
self._recursively_apply_get_cassette_subclass(
|
||||
replacement_class))
|
||||
return mock.patch.object(
|
||||
obj, patched_attribute, self._recursively_apply_get_cassette_subclass(replacement_class)
|
||||
)
|
||||
|
||||
def _recursively_apply_get_cassette_subclass(self, replacement_dict_or_obj):
|
||||
"""One of the subtleties of this class is that it does not directly
|
||||
@@ -153,13 +152,11 @@ class CassettePatcherBuilder(object):
|
||||
"""
|
||||
if isinstance(replacement_dict_or_obj, dict):
|
||||
for key, replacement_obj in replacement_dict_or_obj.items():
|
||||
replacement_obj = self._recursively_apply_get_cassette_subclass(
|
||||
replacement_obj)
|
||||
replacement_obj = self._recursively_apply_get_cassette_subclass(replacement_obj)
|
||||
replacement_dict_or_obj[key] = replacement_obj
|
||||
return replacement_dict_or_obj
|
||||
if hasattr(replacement_dict_or_obj, 'cassette'):
|
||||
replacement_dict_or_obj = self._get_cassette_subclass(
|
||||
replacement_dict_or_obj)
|
||||
if hasattr(replacement_dict_or_obj, "cassette"):
|
||||
replacement_dict_or_obj = self._get_cassette_subclass(replacement_dict_or_obj)
|
||||
return replacement_dict_or_obj
|
||||
|
||||
def _get_cassette_subclass(self, klass):
|
||||
@@ -174,13 +171,14 @@ class CassettePatcherBuilder(object):
|
||||
bases = (base_class,)
|
||||
if not issubclass(base_class, object): # Check for old style class
|
||||
bases += (object,)
|
||||
return type('{}{}'.format(base_class.__name__, self._cassette._path),
|
||||
bases, dict(cassette=self._cassette))
|
||||
return type(
|
||||
"{}{}".format(base_class.__name__, self._cassette._path), bases, dict(cassette=self._cassette)
|
||||
)
|
||||
|
||||
@_build_patchers_from_mock_triples_decorator
|
||||
def _httplib(self):
|
||||
yield httplib, 'HTTPConnection', VCRHTTPConnection
|
||||
yield httplib, 'HTTPSConnection', VCRHTTPSConnection
|
||||
yield httplib, "HTTPConnection", VCRHTTPConnection
|
||||
yield httplib, "HTTPSConnection", VCRHTTPSConnection
|
||||
|
||||
def _requests(self):
|
||||
try:
|
||||
@@ -203,12 +201,14 @@ class CassettePatcherBuilder(object):
|
||||
pass
|
||||
else:
|
||||
from .stubs import boto3_stubs
|
||||
|
||||
yield self._urllib3_patchers(cpool, boto3_stubs)
|
||||
else:
|
||||
from .stubs import boto3_stubs
|
||||
|
||||
log.debug("Patching boto3 cpool with %s", cpool)
|
||||
yield cpool.AWSHTTPConnectionPool, 'ConnectionCls', boto3_stubs.VCRRequestsHTTPConnection
|
||||
yield cpool.AWSHTTPSConnectionPool, 'ConnectionCls', boto3_stubs.VCRRequestsHTTPSConnection
|
||||
yield cpool.AWSHTTPConnectionPool, "ConnectionCls", boto3_stubs.VCRRequestsHTTPConnection
|
||||
yield cpool.AWSHTTPSConnectionPool, "ConnectionCls", boto3_stubs.VCRRequestsHTTPSConnection
|
||||
|
||||
def _patched_get_conn(self, connection_pool_class, connection_class_getter):
|
||||
get_conn = connection_pool_class._get_conn
|
||||
@@ -217,8 +217,8 @@ class CassettePatcherBuilder(object):
|
||||
def patched_get_conn(pool, timeout=None):
|
||||
connection = get_conn(pool, timeout)
|
||||
connection_class = (
|
||||
pool.ConnectionCls if hasattr(pool, 'ConnectionCls')
|
||||
else connection_class_getter())
|
||||
pool.ConnectionCls if hasattr(pool, "ConnectionCls") else connection_class_getter()
|
||||
)
|
||||
# We need to make sure that we are actually providing a
|
||||
# patched version of the connection class. This might not
|
||||
# always be the case because the pool keeps previously
|
||||
@@ -248,6 +248,7 @@ class CassettePatcherBuilder(object):
|
||||
except ImportError: # pragma: no cover
|
||||
return ()
|
||||
from .stubs import urllib3_stubs
|
||||
|
||||
return self._urllib3_patchers(cpool, urllib3_stubs)
|
||||
|
||||
@_build_patchers_from_mock_triples_decorator
|
||||
@@ -260,10 +261,12 @@ class CassettePatcherBuilder(object):
|
||||
from .stubs.httplib2_stubs import VCRHTTPConnectionWithTimeout
|
||||
from .stubs.httplib2_stubs import VCRHTTPSConnectionWithTimeout
|
||||
|
||||
yield cpool, 'HTTPConnectionWithTimeout', VCRHTTPConnectionWithTimeout
|
||||
yield cpool, 'HTTPSConnectionWithTimeout', VCRHTTPSConnectionWithTimeout
|
||||
yield cpool, 'SCHEME_TO_CONNECTION', {'http': VCRHTTPConnectionWithTimeout,
|
||||
'https': VCRHTTPSConnectionWithTimeout}
|
||||
yield cpool, "HTTPConnectionWithTimeout", VCRHTTPConnectionWithTimeout
|
||||
yield cpool, "HTTPSConnectionWithTimeout", VCRHTTPSConnectionWithTimeout
|
||||
yield cpool, "SCHEME_TO_CONNECTION", {
|
||||
"http": VCRHTTPConnectionWithTimeout,
|
||||
"https": VCRHTTPSConnectionWithTimeout,
|
||||
}
|
||||
|
||||
@_build_patchers_from_mock_triples_decorator
|
||||
def _boto(self):
|
||||
@@ -273,7 +276,8 @@ class CassettePatcherBuilder(object):
|
||||
pass
|
||||
else:
|
||||
from .stubs.boto_stubs import VCRCertValidatingHTTPSConnection
|
||||
yield cpool, 'CertValidatingHTTPSConnection', VCRCertValidatingHTTPSConnection
|
||||
|
||||
yield cpool, "CertValidatingHTTPSConnection", VCRCertValidatingHTTPSConnection
|
||||
|
||||
@_build_patchers_from_mock_triples_decorator
|
||||
def _tornado(self):
|
||||
@@ -284,10 +288,8 @@ class CassettePatcherBuilder(object):
|
||||
else:
|
||||
from .stubs.tornado_stubs import vcr_fetch_impl
|
||||
|
||||
new_fetch_impl = vcr_fetch_impl(
|
||||
self._cassette, _SimpleAsyncHTTPClient_fetch_impl
|
||||
)
|
||||
yield simple.SimpleAsyncHTTPClient, 'fetch_impl', new_fetch_impl
|
||||
new_fetch_impl = vcr_fetch_impl(self._cassette, _SimpleAsyncHTTPClient_fetch_impl)
|
||||
yield simple.SimpleAsyncHTTPClient, "fetch_impl", new_fetch_impl
|
||||
try:
|
||||
import tornado.curl_httpclient as curl
|
||||
except ImportError: # pragma: no cover
|
||||
@@ -295,10 +297,8 @@ class CassettePatcherBuilder(object):
|
||||
else:
|
||||
from .stubs.tornado_stubs import vcr_fetch_impl
|
||||
|
||||
new_fetch_impl = vcr_fetch_impl(
|
||||
self._cassette, _CurlAsyncHTTPClient_fetch_impl
|
||||
)
|
||||
yield curl.CurlAsyncHTTPClient, 'fetch_impl', new_fetch_impl
|
||||
new_fetch_impl = vcr_fetch_impl(self._cassette, _CurlAsyncHTTPClient_fetch_impl)
|
||||
yield curl.CurlAsyncHTTPClient, "fetch_impl", new_fetch_impl
|
||||
|
||||
@_build_patchers_from_mock_triples_decorator
|
||||
def _aiohttp(self):
|
||||
@@ -308,10 +308,9 @@ class CassettePatcherBuilder(object):
|
||||
pass
|
||||
else:
|
||||
from .stubs.aiohttp_stubs import vcr_request
|
||||
new_request = vcr_request(
|
||||
self._cassette, _AiohttpClientSessionRequest
|
||||
)
|
||||
yield client.ClientSession, '_request', new_request
|
||||
|
||||
new_request = vcr_request(self._cassette, _AiohttpClientSessionRequest)
|
||||
yield client.ClientSession, "_request", new_request
|
||||
|
||||
def _urllib3_patchers(self, cpool, stubs):
|
||||
http_connection_remover = ConnectionRemover(
|
||||
@@ -321,34 +320,45 @@ class CassettePatcherBuilder(object):
|
||||
self._get_cassette_subclass(stubs.VCRRequestsHTTPSConnection)
|
||||
)
|
||||
mock_triples = (
|
||||
(cpool, 'VerifiedHTTPSConnection', stubs.VCRRequestsHTTPSConnection),
|
||||
(cpool, 'HTTPConnection', stubs.VCRRequestsHTTPConnection),
|
||||
(cpool, 'HTTPSConnection', stubs.VCRRequestsHTTPSConnection),
|
||||
(cpool, 'is_connection_dropped', mock.Mock(return_value=False)), # Needed on Windows only
|
||||
(cpool.HTTPConnectionPool, 'ConnectionCls', stubs.VCRRequestsHTTPConnection),
|
||||
(cpool.HTTPSConnectionPool, 'ConnectionCls', stubs.VCRRequestsHTTPSConnection),
|
||||
(cpool, "VerifiedHTTPSConnection", stubs.VCRRequestsHTTPSConnection),
|
||||
(cpool, "HTTPConnection", stubs.VCRRequestsHTTPConnection),
|
||||
(cpool, "HTTPSConnection", stubs.VCRRequestsHTTPSConnection),
|
||||
(cpool, "is_connection_dropped", mock.Mock(return_value=False)), # Needed on Windows only
|
||||
(cpool.HTTPConnectionPool, "ConnectionCls", stubs.VCRRequestsHTTPConnection),
|
||||
(cpool.HTTPSConnectionPool, "ConnectionCls", stubs.VCRRequestsHTTPSConnection),
|
||||
)
|
||||
# These handle making sure that sessions only use the
|
||||
# connections of the appropriate type.
|
||||
mock_triples += ((cpool.HTTPConnectionPool, '_get_conn',
|
||||
self._patched_get_conn(cpool.HTTPConnectionPool,
|
||||
lambda: cpool.HTTPConnection)),
|
||||
(cpool.HTTPSConnectionPool, '_get_conn',
|
||||
self._patched_get_conn(cpool.HTTPSConnectionPool,
|
||||
lambda: cpool.HTTPSConnection)),
|
||||
(cpool.HTTPConnectionPool, '_new_conn',
|
||||
self._patched_new_conn(cpool.HTTPConnectionPool,
|
||||
http_connection_remover)),
|
||||
(cpool.HTTPSConnectionPool, '_new_conn',
|
||||
self._patched_new_conn(cpool.HTTPSConnectionPool,
|
||||
https_connection_remover)))
|
||||
mock_triples += (
|
||||
(
|
||||
cpool.HTTPConnectionPool,
|
||||
"_get_conn",
|
||||
self._patched_get_conn(cpool.HTTPConnectionPool, lambda: cpool.HTTPConnection),
|
||||
),
|
||||
(
|
||||
cpool.HTTPSConnectionPool,
|
||||
"_get_conn",
|
||||
self._patched_get_conn(cpool.HTTPSConnectionPool, lambda: cpool.HTTPSConnection),
|
||||
),
|
||||
(
|
||||
cpool.HTTPConnectionPool,
|
||||
"_new_conn",
|
||||
self._patched_new_conn(cpool.HTTPConnectionPool, http_connection_remover),
|
||||
),
|
||||
(
|
||||
cpool.HTTPSConnectionPool,
|
||||
"_new_conn",
|
||||
self._patched_new_conn(cpool.HTTPSConnectionPool, https_connection_remover),
|
||||
),
|
||||
)
|
||||
|
||||
return itertools.chain(self._build_patchers_from_mock_triples(mock_triples),
|
||||
(http_connection_remover, https_connection_remover))
|
||||
return itertools.chain(
|
||||
self._build_patchers_from_mock_triples(mock_triples),
|
||||
(http_connection_remover, https_connection_remover),
|
||||
)
|
||||
|
||||
|
||||
class ConnectionRemover(object):
|
||||
|
||||
def __init__(self, connection_class):
|
||||
self._connection_class = connection_class
|
||||
self._connection_pool_to_connections = {}
|
||||
@@ -378,11 +388,12 @@ class ConnectionRemover(object):
|
||||
|
||||
|
||||
def reset_patchers():
|
||||
yield mock.patch.object(httplib, 'HTTPConnection', _HTTPConnection)
|
||||
yield mock.patch.object(httplib, 'HTTPSConnection', _HTTPSConnection)
|
||||
yield mock.patch.object(httplib, "HTTPConnection", _HTTPConnection)
|
||||
yield mock.patch.object(httplib, "HTTPSConnection", _HTTPSConnection)
|
||||
|
||||
try:
|
||||
import requests
|
||||
|
||||
if requests.__build__ < 0x021603:
|
||||
# Avoid double unmock if requests 2.16.3
|
||||
# First, this is pointless, requests.packages.urllib3 *IS* urllib3 (see packages.py)
|
||||
@@ -400,29 +411,27 @@ def reset_patchers():
|
||||
pass
|
||||
else:
|
||||
# unpatch requests v1.x
|
||||
yield mock.patch.object(cpool, 'VerifiedHTTPSConnection', _VerifiedHTTPSConnection)
|
||||
yield mock.patch.object(cpool, 'HTTPConnection', _cpoolHTTPConnection)
|
||||
yield mock.patch.object(cpool, "VerifiedHTTPSConnection", _VerifiedHTTPSConnection)
|
||||
yield mock.patch.object(cpool, "HTTPConnection", _cpoolHTTPConnection)
|
||||
# unpatch requests v2.x
|
||||
if hasattr(cpool.HTTPConnectionPool, 'ConnectionCls'):
|
||||
yield mock.patch.object(cpool.HTTPConnectionPool, 'ConnectionCls',
|
||||
_cpoolHTTPConnection)
|
||||
yield mock.patch.object(cpool.HTTPSConnectionPool, 'ConnectionCls',
|
||||
_cpoolHTTPSConnection)
|
||||
if hasattr(cpool.HTTPConnectionPool, "ConnectionCls"):
|
||||
yield mock.patch.object(cpool.HTTPConnectionPool, "ConnectionCls", _cpoolHTTPConnection)
|
||||
yield mock.patch.object(cpool.HTTPSConnectionPool, "ConnectionCls", _cpoolHTTPSConnection)
|
||||
|
||||
if hasattr(cpool, 'HTTPSConnection'):
|
||||
yield mock.patch.object(cpool, 'HTTPSConnection', _cpoolHTTPSConnection)
|
||||
if hasattr(cpool, "HTTPSConnection"):
|
||||
yield mock.patch.object(cpool, "HTTPSConnection", _cpoolHTTPSConnection)
|
||||
|
||||
try:
|
||||
import urllib3.connectionpool as cpool
|
||||
except ImportError: # pragma: no cover
|
||||
pass
|
||||
else:
|
||||
yield mock.patch.object(cpool, 'VerifiedHTTPSConnection', _VerifiedHTTPSConnection)
|
||||
yield mock.patch.object(cpool, 'HTTPConnection', _cpoolHTTPConnection)
|
||||
yield mock.patch.object(cpool, 'HTTPSConnection', _cpoolHTTPSConnection)
|
||||
if hasattr(cpool.HTTPConnectionPool, 'ConnectionCls'):
|
||||
yield mock.patch.object(cpool.HTTPConnectionPool, 'ConnectionCls', _cpoolHTTPConnection)
|
||||
yield mock.patch.object(cpool.HTTPSConnectionPool, 'ConnectionCls', _cpoolHTTPSConnection)
|
||||
yield mock.patch.object(cpool, "VerifiedHTTPSConnection", _VerifiedHTTPSConnection)
|
||||
yield mock.patch.object(cpool, "HTTPConnection", _cpoolHTTPConnection)
|
||||
yield mock.patch.object(cpool, "HTTPSConnection", _cpoolHTTPSConnection)
|
||||
if hasattr(cpool.HTTPConnectionPool, "ConnectionCls"):
|
||||
yield mock.patch.object(cpool.HTTPConnectionPool, "ConnectionCls", _cpoolHTTPConnection)
|
||||
yield mock.patch.object(cpool.HTTPSConnectionPool, "ConnectionCls", _cpoolHTTPSConnection)
|
||||
|
||||
try:
|
||||
# unpatch botocore with awsrequest
|
||||
@@ -435,64 +444,53 @@ def reset_patchers():
|
||||
pass
|
||||
else:
|
||||
# unpatch requests v1.x
|
||||
yield mock.patch.object(cpool, 'VerifiedHTTPSConnection', _Boto3VerifiedHTTPSConnection)
|
||||
yield mock.patch.object(cpool, 'HTTPConnection', _cpoolBoto3HTTPConnection)
|
||||
yield mock.patch.object(cpool, "VerifiedHTTPSConnection", _Boto3VerifiedHTTPSConnection)
|
||||
yield mock.patch.object(cpool, "HTTPConnection", _cpoolBoto3HTTPConnection)
|
||||
# unpatch requests v2.x
|
||||
if hasattr(cpool.HTTPConnectionPool, 'ConnectionCls'):
|
||||
yield mock.patch.object(cpool.HTTPConnectionPool, 'ConnectionCls',
|
||||
_cpoolBoto3HTTPConnection)
|
||||
yield mock.patch.object(cpool.HTTPSConnectionPool, 'ConnectionCls',
|
||||
_cpoolBoto3HTTPSConnection)
|
||||
if hasattr(cpool.HTTPConnectionPool, "ConnectionCls"):
|
||||
yield mock.patch.object(cpool.HTTPConnectionPool, "ConnectionCls", _cpoolBoto3HTTPConnection)
|
||||
yield mock.patch.object(
|
||||
cpool.HTTPSConnectionPool, "ConnectionCls", _cpoolBoto3HTTPSConnection
|
||||
)
|
||||
|
||||
if hasattr(cpool, 'HTTPSConnection'):
|
||||
yield mock.patch.object(cpool, 'HTTPSConnection', _cpoolBoto3HTTPSConnection)
|
||||
if hasattr(cpool, "HTTPSConnection"):
|
||||
yield mock.patch.object(cpool, "HTTPSConnection", _cpoolBoto3HTTPSConnection)
|
||||
else:
|
||||
if hasattr(cpool.AWSHTTPConnectionPool, 'ConnectionCls'):
|
||||
yield mock.patch.object(cpool.AWSHTTPConnectionPool, 'ConnectionCls',
|
||||
_cpoolBoto3HTTPConnection)
|
||||
yield mock.patch.object(cpool.AWSHTTPSConnectionPool, 'ConnectionCls',
|
||||
_cpoolBoto3HTTPSConnection)
|
||||
if hasattr(cpool.AWSHTTPConnectionPool, "ConnectionCls"):
|
||||
yield mock.patch.object(cpool.AWSHTTPConnectionPool, "ConnectionCls", _cpoolBoto3HTTPConnection)
|
||||
yield mock.patch.object(cpool.AWSHTTPSConnectionPool, "ConnectionCls", _cpoolBoto3HTTPSConnection)
|
||||
|
||||
if hasattr(cpool, 'AWSHTTPSConnection'):
|
||||
yield mock.patch.object(cpool, 'AWSHTTPSConnection', _cpoolBoto3HTTPSConnection)
|
||||
if hasattr(cpool, "AWSHTTPSConnection"):
|
||||
yield mock.patch.object(cpool, "AWSHTTPSConnection", _cpoolBoto3HTTPSConnection)
|
||||
|
||||
try:
|
||||
import httplib2 as cpool
|
||||
except ImportError: # pragma: no cover
|
||||
pass
|
||||
else:
|
||||
yield mock.patch.object(cpool, 'HTTPConnectionWithTimeout', _HTTPConnectionWithTimeout)
|
||||
yield mock.patch.object(cpool, 'HTTPSConnectionWithTimeout', _HTTPSConnectionWithTimeout)
|
||||
yield mock.patch.object(cpool, 'SCHEME_TO_CONNECTION', _SCHEME_TO_CONNECTION)
|
||||
yield mock.patch.object(cpool, "HTTPConnectionWithTimeout", _HTTPConnectionWithTimeout)
|
||||
yield mock.patch.object(cpool, "HTTPSConnectionWithTimeout", _HTTPSConnectionWithTimeout)
|
||||
yield mock.patch.object(cpool, "SCHEME_TO_CONNECTION", _SCHEME_TO_CONNECTION)
|
||||
|
||||
try:
|
||||
import boto.https_connection as cpool
|
||||
except ImportError: # pragma: no cover
|
||||
pass
|
||||
else:
|
||||
yield mock.patch.object(cpool, 'CertValidatingHTTPSConnection',
|
||||
_CertValidatingHTTPSConnection)
|
||||
yield mock.patch.object(cpool, "CertValidatingHTTPSConnection", _CertValidatingHTTPSConnection)
|
||||
|
||||
try:
|
||||
import tornado.simple_httpclient as simple
|
||||
except ImportError: # pragma: no cover
|
||||
pass
|
||||
else:
|
||||
yield mock.patch.object(
|
||||
simple.SimpleAsyncHTTPClient,
|
||||
'fetch_impl',
|
||||
_SimpleAsyncHTTPClient_fetch_impl,
|
||||
)
|
||||
yield mock.patch.object(simple.SimpleAsyncHTTPClient, "fetch_impl", _SimpleAsyncHTTPClient_fetch_impl)
|
||||
try:
|
||||
import tornado.curl_httpclient as curl
|
||||
except ImportError: # pragma: no cover
|
||||
pass
|
||||
else:
|
||||
yield mock.patch.object(
|
||||
curl.CurlAsyncHTTPClient,
|
||||
'fetch_impl',
|
||||
_CurlAsyncHTTPClient_fetch_impl,
|
||||
)
|
||||
yield mock.patch.object(curl.CurlAsyncHTTPClient, "fetch_impl", _CurlAsyncHTTPClient_fetch_impl)
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
|
||||
@@ -5,14 +5,13 @@ from ..serialize import serialize, deserialize
|
||||
|
||||
|
||||
class FilesystemPersister(object):
|
||||
|
||||
@classmethod
|
||||
def load_cassette(cls, cassette_path, serializer):
|
||||
try:
|
||||
with open(cassette_path) as f:
|
||||
cassette_content = f.read()
|
||||
except IOError:
|
||||
raise ValueError('Cassette not found.')
|
||||
raise ValueError("Cassette not found.")
|
||||
cassette = deserialize(cassette_content, serializer)
|
||||
return cassette
|
||||
|
||||
@@ -22,5 +21,5 @@ class FilesystemPersister(object):
|
||||
dirname, filename = os.path.split(cassette_path)
|
||||
if dirname and not os.path.exists(dirname):
|
||||
os.makedirs(dirname)
|
||||
with open(cassette_path, 'w') as f:
|
||||
with open(cassette_path, "w") as f:
|
||||
f.write(data)
|
||||
|
||||
@@ -15,7 +15,7 @@ class Request(object):
|
||||
def __init__(self, method, uri, body, headers):
|
||||
self.method = method
|
||||
self.uri = uri
|
||||
self._was_file = hasattr(body, 'read')
|
||||
self._was_file = hasattr(body, "read")
|
||||
if self._was_file:
|
||||
self.body = body.read()
|
||||
else:
|
||||
@@ -40,13 +40,14 @@ class Request(object):
|
||||
@body.setter
|
||||
def body(self, value):
|
||||
if isinstance(value, text_type):
|
||||
value = value.encode('utf-8')
|
||||
value = value.encode("utf-8")
|
||||
self._body = value
|
||||
|
||||
def add_header(self, key, value):
|
||||
warnings.warn("Request.add_header is deprecated. "
|
||||
"Please assign to request.headers instead.",
|
||||
DeprecationWarning)
|
||||
warnings.warn(
|
||||
"Request.add_header is deprecated. " "Please assign to request.headers instead.",
|
||||
DeprecationWarning,
|
||||
)
|
||||
self.headers[key] = value
|
||||
|
||||
@property
|
||||
@@ -63,7 +64,7 @@ class Request(object):
|
||||
port = parse_uri.port
|
||||
if port is None:
|
||||
try:
|
||||
port = {'https': 443, 'http': 80}[parse_uri.scheme]
|
||||
port = {"https": 443, "http": 80}[parse_uri.scheme]
|
||||
except KeyError:
|
||||
pass
|
||||
return port
|
||||
@@ -95,10 +96,10 @@ class Request(object):
|
||||
|
||||
def _to_dict(self):
|
||||
return {
|
||||
'method': self.method,
|
||||
'uri': self.uri,
|
||||
'body': self.body,
|
||||
'headers': {k: [v] for k, v in self.headers.items()},
|
||||
"method": self.method,
|
||||
"uri": self.uri,
|
||||
"body": self.body,
|
||||
"headers": {k: [v] for k, v in self.headers.items()},
|
||||
}
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -20,7 +20,7 @@ Deserializing: string (yaml converts from utf-8) -> bytestring
|
||||
|
||||
|
||||
def _looks_like_an_old_cassette(data):
|
||||
return isinstance(data, list) and len(data) and 'request' in data[0]
|
||||
return isinstance(data, list) and len(data) and "request" in data[0]
|
||||
|
||||
|
||||
def _warn_about_old_cassette_format():
|
||||
@@ -41,23 +41,18 @@ def deserialize(cassette_string, serializer):
|
||||
if _looks_like_an_old_cassette(data):
|
||||
_warn_about_old_cassette_format()
|
||||
|
||||
requests = [Request._from_dict(r['request']) for r in data['interactions']]
|
||||
responses = [
|
||||
compat.convert_to_bytes(r['response']) for r in data['interactions']
|
||||
]
|
||||
requests = [Request._from_dict(r["request"]) for r in data["interactions"]]
|
||||
responses = [compat.convert_to_bytes(r["response"]) for r in data["interactions"]]
|
||||
return requests, responses
|
||||
|
||||
|
||||
def serialize(cassette_dict, serializer):
|
||||
interactions = ([{
|
||||
'request': compat.convert_to_unicode(request._to_dict()),
|
||||
'response': compat.convert_to_unicode(response),
|
||||
} for request, response in zip(
|
||||
cassette_dict['requests'],
|
||||
cassette_dict['responses'],
|
||||
)])
|
||||
data = {
|
||||
'version': CASSETTE_FORMAT_VERSION,
|
||||
'interactions': interactions,
|
||||
}
|
||||
interactions = [
|
||||
{
|
||||
"request": compat.convert_to_unicode(request._to_dict()),
|
||||
"response": compat.convert_to_unicode(response),
|
||||
}
|
||||
for request, response in zip(cassette_dict["requests"], cassette_dict["responses"])
|
||||
]
|
||||
data = {"version": CASSETTE_FORMAT_VERSION, "interactions": interactions}
|
||||
return serializer.serialize(data)
|
||||
|
||||
@@ -24,8 +24,8 @@ def convert_body_to_bytes(resp):
|
||||
http://pyyaml.org/wiki/PyYAMLDocumentation#Python3support
|
||||
"""
|
||||
try:
|
||||
if resp['body']['string'] is not None and not isinstance(resp['body']['string'], six.binary_type):
|
||||
resp['body']['string'] = resp['body']['string'].encode('utf-8')
|
||||
if resp["body"]["string"] is not None and not isinstance(resp["body"]["string"], six.binary_type):
|
||||
resp["body"]["string"] = resp["body"]["string"].encode("utf-8")
|
||||
except (KeyError, TypeError, UnicodeEncodeError):
|
||||
# The thing we were converting either wasn't a dictionary or didn't
|
||||
# have the keys we were expecting. Some of the tests just serialize
|
||||
@@ -45,7 +45,7 @@ def _convert_string_to_unicode(string):
|
||||
|
||||
try:
|
||||
if string is not None and not isinstance(string, six.text_type):
|
||||
result = string.decode('utf-8')
|
||||
result = string.decode("utf-8")
|
||||
except (TypeError, UnicodeDecodeError, AttributeError):
|
||||
# Sometimes the string actually is binary or StringIO object,
|
||||
# so if you can't decode it, just give up.
|
||||
@@ -63,17 +63,15 @@ def convert_body_to_unicode(resp):
|
||||
# Some of the tests just serialize and deserialize a string.
|
||||
return _convert_string_to_unicode(resp)
|
||||
else:
|
||||
body = resp.get('body')
|
||||
body = resp.get("body")
|
||||
|
||||
if body is not None:
|
||||
try:
|
||||
body['string'] = _convert_string_to_unicode(
|
||||
body['string']
|
||||
)
|
||||
body["string"] = _convert_string_to_unicode(body["string"])
|
||||
except (KeyError, TypeError, AttributeError):
|
||||
# The thing we were converting either wasn't a dictionary or
|
||||
# didn't have the keys we were expecting.
|
||||
# For example request object has no 'string' key.
|
||||
resp['body'] = _convert_string_to_unicode(body)
|
||||
resp["body"] = _convert_string_to_unicode(body)
|
||||
|
||||
return resp
|
||||
|
||||
@@ -23,7 +23,7 @@ def serialize(cassette_dict):
|
||||
b"Error serializing cassette to JSON",
|
||||
original.start,
|
||||
original.end,
|
||||
original.args[-1] + error_message
|
||||
original.args[-1] + error_message,
|
||||
)
|
||||
except TypeError: # py3
|
||||
raise TypeError(error_message)
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
'''Stubs for patching HTTP and HTTPS requests'''
|
||||
"""Stubs for patching HTTP and HTTPS requests"""
|
||||
|
||||
import logging
|
||||
import six
|
||||
from six.moves.http_client import (
|
||||
HTTPConnection,
|
||||
HTTPSConnection,
|
||||
HTTPResponse,
|
||||
)
|
||||
from six.moves.http_client import HTTPConnection, HTTPSConnection, HTTPResponse
|
||||
from six import BytesIO
|
||||
from vcr.request import Request
|
||||
from vcr.errors import CannotOverwriteExistingCassetteException
|
||||
@@ -45,8 +41,7 @@ def parse_headers(header_list):
|
||||
header_string = b""
|
||||
for key, values in header_list.items():
|
||||
for v in values:
|
||||
header_string += \
|
||||
key.encode('utf-8') + b":" + v.encode('utf-8') + b"\r\n"
|
||||
header_string += key.encode("utf-8") + b":" + v.encode("utf-8") + b"\r\n"
|
||||
return compat.get_httpmessage(header_string)
|
||||
|
||||
|
||||
@@ -62,27 +57,28 @@ class VCRHTTPResponse(HTTPResponse):
|
||||
"""
|
||||
Stub response class that gets returned instead of a HTTPResponse
|
||||
"""
|
||||
|
||||
def __init__(self, recorded_response):
|
||||
self.fp = None
|
||||
self.recorded_response = recorded_response
|
||||
self.reason = recorded_response['status']['message']
|
||||
self.status = self.code = recorded_response['status']['code']
|
||||
self.reason = recorded_response["status"]["message"]
|
||||
self.status = self.code = recorded_response["status"]["code"]
|
||||
self.version = None
|
||||
self._content = BytesIO(self.recorded_response['body']['string'])
|
||||
self._content = BytesIO(self.recorded_response["body"]["string"])
|
||||
self._closed = False
|
||||
|
||||
headers = self.recorded_response['headers']
|
||||
headers = self.recorded_response["headers"]
|
||||
# Since we are loading a response that has already been serialized, our
|
||||
# response is no longer chunked. That means we don't want any
|
||||
# libraries trying to process a chunked response. By removing the
|
||||
# transfer-encoding: chunked header, this should cause the downstream
|
||||
# libraries to process this as a non-chunked response.
|
||||
te_key = [h for h in headers.keys() if h.upper() == 'TRANSFER-ENCODING']
|
||||
te_key = [h for h in headers.keys() if h.upper() == "TRANSFER-ENCODING"]
|
||||
if te_key:
|
||||
del headers[te_key[0]]
|
||||
self.headers = self.msg = parse_headers(headers)
|
||||
|
||||
self.length = compat.get_header(self.msg, 'content-length') or None
|
||||
self.length = compat.get_header(self.msg, "content-length") or None
|
||||
|
||||
@property
|
||||
def closed(self):
|
||||
@@ -129,17 +125,17 @@ class VCRHTTPResponse(HTTPResponse):
|
||||
return self.closed
|
||||
|
||||
def info(self):
|
||||
return parse_headers(self.recorded_response['headers'])
|
||||
return parse_headers(self.recorded_response["headers"])
|
||||
|
||||
def getheaders(self):
|
||||
message = parse_headers(self.recorded_response['headers'])
|
||||
message = parse_headers(self.recorded_response["headers"])
|
||||
return list(compat.get_header_items(message))
|
||||
|
||||
def getheader(self, header, default=None):
|
||||
values = [v for (k, v) in self.getheaders() if k.lower() == header.lower()]
|
||||
|
||||
if values:
|
||||
return ', '.join(values)
|
||||
return ", ".join(values)
|
||||
else:
|
||||
return default
|
||||
|
||||
@@ -156,41 +152,27 @@ class VCRConnection(object):
|
||||
Returns empty string for the default port and ':port' otherwise
|
||||
"""
|
||||
port = self.real_connection.port
|
||||
default_port = {'https': 443, 'http': 80}[self._protocol]
|
||||
return ':{}'.format(port) if port != default_port else ''
|
||||
default_port = {"https": 443, "http": 80}[self._protocol]
|
||||
return ":{}".format(port) if port != default_port else ""
|
||||
|
||||
def _uri(self, url):
|
||||
"""Returns request absolute URI"""
|
||||
if url and not url.startswith('/'):
|
||||
if url and not url.startswith("/"):
|
||||
# Then this must be a proxy request.
|
||||
return url
|
||||
uri = "{}://{}{}{}".format(
|
||||
self._protocol,
|
||||
self.real_connection.host,
|
||||
self._port_postfix(),
|
||||
url,
|
||||
)
|
||||
uri = "{}://{}{}{}".format(self._protocol, self.real_connection.host, self._port_postfix(), url)
|
||||
log.debug("Absolute URI: %s", uri)
|
||||
return uri
|
||||
|
||||
def _url(self, uri):
|
||||
"""Returns request selector url from absolute URI"""
|
||||
prefix = "{}://{}{}".format(
|
||||
self._protocol,
|
||||
self.real_connection.host,
|
||||
self._port_postfix(),
|
||||
)
|
||||
return uri.replace(prefix, '', 1)
|
||||
prefix = "{}://{}{}".format(self._protocol, self.real_connection.host, self._port_postfix())
|
||||
return uri.replace(prefix, "", 1)
|
||||
|
||||
def request(self, method, url, body=None, headers=None, *args, **kwargs):
|
||||
'''Persist the request metadata in self._vcr_request'''
|
||||
self._vcr_request = Request(
|
||||
method=method,
|
||||
uri=self._uri(url),
|
||||
body=body,
|
||||
headers=headers or {}
|
||||
)
|
||||
log.debug('Got {}'.format(self._vcr_request))
|
||||
"""Persist the request metadata in self._vcr_request"""
|
||||
self._vcr_request = Request(method=method, uri=self._uri(url), body=body, headers=headers or {})
|
||||
log.debug("Got {}".format(self._vcr_request))
|
||||
|
||||
# Note: The request may not actually be finished at this point, so
|
||||
# I'm not sending the actual request until getresponse(). This
|
||||
@@ -205,25 +187,19 @@ class VCRConnection(object):
|
||||
to start building up a request. Usually followed by a bunch
|
||||
of putheader() calls.
|
||||
"""
|
||||
self._vcr_request = Request(
|
||||
method=method,
|
||||
uri=self._uri(url),
|
||||
body="",
|
||||
headers={}
|
||||
)
|
||||
log.debug('Got {}'.format(self._vcr_request))
|
||||
self._vcr_request = Request(method=method, uri=self._uri(url), body="", headers={})
|
||||
log.debug("Got {}".format(self._vcr_request))
|
||||
|
||||
def putheader(self, header, *values):
|
||||
self._vcr_request.headers[header] = values
|
||||
|
||||
def send(self, data):
|
||||
'''
|
||||
"""
|
||||
This method is called after request(), to add additional data to the
|
||||
body of the request. So if that happens, let's just append the data
|
||||
onto the most recent request in the cassette.
|
||||
'''
|
||||
self._vcr_request.body = self._vcr_request.body + data \
|
||||
if self._vcr_request.body else data
|
||||
"""
|
||||
self._vcr_request.body = self._vcr_request.body + data if self._vcr_request.body else data
|
||||
|
||||
def close(self):
|
||||
# Note: the real connection will only close if it's open, so
|
||||
@@ -240,37 +216,27 @@ class VCRConnection(object):
|
||||
self._vcr_request.body = message_body
|
||||
|
||||
def getresponse(self, _=False, **kwargs):
|
||||
'''Retrieve the response'''
|
||||
"""Retrieve the response"""
|
||||
# Check to see if the cassette has a response for this request. If so,
|
||||
# then return it
|
||||
if self.cassette.can_play_response_for(self._vcr_request):
|
||||
log.info(
|
||||
"Playing response for {} from cassette".format(
|
||||
self._vcr_request
|
||||
)
|
||||
)
|
||||
log.info("Playing response for {} from cassette".format(self._vcr_request))
|
||||
response = self.cassette.play_response(self._vcr_request)
|
||||
return VCRHTTPResponse(response)
|
||||
else:
|
||||
if self.cassette.write_protected and self.cassette.filter_request(
|
||||
self._vcr_request
|
||||
):
|
||||
if self.cassette.write_protected and self.cassette.filter_request(self._vcr_request):
|
||||
raise CannotOverwriteExistingCassetteException(
|
||||
cassette=self.cassette,
|
||||
failed_request=self._vcr_request
|
||||
cassette=self.cassette, failed_request=self._vcr_request
|
||||
)
|
||||
|
||||
# Otherwise, we should send the request, then get the response
|
||||
# and return it.
|
||||
|
||||
log.info(
|
||||
"{} not in cassette, sending to real server".format(
|
||||
self._vcr_request
|
||||
)
|
||||
)
|
||||
log.info("{} not in cassette, sending to real server".format(self._vcr_request))
|
||||
# This is imported here to avoid circular import.
|
||||
# TODO(@IvanMalison): Refactor to allow normal import.
|
||||
from vcr.patch import force_reset
|
||||
|
||||
with force_reset():
|
||||
self.real_connection.request(
|
||||
method=self._vcr_request.method,
|
||||
@@ -284,12 +250,9 @@ class VCRConnection(object):
|
||||
|
||||
# put the response into the cassette
|
||||
response = {
|
||||
'status': {
|
||||
'code': response.status,
|
||||
'message': response.reason
|
||||
},
|
||||
'headers': serialize_headers(response),
|
||||
'body': {'string': response.read()},
|
||||
"status": {"code": response.status, "message": response.reason},
|
||||
"headers": serialize_headers(response),
|
||||
"body": {"string": response.read()},
|
||||
}
|
||||
self.cassette.append(self._vcr_request, response)
|
||||
return VCRHTTPResponse(response)
|
||||
@@ -305,8 +268,7 @@ class VCRConnection(object):
|
||||
and are not write-protected.
|
||||
"""
|
||||
|
||||
if hasattr(self, '_vcr_request') and \
|
||||
self.cassette.can_play_response_for(self._vcr_request):
|
||||
if hasattr(self, "_vcr_request") and self.cassette.can_play_response_for(self._vcr_request):
|
||||
# We already have a response we are going to play, don't
|
||||
# actually connect
|
||||
return
|
||||
@@ -316,6 +278,7 @@ class VCRConnection(object):
|
||||
return
|
||||
|
||||
from vcr.patch import force_reset
|
||||
|
||||
with force_reset():
|
||||
return self.real_connection.connect(*args, **kwargs)
|
||||
|
||||
@@ -334,12 +297,13 @@ class VCRConnection(object):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if six.PY3:
|
||||
kwargs.pop('strict', None) # apparently this is gone in py3
|
||||
kwargs.pop("strict", None) # apparently this is gone in py3
|
||||
|
||||
# need to temporarily reset here because the real connection
|
||||
# inherits from the thing that we are mocking out. Take out
|
||||
# the reset if you want to see what I mean :)
|
||||
from vcr.patch import force_reset
|
||||
|
||||
with force_reset():
|
||||
self.real_connection = self._baseclass(*args, **kwargs)
|
||||
|
||||
@@ -371,7 +335,7 @@ class VCRConnection(object):
|
||||
Send requests for weird attributes up to the real connection
|
||||
(counterpart to __setattr above)
|
||||
"""
|
||||
if self.__dict__.get('real_connection'):
|
||||
if self.__dict__.get("real_connection"):
|
||||
# check in case real_connection has not been set yet, such as when
|
||||
# we're setting the real_connection itself for the first time
|
||||
return getattr(self.real_connection, name)
|
||||
@@ -385,13 +349,15 @@ for k, v in HTTPConnection.__dict__.items():
|
||||
|
||||
|
||||
class VCRHTTPConnection(VCRConnection):
|
||||
'''A Mocked class for HTTP requests'''
|
||||
"""A Mocked class for HTTP requests"""
|
||||
|
||||
_baseclass = HTTPConnection
|
||||
_protocol = 'http'
|
||||
_protocol = "http"
|
||||
|
||||
|
||||
class VCRHTTPSConnection(VCRConnection):
|
||||
'''A Mocked class for HTTPS requests'''
|
||||
"""A Mocked class for HTTPS requests"""
|
||||
|
||||
_baseclass = HTTPSConnection
|
||||
_protocol = 'https'
|
||||
_protocol = "https"
|
||||
is_verified = True
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
'''Stubs for aiohttp HTTP clients'''
|
||||
"""Stubs for aiohttp HTTP clients"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
import asyncio
|
||||
@@ -33,14 +33,14 @@ class MockClientResponse(ClientResponse):
|
||||
session=None,
|
||||
)
|
||||
|
||||
async def json(self, *, encoding='utf-8', loads=json.loads, **kwargs): # NOQA: E999
|
||||
async def json(self, *, encoding="utf-8", loads=json.loads, **kwargs): # NOQA: E999
|
||||
stripped = self._body.strip()
|
||||
if not stripped:
|
||||
return None
|
||||
|
||||
return loads(stripped.decode(encoding))
|
||||
|
||||
async def text(self, encoding='utf-8', errors='strict'):
|
||||
async def text(self, encoding="utf-8", errors="strict"):
|
||||
return self._body.decode(encoding, errors=errors)
|
||||
|
||||
async def read(self):
|
||||
@@ -58,11 +58,11 @@ class MockClientResponse(ClientResponse):
|
||||
|
||||
|
||||
def build_response(vcr_request, vcr_response, history):
|
||||
response = MockClientResponse(vcr_request.method, URL(vcr_response.get('url')))
|
||||
response.status = vcr_response['status']['code']
|
||||
response._body = vcr_response['body'].get('string', b'')
|
||||
response.reason = vcr_response['status']['message']
|
||||
response._headers = CIMultiDictProxy(CIMultiDict(vcr_response['headers']))
|
||||
response = MockClientResponse(vcr_request.method, URL(vcr_response.get("url")))
|
||||
response.status = vcr_response["status"]["code"]
|
||||
response._body = vcr_response["body"].get("string", b"")
|
||||
response.reason = vcr_response["status"]["message"]
|
||||
response._headers = CIMultiDictProxy(CIMultiDict(vcr_response["headers"]))
|
||||
response._history = tuple(history)
|
||||
|
||||
response.close()
|
||||
@@ -83,17 +83,14 @@ def play_responses(cassette, vcr_request):
|
||||
|
||||
|
||||
async def record_response(cassette, vcr_request, response, past=False):
|
||||
body = {} if past else {'string': (await response.read())}
|
||||
body = {} if past else {"string": (await response.read())}
|
||||
headers = {str(key): value for key, value in response.headers.items()}
|
||||
|
||||
vcr_response = {
|
||||
'status': {
|
||||
'code': response.status,
|
||||
'message': response.reason,
|
||||
},
|
||||
'headers': headers,
|
||||
'body': body, # NOQA: E999
|
||||
'url': str(response.url),
|
||||
"status": {"code": response.status, "message": response.reason},
|
||||
"headers": headers,
|
||||
"body": body, # NOQA: E999
|
||||
"url": str(response.url),
|
||||
}
|
||||
cassette.append(vcr_request, vcr_response)
|
||||
|
||||
@@ -108,14 +105,14 @@ async def record_responses(cassette, vcr_request, response):
|
||||
def vcr_request(cassette, real_request):
|
||||
@functools.wraps(real_request)
|
||||
async def new_request(self, method, url, **kwargs):
|
||||
headers = kwargs.get('headers')
|
||||
auth = kwargs.get('auth')
|
||||
headers = kwargs.get("headers")
|
||||
auth = kwargs.get("auth")
|
||||
headers = self._prepare_headers(headers)
|
||||
data = kwargs.get('data', kwargs.get('json'))
|
||||
params = kwargs.get('params')
|
||||
data = kwargs.get("data", kwargs.get("json"))
|
||||
params = kwargs.get("params")
|
||||
|
||||
if auth is not None:
|
||||
headers['AUTHORIZATION'] = auth.encode()
|
||||
headers["AUTHORIZATION"] = auth.encode()
|
||||
|
||||
request_url = URL(url)
|
||||
if params:
|
||||
@@ -131,14 +128,16 @@ def vcr_request(cassette, real_request):
|
||||
if cassette.write_protected and cassette.filter_request(vcr_request):
|
||||
response = MockClientResponse(method, URL(url))
|
||||
response.status = 599
|
||||
msg = ("No match for the request {!r} was found. Can't overwrite "
|
||||
"existing cassette {!r} in your current record mode {!r}.")
|
||||
msg = (
|
||||
"No match for the request {!r} was found. Can't overwrite "
|
||||
"existing cassette {!r} in your current record mode {!r}."
|
||||
)
|
||||
msg = msg.format(vcr_request, cassette._path, cassette.record_mode)
|
||||
response._body = msg.encode()
|
||||
response.close()
|
||||
return response
|
||||
|
||||
log.info('%s not in cassette, sending to real server', vcr_request)
|
||||
log.info("%s not in cassette, sending to real server", vcr_request)
|
||||
|
||||
response = await real_request(self, method, url, **kwargs) # NOQA: E999
|
||||
await record_responses(cassette, vcr_request, response)
|
||||
|
||||
@@ -27,17 +27,18 @@ class VCRRequestsHTTPSConnection(VCRHTTPSConnection, VerifiedHTTPSConnection):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if six.PY3:
|
||||
kwargs.pop('strict', None) # apparently this is gone in py3
|
||||
kwargs.pop("strict", None) # apparently this is gone in py3
|
||||
|
||||
# need to temporarily reset here because the real connection
|
||||
# inherits from the thing that we are mocking out. Take out
|
||||
# the reset if you want to see what I mean :)
|
||||
from vcr.patch import force_reset
|
||||
|
||||
with force_reset():
|
||||
self.real_connection = self._baseclass(*args, **kwargs)
|
||||
# Make sure to set those attributes as it seems `AWSHTTPConnection` does not
|
||||
# set them, making the connection to fail !
|
||||
self.real_connection.assert_hostname = kwargs.get("assert_hostname", False)
|
||||
self.real_connection.cert_reqs = kwargs.get("cert_reqs", 'CERT_NONE')
|
||||
self.real_connection.cert_reqs = kwargs.get("cert_reqs", "CERT_NONE")
|
||||
|
||||
self._sock = None
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
'''Stubs for boto'''
|
||||
"""Stubs for boto"""
|
||||
|
||||
from boto.https_connection import CertValidatingHTTPSConnection
|
||||
from ..stubs import VCRHTTPSConnection
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import six
|
||||
from six import BytesIO
|
||||
from six.moves.http_client import HTTPMessage
|
||||
|
||||
try:
|
||||
import http.client
|
||||
except ImportError:
|
||||
|
||||
@@ -1,62 +1,60 @@
|
||||
'''Stubs for httplib2'''
|
||||
"""Stubs for httplib2"""
|
||||
|
||||
from httplib2 import HTTPConnectionWithTimeout, HTTPSConnectionWithTimeout
|
||||
from ..stubs import VCRHTTPConnection, VCRHTTPSConnection
|
||||
|
||||
|
||||
class VCRHTTPConnectionWithTimeout(VCRHTTPConnection,
|
||||
HTTPConnectionWithTimeout):
|
||||
class VCRHTTPConnectionWithTimeout(VCRHTTPConnection, HTTPConnectionWithTimeout):
|
||||
_baseclass = HTTPConnectionWithTimeout
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
'''I overrode the init because I need to clean kwargs before calling
|
||||
HTTPConnection.__init__.'''
|
||||
"""I overrode the init because I need to clean kwargs before calling
|
||||
HTTPConnection.__init__."""
|
||||
|
||||
# Delete the keyword arguments that HTTPConnection would not recognize
|
||||
safe_keys = {'host', 'port', 'strict', 'timeout', 'source_address'}
|
||||
safe_keys = {"host", "port", "strict", "timeout", "source_address"}
|
||||
unknown_keys = set(kwargs.keys()) - safe_keys
|
||||
safe_kwargs = kwargs.copy()
|
||||
for kw in unknown_keys:
|
||||
del safe_kwargs[kw]
|
||||
|
||||
self.proxy_info = kwargs.pop('proxy_info', None)
|
||||
self.proxy_info = kwargs.pop("proxy_info", None)
|
||||
VCRHTTPConnection.__init__(self, *args, **safe_kwargs)
|
||||
self.sock = self.real_connection.sock
|
||||
|
||||
|
||||
class VCRHTTPSConnectionWithTimeout(VCRHTTPSConnection,
|
||||
HTTPSConnectionWithTimeout):
|
||||
class VCRHTTPSConnectionWithTimeout(VCRHTTPSConnection, HTTPSConnectionWithTimeout):
|
||||
_baseclass = HTTPSConnectionWithTimeout
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
# Delete the keyword arguments that HTTPSConnection would not recognize
|
||||
safe_keys = {
|
||||
'host',
|
||||
'port',
|
||||
'key_file',
|
||||
'cert_file',
|
||||
'strict',
|
||||
'timeout',
|
||||
'source_address',
|
||||
'ca_certs',
|
||||
'disable_ssl_certificate_validation',
|
||||
"host",
|
||||
"port",
|
||||
"key_file",
|
||||
"cert_file",
|
||||
"strict",
|
||||
"timeout",
|
||||
"source_address",
|
||||
"ca_certs",
|
||||
"disable_ssl_certificate_validation",
|
||||
}
|
||||
unknown_keys = set(kwargs.keys()) - safe_keys
|
||||
safe_kwargs = kwargs.copy()
|
||||
for kw in unknown_keys:
|
||||
del safe_kwargs[kw]
|
||||
self.proxy_info = kwargs.pop('proxy_info', None)
|
||||
if 'ca_certs' not in kwargs or kwargs['ca_certs'] is None:
|
||||
self.proxy_info = kwargs.pop("proxy_info", None)
|
||||
if "ca_certs" not in kwargs or kwargs["ca_certs"] is None:
|
||||
try:
|
||||
import httplib2
|
||||
|
||||
self.ca_certs = httplib2.CA_CERTS
|
||||
except ImportError:
|
||||
self.ca_certs = None
|
||||
else:
|
||||
self.ca_certs = kwargs['ca_certs']
|
||||
self.ca_certs = kwargs["ca_certs"]
|
||||
|
||||
self.disable_ssl_certificate_validation = kwargs.pop(
|
||||
'disable_ssl_certificate_validation', None)
|
||||
self.disable_ssl_certificate_validation = kwargs.pop("disable_ssl_certificate_validation", None)
|
||||
VCRHTTPSConnection.__init__(self, *args, **safe_kwargs)
|
||||
self.sock = self.real_connection.sock
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
'''Stubs for requests'''
|
||||
"""Stubs for requests"""
|
||||
|
||||
try:
|
||||
from urllib3.connectionpool import HTTPConnection, VerifiedHTTPSConnection
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
'''Stubs for tornado HTTP clients'''
|
||||
"""Stubs for tornado HTTP clients"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
import functools
|
||||
@@ -12,20 +12,19 @@ from vcr.request import Request
|
||||
|
||||
|
||||
def vcr_fetch_impl(cassette, real_fetch_impl):
|
||||
|
||||
@functools.wraps(real_fetch_impl)
|
||||
def new_fetch_impl(self, request, callback):
|
||||
headers = request.headers.copy()
|
||||
if request.user_agent:
|
||||
headers.setdefault('User-Agent', request.user_agent)
|
||||
headers.setdefault("User-Agent", request.user_agent)
|
||||
|
||||
# TODO body_producer, header_callback, and streaming_callback are not
|
||||
# yet supported.
|
||||
|
||||
unsupported_call = (
|
||||
getattr(request, 'body_producer', None) is not None or
|
||||
request.header_callback is not None or
|
||||
request.streaming_callback is not None
|
||||
getattr(request, "body_producer", None) is not None
|
||||
or request.header_callback is not None
|
||||
or request.streaming_callback is not None
|
||||
)
|
||||
if unsupported_call:
|
||||
response = HTTPResponse(
|
||||
@@ -40,18 +39,13 @@ def vcr_fetch_impl(cassette, real_fetch_impl):
|
||||
)
|
||||
return callback(response)
|
||||
|
||||
vcr_request = Request(
|
||||
request.method,
|
||||
request.url,
|
||||
request.body,
|
||||
headers,
|
||||
)
|
||||
vcr_request = Request(request.method, request.url, request.body, headers)
|
||||
|
||||
if cassette.can_play_response_for(vcr_request):
|
||||
vcr_response = cassette.play_response(vcr_request)
|
||||
headers = httputil.HTTPHeaders()
|
||||
|
||||
recorded_headers = vcr_response['headers']
|
||||
recorded_headers = vcr_response["headers"]
|
||||
if isinstance(recorded_headers, dict):
|
||||
recorded_headers = recorded_headers.items()
|
||||
for k, vs in recorded_headers:
|
||||
@@ -59,43 +53,34 @@ def vcr_fetch_impl(cassette, real_fetch_impl):
|
||||
headers.add(k, v)
|
||||
response = HTTPResponse(
|
||||
request,
|
||||
code=vcr_response['status']['code'],
|
||||
reason=vcr_response['status']['message'],
|
||||
code=vcr_response["status"]["code"],
|
||||
reason=vcr_response["status"]["message"],
|
||||
headers=headers,
|
||||
buffer=BytesIO(vcr_response['body']['string']),
|
||||
effective_url=vcr_response.get('url'),
|
||||
buffer=BytesIO(vcr_response["body"]["string"]),
|
||||
effective_url=vcr_response.get("url"),
|
||||
request_time=self.io_loop.time() - request.start_time,
|
||||
)
|
||||
return callback(response)
|
||||
else:
|
||||
if cassette.write_protected and cassette.filter_request(
|
||||
vcr_request
|
||||
):
|
||||
if cassette.write_protected and cassette.filter_request(vcr_request):
|
||||
response = HTTPResponse(
|
||||
request,
|
||||
599,
|
||||
error=CannotOverwriteExistingCassetteException(
|
||||
cassette=cassette,
|
||||
failed_request=vcr_request
|
||||
cassette=cassette, failed_request=vcr_request
|
||||
),
|
||||
request_time=self.io_loop.time() - request.start_time,
|
||||
)
|
||||
return callback(response)
|
||||
|
||||
def new_callback(response):
|
||||
headers = [
|
||||
(k, response.headers.get_list(k))
|
||||
for k in response.headers.keys()
|
||||
]
|
||||
headers = [(k, response.headers.get_list(k)) for k in response.headers.keys()]
|
||||
|
||||
vcr_response = {
|
||||
'status': {
|
||||
'code': response.code,
|
||||
'message': response.reason,
|
||||
},
|
||||
'headers': headers,
|
||||
'body': {'string': response.body},
|
||||
'url': response.effective_url,
|
||||
"status": {"code": response.code, "message": response.reason},
|
||||
"headers": headers,
|
||||
"body": {"string": response.body},
|
||||
"url": response.effective_url,
|
||||
}
|
||||
cassette.append(vcr_request, vcr_response)
|
||||
return callback(response)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
'''Stubs for urllib3'''
|
||||
"""Stubs for urllib3"""
|
||||
|
||||
from urllib3.connectionpool import HTTPConnection, VerifiedHTTPSConnection
|
||||
from ..stubs import VCRHTTPConnection, VCRHTTPSConnection
|
||||
|
||||
28
vcr/util.py
28
vcr/util.py
@@ -29,6 +29,7 @@ class CaseInsensitiveDict(MutableMapping):
|
||||
operations are given keys that have equal ``.lower()``s, the
|
||||
behavior is undefined.
|
||||
"""
|
||||
|
||||
def __init__(self, data=None, **kwargs):
|
||||
self._store = dict()
|
||||
if data is None:
|
||||
@@ -54,11 +55,7 @@ class CaseInsensitiveDict(MutableMapping):
|
||||
|
||||
def lower_items(self):
|
||||
"""Like iteritems(), but with all lowercase keys."""
|
||||
return (
|
||||
(lowerkey, keyval[1])
|
||||
for (lowerkey, keyval)
|
||||
in self._store.items()
|
||||
)
|
||||
return ((lowerkey, keyval[1]) for (lowerkey, keyval) in self._store.items())
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, Mapping):
|
||||
@@ -92,37 +89,30 @@ def compose(*functions):
|
||||
if function:
|
||||
res = function(res)
|
||||
return res
|
||||
|
||||
return composed
|
||||
|
||||
|
||||
def read_body(request):
|
||||
if hasattr(request.body, 'read'):
|
||||
if hasattr(request.body, "read"):
|
||||
return request.body.read()
|
||||
return request.body
|
||||
|
||||
|
||||
def auto_decorate(
|
||||
decorator,
|
||||
predicate=lambda name, value: isinstance(value, types.FunctionType)
|
||||
):
|
||||
def auto_decorate(decorator, predicate=lambda name, value: isinstance(value, types.FunctionType)):
|
||||
def maybe_decorate(attribute, value):
|
||||
if predicate(attribute, value):
|
||||
value = decorator(value)
|
||||
return value
|
||||
|
||||
class DecorateAll(type):
|
||||
|
||||
def __setattr__(cls, attribute, value):
|
||||
return super(DecorateAll, cls).__setattr__(
|
||||
attribute, maybe_decorate(attribute, value)
|
||||
)
|
||||
return super(DecorateAll, cls).__setattr__(attribute, maybe_decorate(attribute, value))
|
||||
|
||||
def __new__(cls, name, bases, attributes_dict):
|
||||
new_attributes_dict = {
|
||||
attribute: maybe_decorate(attribute, value)
|
||||
for attribute, value in attributes_dict.items()
|
||||
attribute: maybe_decorate(attribute, value) for attribute, value in attributes_dict.items()
|
||||
}
|
||||
return super(DecorateAll, cls).__new__(
|
||||
cls, name, bases, new_attributes_dict
|
||||
)
|
||||
return super(DecorateAll, cls).__new__(cls, name, bases, new_attributes_dict)
|
||||
|
||||
return DecorateAll
|
||||
|
||||
Reference in New Issue
Block a user