helpers.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. from contextlib import contextmanager
  2. import os
  3. import sys
  4. import unittest
  5. from six import reraise
  6. from cloudbridge.cloud.factory import CloudProviderFactory
  7. from cloudbridge.cloud.interfaces import TestMockHelperMixin
  8. def parse_bool(val):
  9. if val:
  10. return str(val).upper() in ['TRUE', 'YES']
  11. else:
  12. return False
  13. @contextmanager
  14. def cleanup_action(cleanup_func):
  15. """
  16. Context manager to carry out a given
  17. cleanup action after carrying out a set
  18. of tasks, or when an exception occurs.
  19. If any errors occur during the cleanup
  20. action, those are ignored, and the original
  21. traceback is preserved.
  22. :params func: This function is called if
  23. an exception occurs or at the end of the
  24. context block. If any exceptions raised
  25. by func are ignored.
  26. Usage:
  27. with cleanup_action(lambda e: print("Oops!")):
  28. do_something()
  29. """
  30. try:
  31. yield
  32. except Exception:
  33. ex_class, ex_val, ex_traceback = sys.exc_info()
  34. try:
  35. cleanup_func()
  36. except Exception as e:
  37. print("Error during exception cleanup: {0}".format(e))
  38. reraise(ex_class, ex_val, ex_traceback)
  39. cleanup_func()
  40. TEST_DATA_CONFIG = {
  41. "AWSCloudProvider": {
  42. "image": os.environ.get('CB_IMAGE_AWS', 'ami-d85e75b0'),
  43. "instance_type": os.environ.get('CB_INSTANCE_TYPE_AWS',
  44. 't1.micro'),
  45. "placement": os.environ.get('CB_PLACEMENT_AWS', 'us-east-1a'),
  46. },
  47. "OpenStackCloudProvider": {
  48. "image": os.environ.get('CB_IMAGE_OS',
  49. 'eaf2fa40-25a3-44cd-b2f1-40de42a62154'),
  50. "instance_type": os.environ.get('CB_INSTANCE_TYPE_OS', 'm1.tiny'),
  51. "placement": os.environ.get('CB_PLACEMENT_OS', 'nova'),
  52. }
  53. }
  54. def get_provider_test_data(provider, key):
  55. if "AWSCloudProvider" in provider.name:
  56. return TEST_DATA_CONFIG.get("AWSCloudProvider").get(key)
  57. elif "OpenStackCloudProvider" in provider.name:
  58. return TEST_DATA_CONFIG.get("OpenStackCloudProvider").get(key)
  59. return None
  60. def create_test_instance(
  61. provider, instance_name, zone=None, launch_config=None,
  62. keypair=None, security_groups=None):
  63. return provider.compute.instances.create(
  64. instance_name,
  65. get_provider_test_data(provider, 'image'),
  66. get_provider_test_data(provider, 'instance_type'),
  67. zone=zone,
  68. keypair=keypair,
  69. security_groups=security_groups,
  70. launch_config=launch_config)
  71. def get_test_instance(provider, name, keypair=None, security_groups=None):
  72. instance = create_test_instance(
  73. provider,
  74. name,
  75. keypair=keypair,
  76. security_groups=security_groups)
  77. instance.wait_till_ready()
  78. return instance
  79. class ProviderTestBase(object):
  80. """
  81. A dummy base class for Test Cases. Does not inherit from unittest.TestCase
  82. to avoid confusing test discovery by unittest and nose2. unittest.TestCase
  83. is injected as a base class by the generator, so calling the unittest
  84. constructor works correctly.
  85. """
  86. def __init__(self, methodName, provider):
  87. unittest.TestCase.__init__(self, methodName=methodName)
  88. self.provider = provider
  89. def setUp(self):
  90. if isinstance(self.provider, TestMockHelperMixin):
  91. self.provider.setUpMock()
  92. def tearDown(self):
  93. if isinstance(self.provider, TestMockHelperMixin):
  94. self.provider.tearDownMock()
  95. class ProviderTestCaseGenerator():
  96. """
  97. Generates test cases for all provider - testcase combinations.
  98. Detailed docs at test/__init__.py
  99. """
  100. def __init__(self, test_classes):
  101. self.all_test_classes = test_classes
  102. def get_provider_wait_interval(self, provider_class):
  103. if issubclass(provider_class, TestMockHelperMixin):
  104. return 0
  105. else:
  106. return 1
  107. def create_provider_instance(self, provider_class):
  108. """
  109. Instantiate a default provider instance. All required connection
  110. settings are expected to be set as environment variables.
  111. """
  112. config = {'default_wait_interval':
  113. self.get_provider_wait_interval(provider_class)}
  114. return provider_class(config)
  115. def generate_new_test_class(self, name, testcase_class):
  116. """
  117. Generates a new type which inherits from the given testcase_class and
  118. unittest.TestCase
  119. """
  120. class_name = "{0}{1}".format(name, testcase_class.__name__)
  121. return type(class_name, (testcase_class, unittest.TestCase), {})
  122. def generate_test_suite_for_provider_testcase(
  123. self, provider_class, testcase_class):
  124. """
  125. Generate and return a suite of tests for a specific provider class and
  126. testcase combination
  127. """
  128. testloader = unittest.TestLoader()
  129. testnames = testloader.getTestCaseNames(testcase_class)
  130. suite = unittest.TestSuite()
  131. for name in testnames:
  132. generated_cls = self.generate_new_test_class(
  133. provider_class.__name__,
  134. testcase_class)
  135. suite.addTest(
  136. generated_cls(
  137. name,
  138. self.create_provider_instance(provider_class)))
  139. return suite
  140. def generate_test_suite_for_provider(self, provider_class):
  141. """
  142. Generate and return a suite of all available tests for a given provider
  143. class
  144. """
  145. suite = unittest.TestSuite()
  146. suites = [
  147. self.generate_test_suite_for_provider_testcase(
  148. provider_class, test_class)
  149. for test_class in self.all_test_classes]
  150. for s in suites:
  151. suite.addTest(s)
  152. return suite
  153. def generate_tests(self):
  154. """
  155. Generate and return a suite of tests for all provider and test class
  156. combinations
  157. """
  158. factory = CloudProviderFactory()
  159. use_mock_drivers = parse_bool(
  160. os.environ.get("CB_USE_MOCK_DRIVERS", True))
  161. provider_name = os.environ.get("CB_TEST_PROVIDER", None)
  162. if provider_name:
  163. provider_classes = [
  164. factory.get_provider_class(
  165. provider_name,
  166. get_mock=use_mock_drivers)]
  167. if not provider_classes[0]:
  168. raise ValueError(
  169. "Could not find specified test provider %s" %
  170. provider_name)
  171. else:
  172. provider_classes = factory.get_all_provider_classes(
  173. get_mock=use_mock_drivers)
  174. suite = unittest.TestSuite()
  175. suites = [
  176. self.generate_test_suite_for_provider(p) for p in provider_classes]
  177. for s in suites:
  178. suite.addTest(s)
  179. return suite