Blame tests/test_tio.c

Packit 6bd9ab
/*
Packit 6bd9ab
   test_tio.c - simple test for the tio module
Packit 6bd9ab
   This file is part of the nss-pam-ldapd library.
Packit 6bd9ab
Packit 6bd9ab
   Copyright (C) 2007, 2008, 2011, 2012, 2013 Arthur de Jong
Packit 6bd9ab
Packit 6bd9ab
   This library is free software; you can redistribute it and/or
Packit 6bd9ab
   modify it under the terms of the GNU Lesser General Public
Packit 6bd9ab
   License as published by the Free Software Foundation; either
Packit 6bd9ab
   version 2.1 of the License, or (at your option) any later version.
Packit 6bd9ab
Packit 6bd9ab
   This library is distributed in the hope that it will be useful,
Packit 6bd9ab
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6bd9ab
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6bd9ab
   Lesser General Public License for more details.
Packit 6bd9ab
Packit 6bd9ab
   You should have received a copy of the GNU Lesser General Public
Packit 6bd9ab
   License along with this library; if not, write to the Free Software
Packit 6bd9ab
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit 6bd9ab
   02110-1301 USA
Packit 6bd9ab
*/
Packit 6bd9ab
Packit 6bd9ab
#include "config.h"
Packit 6bd9ab
Packit 6bd9ab
#include <stdio.h>
Packit 6bd9ab
#include <string.h>
Packit 6bd9ab
#include <assert.h>
Packit 6bd9ab
#include <sys/types.h>
Packit 6bd9ab
#include <sys/socket.h>
Packit 6bd9ab
#include <pthread.h>
Packit 6bd9ab
#ifdef HAVE_STDINT_H
Packit 6bd9ab
#include <stdint.h>
Packit 6bd9ab
#endif /* HAVE_STDINT_H */
Packit 6bd9ab
#include <stdlib.h>
Packit 6bd9ab
#include <errno.h>
Packit 6bd9ab
#include <unistd.h>
Packit 6bd9ab
#include <fcntl.h>
Packit 6bd9ab
Packit 6bd9ab
#include "common.h"
Packit 6bd9ab
Packit 6bd9ab
#include "common/tio.h"
Packit 6bd9ab
Packit 6bd9ab
/* for platforms that don't have ETIME use ETIMEDOUT */
Packit 6bd9ab
#ifndef ETIME
Packit 6bd9ab
#define ETIME ETIMEDOUT
Packit 6bd9ab
#endif /* ETIME */
Packit 6bd9ab
Packit 6bd9ab
/* structure for passing arguments to helper (is a thread) */
Packit 6bd9ab
struct helper_args {
Packit 6bd9ab
  int fd;
Packit 6bd9ab
  size_t blocksize;
Packit 6bd9ab
  size_t blocks;
Packit 6bd9ab
  int timeout;
Packit 6bd9ab
};
Packit 6bd9ab
Packit 6bd9ab
static void *help_tiowriter(void *arg)
Packit 6bd9ab
{
Packit 6bd9ab
  TFILE *fp;
Packit 6bd9ab
  size_t i, j, k;
Packit 6bd9ab
  uint8_t *buf;
Packit 6bd9ab
  struct helper_args *hargs = (struct helper_args *)arg;
Packit 6bd9ab
  /* allocate the buffer */
Packit 6bd9ab
  buf = (uint8_t *)malloc(hargs->blocksize);
Packit 6bd9ab
  assert(buf != NULL);
Packit 6bd9ab
  /* open the file */
Packit 6bd9ab
  fp = tio_fdopen(hargs->fd, hargs->timeout * 1000, hargs->timeout * 1000,
Packit 6bd9ab
                  4 * 1024, 8 * 1024, 4 * 1024, 8 * 1024);
Packit 6bd9ab
  assertok(fp != NULL);
Packit 6bd9ab
  /* write the blocks */
Packit 6bd9ab
  i = 0;
Packit 6bd9ab
  for (k = 0; k < hargs->blocks; k++)
Packit 6bd9ab
  {
Packit 6bd9ab
    /* fill the buffer */
Packit 6bd9ab
    for (j = 0; j < hargs->blocksize; j++)
Packit 6bd9ab
      buf[j] = i++;
Packit 6bd9ab
    assertok(tio_write(fp, buf, hargs->blocksize) == 0);
Packit 6bd9ab
  }
Packit 6bd9ab
  /* close the file flushing the buffer */
Packit 6bd9ab
  assertok(tio_close(fp) == 0);
Packit 6bd9ab
  /* we're done */
Packit 6bd9ab
  free(buf);
Packit 6bd9ab
  return NULL;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
static void *help_tioreader(void *arg)
Packit 6bd9ab
{
Packit 6bd9ab
  TFILE *fp;
Packit 6bd9ab
  size_t i, j, k;
Packit 6bd9ab
  uint8_t *buf;
Packit 6bd9ab
  struct helper_args *hargs = (struct helper_args *)arg;
Packit 6bd9ab
  /* allocate the buffer */
Packit 6bd9ab
  buf = (uint8_t *)malloc(hargs->blocksize);
Packit 6bd9ab
  assert(buf != NULL);
Packit 6bd9ab
  /* open the file */
Packit 6bd9ab
  fp = tio_fdopen(hargs->fd, hargs->timeout * 1000, hargs->timeout * 1000,
Packit 6bd9ab
                  4 * 1024, 8 * 1024, 4 * 1024, 8 * 1024);
Packit 6bd9ab
  assertok(fp != NULL);
Packit 6bd9ab
  /* read the blocks */
Packit 6bd9ab
  i = 0;
Packit 6bd9ab
  for (k = 0; k < hargs->blocks; k++)
Packit 6bd9ab
  {
Packit 6bd9ab
    assertok(tio_read(fp, buf, hargs->blocksize) == 0);
Packit 6bd9ab
    /* check the buffer */
Packit 6bd9ab
    for (j = 0; j < hargs->blocksize; j++)
Packit 6bd9ab
      assert(buf[j] == (uint8_t)(i++));
Packit 6bd9ab
  }
Packit 6bd9ab
  /* close the file */
Packit 6bd9ab
  assertok(tio_close(fp) == 0);
Packit 6bd9ab
  /* we're done */
Packit 6bd9ab
  free(buf);
Packit 6bd9ab
  return NULL;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
static void *help_normwriter(void *arg)
Packit 6bd9ab
{
Packit 6bd9ab
  FILE *fp;
Packit 6bd9ab
  size_t i, j, k;
Packit 6bd9ab
  uint8_t *buf;
Packit 6bd9ab
  struct helper_args *hargs = (struct helper_args *)arg;
Packit 6bd9ab
  /* allocate the buffer */
Packit 6bd9ab
  buf = (uint8_t *)malloc(hargs->blocksize);
Packit 6bd9ab
  assert(buf != NULL);
Packit 6bd9ab
  /* open the file */
Packit 6bd9ab
  fp = fdopen(hargs->fd, "wb");
Packit 6bd9ab
  assertok(fp != NULL);
Packit 6bd9ab
  /* write the blocks */
Packit 6bd9ab
  i = 0;
Packit 6bd9ab
  for (k = 0; k < hargs->blocks; k++)
Packit 6bd9ab
  {
Packit 6bd9ab
    /* fill the buffer */
Packit 6bd9ab
    for (j = 0; j < hargs->blocksize; j++)
Packit 6bd9ab
      buf[j] = i++;
Packit 6bd9ab
    assertok(fwrite(buf, hargs->blocksize, 1, fp) == 1);
Packit 6bd9ab
  }
Packit 6bd9ab
  /* close the file flushing the buffer */
Packit 6bd9ab
  assertok(fclose(fp) == 0);
Packit 6bd9ab
  /* we're done */
Packit 6bd9ab
  free(buf);
Packit 6bd9ab
  return NULL;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
static void *help_normreader(void *arg)
Packit 6bd9ab
{
Packit 6bd9ab
  FILE *fp;
Packit 6bd9ab
  size_t i, j, k;
Packit 6bd9ab
  struct helper_args *hargs = (struct helper_args *)arg;
Packit 6bd9ab
  /* open the file */
Packit 6bd9ab
  fp = fdopen(hargs->fd, "rb");
Packit 6bd9ab
  assertok(fp != NULL);
Packit 6bd9ab
  /* read the blocks */
Packit 6bd9ab
  i = 0;
Packit 6bd9ab
  for (k = 0; k < hargs->blocks; k++)
Packit 6bd9ab
  {
Packit 6bd9ab
    /* check the buffer */
Packit 6bd9ab
    for (j = 0; j < hargs->blocksize; j++)
Packit 6bd9ab
      assertok(fgetc(fp) == (uint8_t)(i++));
Packit 6bd9ab
  }
Packit 6bd9ab
  /* close the file */
Packit 6bd9ab
  assertok(fclose(fp) == 0);
Packit 6bd9ab
  return NULL;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/*
Packit 6bd9ab
TODO: test timeout
Packit 6bd9ab
TODO: test whether a simple request/response works
Packit 6bd9ab
*/
Packit 6bd9ab
Packit 6bd9ab
static int test_blocks(size_t wbs, size_t wbl, size_t rbs, size_t rbl)
Packit 6bd9ab
{
Packit 6bd9ab
  int sp[2];
Packit 6bd9ab
  pthread_t wthread, rthread;
Packit 6bd9ab
  struct helper_args wargs, rargs;
Packit 6bd9ab
  /* set up the socket pair */
Packit 6bd9ab
  assertok(socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == 0);
Packit 6bd9ab
  /* log */
Packit 6bd9ab
  printf("test_tio: writing %d blocks of %d bytes (%d total)\n",
Packit 6bd9ab
         (int)wbl, (int)wbs, (int)(wbl * wbs));
Packit 6bd9ab
  printf("test_tio: reading %d blocks of %d bytes (%d total)\n",
Packit 6bd9ab
         (int)rbl, (int)rbs, (int)(rbl * rbs));
Packit 6bd9ab
  /* start the writer thread */
Packit 6bd9ab
  wargs.fd = sp[0];
Packit 6bd9ab
  wargs.blocksize = wbs;
Packit 6bd9ab
  wargs.blocks = wbl;
Packit 6bd9ab
  wargs.timeout = 2;
Packit 6bd9ab
  assertok(pthread_create(&wthread, NULL, help_tiowriter, &wargs) == 0);
Packit 6bd9ab
/*  sleep(1); */
Packit 6bd9ab
  /* start the reader thread */
Packit 6bd9ab
  rargs.fd = sp[1];
Packit 6bd9ab
  rargs.blocksize = rbs;
Packit 6bd9ab
  rargs.blocks = rbl;
Packit 6bd9ab
  rargs.timeout = 2;
Packit 6bd9ab
  assertok(pthread_create(&rthread, NULL, help_tioreader, &rargs) == 0);
Packit 6bd9ab
  /* wait for all threads to die */
Packit 6bd9ab
  assertok(pthread_join(wthread, NULL) == 0);
Packit 6bd9ab
  assertok(pthread_join(rthread, NULL) == 0);
Packit 6bd9ab
  /* we're done */
Packit 6bd9ab
  return 0;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
static void test_reset(void)
Packit 6bd9ab
{
Packit 6bd9ab
  int sp[2];
Packit 6bd9ab
  pthread_t wthread;
Packit 6bd9ab
  struct helper_args wargs;
Packit 6bd9ab
  TFILE *fp;
Packit 6bd9ab
  size_t i, j, k, save;
Packit 6bd9ab
  uint8_t buf[20];
Packit 6bd9ab
  /* set up the socket pair */
Packit 6bd9ab
  assertok(socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == 0);
Packit 6bd9ab
  /* start the writer thread */
Packit 6bd9ab
  wargs.fd = sp[0];
Packit 6bd9ab
  wargs.blocksize = 4 * 1024;
Packit 6bd9ab
  wargs.blocks = 10;
Packit 6bd9ab
  wargs.timeout = 2;
Packit 6bd9ab
  assertok(pthread_create(&wthread, NULL, help_normwriter, &wargs) == 0);
Packit 6bd9ab
  /* set up read handle */
Packit 6bd9ab
  fp = tio_fdopen(sp[1], 2000, 2000, 2 * 1024, 4 * 1024, 2 * 1024, 4 * 1024);
Packit 6bd9ab
  assertok(fp != NULL);
Packit 6bd9ab
  /* perform 20 reads */
Packit 6bd9ab
  i = 0;
Packit 6bd9ab
  for (k = 0; k < 20; k++)
Packit 6bd9ab
  {
Packit 6bd9ab
    assertok(tio_read(fp, buf, sizeof(buf)) == 0);
Packit 6bd9ab
    /* check the buffer */
Packit 6bd9ab
    for (j = 0; j < sizeof(buf); j++)
Packit 6bd9ab
      assert(buf[j] == (uint8_t)(i++));
Packit 6bd9ab
  }
Packit 6bd9ab
  /* mark and perform another 2 reads */
Packit 6bd9ab
  tio_mark(fp);
Packit 6bd9ab
  save = i;
Packit 6bd9ab
  for (k = 20; k < 22; k++)
Packit 6bd9ab
  {
Packit 6bd9ab
    assertok(tio_read(fp, buf, sizeof(buf)) == 0);
Packit 6bd9ab
    /* check the buffer */
Packit 6bd9ab
    for (j = 0; j < sizeof(buf); j++)
Packit 6bd9ab
      assert(buf[j] == (uint8_t)(i++));
Packit 6bd9ab
  }
Packit 6bd9ab
  /* check that we can reset */
Packit 6bd9ab
  assertok(tio_reset(fp) == 0);
Packit 6bd9ab
  /* perform 204 reads (partially the same as before) */
Packit 6bd9ab
  i = save;
Packit 6bd9ab
  for (k = 20; k < 224; k++)
Packit 6bd9ab
  {
Packit 6bd9ab
    assert(tio_read(fp, buf, sizeof(buf)) == 0);
Packit 6bd9ab
    /* check the buffer */
Packit 6bd9ab
    for (j = 0; j < sizeof(buf); j++)
Packit 6bd9ab
      assert(buf[j] == (uint8_t)(i++));
Packit 6bd9ab
  }
Packit 6bd9ab
  /* check that we can reset */
Packit 6bd9ab
  assertok(tio_reset(fp) == 0);
Packit 6bd9ab
  /* perform 502 reads (partially the same) */
Packit 6bd9ab
  i = save;
Packit 6bd9ab
  for (k = 20; k < 522; k++)
Packit 6bd9ab
  {
Packit 6bd9ab
    assert(tio_read(fp, buf, sizeof(buf)) == 0);
Packit 6bd9ab
    /* check the buffer */
Packit 6bd9ab
    for (j = 0; j < sizeof(buf); j++)
Packit 6bd9ab
      assert(buf[j] == (uint8_t)(i++));
Packit 6bd9ab
  }
Packit 6bd9ab
  /* check that reset is no longer possible */
Packit 6bd9ab
  assertok(tio_reset(fp) != 0);
Packit 6bd9ab
  /* read the remainder of the data 1526 reads */
Packit 6bd9ab
  for (k = 522; k < 2048; k++)
Packit 6bd9ab
  {
Packit 6bd9ab
    assertok(tio_read(fp, buf, sizeof(buf)) == 0);
Packit 6bd9ab
    /* check the buffer */
Packit 6bd9ab
    for (j = 0; j < sizeof(buf); j++)
Packit 6bd9ab
      assert(buf[j] == (uint8_t)(i++));
Packit 6bd9ab
  }
Packit 6bd9ab
  /* close the file */
Packit 6bd9ab
  assertok(tio_close(fp) == 0);
Packit 6bd9ab
  /* wait for the writer thread to die */
Packit 6bd9ab
  assertok(pthread_join(wthread, NULL) == 0);
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* this test starts a reader and writer and does not write for a while */
Packit 6bd9ab
static void test_timeout_reader(void)
Packit 6bd9ab
{
Packit 6bd9ab
  int sp[2];
Packit 6bd9ab
  TFILE *rfp;
Packit 6bd9ab
  FILE *wfp;
Packit 6bd9ab
  uint8_t buf[20];
Packit 6bd9ab
  time_t start, end;
Packit 6bd9ab
  int saved_errno;
Packit 6bd9ab
  /* set up the socket pair */
Packit 6bd9ab
  assertok(socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == 0);
Packit 6bd9ab
  /* open the writer */
Packit 6bd9ab
  assertok((wfp = fdopen(sp[0], "wb")) != NULL);
Packit 6bd9ab
  /* open the reader */
Packit 6bd9ab
  assertok((rfp = tio_fdopen(sp[1], 1100, 1100, 2 * 1024, 4 * 1024, 2 * 1024, 4 * 1024)) != NULL);
Packit 6bd9ab
  printf("test_tio: test_timeout_reader: trying to read a block of %d bytes\n",
Packit 6bd9ab
         (int)sizeof(buf));
Packit 6bd9ab
  /* perform a read */
Packit 6bd9ab
  start = time(NULL);
Packit 6bd9ab
  errno = 0;
Packit 6bd9ab
  assertok(tio_read(rfp, buf, sizeof(buf)) != 0);
Packit 6bd9ab
  saved_errno = errno;
Packit 6bd9ab
  end = time(NULL);
Packit 6bd9ab
  printf("test_tio: test_timeout_reader: read 0 blocks of %d bytes in %d second(s) (%s)\n",
Packit 6bd9ab
         (int)sizeof(buf), (int)(end - start), strerror(saved_errno));
Packit 6bd9ab
  /* since the read timeout is more than a second end time should be bigger
Packit 6bd9ab
     than start time */
Packit 6bd9ab
  assert(end > start);
Packit 6bd9ab
  /* the error should be timeout */
Packit 6bd9ab
  assert(saved_errno == ETIME);
Packit 6bd9ab
  /* close the files */
Packit 6bd9ab
  assertok(tio_close(rfp) == 0);
Packit 6bd9ab
  assertok(fclose(wfp) == 0);
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* this test starts a writer and an idle reader */
Packit 6bd9ab
static void test_timeout_writer(void)
Packit 6bd9ab
{
Packit 6bd9ab
  int sp[2];
Packit 6bd9ab
  FILE *rfp;
Packit 6bd9ab
  TFILE *wfp;
Packit 6bd9ab
  int i;
Packit 6bd9ab
  uint8_t buf[20];
Packit 6bd9ab
  time_t start, end;
Packit 6bd9ab
  int numblocks = 10000;
Packit 6bd9ab
  int saved_errno;
Packit 6bd9ab
  /* set up the socket pair */
Packit 6bd9ab
  assertok(socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == 0);
Packit 6bd9ab
  /* open the reader */
Packit 6bd9ab
  assertok((rfp = fdopen(sp[0], "rb")) != NULL);
Packit 6bd9ab
  /* open the writer */
Packit 6bd9ab
  assertok((wfp = tio_fdopen(sp[1], 1100, 1100, 2 * 1024, 4 * 1024,
Packit 6bd9ab
                             2 * sizeof(buf), 4 * sizeof(buf) + 1)) != NULL);
Packit 6bd9ab
  printf("test_tio: test_timeout_writer: trying to write %d blocks of %d bytes\n",
Packit 6bd9ab
         numblocks, (int)sizeof(buf));
Packit 6bd9ab
  /* we perform a number of writes to the stream to see if they are buffered */
Packit 6bd9ab
  start = time(NULL);
Packit 6bd9ab
  errno = 0;
Packit 6bd9ab
  for (i = 0; (i < numblocks) && (tio_write(wfp, buf, sizeof(buf)) == 0); i++)
Packit 6bd9ab
    /* nothing */ ;
Packit 6bd9ab
  saved_errno = errno;
Packit 6bd9ab
  end = time(NULL);
Packit 6bd9ab
  printf("test_tio: test_timeout_writer: written %d blocks of %d bytes in %d second(s) (%s)\n",
Packit 6bd9ab
       i, (int)sizeof(buf), (int)(end - start), strerror(saved_errno));
Packit 6bd9ab
  /* at the very least 4 writes should be OK because they filled the tio buffer */
Packit 6bd9ab
  assert(i >= 4);
Packit 6bd9ab
  /* but at a certain point the writes should have failed */
Packit 6bd9ab
  assert(i < numblocks);
Packit 6bd9ab
  /* since the write timeout is more than a second end time should be bigger
Packit 6bd9ab
     than start time */
Packit 6bd9ab
  assert(end > start);
Packit 6bd9ab
  /* the error should be timeout */
Packit 6bd9ab
  assert(saved_errno == ETIME);
Packit 6bd9ab
  /* close the files */
Packit 6bd9ab
  assertok(tio_close(wfp) != 0); /* fails because of bufferred data */
Packit 6bd9ab
  assertok(fclose(rfp) == 0);
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* the main program... */
Packit 6bd9ab
int main(int UNUSED(argc), char UNUSED(*argv[]))
Packit 6bd9ab
{
Packit 6bd9ab
  /* normal read-writes */
Packit 6bd9ab
  test_blocks(400, 11, 11, 400);
Packit 6bd9ab
  test_blocks(10 * 1024, 11, 10 * 11, 1024);
Packit 6bd9ab
  test_blocks(5 * 1023, 20, 20 * 1023, 5);
Packit 6bd9ab
  /* reader closes file sooner */
Packit 6bd9ab
/*  test_blocks(2 * 6 * 1023, 20, 20 * 1023, 5); */
Packit 6bd9ab
/*  test_blocks(10, 10, 10, 9); */
Packit 6bd9ab
  /* writer closes file sooner */
Packit 6bd9ab
/*  test_blocks(4 * 1023, 20, 20 * 1023, 5); */
Packit 6bd9ab
/*  test_blocks(10, 9, 10, 10); */
Packit 6bd9ab
  /* set tio_mark() and tio_reset() functions */
Packit 6bd9ab
  test_reset();
Packit 6bd9ab
  /* test timeout functionality */
Packit 6bd9ab
  test_timeout_reader();
Packit 6bd9ab
  test_timeout_writer();
Packit 6bd9ab
  return 0;
Packit 6bd9ab
}