How to write python unit tests for kernel code
Tags: linux, python, testing
Published: 2019-12-04 20:02:20

#Intro
Testing is a crucial part of every software project, and the Linux Kernel is no exception. Not to repeat many great articles about the subject such as this one, {% link https://dev.to/alysivji/testing-101-introduction-to-testing-5hdk %} the article will try to cover some of the testing efforts in the Linux Kernel community, based on an LWN [article](https://lwn.net/Articles/804050/) covering the topic.

The solutions for end to end testing category include [**syzbot**](https://github.com/google/syzkaller/blob/master/docs/syzbot.md) which fuzzes the kernel to find crashes; [**kselftests**](https://www.kernel.org/doc/Documentation/kselftest.txt) and [**LTP**](https://linux-test-project.github.io/) that test kernel features such as cgroups, inotify, bpf, chmod and more; and [**kernelCI**](https://kernelci.org/) that tests the kernel boots on a variety of boards.

As for unit tests we have the recently merged to mainline [**KUnit**](https://lwn.net/Articles/780985/) and Oracle's [**KTF**](https://github.com/oracle/ktf). In both frameworks tests are written in C and execute within the Kernel.

So, what's missing? Aside from having a couple of solutions that pretty much solve the same problem, it seems that the testing efforts are going in the right direction. However, if you want to unit test your code, you're going to have to write kernel code. Writing kernel code usually takes more time than writing python code, and certainly require a different skill and experience.

#Skunk
[Skunk](https://github.com/carmeli-tamir/skunk) aims to bridge the mentioned gap of time and skill, and enables Python programmers to unit test kernel code. It basically "wraps" kernel function calls in userspace and sends them to the Skunk Kernel Module, which performs the actual call and returns the response to user space.

[Skunk](https://github.com/carmeli-tamir/skunk) uses a version of [Google Protobuf](https://developers.google.com/protocol-buffers) that is [ported](https://github.com/carmeli-tamir/protobuf-c/tree/linux_kernel_support) to the Linux Kernel to pack and unpack function calls and return values. Generally speaking, parsing stuff in the kernel is considered a bad practice in terms of security since it might lead to all sorts of bugs and vulnerabilities. However, [Skunk](https://github.com/carmeli-tamir/skunk) is only meant to run on a testing environment and definitely not on production.

The [Skunk](https://github.com/carmeli-tamir/skunk) architecture is roughly:
![Skunk Architecture](https://github.com/carmeli-tamir/skunk/blob/master/doc/skunk_arch.png?raw=true)

Let's consider this simple example of testing the kernel implementation of strstr:
```
sk = Skunk()
ret = sk.call_function_two_arg(
                                "strstr",                                               # Function name
                                2,                                                      # Number of arguments
                                skunk_pb2.FunctionCall.string,                          # Type of return value
                                "whatisthemeaningoflife", skunk_pb2.Argument.string,    # First argument value and type
                                "ning", skunk_pb2.Argument.string)                      # Second argument value and type

assert ret.string=="ningoflife", "error"
```

As you might have guessed, Skunk is just starting, and with the help of the open source community we aim to make it much more comfortable to use. In the longer term we also aim to enable mocking.


#Summary
We reviewed some of the Linux Kernel testing solutions. We then introduced [Skunk](https://github.com/carmeli-tamir/skunk) and explained that it might mitigate difficulties that currently exist when writing kernel UT.
[Skunk](https://github.com/carmeli-tamir/skunk) needs your help to move forward. There are already open issues suitable for new comers. Any help is appreciated!