Skip to content

Commit ead5ccf

Browse files
authored
add: unittest (#6)
1 parent 9d35cd8 commit ead5ccf

File tree

6 files changed

+123
-35
lines changed

6 files changed

+123
-35
lines changed

aws_paramstore_py/__init__.py

Lines changed: 3 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import argparse
22
import json
33

4-
import boto3
4+
from .main import get
55

6-
__version__ = '0.0.3'
6+
__version__ = '0.0.4'
77

88

9-
def main():
9+
def cli():
1010
parser = argparse.ArgumentParser(description='Query params from AWS System Manager Parameter Store')
1111
parser.add_argument('paths', metavar='path', nargs='*', help='The hierarchy for the parameter')
1212
parser.add_argument('--decryption', action='store_true', help='Decrypt secure values or not')
@@ -16,29 +16,3 @@ def main():
1616
decryption = args.decryption
1717
params = get(*paths, decryption=decryption)
1818
print(json.dumps(params))
19-
20-
21-
def get(*paths, decryption=False):
22-
ssm = boto3.client('ssm')
23-
path = '/'.join(paths)
24-
path = _complement_slashes(path)
25-
response = ssm.get_parameters_by_path(Path=path, Recursive=True, WithDecryption=decryption)
26-
params = map(lambda p: _remove_prefix(p, path), response['Parameters'])
27-
return _convert_to_dict(params)
28-
29-
30-
def _complement_slashes(path):
31-
if path[len(path):] != '/':
32-
path = path + '/'
33-
if path[:1] != '/':
34-
path = '/' + path
35-
return path
36-
37-
38-
def _remove_prefix(param, prefix):
39-
param['Name'] = param['Name'][len(prefix):]
40-
return param
41-
42-
43-
def _convert_to_dict(params):
44-
return {p['Name']: p['Value'] for p in params}

aws_paramstore_py/main.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import boto3
2+
3+
4+
def get(*paths, decryption=False):
5+
ssm = boto3.client('ssm')
6+
path = _join_slashes(paths)
7+
response = ssm.get_parameters_by_path(Path=path, Recursive=True, WithDecryption=decryption)
8+
params = map(lambda p: _remove_prefix(p, path), response['Parameters'])
9+
return _convert_to_dict(params)
10+
11+
12+
def _join_slashes(paths):
13+
path = '/'.join(filter(lambda e: len(e), map(lambda e: _remove_slashes_on_edge(e), paths)))
14+
if not path:
15+
return '/'
16+
else:
17+
return '/' + path + '/'
18+
19+
20+
def _remove_slashes_on_edge(string):
21+
if _is_led_by_slash(string):
22+
string = string[1:]
23+
if _is_followed_by_slash(string):
24+
string = string[:-1]
25+
return string
26+
27+
28+
def _is_led_by_slash(string):
29+
return string[:1] == '/'
30+
31+
32+
def _is_followed_by_slash(string):
33+
return string[-1:] == '/'
34+
35+
36+
def _remove_prefix(param, prefix):
37+
param['Name'] = param['Name'][len(prefix):]
38+
return param
39+
40+
41+
def _convert_to_dict(params):
42+
return {p['Name']: p['Value'] for p in params}

scripts/spec.sh

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ set -eu
44
here=$(cd $(dirname "$0") && pwd)
55
project_root=$(cd "${here}/.." && pwd)
66

7+
spec() {
8+
cd "${project_root}"
9+
python3 setup.py test
10+
cd -
11+
}
12+
713
set -x
814

9-
echo "Test"
15+
spec

setup.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@
55
here = path.abspath(path.dirname(__file__))
66

77
# Get the long description from the README file
8-
with open(path.join(here, 'README.rst'), encoding='utf-8') as f:
9-
long_description = f.read()
8+
readme = path.join(here, 'README.rst')
9+
if path.exists(readme):
10+
with open(readme, encoding='utf-8') as f:
11+
long_description = f.read()
12+
else:
13+
long_description = ''
1014

1115
setup(
1216
# This is the name of your project. The first time you publish this
@@ -28,7 +32,7 @@
2832
# For a discussion on single-sourcing the version across setup.py and the
2933
# project code, see
3034
# https://packaging.python.org/en/latest/single_source_version.html
31-
version='0.0.3', # Required
35+
version='0.0.4', # Required
3236

3337
# This is a one-line description or tagline of what your project does. This
3438
# corresponds to the "Summary" metadata field:
@@ -100,7 +104,7 @@
100104
#
101105
# py_modules=["my_module"],
102106
#
103-
packages=find_packages(exclude=['contrib', 'docs', 'tests']), # Required
107+
packages=find_packages(exclude=['spec']), # Required
104108

105109
# If your project only runs on certain Python versions, setting the python
106110
# requires argument to the appropriate PEP 440 version specifier string will
@@ -156,7 +160,15 @@
156160
# executes the function `main` from this package when invoked:
157161
entry_points={ # Optional
158162
'console_scripts': [
159-
'aws-pspy=aws_paramstore_py:main',
163+
'aws-pspy=aws_paramstore_py:cli',
160164
],
161165
},
166+
167+
# A string naming a unittest.TestCase subclass (or a package or module containing
168+
# one or more of them, or a method of such a subclass), or naming a function that
169+
# can be called with no arguments and returns a unittest.TestSuite. If the named
170+
# suite is a module, and the module has an additional_tests() function, it is called
171+
# and the results are added to the tests to be run. If the named suite is a package,
172+
# any submodules and subpackages are recursively added to the overall test suite.
173+
test_suite='spec',
162174
)

spec/__init__.py

Whitespace-only changes.

spec/test_main.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import unittest
2+
from unittest.mock import patch
3+
4+
import aws_paramstore_py as paramstore
5+
6+
7+
@patch('aws_paramstore_py.main.boto3')
8+
class TestMain(unittest.TestCase):
9+
def test_get(self, mock):
10+
method = mock.client('ssm').get_parameters_by_path
11+
method.return_value = {'Parameters': [
12+
{'Name': '/path/to/params/key1', 'Value': "value1"},
13+
{'Name': '/path/to/params/key2', 'Value': "value2"}
14+
]}
15+
16+
params = paramstore.get('path', 'to', 'params')
17+
18+
method.assert_called_with(Path='/path/to/params/', Recursive=True, WithDecryption=False)
19+
self.assertDictEqual({"key1": "value1", "key2": "value2"}, params)
20+
21+
def test_get_root(self, mock):
22+
method = mock.client('ssm').get_parameters_by_path
23+
24+
paramstore.get()
25+
26+
method.assert_called_with(Path='/', Recursive=True, WithDecryption=False)
27+
28+
def test_get_slash(self, mock):
29+
method = mock.client('ssm').get_parameters_by_path
30+
31+
paramstore.get('/')
32+
33+
method.assert_called_with(Path='/', Recursive=True, WithDecryption=False)
34+
35+
def test_get_leading_slash(self, mock):
36+
method = mock.client('ssm').get_parameters_by_path
37+
38+
paramstore.get('/path/to')
39+
40+
method.assert_called_with(Path='/path/to/', Recursive=True, WithDecryption=False)
41+
42+
def test_get_following_slash(self, mock):
43+
method = mock.client('ssm').get_parameters_by_path
44+
45+
paramstore.get('path/to/')
46+
47+
method.assert_called_with(Path='/path/to/', Recursive=True, WithDecryption=False)
48+
49+
def test_get_with_decryption(self, mock):
50+
method = mock.client('ssm').get_parameters_by_path
51+
52+
paramstore.get('path/to/params', decryption=True)
53+
54+
method.assert_called_with(Path='/path/to/params/', Recursive=True, WithDecryption=True)

0 commit comments

Comments
 (0)