Message ID | 20230824143129.1957914-10-rf@opensource.cirrus.com (mailing list archive) |
---|---|
State | New |
Delegated to: | Brendan Higgins |
Headers | show |
Series | kunit: Add dynamically-extending log | expand |
Hi Richard, kernel test robot noticed the following build warnings: [auto build test WARNING on shuah-kselftest/kunit] [also build test WARNING on next-20230824] [cannot apply to shuah-kselftest/kunit-fixes linus/master v6.5-rc7] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Richard-Fitzgerald/kunit-string-stream-Don-t-create-a-fragment-for-empty-strings/20230824-223722 base: https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git kunit patch link: https://lore.kernel.org/r/20230824143129.1957914-10-rf%40opensource.cirrus.com patch subject: [PATCH v5 09/10] kunit: Use string_stream for test log config: hexagon-randconfig-002-20230825 (https://download.01.org/0day-ci/archive/20230825/202308251443.dMAw1CW3-lkp@intel.com/config) compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project.git 4a5ac14ee968ff0ad5d2cc1ffa0299048db4c88a) reproduce: (https://download.01.org/0day-ci/archive/20230825/202308251443.dMAw1CW3-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202308251443.dMAw1CW3-lkp@intel.com/ All warnings (new ones prefixed by >>): >> lib/kunit/kunit-test.c:542:8: warning: unused variable 'full_log' [-Wunused-variable] 542 | char *full_log; | ^ lib/kunit/kunit-test.c:581:26: warning: cast from 'void (*)(const void *)' to 'kunit_action_t *' (aka 'void (*)(void *)') converts to incompatible function type [-Wcast-function-type-strict] 581 | kunit_add_action(test, (kunit_action_t *)kfree, full_log); | ^~~~~~~~~~~~~~~~~~~~~~~ 2 warnings generated. vim +/full_log +542 lib/kunit/kunit-test.c 533 534 /* 535 * Log tests call string_stream functions, which aren't exported. So only 536 * build this code if this test is built-in. 537 */ 538 #if IS_BUILTIN(CONFIG_KUNIT_TEST) 539 static void kunit_log_test(struct kunit *test) 540 { 541 struct kunit_suite suite; > 542 char *full_log; 543 544 suite.log = kunit_alloc_string_stream(test, GFP_KERNEL); 545 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, suite.log); 546 string_stream_set_append_newlines(suite.log, true); 547 548 kunit_log(KERN_INFO, test, "put this in log."); 549 kunit_log(KERN_INFO, test, "this too."); 550 kunit_log(KERN_INFO, &suite, "add to suite log."); 551 kunit_log(KERN_INFO, &suite, "along with this."); 552
On Thu, 24 Aug 2023 at 22:33, Richard Fitzgerald <rf@opensource.cirrus.com> wrote: > > Replace the fixed-size log buffer with a string_stream so that the > log can grow as lines are added. > > string_stream_clear() has been made public for the log truncation > done in kunit_init_test(). > > The existing kunit log tests have been updated for using a > string_stream as the log. No new test have been added because there > are already tests for the underlying string_stream. > > As the log tests now depend on string_stream functions they cannot > build when kunit-test is a module. They have been surrounded by > a #if to replace them with skipping version when the test is > build as a module. Though this isn't pretty, it avoids moving > code to another file while that code is also being changed. > > Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com> > --- > Changes since V4: > - Don't move the log tests to another file. Deal with only including them > when the test is built-in by wrapping them in a #if. This is to simplify > code review, because it avoids having a block of code which moves from > one file to another but at the same time the code has changed. > - Use kunit_add_action() to automatically free the string returned by > string_stream_get_string(). > --- Looks pretty good to me, and works fine here. The kunit_add_action() cast does trigger the clang warning (but again, it's not something which bothers me much personally). But since you've cleaned it up elsewhere, it may be worth adding a wrapper here, at least until we have a kunit_free_at_end() function or similar. Otherwise, Reviewed-by: David Gow <davidgow@google.com> Cheers, -- David > include/kunit/test.h | 14 +++++------- > lib/kunit/debugfs.c | 36 +++++++++++++++++++----------- > lib/kunit/kunit-test.c | 46 ++++++++++++++++++++++++++++++++------- > lib/kunit/string-stream.c | 2 +- > lib/kunit/string-stream.h | 2 ++ > lib/kunit/test.c | 44 +++++-------------------------------- > 6 files changed, 75 insertions(+), 69 deletions(-) > > diff --git a/include/kunit/test.h b/include/kunit/test.h > index d33114097d0d..b915a0fe93c0 100644 > --- a/include/kunit/test.h > +++ b/include/kunit/test.h > @@ -32,9 +32,7 @@ > DECLARE_STATIC_KEY_FALSE(kunit_running); > > struct kunit; > - > -/* Size of log associated with test. */ > -#define KUNIT_LOG_SIZE 2048 > +struct string_stream; > > /* Maximum size of parameter description string. */ > #define KUNIT_PARAM_DESC_SIZE 128 > @@ -132,7 +130,7 @@ struct kunit_case { > /* private: internal use only. */ > enum kunit_status status; > char *module_name; > - char *log; > + struct string_stream *log; > }; > > static inline char *kunit_status_to_ok_not_ok(enum kunit_status status) > @@ -252,7 +250,7 @@ struct kunit_suite { > /* private: internal use only */ > char status_comment[KUNIT_STATUS_COMMENT_SIZE]; > struct dentry *debugfs; > - char *log; > + struct string_stream *log; > int suite_init_err; > }; > > @@ -278,7 +276,7 @@ struct kunit { > > /* private: internal use only. */ > const char *name; /* Read only after initialization! */ > - char *log; /* Points at case log after initialization */ > + struct string_stream *log; /* Points at case log after initialization */ > struct kunit_try_catch try_catch; > /* param_value is the current parameter value for a test case. */ > const void *param_value; > @@ -314,7 +312,7 @@ const char *kunit_filter_glob(void); > char *kunit_filter(void); > char *kunit_filter_action(void); > > -void kunit_init_test(struct kunit *test, const char *name, char *log); > +void kunit_init_test(struct kunit *test, const char *name, struct string_stream *log); > > int kunit_run_tests(struct kunit_suite *suite); > > @@ -472,7 +470,7 @@ static inline void *kunit_kcalloc(struct kunit *test, size_t n, size_t size, gfp > > void kunit_cleanup(struct kunit *test); > > -void __printf(2, 3) kunit_log_append(char *log, const char *fmt, ...); > +void __printf(2, 3) kunit_log_append(struct string_stream *log, const char *fmt, ...); > > /** > * kunit_mark_skipped() - Marks @test_or_suite as skipped > diff --git a/lib/kunit/debugfs.c b/lib/kunit/debugfs.c > index 22c5c496a68f..270d185737e6 100644 > --- a/lib/kunit/debugfs.c > +++ b/lib/kunit/debugfs.c > @@ -37,14 +37,21 @@ void kunit_debugfs_init(void) > debugfs_rootdir = debugfs_create_dir(KUNIT_DEBUGFS_ROOT, NULL); > } > > -static void debugfs_print_result(struct seq_file *seq, > - struct kunit_suite *suite, > - struct kunit_case *test_case) > +static void debugfs_print_result(struct seq_file *seq, struct string_stream *log) > { > - if (!test_case || !test_case->log) > + struct string_stream_fragment *frag_container; > + > + if (!log) > return; > > - seq_printf(seq, "%s", test_case->log); > + /* > + * Walk the fragments so we don't need to allocate a temporary > + * buffer to hold the entire string. > + */ > + spin_lock(&log->lock); > + list_for_each_entry(frag_container, &log->fragments, node) > + seq_printf(seq, "%s", frag_container->fragment); > + spin_unlock(&log->lock); > } > > /* > @@ -69,10 +76,9 @@ static int debugfs_print_results(struct seq_file *seq, void *v) > seq_printf(seq, KUNIT_SUBTEST_INDENT "1..%zd\n", kunit_suite_num_test_cases(suite)); > > kunit_suite_for_each_test_case(suite, test_case) > - debugfs_print_result(seq, suite, test_case); > + debugfs_print_result(seq, test_case->log); > > - if (suite->log) > - seq_printf(seq, "%s", suite->log); > + debugfs_print_result(seq, suite->log); > > seq_printf(seq, "%s %d %s\n", > kunit_status_to_ok_not_ok(success), 1, suite->name); > @@ -105,9 +111,13 @@ void kunit_debugfs_create_suite(struct kunit_suite *suite) > struct kunit_case *test_case; > > /* Allocate logs before creating debugfs representation. */ > - suite->log = kzalloc(KUNIT_LOG_SIZE, GFP_KERNEL); > - kunit_suite_for_each_test_case(suite, test_case) > - test_case->log = kzalloc(KUNIT_LOG_SIZE, GFP_KERNEL); > + suite->log = alloc_string_stream(GFP_KERNEL); > + string_stream_set_append_newlines(suite->log, true); > + > + kunit_suite_for_each_test_case(suite, test_case) { > + test_case->log = alloc_string_stream(GFP_KERNEL); > + string_stream_set_append_newlines(test_case->log, true); > + } > > suite->debugfs = debugfs_create_dir(suite->name, debugfs_rootdir); > > @@ -121,7 +131,7 @@ void kunit_debugfs_destroy_suite(struct kunit_suite *suite) > struct kunit_case *test_case; > > debugfs_remove_recursive(suite->debugfs); > - kfree(suite->log); > + string_stream_destroy(suite->log); > kunit_suite_for_each_test_case(suite, test_case) > - kfree(test_case->log); > + string_stream_destroy(test_case->log); > } > diff --git a/lib/kunit/kunit-test.c b/lib/kunit/kunit-test.c > index 83d8e90ca7a2..616e287aa4bf 100644 > --- a/lib/kunit/kunit-test.c > +++ b/lib/kunit/kunit-test.c > @@ -8,6 +8,7 @@ > #include <kunit/test.h> > #include <kunit/test-bug.h> > > +#include "string-stream.h" > #include "try-catch-impl.h" > > struct kunit_try_catch_test_context { > @@ -530,12 +531,19 @@ static struct kunit_suite kunit_resource_test_suite = { > .test_cases = kunit_resource_test_cases, > }; > > +/* > + * Log tests call string_stream functions, which aren't exported. So only > + * build this code if this test is built-in. > + */ > +#if IS_BUILTIN(CONFIG_KUNIT_TEST) > static void kunit_log_test(struct kunit *test) > { > struct kunit_suite suite; > + char *full_log; > > - suite.log = kunit_kzalloc(test, KUNIT_LOG_SIZE, GFP_KERNEL); > + suite.log = kunit_alloc_string_stream(test, GFP_KERNEL); > KUNIT_ASSERT_NOT_ERR_OR_NULL(test, suite.log); > + string_stream_set_append_newlines(suite.log, true); > > kunit_log(KERN_INFO, test, "put this in log."); > kunit_log(KERN_INFO, test, "this too."); > @@ -543,14 +551,21 @@ static void kunit_log_test(struct kunit *test) > kunit_log(KERN_INFO, &suite, "along with this."); > > #ifdef CONFIG_KUNIT_DEBUGFS > + KUNIT_EXPECT_TRUE(test, test->log->append_newlines); > + > + full_log = string_stream_get_string(test->log); > + kunit_add_action(test, (kunit_action_t *)kfree, full_log); > KUNIT_EXPECT_NOT_ERR_OR_NULL(test, > - strstr(test->log, "put this in log.")); > + strstr(full_log, "put this in log.")); > KUNIT_EXPECT_NOT_ERR_OR_NULL(test, > - strstr(test->log, "this too.")); > + strstr(full_log, "this too.")); > + > + full_log = string_stream_get_string(suite.log); > + kunit_add_action(test, (kunit_action_t *)kfree, full_log); > KUNIT_EXPECT_NOT_ERR_OR_NULL(test, > - strstr(suite.log, "add to suite log.")); > + strstr(full_log, "add to suite log.")); > KUNIT_EXPECT_NOT_ERR_OR_NULL(test, > - strstr(suite.log, "along with this.")); > + strstr(full_log, "along with this.")); > #else > KUNIT_EXPECT_NULL(test, test->log); > #endif > @@ -558,15 +573,30 @@ static void kunit_log_test(struct kunit *test) > > static void kunit_log_newline_test(struct kunit *test) > { > + char *full_log; > + > kunit_info(test, "Add newline\n"); > if (test->log) { > - KUNIT_ASSERT_NOT_NULL_MSG(test, strstr(test->log, "Add newline\n"), > - "Missing log line, full log:\n%s", test->log); > - KUNIT_EXPECT_NULL(test, strstr(test->log, "Add newline\n\n")); > + full_log = string_stream_get_string(test->log); > + kunit_add_action(test, (kunit_action_t *)kfree, full_log); > + KUNIT_ASSERT_NOT_NULL_MSG(test, strstr(full_log, "Add newline\n"), > + "Missing log line, full log:\n%s", full_log); > + KUNIT_EXPECT_NULL(test, strstr(full_log, "Add newline\n\n")); > } else { > kunit_skip(test, "only useful when debugfs is enabled"); > } > } > +#else > +static void kunit_log_test(struct kunit *test) > +{ > + kunit_skip(test, "Log tests only run when built-in"); > +} > + > +static void kunit_log_newline_test(struct kunit *test) > +{ > + kunit_skip(test, "Log tests only run when built-in"); > +} > +#endif /* IS_BUILTIN(CONFIG_KUNIT_TEST) */ > > static struct kunit_case kunit_log_test_cases[] = { > KUNIT_CASE(kunit_log_test), > diff --git a/lib/kunit/string-stream.c b/lib/kunit/string-stream.c > index d2ded5207e9e..a6f3616c2048 100644 > --- a/lib/kunit/string-stream.c > +++ b/lib/kunit/string-stream.c > @@ -99,7 +99,7 @@ int string_stream_add(struct string_stream *stream, const char *fmt, ...) > return result; > } > > -static void string_stream_clear(struct string_stream *stream) > +void string_stream_clear(struct string_stream *stream) > { > struct string_stream_fragment *frag_container, *frag_container_safe; > > diff --git a/lib/kunit/string-stream.h b/lib/kunit/string-stream.h > index c55925a9b67f..7be2450c7079 100644 > --- a/lib/kunit/string-stream.h > +++ b/lib/kunit/string-stream.h > @@ -42,6 +42,8 @@ int __printf(2, 0) string_stream_vadd(struct string_stream *stream, > const char *fmt, > va_list args); > > +void string_stream_clear(struct string_stream *stream); > + > char *string_stream_get_string(struct string_stream *stream); > > int string_stream_append(struct string_stream *stream, > diff --git a/lib/kunit/test.c b/lib/kunit/test.c > index 2ad45a4ac06a..b153808ff1ec 100644 > --- a/lib/kunit/test.c > +++ b/lib/kunit/test.c > @@ -109,51 +109,17 @@ static void kunit_print_test_stats(struct kunit *test, > stats.total); > } > > -/** > - * kunit_log_newline() - Add newline to the end of log if one is not > - * already present. > - * @log: The log to add the newline to. > - */ > -static void kunit_log_newline(char *log) > -{ > - int log_len, len_left; > - > - log_len = strlen(log); > - len_left = KUNIT_LOG_SIZE - log_len - 1; > - > - if (log_len > 0 && log[log_len - 1] != '\n') > - strncat(log, "\n", len_left); > -} > - > -/* > - * Append formatted message to log, size of which is limited to > - * KUNIT_LOG_SIZE bytes (including null terminating byte). > - */ > -void kunit_log_append(char *log, const char *fmt, ...) > +/* Append formatted message to log. */ > +void kunit_log_append(struct string_stream *log, const char *fmt, ...) > { > va_list args; > - int len, log_len, len_left; > > if (!log) > return; > > - log_len = strlen(log); > - len_left = KUNIT_LOG_SIZE - log_len - 1; > - if (len_left <= 0) > - return; > - > - /* Evaluate length of line to add to log */ > va_start(args, fmt); > - len = vsnprintf(NULL, 0, fmt, args) + 1; > + string_stream_vadd(log, fmt, args); > va_end(args); > - > - /* Print formatted line to the log */ > - va_start(args, fmt); > - vsnprintf(log + log_len, min(len, len_left), fmt, args); > - va_end(args); > - > - /* Add newline to end of log if not already present. */ > - kunit_log_newline(log); > } > EXPORT_SYMBOL_GPL(kunit_log_append); > > @@ -359,14 +325,14 @@ void __kunit_do_failed_assertion(struct kunit *test, > } > EXPORT_SYMBOL_GPL(__kunit_do_failed_assertion); > > -void kunit_init_test(struct kunit *test, const char *name, char *log) > +void kunit_init_test(struct kunit *test, const char *name, struct string_stream *log) > { > spin_lock_init(&test->lock); > INIT_LIST_HEAD(&test->resources); > test->name = name; > test->log = log; > if (test->log) > - test->log[0] = '\0'; > + string_stream_clear(log); > test->status = KUNIT_SUCCESS; > test->status_comment[0] = '\0'; > } > -- > 2.30.2 >
Hi Richard, kernel test robot noticed the following build warnings: [auto build test WARNING on shuah-kselftest/kunit] [also build test WARNING on next-20230824] [cannot apply to shuah-kselftest/kunit-fixes linus/master v6.5-rc7] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Richard-Fitzgerald/kunit-string-stream-Don-t-create-a-fragment-for-empty-strings/20230824-223722 base: https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git kunit patch link: https://lore.kernel.org/r/20230824143129.1957914-10-rf%40opensource.cirrus.com patch subject: [PATCH v5 09/10] kunit: Use string_stream for test log config: hexagon-randconfig-001-20230825 (https://download.01.org/0day-ci/archive/20230825/202308251509.VjWK804c-lkp@intel.com/config) compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project.git 4a5ac14ee968ff0ad5d2cc1ffa0299048db4c88a) reproduce: (https://download.01.org/0day-ci/archive/20230825/202308251509.VjWK804c-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202308251509.VjWK804c-lkp@intel.com/ All warnings (new ones prefixed by >>): >> lib/kunit/kunit-test.c:557:25: warning: cast from 'void (*)(const void *)' to 'kunit_action_t *' (aka 'void (*)(void *)') converts to incompatible function type [-Wcast-function-type-strict] 557 | kunit_add_action(test, (kunit_action_t *)kfree, full_log); | ^~~~~~~~~~~~~~~~~~~~~~~ lib/kunit/kunit-test.c:564:25: warning: cast from 'void (*)(const void *)' to 'kunit_action_t *' (aka 'void (*)(void *)') converts to incompatible function type [-Wcast-function-type-strict] 564 | kunit_add_action(test, (kunit_action_t *)kfree, full_log); | ^~~~~~~~~~~~~~~~~~~~~~~ lib/kunit/kunit-test.c:581:26: warning: cast from 'void (*)(const void *)' to 'kunit_action_t *' (aka 'void (*)(void *)') converts to incompatible function type [-Wcast-function-type-strict] 581 | kunit_add_action(test, (kunit_action_t *)kfree, full_log); | ^~~~~~~~~~~~~~~~~~~~~~~ 3 warnings generated. vim +557 lib/kunit/kunit-test.c 533 534 /* 535 * Log tests call string_stream functions, which aren't exported. So only 536 * build this code if this test is built-in. 537 */ 538 #if IS_BUILTIN(CONFIG_KUNIT_TEST) 539 static void kunit_log_test(struct kunit *test) 540 { 541 struct kunit_suite suite; 542 char *full_log; 543 544 suite.log = kunit_alloc_string_stream(test, GFP_KERNEL); 545 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, suite.log); 546 string_stream_set_append_newlines(suite.log, true); 547 548 kunit_log(KERN_INFO, test, "put this in log."); 549 kunit_log(KERN_INFO, test, "this too."); 550 kunit_log(KERN_INFO, &suite, "add to suite log."); 551 kunit_log(KERN_INFO, &suite, "along with this."); 552 553 #ifdef CONFIG_KUNIT_DEBUGFS 554 KUNIT_EXPECT_TRUE(test, test->log->append_newlines); 555 556 full_log = string_stream_get_string(test->log); > 557 kunit_add_action(test, (kunit_action_t *)kfree, full_log); 558 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, 559 strstr(full_log, "put this in log.")); 560 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, 561 strstr(full_log, "this too.")); 562 563 full_log = string_stream_get_string(suite.log); 564 kunit_add_action(test, (kunit_action_t *)kfree, full_log); 565 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, 566 strstr(full_log, "add to suite log.")); 567 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, 568 strstr(full_log, "along with this.")); 569 #else 570 KUNIT_EXPECT_NULL(test, test->log); 571 #endif 572 } 573
diff --git a/include/kunit/test.h b/include/kunit/test.h index d33114097d0d..b915a0fe93c0 100644 --- a/include/kunit/test.h +++ b/include/kunit/test.h @@ -32,9 +32,7 @@ DECLARE_STATIC_KEY_FALSE(kunit_running); struct kunit; - -/* Size of log associated with test. */ -#define KUNIT_LOG_SIZE 2048 +struct string_stream; /* Maximum size of parameter description string. */ #define KUNIT_PARAM_DESC_SIZE 128 @@ -132,7 +130,7 @@ struct kunit_case { /* private: internal use only. */ enum kunit_status status; char *module_name; - char *log; + struct string_stream *log; }; static inline char *kunit_status_to_ok_not_ok(enum kunit_status status) @@ -252,7 +250,7 @@ struct kunit_suite { /* private: internal use only */ char status_comment[KUNIT_STATUS_COMMENT_SIZE]; struct dentry *debugfs; - char *log; + struct string_stream *log; int suite_init_err; }; @@ -278,7 +276,7 @@ struct kunit { /* private: internal use only. */ const char *name; /* Read only after initialization! */ - char *log; /* Points at case log after initialization */ + struct string_stream *log; /* Points at case log after initialization */ struct kunit_try_catch try_catch; /* param_value is the current parameter value for a test case. */ const void *param_value; @@ -314,7 +312,7 @@ const char *kunit_filter_glob(void); char *kunit_filter(void); char *kunit_filter_action(void); -void kunit_init_test(struct kunit *test, const char *name, char *log); +void kunit_init_test(struct kunit *test, const char *name, struct string_stream *log); int kunit_run_tests(struct kunit_suite *suite); @@ -472,7 +470,7 @@ static inline void *kunit_kcalloc(struct kunit *test, size_t n, size_t size, gfp void kunit_cleanup(struct kunit *test); -void __printf(2, 3) kunit_log_append(char *log, const char *fmt, ...); +void __printf(2, 3) kunit_log_append(struct string_stream *log, const char *fmt, ...); /** * kunit_mark_skipped() - Marks @test_or_suite as skipped diff --git a/lib/kunit/debugfs.c b/lib/kunit/debugfs.c index 22c5c496a68f..270d185737e6 100644 --- a/lib/kunit/debugfs.c +++ b/lib/kunit/debugfs.c @@ -37,14 +37,21 @@ void kunit_debugfs_init(void) debugfs_rootdir = debugfs_create_dir(KUNIT_DEBUGFS_ROOT, NULL); } -static void debugfs_print_result(struct seq_file *seq, - struct kunit_suite *suite, - struct kunit_case *test_case) +static void debugfs_print_result(struct seq_file *seq, struct string_stream *log) { - if (!test_case || !test_case->log) + struct string_stream_fragment *frag_container; + + if (!log) return; - seq_printf(seq, "%s", test_case->log); + /* + * Walk the fragments so we don't need to allocate a temporary + * buffer to hold the entire string. + */ + spin_lock(&log->lock); + list_for_each_entry(frag_container, &log->fragments, node) + seq_printf(seq, "%s", frag_container->fragment); + spin_unlock(&log->lock); } /* @@ -69,10 +76,9 @@ static int debugfs_print_results(struct seq_file *seq, void *v) seq_printf(seq, KUNIT_SUBTEST_INDENT "1..%zd\n", kunit_suite_num_test_cases(suite)); kunit_suite_for_each_test_case(suite, test_case) - debugfs_print_result(seq, suite, test_case); + debugfs_print_result(seq, test_case->log); - if (suite->log) - seq_printf(seq, "%s", suite->log); + debugfs_print_result(seq, suite->log); seq_printf(seq, "%s %d %s\n", kunit_status_to_ok_not_ok(success), 1, suite->name); @@ -105,9 +111,13 @@ void kunit_debugfs_create_suite(struct kunit_suite *suite) struct kunit_case *test_case; /* Allocate logs before creating debugfs representation. */ - suite->log = kzalloc(KUNIT_LOG_SIZE, GFP_KERNEL); - kunit_suite_for_each_test_case(suite, test_case) - test_case->log = kzalloc(KUNIT_LOG_SIZE, GFP_KERNEL); + suite->log = alloc_string_stream(GFP_KERNEL); + string_stream_set_append_newlines(suite->log, true); + + kunit_suite_for_each_test_case(suite, test_case) { + test_case->log = alloc_string_stream(GFP_KERNEL); + string_stream_set_append_newlines(test_case->log, true); + } suite->debugfs = debugfs_create_dir(suite->name, debugfs_rootdir); @@ -121,7 +131,7 @@ void kunit_debugfs_destroy_suite(struct kunit_suite *suite) struct kunit_case *test_case; debugfs_remove_recursive(suite->debugfs); - kfree(suite->log); + string_stream_destroy(suite->log); kunit_suite_for_each_test_case(suite, test_case) - kfree(test_case->log); + string_stream_destroy(test_case->log); } diff --git a/lib/kunit/kunit-test.c b/lib/kunit/kunit-test.c index 83d8e90ca7a2..616e287aa4bf 100644 --- a/lib/kunit/kunit-test.c +++ b/lib/kunit/kunit-test.c @@ -8,6 +8,7 @@ #include <kunit/test.h> #include <kunit/test-bug.h> +#include "string-stream.h" #include "try-catch-impl.h" struct kunit_try_catch_test_context { @@ -530,12 +531,19 @@ static struct kunit_suite kunit_resource_test_suite = { .test_cases = kunit_resource_test_cases, }; +/* + * Log tests call string_stream functions, which aren't exported. So only + * build this code if this test is built-in. + */ +#if IS_BUILTIN(CONFIG_KUNIT_TEST) static void kunit_log_test(struct kunit *test) { struct kunit_suite suite; + char *full_log; - suite.log = kunit_kzalloc(test, KUNIT_LOG_SIZE, GFP_KERNEL); + suite.log = kunit_alloc_string_stream(test, GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, suite.log); + string_stream_set_append_newlines(suite.log, true); kunit_log(KERN_INFO, test, "put this in log."); kunit_log(KERN_INFO, test, "this too."); @@ -543,14 +551,21 @@ static void kunit_log_test(struct kunit *test) kunit_log(KERN_INFO, &suite, "along with this."); #ifdef CONFIG_KUNIT_DEBUGFS + KUNIT_EXPECT_TRUE(test, test->log->append_newlines); + + full_log = string_stream_get_string(test->log); + kunit_add_action(test, (kunit_action_t *)kfree, full_log); KUNIT_EXPECT_NOT_ERR_OR_NULL(test, - strstr(test->log, "put this in log.")); + strstr(full_log, "put this in log.")); KUNIT_EXPECT_NOT_ERR_OR_NULL(test, - strstr(test->log, "this too.")); + strstr(full_log, "this too.")); + + full_log = string_stream_get_string(suite.log); + kunit_add_action(test, (kunit_action_t *)kfree, full_log); KUNIT_EXPECT_NOT_ERR_OR_NULL(test, - strstr(suite.log, "add to suite log.")); + strstr(full_log, "add to suite log.")); KUNIT_EXPECT_NOT_ERR_OR_NULL(test, - strstr(suite.log, "along with this.")); + strstr(full_log, "along with this.")); #else KUNIT_EXPECT_NULL(test, test->log); #endif @@ -558,15 +573,30 @@ static void kunit_log_test(struct kunit *test) static void kunit_log_newline_test(struct kunit *test) { + char *full_log; + kunit_info(test, "Add newline\n"); if (test->log) { - KUNIT_ASSERT_NOT_NULL_MSG(test, strstr(test->log, "Add newline\n"), - "Missing log line, full log:\n%s", test->log); - KUNIT_EXPECT_NULL(test, strstr(test->log, "Add newline\n\n")); + full_log = string_stream_get_string(test->log); + kunit_add_action(test, (kunit_action_t *)kfree, full_log); + KUNIT_ASSERT_NOT_NULL_MSG(test, strstr(full_log, "Add newline\n"), + "Missing log line, full log:\n%s", full_log); + KUNIT_EXPECT_NULL(test, strstr(full_log, "Add newline\n\n")); } else { kunit_skip(test, "only useful when debugfs is enabled"); } } +#else +static void kunit_log_test(struct kunit *test) +{ + kunit_skip(test, "Log tests only run when built-in"); +} + +static void kunit_log_newline_test(struct kunit *test) +{ + kunit_skip(test, "Log tests only run when built-in"); +} +#endif /* IS_BUILTIN(CONFIG_KUNIT_TEST) */ static struct kunit_case kunit_log_test_cases[] = { KUNIT_CASE(kunit_log_test), diff --git a/lib/kunit/string-stream.c b/lib/kunit/string-stream.c index d2ded5207e9e..a6f3616c2048 100644 --- a/lib/kunit/string-stream.c +++ b/lib/kunit/string-stream.c @@ -99,7 +99,7 @@ int string_stream_add(struct string_stream *stream, const char *fmt, ...) return result; } -static void string_stream_clear(struct string_stream *stream) +void string_stream_clear(struct string_stream *stream) { struct string_stream_fragment *frag_container, *frag_container_safe; diff --git a/lib/kunit/string-stream.h b/lib/kunit/string-stream.h index c55925a9b67f..7be2450c7079 100644 --- a/lib/kunit/string-stream.h +++ b/lib/kunit/string-stream.h @@ -42,6 +42,8 @@ int __printf(2, 0) string_stream_vadd(struct string_stream *stream, const char *fmt, va_list args); +void string_stream_clear(struct string_stream *stream); + char *string_stream_get_string(struct string_stream *stream); int string_stream_append(struct string_stream *stream, diff --git a/lib/kunit/test.c b/lib/kunit/test.c index 2ad45a4ac06a..b153808ff1ec 100644 --- a/lib/kunit/test.c +++ b/lib/kunit/test.c @@ -109,51 +109,17 @@ static void kunit_print_test_stats(struct kunit *test, stats.total); } -/** - * kunit_log_newline() - Add newline to the end of log if one is not - * already present. - * @log: The log to add the newline to. - */ -static void kunit_log_newline(char *log) -{ - int log_len, len_left; - - log_len = strlen(log); - len_left = KUNIT_LOG_SIZE - log_len - 1; - - if (log_len > 0 && log[log_len - 1] != '\n') - strncat(log, "\n", len_left); -} - -/* - * Append formatted message to log, size of which is limited to - * KUNIT_LOG_SIZE bytes (including null terminating byte). - */ -void kunit_log_append(char *log, const char *fmt, ...) +/* Append formatted message to log. */ +void kunit_log_append(struct string_stream *log, const char *fmt, ...) { va_list args; - int len, log_len, len_left; if (!log) return; - log_len = strlen(log); - len_left = KUNIT_LOG_SIZE - log_len - 1; - if (len_left <= 0) - return; - - /* Evaluate length of line to add to log */ va_start(args, fmt); - len = vsnprintf(NULL, 0, fmt, args) + 1; + string_stream_vadd(log, fmt, args); va_end(args); - - /* Print formatted line to the log */ - va_start(args, fmt); - vsnprintf(log + log_len, min(len, len_left), fmt, args); - va_end(args); - - /* Add newline to end of log if not already present. */ - kunit_log_newline(log); } EXPORT_SYMBOL_GPL(kunit_log_append); @@ -359,14 +325,14 @@ void __kunit_do_failed_assertion(struct kunit *test, } EXPORT_SYMBOL_GPL(__kunit_do_failed_assertion); -void kunit_init_test(struct kunit *test, const char *name, char *log) +void kunit_init_test(struct kunit *test, const char *name, struct string_stream *log) { spin_lock_init(&test->lock); INIT_LIST_HEAD(&test->resources); test->name = name; test->log = log; if (test->log) - test->log[0] = '\0'; + string_stream_clear(log); test->status = KUNIT_SUCCESS; test->status_comment[0] = '\0'; }
Replace the fixed-size log buffer with a string_stream so that the log can grow as lines are added. string_stream_clear() has been made public for the log truncation done in kunit_init_test(). The existing kunit log tests have been updated for using a string_stream as the log. No new test have been added because there are already tests for the underlying string_stream. As the log tests now depend on string_stream functions they cannot build when kunit-test is a module. They have been surrounded by a #if to replace them with skipping version when the test is build as a module. Though this isn't pretty, it avoids moving code to another file while that code is also being changed. Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com> --- Changes since V4: - Don't move the log tests to another file. Deal with only including them when the test is built-in by wrapping them in a #if. This is to simplify code review, because it avoids having a block of code which moves from one file to another but at the same time the code has changed. - Use kunit_add_action() to automatically free the string returned by string_stream_get_string(). --- include/kunit/test.h | 14 +++++------- lib/kunit/debugfs.c | 36 +++++++++++++++++++----------- lib/kunit/kunit-test.c | 46 ++++++++++++++++++++++++++++++++------- lib/kunit/string-stream.c | 2 +- lib/kunit/string-stream.h | 2 ++ lib/kunit/test.c | 44 +++++-------------------------------- 6 files changed, 75 insertions(+), 69 deletions(-)