Skip to content

Commit

Permalink
Parse --statistic-values values into a decimal type
Browse files Browse the repository at this point in the history
This was failing the improved botocore param validation because
we were previously setting this value to a string.  We now set
this value to a decimal.Decimal to ensure we have a valid type
that will also pass the botocore param validation.

While I was in the code, I also updated the code to use the new
botocore CamelCasing from metric_data to MetricData.  There was
also some general test cleanup to switch the tests to
assert_params_for_cmd2.

Fixes aws#1036.
  • Loading branch information
jamesls committed Dec 2, 2014
1 parent d720664 commit 57ad680
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 23 deletions.
17 changes: 10 additions & 7 deletions awscli/customizations/putmetricdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,24 +98,24 @@ def add_to_params(self, parameters, value):
method_name = '_add_param_%s' % self.name.replace('-', '_')
return getattr(self, method_name)(parameters, value)

@insert_first_element('metric_data')
@insert_first_element('MetricData')
def _add_param_metric_name(self, first_element, value):
first_element['MetricName'] = value

@insert_first_element('metric_data')
@insert_first_element('MetricData')
def _add_param_unit(self, first_element, value):
first_element['Unit'] = value

@insert_first_element('metric_data')
@insert_first_element('MetricData')
def _add_param_timestamp(self, first_element, value):
first_element['Timestamp'] = value

@insert_first_element('metric_data')
@insert_first_element('MetricData')
def _add_param_value(self, first_element, value):
# Use a Decimal to avoid loss in precision.
first_element['Value'] = decimal.Decimal(value)

@insert_first_element('metric_data')
@insert_first_element('MetricData')
def _add_param_dimensions(self, first_element, value):
# Dimensions needs a little more processing. We support
# the key=value,key2=value syntax so we need to parse
Expand All @@ -126,12 +126,15 @@ def _add_param_dimensions(self, first_element, value):
dimensions.append({'Name': key, 'Value': value})
first_element['Dimensions'] = dimensions

@insert_first_element('metric_data')
@insert_first_element('MetricData')
def _add_param_statistic_values(self, first_element, value):
# StatisticValues is a struct type so we are parsing
# a csv keyval list into a dict.
statistics = {}
for pair in split_on_commas(value):
key, value = pair.split('=')
statistics[key] = value
# There are four supported values: Maximum, Minimum, SampleCount,
# and Sum. All of them are documented as a type double so we can
# convert these to a decimal value to preserve precision.
statistics[key] = decimal.Decimal(value)
first_element['StatisticValues'] = statistics
40 changes: 32 additions & 8 deletions tests/unit/cloudwatch/test_put_metric_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
import decimal

from awscli.testutils import BaseAWSCommandParamsTest


Expand All @@ -20,12 +22,12 @@ class TestPutMetricData(BaseAWSCommandParamsTest):
prefix = 'cloudwatch put-metric-data '

expected_output = {
'MetricData.member.1.MetricName': 'FreeMemoryBytes',
'MetricData.member.1.Timestamp': '2013-08-22T10:58:12.283000Z',
'MetricData.member.1.Unit': 'Bytes',
'MetricData.member.1.Value': 9130160128,
'Namespace': '"Foo/Bar"'
}
'MetricData': [
{'MetricName': 'FreeMemoryBytes',
'Unit': 'Bytes',
'Timestamp': '2013-08-22T10:58:12.283Z',
'Value': decimal.Decimal("9130160128")}],
'Namespace': '"Foo/Bar"'}

def test_using_json(self):
args = ('--namespace "Foo/Bar" '
Expand All @@ -34,7 +36,7 @@ def test_using_json(self):
'"Timestamp":"2013-08-22T10:58:12.283Z",'
'"Value":9130160128}]')
cmdline = self.prefix + args
self.assert_params_for_cmd(cmdline, self.expected_output)
self.assert_params_for_cmd2(cmdline, self.expected_output)

