linux-kselftest-kunit-6.4-rc1
This KUnit update Linux 6.4-rc1 consists of: - several fixes to kunit tool - new klist structure test - support for m68k under QEMU - support for overriding the QEMU serial port - support for SH under QEMU -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEPZKym/RZuOCGeA/kCwJExA0NQxwFAmRFYFsACgkQCwJExA0N Qxw+PxAA1KHnHool3QbzZouFgLgTS2N/hxsOIoWKeUl6guUPX0XYu67FEIyt7p5k a1eFLjt+q4URW/heHKYdffP+Up6xhN5yVP8xJEcbn6GD13lz1clI9RAjObiPOehc KOV90PeAEfzosEGRIp97g4Gzu8NUMZqN7BsKBdzYJ4rEftlcjaILBVp4OfSuCyAi UbYBdRjK4eIOwGXuHVfhNqzH1HRSbzcoSRTywj5qW0Qhpe6KnZBRuZESXYBsxzGb G0nd4+OttjZyplI/xQYwaU0XGAI6roG5G4nAT5YGHLp5g8rTaHetTi+i3iK4iEru wEL0NgywkA0ujAge97RldOjtU97vvSFk7FwxdS9lxaMW/Ut2sN72I2ThI8dBvVRZ fcw8t8mmT1gUv3SCq+s1X13vz22IedXLOfvOY2o/fLk2zxOw5e8FirAz/aFeOf3K ++hK+IQvDmeMMv08bz0ORzdRQcjdwQNQ3klnfdrUVFN9yK+iAllOJ/nrXHLNIXu4 c3ITlAMldcAf2W+LRWzvqqKyT4H8MCXL3L0bBc1M1reRu9nM89AZedO8MHCB0R9Q 2ic0rOxIwZzPJuk0qPDxEVmN7Rpyx85I96YOwRemJTEfdkB/ZX+BfOU0KzinOVHC 3qrHuIw/SyRTlUEDAr53gJ5WHbdjhKAmrd1/FuplyoOSX0w6VVA= =COQn -----END PGP SIGNATURE----- Merge tag 'linux-kselftest-kunit-6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest Pull KUnit updates from Shuah Khan: - several fixes to kunit tool - new klist structure test - support for m68k under QEMU - support for overriding the QEMU serial port - support for SH under QEMU * tag 'linux-kselftest-kunit-6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest: kunit: add tests for using current KUnit test field kunit: tool: Add support for SH under QEMU kunit: tool: Add support for overriding the QEMU serial port .gitignore: Unignore .kunitconfig list: test: Test the klist structure kunit: increase KUNIT_LOG_SIZE to 2048 bytes kunit: Use gfp in kunit_alloc_resource() kernel-doc kunit: tool: fix pre-existing `mypy --strict` errors and update run_checks.py kunit: tool: remove unused imports and variables kunit: tool: add subscripts for type annotations where appropriate kunit: fix bug of extra newline characters in debugfs logs kunit: fix bug in the order of lines in debugfs logs kunit: fix bug in debugfs logs of parameterized tests kunit: tool: Add support for m68k under QEMU
This commit is contained in:
Коммит
1be89faab3
|
@ -103,6 +103,7 @@ modules.order
|
||||||
!.get_maintainer.ignore
|
!.get_maintainer.ignore
|
||||||
!.gitattributes
|
!.gitattributes
|
||||||
!.gitignore
|
!.gitignore
|
||||||
|
!.kunitconfig
|
||||||
!.mailmap
|
!.mailmap
|
||||||
!.rustfmt.toml
|
!.rustfmt.toml
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ typedef void (*kunit_resource_free_t)(struct kunit_resource *);
|
||||||
* params.gfp = gfp;
|
* params.gfp = gfp;
|
||||||
*
|
*
|
||||||
* return kunit_alloc_resource(test, kunit_kmalloc_init,
|
* return kunit_alloc_resource(test, kunit_kmalloc_init,
|
||||||
* kunit_kmalloc_free, ¶ms);
|
* kunit_kmalloc_free, gfp, ¶ms);
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* Resources can also be named, with lookup/removal done on a name
|
* Resources can also be named, with lookup/removal done on a name
|
||||||
|
|
|
@ -34,7 +34,7 @@ DECLARE_STATIC_KEY_FALSE(kunit_running);
|
||||||
struct kunit;
|
struct kunit;
|
||||||
|
|
||||||
/* Size of log associated with test. */
|
/* Size of log associated with test. */
|
||||||
#define KUNIT_LOG_SIZE 512
|
#define KUNIT_LOG_SIZE 2048
|
||||||
|
|
||||||
/* Maximum size of parameter description string. */
|
/* Maximum size of parameter description string. */
|
||||||
#define KUNIT_PARAM_DESC_SIZE 128
|
#define KUNIT_PARAM_DESC_SIZE 128
|
||||||
|
@ -420,7 +420,7 @@ void __printf(2, 3) kunit_log_append(char *log, const char *fmt, ...);
|
||||||
#define kunit_log(lvl, test_or_suite, fmt, ...) \
|
#define kunit_log(lvl, test_or_suite, fmt, ...) \
|
||||||
do { \
|
do { \
|
||||||
printk(lvl fmt, ##__VA_ARGS__); \
|
printk(lvl fmt, ##__VA_ARGS__); \
|
||||||
kunit_log_append((test_or_suite)->log, fmt "\n", \
|
kunit_log_append((test_or_suite)->log, fmt, \
|
||||||
##__VA_ARGS__); \
|
##__VA_ARGS__); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
|
@ -55,14 +55,24 @@ static int debugfs_print_results(struct seq_file *seq, void *v)
|
||||||
enum kunit_status success = kunit_suite_has_succeeded(suite);
|
enum kunit_status success = kunit_suite_has_succeeded(suite);
|
||||||
struct kunit_case *test_case;
|
struct kunit_case *test_case;
|
||||||
|
|
||||||
if (!suite || !suite->log)
|
if (!suite)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
seq_printf(seq, "%s", suite->log);
|
/* Print KTAP header so the debugfs log can be parsed as valid KTAP. */
|
||||||
|
seq_puts(seq, "KTAP version 1\n");
|
||||||
|
seq_puts(seq, "1..1\n");
|
||||||
|
|
||||||
|
/* Print suite header because it is not stored in the test logs. */
|
||||||
|
seq_puts(seq, KUNIT_SUBTEST_INDENT "KTAP version 1\n");
|
||||||
|
seq_printf(seq, KUNIT_SUBTEST_INDENT "# Subtest: %s\n", suite->name);
|
||||||
|
seq_printf(seq, KUNIT_SUBTEST_INDENT "1..%zd\n", kunit_suite_num_test_cases(suite));
|
||||||
|
|
||||||
kunit_suite_for_each_test_case(suite, test_case)
|
kunit_suite_for_each_test_case(suite, test_case)
|
||||||
debugfs_print_result(seq, suite, test_case);
|
debugfs_print_result(seq, suite, test_case);
|
||||||
|
|
||||||
|
if (suite->log)
|
||||||
|
seq_printf(seq, "%s", suite->log);
|
||||||
|
|
||||||
seq_printf(seq, "%s %d %s\n",
|
seq_printf(seq, "%s %d %s\n",
|
||||||
kunit_status_to_ok_not_ok(success), 1, suite->name);
|
kunit_status_to_ok_not_ok(success), 1, suite->name);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
* Author: Brendan Higgins <brendanhiggins@google.com>
|
* Author: Brendan Higgins <brendanhiggins@google.com>
|
||||||
*/
|
*/
|
||||||
#include <kunit/test.h>
|
#include <kunit/test.h>
|
||||||
|
#include <kunit/test-bug.h>
|
||||||
|
|
||||||
#include "try-catch-impl.h"
|
#include "try-catch-impl.h"
|
||||||
|
|
||||||
|
@ -443,18 +444,6 @@ static struct kunit_suite kunit_resource_test_suite = {
|
||||||
.test_cases = kunit_resource_test_cases,
|
.test_cases = kunit_resource_test_cases,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void kunit_log_test(struct kunit *test);
|
|
||||||
|
|
||||||
static struct kunit_case kunit_log_test_cases[] = {
|
|
||||||
KUNIT_CASE(kunit_log_test),
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct kunit_suite kunit_log_test_suite = {
|
|
||||||
.name = "kunit-log-test",
|
|
||||||
.test_cases = kunit_log_test_cases,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void kunit_log_test(struct kunit *test)
|
static void kunit_log_test(struct kunit *test)
|
||||||
{
|
{
|
||||||
struct kunit_suite suite;
|
struct kunit_suite suite;
|
||||||
|
@ -481,6 +470,29 @@ static void kunit_log_test(struct kunit *test)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void kunit_log_newline_test(struct kunit *test)
|
||||||
|
{
|
||||||
|
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"));
|
||||||
|
} else {
|
||||||
|
kunit_skip(test, "only useful when debugfs is enabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct kunit_case kunit_log_test_cases[] = {
|
||||||
|
KUNIT_CASE(kunit_log_test),
|
||||||
|
KUNIT_CASE(kunit_log_newline_test),
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct kunit_suite kunit_log_test_suite = {
|
||||||
|
.name = "kunit-log-test",
|
||||||
|
.test_cases = kunit_log_test_cases,
|
||||||
|
};
|
||||||
|
|
||||||
static void kunit_status_set_failure_test(struct kunit *test)
|
static void kunit_status_set_failure_test(struct kunit *test)
|
||||||
{
|
{
|
||||||
struct kunit fake;
|
struct kunit fake;
|
||||||
|
@ -521,7 +533,46 @@ static struct kunit_suite kunit_status_test_suite = {
|
||||||
.test_cases = kunit_status_test_cases,
|
.test_cases = kunit_status_test_cases,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void kunit_current_test(struct kunit *test)
|
||||||
|
{
|
||||||
|
/* Check results of both current->kunit_test and
|
||||||
|
* kunit_get_current_test() are equivalent to current test.
|
||||||
|
*/
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, test, current->kunit_test);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, test, kunit_get_current_test());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kunit_current_fail_test(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct kunit fake;
|
||||||
|
|
||||||
|
kunit_init_test(&fake, "fake test", NULL);
|
||||||
|
KUNIT_EXPECT_EQ(test, fake.status, KUNIT_SUCCESS);
|
||||||
|
|
||||||
|
/* Set current->kunit_test to fake test. */
|
||||||
|
current->kunit_test = &fake;
|
||||||
|
|
||||||
|
kunit_fail_current_test("This should make `fake` test fail.");
|
||||||
|
KUNIT_EXPECT_EQ(test, fake.status, (enum kunit_status)KUNIT_FAILURE);
|
||||||
|
kunit_cleanup(&fake);
|
||||||
|
|
||||||
|
/* Reset current->kunit_test to current test. */
|
||||||
|
current->kunit_test = test;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct kunit_case kunit_current_test_cases[] = {
|
||||||
|
KUNIT_CASE(kunit_current_test),
|
||||||
|
KUNIT_CASE(kunit_current_fail_test),
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct kunit_suite kunit_current_test_suite = {
|
||||||
|
.name = "kunit_current",
|
||||||
|
.test_cases = kunit_current_test_cases,
|
||||||
|
};
|
||||||
|
|
||||||
kunit_test_suites(&kunit_try_catch_test_suite, &kunit_resource_test_suite,
|
kunit_test_suites(&kunit_try_catch_test_suite, &kunit_resource_test_suite,
|
||||||
&kunit_log_test_suite, &kunit_status_test_suite);
|
&kunit_log_test_suite, &kunit_status_test_suite,
|
||||||
|
&kunit_current_test_suite);
|
||||||
|
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
|
|
@ -108,28 +108,51 @@ static void kunit_print_test_stats(struct kunit *test,
|
||||||
stats.total);
|
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
|
* Append formatted message to log, size of which is limited to
|
||||||
* KUNIT_LOG_SIZE bytes (including null terminating byte).
|
* KUNIT_LOG_SIZE bytes (including null terminating byte).
|
||||||
*/
|
*/
|
||||||
void kunit_log_append(char *log, const char *fmt, ...)
|
void kunit_log_append(char *log, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
char line[KUNIT_LOG_SIZE];
|
|
||||||
va_list args;
|
va_list args;
|
||||||
int len_left;
|
int len, log_len, len_left;
|
||||||
|
|
||||||
if (!log)
|
if (!log)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
len_left = KUNIT_LOG_SIZE - strlen(log) - 1;
|
log_len = strlen(log);
|
||||||
|
len_left = KUNIT_LOG_SIZE - log_len - 1;
|
||||||
if (len_left <= 0)
|
if (len_left <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* Evaluate length of line to add to log */
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
vsnprintf(line, sizeof(line), fmt, args);
|
len = vsnprintf(NULL, 0, fmt, args) + 1;
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
strncat(log, line, len_left);
|
/* 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);
|
EXPORT_SYMBOL_GPL(kunit_log_append);
|
||||||
|
|
||||||
|
@ -147,10 +170,18 @@ EXPORT_SYMBOL_GPL(kunit_suite_num_test_cases);
|
||||||
|
|
||||||
static void kunit_print_suite_start(struct kunit_suite *suite)
|
static void kunit_print_suite_start(struct kunit_suite *suite)
|
||||||
{
|
{
|
||||||
kunit_log(KERN_INFO, suite, KUNIT_SUBTEST_INDENT "KTAP version 1\n");
|
/*
|
||||||
kunit_log(KERN_INFO, suite, KUNIT_SUBTEST_INDENT "# Subtest: %s",
|
* We do not log the test suite header as doing so would
|
||||||
|
* mean debugfs display would consist of the test suite
|
||||||
|
* header prior to individual test results.
|
||||||
|
* Hence directly printk the suite status, and we will
|
||||||
|
* separately seq_printf() the suite header for the debugfs
|
||||||
|
* representation.
|
||||||
|
*/
|
||||||
|
pr_info(KUNIT_SUBTEST_INDENT "KTAP version 1\n");
|
||||||
|
pr_info(KUNIT_SUBTEST_INDENT "# Subtest: %s\n",
|
||||||
suite->name);
|
suite->name);
|
||||||
kunit_log(KERN_INFO, suite, KUNIT_SUBTEST_INDENT "1..%zd",
|
pr_info(KUNIT_SUBTEST_INDENT "1..%zd\n",
|
||||||
kunit_suite_num_test_cases(suite));
|
kunit_suite_num_test_cases(suite));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,10 +198,9 @@ static void kunit_print_ok_not_ok(void *test_or_suite,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We do not log the test suite results as doing so would
|
* We do not log the test suite results as doing so would
|
||||||
* mean debugfs display would consist of the test suite
|
* mean debugfs display would consist of an incorrect test
|
||||||
* description and status prior to individual test results.
|
* number. Hence directly printk the suite result, and we will
|
||||||
* Hence directly printk the suite status, and we will
|
* separately seq_printf() the suite results for the debugfs
|
||||||
* separately seq_printf() the suite status for the debugfs
|
|
||||||
* representation.
|
* representation.
|
||||||
*/
|
*/
|
||||||
if (suite)
|
if (suite)
|
||||||
|
@ -437,7 +467,6 @@ static void kunit_run_case_catch_errors(struct kunit_suite *suite,
|
||||||
struct kunit_try_catch_context context;
|
struct kunit_try_catch_context context;
|
||||||
struct kunit_try_catch *try_catch;
|
struct kunit_try_catch *try_catch;
|
||||||
|
|
||||||
kunit_init_test(test, test_case->name, test_case->log);
|
|
||||||
try_catch = &test->try_catch;
|
try_catch = &test->try_catch;
|
||||||
|
|
||||||
kunit_try_catch_init(try_catch,
|
kunit_try_catch_init(try_catch,
|
||||||
|
@ -533,6 +562,8 @@ int kunit_run_tests(struct kunit_suite *suite)
|
||||||
struct kunit_result_stats param_stats = { 0 };
|
struct kunit_result_stats param_stats = { 0 };
|
||||||
test_case->status = KUNIT_SKIPPED;
|
test_case->status = KUNIT_SKIPPED;
|
||||||
|
|
||||||
|
kunit_init_test(&test, test_case->name, test_case->log);
|
||||||
|
|
||||||
if (!test_case->generate_params) {
|
if (!test_case->generate_params) {
|
||||||
/* Non-parameterised test. */
|
/* Non-parameterised test. */
|
||||||
kunit_run_case_catch_errors(suite, test_case, &test);
|
kunit_run_case_catch_errors(suite, test_case, &test);
|
||||||
|
|
300
lib/list-test.c
300
lib/list-test.c
|
@ -8,6 +8,7 @@
|
||||||
#include <kunit/test.h>
|
#include <kunit/test.h>
|
||||||
|
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
|
#include <linux/klist.h>
|
||||||
|
|
||||||
struct list_test_struct {
|
struct list_test_struct {
|
||||||
int data;
|
int data;
|
||||||
|
@ -1199,6 +1200,303 @@ static struct kunit_suite hlist_test_module = {
|
||||||
.test_cases = hlist_test_cases,
|
.test_cases = hlist_test_cases,
|
||||||
};
|
};
|
||||||
|
|
||||||
kunit_test_suites(&list_test_module, &hlist_test_module);
|
|
||||||
|
struct klist_test_struct {
|
||||||
|
int data;
|
||||||
|
struct klist klist;
|
||||||
|
struct klist_node klist_node;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int node_count;
|
||||||
|
static struct klist_node *last_node;
|
||||||
|
|
||||||
|
static void check_node(struct klist_node *node_ptr)
|
||||||
|
{
|
||||||
|
node_count++;
|
||||||
|
last_node = node_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_delete_node(struct klist_node *node_ptr)
|
||||||
|
{
|
||||||
|
node_count--;
|
||||||
|
last_node = node_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void klist_test_add_tail(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct klist_node a, b;
|
||||||
|
struct klist mylist;
|
||||||
|
struct klist_iter i;
|
||||||
|
|
||||||
|
node_count = 0;
|
||||||
|
klist_init(&mylist, &check_node, NULL);
|
||||||
|
|
||||||
|
klist_add_tail(&a, &mylist);
|
||||||
|
KUNIT_EXPECT_EQ(test, node_count, 1);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, last_node, &a);
|
||||||
|
|
||||||
|
klist_add_tail(&b, &mylist);
|
||||||
|
KUNIT_EXPECT_EQ(test, node_count, 2);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, last_node, &b);
|
||||||
|
|
||||||
|
/* should be [list] -> a -> b */
|
||||||
|
klist_iter_init(&mylist, &i);
|
||||||
|
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &a);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &b);
|
||||||
|
KUNIT_EXPECT_NULL(test, klist_next(&i));
|
||||||
|
|
||||||
|
klist_iter_exit(&i);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void klist_test_add_head(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct klist_node a, b;
|
||||||
|
struct klist mylist;
|
||||||
|
struct klist_iter i;
|
||||||
|
|
||||||
|
node_count = 0;
|
||||||
|
klist_init(&mylist, &check_node, NULL);
|
||||||
|
|
||||||
|
klist_add_head(&a, &mylist);
|
||||||
|
KUNIT_EXPECT_EQ(test, node_count, 1);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, last_node, &a);
|
||||||
|
|
||||||
|
klist_add_head(&b, &mylist);
|
||||||
|
KUNIT_EXPECT_EQ(test, node_count, 2);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, last_node, &b);
|
||||||
|
|
||||||
|
/* should be [list] -> b -> a */
|
||||||
|
klist_iter_init(&mylist, &i);
|
||||||
|
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &b);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &a);
|
||||||
|
KUNIT_EXPECT_NULL(test, klist_next(&i));
|
||||||
|
|
||||||
|
klist_iter_exit(&i);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void klist_test_add_behind(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct klist_node a, b, c, d;
|
||||||
|
struct klist mylist;
|
||||||
|
struct klist_iter i;
|
||||||
|
|
||||||
|
node_count = 0;
|
||||||
|
klist_init(&mylist, &check_node, NULL);
|
||||||
|
|
||||||
|
klist_add_head(&a, &mylist);
|
||||||
|
klist_add_head(&b, &mylist);
|
||||||
|
|
||||||
|
klist_add_behind(&c, &a);
|
||||||
|
KUNIT_EXPECT_EQ(test, node_count, 3);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, last_node, &c);
|
||||||
|
|
||||||
|
klist_add_behind(&d, &b);
|
||||||
|
KUNIT_EXPECT_EQ(test, node_count, 4);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, last_node, &d);
|
||||||
|
|
||||||
|
klist_iter_init(&mylist, &i);
|
||||||
|
|
||||||
|
/* should be [list] -> b -> d -> a -> c*/
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &b);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &d);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &a);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &c);
|
||||||
|
KUNIT_EXPECT_NULL(test, klist_next(&i));
|
||||||
|
|
||||||
|
klist_iter_exit(&i);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void klist_test_add_before(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct klist_node a, b, c, d;
|
||||||
|
struct klist mylist;
|
||||||
|
struct klist_iter i;
|
||||||
|
|
||||||
|
node_count = 0;
|
||||||
|
klist_init(&mylist, &check_node, NULL);
|
||||||
|
|
||||||
|
klist_add_head(&a, &mylist);
|
||||||
|
klist_add_head(&b, &mylist);
|
||||||
|
klist_add_before(&c, &a);
|
||||||
|
KUNIT_EXPECT_EQ(test, node_count, 3);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, last_node, &c);
|
||||||
|
|
||||||
|
klist_add_before(&d, &b);
|
||||||
|
KUNIT_EXPECT_EQ(test, node_count, 4);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, last_node, &d);
|
||||||
|
|
||||||
|
klist_iter_init(&mylist, &i);
|
||||||
|
|
||||||
|
/* should be [list] -> b -> d -> a -> c*/
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &d);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &b);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &c);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &a);
|
||||||
|
KUNIT_EXPECT_NULL(test, klist_next(&i));
|
||||||
|
|
||||||
|
klist_iter_exit(&i);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify that klist_del() delays the deletion of a node until there
|
||||||
|
* are no other references to it
|
||||||
|
*/
|
||||||
|
static void klist_test_del_refcount_greater_than_zero(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct klist_node a, b, c, d;
|
||||||
|
struct klist mylist;
|
||||||
|
struct klist_iter i;
|
||||||
|
|
||||||
|
node_count = 0;
|
||||||
|
klist_init(&mylist, &check_node, &check_delete_node);
|
||||||
|
|
||||||
|
/* Add nodes a,b,c,d to the list*/
|
||||||
|
klist_add_tail(&a, &mylist);
|
||||||
|
klist_add_tail(&b, &mylist);
|
||||||
|
klist_add_tail(&c, &mylist);
|
||||||
|
klist_add_tail(&d, &mylist);
|
||||||
|
|
||||||
|
klist_iter_init(&mylist, &i);
|
||||||
|
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &a);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &b);
|
||||||
|
/* Advance the iterator to point to node c*/
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &c);
|
||||||
|
|
||||||
|
/* Try to delete node c while there is a reference to it*/
|
||||||
|
klist_del(&c);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify that node c is still attached to the list even after being
|
||||||
|
* deleted. Since the iterator still points to c, the reference count is not
|
||||||
|
* decreased to 0
|
||||||
|
*/
|
||||||
|
KUNIT_EXPECT_TRUE(test, klist_node_attached(&c));
|
||||||
|
|
||||||
|
/* Check that node c has not been removed yet*/
|
||||||
|
KUNIT_EXPECT_EQ(test, node_count, 4);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, last_node, &d);
|
||||||
|
|
||||||
|
klist_iter_exit(&i);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since the iterator is no longer pointing to node c, node c is removed
|
||||||
|
* from the list
|
||||||
|
*/
|
||||||
|
KUNIT_EXPECT_EQ(test, node_count, 3);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, last_node, &c);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify that klist_del() deletes a node immediately when there are no
|
||||||
|
* other references to it.
|
||||||
|
*/
|
||||||
|
static void klist_test_del_refcount_zero(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct klist_node a, b, c, d;
|
||||||
|
struct klist mylist;
|
||||||
|
struct klist_iter i;
|
||||||
|
|
||||||
|
node_count = 0;
|
||||||
|
klist_init(&mylist, &check_node, &check_delete_node);
|
||||||
|
|
||||||
|
/* Add nodes a,b,c,d to the list*/
|
||||||
|
klist_add_tail(&a, &mylist);
|
||||||
|
klist_add_tail(&b, &mylist);
|
||||||
|
klist_add_tail(&c, &mylist);
|
||||||
|
klist_add_tail(&d, &mylist);
|
||||||
|
/* Delete node c*/
|
||||||
|
klist_del(&c);
|
||||||
|
|
||||||
|
/* Check that node c is deleted from the list*/
|
||||||
|
KUNIT_EXPECT_EQ(test, node_count, 3);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, last_node, &c);
|
||||||
|
|
||||||
|
/* Should be [list] -> a -> b -> d*/
|
||||||
|
klist_iter_init(&mylist, &i);
|
||||||
|
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &a);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &b);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &d);
|
||||||
|
KUNIT_EXPECT_NULL(test, klist_next(&i));
|
||||||
|
|
||||||
|
klist_iter_exit(&i);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void klist_test_remove(struct kunit *test)
|
||||||
|
{
|
||||||
|
/* This test doesn't check correctness under concurrent access */
|
||||||
|
struct klist_node a, b, c, d;
|
||||||
|
struct klist mylist;
|
||||||
|
struct klist_iter i;
|
||||||
|
|
||||||
|
node_count = 0;
|
||||||
|
klist_init(&mylist, &check_node, &check_delete_node);
|
||||||
|
|
||||||
|
/* Add nodes a,b,c,d to the list*/
|
||||||
|
klist_add_tail(&a, &mylist);
|
||||||
|
klist_add_tail(&b, &mylist);
|
||||||
|
klist_add_tail(&c, &mylist);
|
||||||
|
klist_add_tail(&d, &mylist);
|
||||||
|
/* Delete node c*/
|
||||||
|
klist_remove(&c);
|
||||||
|
|
||||||
|
/* Check the nodes in the list*/
|
||||||
|
KUNIT_EXPECT_EQ(test, node_count, 3);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, last_node, &c);
|
||||||
|
|
||||||
|
/* should be [list] -> a -> b -> d*/
|
||||||
|
klist_iter_init(&mylist, &i);
|
||||||
|
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &a);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &b);
|
||||||
|
KUNIT_EXPECT_PTR_EQ(test, klist_next(&i), &d);
|
||||||
|
KUNIT_EXPECT_NULL(test, klist_next(&i));
|
||||||
|
|
||||||
|
klist_iter_exit(&i);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void klist_test_node_attached(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct klist_node a = {};
|
||||||
|
struct klist mylist;
|
||||||
|
|
||||||
|
klist_init(&mylist, NULL, NULL);
|
||||||
|
|
||||||
|
KUNIT_EXPECT_FALSE(test, klist_node_attached(&a));
|
||||||
|
klist_add_head(&a, &mylist);
|
||||||
|
KUNIT_EXPECT_TRUE(test, klist_node_attached(&a));
|
||||||
|
klist_del(&a);
|
||||||
|
KUNIT_EXPECT_FALSE(test, klist_node_attached(&a));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct kunit_case klist_test_cases[] = {
|
||||||
|
KUNIT_CASE(klist_test_add_tail),
|
||||||
|
KUNIT_CASE(klist_test_add_head),
|
||||||
|
KUNIT_CASE(klist_test_add_behind),
|
||||||
|
KUNIT_CASE(klist_test_add_before),
|
||||||
|
KUNIT_CASE(klist_test_del_refcount_greater_than_zero),
|
||||||
|
KUNIT_CASE(klist_test_del_refcount_zero),
|
||||||
|
KUNIT_CASE(klist_test_remove),
|
||||||
|
KUNIT_CASE(klist_test_node_attached),
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct kunit_suite klist_test_module = {
|
||||||
|
.name = "klist",
|
||||||
|
.test_cases = klist_test_cases,
|
||||||
|
};
|
||||||
|
|
||||||
|
kunit_test_suites(&list_test_module, &hlist_test_module, &klist_test_module);
|
||||||
|
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
|
|
@ -123,7 +123,7 @@ def _suites_from_test_list(tests: List[str]) -> List[str]:
|
||||||
parts = t.split('.', maxsplit=2)
|
parts = t.split('.', maxsplit=2)
|
||||||
if len(parts) != 2:
|
if len(parts) != 2:
|
||||||
raise ValueError(f'internal KUnit error, test name should be of the form "<suite>.<test>", got "{t}"')
|
raise ValueError(f'internal KUnit error, test name should be of the form "<suite>.<test>", got "{t}"')
|
||||||
suite, case = parts
|
suite, _ = parts
|
||||||
if not suites or suites[-1] != suite:
|
if not suites or suites[-1] != suite:
|
||||||
suites.append(suite)
|
suites.append(suite)
|
||||||
return suites
|
return suites
|
||||||
|
@ -269,7 +269,7 @@ def massage_argv(argv: Sequence[str]) -> Sequence[str]:
|
||||||
def get_default_jobs() -> int:
|
def get_default_jobs() -> int:
|
||||||
return len(os.sched_getaffinity(0))
|
return len(os.sched_getaffinity(0))
|
||||||
|
|
||||||
def add_common_opts(parser) -> None:
|
def add_common_opts(parser: argparse.ArgumentParser) -> None:
|
||||||
parser.add_argument('--build_dir',
|
parser.add_argument('--build_dir',
|
||||||
help='As in the make command, it specifies the build '
|
help='As in the make command, it specifies the build '
|
||||||
'directory.',
|
'directory.',
|
||||||
|
@ -320,13 +320,13 @@ def add_common_opts(parser) -> None:
|
||||||
help='Additional QEMU arguments, e.g. "-smp 8"',
|
help='Additional QEMU arguments, e.g. "-smp 8"',
|
||||||
action='append', metavar='')
|
action='append', metavar='')
|
||||||
|
|
||||||
def add_build_opts(parser) -> None:
|
def add_build_opts(parser: argparse.ArgumentParser) -> None:
|
||||||
parser.add_argument('--jobs',
|
parser.add_argument('--jobs',
|
||||||
help='As in the make command, "Specifies the number of '
|
help='As in the make command, "Specifies the number of '
|
||||||
'jobs (commands) to run simultaneously."',
|
'jobs (commands) to run simultaneously."',
|
||||||
type=int, default=get_default_jobs(), metavar='N')
|
type=int, default=get_default_jobs(), metavar='N')
|
||||||
|
|
||||||
def add_exec_opts(parser) -> None:
|
def add_exec_opts(parser: argparse.ArgumentParser) -> None:
|
||||||
parser.add_argument('--timeout',
|
parser.add_argument('--timeout',
|
||||||
help='maximum number of seconds to allow for all tests '
|
help='maximum number of seconds to allow for all tests '
|
||||||
'to run. This does not include time taken to build the '
|
'to run. This does not include time taken to build the '
|
||||||
|
@ -351,7 +351,7 @@ def add_exec_opts(parser) -> None:
|
||||||
type=str,
|
type=str,
|
||||||
choices=['suite', 'test'])
|
choices=['suite', 'test'])
|
||||||
|
|
||||||
def add_parse_opts(parser) -> None:
|
def add_parse_opts(parser: argparse.ArgumentParser) -> None:
|
||||||
parser.add_argument('--raw_output', help='If set don\'t parse output from kernel. '
|
parser.add_argument('--raw_output', help='If set don\'t parse output from kernel. '
|
||||||
'By default, filters to just KUnit output. Use '
|
'By default, filters to just KUnit output. Use '
|
||||||
'--raw_output=all to show everything',
|
'--raw_output=all to show everything',
|
||||||
|
@ -386,7 +386,7 @@ def tree_from_args(cli_args: argparse.Namespace) -> kunit_kernel.LinuxSourceTree
|
||||||
extra_qemu_args=qemu_args)
|
extra_qemu_args=qemu_args)
|
||||||
|
|
||||||
|
|
||||||
def run_handler(cli_args):
|
def run_handler(cli_args: argparse.Namespace) -> None:
|
||||||
if not os.path.exists(cli_args.build_dir):
|
if not os.path.exists(cli_args.build_dir):
|
||||||
os.mkdir(cli_args.build_dir)
|
os.mkdir(cli_args.build_dir)
|
||||||
|
|
||||||
|
@ -405,7 +405,7 @@ def run_handler(cli_args):
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def config_handler(cli_args):
|
def config_handler(cli_args: argparse.Namespace) -> None:
|
||||||
if cli_args.build_dir and (
|
if cli_args.build_dir and (
|
||||||
not os.path.exists(cli_args.build_dir)):
|
not os.path.exists(cli_args.build_dir)):
|
||||||
os.mkdir(cli_args.build_dir)
|
os.mkdir(cli_args.build_dir)
|
||||||
|
@ -421,7 +421,7 @@ def config_handler(cli_args):
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def build_handler(cli_args):
|
def build_handler(cli_args: argparse.Namespace) -> None:
|
||||||
linux = tree_from_args(cli_args)
|
linux = tree_from_args(cli_args)
|
||||||
request = KunitBuildRequest(build_dir=cli_args.build_dir,
|
request = KunitBuildRequest(build_dir=cli_args.build_dir,
|
||||||
make_options=cli_args.make_options,
|
make_options=cli_args.make_options,
|
||||||
|
@ -434,7 +434,7 @@ def build_handler(cli_args):
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def exec_handler(cli_args):
|
def exec_handler(cli_args: argparse.Namespace) -> None:
|
||||||
linux = tree_from_args(cli_args)
|
linux = tree_from_args(cli_args)
|
||||||
exec_request = KunitExecRequest(raw_output=cli_args.raw_output,
|
exec_request = KunitExecRequest(raw_output=cli_args.raw_output,
|
||||||
build_dir=cli_args.build_dir,
|
build_dir=cli_args.build_dir,
|
||||||
|
@ -450,10 +450,10 @@ def exec_handler(cli_args):
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def parse_handler(cli_args):
|
def parse_handler(cli_args: argparse.Namespace) -> None:
|
||||||
if cli_args.file is None:
|
if cli_args.file is None:
|
||||||
sys.stdin.reconfigure(errors='backslashreplace') # pytype: disable=attribute-error
|
sys.stdin.reconfigure(errors='backslashreplace') # type: ignore
|
||||||
kunit_output = sys.stdin
|
kunit_output = sys.stdin # type: Iterable[str]
|
||||||
else:
|
else:
|
||||||
with open(cli_args.file, 'r', errors='backslashreplace') as f:
|
with open(cli_args.file, 'r', errors='backslashreplace') as f:
|
||||||
kunit_output = f.read().splitlines()
|
kunit_output = f.read().splitlines()
|
||||||
|
@ -475,7 +475,7 @@ subcommand_handlers_map = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def main(argv):
|
def main(argv: Sequence[str]) -> None:
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description='Helps writing and running KUnit tests.')
|
description='Helps writing and running KUnit tests.')
|
||||||
subparser = parser.add_subparsers(dest='subcommand')
|
subparser = parser.add_subparsers(dest='subcommand')
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
import re
|
import re
|
||||||
from typing import Dict, Iterable, List, Set, Tuple
|
from typing import Any, Dict, Iterable, List, Tuple
|
||||||
|
|
||||||
CONFIG_IS_NOT_SET_PATTERN = r'^# CONFIG_(\w+) is not set$'
|
CONFIG_IS_NOT_SET_PATTERN = r'^# CONFIG_(\w+) is not set$'
|
||||||
CONFIG_PATTERN = r'^CONFIG_(\w+)=(\S+|".*")$'
|
CONFIG_PATTERN = r'^CONFIG_(\w+)=(\S+|".*")$'
|
||||||
|
@ -34,7 +34,7 @@ class Kconfig:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self._entries = {} # type: Dict[str, str]
|
self._entries = {} # type: Dict[str, str]
|
||||||
|
|
||||||
def __eq__(self, other) -> bool:
|
def __eq__(self, other: Any) -> bool:
|
||||||
if not isinstance(other, self.__class__):
|
if not isinstance(other, self.__class__):
|
||||||
return False
|
return False
|
||||||
return self._entries == other._entries
|
return self._entries == other._entries
|
||||||
|
|
|
@ -16,9 +16,9 @@ import shutil
|
||||||
import signal
|
import signal
|
||||||
import threading
|
import threading
|
||||||
from typing import Iterator, List, Optional, Tuple
|
from typing import Iterator, List, Optional, Tuple
|
||||||
|
from types import FrameType
|
||||||
|
|
||||||
import kunit_config
|
import kunit_config
|
||||||
from kunit_printer import stdout
|
|
||||||
import qemu_config
|
import qemu_config
|
||||||
|
|
||||||
KCONFIG_PATH = '.config'
|
KCONFIG_PATH = '.config'
|
||||||
|
@ -57,7 +57,7 @@ class LinuxSourceTreeOperations:
|
||||||
def make_arch_config(self, base_kunitconfig: kunit_config.Kconfig) -> kunit_config.Kconfig:
|
def make_arch_config(self, base_kunitconfig: kunit_config.Kconfig) -> kunit_config.Kconfig:
|
||||||
return base_kunitconfig
|
return base_kunitconfig
|
||||||
|
|
||||||
def make_olddefconfig(self, build_dir: str, make_options) -> None:
|
def make_olddefconfig(self, build_dir: str, make_options: Optional[List[str]]) -> None:
|
||||||
command = ['make', 'ARCH=' + self._linux_arch, 'O=' + build_dir, 'olddefconfig']
|
command = ['make', 'ARCH=' + self._linux_arch, 'O=' + build_dir, 'olddefconfig']
|
||||||
if self._cross_compile:
|
if self._cross_compile:
|
||||||
command += ['CROSS_COMPILE=' + self._cross_compile]
|
command += ['CROSS_COMPILE=' + self._cross_compile]
|
||||||
|
@ -71,7 +71,7 @@ class LinuxSourceTreeOperations:
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
raise ConfigError(e.output.decode())
|
raise ConfigError(e.output.decode())
|
||||||
|
|
||||||
def make(self, jobs, build_dir: str, make_options) -> None:
|
def make(self, jobs: int, build_dir: str, make_options: Optional[List[str]]) -> None:
|
||||||
command = ['make', 'ARCH=' + self._linux_arch, 'O=' + build_dir, '--jobs=' + str(jobs)]
|
command = ['make', 'ARCH=' + self._linux_arch, 'O=' + build_dir, '--jobs=' + str(jobs)]
|
||||||
if make_options:
|
if make_options:
|
||||||
command.extend(make_options)
|
command.extend(make_options)
|
||||||
|
@ -92,7 +92,7 @@ class LinuxSourceTreeOperations:
|
||||||
if stderr: # likely only due to build warnings
|
if stderr: # likely only due to build warnings
|
||||||
print(stderr.decode())
|
print(stderr.decode())
|
||||||
|
|
||||||
def start(self, params: List[str], build_dir: str) -> subprocess.Popen:
|
def start(self, params: List[str], build_dir: str) -> subprocess.Popen[str]:
|
||||||
raise RuntimeError('not implemented!')
|
raise RuntimeError('not implemented!')
|
||||||
|
|
||||||
|
|
||||||
|
@ -106,13 +106,14 @@ class LinuxSourceTreeOperationsQemu(LinuxSourceTreeOperations):
|
||||||
self._kernel_path = qemu_arch_params.kernel_path
|
self._kernel_path = qemu_arch_params.kernel_path
|
||||||
self._kernel_command_line = qemu_arch_params.kernel_command_line + ' kunit_shutdown=reboot'
|
self._kernel_command_line = qemu_arch_params.kernel_command_line + ' kunit_shutdown=reboot'
|
||||||
self._extra_qemu_params = qemu_arch_params.extra_qemu_params
|
self._extra_qemu_params = qemu_arch_params.extra_qemu_params
|
||||||
|
self._serial = qemu_arch_params.serial
|
||||||
|
|
||||||
def make_arch_config(self, base_kunitconfig: kunit_config.Kconfig) -> kunit_config.Kconfig:
|
def make_arch_config(self, base_kunitconfig: kunit_config.Kconfig) -> kunit_config.Kconfig:
|
||||||
kconfig = kunit_config.parse_from_string(self._kconfig)
|
kconfig = kunit_config.parse_from_string(self._kconfig)
|
||||||
kconfig.merge_in_entries(base_kunitconfig)
|
kconfig.merge_in_entries(base_kunitconfig)
|
||||||
return kconfig
|
return kconfig
|
||||||
|
|
||||||
def start(self, params: List[str], build_dir: str) -> subprocess.Popen:
|
def start(self, params: List[str], build_dir: str) -> subprocess.Popen[str]:
|
||||||
kernel_path = os.path.join(build_dir, self._kernel_path)
|
kernel_path = os.path.join(build_dir, self._kernel_path)
|
||||||
qemu_command = ['qemu-system-' + self._qemu_arch,
|
qemu_command = ['qemu-system-' + self._qemu_arch,
|
||||||
'-nodefaults',
|
'-nodefaults',
|
||||||
|
@ -121,7 +122,7 @@ class LinuxSourceTreeOperationsQemu(LinuxSourceTreeOperations):
|
||||||
'-append', ' '.join(params + [self._kernel_command_line]),
|
'-append', ' '.join(params + [self._kernel_command_line]),
|
||||||
'-no-reboot',
|
'-no-reboot',
|
||||||
'-nographic',
|
'-nographic',
|
||||||
'-serial', 'stdio'] + self._extra_qemu_params
|
'-serial', self._serial] + self._extra_qemu_params
|
||||||
# Note: shlex.join() does what we want, but requires python 3.8+.
|
# Note: shlex.join() does what we want, but requires python 3.8+.
|
||||||
print('Running tests with:\n$', ' '.join(shlex.quote(arg) for arg in qemu_command))
|
print('Running tests with:\n$', ' '.join(shlex.quote(arg) for arg in qemu_command))
|
||||||
return subprocess.Popen(qemu_command,
|
return subprocess.Popen(qemu_command,
|
||||||
|
@ -133,7 +134,7 @@ class LinuxSourceTreeOperationsQemu(LinuxSourceTreeOperations):
|
||||||
class LinuxSourceTreeOperationsUml(LinuxSourceTreeOperations):
|
class LinuxSourceTreeOperationsUml(LinuxSourceTreeOperations):
|
||||||
"""An abstraction over command line operations performed on a source tree."""
|
"""An abstraction over command line operations performed on a source tree."""
|
||||||
|
|
||||||
def __init__(self, cross_compile=None):
|
def __init__(self, cross_compile: Optional[str]=None):
|
||||||
super().__init__(linux_arch='um', cross_compile=cross_compile)
|
super().__init__(linux_arch='um', cross_compile=cross_compile)
|
||||||
|
|
||||||
def make_arch_config(self, base_kunitconfig: kunit_config.Kconfig) -> kunit_config.Kconfig:
|
def make_arch_config(self, base_kunitconfig: kunit_config.Kconfig) -> kunit_config.Kconfig:
|
||||||
|
@ -141,7 +142,7 @@ class LinuxSourceTreeOperationsUml(LinuxSourceTreeOperations):
|
||||||
kconfig.merge_in_entries(base_kunitconfig)
|
kconfig.merge_in_entries(base_kunitconfig)
|
||||||
return kconfig
|
return kconfig
|
||||||
|
|
||||||
def start(self, params: List[str], build_dir: str) -> subprocess.Popen:
|
def start(self, params: List[str], build_dir: str) -> subprocess.Popen[str]:
|
||||||
"""Runs the Linux UML binary. Must be named 'linux'."""
|
"""Runs the Linux UML binary. Must be named 'linux'."""
|
||||||
linux_bin = os.path.join(build_dir, 'linux')
|
linux_bin = os.path.join(build_dir, 'linux')
|
||||||
params.extend(['mem=1G', 'console=tty', 'kunit_shutdown=halt'])
|
params.extend(['mem=1G', 'console=tty', 'kunit_shutdown=halt'])
|
||||||
|
@ -216,7 +217,7 @@ def _get_qemu_ops(config_path: str,
|
||||||
|
|
||||||
if not hasattr(config, 'QEMU_ARCH'):
|
if not hasattr(config, 'QEMU_ARCH'):
|
||||||
raise ValueError('qemu_config module missing "QEMU_ARCH": ' + config_path)
|
raise ValueError('qemu_config module missing "QEMU_ARCH": ' + config_path)
|
||||||
params: qemu_config.QemuArchParams = config.QEMU_ARCH # type: ignore
|
params: qemu_config.QemuArchParams = config.QEMU_ARCH
|
||||||
if extra_qemu_args:
|
if extra_qemu_args:
|
||||||
params.extra_qemu_params.extend(extra_qemu_args)
|
params.extra_qemu_params.extend(extra_qemu_args)
|
||||||
return params.linux_arch, LinuxSourceTreeOperationsQemu(
|
return params.linux_arch, LinuxSourceTreeOperationsQemu(
|
||||||
|
@ -230,10 +231,10 @@ class LinuxSourceTree:
|
||||||
build_dir: str,
|
build_dir: str,
|
||||||
kunitconfig_paths: Optional[List[str]]=None,
|
kunitconfig_paths: Optional[List[str]]=None,
|
||||||
kconfig_add: Optional[List[str]]=None,
|
kconfig_add: Optional[List[str]]=None,
|
||||||
arch=None,
|
arch: Optional[str]=None,
|
||||||
cross_compile=None,
|
cross_compile: Optional[str]=None,
|
||||||
qemu_config_path=None,
|
qemu_config_path: Optional[str]=None,
|
||||||
extra_qemu_args=None) -> None:
|
extra_qemu_args: Optional[List[str]]=None) -> None:
|
||||||
signal.signal(signal.SIGINT, self.signal_handler)
|
signal.signal(signal.SIGINT, self.signal_handler)
|
||||||
if qemu_config_path:
|
if qemu_config_path:
|
||||||
self._arch, self._ops = _get_qemu_ops(qemu_config_path, extra_qemu_args, cross_compile)
|
self._arch, self._ops = _get_qemu_ops(qemu_config_path, extra_qemu_args, cross_compile)
|
||||||
|
@ -276,7 +277,7 @@ class LinuxSourceTree:
|
||||||
logging.error(message)
|
logging.error(message)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def build_config(self, build_dir: str, make_options) -> bool:
|
def build_config(self, build_dir: str, make_options: Optional[List[str]]) -> bool:
|
||||||
kconfig_path = get_kconfig_path(build_dir)
|
kconfig_path = get_kconfig_path(build_dir)
|
||||||
if build_dir and not os.path.exists(build_dir):
|
if build_dir and not os.path.exists(build_dir):
|
||||||
os.mkdir(build_dir)
|
os.mkdir(build_dir)
|
||||||
|
@ -304,7 +305,7 @@ class LinuxSourceTree:
|
||||||
old_kconfig = kunit_config.parse_file(old_path)
|
old_kconfig = kunit_config.parse_file(old_path)
|
||||||
return old_kconfig != self._kconfig
|
return old_kconfig != self._kconfig
|
||||||
|
|
||||||
def build_reconfig(self, build_dir: str, make_options) -> bool:
|
def build_reconfig(self, build_dir: str, make_options: Optional[List[str]]) -> bool:
|
||||||
"""Creates a new .config if it is not a subset of the .kunitconfig."""
|
"""Creates a new .config if it is not a subset of the .kunitconfig."""
|
||||||
kconfig_path = get_kconfig_path(build_dir)
|
kconfig_path = get_kconfig_path(build_dir)
|
||||||
if not os.path.exists(kconfig_path):
|
if not os.path.exists(kconfig_path):
|
||||||
|
@ -320,7 +321,7 @@ class LinuxSourceTree:
|
||||||
os.remove(kconfig_path)
|
os.remove(kconfig_path)
|
||||||
return self.build_config(build_dir, make_options)
|
return self.build_config(build_dir, make_options)
|
||||||
|
|
||||||
def build_kernel(self, jobs, build_dir: str, make_options) -> bool:
|
def build_kernel(self, jobs: int, build_dir: str, make_options: Optional[List[str]]) -> bool:
|
||||||
try:
|
try:
|
||||||
self._ops.make_olddefconfig(build_dir, make_options)
|
self._ops.make_olddefconfig(build_dir, make_options)
|
||||||
self._ops.make(jobs, build_dir, make_options)
|
self._ops.make(jobs, build_dir, make_options)
|
||||||
|
@ -329,7 +330,7 @@ class LinuxSourceTree:
|
||||||
return False
|
return False
|
||||||
return self.validate_config(build_dir)
|
return self.validate_config(build_dir)
|
||||||
|
|
||||||
def run_kernel(self, args=None, build_dir='', filter_glob='', timeout=None) -> Iterator[str]:
|
def run_kernel(self, args: Optional[List[str]]=None, build_dir: str='', filter_glob: str='', timeout: Optional[int]=None) -> Iterator[str]:
|
||||||
if not args:
|
if not args:
|
||||||
args = []
|
args = []
|
||||||
if filter_glob:
|
if filter_glob:
|
||||||
|
@ -340,7 +341,7 @@ class LinuxSourceTree:
|
||||||
assert process.stdout is not None # tell mypy it's set
|
assert process.stdout is not None # tell mypy it's set
|
||||||
|
|
||||||
# Enforce the timeout in a background thread.
|
# Enforce the timeout in a background thread.
|
||||||
def _wait_proc():
|
def _wait_proc() -> None:
|
||||||
try:
|
try:
|
||||||
process.wait(timeout=timeout)
|
process.wait(timeout=timeout)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -366,6 +367,6 @@ class LinuxSourceTree:
|
||||||
waiter.join()
|
waiter.join()
|
||||||
subprocess.call(['stty', 'sane'])
|
subprocess.call(['stty', 'sane'])
|
||||||
|
|
||||||
def signal_handler(self, unused_sig, unused_frame) -> None:
|
def signal_handler(self, unused_sig: int, unused_frame: Optional[FrameType]) -> None:
|
||||||
logging.error('Build interruption occurred. Cleaning console.')
|
logging.error('Build interruption occurred. Cleaning console.')
|
||||||
subprocess.call(['stty', 'sane'])
|
subprocess.call(['stty', 'sane'])
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
import re
|
import re
|
||||||
import sys
|
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
|
|
|
@ -15,7 +15,7 @@ _RESET = '\033[0;0m'
|
||||||
class Printer:
|
class Printer:
|
||||||
"""Wraps a file object, providing utilities for coloring output, etc."""
|
"""Wraps a file object, providing utilities for coloring output, etc."""
|
||||||
|
|
||||||
def __init__(self, output: typing.IO):
|
def __init__(self, output: typing.IO[str]):
|
||||||
self._output = output
|
self._output = output
|
||||||
self._use_color = output.isatty()
|
self._use_color = output.isatty()
|
||||||
|
|
||||||
|
|
|
@ -328,7 +328,7 @@ class KUnitParserTest(unittest.TestCase):
|
||||||
def test_parse_subtest_header(self):
|
def test_parse_subtest_header(self):
|
||||||
ktap_log = test_data_path('test_parse_subtest_header.log')
|
ktap_log = test_data_path('test_parse_subtest_header.log')
|
||||||
with open(ktap_log) as file:
|
with open(ktap_log) as file:
|
||||||
result = kunit_parser.parse_run_tests(file.readlines())
|
kunit_parser.parse_run_tests(file.readlines())
|
||||||
self.print_mock.assert_any_call(StrContains('suite (1 subtest)'))
|
self.print_mock.assert_any_call(StrContains('suite (1 subtest)'))
|
||||||
|
|
||||||
def test_show_test_output_on_failure(self):
|
def test_show_test_output_on_failure(self):
|
||||||
|
|
|
@ -17,3 +17,4 @@ class QemuArchParams:
|
||||||
kernel_path: str
|
kernel_path: str
|
||||||
kernel_command_line: str
|
kernel_command_line: str
|
||||||
extra_qemu_params: List[str]
|
extra_qemu_params: List[str]
|
||||||
|
serial: str = 'stdio'
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
from ..qemu_config import QemuArchParams
|
||||||
|
|
||||||
|
QEMU_ARCH = QemuArchParams(linux_arch='m68k',
|
||||||
|
kconfig='''
|
||||||
|
CONFIG_VIRT=y''',
|
||||||
|
qemu_arch='m68k',
|
||||||
|
kernel_path='vmlinux',
|
||||||
|
kernel_command_line='console=hvc0',
|
||||||
|
extra_qemu_params=['-machine', 'virt'])
|
|
@ -0,0 +1,17 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
from ..qemu_config import QemuArchParams
|
||||||
|
|
||||||
|
QEMU_ARCH = QemuArchParams(linux_arch='sh',
|
||||||
|
kconfig='''
|
||||||
|
CONFIG_CPU_SUBTYPE_SH7751R=y
|
||||||
|
CONFIG_MEMORY_START=0x0c000000
|
||||||
|
CONFIG_SH_RTS7751R2D=y
|
||||||
|
CONFIG_RTS7751R2D_PLUS=y
|
||||||
|
CONFIG_SERIAL_SH_SCI=y''',
|
||||||
|
qemu_arch='sh4',
|
||||||
|
kernel_path='arch/sh/boot/zImage',
|
||||||
|
kernel_command_line='console=ttySC1',
|
||||||
|
serial='null',
|
||||||
|
extra_qemu_params=[
|
||||||
|
'-machine', 'r2d',
|
||||||
|
'-serial', 'mon:stdio'])
|
|
@ -23,7 +23,7 @@ commands: Dict[str, Sequence[str]] = {
|
||||||
'kunit_tool_test.py': ['./kunit_tool_test.py'],
|
'kunit_tool_test.py': ['./kunit_tool_test.py'],
|
||||||
'kunit smoke test': ['./kunit.py', 'run', '--kunitconfig=lib/kunit', '--build_dir=kunit_run_checks'],
|
'kunit smoke test': ['./kunit.py', 'run', '--kunitconfig=lib/kunit', '--build_dir=kunit_run_checks'],
|
||||||
'pytype': ['/bin/sh', '-c', 'pytype *.py'],
|
'pytype': ['/bin/sh', '-c', 'pytype *.py'],
|
||||||
'mypy': ['/bin/sh', '-c', 'mypy *.py'],
|
'mypy': ['mypy', '--strict', '--exclude', '_test.py$', '--exclude', 'qemu_configs/', '.'],
|
||||||
}
|
}
|
||||||
|
|
||||||
# The user might not have mypy or pytype installed, skip them if so.
|
# The user might not have mypy or pytype installed, skip them if so.
|
||||||
|
@ -37,7 +37,7 @@ def main(argv: Sequence[str]) -> None:
|
||||||
if argv:
|
if argv:
|
||||||
raise RuntimeError('This script takes no arguments')
|
raise RuntimeError('This script takes no arguments')
|
||||||
|
|
||||||
future_to_name: Dict[futures.Future, str] = {}
|
future_to_name: Dict[futures.Future[None], str] = {}
|
||||||
executor = futures.ThreadPoolExecutor(max_workers=len(commands))
|
executor = futures.ThreadPoolExecutor(max_workers=len(commands))
|
||||||
for name, argv in commands.items():
|
for name, argv in commands.items():
|
||||||
if name in necessary_deps and shutil.which(necessary_deps[name]) is None:
|
if name in necessary_deps and shutil.which(necessary_deps[name]) is None:
|
||||||
|
@ -73,7 +73,7 @@ def main(argv: Sequence[str]) -> None:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def run_cmd(argv: Sequence[str]):
|
def run_cmd(argv: Sequence[str]) -> None:
|
||||||
subprocess.check_output(argv, stderr=subprocess.STDOUT, cwd=ABS_TOOL_PATH, timeout=TIMEOUT)
|
subprocess.check_output(argv, stderr=subprocess.STDOUT, cwd=ABS_TOOL_PATH, timeout=TIMEOUT)
|
||||||
|
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче