16 ms·
Ask HN: Why the Linux Kernel doesn't have unit tests?
Linux is present in a big percent of the devices on the planet, from smart phones to servers to IoT devices to (...). It's fair enough to assume that bugs and/or regressions in it can (and will) affect big portions of these devices. This makes me wonder why aren't there any unit tests in the kernel (and the different drivers in it; especially file system related). Or maybe there are and I just haven't found them?
- elitepleb 4y agohttps://kernel.org/doc/html/latest/dev-tools/kunit/ https://kernel.org/doc/html/latest/dev-tools/kunit/
- develatio 4y agoIf I understand correctly the documentation, this was implemented fairly recently, which would explain why I missed it the last time I researched this topic. Nice to see progress on a framework unit testing in the kernel!!
- dottedmag 4y ago4 years ago: https://lwn.net/Articles/769358/ https://lwn.net/Articles/769358/
- jjgreen 4y agoAnyone ever used for non-kernel work? (Is that even possible?)
- ape4 4y agoLots of info here https://stackoverflow.com/questions/3177338/how-is-the-linux-kernel-tested https://stackoverflow.com/questions/3177338/how-is-the-linux...
- k__ 4y agoTesting in production, like one should, lol.
- deleted 4y ago[deleted]
- throw_a_grenade 4y agoThere's LTP, which tests individual syscalls: - https://en.wikipedia.org/wiki/Linux_Test_Project https://en.wikipedia.org/wiki/Linux_Test_Project - https://github.com/linux-test-project/ltp https://github.com/linux-test-project/ltp - https://linux-test-project.github.io/ https://linux-test-project.github.io/ - https://lists.linux.it/listinfo/ltp https://lists.linux.it/listinfo/ltp
- mueddib 4y agohuh, unit test for low-level C codes? I suggest to learn kernel self test -> Linux kernel contains a "self test suite" and this tool testing coding at module compile time so these are intended tests to exercise individual code paths in kernel and tests are intended to be run after building, installing and booting a kernel.
- Waterluvian 4y agoMy intuition tells me the minimal testing + community testing is not sufficient. But I’m curious what reality tells us. How often has this been a problem? How often are there significant bugs that testing would have caught?
- develatio 4y agoI don't have that kind of data, so any numbers that I might say are based solely on my own experience and my circle of friends working in tech. That said, a friend of mine hit an EXT4 resize bug (https://www.spinics.net/lists/linux-ext4/msg86163.html https://www.spinics.net/lists/linux-ext4/msg86163.html) the other day. IMHO regressions on fairly common features should be captured by unit tests and should never get their way to production.
- anaisbetts 4y agoUnit tests are poorly suited for kernel code. The *vast* majority of production failures in kernel code are due to race conditions and other timing-specific issues, which unit tests are extremely poor at reproducing in a way that mimics how the code is used in real life Another huge source of issues is due to hardware doing something unexpected/not-to-spec - another thing that unit tests would very poorly verify given that, any unit test will simply reproduce how the developer thinks some piece of hardware works, rather than what it does in real life Production kernels are usually better served by long-running stress tests, that try to reproduce real-world use-cases but inject randomness into what they are doing. And indeed, both NT and Linux kernels are extensively tested in this fashion
- darau1 4y agoI don't suppose those long-running stress tests can be automated in any way, can they?
- hannob 4y agoThey are. There's a project by google called syzcaller, which pretty much does that (it's a bit more intelligent than that, and also includes running sanitizers, which find otherwise hard to detect memory safety and concurrency issues). It's actually causing an unexpected problem: It finds so many issues that kernel devs have troule keeping up fixing them.
- galangalalgol 4y agoExcellent! I keep complaining after each vuln pops up here that there isn't anyone with a kernel pipeline. Hopefully they have some static analysis too? Does the data out of this effort support the ggp that most of these defects are concurrency related vs the norm of memory safety?
- vincnetas 4y agoSo it turns out kernel does have unit tests, just that they are running after release.
- Slartie 4y agoAs huge parts of the kernel are effectively device driver code which interacts with hardware on a low level, classic unit testing techniques like mocking can't be applied - or they could be, by writing a mock for the device in question, but that's usually prohibitively expensive if you aim for a fidelity level at which such a mock would actually be of any worth and wouldn't just provide you the "good feeling" of having some unit test coverage while not really increasing the confidence in the tested code. This is especially true when we're talking about reverse-engineered device communication protocols, where you don't have a clue how the device actually works internally, and thus lack the basic means of constructing a mock that does more than just implement the exact same assumptions you've already based your driver code on (resulting in always-green tests that never find actual bugs). But also in cases where you have a protocol spec, the vast majority of ugly bugs in drivers usually originate from differences between that spec and the behavior of the device in the real world.
- rbanffy 4y ago> or they could be, by writing a mock for the device in question That would create a good description of the hardware that could be used for emulators and to test whether actual hardware behaves the way it was specified to behave. > the vast majority of ugly bugs in drivers usually originate from differences between that spec and the behavior of the device in the real world. Having the model hardware encoded in software would make it possible to test its behavior against real hardware for comparison and allow making adjustments.
- ilyt 4y agoThat takes massive amount of effort (most likely writing the emulator is way more than the actual driver code) and still only allows you to say "given those assumptions, that might be not correct, the code works". > Having the model hardware encoded in software would make it possible to test its behavior against real hardware for comparison and allow making adjustments. So you waste weeks to set up a hardware test jig, trying to match it with software and next firmware update changes some stuff that makes model incorrect again. I mean I would expect that if you're a company that wants to put a driver for your hardware into kernel, but many drivers are just RE stuff and setting up a test jig for hardware that allows for fully automated testing can be quite an effort
- throwaway2037 4y agoIf you want to contribute unit tests, I believe that Linus would be open to the idea. For example, there are a bunch of internal APIs: linked lists come to mind. If you wrote unit tests for an internal API, he might accept it. I would start very small -- one .c file with no more than 20 unit tests -- to gauge if there is interest from the community. It seems like a nice gateway to get junior developers (university-level students) in the kernel development. Reading open source mailing lists, I have learned that the best way to "break-in" is a tiny code change that is well-tested. It is hard to reject this type of submission. Be unopinionated, but competant in your submission, and they will be open-minded.
- deleted 4y ago[deleted]
- codethief 4y ago> If you want to contribute unit tests, I believe that Linus would be open to the idea. Not saying this is not true but has Linus stated this anywhere? Because once unit tests have been introduced, the question becomes: Who / what executes those unit tests? Who makes sure no one breaks them? You basically need CI pipelines and infrastructure and suddenly the tiny code change is not so tiny anymore.
- IgorPartola 4y agoYou can also run them yourself and just submit bug reports. You don’t need anyone’s permission to do that.
- st_goliath 4y ago> ... there are a bunch of internal APIs: linked lists come to mind. Those already have unit tests: https://github.com/torvalds/linux/blob/master/lib/list-test.c https://github.com/torvalds/linux/blob/master/lib/list-test.... using an existing in-kernel test framework no less. If you step up into the 'lib' directory (containing generic in-kernel utility code) you might notice that there are a whole bunch of C files already that have an "_test" suffix in their name (or "_kunit").
- cesarb 4y ago> This makes me wonder why aren't there any unit tests in the kernel (and the different drivers in it; especially file system related). Others have already commented on the testing situation for the kernel in general (historically, the tests were all in separate projects outside the kernel, and more recently, the kernel itself has a testing framework), but for filesystems in particular, there's an external project called "xfstests". The name might imply they're only for xfs (and they were originally made to test xfs in particular), but they're used for all filesystems (and also for the common filesystem-related code in the kernel).
- teeray 4y agoSo, if no tests, what is the feedback cycle like for kernel work? Write, compile, put it on some hardware, reboot, collect an oops, debug, repeat?
- marginalia_nu 4y agoThere's other means of coding than trial-and-error.
- sph 4y agoTo add to all the excellent answers in this thread: unit tests are massively overrated. It is good to know that your base64 encoding function is tested for all corner cases, but integration and behaviour tests for the external interface/API are more important than exercising an internal implementation detail. What is the external interface of the kernel? What is its surface area? A kernel is so central and massive the only way to test its complete contract with the user (space) is... just to run stuff and see if it breaks. TDD has some good ideas but for a while it had turned in a religion. While tests are great to have, a good and underrated integration testing system is just for someone to run your software. If no one complains, either no one is using it, or the software is doing its work. Do you really need tests for the read(2) syscall when Linux is running on a billion devices, and that syscall is called some 10^12 times per second globally? https://www.youtube.com/watch?v=EZ05e7EMOLM https://www.youtube.com/watch?v=EZ05e7EMOLM
- bluepoint 4y agoThank you! In a previous job I was doing the equivalent of integration testing and the very young collaborators were bashing me and demanded that I contribute to small random and useless (according to them even) tests that were not really testing anything.
- kwhitefoot 4y ago> If no one complains, either no one is using it, or the software is doing its work. Or it crashed and they couldn't be bothered to report it. Looks the same as no one used it but has a different cause.
- sph 4y agoIf one person globally used a feature, it crashed and they didn't report it (so it was not critical for them), it's a massive waste of time and energy to commit and maintain a test case for it. In fact, perhaps that feature has no place existing at all in the first place and should be dropped. You're underrating the fact that Linux's massive and diverse user base is a great filter for bugs. Only the weirdest heisenbugs can survive this filter, and because of their nature, they wouldn't be tested anyway.
- logicallee 4y agoMy opinion: Linux Kernel coders are real programmers. Do you think Mel wrote unit tests?[1] Real programmers are discrete mathematicians in their head. With pointers. Their code isn't perfect. By analogy, when Andrew Wiles published his some 109 page proof of Fermat's Last Theorem it had bugs. [2] The mathematics community tested it and he eventually corrected it. The Linux Kernel is like that. There are no unit tests for a^n + b^n = c^n because no integers above n=2 satisfy them. You can't unit test your way to secure, correct code in the kernel either. Only a community of testers and verifiers can do that. "given enough eyeballs, all bugs are shallow"[3] [1] http://www.catb.org/jargon/html/story-of-mel.html http://www.catb.org/jargon/html/story-of-mel.html [2] https://en.wikipedia.org/wiki/Wiles%27s_proof_of_Fermat%27s_Last_Theorem https://en.wikipedia.org/wiki/Wiles%27s_proof_of_Fermat%27s_... [3] https://en.wikipedia.org/wiki/Linus%27s_law https://en.wikipedia.org/wiki/Linus%27s_law
- saagarjha 4y agoWhen Andrew Wiles writes a flawed proof he gets to think for a while and try to fix it. When someone puts broken code into Linux someone else gets to think for a whole and try to fix it. Except they’re losing thousands per hour or someone is having their phone hacked. Unit tests are just one part of the story, but they can be very important.
- Xelynega 4y agoI think their point is that Andrew Wiles' flawed proof was shown to a community and improved without any automated testing because something can be verified before it's integrated and that verification never changes. You don't need testing for verified code interacting with verified code in an environment verified to run verified code, but testing takes half the time for "good enough" reliability so we don't spend the time.
- MaxBarraclough 4y agoI'm not sure I see the point of this comparison. Publication of a bad proof with an untrue conclusion may lead to man-years of wasted research effort. The dollar figure of the cost of a bad proof, or of a kernel bug, will always depend on the specifics of the case.
- exabrial 4y agoI think the comment about race conditions is spot on. A while, back on hacker news, there was an article about a company developing a database. Their entire testing methodology came down to producing a deterministic kernel and thread scheduler. This allowed them to simulate every possible permutation of their concurrent code in scientifically speaking reproducible manner. Developing this test framework was actually the majority of what the company did. Testing the kernel would be a similar level of effort.
- jsty 4y agoQuite possibly FoundationDB - they do a lot with deterministic simulation https://www.foundationdb.org/files/fdb-paper.pdf https://www.foundationdb.org/files/fdb-paper.pdf
- titzer 4y ago> every possible permutation of their concurrent code Did they test against weak memory models? Because weak memory models do not necessarily have any equivalent interleaving behavior (stores can appear in different orders on different cores).
- dannymi 4y agoThere are automated (integration) test rigs that run your changes that watch Linux kernel branches. If you send a patch to a Linux kernel maintainer then it will make it into their branch and then you (the author of the patch) will get emails with the results of the automated tests.
- endofreach 4y agoThat‘s super cool! Did you personally, patch something in the kernel? May I ask what it was?
- dannymi 4y agoI fixed some stuff in the Allwinner A20 (an ARM CPU) audio driver. Added a lot of mixer controls :)
- _8j50 4y agoThey do perform automated fuzzing which isn't the same thing but for most of its use cases like drivers, it might be enough so long as coverage is validated routinely.
- st_goliath 4y agoMaybe not "typical" unit tests, but Linux does have test cases for stuff like the generic library code (data compression, encryption, ECC, ...) in the shape of special modules that, when built, run through their test cases during boot up. It gets harder to test low-level driver code, but some subsystems have similar sets of tests, e.g. MTD has a set of tests for drivers & flash chips that they interact with. In 2016 I ported those tests to userspace as part of mtd-utils. The tests for the kernel crypto stuff I mentioned would also test hardware accelerators, if enabled. Filesystems have the fstests project (formerly xfstests, as it was originally written when porting XFS to Linux), testing filesystem semantics and known bugs. There is something similar for the block layer (blktests). The downside being that those test suits take rather long to do a full run. Those are just things that I can think of on top of my head, given the subsystems that I have interacted with in the past. Static analysis on the kernel code is also being done[1][2], there are also CI test farms[3][4], fuzzing farms[5], etc. As others have pointed out, there is a unit testing framework in the kernel[6], IIRC replacing an older framework and ad-hoc test code. [1] https://www.kernel.org/doc/html/v4.15/dev-tools/coccinelle.html https://www.kernel.org/doc/html/v4.15/dev-tools/coccinelle.h... [2] https://scan.coverity.com/projects/linux https://scan.coverity.com/projects/linux [3] https://cki-project.org/ https://cki-project.org/ [4] https://bottest.wiki.kernel.org/ https://bottest.wiki.kernel.org/ [5] https://syzkaller.appspot.com/upstream https://syzkaller.appspot.com/upstream [6] https://kernel.org/doc/html/latest/dev-tools/kunit https://kernel.org/doc/html/latest/dev-tools/kunit
- dshacker 4y agoI recently took a class on linux kernel development, and this is indeed correct, you can always expect when developing for the linux kernel to get your bugs from external sources. If your code has a bug or breaks something, you get a nice email from them telling you what errors you have.
- raverbashing 4y agoWhile uncle bob and other unit test dogmatists have "convinced" some cargo-cultists and inexperienced people that "code without tests" doesn't work (and of course they do some fine goalpoast moving while at it) it is a fact that it, in fact, it does work.
- ajmurmann 4y agoTests != Unit tests & TDD != Unit tests Linux definitely has tests.
- snovv_crash 4y agoWithout tests, how do you know your code actually does what you think? Run it and manually click through every type of functionality? And without tests, how do you know if you introduced a bug or not? Send it to QA and wait for a week?
- raverbashing 4y agoBecause it runs? And people are using it? Do you really think most code out there is fully end-to-end tested automatically? Having integration tests are a good idea. Mandating TDD dogmatism and selling unit tests as the only type of test acceptable is what's wrong here
- endofreach 4y agoIt‘s the classic „what came first“ question that everybody knows. What was written first: A. Unit tests B. Binary code (The answer might shock some of you…) -
- snovv_crash 4y agoThere are studies on the effectiveness of unit tests (and other layers of tests) from the 1980s. Unit tests catch about 20% of bugs. Integration tests catch 40% of bugs, but the overlap between the two is small, so you still benefit from having both. Which one came first is irrelevant, the question is if they help us write better software.
- phtrivier 4y agoI just love threads that start with "why don't they do X ?", followed by dozens of comments explaining why "X is useless, they would never bother doing it, and you should not either", followed by "maybe you should try doing X, who knows", before someone mentions, "hum, well, actually they have been doing it for a few years now" - and that point _not_ being the end of the conversation. Fontenelle, golden tooth, etc..
- sph 4y agoPersonally, I am a fan of meta comments ranting about comments explaining why X is useless.
- ajkjk 4y agoFeels like HN comment sections are like seeing all the thoughts a brain can come up with on a subject written out in parallel, including the dead-ends and false-starts and "on second thought"s. Normally a person only continues thinking the resulting two or three most compelling thoughts, and only says one of them out loud, but on here you get to see the whole process.
- oxff 4y agoUnit Tests are a colossal waste of time 80% of the time, and at least 80% of that time should be spends in thinking how to make your system debuggable.
- jjgreen 4y agoThe problem is, you don't know which 80%
- IgorPartola 4y agoA good rule of thumb is that if a unit test was easy to write then it is useless because either the code it’s testing is so simple that it will never change and/or does not warrant testing, or that the unit test itself isn’t actually doing anything useful (for example it could just be doing an echo test on a function that does something very complex). There are some things that are absolutely worth testing. For example my current project is a library that calculates payroll taxes for US employers. This stuff is self contained, stateless, idempotent, but complex. And yet I know what kinds of inputs are non-trivial and can calculate the outputs by hand, so I can test it. On the other hand, testing that CRUD form that submits data to S3 as well as saving it in the local database is nearly useless. Run through the form when you update it manually and make sure it works. S3 semantics change rarely, your own database changes would necessitate you changing the corresponding form.
- snovv_crash 4y agoIt depends on your field and architecture. Functional-ish design lends itself well to unit tests, where you have known expected inputs and outputs. CRUD apps, not so much.
- fsloth 4y agoDisagree, but depends on context. When you have a complex monolith, unit tests and static typing allow you to create features and refactor the code fearlessly ("Computer says no" is a good thing here). For example, a decades old cad product with millions of lines and tens of developers doing parallel changes. The unit tests allow the continuous integration system to dish out isolated reports on failing tests before pullrequest is merged to main, instead of integration test just bombing at some random place. Unit tests save time.
- emilengler 4y ago[BSD systems do](https://github.com/openbsd/src/tree/master/regress/sys https://github.com/openbsd/src/tree/master/regress/sys)
- deleted 4y ago[deleted]
- revskill 4y agoUnit testing is a way to debug logic error, not "hardware" error. It's like quarantine when you know a part of codebase is infected by "bugs"
- dboreham 4y agoCeci n'est pas un test.
- monocasa 4y agoThere are tests, they're mainly just out of tree, focused on integration rather than unit, and very decentralized. You'll get nastygrams on lkml if you break them. Here's one prominent example: https://github.com/linux-test-project/ltp https://github.com/linux-test-project/ltp
- amluto 4y agoLinux has unit tests for portions of the kernel. Look in the tools/selftests directory. x86 in particular has quite a few, although they run from userspace and exercise stable ABIs, so one might argue that they’re really integration tests.
- nurettin 4y agoLinux didn't have unit tests. For the most part we had Linus eyeballing every line of code before merging it. And if you wrote an extra if or did a boo boo using the wrong enum flag or you overran your buffer, you were flogged, berated and pitied in front of an international audience of engineers. I don't know how things go now in the post-sensitivity world.
- deleted 4y ago[deleted]
- alexfromapex 4y agoThe real reason is there's just too many units
- fedeb95 4y agoLinux test project exists
- strangattractor 4y agoI have spent more time fixing bugs in unit test than fixing bugs they exposed. The one exception is in untyped scripting languages. Test are necessary to run every piece of code to at least attempt to insure a type or function signature has not changed in a way that completely breaks the code.
- goto11 4y agoThere are unit tests for the Linux kernel and even a kernel-specific unit-test framework. See: https://kernel.org/doc/html/latest/dev-tools/kunit/ https://kernel.org/doc/html/latest/dev-tools/kunit/ Here is an article about the various ways Linux is tested: https://embeddedbits.org/how-is-the-linux-kernel-tested/ https://embeddedbits.org/how-is-the-linux-kernel-tested/ Unit tests are just a small part of the array of automated testing used.
- wizofaus 4y agoPresumably there are some sort of automated tests though. If those are working well enough to find bugs there's probably no need for "pure" unit tests (which I normally write because of performance and reliability issues that plague automated tests running at a higher level). It makes sense that kernel OS code would be more suitable to such higher level testing, given it typically doesn't have expensive/slow dependencies on external resources out of its control.
- 7e 4y agoIt’s because unit testing is hard and most OSS devs are wankers.
- deterministic 4y agoUnit tests are a waste of time. System level tests are awesome. I am maintaining a very large C++ library used in production by large corporations around the world. And I haven’t had a production bug, not even one, for more than 6 years. The reason why is 9000+ system level tests. A combination of 1500+ hand written tests and 7500+ auto generated regression tests.
- _448 4y agoEngineers working on the kernel and drivers have a dilemma. They cannot test the code for every conceivable platform because they do not have that many resources. They will test the code for the devices they have, and then ask for others to test on other similar platforms. This is because the code is near metal. The most the developers can do is to develop using the design-by-contract methodology. But that too goes out of the window when others start supporting more platforms and devices. So the only approach that has worked is solid code reviews. There was a very interesting email exchange between Linus and an engineer from Sun. Linus was rejecting his patch because there was a spelling mistake in a comment. That's how strict he is about code quality.
- matttproud 4y agoPlease forgive me for a potentially dumb question: Is there a reason something like the scheduler, which should be mostly algorithmic, should lack unit tests? I can see an argument against some aspects of device driver testing, but the scheduler is in a different class of code, right?
- LaundroMat 4y agoI see a lot of headlines written in the form of : "Why [subject] doesn't/isn't [verb]?" instead of "Why doesn't/isn't [subject] [verb]?". Is this an evolution of English of simply a sign the writer is not a native English speaker? (I mean no judgement with this question)
- Kepouick 4y agoWith plain logic application, writing good unit tests is much harder than writing good code. Probably by a magnitude of 10 or more. Think about it, you have to surround every path in code by a test case ! You have to create mocks everywhere and end up consuming pretty much the whole team time in writing and maintaining tests, whereas in less time through code reviews/rewrites you could have fixed several issues, improved readability, improved team knowledge, facilitate long term support, and so on... In software real troubles comes from integration, not much unitary stuff (unless you praise Monkey coding). And for Linux, it is not just a plain logic application but a kernel that runs on different hardware and has huge base of users and applications. Testing the thing as whole is the only thing that matters. Releasing alpha and beta software is a much more sound, rational and efficient approach. IT industry is (or at least was) organized to test before production. I am certainly not against unit testing. It remains a wise approach for piece of software that need to be glued in stone forever or have super bounded in/out outcome (eg: bank transfers). But it is nothing more than a tool that you might use or not based on situations. Certainly never a one fit all solution !