What is the most accurate way to test the networking code on Linux? What is the most accurate way to test the networking code on Linux? linux linux

What is the most accurate way to test the networking code on Linux?


On ELF systems you can use elf_hook to temporarily replace the real versions of various functions with your own mocked versions.

It allows you to redirect calls to any function from within a shared library to your own arbitrary function.

  • Create a shared library containing the code under test
  • In your test load the shared library dynamically (dlopen)
  • Redirect the symbols you want to mock to your test functions (elf_hook)
  • Now any calls to the real function within the library (the code under test) will be redirected to your mocked function

A plus for this method is that you can still call the original function when required.

  • If for some tests you want to have the call to, eg getaddrinfo, succeed, you can call the system version.
  • In other tests you can use your own mocked version, eg mocked_getaddrinfo, and have it return whatever you want.
  • You can create as many mocked_getaddrinfo functions as you want, to test multiple scenarios

elf_hook has the following signature:

void* elf_hook(char const* library_filename,                void const* library_address,                char const* function_name,                void const* substitution_address);

You would use it like this:

#include <dlfcn.h>#include "elf_hook.h"void do_stuff(); // from the library under test (do_stuff calls getaddrinfo)// our mocked function which will alter the behaviour inside do_stuff()int mocked_getaddrinfo(const char* node,                        const char* service,                       const struct addrinfo* hints,                       struct addrinfo** res){    // return a broken value to test a getaddrinfo failure    return 42;}// another version which actually calls the real functionint real_getaddrinfo(const char* node,                      const char* service,                     const struct addrinfo* hints,                     struct addrinfo** res){    // the real getaddrinfo is available to us here, we only replace it in the shared lib    return getaddrinfo(node, service, hints, res);}int main(){    const char* lib_path = "path/to/library/under/test.so";    // load the library under test    void* lib_handle = dlopen(lib_path, RTLD_LAZY);    // test 1: getraddrinfo is broken    //--------------------------------    // replace getaddrinfo with our 'mocked_getaddrinfo' version    elf_hook(lib_path, LIBRARY_ADDRESS_BY_HANDLE(lib_handle),              "getaddrinfo", mocked_getaddrinfo);    // call a function in the library under test where getaddrinfo fails    do_stuff();    // test 2: getraddrinfo is the system version    //--------------------------------    // replace getaddrinfo with our 'real_getaddrinfo' version     elf_hook(lib_path, LIBRARY_ADDRESS_BY_HANDLE(lib_handle),              "getaddrinfo", real_getaddrinfo);    // call the same function in the library, now getaddrinfo works    do_stuff();    dlclose(lib_handle);    return 0;}

Any call to getaddrinfo from within the library under test will now call mocked_getaddrinfo.

A comprehensive article by the elf_hook author, Anthony Shoumikhin, is here.


You can unit test any code if you are willing to spend the time and energy to do it. Basically with unit testing you are interested in achieving a target percentage of code coverage and in some industries MC/DC coverage. In some cases you will need to write mock code (modules that export functions that look like OS API / socket API, to your unit under test) which will then help drive execution through every nook and cranny in the "unit under test" (a .c/.cpp file) by returning the values you tell it to.

You may need to specify different include paths for your unit under test from the rest of your test application to avoid name conflicts, and you may also have to use pre-processor macros in the test headers to make the mock API appear like the real deal to your "unit" and keep it same as in production code.

You can test hardware drivers and any sort of low level code.

For example, if your code is writing and reading memory mapped registers which you expect say FPGA based logic to change, and you don't have the hardware (or it is tough for you to generate a test condition without actually travelling to mars), then you can write macros/wrapper functions for reading and writing to registers that will return your mocked up values. In the past have used CppUTest in the past which was easy to learn. I suppose a google search will turn up many results.