import base64
import contextlib
import io
import sys
from botocore.compat import json
import platform
from awscli.formatter import JSONFormatter
from awscli.testutils import BaseAWSCommandParamsTest, unittest
from awscli.testutils import mock, skip_if_windows
from awscli.compat import StringIO, get_stdout_text_writer
class TestGetPasswordData(BaseAWSCommandParamsTest):
COMMAND = 'iam add-user-to-group --group-name foo --user-name bar'
def setUp(self):
super(TestGetPasswordData, self).setUp()
self.parsed_response = {}
def test_empty_dict_response_prints_nothing(self):
self.parsed_response = {}
stdout = self.run_cmd(self.COMMAND, expected_rc=0)[0]
self.assertEqual(stdout, '')
def test_empty_list_prints_list(self):
self.parsed_response = []
stdout = self.run_cmd(self.COMMAND, expected_rc=0)[0]
self.assertEqual(stdout, '[]\n')
def test_empty_string_prints_nothing(self):
self.parsed_response = ''
stdout = self.run_cmd(self.COMMAND, expected_rc=0)[0]
self.assertEqual(stdout, '""\n')
class TestListUsers(BaseAWSCommandParamsTest):
def setUp(self):
super(TestListUsers, self).setUp()
self.parsed_response = {
'Users': [
{
"UserName": "testuser-50",
"Path": "/",
"CreateDate": "2013-02-12T19:08:52Z",
"UserId": "EXAMPLEUSERID",
"Arn": "arn:aws:iam::12345:user/testuser1"
},
{
"UserName": "testuser-51",
"Path": "/",
"CreateDate": "2012-10-14T23:53:39Z",
"UserId": u"EXAMPLEUSERID",
"Arn": "arn:aws:iam::123456:user/testuser2"
},
]
}
def test_json_response(self):
output = self.run_cmd('iam list-users', expected_rc=0)[0]
parsed_output = json.loads(output)
self.assertIn('Users', parsed_output)
self.assertEqual(len(parsed_output['Users']), 2)
self.assertEqual(sorted(parsed_output['Users'][0].keys()),
['Arn', 'CreateDate', 'Path', 'UserId', 'UserName'])
def test_jmespath_json_response(self):
jmespath_query = 'Users[*].UserName'
output = self.run_cmd('iam list-users --query %s' % jmespath_query,
expected_rc=0)[0]
parsed_output = json.loads(output)
self.assertEqual(parsed_output, ['testuser-50', 'testuser-51'])
def test_zero_value_is_printed(self):
jmespath_query = '`0`'
output = self.run_cmd('iam list-users --query %s' % jmespath_query,
expected_rc=0)[0]
self.assertEqual(output, '0\n')
def test_unknown_output_type_from_env_var(self):
self.environ['AWS_DEFAULT_OUTPUT'] = 'bad-output-type'
self.run_cmd('iam list-users', expected_rc=255)
@skip_if_windows('Encoding tests only supported on mac/linux')
def test_json_prints_unicode_chars(self):
self.parsed_response['Users'][1]['UserId'] = u'\u2713'
output = self.run_cmd('iam list-users', expected_rc=0)[0]
with mock.patch('sys.stdout', StringIO()) as f:
out = get_stdout_text_writer()
out.write(u'\u2713')
expected = f.getvalue()
self.assertNotIn('\\u2713', output)
self.assertIn(expected, output)
class TestFormattersHandleClosedPipes(unittest.TestCase):
def test_fully_buffered_handles_io_error(self):
args = mock.Mock(query=None)
operation = mock.Mock(can_paginate=False)
response = '{"Foo": "Bar"}'
fake_closed_stream = mock.Mock(spec=StringIO)
fake_closed_stream.flush.side_effect = IOError
formatter = JSONFormatter(args)
formatter('command_name', response, stream=fake_closed_stream)
fake_closed_stream.flush.assert_called_with()
class TestBinaryData(unittest.TestCase):
def test_binary_data_gets_base64_encoded(self):
args = mock.Mock(query=None)
raw_bytes = b'foo'
response = {'BinaryValue': raw_bytes}
stdout_b = io.BytesIO()
stdout = io.TextIOWrapper(stdout_b, newline='\n')
formatter = JSONFormatter(args)
with contextlib.redirect_stdout(stdout):
formatter('command-name', response, sys.stdout)
stdout.flush()
assert (
stdout_b.getvalue()
== (
'{\n'
f' "BinaryValue": "{base64.b64encode(raw_bytes).decode("utf-8")}"\n'
'}\n'
).encode()
)