Merge tag 'linux-kselftest-5.5-rc1-kunit' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest

Pull kselftest KUnit support gtom Shuah Khan:
 "This adds KUnit, a lightweight unit testing and mocking framework for
  the Linux kernel from Brendan Higgins.

  KUnit is not an end-to-end testing framework. It is currently
  supported on UML and sub-systems can write unit tests and run them in
  UML env. KUnit documentation is included in this update.

  In addition, this Kunit update adds 3 new kunit tests:

   - proc sysctl test from Iurii Zaikin

   - the 'list' doubly linked list test from David Gow

   - ext4 tests for decoding extended timestamps from Iurii Zaikin

  In the future KUnit will be linked to Kselftest framework to provide a
  way to trigger KUnit tests from user-space"

* tag 'linux-kselftest-5.5-rc1-kunit' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest: (23 commits)
  lib/list-test: add a test for the 'list' doubly linked list
  ext4: add kunit test for decoding extended timestamps
  Documentation: kunit: Fix verification command
  kunit: Fix '--build_dir' option
  kunit: fix failure to build without printk
  MAINTAINERS: add proc sysctl KUnit test to PROC SYSCTL section
  kernel/sysctl-test: Add null pointer test for sysctl.c:proc_dointvec()
  MAINTAINERS: add entry for KUnit the unit testing framework
  Documentation: kunit: add documentation for KUnit
  kunit: defconfig: add defconfigs for building KUnit tests
  kunit: tool: add Python wrappers for running KUnit tests
  kunit: test: add tests for KUnit managed resources
  kunit: test: add the concept of assertions
  kunit: test: add tests for kunit test abort
  kunit: test: add support for test abort
  objtool: add kunit_try_catch_throw to the noreturn list
  kunit: test: add initial tests
  lib: enable building KUnit in lib/
  kunit: test: add the concept of expectations
  kunit: test: add assertion printing library
  ...
This commit is contained in:
Linus Torvalds committed 2019-11-25 15:01:30 -08:00
commit e25645b181
44 files changed
+7067

No files matched your search

