Skip to content

Commit

Permalink
Add decrby to redis_client (#275)
Browse files Browse the repository at this point in the history
* Add decrby to redis_client

- Added a simple decorator for functions that are behind a feature flag

* formatting

* Fix code QL issues
  • Loading branch information
whabanks authored Feb 14, 2024
1 parent 3a74e06 commit e86daba
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .github/actions/waffles/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
docopt==0.6.2
Flask==2.3.3
markupsafe==2.1.4
git+https://github.com/cds-snc/[email protected].1#egg=notifications-utils
git+https://github.com/cds-snc/[email protected].2#egg=notifications-utils
15 changes: 15 additions & 0 deletions notifications_utils/clients/redis/redis_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,21 @@ def incrby(self, key, by, raise_exception=False):
except Exception as e:
self.__handle_exception(e, raise_exception, "incrby", key)

def decrby(
self,
key,
by,
raise_exception=False,
):
key = prepare_value(key)
if self.active:
try:
return self.redis_store.decrby(key, by)
except Exception as e:
self.__handle_exception(e, raise_exception, "decrby", key)

return None

def get(self, key, raise_exception=False):
key = prepare_value(key)
if self.active:
Expand Down
15 changes: 15 additions & 0 deletions notifications_utils/decorators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from flask import current_app
from functools import wraps


def requires_feature(flag):
def decorator_feature_flag(func):
@wraps(func)
def wrapper(*args, **kwargs):
if current_app.config[flag]:
return func(*args, **kwargs)
return None

return wrapper

return decorator_feature_flag
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ include = '(notifications_utils|tests)/.*\.pyi?$'

[tool.poetry]
name = "notifications-utils"
version = "52.1.1"
version = "52.1.2"
description = "Shared python code for Notification - Provides logging utils etc."
authors = ["Canadian Digital Service"]
license = "MIT license"
Expand Down
18 changes: 18 additions & 0 deletions tests/test_decorators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from notifications_utils.decorators import requires_feature


@requires_feature("FEATURE_FLAG")
def decorated_function():
return "Feature enabled"


def test_requires_feature_enabled(mocker, app):
app.config["FEATURE_FLAG"] = True
result = decorated_function()
assert result == "Feature enabled"


def test_requires_feature_disabled(mocker, app):
app.config["FEATURE_FLAG"] = False
result = decorated_function()
assert result is None
5 changes: 5 additions & 0 deletions tests/test_redis_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,15 @@ def test_should_not_raise_exception_if_raise_set_to_false(app, caplog, mocker):
redis_client.redis_store.get = Mock(side_effect=Exception())
redis_client.redis_store.set = Mock(side_effect=Exception())
redis_client.redis_store.incr = Mock(side_effect=Exception())
redis_client.redis_store.decrby = Mock(side_effect=Exception())
redis_client.redis_store.pipeline = Mock(side_effect=Exception())
redis_client.redis_store.expire = Mock(side_effect=Exception())
redis_client.redis_store.delete = Mock(side_effect=Exception())
assert redis_client.get("get_key") is None
assert redis_client.set("set_key", "set_value") is None
assert redis_client.incr("incr_key") is None
assert redis_client.incrby("incrby_key", by=1) is None
assert redis_client.decrby("decrby_key", by=1) is None
assert redis_client.exceeded_rate_limit("rate_limit_key", 100, 100) is False
assert redis_client.expire("expire_key", 100) is None
assert redis_client.delete("delete_key") is None
Expand All @@ -79,6 +81,7 @@ def test_should_not_raise_exception_if_raise_set_to_false(app, caplog, mocker):
call.exception("Redis error performing set on set_key"),
call.exception("Redis error performing incr on incr_key"),
call.exception("Redis error performing incrby on incrby_key"),
call.exception("Redis error performing decrby on decrby_key"),
call.exception("Redis error performing rate-limit-pipeline on rate_limit_key"),
call.exception("Redis error performing expire on expire_key"),
call.exception("Redis error performing delete on delete_key"),
Expand Down Expand Up @@ -109,6 +112,8 @@ def test_should_raise_exception_if_raise_set_to_true(app):
with pytest.raises(Exception) as e:
redis_client.incrby("test", by=1, raise_exception=True)
assert str(e.value) == "incrby failed"
with pytest.raises(Exception) as e:
redis_client.decrby("test", by=1, raise_exception=True)
with pytest.raises(Exception) as e:
redis_client.exceeded_rate_limit("test", 100, 200, raise_exception=True)
assert str(e.value) == "pipeline failed"
Expand Down

0 comments on commit e86daba

Please sign in to comment.