tests: further expand logctl unit tests 59/198459/3
authorMichal Bloch <m.bloch@samsung.com>
Thu, 24 Jan 2019 18:30:40 +0000 (19:30 +0100)
committerMichal Bloch <m.bloch@samsung.com>
Fri, 25 Jan 2019 16:02:53 +0000 (16:02 +0000)
Change-Id: I022b9e8c090a2bcfcff7b7e7d697257f73d545cc
Signed-off-by: Michal Bloch <m.bloch@samsung.com>
include/logctl.h
src/logctl/logctl.c
src/tests/logctl.c

index 068c9af..31154a1 100644 (file)
@@ -19,8 +19,8 @@ struct parsed_params {
        const char *tag;
        char prio;
        const char *value;
-       int plog_buffers_bitset;
        bool plog_enable;
+       int plog_buffers_bitset;
 };
 
 struct keys_values {
@@ -33,3 +33,7 @@ bool parse_options(int argc, const char **argv, struct parsed_params *params, in
 
 int copy_file_with_exceptions(const char *config_path, struct keys_values *kv);
 
+int handle_set(const struct parsed_params *params, const char *config_path, struct log_config *conf);
+int handle_plog(const struct parsed_params *params, const char *config_path, struct log_config *conf);
+int handle_clear(const struct parsed_params *params, const char *config_path, struct log_config *conf);
+
index f809b0c..3cb6835 100644 (file)
@@ -298,7 +298,7 @@ remove_temp:
        return EXIT_FAILURE;
 }
 
-int handle_set(const struct parsed_params *params, char *config_path, struct log_config *conf)
+int handle_set(const struct parsed_params *params, const char *config_path, struct log_config *conf)
 {
        __attribute__((cleanup(free_ptr))) char *key;
        if (asprintf(&key, "limiter|%s|%c=", params->tag, params->prio) < 0) {
@@ -317,7 +317,7 @@ int handle_set(const struct parsed_params *params, char *config_path, struct log
        return copy_file_with_exceptions(config_path, &kv);
 }
 
-int handle_clear(const struct parsed_params *params, char *config_path, struct log_config *conf)
+int handle_clear(const struct parsed_params *params, const char *config_path, struct log_config *conf)
 {
        char *key = "limiter|"; // note: no '=' at the end, so as to match all rules
        const char *value = NULL; // removal
@@ -331,7 +331,7 @@ int handle_clear(const struct parsed_params *params, char *config_path, struct l
        return copy_file_with_exceptions(config_path, &kv);
 }
 
-int handle_plog(const struct parsed_params *params, char *config_path, struct log_config *conf)
+int handle_plog(const struct parsed_params *params, const char *config_path, struct log_config *conf)
 {
        const int buffers_bitset = params->plog_buffers_bitset ?: ((1 << LOG_ID_MAX) - 1);
 
@@ -366,6 +366,7 @@ int handle_plog(const struct parsed_params *params, char *config_path, struct lo
        return copy_file_with_exceptions(config_path, &kv);
 }
 
+#ifndef UNIT_TEST
 static void print_limit(int limit, const char *tag, char prio, bool *shadowed, bool dynamic)
 {
        const char *const shadow_str = *shadowed ? "[shadowed] " : "";
@@ -390,7 +391,7 @@ static void print_limit(int limit, const char *tag, char prio, bool *shadowed, b
                *shadowed = true;
 }
 
-static void get_limits(const struct parsed_params *params, char *config_path, struct log_config *conf)
+static void get_limits(const struct parsed_params *params, const char *config_path, struct log_config *conf)
 {
        struct limiter_limits lims_static = __log_limiter_get_limits(params->tag, params->prio);
 
@@ -450,7 +451,7 @@ static void print_limits_for_prio(const struct parsed_params *params, const char
        }
 }
 
-static void get_prio_limits(const struct parsed_params *params, char *config_path, struct log_config *conf)
+static void get_prio_limits(const struct parsed_params *params, const char *config_path, struct log_config *conf)
 {
        static const char prio_list[] = {'V', 'D', 'I', 'W', 'E', 'F' , 'S' , '*'};
        struct prio_applies_to applies_dynamic = { .count = 0 };
@@ -472,7 +473,7 @@ static void get_prio_limits(const struct parsed_params *params, char *config_pat
 }
 
 
-int handle_get(const struct parsed_params *params, char *config_path, struct log_config *conf)
+int handle_get(const struct parsed_params *params, const char *config_path, struct log_config *conf)
 {
        if (!__log_limiter_create(conf)) {
                ERR("error creating limiter\n");
@@ -488,7 +489,7 @@ int handle_get(const struct parsed_params *params, char *config_path, struct log
        return EXIT_SUCCESS;
 }
 
-int handle_dump(const struct parsed_params *params, char *config_path, struct log_config *conf)
+int handle_dump(const struct parsed_params *params, const char *config_path, struct log_config *conf)
 {
        if (!__log_limiter_create(conf)) {
                ERR("error creating limiter\n");
@@ -524,7 +525,6 @@ int handle_dump(const struct parsed_params *params, char *config_path, struct lo
        return EXIT_SUCCESS;
 }
 
-#ifndef UNIT_TEST
 int main(int argc, const char **argv)
 {
        int exit_code = EXIT_FAILURE;
@@ -556,7 +556,7 @@ int main(int argc, const char **argv)
                return EXIT_FAILURE;
        }
 
-       int (*handles[])(const struct parsed_params *, char *, struct log_config *) = {
+       int (*handles[])(const struct parsed_params *, const char *, struct log_config *) = {
                [ACTION_GET]   = handle_get,
                [ACTION_SET]   = handle_set,
                [ACTION_DUMP]  = handle_dump,
@@ -567,4 +567,4 @@ int main(int argc, const char **argv)
 
        return exit_code;
 }
-#endif
+#endif // !UNIT_TEST
index ecd7912..a5631d4 100644 (file)
@@ -6,9 +6,41 @@
 #include <logcommon.h>
 #include <logctl.h>
 
+static const char *const TMPFILE_PATH = "src/tests/logctl_testfile";
+
+void _prepare_file(const char *const *lines, size_t lines_cnt)
+{
+       __attribute__((cleanup(close_FILE))) FILE *const file_prep = fopen(TMPFILE_PATH, "w");
+       assert(file_prep);
+
+       for (size_t i = 0; i < lines_cnt; ++i) {
+               fputs(lines[i], file_prep);
+               fputc('\n', file_prep);
+       }
+}
+#define PREPARE_FILE(lines) _prepare_file(lines, NELEMS(lines))
+
+void _compare_file(const char *const *lines, size_t lines_cnt)
+{
+       __attribute__((cleanup(close_FILE))) FILE *const file_result = fopen(TMPFILE_PATH, "r");
+       assert(file_result);
+
+       char line[1024];
+       size_t lines_read = 0;
+       while (fgets(line, sizeof line, file_result)) {
+               assert(lines_read < lines_cnt);
+
+               const size_t expected_len = strlen(lines[lines_read]);
+               assert(line[expected_len] == '\n');
+               assert(!strncmp(line, lines[lines_read], expected_len));
+
+               ++lines_read;
+       }
+}
+#define COMPARE_FILE(lines) _compare_file(lines, NELEMS(lines))
+
 void test_copy_file_with_exceptions()
 {
-       static const char *const tmpfile_path = "src/tests/logctl_testfile";
        static const char *const lines_in[] = {
                "FOO=BAR",
                "FOOOO=BAZ",
@@ -30,6 +62,8 @@ void test_copy_file_with_exceptions()
                {"QWER=", "ASDF"},
        };
 
+       PREPARE_FILE(lines_in);
+
        struct keys_values kv = {
                .keys   = calloc(NELEMS(kv_pairs), sizeof *kv.keys),
                .values = calloc(NELEMS(kv_pairs), sizeof *kv.values),
@@ -42,37 +76,219 @@ void test_copy_file_with_exceptions()
                kv.values[i] = kv_pairs[i].value;
        }
 
-       FILE *const file_prep = fopen(tmpfile_path, "w");
-       assert(file_prep);
-       for (size_t i = 0; i < NELEMS(lines_in); ++i) {
-               fputs(lines_in[i], file_prep);
-               fputc('\n', file_prep);
-       }
-       fclose(file_prep);
-
-       const int ret = copy_file_with_exceptions(tmpfile_path, &kv);
+       const int ret = copy_file_with_exceptions(TMPFILE_PATH, &kv);
        assert(ret == EXIT_SUCCESS);
 
-       FILE *const file_result = fopen(tmpfile_path, "r");
-       assert(file_result);
+       COMPARE_FILE(lines_out);
+}
 
-       char line[1024];
-       size_t lines_read = 0;
-       while (fgets(line, sizeof line, file_result)) {
-               assert(lines_read <= NELEMS(lines_out));
-               if (lines_read == NELEMS(lines_out))
-                       continue;
+void test_handle_clear()
+{
+       static const char *const lines_in[] = {
+               "limiter|x|y=BAR",
+               "FOOOO=BAZ",
+               "ABC=XYZ",
+               "limiter|zzz|*=15",
+               "ABC=ZYX",
+               "limiter|qwe|*=22",
+               "limiter|qwe|*=22",
+               "QWEZ=ASDX",
+       };
+       static const char *const lines_out[] = {
+               "FOOOO=BAZ",
+               "ABC=XYZ",
+               "ABC=ZYX",
+               "QWEZ=ASDX",
+       };
 
-               const size_t expected_len = strlen(lines_out[lines_read]);
-               assert(line[expected_len] == '\n');
-               assert(!strncmp(line, lines_out[lines_read], expected_len));
+       PREPARE_FILE(lines_in);
+       assert(EXIT_SUCCESS == handle_clear(NULL, TMPFILE_PATH, NULL));
+       COMPARE_FILE(lines_out);
+}
 
-               ++lines_read;
-       }
-       fclose(file_result);
+void test_handle_set()
+{
+       static const char *const lines_in[] = {
+               "QWER=QWER",
+               "limiter|x|y=BAR",
+               "FOOOO=BAZ",
+               "limiter|z|t=FOO",
+               "ABC=XYZ",
+       };
+       static const char *const lines_set[] = {
+               "QWER=QWER",
+               "FOOOO=BAZ",
+               "limiter|z|t=FOO",
+               "ABC=XYZ",
+               "limiter|x|y=QUUX",
+       };
+       static const char *const lines_clear[] = {
+               "QWER=QWER",
+               "FOOOO=BAZ",
+               "ABC=XYZ",
+               "limiter|x|y=QUUX",
+       };
+
+       struct parsed_params pp;
+       PREPARE_FILE(lines_in);
+
+       pp.tag = "x";
+       pp.prio = 'y';
+       pp.value = "QUUX";
+       assert(EXIT_SUCCESS == handle_set(&pp, TMPFILE_PATH, NULL));
+       COMPARE_FILE(lines_set);
+
+       pp.tag = "z";
+       pp.prio = 't';
+       pp.value = NULL;
+       assert(EXIT_SUCCESS == handle_set(&pp, TMPFILE_PATH, NULL));
+       COMPARE_FILE(lines_clear);
+}
+
+void test_handle_plog()
+{
+       static const char *const lines_in[] = {
+               "QWER=QWER",
+               "enable_main=1",
+               "FOOOO=BAZ",
+               "enable_radio=0",
+               "ABC=XYZ",
+       };
+       static const char *const lines_enabled[] = {
+               "QWER=QWER",
+               "FOOOO=BAZ",
+               "enable_radio=0",
+               "ABC=XYZ",
+               "enable_main=1",
+               "enable_system=1",
+       };
+       static const char *const lines_disabled[] = {
+               "QWER=QWER",
+               "FOOOO=BAZ",
+               "ABC=XYZ",
+               "enable_system=1",
+               "enable_main=0",
+               "enable_radio=0",
+       };
+       static const char *const lines_all[] = {
+               "QWER=QWER",
+               "FOOOO=BAZ",
+               "ABC=XYZ",
+               "enable_main=1",
+               "enable_radio=1",
+               "enable_system=1",
+               "enable_apps=1",
+               "enable_kmsg=1",
+               "enable_syslog=1",
+       };
+
+       struct parsed_params pp;
+       PREPARE_FILE(lines_in);
+
+       pp.plog_enable = true;
+       pp.plog_buffers_bitset = (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM);
+       assert(EXIT_SUCCESS == handle_plog(&pp, TMPFILE_PATH, NULL));
+       COMPARE_FILE(lines_enabled);
+
+       pp.plog_enable = false;
+       pp.plog_buffers_bitset = (1 << LOG_ID_MAIN) | (1 << LOG_ID_RADIO);
+       assert(EXIT_SUCCESS == handle_plog(&pp, TMPFILE_PATH, NULL));
+       COMPARE_FILE(lines_disabled);
+
+       pp.plog_enable = true;
+       pp.plog_buffers_bitset = 0;
+       assert(EXIT_SUCCESS == handle_plog(&pp, TMPFILE_PATH, NULL));
+       COMPARE_FILE(lines_all);
+}
+
+struct expected_opts {
+       int exit_code;
+       bool retval;
+       struct parsed_params pp;
+};
+
+void check_option_set(size_t argc, const char **argv, const struct expected_opts *exp)
+{
+       struct parsed_params pp = {0};
+       int exit_code = 42;
+       bool retval = parse_options((int) argc, argv, &pp, &exit_code);
+
+       optind = 0;
+       optopt = 0;
+       optarg = NULL;
+
+       assert(retval == exp->retval);
+       assert(retval || (exit_code == exp->exit_code));
+       assert(pp.action == exp->pp.action);
+       assert(pp.prio == exp->pp.prio);
+       assert(pp.plog_buffers_bitset == exp->pp.plog_buffers_bitset);
+       assert(pp.plog_enable == exp->pp.plog_enable);
+       assert(pp.value || !exp->pp.value);
+       assert(!pp.value || exp->pp.value);
+       assert(!pp.value || !strcmp(exp->pp.value, pp.value));
+       assert(pp.tag || !exp->pp.tag);
+       assert(!pp.tag || exp->pp.tag);
+       assert(!pp.tag || !strcmp(exp->pp.tag, pp.tag));
+}
+
+void test_parse_options()
+{
+       /* These are primarily covered by integration tests but there's some value
+        * in running this at build time as well to detect any breakage ASAP. */
+
+       const char *none_args[]     = { "x"                                          , NULL};
+       const char *garbage_args[]  = { "x", "--cactus"                              , NULL};
+       const char *clear_args[]    = { "x", "-c", "-t", "tag_to_clear"              , NULL};
+       const char *clr_all_args[]  = { "x", "-c"                                    , NULL};
+       const char *set_args[]      = { "x", "-s", "15", "--priority", "e"           , NULL};
+       const char *get_args[]      = { "x", "-g", "-p", "*", "-t", "*"              , NULL};
+       const char *dump_args[]     = { "x", "-g"                                    , NULL};
+       const char *enable_args[]   = { "x", "--enable",  "-b", "main", "-b", "radio", NULL};
+       const char *disable_args[]  = { "x", "--disable", "-b", "main", "-b", "radio", NULL};
+       const char *help_args[]     = { "x", "--help"                                , NULL};
+
+       const char *prio_err_args[] = { "x", "--priority", "]"                       , NULL};
+       const char *buf_err_args[]  = { "x", "--buffer", "invalid"                   , NULL};
+       const char *plog_err_args[] = { "x", "-g", "--buffer", "main"                , NULL};
+
+       static const struct expected_opts none_opts     = { EXIT_SUCCESS, false, { ACTION_NONE , "*"           , '\0', NULL, false, 0 } };
+       static const struct expected_opts garbage_opts  = { EXIT_SUCCESS, false, { ACTION_NONE , "*"           , '\0', NULL, false, 0 } };
+       static const struct expected_opts clear_opts    = { EXIT_SUCCESS, true , { ACTION_SET  , "tag_to_clear",  '*', NULL, false, 0 } };
+       static const struct expected_opts clr_all_opts  = { EXIT_SUCCESS, true , { ACTION_CLEAR, "*"           , '\0', NULL, false, 0 } };
+       static const struct expected_opts set_opts      = { EXIT_SUCCESS, true , { ACTION_SET  , "*"           ,  'E', "15", false, 0 } };
+       static const struct expected_opts get_opts      = { EXIT_SUCCESS, true , { ACTION_GET  , "*"           ,  '*', NULL, false, 0 } };
+       static const struct expected_opts dump_opts     = { EXIT_SUCCESS, true , { ACTION_DUMP , "*"           , '\0', NULL, false, 0 } };
+       static const struct expected_opts enable_opts   = { EXIT_SUCCESS, true , { ACTION_PLOG , "*"           , '\0', NULL, true , 1 << LOG_ID_MAIN | 1 << LOG_ID_RADIO } };
+       static const struct expected_opts disable_opts  = { EXIT_SUCCESS, true , { ACTION_PLOG , "*"           , '\0', NULL, false, 1 << LOG_ID_MAIN | 1 << LOG_ID_RADIO } };
+       static const struct expected_opts help_opts     = { EXIT_SUCCESS, false, { ACTION_NONE , "*"           , '\0', NULL, false, 0 } };
+
+       static const struct expected_opts prio_err_opts = { EXIT_FAILURE, false, { ACTION_NONE , "*"           ,  ']', NULL, false, 0 } };
+       static const struct expected_opts buf_err_opts  = { EXIT_FAILURE, false, { ACTION_NONE , "*"           , '\0', NULL, false, 0 } };
+       static const struct expected_opts plog_err_opts = { EXIT_FAILURE, false, { ACTION_GET  , "*"           , '\0', NULL, false, 1 << LOG_ID_MAIN } };
+
+#define CHECK_OPTION_SET(TYPE) check_option_set(NELEMS(TYPE##_args) - 1, TYPE##_args, &(TYPE##_opts))
+       CHECK_OPTION_SET(none);
+       CHECK_OPTION_SET(garbage);
+       CHECK_OPTION_SET(clear);
+       CHECK_OPTION_SET(clr_all);
+       CHECK_OPTION_SET(set);
+       CHECK_OPTION_SET(get);
+       CHECK_OPTION_SET(dump);
+       CHECK_OPTION_SET(enable);
+       CHECK_OPTION_SET(disable);
+       CHECK_OPTION_SET(help);
+
+       CHECK_OPTION_SET(prio_err);
+       CHECK_OPTION_SET(buf_err);
+       CHECK_OPTION_SET(plog_err);
+#undef CHECK_OPTION_SET
 }
 
 int main()
 {
        test_copy_file_with_exceptions();
+       test_parse_options();
+       test_handle_clear();
+       test_handle_set();
+       test_handle_plog();
 }