Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aws
GitHub Repository: aws/aws-cli
Path: blob/develop/tests/unit/customizations/history/test_show.py
1569 views
1
# Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
#
3
# Licensed under the Apache License, Version 2.0 (the "License"). You
4
# may not use this file except in compliance with the License. A copy of
5
# the License is located at
6
#
7
# http://aws.amazon.com/apache2.0/
8
#
9
# or in the "license" file accompanying this file. This file is
10
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
# ANY KIND, either express or implied. See the License for the specific
12
# language governing permissions and limitations under the License.
13
import os
14
import argparse
15
import xml.dom.minidom
16
17
from botocore.session import Session
18
19
from awscli.compat import ensure_text_type
20
from awscli.compat import BytesIO
21
from awscli.utils import OutputStreamFactory
22
from awscli.testutils import unittest, mock, FileCreator
23
from awscli.customizations.history.show import ShowCommand
24
from awscli.customizations.history.show import Formatter
25
from awscli.customizations.history.show import DetailedFormatter
26
from awscli.customizations.history.db import DatabaseRecordReader
27
28
29
class FakeError(Exception):
30
pass
31
32
33
class RecordingFormatter(Formatter):
34
def __init__(self, output=None, include=None, exclude=None):
35
super(RecordingFormatter, self).__init__(
36
output=output, include=include, exclude=exclude)
37
self.history = []
38
39
def _display(self, event_record):
40
self.history.append(event_record)
41
42
43
class TestFormatter(unittest.TestCase):
44
def test_display_no_filters(self):
45
formatter = RecordingFormatter()
46
event_record = {'event_type': 'my_event'}
47
other_event_record = {'event_type': 'my_other_event'}
48
formatter.display(event_record)
49
formatter.display(other_event_record)
50
self.assertEqual(
51
formatter.history,
52
[
53
event_record,
54
other_event_record
55
]
56
)
57
58
def test_include_specified_event_type(self):
59
formatter = RecordingFormatter(include=['my_event'])
60
event_record = {'event_type': 'my_event'}
61
formatter.display(event_record)
62
self.assertEqual(formatter.history, [event_record])
63
64
def test_include_on_unspecified_event_type(self):
65
formatter = RecordingFormatter(include=['my_event'])
66
other_event_record = {'event_type': 'my_other_event'}
67
formatter.display(other_event_record)
68
self.assertEqual(formatter.history, [])
69
70
def test_exclude_on_specified_event_type(self):
71
formatter = RecordingFormatter(exclude=['my_event'])
72
event_record = {'event_type': 'my_event'}
73
formatter.display(event_record)
74
self.assertEqual(formatter.history, [])
75
76
def test_exclude_on_unspecified_event_type(self):
77
formatter = RecordingFormatter(exclude=['my_event'])
78
other_event_record = {'event_type': 'my_other_event'}
79
formatter.display(other_event_record)
80
self.assertEqual(
81
formatter.history, [other_event_record])
82
83
def test_raises_error_when_both_include_and_exclude(self):
84
with self.assertRaises(ValueError):
85
Formatter(include=['one_event'], exclude=['other_event'])
86
87
88
class TestDetailedFormatter(unittest.TestCase):
89
def setUp(self):
90
self.output = BytesIO()
91
self.formatter = DetailedFormatter(self.output, colorize=False)
92
93
def get_pretty_xml(self, xml_str):
94
xml_dom = xml.dom.minidom.parseString(xml_str)
95
return xml_dom.toprettyxml(indent=' '*4, newl='\n')
96
97
def assert_output(self, for_event, contains):
98
self.formatter.display(for_event)
99
collected_output = ensure_text_type(self.output.getvalue())
100
for line in contains:
101
self.assertIn(line, collected_output)
102
103
def test_display_cli_version(self):
104
self.assert_output(
105
for_event={
106
'event_type': 'CLI_VERSION',
107
'id': 'my-id',
108
'payload': 'aws-cli/1.11.188',
109
'timestamp': 86400000,
110
'request_id': None
111
},
112
contains=[
113
'AWS CLI command entered',
114
'with AWS CLI version: aws-cli/1.11.188'
115
]
116
)
117
118
def test_can_use_color(self):
119
self.formatter = DetailedFormatter(self.output, colorize=True)
120
self.assert_output(
121
for_event={
122
'event_type': 'CLI_VERSION',
123
'id': 'my-id',
124
'payload': 'aws-cli/1.11.188',
125
'timestamp': 86400000,
126
'request_id': None
127
},
128
contains=[
129
'\x1b[1mAWS CLI command entered',
130
'\x1b[36mwith AWS CLI version:'
131
]
132
)
133
134
def test_display_cli_arguments(self):
135
self.assert_output(
136
for_event={
137
'event_type': 'CLI_ARGUMENTS',
138
'id': 'my-id',
139
'payload': ['ec2', 'describe-regions'],
140
'timestamp': 86400000,
141
'request_id': None
142
},
143
contains=[
144
"with arguments: ['ec2', 'describe-regions']"
145
]
146
)
147
148
def test_display_api_call(self):
149
self.assert_output(
150
for_event={
151
'event_type': 'API_CALL',
152
'id': 'my-id',
153
'request_id': 'some-id',
154
'payload': {
155
'service': 'ec2',
156
'operation': 'DescribeRegions',
157
'params': {}
158
},
159
'timestamp': 86400000,
160
},
161
contains=[
162
'to service: ec2\n',
163
'using operation: DescribeRegions\n',
164
'with parameters: {}\n'
165
]
166
)
167
168
def test_two_different_api_calls_have_different_numbers(self):
169
event = {
170
'event_type': 'API_CALL',
171
'id': 'my-id',
172
'request_id': 'some-id',
173
'payload': {
174
'service': 'ec2',
175
'operation': 'DescribeRegions',
176
'params': {}
177
},
178
'timestamp': 86400000,
179
}
180
self.formatter.display(event)
181
collected_output = ensure_text_type(self.output.getvalue())
182
self.assertIn('[0] API call made', collected_output)
183
184
other_event = {
185
'event_type': 'API_CALL',
186
'id': 'my-id',
187
'request_id': 'other-id',
188
'payload': {
189
'service': 'ec2',
190
'operation': 'DescribeRegions',
191
'params': {}
192
},
193
'timestamp': 86400000,
194
}
195
self.formatter.display(other_event)
196
new_output = ensure_text_type(self.output.getvalue())[
197
len(collected_output):]
198
self.assertIn('[1] API call made', new_output)
199
200
def test_display_http_request(self):
201
self.assert_output(
202
for_event={
203
'event_type': 'HTTP_REQUEST',
204
'id': 'my-id',
205
'request_id': 'some-id',
206
'payload': {
207
'method': 'GET',
208
'url': 'https://myservice.us-west-2.amazonaws.com',
209
'headers': {},
210
'body': 'This is my body'
211
},
212
'timestamp': 86400000,
213
},
214
contains=[
215
'to URL: https://myservice.us-west-2.amazonaws.com\n',
216
'with method: GET\n',
217
'with headers: {}\n',
218
'with body: This is my body\n'
219
]
220
)
221
222
def test_display_http_request_filter_signature(self):
223
self.assert_output(
224
for_event={
225
'event_type': 'HTTP_REQUEST',
226
'id': 'my-id',
227
'request_id': 'some-id',
228
'payload': {
229
'method': 'GET',
230
'url': 'https://myservice.us-west-2.amazonaws.com',
231
'headers': {
232
'Authorization': (
233
'Signature=d7fa4de082b598a0ac08b756db438c630a6'
234
'cc79c4f3d1636cf69fac0e7c1abcd'
235
)
236
},
237
'body': 'This is my body'
238
},
239
'timestamp': 86400000,
240
},
241
contains=[
242
'"Authorization": "Signature=d7fa..."'
243
]
244
)
245
246
def test_display_http_request_with_streaming_body(self):
247
self.assert_output(
248
for_event={
249
'event_type': 'HTTP_REQUEST',
250
'id': 'my-id',
251
'request_id': 'some-id',
252
'payload': {
253
'method': 'GET',
254
'url': 'https://myservice.us-west-2.amazonaws.com',
255
'headers': {},
256
'body': 'This should not be printed out',
257
'streaming': True
258
},
259
'timestamp': 86400000,
260
},
261
contains=[
262
'with body: The body is a stream and will not be displayed',
263
]
264
)
265
266
def test_display_http_request_with_no_payload(self):
267
self.assert_output(
268
for_event={
269
'event_type': 'HTTP_REQUEST',
270
'id': 'my-id',
271
'request_id': 'some-id',
272
'payload': {
273
'method': 'GET',
274
'url': 'https://myservice.us-west-2.amazonaws.com',
275
'headers': {},
276
'body': None
277
},
278
'timestamp': 86400000,
279
},
280
contains=[
281
'with body: There is no associated body'
282
]
283
)
284
285
def test_display_http_request_with_empty_string_payload(self):
286
self.assert_output(
287
for_event={
288
'event_type': 'HTTP_REQUEST',
289
'id': 'my-id',
290
'request_id': 'some-id',
291
'payload': {
292
'method': 'GET',
293
'url': 'https://myservice.us-west-2.amazonaws.com',
294
'headers': {},
295
'body': ''
296
},
297
'timestamp': 86400000,
298
},
299
contains=[
300
'with body: There is no associated body'
301
]
302
)
303
304
def test_display_http_request_with_xml_payload(self):
305
xml_body = '<?xml version="1.0" ?><foo><bar>text</bar></foo>'
306
self.assert_output(
307
for_event={
308
'event_type': 'HTTP_REQUEST',
309
'id': 'my-id',
310
'request_id': 'some-id',
311
'payload': {
312
'method': 'GET',
313
'url': 'https://myservice.us-west-2.amazonaws.com',
314
'headers': {},
315
'body': xml_body
316
},
317
'timestamp': 86400000,
318
},
319
contains=[
320
'with body: ' + self.get_pretty_xml(xml_body)
321
]
322
)
323
324
def test_display_http_request_with_xml_payload_and_whitespace(self):
325
xml_body = '<?xml version="1.0" ?><foo><bar>text</bar></foo>'
326
self.assert_output(
327
for_event={
328
'event_type': 'HTTP_REQUEST',
329
'id': 'my-id',
330
'request_id': 'some-id',
331
'payload': {
332
'method': 'GET',
333
'url': 'https://myservice.us-west-2.amazonaws.com',
334
'headers': {},
335
'body': self.get_pretty_xml(xml_body)
336
},
337
'timestamp': 86400000,
338
},
339
# The XML should not be prettified more than once if the body
340
# of the request was already prettied.
341
contains=[
342
'with body: ' + self.get_pretty_xml(xml_body)
343
]
344
)
345
346
def test_display_http_request_with_json_struct_payload(self):
347
self.assert_output(
348
for_event={
349
'event_type': 'HTTP_REQUEST',
350
'id': 'my-id',
351
'request_id': 'some-id',
352
'payload': {
353
'method': 'GET',
354
'url': 'https://myservice.us-west-2.amazonaws.com',
355
'headers': {},
356
'body': '{"foo": "bar"}'
357
},
358
'timestamp': 86400000,
359
},
360
contains=[
361
'with body: {\n'
362
' "foo": "bar"\n'
363
'}'
364
]
365
)
366
367
def test_shares_api_number_across_events_of_same_api_call(self):
368
self.assert_output(
369
for_event={
370
'event_type': 'API_CALL',
371
'id': 'my-id',
372
'request_id': 'some-id',
373
'payload': {
374
'service': 'ec2',
375
'operation': 'DescribeRegions',
376
'params': {}
377
},
378
'timestamp': 86400000,
379
},
380
contains=[
381
'[0] API call made'
382
]
383
)
384
self.assert_output(
385
for_event={
386
'event_type': 'HTTP_REQUEST',
387
'id': 'my-id',
388
'request_id': 'some-id',
389
'payload': {
390
'method': 'GET',
391
'url': 'https://myservice.us-west-2.amazonaws.com',
392
'headers': {},
393
'body': 'This is my body'
394
},
395
'timestamp': 86400000,
396
},
397
contains=[
398
'[0] HTTP request sent'
399
]
400
)
401
402
def test_display_http_response(self):
403
self.assert_output(
404
for_event={
405
'event_type': 'HTTP_RESPONSE',
406
'id': 'my-id',
407
'request_id': 'some-id',
408
'payload': {
409
'status_code': 200,
410
'headers': {},
411
'body': 'This is my body'
412
},
413
'timestamp': 86400000,
414
},
415
contains=[
416
'[0] HTTP response received',
417
'with status code: 200\n',
418
'with headers: {}\n',
419
'with body: This is my body\n'
420
421
]
422
)
423
424
def test_display_http_response_with_streaming_body(self):
425
self.assert_output(
426
for_event={
427
'event_type': 'HTTP_RESPONSE',
428
'id': 'my-id',
429
'request_id': 'some-id',
430
'payload': {
431
'status_code': 200,
432
'headers': {},
433
'body': 'This should not be printed out',
434
'streaming': True
435
},
436
'timestamp': 86400000,
437
},
438
contains=[
439
'with body: The body is a stream and will not be displayed'
440
]
441
)
442
443
def test_display_http_response_with_no_payload(self):
444
self.assert_output(
445
for_event={
446
'event_type': 'HTTP_RESPONSE',
447
'id': 'my-id',
448
'request_id': 'some-id',
449
'payload': {
450
'status_code': 200,
451
'headers': {},
452
'body': None
453
},
454
'timestamp': 86400000,
455
},
456
contains=[
457
'with body: There is no associated body'
458
]
459
)
460
461
def test_display_http_response_with_empty_string_payload(self):
462
self.assert_output(
463
for_event={
464
'event_type': 'HTTP_RESPONSE',
465
'id': 'my-id',
466
'request_id': 'some-id',
467
'payload': {
468
'status_code': 200,
469
'headers': {},
470
'body': ''
471
},
472
'timestamp': 86400000,
473
},
474
contains=[
475
'with body: There is no associated body'
476
]
477
)
478
479
def test_display_http_response_with_xml_payload(self):
480
xml_body = '<?xml version="1.0" ?><foo><bar>text</bar></foo>'
481
self.assert_output(
482
for_event={
483
'event_type': 'HTTP_RESPONSE',
484
'id': 'my-id',
485
'request_id': 'some-id',
486
'payload': {
487
'status_code': 200,
488
'headers': {},
489
'body': xml_body
490
},
491
'timestamp': 86400000,
492
},
493
contains=[
494
'with body: ' + self.get_pretty_xml(xml_body)
495
]
496
)
497
498
def test_display_http_response_with_xml_payload_and_whitespace(self):
499
xml_body = '<?xml version="1.0" ?><foo><bar>text</bar></foo>'
500
self.assert_output(
501
for_event={
502
'event_type': 'HTTP_RESPONSE',
503
'id': 'my-id',
504
'request_id': 'some-id',
505
'payload': {
506
'status_code': 200,
507
'headers': {},
508
'body': self.get_pretty_xml(xml_body)
509
},
510
'timestamp': 86400000,
511
},
512
# The XML should not be prettified more than once if the body
513
# of the response was already prettied.
514
contains=[
515
'with body: ' + self.get_pretty_xml(xml_body)
516
]
517
)
518
519
def test_display_http_response_with_json_struct_payload(self):
520
self.assert_output(
521
for_event={
522
'event_type': 'HTTP_RESPONSE',
523
'id': 'my-id',
524
'request_id': 'some-id',
525
'payload': {
526
'status_code': 200,
527
'headers': {},
528
'body': '{"foo": "bar"}'
529
},
530
'timestamp': 86400000,
531
},
532
contains=[
533
'with body: {\n',
534
' "foo": "bar"\n',
535
'}',
536
]
537
)
538
539
def test_display_parsed_response(self):
540
self.assert_output(
541
for_event={
542
'event_type': 'PARSED_RESPONSE',
543
'id': 'my-id',
544
'request_id': 'some-id',
545
'payload': {},
546
'timestamp': 86400000,
547
},
548
contains=[
549
'[0] HTTP response parsed',
550
'parsed to: {}'
551
]
552
)
553
554
def test_display_cli_rc(self):
555
self.assert_output(
556
for_event={
557
'event_type': 'CLI_RC',
558
'id': 'my-id',
559
'payload': 0,
560
'timestamp': 86400000,
561
'request_id': None
562
},
563
contains=[
564
'AWS CLI command exited',
565
'with return code: 0'
566
]
567
)
568
569
def test_display_unknown_type(self):
570
event = {
571
'event_type': 'UNKNOWN',
572
'id': 'my-id',
573
'payload': 'foo',
574
'timestamp': 86400000,
575
'request_id': None
576
}
577
self.formatter.display(event)
578
collected_output = ensure_text_type(self.output.getvalue())
579
self.assertEqual('', collected_output)
580
581
582
class TestShowCommand(unittest.TestCase):
583
def setUp(self):
584
self.session = mock.Mock(Session)
585
586
self.output_stream_factory = mock.Mock(OutputStreamFactory)
587
588
# MagicMock is needed because it can handle context managers.
589
# Normal Mock will throw AttributeErrors
590
output_stream_context = mock.MagicMock()
591
self.output_stream = mock.Mock()
592
output_stream_context.__enter__.return_value = self.output_stream
593
594
self.output_stream_factory.get_pager_stream.return_value = \
595
output_stream_context
596
597
self.output_stream_factory.get_stdout_stream.return_value = \
598
output_stream_context
599
600
self.db_reader = mock.Mock(DatabaseRecordReader)
601
self.db_reader.iter_latest_records.return_value = []
602
self.db_reader.iter_records.return_value = []
603
604
self.show_cmd = ShowCommand(
605
self.session, self.db_reader, self.output_stream_factory)
606
607
self.formatter = mock.Mock(Formatter)
608
self.add_formatter('mock', self.formatter)
609
610
self.parsed_args = argparse.Namespace()
611
self.parsed_args.format = 'mock'
612
self.parsed_args.include = None
613
self.parsed_args.exclude = None
614
615
self.parsed_globals = argparse.Namespace()
616
self.parsed_globals.color = 'auto'
617
618
self.files = FileCreator()
619
620
def tearDown(self):
621
self.files.remove_all()
622
623
def test_does_close_connection(self):
624
self.parsed_args.command_id = 'latest'
625
self.show_cmd._run_main(self.parsed_args, self.parsed_globals)
626
self.assertTrue(self.db_reader.close.called)
627
628
def test_does_close_connection_with_error(self):
629
self.parsed_args.command_id = 'latest'
630
self.db_reader.iter_latest_records.side_effect = FakeError('ERROR')
631
with self.assertRaises(FakeError):
632
self.show_cmd._run_main(self.parsed_args, self.parsed_globals)
633
self.assertTrue(self.db_reader.close.called)
634
635
def test_detects_if_history_exists(self):
636
self.show_cmd = ShowCommand(self.session)
637
self.parsed_args.command_id = 'latest'
638
639
db_filename = os.path.join(self.files.rootdir, 'name.db')
640
with mock.patch('os.environ', {'AWS_CLI_HISTORY_FILE': db_filename}):
641
with self.assertRaisesRegex(
642
RuntimeError, 'Could not locate history'):
643
self.show_cmd._run_main(self.parsed_args, self.parsed_globals)
644
645
def add_formatter(self, formatter_name, formatter):
646
# We do not want to be adding to the dictionary directly because
647
# the dictionary is scoped to the class as well so even a formatter
648
# to an instance of the class will add it to the class as well.
649
formatters = self.show_cmd.FORMATTERS.copy()
650
formatters[formatter_name] = formatter
651
self.show_cmd.FORMATTERS = formatters
652
653
def test_show_latest(self):
654
self.parsed_args.command_id = 'latest'
655
self.show_cmd._run_main(self.parsed_args, self.parsed_globals)
656
self.assertTrue(self.db_reader.iter_latest_records.called)
657
658
def test_show_specific_id(self):
659
self.parsed_args.command_id = 'some-specific-id'
660
self.show_cmd._run_main(self.parsed_args, self.parsed_globals)
661
self.assertEqual(
662
self.db_reader.iter_records.call_args,
663
mock.call('some-specific-id')
664
)
665
666
def test_uses_format(self):
667
formatter = mock.Mock(Formatter)
668
self.add_formatter('myformatter', formatter)
669
670
return_record = {'id': 'myid', 'event_type': 'CLI_RC', 'payload': 0}
671
self.db_reader.iter_latest_records.return_value = [return_record]
672
673
self.parsed_args.format = 'myformatter'
674
self.parsed_args.command_id = 'latest'
675
self.show_cmd._run_main(self.parsed_args, self.parsed_globals)
676
677
self.assertTrue(formatter.called)
678
self.assertEqual(
679
formatter.return_value.display.call_args_list,
680
[mock.call(return_record)]
681
)
682
683
def test_uses_include(self):
684
self.parsed_args.command_id = 'latest'
685
self.parsed_args.include = ['API_CALL']
686
self.parsed_args.exclude = None
687
self.show_cmd._run_main(self.parsed_args, self.parsed_globals)
688
689
self.assertEqual(
690
self.formatter.call_args,
691
mock.call(
692
include=['API_CALL'], exclude=None,
693
output=self.output_stream)
694
)
695
696
def test_uses_exclude(self):
697
self.parsed_args.command_id = 'latest'
698
self.parsed_args.include = None
699
self.parsed_args.exclude = ['CLI_RC']
700
self.show_cmd._run_main(self.parsed_args, self.parsed_globals)
701
702
self.assertEqual(
703
self.formatter.call_args,
704
mock.call(
705
include=None, exclude=['CLI_RC'],
706
output=self.output_stream)
707
)
708
709
def test_raises_error_when_both_include_and_exclude(self):
710
self.parsed_args.include = ['API_CALL']
711
self.parsed_args.exclude = ['CLI_RC']
712
with self.assertRaises(ValueError):
713
self.show_cmd._run_main(self.parsed_args, self.parsed_globals)
714
715
@mock.patch('awscli.customizations.history.commands.is_windows', False)
716
@mock.patch('awscli.customizations.history.commands.is_a_tty')
717
def test_detailed_formatter_is_a_tty(self, mock_is_a_tty):
718
mock_is_a_tty.return_value = True
719
self.formatter = mock.Mock(DetailedFormatter)
720
self.add_formatter('detailed', self.formatter)
721
self.parsed_args.format = 'detailed'
722
self.parsed_args.command_id = 'latest'
723
724
self.show_cmd._run_main(self.parsed_args, self.parsed_globals)
725
call = self.output_stream_factory.get_pager_stream.call_args
726
self.assertEqual(
727
self.formatter.call_args,
728
mock.call(
729
include=None, exclude=None,
730
output=self.output_stream, colorize=True
731
)
732
)
733
734
@mock.patch('awscli.customizations.history.commands.is_windows', False)
735
@mock.patch('awscli.customizations.history.commands.is_a_tty')
736
def test_detailed_formatter_not_a_tty(self, mock_is_a_tty):
737
mock_is_a_tty.return_value = False
738
self.formatter = mock.Mock(DetailedFormatter)
739
self.add_formatter('detailed', self.formatter)
740
self.parsed_args.format = 'detailed'
741
self.parsed_args.command_id = 'latest'
742
743
self.show_cmd._run_main(self.parsed_args, self.parsed_globals)
744
self.assertTrue(
745
self.output_stream_factory.get_stdout_stream.called)
746
self.assertEqual(
747
self.formatter.call_args,
748
mock.call(
749
include=None, exclude=None,
750
output=self.output_stream, colorize=False
751
)
752
)
753
754
@mock.patch('awscli.customizations.history.commands.is_windows', True)
755
def test_detailed_formatter_no_color_for_windows(self):
756
self.formatter = mock.Mock(DetailedFormatter)
757
self.add_formatter('detailed', self.formatter)
758
self.parsed_args.format = 'detailed'
759
self.parsed_args.command_id = 'latest'
760
761
self.show_cmd._run_main(self.parsed_args, self.parsed_globals)
762
self.assertEqual(
763
self.formatter.call_args,
764
mock.call(
765
include=None, exclude=None,
766
output=self.output_stream, colorize=False
767
)
768
)
769
770
@mock.patch('awscli.customizations.history.commands.is_windows', True)
771
@mock.patch('awscli.customizations.history.commands.is_a_tty')
772
def test_force_color(self, mock_is_a_tty):
773
self.formatter = mock.Mock(DetailedFormatter)
774
self.add_formatter('detailed', self.formatter)
775
self.parsed_args.format = 'detailed'
776
self.parsed_args.command_id = 'latest'
777
778
self.parsed_globals.color = 'on'
779
# Even with settings that would typically turn off color, it
780
# should be turned on because it was explicitly turned on
781
mock_is_a_tty.return_value = False
782
783
self.show_cmd._run_main(self.parsed_args, self.parsed_globals)
784
self.assertEqual(
785
self.formatter.call_args,
786
mock.call(
787
include=None, exclude=None,
788
output=self.output_stream, colorize=True
789
)
790
)
791
792
@mock.patch('awscli.customizations.history.commands.is_windows', False)
793
@mock.patch('awscli.customizations.history.commands.is_a_tty')
794
def test_disable_color(self, mock_is_a_tty):
795
self.formatter = mock.Mock(DetailedFormatter)
796
self.add_formatter('detailed', self.formatter)
797
self.parsed_args.format = 'detailed'
798
self.parsed_args.command_id = 'latest'
799
800
self.parsed_globals.color = 'off'
801
# Even with settings that would typically enable color, it
802
# should be turned off because it was explicitly turned off
803
mock_is_a_tty.return_value = True
804
805
self.show_cmd._run_main(self.parsed_args, self.parsed_globals)
806
self.assertEqual(
807
self.formatter.call_args,
808
mock.call(
809
include=None, exclude=None,
810
output=self.output_stream, colorize=False
811
)
812
)
813
814