+1
View File
@@ -24,6 +24,7 @@ whole; patches welcome!
gdb-kernel-debugging
kgdb
kselftest
kunit/index
.. only:: subproject and html
@@ -0,0 +1,16 @@
.. SPDX-License-Identifier: GPL-2.0
=============
API Reference
=============
.. toctree::
test
This section documents the KUnit kernel testing API. It is divided into the
following sections:
================================= ==============================================
:doc:`test` documents all of the standard testing API
excluding mocking or mocking related features.
================================= ==============================================
@@ -0,0 +1,11 @@
.. SPDX-License-Identifier: GPL-2.0
========
Test API
========
This file documents all of the standard testing API excluding mocking or mocking
related features.
.. kernel-doc:: include/kunit/test.h
:internal:
+62
View File
@@ -0,0 +1,62 @@
.. SPDX-License-Identifier: GPL-2.0
==========================
Frequently Asked Questions
==========================
How is this different from Autotest, kselftest, etc?
====================================================
KUnit is a unit testing framework. Autotest, kselftest (and some others) are
not.
A `unit test <https://martinfowler.com/bliki/UnitTest.html>`_ is supposed to
test a single unit of code in isolation, hence the name. A unit test should be
the finest granularity of testing and as such should allow all possible code
paths to be tested in the code under test; this is only possible if the code
under test is very small and does not have any external dependencies outside of
the test's control like hardware.
There are no testing frameworks currently available for the kernel that do not
require installing the kernel on a test machine or in a VM and all require
tests to be written in userspace and run on the kernel under test; this is true
for Autotest, kselftest, and some others, disqualifying any of them from being
considered unit testing frameworks.
Does KUnit support running on architectures other than UML?
===========================================================
Yes, well, mostly.
For the most part, the KUnit core framework (what you use to write the tests)
can compile to any architecture; it compiles like just another part of the
kernel and runs when the kernel boots. However, there is some infrastructure,
like the KUnit Wrapper (``tools/testing/kunit/kunit.py``) that does not support
other architectures.
In short, this means that, yes, you can run KUnit on other architectures, but
it might require more work than using KUnit on UML.
For more information, see :ref:`kunit-on-non-uml`.
What is the difference between a unit test and these other kinds of tests?
==========================================================================
Most existing tests for the Linux kernel would be categorized as an integration
test, or an end-to-end test.
- A unit test is supposed to test a single unit of code in isolation, hence the
name. A unit test should be the finest granularity of testing and as such
should allow all possible code paths to be tested in the code under test; this
is only possible if the code under test is very small and does not have any
external dependencies outside of the test's control like hardware.
- An integration test tests the interaction between a minimal set of components,
usually just two or three. For example, someone might write an integration
test to test the interaction between a driver and a piece of hardware, or to
test the interaction between the userspace libraries the kernel provides and
the kernel itself; however, one of these tests would probably not test the
entire kernel along with hardware interactions and interactions with the
userspace.
- An end-to-end test usually tests the entire system from the perspective of the
code under test. For example, someone might write an end-to-end test for the
kernel by installing a production configuration of the kernel on production
hardware with a production userspace and then trying to exercise some behavior
that depends on interactions between the hardware, the kernel, and userspace.
+79
View File
@@ -0,0 +1,79 @@
.. SPDX-License-Identifier: GPL-2.0
=========================================
KUnit - Unit Testing for the Linux Kernel
=========================================
.. toctree::
:maxdepth: 2
start
usage
api/index
faq
What is KUnit?
==============
KUnit is a lightweight unit testing and mocking framework for the Linux kernel.
These tests are able to be run locally on a developer's workstation without a VM
or special hardware.
KUnit is heavily inspired by JUnit, Python's unittest.mock, and
Googletest/Googlemock for C++. KUnit provides facilities for defining unit test
cases, grouping related test cases into test suites, providing common
infrastructure for running tests, and much more.
Get started now: :doc:`start`
Why KUnit?
==========
A unit test is supposed to test a single unit of code in isolation, hence the
name. A unit test should be the finest granularity of testing and as such should
allow all possible code paths to be tested in the code under test; this is only
possible if the code under test is very small and does not have any external
dependencies outside of the test's control like hardware.
Outside of KUnit, there are no testing frameworks currently
available for the kernel that do not require installing the kernel on a test
machine or in a VM and all require tests to be written in userspace running on
the kernel; this is true for Autotest, and kselftest, disqualifying
any of them from being considered unit testing frameworks.
KUnit addresses the problem of being able to run tests without needing a virtual
machine or actual hardware with User Mode Linux. User Mode Linux is a Linux
architecture, like ARM or x86; however, unlike other architectures it compiles
to a standalone program that can be run like any other program directly inside
of a host operating system; to be clear, it does not require any virtualization
support; it is just a regular program.
KUnit is fast. Excluding build time, from invocation to completion KUnit can run
several dozen tests in only 10 to 20 seconds; this might not sound like a big
deal to some people, but having such fast and easy to run tests fundamentally
changes the way you go about testing and even writing code in the first place.
Linus himself said in his `git talk at Google
<https://gist.github.com/lorn/1272686/revisions#diff-53c65572127855f1b003db4064a94573R874>`_:
"... a lot of people seem to think that performance is about doing the
same thing, just doing it faster, and that is not true. That is not what
performance is all about. If you can do something really fast, really
well, people will start using it differently."
In this context Linus was talking about branching and merging,
but this point also applies to testing. If your tests are slow, unreliable, are
difficult to write, and require a special setup or special hardware to run,
then you wait a lot longer to write tests, and you wait a lot longer to run
tests; this means that tests are likely to break, unlikely to test a lot of
things, and are unlikely to be rerun once they pass. If your tests are really
fast, you run them all the time, every time you make a change, and every time
someone sends you some code. Why trust that someone ran all their tests
correctly on every change when you can just run them yourself in less time than
it takes to read their test log?
How do I use it?
================
* :doc:`start` - for new users of KUnit
* :doc:`usage` - for a more detailed explanation of KUnit features
* :doc:`api/index` - for the list of KUnit APIs used for testing
+180
View File
@@ -0,0 +1,180 @@
.. SPDX-License-Identifier: GPL-2.0
===============
Getting Started
===============
Installing dependencies
=======================
KUnit has the same dependencies as the Linux kernel. As long as you can build
the kernel, you can run KUnit.
KUnit Wrapper
=============
Included with KUnit is a simple Python wrapper that helps format the output to
easily use and read KUnit output. It handles building and running the kernel, as
well as formatting the output.
The wrapper can be run with:
.. code-block:: bash
./tools/testing/kunit/kunit.py run
Creating a kunitconfig
======================
The Python script is a thin wrapper around Kbuild as such, it needs to be
configured with a ``kunitconfig`` file. This file essentially contains the
regular Kernel config, with the specific test targets as well.
.. code-block:: bash
git clone -b master https://kunit.googlesource.com/kunitconfig $PATH_TO_KUNITCONFIG_REPO
cd $PATH_TO_LINUX_REPO
ln -s $PATH_TO_KUNIT_CONFIG_REPO/kunitconfig kunitconfig
You may want to add kunitconfig to your local gitignore.
Verifying KUnit Works
---------------------
To make sure that everything is set up correctly, simply invoke the Python
wrapper from your kernel repo:
.. code-block:: bash
./tools/testing/kunit/kunit.py run
.. note::
You may want to run ``make mrproper`` first.
If everything worked correctly, you should see the following:
.. code-block:: bash
Generating .config ...
Building KUnit Kernel ...
Starting KUnit Kernel ...
followed by a list of tests that are run. All of them should be passing.
.. note::
Because it is building a lot of sources for the first time, the ``Building
kunit kernel`` step may take a while.
Writing your first test
=======================
In your kernel repo let's add some code that we can test. Create a file
``drivers/misc/example.h`` with the contents:
.. code-block:: c
int misc_example_add(int left, int right);
create a file ``drivers/misc/example.c``:
.. code-block:: c
#include <linux/errno.h>
#include "example.h"
int misc_example_add(int left, int right)
{
return left + right;
}
Now add the following lines to ``drivers/misc/Kconfig``:
.. code-block:: kconfig
config MISC_EXAMPLE
bool "My example"
and the following lines to ``drivers/misc/Makefile``:
.. code-block:: make
obj-$(CONFIG_MISC_EXAMPLE) += example.o
Now we are ready to write the test. The test will be in
``drivers/misc/example-test.c``:
.. code-block:: c
#include <kunit/test.h>
#include "example.h"
/* Define the test cases. */
static void misc_example_add_test_basic(struct kunit *test)
{
KUNIT_EXPECT_EQ(test, 1, misc_example_add(1, 0));
KUNIT_EXPECT_EQ(test, 2, misc_example_add(1, 1));
KUNIT_EXPECT_EQ(test, 0, misc_example_add(-1, 1));
KUNIT_EXPECT_EQ(test, INT_MAX, misc_example_add(0, INT_MAX));
KUNIT_EXPECT_EQ(test, -1, misc_example_add(INT_MAX, INT_MIN));
}
static void misc_example_test_failure(struct kunit *test)
{
KUNIT_FAIL(test, "This test never passes.");
}
static struct kunit_case misc_example_test_cases[] = {
KUNIT_CASE(misc_example_add_test_basic),
KUNIT_CASE(misc_example_test_failure),
{}
};
static struct kunit_suite misc_example_test_suite = {
.name = "misc-example",
.test_cases = misc_example_test_cases,
};
kunit_test_suite(misc_example_test_suite);
Now add the following to ``drivers/misc/Kconfig``:
.. code-block:: kconfig
config MISC_EXAMPLE_TEST
bool "Test for my example"
depends on MISC_EXAMPLE && KUNIT
and the following to ``drivers/misc/Makefile``:
.. code-block:: make
obj-$(CONFIG_MISC_EXAMPLE_TEST) += example-test.o
Now add it to your ``kunitconfig``:
.. code-block:: none
CONFIG_MISC_EXAMPLE=y
CONFIG_MISC_EXAMPLE_TEST=y
Now you can run the test:
.. code-block:: bash
./tools/testing/kunit/kunit.py
You should see the following failure:
.. code-block:: none
...
[16:08:57] [PASSED] misc-example:misc_example_add_test_basic
[16:08:57] [FAILED] misc-example:misc_example_test_failure
[16:08:57] EXPECTATION FAILED at drivers/misc/example-test.c:17
[16:08:57] This test never passes.
...
Congrats! You just wrote your first KUnit test!
Next Steps
==========
* Check out the :doc:`usage` page for a more
in-depth explanation of KUnit.
File diff suppressed because it is too large. Load diff
+20
View File
@@ -8928,6 +8928,17 @@ S: Maintained
F: tools/testing/selftests/
F: Documentation/dev-tools/kselftest*
KERNEL UNIT TESTING FRAMEWORK (KUnit)
M: Brendan Higgins <brendanhiggins@google.com>
L: linux-kselftest@vger.kernel.org
L: kunit-dev@googlegroups.com
W: https://google.github.io/kunit-docs/third_party/kernel/docs/
S: Maintained
F: Documentation/dev-tools/kunit/
F: include/kunit/
F: lib/kunit/
F: tools/testing/kunit/
KERNEL USERMODE HELPER
M: Luis Chamberlain <mcgrof@kernel.org>
L: linux-kernel@vger.kernel.org
@@ -9505,6 +9516,13 @@ F: Documentation/misc-devices/lis3lv02d.rst
F: drivers/misc/lis3lv02d/
F: drivers/platform/x86/hp_accel.c
LIST KUNIT TEST
M: David Gow <davidgow@google.com>
L: linux-kselftest@vger.kernel.org
L: kunit-dev@googlegroups.com
S: Maintained
F: lib/list-test.c
LIVE PATCHING
M: Josh Poimboeuf <jpoimboe@redhat.com>
M: Jiri Kosina <jikos@kernel.org>
@@ -13139,12 +13157,14 @@ F: Documentation/filesystems/proc.txt
PROC SYSCTL
M: Luis Chamberlain <mcgrof@kernel.org>
M: Kees Cook <keescook@chromium.org>
M: Iurii Zaikin <yzaikin@google.com>
L: linux-kernel@vger.kernel.org
L: linux-fsdevel@vger.kernel.org
S: Maintained
F: fs/proc/proc_sysctl.c
F: include/linux/sysctl.h
F: kernel/sysctl.c
F: kernel/sysctl-test.c
F: tools/testing/selftests/sysctl/
PS3 NETWORK SUPPORT
+3
View File
@@ -0,0 +1,3 @@
CONFIG_KUNIT=y
CONFIG_KUNIT_TEST=y
CONFIG_KUNIT_EXAMPLE_TEST=y
+17
View File
@@ -106,3 +106,20 @@ config EXT4_DEBUG
If you select Y here, then you will be able to turn on debugging
with a command such as:
echo 1 > /sys/module/ext4/parameters/mballoc_debug
config EXT4_KUNIT_TESTS
bool "KUnit tests for ext4"
select EXT4_FS
depends on KUNIT
help
This builds the ext4 KUnit tests.
KUnit tests run during boot and output the results to the debug log
in TAP format (http://testanything.org/). Only useful for kernel devs
running KUnit test harness and are not for inclusion into a production
build.
For more information on KUnit and unit tests in general please refer
to the KUnit documentation in Documentation/dev-tools/kunit/.
If unsure, say N.
+1
View File
@@ -13,4 +13,5 @@ ext4-y := balloc.o bitmap.o block_validity.o dir.o ext4_jbd2.o extents.o \
ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o
ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o
ext4-$(CONFIG_EXT4_KUNIT_TESTS) += inode-test.o
ext4-$(CONFIG_FS_VERITY) += verity.o
+272
View File
@@ -0,0 +1,272 @@
// SPDX-License-Identifier: GPL-2.0
/*
* KUnit test of ext4 inode that verify the seconds part of [a/c/m]
* timestamps in ext4 inode structs are decoded correctly.
*/
#include <kunit/test.h>
#include <linux/kernel.h>
#include <linux/time64.h>
#include "ext4.h"
/*
* For constructing the nonnegative timestamp lower bound value.
* binary: 00000000 00000000 00000000 00000000
*/
#define LOWER_MSB_0 0L
/*
* For constructing the nonnegative timestamp upper bound value.
* binary: 01111111 11111111 11111111 11111111
*
*/
#define UPPER_MSB_0 0x7fffffffL
/*
* For constructing the negative timestamp lower bound value.
* binary: 10000000 00000000 00000000 00000000
*/
#define LOWER_MSB_1 (-0x80000000L)
/*
* For constructing the negative timestamp upper bound value.
* binary: 11111111 11111111 11111111 11111111
*/
#define UPPER_MSB_1 (-1L)
/*
* Upper bound for nanoseconds value supported by the encoding.
* binary: 00111111 11111111 11111111 11111111
*/
#define MAX_NANOSECONDS ((1L << 30) - 1)
#define CASE_NAME_FORMAT "%s: msb:%x lower_bound:%x extra_bits: %x"
#define LOWER_BOUND_NEG_NO_EXTRA_BITS_CASE\
"1901-12-13 Lower bound of 32bit < 0 timestamp, no extra bits"
#define UPPER_BOUND_NEG_NO_EXTRA_BITS_CASE\
"1969-12-31 Upper bound of 32bit < 0 timestamp, no extra bits"
#define LOWER_BOUND_NONNEG_NO_EXTRA_BITS_CASE\
"1970-01-01 Lower bound of 32bit >=0 timestamp, no extra bits"
#define UPPER_BOUND_NONNEG_NO_EXTRA_BITS_CASE\
"2038-01-19 Upper bound of 32bit >=0 timestamp, no extra bits"
#define LOWER_BOUND_NEG_LO_1_CASE\
"2038-01-19 Lower bound of 32bit <0 timestamp, lo extra sec bit on"
#define UPPER_BOUND_NEG_LO_1_CASE\
"2106-02-07 Upper bound of 32bit <0 timestamp, lo extra sec bit on"
#define LOWER_BOUND_NONNEG_LO_1_CASE\
"2106-02-07 Lower bound of 32bit >=0 timestamp, lo extra sec bit on"
#define UPPER_BOUND_NONNEG_LO_1_CASE\
"2174-02-25 Upper bound of 32bit >=0 timestamp, lo extra sec bit on"
#define LOWER_BOUND_NEG_HI_1_CASE\
"2174-02-25 Lower bound of 32bit <0 timestamp, hi extra sec bit on"
#define UPPER_BOUND_NEG_HI_1_CASE\
"2242-03-16 Upper bound of 32bit <0 timestamp, hi extra sec bit on"
#define LOWER_BOUND_NONNEG_HI_1_CASE\
"2242-03-16 Lower bound of 32bit >=0 timestamp, hi extra sec bit on"
#define UPPER_BOUND_NONNEG_HI_1_CASE\
"2310-04-04 Upper bound of 32bit >=0 timestamp, hi extra sec bit on"
#define UPPER_BOUND_NONNEG_HI_1_NS_1_CASE\
"2310-04-04 Upper bound of 32bit>=0 timestamp, hi extra sec bit 1. 1 ns"
#define LOWER_BOUND_NONNEG_HI_1_NS_MAX_CASE\
"2378-04-22 Lower bound of 32bit>= timestamp. Extra sec bits 1. Max ns"
#define LOWER_BOUND_NONNEG_EXTRA_BITS_1_CASE\
"2378-04-22 Lower bound of 32bit >=0 timestamp. All extra sec bits on"
#define UPPER_BOUND_NONNEG_EXTRA_BITS_1_CASE\
"2446-05-10 Upper bound of 32bit >=0 timestamp. All extra sec bits on"
struct timestamp_expectation {
const char *test_case_name;
struct timespec64 expected;
u32 extra_bits;
bool msb_set;
bool lower_bound;
};
static time64_t get_32bit_time(const struct timestamp_expectation * const test)
{
if (test->msb_set) {
if (test->lower_bound)
return LOWER_MSB_1;
return UPPER_MSB_1;
}
if (test->lower_bound)
return LOWER_MSB_0;
return UPPER_MSB_0;
}
/*
* Test data is derived from the table in the Inode Timestamps section of
* Documentation/filesystems/ext4/inodes.rst.
*/
static void inode_test_xtimestamp_decoding(struct kunit *test)
{
const struct timestamp_expectation test_data[] = {
{
.test_case_name = LOWER_BOUND_NEG_NO_EXTRA_BITS_CASE,
.msb_set = true,
.lower_bound = true,
.extra_bits = 0,
.expected = {.tv_sec = -0x80000000LL, .tv_nsec = 0L},
},
{
.test_case_name = UPPER_BOUND_NEG_NO_EXTRA_BITS_CASE,
.msb_set = true,
.lower_bound = false,
.extra_bits = 0,
.expected = {.tv_sec = -1LL, .tv_nsec = 0L},
},
{
.test_case_name = LOWER_BOUND_NONNEG_NO_EXTRA_BITS_CASE,
.msb_set = false,
.lower_bound = true,
.extra_bits = 0,
.expected = {0LL, 0L},
},
{
.test_case_name = UPPER_BOUND_NONNEG_NO_EXTRA_BITS_CASE,
.msb_set = false,
.lower_bound = false,
.extra_bits = 0,
.expected = {.tv_sec = 0x7fffffffLL, .tv_nsec = 0L},
},
{
.test_case_name = LOWER_BOUND_NEG_LO_1_CASE,
.msb_set = true,
.lower_bound = true,
.extra_bits = 1,
.expected = {.tv_sec = 0x80000000LL, .tv_nsec = 0L},
},
{
.test_case_name = UPPER_BOUND_NEG_LO_1_CASE,
.msb_set = true,
.lower_bound = false,
.extra_bits = 1,
.expected = {.tv_sec = 0xffffffffLL, .tv_nsec = 0L},
},
{
.test_case_name = LOWER_BOUND_NONNEG_LO_1_CASE,
.msb_set = false,
.lower_bound = true,
.extra_bits = 1,
.expected = {.tv_sec = 0x100000000LL, .tv_nsec = 0L},
},
{
.test_case_name = UPPER_BOUND_NONNEG_LO_1_CASE,
.msb_set = false,
.lower_bound = false,
.extra_bits = 1,
.expected = {.tv_sec = 0x17fffffffLL, .tv_nsec = 0L},
},
{
.test_case_name = LOWER_BOUND_NEG_HI_1_CASE,
.msb_set = true,
.lower_bound = true,
.extra_bits = 2,
.expected = {.tv_sec = 0x180000000LL, .tv_nsec = 0L},
},
{
.test_case_name = UPPER_BOUND_NEG_HI_1_CASE,
.msb_set = true,
.lower_bound = false,
.extra_bits = 2,
.expected = {.tv_sec = 0x1ffffffffLL, .tv_nsec = 0L},
},
{
.test_case_name = LOWER_BOUND_NONNEG_HI_1_CASE,
.msb_set = false,
.lower_bound = true,
.extra_bits = 2,
.expected = {.tv_sec = 0x200000000LL, .tv_nsec = 0L},
},
{
.test_case_name = UPPER_BOUND_NONNEG_HI_1_CASE,
.msb_set = false,
.lower_bound = false,
.extra_bits = 2,
.expected = {.tv_sec = 0x27fffffffLL, .tv_nsec = 0L},
},
{
.test_case_name = UPPER_BOUND_NONNEG_HI_1_NS_1_CASE,
.msb_set = false,
.lower_bound = false,
.extra_bits = 6,
.expected = {.tv_sec = 0x27fffffffLL, .tv_nsec = 1L},
},
{
.test_case_name = LOWER_BOUND_NONNEG_HI_1_NS_MAX_CASE,
.msb_set = false,
.lower_bound = true,
.extra_bits = 0xFFFFFFFF,
.expected = {.tv_sec = 0x300000000LL,
.tv_nsec = MAX_NANOSECONDS},
},
{
.test_case_name = LOWER_BOUND_NONNEG_EXTRA_BITS_1_CASE,
.msb_set = false,
.lower_bound = true,
.extra_bits = 3,
.expected = {.tv_sec = 0x300000000LL, .tv_nsec = 0L},
},
{
.test_case_name = UPPER_BOUND_NONNEG_EXTRA_BITS_1_CASE,
.msb_set = false,
.lower_bound = false,
.extra_bits = 3,
.expected = {.tv_sec = 0x37fffffffLL, .tv_nsec = 0L},
}
};
struct timespec64 timestamp;
int i;
for (i = 0; i < ARRAY_SIZE(test_data); ++i) {
timestamp.tv_sec = get_32bit_time(&test_data[i]);
ext4_decode_extra_time(&timestamp,
cpu_to_le32(test_data[i].extra_bits));
KUNIT_EXPECT_EQ_MSG(test,
test_data[i].expected.tv_sec,
timestamp.tv_sec,
CASE_NAME_FORMAT,
test_data[i].test_case_name,
test_data[i].msb_set,
test_data[i].lower_bound,
test_data[i].extra_bits);
KUNIT_EXPECT_EQ_MSG(test,
test_data[i].expected.tv_nsec,
timestamp.tv_nsec,
CASE_NAME_FORMAT,
test_data[i].test_case_name,
test_data[i].msb_set,
test_data[i].lower_bound,
test_data[i].extra_bits);
}
}
static struct kunit_case ext4_inode_test_cases[] = {
KUNIT_CASE(inode_test_xtimestamp_decoding),
{}
};
static struct kunit_suite ext4_inode_test_suite = {
.name = "ext4_inode_test",
.test_cases = ext4_inode_test_cases,
};
kunit_test_suite(ext4_inode_test_suite);
+356
View File
@@ -0,0 +1,356 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Assertion and expectation serialization API.
*
* Copyright (C) 2019, Google LLC.
* Author: Brendan Higgins <brendanhiggins@google.com>
*/
#ifndef _KUNIT_ASSERT_H
#define _KUNIT_ASSERT_H
#include <kunit/string-stream.h>
#include <linux/err.h>
struct kunit;
/**
* enum kunit_assert_type - Type of expectation/assertion.
* @KUNIT_ASSERTION: Used to denote that a kunit_assert represents an assertion.
* @KUNIT_EXPECTATION: Denotes that a kunit_assert represents an expectation.
*
* Used in conjunction with a &struct kunit_assert to denote whether it
* represents an expectation or an assertion.
*/
enum kunit_assert_type {
KUNIT_ASSERTION,
KUNIT_EXPECTATION,
};
/**
* struct kunit_assert - Data for printing a failed assertion or expectation.
* @test: the test case this expectation/assertion is associated with.
* @type: the type (either an expectation or an assertion) of this kunit_assert.
* @line: the source code line number that the expectation/assertion is at.
* @file: the file path of the source file that the expectation/assertion is in.
* @message: an optional message to provide additional context.
* @format: a function which formats the data in this kunit_assert to a string.
*
* Represents a failed expectation/assertion. Contains all the data necessary to
* format a string to a user reporting the failure.
*/
struct kunit_assert {
struct kunit *test;
enum kunit_assert_type type;
int line;
const char *file;
struct va_format message;
void (*format)(const struct kunit_assert *assert,
struct string_stream *stream);
};
/**
* KUNIT_INIT_VA_FMT_NULL - Default initializer for struct va_format.
*
* Used inside a struct initialization block to initialize struct va_format to
* default values where fmt and va are null.
*/
#define KUNIT_INIT_VA_FMT_NULL { .fmt = NULL, .va = NULL }
/**
* KUNIT_INIT_ASSERT_STRUCT() - Initializer for a &struct kunit_assert.
* @kunit: The test case that this expectation/assertion is associated with.
* @assert_type: The type (assertion or expectation) of this kunit_assert.
* @fmt: The formatting function which builds a string out of this kunit_assert.
*
* The base initializer for a &struct kunit_assert.
*/
#define KUNIT_INIT_ASSERT_STRUCT(kunit, assert_type, fmt) { \
.test = kunit, \
.type = assert_type, \
.file = __FILE__, \
.line = __LINE__, \
.message = KUNIT_INIT_VA_FMT_NULL, \
.format = fmt \
}
void kunit_base_assert_format(const struct kunit_assert *assert,
struct string_stream *stream);
void kunit_assert_print_msg(const struct kunit_assert *assert,
struct string_stream *stream);
/**
* struct kunit_fail_assert - Represents a plain fail expectation/assertion.
* @assert: The parent of this type.
*
* Represents a simple KUNIT_FAIL/KUNIT_ASSERT_FAILURE that always fails.
*/
struct kunit_fail_assert {
struct kunit_assert assert;
};
void kunit_fail_assert_format(const struct kunit_assert *assert,
struct string_stream *stream);
/**
* KUNIT_INIT_FAIL_ASSERT_STRUCT() - Initializer for &struct kunit_fail_assert.
* @test: The test case that this expectation/assertion is associated with.
* @type: The type (assertion or expectation) of this kunit_assert.
*
* Initializes a &struct kunit_fail_assert. Intended to be used in
* KUNIT_EXPECT_* and KUNIT_ASSERT_* macros.
*/
#define KUNIT_INIT_FAIL_ASSERT_STRUCT(test, type) { \
.assert = KUNIT_INIT_ASSERT_STRUCT(test, \
type, \
kunit_fail_assert_format) \
}
/**
* struct kunit_unary_assert - Represents a KUNIT_{EXPECT|ASSERT}_{TRUE|FALSE}
* @assert: The parent of this type.
* @condition: A string representation of a conditional expression.
* @expected_true: True if of type KUNIT_{EXPECT|ASSERT}_TRUE, false otherwise.
*
* Represents a simple expectation or assertion that simply asserts something is
* true or false. In other words, represents the expectations:
* KUNIT_{EXPECT|ASSERT}_{TRUE|FALSE}
*/
struct kunit_unary_assert {
struct kunit_assert assert;
const char *condition;
bool expected_true;
};
void kunit_unary_assert_format(const struct kunit_assert *assert,
struct string_stream *stream);
/**
* KUNIT_INIT_UNARY_ASSERT_STRUCT() - Initializes &struct kunit_unary_assert.
* @test: The test case that this expectation/assertion is associated with.
* @type: The type (assertion or expectation) of this kunit_assert.
* @cond: A string representation of the expression asserted true or false.
* @expect_true: True if of type KUNIT_{EXPECT|ASSERT}_TRUE, false otherwise.
*
* Initializes a &struct kunit_unary_assert. Intended to be used in
* KUNIT_EXPECT_* and KUNIT_ASSERT_* macros.
*/
#define KUNIT_INIT_UNARY_ASSERT_STRUCT(test, type, cond, expect_true) { \
.assert = KUNIT_INIT_ASSERT_STRUCT(test, \
type, \
kunit_unary_assert_format), \
.condition = cond, \
.expected_true = expect_true \
}
/**
* struct kunit_ptr_not_err_assert - An expectation/assertion that a pointer is
* not NULL and not a -errno.
* @assert: The parent of this type.
* @text: A string representation of the expression passed to the expectation.
* @value: The actual evaluated pointer value of the expression.
*
* Represents an expectation/assertion that a pointer is not null and is does
* not contain a -errno. (See IS_ERR_OR_NULL().)
*/
struct kunit_ptr_not_err_assert {
struct kunit_assert assert;
const char *text;
const void *value;
};
void kunit_ptr_not_err_assert_format(const struct kunit_assert *assert,
struct string_stream *stream);
/**
* KUNIT_INIT_PTR_NOT_ERR_ASSERT_STRUCT() - Initializes a
* &struct kunit_ptr_not_err_assert.
* @test: The test case that this expectation/assertion is associated with.
* @type: The type (assertion or expectation) of this kunit_assert.
* @txt: A string representation of the expression passed to the expectation.
* @val: The actual evaluated pointer value of the expression.
*
* Initializes a &struct kunit_ptr_not_err_assert. Intended to be used in
* KUNIT_EXPECT_* and KUNIT_ASSERT_* macros.
*/
#define KUNIT_INIT_PTR_NOT_ERR_STRUCT(test, type, txt, val) { \
.assert = KUNIT_INIT_ASSERT_STRUCT(test, \
type, \
kunit_ptr_not_err_assert_format), \
.text = txt, \
.value = val \
}
/**
* struct kunit_binary_assert - An expectation/assertion that compares two
* non-pointer values (for example, KUNIT_EXPECT_EQ(test, 1 + 1, 2)).
* @assert: The parent of this type.
* @operation: A string representation of the comparison operator (e.g. "==").
* @left_text: A string representation of the expression in the left slot.
* @left_value: The actual evaluated value of the expression in the left slot.
* @right_text: A string representation of the expression in the right slot.
* @right_value: The actual evaluated value of the expression in the right slot.
*
* Represents an expectation/assertion that compares two non-pointer values. For
* example, to expect that 1 + 1 == 2, you can use the expectation
* KUNIT_EXPECT_EQ(test, 1 + 1, 2);
*/
struct kunit_binary_assert {
struct kunit_assert assert;
const char *operation;
const char *left_text;
long long left_value;
const char *right_text;
long long right_value;
};
void kunit_binary_assert_format(const struct kunit_assert *assert,
struct string_stream *stream);
/**
* KUNIT_INIT_BINARY_ASSERT_STRUCT() - Initializes a
* &struct kunit_binary_assert.
* @test: The test case that this expectation/assertion is associated with.
* @type: The type (assertion or expectation) of this kunit_assert.
* @op_str: A string representation of the comparison operator (e.g. "==").
* @left_str: A string representation of the expression in the left slot.
* @left_val: The actual evaluated value of the expression in the left slot.
* @right_str: A string representation of the expression in the right slot.
* @right_val: The actual evaluated value of the expression in the right slot.
*
* Initializes a &struct kunit_binary_assert. Intended to be used in
* KUNIT_EXPECT_* and KUNIT_ASSERT_* macros.
*/
#define KUNIT_INIT_BINARY_ASSERT_STRUCT(test, \
type, \
op_str, \
left_str, \
left_val, \
right_str, \
right_val) { \
.assert = KUNIT_INIT_ASSERT_STRUCT(test, \
type, \
kunit_binary_assert_format), \
.operation = op_str, \
.left_text = left_str, \
.left_value = left_val, \
.right_text = right_str, \
.right_value = right_val \
}
/**
* struct kunit_binary_ptr_assert - An expectation/assertion that compares two
* pointer values (for example, KUNIT_EXPECT_PTR_EQ(test, foo, bar)).
* @assert: The parent of this type.
* @operation: A string representation of the comparison operator (e.g. "==").
* @left_text: A string representation of the expression in the left slot.
* @left_value: The actual evaluated value of the expression in the left slot.
* @right_text: A string representation of the expression in the right slot.
* @right_value: The actual evaluated value of the expression in the right slot.
*
* Represents an expectation/assertion that compares two pointer values. For
* example, to expect that foo and bar point to the same thing, you can use the
* expectation KUNIT_EXPECT_PTR_EQ(test, foo, bar);
*/
struct kunit_binary_ptr_assert {
struct kunit_assert assert;
const char *operation;
const char *left_text;
const void *left_value;
const char *right_text;
const void *right_value;
};
void kunit_binary_ptr_assert_format(const struct kunit_assert *assert,
struct string_stream *stream);
/**
* KUNIT_INIT_BINARY_PTR_ASSERT_STRUCT() - Initializes a
* &struct kunit_binary_ptr_assert.
* @test: The test case that this expectation/assertion is associated with.
* @type: The type (assertion or expectation) of this kunit_assert.
* @op_str: A string representation of the comparison operator (e.g. "==").
* @left_str: A string representation of the expression in the left slot.
* @left_val: The actual evaluated value of the expression in the left slot.
* @right_str: A string representation of the expression in the right slot.
* @right_val: The actual evaluated value of the expression in the right slot.
*
* Initializes a &struct kunit_binary_ptr_assert. Intended to be used in
* KUNIT_EXPECT_* and KUNIT_ASSERT_* macros.
*/
#define KUNIT_INIT_BINARY_PTR_ASSERT_STRUCT(test, \
type, \
op_str, \
left_str, \
left_val, \
right_str, \
right_val) { \
.assert = KUNIT_INIT_ASSERT_STRUCT(test, \
type, \
kunit_binary_ptr_assert_format), \
.operation = op_str, \
.left_text = left_str, \
.left_value = left_val, \
.right_text = right_str, \
.right_value = right_val \
}
/**
* struct kunit_binary_str_assert - An expectation/assertion that compares two
* string values (for example, KUNIT_EXPECT_STREQ(test, foo, "bar")).
* @assert: The parent of this type.
* @operation: A string representation of the comparison operator (e.g. "==").
* @left_text: A string representation of the expression in the left slot.
* @left_value: The actual evaluated value of the expression in the left slot.
* @right_text: A string representation of the expression in the right slot.
* @right_value: The actual evaluated value of the expression in the right slot.
*
* Represents an expectation/assertion that compares two string values. For
* example, to expect that the string in foo is equal to "bar", you can use the
* expectation KUNIT_EXPECT_STREQ(test, foo, "bar");
*/
struct kunit_binary_str_assert {
struct kunit_assert assert;
const char *operation;
const char *left_text;
const char *left_value;
const char *right_text;
const char *right_value;
};
void kunit_binary_str_assert_format(const struct kunit_assert *assert,
struct string_stream *stream);
/**
* KUNIT_INIT_BINARY_STR_ASSERT_STRUCT() - Initializes a
* &struct kunit_binary_str_assert.
* @test: The test case that this expectation/assertion is associated with.
* @type: The type (assertion or expectation) of this kunit_assert.
* @op_str: A string representation of the comparison operator (e.g. "==").
* @left_str: A string representation of the expression in the left slot.
* @left_val: The actual evaluated value of the expression in the left slot.
* @right_str: A string representation of the expression in the right slot.
* @right_val: The actual evaluated value of the expression in the right slot.
*
* Initializes a &struct kunit_binary_str_assert. Intended to be used in
* KUNIT_EXPECT_* and KUNIT_ASSERT_* macros.
*/
#define KUNIT_INIT_BINARY_STR_ASSERT_STRUCT(test, \
type, \
op_str, \
left_str, \
left_val, \
right_str, \
right_val) { \
.assert = KUNIT_INIT_ASSERT_STRUCT(test, \
type, \
kunit_binary_str_assert_format), \
.operation = op_str, \
.left_text = left_str, \
.left_value = left_val, \
.right_text = right_str, \
.right_value = right_val \
}
#endif /* _KUNIT_ASSERT_H */
+51
View File
@@ -0,0 +1,51 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* C++ stream style string builder used in KUnit for building messages.
*
* Copyright (C) 2019, Google LLC.
* Author: Brendan Higgins <brendanhiggins@google.com>
*/
#ifndef _KUNIT_STRING_STREAM_H
#define _KUNIT_STRING_STREAM_H
#include <linux/spinlock.h>
#include <linux/types.h>
#include <stdarg.h>
struct string_stream_fragment {
struct kunit *test;
struct list_head node;
char *fragment;
};
struct string_stream {
size_t length;
struct list_head fragments;
/* length and fragments are protected by this lock */
spinlock_t lock;
struct kunit *test;
gfp_t gfp;
};
struct kunit;
struct string_stream *alloc_string_stream(struct kunit *test, gfp_t gfp);
int __printf(2, 3) string_stream_add(struct string_stream *stream,
const char *fmt, ...);
int string_stream_vadd(struct string_stream *stream,
const char *fmt,
va_list args);
char *string_stream_get_string(struct string_stream *stream);
int string_stream_append(struct string_stream *stream,
struct string_stream *other);
bool string_stream_is_empty(struct string_stream *stream);
int string_stream_destroy(struct string_stream *stream);
#endif /* _KUNIT_STRING_STREAM_H */
+1490
View File
File diff suppressed because it is too large. Load diff
+75
View File
@@ -0,0 +1,75 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* An API to allow a function, that may fail, to be executed, and recover in a
* controlled manner.
*
* Copyright (C) 2019, Google LLC.
* Author: Brendan Higgins <brendanhiggins@google.com>
*/
#ifndef _KUNIT_TRY_CATCH_H
#define _KUNIT_TRY_CATCH_H
#include <linux/types.h>
typedef void (*kunit_try_catch_func_t)(void *);
struct completion;
struct kunit;
/**
* struct kunit_try_catch - provides a generic way to run code which might fail.
* @test: The test case that is currently being executed.
* @try_completion: Completion that the control thread waits on while test runs.
* @try_result: Contains any errno obtained while running test case.
* @try: The function, the test case, to attempt to run.
* @catch: The function called if @try bails out.
* @context: used to pass user data to the try and catch functions.
*
* kunit_try_catch provides a generic, architecture independent way to execute
* an arbitrary function of type kunit_try_catch_func_t which may bail out by
* calling kunit_try_catch_throw(). If kunit_try_catch_throw() is called, @try
* is stopped at the site of invocation and @catch is called.
*
* struct kunit_try_catch provides a generic interface for the functionality
* needed to implement kunit->abort() which in turn is needed for implementing
* assertions. Assertions allow stating a precondition for a test simplifying
* how test cases are written and presented.
*
* Assertions are like expectations, except they abort (call
* kunit_try_catch_throw()) when the specified condition is not met. This is
* useful when you look at a test case as a logical statement about some piece
* of code, where assertions are the premises for the test case, and the
* conclusion is a set of predicates, rather expectations, that must all be
* true. If your premises are violated, it does not makes sense to continue.
*/
struct kunit_try_catch {
/* private: internal use only. */
struct kunit *test;
struct completion *try_completion;
int try_result;
kunit_try_catch_func_t try;
kunit_try_catch_func_t catch;
void *context;
};
void kunit_try_catch_init(struct kunit_try_catch *try_catch,
struct kunit *test,
kunit_try_catch_func_t try,
kunit_try_catch_func_t catch);
void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context);
void __noreturn kunit_try_catch_throw(struct kunit_try_catch *try_catch);
static inline int kunit_try_catch_get_result(struct kunit_try_catch *try_catch)
{
return try_catch->try_result;
}
/*
* Exposed for testing only.
*/
void kunit_generic_try_catch_init(struct kunit_try_catch *try_catch);
#endif /* _KUNIT_TRY_CATCH_H */
+2
View File
@@ -115,6 +115,8 @@ obj-$(CONFIG_TORTURE_TEST) += torture.o
obj-$(CONFIG_HAS_IOMEM) += iomem.o
obj-$(CONFIG_RSEQ) += rseq.o
obj-$(CONFIG_SYSCTL_KUNIT_TEST) += sysctl-test.o
obj-$(CONFIG_GCC_PLUGIN_STACKLEAK) += stackleak.o
KASAN_SANITIZE_stackleak.o := n
KCOV_INSTRUMENT_stackleak.o := n
+392
View File
@@ -0,0 +1,392 @@
// SPDX-License-Identifier: GPL-2.0
/*
* KUnit test of proc sysctl.
*/
#include <kunit/test.h>
#include <linux/sysctl.h>
#define KUNIT_PROC_READ 0
#define KUNIT_PROC_WRITE 1
static int i_zero;
static int i_one_hundred = 100;
/*
* Test that proc_dointvec will not try to use a NULL .data field even when the
* length is non-zero.
*/
static void sysctl_test_api_dointvec_null_tbl_data(struct kunit *test)
{
struct ctl_table null_data_table = {
.procname = "foo",
/*
* Here we are testing that proc_dointvec behaves correctly when
* we give it a NULL .data field. Normally this would point to a
* piece of memory where the value would be stored.
*/
.data = NULL,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
.extra1 = &i_zero,
.extra2 = &i_one_hundred,
};
/*
* proc_dointvec expects a buffer in user space, so we allocate one. We
* also need to cast it to __user so sparse doesn't get mad.
*/
void __user *buffer = (void __user *)kunit_kzalloc(test, sizeof(int),
GFP_USER);
size_t len;
loff_t pos;
/*
* We don't care what the starting length is since proc_dointvec should
* not try to read because .data is NULL.
*/
len = 1234;
KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&null_data_table,
KUNIT_PROC_READ, buffer, &len,
&pos));
KUNIT_EXPECT_EQ(test, (size_t)0, len);
/*
* See above.
*/
len = 1234;
KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&null_data_table,
KUNIT_PROC_WRITE, buffer, &len,
&pos));
KUNIT_EXPECT_EQ(test, (size_t)0, len);
}
/*
* Similar to the previous test, we create a struct ctrl_table that has a .data
* field that proc_dointvec cannot do anything with; however, this time it is
* because we tell proc_dointvec that the size is 0.
*/
static void sysctl_test_api_dointvec_table_maxlen_unset(struct kunit *test)
{
int data = 0;
struct ctl_table data_maxlen_unset_table = {
.procname = "foo",
.data = &data,
/*
* So .data is no longer NULL, but we tell proc_dointvec its
* length is 0, so it still shouldn't try to use it.
*/
.maxlen = 0,
.mode = 0644,
.proc_handler = proc_dointvec,
.extra1 = &i_zero,
.extra2 = &i_one_hundred,
};
void __user *buffer = (void __user *)kunit_kzalloc(test, sizeof(int),
GFP_USER);
size_t len;
loff_t pos;
/*
* As before, we don't care what buffer length is because proc_dointvec
* cannot do anything because its internal .data buffer has zero length.
*/
len = 1234;
KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&data_maxlen_unset_table,
KUNIT_PROC_READ, buffer, &len,
&pos));
KUNIT_EXPECT_EQ(test, (size_t)0, len);
/*
* See previous comment.
*/
len = 1234;
KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&data_maxlen_unset_table,
KUNIT_PROC_WRITE, buffer, &len,
&pos));
KUNIT_EXPECT_EQ(test, (size_t)0, len);
}
/*
* Here we provide a valid struct ctl_table, but we try to read and write from
* it using a buffer of zero length, so it should still fail in a similar way as
* before.
*/
static void sysctl_test_api_dointvec_table_len_is_zero(struct kunit *test)
{
int data = 0;
/* Good table. */
struct ctl_table table = {
.procname = "foo",
.data = &data,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
.extra1 = &i_zero,
.extra2 = &i_one_hundred,
};
void __user *buffer = (void __user *)kunit_kzalloc(test, sizeof(int),
GFP_USER);
/*
* However, now our read/write buffer has zero length.
*/
size_t len = 0;
loff_t pos;
KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, KUNIT_PROC_READ, buffer,
&len, &pos));
KUNIT_EXPECT_EQ(test, (size_t)0, len);
KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, KUNIT_PROC_WRITE, buffer,
&len, &pos));
KUNIT_EXPECT_EQ(test, (size_t)0, len);
}
/*
* Test that proc_dointvec refuses to read when the file position is non-zero.
*/
static void sysctl_test_api_dointvec_table_read_but_position_set(
struct kunit *test)
{
int data = 0;
/* Good table. */
struct ctl_table table = {
.procname = "foo",
.data = &data,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
.extra1 = &i_zero,
.extra2 = &i_one_hundred,
};
void __user *buffer = (void __user *)kunit_kzalloc(test, sizeof(int),
GFP_USER);
/*
* We don't care about our buffer length because we start off with a
* non-zero file position.
*/
size_t len = 1234;
/*
* proc_dointvec should refuse to read into the buffer since the file
* pos is non-zero.
*/
loff_t pos = 1;
KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, KUNIT_PROC_READ, buffer,
&len, &pos));
KUNIT_EXPECT_EQ(test, (size_t)0, len);
}
/*
* Test that we can read a two digit number in a sufficiently size buffer.
* Nothing fancy.
*/
static void sysctl_test_dointvec_read_happy_single_positive(struct kunit *test)
{
int data = 0;
/* Good table. */
struct ctl_table table = {
.procname = "foo",
.data = &data,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
.extra1 = &i_zero,
.extra2 = &i_one_hundred,
};
size_t len = 4;
loff_t pos = 0;
char *buffer = kunit_kzalloc(test, len, GFP_USER);
char __user *user_buffer = (char __user *)buffer;
/* Store 13 in the data field. */
*((int *)table.data) = 13;
KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, KUNIT_PROC_READ,
user_buffer, &len, &pos));
KUNIT_ASSERT_EQ(test, (size_t)3, len);
buffer[len] = '\0';
/* And we read 13 back out. */
KUNIT_EXPECT_STREQ(test, "13\n", buffer);
}
/*
* Same as previous test, just now with negative numbers.
*/
static void sysctl_test_dointvec_read_happy_single_negative(struct kunit *test)
{
int data = 0;
/* Good table. */
struct ctl_table table = {
.procname = "foo",
.data = &data,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
.extra1 = &i_zero,
.extra2 = &i_one_hundred,
};
size_t len = 5;
loff_t pos = 0;
char *buffer = kunit_kzalloc(test, len, GFP_USER);
char __user *user_buffer = (char __user *)buffer;
*((int *)table.data) = -16;
KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, KUNIT_PROC_READ,
user_buffer, &len, &pos));
KUNIT_ASSERT_EQ(test, (size_t)4, len);
buffer[len] = '\0';
KUNIT_EXPECT_STREQ(test, "-16\n", (char *)buffer);
}
/*
* Test that a simple positive write works.
*/
static void sysctl_test_dointvec_write_happy_single_positive(struct kunit *test)
{
int data = 0;
/* Good table. */
struct ctl_table table = {
.procname = "foo",
.data = &data,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
.extra1 = &i_zero,
.extra2 = &i_one_hundred,
};
char input[] = "9";
size_t len = sizeof(input) - 1;
loff_t pos = 0;
char *buffer = kunit_kzalloc(test, len, GFP_USER);
char __user *user_buffer = (char __user *)buffer;
memcpy(buffer, input, len);
KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, KUNIT_PROC_WRITE,
user_buffer, &len, &pos));
KUNIT_EXPECT_EQ(test, sizeof(input) - 1, len);
KUNIT_EXPECT_EQ(test, sizeof(input) - 1, (size_t)pos);
KUNIT_EXPECT_EQ(test, 9, *((int *)table.data));
}
/*
* Same as previous test, but now with negative numbers.
*/
static void sysctl_test_dointvec_write_happy_single_negative(struct kunit *test)
{
int data = 0;
struct ctl_table table = {
.procname = "foo",
.data = &data,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
.extra1 = &i_zero,
.extra2 = &i_one_hundred,
};
char input[] = "-9";
size_t len = sizeof(input) - 1;
loff_t pos = 0;
char *buffer = kunit_kzalloc(test, len, GFP_USER);
char __user *user_buffer = (char __user *)buffer;
memcpy(buffer, input, len);
KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, KUNIT_PROC_WRITE,
user_buffer, &len, &pos));
KUNIT_EXPECT_EQ(test, sizeof(input) - 1, len);
KUNIT_EXPECT_EQ(test, sizeof(input) - 1, (size_t)pos);
KUNIT_EXPECT_EQ(test, -9, *((int *)table.data));
}
/*
* Test that writing a value smaller than the minimum possible value is not
* allowed.
*/
static void sysctl_test_api_dointvec_write_single_less_int_min(
struct kunit *test)
{
int data = 0;
struct ctl_table table = {
.procname = "foo",
.data = &data,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
.extra1 = &i_zero,
.extra2 = &i_one_hundred,
};
size_t max_len = 32, len = max_len;
loff_t pos = 0;
char *buffer = kunit_kzalloc(test, max_len, GFP_USER);
char __user *user_buffer = (char __user *)buffer;
unsigned long abs_of_less_than_min = (unsigned long)INT_MAX
- (INT_MAX + INT_MIN) + 1;
/*
* We use this rigmarole to create a string that contains a value one
* less than the minimum accepted value.
*/
KUNIT_ASSERT_LT(test,
(size_t)snprintf(buffer, max_len, "-%lu",
abs_of_less_than_min),
max_len);
KUNIT_EXPECT_EQ(test, -EINVAL, proc_dointvec(&table, KUNIT_PROC_WRITE,
user_buffer, &len, &pos));
KUNIT_EXPECT_EQ(test, max_len, len);
KUNIT_EXPECT_EQ(test, 0, *((int *)table.data));
}
/*
* Test that writing the maximum possible value works.
*/
static void sysctl_test_api_dointvec_write_single_greater_int_max(
struct kunit *test)
{
int data = 0;
struct ctl_table table = {
.procname = "foo",
.data = &data,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
.extra1 = &i_zero,
.extra2 = &i_one_hundred,
};
size_t max_len = 32, len = max_len;
loff_t pos = 0;
char *buffer = kunit_kzalloc(test, max_len, GFP_USER);
char __user *user_buffer = (char __user *)buffer;
unsigned long greater_than_max = (unsigned long)INT_MAX + 1;
KUNIT_ASSERT_GT(test, greater_than_max, (unsigned long)INT_MAX);
KUNIT_ASSERT_LT(test, (size_t)snprintf(buffer, max_len, "%lu",
greater_than_max),
max_len);
KUNIT_EXPECT_EQ(test, -EINVAL, proc_dointvec(&table, KUNIT_PROC_WRITE,
user_buffer, &len, &pos));
KUNIT_ASSERT_EQ(test, max_len, len);
KUNIT_EXPECT_EQ(test, 0, *((int *)table.data));
}
static struct kunit_case sysctl_test_cases[] = {
KUNIT_CASE(sysctl_test_api_dointvec_null_tbl_data),
KUNIT_CASE(sysctl_test_api_dointvec_table_maxlen_unset),
KUNIT_CASE(sysctl_test_api_dointvec_table_len_is_zero),
KUNIT_CASE(sysctl_test_api_dointvec_table_read_but_position_set),
KUNIT_CASE(sysctl_test_dointvec_read_happy_single_positive),
KUNIT_CASE(sysctl_test_dointvec_read_happy_single_negative),
KUNIT_CASE(sysctl_test_dointvec_write_happy_single_positive),
KUNIT_CASE(sysctl_test_dointvec_write_happy_single_negative),
KUNIT_CASE(sysctl_test_api_dointvec_write_single_less_int_min),
KUNIT_CASE(sysctl_test_api_dointvec_write_single_greater_int_max),
{}
};
static struct kunit_suite sysctl_test_suite = {
.name = "sysctl_test",
.test_cases = sysctl_test_cases,
};
kunit_test_suite(sysctl_test_suite);
+31
View File
@@ -1664,6 +1664,8 @@ config PROVIDE_OHCI1394_DMA_INIT
See Documentation/debugging-via-ohci1394.txt for more information.
source "lib/kunit/Kconfig"
menuconfig RUNTIME_TESTING_MENU
bool "Runtime Testing"
def_bool y
@@ -1948,6 +1950,35 @@ config TEST_SYSCTL
If unsure, say N.
config SYSCTL_KUNIT_TEST
bool "KUnit test for sysctl"
depends on KUNIT
help
This builds the proc sysctl unit test, which runs on boot.
Tests the API contract and implementation correctness of sysctl.
For more information on KUnit and unit tests in general please refer
to the KUnit documentation in Documentation/dev-tools/kunit/.
If unsure, say N.
config LIST_KUNIT_TEST
bool "KUnit Test for Kernel Linked-list structures"
depends on KUNIT
help
This builds the linked list KUnit test suite.
It tests that the API and basic functionality of the list_head type
and associated macros.
KUnit tests run during boot and output the results to the debug log
in TAP format (http://testanything.org/). Only useful for kernel devs
running the KUnit test harness, and not intended for inclusion into a
production build.
For more information on KUnit and unit tests in general please refer
to the KUnit documentation in Documentation/dev-tools/kunit/.
If unsure, say N.
config TEST_UDELAY
tristate "udelay test driver"
help
+5
View File
@@ -92,6 +92,8 @@ obj-$(CONFIG_TEST_MEMINIT) += test_meminit.o
obj-$(CONFIG_TEST_LIVEPATCH) += livepatch/
obj-$(CONFIG_KUNIT) += kunit/
ifeq ($(CONFIG_DEBUG_KOBJECT),y)
CFLAGS_kobject.o += -DDEBUG
CFLAGS_kobject_uevent.o += -DDEBUG
@@ -290,3 +292,6 @@ obj-$(CONFIG_GENERIC_LIB_MULDI3) += muldi3.o
obj-$(CONFIG_GENERIC_LIB_CMPDI2) += cmpdi2.o
obj-$(CONFIG_GENERIC_LIB_UCMPDI2) += ucmpdi2.o
obj-$(CONFIG_OBJAGG) += objagg.o
# KUnit tests
obj-$(CONFIG_LIST_KUNIT_TEST) += list-test.o
Loaded 20 of 44 files, more files were not shown because too many files have changed in this diff. Show more