Prechádzať zdrojové kódy

Make mock providers available by default

Nuwan Goonasekera 7 rokov pred
rodič
commit
9d635ee83e

+ 4 - 0
.travis.yml

@@ -17,6 +17,8 @@ matrix:
     env: TOX_ENV=py27-azure
   - python: 2.7
     env: TOX_ENV=py27-gce
+  - python: 2.7
+    env: TOX_ENV=py27-mock
   - python: 2.7
     env: TOX_ENV=py27-openstack
   - python: 3.6
@@ -25,6 +27,8 @@ matrix:
     env: TOX_ENV=py36-azure
   - python: 3.6
     env: TOX_ENV=py36-gce
+  - python: 3.6
+    env: TOX_ENV=py36-mock
   - python: 3.6
     env: TOX_ENV=py36-openstack
 env:

+ 12 - 5
README.rst

@@ -24,22 +24,27 @@ Build Status Tests
 
 .. |aws-py27| image:: https://travis-matrix-badges.herokuapp.com/repos/CloudVE/cloudbridge/branches/master/1
               :target: https://travis-ci.org/CloudVE/cloudbridge
-.. |aws-py36| image:: https://travis-matrix-badges.herokuapp.com/repos/CloudVE/cloudbridge/branches/master/5
+.. |aws-py36| image:: https://travis-matrix-badges.herokuapp.com/repos/CloudVE/cloudbridge/branches/master/6
               :target: https://travis-ci.org/CloudVE/cloudbridge
 
 .. |azure-py27| image:: https://travis-matrix-badges.herokuapp.com/repos/CloudVE/cloudbridge/branches/master/2
                 :target: https://travis-ci.org/CloudVE/cloudbridge
-.. |azure-py36| image:: https://travis-matrix-badges.herokuapp.com/repos/CloudVE/cloudbridge/branches/master/6
+.. |azure-py36| image:: https://travis-matrix-badges.herokuapp.com/repos/CloudVE/cloudbridge/branches/master/7
                 :target: https://travis-ci.org/CloudVE/cloudbridge
 
 .. |gce-py27| image:: https://travis-matrix-badges.herokuapp.com/repos/CloudVE/cloudbridge/branches/master/3
               :target: https://travis-ci.org/CloudVE/cloudbridge
-.. |gce-py36| image:: https://travis-matrix-badges.herokuapp.com/repos/CloudVE/cloudbridge/branches/master/7
+.. |gce-py36| image:: https://travis-matrix-badges.herokuapp.com/repos/CloudVE/cloudbridge/branches/master/8
               :target: https://travis-ci.org/CloudVE/cloudbridge
 
-.. |os-py27| image:: https://travis-matrix-badges.herokuapp.com/repos/CloudVE/cloudbridge/branches/master/4
+.. |mock-py27| image:: https://travis-matrix-badges.herokuapp.com/repos/CloudVE/cloudbridge/branches/master/4
+              :target: https://travis-ci.org/CloudVE/cloudbridge
+.. |mock-py36| image:: https://travis-matrix-badges.herokuapp.com/repos/CloudVE/cloudbridge/branches/master/9
+              :target: https://travis-ci.org/CloudVE/cloudbridge
+
+.. |os-py27| image:: https://travis-matrix-badges.herokuapp.com/repos/CloudVE/cloudbridge/branches/master/5
              :target: https://travis-ci.org/CloudVE/cloudbridge
-.. |os-py36| image:: https://travis-matrix-badges.herokuapp.com/repos/CloudVE/cloudbridge/branches/master/8
+.. |os-py36| image:: https://travis-matrix-badges.herokuapp.com/repos/CloudVE/cloudbridge/branches/master/10
              :target: https://travis-ci.org/CloudVE/cloudbridge
 
 +---------------------------+----------------+----------------+
@@ -53,6 +58,8 @@ Build Status Tests
 +---------------------------+----------------+----------------+
 | **OpenStack**             | |os-py27|      | |os-py36|      |
 +---------------------------+----------------+----------------+
+| **Mock Provider**         | |mock-py27|    | |mock-py36|    |
++---------------------------+----------------+----------------+
 
 Installation
 ~~~~~~~~~~~~

+ 17 - 35
cloudbridge/cloud/factory.py

@@ -17,6 +17,7 @@ class ProviderList(object):
     AZURE = 'azure'
     GCE = 'gce'
     OPENSTACK = 'openstack'
+    MOCK = 'mock'
 
 
 class CloudProviderFactory(object):
