Changeset View
Changeset View
Standalone View
Standalone View
test/functional/test_framework/test_node.py
Show First 20 Lines • Show All 159 Lines • ▼ Show 20 Lines | PRIV_KEYS = [ | ||||
'cPiRWE8KMjTRxH1MWkPerhfoHFn5iHPWVK5aPqjW8NxmdwenFinJ'), | 'cPiRWE8KMjTRxH1MWkPerhfoHFn5iHPWVK5aPqjW8NxmdwenFinJ'), | ||||
] | ] | ||||
def get_deterministic_priv_key(self): | def get_deterministic_priv_key(self): | ||||
"""Return a deterministic priv key in base58, that only depends on the node's index""" | """Return a deterministic priv key in base58, that only depends on the node's index""" | ||||
assert len(self.PRIV_KEYS) == MAX_NODES | assert len(self.PRIV_KEYS) == MAX_NODES | ||||
return self.PRIV_KEYS[self.index] | return self.PRIV_KEYS[self.index] | ||||
def get_mem_rss(self): | |||||
"""Get the memory usage (RSS) per `ps`. | |||||
If process is stopped or `ps` is unavailable, return None. | |||||
""" | |||||
if not (self.running and self.process): | |||||
self.log.warning( | |||||
"Couldn't get memory usage; process isn't running.") | |||||
return None | |||||
try: | |||||
return int(subprocess.check_output( | |||||
"ps h -o rss {}".format(self.process.pid), | |||||
shell=True, stderr=subprocess.DEVNULL).strip()) | |||||
# Catching `Exception` broadly to avoid failing on platforms where ps | |||||
# isn't installed or doesn't work as expected, e.g. OpenBSD. | |||||
# | |||||
# We could later use something like `psutils` to work across platforms. | |||||
except Exception: | |||||
self.log.exception("Unable to get memory usage") | |||||
return None | |||||
nakihito: This is different from [[ https://github.com/bitcoin/bitcoin/pull/17469/files? | |||||
jasonbcoxAuthorUnsubmitted Done Inline ActionsApparently there were more than one attempts to fix this, which makes the argument to avoid replicating that process all the more strong. jasonbcox: Apparently there were more than one attempts to fix this, which makes the argument to avoid… | |||||
def _node_msg(self, msg: str) -> str: | def _node_msg(self, msg: str) -> str: | ||||
"""Return a modified msg that identifies this node by its index as a debugging aid.""" | """Return a modified msg that identifies this node by its index as a debugging aid.""" | ||||
return "[node {}] {}".format(self.index, msg) | return "[node {}] {}".format(self.index, msg) | ||||
def _raise_assertion_error(self, msg: str): | def _raise_assertion_error(self, msg: str): | ||||
"""Raise an AssertionError with msg modified to identify this node.""" | """Raise an AssertionError with msg modified to identify this node.""" | ||||
raise AssertionError(self._node_msg(msg)) | raise AssertionError(self._node_msg(msg)) | ||||
▲ Show 20 Lines • Show All 221 Lines • ▼ Show 20 Lines | def assert_debug_log(self, expected_msgs, unexpected_msgs=None, timeout=2): | ||||
return | return | ||||
if time.time() >= time_end: | if time.time() >= time_end: | ||||
break | break | ||||
time.sleep(0.05) | time.sleep(0.05) | ||||
self._raise_assertion_error( | self._raise_assertion_error( | ||||
'Expected messages "{}" does not partially match log:\n\n{}\n\n'.format( | 'Expected messages "{}" does not partially match log:\n\n{}\n\n'.format( | ||||
str(expected_msgs), print_log)) | str(expected_msgs), print_log)) | ||||
@contextlib.contextmanager | |||||
def assert_memory_usage_stable(self, perc_increase_allowed=0.03): | |||||
"""Context manager that allows the user to assert that a node's memory usage (RSS) | |||||
hasn't increased beyond some threshold percentage. | |||||
""" | |||||
before_memory_usage = self.get_mem_rss() | |||||
yield | |||||
after_memory_usage = self.get_mem_rss() | |||||
if not (before_memory_usage and after_memory_usage): | |||||
self.log.warning( | |||||
"Unable to detect memory usage (RSS) - skipping memory check.") | |||||
return | |||||
perc_increase_memory_usage = 1 - \ | |||||
(float(before_memory_usage) / after_memory_usage) | |||||
if perc_increase_memory_usage > perc_increase_allowed: | |||||
self._raise_assertion_error( | |||||
"Memory usage increased over threshold of {:.3f}% from {} to {} ({:.3f}%)".format( | |||||
perc_increase_allowed * 100, before_memory_usage, after_memory_usage, | |||||
perc_increase_memory_usage * 100)) | |||||
def assert_start_raises_init_error( | def assert_start_raises_init_error( | ||||
self, extra_args=None, expected_msg=None, match=ErrorMatch.FULL_TEXT, *args, **kwargs): | self, extra_args=None, expected_msg=None, match=ErrorMatch.FULL_TEXT, *args, **kwargs): | ||||
"""Attempt to start the node and expect it to raise an error. | """Attempt to start the node and expect it to raise an error. | ||||
extra_args: extra arguments to pass through to bitcoind | extra_args: extra arguments to pass through to bitcoind | ||||
expected_msg: regex that stderr should match when bitcoind fails | expected_msg: regex that stderr should match when bitcoind fails | ||||
Will throw if bitcoind starts without an error. | Will throw if bitcoind starts without an error. | ||||
▲ Show 20 Lines • Show All 178 Lines • Show Last 20 Lines |
This is different from PR17469 and the change isn't made in PR14794. The changes are made in PR14693 and PR14812, but since its being removed, its probably fine to skip them.