Tests - Default to having Python objects as "hook log"

This commit is contained in:
Renato Alves 2015-02-15 18:05:52 +00:00
parent 80c01f3ffb
commit 1bd26fe9ab

View file

@ -368,8 +368,30 @@ class LoggedHook(Hook):
# Cache is up to date
return True
def _parse_log(self):
"""Parse the logs generated by the hook
def enable(self):
"""Make hookfile executable to allow triggering
"""
super(LoggedHook, self).enable()
os.chmod(self.wrappedfile, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
def disable(self):
"""Remove hookfile executable bit to deny triggering
"""
super(LoggedHook, self).disable()
os.chmod(self.wrappedfile, stat.S_IREAD | stat.S_IWRITE)
def is_active(self):
"""Check if hook is active by verifying the execute bit
"""
parent_is_active = super(LoggedHook, self).disable()
return parent_is_active and os.access(self.wrappedfile, os.X_OK)
def get_logs(self):
"""Parse the logs generated by the hook and return a dictionary
containing the logs collected with the wrapper in a python friendly
format:
* JSON is parsed as python dictionaries
* timestamps are parsed as datetime objects
It should look something like this:
@ -404,9 +426,13 @@ class LoggedHook(Hook):
if line.startswith("%"):
# Timestamp includes nanosecond resolution
timestamp = line.split(" ")[-1]
log["calls"].append(timestamp)
# convert timestamp to python datetime object
log["calls"].append(
datetime.fromtimestamp(float(timestamp))
)
elif line.startswith("{"):
log["input"]["json"].append(line)
# Decode json input (to hook)
log["input"]["json"].append(json_decoder(line))
else:
raise IOError("Unexpected content on STDIN line {0}: {1}"
.format(i, line))
@ -418,10 +444,13 @@ class LoggedHook(Hook):
exitcode = int(line.split(" ")[-1])
log["exitcode"] = exitcode
elif line.startswith("{"):
log["output"]["json"].append(line)
# Decode json output (from hook)
log["output"]["json"].append(json_decoder(line))
else:
log["output"]["msgs"].append(line)
# NOTE convert all lists to tuples to prevent tampering?
self._cache["log"] = log
# Update last modification timestamp in cache
@ -429,60 +458,11 @@ class LoggedHook(Hook):
return self._cache["log"]
def enable(self):
"""Make hookfile executable to allow triggering
"""
super(LoggedHook, self).enable()
os.chmod(self.wrappedfile, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
def disable(self):
"""Remove hookfile executable bit to deny triggering
"""
super(LoggedHook, self).disable()
os.chmod(self.wrappedfile, stat.S_IREAD | stat.S_IWRITE)
def is_active(self):
"""Check if hook is active by verifying the execute bit
"""
parent_is_active = super(LoggedHook, self).disable()
return parent_is_active and os.access(self.wrappedfile, os.X_OK)
def get_logs(self):
"""Return a dictionary containing the logs collected with the wrapper
in a python friendly format:
* JSON is parsed as python dictionaries
* timestamps are parsed as datetime objects
"""
log = self._parse_log()
newlog = {}
for k1 in log:
# Timestamps
if k1 == "calls":
timestamp = lambda x: datetime.fromtimestamp(float(x))
newlog[k1] = map(timestamp, log[k1])
elif k1 in ("input", "output"):
newlog[k1] = {}
for k2 in log[k1]:
if k2 == "json":
# JSON replies
newlog[k1][k2] = map(json_decoder, log[k1][k2])
else:
# Messages and future fields
newlog[k1][k2] = deepcopy(log[k1][k2])
else:
# exitcode and future fields
newlog[k1] = deepcopy(log[k1])
return newlog
def assertTriggeredCount(self, count):
"""Check if current hook file was triggered/used by taskwarrior and
how many times.
"""
log = self._parse_log()
log = self.get_logs()
assert len(log["calls"]) == count, ("{0} calls expected for {1} but "
"found {2}".format(
@ -494,7 +474,7 @@ class LoggedHook(Hook):
def assertExitcode(self, exitcode):
"""Check if current hook finished with the expected exit code
"""
log = self._parse_log()
log = self.get_logs()
assert log["exitcode"] == exitcode, ("Expected exit code {0} for {1} "
"but found {2}".format(