diff options
author | Sage Weil <sage@inktank.com> | 2013-09-23 16:42:26 -0700 |
---|---|---|
committer | Sage Weil <sage@inktank.com> | 2013-09-23 16:42:26 -0700 |
commit | 08c386f54254bb5652d811e4caf339b619a39109 (patch) | |
tree | ef5b65cab1cb447e5bd656363fd343497ff2e926 | |
parent | 286a6991900fdfc66e1c44a0299f3de8d30e7785 (diff) | |
parent | bfd4db2525b37f52a90c74deb8233edb60cc5d97 (diff) | |
download | ceph-08c386f54254bb5652d811e4caf339b619a39109.tar.gz |
Merge pull request #588 from dachary/wip-6274
mon: unit tests to protect against some MonCommands.h typos
-rw-r--r-- | .gitignore | 8 | ||||
-rw-r--r-- | ceph.spec.in | 1 | ||||
-rw-r--r-- | debian/control | 1 | ||||
-rw-r--r-- | src/.gitignore | 1 | ||||
-rw-r--r-- | src/Makefile-env.am | 7 | ||||
-rw-r--r-- | src/Makefile.am | 5 | ||||
-rw-r--r-- | src/mon/MonCommands.h | 2 | ||||
-rw-r--r-- | src/mon/Monitor.cc | 46 | ||||
-rw-r--r-- | src/mon/Monitor.h | 12 | ||||
-rw-r--r-- | src/pybind/ceph_argparse.py | 5 | ||||
-rw-r--r-- | src/test/Makefile.am | 11 | ||||
-rw-r--r-- | src/test/common/get_command_descriptions.cc | 116 | ||||
-rwxr-xr-x | src/test/pybind/test_ceph_argparse.py | 1036 |
13 files changed, 1223 insertions, 28 deletions
diff --git a/.gitignore b/.gitignore index 211c09cbba7..7e637866366 100644 --- a/.gitignore +++ b/.gitignore @@ -69,4 +69,10 @@ web/*.html # dir from coverity tools cov-int/ -/test-driver
\ No newline at end of file +/test-driver + +# gtags(1) generated files +GPATH +GRTAGS +GSYMS +GTAGS diff --git a/ceph.spec.in b/ceph.spec.in index 851ee7acfd5..a60d87ad814 100644 --- a/ceph.spec.in +++ b/ceph.spec.in @@ -37,6 +37,7 @@ BuildRequires: perl BuildRequires: gdbm BuildRequires: pkgconfig BuildRequires: python +BuildRequires: python-nose BuildRequires: libaio-devel BuildRequires: libcurl-devel BuildRequires: libxml2-devel diff --git a/debian/control b/debian/control index 44ee725efd4..1aec592c9f8 100644 --- a/debian/control +++ b/debian/control @@ -34,6 +34,7 @@ Build-Depends: autoconf, libxml2-dev, pkg-config, python (>= 2.6.6-3~), + python-nose, uuid-dev, yasm Standards-Version: 3.9.3 diff --git a/src/.gitignore b/src/.gitignore index 4c98529bd87..6efe8dc6bc4 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -68,6 +68,7 @@ Makefile /test_* /cls_test_* /unittest_* +/get_command_descriptions # old dir, may in use by older branches /leveldb diff --git a/src/Makefile-env.am b/src/Makefile-env.am index 900998702f5..6a4e09512a2 100644 --- a/src/Makefile-env.am +++ b/src/Makefile-env.am @@ -8,6 +8,7 @@ CLEANFILES = noinst_HEADERS = bin_PROGRAMS = +noinst_PROGRAMS = bin_SCRIPTS = sbin_PROGRAMS = sbin_SCRIPTS = @@ -26,6 +27,12 @@ ceph_sbindir = $(exec_prefix)$(sbindir) # C/C++ tests to build will be appended to this check_PROGRAMS = +# tests scripts will be appended to this +check_SCRIPTS = + +# python unit tests need to know where the scripts are located +export PYTHONPATH=$(top_srcdir)/src/pybind + # when doing a debug build, make sure to make the targets if WITH_DEBUG bin_PROGRAMS += $(bin_DEBUGPROGRAMS) diff --git a/src/Makefile.am b/src/Makefile.am index ed07a91e3ae..5e745a0573f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -251,10 +251,11 @@ shell_scripts += init-ceph mkcephfs # executables built, you need to replace this with manual assignments # target by target -TESTS = $(check_PROGRAMS) unittest_bufferlist.sh +TESTS = \ + $(check_PROGRAMS) \ + $(check_SCRIPTS) check-local: - $(srcdir)/test/encoding/check-generated.sh $(srcdir)/test/encoding/readable.sh ../ceph-object-corpus diff --git a/src/mon/MonCommands.h b/src/mon/MonCommands.h index 365fd28b64e..482ea91ea02 100644 --- a/src/mon/MonCommands.h +++ b/src/mon/MonCommands.h @@ -290,7 +290,7 @@ COMMAND("mds newfs " \ * Monmap commands */ COMMAND("mon dump " \ - "name=epoch,type=CephInt,req=false", \ + "name=epoch,type=CephInt,range=0,req=false", \ "dump formatted monmap (optionally from epoch)", \ "mon", "r", "cli,rest") COMMAND("mon stat", "summarize monitor status", "mon", "r", "cli,rest") diff --git a/src/mon/Monitor.cc b/src/mon/Monitor.cc index 10f5bfb149c..2c64a8f2ef2 100644 --- a/src/mon/Monitor.cc +++ b/src/mon/Monitor.cc @@ -1854,13 +1854,7 @@ void Monitor::get_status(stringstream &ss, Formatter *f) } #undef COMMAND -struct MonCommand { - string cmdstring; - string helpstring; - string module; - string req_perms; - string availability; -} mon_commands[] = { +MonCommand mon_commands[] = { #define COMMAND(parsesig, helptext, modulename, req_perms, avail) \ {parsesig, helptext, modulename, req_perms, avail}, #include <mon/MonCommands.h> @@ -1909,6 +1903,26 @@ bool Monitor::_allowed_command(MonSession *s, string &module, string &prefix, return capable; } +void get_command_descriptions(const MonCommand *commands, + unsigned commands_size, + Formatter *f, + bufferlist *rdata) { + int cmdnum = 0; + f->open_object_section("command_descriptions"); + for (const MonCommand *cp = commands; + cp < &commands[commands_size]; cp++) { + + ostringstream secname; + secname << "cmd" << setfill('0') << std::setw(3) << cmdnum; + dump_cmddesc_to_json(f, secname.str(), + cp->cmdstring, cp->helpstring, cp->module, + cp->req_perms, cp->availability); + cmdnum++; + } + f->close_section(); // command_descriptions + + f->flush(*rdata); +} void Monitor::handle_command(MMonCommand *m) { @@ -1953,23 +1967,9 @@ void Monitor::handle_command(MMonCommand *m) cmd_getval(g_ceph_context, cmdmap, "prefix", prefix); if (prefix == "get_command_descriptions") { - int cmdnum = 0; - Formatter *f = new_formatter("json"); - f->open_object_section("command_descriptions"); - for (MonCommand *cp = mon_commands; - cp < &mon_commands[ARRAY_SIZE(mon_commands)]; cp++) { - - ostringstream secname; - secname << "cmd" << setfill('0') << std::setw(3) << cmdnum; - dump_cmddesc_to_json(f, secname.str(), - cp->cmdstring, cp->helpstring, cp->module, - cp->req_perms, cp->availability); - cmdnum++; - } - f->close_section(); // command_descriptions - bufferlist rdata; - f->flush(rdata); + Formatter *f = new_formatter("json"); + get_command_descriptions(mon_commands, ARRAY_SIZE(mon_commands), f, &rdata); delete f; reply_command(m, 0, "", rdata, 0); return; diff --git a/src/mon/Monitor.h b/src/mon/Monitor.h index df4a751361a..9b304428732 100644 --- a/src/mon/Monitor.h +++ b/src/mon/Monitor.h @@ -844,5 +844,17 @@ public: long parse_pos_long(const char *s, ostream *pss = NULL); +struct MonCommand { + string cmdstring; + string helpstring; + string module; + string req_perms; + string availability; +}; + +void get_command_descriptions(const MonCommand *commands, + unsigned commands_size, + Formatter *f, + bufferlist *rdata); #endif diff --git a/src/pybind/ceph_argparse.py b/src/pybind/ceph_argparse.py index 427a4621216..f115d3791af 100644 --- a/src/pybind/ceph_argparse.py +++ b/src/pybind/ceph_argparse.py @@ -278,7 +278,10 @@ class CephEntityAddr(CephIPAddr): EntityAddress, that is, IP address/nonce """ def valid(self, s, partial=False): - ip, nonce = s.split('/') + try: + ip, nonce = s.split('/') + except: + raise ArgumentValid('{0} must contain a /'.format(s)) super(self.__class__, self).valid(ip) self.nonce = nonce self.val = s diff --git a/src/test/Makefile.am b/src/test/Makefile.am index 647aad3550d..5b709d248a8 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -65,6 +65,11 @@ endif bin_PROGRAMS += ceph-dencoder +get_command_descriptions_SOURCES = test/common/get_command_descriptions.cc +get_command_descriptions_CXXFLAGS = $(UNITTEST_CXXFLAGS) +get_command_descriptions_LDADD = $(LIBMON) $(LIBCOMMON) $(UNITTEST_LDADD) $(CEPH_GLOBAL) +noinst_PROGRAMS += get_command_descriptions + ## Build tests # These should all use explicit _CXXFLAGS so avoid basename conflicts @@ -228,6 +233,10 @@ bin_DEBUGPROGRAMS += ceph_bench_log ## Unit tests +check_SCRIPTS += \ + $(srcdir)/unittest_bufferlist.sh \ + $(srcdir)/test/encoding/check-generated.sh + # target to build but not run the unit tests unittests:: $(check_PROGRAMS) @@ -537,6 +546,8 @@ unittest_texttable_LDADD = $(LIBCOMMON) $(UNITTEST_LDADD) unittest_texttable_CXXFLAGS = $(UNITTEST_CXXFLAGS) check_PROGRAMS += unittest_texttable +check_SCRIPTS += test/pybind/test_ceph_argparse.py + if WITH_RADOSGW ceph_test_cors_SOURCES = test/test_cors.cc ceph_test_cors_LDADD = \ diff --git a/src/test/common/get_command_descriptions.cc b/src/test/common/get_command_descriptions.cc new file mode 100644 index 00000000000..afca8254c42 --- /dev/null +++ b/src/test/common/get_command_descriptions.cc @@ -0,0 +1,116 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2013 Cloudwatt <libre.licensing@cloudwatt.com> + * + * Author: Loic Dachary <loic@dachary.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details. + * + */ + +#include <stdio.h> +#include <signal.h> +#include "mon/Monitor.h" +#include "common/ceph_argparse.h" +#include "global/global_init.h" +#include "common/debug.h" + +#define dout_subsys ceph_subsys_mon + +static void usage(ostream &out) +{ + out << "usage: get_command_descriptions [options ...]" << std::endl; + out << "print on stdout the result of JSON formatted options\n"; + out << "found in mon/MonCommands.h as produced by the\n"; + out << "Monitor.cc::get_command_descriptions function.\n"; + out << "Designed as a helper for ceph_argparse.py unit tests.\n"; + out << "\n"; + out << " --all all of mon/MonCommands.h \n"; + out << " --pull585 reproduce the bug fixed by #585\n"; + out << "\n"; + out << "Examples:\n"; + out << " get_command_descriptions --all\n"; + out << " get_command_descriptions --pull585\n"; +} + +static void json_print(const MonCommand *mon_commands, int size) +{ + bufferlist rdata; + Formatter *f = new_formatter("json"); + get_command_descriptions(mon_commands, size, f, &rdata); + delete f; + string data(rdata.c_str()); + dout(0) << data << dendl; +} + +static void all() +{ +#undef COMMAND + MonCommand mon_commands[] = { +#define COMMAND(parsesig, helptext, modulename, req_perms, avail) \ + {parsesig, helptext, modulename, req_perms, avail}, +#include <mon/MonCommands.h> + }; + + json_print(mon_commands, ARRAY_SIZE(mon_commands)); +} + +// syntax error https://github.com/ceph/ceph/pull/585 +static void pull585() +{ + MonCommand mon_commands[] = { + { "osd pool create " + "name=pool,type=CephPoolname " + "name=pg_num,type=CephInt,range=0 " + "name=pgp_num,type=CephInt,range=0,req=false" // !!! missing trailing space + "name=properties,type=CephString,n=N,req=false,goodchars=[A-Za-z0-9-_.=]", + "create pool", "osd", "rw", "cli,rest" } + }; + + json_print(mon_commands, ARRAY_SIZE(mon_commands)); +} + +int main(int argc, char **argv) { + vector<const char*> args; + argv_to_vec(argc, (const char **)argv, args); + + global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); + common_init_finish(g_ceph_context); + + if (args.empty()) { + usage(cerr); + exit(1); + } + for (std::vector<const char*>::iterator i = args.begin(); i != args.end(); ++i) { + string err; + + if (*i == string("help") || *i == string("-h") || *i == string("--help")) { + usage(cout); + exit(0); + } else if (*i == string("--all")) { + all(); + } else if (*i == string("--pull585")) { + pull585(); + } + } +} + +/* + * Local Variables: + * compile-command: "cd ../.. ; + * make get_command_descriptions && + * ./get_command_descriptions --all --pull585" + * End: + */ + diff --git a/src/test/pybind/test_ceph_argparse.py b/src/test/pybind/test_ceph_argparse.py new file mode 100755 index 00000000000..85af54d6f75 --- /dev/null +++ b/src/test/pybind/test_ceph_argparse.py @@ -0,0 +1,1036 @@ +#!/usr/bin/nosetests --nocapture +# -*- mode:python; tab-width:4; indent-tabs-mode:t -*- +# vim: ts=4 sw=4 smarttab expandtab +# +# Ceph - scalable distributed file system +# +# Copyright (C) 2013 Cloudwatt <libre.licensing@cloudwatt.com> +# +# Author: Loic Dachary <loic@dachary.org> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# + +from nose.tools import eq_ as eq +from nose.tools import * + +from ceph_argparse import validate_command, parse_json_funcsigs + +import os +import re +import json + +def get_command_descriptions(what): + buffer = os.popen("./get_command_descriptions " + "--" + what + + " 2>&1 | grep cmd000").read() + return re.sub(r'^.*?(\{.*\})', '\g<1>', buffer) + +def test_parse_json_funcsigs(): + commands = get_command_descriptions("all") + cmd_json = parse_json_funcsigs(commands, 'cli') + + # syntax error https://github.com/ceph/ceph/pull/585 + commands = get_command_descriptions("pull585") + assert_raises(TypeError, parse_json_funcsigs, commands, 'cli') + +sigdict = parse_json_funcsigs(get_command_descriptions("all"), 'cli') + + +class TestArgparse: + + def assert_valid_command(self, args): + result = validate_command(sigdict, args) + assert_not_in(result, [None, {}]) + + def check_1_natural_arg(self, prefix, command): + self.assert_valid_command([prefix, command, '1']) + assert_equal({}, validate_command(sigdict, [prefix, command])) + assert_equal({}, validate_command(sigdict, [prefix, command, '-1'])) + assert_equal({}, validate_command(sigdict, [prefix, command, '1', + '1'])) + + def check_0_or_1_natural_arg(self, prefix, command): + self.assert_valid_command([prefix, command, '1']) + self.assert_valid_command([prefix, command]) + assert_equal({}, validate_command(sigdict, [prefix, command, '-1'])) + assert_equal({}, validate_command(sigdict, [prefix, command, '1', + '1'])) + + def check_1_string_arg(self, prefix, command): + assert_equal({}, validate_command(sigdict, [prefix, command])) + self.assert_valid_command([prefix, command, 'string']) + assert_equal({}, validate_command(sigdict, [prefix, + command, + 'string', + 'toomany'])) + + def check_1_or_more_string_args(self, prefix, command): + assert_equal({}, validate_command(sigdict, [prefix, + command])) + self.assert_valid_command([prefix, + command, + 'string']) + self.assert_valid_command([prefix, + command, + 'string', + 'more string']) + + def check_no_arg(self, prefix, command): + self.assert_valid_command([prefix, + command]) + assert_equal({}, validate_command(sigdict, [prefix, + command, + 'toomany'])) + + +class TestPG(TestArgparse): + + def test_stat(self): + self.assert_valid_command(['pg', 'stat']) + + def test_getmap(self): + self.assert_valid_command(['pg', 'getmap']) + + def test_send_pg_creates(self): + self.assert_valid_command(['pg', 'send_pg_creates']) + + def test_dump(self): + self.assert_valid_command(['pg', 'dump']) + self.assert_valid_command(['pg', 'dump', + 'all', + 'summary', + 'sum', + 'delta', + 'pools', + 'osds', + 'pgs', + 'pgs_brief']) + assert_equal({}, validate_command(sigdict, ['pg', 'dump', 'invalid'])) + + def test_dump_json(self): + self.assert_valid_command(['pg', 'dump_json']) + self.assert_valid_command(['pg', 'dump_json', + 'all', + 'summary', + 'sum', + 'pools', + 'osds', + 'pgs']) + assert_equal({}, validate_command(sigdict, ['pg', 'dump_json', + 'invalid'])) + + def test_dump_pools_json(self): + self.assert_valid_command(['pg', 'dump_pools_json']) + + def test_dump_pools_stuck(self): + self.assert_valid_command(['pg', 'dump_stuck']) + self.assert_valid_command(['pg', 'dump_stuck', + 'inactive', + 'unclean', + 'stale']) + assert_equal({}, validate_command(sigdict, ['pg', 'dump_stuck', + 'invalid'])) + self.assert_valid_command(['pg', 'dump_stuck', + 'inactive', + '1234']) + + def one_pgid(self, command): + self.assert_valid_command(['pg', command, '1.1']) + assert_equal({}, validate_command(sigdict, ['pg', command])) + assert_equal({}, validate_command(sigdict, ['pg', command, '1'])) + + def test_map(self): + self.one_pgid('map') + + def test_scrub(self): + self.one_pgid('scrub') + + def test_deep_scrub(self): + self.one_pgid('deep-scrub') + + def test_repair(self): + self.one_pgid('repair') + + def test_debug(self): + self.assert_valid_command(['pg', + 'debug', + 'unfound_objects_exist']) + self.assert_valid_command(['pg', + 'debug', + 'degraded_pgs_exist']) + assert_equal({}, validate_command(sigdict, ['pg', 'debug'])) + assert_equal({}, validate_command(sigdict, ['pg', 'debug', + 'invalid'])) + + def test_force_create_pg(self): + self.one_pgid('force_create_pg') + + def set_ratio(self, command): + self.assert_valid_command(['pg', + command, + '0.0']) + assert_equal({}, validate_command(sigdict, ['pg', command])) + assert_equal({}, validate_command(sigdict, ['pg', + command, + '2.0'])) + + def test_set_full_ratio(self): + self.set_ratio('set_full_ratio') + + def test_set_nearfull_ratio(self): + self.set_ratio('set_nearfull_ratio') + + +class TestAuth(TestArgparse): + + def test_export(self): + self.assert_valid_command(['auth', 'export']) + self.assert_valid_command(['auth', + 'export', + 'string']) + assert_equal({}, validate_command(sigdict, ['auth', + 'export', + 'string', + 'toomany'])) + + def test_get(self): + self.check_1_string_arg('auth', 'get') + + def test_get_key(self): + self.check_1_string_arg('auth', 'get-key') + + def test_print_key(self): + self.check_1_string_arg('auth', 'print-key') + self.check_1_string_arg('auth', 'print_key') + + def test_list(self): + self.check_no_arg('auth', 'list') + + def test_import(self): + self.check_no_arg('auth', 'import') + + def test_add(self): + self.check_1_or_more_string_args('auth', 'add') + + def test_get_or_create_key(self): + self.check_1_or_more_string_args('auth', 'get-or-create-key') + + def test_get_or_create(self): + self.check_1_or_more_string_args('auth', 'get-or-create') + + def test_caps(self): + assert_equal({}, validate_command(sigdict, ['auth', + 'caps'])) + assert_equal({}, validate_command(sigdict, ['auth', + 'caps', + 'string'])) + self.assert_valid_command(['auth', + 'caps', + 'string', + 'more string']) + + def test_del(self): + self.check_1_string_arg('auth', 'del') + + +class TestMonitor(TestArgparse): + + def test_compact(self): + self.assert_valid_command(['compact']) + + def test_scrub(self): + self.assert_valid_command(['scrub']) + + def test_fsid(self): + self.assert_valid_command(['fsid']) + + def test_log(self): + assert_equal({}, validate_command(sigdict, ['log'])) + self.assert_valid_command(['log', 'a logtext']) + self.assert_valid_command(['log', 'a logtext', 'and another']) + + def test_injectargs(self): + assert_equal({}, validate_command(sigdict, ['injectargs'])) + self.assert_valid_command(['injectargs', 'one']) + self.assert_valid_command(['injectargs', 'one', 'two']) + + def test_status(self): + self.assert_valid_command(['status']) + + def test_health(self): + self.assert_valid_command(['health']) + self.assert_valid_command(['health', 'detail']) + assert_equal({}, validate_command(sigdict, ['health', 'invalid'])) + assert_equal({}, validate_command(sigdict, ['health', 'detail', + 'toomany'])) + + def test_df(self): + self.assert_valid_command(['df']) + self.assert_valid_command(['df', 'detail']) + assert_equal({}, validate_command(sigdict, ['df', 'invalid'])) + assert_equal({}, validate_command(sigdict, ['df', 'detail', + 'toomany'])) + + def test_report(self): + self.assert_valid_command(['report']) + self.assert_valid_command(['report', 'tag1']) + self.assert_valid_command(['report', 'tag1', 'tag2']) + + def test_quorum_status(self): + self.assert_valid_command(['quorum_status']) + + def test_mon_status(self): + self.assert_valid_command(['mon_status']) + + def test_sync_force(self): + self.assert_valid_command(['sync', + 'force', + '--yes-i-really-mean-it', + '--i-know-what-i-am-doing']) + assert_equal({}, validate_command(sigdict, ['sync'])) + assert_equal({}, validate_command(sigdict, ['sync', + 'force'])) + assert_equal({}, validate_command(sigdict, ['sync', + 'force', + '--yes-i-really-mean-it'])) + assert_equal({}, validate_command(sigdict, ['sync', + 'force', + '--yes-i-really-mean-it', + '--i-know-what-i-am-doing', + 'toomany'])) + + def test_heap(self): + assert_equal({}, validate_command(sigdict, ['heap'])) + assert_equal({}, validate_command(sigdict, ['heap', 'invalid'])) + self.assert_valid_command(['heap', 'dump']) + self.assert_valid_command(['heap', 'start_profiler']) + self.assert_valid_command(['heap', 'stop_profiler']) + self.assert_valid_command(['heap', 'release']) + self.assert_valid_command(['heap', 'stats']) + + def test_quorum(self): + assert_equal({}, validate_command(sigdict, ['quorum'])) + assert_equal({}, validate_command(sigdict, ['quorum', 'invalid'])) + self.assert_valid_command(['quorum', 'enter']) + self.assert_valid_command(['quorum', 'exit']) + assert_equal({}, validate_command(sigdict, ['quorum', + 'enter', + 'toomany'])) + + def test_tell(self): + assert_equal({}, validate_command(sigdict, ['tell'])) + assert_equal({}, validate_command(sigdict, ['tell', 'invalid'])) + for name in ('osd', 'mon', 'client', 'mds'): + assert_equal({}, validate_command(sigdict, ['tell', name])) + assert_equal({}, validate_command(sigdict, ['tell', + name + ".42"])) + self.assert_valid_command(['tell', name + ".42", 'something']) + self.assert_valid_command(['tell', name + ".42", + 'something', + 'something else']) + + +class TestMDS(TestArgparse): + + def test_stat(self): + self.check_no_arg('mds', 'stat') + + def test_dump(self): + self.check_0_or_1_natural_arg('mds', 'dump') + + def test_tell(self): + self.assert_valid_command(['mds', 'tell', + 'someone', + 'something']) + self.assert_valid_command(['mds', 'tell', + 'someone', + 'something', + 'something else']) + assert_equal({}, validate_command(sigdict, ['mds', 'tell'])) + assert_equal({}, validate_command(sigdict, ['mds', 'tell', + 'someone'])) + + def test_compat_show(self): + self.assert_valid_command(['mds', 'compat', 'show']) + assert_equal({}, validate_command(sigdict, ['mds', 'compat'])) + assert_equal({}, validate_command(sigdict, ['mds', 'compat', + 'show', 'toomany'])) + + def test_stop(self): + self.assert_valid_command(['mds', 'stop', 'someone']) + assert_equal({}, validate_command(sigdict, ['mds', 'stop'])) + assert_equal({}, validate_command(sigdict, ['mds', 'stop', + 'someone', 'toomany'])) + + def test_deactivate(self): + self.assert_valid_command(['mds', 'deactivate', 'someone']) + assert_equal({}, validate_command(sigdict, ['mds', 'deactivate'])) + assert_equal({}, validate_command(sigdict, ['mds', 'deactivate', + 'someone', 'toomany'])) + + def test_set_max_mds(self): + self.check_1_natural_arg('mds', 'set_max_mds') + + def test_setmap(self): + self.check_1_natural_arg('mds', 'setmap') + + def test_set_state(self): + self.assert_valid_command(['mds', 'set_state', '1', '2']) + assert_equal({}, validate_command(sigdict, ['mds', 'set_state'])) + assert_equal({}, validate_command(sigdict, ['mds', 'set_state', '-1'])) + assert_equal({}, validate_command(sigdict, ['mds', 'set_state', + '1', '-1'])) + assert_equal({}, validate_command(sigdict, ['mds', 'set_state', + '1', '21'])) + + def test_fail(self): + self.check_1_string_arg('mds', 'fail') + + def test_rm(self): + assert_equal({}, validate_command(sigdict, ['mds', 'rm'])) + assert_equal({}, validate_command(sigdict, ['mds', 'rm', '1'])) + for name in ('osd', 'mon', 'client', 'mds'): + self.assert_valid_command(['mds', 'rm', '1', name + '.42']) + assert_equal({}, validate_command(sigdict, ['mds', 'rm', + '-1', name + '.42'])) + assert_equal({}, validate_command(sigdict, ['mds', 'rm', + '-1', name])) + assert_equal({}, validate_command(sigdict, ['mds', 'rm', + '1', name + '.42', + 'toomany'])) + + def test_rmfailed(self): + self.check_1_natural_arg('mds', 'rmfailed') + + def test_cluster_down(self): + self.check_no_arg('mds', 'cluster_down') + + def test_cluster_up(self): + self.check_no_arg('mds', 'cluster_up') + + def test_compat_rm_compat(self): + self.assert_valid_command(['mds', 'compat', 'rm_compat', '1']) + assert_equal({}, validate_command(sigdict, ['mds', + 'compat', + 'rm_compat'])) + assert_equal({}, validate_command(sigdict, ['mds', + 'compat', + 'rm_compat', '-1'])) + assert_equal({}, validate_command(sigdict, ['mds', + 'compat', + 'rm_compat', '1', '1'])) + + def test_incompat_rm_incompat(self): + self.assert_valid_command(['mds', 'compat', 'rm_incompat', '1']) + assert_equal({}, validate_command(sigdict, ['mds', + 'compat', + 'rm_incompat'])) + assert_equal({}, validate_command(sigdict, ['mds', + 'compat', + 'rm_incompat', '-1'])) + assert_equal({}, validate_command(sigdict, ['mds', + 'compat', + 'rm_incompat', '1', '1'])) + + def test_add_data_pool(self): + self.check_1_natural_arg('mds', 'add_data_pool') + + def test_remove_data_pool(self): + self.check_1_natural_arg('mds', 'remove_data_pool') + + def test_newfs(self): + self.assert_valid_command(['mds', 'newfs', '1', '2', + '--yes-i-really-mean-it']) + assert_equal({}, validate_command(sigdict, ['mds', 'newfs'])) + assert_equal({}, validate_command(sigdict, ['mds', 'newfs', '1'])) + assert_equal({}, validate_command(sigdict, ['mds', 'newfs', '1', '1'])) + assert_equal({}, validate_command(sigdict, ['mds', 'newfs', '1', '1', + 'no I dont'])) + assert_equal({}, validate_command(sigdict, ['mds', + 'newfs', + '1', + '2', + '--yes-i-really-mean-it', + 'toomany'])) + assert_equal({}, validate_command(sigdict, ['mds', + 'newfs', + '-1', + '2', + '--yes-i-really-mean-it'])) + assert_equal({}, validate_command(sigdict, ['mds', + 'newfs', + '1', + '-1', + '--yes-i-really-mean-it'])) + + +class TestMon(TestArgparse): + + def test_dump(self): + self.check_0_or_1_natural_arg('mon', 'dump') + + def test_stat(self): + self.check_no_arg('mon', 'stat') + + def test_getmap(self): + self.check_0_or_1_natural_arg('mon', 'getmap') + + def test_add(self): + self.assert_valid_command(['mon', 'add', 'name', '1.2.3.4:1234']) + assert_equal({}, validate_command(sigdict, ['mon', 'add'])) + assert_equal({}, validate_command(sigdict, ['mon', 'add', 'name'])) + assert_equal({}, validate_command(sigdict, ['mon', 'add', + 'name', + '400.500.600.700'])) + assert_equal({}, validate_command(sigdict, ['mon', 'add', 'name', + '1.2.3.4:1234', + 'toomany'])) + + def test_remove(self): + self.assert_valid_command(['mon', 'remove', 'name']) + assert_equal({}, validate_command(sigdict, ['mon', 'remove'])) + assert_equal({}, validate_command(sigdict, ['mon', 'remove', + 'name', 'toomany'])) + + +class TestOSD(TestArgparse): + + def test_stat(self): + self.check_no_arg('osd', 'stat') + + def test_dump(self): + self.check_0_or_1_natural_arg('osd', 'dump') + + def test_osd_tree(self): + self.check_0_or_1_natural_arg('osd', 'tree') + + def test_osd_ls(self): + self.check_0_or_1_natural_arg('osd', 'ls') + + def test_osd_getmap(self): + self.check_0_or_1_natural_arg('osd', 'getmap') + + def test_osd_getcrushmap(self): + self.check_0_or_1_natural_arg('osd', 'getcrushmap') + + def test_perf(self): + self.check_no_arg('osd', 'perf') + + def test_getmaxosd(self): + self.check_no_arg('osd', 'getmaxosd') + + def test_find(self): + self.check_1_natural_arg('osd', 'find') + + def test_map(self): + self.assert_valid_command(['osd', 'map', 'poolname', 'objectname']) + assert_equal({}, validate_command(sigdict, ['osd', 'map'])) + assert_equal({}, validate_command(sigdict, ['osd', 'map', 'poolname'])) + assert_equal({}, validate_command(sigdict, ['osd', 'map', + 'poolname', 'objectname', + 'toomany'])) + + def test_scrub(self): + self.check_1_string_arg('osd', 'scrub') + + def test_deep_scrub(self): + self.check_1_string_arg('osd', 'deep-scrub') + + def test_repair(self): + self.check_1_string_arg('osd', 'repair') + + def test_lspools(self): + self.assert_valid_command(['osd', 'lspools']) + self.assert_valid_command(['osd', 'lspools', '1']) + self.assert_valid_command(['osd', 'lspools', '-1']) + assert_equal({}, validate_command(sigdict, ['osd', 'lspools', + '1', 'toomany'])) + + def test_blacklist_ls(self): + self.assert_valid_command(['osd', 'blacklist', 'ls']) + assert_equal({}, validate_command(sigdict, ['osd', 'blacklist'])) + assert_equal({}, validate_command(sigdict, ['osd', 'blacklist', + 'ls', 'toomany'])) + + def test_crush_rule(self): + assert_equal({}, validate_command(sigdict, ['osd', 'crush'])) + assert_equal({}, validate_command(sigdict, ['osd', 'crush', 'rule'])) + for subcommand in ('list', 'ls', 'dump'): + self.assert_valid_command(['osd', 'crush', 'rule', subcommand]) + assert_equal({}, validate_command(sigdict, ['osd', 'crush', + 'rule', subcommand, + 'toomany'])) + + def test_crush_dump(self): + self.assert_valid_command(['osd', 'crush', 'dump']) + assert_equal({}, validate_command(sigdict, ['osd', 'crush'])) + assert_equal({}, validate_command(sigdict, ['osd', 'crush', + 'dump', 'toomany'])) + + def test_setcrushmap(self): + self.check_no_arg('osd', 'setcrushmap') + + def test_crush_add_bucket(self): + self.assert_valid_command(['osd', 'crush', 'add-bucket', + 'name', 'type']) + assert_equal({}, validate_command(sigdict, ['osd', 'crush'])) + assert_equal({}, validate_command(sigdict, ['osd', 'crush', + 'add-bucket'])) + assert_equal({}, validate_command(sigdict, ['osd', 'crush', + 'add-bucket', 'name', + 'type', + 'toomany'])) + assert_equal({}, validate_command(sigdict, ['osd', 'crush', + 'add-bucket', '!!!', + 'type'])) + + def check_crush_setter(self, setter): + self.assert_valid_command(['osd', 'crush', setter, + '*', '2.3', 'AZaz09-_.=']) + self.assert_valid_command(['osd', 'crush', setter, + 'osd.0', '2.3', 'AZaz09-_.=']) + self.assert_valid_command(['osd', 'crush', setter, + '0', '2.3', 'AZaz09-_.=']) + self.assert_valid_command(['osd', 'crush', setter, + '0', '2.3', 'AZaz09-_.=', 'AZaz09-_.=']) + assert_equal({}, validate_command(sigdict, ['osd', 'crush', + setter, + 'osd.0'])) + assert_in(validate_command(sigdict, ['osd', 'crush', + setter, + 'osd.0', + '-1.0']), + [None, {}]) + assert_equal({}, validate_command(sigdict, ['osd', 'crush', + setter, + 'osd.0', + '1.0', + '!!!'])) + + def test_crush_set(self): + assert_equal({}, validate_command(sigdict, ['osd', 'crush'])) + self.check_crush_setter('set') + + def test_crush_add(self): + assert_equal({}, validate_command(sigdict, ['osd', 'crush'])) + self.check_crush_setter('add') + + def test_crush_create_or_move(self): + assert_equal({}, validate_command(sigdict, ['osd', 'crush'])) + self.check_crush_setter('create-or-move') + + def test_crush_move(self): + self.assert_valid_command(['osd', 'crush', 'move', + 'AZaz09-_.', 'AZaz09-_.=']) + self.assert_valid_command(['osd', 'crush', 'move', + '0', 'AZaz09-_.=', 'AZaz09-_.=']) + assert_equal({}, validate_command(sigdict, ['osd', 'crush', + 'move'])) + assert_equal({}, validate_command(sigdict, ['osd', 'crush', + 'move', 'AZaz09-_.'])) + assert_equal({}, validate_command(sigdict, ['osd', 'crush', + 'move', '!!!', + 'AZaz09-_.='])) + assert_equal({}, validate_command(sigdict, ['osd', 'crush', + 'move', 'AZaz09-_.', + '!!!'])) + + def test_crush_link(self): + self.assert_valid_command(['osd', 'crush', 'link', + 'name', 'AZaz09-_.=']) + self.assert_valid_command(['osd', 'crush', 'link', + 'name', 'AZaz09-_.=', 'AZaz09-_.=']) + assert_equal({}, validate_command(sigdict, ['osd', 'crush', + 'link'])) + assert_equal({}, validate_command(sigdict, ['osd', 'crush', + 'link', + 'name'])) + + def test_crush_rm(self): + for alias in ('rm', 'remove', 'unlink'): + self.assert_valid_command(['osd', 'crush', alias, 'AZaz09-_.']) + self.assert_valid_command(['osd', 'crush', alias, + 'AZaz09-_.', 'AZaz09-_.']) + assert_equal({}, validate_command(sigdict, ['osd', 'crush', + alias])) + assert_equal({}, validate_command(sigdict, ['osd', 'crush', + alias, + 'AZaz09-_.', + 'AZaz09-_.', + 'toomany'])) + + def test_crush_reweight(self): + self.assert_valid_command(['osd', 'crush', 'reweight', + 'AZaz09-_.', '2.3']) + assert_equal({}, validate_command(sigdict, ['osd', 'crush', + 'reweight'])) + assert_equal({}, validate_command(sigdict, ['osd', 'crush', + 'reweight', + 'AZaz09-_.'])) + assert_equal({}, validate_command(sigdict, ['osd', 'crush', + 'reweight', + 'AZaz09-_.', + '-1.0'])) + assert_equal({}, validate_command(sigdict, ['osd', 'crush', + 'reweight', + '!!!', + '2.3'])) + + def test_crush_tunables(self): + for tunable in ('legacy', 'argonaut', 'bobtail', 'optimal', 'default'): + self.assert_valid_command(['osd', 'crush', 'tunables', + tunable]) + assert_equal({}, validate_command(sigdict, ['osd', 'crush', + 'tunables'])) + assert_equal(None, validate_command(sigdict, ['osd', 'crush', + 'default', 'toomany'])) + + def test_crush_rule_create_simple(self): + self.assert_valid_command(['osd', 'crush', 'rule', 'create-simple', + 'AZaz09-_.', 'AZaz09-_.', 'AZaz09-_.']) + assert_equal(None, validate_command(sigdict, ['osd', 'crush', + 'create-simple'])) + assert_equal(None, validate_command(sigdict, ['osd', 'crush', + 'create-simple', + 'AZaz09-_.'])) + assert_equal(None, validate_command(sigdict, ['osd', 'crush', + 'create-simple', + 'AZaz09-_.', + 'AZaz09-_.'])) + assert_equal(None, validate_command(sigdict, ['osd', 'crush', + 'create-simple', + '!!!', + 'AZaz09-_.', + 'AZaz09-_.'])) + assert_equal(None, validate_command(sigdict, ['osd', 'crush', + 'create-simple', + 'AZaz09-_.', + '|||', + 'AZaz09-_.'])) + assert_equal(None, validate_command(sigdict, ['osd', 'crush', + 'create-simple', + 'AZaz09-_.', + 'AZaz09-_.', + '+++'])) + assert_equal(None, validate_command(sigdict, ['osd', 'crush', + 'create-simple', + 'AZaz09-_.', + 'AZaz09-_.', + 'AZaz09-_.', + 'toomany'])) + + def test_crush_rule_rm(self): + self.assert_valid_command(['osd', 'crush', 'rule', 'rm', 'AZaz09-_.']) + assert_equal({}, validate_command(sigdict, ['osd', 'crush', + 'rule', 'rm'])) + assert_equal({}, validate_command(sigdict, ['osd', 'crush', + 'rule', 'rm', + '!!!!'])) + assert_equal({}, validate_command(sigdict, ['osd', 'crush', + 'rule', 'rm', + 'AZaz09-_.', + 'toomany'])) + + def test_setmaxosd(self): + self.check_1_natural_arg('osd', 'setmaxosd') + + def test_pause(self): + self.check_no_arg('osd', 'pause') + + def test_unpause(self): + self.check_no_arg('osd', 'unpause') + + def test_set_unset(self): + for action in ('set', 'unset'): + for flag in ('pause', 'noup', 'nodown', 'noout', 'noin', + 'nobackfill', 'norecover', 'noscrub', 'nodeep-scrub'): + self.assert_valid_command(['osd', action, flag]) + assert_equal({}, validate_command(sigdict, ['osd', action])) + assert_equal({}, validate_command(sigdict, ['osd', action, + 'invalid'])) + assert_equal({}, validate_command(sigdict, ['osd', action, + 'pause', 'toomany'])) + + def test_cluster_snap(self): + assert_equal(None, validate_command(sigdict, ['osd', 'cluster_snap'])) + + def test_down(self): + self.check_1_or_more_string_args('osd', 'down') + + def test_out(self): + self.check_1_or_more_string_args('osd', 'out') + + def test_in(self): + self.check_1_or_more_string_args('osd', 'in') + + def test_rm(self): + self.check_1_or_more_string_args('osd', 'rm') + + def test_reweight(self): + self.assert_valid_command(['osd', 'reweight', '1', '0.1']) + assert_equal({}, validate_command(sigdict, ['osd', 'reweight'])) + assert_equal({}, validate_command(sigdict, ['osd', 'reweight', + '1'])) + assert_equal({}, validate_command(sigdict, ['osd', 'reweight', + '1', '2.0'])) + assert_equal({}, validate_command(sigdict, ['osd', 'reweight', + '-1', '0.1'])) + assert_equal({}, validate_command(sigdict, ['osd', 'reweight', + '1', '0.1', + 'toomany'])) + + def test_lost(self): + self.assert_valid_command(['osd', 'lost', '1', + '--yes-i-really-mean-it']) + assert_equal({}, validate_command(sigdict, ['osd', 'lost'])) + assert_equal({}, validate_command(sigdict, ['osd', 'lost', + '1'])) + assert_equal({}, validate_command(sigdict, ['osd', 'lost', + '1', + 'what?'])) + assert_equal({}, validate_command(sigdict, ['osd', 'lost', + '-1', + '--yes-i-really-mean-it'])) + assert_equal({}, validate_command(sigdict, ['osd', 'lost', + '1', + '--yes-i-really-mean-it', + 'toomany'])) + + def test_create(self): + uuid = '12345678123456781234567812345678' + self.assert_valid_command(['osd', 'create']) + self.assert_valid_command(['osd', 'create', + uuid]) + assert_equal({}, validate_command(sigdict, ['osd', 'create', + 'invalid'])) + assert_equal({}, validate_command(sigdict, ['osd', 'create', + uuid, + 'toomany'])) + + def test_blackist(self): + for action in ('add', 'rm'): + self.assert_valid_command(['osd', 'blacklist', action, + '1.2.3.4/nonce']) + self.assert_valid_command(['osd', 'blacklist', action, + '1.2.3.4/nonce', '600.40']) + assert_equal({}, validate_command(sigdict, ['osd', 'blacklist', + action, + 'invalid', + '600.40'])) + assert_equal({}, validate_command(sigdict, ['osd', 'blacklist', + action, + '1.2.3.4/nonce', + '-1.0'])) + assert_equal({}, validate_command(sigdict, ['osd', 'blacklist', + action, + '1.2.3.4/nonce', + '600.40', + 'toomany'])) + + def test_pool_mksnap(self): + self.assert_valid_command(['osd', 'pool', 'mksnap', + 'poolname', 'snapname']) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'mksnap'])) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'mksnap', + 'poolname'])) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'mksnap', + 'poolname', 'snapname', + 'toomany'])) + + def test_pool_rmsnap(self): + self.assert_valid_command(['osd', 'pool', 'rmsnap', + 'poolname', 'snapname']) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'rmsnap'])) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'rmsnap', + 'poolname'])) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'rmsnap', + 'poolname', 'snapname', + 'toomany'])) + + def test_pool_create(self): + self.assert_valid_command(['osd', 'pool', 'create', + 'poolname', '128']) + self.assert_valid_command(['osd', 'pool', 'create', + 'poolname', '128', '128']) + self.assert_valid_command(['osd', 'pool', 'create', + 'poolname', '128', '128', + 'foo=bar']) + self.assert_valid_command(['osd', 'pool', 'create', + 'poolname', '128', '128', + 'foo=bar', 'baz=frob']) + self.assert_valid_command(['osd', 'pool', 'create', + 'poolname', '128', + 'foo=bar', 'baz=frob']) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'create'])) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'create', + 'poolname'])) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'create', + 'poolname', '-1'])) + + def test_pool_delete(self): + self.assert_valid_command(['osd', 'pool', 'delete', + 'poolname', 'poolname', + '--yes-i-really-really-mean-it']) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'delete'])) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'delete', + 'poolname'])) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'delete', + 'poolname', 'poolname'])) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'delete', + 'poolname', 'poolname', + 'not really'])) + assert_equal({}, validate_command(sigdict, + ['osd', 'pool', 'delete', + 'poolname', 'poolname', + '--yes-i-really-really-mean-it', + 'toomany'])) + + def test_pool_rename(self): + self.assert_valid_command(['osd', 'pool', 'rename', + 'poolname', 'othername']) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'rename'])) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'rename', + 'poolname'])) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', 'rename', + 'poolname', 'othername', + 'toomany'])) + + def test_pool_get(self): + for var in ('size', 'min_size', 'crash_replay_interval', + 'pg_num', 'pgp_num', 'crush_ruleset'): + self.assert_valid_command(['osd', 'pool', 'get', 'poolname', var]) + assert_equal({}, validate_command(sigdict, ['osd', 'pool'])) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', + 'get'])) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', + 'get', 'poolname'])) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', + 'get', 'poolname', + 'size', 'toomany'])) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', + 'get', 'poolname', + 'invalid'])) + + def test_pool_set(self): + for var in ('size', 'min_size', 'crash_replay_interval', + 'pg_num', 'pgp_num', 'crush_ruleset'): + self.assert_valid_command(['osd', 'pool', + 'set', 'poolname', var, '-1']) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', + 'set'])) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', + 'set', 'poolname'])) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', + 'set', 'poolname', + 'size', 'invalid'])) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', + 'set', 'poolname', + 'invalid', '-1'])) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', + 'set', 'poolname', + 'size', '-1', + 'toomany'])) + + def test_pool_set_quota(self): + for field in ('max_objects', 'max_bytes'): + self.assert_valid_command(['osd', 'pool', 'set-quota', + 'poolname', field, '10K']) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', + 'set-quota'])) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', + 'set-quota', + 'poolname'])) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', + 'set-quota', + 'poolname', + 'max_objects'])) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', + 'set-quota', + 'poolname', + 'invalid', + '10K'])) + assert_equal({}, validate_command(sigdict, ['osd', 'pool', + 'set-quota', + 'poolname', + 'max_objects', + '10K', + 'toomany'])) + + def test_reweight_by_utilization(self): + self.assert_valid_command(['osd', 'reweight-by-utilization']) + self.assert_valid_command(['osd', 'reweight-by-utilization', '100']) + assert_equal({}, validate_command(sigdict, ['osd', + 'reweight-by-utilization', + '50'])) + assert_equal({}, validate_command(sigdict, ['osd', + 'reweight-by-utilization', + '100', + 'toomany'])) + + def test_thrash(self): + self.check_1_natural_arg('osd', 'thrash') + + def test_tier_op(self): + for op in ('add', 'remove', 'set-overlay'): + self.assert_valid_command(['osd', 'tier', op, + 'poolname', 'othername']) + assert_equal({}, validate_command(sigdict, ['osd', 'tier', op])) + assert_equal({}, validate_command(sigdict, ['osd', 'tier', op, + 'poolname'])) + assert_equal({}, validate_command(sigdict, ['osd', 'tier', op, + 'poolname', + 'othername', + 'toomany'])) + + def test_tier_cache_mode(self): + for mode in ('none', 'writeback', 'invalidate+forward', 'readonly'): + self.assert_valid_command(['osd', 'tier', 'cache-mode', + 'poolname', mode]) + assert_equal({}, validate_command(sigdict, ['osd', 'tier', + 'cache-mode'])) + assert_equal({}, validate_command(sigdict, ['osd', 'tier', + 'cache-mode', + 'invalid'])) + + def test_tier_remove_overlay(self): + self.assert_valid_command(['osd', 'tier', 'remove-overlay', + 'poolname']) + assert_equal({}, validate_command(sigdict, ['osd', 'tier', + 'remove-overlay'])) + assert_equal({}, validate_command(sigdict, ['osd', 'tier', + 'remove-overlay', + 'poolname', + 'toomany'])) + + +class TestConfigKey(TestArgparse): + + def test_get(self): + self.check_1_string_arg('config-key', 'get') + + def test_put(self): + self.assert_valid_command(['config-key', 'put', + 'key']) + self.assert_valid_command(['config-key', 'put', + 'key', 'value']) + assert_equal({}, validate_command(sigdict, ['config-key', 'put'])) + assert_equal({}, validate_command(sigdict, ['config-key', 'put', + 'key', 'value', + 'toomany'])) + + def test_del(self): + self.check_1_string_arg('config-key', 'del') + + def test_exists(self): + self.check_1_string_arg('config-key', 'exists') + + def test_list(self): + self.check_no_arg('config-key', 'list') +# Local Variables: +# compile-command: "cd ../.. ; make -j4 && +# PYTHONPATH=pybind nosetests --stop \ +# test/pybind/test_ceph_argparse.py # test_ceph_argparse.py:TestOSD.test_rm" +# End: |