@@ -48,19 +49,11 @@ class CloudProviderFactory(object):
         if isinstance(cls, type) and issubclass(cls, CloudProvider):
             if hasattr(cls, "PROVIDER_ID"):
                 provider_id = getattr(cls, "PROVIDER_ID")
-                if issubclass(cls, TestMockHelperMixin):
-                    if self.provider_list.get(provider_id, {}).get(
-                            'mock_class'):
-                        log.warning("Mock provider with id: %s is already "
-                                    "registered. Overriding with class: %s",
-                                    provider_id, cls)
-                    self.provider_list[provider_id]['mock_class'] = cls
-                else:
-                    if self.provider_list.get(provider_id, {}).get('class'):
-                        log.warning("Provider with id: %s is already "
-                                    "registered. Overriding with class: %s",
-                                    provider_id, cls)
-                    self.provider_list[provider_id]['class'] = cls
+                if self.provider_list.get(provider_id, {}).get('class'):
+                    log.warning("Provider with id: %s is already "
+                                "registered. Overriding with class: %s",
+                                provider_id, cls)
+                self.provider_list[provider_id]['class'] = cls
             else:
                 log.warning("Provider class: %s implements CloudProvider but"
                             " does not define PROVIDER_ID. Ignoring...", cls)
@@ -102,8 +95,7 @@ class CloudProviderFactory(object):
         :rtype: dict
         :return: A dict of available providers and their implementations in the
                  following format::
