mirror of
https://github.com/ansible/awx.git
synced 2026-10-31 06:26:15 -02:30
Complete the FakeRedis test double for the subsystem metrics pipe (#16745)
TestCallbackBrokerWorker::test_duplicate_key_not_saved_twice can crash
with AttributeError: 'FakeRedis' object has no attribute 'hincrby'.
CallbackBrokerWorker.flush() ends with
if self.subsystem_metrics.should_pipe_execute() is True:
self.subsystem_metrics.pipe_execute()
and should_pipe_execute() is True once more than
SUBSYSTEM_METRICS_INTERVAL_SAVE_TO_REDIS seconds have passed since the
last pipe execute. On a fast machine that interval never elapses during
the test, so the pipe is never executed and nothing notices; on a slow
one it does, pipe_execute() calls store_value() on every metric, and
IntM/FloatM/SetIntM reach for hincrby/hincrbyfloat/hset, which the
FakeRedis double in awx/main/tests/functional/conftest.py does not have.
Rather than suppress the pipe execute in the one test, make the double
complete enough to execute it: add the hash commands the metric
store_value() implementations use, an execute() for the pipeline
(pipeline() returns self), and a lock() returning a lock that never
acquires, so send_metrics() takes its "another thread holds the lock"
early return instead of trying to emit a websocket notification through
a channel layer that is not available under test.
This commit is contained in:
@@ -76,6 +76,16 @@ def swagger_autogen(requests=__SWAGGER_REQUESTS__):
|
|||||||
return requests
|
return requests
|
||||||
|
|
||||||
|
|
||||||
|
class FakeLock:
|
||||||
|
# Never acquirable, so callers that guard work with a redis lock take the
|
||||||
|
# "someone else holds it" branch instead of reaching for real services.
|
||||||
|
def acquire(self, *args, **kwargs):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def release(self, *args, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class FakeRedis:
|
class FakeRedis:
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
# Accept and ignore all arguments to match redis.Redis signature
|
# Accept and ignore all arguments to match redis.Redis signature
|
||||||
@@ -90,6 +100,21 @@ class FakeRedis:
|
|||||||
def get(self, *args, **kwargs):
|
def get(self, *args, **kwargs):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def hset(self, *args, **kwargs):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def hget(self, *args, **kwargs):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def hincrby(self, *args, **kwargs):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def hincrbyfloat(self, *args, **kwargs):
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
def lock(self, *args, **kwargs):
|
||||||
|
return FakeLock()
|
||||||
|
|
||||||
def rpush(self, *args, **kwargs):
|
def rpush(self, *args, **kwargs):
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
@@ -112,6 +137,9 @@ class FakeRedis:
|
|||||||
def pipeline(self):
|
def pipeline(self):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def execute(self, *args, **kwargs):
|
||||||
|
return []
|
||||||
|
|
||||||
def ping(self):
|
def ping(self):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user