Commit 99c1d7ea authored by Alain Takoudjou's avatar Alain Takoudjou

slapgid.promise: add tests, fixup

parent 6e07cd0b
......@@ -107,12 +107,11 @@ class GenericPromise(object):
self.__log_folder = self.__config.pop('log-folder', None)
self.__partition_folder = self.__config.pop('partition-folder', None)
self.__check_anomaly = self.__config.pop('check-anomaly', False)
self.__periodicity = self.__config.pop('periodicity', 2)
self.__debug = self.__config.pop('debug', True)
self.__name = self.__config.pop('name', None)
self.__promise_path = self.__config.pop('path', None)
self.queue = self.__config.pop('queue', None)
self.__queue = self.__config.pop('queue', None)
self.__logger_buffer = None
self._validateConf()
......@@ -122,6 +121,8 @@ class GenericPromise(object):
def _configureLogger(self):
self.logger = logging.getLogger(self.__name)
for handler in self.logger.handlers:
self.logger.removeHandler(handler)
if self.__log_folder is None:
# configure logger with StringIO
import cStringIO
......@@ -143,7 +144,7 @@ class GenericPromise(object):
self.logger.addHandler(logger_handler)
def _validateConf(self):
if self.queue is None:
if self.__queue is None:
raise ValueError("Queue object is not set in configuration")
if self.__name is None:
raise ValueError("Monitor name is not set in configuration")
......@@ -153,8 +154,11 @@ class GenericPromise(object):
if self.__partition_folder is None:
raise ValueError("Monitor partition folder is not set in configuration")
def getConfig(self):
return self.__config
def getConfig(self, key, default=None):
return self.__config.get(key, default)
def setConfig(self, key, value):
self.__config[key] = value
def getTitle(self):
return self.__title
......@@ -271,7 +275,7 @@ class GenericPromise(object):
if line != "":
result = regex.match(line)
if result is not None:
if result.groups()[0] < date_string:
if result.groups()[0] <= date_string:
break
if not only_failure or \
(only_failure and result.groups()[1] == 'ERROR'):
......@@ -288,21 +292,13 @@ class GenericPromise(object):
line_list.reverse()
return line_list
def defaultTest(self, latest_minute=2, failure_amount=1, exact_match=True,
is_anomaly=False):
def defaultTest(self, latest_minute=2, failure_amount=1, is_anomaly=False):
"""
Test if the latest messages contain `failure_amount` failures.
@param latest_minute: test the result from now to the latest X minutes in
the past.
@param failure_amount: fail is this amount of failure is found in result
@param exact_match: bool (True|False).
True:
only fail if the number of failure found is equal to
`failure_amount`, exactly `failure_amount` promise result are tested
starting from the most recent .
False:
fail if at least one failure is found.
@param is_anomaly: Say if the result is an AnomalyResult of TestResult
"""
......@@ -315,19 +311,19 @@ class GenericPromise(object):
)
result_size = len(latest_result_list)
if result_size == 0:
return module(problem=False, message="No result!")
return module(problem=False, message="No result found!")
i = 0
failure_found = 0
latest_result_list.reverse()
# we test at most the `failure_amount` latest results
while i < result_size and i < failure_amount:
while i < result_size and failure_found < failure_amount:
if latest_result_list[i][1] == 'ERROR':
failure_found += 1
problem = True
i += 1
if exact_match and failure_found != failure_amount:
if failure_found != failure_amount:
return module(problem=False, message=latest_result_list[0][2])
return module(problem=problem, message=latest_result_list[0][2])
......@@ -354,7 +350,7 @@ class GenericPromise(object):
except Exception, e:
# log the result
self.logger.error(str(e))
if self.__check_anomaly:
if self.getConfig('check-anomaly', False):
# run sense, anomaly
try:
result = self.anomaly()
......@@ -362,8 +358,9 @@ class GenericPromise(object):
raise ValueError("Promise anomaly method returned 'None'")
except Exception, e:
result = AnomalyResult(problem=True, message=str(e))
if result.hasFailed() and can_bang:
self.__bang("Promise %s is failing" % self.__title)
else:
if result.hasFailed() and can_bang:
self.__bang("Promise %s is failing" % self.__title)
else:
# run sense, test
try:
......@@ -377,8 +374,7 @@ class GenericPromise(object):
self.__logger_buffer.close()
# send the result of this promise
# should not raise Queue.Full exception as limit is not set to constructor
self.queue.put(PromiseQueueResult(
self.__queue.put(PromiseQueueResult(
path=self.__promise_path,
name=self.__name,
title=self.__title,
......@@ -395,6 +391,7 @@ class PromiseWrapper(GenericPromise):
def __init__(self, config):
GenericPromise.__init__(self, config)
self.setConfig("check-anomaly", False)
self.setPeriodicity(minute=2)
@staticmethod
......@@ -550,11 +547,13 @@ class PromiseLauncher(object):
if logger is None:
self.logger = logging.getLogger(__name__)
self.logger.setLevel(logging.DEBUG if self.debug else logging.INFO)
handler = logging.StreamHandler()
handler.setFormatter(
logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
)
self.logger.addHandler(handler)
if len(self.logger.handlers) == 0 or \
not isinstance(self.logger.handlers[0], logging.StreamHandler):
handler = logging.StreamHandler()
handler.setFormatter(
logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
)
self.logger.addHandler(handler)
else:
self.logger = logger
......@@ -580,8 +579,7 @@ class PromiseLauncher(object):
try:
latest_timestamp = float(f.read())
current_timediff = (time.time() - latest_timestamp) / 60.0
margin_error = 0.15 # 0.15 seconds less is accepted
if current_timediff + margin_error >= periodicity:
if current_timediff >= periodicity:
return True
self.logger.debug("Skip Promise %r. periodicity=%s, time_diff=%s" % (
promise_name, periodicity, current_timediff))
......@@ -679,10 +677,10 @@ class PromiseLauncher(object):
# process is gone
pass
for current_increment in range(0, increment_limit):
execution_time = current_increment * sleep_time
execution_time = (current_increment + 1) * sleep_time
if not promise_process.is_alive():
try:
queue_item = self.queue_result.get(False, 2)
queue_item = self.queue_result.get(True, 1)
except Queue.Empty:
# no result found in process result Queue
if self.save_method is None:
......@@ -751,6 +749,7 @@ class PromiseLauncher(object):
'partition-folder': self.partition_folder,
'debug': self.debug,
'slapgrid-mode': self.slapgrid_mode,
'check-anomaly': self.check_anomaly,
'master-url': self.master_url,
'partition-cert': self.partition_cert,
'partition-key': self.partition_key,
......@@ -781,13 +780,20 @@ class PromiseLauncher(object):
promise_list.append((promise_name,
self._loadPromiseModule(promise_name)))
for promise in promise_list:
for name, module in promise_list:
promise_path = os.path.join(self.promise_folder, name)
config = {
'path': os.path.join(self.promise_folder, promise[0]),
'name': promise[0]
'path': promise_path,
'name': name
}
if module.__file__ != promise_path:
# cached module need to be updated
module = reload(module)
#if os.path.getmtime(promise_path) > os.path.getmtime('%sc' % promise_path):
# module = reload(module)
config.update(base_config)
self._launchPromise(promise_name, config, promise[1])
self._launchPromise(name, config, module)
if not self.run_only_promise_list and os.path.exists(self.old_promise_folder) \
and os.path.isdir(self.old_promise_folder):
......
##############################################################################
#
# Copyright (c) 2018 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import os, shutil
import tempfile
import unittest
import sys
import time
from datetime import datetime, timedelta
import Queue
from zope import interface as zope_interface
from slapos.grid.promise import interface
from slapos.grid.promise import (GenericPromise, TestResult, AnomalyResult,
PromiseQueueResult, PromiseLauncher,
PromiseError, PROMISE_STATE_FOLDER_NAME)
class TestSlapOSPromiseMixin(unittest.TestCase):
def setUp(self):
self.partition_dir = tempfile.mkdtemp()
self.plugin_dir = os.path.join(self.partition_dir, 'plugins')
self.old_promise_dir = os.path.join(self.partition_dir, 'promise')
self.log_dir = os.path.join(self.partition_dir, 'log')
os.mkdir(self.plugin_dir)
os.mkdir(self.log_dir)
os.mkdir(self.old_promise_dir)
self.partition_id = "slappart0"
self.computer_id = "COMP-1234"
def writeInit(self):
with open(os.path.join(self.plugin_dir, '__init__'), 'w') as f:
f.write('')
os.chmod(os.path.join(self.plugin_dir, '__init__'), 0644)
if sys.path[0] != self.plugin_dir:
sys.path[0:0] = [self.plugin_dir]
def tearDown(self):
if os.path.exists(self.partition_dir):
shutil.rmtree(self.partition_dir)
if sys.path[0] == self.plugin_dir:
del sys.path[0]
def configureLauncher(self, save_method=None, timeout=0.5, master_url="", debug=False,
run_list=[], uid=None, gid=None, run_as_slapgrid=False, enable_anomaly=False, force=False,
logdir=True):
parameter_dict = {
'promise-timeout': timeout,
'promise-folder': self.plugin_dir,
'old-promise-folder': self.old_promise_dir,
'log-folder': self.log_dir if logdir else None,
'partition-folder': self.partition_dir,
'master-url': master_url,
'partition-cert': "",
'partition-key': "",
'partition-id': self.partition_id,
'computer-id': self.computer_id,
'debug': debug,
'check-anomaly': enable_anomaly,
'force': force,
'run-only-promise-list': run_list,
'uid': uid,
'gid': gid,
'slapgrid-mode': run_as_slapgrid
}
self.launcher = PromiseLauncher(
config=parameter_dict,
logger=None,
save_method=save_method
)
def writeFile(self, path, content, mode=0644):
with open(path, 'w') as f:
f.write(content)
os.chmod(path, mode)
def generatePromiseScript(self, name, success=True, failure_count=1, content="",
periodicity=0.03):
promise_content = """from zope import interface as zope_interface
from slapos.grid.promise import interface
from slapos.grid.promise import GenericPromise
class RunPromise(GenericPromise):
zope_interface.implements(interface.IPromise)
def __init__(self, config):
GenericPromise.__init__(self, config)
self.setPeriodicity(minute=%(periodicity)s)
def sense(self):
%(content)s
if not %(success)s:
self.logger.error("failed")
else:
self.logger.info("success")
def anomaly(self):
return self.defaultTest(latest_minute=%(periodicity)s, failure_amount=%(failure_amount)s, is_anomaly=True)
def test(self):
return self.defaultTest(latest_minute=%(periodicity)s, failure_amount=%(failure_amount)s, is_anomaly=False)
""" % {'success': success, 'content': content, 'failure_amount': failure_count,
'periodicity': periodicity}
with open(os.path.join(self.plugin_dir, name), 'w') as f:
f.write(promise_content)
class TestSlapOSPromiseLauncher(TestSlapOSPromiseMixin):
def test_promise_match_interface(self):
promise_name = 'my_promise.py'
self.configureLauncher()
self.generatePromiseScript(promise_name)
self.writeInit()
promise_module = self.launcher._loadPromiseModule(promise_name)
def test_promise_match_interface_bad_name(self):
promise_name = 'my_promise_no_py'
self.configureLauncher()
self.generatePromiseScript(promise_name)
self.writeInit()
with self.assertRaises(ImportError):
promise_module = self.launcher._loadPromiseModule(promise_name)
def test_promise_match_interface_no_implement(self):
promise_name = 'my_promise_noimplement.py'
promise_content = """from slapos.grid.promise import GenericPromise
class RunPromise(GenericPromise):
def __init__(self, config):
GenericPromise.__init__(self, config)
def sense(self):
pass
"""
promise_path = os.path.join(self.plugin_dir, promise_name)
self.configureLauncher()
self.writeInit()
self.writeFile(promise_path, promise_content)
with self.assertRaises(RuntimeError):
promise_module = self.launcher._loadPromiseModule(promise_name)
def test_promise_match_interface_no_generic(self):
promise_name = 'my_promise_nogeneric.py'
promise_content = """from zope import interface as zope_interface
from slapos.grid.promise import interface
class RunPromise(object):
zope_interface.implements(interface.IPromise)
def __init__(self, config):
pass
def sense(self):
pass
"""
promise_path = os.path.join(self.plugin_dir, promise_name)
self.configureLauncher()
self.writeInit()
self.writeFile(promise_path, promise_content)
with self.assertRaises(RuntimeError):
promise_module = self.launcher._loadPromiseModule(promise_name)
def test_promise_match_interface_no_sense(self):
promise_name = 'my_promise_nosense.py'
promise_content = """from zope import interface as zope_interface
from slapos.grid.promise import interface
from slapos.grid.promise import GenericPromise
class RunPromise(GenericPromise):
zope_interface.implements(interface.IPromise)
def __init__(self, config):
pass
def noSenseMethod(self):
pass
"""
promise_path = os.path.join(self.plugin_dir, promise_name)
self.configureLauncher()
self.writeInit()
self.writeFile(promise_path, promise_content)
with self.assertRaises(TypeError):
promise_module = self.launcher._loadPromiseModule(promise_name)
promise = promise_module.RunPromise({})
def test_runpromise(self):
promise_name = 'my_promise.py'
self.configureLauncher()
self.generatePromiseScript(promise_name, success=True)
state_file = os.path.join(self.partition_dir, PROMISE_STATE_FOLDER_NAME)
# run promise will not fail
self.launcher.run()
self.assertTrue(os.path.exists(state_file))
self.assertTrue(os.path.exists(os.path.join(self.log_dir, 'my_promise.log')))
def test_runpromise_no_logdir(self):
promise_name = 'my_promise.py'
# no promise log output dir
self.configureLauncher(logdir=False)
self.generatePromiseScript(promise_name, success=True)
state_file = os.path.join(self.partition_dir, PROMISE_STATE_FOLDER_NAME)
# run promise will not failt
self.launcher.run()
self.assertTrue(os.path.exists(state_file))
self.assertFalse(os.path.exists(os.path.join(self.log_dir, 'my_promise.log')))
def test_runpromise_savemethod(self):
promise_name = 'my_promise.py'
def test_method(result):
self.assertTrue(isinstance(result, PromiseQueueResult))
self.assertTrue(isinstance(result.item, TestResult))
self.assertTrue(result.execution_time != 0)
self.assertEquals(result.title, 'my_promise')
self.assertEquals(result.name, promise_name)
self.assertEquals(result.path, os.path.join(self.plugin_dir, promise_name))
self.assertEquals(result.item.message, "success")
self.assertEquals(result.item.hasFailed(), False)
self.assertTrue(isinstance(result.item.date, datetime))
self.configureLauncher(save_method=test_method)
self.generatePromiseScript(promise_name, success=True)
state_file = os.path.join(self.partition_dir, PROMISE_STATE_FOLDER_NAME)
# run promise will not fail
self.launcher.run()
self.assertTrue(os.path.exists(state_file))
self.assertTrue(os.path.exists(os.path.join(self.log_dir, 'my_promise.log')))
def test_runpromise_savemethod_no_logdir(self):
promise_name = 'my_promise.py'
def test_method(result):
self.assertTrue(isinstance(result, PromiseQueueResult))
self.assertTrue(isinstance(result.item, TestResult))
self.assertTrue(result.execution_time != 0)
self.assertEquals(result.title, 'my_promise')
self.assertEquals(result.name, promise_name)
self.assertEquals(result.path, os.path.join(self.plugin_dir, promise_name))
self.assertEquals(result.item.message, "success")
self.assertEquals(result.item.hasFailed(), False)
self.assertTrue(isinstance(result.item.date, datetime))
# no promise log output dir
self.configureLauncher(logdir=False, save_method=test_method)
self.generatePromiseScript(promise_name, success=True)
state_file = os.path.join(self.partition_dir, PROMISE_STATE_FOLDER_NAME)
# run promise will not fail
self.launcher.run()
self.assertTrue(os.path.exists(state_file))
self.assertFalse(os.path.exists(os.path.join(self.log_dir, 'my_promise.log')))
def test_runpromise_savemethod_anomaly(self):
promise_name = 'my_promise.py'
def test_method(result):
self.assertTrue(isinstance(result, PromiseQueueResult))
self.assertTrue(isinstance(result.item, AnomalyResult))
self.assertTrue(result.execution_time != 0)
self.assertEquals(result.title, 'my_promise')
self.assertEquals(result.name, promise_name)
self.assertEquals(result.path, os.path.join(self.plugin_dir, promise_name))
self.assertEquals(result.item.message, "success")
self.assertEquals(result.item.hasFailed(), False)
self.assertTrue(isinstance(result.item.date, datetime))
self.configureLauncher(save_method=test_method, enable_anomaly=True)
self.generatePromiseScript(promise_name, success=True)
state_file = os.path.join(self.partition_dir, PROMISE_STATE_FOLDER_NAME)
# run promise will not fail
self.launcher.run()
self.assertTrue(os.path.exists(state_file))
self.assertTrue(os.path.exists(os.path.join(self.log_dir, 'my_promise.log')))
def test_runpromise_savemethod_multiple(self):
promise_name = 'my_promise.py'
promise_failed = 'my_failed_promise.py'
self.counter = 0
def test_method(result):
self.assertTrue(isinstance(result, PromiseQueueResult))
self.assertTrue(isinstance(result.item, TestResult))
self.assertTrue(result.name in [promise_failed, promise_name])
if result.name == promise_failed:
self.assertEquals(result.item.hasFailed(), True)
self.assertEquals(result.item.message, "failed")
else:
self.assertEquals(result.item.hasFailed(), False)
self.assertEquals(result.item.message, "success")
self.counter += 1
self.configureLauncher(save_method=test_method)
self.generatePromiseScript(promise_name, success=True)
self.generatePromiseScript(promise_failed, success=False)
state_file = os.path.join(self.partition_dir, PROMISE_STATE_FOLDER_NAME)
# run promise will not fail
self.launcher.run()
self.assertEquals(self.counter, 2)
self.assertTrue(os.path.exists(state_file))
self.assertTrue(os.path.exists(os.path.join(self.log_dir, 'my_promise.log')))
self.assertTrue(os.path.exists(os.path.join(self.log_dir, 'my_failed_promise.log')))
def test_runpromise_savemethod_multiple_success(self):
first_promise = 'my_first_promise.py'
second_promise = 'my_second_promise.py'
third_promise = 'my_third_promise.py'
self.counter = 0
def test_method(result):
self.assertTrue(isinstance(result, PromiseQueueResult))
self.assertTrue(isinstance(result.item, TestResult))
self.assertTrue(result.name in [first_promise, second_promise, third_promise])
self.assertEquals(result.item.hasFailed(), False)
self.assertEquals(result.item.message, "success")
self.counter += 1
self.configureLauncher(save_method=test_method)
self.generatePromiseScript(first_promise, success=True)
self.generatePromiseScript(second_promise, success=True)
self.generatePromiseScript(third_promise, success=True)
state_file = os.path.join(self.partition_dir, PROMISE_STATE_FOLDER_NAME)
# run promise will not fail
self.launcher.run()
self.assertEquals(self.counter, 3)
self.assertTrue(os.path.exists(state_file))
self.assertTrue(os.path.exists(os.path.join(self.log_dir, 'my_first_promise.log')))
self.assertTrue(os.path.exists(os.path.join(self.log_dir, 'my_second_promise.log')))
self.assertTrue(os.path.exists(os.path.join(self.log_dir, 'my_third_promise.log')))
def test_runpromise_no_savemethod_and_raise(self):
first_promise = 'my_first_promise.py'
second_promise = 'my_second_promise.py'
self.configureLauncher()
self.generatePromiseScript(first_promise, success=True)
self.generatePromiseScript(second_promise, success=False)
state_file = os.path.join(self.partition_dir, PROMISE_STATE_FOLDER_NAME)
# run promise will fail when promise fail (usefull for slapgrid)
with self.assertRaises(PromiseError) as exc:
self.launcher.run()
self.assertEquals(exc.exception.message, 'failed')
def test_runpromise_fail_and_success(self):
first_promise = 'my_first_promise.py'
second_promise = 'my_second_promise.py'
self.configureLauncher()
self.generatePromiseScript(first_promise, success=True)
self.generatePromiseScript(second_promise, success=False)
# run promise will fail when promise fail (usefull for slapgrid)
with self.assertRaises(PromiseError) as exc:
self.launcher.run()
self.assertEquals(exc.exception.message, 'failed')
if "my_second_promise" in sys.modules:
# force to reload the module without rerun python
os.system('rm %s/*.pyc' % self.plugin_dir)
del sys.modules["my_second_promise"]
self.generatePromiseScript(second_promise, success=True)
# wait next periodicity
time.sleep(2)
self.launcher.run()
log_file = os.path.join(self.log_dir, 'my_second_promise.log')
self.assertTrue(os.path.exists(log_file))
with open(log_file) as f:
line = f.readline()
self.assertTrue('failed' in line, line)
line = f.readline()
self.assertTrue('success' in line, line)
def test_runpromise_with_periodicity(self):
first_promise = 'my_first_promise.py'
second_promise = 'my_second_promise.py'
self.counter = 0
def test_method_first(result):
self.assertTrue(result.name in [first_promise, second_promise])
self.assertEquals(result.item.hasFailed(), False)
self.assertEquals(result.item.message, "success")
self.counter += 1
def test_method_one(result):
self.counter += 1
self.assertEquals(result.name, first_promise)
self.assertEquals(result.item.hasFailed(), False)
self.assertEquals(result.item.message, "success")
self.configureLauncher(save_method=test_method_first)
# ~2 seconds
self.generatePromiseScript(first_promise, success=True, periodicity=0.03)
# ~3 seconds
self.generatePromiseScript(second_promise, success=True, periodicity=0.05)
self.launcher.run()
self.assertEquals(self.counter, 2)
self.configureLauncher(save_method=test_method_one)
time.sleep(2)
self.counter = 0
self.launcher.run() # only my_first_promise will run
self.assertEquals(self.counter, 1)
time.sleep(3)
self.counter = 0
self.configureLauncher(save_method=test_method_first)
self.launcher.run()
self.assertEquals(self.counter, 2)
def test_runpromise_with_periodicity_same(self):
first_promise = 'my_first_promise.py'
second_promise = 'my_second_promise.py'
self.counter = 0
def test_method(result):
self.assertTrue(result.name in [first_promise, second_promise])
self.assertEquals(result.item.hasFailed(), False)
self.assertEquals(result.item.message, "success")
self.counter += 1
self.configureLauncher(save_method=test_method)
# ~2 seconds
self.generatePromiseScript(first_promise, success=True, periodicity=0.03)
self.generatePromiseScript(second_promise, success=True, periodicity=0.03)
self.launcher.run()
self.assertEquals(self.counter, 2)
self.configureLauncher(save_method=test_method)
time.sleep(1)
self.counter = 0
self.launcher.run() # run nothing
self.assertEquals(self.counter, 0)
time.sleep(1)
self.counter = 0
self.configureLauncher(save_method=test_method)
self.launcher.run()
self.assertEquals(self.counter, 2)
def test_runpromise_force(self):
first_promise = 'my_first_promise.py'
second_promise = 'my_second_promise.py'
self.counter = 0
def test_method(result):
self.assertTrue(result.name in [first_promise, second_promise])
self.assertEquals(result.item.hasFailed(), False)
self.assertEquals(result.item.message, "success")
self.counter += 1
self.configureLauncher(save_method=test_method)
# ~2 seconds
self.generatePromiseScript(first_promise, success=True, periodicity=0.03)
self.generatePromiseScript(second_promise, success=True, periodicity=0.03)
self.launcher.run()
self.assertEquals(self.counter, 2)
self.configureLauncher(save_method=test_method)
time.sleep(1)
self.counter = 0
self.launcher.run() # run nothing
self.assertEquals(self.counter, 0)
self.configureLauncher(save_method=test_method, force=True)
self.counter = 0
self.launcher.run() # will run all as force is True
self.assertEquals(self.counter, 2)
self.configureLauncher(save_method=test_method)
time.sleep(1)
self.counter = 0
self.launcher.run() # run nothing
self.assertEquals(self.counter, 0)
time.sleep(1)
self.counter = 0
self.configureLauncher(save_method=test_method)
self.launcher.run() # after 2 seconds will run all
self.assertEquals(self.counter, 2)
def test_runpromise_wrapped(self):
promise_name = "my_bash_promise"
promise_path = os.path.join(self.old_promise_dir, promise_name)
self.called = False
with open(promise_path, 'w') as f:
f.write("""#!/bin/bash
echo "success"
""")
os.chmod(promise_path, 0744)
def test_method(result):
self.called = True
self.assertTrue(isinstance(result, PromiseQueueResult))
self.assertTrue(isinstance(result.item, TestResult))
self.assertTrue(result.execution_time != 0)
self.assertEquals(result.title, promise_name)
self.assertEquals(result.name, promise_name)
self.assertEquals(result.path, os.path.join(self.old_promise_dir, promise_name))
self.assertEquals(result.item.message, "success")
self.assertEquals(result.item.hasFailed(), False)
self.assertTrue(isinstance(result.item.date, datetime))
self.configureLauncher(save_method=test_method)
state_file = os.path.join(self.partition_dir, PROMISE_STATE_FOLDER_NAME)
self.launcher.run()
self.assertTrue(self.called)
self.assertTrue(os.path.exists(state_file))
def test_runpromise_wrapped_failed(self):
promise_name = "my_bash_promise"
promise_path = os.path.join(self.old_promise_dir, promise_name)
with open(promise_path, 'w') as f:
f.write("""#!/bin/bash
echo "This promise failed"
exit 1
""")
os.chmod(promise_path, 0744)
self.configureLauncher()
state_file = os.path.join(self.partition_dir, PROMISE_STATE_FOLDER_NAME)
with self.assertRaises(PromiseError) as exc:
self.launcher.run()
self.assertEquals(exc.exception.message, 'This promise failed')
def test_runpromise_wrapped_mixed(self):
self.called = 0
result_dict = {"my_bash_promise": "", "my_bash_promise2": "", "first_promise.py": "", "second_promise.py": ""}
def test_method(result):
self.called += 1
result_dict.pop(result.name)
if result.title == "first_promise" or result.title == "second_promise":
self.assertEquals(result.item.message, "success")
if result.title == "my_bash_promise":
self.assertEquals(result.item.message, "promise 1 succeeded")
if result.title == "my_bash_promise2":
self.assertEquals(result.item.message, "promise 2 succeeded")
self.assertEquals(result.item.hasFailed(), False)
promise_name = "my_bash_promise"
promise_path = os.path.join(self.old_promise_dir, promise_name)
promise_name2 = "my_bash_promise2"
promise_path2 = os.path.join(self.old_promise_dir, promise_name2)
with open(promise_path, 'w') as f:
f.write("""#!/bin/bash
echo "promise 1 succeeded"
exit 0
""")
os.chmod(promise_path, 0744)
with open(promise_path2, 'w') as f:
f.write("""#!/bin/bash
echo "promise 2 succeeded"
exit 0
""")
os.chmod(promise_path2, 0744)
self.generatePromiseScript("first_promise.py", success=True)
self.generatePromiseScript("second_promise.py", success=True)
self.configureLauncher(save_method=test_method)
self.launcher.run()
self.assertEquals(self.called, 4)
def test_runpromise_run_only(self):
first_promise = 'my_first_promise.py'
second_promise = 'my_second_promise.py'
third_promise = 'my_third_promise.py'
self.counter = 0
self.check_list = [first_promise, second_promise, third_promise]
def test_method(result):
self.assertTrue(result.name in self.check_list)
self.assertEquals(result.item.hasFailed(), False)
self.assertEquals(result.item.message, "success")
self.counter += 1
self.configureLauncher(save_method=test_method)
self.generatePromiseScript(first_promise, success=True)
self.generatePromiseScript(second_promise, success=True)
self.generatePromiseScript(third_promise, success=True)
# run promise will not fail
self.launcher.run()
self.assertEquals(self.counter, 3)
self.counter = 0
self.check_list = [second_promise]
self.configureLauncher(save_method=test_method, run_list=[second_promise], force=True)
self.launcher.run()
self.assertEquals(self.counter, 1)
def test_runpromise_run_only_multiple(self):
first_promise = 'my_first_promise.py'
second_promise = 'my_second_promise.py'
third_promise = 'my_third_promise.py'
self.counter = 0
self.check_list = [first_promise, second_promise, third_promise]
def test_method(result):
self.assertTrue(result.name in self.check_list)
self.assertEquals(result.item.hasFailed(), False)
self.assertEquals(result.item.message, "success")
self.counter += 1
self.configureLauncher(save_method=test_method)
self.generatePromiseScript(first_promise, success=True)
self.generatePromiseScript(second_promise, success=True)
self.generatePromiseScript(third_promise, success=True)
# run promise will not fail
self.launcher.run()
self.assertEquals(self.counter, 3)
self.counter = 0
self.check_list = [third_promise, second_promise]
self.configureLauncher(save_method=test_method, run_list=self.check_list, force=True)
self.launcher.run()
self.assertEquals(self.counter, 2)
def test_runpromise_will_timeout(self):
self.called = False
promise_name = 'my_promise.py'
def test_method(result):
self.called = True
self.assertTrue(isinstance(result, PromiseQueueResult))
self.assertTrue(isinstance(result.item, AnomalyResult))
self.assertTrue(result.execution_time >= 1)
self.assertEquals(result.title, 'my_promise')
self.assertEquals(result.name, promise_name)
self.assertTrue("Promise timed out after" in result.item.message)
self.assertEquals(result.item.hasFailed(), True)
self.configureLauncher(save_method=test_method, enable_anomaly=True, timeout=1)
self.generatePromiseScript(promise_name, success=True, content="""import time
time.sleep(5)""")
# run promise will timeout
self.launcher.run()
self.assertTrue(self.called)
class TestSlapOSGenericPromise(TestSlapOSPromiseMixin):
def initialisePromise(self, promise_content="", success=True):
self.promise_name = 'my_promise.py'
self.promise_path = os.path.join(self.plugin_dir, self.promise_name)
self.configureLauncher()
self.generatePromiseScript(self.promise_name, periodicity=1, content=promise_content, success=success)
self.writeInit()
self.queue = Queue.Queue()
self.promise_config = {
'log-folder': self.log_dir,
'partition-folder': self.partition_dir,
'debug': False,
'slapgrid-mode': False,
'check-anomaly': True,
'master-url': "https://master.url.com",
'partition-cert': '',
'partition-key': '',
'partition-id': self.partition_id,
'computer-id': self.computer_id,
'queue': self.queue,
'path': self.promise_path,
'name': self.promise_name
}
def test_create_simple_promise(self):
self.initialisePromise()
promise_module = self.launcher._loadPromiseModule(self.promise_name)
reload(promise_module)
promise = promise_module.RunPromise(self.promise_config)
self.assertEquals(promise.getPeriodicity(), 1)
self.assertEquals(promise.getName(), self.promise_name)
self.assertEquals(promise.getTitle(), 'my_promise')
self.assertEquals(promise.getPartitionFolder(), self.partition_dir)
self.assertEquals(promise.getPromiseFile(), self.promise_path)
self.assertEquals(promise.getLogFolder(), self.log_dir)
self.assertEquals(promise.getLogFile(), os.path.join(self.log_dir, 'my_promise.log'))
promise.setPeriodicity(2)
self.assertEquals(promise.getPeriodicity(), 2)
with self.assertRaises(ValueError):
promise.setPeriodicity(0)
promise.run()
result = self.queue.get(True, 1)
self.assertTrue(isinstance(result, PromiseQueueResult))
self.assertTrue(isinstance(result.item, AnomalyResult))
self.assertEquals(result.title, 'my_promise')
self.assertEquals(result.name, self.promise_name)
self.assertEquals(result.path, os.path.join(self.plugin_dir, self.promise_name))
self.assertEquals(result.item.message, "success")
self.assertEquals(result.item.hasFailed(), False)
self.assertTrue(isinstance(result.item.date, datetime))
def test_promise_anomaly_disabled(self):
self.initialisePromise()
promise_module = self.launcher._loadPromiseModule(self.promise_name)
reload(promise_module)
promise = promise_module.RunPromise(self.promise_config)
# disable anomaly call, enable test call
promise.setConfig("check-anomaly", False)
promise.run()
result = self.queue.get(True, 1)
self.assertTrue(isinstance(result, PromiseQueueResult))
self.assertTrue(isinstance(result.item, TestResult))
self.assertEquals(result.title, 'my_promise')
self.assertEquals(result.name, self.promise_name)
self.assertEquals(result.path, os.path.join(self.plugin_dir, self.promise_name))
self.assertEquals(result.item.message, "success")
self.assertEquals(result.item.hasFailed(), False)
self.assertTrue(isinstance(result.item.date, datetime))
def test_promise_with_raise(self):
promise_content = "raise ValueError('Bad Promise raised')"
self.initialisePromise(promise_content)
promise_module = self.launcher._loadPromiseModule(self.promise_name)
reload(promise_module)
promise = promise_module.RunPromise(self.promise_config)
# no raise
promise.run()
result = self.queue.get(True, 1)
self.assertEquals(result.title, 'my_promise')
self.assertEquals(result.name, self.promise_name)
self.assertEquals(result.item.message, "Bad Promise raised")
self.assertEquals(result.item.hasFailed(), True)
def test_promise_no_return(self):
promise_content = "return"
self.initialisePromise(promise_content)
promise_module = self.launcher._loadPromiseModule(self.promise_name)
reload(promise_module)
promise = promise_module.RunPromise(self.promise_config)
# no raise
promise.run()
result = self.queue.get(True, 1)
self.assertEquals(result.title, 'my_promise')
self.assertEquals(result.name, self.promise_name)
self.assertEquals(result.item.message, "No result found!")
self.assertEquals(result.item.hasFailed(), False)
def test_promise_resultfromlog(self):
promise_content = "self.logger.info('Promise is running...')"
self.initialisePromise(promise_content)
promise_module = self.launcher._loadPromiseModule(self.promise_name)
reload(promise_module)
promise = promise_module.RunPromise(self.promise_config)
date = datetime.now()
promise.sense()
# get all messages during the latest minute
latest_message_list = promise.getLastPromiseResultList(latest_minute=1)
date_string = date.strftime('%Y-%m-%d %H:%M:%S')
self.assertEquals(len(latest_message_list), 2)
self.assertEquals(latest_message_list[0], [date_string, 'INFO', 'Promise is running...'])
self.assertEquals(latest_message_list[1], [date_string, 'INFO', 'success'])
def test_promise_resultfromlog_error(self):
promise_content = 'self.logger.error("Promise is running...\\nmessage in new line")'
self.initialisePromise(promise_content)
promise_module = self.launcher._loadPromiseModule(self.promise_name)
reload(promise_module)
promise = promise_module.RunPromise(self.promise_config)
date = datetime.now()
promise.sense()
# get all messages during the latest minute
latest_message_list = promise.getLastPromiseResultList(latest_minute=1)
date_string = date.strftime('%Y-%m-%d %H:%M:%S')
self.assertEquals(len(latest_message_list), 2)
self.assertEquals(latest_message_list[0], [date_string, 'ERROR', 'Promise is running...\nmessage in new line'])
self.assertEquals(latest_message_list[1], [date_string, 'INFO', 'success'])
def test_promise_resultfromlog_no_logfolder(self):
self.log_dir = None
promise_content = "self.logger.info('Promise is running...')"
self.initialisePromise(promise_content)
promise_module = self.launcher._loadPromiseModule(self.promise_name)
reload(promise_module)
promise = promise_module.RunPromise(self.promise_config)
date = datetime.now()
promise.sense()
self.assertEquals(promise.getLogFolder(), None)
self.assertEquals(promise.getLogFile(), None)
# get all messages during the latest minute
latest_message_list = promise.getLastPromiseResultList(latest_minute=1)
date_string = date.strftime('%Y-%m-%d %H:%M:%S')
self.assertEquals(len(latest_message_list), 2)
self.assertEquals(latest_message_list[0], [date_string, 'INFO', 'Promise is running...'])
self.assertEquals(latest_message_list[1], [date_string, 'INFO', 'success'])
def test_promise_resultfromlog_older_log(self):
self.initialisePromise()
promise_module = self.launcher._loadPromiseModule(self.promise_name)
reload(promise_module)
promise = promise_module.RunPromise(self.promise_config)
# write some random logs
start_date = datetime.now()
with open(promise.getLogFile(), 'w') as f:
for i in range(0, 50):
date = start_date - timedelta(minutes=(49 - i))
date_string = date.strftime('%Y-%m-%d %H:%M:%S')
line = "%s - INFO - Promise result %s\n" % (date_string, i)
f.write(line)
#promise.sense()
latest_message_list = promise.getLastPromiseResultList(latest_minute=10)
start_date_string = start_date.strftime('%Y-%m-%d %H:%M:%S')
end_date_string = (start_date - timedelta(minutes=9)).strftime('%Y-%m-%d %H:%M:%S')
self.assertEquals(len(latest_message_list), 10)
self.assertEquals(latest_message_list[-1], [start_date_string, 'INFO', 'Promise result 49'])
self.assertEquals(latest_message_list[0], [end_date_string, 'INFO', 'Promise result 40'])
def test_promise_resultfromlog_older_log_more(self):
self.initialisePromise()
promise_module = self.launcher._loadPromiseModule(self.promise_name)
reload(promise_module)
promise = promise_module.RunPromise(self.promise_config)
# write some random logs
start_date = datetime.now()
date = start_date
line_list = []
for i in range(0, 50):
date_string = date.strftime('%Y-%m-%d %H:%M:%S')
line_list.append("%s - INFO - Promise result %s" % (date_string, i))
date = date - timedelta(seconds=30)
line_list.reverse()
with open(promise.getLogFile(), 'w') as f:
f.write('\n'.join(line_list))
#promise.sense()
latest_message_list = promise.getLastPromiseResultList(latest_minute=10)
start_date_string = start_date.strftime('%Y-%m-%d %H:%M:%S')
end_date_string = (start_date - timedelta(seconds=30*19)).strftime('%Y-%m-%d %H:%M:%S')
# there is 2 result line per minutes
self.assertEquals(len(latest_message_list), 20)
self.assertEquals(latest_message_list[-1], [start_date_string, 'INFO', 'Promise result 0'])
self.assertEquals(latest_message_list[0], [end_date_string, 'INFO', 'Promise result 19'])
def test_promise_defaulttest(self):
promise_content = 'self.logger.info("Promise is running...\\nmessage in new line")'
self.initialisePromise(promise_content)
promise_module = self.launcher._loadPromiseModule(self.promise_name)
reload(promise_module)
promise = promise_module.RunPromise(self.promise_config)
promise.sense()
result = promise.defaultTest(latest_minute=1, failure_amount=1)
self.assertTrue(isinstance(result, TestResult))
self.assertEquals(result.message, 'success')
self.assertEquals(result.hasFailed(), False)
def test_promise_defaulttest_failure(self):
self.initialisePromise(success=False)
promise_module = self.launcher._loadPromiseModule(self.promise_name)
reload(promise_module)
promise = promise_module.RunPromise(self.promise_config)
promise.sense()
result = promise.defaultTest(latest_minute=1, failure_amount=1)
self.assertTrue(isinstance(result, TestResult))
self.assertEquals(result.message, 'failed')
self.assertEquals(result.hasFailed(), True)
def test_promise_defaulttest_error_if_two_fail(self):
self.initialisePromise(success=False)
promise_module = self.launcher._loadPromiseModule(self.promise_name)
reload(promise_module)
promise = promise_module.RunPromise(self.promise_config)
promise.sense()
# fail if 2 errors found
result = promise.defaultTest(latest_minute=1, failure_amount=2)
self.assertTrue(isinstance(result, TestResult))
self.assertEquals(result.message, 'failed')
self.assertEquals(result.hasFailed(), False)
promise.sense()
result = promise.defaultTest(latest_minute=1, failure_amount=2)
self.assertEquals(result.message, 'failed')
self.assertEquals(result.hasFailed(), True)
# will continue to fail
promise.sense()
result = promise.defaultTest(latest_minute=1, failure_amount=2)
self.assertEquals(result.message, 'failed')
self.assertEquals(result.hasFailed(), True)
def test_promise_defaulttest_anomaly(self):
promise_content = 'self.logger.info("Promise is running...\\nmessage in new line")'
self.initialisePromise(promise_content)
promise_module = self.launcher._loadPromiseModule(self.promise_name)
reload(promise_module)
promise = promise_module.RunPromise(self.promise_config)
promise.sense()
result = promise.defaultTest(latest_minute=1, failure_amount=1, is_anomaly=True)
self.assertTrue(isinstance(result, AnomalyResult))
self.assertEquals(result.message, 'success')
self.assertEquals(result.hasFailed(), False)
if __name__ == '__main__':
unittest.main()
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