lindelof lindelof - 2 months ago 15
C Question

How to stub a socket in C?

I've written client code that's supposed to send some data through a socket and read back an answer from the remote server.

I would like to unit-test that code. The function's signature is something along the lines of:

double call_remote(double[] args, int fd);


where
fd
is the file descriptor of the socket to the remote server.

Now the
call_remote
function will, after sending the data, block on reading the answer from the server. How can I stub such a remote server for unit-testing the code?

Ideally I would like something like:

int main() {
int stub = /* initialize stub */
double expected = 42.0;

assert(expected == call_remote(/* args */, stub);

return 0;
}

double stub_behavior(double[] args) {
return 42.0;
}


I would like
stub_behavior
to be called and send the
42.0
value down the stubbed file descriptor.

Any easy way I can do that?

caf caf
Answer

If this is a POSIX system, you can use fork() and socketpair():

#define N_DOUBLES_EXPECTED 10
double stub_behaviour(double []);

int initialize_stub(void)
{
    int sock[2];
    double data[N_DOUBLES_EXPECTED];

    socketpair(AF_UNIX, SOCK_STREAM, 0, p);

    if (fork()) {
        close(sock[0]);
        return sock[1];
    }

    /* Child process */

    close(sock[1]);

    /* read N_DOUBLES_EXPECTED in */
    read(sock[0], data, sizeof data);

    /* execute stub */
    data[0] = stub_behaviour(data);

    /* write one double back */
    write(sock[0], data, sizeof data[0]);
    close(sock[0]);
    _exit(0);
}


int main()
{
  int stub = initialize_stub();
  double expected = 42.0;

  assert(expected == call_remote(/* args */, stub);

  return 0;
}

double stub_behavior(double args[])
{
  return 42.0;
}

...of course, you will probably want to add some error checking, and alter the logic that reads the request.

The file descriptor created by socketpair() is a normal socket, and thus socket calls like send() and recv() will work fine on it.