Commit 92c9a0fb authored by Jérome Perrin's avatar Jérome Perrin

testing/testcase: separate instance/software snapshot

Log files from slapos node software are large and they are always the
same after each test method, so it does not make much sense to store
them for each test method snapshot, because we only run slapos node
software at setupModule step.

Log files from slapos node instance are smaller, but it's also not
needed to make a snapshot after each test, because we only run slapos
node instance at setUpClass step.

To prevent duplication, store slapos log files only at setupModule (for
software) and at setUpClass (for instance).

Also store log slapos log files in all the steps that can fail in
_cleanup.
parent 8354f1a4
...@@ -218,12 +218,22 @@ def installSoftwareUrlList(cls, software_url_list, max_retry=2, debug=False): ...@@ -218,12 +218,22 @@ def installSoftwareUrlList(cls, software_url_list, max_retry=2, debug=False):
This also check softwares with `checkSoftware` This also check softwares with `checkSoftware`
""" """
def _storeSoftwareLogSnapshot(name):
for standalone_log in glob.glob(os.path.join(
cls._base_directory,
'var',
'log',
'*',
)):
cls._copySnapshot(standalone_log, name)
try: try:
for software_url in software_url_list: for software_url in software_url_list:
cls.logger.debug("Supplying %s", software_url) cls.logger.debug("Supplying %s", software_url)
cls.slap.supply(software_url) cls.slap.supply(software_url)
cls.logger.debug("Waiting for slapos node software to build") cls.logger.debug("Waiting for slapos node software to build")
cls.slap.waitForSoftware(max_retry=max_retry, debug=debug) cls.slap.waitForSoftware(max_retry=max_retry, debug=debug)
_storeSoftwareLogSnapshot('setupModule')
for software_url in software_url_list: for software_url in software_url_list:
checkSoftware(cls.slap, software_url) checkSoftware(cls.slap, software_url)
except BaseException as e: except BaseException as e:
...@@ -237,8 +247,8 @@ def installSoftwareUrlList(cls, software_url_list, max_retry=2, debug=False): ...@@ -237,8 +247,8 @@ def installSoftwareUrlList(cls, software_url_list, max_retry=2, debug=False):
cls.slap.waitForSoftware(max_retry=max_retry, debug=debug) cls.slap.waitForSoftware(max_retry=max_retry, debug=debug)
except BaseException: except BaseException:
cls.logger.exception("Error removing software") cls.logger.exception("Error removing software")
pass _storeSoftwareLogSnapshot('setupModule removing software')
cls._cleanup() cls._cleanup('setupModule')
raise e raise e
...@@ -336,6 +346,7 @@ class SlapOSInstanceTestCase(unittest.TestCase): ...@@ -336,6 +346,7 @@ class SlapOSInstanceTestCase(unittest.TestCase):
"""Request an instance. """Request an instance.
""" """
cls._instance_parameter_dict = cls.getInstanceParameterDict() cls._instance_parameter_dict = cls.getInstanceParameterDict()
snapshot_name = "{}.{}.setUpClass".format(cls.__module__, cls.__name__)
try: try:
cls.logger.debug("Starting") cls.logger.debug("Starting")
...@@ -376,27 +387,27 @@ class SlapOSInstanceTestCase(unittest.TestCase): ...@@ -376,27 +387,27 @@ class SlapOSInstanceTestCase(unittest.TestCase):
cls.computer_partition_root_path = os.path.join( cls.computer_partition_root_path = os.path.join(
cls.slap._instance_root, cls.computer_partition.getId()) cls.slap._instance_root, cls.computer_partition.getId())
cls.logger.debug("setUpClass done") cls.logger.debug("setUpClass done")
except BaseException: except BaseException:
cls.logger.exception("Error during setUpClass") cls.logger.exception("Error during setUpClass")
cls._storeSnapshot("{}.setUpClass".format(cls.__name__)) cls._storeSystemSnapshot(snapshot_name)
cls._cleanup() cls._cleanup(snapshot_name)
cls.setUp = lambda self: self.fail('Setup Class failed.') cls.setUp = lambda self: self.fail('Setup Class failed.')
raise raise
else:
cls._storeSystemSnapshot(snapshot_name)
@classmethod @classmethod
def tearDownClass(cls): def tearDownClass(cls):
"""Tear down class, stop the processes and destroy instance. """Tear down class, stop the processes and destroy instance.
""" """
cls._cleanup() cls._cleanup("{}.{}.tearDownClass".format(cls.__module__, cls.__name__))
@classmethod @classmethod
def _storeSnapshot(cls, name): def _storePartitionSnapshot(cls, name):
# copy log files from standalone """Store snapshot of partitions.
for standalone_log in glob.glob(os.path.join(
cls._base_directory, 'var', 'log', '*')):
cls._copySnapshot(standalone_log, name)
This uses the definition from class attribute `_save_instance_file_pattern_list`
"""
# copy config and log files from partitions # copy config and log files from partitions
for (dirpath, dirnames, filenames) in os.walk(cls.slap.instance_directory): for (dirpath, dirnames, filenames) in os.walk(cls.slap.instance_directory):
for dirname in list(dirnames): for dirname in list(dirnames):
...@@ -416,8 +427,27 @@ class SlapOSInstanceTestCase(unittest.TestCase): ...@@ -416,8 +427,27 @@ class SlapOSInstanceTestCase(unittest.TestCase):
) for pattern in cls._save_instance_file_pattern_list): ) for pattern in cls._save_instance_file_pattern_list):
cls._copySnapshot(fileabspath, name) cls._copySnapshot(fileabspath, name)
@classmethod
def _storeSystemSnapshot(cls, name):
"""Store a snapshot of standalone slapos
Does not include software log, because this is stored at the end of software
installation and software log is large.
"""
# copy log files from standalone
for standalone_log in glob.glob(os.path.join(
cls._base_directory,
'var',
'log',
'*',
)):
if not standalone_log.startswith('slapos-node-software.log'):
cls._copySnapshot(standalone_log, name)
# store slapproxy database
cls._copySnapshot(cls.slap._proxy_database, name)
def tearDown(self): def tearDown(self):
self._storeSnapshot(self.id()) self._storePartitionSnapshot(self.id())
@classmethod @classmethod
def _copySnapshot(cls, source_file_name, name): def _copySnapshot(cls, source_file_name, name):
...@@ -459,18 +489,23 @@ class SlapOSInstanceTestCase(unittest.TestCase): ...@@ -459,18 +489,23 @@ class SlapOSInstanceTestCase(unittest.TestCase):
# implementation methods # implementation methods
@classmethod @classmethod
def _cleanup(cls): def _cleanup(cls, snapshot_name):
# type: (str) -> None
"""Destroy all instances and stop subsystem. """Destroy all instances and stop subsystem.
Catches and log all exceptions. Catches and log all exceptions and take snapshot named `snapshot_name` + the failing step.
""" """
try: try:
cls.requestDefaultInstance(state='destroyed') cls.requestDefaultInstance(state='destroyed')
except: except:
cls.logger.exception("Error during request destruction") cls.logger.exception("Error during request destruction")
cls._storeSystemSnapshot(
"{}._cleanup request destroy".format(snapshot_name))
try: try:
cls.slap.waitForReport(max_retry=cls.report_max_retry, debug=cls._debug) cls.slap.waitForReport(max_retry=cls.report_max_retry, debug=cls._debug)
except: except:
cls.logger.exception("Error during actual destruction") cls.logger.exception("Error during actual destruction")
cls._storeSystemSnapshot(
"{}._cleanup waitForReport".format(snapshot_name))
leaked_partitions = [ leaked_partitions = [
cp for cp in cls.slap.computer.getComputerPartitionList() cp for cp in cls.slap.computer.getComputerPartitionList()
if cp.getState() != 'destroyed' if cp.getState() != 'destroyed'
...@@ -479,6 +514,8 @@ class SlapOSInstanceTestCase(unittest.TestCase): ...@@ -479,6 +514,8 @@ class SlapOSInstanceTestCase(unittest.TestCase):
cls.logger.critical( cls.logger.critical(
"The following partitions were not cleaned up: %s", "The following partitions were not cleaned up: %s",
[cp.getId() for cp in leaked_partitions]) [cp.getId() for cp in leaked_partitions])
cls._storeSystemSnapshot(
"{}._cleanup leaked_partitions".format(snapshot_name))
for cp in leaked_partitions: for cp in leaked_partitions:
try: try:
cls.slap.request( cls.slap.request(
...@@ -490,14 +527,21 @@ class SlapOSInstanceTestCase(unittest.TestCase): ...@@ -490,14 +527,21 @@ class SlapOSInstanceTestCase(unittest.TestCase):
except: except:
cls.logger.exception( cls.logger.exception(
"Error during request destruction of leaked partition") "Error during request destruction of leaked partition")
cls._storeSystemSnapshot(
"{}._cleanup leaked_partitions request destruction".format(
snapshot_name))
try: try:
cls.slap.waitForReport(max_retry=cls.report_max_retry, debug=cls._debug) cls.slap.waitForReport(max_retry=cls.report_max_retry, debug=cls._debug)
except: except:
cls.logger.exception("Error during leaked partitions actual destruction") cls.logger.exception(
"Error during leaked partitions actual destruction")
cls._storeSystemSnapshot(
"{}._cleanup leaked_partitions waitForReport".format(snapshot_name))
try: try:
cls.slap.stop() cls.slap.stop()
except: except:
cls.logger.exception("Error during stop") cls.logger.exception("Error during stop")
cls._storeSystemSnapshot("{}._cleanup stop".format(snapshot_name))
leaked_supervisor_configs = glob.glob( leaked_supervisor_configs = glob.glob(
os.path.join(cls.slap.instance_directory, 'etc', 'supervisord.conf.d', '*.conf')) os.path.join(cls.slap.instance_directory, 'etc', 'supervisord.conf.d', '*.conf'))
if leaked_supervisor_configs: if leaked_supervisor_configs:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment