helpers.py 6.8 KB

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