Line data Source code
1 : /*
2 : *
3 : * Copyright 2015, Google Inc.
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions are
8 : * met:
9 : *
10 : * * Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * * Redistributions in binary form must reproduce the above
13 : * copyright notice, this list of conditions and the following disclaimer
14 : * in the documentation and/or other materials provided with the
15 : * distribution.
16 : * * Neither the name of Google Inc. nor the names of its
17 : * contributors may be used to endorse or promote products derived from
18 : * this software without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 : * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 : * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 : * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 : *
32 : */
33 :
34 : #include "test/core/iomgr/endpoint_tests.h"
35 :
36 : #include <sys/types.h>
37 :
38 : #include <grpc/support/alloc.h>
39 : #include <grpc/support/slice.h>
40 : #include <grpc/support/log.h>
41 : #include <grpc/support/time.h>
42 : #include <grpc/support/useful.h>
43 : #include "test/core/util/test_config.h"
44 :
45 : /*
46 : General test notes:
47 :
48 : All tests which write data into an endpoint write i%256 into byte i, which
49 : is verified by readers.
50 :
51 : In general there are a few interesting things to vary which may lead to
52 : exercising different codepaths in an implementation:
53 : 1. Total amount of data written to the endpoint
54 : 2. Size of slice allocations
55 : 3. Amount of data we read from or write to the endpoint at once
56 :
57 : The tests here tend to parameterize these where applicable.
58 :
59 : */
60 :
61 : static grpc_pollset *g_pollset;
62 :
63 914891 : size_t count_slices(gpr_slice *slices, size_t nslices, int *current_data) {
64 914891 : size_t num_bytes = 0;
65 : size_t i;
66 : size_t j;
67 : unsigned char *buf;
68 3267927 : for (i = 0; i < nslices; ++i) {
69 2353036 : buf = GPR_SLICE_START_PTR(slices[i]);
70 38981836 : for (j = 0; j < GPR_SLICE_LENGTH(slices[i]); ++j) {
71 36628800 : GPR_ASSERT(buf[j] == *current_data);
72 36628800 : *current_data = (*current_data + 1) % 256;
73 : }
74 2353036 : num_bytes += GPR_SLICE_LENGTH(slices[i]);
75 : }
76 914891 : return num_bytes;
77 : }
78 :
79 99 : static grpc_endpoint_test_fixture begin_test(grpc_endpoint_test_config config,
80 : const char *test_name,
81 : size_t slice_size) {
82 99 : gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
83 99 : return config.create_fixture(slice_size);
84 : }
85 :
86 99 : static void end_test(grpc_endpoint_test_config config) { config.clean_up(); }
87 :
88 394245 : static gpr_slice *allocate_blocks(size_t num_bytes, size_t slice_size,
89 : size_t *num_blocks, gpr_uint8 *current_data) {
90 394245 : size_t nslices = num_bytes / slice_size + (num_bytes % slice_size ? 1 : 0);
91 394245 : gpr_slice *slices = malloc(sizeof(gpr_slice) * nslices);
92 394245 : size_t num_bytes_left = num_bytes;
93 : size_t i;
94 : size_t j;
95 : unsigned char *buf;
96 394245 : *num_blocks = nslices;
97 :
98 792558 : for (i = 0; i < nslices; ++i) {
99 398313 : slices[i] = gpr_slice_malloc(slice_size > num_bytes_left ? num_bytes_left
100 : : slice_size);
101 398313 : num_bytes_left -= GPR_SLICE_LENGTH(slices[i]);
102 398313 : buf = GPR_SLICE_START_PTR(slices[i]);
103 37927113 : for (j = 0; j < GPR_SLICE_LENGTH(slices[i]); ++j) {
104 37528800 : buf[j] = *current_data;
105 37528800 : (*current_data)++;
106 : }
107 : }
108 394245 : GPR_ASSERT(num_bytes_left == 0);
109 394245 : return slices;
110 : }
111 :
112 : struct read_and_write_test_state {
113 : grpc_endpoint *read_ep;
114 : grpc_endpoint *write_ep;
115 : size_t target_bytes;
116 : size_t bytes_read;
117 : size_t current_write_size;
118 : size_t bytes_written;
119 : int current_read_data;
120 : gpr_uint8 current_write_data;
121 : int read_done;
122 : int write_done;
123 : gpr_slice_buffer incoming;
124 : gpr_slice_buffer outgoing;
125 : grpc_closure done_read;
126 : grpc_closure done_write;
127 : };
128 :
129 914891 : static void read_and_write_test_read_handler(grpc_exec_ctx *exec_ctx,
130 : void *data, int success) {
131 914891 : struct read_and_write_test_state *state = data;
132 :
133 914891 : state->bytes_read += count_slices(
134 : state->incoming.slices, state->incoming.count, &state->current_read_data);
135 914891 : if (state->bytes_read == state->target_bytes || !success) {
136 99 : gpr_log(GPR_INFO, "Read handler done");
137 99 : gpr_mu_lock(GRPC_POLLSET_MU(g_pollset));
138 99 : state->read_done = 1 + success;
139 99 : grpc_pollset_kick(g_pollset, NULL);
140 99 : gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset));
141 914792 : } else if (success) {
142 914792 : grpc_endpoint_read(exec_ctx, state->read_ep, &state->incoming,
143 : &state->done_read);
144 : }
145 914891 : }
146 :
147 394344 : static void read_and_write_test_write_handler(grpc_exec_ctx *exec_ctx,
148 : void *data, int success) {
149 394344 : struct read_and_write_test_state *state = data;
150 394344 : gpr_slice *slices = NULL;
151 : size_t nslices;
152 :
153 394344 : if (success) {
154 394341 : state->bytes_written += state->current_write_size;
155 788682 : if (state->target_bytes - state->bytes_written <
156 394341 : state->current_write_size) {
157 147 : state->current_write_size = state->target_bytes - state->bytes_written;
158 : }
159 394341 : if (state->current_write_size != 0) {
160 394245 : slices = allocate_blocks(state->current_write_size, 8192, &nslices,
161 : &state->current_write_data);
162 394245 : gpr_slice_buffer_reset_and_unref(&state->outgoing);
163 394245 : gpr_slice_buffer_addn(&state->outgoing, slices, nslices);
164 394245 : grpc_endpoint_write(exec_ctx, state->write_ep, &state->outgoing,
165 : &state->done_write);
166 394245 : free(slices);
167 788589 : return;
168 : }
169 : }
170 :
171 99 : gpr_log(GPR_INFO, "Write handler done");
172 99 : gpr_mu_lock(GRPC_POLLSET_MU(g_pollset));
173 99 : state->write_done = 1 + success;
174 99 : grpc_pollset_kick(g_pollset, NULL);
175 99 : gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset));
176 : }
177 :
178 : /* Do both reading and writing using the grpc_endpoint API.
179 :
180 : This also includes a test of the shutdown behavior.
181 : */
182 99 : static void read_and_write_test(grpc_endpoint_test_config config,
183 : size_t num_bytes, size_t write_size,
184 : size_t slice_size, int shutdown) {
185 : struct read_and_write_test_state state;
186 99 : gpr_timespec deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(20);
187 99 : grpc_endpoint_test_fixture f =
188 : begin_test(config, "read_and_write_test", slice_size);
189 99 : grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
190 99 : gpr_log(GPR_DEBUG, "num_bytes=%d write_size=%d slice_size=%d shutdown=%d",
191 : num_bytes, write_size, slice_size, shutdown);
192 :
193 99 : if (shutdown) {
194 3 : gpr_log(GPR_INFO, "Start read and write shutdown test");
195 : } else {
196 96 : gpr_log(GPR_INFO, "Start read and write test with %d bytes, slice size %d",
197 : num_bytes, slice_size);
198 : }
199 :
200 99 : state.read_ep = f.client_ep;
201 99 : state.write_ep = f.server_ep;
202 99 : state.target_bytes = num_bytes;
203 99 : state.bytes_read = 0;
204 99 : state.current_write_size = write_size;
205 99 : state.bytes_written = 0;
206 99 : state.read_done = 0;
207 99 : state.write_done = 0;
208 99 : state.current_read_data = 0;
209 99 : state.current_write_data = 0;
210 99 : grpc_closure_init(&state.done_read, read_and_write_test_read_handler, &state);
211 99 : grpc_closure_init(&state.done_write, read_and_write_test_write_handler,
212 : &state);
213 99 : gpr_slice_buffer_init(&state.outgoing);
214 99 : gpr_slice_buffer_init(&state.incoming);
215 :
216 : /* Get started by pretending an initial write completed */
217 : /* NOTE: Sets up initial conditions so we can have the same write handler
218 : for the first iteration as for later iterations. It does the right thing
219 : even when bytes_written is unsigned. */
220 99 : state.bytes_written -= state.current_write_size;
221 99 : read_and_write_test_write_handler(&exec_ctx, &state, 1);
222 99 : grpc_exec_ctx_finish(&exec_ctx);
223 :
224 99 : grpc_endpoint_read(&exec_ctx, state.read_ep, &state.incoming,
225 : &state.done_read);
226 :
227 99 : if (shutdown) {
228 3 : gpr_log(GPR_DEBUG, "shutdown read");
229 3 : grpc_endpoint_shutdown(&exec_ctx, state.read_ep);
230 3 : gpr_log(GPR_DEBUG, "shutdown write");
231 3 : grpc_endpoint_shutdown(&exec_ctx, state.write_ep);
232 : }
233 99 : grpc_exec_ctx_finish(&exec_ctx);
234 :
235 99 : gpr_mu_lock(GRPC_POLLSET_MU(g_pollset));
236 3363 : while (!state.read_done || !state.write_done) {
237 : grpc_pollset_worker worker;
238 3165 : GPR_ASSERT(gpr_time_cmp(gpr_now(GPR_CLOCK_MONOTONIC), deadline) < 0);
239 3165 : grpc_pollset_work(&exec_ctx, g_pollset, &worker,
240 : gpr_now(GPR_CLOCK_MONOTONIC), deadline);
241 : }
242 99 : gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset));
243 99 : grpc_exec_ctx_finish(&exec_ctx);
244 :
245 99 : end_test(config);
246 99 : gpr_slice_buffer_destroy(&state.outgoing);
247 99 : gpr_slice_buffer_destroy(&state.incoming);
248 99 : grpc_endpoint_destroy(&exec_ctx, state.read_ep);
249 99 : grpc_endpoint_destroy(&exec_ctx, state.write_ep);
250 99 : grpc_exec_ctx_finish(&exec_ctx);
251 99 : }
252 :
253 3 : void grpc_endpoint_tests(grpc_endpoint_test_config config,
254 : grpc_pollset *pollset) {
255 : size_t i;
256 3 : g_pollset = pollset;
257 3 : read_and_write_test(config, 10000000, 100000, 8192, 0);
258 3 : read_and_write_test(config, 1000000, 100000, 1, 0);
259 3 : read_and_write_test(config, 100000000, 100000, 1, 1);
260 93 : for (i = 1; i < 1000; i = GPR_MAX(i + 1, i * 5 / 4)) {
261 90 : read_and_write_test(config, 40320, i, i, 0);
262 : }
263 3 : g_pollset = NULL;
264 3 : }
|