]>
Commit | Line | Data |
---|---|---|
9f95a23c | 1 | #!/usr/bin/env python3 |
b3b6e05e | 2 | # -*- mode:python; tab-width:4; indent-tabs-mode:nil; coding:utf-8 -*- |
7c673cae FG |
3 | # vim: ts=4 sw=4 smarttab expandtab fileencoding=utf-8 |
4 | # | |
5 | # Ceph - scalable distributed file system | |
6 | # | |
7 | # Copyright (C) 2013,2014 Cloudwatt <libre.licensing@cloudwatt.com> | |
8 | # Copyright (C) 2014 Red Hat <contact@redhat.com> | |
9 | # | |
10 | # Author: Loic Dachary <loic@dachary.org> | |
11 | # | |
12 | # This library is free software; you can redistribute it and/or | |
13 | # modify it under the terms of the GNU Lesser General Public | |
14 | # License as published by the Free Software Foundation; either | |
15 | # version 2.1 of the License, or (at your option) any later version. | |
16 | # | |
17 | ||
b3b6e05e TL |
18 | from nose.tools import assert_equal, assert_raises, \ |
19 | assert_not_in, assert_in, \ | |
20 | assert_regexp_matches, \ | |
21 | nottest | |
9f95a23c | 22 | from unittest import TestCase |
7c673cae | 23 | |
9f95a23c TL |
24 | from ceph_argparse import validate_command, parse_json_funcsigs, validate, \ |
25 | parse_funcsig, ArgumentError, ArgumentTooFew, ArgumentMissing, \ | |
26 | ArgumentNumber, ArgumentValid | |
7c673cae FG |
27 | |
28 | import os | |
9f95a23c | 29 | import random |
7c673cae | 30 | import re |
9f95a23c | 31 | import string |
94b18763 | 32 | import sys |
1adf2230 AA |
33 | try: |
34 | from StringIO import StringIO | |
35 | except ImportError: | |
36 | from io import StringIO | |
7c673cae | 37 | |
b3b6e05e | 38 | |
7c673cae FG |
39 | def get_command_descriptions(what): |
40 | CEPH_BIN = os.environ['CEPH_BIN'] | |
41 | if CEPH_BIN == "": | |
42 | CEPH_BIN = "." | |
43 | return os.popen(CEPH_BIN + "/get_command_descriptions " + "--" + what).read() | |
44 | ||
b3b6e05e | 45 | |
7c673cae FG |
46 | def test_parse_json_funcsigs(): |
47 | commands = get_command_descriptions("all") | |
48 | cmd_json = parse_json_funcsigs(commands, 'cli') | |
49 | ||
50 | # syntax error https://github.com/ceph/ceph/pull/585 | |
51 | commands = get_command_descriptions("pull585") | |
52 | assert_raises(TypeError, parse_json_funcsigs, commands, 'cli') | |
53 | ||
b3b6e05e | 54 | |
7c673cae FG |
55 | sigdict = parse_json_funcsigs(get_command_descriptions("all"), 'cli') |
56 | ||
57 | ||
58 | class TestArgparse: | |
59 | ||
60 | def assert_valid_command(self, args): | |
61 | result = validate_command(sigdict, args) | |
94b18763 | 62 | assert_not_in(result, [{}, None]) |
7c673cae FG |
63 | |
64 | def check_1_natural_arg(self, prefix, command): | |
65 | self.assert_valid_command([prefix, command, '1']) | |
66 | assert_equal({}, validate_command(sigdict, [prefix, command])) | |
67 | assert_equal({}, validate_command(sigdict, [prefix, command, '-1'])) | |
68 | assert_equal({}, validate_command(sigdict, [prefix, command, '1', | |
69 | '1'])) | |
70 | ||
71 | def check_0_or_1_natural_arg(self, prefix, command): | |
72 | self.assert_valid_command([prefix, command, '1']) | |
73 | self.assert_valid_command([prefix, command]) | |
74 | assert_equal({}, validate_command(sigdict, [prefix, command, '-1'])) | |
75 | assert_equal({}, validate_command(sigdict, [prefix, command, '1', | |
76 | '1'])) | |
77 | ||
78 | def check_1_string_arg(self, prefix, command): | |
79 | assert_equal({}, validate_command(sigdict, [prefix, command])) | |
80 | self.assert_valid_command([prefix, command, 'string']) | |
81 | assert_equal({}, validate_command(sigdict, [prefix, | |
82 | command, | |
83 | 'string', | |
84 | 'toomany'])) | |
85 | ||
11fdf7f2 TL |
86 | def check_0_or_1_string_arg(self, prefix, command): |
87 | self.assert_valid_command([prefix, command, 'string']) | |
88 | self.assert_valid_command([prefix, command]) | |
89 | assert_equal({}, validate_command(sigdict, [prefix, command, 'string', | |
90 | 'toomany'])) | |
91 | ||
7c673cae FG |
92 | def check_1_or_more_string_args(self, prefix, command): |
93 | assert_equal({}, validate_command(sigdict, [prefix, | |
94 | command])) | |
95 | self.assert_valid_command([prefix, | |
96 | command, | |
97 | 'string']) | |
98 | self.assert_valid_command([prefix, | |
99 | command, | |
100 | 'string', | |
101 | 'more string']) | |
102 | ||
103 | def check_no_arg(self, prefix, command): | |
104 | self.assert_valid_command([prefix, | |
105 | command]) | |
106 | assert_equal({}, validate_command(sigdict, [prefix, | |
107 | command, | |
108 | 'toomany'])) | |
109 | ||
11fdf7f2 | 110 | def capture_output(self, args, stdout=None, stderr=None): |
94b18763 FG |
111 | if stdout: |
112 | stdout = StringIO() | |
113 | sys.stdout = stdout | |
114 | if stderr: | |
115 | stderr = StringIO() | |
116 | sys.stderr = stderr | |
117 | ret = validate_command(sigdict, args) | |
118 | if stdout: | |
119 | stdout = stdout.getvalue().strip() | |
120 | if stderr: | |
121 | stderr = stderr.getvalue().strip() | |
122 | return ret, stdout, stderr | |
123 | ||
7c673cae FG |
124 | |
125 | class TestBasic: | |
126 | ||
127 | def test_non_ascii_in_non_options(self): | |
128 | # ArgumentPrefix("no match for {0}".format(s)) is not able to convert | |
129 | # unicode str parameter into str. and validate_command() should not | |
130 | # choke on it. | |
94b18763 FG |
131 | assert_equal({}, validate_command(sigdict, [u'章鱼和鱿鱼'])) |
132 | assert_equal({}, validate_command(sigdict, [u'–w'])) | |
7c673cae FG |
133 | # actually we always pass unicode strings to validate_command() in "ceph" |
134 | # CLI, but we also use bytestrings in our tests, so make sure it does not | |
135 | # break. | |
94b18763 FG |
136 | assert_equal({}, validate_command(sigdict, ['章鱼和鱿鱼'])) |
137 | assert_equal({}, validate_command(sigdict, ['–w'])) | |
7c673cae FG |
138 | |
139 | ||
140 | class TestPG(TestArgparse): | |
141 | ||
142 | def test_stat(self): | |
143 | self.assert_valid_command(['pg', 'stat']) | |
144 | ||
145 | def test_getmap(self): | |
146 | self.assert_valid_command(['pg', 'getmap']) | |
147 | ||
148 | def test_dump(self): | |
b3b6e05e TL |
149 | valid_commands = { |
150 | 'pg dump': {'prefix': 'pg dump'}, | |
151 | 'pg dump all summary sum delta pools osds pgs pgs_brief': | |
152 | {'prefix': 'pg dump', | |
153 | 'dumpcontents': | |
154 | 'all summary sum delta pools osds pgs pgs_brief'.split() | |
155 | }, | |
156 | 'pg dump --dumpcontents summary,sum': | |
157 | {'prefix': 'pg dump', | |
158 | 'dumpcontents': 'summary,sum'.split(',') | |
159 | } | |
160 | } | |
161 | for command, expected_result in valid_commands.items(): | |
162 | actual_result = validate_command(sigdict, command.split()) | |
163 | expected_result['target'] = ('mon-mgr', '') | |
164 | assert_equal(expected_result, actual_result) | |
165 | invalid_commands = ['pg dump invalid'] | |
166 | for command in invalid_commands: | |
167 | actual_result = validate_command(sigdict, command.split()) | |
168 | assert_equal({}, actual_result) | |
7c673cae FG |
169 | |
170 | def test_dump_json(self): | |
171 | self.assert_valid_command(['pg', 'dump_json']) | |
172 | self.assert_valid_command(['pg', 'dump_json', | |
173 | 'all', | |
174 | 'summary', | |
175 | 'sum', | |
176 | 'pools', | |
177 | 'osds', | |
178 | 'pgs']) | |
179 | assert_equal({}, validate_command(sigdict, ['pg', 'dump_json', | |
180 | 'invalid'])) | |
181 | ||
182 | def test_dump_pools_json(self): | |
183 | self.assert_valid_command(['pg', 'dump_pools_json']) | |
184 | ||
185 | def test_dump_pools_stuck(self): | |
186 | self.assert_valid_command(['pg', 'dump_stuck']) | |
187 | self.assert_valid_command(['pg', 'dump_stuck', | |
188 | 'inactive', | |
189 | 'unclean', | |
190 | 'stale']) | |
191 | assert_equal({}, validate_command(sigdict, ['pg', 'dump_stuck', | |
192 | 'invalid'])) | |
193 | self.assert_valid_command(['pg', 'dump_stuck', | |
194 | 'inactive', | |
195 | '1234']) | |
196 | ||
197 | def one_pgid(self, command): | |
198 | self.assert_valid_command(['pg', command, '1.1']) | |
199 | assert_equal({}, validate_command(sigdict, ['pg', command])) | |
200 | assert_equal({}, validate_command(sigdict, ['pg', command, '1'])) | |
201 | ||
202 | def test_map(self): | |
203 | self.one_pgid('map') | |
204 | ||
205 | def test_scrub(self): | |
206 | self.one_pgid('scrub') | |
207 | ||
208 | def test_deep_scrub(self): | |
209 | self.one_pgid('deep-scrub') | |
210 | ||
211 | def test_repair(self): | |
212 | self.one_pgid('repair') | |
213 | ||
214 | def test_debug(self): | |
215 | self.assert_valid_command(['pg', | |
216 | 'debug', | |
217 | 'unfound_objects_exist']) | |
218 | self.assert_valid_command(['pg', | |
219 | 'debug', | |
220 | 'degraded_pgs_exist']) | |
221 | assert_equal({}, validate_command(sigdict, ['pg', 'debug'])) | |
222 | assert_equal({}, validate_command(sigdict, ['pg', 'debug', | |
223 | 'invalid'])) | |
224 | ||
94b18763 FG |
225 | def test_pg_missing_args_output(self): |
226 | ret, _, stderr = self.capture_output(['pg'], stderr=True) | |
227 | assert_equal({}, ret) | |
228 | assert_regexp_matches(stderr, re.compile('no valid command found.* closest matches')) | |
229 | ||
230 | def test_pg_wrong_arg_output(self): | |
231 | ret, _, stderr = self.capture_output(['pg', 'map', 'bad-pgid'], | |
232 | stderr=True) | |
233 | assert_equal({}, ret) | |
234 | assert_in("Invalid command", stderr) | |
235 | ||
7c673cae FG |
236 | |
237 | class TestAuth(TestArgparse): | |
238 | ||
239 | def test_export(self): | |
240 | self.assert_valid_command(['auth', 'export']) | |
241 | self.assert_valid_command(['auth', | |
242 | 'export', | |
243 | 'string']) | |
244 | assert_equal({}, validate_command(sigdict, ['auth', | |
245 | 'export', | |
246 | 'string', | |
247 | 'toomany'])) | |
248 | ||
249 | def test_get(self): | |
250 | self.check_1_string_arg('auth', 'get') | |
251 | ||
252 | def test_get_key(self): | |
253 | self.check_1_string_arg('auth', 'get-key') | |
254 | ||
255 | def test_print_key(self): | |
256 | self.check_1_string_arg('auth', 'print-key') | |
257 | self.check_1_string_arg('auth', 'print_key') | |
258 | ||
259 | def test_list(self): | |
260 | self.check_no_arg('auth', 'list') | |
261 | ||
262 | def test_import(self): | |
263 | self.check_no_arg('auth', 'import') | |
264 | ||
265 | def test_add(self): | |
266 | self.check_1_or_more_string_args('auth', 'add') | |
267 | ||
268 | def test_get_or_create_key(self): | |
269 | self.check_1_or_more_string_args('auth', 'get-or-create-key') | |
b3b6e05e TL |
270 | prefix = 'auth get-or-create-key' |
271 | entity = 'client.test' | |
272 | caps = ['mon', | |
273 | 'allow r', | |
274 | 'osd', | |
275 | 'allow rw pool=nfs-ganesha namespace=test, allow rw tag cephfs data=user_test_fs', | |
276 | 'mds', | |
277 | 'allow rw path=/'] | |
278 | cmd = prefix.split() + [entity] + caps | |
279 | assert_equal( | |
280 | { | |
281 | 'prefix': prefix, | |
282 | 'entity': entity, | |
283 | 'caps': caps | |
284 | }, validate_command(sigdict, cmd)) | |
7c673cae FG |
285 | |
286 | def test_get_or_create(self): | |
287 | self.check_1_or_more_string_args('auth', 'get-or-create') | |
288 | ||
289 | def test_caps(self): | |
290 | assert_equal({}, validate_command(sigdict, ['auth', | |
291 | 'caps'])) | |
292 | assert_equal({}, validate_command(sigdict, ['auth', | |
293 | 'caps', | |
294 | 'string'])) | |
295 | self.assert_valid_command(['auth', | |
296 | 'caps', | |
297 | 'string', | |
298 | 'more string']) | |
299 | ||
300 | def test_del(self): | |
301 | self.check_1_string_arg('auth', 'del') | |
302 | ||
303 | ||
304 | class TestMonitor(TestArgparse): | |
305 | ||
306 | def test_compact(self): | |
307 | self.assert_valid_command(['compact']) | |
308 | ||
7c673cae FG |
309 | def test_fsid(self): |
310 | self.assert_valid_command(['fsid']) | |
311 | ||
312 | def test_log(self): | |
313 | assert_equal({}, validate_command(sigdict, ['log'])) | |
314 | self.assert_valid_command(['log', 'a logtext']) | |
315 | self.assert_valid_command(['log', 'a logtext', 'and another']) | |
316 | ||
317 | def test_injectargs(self): | |
318 | assert_equal({}, validate_command(sigdict, ['injectargs'])) | |
319 | self.assert_valid_command(['injectargs', 'one']) | |
320 | self.assert_valid_command(['injectargs', 'one', 'two']) | |
321 | ||
322 | def test_status(self): | |
323 | self.assert_valid_command(['status']) | |
324 | ||
325 | def test_health(self): | |
326 | self.assert_valid_command(['health']) | |
327 | self.assert_valid_command(['health', 'detail']) | |
328 | assert_equal({}, validate_command(sigdict, ['health', 'invalid'])) | |
329 | assert_equal({}, validate_command(sigdict, ['health', 'detail', | |
330 | 'toomany'])) | |
331 | ||
332 | def test_df(self): | |
333 | self.assert_valid_command(['df']) | |
334 | self.assert_valid_command(['df', 'detail']) | |
335 | assert_equal({}, validate_command(sigdict, ['df', 'invalid'])) | |
336 | assert_equal({}, validate_command(sigdict, ['df', 'detail', | |
337 | 'toomany'])) | |
338 | ||
339 | def test_report(self): | |
340 | self.assert_valid_command(['report']) | |
341 | self.assert_valid_command(['report', 'tag1']) | |
342 | self.assert_valid_command(['report', 'tag1', 'tag2']) | |
343 | ||
344 | def test_quorum_status(self): | |
345 | self.assert_valid_command(['quorum_status']) | |
346 | ||
7c673cae FG |
347 | def test_tell(self): |
348 | assert_equal({}, validate_command(sigdict, ['tell'])) | |
349 | assert_equal({}, validate_command(sigdict, ['tell', 'invalid'])) | |
350 | for name in ('osd', 'mon', 'client', 'mds'): | |
351 | assert_equal({}, validate_command(sigdict, ['tell', name])) | |
352 | assert_equal({}, validate_command(sigdict, ['tell', | |
353 | name + ".42"])) | |
354 | self.assert_valid_command(['tell', name + ".42", 'something']) | |
355 | self.assert_valid_command(['tell', name + ".42", | |
356 | 'something', | |
357 | 'something else']) | |
358 | ||
359 | ||
360 | class TestMDS(TestArgparse): | |
361 | ||
362 | def test_stat(self): | |
363 | self.check_no_arg('mds', 'stat') | |
364 | ||
7c673cae FG |
365 | def test_compat_show(self): |
366 | self.assert_valid_command(['mds', 'compat', 'show']) | |
367 | assert_equal({}, validate_command(sigdict, ['mds', 'compat'])) | |
368 | assert_equal({}, validate_command(sigdict, ['mds', 'compat', | |
369 | 'show', 'toomany'])) | |
370 | ||
7c673cae FG |
371 | def test_set_state(self): |
372 | self.assert_valid_command(['mds', 'set_state', '1', '2']) | |
373 | assert_equal({}, validate_command(sigdict, ['mds', 'set_state'])) | |
374 | assert_equal({}, validate_command(sigdict, ['mds', 'set_state', '-1'])) | |
375 | assert_equal({}, validate_command(sigdict, ['mds', 'set_state', | |
376 | '1', '-1'])) | |
377 | assert_equal({}, validate_command(sigdict, ['mds', 'set_state', | |
378 | '1', '21'])) | |
379 | ||
380 | def test_fail(self): | |
381 | self.check_1_string_arg('mds', 'fail') | |
382 | ||
383 | def test_rm(self): | |
384 | # Valid: single GID argument present | |
385 | self.assert_valid_command(['mds', 'rm', '1']) | |
386 | ||
387 | # Missing GID arg: invalid | |
388 | assert_equal({}, validate_command(sigdict, ['mds', 'rm'])) | |
389 | # Extra arg: invalid | |
390 | assert_equal({}, validate_command(sigdict, ['mds', 'rm', '1', 'mds.42'])) | |
391 | ||
392 | def test_rmfailed(self): | |
393 | self.assert_valid_command(['mds', 'rmfailed', '0']) | |
394 | self.assert_valid_command(['mds', 'rmfailed', '0', '--yes-i-really-mean-it']) | |
395 | assert_equal({}, validate_command(sigdict, ['mds', 'rmfailed', '0', | |
396 | '--yes-i-really-mean-it', | |
397 | 'toomany'])) | |
398 | ||
7c673cae FG |
399 | def test_compat_rm_compat(self): |
400 | self.assert_valid_command(['mds', 'compat', 'rm_compat', '1']) | |
401 | assert_equal({}, validate_command(sigdict, ['mds', | |
402 | 'compat', | |
403 | 'rm_compat'])) | |
404 | assert_equal({}, validate_command(sigdict, ['mds', | |
405 | 'compat', | |
406 | 'rm_compat', '-1'])) | |
407 | assert_equal({}, validate_command(sigdict, ['mds', | |
408 | 'compat', | |
409 | 'rm_compat', '1', '1'])) | |
410 | ||
411 | def test_incompat_rm_incompat(self): | |
412 | self.assert_valid_command(['mds', 'compat', 'rm_incompat', '1']) | |
413 | assert_equal({}, validate_command(sigdict, ['mds', | |
414 | 'compat', | |
415 | 'rm_incompat'])) | |
416 | assert_equal({}, validate_command(sigdict, ['mds', | |
417 | 'compat', | |
418 | 'rm_incompat', '-1'])) | |
419 | assert_equal({}, validate_command(sigdict, ['mds', | |
420 | 'compat', | |
421 | 'rm_incompat', '1', '1'])) | |
422 | ||
7c673cae FG |
423 | |
424 | class TestFS(TestArgparse): | |
425 | ||
426 | def test_dump(self): | |
427 | self.check_0_or_1_natural_arg('fs', 'dump') | |
428 | ||
429 | def test_fs_new(self): | |
430 | self.assert_valid_command(['fs', 'new', 'default', 'metadata', 'data']) | |
431 | ||
11fdf7f2 TL |
432 | def test_fs_set_max_mds(self): |
433 | self.assert_valid_command(['fs', 'set', 'default', 'max_mds', '1']) | |
434 | self.assert_valid_command(['fs', 'set', 'default', 'max_mds', '2']) | |
435 | ||
436 | def test_fs_set_cluster_down(self): | |
437 | self.assert_valid_command(['fs', 'set', 'default', 'down', 'true']) | |
438 | ||
439 | def test_fs_set_cluster_up(self): | |
440 | self.assert_valid_command(['fs', 'set', 'default', 'down', 'false']) | |
441 | ||
442 | def test_fs_set_cluster_joinable(self): | |
443 | self.assert_valid_command(['fs', 'set', 'default', 'joinable', 'true']) | |
444 | ||
445 | def test_fs_set_cluster_not_joinable(self): | |
446 | self.assert_valid_command(['fs', 'set', 'default', 'joinable', 'false']) | |
447 | ||
448 | def test_fs_set(self): | |
449 | self.assert_valid_command(['fs', 'set', 'default', 'max_file_size', '2']) | |
450 | self.assert_valid_command(['fs', 'set', 'default', 'allow_new_snaps', 'no']) | |
451 | assert_equal({}, validate_command(sigdict, ['fs', | |
452 | 'set', | |
453 | 'invalid'])) | |
454 | ||
455 | def test_fs_add_data_pool(self): | |
456 | self.assert_valid_command(['fs', 'add_data_pool', 'default', '1']) | |
457 | self.assert_valid_command(['fs', 'add_data_pool', 'default', 'foo']) | |
458 | ||
459 | def test_fs_remove_data_pool(self): | |
460 | self.assert_valid_command(['fs', 'rm_data_pool', 'default', '1']) | |
461 | self.assert_valid_command(['fs', 'rm_data_pool', 'default', 'foo']) | |
462 | ||
7c673cae FG |
463 | def test_fs_rm(self): |
464 | self.assert_valid_command(['fs', 'rm', 'default']) | |
465 | self.assert_valid_command(['fs', 'rm', 'default', '--yes-i-really-mean-it']) | |
466 | assert_equal({}, validate_command(sigdict, ['fs', 'rm', 'default', '--yes-i-really-mean-it', 'toomany'])) | |
467 | ||
468 | def test_fs_ls(self): | |
469 | self.assert_valid_command(['fs', 'ls']) | |
470 | assert_equal({}, validate_command(sigdict, ['fs', 'ls', 'toomany'])) | |
471 | ||
472 | def test_fs_set_default(self): | |
473 | self.assert_valid_command(['fs', 'set-default', 'cephfs']) | |
474 | assert_equal({}, validate_command(sigdict, ['fs', 'set-default'])) | |
475 | assert_equal({}, validate_command(sigdict, ['fs', 'set-default', 'cephfs', 'toomany'])) | |
476 | ||
11fdf7f2 | 477 | |
7c673cae FG |
478 | class TestMon(TestArgparse): |
479 | ||
480 | def test_dump(self): | |
481 | self.check_0_or_1_natural_arg('mon', 'dump') | |
482 | ||
483 | def test_stat(self): | |
484 | self.check_no_arg('mon', 'stat') | |
485 | ||
486 | def test_getmap(self): | |
487 | self.check_0_or_1_natural_arg('mon', 'getmap') | |
488 | ||
489 | def test_add(self): | |
490 | self.assert_valid_command(['mon', 'add', 'name', '1.2.3.4:1234']) | |
491 | assert_equal({}, validate_command(sigdict, ['mon', 'add'])) | |
492 | assert_equal({}, validate_command(sigdict, ['mon', 'add', 'name'])) | |
493 | assert_equal({}, validate_command(sigdict, ['mon', 'add', | |
494 | 'name', | |
495 | '400.500.600.700'])) | |
7c673cae FG |
496 | |
497 | def test_remove(self): | |
498 | self.assert_valid_command(['mon', 'remove', 'name']) | |
499 | assert_equal({}, validate_command(sigdict, ['mon', 'remove'])) | |
500 | assert_equal({}, validate_command(sigdict, ['mon', 'remove', | |
501 | 'name', 'toomany'])) | |
502 | ||
503 | ||
504 | class TestOSD(TestArgparse): | |
505 | ||
506 | def test_stat(self): | |
507 | self.check_no_arg('osd', 'stat') | |
508 | ||
509 | def test_dump(self): | |
510 | self.check_0_or_1_natural_arg('osd', 'dump') | |
511 | ||
512 | def test_osd_tree(self): | |
513 | self.check_0_or_1_natural_arg('osd', 'tree') | |
b3b6e05e TL |
514 | cmd = 'osd tree down,out' |
515 | assert_equal( | |
516 | { | |
517 | 'prefix': 'osd tree', | |
518 | 'states': ['down', 'out'] | |
519 | }, validate_command(sigdict, cmd.split())) | |
7c673cae FG |
520 | |
521 | def test_osd_ls(self): | |
522 | self.check_0_or_1_natural_arg('osd', 'ls') | |
523 | ||
524 | def test_osd_getmap(self): | |
525 | self.check_0_or_1_natural_arg('osd', 'getmap') | |
526 | ||
527 | def test_osd_getcrushmap(self): | |
528 | self.check_0_or_1_natural_arg('osd', 'getcrushmap') | |
529 | ||
530 | def test_perf(self): | |
531 | self.check_no_arg('osd', 'perf') | |
532 | ||
533 | def test_getmaxosd(self): | |
534 | self.check_no_arg('osd', 'getmaxosd') | |
535 | ||
536 | def test_find(self): | |
537 | self.check_1_natural_arg('osd', 'find') | |
538 | ||
539 | def test_map(self): | |
540 | self.assert_valid_command(['osd', 'map', 'poolname', 'objectname']) | |
541 | self.assert_valid_command(['osd', 'map', 'poolname', 'objectname', 'nspace']) | |
542 | assert_equal({}, validate_command(sigdict, ['osd', 'map'])) | |
543 | assert_equal({}, validate_command(sigdict, ['osd', 'map', 'poolname'])) | |
544 | assert_equal({}, validate_command(sigdict, ['osd', 'map', | |
545 | 'poolname', 'objectname', 'nspace', | |
546 | 'toomany'])) | |
547 | ||
548 | def test_metadata(self): | |
549 | self.check_0_or_1_natural_arg('osd', 'metadata') | |
550 | ||
551 | def test_scrub(self): | |
552 | self.check_1_string_arg('osd', 'scrub') | |
553 | ||
554 | def test_deep_scrub(self): | |
555 | self.check_1_string_arg('osd', 'deep-scrub') | |
556 | ||
557 | def test_repair(self): | |
558 | self.check_1_string_arg('osd', 'repair') | |
559 | ||
560 | def test_lspools(self): | |
561 | self.assert_valid_command(['osd', 'lspools']) | |
7c673cae | 562 | assert_equal({}, validate_command(sigdict, ['osd', 'lspools', |
11fdf7f2 | 563 | 'toomany'])) |
7c673cae | 564 | |
f67539c2 TL |
565 | def test_blocklist_ls(self): |
566 | self.assert_valid_command(['osd', 'blocklist', 'ls']) | |
567 | assert_equal({}, validate_command(sigdict, ['osd', 'blocklist'])) | |
568 | assert_equal({}, validate_command(sigdict, ['osd', 'blocklist', | |
7c673cae FG |
569 | 'ls', 'toomany'])) |
570 | ||
571 | def test_crush_rule(self): | |
572 | assert_equal({}, validate_command(sigdict, ['osd', 'crush'])) | |
573 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', 'rule'])) | |
574 | for subcommand in ('list', 'ls'): | |
575 | self.assert_valid_command(['osd', 'crush', 'rule', subcommand]) | |
576 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
577 | 'rule', subcommand, | |
578 | 'toomany'])) | |
579 | ||
580 | def test_crush_rule_dump(self): | |
581 | self.assert_valid_command(['osd', 'crush', 'rule', 'dump']) | |
582 | self.assert_valid_command(['osd', 'crush', 'rule', 'dump', 'RULE']) | |
583 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
584 | 'rule', 'dump', | |
585 | 'RULE', | |
586 | 'toomany'])) | |
587 | ||
588 | def test_crush_dump(self): | |
589 | self.assert_valid_command(['osd', 'crush', 'dump']) | |
590 | assert_equal({}, validate_command(sigdict, ['osd', 'crush'])) | |
591 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
592 | 'dump', | |
593 | 'toomany'])) | |
594 | ||
595 | def test_setcrushmap(self): | |
596 | self.check_no_arg('osd', 'setcrushmap') | |
597 | ||
598 | def test_crush_add_bucket(self): | |
599 | self.assert_valid_command(['osd', 'crush', 'add-bucket', | |
600 | 'name', 'type']) | |
11fdf7f2 TL |
601 | self.assert_valid_command(['osd', 'crush', 'add-bucket', |
602 | 'name', 'type', 'root=foo-root', 'host=foo-host']) | |
7c673cae FG |
603 | assert_equal({}, validate_command(sigdict, ['osd', 'crush'])) |
604 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
605 | 'add-bucket'])) | |
7c673cae FG |
606 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', |
607 | 'add-bucket', '^^^', | |
608 | 'type'])) | |
609 | ||
610 | def test_crush_rename_bucket(self): | |
611 | self.assert_valid_command(['osd', 'crush', 'rename-bucket', | |
612 | 'srcname', 'dstname']) | |
613 | assert_equal({}, validate_command(sigdict, ['osd', 'crush'])) | |
614 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
615 | 'rename-bucket'])) | |
616 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
617 | 'rename-bucket', | |
618 | 'srcname'])) | |
619 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
620 | 'rename-bucket', 'srcname', | |
621 | 'dstname', | |
622 | 'toomany'])) | |
623 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
624 | 'rename-bucket', '^^^', | |
625 | 'dstname'])) | |
626 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
627 | 'rename-bucket', 'srcname', | |
628 | '^^^^'])) | |
629 | ||
630 | def check_crush_setter(self, setter): | |
631 | self.assert_valid_command(['osd', 'crush', setter, | |
632 | '*', '2.3', 'AZaz09-_.=']) | |
633 | self.assert_valid_command(['osd', 'crush', setter, | |
634 | 'osd.0', '2.3', 'AZaz09-_.=']) | |
635 | self.assert_valid_command(['osd', 'crush', setter, | |
636 | '0', '2.3', 'AZaz09-_.=']) | |
637 | self.assert_valid_command(['osd', 'crush', setter, | |
638 | '0', '2.3', 'AZaz09-_.=', 'AZaz09-_.=']) | |
639 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
640 | setter, | |
641 | 'osd.0'])) | |
642 | ret = validate_command(sigdict, ['osd', 'crush', | |
643 | setter, | |
644 | 'osd.0', | |
645 | '-1.0']) | |
646 | assert ret in [None, {}] | |
647 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
648 | setter, | |
649 | 'osd.0', | |
650 | '1.0', | |
651 | '^^^'])) | |
652 | ||
653 | def test_crush_set(self): | |
654 | assert_equal({}, validate_command(sigdict, ['osd', 'crush'])) | |
655 | self.check_crush_setter('set') | |
656 | ||
657 | def test_crush_add(self): | |
658 | assert_equal({}, validate_command(sigdict, ['osd', 'crush'])) | |
659 | self.check_crush_setter('add') | |
660 | ||
661 | def test_crush_create_or_move(self): | |
662 | assert_equal({}, validate_command(sigdict, ['osd', 'crush'])) | |
663 | self.check_crush_setter('create-or-move') | |
664 | ||
665 | def test_crush_move(self): | |
666 | self.assert_valid_command(['osd', 'crush', 'move', | |
667 | 'AZaz09-_.', 'AZaz09-_.=']) | |
668 | self.assert_valid_command(['osd', 'crush', 'move', | |
669 | '0', 'AZaz09-_.=', 'AZaz09-_.=']) | |
670 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
671 | 'move'])) | |
672 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
673 | 'move', 'AZaz09-_.'])) | |
674 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
675 | 'move', '^^^', | |
676 | 'AZaz09-_.='])) | |
677 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
678 | 'move', 'AZaz09-_.', | |
679 | '^^^'])) | |
680 | ||
681 | def test_crush_link(self): | |
682 | self.assert_valid_command(['osd', 'crush', 'link', | |
683 | 'name', 'AZaz09-_.=']) | |
684 | self.assert_valid_command(['osd', 'crush', 'link', | |
685 | 'name', 'AZaz09-_.=', 'AZaz09-_.=']) | |
686 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
687 | 'link'])) | |
688 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
689 | 'link', | |
690 | 'name'])) | |
691 | ||
692 | def test_crush_rm(self): | |
693 | for alias in ('rm', 'remove', 'unlink'): | |
694 | self.assert_valid_command(['osd', 'crush', alias, 'AZaz09-_.']) | |
695 | self.assert_valid_command(['osd', 'crush', alias, | |
696 | 'AZaz09-_.', 'AZaz09-_.']) | |
697 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
698 | alias])) | |
699 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
700 | alias, | |
701 | 'AZaz09-_.', | |
702 | 'AZaz09-_.', | |
703 | 'toomany'])) | |
704 | ||
705 | def test_crush_reweight(self): | |
706 | self.assert_valid_command(['osd', 'crush', 'reweight', | |
707 | 'AZaz09-_.', '2.3']) | |
708 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
709 | 'reweight'])) | |
710 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
711 | 'reweight', | |
712 | 'AZaz09-_.'])) | |
713 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
714 | 'reweight', | |
715 | 'AZaz09-_.', | |
716 | '-1.0'])) | |
717 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
718 | 'reweight', | |
719 | '^^^', | |
720 | '2.3'])) | |
721 | ||
722 | def test_crush_tunables(self): | |
723 | for tunable in ('legacy', 'argonaut', 'bobtail', 'firefly', | |
724 | 'optimal', 'default'): | |
725 | self.assert_valid_command(['osd', 'crush', 'tunables', | |
726 | tunable]) | |
727 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
728 | 'tunables'])) | |
729 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
730 | 'tunables', | |
731 | 'default', 'toomany'])) | |
732 | ||
733 | def test_crush_rule_create_simple(self): | |
734 | self.assert_valid_command(['osd', 'crush', 'rule', 'create-simple', | |
735 | 'AZaz09-_.', 'AZaz09-_.', 'AZaz09-_.']) | |
736 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', 'rule', | |
737 | 'create-simple'])) | |
738 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', 'rule', | |
739 | 'create-simple', | |
740 | 'AZaz09-_.'])) | |
741 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', 'rule', | |
742 | 'create-simple', | |
743 | 'AZaz09-_.', | |
744 | 'AZaz09-_.'])) | |
745 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', 'rule', | |
746 | 'create-simple', | |
747 | '^^^', | |
748 | 'AZaz09-_.', | |
749 | 'AZaz09-_.'])) | |
750 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', 'rule', | |
751 | 'create-simple', | |
752 | 'AZaz09-_.', | |
753 | '|||', | |
754 | 'AZaz09-_.'])) | |
755 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', 'rule', | |
756 | 'create-simple', | |
757 | 'AZaz09-_.', | |
758 | 'AZaz09-_.', | |
759 | '+++'])) | |
760 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', 'rule', | |
761 | 'create-simple', | |
762 | 'AZaz09-_.', | |
763 | 'AZaz09-_.', | |
764 | 'AZaz09-_.', | |
765 | 'toomany'])) | |
766 | ||
767 | def test_crush_rule_create_erasure(self): | |
768 | self.assert_valid_command(['osd', 'crush', 'rule', 'create-erasure', | |
769 | 'AZaz09-_.']) | |
770 | self.assert_valid_command(['osd', 'crush', 'rule', 'create-erasure', | |
771 | 'AZaz09-_.', 'whatever']) | |
772 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', 'rule', | |
773 | 'create-erasure'])) | |
774 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', 'rule', | |
775 | 'create-erasure', | |
776 | '^^^'])) | |
777 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', 'rule', | |
778 | 'create-erasure', | |
779 | 'name', '^^^'])) | |
780 | ||
781 | def test_crush_rule_rm(self): | |
782 | self.assert_valid_command(['osd', 'crush', 'rule', 'rm', 'AZaz09-_.']) | |
783 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
784 | 'rule', 'rm'])) | |
785 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
786 | 'rule', 'rm', | |
787 | '^^^^'])) | |
788 | assert_equal({}, validate_command(sigdict, ['osd', 'crush', | |
789 | 'rule', 'rm', | |
790 | 'AZaz09-_.', | |
791 | 'toomany'])) | |
792 | ||
793 | def test_setmaxosd(self): | |
794 | self.check_1_natural_arg('osd', 'setmaxosd') | |
795 | ||
796 | def test_pause(self): | |
797 | self.check_no_arg('osd', 'pause') | |
798 | ||
799 | def test_unpause(self): | |
800 | self.check_no_arg('osd', 'unpause') | |
801 | ||
802 | def test_erasure_code_profile_set(self): | |
803 | self.assert_valid_command(['osd', 'erasure-code-profile', 'set', | |
804 | 'name']) | |
805 | self.assert_valid_command(['osd', 'erasure-code-profile', 'set', | |
806 | 'name', 'A=B']) | |
807 | self.assert_valid_command(['osd', 'erasure-code-profile', 'set', | |
808 | 'name', 'A=B', 'C=D']) | |
809 | assert_equal({}, validate_command(sigdict, ['osd', | |
810 | 'erasure-code-profile', | |
811 | 'set'])) | |
812 | assert_equal({}, validate_command(sigdict, ['osd', | |
813 | 'erasure-code-profile', | |
814 | 'set', | |
815 | '^^^^'])) | |
816 | ||
817 | def test_erasure_code_profile_get(self): | |
818 | self.assert_valid_command(['osd', 'erasure-code-profile', 'get', | |
819 | 'name']) | |
820 | assert_equal({}, validate_command(sigdict, ['osd', | |
821 | 'erasure-code-profile', | |
822 | 'get'])) | |
823 | assert_equal({}, validate_command(sigdict, ['osd', | |
824 | 'erasure-code-profile', | |
825 | 'get', | |
826 | '^^^^'])) | |
827 | ||
828 | def test_erasure_code_profile_rm(self): | |
829 | self.assert_valid_command(['osd', 'erasure-code-profile', 'rm', | |
830 | 'name']) | |
831 | assert_equal({}, validate_command(sigdict, ['osd', | |
832 | 'erasure-code-profile', | |
833 | 'rm'])) | |
834 | assert_equal({}, validate_command(sigdict, ['osd', | |
835 | 'erasure-code-profile', | |
836 | 'rm', | |
837 | '^^^^'])) | |
838 | ||
839 | def test_erasure_code_profile_ls(self): | |
840 | self.assert_valid_command(['osd', 'erasure-code-profile', 'ls']) | |
841 | assert_equal({}, validate_command(sigdict, ['osd', | |
842 | 'erasure-code-profile', | |
843 | 'ls', | |
844 | 'toomany'])) | |
845 | ||
846 | def test_set_unset(self): | |
847 | for action in ('set', 'unset'): | |
848 | for flag in ('pause', 'noup', 'nodown', 'noout', 'noin', | |
849 | 'nobackfill', 'norecover', 'noscrub', 'nodeep-scrub'): | |
850 | self.assert_valid_command(['osd', action, flag]) | |
851 | assert_equal({}, validate_command(sigdict, ['osd', action])) | |
852 | assert_equal({}, validate_command(sigdict, ['osd', action, | |
853 | 'invalid'])) | |
854 | assert_equal({}, validate_command(sigdict, ['osd', action, | |
855 | 'pause', 'toomany'])) | |
856 | ||
7c673cae FG |
857 | def test_down(self): |
858 | self.check_1_or_more_string_args('osd', 'down') | |
859 | ||
860 | def test_out(self): | |
861 | self.check_1_or_more_string_args('osd', 'out') | |
862 | ||
863 | def test_in(self): | |
864 | self.check_1_or_more_string_args('osd', 'in') | |
865 | ||
866 | def test_rm(self): | |
867 | self.check_1_or_more_string_args('osd', 'rm') | |
868 | ||
869 | def test_reweight(self): | |
870 | self.assert_valid_command(['osd', 'reweight', '1', '0.1']) | |
871 | assert_equal({}, validate_command(sigdict, ['osd', 'reweight'])) | |
872 | assert_equal({}, validate_command(sigdict, ['osd', 'reweight', | |
873 | '1'])) | |
874 | assert_equal({}, validate_command(sigdict, ['osd', 'reweight', | |
875 | '1', '2.0'])) | |
876 | assert_equal({}, validate_command(sigdict, ['osd', 'reweight', | |
877 | '-1', '0.1'])) | |
878 | assert_equal({}, validate_command(sigdict, ['osd', 'reweight', | |
879 | '1', '0.1', | |
880 | 'toomany'])) | |
881 | ||
882 | def test_lost(self): | |
883 | self.assert_valid_command(['osd', 'lost', '1', | |
884 | '--yes-i-really-mean-it']) | |
885 | self.assert_valid_command(['osd', 'lost', '1']) | |
886 | assert_equal({}, validate_command(sigdict, ['osd', 'lost'])) | |
887 | assert_equal({}, validate_command(sigdict, ['osd', 'lost', | |
888 | '1', | |
889 | 'what?'])) | |
890 | assert_equal({}, validate_command(sigdict, ['osd', 'lost', | |
891 | '-1', | |
892 | '--yes-i-really-mean-it'])) | |
893 | assert_equal({}, validate_command(sigdict, ['osd', 'lost', | |
894 | '1', | |
895 | '--yes-i-really-mean-it', | |
896 | 'toomany'])) | |
897 | ||
898 | def test_create(self): | |
899 | uuid = '12345678123456781234567812345678' | |
900 | self.assert_valid_command(['osd', 'create']) | |
901 | self.assert_valid_command(['osd', 'create', | |
902 | uuid]) | |
903 | assert_equal({}, validate_command(sigdict, ['osd', 'create', | |
904 | 'invalid'])) | |
905 | assert_equal({}, validate_command(sigdict, ['osd', 'create', | |
906 | uuid, | |
907 | 'toomany'])) | |
908 | ||
f67539c2 | 909 | def test_blocklist(self): |
7c673cae | 910 | for action in ('add', 'rm'): |
f67539c2 | 911 | self.assert_valid_command(['osd', 'blocklist', action, |
7c673cae | 912 | '1.2.3.4/567']) |
f67539c2 | 913 | self.assert_valid_command(['osd', 'blocklist', action, |
7c673cae | 914 | '1.2.3.4']) |
f67539c2 | 915 | self.assert_valid_command(['osd', 'blocklist', action, |
7c673cae | 916 | '1.2.3.4/567', '600.40']) |
f67539c2 | 917 | self.assert_valid_command(['osd', 'blocklist', action, |
7c673cae | 918 | '1.2.3.4', '600.40']) |
f67539c2 | 919 | assert_equal({}, validate_command(sigdict, ['osd', 'blocklist', |
7c673cae FG |
920 | action, |
921 | 'invalid', | |
922 | '600.40'])) | |
f67539c2 | 923 | assert_equal({}, validate_command(sigdict, ['osd', 'blocklist', |
7c673cae FG |
924 | action, |
925 | '1.2.3.4/567', | |
926 | '-1.0'])) | |
f67539c2 | 927 | assert_equal({}, validate_command(sigdict, ['osd', 'blocklist', |
7c673cae FG |
928 | action, |
929 | '1.2.3.4/567', | |
930 | '600.40', | |
931 | 'toomany'])) | |
932 | ||
933 | def test_pool_mksnap(self): | |
934 | self.assert_valid_command(['osd', 'pool', 'mksnap', | |
935 | 'poolname', 'snapname']) | |
936 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'mksnap'])) | |
937 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'mksnap', | |
938 | 'poolname'])) | |
939 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'mksnap', | |
940 | 'poolname', 'snapname', | |
941 | 'toomany'])) | |
942 | ||
943 | def test_pool_rmsnap(self): | |
944 | self.assert_valid_command(['osd', 'pool', 'rmsnap', | |
945 | 'poolname', 'snapname']) | |
946 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'rmsnap'])) | |
947 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'rmsnap', | |
948 | 'poolname'])) | |
949 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'rmsnap', | |
950 | 'poolname', 'snapname', | |
951 | 'toomany'])) | |
952 | ||
11fdf7f2 TL |
953 | def test_pool_kwargs(self): |
954 | """ | |
955 | Use the pool creation command to exercise keyword-style arguments | |
956 | since it has lots of parameters | |
957 | """ | |
958 | # Simply use a keyword arg instead of a positional arg, in its | |
959 | # normal order (pgp_num after pg_num) | |
960 | assert_equal( | |
961 | { | |
962 | "prefix": "osd pool create", | |
963 | "pool": "foo", | |
964 | "pg_num": 8, | |
965 | "pgp_num": 16 | |
966 | }, validate_command(sigdict, [ | |
967 | 'osd', 'pool', 'create', "foo", "8", "--pgp_num", "16"])) | |
968 | ||
969 | # Again, but using the "--foo=bar" style | |
970 | assert_equal( | |
971 | { | |
972 | "prefix": "osd pool create", | |
973 | "pool": "foo", | |
974 | "pg_num": 8, | |
975 | "pgp_num": 16 | |
976 | }, validate_command(sigdict, [ | |
977 | 'osd', 'pool', 'create', "foo", "8", "--pgp_num=16"])) | |
978 | ||
979 | # Specify keyword args in a different order than their definitions | |
980 | # (pgp_num after pool_type) | |
981 | assert_equal( | |
982 | { | |
983 | "prefix": "osd pool create", | |
984 | "pool": "foo", | |
985 | "pg_num": 8, | |
986 | "pgp_num": 16, | |
987 | "pool_type": "replicated" | |
988 | }, validate_command(sigdict, [ | |
989 | 'osd', 'pool', 'create', "foo", "8", | |
990 | "--pool_type", "replicated", | |
991 | "--pgp_num", "16"])) | |
992 | ||
993 | # Use a keyword argument that doesn't exist, should fail validation | |
994 | assert_equal({}, validate_command(sigdict, | |
995 | ['osd', 'pool', 'create', "foo", "8", "--foo=bar"])) | |
996 | ||
997 | def test_foo(self): | |
998 | # Long form of a boolean argument (--foo=true) | |
999 | assert_equal( | |
1000 | { | |
1001 | "prefix": "osd pool delete", | |
1002 | "pool": "foo", | |
1003 | "pool2": "foo", | |
1004 | "yes_i_really_really_mean_it": True | |
1005 | }, validate_command(sigdict, [ | |
1006 | 'osd', 'pool', 'delete', "foo", "foo", | |
1007 | "--yes-i-really-really-mean-it=true"])) | |
1008 | ||
1009 | def test_pool_bool_args(self): | |
1010 | """ | |
1011 | Use pool deletion to exercise boolean arguments since it has | |
1012 | the --yes-i-really-really-mean-it flags | |
1013 | """ | |
1014 | ||
1015 | # Short form of a boolean argument (--foo) | |
1016 | assert_equal( | |
1017 | { | |
1018 | "prefix": "osd pool delete", | |
1019 | "pool": "foo", | |
1020 | "pool2": "foo", | |
1021 | "yes_i_really_really_mean_it": True | |
1022 | }, validate_command(sigdict, [ | |
1023 | 'osd', 'pool', 'delete', "foo", "foo", | |
1024 | "--yes-i-really-really-mean-it"])) | |
1025 | ||
1026 | # Long form of a boolean argument (--foo=true) | |
1027 | assert_equal( | |
1028 | { | |
1029 | "prefix": "osd pool delete", | |
1030 | "pool": "foo", | |
1031 | "pool2": "foo", | |
1032 | "yes_i_really_really_mean_it": True | |
1033 | }, validate_command(sigdict, [ | |
1034 | 'osd', 'pool', 'delete', "foo", "foo", | |
1035 | "--yes-i-really-really-mean-it=true"])) | |
1036 | ||
1037 | # Negative form of a boolean argument (--foo=false) | |
1038 | assert_equal( | |
1039 | { | |
1040 | "prefix": "osd pool delete", | |
1041 | "pool": "foo", | |
1042 | "pool2": "foo", | |
1043 | "yes_i_really_really_mean_it": False | |
1044 | }, validate_command(sigdict, [ | |
1045 | 'osd', 'pool', 'delete', "foo", "foo", | |
1046 | "--yes-i-really-really-mean-it=false"])) | |
1047 | ||
1048 | # Invalid value boolean argument (--foo=somethingelse) | |
1049 | assert_equal({}, validate_command(sigdict, [ | |
1050 | 'osd', 'pool', 'delete', "foo", "foo", | |
1051 | "--yes-i-really-really-mean-it=rhubarb"])) | |
1052 | ||
7c673cae FG |
1053 | def test_pool_create(self): |
1054 | self.assert_valid_command(['osd', 'pool', 'create', | |
1055 | 'poolname', '128']) | |
1056 | self.assert_valid_command(['osd', 'pool', 'create', | |
1057 | 'poolname', '128', '128']) | |
1058 | self.assert_valid_command(['osd', 'pool', 'create', | |
1059 | 'poolname', '128', '128', | |
1060 | 'replicated']) | |
1061 | self.assert_valid_command(['osd', 'pool', 'create', | |
1062 | 'poolname', '128', '128', | |
1063 | 'erasure', 'A-Za-z0-9-_.', 'ruleset^^']) | |
9f95a23c | 1064 | self.assert_valid_command(['osd', 'pool', 'create', 'poolname']) |
7c673cae | 1065 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'create'])) |
9f95a23c TL |
1066 | # invalid pg_num and pgp_num, like "-1", could spill over to |
1067 | # erasure_code_profile and rule as they are valid profile and rule | |
1068 | # names, so validate_commands() cannot identify such cases. | |
1069 | # but if they are matched by profile and rule, the "rule" argument | |
1070 | # won't get a chance to be matched anymore. | |
7c673cae | 1071 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'create', |
9f95a23c TL |
1072 | 'poolname', |
1073 | '-1', '-1', | |
1074 | 'ruleset'])) | |
7c673cae FG |
1075 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'create', |
1076 | 'poolname', | |
1077 | '128', '128', | |
1078 | 'erasure', '^^^', | |
1079 | 'ruleset'])) | |
1080 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'create', | |
1081 | 'poolname', | |
1082 | '128', '128', | |
1083 | 'erasure', 'profile', | |
1084 | 'ruleset', | |
1085 | 'toomany'])) | |
1086 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'create', | |
1087 | 'poolname', | |
1088 | '128', '128', | |
1089 | 'INVALID', 'profile', | |
1090 | 'ruleset'])) | |
1091 | ||
1092 | def test_pool_delete(self): | |
1093 | self.assert_valid_command(['osd', 'pool', 'delete', | |
1094 | 'poolname', 'poolname', | |
1095 | '--yes-i-really-really-mean-it']) | |
1096 | self.assert_valid_command(['osd', 'pool', 'delete', | |
1097 | 'poolname', 'poolname']) | |
1098 | self.assert_valid_command(['osd', 'pool', 'delete', | |
1099 | 'poolname']) | |
1100 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'delete'])) | |
7c673cae FG |
1101 | assert_equal({}, validate_command(sigdict, |
1102 | ['osd', 'pool', 'delete', | |
1103 | 'poolname', 'poolname', | |
1104 | '--yes-i-really-really-mean-it', | |
1105 | 'toomany'])) | |
1106 | ||
1107 | def test_pool_rename(self): | |
1108 | self.assert_valid_command(['osd', 'pool', 'rename', | |
1109 | 'poolname', 'othername']) | |
1110 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'rename'])) | |
1111 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'rename', | |
1112 | 'poolname'])) | |
1113 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'rename', | |
1114 | 'poolname', 'othername', | |
1115 | 'toomany'])) | |
1116 | ||
1117 | def test_pool_get(self): | |
11fdf7f2 TL |
1118 | for var in ('size', 'min_size', |
1119 | 'pg_num', 'pgp_num', 'crush_rule', 'fast_read', | |
7c673cae FG |
1120 | 'scrub_min_interval', 'scrub_max_interval', |
1121 | 'deep_scrub_interval', 'recovery_priority', | |
1122 | 'recovery_op_priority'): | |
1123 | self.assert_valid_command(['osd', 'pool', 'get', 'poolname', var]) | |
1124 | assert_equal({}, validate_command(sigdict, ['osd', 'pool'])) | |
1125 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', | |
1126 | 'get'])) | |
1127 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', | |
1128 | 'get', 'poolname'])) | |
1129 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', | |
1130 | 'get', 'poolname', | |
1131 | 'size', 'toomany'])) | |
1132 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', | |
1133 | 'get', 'poolname', | |
1134 | 'invalid'])) | |
1135 | ||
1136 | def test_pool_set(self): | |
11fdf7f2 | 1137 | for var in ('size', 'min_size', |
31f18b77 | 1138 | 'pg_num', 'pgp_num', 'crush_rule', |
11fdf7f2 | 1139 | 'hashpspool', 'fast_read', |
7c673cae FG |
1140 | 'scrub_min_interval', 'scrub_max_interval', |
1141 | 'deep_scrub_interval', 'recovery_priority', | |
1142 | 'recovery_op_priority'): | |
1143 | self.assert_valid_command(['osd', 'pool', | |
1144 | 'set', 'poolname', var, 'value']) | |
1145 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', | |
1146 | 'set'])) | |
1147 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', | |
1148 | 'set', 'poolname'])) | |
1149 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', | |
1150 | 'set', 'poolname', | |
1151 | 'size', 'value', | |
1152 | 'toomany'])) | |
1153 | ||
1154 | def test_pool_set_quota(self): | |
1155 | for field in ('max_objects', 'max_bytes'): | |
1156 | self.assert_valid_command(['osd', 'pool', 'set-quota', | |
1157 | 'poolname', field, '10K']) | |
1158 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', | |
1159 | 'set-quota'])) | |
1160 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', | |
1161 | 'set-quota', | |
1162 | 'poolname'])) | |
1163 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', | |
1164 | 'set-quota', | |
1165 | 'poolname', | |
1166 | 'max_objects'])) | |
1167 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', | |
1168 | 'set-quota', | |
1169 | 'poolname', | |
1170 | 'invalid', | |
1171 | '10K'])) | |
1172 | assert_equal({}, validate_command(sigdict, ['osd', 'pool', | |
1173 | 'set-quota', | |
1174 | 'poolname', | |
1175 | 'max_objects', | |
1176 | '10K', | |
1177 | 'toomany'])) | |
1178 | ||
1179 | def test_reweight_by_utilization(self): | |
1180 | self.assert_valid_command(['osd', 'reweight-by-utilization']) | |
1181 | self.assert_valid_command(['osd', 'reweight-by-utilization', '100']) | |
1182 | self.assert_valid_command(['osd', 'reweight-by-utilization', '100', '.1']) | |
7c673cae FG |
1183 | assert_equal({}, validate_command(sigdict, ['osd', |
1184 | 'reweight-by-utilization', | |
1185 | '100', | |
1186 | 'toomany'])) | |
1187 | ||
1188 | def test_tier_op(self): | |
1189 | for op in ('add', 'remove', 'set-overlay'): | |
1190 | self.assert_valid_command(['osd', 'tier', op, | |
1191 | 'poolname', 'othername']) | |
1192 | assert_equal({}, validate_command(sigdict, ['osd', 'tier', op])) | |
1193 | assert_equal({}, validate_command(sigdict, ['osd', 'tier', op, | |
1194 | 'poolname'])) | |
1195 | assert_equal({}, validate_command(sigdict, ['osd', 'tier', op, | |
1196 | 'poolname', | |
1197 | 'othername', | |
1198 | 'toomany'])) | |
1199 | ||
1200 | def test_tier_cache_mode(self): | |
b3b6e05e | 1201 | for mode in ('none', 'writeback', 'readonly', 'readproxy'): |
7c673cae FG |
1202 | self.assert_valid_command(['osd', 'tier', 'cache-mode', |
1203 | 'poolname', mode]) | |
1204 | assert_equal({}, validate_command(sigdict, ['osd', 'tier', | |
1205 | 'cache-mode'])) | |
1206 | assert_equal({}, validate_command(sigdict, ['osd', 'tier', | |
1207 | 'cache-mode', | |
1208 | 'invalid'])) | |
1209 | ||
1210 | def test_tier_remove_overlay(self): | |
1211 | self.assert_valid_command(['osd', 'tier', 'remove-overlay', | |
1212 | 'poolname']) | |
1213 | assert_equal({}, validate_command(sigdict, ['osd', 'tier', | |
1214 | 'remove-overlay'])) | |
1215 | assert_equal({}, validate_command(sigdict, ['osd', 'tier', | |
1216 | 'remove-overlay', | |
1217 | 'poolname', | |
1218 | 'toomany'])) | |
1219 | ||
1220 | def set_ratio(self, command): | |
1221 | self.assert_valid_command(['osd', | |
1222 | command, | |
1223 | '0.0']) | |
1224 | assert_equal({}, validate_command(sigdict, ['osd', command])) | |
1225 | assert_equal({}, validate_command(sigdict, ['osd', | |
1226 | command, | |
1227 | '2.0'])) | |
1228 | ||
1229 | def test_set_full_ratio(self): | |
1230 | self.set_ratio('set-full-ratio') | |
1231 | ||
1232 | def test_set_backfillfull_ratio(self): | |
1233 | self.set_ratio('set-backfillfull-ratio') | |
1234 | ||
1235 | def test_set_nearfull_ratio(self): | |
1236 | self.set_ratio('set-nearfull-ratio') | |
1237 | ||
1238 | ||
1239 | class TestConfigKey(TestArgparse): | |
1240 | ||
1241 | def test_get(self): | |
1242 | self.check_1_string_arg('config-key', 'get') | |
1243 | ||
1244 | def test_put(self): | |
1245 | self.assert_valid_command(['config-key', 'put', | |
1246 | 'key']) | |
1247 | self.assert_valid_command(['config-key', 'put', | |
1248 | 'key', 'value']) | |
1249 | assert_equal({}, validate_command(sigdict, ['config-key', 'put'])) | |
1250 | assert_equal({}, validate_command(sigdict, ['config-key', 'put', | |
1251 | 'key', 'value', | |
1252 | 'toomany'])) | |
1253 | ||
1254 | def test_del(self): | |
1255 | self.check_1_string_arg('config-key', 'del') | |
1256 | ||
1257 | def test_exists(self): | |
1258 | self.check_1_string_arg('config-key', 'exists') | |
1259 | ||
1260 | def test_dump(self): | |
11fdf7f2 | 1261 | self.check_0_or_1_string_arg('config-key', 'dump') |
7c673cae FG |
1262 | |
1263 | def test_list(self): | |
1264 | self.check_no_arg('config-key', 'list') | |
9f95a23c TL |
1265 | |
1266 | ||
1267 | class TestValidate(TestCase): | |
1268 | ||
1269 | ARGS = 0 | |
1270 | KWARGS = 1 | |
1271 | KWARGS_EQ = 2 | |
1272 | MIXED = 3 | |
1273 | ||
1274 | def setUp(self): | |
1275 | self.prefix = ['some', 'random', 'cmd'] | |
1276 | self.args_dict = [ | |
1277 | {'name': 'variable_one', 'type': 'CephString'}, | |
1278 | {'name': 'variable_two', 'type': 'CephString'}, | |
1279 | {'name': 'variable_three', 'type': 'CephString'}, | |
1280 | {'name': 'variable_four', 'type': 'CephInt'}, | |
1281 | {'name': 'variable_five', 'type': 'CephString'}] | |
1282 | self.args = [] | |
1283 | for d in self.args_dict: | |
1284 | if d['type'] == 'CephInt': | |
1285 | val = "{}".format(random.randint(0, 100)) | |
1286 | elif d['type'] == 'CephString': | |
1287 | letters = string.ascii_letters | |
1288 | str_len = random.randint(5, 10) | |
1289 | val = ''.join(random.choice(letters) for _ in range(str_len)) | |
1290 | else: | |
1291 | self.skipTest() | |
1292 | ||
1293 | self.args.append((d['name'], val)) | |
1294 | ||
1295 | self.sig = parse_funcsig(self.prefix + self.args_dict) | |
1296 | ||
b3b6e05e | 1297 | @nottest |
9f95a23c TL |
1298 | def arg_kwarg_test(self, prefix, args, sig, arg_type=0): |
1299 | """ | |
1300 | Runs validate in different arg/kargs ways. | |
1301 | ||
1302 | :param prefix: List of prefix commands (that can't be kwarged) | |
1303 | :param args: a list of kwarg, arg pairs: [(k1, v1), (k2, v2), ...] | |
1304 | :param sig: The sig to match | |
1305 | :param arg_type: how to build the args to send. As positional args (ARGS), | |
1306 | as long kwargs (KWARGS [--k v]), other style long kwargs | |
1307 | (KWARGS_EQ (--k=v]), and mixed (MIXED) where there will be | |
1308 | a random mix of the above. | |
1309 | :return: None, the method will assert. | |
1310 | """ | |
1311 | final_args = list(prefix) | |
1312 | for k, v in args: | |
1313 | a_type = arg_type | |
1314 | if a_type == self.MIXED: | |
1315 | a_type = random.choice((self.ARGS, | |
b3b6e05e TL |
1316 | self.KWARGS, |
1317 | self.KWARGS_EQ)) | |
9f95a23c TL |
1318 | if a_type == self.ARGS: |
1319 | final_args.append(v) | |
1320 | elif a_type == self.KWARGS: | |
1321 | final_args.extend(["--{}".format(k), v]) | |
1322 | else: | |
1323 | final_args.append("--{}={}".format(k, v)) | |
1324 | ||
1325 | try: | |
1326 | validate(final_args, sig) | |
1327 | except (ArgumentError, ArgumentMissing, | |
1328 | ArgumentNumber, ArgumentTooFew, ArgumentValid) as ex: | |
1329 | self.fail("Validation failed: {}".format(str(ex))) | |
1330 | ||
1331 | def test_args_and_kwargs_validate(self): | |
1332 | for arg_type in (self.ARGS, self.KWARGS, self.KWARGS_EQ, self.MIXED): | |
1333 | self.arg_kwarg_test(self.prefix, self.args, self.sig, arg_type) | |
1334 | ||
7c673cae | 1335 | # Local Variables: |
9f95a23c TL |
1336 | # compile-command: "cd ../../..; cmake --build build --target get_command_descriptions -j4 && |
1337 | # CEPH_BIN=build/bin \ | |
1338 | # PYTHONPATH=src/pybind nosetests --stop \ | |
1339 | # src/test/pybind/test_ceph_argparse.py:TestOSD.test_rm" | |
7c673cae | 1340 | # End: |