summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Nemec <bnemec@redhat.com>2018-11-28 19:38:48 +0000
committerBen Nemec <bnemec@redhat.com>2018-12-03 16:44:28 +0000
commitddc436925887b6ece4aba19a36e53ede0b22ae21 (patch)
tree1b6b47759b64c505f102a1d1f9e2aeefbafae343
parentc568717706b18eab1c679c6792b8016f5fbb9a35 (diff)
downloadoslo-utils-ddc436925887b6ece4aba19a36e53ede0b22ae21.tar.gz
Support non-dict mappings in mask_dict_password
mask_dict_password doesn't actually have a dependency on the dict type specifically. It can work on any subclass of collections.Mapping. This changes the isinstance check to reflect that and adds a unit test using a collections.Mapping subclass. Change-Id: I28781acf027b9b34f8274196db5dd4d2a9adc9ba Closes-Bug: 1804528
-rw-r--r--oslo_utils/strutils.py7
-rw-r--r--oslo_utils/tests/test_strutils.py41
2 files changed, 45 insertions, 3 deletions
diff --git a/oslo_utils/strutils.py b/oslo_utils/strutils.py
index ebcc104..d7b104d 100644
--- a/oslo_utils/strutils.py
+++ b/oslo_utils/strutils.py
@@ -17,6 +17,7 @@
System-level utilities and helper functions.
"""
+import collections
import math
import re
import unicodedata
@@ -390,12 +391,12 @@ def mask_dict_password(dictionary, secret="***"): # nosec
"""
- if not isinstance(dictionary, dict):
- raise TypeError("Expected a dictionary, got %s instead."
+ if not isinstance(dictionary, collections.Mapping):
+ raise TypeError("Expected a Mapping, got %s instead."
% type(dictionary))
out = {}
for k, v in dictionary.items():
- if isinstance(v, dict):
+ if isinstance(v, collections.Mapping):
out[k] = mask_dict_password(v, secret=secret)
continue
# NOTE(jlvillal): Check to see if anything in the dictionary 'key'
diff --git a/oslo_utils/tests/test_strutils.py b/oslo_utils/tests/test_strutils.py
index 301b619..e015b2e 100644
--- a/oslo_utils/tests/test_strutils.py
+++ b/oslo_utils/tests/test_strutils.py
@@ -15,6 +15,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import collections
import copy
import math
@@ -613,6 +614,31 @@ class MaskPasswordTestCase(test_base.BaseTestCase):
self.assertEqual(expected, strutils.mask_password(payload))
+class TestMapping(collections.Mapping):
+ """Test class for non-dict mappings"""
+ def __init__(self):
+ super(TestMapping, self).__init__()
+ self.data = {'password': 'shhh',
+ 'foo': 'bar',
+ }
+
+ def __getitem__(self, key):
+ return self.data[key]
+
+ def __iter__(self):
+ return self.data.__iter__()
+
+ def __len__(self):
+ return len(self.data)
+
+
+class NestedMapping(TestMapping):
+ """Test class that contains an instance of TestMapping"""
+ def __init__(self):
+ super(NestedMapping, self).__init__()
+ self.data = {'nested': TestMapping()}
+
+
class MaskDictionaryPasswordTestCase(test_base.BaseTestCase):
def test_dictionary(self):
@@ -696,6 +722,21 @@ class MaskDictionaryPasswordTestCase(test_base.BaseTestCase):
strutils.mask_dict_password(payload)
self.assertEqual(pristine, payload)
+ def test_non_dict(self):
+ expected = {'password': '***',
+ 'foo': 'bar',
+ }
+ payload = TestMapping()
+ self.assertEqual(expected, strutils.mask_dict_password(payload))
+
+ def test_nested_non_dict(self):
+ expected = {'nested': {'password': '***',
+ 'foo': 'bar',
+ }
+ }
+ payload = NestedMapping()
+ self.assertEqual(expected, strutils.mask_dict_password(payload))
+
class IsIntLikeTestCase(test_base.BaseTestCase):
def test_is_int_like_true(self):