diff options
Diffstat (limited to 'test/core/support')
-rw-r--r-- | test/core/support/cancellable_test.c | 160 | ||||
-rw-r--r-- | test/core/support/cmdline_test.c | 293 | ||||
-rw-r--r-- | test/core/support/histogram_test.c | 178 | ||||
-rw-r--r-- | test/core/support/host_port_test.c | 72 | ||||
-rw-r--r-- | test/core/support/log_test.c | 47 | ||||
-rw-r--r-- | test/core/support/murmur_hash_test.c | 87 | ||||
-rw-r--r-- | test/core/support/slice_buffer_test.c | 70 | ||||
-rw-r--r-- | test/core/support/slice_test.c | 227 | ||||
-rw-r--r-- | test/core/support/string_test.c | 158 | ||||
-rw-r--r-- | test/core/support/sync_test.c | 451 | ||||
-rw-r--r-- | test/core/support/thd_test.c | 90 | ||||
-rw-r--r-- | test/core/support/time_test.c | 255 |
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; +} |