Hello community, here is the log from the commit of package python-gabbi for openSUSE:Factory checked in at 2017-08-04 11:59:48 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-gabbi (Old) and /work/SRC/openSUSE:Factory/.python-gabbi.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-gabbi" Fri Aug 4 11:59:48 2017 rev:2 rq:511532 version:1.35.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-gabbi/python-gabbi.changes 2017-04-17 10:25:19.470598774 +0200 +++ /work/SRC/openSUSE:Factory/.python-gabbi.new/python-gabbi.changes 2017-08-04 11:59:49.911801387 +0200 @@ -1,0 +2,38 @@ +Thu Jul 20 05:41:40 UTC 2017 - [email protected] + +- update to 1.35.0: + * release 1.35.0 + * Documentation for <@ in json path values + * Allow value of a json path query to be read from disk + * Make _load_data_file public + * Add some simple docs for the LHS json path substitution + * Template expansion in LHS of json path test + * Correct location of gnocchi repo in gnocchi tests + +------------------------------------------------------------------- +Wed Jul 5 08:23:44 UTC 2017 - [email protected] + +- update to 1.34.1: + * Release 1.34.1 + * Add configuration for uploading signed sdists and wheels + * use assertRegex not assertRegexpMatches + * Update contributors list to reflect recent activity + * Relase 1.34.0 + * Add additional test to coerce.yaml + * Manage numerals more effectively in replacers + * Add optional `test` param for custom content handlers (#212) + * Remove .testrepository/times.dbm each test run + * release 1.33.0 + * Enforce type of response/content-handler test data + * Make verbose accept additional valid strings + * Add verbose option to `build_tests` + * Allow substitutions in count and delay + * Fix prefix handling for relative urls + * Add a test for a relative link and add a comment + * Avoid duplicating prefix when re-using urls + * Ensure that $HOME is in passenv + * Unicode content from disk must become bytes +- convert to singlespec +- disable tests for now. remote access needed for some + +------------------------------------------------------------------- Old: ---- gabbi-1.32.0.tar.gz New: ---- gabbi-1.35.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-gabbi.spec ++++++ --- /var/tmp/diff_new_pack.POpNC4/_old 2017-08-04 11:59:50.791677194 +0200 +++ /var/tmp/diff_new_pack.POpNC4/_new 2017-08-04 11:59:50.795676629 +0200 @@ -16,39 +16,49 @@ # +%{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-gabbi -Version: 1.32.0 +Version: 1.35.0 Release: 0 Summary: Declarative HTTP testing library License: Apache-2.0 Group: Development/Languages/Python Url: https://github.com/cdent/gabbi Source: https://pypi.io/packages/source/g/gabbi/gabbi-%{version}.tar.gz -BuildRequires: python-colorama -#BuildRequires: python-coverage, python-hacking, python-testtools, python-testrepository -BuildRequires: python-PyYAML -BuildRequires: python-devel -BuildRequires: python-httplib2 -BuildRequires: python-jsonpath-rw -BuildRequires: python-mock -BuildRequires: python-nose -BuildRequires: python-pbr -BuildRequires: python-setuptools -BuildRequires: python-six -BuildRequires: python-wsgi_intercept >= 1.0 +# BuildRequires: %{python_module PyYAML} +# BuildRequires: %{python_module Sphinx} +# BuildRequires: %{python_module colorama} +# BuildRequires: %{python_module fixtures} +# BuildRequires: %{python_module httplib2} +# BuildRequires: %{python_module jsonpath-rw-ext} +# BuildRequires: %{python_module jsonpath-rw} +# BuildRequires: %{python_module mock} +# BuildRequires: %{python_module nose} +# BuildRequires: %{python_module pytest-cov} +# BuildRequires: %{python_module pytest} +# BuildRequires: %{python_module six} +# BuildRequires: %{python_module testrepository} +# BuildRequires: %{python_module testtools} +# BuildRequires: %{python_module urllib3} +# BuildRequires: %{python_module wsgi_intercept} +BuildRequires: %{python_module devel} +BuildRequires: %{python_module pbr} +BuildRequires: %{python_module setuptools} +BuildRequires: python-rpm-macros Requires: python-PyYAML Requires: python-colorama Requires: python-jsonpath-rw-ext Requires: python-pytest Requires: python-six +Requires: python-testtools Requires: python-urllib3 >= 1.11.0 Requires: python-wsgi_intercept >= 1.2.2 BuildRoot: %{_tmppath}/%{name}-%{version}-build -%if 0%{?suse_version} && 0%{?suse_version} <= 1110 -%{!?python_sitelib: %global python_sitelib %(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} -%else +Requires(post): update-alternatives +Requires(postun): update-alternatives BuildArch: noarch -%endif + +%python_subpackages %description Gabbi is a tool for running HTTP tests where requests and responses @@ -59,18 +69,22 @@ %setup -q -n gabbi-%{version} %build -python setup.py build +%python_build %install -python setup.py install --prefix=%{_prefix} --root=%{buildroot} +%python_install +%python_clone -a %{buildroot}%{_bindir}/gabbi-run + +%post +%python_install_alternative gabbi-run -%check -python setup.py testr +%postun +%python_uninstall_alternative gabbi-run -%files +%files %{python_files} %defattr(-,root,root,-) %doc AUTHORS ChangeLog LICENSE README.rst %{python_sitelib}/* -%{_bindir}/gabbi-run +%python_alternative %{_bindir}/gabbi-run %changelog ++++++ gabbi-1.32.0.tar.gz -> gabbi-1.35.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/AUTHORS new/gabbi-1.35.0/AUTHORS --- old/gabbi-1.32.0/AUTHORS 2017-02-06 14:44:48.000000000 +0100 +++ new/gabbi-1.35.0/AUTHORS 2017-07-07 15:36:26.000000000 +0200 @@ -12,6 +12,8 @@ Mehdi Abaakouk <[email protected]> Mehdi Abaakouk <[email protected]> Michael McCune <[email protected]> +Ryan James Spencer <[email protected]> +Ryan Spencer <[email protected]> Samuel Fekete <[email protected]> Tom Viner <[email protected]> Tom Viner <[email protected]> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/ChangeLog new/gabbi-1.35.0/ChangeLog --- old/gabbi-1.32.0/ChangeLog 2017-02-06 14:44:48.000000000 +0100 +++ new/gabbi-1.35.0/ChangeLog 2017-07-07 15:36:26.000000000 +0200 @@ -1,6 +1,44 @@ CHANGES ======= +1.35.0 +------ + +* release 1.35.0 +* Documentation for <@ in json path values +* Allow value of a json path query to be read from disk +* Make _load_data_file public +* Add some simple docs for the LHS json path substitution +* Template expansion in LHS of json path test +* Correct location of gnocchi repo in gnocchi tests +* Release 1.34.1 +* Add configuration for uploading signed sdists and wheels +* use assertRegex not assertRegexpMatches +* Update contributors list to reflect recent activity + +1.34.0 +------ + +* Relase 1.34.0 +* Add additional test to coerce.yaml +* Manage numerals more effectively in replacers +* Add optional `test` param for custom content handlers (#212) + +1.33.0 +------ + +* Remove .testrepository/times.dbm each test run +* release 1.33.0 +* Enforce type of response/content-handler test data +* Make verbose accept additional valid strings +* Add verbose option to `build_tests` +* Allow substitutions in count and delay +* Fix prefix handling for relative urls +* Add a test for a relative link and add a comment +* Avoid duplicating prefix when re-using urls +* Ensure that $HOME is in passenv +* Unicode content from disk must become bytes + 1.32.0 ------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/Makefile new/gabbi-1.35.0/Makefile --- old/gabbi-1.32.0/Makefile 2017-01-06 23:00:06.000000000 +0100 +++ new/gabbi-1.35.0/Makefile 2017-06-28 16:57:09.000000000 +0200 @@ -34,9 +34,9 @@ tox --skip-missing-interpreters dist: test - python setup.py sdist + python setup.py sdist bdist_wheel release: clean test cleanagain tagv pypi pypi: - python setup.py sdist upload + python setup.py sdist bdist_wheel upload --sign diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/PKG-INFO new/gabbi-1.35.0/PKG-INFO --- old/gabbi-1.32.0/PKG-INFO 2017-02-06 14:44:48.000000000 +0100 +++ new/gabbi-1.35.0/PKG-INFO 2017-07-07 15:36:27.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: gabbi -Version: 1.32.0 +Version: 1.35.0 Summary: Declarative HTTP testing library Home-page: https://github.com/cdent/gabbi Author: Chris Dent diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/docs/source/format.rst new/gabbi-1.35.0/docs/source/format.rst --- old/gabbi-1.32.0/docs/source/format.rst 2016-12-30 16:42:42.000000000 +0100 +++ new/gabbi-1.35.0/docs/source/format.rst 2017-07-07 15:03:57.000000000 +0200 @@ -274,9 +274,11 @@ * ``data`` * ``request_headers`` * ``response_strings`` -* ``response_json_paths`` (on the value side of the key value pair) +* ``response_json_paths`` (in both the key and value, see + :ref:`json path substitution <json-subs>` for more info) * ``response_headers`` (on the value side of the key value pair) * ``response_forbidden_headers`` +* ``count`` and ``delay`` fields of ``poll`` With these variables it ought to be possible to traverse an API without any explicit statements about the URLs being used. If you need a diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/docs/source/handlers.rst new/gabbi-1.35.0/docs/source/handlers.rst --- old/gabbi-1.32.0/docs/source/handlers.rst 2016-09-27 12:20:21.000000000 +0200 +++ new/gabbi-1.35.0/docs/source/handlers.rst 2017-04-26 14:15:42.000000000 +0200 @@ -107,8 +107,12 @@ If ``accepts`` is defined two additional static methods should be defined: -* ``dumps``: Turn structured Python data from the ``data`` key in a - test into a string or byte stream. +* ``dumps``: Turn structured Python data from the ``data`` key in a test into a + string or byte stream. The optional ``test`` param allows you to access the + current test case which may help with manipulations for custom content + handlers, e.g. ``multipart/form-data`` needs to add a ``boundary`` to the + ``Content-Type`` header in order to mark the appropriate sections of the + body. * ``loads``: Turn a string or byte stream in a response into a Python data structure. Gabbi will put this data on the ``response_data`` attribute on the test, where it can be used in the evaluations diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/docs/source/jsonpath.rst new/gabbi-1.35.0/docs/source/jsonpath.rst --- old/gabbi-1.32.0/docs/source/jsonpath.rst 2016-07-13 05:57:28.000000000 +0200 +++ new/gabbi-1.35.0/docs/source/jsonpath.rst 2017-07-07 15:03:57.000000000 +0200 @@ -64,8 +64,48 @@ gabbi tests are being used to test your serializers and data models, not just your API interactions. +It is also possible to read raw JSON from disk for either all or +some of a JSON response:: + + response_json_paths: + $: @<data.json + +or:: + + response_json_paths: + $.pets: <@pets.json + $.pets[0]: <@cat.json + +Examples like this can be found in one of gabbi's `own tests`_. + There are more JSONPath examples in :doc:`example` and in the `jsonpath_rw`_ and `jsonpath_rw_ext`_ documentation. +.. _json-subs: + +Substitution +------------ + +:ref:`Substitutions <state-substitution>` can be made in both the +left (query) and right (expected) hand sides of the json path +expression. When subtitutions are used in the query, care must be +taken to ensure proper quoting of the resulting value. For example +if there is a uuid (with hyphens) at ``$RESPONSE['$.id']`` then this +expression may fail:: + + $.nested.structure.$RESPONSE['$.id'].name: foobar + +as it will evaluate to something like:: + + $.nested.structure.ADC8AAFC-D564-40D1-9724-7680D3C010C2.name: foobar + +which may be treated as an arithemtic expression by the json path +parser. The test author should write:: + + $.nested.structure["$RESPONSE['$.id']"].name: foobar + +to quote the result of the substitution. + .. _jsonpath_rw: http://jsonpath-rw.readthedocs.io/en/latest/ .. _jsonpath_rw_ext: https://python-jsonpath-rw-ext.readthedocs.io/en/latest/ +.. _own tests: https://github.com/cdent/gabbi/blob/master/gabbi/tests/gabbits_intercept/data.yaml diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/docs/source/release.rst new/gabbi-1.35.0/docs/source/release.rst --- old/gabbi-1.32.0/docs/source/release.rst 2017-02-06 14:28:32.000000000 +0100 +++ new/gabbi-1.35.0/docs/source/release.rst 2017-07-07 15:22:42.000000000 +0200 @@ -5,6 +5,34 @@ highlighting major features and changes. For more detail see the `commit logs`_ on GitHub. +1.35.0 +------ + +:doc:`jsonpath` handling gets two improvements: + +* The value side of a ``response_json_paths`` entry can be loaded + from a file using the ``<@file.json`` syntax also used in + :ref:`data`. +* The key side of a ``response_json_paths`` entry can use + :ref:`substitutions <state-substitution>`. This was already true + for the value side. + +1.34.0 +------ + +:ref:`Substitutions <state-substitution>` in ``$RESPONSE`` handling +now preserve numeric types instead of casting to a string. This is +useful when servers are expecting strong types and tests want to +send response data back to the server. + +1.33.0 +------ + +``count`` and ``delay`` test keys allow :ref:`substitutions +<state-substitution>`. :meth:`gabbi.driver.build_tests` accepts +a ``verbose`` parameter to set test :ref:`verbosity <metadata>` for +an entire session. + 1.32.0 ------ @@ -191,8 +219,11 @@ * Chris Dent * FND * Mehdi Abaakouk +* Tom Viner * Jason Myers +* Ryan Spencer * Kim Raymoure +* Travis Truman * Samuel Fekete * Michael McCune * Imran Hayder diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi/__init__.py new/gabbi-1.35.0/gabbi/__init__.py --- old/gabbi-1.32.0/gabbi/__init__.py 2017-02-06 14:27:22.000000000 +0100 +++ new/gabbi-1.35.0/gabbi/__init__.py 2017-07-07 15:17:56.000000000 +0200 @@ -12,4 +12,4 @@ # under the License. """See gabbi.driver and gabbbi.case.""" -__version__ = '1.32.0' +__version__ = '1.35.0' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi/case.py new/gabbi-1.35.0/gabbi/case.py --- old/gabbi-1.32.0/gabbi/case.py 2016-12-23 16:00:53.000000000 +0100 +++ new/gabbi-1.35.0/gabbi/case.py 2017-07-07 15:03:57.000000000 +0200 @@ -154,6 +154,9 @@ message[k] = self.replace_template(message[k]) return message + if isinstance(message, list): + return [self.replace_template(line) for line in message] + for replacer in REPLACERS: template = '$%s' % replacer method = '_%s_replace' % replacer.lower() @@ -171,6 +174,10 @@ return message + def load_data_file(self, filename): + """Read a file from the current test directory.""" + return self._load_data_file(filename) + def _assert_response(self): """Compare the response with expected data.""" self._test_status(self.test_data['status'], self.response['status']) @@ -187,13 +194,27 @@ return value def _environ_replace(self, message): - """Replace an indicator in a message with the environment value.""" + """Replace an indicator in a message with the environment value. + + If value can be a number, cast it as such. If value is a form of + "null", "true", or "false" cast it to None, True, False. + """ value = re.sub(self._replacer_regex('ENVIRON'), self._environ_replacer, message) - if value == "False": + try: + if '.' in value: + value = float(value) + else: + value = int(value) + return value + except ValueError: + pass + if value.lower() == "false": return False - if value == "True": + if value.lower() == "true": return True + if value.lower() == "null": + return None return value @staticmethod @@ -351,11 +372,18 @@ return r"%s\$%s" % (case, key) def _response_replace(self, message): - """Replace a content path with the value from a previous response.""" - return re.sub(self._replacer_regex('RESPONSE'), - self._response_replacer, message) + """Replace a content path with the value from a previous response. + + If the match would replace the entire message, then don't cast it + to a string. + """ + regex = self._replacer_regex('RESPONSE') + match = re.match('^%s$' % regex, message) + if match: + return self._response_replacer(match, preserve=True) + return re.sub(regex, self._response_replacer, message) - def _response_replacer(self, match): + def _response_replacer(self, match, preserve=False): """Replace a regex match with the value from a previous response.""" response_path = match.group('arg') case = match.group('case') @@ -368,8 +396,12 @@ # If no handler can be found use the null replacer, # which returns "foo" when "$RESPONSE['foo']". replacer_class = replacer_class or base.ContentHandler - return replacer_class.replacer( + result = replacer_class.replacer( referred_case.response_data, response_path) + if preserve: + return result + else: + return six.text_type(result) def _run_request(self, url, method, headers, body, redirect=False): """Run the http request and decode output. @@ -436,9 +468,15 @@ else: body = '' + # ensure body is bytes, encoding as UTF-8 because that's + # what we do here + if isinstance(body, six.text_type): + body = body.encode('UTF-8') + if test['poll']: - count = test['poll'].get('count', 1) - delay = test['poll'].get('delay', 1) + count = int(float(self.replace_template( + test['poll'].get('count', 1)))) + delay = float(self.replace_template(test['poll'].get('delay', 1))) failure = None while count: try: @@ -471,19 +509,16 @@ """ if isinstance(data, str): if data.startswith('<@'): - info = self._load_data_file(data.replace('<@', '', 1)) + info = self.load_data_file(data.replace('<@', '', 1)) if utils.not_binary(content_type): - try: - info = str(info, 'UTF-8') - except TypeError: - info = info.encode('UTF-8') - data = info + data = six.text_type(info, 'UTF-8') else: return info else: dumper_class = self.get_content_handler(content_type) if dumper_class: - data = dumper_class.dumps(data) + data = self.replace_template(data) + data = dumper_class.dumps(data, test=self) else: raise ValueError( 'unable to process data to %s' % content_type) @@ -542,7 +577,7 @@ dumper_class = self.get_content_handler(self.content_type) if dumper_class: full_response = dumper_class.dumps(self.response_data, - pretty=True) + pretty=True, test=self) else: full_response = self.output else: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi/driver.py new/gabbi-1.35.0/gabbi/driver.py --- old/gabbi-1.32.0/gabbi/driver.py 2016-11-30 18:47:39.000000000 +0100 +++ new/gabbi-1.35.0/gabbi/driver.py 2017-04-26 14:15:42.000000000 +0200 @@ -42,7 +42,7 @@ test_loader_name=None, fixture_module=None, response_handlers=None, content_handlers=None, prefix='', require_ssl=False, url=None, - inner_fixtures=None): + inner_fixtures=None, verbose=False): """Read YAML files from a directory to create tests. Each YAML file represents an ordered sequence of HTTP requests. @@ -64,6 +64,8 @@ :param require_ssl: If ``True``, make all tests default to using SSL. :param inner_fixtures: A list of ``Fixtures`` to use with each individual test request. + :param verbose: If ``True`` or ``'all'``, make tests verbose by default + ``'headers'`` and ``'body'`` are also accepted. :type inner_fixtures: List of fixtures.Fixture classes. :rtype: TestSuite containing multiple TestSuites (one for each YAML file). """ @@ -117,6 +119,12 @@ else: suite_dict['defaults'] = {'ssl': True} + if any((verbose == opt for opt in [True, 'all', 'headers', 'body'])): + if 'defaults' in suite_dict: + suite_dict['defaults']['verbose'] = verbose + else: + suite_dict['defaults'] = {'verbose': verbose} + file_suite = suitemaker.test_suite_from_dict( loader, test_base_name, suite_dict, path, host, port, fixture_module, intercept, prefix=prefix, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi/handlers/base.py new/gabbi-1.35.0/gabbi/handlers/base.py --- old/gabbi-1.32.0/gabbi/handlers/base.py 2016-12-23 16:00:53.000000000 +0100 +++ new/gabbi-1.35.0/gabbi/handlers/base.py 2017-04-26 14:15:42.000000000 +0200 @@ -13,6 +13,9 @@ """Base classes for response and content handlers.""" +from gabbi.exception import GabbiFormatError + + class ResponseHandler(object): """Add functionality for making assertions about an HTTP response. @@ -38,6 +41,11 @@ def __call__(self, test): if test.test_data[self._key]: self.preprocess(test) + if type(self.test_key_value) != type(test.test_data[self._key]): + raise GabbiFormatError( + "%s in '%s' has incorrect type, must be %s" + % (self._key, test.test_data['name'], + type(self.test_key_value))) for item in test.test_data[self._key]: try: value = test.test_data[self._key][item] @@ -92,7 +100,7 @@ return path @staticmethod - def dumps(data, pretty=False): + def dumps(data, pretty=False, test=None): """Return structured data as a string. If pretty is true, prettify. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi/handlers/core.py new/gabbi-1.35.0/gabbi/handlers/core.py --- old/gabbi-1.32.0/gabbi/handlers/core.py 2016-09-27 12:20:21.000000000 +0200 +++ new/gabbi-1.35.0/gabbi/handlers/core.py 2017-06-28 16:57:09.000000000 +0200 @@ -66,7 +66,7 @@ if header_value.startswith('/') and header_value.endswith('/'): header_value = header_value.strip('/').rstrip('/') - test.assertRegexpMatches( + test.assertRegex( response_value, header_value, 'Expect header %s to match /%s/, got %s' % (header, header_value, response_value)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi/handlers/jsonhandler.py new/gabbi-1.35.0/gabbi/handlers/jsonhandler.py --- old/gabbi-1.32.0/gabbi/handlers/jsonhandler.py 2016-10-28 12:04:01.000000000 +0200 +++ new/gabbi-1.35.0/gabbi/handlers/jsonhandler.py 2017-07-07 15:03:57.000000000 +0200 @@ -14,6 +14,8 @@ import json +import six + from gabbi.handlers import base from gabbi import json_parser @@ -41,10 +43,10 @@ @classmethod def replacer(cls, response_data, match): - return str(cls.extract_json_path_value(response_data, match)) + return cls.extract_json_path_value(response_data, match) @staticmethod - def dumps(data, pretty=False): + def dumps(data, pretty=False, test=None): if pretty: return json.dumps(data, indent=2, separators=(',', ': ')) else: @@ -73,11 +75,8 @@ def action(self, test, path, value=None): """Test json_paths against json data.""" - # NOTE: This process has some advantages over other process that - # might come along because the JSON data has already been - # processed (to provided for the magic template replacing). - # Other handlers that want access to data structures will need - # to do their own processing. + # Do template expansion in the left hand side. + path = test.replace_template(path) try: match = self.extract_json_path_value( test.response_data, path) @@ -86,6 +85,13 @@ except ValueError: raise AssertionError('json path %s cannot match %s' % (path, test.response_data)) + + # read data from disk if the value starts with '<@' + if isinstance(value, str) and value.startswith('<@'): + info = test.load_data_file(value.replace('<@', '', 1)) + info = six.text_type(info, 'UTF-8') + value = self.loads(info) + expected = test.replace_template(value) # If expected is a string, check to see if it is a regex. if (hasattr(expected, 'startswith') and expected.startswith('/') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi/tests/gabbits_intercept/cat.json new/gabbi-1.35.0/gabbi/tests/gabbits_intercept/cat.json --- old/gabbi-1.32.0/gabbi/tests/gabbits_intercept/cat.json 1970-01-01 01:00:00.000000000 +0100 +++ new/gabbi-1.35.0/gabbi/tests/gabbits_intercept/cat.json 2017-07-07 15:03:57.000000000 +0200 @@ -0,0 +1,4 @@ +{ + "type": "cat", + "sound": "meow" +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi/tests/gabbits_intercept/coerce.yaml new/gabbi-1.35.0/gabbi/tests/gabbits_intercept/coerce.yaml --- old/gabbi-1.32.0/gabbi/tests/gabbits_intercept/coerce.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/gabbi-1.35.0/gabbi/tests/gabbits_intercept/coerce.yaml 2017-04-26 22:25:27.000000000 +0200 @@ -0,0 +1,201 @@ +defaults: + request_headers: + content-type: application/json + verbose: True + +tests: +- name: post data + POST: / + data: + one_string: "1" + one_int: 1 + one_float: 1.1 + response_json_paths: + $.one_string: "1" + $.one_int: 1 + $.one_float: 1.1 + response_strings: + - '"one_string": "1"' + - '"one_int": 1' + - '"one_float": 1.1' + +- name: use data + desc: data will be coerced because templates in use + POST: / + data: + one_string: !!str "$RESPONSE['$.one_string']" + one_int: $RESPONSE['$.one_int'] + one_float: $RESPONSE['$.one_float'] + response_json_paths: + $.one_string: "1" + $.one_int: 1 + $.one_float: 1.1 + response_strings: + - '"one_string": "1"' + - '"one_int": 1' + - '"one_float": 1.1' + +- name: from environ + POST: / + data: + one_environ: $ENVIRON['ONE'] + response_json_paths: + $.one_environ: 1 + response_strings: + - '"one_environ": 1' + +- name: with list + POST: / + data: + - $ENVIRON['ONE'] + - 2 + - "3" + response_json_paths: + $[0]: 1 + $[1]: 2 + $[2]: "3" + response_strings: + - '[1, 2, "3"]' + +- name: object with list + desc: without recursive handling no coersion + POST: / + data: + collection: + - alpha: $ENVIRON['ONE'] + beta: max + - alpha: 2 + beta: climb + response_json_paths: + $.collection[0].alpha: 1 + $.collection[0].beta: max + $.collection[1].alpha: 2 + $.collection[1].beta: climb + response_strings: + - '"alpha": 1' + - '"beta": "max"' + +- name: post extra data + POST: / + data: + a: 1 + b: 1.0 + c: '[1,2,3]' + d: true + e: false + f: + key: val + g: null + h: + key: + less_key: [1, true, null] + more_key: 1 + response_json_paths: + a: 1 + b: 1.0 + c: '[1,2,3]' + d: true + e: false + f: + key: val + g: null + h: + key: + less_key: [1, true, null] + more_key: 1 + +- name: check posted data + POST: / + data: + a: $RESPONSE['$.a'] + b: $RESPONSE['$.b'] + c: $RESPONSE['$.c'] + d: $RESPONSE['$.d'] + e: $RESPONSE['$.e'] + f: $RESPONSE['$.f'] + g: $RESPONSE['$.g'] + h: $RESPONSE['$.h'] + response_json_paths: + a: 1 + b: 1.0 + c: '[1,2,3]' + d: true + e: false + f: + key: val + g: null + h: + key: + less_key: [1, true, null] + more_key: 1 + +- name: Post again and check the results + POST: / + data: + a: $HISTORY['post extra data'].$RESPONSE['$.a'] + b: $HISTORY['post extra data'].$RESPONSE['$.b'] + c: $HISTORY['post extra data'].$RESPONSE['$.c'] + d: $HISTORY['post extra data'].$RESPONSE['$.d'] + e: $HISTORY['post extra data'].$RESPONSE['$.e'] + f: $HISTORY['post extra data'].$RESPONSE['$.f'] + g: $HISTORY['post extra data'].$RESPONSE['$.g'] + h: $HISTORY['post extra data'].$RESPONSE['$.h'] + response_json_paths: + a: $ENVIRON['ONE'] + b: $ENVIRON['DECIMAL'] + c: $ENVIRON['ARRAY_STRING'] + d: $ENVIRON['TRUE'] + e: $ENVIRON['FALSE'] + f: + key: $ENVIRON['STRING'] + g: $ENVIRON['NULL'] + h: + key: + less_key: + - $ENVIRON['ONE'] + - $ENVIRON['TRUE'] + - $ENVIRON['NULL'] + more_key: $ENVIRON['ONE'] + +- name: Post again and check the results (reversed) + POST: / + data: + a: $ENVIRON['ONE'] + b: $ENVIRON['DECIMAL'] + c: $ENVIRON['ARRAY_STRING'] + d: $ENVIRON['TRUE'] + e: $ENVIRON['FALSE'] + f: + key: $ENVIRON['STRING'] + g: $ENVIRON['NULL'] + h: + key: + less_key: + - $ENVIRON['ONE'] + - $ENVIRON['TRUE'] + - $ENVIRON['NULL'] + more_key: $ENVIRON['ONE'] + response_json_paths: + a: $HISTORY['check posted data'].$RESPONSE['$.a'] + b: $HISTORY['check posted data'].$RESPONSE['$.b'] + c: $HISTORY['check posted data'].$RESPONSE['$.c'] + d: $HISTORY['check posted data'].$RESPONSE['$.d'] + e: $HISTORY['check posted data'].$RESPONSE['$.e'] + f: $HISTORY['check posted data'].$RESPONSE['$.f'] + g: $HISTORY['check posted data'].$RESPONSE['$.g'] + h: + key: + less_key: + - $HISTORY['check posted data'].$RESPONSE['$.h.key.less_key[0]'] + - $HISTORY['check posted data'].$RESPONSE['$.h.key.less_key[1]'] + - $HISTORY['check posted data'].$RESPONSE['$.h.key.less_key[2]'] + more_key: $HISTORY['check posted data'].$RESPONSE['$.h.key.more_key'] + +- name: string internal replace + POST: / + data: + endpoint_resp: /api/0.1/item/$HISTORY['check posted data'].$RESPONSE['$.a'] + endpoint_var: /api/0.1/item/$ENVIRON['ONE'] + response_json_paths: + endpoint_resp: /api/0.1/item/1 + endpoint_var: /api/0.1/item/1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi/tests/gabbits_intercept/data.json new/gabbi-1.35.0/gabbi/tests/gabbits_intercept/data.json --- old/gabbi-1.32.0/gabbi/tests/gabbits_intercept/data.json 2016-07-13 05:57:28.000000000 +0200 +++ new/gabbi-1.35.0/gabbi/tests/gabbits_intercept/data.json 2017-04-26 14:15:42.000000000 +0200 @@ -1 +1 @@ -{"foo": {"bar": 1}} +{"foo": {"bár": 1}} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi/tests/gabbits_intercept/data.yaml new/gabbi-1.35.0/gabbi/tests/gabbits_intercept/data.yaml --- old/gabbi-1.32.0/gabbi/tests/gabbits_intercept/data.yaml 2016-07-13 05:57:28.000000000 +0200 +++ new/gabbi-1.35.0/gabbi/tests/gabbits_intercept/data.yaml 2017-07-07 15:03:57.000000000 +0200 @@ -34,7 +34,7 @@ content-type: application/json data: <@data.json response_json_paths: - foo.bar: 1 + foo['bár']: 1 - name: load image file url: / @@ -42,3 +42,33 @@ request_headers: content-type: image/png data: <@kitten.png + + - name: load encoded text + url: / + method: POST + request_headers: + content-type: text/plain + data: <@utf8.txt + + - name: json value from disk + POST: / + request_headers: + content-type: application/json + data: <@data.json + response_json_paths: + foo['bár']: 1 + $: <@data.json + + - name: partial json from disk + POST: / + request_headers: + content-type: application/json + data: + pets: + - type: cat + sound: meow + - type: dog + sound: woof + response_json_paths: + $.pets: <@pets.json + $.pets[0]: <@cat.json diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi/tests/gabbits_intercept/json-left-side.yaml new/gabbi-1.35.0/gabbi/tests/gabbits_intercept/json-left-side.yaml --- old/gabbi-1.32.0/gabbi/tests/gabbits_intercept/json-left-side.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/gabbi-1.35.0/gabbi/tests/gabbits_intercept/json-left-side.yaml 2017-07-07 15:03:57.000000000 +0200 @@ -0,0 +1,37 @@ +defaults: + request_headers: + content-type: application/json + verbose: True + +tests: +- name: left side json one + desc: for reuse on the next test + POST: / + data: + alpha: alpha1 + beta: beta1 + +- name: expand left side + POST: / + data: + alpha1: alpha + beta1: beta + response_json_paths: + $["$RESPONSE['$.alpha']"]: alpha + +- name: expand environ left side + POST: / + data: + alpha1: alpha + beta1: beta + 1: cow + response_json_paths: + $.['$ENVIRON['ONE']']: cow + +- name: set key and value + GET: /jsonator?key=$ENVIRON['ONE']&value=10 + +- name: check key and value + GET: /jsonator?key=$ENVIRON['ONE']&value=10 + response_json_paths: + $.["$ENVIRON['ONE']"]: $RESPONSE['$['1']'] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi/tests/gabbits_intercept/pets.json new/gabbi-1.35.0/gabbi/tests/gabbits_intercept/pets.json --- old/gabbi-1.32.0/gabbi/tests/gabbits_intercept/pets.json 1970-01-01 01:00:00.000000000 +0100 +++ new/gabbi-1.35.0/gabbi/tests/gabbits_intercept/pets.json 2017-07-07 15:03:57.000000000 +0200 @@ -0,0 +1,10 @@ +[ + { + "type": "cat", + "sound": "meow" + }, + { + "type": "dog", + "sound": "woof" + } +] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi/tests/gabbits_intercept/poll.yaml new/gabbi-1.35.0/gabbi/tests/gabbits_intercept/poll.yaml --- old/gabbi-1.32.0/gabbi/tests/gabbits_intercept/poll.yaml 2016-08-05 20:51:31.000000000 +0200 +++ new/gabbi-1.35.0/gabbi/tests/gabbits_intercept/poll.yaml 2017-04-26 14:15:42.000000000 +0200 @@ -26,7 +26,7 @@ # Confirm that $LOCATION and $RESPONSE behave in poll. - name: create a thing - url: /poller?count=2&x=1&y=2 + url: /poller?count=2&x=1&y=2&z=3.4 method: POST request_headers: content-type: application/json @@ -34,15 +34,16 @@ count: 3 delay: .01 response_json_paths: - $.x[0]: '1' - $.y[0]: '2' + $.x[0]: "1" + $.y[0]: "2" + $.z[0]: "3.4" - name: loop location url: $LOCATION verbose: True poll: - count: 3 + count: $RESPONSE['$.z[0]'] delay: .01 response_json_paths: $.x[0]: $RESPONSE['$.x[0]'] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi/tests/gabbits_intercept/prefix.yaml new/gabbi-1.35.0/gabbi/tests/gabbits_intercept/prefix.yaml --- old/gabbi-1.32.0/gabbi/tests/gabbits_intercept/prefix.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/gabbi-1.35.0/gabbi/tests/gabbits_intercept/prefix.yaml 2017-04-26 14:15:42.000000000 +0200 @@ -0,0 +1,20 @@ + +tests: + +- name: provide a link + POST: / + request_headers: + content-type: application/json + data: + link: $ENVIRON['GABBI_PREFIX']/barnabas + relative: link + +- name: get that link + GET: $RESPONSE['$.link'] + response_headers: + x-gabbi-url: "///[a-f0-9:-]+$ENVIRON['GABBI_PREFIX']/barnabas/" + +- name: get relative link + GET: $HISTORY['provide a link'].$RESPONSE['$.relative'] + response_headers: + x-gabbi-url: "///[a-f0-9:-]+$ENVIRON['GABBI_PREFIX']/link/" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi/tests/gabbits_intercept/utf8.txt new/gabbi-1.35.0/gabbi/tests/gabbits_intercept/utf8.txt --- old/gabbi-1.32.0/gabbi/tests/gabbits_intercept/utf8.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/gabbi-1.35.0/gabbi/tests/gabbits_intercept/utf8.txt 2017-04-26 14:15:42.000000000 +0200 @@ -0,0 +1,222 @@ +<h1>Unicode Demo</h1> + +<p>Taken from <a +href="http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-demo.txt">http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-demo.txt</a></p> + +<pre> + +$ENVIRON['HOME'] + +UTF-8 encoded sample plain-text file +‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ + +Markus Kuhn [ˈmaʳkʊs kuːn] <http://www.cl.cam.ac.uk/~mgk25/> — 2002-07-25 + + +The ASCII compatible UTF-8 encoding used in this plain-text file +is defined in Unicode, ISO 10646-1, and RFC 2279. + + +Using Unicode/UTF-8, you can write in emails and source code things such as + +Mathematics and sciences: + + ∮ E⋅da = Q, n → ∞, ∑ f(i) = ∏ g(i), ⎧⎡⎛┌─────┐⎞⎤⎫ + ⎪⎢⎜│a²+b³ ⎟⎥⎪ + ∀x∈ℝ: ⌈x⌉ = −⌊−x⌋, α ∧ ¬β = ¬(¬α ∨ β), ⎪⎢⎜│───── ⎟⎥⎪ + ⎪⎢⎜⎷ c₈ ⎟⎥⎪ + ℕ ⊆ ℕ₀ ⊂ ℤ ⊂ ℚ ⊂ ℝ ⊂ ℂ, ⎨⎢⎜ ⎟⎥⎬ + ⎪⎢⎜ ∞ ⎟⎥⎪ + ⊥ < a ≠ b ≡ c ≤ d ≪ ⊤ ⇒ (⟦A⟧ ⇔ ⟪B⟫), ⎪⎢⎜ ⎲ ⎟⎥⎪ + ⎪⎢⎜ ⎳aⁱ-bⁱ⎟⎥⎪ + 2H₂ + O₂ ⇌ 2H₂O, R = 4.7 kΩ, ⌀ 200 mm ⎩⎣⎝i=1 ⎠⎦⎭ + +Linguistics and dictionaries: + + ði ıntəˈnæʃənəl fəˈnɛtık əsoʊsiˈeıʃn + Y [ˈʏpsilɔn], Yen [jɛn], Yoga [ˈjoːgɑ] + +APL: + + ((V⍳V)=⍳⍴V)/V←,V ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈ + +Nicer typography in plain text files: + + ╔══════════════════════════════════════════╗ + ║ ║ + ║ • ‘single’ and “double” quotes ║ + ║ ║ + ║ • Curly apostrophes: “We’ve been here” ║ + ║ ║ + ║ • Latin-1 apostrophe and accents: '´` ║ + ║ ║ + ║ • ‚deutsche‘ „Anführungszeichen“ ║ + ║ ║ + ║ • †, ‡, ‰, •, 3–4, —, −5/+5, ™, … ║ + ║ ║ + ║ • ASCII safety test: 1lI|, 0OD, 8B ║ + ║ ╭─────────╮ ║ + ║ • the euro symbol: │ 14.95 € │ ║ + ║ ╰─────────╯ ║ + ╚══════════════════════════════════════════╝ + +Combining characters: + + STARGΛ̊TE SG-1, a = v̇ = r̈, a⃑ ⊥ b⃑ + +Greek (in Polytonic): + + The Greek anthem: + + Σὲ γνωρίζω ἀπὸ τὴν κόψη + τοῦ σπαθιοῦ τὴν τρομερή, + σὲ γνωρίζω ἀπὸ τὴν ὄψη + ποὺ μὲ βία μετράει τὴ γῆ. + + ᾿Απ᾿ τὰ κόκκαλα βγαλμένη + τῶν ῾Ελλήνων τὰ ἱερά + καὶ σὰν πρῶτα ἀνδρειωμένη + χαῖρε, ὦ χαῖρε, ᾿Ελευθεριά! + + From a speech of Demosthenes in the 4th century BC: + + Οὐχὶ ταὐτὰ παρίσταταί μοι γιγνώσκειν, ὦ ἄνδρες ᾿Αθηναῖοι, + ὅταν τ᾿ εἰς τὰ πράγματα ἀποβλέψω καὶ ὅταν πρὸς τοὺς + λόγους οὓς ἀκούω· τοὺς μὲν γὰρ λόγους περὶ τοῦ + τιμωρήσασθαι Φίλιππον ὁρῶ γιγνομένους, τὰ δὲ πράγματ᾿ + εἰς τοῦτο προήκοντα, ὥσθ᾿ ὅπως μὴ πεισόμεθ᾿ αὐτοὶ + πρότερον κακῶς σκέψασθαι δέον. οὐδέν οὖν ἄλλο μοι δοκοῦσιν + οἱ τὰ τοιαῦτα λέγοντες ἢ τὴν ὑπόθεσιν, περὶ ἧς βουλεύεσθαι, + οὐχὶ τὴν οὖσαν παριστάντες ὑμῖν ἁμαρτάνειν. ἐγὼ δέ, ὅτι μέν + ποτ᾿ ἐξῆν τῇ πόλει καὶ τὰ αὑτῆς ἔχειν ἀσφαλῶς καὶ Φίλιππον + τιμωρήσασθαι, καὶ μάλ᾿ ἀκριβῶς οἶδα· ἐπ᾿ ἐμοῦ γάρ, οὐ πάλαι + γέγονεν ταῦτ᾿ ἀμφότερα· νῦν μέντοι πέπεισμαι τοῦθ᾿ ἱκανὸν + προλαβεῖν ἡμῖν εἶναι τὴν πρώτην, ὅπως τοὺς συμμάχους + σώσομεν. ἐὰν γὰρ τοῦτο βεβαίως ὑπάρξῃ, τότε καὶ περὶ τοῦ + τίνα τιμωρήσεταί τις καὶ ὃν τρόπον ἐξέσται σκοπεῖν· πρὶν δὲ + τὴν ἀρχὴν ὀρθῶς ὑποθέσθαι, μάταιον ἡγοῦμαι περὶ τῆς + τελευτῆς ὁντινοῦν ποιεῖσθαι λόγον. + + Δημοσθένους, Γ´ ᾿Ολυνθιακὸς + +Georgian: + + From a Unicode conference invitation: + + გთხოვთ ახლავე გაიაროთ რეგისტრაცია Unicode-ის მეათე საერთაშორისო + კონფერენციაზე დასასწრებად, რომელიც გაიმართება 10-12 მარტს, + ქ. მაინცში, გერმანიაში. კონფერენცია შეჰკრებს ერთად მსოფლიოს + ექსპერტებს ისეთ დარგებში როგორიცაა ინტერნეტი და Unicode-ი, + ინტერნაციონალიზაცია და ლოკალიზაცია, Unicode-ის გამოყენება + ოპერაციულ სისტემებსა, და გამოყენებით პროგრამებში, შრიფტებში, + ტექსტების დამუშავებასა და მრავალენოვან კომპიუტერულ სისტემებში. + +Russian: + + From a Unicode conference invitation: + + Зарегистрируйтесь сейчас на Десятую Международную Конференцию по + Unicode, которая состоится 10-12 марта 1997 года в Майнце в Германии. + Конференция соберет широкий круг экспертов по вопросам глобального + Интернета и Unicode, локализации и интернационализации, воплощению и + применению Unicode в различных операционных системах и программных + приложениях, шрифтах, верстке и многоязычных компьютерных системах. + +Thai (UCS Level 2): + + Excerpt from a poetry on The Romance of The Three Kingdoms (a Chinese + classic 'San Gua'): + + [----------------------------|------------------------] + ๏ แผ่นดินฮั่นเสื่อมโทรมแสนสังเวช พระปกเกศกองบู๊กู้ขึ้นใหม่ + สิบสองกษัตริย์ก่อนหน้าแลถัดไป สององค์ไซร้โง่เขลาเบาปัญญา + ทรงนับถือขันทีเป็นที่พึ่ง บ้านเมืองจึงวิปริตเป็นนักหนา + โฮจิ๋นเรียกทัพทั่วหัวเมืองมา หมายจะฆ่ามดชั่วตัวสำคัญ + เหมือนขับไสไล่เสือจากเคหา รับหมาป่าเข้ามาเลยอาสัญ + ฝ่ายอ้องอุ้นยุแยกให้แตกกัน ใช้สาวนั้นเป็นชนวนชื่นชวนใจ + พลันลิฉุยกุยกีกลับก่อเหตุ ช่างอาเพศจริงหนาฟ้าร้องไห้ + ต้องรบราฆ่าฟันจนบรรลัย ฤๅหาใครค้ำชูกู้บรรลังก์ ฯ + + (The above is a two-column text. If combining characters are handled + correctly, the lines of the second column should be aligned with the + | character above.) + +Ethiopian: + + Proverbs in the Amharic language: + + ሰማይ አይታረስ ንጉሥ አይከሰስ። + ብላ ካለኝ እንደአባቴ በቆመጠኝ። + ጌጥ ያለቤቱ ቁምጥና ነው። + ደሀ በሕልሙ ቅቤ ባይጠጣ ንጣት በገደለው። + የአፍ ወለምታ በቅቤ አይታሽም። + አይጥ በበላ ዳዋ ተመታ። + ሲተረጉሙ ይደረግሙ። + ቀስ በቀስ፥ ዕንቁላል በእግሩ ይሄዳል። + ድር ቢያብር አንበሳ ያስር። + ሰው እንደቤቱ እንጅ እንደ ጉረቤቱ አይተዳደርም። + እግዜር የከፈተውን ጉሮሮ ሳይዘጋው አይድርም። + የጎረቤት ሌባ፥ ቢያዩት ይስቅ ባያዩት ያጠልቅ። + ሥራ ከመፍታት ልጄን ላፋታት። + ዓባይ ማደሪያ የለው፥ ግንድ ይዞ ይዞራል። + የእስላም አገሩ መካ የአሞራ አገሩ ዋርካ። + ተንጋሎ ቢተፉ ተመልሶ ባፉ። + ወዳጅህ ማር ቢሆን ጨርስህ አትላሰው። + እግርህን በፍራሽህ ልክ ዘርጋ። + +Runes: + + ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ + + (Old English, which transcribed into Latin reads 'He cwaeth that he + bude thaem lande northweardum with tha Westsae.' and means 'He said + that he lived in the northern land near the Western Sea.') + +Braille: + + ⡌⠁⠧⠑ ⠼⠁⠒ ⡍⠜⠇⠑⠹⠰⠎ ⡣⠕⠌ + + ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠙⠑⠁⠙⠒ ⠞⠕ ⠃⠑⠛⠔ ⠺⠊⠹⠲ ⡹⠻⠑ ⠊⠎ ⠝⠕ ⠙⠳⠃⠞ + ⠱⠁⠞⠑⠧⠻ ⠁⠃⠳⠞ ⠹⠁⠞⠲ ⡹⠑ ⠗⠑⠛⠊⠌⠻ ⠕⠋ ⠙⠊⠎ ⠃⠥⠗⠊⠁⠇ ⠺⠁⠎ + ⠎⠊⠛⠝⠫ ⠃⠹ ⠹⠑ ⠊⠇⠻⠛⠹⠍⠁⠝⠂ ⠹⠑ ⠊⠇⠻⠅⠂ ⠹⠑ ⠥⠝⠙⠻⠞⠁⠅⠻⠂ + ⠁⠝⠙ ⠹⠑ ⠡⠊⠑⠋ ⠍⠳⠗⠝⠻⠲ ⡎⠊⠗⠕⠕⠛⠑ ⠎⠊⠛⠝⠫ ⠊⠞⠲ ⡁⠝⠙ + ⡎⠊⠗⠕⠕⠛⠑⠰⠎ ⠝⠁⠍⠑ ⠺⠁⠎ ⠛⠕⠕⠙ ⠥⠏⠕⠝ ⠰⡡⠁⠝⠛⠑⠂ ⠋⠕⠗ ⠁⠝⠹⠹⠔⠛ ⠙⠑ + ⠡⠕⠎⠑ ⠞⠕ ⠏⠥⠞ ⠙⠊⠎ ⠙⠁⠝⠙ ⠞⠕⠲ + + ⡕⠇⠙ ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ + + ⡍⠔⠙⠖ ⡊ ⠙⠕⠝⠰⠞ ⠍⠑⠁⠝ ⠞⠕ ⠎⠁⠹ ⠹⠁⠞ ⡊ ⠅⠝⠪⠂ ⠕⠋ ⠍⠹ + ⠪⠝ ⠅⠝⠪⠇⠫⠛⠑⠂ ⠱⠁⠞ ⠹⠻⠑ ⠊⠎ ⠏⠜⠞⠊⠊⠥⠇⠜⠇⠹ ⠙⠑⠁⠙ ⠁⠃⠳⠞ + ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ ⡊ ⠍⠊⠣⠞ ⠙⠁⠧⠑ ⠃⠑⠲ ⠔⠊⠇⠔⠫⠂ ⠍⠹⠎⠑⠇⠋⠂ ⠞⠕ + ⠗⠑⠛⠜⠙ ⠁ ⠊⠕⠋⠋⠔⠤⠝⠁⠊⠇ ⠁⠎ ⠹⠑ ⠙⠑⠁⠙⠑⠌ ⠏⠊⠑⠊⠑ ⠕⠋ ⠊⠗⠕⠝⠍⠕⠝⠛⠻⠹ + ⠔ ⠹⠑ ⠞⠗⠁⠙⠑⠲ ⡃⠥⠞ ⠹⠑ ⠺⠊⠎⠙⠕⠍ ⠕⠋ ⠳⠗ ⠁⠝⠊⠑⠌⠕⠗⠎ + ⠊⠎ ⠔ ⠹⠑ ⠎⠊⠍⠊⠇⠑⠆ ⠁⠝⠙ ⠍⠹ ⠥⠝⠙⠁⠇⠇⠪⠫ ⠙⠁⠝⠙⠎ + ⠩⠁⠇⠇ ⠝⠕⠞ ⠙⠊⠌⠥⠗⠃ ⠊⠞⠂ ⠕⠗ ⠹⠑ ⡊⠳⠝⠞⠗⠹⠰⠎ ⠙⠕⠝⠑ ⠋⠕⠗⠲ ⡹⠳ + ⠺⠊⠇⠇ ⠹⠻⠑⠋⠕⠗⠑ ⠏⠻⠍⠊⠞ ⠍⠑ ⠞⠕ ⠗⠑⠏⠑⠁⠞⠂ ⠑⠍⠏⠙⠁⠞⠊⠊⠁⠇⠇⠹⠂ ⠹⠁⠞ + ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ + + (The first couple of paragraphs of "A Christmas Carol" by Dickens) + +Compact font selection example text: + + ABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789 + abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ + –—‘“”„†•…‰™œŠŸž€ ΑΒΓΔΩαβγδω АБВГДабвгд + ∀∂∈ℝ∧∪≡∞ ↑↗↨↻⇣ ┐┼╔╘░►☺♀ fi�⑀₂ἠḂӥẄɐː⍎אԱა + +Greetings in various languages: + + Hello world, Καλημέρα κόσμε, コンニチハ + +Box drawing alignment tests: █ + ▉ + ╔══╦══╗ ┌──┬──┐ ╭──┬──╮ ╭──┬──╮ ┏━━┳━━┓ ┎┒┏┑ ╷ ╻ ┏┯┓ ┌┰┐ ▊ ╱╲╱╲╳╳╳ + ║┌─╨─┐║ │╔═╧═╗│ │╒═╪═╕│ │╓─╁─╖│ ┃┌─╂─┐┃ ┗╃╄┙ ╶┼╴╺╋╸┠┼┨ ┝╋┥ ▋ ╲╱╲╱╳╳╳ + ║│╲ ╱│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╿ │┃ ┍╅╆┓ ╵ ╹ ┗┷┛ └┸┘ ▌ ╱╲╱╲╳╳╳ + ╠╡ ╳ ╞╣ ├╢ ╟┤ ├┼─┼─┼┤ ├╫─╂─╫┤ ┣┿╾┼╼┿┫ ┕┛┖┚ ┌┄┄┐ ╎ ┏┅┅┓ ┋ ▍ ╲╱╲╱╳╳╳ + ║│╱ ╲│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╽ │┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▎ + ║└─╥─┘║ │╚═╤═╝│ │╘═╪═╛│ │╙─╀─╜│ ┃└─╂─┘┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▏ + ╚══╩══╝ └──┴──┘ ╰──┴──╯ ╰──┴──╯ ┗━━┻━━┛ ▗▄▖▛▀▜ └╌╌┘ ╎ ┗╍╍┛ ┋ ▁▂▃▄▅▆▇█ + ▝▀▘▙▄▟ + +</pre> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi/tests/simple_wsgi.py new/gabbi-1.35.0/gabbi/tests/simple_wsgi.py --- old/gabbi-1.32.0/gabbi/tests/simple_wsgi.py 2016-10-28 12:04:01.000000000 +0200 +++ new/gabbi-1.35.0/gabbi/tests/simple_wsgi.py 2017-07-07 15:03:57.000000000 +0200 @@ -107,6 +107,11 @@ # fall through if we've ended the loop elif path_info == '/cookie': headers.append(('Set-Cookie', 'session=1234; domain=.example.com')) + elif path_info == '/jsonator': + json_data = json.dumps({query_data['key'][0]: + query_data['value'][0]}) + start_response('200 OK', [('Content-Type', 'application/json')]) + return [json_data.encode('utf-8')] start_response('200 OK', headers) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi/tests/test_gabbits_pytest.py new/gabbi-1.35.0/gabbi/tests/test_gabbits_pytest.py --- old/gabbi-1.32.0/gabbi/tests/test_gabbits_pytest.py 2016-11-30 18:47:39.000000000 +0100 +++ new/gabbi-1.35.0/gabbi/tests/test_gabbits_pytest.py 2017-04-26 22:25:27.000000000 +0200 @@ -24,12 +24,13 @@ from gabbi.driver import test_pytest # noqa from gabbi.tests import simple_wsgi from gabbi.tests import test_intercept +from gabbi.tests import util TESTS_DIR = 'gabbits_intercept' def pytest_generate_tests(metafunc): - os.environ['GABBI_TEST_URL'] = 'takingnames' + util.set_test_environ() test_dir = os.path.join(os.path.dirname(__file__), TESTS_DIR) driver.py_test_generator( test_dir, intercept=simple_wsgi.SimpleWsgi, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi/tests/test_handlers.py new/gabbi-1.35.0/gabbi/tests/test_handlers.py --- old/gabbi-1.32.0/gabbi/tests/test_handlers.py 2016-10-28 12:04:01.000000000 +0200 +++ new/gabbi-1.35.0/gabbi/tests/test_handlers.py 2017-04-26 14:15:42.000000000 +0200 @@ -17,6 +17,7 @@ import unittest from gabbi import case +from gabbi.exception import GabbiFormatError from gabbi.handlers import core from gabbi.handlers import jsonhandler from gabbi import suitemaker @@ -104,6 +105,19 @@ # Check the pprint of the json self.assertIn(' "location": "house"', msg) + def test_response_string_list_type(self): + handler = core.StringResponseHandler() + self.test.test_data = { + 'name': 'omega test', + 'response_strings': 'omega' + } + self.test.output = 'omega\n' + with self.assertRaises(GabbiFormatError) as exc: + self._assert_handler(handler) + self.assertIn('has incorrect type', str(exc)) + self.assertIn("response_strings in 'omega test'", + str(exc)) + def test_response_json_paths(self): handler = jsonhandler.JSONHandler() self.test.content_type = "application/json" @@ -178,6 +192,19 @@ } self._assert_handler(handler) + def test_response_json_paths_dict_type(self): + handler = jsonhandler.JSONHandler() + self.test.test_data = { + 'name': 'omega test', + 'response_json_paths': ['alpha', 'beta'] + } + self.test.output = 'omega\n' + with self.assertRaises(GabbiFormatError) as exc: + self._assert_handler(handler) + self.assertIn('has incorrect type', str(exc)) + self.assertIn("response_json_paths in 'omega test'", + str(exc)) + def test_response_headers(self): handler = core.HeadersResponseHandler() self.test.response = {'content-type': 'text/plain'} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi/tests/test_intercept.py new/gabbi-1.35.0/gabbi/tests/test_intercept.py --- old/gabbi-1.32.0/gabbi/tests/test_intercept.py 2017-01-13 16:05:52.000000000 +0100 +++ new/gabbi-1.35.0/gabbi/tests/test_intercept.py 2017-04-26 22:25:27.000000000 +0200 @@ -23,6 +23,7 @@ from gabbi import fixture from gabbi.handlers import base from gabbi.tests import simple_wsgi +from gabbi.tests import util TESTS_DIR = 'gabbits_intercept' @@ -64,7 +65,8 @@ def load_tests(loader, tests, pattern): """Provide a TestSuite to the discovery process.""" # Set and environment variable for one of the tests. - os.environ['GABBI_TEST_URL'] = 'takingnames' + util.set_test_environ() + prefix = os.environ.get('GABBI_PREFIX') test_dir = os.path.join(os.path.dirname(__file__), TESTS_DIR) return driver.build_tests(test_dir, loader, host=None, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi/tests/test_load_data_file.py new/gabbi-1.35.0/gabbi/tests/test_load_data_file.py --- old/gabbi-1.32.0/gabbi/tests/test_load_data_file.py 2016-11-28 21:19:29.000000000 +0100 +++ new/gabbi-1.35.0/gabbi/tests/test_load_data_file.py 2017-07-07 15:03:57.000000000 +0200 @@ -35,7 +35,7 @@ def _assert_content_read(self, filepath): self.assertEqual( - 'dummy content', self.http_case._load_data_file(filepath)) + 'dummy content', self.http_case.load_data_file(filepath)) def test_load_file(self, m_open): self.http_case.test_directory = '.' @@ -52,7 +52,7 @@ filepath = '/top-level.private' with self.assertRaises(ValueError): - self.http_case._load_data_file(filepath) + self.http_case.load_data_file(filepath) self.assertFalse(m_open.called) def test_load_file_in_parent_dir(self, m_open): @@ -60,7 +60,7 @@ filepath = '../file-in-parent-dir.txt' with self.assertRaises(ValueError): - self.http_case._load_data_file(filepath) + self.http_case.load_data_file(filepath) self.assertFalse(m_open.called) def test_load_file_within_test_directory(self, m_open): @@ -73,5 +73,5 @@ self.http_case.test_directory = '/a/b/c' filepath = '../../b/E/file-in-test-dir.txt' with self.assertRaises(ValueError): - self.http_case._load_data_file(filepath) + self.http_case.load_data_file(filepath) self.assertFalse(m_open.called) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi/tests/test_replacers.py new/gabbi-1.35.0/gabbi/tests/test_replacers.py --- old/gabbi-1.32.0/gabbi/tests/test_replacers.py 2016-07-13 05:57:28.000000000 +0200 +++ new/gabbi-1.35.0/gabbi/tests/test_replacers.py 2017-04-26 22:25:27.000000000 +0200 @@ -37,8 +37,17 @@ os.environ['moo'] = "False" self.assertEqual(False, http_case._environ_replace(message)) + os.environ['moo'] = "true" + self.assertEqual(True, http_case._environ_replace(message)) + + os.environ['moo'] = "faLse" + self.assertEqual(False, http_case._environ_replace(message)) + + os.environ['moo'] = "null" + self.assertEqual(None, http_case._environ_replace(message)) + os.environ['moo'] = "1" - self.assertEqual("1", http_case._environ_replace(message)) + self.assertEqual(1, http_case._environ_replace(message)) os.environ['moo'] = "cow" self.assertEqual("cow", http_case._environ_replace(message)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi/tests/util.py new/gabbi-1.35.0/gabbi/tests/util.py --- old/gabbi-1.32.0/gabbi/tests/util.py 1970-01-01 01:00:00.000000000 +0100 +++ new/gabbi-1.35.0/gabbi/tests/util.py 2017-04-26 22:25:27.000000000 +0200 @@ -0,0 +1,29 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +"""Utility methods shared by some tests.""" + +import os + + +def set_test_environ(): + """Set some environment variables used in tests.""" + os.environ['GABBI_TEST_URL'] = 'takingnames' + + # Setup environment variables for `coerce.yaml` + os.environ['ONE'] = '1' + os.environ['DECIMAL'] = '1.0' + os.environ['ARRAY_STRING'] = '[1,2,3]' + os.environ['TRUE'] = 'true' + os.environ['FALSE'] = 'false' + os.environ['STRING'] = 'val' + os.environ['NULL'] = 'null' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi/utils.py new/gabbi-1.35.0/gabbi/utils.py --- old/gabbi-1.32.0/gabbi/utils.py 2017-01-06 23:00:06.000000000 +0100 +++ new/gabbi-1.35.0/gabbi/utils.py 2017-04-26 14:15:42.000000000 +0200 @@ -52,9 +52,20 @@ query_string = parsed_url.query path = parsed_url.path - # Guard against a prefix of None - if prefix: - path = '%s%s' % (prefix, path) + # Guard against a prefix of None or the url already having the + # prefix. Without the startswith check, the tests in prefix.yaml + # fail. This is a pragmatic fix which does this for any URL in a + # test request that does not have a scheme and does not + # distinguish between URLs in a gabbi test file and those + # generated by the server. Idealy we would not mutate nor need + # to check URLs returned from the server. Doing that, however, + # would require more complex data handling than we have now and + # this covers most common cases and will be okay until someone + # reports a bug. + if prefix and not path.startswith(prefix): + prefix = prefix.rstrip('/') + path = path.lstrip('/') + path = '%s/%s' % (prefix, path) return urlparse.urlunsplit((scheme, netloc, path, query_string, '')) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi.egg-info/PKG-INFO new/gabbi-1.35.0/gabbi.egg-info/PKG-INFO --- old/gabbi-1.32.0/gabbi.egg-info/PKG-INFO 2017-02-06 14:44:48.000000000 +0100 +++ new/gabbi-1.35.0/gabbi.egg-info/PKG-INFO 2017-07-07 15:36:26.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: gabbi -Version: 1.32.0 +Version: 1.35.0 Summary: Declarative HTTP testing library Home-page: https://github.com/cdent/gabbi Author: Chris Dent diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi.egg-info/SOURCES.txt new/gabbi-1.35.0/gabbi.egg-info/SOURCES.txt --- old/gabbi-1.32.0/gabbi.egg-info/SOURCES.txt 2017-02-06 14:44:48.000000000 +0100 +++ new/gabbi-1.35.0/gabbi.egg-info/SOURCES.txt 2017-07-07 15:36:27.000000000 +0200 @@ -79,8 +79,11 @@ gabbi/tests/test_suitemaker.py gabbi/tests/test_syntax_warning.py gabbi/tests/test_utils.py +gabbi/tests/util.py gabbi/tests/gabbits_inner/inner.yaml gabbi/tests/gabbits_intercept/backref.yaml +gabbi/tests/gabbits_intercept/cat.json +gabbi/tests/gabbits_intercept/coerce.yaml gabbi/tests/gabbits_intercept/contenttype.yaml gabbi/tests/gabbits_intercept/cookie.yaml gabbi/tests/gabbits_intercept/data.json @@ -90,15 +93,19 @@ gabbi/tests/gabbits_intercept/forbiddenheaders.yaml gabbi/tests/gabbits_intercept/horse gabbi/tests/gabbits_intercept/json-extensions.yaml +gabbi/tests/gabbits_intercept/json-left-side.yaml gabbi/tests/gabbits_intercept/jsonbody.yaml gabbi/tests/gabbits_intercept/kitten.png gabbi/tests/gabbits_intercept/last-url.yaml gabbi/tests/gabbits_intercept/method-shortcut.yaml +gabbi/tests/gabbits_intercept/pets.json gabbi/tests/gabbits_intercept/poll.yaml +gabbi/tests/gabbits_intercept/prefix.yaml gabbi/tests/gabbits_intercept/queryparams.yaml gabbi/tests/gabbits_intercept/regex.yaml gabbi/tests/gabbits_intercept/self.yaml gabbi/tests/gabbits_intercept/skipall.yaml +gabbi/tests/gabbits_intercept/utf8.txt gabbi/tests/gabbits_live/google.yaml gabbi/tests/gabbits_runner/failure.yaml gabbi/tests/gabbits_runner/success.yaml diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/gabbi.egg-info/pbr.json new/gabbi-1.35.0/gabbi.egg-info/pbr.json --- old/gabbi-1.32.0/gabbi.egg-info/pbr.json 2017-02-06 14:44:48.000000000 +0100 +++ new/gabbi-1.35.0/gabbi.egg-info/pbr.json 2017-07-07 15:36:26.000000000 +0200 @@ -1 +1 @@ -{"is_release": true, "git_version": "d8fe9f8"} \ No newline at end of file +{"is_release": true, "git_version": "64f274d"} \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/setup.cfg new/gabbi-1.35.0/setup.cfg --- old/gabbi-1.32.0/setup.cfg 2017-02-06 14:44:48.000000000 +0100 +++ new/gabbi-1.35.0/setup.cfg 2017-07-07 15:36:27.000000000 +0200 @@ -36,8 +36,10 @@ console_scripts = gabbi-run = gabbi.runner:run +[bdist_wheel] +universal = 1 + [egg_info] tag_build = tag_date = 0 -tag_svn_revision = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gabbi-1.32.0/tox.ini new/gabbi-1.35.0/tox.ini --- old/gabbi-1.32.0/tox.ini 2017-01-02 18:00:16.000000000 +0100 +++ new/gabbi-1.35.0/tox.ini 2017-06-28 16:57:09.000000000 +0200 @@ -6,9 +6,13 @@ [testenv] deps = -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt +whitelist_externals = rm install_command = pip install -U {opts} {packages} -commands = python setup.py testr --testr-args="{posargs}" -passenv = GABBI_* +commands = + rm -f .testrepository/times.dbm + python setup.py testr --testr-args="{posargs}" +setenv = GABBI_PREFIX= +passenv = GABBI_* HOME [testenv:venv] deps = -r{toxinidir}/requirements.txt @@ -52,7 +56,7 @@ [testenv:gnocchi] basepython = python2.7 -deps = -egit+http://git.openstack.org/openstack/gnocchi#egg=gnocchi +deps = -egit+https://github.com/gnocchixyz/gnocchi#egg=gnocchi tox changedir = {envdir}/src/gnocchi commands = tox -e py27-gabbi --notest # ensure a virtualenv is built