-                 {'aws': {'class': aws.provider.AWSCloudProvider,
-                          'mock_class': aws.provider.MockAWSCloudProvider},
+                 {'aws': {'class': aws.provider.AWSCloudProvider},
                   'openstack': {'class': openstack.provider.OpenStackCloudProvi
                                          der}
                  }
@@ -143,14 +135,10 @@ class CloudProviderFactory(object):
         log.debug("Created '%s' provider", name)
         return provider_class(config)
 
-    def get_provider_class(self, name, get_mock=False):
+    def get_provider_class(self, name):
         """
         Return a class for the requested provider.
 
-        :type get_mock: ``bool``
-        :param get_mock: If True, returns a mock version of the provider
-        if available, or the real version if not.
-
         :rtype: provider class or ``None``
         :return: A class corresponding to the requested provider or ``None``
                  if the provider was not found.
@@ -158,24 +146,19 @@ class CloudProviderFactory(object):
         log.debug("Returning a class for the %s provider", name)
         impl = self.list_providers().get(name)
         if impl:
-            if get_mock and impl.get("mock_class"):
-                log.debug("param get_mock set to True, returning "
-                          "a mock version of the provider %s", name)
-                return impl["mock_class"]
-            else:
-                log.debug("Returning the real version of %s", name)
-                return impl["class"]
+            log.debug("Returning provider class for %s", name)
+            return impl["class"]
         else:
             log.debug("Provider with the name: %s not found", name)
             return None
 
-    def get_all_provider_classes(self, get_mock=False):
+    def get_all_provider_classes(self, ignore_mocks=False):
         """
         Returns a list of classes for all available provider implementations
 
-        :type get_mock: ``bool``
-        :param get_mock: If True, returns a mock version of the provider
-        if available, or the real version if not.
+        :type ignore_mocks: ``bool``
+        :param ignore_mocks: If True, does not return mock providers. Mock
+        providers are providers which implement the TestMockHelperMixin.
 
         :rtype: type ``class`` or ``None``
         :return: A list of all available provider classes or an empty list
@@ -183,10 +166,9 @@ class CloudProviderFactory(object):
         """
         all_providers = []
         for impl in self.list_providers().values():
-            if get_mock and impl.get("mock_class"):
-                log.debug("param get_mock set to True, appending "
-                          "a mock version of the provider %s", impl)
-                all_providers.append(impl["mock_class"])
+            if ignore_mocks:
+                if not issubclass(impl["class"], TestMockHelperMixin):
+                    all_providers.append(impl["class"])
             else:
                 all_providers.append(impl["class"])
         log.info("List of provider classes: %s", all_providers)

+ 0 - 1
cloudbridge/cloud/providers/aws/__init__.py

@@ -3,4 +3,3 @@ Exports from this provider
 """
 
 from .provider import AWSCloudProvider  # noqa
-from .provider import MockAWSCloudProvider  # noqa

+ 0 - 86
cloudbridge/cloud/providers/aws/provider.py

@@ -3,18 +3,8 @@ import logging as log
 
 import boto3
 
-try:
-    # These are installed only for the case of a dev instance
-    from moto import mock_ec2
-    from moto import mock_s3
-
-    import responses
-except ImportError:
-    log.debug("Development library moto is not installed.")
-
 from cloudbridge.cloud.base import BaseCloudProvider
 from cloudbridge.cloud.base.helpers import get_env
-from cloudbridge.cloud.interfaces import TestMockHelperMixin
 
 from .services import AWSComputeService
 from .services import AWSNetworkingService
@@ -118,79 +108,3 @@ class AWSCloudProvider(BaseCloudProvider):
         '''Get an S3 resource object'''
         return self.session.resource(
             's3', region_name=self.region_name, **self.s3_cfg)
-
-
-class MockAWSCloudProvider(AWSCloudProvider, TestMockHelperMixin):
-
-    def __init__(self, config):
-        super(MockAWSCloudProvider, self).__init__(config)
-
-    def setUpMock(self):
-        """
-        Let Moto take over all socket communications
-        """
-        self.ec2mock = mock_ec2()
-        self.ec2mock.start()
-        self.s3mock = mock_s3()
-        self.s3mock.start()
-        responses.add(
-            responses.GET,
-            self.AWS_INSTANCE_DATA_DEFAULT_URL,
-            body=u"""
-[
-  {
-    "family": "General Purpose",
-    "enhanced_networking": false,
-    "vCPU": 1,
-    "generation": "current",
-    "ebs_iops": 0,
-    "network_performance": "Low",
-    "ebs_throughput": 0,
-    "vpc": {
-      "ips_per_eni": 2,
-      "max_enis": 2
-    },
-    "arch": [
-      "x86_64"
-    ],
-    "linux_virtualization_types": [
-        "HVM"
-    ],
-    "pricing": {
-        "us-east-1": {
-            "linux": {
-                "ondemand": "0.0058",
-                "reserved": {
-                    "yrTerm1Convertible.allUpfront": "0.003881",
-                    "yrTerm1Convertible.noUpfront": "0.0041",
-                    "yrTerm1Convertible.partialUpfront": "0.003941",
-                    "yrTerm1Standard.allUpfront": "0.003311",
-                    "yrTerm1Standard.noUpfront": "0.0036",
-                    "yrTerm1Standard.partialUpfront": "0.003412",
-                    "yrTerm3Convertible.allUpfront": "0.002626",
-                    "yrTerm3Convertible.noUpfront": "0.0029",
-                    "yrTerm3Convertible.partialUpfront": "0.002632",
-                    "yrTerm3Standard.allUpfront": "0.002169",
-                    "yrTerm3Standard.noUpfront": "0.0025",
-                    "yrTerm3Standard.partialUpfront": "0.002342"
-                }
-            }
-        }
-    },
-    "ebs_optimized": false,
-    "storage": null,
-    "max_bandwidth": 0,
-    "instance_type": "t2.nano",
-    "ECU": "variable",
-    "memory": 0.5,
-    "ebs_max_bandwidth": 0
-  }
-]
-""")
-
-    def tearDownMock(self):
-        """
-        Stop Moto intercepting all socket communications
-        """
-        self.s3mock.stop()
-        self.ec2mock.stop()

+ 0 - 3
docs/topics/setup.rst

@@ -329,9 +329,6 @@ a whole.
 |                             | debug output to be printed for each provider         |
 |                             | (including HTTP traces).                             |
 +-----------------------------+------------------------------------------------------+
-| CB_USE_MOCK_PROVIDERS       | Setting this to ``True`` will cause the CloudBridge  |
-|                             | test suite to use mock drivers when available.       |
-+-----------------------------+------------------------------------------------------+
 | CB_TEST_PROVIDER            | Set this value to a valid :class:`.ProviderList`     |
 |                             | value such as ``aws``, to limit tests to that        |
 |                             | provider only.                                       |

+ 4 - 6
docs/topics/testing.rst

@@ -59,9 +59,8 @@ Using unittest directly
 ~~~~~~~~~~~~~~~~~~~~~~~
 You can also run the tests against your active virtual environment directly
 with ``python setup.py test``. You will need to set the ``CB_TEST_PROVIDER``
-and ``CB_USE_MOCK_PROVIDERS`` environment variables prior to running the tests,
-or they will default to ``CB_TEST_PROVIDER=aws`` and
-``CB_USE_MOCK_PROVIDERS=True``.
+environment variable prior to running the tests, or they will default to
+``CB_TEST_PROVIDER=aws``.
 
 You can also run a specific test case, as follows:
 ``python setup.py test -s test.test_cloud_factory.CloudFactoryTestCase``
@@ -71,9 +70,8 @@ Using a mock provider
 
 Note that running the tests may create various cloud resources, for which you
 may incur costs. For the AWS cloud, there is also a mock provider (`moto`_) that
-will simulate AWS resources. It is used by default when running the test suite.
-You can toggle the use of mock providers by setting an environment variable:
-``CB_USE_MOCK_PROVIDERS`` to ``Yes`` or ``No``.
+will simulate AWS resources. You can use ``CB_TEST_PROVIDER=mock`` to run tests
+against the mock provider only, which will provide faster feedback times.
 
 
 .. _design goals: https://github.com/CloudVE/cloudbridge/

+ 0 - 5
test/__init__.py

@@ -1,9 +1,4 @@
 """
 Use ``python setup.py test`` to run these unit tests (alternatively, use
 ``python -m unittest test``).
-
-You must set the CB_TEST_PROVIDER environment variable before running the
-tests. Otherwise, the test suite will default to running against the mock
-aws provider. Alternatively, use tox, which will run tests for all available
-provider combinations.
 """

+ 1 - 4
test/helpers/__init__.py

@@ -294,11 +294,8 @@ class ProviderTestBase(unittest.TestCase):
 
     def create_provider_instance(self):
         provider_name = get_env("CB_TEST_PROVIDER", "aws")
-        use_mock_drivers = parse_bool(
-            os.environ.get("CB_USE_MOCK_PROVIDERS", "True"))
         factory = CloudProviderFactory()
-        provider_class = factory.get_provider_class(provider_name,
-                                                    get_mock=use_mock_drivers)
+        provider_class = factory.get_provider_class(provider_name)
         config = {'default_wait_interval':
                   self.get_provider_wait_interval(provider_class),
                   'default_result_limit': 5}

+ 18 - 40
test/test_cloud_factory.py

@@ -6,9 +6,6 @@ from cloudbridge.cloud.factory import CloudProviderFactory
 from cloudbridge.cloud.interfaces import TestMockHelperMixin
 from cloudbridge.cloud.interfaces.provider import CloudProvider
 from cloudbridge.cloud.providers.aws import AWSCloudProvider
-from cloudbridge.cloud.providers.aws.provider import MockAWSCloudProvider
-
-from test import helpers
 
 
 class CloudFactoryTestCase(unittest.TestCase):
@@ -29,25 +26,6 @@ class CloudFactoryTestCase(unittest.TestCase):
         with self.assertRaises(NotImplementedError):
             CloudProviderFactory().create_provider("ec23", {})
 
-    def test_find_provider_mock_valid(self):
-        # Searching for a provider with a known mock driver should return
-        # an implementation implementing helpers.TestMockHelperMixin
-        mock = CloudProviderFactory().get_provider_class(
-            factory.ProviderList.AWS, get_mock=True)
-        self.assertTrue(
-            issubclass(
-                mock,
-                helpers.TestMockHelperMixin),
-            "Expected mock for AWS but class does not implement mock provider")
-        for cls in CloudProviderFactory().get_all_provider_classes(
-                get_mock=False):
-            self.assertTrue(
-                not issubclass(
-                    cls,
-                    TestMockHelperMixin),
-                "Did not expect mock but %s implements mock provider" %
-                cls)
-
     def test_get_provider_class_valid(self):
         # Searching for a provider class with a known name should return a
         # valid class
@@ -59,6 +37,20 @@ class CloudFactoryTestCase(unittest.TestCase):
         # return None
         self.assertIsNone(CloudProviderFactory().get_provider_class("aws1"))
 
+    def test_find_provider_include_mocks(self):
+        self.assertTrue(
+            any(cls for cls
+                in CloudProviderFactory().get_all_provider_classes()
+                if issubclass(cls, TestMockHelperMixin)),
+            "expected to find at least one mock provider")
+
+    def test_find_provider_exclude_mocks(self):
+        for cls in CloudProviderFactory().get_all_provider_classes(
+                ignore_mocks=True):
+            self.assertTrue(
+                not issubclass(cls, TestMockHelperMixin),
+                "Did not expect mock but %s implements mock provider" % cls)
+
     def test_register_provider_class_invalid(self):
         # Attempting to register an invalid test class should be ignored
         class DummyClass(object):
@@ -67,7 +59,7 @@ class CloudFactoryTestCase(unittest.TestCase):
         factory = CloudProviderFactory()
         factory.register_provider_class(DummyClass)
         self.assertTrue(DummyClass not in
-                        factory.get_all_provider_classes(get_mock=False))
+                        factory.get_all_provider_classes())
 
     def test_register_provider_class_double(self):
         # Attempting to register the same class twice should register second
