Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aws
GitHub Repository: aws/aws-cli
Path: blob/develop/tests/unit/output/test_json_output.py
1567 views
1
#!/usr/bin/env python
2
# Copyright 2012-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
#
4
# Licensed under the Apache License, Version 2.0 (the "License"). You
5
# may not use this file except in compliance with the License. A copy of
6
# the License is located at
7
#
8
# http://aws.amazon.com/apache2.0/
9
#
10
# or in the "license" file accompanying this file. This file is
11
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
12
# ANY KIND, either express or implied. See the License for the specific
13
# language governing permissions and limitations under the License.
14
import base64
15
import contextlib
16
import io
17
import sys
18
from botocore.compat import json
19
import platform
20
from awscli.formatter import JSONFormatter
21
22
from awscli.testutils import BaseAWSCommandParamsTest, unittest
23
from awscli.testutils import mock, skip_if_windows
24
from awscli.compat import StringIO, get_stdout_text_writer
25
26
27
class TestGetPasswordData(BaseAWSCommandParamsTest):
28
29
COMMAND = 'iam add-user-to-group --group-name foo --user-name bar'
30
31
def setUp(self):
32
super(TestGetPasswordData, self).setUp()
33
self.parsed_response = {}
34
35
def test_empty_dict_response_prints_nothing(self):
36
# This is the default response, but we want to be explicit
37
# that we're returning an empty dict.
38
self.parsed_response = {}
39
stdout = self.run_cmd(self.COMMAND, expected_rc=0)[0]
40
self.assertEqual(stdout, '')
41
42
def test_empty_list_prints_list(self):
43
self.parsed_response = []
44
stdout = self.run_cmd(self.COMMAND, expected_rc=0)[0]
45
self.assertEqual(stdout, '[]\n')
46
47
def test_empty_string_prints_nothing(self):
48
self.parsed_response = ''
49
stdout = self.run_cmd(self.COMMAND, expected_rc=0)[0]
50
self.assertEqual(stdout, '""\n')
51
52
53
class TestListUsers(BaseAWSCommandParamsTest):
54
55
def setUp(self):
56
super(TestListUsers, self).setUp()
57
self.parsed_response = {
58
'Users': [
59
{
60
"UserName": "testuser-50",
61
"Path": "/",
62
"CreateDate": "2013-02-12T19:08:52Z",
63
"UserId": "EXAMPLEUSERID",
64
"Arn": "arn:aws:iam::12345:user/testuser1"
65
},
66
{
67
"UserName": "testuser-51",
68
"Path": "/",
69
"CreateDate": "2012-10-14T23:53:39Z",
70
"UserId": u"EXAMPLEUSERID",
71
"Arn": "arn:aws:iam::123456:user/testuser2"
72
},
73
]
74
}
75
76
def test_json_response(self):
77
output = self.run_cmd('iam list-users', expected_rc=0)[0]
78
parsed_output = json.loads(output)
79
self.assertIn('Users', parsed_output)
80
self.assertEqual(len(parsed_output['Users']), 2)
81
self.assertEqual(sorted(parsed_output['Users'][0].keys()),
82
['Arn', 'CreateDate', 'Path', 'UserId', 'UserName'])
83
84
def test_jmespath_json_response(self):
85
jmespath_query = 'Users[*].UserName'
86
output = self.run_cmd('iam list-users --query %s' % jmespath_query,
87
expected_rc=0)[0]
88
parsed_output = json.loads(output)
89
self.assertEqual(parsed_output, ['testuser-50', 'testuser-51'])
90
91
def test_zero_value_is_printed(self):
92
# Even though the integer 0 is false-like, we still
93
# should be printing it to stdout if a jmespath query
94
# evaluates to 0.
95
jmespath_query = '`0`'
96
output = self.run_cmd('iam list-users --query %s' % jmespath_query,
97
expected_rc=0)[0]
98
self.assertEqual(output, '0\n')
99
100
def test_unknown_output_type_from_env_var(self):
101
# argparse already handles the case with a bad --output
102
# specified on the CLI, we need to verify that a bad
103
# output format from the env var still gives an error.
104
self.environ['AWS_DEFAULT_OUTPUT'] = 'bad-output-type'
105
self.run_cmd('iam list-users', expected_rc=255)
106
107
@skip_if_windows('Encoding tests only supported on mac/linux')
108
def test_json_prints_unicode_chars(self):
109
self.parsed_response['Users'][1]['UserId'] = u'\u2713'
110
output = self.run_cmd('iam list-users', expected_rc=0)[0]
111
with mock.patch('sys.stdout', StringIO()) as f:
112
out = get_stdout_text_writer()
113
out.write(u'\u2713')
114
expected = f.getvalue()
115
# We should not see the '\u<hex>' for of the unicode character.
116
# It should be encoded into the default encoding.
117
self.assertNotIn('\\u2713', output)
118
self.assertIn(expected, output)
119
120
121
class TestFormattersHandleClosedPipes(unittest.TestCase):
122
def test_fully_buffered_handles_io_error(self):
123
args = mock.Mock(query=None)
124
operation = mock.Mock(can_paginate=False)
125
response = '{"Foo": "Bar"}'
126
fake_closed_stream = mock.Mock(spec=StringIO)
127
fake_closed_stream.flush.side_effect = IOError
128
formatter = JSONFormatter(args)
129
formatter('command_name', response, stream=fake_closed_stream)
130
# We should not have let the IOError propagate, but
131
# we still should have called the flush() on the
132
# stream.
133
fake_closed_stream.flush.assert_called_with()
134
135
136
class TestBinaryData(unittest.TestCase):
137
def test_binary_data_gets_base64_encoded(self):
138
args = mock.Mock(query=None)
139
raw_bytes = b'foo'
140
response = {'BinaryValue': raw_bytes}
141
stdout_b = io.BytesIO()
142
stdout = io.TextIOWrapper(stdout_b, newline='\n')
143
formatter = JSONFormatter(args)
144
145
with contextlib.redirect_stdout(stdout):
146
formatter('command-name', response, sys.stdout)
147
stdout.flush()
148
149
assert (
150
stdout_b.getvalue()
151
== (
152
'{\n'
153
f' "BinaryValue": "{base64.b64encode(raw_bytes).decode("utf-8")}"\n'
154
'}\n'
155
).encode()
156
)
157
158