Unit test for the Linux kernel using Kunit

업데이트 (2020-01-01): KUnit 은 v5.5 머지 윈도우 사이 메인라인에 머지되었습니다. 이 포스트 작성 시점 이후로 많은 KUnit 에도 많은 변화가 있었고, 따라서 아래 내용 중 일부, 특히 테스트 셋업과 수행 부분은 좀 많이 달라졌습니다. 해당 내용을 위해선 공식 문서 를 참고하시길 권장합니다. 또한, 최신 버전은 파이썬 버전 종속성이 생겨서 우분투 16.04 위에서는 문제를 겪으실 수 있습니다. 최신버전의 파이썬을 쓰시거나 그냥 우분투 18.04 를 사용하시길 권장합니다.

지난 2월 말에 FAST'19 학회를 다녀왔는데요, Ted Tso 도 왔더군요. 심지어 구글 부스를 지키고 계시더라구요. 어쩌다보니 식사자리에서 합석하고 잡담 나눈 레드햇 개발자 분들이랑 이야기를 하고 있길래 껴서 좀 이야기를 했는데, 이야기 중 테스트에 대한 이야기가 나왔고, 이에 Ted 가 KUnit 이라는 도구를 소개해 줬습니다. 잠깐 사용해 보니 매우 매력적인 것 같아서 이 블로그에서도 소개해 볼까 합니다.

KUnit 은 이름에서 짐작했겠지만 리눅스 커널을 위한 유닛 테스트 프레임웍입니다. 구글의 Brendan Higgins 라는 분이 개발하고 있고, 커널 내에 머지되는 걸 목표로 해서 LKML 에도 RFC 패치를 보내고 있습니다. 구글러다 보니 구글에서 호스팅 되는 소스트리 위에서 개발을 하고 있고, 문서화 도 잘 해뒀군요.

이 글은 이런 KUnit 을 사용하는 법을 간단히 정리해 봅니다. 글 내의 테스트에 사용된 환경은 Ubuntu 16.04 서버 버전입니다.

Install

Kunit 개발 커널은 https://kunit.googlesource.com 에서 받을 수 있습니다. 간단히 아래 명령으로 커널 코드를 땡겨옵시다. 여기선 가장 최근에 RFC 패치를 보냈던 5.0-rc5 위의 버전으로 가져오겠습니다.

$ git clone -b kunit/rfc/5.0-rc5/v4 https://kunit.googlesource.com/linux

물론, [Patchwork] (https://lore.kernel.org/patchwork/project/lkml/list/?series=383391) 을 통해 KUnit 패치만 직접 받아와 사용중인 커널에 적용하실 수도 있습니다. 전 v5.0 버전 위에도 적용해 봤는데 문제 없이 잘 적용되더군요.

이어서 KUnit 을 위한 패키지를 깔아야 할텐데요, 커널 빌드에 필요한 패키지만 깔면 됩니다. 커널 빌드에 필요한 패키지에 대한 정보는 이 블로그의 커널 빌드 및 설치에 대한 포스트 를 참고해 주세요.

Test

커널 빌드 종속성 패키지까지 다 설치했다면 준비가 거의 끝났습니다. 잘 돌아가는지 확인해 보기 위해 kunit 에서 제공하는 예제 테스트들을 돌려봅시다.

KUnit 을 돌리기 위해선 configuration 을 커널 트리 루트에 kunitconfig 라는 이름의 파일로 써줘야 합니다. 이 설정은 어떤 테스트를 돌릴지 등을 지정합니다. 일단 아래 내용으로 해당 파일을 써줍시다:

$ cd linux
$ echo CONFIG_KUNIT=y > kunitconfig
$ echo CONFIG_KUNIT_TEST=y >> kunitconfig
$ echo CONFIG_KUNIT_EXAMPLE_TEST=y >> kunitconfig

이제 다음의 간단한 명령만으로 KUnit 예제 테스트를 돌릴 수 있습니다:

$ ./tools/testing/kunit/kunit.py

아래와 같은 결과가 터미널에 뜰겁니다:

[11:31:47] Building KUnit Kernel ...
[11:32:12] Starting KUnit Kernel ...
[11:32:12] ==============================
[11:32:13] [PASSED] kunit-resource-test:kunit_resource_test_init_resources
[11:32:13] [PASSED] kunit-resource-test:kunit_resource_test_alloc_resource
[11:32:13] [PASSED] kunit-resource-test:kunit_resource_test_free_resource
[11:32:13] [PASSED] kunit-resource-test:kunit_resource_test_cleanup_resources
[11:32:13] ==============================
[11:32:13] [PASSED] kunit-try-catch-test:kunit_test_try_catch_successful_try_no_catch
[11:32:13] [PASSED] kunit-try-catch-test:kunit_test_try_catch_unsuccessful_try_does_catch
[11:32:13] [PASSED] kunit-try-catch-test:kunit_test_generic_try_catch_successful_try_no_catch
[11:32:13] [PASSED] kunit-try-catch-test:kunit_test_generic_try_catch_unsuccessful_try_does_catch
[11:32:13] ==============================
[11:32:13] [PASSED] string-stream-test:string_stream_test_get_string
[11:32:13] [PASSED] string-stream-test:string_stream_test_add_and_clear
[11:32:13] ==============================
[11:32:13] [PASSED] example:example_simple_test
[11:32:13] ==============================
[11:32:13] Testing complete. 11 tests run. 0 failed. 0 crashed.
[11:32:13] Elapsed time: 26.005s total, 0.000s configuring, 25.736s building, 0.268s running.

kunit-resource-test, kunit-try-catch-test, string-stream-tets, example 등의 예제 테스트가 돌아갔고, 모두 테스트를 통과해서 문제가 없음을 보여줍니다.

KUnit 은 테스트를 위해 커널도 빌드하기 때문에 빌드 시간이 조금 길긴 합니다. 이 경우엔 26초 정도 걸렸네요. 하지만 이건 처음 빌드라 그렇고, 기존에 빌드를 해두고 파일 하나만 수정하는 경우엔 약 10초 정도 걸리는 것 같습니다. 하지만 이후 실제 테스트를 돌리는건 매우 짧은 시간을 필요로 합니다. 이 경우 0.27초 가량 걸렸군요! 따라서 테스트가 늘어나도 많은 시간을 요하지 않습니다.

스스로를 위한 유닛 테스트를 추가하는 법은 Kunit 공식 문서[1] 를 참고하시기 바랍니다. 어렵지 않습니다 :)

[1] https://google.github.io/kunit-docs/third_party/kernel/docs/start.html#writing-your-first-test

Conclusion

리눅스 커널을 위한 Unit test framework 인 KUnit 에 대한 간단한 소개와 사용법을 설명했습니다. 저도 최근 개발에 활용하고 있는데, TDD 의 장점을 오랫만에 느낄 수 있었습니다. 하루 빨리 업스트림에도 머지되었으면 좋겠네요!

Avatar
SeongJae Park (SJ)
Kernel Programmer

SeongJae Park (SJ) is a programmer who loves to analyze and develop systems.

Related