Как заглушить сокет в C? - PullRequest
9 голосов
/ 13 июля 2011

Я написал клиентский код, который должен посылать некоторые данные через сокет и считывать ответ с удаленного сервера.

Я хотел бы выполнить модульное тестирование этого кода.Подпись функции выглядит следующим образом:

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

, где fd - дескриптор файла сокета для удаленного сервера.

Теперь функция call_remote будет послеотправив данные, заблокируйте чтение ответа с сервера.Как я могу заглушить такой удаленный сервер для модульного тестирования кода?

В идеале я хотел бы что-то вроде:

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;
}

Я хотел бы, чтобы stub_behavior был вызван и отправил 42.0 значение в дескрипторе заглушки файла.

Любой простой способ сделать это?

Ответы [ 4 ]

3 голосов
/ 13 июля 2011

Если это система POSIX, вы можете использовать fork() и 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, sock);

    if (fork()) {
        /* Parent process */
        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;
}

... конечно, вы, вероятно, захотите добавить некоторую проверку ошибок и изменить логику, которая читает запрос.

Файловый дескриптор, созданный socketpair(), является обычным сокетом, и поэтому вызовы сокетов, такие как send() и recv(), будут нормально работать на нем.

1 голос
/ 13 июля 2011

Вы можете использовать все, что можно получить с помощью файлового дескриптора.Файл или, если вы хотите смоделировать блокирующее поведение, канал.

Примечание: явно определенные вызовы сокетов (setsockopt, fcntl, ioctl, ...) не будут работать.

0 голосов
/ 27 сентября 2016

Вот реализация C ++ (я знаю, оригинальный вопрос был о C, но при желании его легко конвертировать обратно в C).Это, вероятно, не работает для очень больших строк, так как сокет, вероятно, будет блокироваться, если строка не может быть буферизована.Но это работает для небольших юнит-тестов.

/// Class creates a simple socket for testing out functions that write to a socket.
/// Usage:
///  1. Call GetSocket() to get a file description socket ID
///  2. write to that socket FD
///  3. Call ReadAll() read back all the data that was written to that socket.
///  The sockets are all closed by ReadAll(), so this is a one-use object.
///
/// \example
///  MockSocket ms;
///  int socket = ms.GetSocket();
///  send(socket,"foo bar",7);
///  ...
///  std::string s = ms.ReadAll();
///  EXPECT_EQ("foo bar",s);

class MockSocket
{
public:
    ~MockSocket()
    {
    }


    int GetSocket()
    {
        socketpair(AF_UNIX, SOCK_STREAM, 0, sockets_);
        return sockets_[0];
    }

    std::string ReadAll()
    {
        close(sockets_[0]);
        std::string s;
        char buffer[256];
        while (true)
        {
            int n = read(sockets_[1], buffer, sizeof(buffer));
            if (n > 0) s.append(buffer,n);
            if (n <= 0) break;
        }
        close(sockets_[1]);
        return s;
    }
private:
    int sockets_[2];
};
0 голосов
/ 13 июля 2011

Я столкнулся с такой же ситуацией, и я поделюсь своим подходом. Я создал сетевые дампы того, что именно должен отправлять клиент, и каким должен быть ответ сервера. Затем я провел побайтовое сравнение запроса клиента, чтобы убедиться, что он совпадает. Если запрос действителен, я читаю из файла ответов и отправляю его обратно клиенту.

Я рад предоставить более подробную информацию (когда я нахожусь на машине с доступом к этому коду)

...