Commit 0e502ce9 authored by Rafael Monnerat's avatar Rafael Monnerat

slapos/grid/promise: Extend promise system to generate history and stats

   This is a port of the code from slapos.toolbox for future
   replacement.
parent ca456d3c
...@@ -38,15 +38,18 @@ import importlib ...@@ -38,15 +38,18 @@ import importlib
import traceback import traceback
import psutil import psutil
import inspect import inspect
import hashlib
from datetime import datetime
from multiprocessing import Process, Queue as MQueue from multiprocessing import Process, Queue as MQueue
from six.moves import queue, reload_module from six.moves import queue, reload_module
from slapos.util import mkdir_p, chownDirectory from slapos.util import str2bytes, mkdir_p, chownDirectory
from slapos.grid.utils import dropPrivileges, killProcessTree from slapos.grid.utils import dropPrivileges, killProcessTree
from slapos.grid.promise import interface from slapos.grid.promise import interface
from slapos.grid.promise.generic import (GenericPromise, PromiseQueueResult, from slapos.grid.promise.generic import (GenericPromise, PromiseQueueResult,
AnomalyResult, TestResult, AnomalyResult, TestResult,
PROMISE_STATE_FOLDER_NAME, PROMISE_STATE_FOLDER_NAME,
PROMISE_RESULT_FOLDER_NAME, PROMISE_RESULT_FOLDER_NAME,
PROMISE_HISTORY_RESULT_FOLDER_NAME,
PROMISE_PARAMETER_NAME) PROMISE_PARAMETER_NAME)
from slapos.grid.promise.wrapper import WrapPromise from slapos.grid.promise.wrapper import WrapPromise
from slapos.version import version from slapos.version import version
...@@ -342,6 +345,14 @@ class PromiseLauncher(object): ...@@ -342,6 +345,14 @@ class PromiseLauncher(object):
mkdir_p(self.promise_output_dir) mkdir_p(self.promise_output_dir)
self._updateFolderOwner() self._updateFolderOwner()
self.promise_history_output_dir = os.path.join(
self.partition_folder,
PROMISE_HISTORY_RESULT_FOLDER_NAME
)
if not os.path.exists(self.promise_history_output_dir):
mkdir_p(self.promise_history_output_dir)
self._updateFolderOwner()
def _generatePromiseResult(self, promise_process, promise_name, promise_path, def _generatePromiseResult(self, promise_process, promise_name, promise_path,
message, execution_time=0): message, execution_time=0):
if self.check_anomaly: if self.check_anomaly:
...@@ -378,6 +389,81 @@ class PromiseLauncher(object): ...@@ -378,6 +389,81 @@ class PromiseLauncher(object):
json.dump(result.serialize(), outputfile) json.dump(result.serialize(), outputfile)
os.rename(promise_tmp_file, promise_output_file) os.rename(promise_tmp_file, promise_output_file)
def _savePromiseHistoryResult(self, result):
state_dict = result.serialize()
previous_state_dict = {}
promise_status_file = os.path.join(PROMISE_STATE_FOLDER_NAME,
'promise_status.json')
if os.path.exists(promise_status_file):
with open(promise_status_file) as f:
try:
previous_state_dict = json.load(f)
except ValueError:
pass
history_file = os.path.join(
self.promise_history_output_dir,
'%s.history.json' % result.title
)
# Remove useless informations
result_dict = state_dict.pop('result')
result_dict["change-date"] = result_dict["date"]
state_dict.update(result_dict)
state_dict.pop('path', '')
state_dict.pop('type', '')
state_dict["status"] = "ERROR" if result.item.hasFailed() else "OK"
if not os.path.exists(history_file) or not os.stat(history_file).st_size:
with open(history_file, 'w') as f:
data_dict = {
"date": time.time(),
"data": [state_dict]
}
json.dump(data_dict, f)
else:
previous_state_list = previous_state_dict.get(result.name, None)
if previous_state_list is not None:
_, change_date, checksum = previous_state_list
current_sum = hashlib.md5(str2bytes(state_dict.get('message', ''))).hexdigest()
if state_dict['change-date'] == change_date and \
current_sum == checksum:
# Only save the changes and not the same info
return
state_dict.pop('title', '')
state_dict.pop('name', '')
with open (history_file, mode="r+") as f:
f.seek(0,2)
f.seek(f.tell() -2)
f.write('%s}' % ',{}]'.format(json.dumps(state_dict)))
def _saveStatisticsData(self, stat_file_path, date, success, error):
# csv-like document for success/error statictics
if not os.path.exists(stat_file_path) or os.stat(stat_file_path).st_size == 0:
with open(stat_file_path, 'w') as fstat:
data_dict = {
"date": time.time(),
"data": ["Date, Success, Error, Warning"]
}
fstat.write(json.dumps(data_dict))
current_state = '%s, %s, %s, %s' % (
date,
success,
error,
'')
# append to file
# XXX this is bad, it is getting everywhere.
if current_state:
with open (stat_file_path, mode="r+") as fstat:
fstat.seek(0,2)
position = fstat.tell() -2
fstat.seek(position)
fstat.write('%s}' % ',"{}"]'.format(current_state))
def _loadPromiseResult(self, promise_title): def _loadPromiseResult(self, promise_title):
promise_output_file = os.path.join( promise_output_file = os.path.join(
self.promise_output_dir, self.promise_output_dir,
...@@ -409,6 +495,7 @@ class PromiseLauncher(object): ...@@ -409,6 +495,7 @@ class PromiseLauncher(object):
self.bang_called = True self.bang_called = True
# Send result # Send result
self._savePromiseResult(result_item) self._savePromiseResult(result_item)
self._savePromiseHistoryResult(result_item)
def _emptyQueue(self): def _emptyQueue(self):
"""Remove all entries from queue until it's empty""" """Remove all entries from queue until it's empty"""
...@@ -565,6 +652,29 @@ class PromiseLauncher(object): ...@@ -565,6 +652,29 @@ class PromiseLauncher(object):
promise_list = [] promise_list = []
failed_promise_name = "" failed_promise_name = ""
failed_promise_output = "" failed_promise_output = ""
previous_state_dict = {}
new_state_dict = {}
report_date = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S+0000')
promise_status_file = os.path.join(self.partition_folder,
PROMISE_STATE_FOLDER_NAME,
'promise_status.json')
promise_result_file = os.path.join(self.partition_folder,
PROMISE_STATE_FOLDER_NAME,
'promise_result.json')
promise_stats_file = os.path.join(self.partition_folder,
PROMISE_STATE_FOLDER_NAME,
'promise_stats.json')
if os.path.exists(promise_status_file):
with open(promise_status_file) as f:
try:
previous_state_dict = json.load(f)
except ValueError:
pass
new_state_dict = previous_state_dict.copy()
base_config = { base_config = {
'log-folder': self.log_folder, 'log-folder': self.log_folder,
'partition-folder': self.partition_folder, 'partition-folder': self.partition_folder,
...@@ -578,7 +688,8 @@ class PromiseLauncher(object): ...@@ -578,7 +688,8 @@ class PromiseLauncher(object):
'queue': self.queue_result, 'queue': self.queue_result,
'slapgrid-version': version, 'slapgrid-version': version,
} }
error = 0
success = 0
if os.path.exists(self.promise_folder) and os.path.isdir(self.promise_folder): if os.path.exists(self.promise_folder) and os.path.isdir(self.promise_folder):
for promise_name in os.listdir(self.promise_folder): for promise_name in os.listdir(self.promise_folder):
if promise_name.startswith('__init__') or \ if promise_name.startswith('__init__') or \
...@@ -597,9 +708,36 @@ class PromiseLauncher(object): ...@@ -597,9 +708,36 @@ class PromiseLauncher(object):
config.update(base_config) config.update(base_config)
promise_result = self._launchPromise(promise_name, promise_path, config) promise_result = self._launchPromise(promise_name, promise_path, config)
if promise_result and promise_result.hasFailed() and not failed_promise_name: if promise_result:
failed_promise_name = promise_name change_date = promise_result.date.strftime('%Y-%m-%dT%H:%M:%S+0000')
failed_promise_output = promise_result.message if promise_result.hasFailed():
promise_status = 'FAILED'
error += 1
else:
promise_status = "OK"
success += 1
if promise_name in previous_state_dict:
status, previous_change_date, _ = previous_state_dict[promise_name]
if promise_status == status:
change_date = previous_change_date
message = promise_result.message if promise_result.message else ""
new_state_dict[promise_name] = [
promise_status,
change_date,
hashlib.md5(str2bytes(message)).hexdigest()]
if promise_result.hasFailed() and not failed_promise_name:
failed_promise_name = promise_name
failed_promise_output = promise_result.message
else:
# The promise was skip, so for statistic point of view we preserve
# the previous result
if promise_name in new_state_dict:
if new_state_dict[promise_name][0] == "FAILED":
error += 1
else:
success += 1
if not self.run_only_promise_list and os.path.exists(self.legacy_promise_folder) \ if not self.run_only_promise_list and os.path.exists(self.legacy_promise_folder) \
and os.path.isdir(self.legacy_promise_folder): and os.path.isdir(self.legacy_promise_folder):
...@@ -621,11 +759,46 @@ class PromiseLauncher(object): ...@@ -621,11 +759,46 @@ class PromiseLauncher(object):
promise_path, promise_path,
config, config,
wrap_process=True) wrap_process=True)
if promise_result and promise_result.hasFailed() and not failed_promise_name: if promise_result:
failed_promise_name = promise_name change_date = promise_result.date.strftime('%Y-%m-%dT%H:%M:%S+0000')
failed_promise_output = promise_result.message if promise_result.hasFailed():
promise_status = 'FAILED'
error += 1
else:
promise_status = "OK"
success += 1
if promise_name in previous_state_dict:
status, previous_change_date, _ = previous_state_dict[promise_name]
if promise_status == status:
change_date = previous_change_date
message = promise_result.message if promise_result.message else ""
new_state_dict[promise_name] = [
promise_status,
change_date,
hashlib.md5(str2bytes(message)).hexdigest()]
if promise_result.hasFailed() and not failed_promise_name:
failed_promise_name = promise_name
failed_promise_output = promise_result.message
else:
# The promise was skip, so for statistic point of view we preserve
# the previous result
if promise_name in new_state_dict:
if new_state_dict[promise_name][0] == "FAILED":
error += 1
else:
success += 1
self._updateFolderOwner(self.promise_output_dir) self._updateFolderOwner(self.promise_output_dir)
# Save Global State
with open(promise_status_file, "w") as f:
json.dump(new_state_dict, f)
self._saveStatisticsData(promise_stats_file,
report_date, success, error)
if self._skipped_amount > 0: if self._skipped_amount > 0:
self.logger.info("%s promises didn't need to be checked." % \ self.logger.info("%s promises didn't need to be checked." % \
self._skipped_amount) self._skipped_amount)
...@@ -633,3 +806,4 @@ class PromiseLauncher(object): ...@@ -633,3 +806,4 @@ class PromiseLauncher(object):
raise PromiseError("Promise %r failed with output: %s" % ( raise PromiseError("Promise %r failed with output: %s" % (
failed_promise_name, failed_promise_name,
failed_promise_output)) failed_promise_output))
...@@ -44,7 +44,7 @@ from datetime import datetime, timedelta ...@@ -44,7 +44,7 @@ from datetime import datetime, timedelta
PROMISE_STATE_FOLDER_NAME = '.slapgrid/promise' PROMISE_STATE_FOLDER_NAME = '.slapgrid/promise'
PROMISE_RESULT_FOLDER_NAME = '.slapgrid/promise/result' PROMISE_RESULT_FOLDER_NAME = '.slapgrid/promise/result'
PROMISE_LOG_FOLDER_NAME = '.slapgrid/promise/log' PROMISE_LOG_FOLDER_NAME = '.slapgrid/promise/log'
PROMISE_HISTORY_RESULT_FOLDER_NAME = '.slapgrid/promise/history'
PROMISE_PARAMETER_NAME = 'extra_config_dict' PROMISE_PARAMETER_NAME = 'extra_config_dict'
LOGLINE_RE = r"(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})\s+\-?\s*(\w+)\s+\-?\s+(\d+\-\d{3})\s+\-?\s*(.*)" LOGLINE_RE = r"(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})\s+\-?\s*(\w+)\s+\-?\s+(\d+\-\d{3})\s+\-?\s*(.*)"
......
...@@ -40,6 +40,7 @@ from slapos.grid.promise import (interface, PromiseLauncher, PromiseProcess, ...@@ -40,6 +40,7 @@ from slapos.grid.promise import (interface, PromiseLauncher, PromiseProcess,
PromiseError, PROMISE_CACHE_FOLDER_NAME) PromiseError, PROMISE_CACHE_FOLDER_NAME)
from slapos.grid.promise.generic import (GenericPromise, TestResult, AnomalyResult, from slapos.grid.promise.generic import (GenericPromise, TestResult, AnomalyResult,
PromiseQueueResult, PROMISE_STATE_FOLDER_NAME, PromiseQueueResult, PROMISE_STATE_FOLDER_NAME,
PROMISE_HISTORY_RESULT_FOLDER_NAME,
PROMISE_RESULT_FOLDER_NAME, PROMISE_RESULT_FOLDER_NAME,
PROMISE_PARAMETER_NAME) PROMISE_PARAMETER_NAME)
...@@ -170,6 +171,73 @@ class RunPromise(GenericPromise): ...@@ -170,6 +171,73 @@ class RunPromise(GenericPromise):
with open(os.path.join(self.plugin_dir, name), 'w') as f: with open(os.path.join(self.plugin_dir, name), 'w') as f:
f.write(promise_content) f.write(promise_content)
def assertSuccessResult(self, name):
expected_result = """{
"result": {
"failed": false,
"message": "success",
"type": "Test Result"
},
"path": "%(promise_dir)s/%(name)s.py",
"name": "%(name)s.py",
"execution-time": 0.05,
"title": "%(name)s"
}"""
# first promise
state_file = os.path.join(self.partition_dir, PROMISE_RESULT_FOLDER_NAME, '%s.status.json' % name)
self.assertTrue(os.path.exists(state_file))
with open(state_file) as f:
result_dict = json.loads(f.read())
result_dict['result'].pop('date')
expected_dict = expected_result % {'promise_dir': self.plugin_dir, 'name': name}
self.assertEqual(json.loads(expected_dict), result_dict)
def assertSuccessHistoryResult(self, name, expected_history=None):
if not expected_history:
expected_history = """{
"data": [{
"execution-time": 0.05,
"failed": false,
"message": "success",
"name": "%(name)s.py",
"status": "OK",
"title": "%(name)s"
}]
}"""
history_file = os.path.join(self.partition_dir, PROMISE_HISTORY_RESULT_FOLDER_NAME, '%s.history.json' % name)
self.assertTrue(os.path.exists(history_file))
with open(history_file) as f:
result_dict = json.loads(f.read())
result_dict.pop('date')
for entry in result_dict["data"]:
d = entry.pop("date")
self.assertEqual(d, entry.pop("change-date"))
expected_dict = expected_history % {'name': name}
self.assertEqual(json.loads(expected_dict), result_dict)
def assertSuccessStatsResult(self, success=1, error=0, expected_stats=None):
if not expected_stats:
expected_stats = """{
"data": ["Date, Success, Error, Warning",
"__DATE__, %(success)s, %(error)s, "
]
}"""
stats_file = os.path.join(self.partition_dir, PROMISE_STATE_FOLDER_NAME, 'promise_stats.json')
self.assertTrue(os.path.exists(stats_file))
with open(stats_file) as f:
result_dict = json.loads(f.read())
result_dict.pop('date')
expected_dict = expected_stats % {'success': success, "error": error}
copy = result_dict["data"]
for nline in range(1, len(result_dict["data"])):
line = result_dict["data"][nline]
result_dict["data"][nline] = "__DATE__,%s" % ",".join(line.split(',')[1:])
self.assertEqual(json.loads(expected_dict), result_dict)
class TestSlapOSPromiseLauncher(TestSlapOSPromiseMixin): class TestSlapOSPromiseLauncher(TestSlapOSPromiseMixin):
...@@ -337,24 +405,10 @@ class RunPromise(GenericPromise): ...@@ -337,24 +405,10 @@ class RunPromise(GenericPromise):
self.launcher.run() self.launcher.run()
self.assertTrue(os.path.exists(state_folder)) self.assertTrue(os.path.exists(state_folder))
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_promise.log')))
expected_result = """{ self.assertSuccessResult("my_promise")
"result": { self.assertSuccessHistoryResult("my_promise")
"failed": false, self.assertSuccessStatsResult(1)
"message": "success",
"type": "Test Result"
},
"path": "%s/my_promise.py",
"name": "my_promise.py",
"execution-time": 0.05,
"title": "my_promise"
}""" % self.plugin_dir
state_file = os.path.join(self.partition_dir, PROMISE_RESULT_FOLDER_NAME, 'my_promise.status.json')
self.assertTrue(os.path.exists(state_file))
with open(state_file) as f:
result_dict = json.loads(f.read())
result_dict['result'].pop('date')
self.assertEqual(json.loads(expected_result), result_dict)
def test_runpromise_multiple(self): def test_runpromise_multiple(self):
promise_name = 'my_promise.py' promise_name = 'my_promise.py'
...@@ -369,35 +423,146 @@ class RunPromise(GenericPromise): ...@@ -369,35 +423,146 @@ class RunPromise(GenericPromise):
self.assertTrue(os.path.exists(state_folder)) self.assertTrue(os.path.exists(state_folder))
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_promise.log')))
expected_result = """{ self.assertSuccessResult("my_promise")
"result": { self.assertSuccessResult("my_second_promise")
"failed": false,
"message": "success", self.assertSuccessHistoryResult("my_promise")
"type": "Test Result" self.assertSuccessHistoryResult("my_second_promise")
}, self.assertSuccessStatsResult(2)
"path": "%(promise_dir)s/%(name)s.py",
"name": "%(name)s.py", def test_runpromise_multiple_times_same_promise(self):
"execution-time": 0.05, promise_name = 'my_promise.py'
"title": "%(name)s" self.configureLauncher()
}""" self.generatePromiseScript(promise_name, success=True)
state_folder = os.path.join(self.partition_dir, PROMISE_STATE_FOLDER_NAME)
# run promise will not fail
self.launcher.run()
time.sleep(1)
self.launcher.run()
time.sleep(1)
self.launcher.run()
time.sleep(1)
self.assertTrue(os.path.exists(state_folder))
self.assertTrue(os.path.exists(os.path.join(self.log_dir, 'my_promise.log')))
self.assertSuccessResult("my_promise")
self.assertSuccessHistoryResult("my_promise", expected_history = """{
"data": [{
"execution-time": 0.05,
"failed": false,
"message": "success",
"name": "%(name)s.py",
"status": "OK",
"title": "%(name)s"
},{
"execution-time": 0.05,
"failed": false,
"message": "success",
"status": "OK"
}]
}""")
self.assertSuccessStatsResult(1, expected_stats = """{
"data": ["Date, Success, Error, Warning",
"__DATE__, %(success)s, %(error)s, ",
"__DATE__, %(success)s, %(error)s, ",
"__DATE__, %(success)s, %(error)s, "
]
}""")
def test_runpromise_multiple_times_same_promise_with_failure(self):
promise_name = 'my_promise.py'
self.configureLauncher()
self.generatePromiseScript(promise_name, success=True)
state_folder = os.path.join(self.partition_dir, PROMISE_STATE_FOLDER_NAME)
# run promise will not fail
self.launcher.run()
time.sleep(1)
self.generatePromiseScript(promise_name, success=False)
time.sleep(1)
with self.assertRaises(PromiseError):
self.launcher.run()
time.sleep(1)
with self.assertRaises(PromiseError):
self.launcher.run()
time.sleep(1)
self.assertTrue(os.path.exists(state_folder))
self.assertTrue(os.path.exists(os.path.join(self.log_dir, 'my_promise.log')))
self.assertSuccessHistoryResult("my_promise", expected_history = """{
"data": [{
"execution-time": 0.05,
"failed": false,
"message": "success",
"name": "%(name)s.py",
"status": "OK",
"title": "%(name)s"
},{
"execution-time": 0.05,
"failed": true,
"message": "failed",
"status": "ERROR"
}]
}""")
self.assertSuccessStatsResult(1, expected_stats = """{
"data": ["Date, Success, Error, Warning",
"__DATE__, %(success)s, %(error)s, ",
"__DATE__, 0, 1, ",
"__DATE__, 0, 1, "
]
}""")
def test_runpromise_multiple_times_same_promise_with_flaky_failures(self):
promise_name = 'my_promise.py'
self.configureLauncher()
self.generatePromiseScript(promise_name, success=True)
state_folder = os.path.join(self.partition_dir, PROMISE_STATE_FOLDER_NAME)
# run promise will not fail
self.launcher.run()
time.sleep(1)
self.generatePromiseScript(promise_name, success=False)
time.sleep(1)
with self.assertRaises(PromiseError):
self.launcher.run()
time.sleep(1)
self.generatePromiseScript(promise_name, success=True)
time.sleep(1)
self.launcher.run()
self.assertTrue(os.path.exists(state_folder))
self.assertTrue(os.path.exists(os.path.join(self.log_dir, 'my_promise.log')))
self.maxDiff = None
self.assertSuccessHistoryResult("my_promise", expected_history = """{
"data": [{
"execution-time": 0.05,
"failed": false,
"message": "success",
"name": "%(name)s.py",
"status": "OK",
"title": "%(name)s"
},{
"execution-time": 0.05,
"failed": true,
"message": "failed",
"status": "ERROR"
},{
"execution-time": 0.05,
"failed": false,
"message": "success",
"status": "OK"
}]
}""")
self.assertSuccessStatsResult(1, expected_stats = """{
"data": ["Date, Success, Error, Warning",
"__DATE__, %(success)s, %(error)s, ",
"__DATE__, 0, 1, ",
"__DATE__, %(success)s, %(error)s, "
]
}""")
# first promise
state_file = os.path.join(self.partition_dir, PROMISE_RESULT_FOLDER_NAME, 'my_promise.status.json')
self.assertTrue(os.path.exists(state_file))
with open(state_file) as f:
result_dict = json.loads(f.read())
result_dict['result'].pop('date')
expected_dict = expected_result % {'promise_dir': self.plugin_dir, 'name': 'my_promise'}
self.assertEqual(json.loads(expected_dict), result_dict)
# second promise
state_file = os.path.join(self.partition_dir, PROMISE_RESULT_FOLDER_NAME, 'my_second_promise.status.json')
self.assertTrue(os.path.exists(state_file))
with open(state_file) as f:
result_dict = json.loads(f.read())
result_dict['result'].pop('date')
expected_dict = expected_result % {'promise_dir': self.plugin_dir, 'name': 'my_second_promise'}
self.assertEqual(json.loads(expected_dict), result_dict)
def test_runpromise_no_logdir(self): def test_runpromise_no_logdir(self):
promise_name = 'my_promise.py' promise_name = 'my_promise.py'
...@@ -410,6 +575,8 @@ class RunPromise(GenericPromise): ...@@ -410,6 +575,8 @@ class RunPromise(GenericPromise):
self.launcher.run() self.launcher.run()
self.assertTrue(os.path.exists(state_file)) self.assertTrue(os.path.exists(state_file))
self.assertFalse(os.path.exists(os.path.join(self.log_dir, 'my_promise.log'))) self.assertFalse(os.path.exists(os.path.join(self.log_dir, 'my_promise.log')))
self.assertSuccessHistoryResult("my_promise")
self.assertSuccessStatsResult(1)
def test_runpromise_savemethod(self): def test_runpromise_savemethod(self):
promise_name = 'my_promise.py' promise_name = 'my_promise.py'
...@@ -433,6 +600,9 @@ class RunPromise(GenericPromise): ...@@ -433,6 +600,9 @@ class RunPromise(GenericPromise):
self.assertTrue(os.path.exists(state_file)) 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_promise.log')))
self.assertSuccessHistoryResult("my_promise")
self.assertSuccessStatsResult(1)
def test_runpromise_savemethod_no_logdir(self): def test_runpromise_savemethod_no_logdir(self):
promise_name = 'my_promise.py' promise_name = 'my_promise.py'
def test_method(result): def test_method(result):
...@@ -455,6 +625,9 @@ class RunPromise(GenericPromise): ...@@ -455,6 +625,9 @@ class RunPromise(GenericPromise):
self.launcher.run() self.launcher.run()
self.assertTrue(os.path.exists(state_file)) self.assertTrue(os.path.exists(state_file))
self.assertFalse(os.path.exists(os.path.join(self.log_dir, 'my_promise.log'))) self.assertFalse(os.path.exists(os.path.join(self.log_dir, 'my_promise.log')))
self.assertSuccessHistoryResult("my_promise")
self.assertSuccessStatsResult(1)
def test_runpromise_savemethod_anomaly(self): def test_runpromise_savemethod_anomaly(self):
promise_name = 'my_promise.py' promise_name = 'my_promise.py'
...@@ -477,6 +650,9 @@ class RunPromise(GenericPromise): ...@@ -477,6 +650,9 @@ class RunPromise(GenericPromise):
self.launcher.run() self.launcher.run()
self.assertTrue(os.path.exists(state_file)) 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_promise.log')))
self.assertSuccessHistoryResult("my_promise")
self.assertSuccessStatsResult(1)
def test_runpromise_savemethod_multiple(self): def test_runpromise_savemethod_multiple(self):
promise_name = 'my_promise.py' promise_name = 'my_promise.py'
...@@ -506,6 +682,19 @@ class RunPromise(GenericPromise): ...@@ -506,6 +682,19 @@ class RunPromise(GenericPromise):
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_promise.log')))
self.assertTrue(os.path.exists(os.path.join(self.log_dir, 'my_failed_promise.log'))) self.assertTrue(os.path.exists(os.path.join(self.log_dir, 'my_failed_promise.log')))
self.assertSuccessHistoryResult("my_promise")
self.assertSuccessHistoryResult("my_failed_promise", expected_history = """{
"data": [{
"execution-time": 0.05,
"failed": true,
"message": "failed",
"name": "%(name)s.py",
"status": "ERROR",
"title": "%(name)s"
}]
}""")
self.assertSuccessStatsResult(success=1, error=1)
def test_runpromise_savemethod_multiple_success(self): def test_runpromise_savemethod_multiple_success(self):
first_promise = 'my_first_promise.py' first_promise = 'my_first_promise.py'
second_promise = 'my_second_promise.py' second_promise = 'my_second_promise.py'
...@@ -533,6 +722,12 @@ class RunPromise(GenericPromise): ...@@ -533,6 +722,12 @@ class RunPromise(GenericPromise):
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_second_promise.log')))
self.assertTrue(os.path.exists(os.path.join(self.log_dir, 'my_third_promise.log'))) self.assertTrue(os.path.exists(os.path.join(self.log_dir, 'my_third_promise.log')))
self.assertSuccessHistoryResult("my_first_promise")
self.assertSuccessHistoryResult("my_second_promise")
self.assertSuccessHistoryResult("my_third_promise")
self.assertSuccessStatsResult(3)
def test_runpromise_fail_and_success(self): def test_runpromise_fail_and_success(self):
first_promise = 'my_first_promise.py' first_promise = 'my_first_promise.py'
second_promise = 'my_second_promise.py' second_promise = 'my_second_promise.py'
...@@ -561,6 +756,12 @@ class RunPromise(GenericPromise): ...@@ -561,6 +756,12 @@ class RunPromise(GenericPromise):
line = f.readline() line = f.readline()
self.assertTrue('success' in line, line) self.assertTrue('success' in line, line)
self.assertSuccessStatsResult(expected_stats = """{
"data": ["Date, Success, Error, Warning",
"__DATE__, 1, 1, ",
"__DATE__, 2, 0, "
]
}""")
def test_runpromise_with_periodicity(self): def test_runpromise_with_periodicity(self):
first_promise = 'my_first_promise.py' first_promise = 'my_first_promise.py'
......
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