Since it's been requested by both Peter and Tony on ntdev and ntfsd, I'm
posting here if it is of any use ...
Unit testing as the owner of a driver should do
a) Any user level buffer passing, where you ask the system not to copy,lock,
and manage for you
should be tested very rigorously. If it is pointer pass a NULL pointer, pass
a pointer to a large memory block etc. cAN
YOU FIND THE BOUNDARY CONDITIONS HERE, is the main theme.
b) Development and test should be iterative. Never try to put lot of
functionality before testing. Unit testing software(s)
should be built along the developement, and never share those with any
tester.
c) Write the unit test procedures in a way that you can use them as
thread(s) to dump lot of requests. If you have an ioctl
interface, you could dump using asychronous methods or lots of threads using
sychronous calls. This will help in testing stress
situation. This also helps reduce having global variables that can be very
damaging. It also helps to have the preemption
and interruption of execution paths free from bugs. LOCAL
d) Initially testing should be under debugger, and never forget to analyze
as much as possible while the debugger is on then
create the dump and save it. There are bugs that shows up at midnight like
ghost, when they are least expected.
e) Test all the error paths using step thru and changing memory to force the
error paths, so that you know error paths are
correct.
f) NEVER WRITE A FUNCTION MORE THAN 30 LINES. IF YOU HAVE TO THEN MAKE A
NOTE ABOUT AND TEST VERY THOROUGHLY. Why 30 ?.
After 30 anyone is an old folk!!!. No, Not quite. Studies show that normal
human can juggle about 3 to 4 different things simultaneously,
and about 10 to 15 lines of solid code is the unit of measure for structured
languages (ie. C, etc).
g) If possible, characterize different types of test: tests for feature,
test for hang, test for crash, test for short and long
brusty stress situation, test for long sustained stress situation, test for
slow memory leaks etc. etc. and all of them under uni and multi processor.
h) Any routine with multiple exit points should be your friend for scrutiny.
They are the harbor of sniper attacks in the
the form of Resource leakage, deadlocks etc. Stress testing helps avoid
those bugs.
i) Any routine with your own data structure(s) should be tested thoroughly:
Make sure the right locking mechanism is used, and test accordingly.
Make sure when it can be blocked waiting and what irql level is permissible.
If you know the permissible levels then guard it with KeGetCurrentIrql(),
and at higher irql, and throw Kdprint() or its variant else try to log it.
If it ever hits at a higher irql then that
has to be solved. OPEN UP YOUR TEST PROGRAM/COMMAND WITH MANY INSTANCES AND
FIRE, FOR AUTOMATIC TEST ONE CAN SPWAN MULTIPLE
PROCESS INSTANCES OF THE SAME TEST ROUTINES.
j) Know your types, be familiar with ntddk.h, ntifs.h, ndis.h, and others
relevant to your driver. Castism is a big problem socially
and programmatically. Test/Clean them by setting appropriate compiler
warning level, and other flags.
k) for NT4 developers, it is fairly easy to build under win2k and test under
Driver verifier. It is very helpful. TEST THE
CODE BY EXANDPING THE USER MEMORY ( TO 3gb ) using boot.ini file, then do
low resource simulation on the verifier.
l) Dieting and weightloss is a big industry, so use a decent code coverage
to get rid off the code that never executes,
and design test cases for exercising the busy paths, specially for memory
leaks, hangs/deadlocks.
m) In case of File system related test, using IOBench, and IOMeter helps.
n) In case of Network related drivers, use TCP view from sysinternals to
have higher level understanding for TCP request,
and ethreal sniffer for raw packet analysis while you test with lot of
rootkit related stuff. For sustained stress situation
you can use of the native commands under batch files, and better yet write
small test programms using tcp/udp, http etc.
This is an old area so plenty of boiler plate code/utilites around, and
often it is fairly easy to grab example and tweak
them to your need.
Some of the random bugs I could still remember :: 1) Double completion of
IRP. 2) File handle being stale due to thread context difference(s)
3) for looping to convert wide string to narrow string, and the loop
condition is one iteration more, and memory manager comes back as ghost when
least expected 4) Deadlocks
-pro