aboutsummaryrefslogtreecommitdiffhomepage
path: root/test/core/support
diff options
context:
space:
mode:
Diffstat (limited to 'test/core/support')
-rw-r--r--test/core/support/cancellable_test.c160
-rw-r--r--test/core/support/cmdline_test.c293
-rw-r--r--test/core/support/histogram_test.c178
-rw-r--r--test/core/support/host_port_test.c72
-rw-r--r--test/core/support/log_test.c47
-rw-r--r--test/core/support/murmur_hash_test.c87
-rw-r--r--test/core/support/slice_buffer_test.c70
-rw-r--r--test/core/support/slice_test.c227
-rw-r--r--test/core/support/string_test.c158
-rw-r--r--test/core/support/sync_test.c451
-rw-r--r--test/core/support/thd_test.c90
-rw-r--r--test/core/support/time_test.c255
12 files changed, 2088 insertions, 0 deletions
diff --git a/test/core/support/cancellable_test.c b/test/core/support/cancellable_test.c
new file mode 100644
index 0000000000..e90c999921
--- /dev/null
+++ b/test/core/support/cancellable_test.c
@@ -0,0 +1,160 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Test of gpr_cancellable. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/time.h>
+#include "test/core/util/test_config.h"
+
+struct test {
+ gpr_mu mu;
+ gpr_cv cv;
+ gpr_event ev;
+ gpr_event done;
+ gpr_cancellable cancel;
+ int n;
+};
+
+/* A thread body. Wait until t->cancel is cancelledm then
+ decrement t->n. If t->n becomes 0, set t->done. */
+static void thd_body(void *v) {
+ struct test *t = v;
+ gpr_mu_lock(&t->mu);
+ while (!gpr_cv_cancellable_wait(&t->cv, &t->mu, gpr_inf_future, &t->cancel)) {
+ }
+ t->n--;
+ if (t->n == 0) {
+ gpr_event_set(&t->done, (void *)1);
+ }
+ gpr_mu_unlock(&t->mu);
+}
+
+static void test(void) {
+ int i;
+ gpr_thd_id thd;
+ struct test t;
+ int n = 1;
+ gpr_timespec interval;
+
+ gpr_mu_init(&t.mu);
+ gpr_cv_init(&t.cv);
+ gpr_event_init(&t.ev);
+ gpr_event_init(&t.done);
+ gpr_cancellable_init(&t.cancel);
+
+ /* A gpr_cancellable starts not cancelled. */
+ GPR_ASSERT(!gpr_cancellable_is_cancelled(&t.cancel));
+
+ /* Test timeout on event wait for uncancelled gpr_cancellable */
+ interval = gpr_now();
+ gpr_event_cancellable_wait(
+ &t.ev, gpr_time_add(gpr_now(), gpr_time_from_micros(1000000)), &t.cancel);
+ interval = gpr_time_sub(gpr_now(), interval);
+ GPR_ASSERT(gpr_time_cmp(interval, gpr_time_from_micros(500000)) >= 0);
+ GPR_ASSERT(gpr_time_cmp(gpr_time_from_micros(2000000), interval) >= 0);
+
+ /* Test timeout on cv wait for uncancelled gpr_cancellable */
+ gpr_mu_lock(&t.mu);
+ interval = gpr_now();
+ while (!gpr_cv_cancellable_wait(
+ &t.cv, &t.mu,
+ gpr_time_add(gpr_now(), gpr_time_from_micros(1000000)),
+ &t.cancel)) {
+ }
+ interval = gpr_time_sub(gpr_now(), interval);
+ GPR_ASSERT(gpr_time_cmp(interval, gpr_time_from_micros(500000)) >= 0);
+ GPR_ASSERT(gpr_time_cmp(gpr_time_from_micros(2000000), interval) >= 0);
+ gpr_mu_unlock(&t.mu);
+
+ /* Create some threads. They all wait until cancelled; the last to finish
+ sets t.done. */
+ t.n = n;
+ for (i = 0; i != n; i++) {
+ GPR_ASSERT(gpr_thd_new(&thd, &thd_body, &t, NULL));
+ }
+ /* Check that t.cancel still is not cancelled. */
+ GPR_ASSERT(!gpr_cancellable_is_cancelled(&t.cancel));
+
+ /* Wait a second, and check that no threads have finished waiting. */
+ gpr_mu_lock(&t.mu);
+ gpr_cv_wait(&t.cv, &t.mu,
+ gpr_time_add(gpr_now(), gpr_time_from_micros(1000000)));
+ GPR_ASSERT(t.n == n);
+ gpr_mu_unlock(&t.mu);
+
+ /* Check that t.cancel still is not cancelled, but when
+ cancelled it retports that it is cacncelled. */
+ GPR_ASSERT(!gpr_cancellable_is_cancelled(&t.cancel));
+ gpr_cancellable_cancel(&t.cancel);
+ GPR_ASSERT(gpr_cancellable_is_cancelled(&t.cancel));
+
+ /* Wait for threads to finish. */
+ gpr_event_wait(&t.done, gpr_inf_future);
+ GPR_ASSERT(t.n == 0);
+
+ /* Test timeout on cv wait for cancelled gpr_cancellable */
+ gpr_mu_lock(&t.mu);
+ interval = gpr_now();
+ while (!gpr_cv_cancellable_wait(
+ &t.cv, &t.mu,
+ gpr_time_add(gpr_now(), gpr_time_from_micros(1000000)),
+ &t.cancel)) {
+ }
+ interval = gpr_time_sub(gpr_now(), interval);
+ GPR_ASSERT(gpr_time_cmp(gpr_time_from_micros(100000), interval) >= 0);
+ gpr_mu_unlock(&t.mu);
+
+ /* Test timeout on event wait for cancelled gpr_cancellable */
+ interval = gpr_now();
+ gpr_event_cancellable_wait(
+ &t.ev, gpr_time_add(gpr_now(), gpr_time_from_micros(1000000)), &t.cancel);
+ interval = gpr_time_sub(gpr_now(), interval);
+ GPR_ASSERT(gpr_time_cmp(gpr_time_from_micros(100000), interval) >= 0);
+
+ gpr_mu_destroy(&t.mu);
+ gpr_cv_destroy(&t.cv);
+ gpr_cancellable_destroy(&t.cancel);
+}
+
+/* ------------------------------------------------- */
+
+int main(int argc, char *argv[]) {
+ grpc_test_init(argc, argv);
+ test();
+ return 0;
+}
diff --git a/test/core/support/cmdline_test.c b/test/core/support/cmdline_test.c
new file mode 100644
index 0000000000..91035a662b
--- /dev/null
+++ b/test/core/support/cmdline_test.c
@@ -0,0 +1,293 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/cmdline.h>
+
+#include <string.h>
+
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+#include "test/core/util/test_config.h"
+
+#define LOG_TEST() gpr_log(GPR_INFO, "%s", __FUNCTION__)
+
+static void test_simple_int() {
+ int x = 1;
+ gpr_cmdline *cl;
+ char *args[] = {(char *)__FUNCTION__, "-foo", "3"};
+
+ LOG_TEST();
+
+ cl = gpr_cmdline_create(NULL);
+ gpr_cmdline_add_int(cl, "foo", NULL, &x);
+ GPR_ASSERT(x == 1);
+ gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+ GPR_ASSERT(x == 3);
+ gpr_cmdline_destroy(cl);
+}
+
+static void test_eq_int() {
+ int x = 1;
+ gpr_cmdline *cl;
+ char *args[] = {(char *)__FUNCTION__, "-foo=3"};
+
+ LOG_TEST();
+
+ cl = gpr_cmdline_create(NULL);
+ gpr_cmdline_add_int(cl, "foo", NULL, &x);
+ GPR_ASSERT(x == 1);
+ gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+ GPR_ASSERT(x == 3);
+ gpr_cmdline_destroy(cl);
+}
+
+static void test_2dash_int() {
+ int x = 1;
+ gpr_cmdline *cl;
+ char *args[] = {(char *)__FUNCTION__, "--foo", "3"};
+
+ LOG_TEST();
+
+ cl = gpr_cmdline_create(NULL);
+ gpr_cmdline_add_int(cl, "foo", NULL, &x);
+ GPR_ASSERT(x == 1);
+ gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+ GPR_ASSERT(x == 3);
+ gpr_cmdline_destroy(cl);
+}
+
+static void test_2dash_eq_int() {
+ int x = 1;
+ gpr_cmdline *cl;
+ char *args[] = {(char *)__FUNCTION__, "--foo=3"};
+
+ LOG_TEST();
+
+ cl = gpr_cmdline_create(NULL);
+ gpr_cmdline_add_int(cl, "foo", NULL, &x);
+ GPR_ASSERT(x == 1);
+ gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+ GPR_ASSERT(x == 3);
+ gpr_cmdline_destroy(cl);
+}
+
+static void test_simple_string() {
+ char *x = NULL;
+ gpr_cmdline *cl;
+ char *args[] = {(char *)__FUNCTION__, "-foo", "3"};
+
+ LOG_TEST();
+
+ cl = gpr_cmdline_create(NULL);
+ gpr_cmdline_add_string(cl, "foo", NULL, &x);
+ GPR_ASSERT(x == NULL);
+ gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+ GPR_ASSERT(0 == strcmp(x, "3"));
+ gpr_cmdline_destroy(cl);
+}
+
+static void test_eq_string() {
+ char *x = NULL;
+ gpr_cmdline *cl;
+ char *args[] = {(char *)__FUNCTION__, "-foo=3"};
+
+ LOG_TEST();
+
+ cl = gpr_cmdline_create(NULL);
+ gpr_cmdline_add_string(cl, "foo", NULL, &x);
+ GPR_ASSERT(x == NULL);
+ gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+ GPR_ASSERT(0 == strcmp(x, "3"));
+ gpr_cmdline_destroy(cl);
+}
+
+static void test_2dash_string() {
+ char *x = NULL;
+ gpr_cmdline *cl;
+ char *args[] = {(char *)__FUNCTION__, "--foo", "3"};
+
+ LOG_TEST();
+
+ cl = gpr_cmdline_create(NULL);
+ gpr_cmdline_add_string(cl, "foo", NULL, &x);
+ GPR_ASSERT(x == NULL);
+ gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+ GPR_ASSERT(0 == strcmp(x, "3"));
+ gpr_cmdline_destroy(cl);
+}
+
+static void test_2dash_eq_string() {
+ char *x = NULL;
+ gpr_cmdline *cl;
+ char *args[] = {(char *)__FUNCTION__, "--foo=3"};
+
+ LOG_TEST();
+
+ cl = gpr_cmdline_create(NULL);
+ gpr_cmdline_add_string(cl, "foo", NULL, &x);
+ GPR_ASSERT(x == NULL);
+ gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+ GPR_ASSERT(0 == strcmp(x, "3"));
+ gpr_cmdline_destroy(cl);
+}
+
+static void test_flag_on() {
+ int x = 2;
+ gpr_cmdline *cl;
+ char *args[] = {(char *)__FUNCTION__, "--foo"};
+
+ LOG_TEST();
+
+ cl = gpr_cmdline_create(NULL);
+ gpr_cmdline_add_flag(cl, "foo", NULL, &x);
+ GPR_ASSERT(x == 2);
+ gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+ GPR_ASSERT(x == 1);
+ gpr_cmdline_destroy(cl);
+}
+
+static void test_flag_no() {
+ int x = 2;
+ gpr_cmdline *cl;
+ char *args[] = {(char *)__FUNCTION__, "--no-foo"};
+
+ LOG_TEST();
+
+ cl = gpr_cmdline_create(NULL);
+ gpr_cmdline_add_flag(cl, "foo", NULL, &x);
+ GPR_ASSERT(x == 2);
+ gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+ GPR_ASSERT(x == 0);
+ gpr_cmdline_destroy(cl);
+}
+
+static void test_flag_val_1() {
+ int x = 2;
+ gpr_cmdline *cl;
+ char *args[] = {(char *)__FUNCTION__, "--foo=1"};
+
+ LOG_TEST();
+
+ cl = gpr_cmdline_create(NULL);
+ gpr_cmdline_add_flag(cl, "foo", NULL, &x);
+ GPR_ASSERT(x == 2);
+ gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+ GPR_ASSERT(x == 1);
+ gpr_cmdline_destroy(cl);
+}
+
+static void test_flag_val_0() {
+ int x = 2;
+ gpr_cmdline *cl;
+ char *args[] = {(char *)__FUNCTION__, "--foo=0"};
+
+ LOG_TEST();
+
+ cl = gpr_cmdline_create(NULL);
+ gpr_cmdline_add_flag(cl, "foo", NULL, &x);
+ GPR_ASSERT(x == 2);
+ gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+ GPR_ASSERT(x == 0);
+ gpr_cmdline_destroy(cl);
+}
+
+static void test_flag_val_true() {
+ int x = 2;
+ gpr_cmdline *cl;
+ char *args[] = {(char *)__FUNCTION__, "--foo=true"};
+
+ LOG_TEST();
+
+ cl = gpr_cmdline_create(NULL);
+ gpr_cmdline_add_flag(cl, "foo", NULL, &x);
+ GPR_ASSERT(x == 2);
+ gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+ GPR_ASSERT(x == 1);
+ gpr_cmdline_destroy(cl);
+}
+
+static void test_flag_val_false() {
+ int x = 2;
+ gpr_cmdline *cl;
+ char *args[] = {(char *)__FUNCTION__, "--foo=false"};
+
+ LOG_TEST();
+
+ cl = gpr_cmdline_create(NULL);
+ gpr_cmdline_add_flag(cl, "foo", NULL, &x);
+ GPR_ASSERT(x == 2);
+ gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+ GPR_ASSERT(x == 0);
+ gpr_cmdline_destroy(cl);
+}
+
+static void test_many() {
+ char *str = NULL;
+ int x = 0;
+ int flag = 2;
+ gpr_cmdline *cl;
+
+ char *args[] = {(char *)__FUNCTION__, "--str", "hello", "-x=4", "-no-flag"};
+
+ LOG_TEST();
+
+ cl = gpr_cmdline_create(NULL);
+ gpr_cmdline_add_string(cl, "str", NULL, &str);
+ gpr_cmdline_add_int(cl, "x", NULL, &x);
+ gpr_cmdline_add_flag(cl, "flag", NULL, &flag);
+ gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+ GPR_ASSERT(x == 4);
+ GPR_ASSERT(0 == strcmp(str, "hello"));
+ GPR_ASSERT(flag == 0);
+ gpr_cmdline_destroy(cl);
+}
+
+int main(int argc, char **argv) {
+ grpc_test_init(argc, argv);
+ test_simple_int();
+ test_eq_int();
+ test_2dash_int();
+ test_2dash_eq_int();
+ test_simple_string();
+ test_eq_string();
+ test_2dash_string();
+ test_2dash_eq_string();
+ test_flag_on();
+ test_flag_no();
+ test_flag_val_1();
+ test_flag_val_0();
+ test_flag_val_true();
+ test_flag_val_false();
+ test_many();
+ return 0;
+}
diff --git a/test/core/support/histogram_test.c b/test/core/support/histogram_test.c
new file mode 100644
index 0000000000..3b5fd73047
--- /dev/null
+++ b/test/core/support/histogram_test.c
@@ -0,0 +1,178 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/histogram.h>
+#include <grpc/support/log.h>
+
+#define LOG_TEST() gpr_log(GPR_INFO, "%s", __FUNCTION__);
+
+static void test_no_op() {
+ gpr_histogram_destroy(gpr_histogram_create(0.01, 60e9));
+}
+
+static void expect_percentile(gpr_histogram *h, double percentile,
+ double min_expect, double max_expect) {
+ double got = gpr_histogram_percentile(h, percentile);
+ gpr_log(GPR_INFO, "@%f%%, expect %f <= %f <= %f", percentile, min_expect, got,
+ max_expect);
+ GPR_ASSERT(min_expect <= got);
+ GPR_ASSERT(got <= max_expect);
+}
+
+static void test_simple() {
+ gpr_histogram *h;
+
+ LOG_TEST();
+
+ h = gpr_histogram_create(0.01, 60e9);
+ gpr_histogram_add(h, 10000);
+ gpr_histogram_add(h, 10000);
+ gpr_histogram_add(h, 11000);
+ gpr_histogram_add(h, 11000);
+
+ expect_percentile(h, 50, 10001, 10999);
+ GPR_ASSERT(gpr_histogram_mean(h) == 10500);
+
+ gpr_histogram_destroy(h);
+}
+
+static void test_percentile() {
+ gpr_histogram *h;
+ double last;
+ double i;
+ double cur;
+
+ LOG_TEST();
+
+ h = gpr_histogram_create(0.05, 1e9);
+ gpr_histogram_add(h, 2.5);
+ gpr_histogram_add(h, 2.5);
+ gpr_histogram_add(h, 8);
+ gpr_histogram_add(h, 4);
+
+ GPR_ASSERT(gpr_histogram_count(h) == 4);
+ GPR_ASSERT(gpr_histogram_minimum(h) == 2.5);
+ GPR_ASSERT(gpr_histogram_maximum(h) == 8);
+ GPR_ASSERT(gpr_histogram_sum(h) == 17);
+ GPR_ASSERT(gpr_histogram_sum_of_squares(h) == 92.5);
+ GPR_ASSERT(gpr_histogram_mean(h) == 4.25);
+ GPR_ASSERT(gpr_histogram_variance(h) == 5.0625);
+ GPR_ASSERT(gpr_histogram_stddev(h) == 2.25);
+
+ expect_percentile(h, -10, 2.5, 2.5);
+ expect_percentile(h, 0, 2.5, 2.5);
+ expect_percentile(h, 12.5, 2.5, 2.5);
+ expect_percentile(h, 25, 2.5, 2.5);
+ expect_percentile(h, 37.5, 2.5, 2.8);
+ expect_percentile(h, 50, 3.0, 3.5);
+ expect_percentile(h, 62.5, 3.5, 4.5);
+ expect_percentile(h, 75, 5, 7.9);
+ expect_percentile(h, 100, 8, 8);
+ expect_percentile(h, 110, 8, 8);
+
+ /* test monotonicity */
+ last = 0.0;
+ for (i = 0; i < 100.0; i += 0.01) {
+ cur = gpr_histogram_percentile(h, i);
+ GPR_ASSERT(cur >= last);
+ last = cur;
+ }
+
+ gpr_histogram_destroy(h);
+}
+
+static void test_merge() {
+ gpr_histogram *h1, *h2;
+ double last;
+ double i;
+ double cur;
+
+ LOG_TEST();
+
+ h1 = gpr_histogram_create(0.05, 1e9);
+ gpr_histogram_add(h1, 2.5);
+ gpr_histogram_add(h1, 2.5);
+ gpr_histogram_add(h1, 8);
+ gpr_histogram_add(h1, 4);
+
+ h2 = gpr_histogram_create(0.01, 1e9);
+ GPR_ASSERT(gpr_histogram_merge(h1, h2) == 0);
+ gpr_histogram_destroy(h2);
+
+ h2 = gpr_histogram_create(0.05, 1e10);
+ GPR_ASSERT(gpr_histogram_merge(h1, h2) == 0);
+ gpr_histogram_destroy(h2);
+
+ h2 = gpr_histogram_create(0.05, 1e9);
+ GPR_ASSERT(gpr_histogram_merge(h1, h2) == 1);
+ GPR_ASSERT(gpr_histogram_count(h1) == 4);
+ GPR_ASSERT(gpr_histogram_minimum(h1) == 2.5);
+ GPR_ASSERT(gpr_histogram_maximum(h1) == 8);
+ GPR_ASSERT(gpr_histogram_sum(h1) == 17);
+ GPR_ASSERT(gpr_histogram_sum_of_squares(h1) == 92.5);
+ GPR_ASSERT(gpr_histogram_mean(h1) == 4.25);
+ GPR_ASSERT(gpr_histogram_variance(h1) == 5.0625);
+ GPR_ASSERT(gpr_histogram_stddev(h1) == 2.25);
+ gpr_histogram_destroy(h2);
+
+ h2 = gpr_histogram_create(0.05, 1e9);
+ gpr_histogram_add(h2, 7.0);
+ gpr_histogram_add(h2, 17.0);
+ gpr_histogram_add(h2, 1.0);
+ GPR_ASSERT(gpr_histogram_merge(h1, h2) == 1);
+ GPR_ASSERT(gpr_histogram_count(h1) == 7);
+ GPR_ASSERT(gpr_histogram_minimum(h1) == 1.0);
+ GPR_ASSERT(gpr_histogram_maximum(h1) == 17.0);
+ GPR_ASSERT(gpr_histogram_sum(h1) == 42.0);
+ GPR_ASSERT(gpr_histogram_sum_of_squares(h1) == 431.5);
+ GPR_ASSERT(gpr_histogram_mean(h1) == 6.0);
+
+ /* test monotonicity */
+ last = 0.0;
+ for (i = 0; i < 100.0; i += 0.01) {
+ cur = gpr_histogram_percentile(h1, i);
+ GPR_ASSERT(cur >= last);
+ last = cur;
+ }
+
+ gpr_histogram_destroy(h1);
+ gpr_histogram_destroy(h2);
+}
+
+int main(void) {
+ test_no_op();
+ test_simple();
+ test_percentile();
+ test_merge();
+ return 0;
+}
diff --git a/test/core/support/host_port_test.c b/test/core/support/host_port_test.c
new file mode 100644
index 0000000000..d1553c514e
--- /dev/null
+++ b/test/core/support/host_port_test.c
@@ -0,0 +1,72 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+#include "test/core/util/test_config.h"
+
+static void join_host_port_expect(const char *host, int port,
+ const char *expected) {
+ char *buf;
+ int len;
+ len = gpr_join_host_port(&buf, host, port);
+ GPR_ASSERT(strlen(expected) == len);
+ GPR_ASSERT(strcmp(expected, buf) == 0);
+ gpr_free(buf);
+}
+
+static void test_join_host_port() {
+ join_host_port_expect("foo", 101, "foo:101");
+ join_host_port_expect("", 102, ":102");
+ join_host_port_expect("1::2", 103, "[1::2]:103");
+ join_host_port_expect("[::1]", 104, "[::1]:104");
+}
+
+/* Garbage in, garbage out. */
+static void test_join_host_port_garbage() {
+ join_host_port_expect("[foo]", 105, "[foo]:105");
+ join_host_port_expect("[::", 106, "[:::106");
+ join_host_port_expect("::]", 107, "[::]]:107");
+}
+
+int main(int argc, char **argv) {
+ grpc_test_init(argc, argv);
+
+ test_join_host_port();
+ test_join_host_port_garbage();
+
+ return 0;
+}
diff --git a/test/core/support/log_test.c b/test/core/support/log_test.c
new file mode 100644
index 0000000000..fbb7c21ffc
--- /dev/null
+++ b/test/core/support/log_test.c
@@ -0,0 +1,47 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/log.h>
+#include "test/core/util/test_config.h"
+
+int main(int argc, char **argv) {
+ grpc_test_init(argc, argv);
+ /* test logging at various verbosity levels */
+ gpr_log(GPR_DEBUG, "%s", "hello world");
+ gpr_log(GPR_INFO, "%s", "hello world");
+ gpr_log(GPR_ERROR, "%s", "hello world");
+ /* should succeed */
+ GPR_ASSERT(1);
+ /* TODO(ctiller): should we add a GPR_ASSERT failure test here */
+ return 0;
+}
diff --git a/test/core/support/murmur_hash_test.c b/test/core/support/murmur_hash_test.c
new file mode 100644
index 0000000000..366bcb20bf
--- /dev/null
+++ b/test/core/support/murmur_hash_test.c
@@ -0,0 +1,87 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/support/murmur_hash.h"
+#include <grpc/support/log.h>
+#include "test/core/util/test_config.h"
+
+#include <string.h>
+
+typedef gpr_uint32 (*hash_func)(const void *key, size_t len, gpr_uint32 seed);
+
+/* From smhasher:
+ This should hopefully be a thorough and uambiguous test of whether a hash
+ is correctly implemented on a given platform */
+
+static void verification_test(hash_func hash, gpr_uint32 expected) {
+ gpr_uint8 key[256];
+ gpr_uint32 hashes[256];
+ gpr_uint32 final = 0;
+ int i;
+
+ memset(key, 0, sizeof(key));
+ memset(hashes, 0, sizeof(hashes));
+
+ /* Hash keys of the form {0}, {0,1}, {0,1,2}... up to N=255,using 256-N as
+ the seed */
+
+ for (i = 0; i < 256; i++) {
+ key[i] = (uint8_t)i;
+ hashes[i] = hash(key, i, 256 - i);
+ }
+
+ /* Then hash the result array */
+
+ final = hash(hashes, sizeof(hashes), 0);
+
+ /* The first four bytes of that hash, interpreted as a little-endian integer,
+ is our
+ verification value */
+
+ if (expected != final) {
+ gpr_log(GPR_INFO, "Verification value 0x%08X : Failed! (Expected 0x%08x)",
+ final, expected);
+ abort();
+ } else {
+ gpr_log(GPR_INFO, "Verification value 0x%08X : Passed!", final);
+ }
+}
+
+int main(int argc, char **argv) {
+ grpc_test_init(argc, argv);
+ /* basic tests to verify that things don't crash */
+ gpr_murmur_hash3("", 0, 0);
+ gpr_murmur_hash3("xyz", 3, 0);
+ verification_test(gpr_murmur_hash3, 0xB0F57EE3);
+ return 0;
+}
diff --git a/test/core/support/slice_buffer_test.c b/test/core/support/slice_buffer_test.c
new file mode 100644
index 0000000000..030d1d4249
--- /dev/null
+++ b/test/core/support/slice_buffer_test.c
@@ -0,0 +1,70 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/log.h>
+#include <grpc/support/slice_buffer.h>
+#include "test/core/util/test_config.h"
+
+int main(int argc, char **argv) {
+ gpr_slice_buffer buf;
+ gpr_slice aaa = gpr_slice_from_copied_string("aaa");
+ gpr_slice bb = gpr_slice_from_copied_string("bb");
+ size_t i;
+
+ grpc_test_init(argc, argv);
+ gpr_slice_buffer_init(&buf);
+ for (i = 0; i < 10; i++) {
+ gpr_slice_ref(aaa);
+ gpr_slice_ref(bb);
+ gpr_slice_buffer_add(&buf, aaa);
+ gpr_slice_buffer_add(&buf, bb);
+ }
+ GPR_ASSERT(buf.count > 0);
+ GPR_ASSERT(buf.length == 50);
+ gpr_slice_buffer_reset_and_unref(&buf);
+ GPR_ASSERT(buf.count == 0);
+ GPR_ASSERT(buf.length == 0);
+ for (i = 0; i < 10; i++) {
+ gpr_slice_ref(aaa);
+ gpr_slice_ref(bb);
+ gpr_slice_buffer_add(&buf, aaa);
+ gpr_slice_buffer_add(&buf, bb);
+ }
+ GPR_ASSERT(buf.count > 0);
+ GPR_ASSERT(buf.length == 50);
+ gpr_slice_unref(aaa);
+ gpr_slice_unref(bb);
+ gpr_slice_buffer_destroy(&buf);
+
+ return 0;
+}
diff --git a/test/core/support/slice_test.c b/test/core/support/slice_test.c
new file mode 100644
index 0000000000..40440344c0
--- /dev/null
+++ b/test/core/support/slice_test.c
@@ -0,0 +1,227 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/slice.h>
+
+#include <string.h>
+
+#include <grpc/support/log.h>
+#include "test/core/util/test_config.h"
+
+#define LOG_TEST_NAME() gpr_log(GPR_INFO, "%s", __FUNCTION__);
+
+static void test_slice_malloc_returns_something_sensible() {
+ /* Calls gpr_slice_create for various lengths and verifies the internals for
+ consistency. */
+ size_t length;
+ size_t i;
+ gpr_slice slice;
+
+ LOG_TEST_NAME();
+
+ for (length = 0; length <= 1024; length++) {
+ slice = gpr_slice_malloc(length);
+ /* If there is a length, slice.data must be non-NULL. If length is zero
+ we don't care. */
+ if (length) {
+ GPR_ASSERT(GPR_SLICE_START_PTR(slice));
+ }
+ /* Returned slice length must be what was requested. */
+ GPR_ASSERT(GPR_SLICE_LENGTH(slice) == length);
+ /* If the slice has a refcount, it must be destroyable. */
+ if (slice.refcount) {
+ GPR_ASSERT(slice.refcount->ref != NULL);
+ GPR_ASSERT(slice.refcount->unref != NULL);
+ }
+ /* We must be able to write to every byte of the data */
+ for (i = 0; i < length; i++) {
+ GPR_SLICE_START_PTR(slice)[i] = (char)i;
+ }
+ /* And finally we must succeed in destroying the slice */
+ gpr_slice_unref(slice);
+ }
+}
+
+static void do_nothing(void *ignored) {}
+
+static void test_slice_new_returns_something_sensible() {
+ gpr_uint8 x;
+
+ gpr_slice slice = gpr_slice_new(&x, 1, do_nothing);
+ GPR_ASSERT(slice.refcount);
+ GPR_ASSERT(slice.data.refcounted.bytes == &x);
+ GPR_ASSERT(slice.data.refcounted.length == 1);
+ gpr_slice_unref(slice);
+}
+
+static int do_nothing_with_len_1_calls = 0;
+
+static void do_nothing_with_len_1(void *ignored, size_t len) {
+ GPR_ASSERT(len == 1);
+ do_nothing_with_len_1_calls++;
+}
+
+static void test_slice_new_with_len_returns_something_sensible() {
+ gpr_uint8 x;
+
+ gpr_slice slice = gpr_slice_new_with_len(&x, 1, do_nothing_with_len_1);
+ GPR_ASSERT(slice.refcount);
+ GPR_ASSERT(slice.data.refcounted.bytes == &x);
+ GPR_ASSERT(slice.data.refcounted.length == 1);
+ GPR_ASSERT(do_nothing_with_len_1_calls == 0);
+ gpr_slice_unref(slice);
+ GPR_ASSERT(do_nothing_with_len_1_calls == 1);
+}
+
+static void test_slice_sub_works(int length) {
+ gpr_slice slice;
+ gpr_slice sub;
+ int i, j, k;
+
+ LOG_TEST_NAME();
+ gpr_log(GPR_INFO, "length=%d", length);
+
+ /* Create a slice in which each byte is equal to the distance from it to the
+ beginning of the slice. */
+ slice = gpr_slice_malloc(length);
+ for (i = 0; i < length; i++) {
+ GPR_SLICE_START_PTR(slice)[i] = i;
+ }
+
+ /* Ensure that for all subsets length is correct and that we start on the
+ correct byte. Additionally check that no copies were made. */
+ for (i = 0; i < length; i++) {
+ for (j = i; j < length; j++) {
+ sub = gpr_slice_sub(slice, i, j);
+ GPR_ASSERT(GPR_SLICE_LENGTH(sub) == j - i);
+ for (k = 0; k < j - i; k++) {
+ GPR_ASSERT(GPR_SLICE_START_PTR(sub)[k] == (gpr_uint8)(i + k));
+ }
+ gpr_slice_unref(sub);
+ }
+ }
+ gpr_slice_unref(slice);
+}
+
+static void check_head_tail(gpr_slice slice, gpr_slice head, gpr_slice tail) {
+ GPR_ASSERT(GPR_SLICE_LENGTH(slice) ==
+ GPR_SLICE_LENGTH(head) + GPR_SLICE_LENGTH(tail));
+ GPR_ASSERT(0 == memcmp(GPR_SLICE_START_PTR(slice), GPR_SLICE_START_PTR(head),
+ GPR_SLICE_LENGTH(head)));
+ GPR_ASSERT(0 == memcmp(GPR_SLICE_START_PTR(slice) + GPR_SLICE_LENGTH(head),
+ GPR_SLICE_START_PTR(tail), GPR_SLICE_LENGTH(tail)));
+}
+
+static void test_slice_split_head_works(int length) {
+ gpr_slice slice;
+ gpr_slice head, tail;
+ int i;
+
+ LOG_TEST_NAME();
+ gpr_log(GPR_INFO, "length=%d", length);
+
+ /* Create a slice in which each byte is equal to the distance from it to the
+ beginning of the slice. */
+ slice = gpr_slice_malloc(length);
+ for (i = 0; i < length; i++) {
+ GPR_SLICE_START_PTR(slice)[i] = i;
+ }
+
+ /* Ensure that for all subsets length is correct and that we start on the
+ correct byte. Additionally check that no copies were made. */
+ for (i = 0; i < length; i++) {
+ tail = gpr_slice_ref(slice);
+ head = gpr_slice_split_head(&tail, i);
+ check_head_tail(slice, head, tail);
+ gpr_slice_unref(tail);
+ gpr_slice_unref(head);
+ }
+
+ gpr_slice_unref(slice);
+}
+
+static void test_slice_split_tail_works(int length) {
+ gpr_slice slice;
+ gpr_slice head, tail;
+ int i;
+
+ LOG_TEST_NAME();
+ gpr_log(GPR_INFO, "length=%d", length);
+
+ /* Create a slice in which each byte is equal to the distance from it to the
+ beginning of the slice. */
+ slice = gpr_slice_malloc(length);
+ for (i = 0; i < length; i++) {
+ GPR_SLICE_START_PTR(slice)[i] = i;
+ }
+
+ /* Ensure that for all subsets length is correct and that we start on the
+ correct byte. Additionally check that no copies were made. */
+ for (i = 0; i < length; i++) {
+ head = gpr_slice_ref(slice);
+ tail = gpr_slice_split_tail(&head, i);
+ check_head_tail(slice, head, tail);
+ gpr_slice_unref(tail);
+ gpr_slice_unref(head);
+ }
+
+ gpr_slice_unref(slice);
+}
+
+static void test_slice_from_copied_string_works() {
+ static const char *text = "HELLO WORLD!";
+ gpr_slice slice;
+
+ LOG_TEST_NAME();
+
+ slice = gpr_slice_from_copied_string(text);
+ GPR_ASSERT(strlen(text) == GPR_SLICE_LENGTH(slice));
+ GPR_ASSERT(0 ==
+ memcmp(text, GPR_SLICE_START_PTR(slice), GPR_SLICE_LENGTH(slice)));
+ gpr_slice_unref(slice);
+}
+
+int main(int argc, char **argv) {
+ int length;
+ grpc_test_init(argc, argv);
+ test_slice_malloc_returns_something_sensible();
+ test_slice_new_returns_something_sensible();
+ test_slice_new_with_len_returns_something_sensible();
+ for (length = 0; length < 128; length++) {
+ test_slice_sub_works(length);
+ test_slice_split_head_works(length);
+ test_slice_split_tail_works(length);
+ }
+ test_slice_from_copied_string_works();
+ return 0;
+}
diff --git a/test/core/support/string_test.c b/test/core/support/string_test.c
new file mode 100644
index 0000000000..1e8039b1e8
--- /dev/null
+++ b/test/core/support/string_test.c
@@ -0,0 +1,158 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/string.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+#include "test/core/util/test_config.h"
+
+#define LOG_TEST_NAME() gpr_log(GPR_INFO, "%s", __FUNCTION__)
+
+static void test_strdup() {
+ static const char *src1 = "hello world";
+ char *dst1;
+
+ LOG_TEST_NAME();
+
+ dst1 = gpr_strdup(src1);
+ GPR_ASSERT(0 == strcmp(src1, dst1));
+ gpr_free(dst1);
+
+ GPR_ASSERT(NULL == gpr_strdup(NULL));
+}
+
+static void expect_hexdump(const char *buf, size_t len, gpr_uint32 flags,
+ const char *result) {
+ char *got = gpr_hexdump(buf, len, flags);
+ GPR_ASSERT(0 == strcmp(got, result));
+ gpr_free(got);
+}
+
+static void test_hexdump() {
+ LOG_TEST_NAME();
+ expect_hexdump("\x01", 1, 0, "01");
+ expect_hexdump("\x01", 1, GPR_HEXDUMP_PLAINTEXT, "01 '.'");
+ expect_hexdump("\x01\x02", 2, 0, "01 02");
+ expect_hexdump("\x01\x23\x45\x67\x89\xab\xcd\xef", 8, 0,
+ "01 23 45 67 89 ab cd ef");
+ expect_hexdump("ab", 2, GPR_HEXDUMP_PLAINTEXT, "61 62 'ab'");
+}
+
+static void test_pu32_fail(const char *s) {
+ gpr_uint32 out;
+ GPR_ASSERT(!gpr_parse_bytes_to_uint32(s, strlen(s), &out));
+}
+
+static void test_pu32_succeed(const char *s, gpr_uint32 want) {
+ gpr_uint32 out;
+ GPR_ASSERT(gpr_parse_bytes_to_uint32(s, strlen(s), &out));
+ GPR_ASSERT(out == want);
+}
+
+static void test_parse_uint32() {
+ LOG_TEST_NAME();
+
+ test_pu32_fail("-1");
+ test_pu32_fail("a");
+ test_pu32_fail("");
+ test_pu32_succeed("0", 0);
+ test_pu32_succeed("1", 1);
+ test_pu32_succeed("2", 2);
+ test_pu32_succeed("3", 3);
+ test_pu32_succeed("4", 4);
+ test_pu32_succeed("5", 5);
+ test_pu32_succeed("6", 6);
+ test_pu32_succeed("7", 7);
+ test_pu32_succeed("8", 8);
+ test_pu32_succeed("9", 9);
+ test_pu32_succeed("10", 10);
+ test_pu32_succeed("11", 11);
+ test_pu32_succeed("12", 12);
+ test_pu32_succeed("13", 13);
+ test_pu32_succeed("14", 14);
+ test_pu32_succeed("15", 15);
+ test_pu32_succeed("16", 16);
+ test_pu32_succeed("17", 17);
+ test_pu32_succeed("18", 18);
+ test_pu32_succeed("19", 19);
+ test_pu32_succeed("1234567890", 1234567890);
+ test_pu32_succeed("4294967295", 4294967295u);
+ test_pu32_fail("4294967296");
+ test_pu32_fail("4294967297");
+ test_pu32_fail("4294967298");
+ test_pu32_fail("4294967299");
+}
+
+static void test_asprintf() {
+ char *buf;
+ int i, j;
+
+ LOG_TEST_NAME();
+
+ /* Print an empty string. */
+ GPR_ASSERT(gpr_asprintf(&buf, "") == 0);
+ GPR_ASSERT(buf[0] == '\0');
+ gpr_free(buf);
+
+ /* Print an invalid format. */
+ GPR_ASSERT(gpr_asprintf(&buf, "%") == -1);
+ GPR_ASSERT(buf == NULL);
+
+ /* Print strings of various lengths. */
+ for (i = 1; i < 100; i++) {
+ GPR_ASSERT(gpr_asprintf(&buf, "%0*d", i, 1) == i);
+
+ /* The buffer should resemble "000001\0". */
+ for (j = 0; j < i - 2; j++) {
+ GPR_ASSERT(buf[j] == '0');
+ }
+ GPR_ASSERT(buf[i - 1] == '1');
+ GPR_ASSERT(buf[i] == '\0');
+ gpr_free(buf);
+ }
+}
+
+int main(int argc, char **argv) {
+ grpc_test_init(argc, argv);
+ test_strdup();
+ test_hexdump();
+ test_parse_uint32();
+ test_asprintf();
+ return 0;
+}
diff --git a/test/core/support/sync_test.c b/test/core/support/sync_test.c
new file mode 100644
index 0000000000..93f9c4cc8d
--- /dev/null
+++ b/test/core/support/sync_test.c
@@ -0,0 +1,451 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Test of gpr synchronization support. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/time.h>
+#include "test/core/util/test_config.h"
+
+/* ==================Example use of interface===================
+
+ A producer-consumer queue of up to N integers,
+ illustrating the use of the calls in this interface. */
+
+#define N 4
+
+typedef struct queue {
+ gpr_cv non_empty; /* Signalled when length becomes non-zero. */
+ gpr_cv non_full; /* Signalled when length becomes non-N. */
+ gpr_mu mu; /* Protects all fields below.
+ (That is, except during initialization or
+ destruction, the fields below should be accessed
+ only by a thread that holds mu.) */
+ int head; /* Index of head of queue 0..N-1. */
+ int length; /* Number of valid elements in queue 0..N. */
+ int elem[N]; /* elem[head .. head+length-1] are queue elements. */
+} queue;
+
+/* Initialize *q. */
+void queue_init(queue *q) {
+ gpr_mu_init(&q->mu);
+ gpr_cv_init(&q->non_empty);
+ gpr_cv_init(&q->non_full);
+ q->head = 0;
+ q->length = 0;
+}
+
+/* Free storage associated with *q. */
+void queue_destroy(queue *q) {
+ gpr_mu_destroy(&q->mu);
+ gpr_cv_destroy(&q->non_empty);
+ gpr_cv_destroy(&q->non_full);
+}
+
+/* Wait until there is room in *q, then append x to *q. */
+void queue_append(queue *q, int x) {
+ gpr_mu_lock(&q->mu);
+ /* To wait for a predicate without a deadline, loop on the negation of the
+ predicate, and use gpr_cv_wait(..., gpr_inf_future) inside the loop
+ to release the lock, wait, and reacquire on each iteration. Code that
+ makes the condition true should use gpr_cv_broadcast() on the
+ corresponding condition variable. The predicate must be on state
+ protected by the lock. */
+ while (q->length == N) {
+ gpr_cv_wait(&q->non_full, &q->mu, gpr_inf_future);
+ }
+ if (q->length == 0) { /* Wake threads blocked in queue_remove(). */
+ /* It's normal to use gpr_cv_broadcast() or gpr_signal() while
+ holding the lock. */
+ gpr_cv_broadcast(&q->non_empty);
+ }
+ q->elem[(q->head + q->length) % N] = x;
+ q->length++;
+ gpr_mu_unlock(&q->mu);
+}
+
+/* If it can be done without blocking, append x to *q and return non-zero.
+ Otherwise return 0. */
+int queue_try_append(queue *q, int x) {
+ int result = 0;
+ if (gpr_mu_trylock(&q->mu)) {
+ if (q->length != N) {
+ if (q->length == 0) { /* Wake threads blocked in queue_remove(). */
+ gpr_cv_broadcast(&q->non_empty);
+ }
+ q->elem[(q->head + q->length) % N] = x;
+ q->length++;
+ result = 1;
+ }
+ gpr_mu_unlock(&q->mu);
+ }
+ return result;
+}
+
+/* Wait until the *q is non-empty or deadline abs_deadline passes. If the
+ queue is non-empty, remove its head entry, place it in *head, and return
+ non-zero. Otherwise return 0. */
+int queue_remove(queue *q, int *head, gpr_timespec abs_deadline) {
+ int result = 0;
+ gpr_mu_lock(&q->mu);
+ /* To wait for a predicate with a deadline, loop on the negation of the
+ predicate or until gpr_cv_wait() returns true. Code that makes
+ the condition true should use gpr_cv_broadcast() on the corresponding
+ condition variable. The predicate must be on state protected by the
+ lock. */
+ while (q->length == 0 && !gpr_cv_wait(&q->non_empty, &q->mu, abs_deadline)) {
+ }
+ if (q->length != 0) { /* Queue is non-empty. */
+ result = 1;
+ if (q->length == N) { /* Wake threads blocked in queue_append(). */
+ gpr_cv_broadcast(&q->non_full);
+ }
+ *head = q->elem[q->head];
+ q->head = (q->head + 1) % N;
+ q->length--;
+ } /* else deadline exceeded */
+ gpr_mu_unlock(&q->mu);
+ return result;
+}
+
+/* ------------------------------------------------- */
+/* Tests for gpr_mu and gpr_cv, and the queue example. */
+struct test {
+ int threads; /* number of threads */
+
+ gpr_int64 iterations; /* number of iterations per thread */
+ gpr_int64 counter;
+ int thread_count; /* used to allocate thread ids */
+ int done; /* threads not yet completed */
+
+ gpr_mu mu; /* protects iterations, counter, thread_count, done */
+
+ gpr_cv cv; /* signalling depends on test */
+
+ gpr_cv done_cv; /* signalled when done == 0 */
+
+ queue q;
+
+ gpr_stats_counter stats_counter;
+
+ gpr_refcount refcount;
+ gpr_refcount thread_refcount;
+ gpr_event event;
+};
+
+/* Return pointer to a new struct test. */
+static struct test *test_new(int threads, gpr_int64 iterations) {
+ struct test *m = gpr_malloc(sizeof(*m));
+ m->threads = threads;
+ m->iterations = iterations;
+ m->counter = 0;
+ m->thread_count = 0;
+ m->done = threads;
+ gpr_mu_init(&m->mu);
+ gpr_cv_init(&m->cv);
+ gpr_cv_init(&m->done_cv);
+ queue_init(&m->q);
+ gpr_stats_init(&m->stats_counter, 0);
+ gpr_ref_init(&m->refcount, 0);
+ gpr_ref_init(&m->thread_refcount, threads);
+ gpr_event_init(&m->event);
+ return m;
+}
+
+/* Return pointer to a new struct test. */
+static void test_destroy(struct test *m) {
+ gpr_mu_destroy(&m->mu);
+ gpr_cv_destroy(&m->cv);
+ gpr_cv_destroy(&m->done_cv);
+ queue_destroy(&m->q);
+ gpr_free(m);
+}
+
+/* Create m->threads threads, each running (*body)(m) */
+static void test_create_threads(struct test *m, void (*body)(void *arg)) {
+ gpr_thd_id id;
+ int i;
+ for (i = 0; i != m->threads; i++) {
+ GPR_ASSERT(gpr_thd_new(&id, body, m, NULL));
+ }
+}
+
+/* Wait until all threads report done. */
+static void test_wait(struct test *m) {
+ gpr_mu_lock(&m->mu);
+ while (m->done != 0) {
+ gpr_cv_wait(&m->done_cv, &m->mu, gpr_inf_future);
+ }
+ gpr_mu_unlock(&m->mu);
+}
+
+/* Get an integer thread id in the raneg 0..threads-1 */
+static int thread_id(struct test *m) {
+ int id;
+ gpr_mu_lock(&m->mu);
+ id = m->thread_count++;
+ gpr_mu_unlock(&m->mu);
+ return id;
+}
+
+/* Indicate that a thread is done, by decrementing m->done
+ and signalling done_cv if m->done==0. */
+static void mark_thread_done(struct test *m) {
+ gpr_mu_lock(&m->mu);
+ GPR_ASSERT(m->done != 0);
+ m->done--;
+ if (m->done == 0) {
+ gpr_cv_signal(&m->done_cv);
+ }
+ gpr_mu_unlock(&m->mu);
+}
+
+/* Test several threads running (*body)(struct test *m) for increasing settings
+ of m->iterations, until about timeout_s to 2*timeout_s seconds have elapsed.
+ If extra!=NULL, run (*extra)(m) in an additional thread. */
+static void test(const char *name, void (*body)(void *m),
+ void (*extra)(void *m), int timeout_s) {
+ gpr_int64 iterations = 1024;
+ struct test *m;
+ gpr_timespec start = gpr_now();
+ gpr_timespec time_taken;
+ gpr_timespec deadline =
+ gpr_time_add(start, gpr_time_from_micros(timeout_s * 1000000));
+ fprintf(stderr, "%s:", name);
+ while (gpr_time_cmp(gpr_now(), deadline) < 0) {
+ iterations <<= 1;
+ fprintf(stderr, " %ld", (long)iterations);
+ m = test_new(10, iterations);
+ if (extra != NULL) {
+ gpr_thd_id id;
+ GPR_ASSERT(gpr_thd_new(&id, extra, m, NULL));
+ m->done++; /* one more thread to wait for */
+ }
+ test_create_threads(m, body);
+ test_wait(m);
+ if (m->counter != m->threads * m->iterations) {
+ fprintf(stderr, "counter %ld threads %d iterations %ld\n",
+ (long)m->counter, m->threads, (long)m->iterations);
+ GPR_ASSERT(0);
+ }
+ test_destroy(m);
+ }
+ time_taken = gpr_time_sub(gpr_now(), start);
+ fprintf(stderr, " done %ld.%09d s\n", (long)time_taken.tv_sec,
+ (int)time_taken.tv_nsec);
+}
+
+/* Increment m->counter on each iteration; then mark thread as done. */
+static void inc(void *v /*=m*/) {
+ struct test *m = v;
+ gpr_int64 i;
+ for (i = 0; i != m->iterations; i++) {
+ gpr_mu_lock(&m->mu);
+ m->counter++;
+ gpr_mu_unlock(&m->mu);
+ }
+ mark_thread_done(m);
+}
+
+/* Increment m->counter under lock acquired with trylock, m->iterations times;
+ then mark thread as done. */
+static void inctry(void *v /*=m*/) {
+ struct test *m = v;
+ gpr_int64 i;
+ for (i = 0; i != m->iterations;) {
+ if (gpr_mu_trylock(&m->mu)) {
+ m->counter++;
+ gpr_mu_unlock(&m->mu);
+ i++;
+ }
+ }
+ mark_thread_done(m);
+}
+
+/* Increment counter only when (m->counter%m->threads)==m->thread_id; then mark
+ thread as done. */
+static void inc_by_turns(void *v /*=m*/) {
+ struct test *m = v;
+ gpr_int64 i;
+ int id = thread_id(m);
+ for (i = 0; i != m->iterations; i++) {
+ gpr_mu_lock(&m->mu);
+ while ((m->counter % m->threads) != id) {
+ gpr_cv_wait(&m->cv, &m->mu, gpr_inf_future);
+ }
+ m->counter++;
+ gpr_cv_broadcast(&m->cv);
+ gpr_mu_unlock(&m->mu);
+ }
+ mark_thread_done(m);
+}
+
+/* Wait a millisecond and increment counter on each iteration;
+ then mark thread as done. */
+static void inc_with_1ms_delay(void *v /*=m*/) {
+ struct test *m = v;
+ gpr_int64 i;
+ for (i = 0; i != m->iterations; i++) {
+ gpr_timespec deadline;
+ gpr_mu_lock(&m->mu);
+ deadline = gpr_time_add(gpr_now(), gpr_time_from_micros(1000));
+ while (!gpr_cv_wait(&m->cv, &m->mu, deadline)) {
+ }
+ m->counter++;
+ gpr_mu_unlock(&m->mu);
+ }
+ mark_thread_done(m);
+}
+
+/* Wait a millisecond and increment counter on each iteration, using an event
+ for timing; then mark thread as done. */
+static void inc_with_1ms_delay_event(void *v /*=m*/) {
+ struct test *m = v;
+ gpr_int64 i;
+ for (i = 0; i != m->iterations; i++) {
+ gpr_timespec deadline;
+ deadline = gpr_time_add(gpr_now(), gpr_time_from_micros(1000));
+ GPR_ASSERT(gpr_event_wait(&m->event, deadline) == NULL);
+ gpr_mu_lock(&m->mu);
+ m->counter++;
+ gpr_mu_unlock(&m->mu);
+ }
+ mark_thread_done(m);
+}
+
+/* Produce m->iterations elements on queue m->q, then mark thread as done.
+ Even threads use queue_append(), and odd threads use queue_try_append()
+ until it succeeds. */
+static void many_producers(void *v /*=m*/) {
+ struct test *m = v;
+ gpr_int64 i;
+ int x = thread_id(m);
+ if ((x & 1) == 0) {
+ for (i = 0; i != m->iterations; i++) {
+ queue_append(&m->q, 1);
+ }
+ } else {
+ for (i = 0; i != m->iterations; i++) {
+ while (!queue_try_append(&m->q, 1)) {
+ }
+ }
+ }
+ mark_thread_done(m);
+}
+
+/* Consume elements from m->q until m->threads*m->iterations are seen,
+ wait an extra second to confirm that no more elements are arriving,
+ then mark thread as done. */
+static void consumer(void *v /*=m*/) {
+ struct test *m = v;
+ gpr_int64 n = m->iterations * m->threads;
+ gpr_int64 i;
+ int value;
+ for (i = 0; i != n; i++) {
+ queue_remove(&m->q, &value, gpr_inf_future);
+ }
+ gpr_mu_lock(&m->mu);
+ m->counter = n;
+ gpr_mu_unlock(&m->mu);
+ GPR_ASSERT(
+ !queue_remove(&m->q, &value,
+ gpr_time_add(gpr_now(), gpr_time_from_micros(1000000))));
+ mark_thread_done(m);
+}
+
+/* Increment m->stats_counter m->iterations times, transfer counter value to
+ m->counter, then mark thread as done. */
+static void statsinc(void *v /*=m*/) {
+ struct test *m = v;
+ gpr_int64 i;
+ for (i = 0; i != m->iterations; i++) {
+ gpr_stats_inc(&m->stats_counter, 1);
+ }
+ gpr_mu_lock(&m->mu);
+ m->counter = gpr_stats_read(&m->stats_counter);
+ gpr_mu_unlock(&m->mu);
+ mark_thread_done(m);
+}
+
+/* Increment m->refcount m->iterations times, decrement m->thread_refcount
+ once, and if it reaches zero, set m->event to (void*)1; then mark thread as
+ done. */
+static void refinc(void *v /*=m*/) {
+ struct test *m = v;
+ gpr_int64 i;
+ for (i = 0; i != m->iterations; i++) {
+ gpr_ref(&m->refcount);
+ }
+ if (gpr_unref(&m->thread_refcount)) {
+ gpr_event_set(&m->event, (void *)1);
+ }
+ mark_thread_done(m);
+}
+
+/* Wait until m->event is set to (void *)1, then decrement m->refcount
+ m->stats_counter m->iterations times, and ensure that the last decrement
+ caused the counter to reach zero, then mark thread as done. */
+static void refcheck(void *v /*=m*/) {
+ struct test *m = v;
+ gpr_int64 n = m->iterations * m->threads;
+ gpr_int64 i;
+ GPR_ASSERT(gpr_event_wait(&m->event, gpr_inf_future) == (void *)1);
+ GPR_ASSERT(gpr_event_get(&m->event) == (void *)1);
+ for (i = 1; i != n; i++) {
+ GPR_ASSERT(!gpr_unref(&m->refcount));
+ m->counter++;
+ }
+ GPR_ASSERT(gpr_unref(&m->refcount));
+ m->counter++;
+ mark_thread_done(m);
+}
+
+/* ------------------------------------------------- */
+
+int main(int argc, char *argv[]) {
+ grpc_test_init(argc, argv);
+ test("mutex", &inc, NULL, 1);
+ test("mutex try", &inctry, NULL, 1);
+ test("cv", &inc_by_turns, NULL, 1);
+ test("timedcv", &inc_with_1ms_delay, NULL, 1);
+ test("queue", &many_producers, &consumer, 10);
+ test("stats_counter", &statsinc, NULL, 1);
+ test("refcount", &refinc, &refcheck, 1);
+ test("timedevent", &inc_with_1ms_delay_event, NULL, 1);
+ return 0;
+}
diff --git a/test/core/support/thd_test.c b/test/core/support/thd_test.c
new file mode 100644
index 0000000000..c70e025326
--- /dev/null
+++ b/test/core/support/thd_test.c
@@ -0,0 +1,90 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Test of gpr thread support. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/time.h>
+#include "test/core/util/test_config.h"
+
+struct test {
+ gpr_mu mu;
+ int n;
+ int is_done;
+ gpr_cv done_cv;
+};
+
+/* A Thread body. Decrement t->n, and if is becomes zero, set t->done. */
+static void thd_body(void *v) {
+ struct test *t = v;
+ gpr_mu_lock(&t->mu);
+ t->n--;
+ if (t->n == 0) {
+ t->is_done = 1;
+ gpr_cv_signal(&t->done_cv);
+ }
+ gpr_mu_unlock(&t->mu);
+}
+
+/* Test that we can create a number of threads and wait for them. */
+static void test(void) {
+ int i;
+ gpr_thd_id thd;
+ struct test t;
+ int n = 1000;
+ gpr_mu_init(&t.mu);
+ gpr_cv_init(&t.done_cv);
+ t.n = n;
+ t.is_done = 0;
+ for (i = 0; i != n; i++) {
+ GPR_ASSERT(gpr_thd_new(&thd, &thd_body, &t, NULL));
+ }
+ gpr_mu_lock(&t.mu);
+ while (!t.is_done) {
+ gpr_cv_wait(&t.done_cv, &t.mu, gpr_inf_future);
+ }
+ gpr_mu_unlock(&t.mu);
+ GPR_ASSERT(t.n == 0);
+}
+
+/* ------------------------------------------------- */
+
+int main(int argc, char *argv[]) {
+ grpc_test_init(argc, argv);
+ test();
+ return 0;
+}
diff --git a/test/core/support/time_test.c b/test/core/support/time_test.c
new file mode 100644
index 0000000000..d74d6a52d9
--- /dev/null
+++ b/test/core/support/time_test.c
@@ -0,0 +1,255 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Test of gpr time support. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/time.h>
+#include "test/core/util/test_config.h"
+
+static void to_fp(void *arg, const char *buf, int len) {
+ fwrite(buf, 1, len, (FILE *)arg);
+}
+
+/* Convert gpr_uintmax x to ascii base b (2..16), and write with
+ (*writer)(arg, ...), zero padding to "chars" digits). */
+static void u_to_s(gpr_uintmax x, unsigned base, int chars,
+ void (*writer)(void *arg, const char *buf, int len),
+ void *arg) {
+ char buf[64];
+ char *p = buf + sizeof(buf);
+ do {
+ *--p = "0123456789abcdef"[x % base];
+ x /= base;
+ chars--;
+ } while (x != 0 || chars > 0);
+ (*writer)(arg, p, buf + sizeof(buf) - p);
+}
+
+/* Convert gpr_intmax x to ascii base b (2..16), and write with
+ (*writer)(arg, ...), zero padding to "chars" digits). */
+static void i_to_s(gpr_intmax x, unsigned base, int chars,
+ void (*writer)(void *arg, const char *buf, int len),
+ void *arg) {
+ if (x < 0) {
+ (*writer)(arg, "-", 1);
+ u_to_s(-x, base, chars - 1, writer, arg);
+ } else {
+ u_to_s(x, base, chars, writer, arg);
+ }
+}
+
+/* Convert ts to ascii, and write with (*writer)(arg, ...). */
+static void ts_to_s(gpr_timespec t,
+ void (*writer)(void *arg, const char *buf, int len),
+ void *arg) {
+ if (t.tv_sec < 0 && t.tv_nsec != 0) {
+ t.tv_sec++;
+ t.tv_nsec = 1000000000 - t.tv_nsec;
+ }
+ i_to_s(t.tv_sec, 10, 0, writer, arg);
+ (*writer)(arg, ".", 1);
+ i_to_s(t.tv_nsec, 10, 9, writer, arg);
+}
+
+static void test_values(void) {
+ int i;
+
+ gpr_timespec x = gpr_time_0;
+ GPR_ASSERT(x.tv_sec == 0 && x.tv_nsec == 0);
+
+ x = gpr_inf_future;
+ fprintf(stderr, "far future ");
+ u_to_s(x.tv_sec, 16, 16, &to_fp, stderr);
+ fprintf(stderr, "\n");
+ GPR_ASSERT(x.tv_sec >= INT_MAX);
+ fprintf(stderr, "far future ");
+ ts_to_s(x, &to_fp, stderr);
+ fprintf(stderr, "\n");
+
+ x = gpr_inf_past;
+ fprintf(stderr, "far past ");
+ u_to_s(x.tv_sec, 16, 16, &to_fp, stderr);
+ fprintf(stderr, "\n");
+ GPR_ASSERT(x.tv_sec <= INT_MIN);
+ fprintf(stderr, "far past ");
+ ts_to_s(x, &to_fp, stderr);
+ fprintf(stderr, "\n");
+
+ for (i = 1; i != 1000 * 1000 * 1000; i *= 10) {
+ x = gpr_time_from_micros(i);
+ GPR_ASSERT(x.tv_sec == i / GPR_US_PER_SEC &&
+ x.tv_nsec == (i % GPR_US_PER_SEC) * GPR_NS_PER_US);
+ x = gpr_time_from_nanos(i);
+ GPR_ASSERT(x.tv_sec == i / GPR_NS_PER_SEC &&
+ x.tv_nsec == (i % GPR_NS_PER_SEC));
+ x = gpr_time_from_millis(i);
+ GPR_ASSERT(x.tv_sec == i / GPR_MS_PER_SEC &&
+ x.tv_nsec == (i % GPR_MS_PER_SEC) * GPR_NS_PER_MS);
+ }
+
+ /* Test possible overflow in conversion of -ve values. */
+ x = gpr_time_from_micros(-(LONG_MAX - 999997));
+ GPR_ASSERT(x.tv_sec < 0);
+ GPR_ASSERT(x.tv_nsec >= 0 && x.tv_nsec < 1000000000);
+
+ x = gpr_time_from_nanos(-(LONG_MAX - 999999997));
+ GPR_ASSERT(x.tv_sec < 0);
+ GPR_ASSERT(x.tv_nsec >= 0 && x.tv_nsec < 1000000000);
+
+ x = gpr_time_from_millis(-(LONG_MAX - 997));
+ GPR_ASSERT(x.tv_sec < 0);
+ GPR_ASSERT(x.tv_nsec >= 0 && x.tv_nsec < 1000000000);
+
+ /* Test general -ve values. */
+ for (i = -1; i > -1000 * 1000 * 1000; i *= 7) {
+ x = gpr_time_from_micros(i);
+ GPR_ASSERT(x.tv_sec * GPR_US_PER_SEC + x.tv_nsec / GPR_NS_PER_US == i);
+ x = gpr_time_from_nanos(i);
+ GPR_ASSERT(x.tv_sec * GPR_NS_PER_SEC + x.tv_nsec == i);
+ x = gpr_time_from_millis(i);
+ GPR_ASSERT(x.tv_sec * GPR_MS_PER_SEC + x.tv_nsec / GPR_NS_PER_MS == i);
+ }
+}
+
+static void test_add_sub(void) {
+ int i;
+ int j;
+ int k;
+ /* Basic addition and subtraction. */
+ for (i = -100; i <= 100; i++) {
+ for (j = -100; j <= 100; j++) {
+ for (k = 1; k <= 10000000; k *= 10) {
+ int sum = i + j;
+ int diff = i - j;
+ gpr_timespec it = gpr_time_from_micros(i * k);
+ gpr_timespec jt = gpr_time_from_micros(j * k);
+ gpr_timespec sumt = gpr_time_add(it, jt);
+ gpr_timespec difft = gpr_time_sub(it, jt);
+ if (gpr_time_cmp(gpr_time_from_micros(sum * k), sumt) != 0) {
+ fprintf(stderr, "i %d j %d sum %d sumt ", i, j, sum);
+ ts_to_s(sumt, &to_fp, stderr);
+ fprintf(stderr, "\n");
+ GPR_ASSERT(0);
+ }
+ if (gpr_time_cmp(gpr_time_from_micros(diff * k), difft) != 0) {
+ fprintf(stderr, "i %d j %d diff %d diff ", i, j, diff);
+ ts_to_s(sumt, &to_fp, stderr);
+ fprintf(stderr, "\n");
+ GPR_ASSERT(0);
+ }
+ }
+ }
+ }
+}
+
+static void test_overflow(void) {
+ /* overflow */
+ gpr_timespec x = gpr_time_from_micros(1);
+ do {
+ x = gpr_time_add(x, x);
+ } while (gpr_time_cmp(x, gpr_inf_future) < 0);
+ GPR_ASSERT(gpr_time_cmp(x, gpr_inf_future) == 0);
+ x = gpr_time_from_micros(-1);
+ do {
+ x = gpr_time_add(x, x);
+ } while (gpr_time_cmp(x, gpr_inf_past) > 0);
+ GPR_ASSERT(gpr_time_cmp(x, gpr_inf_past) == 0);
+}
+
+static void test_sticky_infinities(void) {
+ int i;
+ int j;
+ int k;
+ static const gpr_timespec *infinity[] = {&gpr_inf_future, &gpr_inf_past};
+ static const gpr_timespec *addend[] = {&gpr_inf_future, &gpr_inf_past,
+ &gpr_time_0, NULL};
+
+ /* Infinities are sticky */
+ for (i = 0; i != sizeof(infinity) / sizeof(infinity[0]); i++) {
+ for (j = 0; j != sizeof(addend) / sizeof(addend[0]); j++) {
+ if (addend[j] == NULL) {
+ for (k = -200; k <= 200; k++) {
+ gpr_timespec y = gpr_time_from_micros(k * 100000);
+ gpr_timespec x = gpr_time_add(*infinity[i], y);
+ GPR_ASSERT(gpr_time_cmp(x, *infinity[i]) == 0);
+ x = gpr_time_sub(*infinity[i], y);
+ GPR_ASSERT(gpr_time_cmp(x, *infinity[i]) == 0);
+ }
+ } else {
+ gpr_timespec x = gpr_time_add(*infinity[i], *addend[j]);
+ GPR_ASSERT(gpr_time_cmp(x, *infinity[i]) == 0);
+ x = gpr_time_sub(*infinity[i], *addend[j]);
+ GPR_ASSERT(gpr_time_cmp(x, *infinity[i]) == 0);
+ }
+ }
+ }
+}
+
+static void test_similar() {
+ GPR_ASSERT(1 == gpr_time_similar(gpr_inf_future, gpr_inf_future, gpr_time_0));
+ GPR_ASSERT(1 == gpr_time_similar(gpr_inf_past, gpr_inf_past, gpr_time_0));
+ GPR_ASSERT(0 == gpr_time_similar(gpr_inf_past, gpr_inf_future, gpr_time_0));
+ GPR_ASSERT(0 == gpr_time_similar(gpr_inf_future, gpr_inf_past, gpr_time_0));
+ GPR_ASSERT(1 == gpr_time_similar(gpr_time_from_micros(10),
+ gpr_time_from_micros(10), gpr_time_0));
+ GPR_ASSERT(1 == gpr_time_similar(gpr_time_from_micros(10),
+ gpr_time_from_micros(15),
+ gpr_time_from_micros(10)));
+ GPR_ASSERT(1 == gpr_time_similar(gpr_time_from_micros(15),
+ gpr_time_from_micros(10),
+ gpr_time_from_micros(10)));
+ GPR_ASSERT(0 == gpr_time_similar(gpr_time_from_micros(10),
+ gpr_time_from_micros(25),
+ gpr_time_from_micros(10)));
+ GPR_ASSERT(0 == gpr_time_similar(gpr_time_from_micros(25),
+ gpr_time_from_micros(10),
+ gpr_time_from_micros(10)));
+}
+
+int main(int argc, char *argv[]) {
+ grpc_test_init(argc, argv);
+
+ test_values();
+ test_add_sub();
+ test_overflow();
+ test_sticky_infinities();
+ test_similar();
+ return 0;
+}