@@ -79,23 +71,9 @@ class CloudFactoryTestCase(unittest.TestCase):
         factory.list_providers()
         factory.register_provider_class(DummyClass)
         self.assertTrue(DummyClass in
-                        factory.get_all_provider_classes(get_mock=False))
+                        factory.get_all_provider_classes())
         self.assertTrue(AWSCloudProvider not in
-                        factory.get_all_provider_classes(get_mock=False))
-
-    def test_register_mock_provider_class_double(self):
-        # Attempting to register the same mock provider twice should register
-        # only the second instance
-        class DummyClass(CloudProvider, TestMockHelperMixin):
-            PROVIDER_ID = 'aws'
-
-        factory = CloudProviderFactory()
-        factory.list_providers()
-        factory.register_provider_class(DummyClass)
-        self.assertTrue(DummyClass in
-                        factory.get_all_provider_classes(get_mock=True))
-        self.assertTrue(MockAWSCloudProvider not in
-                        factory.get_all_provider_classes(get_mock=True))
+                        factory.get_all_provider_classes())
 
     def test_register_provider_class_without_id(self):
         # Attempting to register a class without a PROVIDER_ID attribute
@@ -106,4 +84,4 @@ class CloudFactoryTestCase(unittest.TestCase):
         factory = CloudProviderFactory()
         factory.register_provider_class(DummyClass)
         self.assertTrue(DummyClass not in
-                        factory.get_all_provider_classes(get_mock=False))
+                        factory.get_all_provider_classes())

