Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aws
GitHub Repository: aws/aws-cli
Path: blob/develop/tests/unit/test_completer.py
1566 views
1
# Copyright 2012-2013 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 pprint
14
import difflib
15
16
from botocore.compat import OrderedDict
17
from botocore.model import OperationModel
18
from awscli.clidriver import (
19
CLIDriver, ServiceCommand, ServiceOperation, CLICommand)
20
from awscli.arguments import BaseCLIArgument, CustomArgument
21
from awscli.help import ProviderHelpCommand
22
from awscli.completer import Completer
23
from awscli.testutils import mock, unittest
24
from awscli.customizations.commands import BasicCommand
25
26
27
class BaseCompleterTest(unittest.TestCase):
28
def setUp(self):
29
self.clidriver_creator = MockCLIDriverFactory()
30
31
def assert_completion(self, completer, cmdline, expected_results,
32
point=None):
33
if point is None:
34
point = len(cmdline)
35
actual = set(completer.complete(cmdline, point))
36
expected = set(expected_results)
37
38
if not actual == expected:
39
# Borrowed from assertDictEqual, though this doesn't
40
# handle the case when unicode literals are used in one
41
# dict but not in the other (and we want to consider them
42
# as being equal).
43
pretty_d1 = pprint.pformat(actual, width=1).splitlines()
44
pretty_d2 = pprint.pformat(expected, width=1).splitlines()
45
diff = ('\n' + '\n'.join(difflib.ndiff(pretty_d1, pretty_d2)))
46
raise AssertionError("Results are not equal:\n%s" % diff)
47
self.assertEqual(actual, expected)
48
49
50
class TestCompleter(BaseCompleterTest):
51
def test_complete_services(self):
52
commands = {
53
'subcommands': {
54
'foo': {},
55
'bar': {
56
'subcommands': {
57
'baz': {}
58
}
59
}
60
},
61
'arguments': []
62
}
63
completer = Completer(
64
self.clidriver_creator.create_clidriver(commands))
65
self.assert_completion(completer, 'aws ', ['foo', 'bar'])
66
67
def test_complete_partial_service_name(self):
68
commands = {
69
'subcommands': {
70
'cloudfront': {},
71
'cloudformation': {},
72
'cloudhsm': {},
73
'sts': {}
74
},
75
'arguments': []
76
}
77
completer = Completer(
78
self.clidriver_creator.create_clidriver(commands))
79
self.assert_completion(completer, 'aws cloud', [
80
'cloudfront', 'cloudformation', 'cloudhsm'])
81
self.assert_completion(completer, 'aws cloudf', [
82
'cloudfront', 'cloudformation'])
83
self.assert_completion(completer, 'aws cloudfr', ['cloudfront'])
84
self.assert_completion(completer, 'aws cloudfront', [])
85
86
def test_complete_on_invalid_service(self):
87
commands = {
88
'subcommands': {
89
'foo': {},
90
'bar': {
91
'subcommands': {
92
'baz': {}
93
}
94
}
95
},
96
'arguments': []
97
}
98
completer = Completer(
99
self.clidriver_creator.create_clidriver(commands))
100
self.assert_completion(completer, 'aws bin', [])
101
102
def test_complete_top_level_args(self):
103
commands = {
104
'subcommands': {},
105
'arguments': ['foo', 'bar']
106
}
107
completer = Completer(
108
self.clidriver_creator.create_clidriver(commands))
109
self.assert_completion(completer, 'aws --', ['--foo', '--bar'])
110
111
def test_complete_partial_top_level_arg(self):
112
commands = {
113
'subcommands': {},
114
'arguments': ['foo', 'bar', 'foobar', 'fubar']
115
}
116
completer = Completer(
117
self.clidriver_creator.create_clidriver(commands))
118
self.assert_completion(completer, 'aws --f', [
119
'--foo', '--fubar', '--foobar'])
120
self.assert_completion(completer, 'aws --fo', [
121
'--foo', '--foobar'])
122
self.assert_completion(completer, 'aws --foob', ['--foobar'])
123
self.assert_completion(completer, 'aws --foobar', [])
124
125
def test_complete_top_level_arg_with_arg_already_used(self):
126
commands = {
127
'subcommands': {
128
'baz': {}
129
},
130
'arguments': ['foo', 'bar']
131
}
132
completer = Completer(
133
self.clidriver_creator.create_clidriver(commands))
134
self.assert_completion(completer, 'aws --foo --f', [])
135
136
def test_complete_service_commands(self):
137
commands = {
138
'subcommands': {
139
'foo': {
140
'subcommands': {
141
'bar': {
142
'arguments': ['bin']
143
},
144
'baz': {}
145
}
146
}
147
},
148
'arguments': []
149
}
150
completer = Completer(
151
self.clidriver_creator.create_clidriver(commands))
152
self.assert_completion(completer, 'aws foo ', ['bar', 'baz'])
153
154
def test_complete_partial_service_commands(self):
155
commands = {
156
'subcommands': {
157
'foo': {
158
'subcommands': {
159
'barb': {
160
'arguments': ['nil']
161
},
162
'baz': {},
163
'biz': {},
164
'foobar': {}
165
}
166
}
167
},
168
'arguments': []
169
}
170
completer = Completer(
171
self.clidriver_creator.create_clidriver(commands))
172
self.assert_completion(completer, 'aws foo b', ['barb', 'baz', 'biz'])
173
self.assert_completion(completer, 'aws foo ba', ['barb', 'baz'])
174
self.assert_completion(completer, 'aws foo bar', ['barb'])
175
self.assert_completion(completer, 'aws foo barb', [])
176
177
def test_complete_service_arguments(self):
178
commands = {
179
'subcommands': {
180
'foo': {}
181
},
182
'arguments': ['baz', 'bin']
183
}
184
completer = Completer(
185
self.clidriver_creator.create_clidriver(commands))
186
self.assert_completion(completer, 'aws foo --', ['--baz', '--bin'])
187
188
def test_complete_partial_service_arguments(self):
189
commands = {
190
'subcommands': {
191
'biz': {}
192
},
193
'arguments': ['foo', 'bar', 'foobar', 'fubar']
194
}
195
completer = Completer(
196
self.clidriver_creator.create_clidriver(commands))
197
self.assert_completion(completer, 'aws biz --f', [
198
'--foo', '--fubar', '--foobar'])
199
self.assert_completion(completer, 'aws biz --fo', [
200
'--foo', '--foobar'])
201
self.assert_completion(completer, 'aws biz --foob', ['--foobar'])
202
203
def test_complete_service_arg_with_arg_already_used(self):
204
commands = {
205
'subcommands': {
206
'baz': {}
207
},
208
'arguments': ['foo', 'bar']
209
}
210
completer = Completer(
211
self.clidriver_creator.create_clidriver(commands))
212
self.assert_completion(completer, 'aws baz --foo --f', [])
213
214
def test_complete_operation_arguments(self):
215
commands = {
216
'subcommands': {
217
'foo': {'subcommands': {
218
'bar': {'arguments': ['baz']}
219
}}
220
},
221
'arguments': ['bin']
222
}
223
completer = Completer(
224
self.clidriver_creator.create_clidriver(commands))
225
self.assert_completion(completer, 'aws foo bar --', ['--baz', '--bin'])
226
227
def test_complete_partial_operation_arguments(self):
228
commands = {
229
'subcommands': {
230
'foo': {'subcommands': {
231
'bar': {'arguments': ['base', 'baz', 'air']}
232
}}
233
},
234
'arguments': ['bin']
235
}
236
completer = Completer(
237
self.clidriver_creator.create_clidriver(commands))
238
self.assert_completion(completer, 'aws foo bar --b', [
239
'--base', '--baz', '--bin'])
240
self.assert_completion(completer, 'aws foo bar --ba', [
241
'--base', '--baz'])
242
self.assert_completion(completer, 'aws foo bar --bas', ['--base'])
243
self.assert_completion(completer, 'aws foo bar --base', [])
244
245
def test_complete_operation_arg_when_arg_already_used(self):
246
commands = {
247
'subcommands': {
248
'foo': {'subcommands': {
249
'bar': {'arguments': ['baz']}
250
}}
251
},
252
'arguments': []
253
}
254
completer = Completer(
255
self.clidriver_creator.create_clidriver(commands))
256
self.assert_completion(completer, 'aws foo bar --baz --b', [])
257
258
def test_complete_positional_argument(self):
259
commands = {
260
'subcommands': {
261
'foo': {'subcommands': {
262
'bar': {'arguments': [
263
'baz',
264
CustomArgument('bin', positional_arg=True)
265
]}
266
}}
267
},
268
'arguments': []
269
}
270
completer = Completer(
271
self.clidriver_creator.create_clidriver(commands))
272
self.assert_completion(completer, 'aws foo bar --bin ', [])
273
self.assert_completion(completer, 'aws foo bar --bin blah --',
274
['--baz'])
275
276
def test_complete_undocumented_command(self):
277
class UndocumentedCommand(CLICommand):
278
_UNDOCUMENTED = True
279
commands = {
280
'subcommands': {
281
'foo': {},
282
'bar': UndocumentedCommand()
283
},
284
'arguments': []
285
}
286
completer = Completer(
287
self.clidriver_creator.create_clidriver(commands))
288
self.assert_completion(completer, 'aws ', ['foo'])
289
290
291
class TestCompleteCustomCommands(BaseCompleterTest):
292
def setUp(self):
293
super(TestCompleteCustomCommands, self).setUp()
294
custom_arguments = [
295
{'name': 'recursive'},
296
{'name': 'sse'}
297
]
298
custom_commands = [
299
self.create_custom_command('mb'),
300
self.create_custom_command('mv'),
301
self.create_custom_command('cp', arguments=custom_arguments)
302
]
303
custom_service = self.create_custom_command('s3', custom_commands)
304
clidriver = self.clidriver_creator.create_clidriver({
305
'subcommands': {
306
's3': custom_service['command_class'](mock.Mock()),
307
'foo': {}
308
},
309
'arguments': ['bar']
310
})
311
self.completer = Completer(clidriver)
312
313
def create_custom_command(self, name, sub_commands=None, arguments=None):
314
arg_table = arguments
315
if arg_table is None:
316
arg_table = []
317
318
subs = sub_commands
319
if subs is None:
320
subs = []
321
322
class CustomCommand(BasicCommand):
323
NAME = name
324
ARG_TABLE = arg_table
325
SUBCOMMANDS = subs
326
return {'name': name, 'command_class': CustomCommand}
327
328
def test_complete_custom_service(self):
329
self.assert_completion(self.completer, 'aws ', ['s3', 'foo'])
330
331
def test_complete_custom_command(self):
332
self.assert_completion(self.completer, 'aws s3 ', ['mb', 'mv', 'cp'])
333
334
def test_complete_partial_custom_command(self):
335
self.assert_completion(self.completer, 'aws s3 m', ['mb', 'mv'])
336
337
def test_complete_custom_command_arguments(self):
338
self.assert_completion(self.completer, 'aws s3 cp --', [
339
'--bar', '--recursive', '--sse'])
340
341
def test_complete_custom_command_arguments_with_arg_already_used(self):
342
self.assert_completion(self.completer, 'aws s3 cp --recursive --', [
343
'--bar', '--sse'])
344
345
346
class MockCLIDriverFactory(object):
347
def create_clidriver(self, commands=None, profiles=None):
348
session = mock.Mock()
349
session.get_data.return_value = None
350
if profiles is not None and isinstance(profiles, list):
351
session.available_profiles = profiles
352
else:
353
session.available_profiles = ['default']
354
clidriver = mock.Mock(spec=CLIDriver)
355
clidriver.create_help_command.return_value = \
356
self._create_top_level_help(commands, session)
357
358
clidriver.session = session
359
return clidriver
360
361
def _create_top_level_help(self, commands, session):
362
command_table = self.create_command_table(
363
commands.get('subcommands', {}), self._create_service_command)
364
argument_table = self.create_argument_table(
365
commands.get('arguments', []))
366
return ProviderHelpCommand(
367
session, command_table, argument_table, None, None, None)
368
369
def _create_service_command(self, name, command):
370
command_table = self.create_command_table(
371
command.get('subcommands', {}), self._create_operation_command)
372
service_command = ServiceCommand(name, None)
373
service_command._service_model = {}
374
service_command._command_table = command_table
375
return service_command
376
377
def _create_operation_command(self, name, command):
378
argument_table = self.create_argument_table(
379
command.get('arguments', []))
380
mock_operation = mock.Mock(spec=OperationModel)
381
mock_operation.deprecated = False
382
operation = ServiceOperation(name, 'parent', None, mock_operation,
383
None)
384
operation._arg_table = argument_table
385
return operation
386
387
def create_command_table(self, commands, command_creator):
388
if not commands:
389
return OrderedDict()
390
command_table = OrderedDict()
391
for name, command in commands.items():
392
if isinstance(command, CLICommand):
393
# Already a valid command, no need to fake one
394
command_table[name] = command
395
else:
396
command_table[name] = command_creator(name, command)
397
return command_table
398
399
def create_argument_table(self, arguments):
400
if not arguments:
401
return OrderedDict()
402
argument_table = OrderedDict()
403
for arg in arguments:
404
if isinstance(arg, BaseCLIArgument):
405
argument_table[arg.name] = arg
406
else:
407
argument_table[arg] = BaseCLIArgument(arg)
408
return argument_table
409
410