int main(int argc, char **argv) { test_state tstate = {0}; nitro_queue_t *q = nitro_queue_new(0, test_state_callback, &tstate); TEST("new non-null", q); nitro_frame_t *hello = nitro_frame_new_copy( "hello", 6); nitro_queue_push(q, hello, 1); TEST("queue went contents", tstate.got_state_change && tstate.state_was == NITRO_QUEUE_STATE_CONTENTS); tstate.got_state_change = 0; nitro_frame_t *back = nitro_queue_pull(q, 1); TEST("got frame back", back == hello); TEST("queue went empty", tstate.got_state_change && tstate.state_was == NITRO_QUEUE_STATE_EMPTY); tstate.got_state_change = 0; /* Ordering */ nitro_frame_t *world = nitro_frame_new_copy( "world", 6); nitro_queue_push(q, hello, 1); nitro_queue_push(q, world, 1); back = nitro_queue_pull(q, 1); TEST("got hello (ordering)", back == hello); back = nitro_queue_pull(q, 1); TEST("got world (ordering)", back == world); nitro_queue_destroy(q); q = nitro_queue_new(0, test_state_callback, &tstate); /* Wrapping */ TEST("pre-wrapping empty queue", nitro_queue_count(q) == 0); TEST("pre-wrapping internal assumption", q->size == 1024); int i; for (i=0; i < 1023; i++) { nitro_frame_t *hcopy = nitro_frame_copy_partial(hello, NULL); nitro_queue_push(q, hcopy, 1); back = nitro_queue_pull(q, 1); assert(back == hcopy); nitro_frame_destroy(back); } nitro_queue_push(q, hello, 1); nitro_queue_push(q, world, 1); TEST("wrapping internals, wrap occurred", q->tail < q->head); back = nitro_queue_pull(q, 1); TEST("got hello (wrapping)", back == hello); back = nitro_queue_pull(q, 1); TEST("got world (wrapping)", back == world); TEST("wrapping internals, wrap back to even", q->tail == q->head); /* Destroy with frames in */ my_frame_data dt = {0}; nitro_frame_destroy(world); world = nitro_frame_new( "hello", 6, my_free, &dt); nitro_queue_push(q, world, 1); TEST("delete outstanding.. not deleted", dt.done == 0); nitro_queue_destroy(q); TEST("post-queue-delete.. frame free", dt.done); nitro_frame_destroy(hello); /* Queue count */ q = nitro_queue_new(0, test_state_callback, &tstate); hello = nitro_frame_new_copy("hello", 6); for (i=0; i < 313; i++) { back = nitro_frame_copy_partial(hello, NULL); nitro_queue_push(q, back, 1); } nitro_frame_destroy(hello); TEST("count basic", nitro_queue_count(q) == 313); /* resize */ nitro_queue_destroy(q); q = nitro_queue_new(0, test_state_callback, &tstate); assert(q->size == 1024); /* get the alignment off */ for (i=0; i < 100; i++) { nitro_queue_push(q, nitro_frame_new_copy((void*)&i, sizeof(int)), 1); } for (i=0; i < 100; i++) { back = nitro_queue_pull(q, 1); nitro_frame_destroy(back); } TEST("resize misalign reset", nitro_queue_count(q) == 0 && q->head > q->q); /* okay, now cause resize */ for (i=0; i < 1050; i++) { nitro_queue_push(q, nitro_frame_new_copy((void*)&i, sizeof(int)), 1); } TEST("was resized", q->size > 1024); for (i=0; i < 1050; i++) { back = nitro_queue_pull(q, 1); if ( *((int*)nitro_frame_data(back)) != i) break; nitro_frame_destroy(back); } TEST("order after resize", i == 1050); nitro_queue_destroy(q); /* Test queue moving */ /* move 0 -> 0 */ q = nitro_queue_new(0, test_state_callback, &tstate); nitro_queue_t *dst = nitro_queue_new(0, test_state_callback, &tstate); nitro_queue_move( q, dst); TEST("move(0->0) src empty", nitro_queue_count(q) == 0); TEST("move(0->0) dest empty", nitro_queue_count(dst) == 0); /* move N -> 0 */ for (i=0; i < 5; i++) { nitro_queue_push(q, nitro_frame_new_copy( (void *)&i, sizeof(int)), 1); } TEST("load 5 into src", nitro_queue_count(q) == 5); nitro_queue_move(q, dst); TEST("move(0->0) src empty", nitro_queue_count(q) == 0); TEST("move(0->0) dest 5", nitro_queue_count(dst) == 5); for (i=0; i < 5; i++) { back = nitro_queue_pull(dst, 1); if ( *((int*)nitro_frame_data(back)) != i) break; nitro_frame_destroy(back); } TEST("order after move", i == 5); nitro_queue_destroy(q); nitro_queue_destroy(dst); /* move with fractional wraparound, ugly copies */ q = nitro_queue_new(0, test_state_callback, &tstate); dst = nitro_queue_new(0, test_state_callback, &tstate); for (i=0; i < 300; i++) { nitro_queue_push(q, nitro_frame_new_copy( (void *)&i, sizeof(int)), 1); } for (i=0; i < 300; i++) { nitro_frame_destroy(nitro_queue_pull(q, 1)); } for (i=0; i < 700; i++) { nitro_queue_push(q, nitro_frame_new_copy( (void *)&i, sizeof(int)), 1); } for (i=0; i < 324; i++) { nitro_queue_push(dst, nitro_frame_new_copy( (void *)&i, sizeof(int)), 1); } for (i=0; i < 324; i++) { nitro_frame_destroy(nitro_queue_pull(dst, 1)); } for (i=0; i < 324; i++) { nitro_queue_push(dst, nitro_frame_new_copy( (void *)&i, sizeof(int)), 1); } TEST("(ugly move) count 700 src", nitro_queue_count(q) == 700); TEST("(ugly move) count 324 dst", nitro_queue_count(dst) == 324); nitro_queue_move(q, dst); TEST("(ugly move post) count 0 src", nitro_queue_count(q) == 0); TEST("(ugly move post) count 1024 dst", nitro_queue_count(dst) == 1024); assert(dst->size == 1024); /* no resizing! */ TEST("(ugly move post) head == tail", dst->head == dst->tail); for (i=0; i < 324; i++) { back = nitro_queue_pull(dst, 1); if ( *((int*)nitro_frame_data(back)) != i) break; nitro_frame_destroy(back); } TEST("(ugly move post) first 324 still there", i == 324); for (i=0; i < 700; i++) { back = nitro_queue_pull(dst, 1); if ( *((int*)nitro_frame_data(back)) != i) break; nitro_frame_destroy(back); } TEST("(ugly move post) appended 700 there", i == 700); TEST("(ugly move post) dst emptied", nitro_queue_count(dst) == 0); nitro_queue_destroy(q); nitro_queue_destroy(dst); /* move with resize */ q = nitro_queue_new(0, test_state_callback, &tstate); dst = nitro_queue_new(0, test_state_callback, &tstate); for (i=0; i < 1000; i++) { nitro_queue_push(q, nitro_frame_new_copy( (void *)&i, sizeof(int)), 1); } for (i=0; i < 324; i++) { nitro_queue_push(dst, nitro_frame_new_copy( (void *)&i, sizeof(int)), 1); } TEST("(resize move) count 1000 src", nitro_queue_count(q) == 1000); TEST("(resize move) count 324 dst", nitro_queue_count(dst) == 324); assert(dst->size == 1024); nitro_queue_move(q, dst); TEST("(resize post-move) size dst is sum", nitro_queue_count(dst) == 1324); assert(dst->size > 1024); for (i=0; i < 324; i++) { back = nitro_queue_pull(dst, 1); if ( *((int*)nitro_frame_data(back)) != i) break; nitro_frame_destroy(back); } TEST("(resize post-move) first 324 still there", i == 324); for (i=0; i < 1000; i++) { back = nitro_queue_pull(dst, 1); if ( *((int*)nitro_frame_data(back)) != i) break; nitro_frame_destroy(back); } TEST("(resize post-move) appended 1000 there", i == 1000); TEST("(resize post-move) dst cleared", nitro_queue_count(dst) == 0); nitro_queue_destroy(q); nitro_queue_destroy(dst); /* Capacity tests */ q = nitro_queue_new(5, test_state_callback, &tstate); for (i=0; i < 5; i++) { nitro_queue_push(q, nitro_frame_new_copy( (void *)&i, sizeof(int)), 1); } double d1 = now_double(); pthread_t t1; pthread_create(&t1, NULL, take_item, (void*)q); nitro_queue_push(q, nitro_frame_new_copy( (void *)&i, sizeof(int)), 1); double d2 = now_double(); TEST("(capacity) got blocked on push", (d2 - d1 > 0.7) && (d2 - d1 < 1.5)); for (i=1; i < 6; i++) { back = nitro_queue_pull(q, 1); if ( *((int*)nitro_frame_data(back)) != i) break; nitro_frame_destroy(back); } TEST("(capacity) have rest", i == 6); TEST("(capacity) emptied", nitro_queue_count(q) == 0); pthread_t t2; d1 = now_double(); pthread_create(&t2, NULL, put_item, (void*)q); back = nitro_queue_pull(q, 1); d2 = now_double(); TEST("(capacity) got blocked on empty pull", (d2 - d1 > 0.7) && (d2 - d1 < 1.5)); TEST("(capacity) empty pull got right frame", *((int*)nitro_frame_data(back)) == 1337); nitro_frame_destroy(back); nitro_queue_destroy(q); void *unused; pthread_join(t1, &unused); pthread_join(t2, &unused); /* Consume */ q = nitro_queue_new(0, test_state_callback, &tstate); gframe = nitro_frame_new_copy("hello", 6); /* Traditional test */ d1 = now_double(); for (i=0; i < CONSUME_COUNT; i++) { nitro_queue_push(q, nitro_frame_copy_partial(gframe, NULL), 1); } d2 = now_double(); char buf[50]; snprintf(buf, 50, "(consume-manual) in %.4f", d2 - d1); TEST(buf, nitro_queue_count(q) == CONSUME_COUNT); nitro_queue_destroy(q); // vs consume i = 0; q = nitro_queue_new(0, test_state_callback, &tstate); d1 = now_double(); nitro_queue_consume(q, make_frames, (void *)&i); d2 = now_double(); snprintf(buf, 50, "(consume-stream) in %.4f", d2 - d1); TEST(buf, nitro_queue_count(q) == CONSUME_COUNT); nitro_queue_destroy(q); nitro_frame_destroy(gframe); /* Write to file */ q = nitro_queue_new(0, test_state_callback, &tstate); for (i=0; i < 50000; i++) { nitro_queue_push(q, nitro_frame_new_copy( "dog", 3), 1); } int ps[2]; int r = pipe(ps); assert(!r); int pread = ps[0]; int pwrite = ps[1]; int flag = 1; r = ioctl(pread, FIONBIO, &flag); assert(r == 0); r = ioctl(pwrite, FIONBIO, &flag); assert(r == 0); int bytes = 0; int total = 0; nitro_frame_t *remain = NULL; pthread_t reader; char out[550000]; pipe_pass pp = {out, pread}; pthread_create(&reader, NULL, pipe_consume, &pp); do { errno = 0; if (bytes > 0) total += bytes; bytes = nitro_queue_fd_write( q, pwrite, remain, &remain); } while (bytes > 0 || errno == EAGAIN || errno == EWOULDBLOCK); if (bytes < 0) { perror("write to pipe:"); assert(bytes == 0); } TEST("(fd write) correct write byte count", total == 550000); void *t_ret; /* wait for reader to finish */ pthread_join(reader, &t_ret); char *ptr = out; nitro_protocol_header target_head = { 1, 0, 0, 0, 3}; for (i=0; i < 50000; i++) { if (memcmp(ptr, &target_head, sizeof(target_head)) || memcmp(ptr + sizeof(target_head), "dog", 3)) { break; } ptr += 11; } TEST("(fd write) read data was correct", ptr == out + 550000); close(pwrite); close(pread); nitro_queue_destroy(q); SUMMARY(0); return 1; }
/* Sinproc_create_queues * ------------------ * * Create the global in queue associated with a socket */ void Sinproc_create_queues(nitro_inproc_socket_t *s) { s->q_recv = nitro_queue_new( s->opt->hwm_in, Sinproc_socket_recv_queue_stat, (void *)s); }