def test_using_promoted_params(self):
# This is equivalent to the json version in test_using_json
Expand All @@ -45,4 +47,26 @@ def test_using_promoted_params(self):
'--timestamp 2013-08-22T10:58:12.283Z '
'--value 9130160128')
cmdline = self.prefix + args
self.assert_params_for_cmd(cmdline, self.expected_output)
self.assert_params_for_cmd2(cmdline, self.expected_output)

def test_using_shorthand_syntax(self):
args = (
'--metric-name PageViewCount '
'--namespace MyService '
'--statistic-value Sum=11,Minimum=2,Maximum=5,SampleCount=3 '
'--timestamp 2014-02-14T12:00:00.000Z'
)
cmdline = self.prefix + args
expected = {
'MetricData': [
{'MetricName': 'PageViewCount',
'StatisticValues': {
'Maximum': decimal.Decimal('5'),
'Minimum': decimal.Decimal('2'),
'SampleCount': decimal.Decimal('3'),
'Sum': decimal.Decimal('11')},
'Timestamp': '2014-02-14T12:00:00.000Z'}
],
'Namespace': 'MyService'
}
self.assert_params_for_cmd2(cmdline, expected)
18 changes: 10 additions & 8 deletions tests/unit/customizations/test_cloudwatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,39 +25,39 @@ def test_build_metric_name_arg(self):
help_text='metric-name')
parameters = {}
arg.add_to_params(parameters, 'MyMetricName')
self.assertEqual(parameters['metric_data'][0]['MetricName'],
self.assertEqual(parameters['MetricData'][0]['MetricName'],
'MyMetricName')

def test_build_unit_arg(self):
arg = putmetricdata.PutMetricArgument('unit',
help_text='unit')
parameters = {}
arg.add_to_params(parameters, 'Percent')
self.assertEqual(parameters['metric_data'][0]['Unit'],
self.assertEqual(parameters['MetricData'][0]['Unit'],
'Percent')

def test_value_arg(self):
arg = putmetricdata.PutMetricArgument('value',
help_text='value')
parameters = {}
arg.add_to_params(parameters, '123.1')
self.assertEqual(parameters['metric_data'][0]['Value'],
self.assertEqual(parameters['MetricData'][0]['Value'],
decimal.Decimal('123.1'))

def test_timestamp_arg(self):
arg = putmetricdata.PutMetricArgument('timestamp',
help_text='timestamp')
parameters = {}
arg.add_to_params(parameters, '2013-09-01')
self.assertEqual(parameters['metric_data'][0]['Timestamp'],
self.assertEqual(parameters['MetricData'][0]['Timestamp'],
'2013-09-01')

def test_dimensions_arg(self):
arg = putmetricdata.PutMetricArgument('dimensions',
help_text='dimensions')
parameters = {}
arg.add_to_params(parameters, 'User=someuser,Stack=test')
self.assertEqual(parameters['metric_data'][0]['Dimensions'],
self.assertEqual(parameters['MetricData'][0]['Dimensions'],
[{"Name": "User", "Value": "someuser"},
{"Name": "Stack", "Value": "test"}])

Expand All @@ -67,9 +67,11 @@ def test_statistics_arg(self):
parameters = {}
arg.add_to_params(parameters,
'Sum=250,Minimum=30,Maximum=70,SampleCount=5')
self.assertEqual(parameters['metric_data'][0]['StatisticValues'],
{'Maximum': '70', 'Minimum': '30',
'SampleCount': '5', 'Sum': '250'})
self.assertEqual(parameters['MetricData'][0]['StatisticValues'],
{'Maximum': decimal.Decimal('70'),
'Minimum': decimal.Decimal('30'),
'SampleCount': decimal.Decimal('5'),
'Sum': decimal.Decimal('250')})

def test_parse_empty_value(self):
arg = putmetricdata.PutMetricArgument('dimensions',
Expand Down

0 comments on commit 57ad680

Please sign in to comment.