+ 4 - 8
tox.ini

@@ -4,15 +4,9 @@
 # To use it, "pip install tox" and then run "tox" from this directory.
 # You will have to set all required environment variables (below) before
 # running the tests.
-#
-# Alternatively, to run mock tests only, run tox as follows:
-# CB_USE_MOCK_PROVIDERS=True tox -e py27-aws
-#
-# Simply running tox -e py27-aws also works because the default is to use
-# mock providers.
 
 [tox]
-envlist = {py27,py36,pypy}-{aws,azure,gce,openstack}
+envlist = {py27,py36,pypy}-{aws,azure,gce,openstack,mock}
 
 [testenv]
 commands = flake8 cloudbridge test setup.py
@@ -26,12 +20,14 @@ setenv =
     azure: CB_TEST_PROVIDER=azure
     gce: CB_TEST_PROVIDER=gce
     openstack: CB_TEST_PROVIDER=openstack
+    mock: CB_TEST_PROVIDER=mock
 passenv =
-    CB_USE_MOCK_PROVIDERS PYTHONUNBUFFERED
+    PYTHONUNBUFFERED
     aws: CB_IMAGE_AWS CB_INSTANCE_TYPE_AWS CB_PLACEMENT_AWS AWS_ACCESS_KEY AWS_SECRET_KEY
     azure: AZURE_SUBSCRIPTION_ID AZURE_CLIENT_ID AZURE_SECRET AZURE_TENANT AZURE_REGION_NAME AZURE_RESOURCE_GROUP AZURE_STORAGE_ACCOUNT AZURE_VM_DEFAULT_USER_NAME AZURE_PUBLIC_KEY_STORAGE_TABLE_NAME
     gce: CB_IMAGE_GCE CB_INSTANCE_TYPE_GCE CB_PLACEMENT_GCE GCE_DEFAULT_REGION GCE_DEFAULT_ZONE GCE_PROJECT_NAME GCE_SERVICE_CREDS_FILE GCE_SERVICE_CREDS_DICT
     openstack:  CB_IMAGE_OS CB_INSTANCE_TYPE_OS CB_PLACEMENT_OS OS_AUTH_URL OS_PASSWORD OS_PROJECT_NAME OS_TENANT_NAME OS_USERNAME OS_REGION_NAME OS_USER_DOMAIN_NAME OS_PROJECT_DOMAIN_NAME NOVA_SERVICE_NAME
+    mock: CB_IMAGE_AWS CB_INSTANCE_TYPE_AWS CB_PLACEMENT_AWS AWS_ACCESS_KEY AWS_SECRET_KEY
 deps =
     -rrequirements.txt
     coverage