From dba18565475454e82e298b886bcd3ceb52f2d6fb Mon Sep 17 00:00:00 2001 From: Pat Ferate Date: Tue, 26 Jul 2016 09:47:22 -0700 Subject: [PATCH] Migrate test runner to py.test Maintainer of pytest_gae needs to merge open PR and push to PyPI. In the mean time, get code directly from GitHub mirror. --- .gitignore | 1 + tests/__init__.py | 22 ------- tests/conftest.py | 106 ++++++++++++++++++++++++++++++++ tests/contrib/test_appengine.py | 4 -- tests/test_jwt.py | 12 ++++ tests/test_service_account.py | 6 ++ tox.ini | 87 +++++++++++--------------- 7 files changed, 161 insertions(+), 77 deletions(-) create mode 100644 tests/conftest.py diff --git a/.gitignore b/.gitignore index 89c1121cb..0bc898c20 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ docs/_build # Test files .tox/ +.cache/ # Django test database db.sqlite3 diff --git a/tests/__init__.py b/tests/__init__.py index 5f6567c4d..e69de29bb 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,22 +0,0 @@ -# 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. - -"""Test package set-up.""" - -from oauth2client import util - -__author__ = 'afshar@google.com (Ali Afshar)' - - -def setup_package(): - """Run on testing package.""" - util.positional_parameters_enforcement = util.POSITIONAL_EXCEPTION diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 000000000..6135af44a --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,106 @@ +# 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. + +""" +Common testing tools for OAuth2Client tests. +""" + +import sys +import tempfile + +import pytest +from six.moves import reload_module + +from oauth2client import util + + +def setup_sdk_imports(): + """Sets up appengine SDK third-party imports.""" + if 'google' in sys.modules: + # Some packages, such as protobuf, clobber the google + # namespace package. This prevents that. + reload_module(sys.modules['google']) + + # This sets up google-provided libraries. + import dev_appserver + dev_appserver.fix_sys_path() + + # Fixes timezone and other os-level items. + import google.appengine.tools.os_compat + (google.appengine.tools.os_compat) + + +def setup_testbed(): + """Sets up the GAE testbed and enables common stubs.""" + from google.appengine.datastore import datastore_stub_util + from google.appengine.ext import testbed as gaetestbed + + # Setup the datastore and memcache stub. + # First, create an instance of the Testbed class. + tb = gaetestbed.Testbed() + # Then activate the testbed, which prepares the service stubs for + # use. + tb.activate() + # Create a consistency policy that will simulate the High + # Replication consistency model. + policy = datastore_stub_util.PseudoRandomHRConsistencyPolicy( + probability=1.0) + # Initialize the datastore stub with this policy. + tb.init_datastore_v3_stub( + datastore_file=tempfile.mkstemp()[1], + consistency_policy=policy) + tb.init_memcache_stub() + + # Setup remaining stubs. + tb.init_urlfetch_stub() + tb.init_app_identity_stub() + tb.init_blobstore_stub() + tb.init_user_stub() + tb.init_logservice_stub() + # tb.init_taskqueue_stub(root_path='tests/resources') + tb.init_taskqueue_stub() + tb.taskqueue_stub = tb.get_stub(gaetestbed.TASKQUEUE_SERVICE_NAME) + + return tb + + +# py.test helpers + +@pytest.yield_fixture +def testbed(): + """py.test fixture for the GAE testbed.""" + testbed = setup_testbed() + yield testbed + testbed.deactivate() + + +@pytest.fixture +def login(testbed): + """py.test fixture for logging in GAE users.""" + def _login(email='user@example.com', id='123', is_admin=False): + testbed.setup_env( + user_email=email, + user_id=id, + user_is_admin='1' if is_admin else '0', + overwrite=True) + return _login + + +def pytest_configure(): + """Pytest hook function for setting up test session.""" + # Google SDK modules only needed in GAE or GCE + try: + setup_sdk_imports() + except ImportError: + pass + # Default of POSITIONAL_WARNING is too verbose for testing + util.positional_parameters_enforcement = util.POSITIONAL_EXCEPTION diff --git a/tests/contrib/test_appengine.py b/tests/contrib/test_appengine.py index af544e3c2..1aad07c25 100644 --- a/tests/contrib/test_appengine.py +++ b/tests/contrib/test_appengine.py @@ -18,10 +18,6 @@ import tempfile import time -import dev_appserver - -dev_appserver.fix_sys_path() - from google.appengine.api import apiproxy_stub from google.appengine.api import apiproxy_stub_map from google.appengine.api import app_identity diff --git a/tests/test_jwt.py b/tests/test_jwt.py index ecc58e868..67fc9c1d6 100644 --- a/tests/test_jwt.py +++ b/tests/test_jwt.py @@ -235,9 +235,13 @@ def setUp(self): class SignedJwtAssertionCredentialsTests(unittest2.TestCase): def setUp(self): + self.orig_signer = crypt.Signer self.format_ = 'p12' crypt.Signer = crypt.OpenSSLSigner + def tearDown(self): + crypt.Signer = self.orig_signer + def _make_credentials(self): private_key = datafile('privatekey.' + self.format_) signer = crypt.Signer.from_string(private_key) @@ -310,17 +314,25 @@ class PEMSignedJwtAssertionCredentialsOpenSSLTests( SignedJwtAssertionCredentialsTests): def setUp(self): + self.orig_signer = crypt.Signer self.format_ = 'pem' crypt.Signer = crypt.OpenSSLSigner + def tearDown(self): + crypt.Signer = self.orig_signer + class PEMSignedJwtAssertionCredentialsPyCryptoTests( SignedJwtAssertionCredentialsTests): def setUp(self): + self.orig_signer = crypt.Signer self.format_ = 'pem' crypt.Signer = crypt.PyCryptoSigner + def tearDown(self): + crypt.Signer = self.orig_signer + class TestHasOpenSSLFlag(unittest2.TestCase): diff --git a/tests/test_service_account.py b/tests/test_service_account.py index 699e6994a..bc91086d5 100644 --- a/tests/test_service_account.py +++ b/tests/test_service_account.py @@ -46,6 +46,8 @@ def datafile(filename): class ServiceAccountCredentialsTests(unittest2.TestCase): def setUp(self): + self.orig_signer = crypt.Signer + self.orig_verifier = crypt.Verifier self.client_id = '123' self.service_account_email = 'dummy@google.com' self.private_key_id = 'ABCDEF' @@ -59,6 +61,10 @@ def setUp(self): client_id=self.client_id, ) + def tearDown(self): + crypt.Signer = self.orig_signer + crypt.Verifier = self.orig_verifier + def test__to_json_override(self): signer = object() creds = service_account.ServiceAccountCredentials( diff --git a/tox.ini b/tox.ini index b0781a8a1..330b3c888 100644 --- a/tox.ini +++ b/tox.ini @@ -7,7 +7,7 @@ basedeps = mock>=1.3.0 cryptography>=1.0 pyopenssl>=0.14 webtest - nose + pytest flask unittest2 sqlalchemy @@ -18,74 +18,65 @@ deps = {[testenv]basedeps} setenv = pypy: with_gmp=no DJANGO_SETTINGS_MODULE=tests.contrib.django_util.settings -commands = nosetests --ignore-files=test_appengine\.py --ignore-files=test__appengine_ndb\.py {posargs} +commands = + py.test \ + --ignore=tests/contrib/test_appengine.py \ + --ignore=tests/contrib/test__appengine_ndb.py \ + {posargs} [coverbase] basepython = python2.7 commands = - nosetests \ - --with-coverage \ - --cover-package=oauth2client \ - --cover-package=tests \ - --cover-erase \ - --cover-tests \ - --cover-branches \ - --ignore-files=test_appengine\.py \ - --ignore-files=test__appengine_ndb\.py - nosetests \ - --with-coverage \ - --cover-package=oauth2client.contrib.appengine \ - --cover-package=oauth2client.contrib._appengine_ndb \ - --cover-package=tests.contrib.test_appengine \ - --cover-package=tests.contrib.test__appengine_ndb \ - --with-gae \ - --cover-tests \ - --cover-branches \ - --gae-application=tests/data \ - --gae-lib-root={env:GAE_PYTHONPATH:google_appengine} \ - --logging-level=INFO \ + py.test \ + --cov=oauth2client \ + --cov=tests \ + --ignore=tests/contrib/test_appengine.py \ + --ignore=tests/contrib/test__appengine_ndb.py + py.test \ + --cov=oauth2client.contrib.appengine \ + --cov=oauth2client.contrib._appengine_ndb \ + --cov=tests.contrib.test__appengine_ndb \ + --cov=tests.contrib.test_appengine \ + --cov-append \ tests/contrib/test_appengine.py \ tests/contrib/test__appengine_ndb.py deps = {[testenv]deps} coverage - nosegae + pytest-cov [testenv:py26] basepython = python2.6 commands = - nosetests \ - --ignore-files=test_appengine\.py \ - --ignore-files=test__appengine_ndb\.py \ - --ignore-files=test_keyring_storage\.py \ - --exclude-dir=oauth2client/contrib/django_util \ - --exclude-dir=tests/contrib/django_util \ + py.test \ + --ignore=tests/contrib/test_appengine.py \ + --ignore=tests/contrib/test__appengine_ndb.py \ + --ignore=tests/contrib/test_keyring_storage.py \ + --ignore=oauth2client/contrib/django_util \ + --ignore=tests/contrib/django_util \ {posargs} deps = {[testenv]basedeps} - nose-exclude [testenv:py33] basepython = python3.3 commands = - nosetests \ - --ignore-files=test_appengine\.py \ - --ignore-files=test__appengine_ndb\.py \ - --ignore-files=test_django_orm\.py \ - --ignore-files=test_django_settings\.py \ - --ignore-files=test_django_util\.py \ - --exclude-dir=oauth2client/contrib/django_util \ - --exclude-dir=tests/contrib/django_util \ + py.test \ + --ignore=tests/contrib/test_appengine.py \ + --ignore=tests/contrib/test__appengine_ndb.py \ + --ignore=tests/contrib/test_django_orm.py \ + --ignore=tests/contrib/test_django_settings.py \ + --ignore=oauth2client/contrib/django_util \ + --ignore=tests/contrib/django_util \ {posargs} deps = {[testenv]basedeps} keyring - nose-exclude [testenv:cover] basepython = {[coverbase]basepython} commands = {[coverbase]commands} - coverage report --show-missing --cover-min-percentage=100 + coverage report --show-missing --fail-under=100 deps = {[coverbase]deps} @@ -114,13 +105,10 @@ commands = {toxinidir}/scripts/build_docs.sh [testenv:gae] basepython = python2.7 deps = {[testenv]basedeps} - nosegae +setenv = + PYTHONPATH = {env:GAE_PYTHONPATH}:{env:PYTHONPATH:} commands = - nosetests \ - --with-gae \ - --gae-lib-root={env:GAE_PYTHONPATH:google_appengine} \ - --gae-application=tests/data \ - --logging-level=INFO \ + py.test \ tests/contrib/test_appengine.py \ tests/contrib/test__appengine_ndb.py @@ -167,11 +155,8 @@ exclude = .tox,.git,./*.egg,build, application-import-names = oauth2client putty-ignore = # E402 module level import not at top of file - # These files have needed configurations defined before import + # This file has needed configurations defined before import docs/conf.py : E402 - tests/contrib/test_appengine.py : E402 - # Additionally, ignore E100 (imports in wrong order) for Django configuration - tests/contrib/test_django_orm.py : E402,I100 # E501 line too long # Ignore lines over 80 chars that include "http:" or "https:" /http:/ : E501