Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2019 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : : #include "spdk/util.h"
8 : :
9 : : #include "spdk_internal/mock.h"
10 : :
11 : : #include "spdk_internal/cunit.h"
12 : :
13 : : #include "common/lib/test_env.c"
14 : : #include "sock/uring/uring.c"
15 : :
16 [ # # ]: 0 : DEFINE_STUB(spdk_sock_map_insert, int, (struct spdk_sock_map *map, int placement_id,
17 : : struct spdk_sock_group_impl *group), 0);
18 : 0 : DEFINE_STUB_V(spdk_sock_map_release, (struct spdk_sock_map *map, int placement_id));
19 [ # # ]: 0 : DEFINE_STUB(spdk_sock_map_lookup, int, (struct spdk_sock_map *map, int placement_id,
20 : : struct spdk_sock_group_impl **group, struct spdk_sock_group_impl *hint), 0);
21 [ # # ]: 0 : DEFINE_STUB(spdk_sock_map_find_free, int, (struct spdk_sock_map *map), -1);
22 : 2 : DEFINE_STUB_V(spdk_sock_map_cleanup, (struct spdk_sock_map *map));
23 : :
24 : 2 : DEFINE_STUB_V(spdk_net_impl_register, (struct spdk_net_impl *impl));
25 [ # # ]: 0 : DEFINE_STUB(spdk_sock_set_default_impl, int, (const char *impl_name), 0);
26 [ # # ]: 0 : DEFINE_STUB(spdk_sock_close, int, (struct spdk_sock **s), 0);
27 [ # # # # ]: 0 : DEFINE_STUB(io_uring_submit, int, (struct io_uring *ring), 0);
28 [ # # # # ]: 0 : DEFINE_STUB(io_uring_queue_init, int, (unsigned entries, struct io_uring *ring, unsigned flags), 0);
29 : 0 : DEFINE_STUB_V(io_uring_queue_exit, (struct io_uring *ring));
30 [ # # ]: 0 : DEFINE_STUB(spdk_sock_group_provide_buf, int, (struct spdk_sock_group *group, void *buf,
31 : : size_t len, void *ctx), 0);
32 [ # # ]: 0 : DEFINE_STUB(spdk_sock_group_get_buf, size_t, (struct spdk_sock_group *group, void **buf,
33 : : void **ctx), 0);
34 : :
35 : : static void
36 : 18 : _req_cb(void *cb_arg, int len)
37 : : {
38 : 18 : *(bool *)cb_arg = true;
39 : 18 : CU_ASSERT(len == 0);
40 : 18 : }
41 : :
42 : : static void
43 : 2 : flush_client(void)
44 : : {
45 : 2 : struct spdk_uring_sock_group_impl group = {};
46 : 2 : struct spdk_uring_sock usock = {};
47 : 2 : struct spdk_sock *sock = &usock.base;
48 : : struct spdk_sock_request *req1, *req2;
49 : 1 : bool cb_arg1, cb_arg2;
50 : : int rc;
51 : :
52 : : /* Set up data structures */
53 : 2 : TAILQ_INIT(&sock->queued_reqs);
54 : 2 : TAILQ_INIT(&sock->pending_reqs);
55 : 2 : sock->group_impl = &group.base;
56 : :
57 : 2 : req1 = calloc(1, sizeof(struct spdk_sock_request) + 3 * sizeof(struct iovec));
58 [ - + ]: 2 : SPDK_CU_ASSERT_FATAL(req1 != NULL);
59 : 2 : SPDK_SOCK_REQUEST_IOV(req1, 0)->iov_base = (void *)100;
60 : 2 : SPDK_SOCK_REQUEST_IOV(req1, 0)->iov_len = 64;
61 : 2 : SPDK_SOCK_REQUEST_IOV(req1, 1)->iov_base = (void *)200;
62 : 2 : SPDK_SOCK_REQUEST_IOV(req1, 1)->iov_len = 64;
63 : 2 : SPDK_SOCK_REQUEST_IOV(req1, 2)->iov_base = (void *)300;
64 : 2 : SPDK_SOCK_REQUEST_IOV(req1, 2)->iov_len = 64;
65 : 2 : req1->iovcnt = 3;
66 : 2 : req1->cb_fn = _req_cb;
67 : 2 : req1->cb_arg = &cb_arg1;
68 : :
69 : 2 : req2 = calloc(1, sizeof(struct spdk_sock_request) + 2 * sizeof(struct iovec));
70 [ - + ]: 2 : SPDK_CU_ASSERT_FATAL(req2 != NULL);
71 : 2 : SPDK_SOCK_REQUEST_IOV(req2, 0)->iov_base = (void *)100;
72 : 2 : SPDK_SOCK_REQUEST_IOV(req2, 0)->iov_len = 32;
73 : 2 : SPDK_SOCK_REQUEST_IOV(req2, 1)->iov_base = (void *)200;
74 : 2 : SPDK_SOCK_REQUEST_IOV(req2, 1)->iov_len = 32;
75 : 2 : req2->iovcnt = 2;
76 : 2 : req2->cb_fn = _req_cb;
77 : 2 : req2->cb_arg = &cb_arg2;
78 : :
79 : : /* Simple test - a request with a 3 element iovec
80 : : * that gets submitted in a single sendmsg. */
81 : 2 : spdk_sock_request_queue(sock, req1);
82 : 2 : MOCK_SET(sendmsg, 192);
83 : 2 : cb_arg1 = false;
84 : 2 : rc = uring_sock_flush(sock);
85 : 2 : CU_ASSERT(rc == 192);
86 [ - + ]: 2 : CU_ASSERT(cb_arg1 == true);
87 : 2 : CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs));
88 : :
89 : : /* Two requests, where both can fully send. */
90 : 2 : spdk_sock_request_queue(sock, req1);
91 : 2 : spdk_sock_request_queue(sock, req2);
92 : 2 : MOCK_SET(sendmsg, 256);
93 : 2 : cb_arg1 = false;
94 : 2 : cb_arg2 = false;
95 : 2 : rc = uring_sock_flush(sock);
96 : 2 : CU_ASSERT(rc == 256);
97 [ - + ]: 2 : CU_ASSERT(cb_arg1 == true);
98 [ - + ]: 2 : CU_ASSERT(cb_arg2 == true);
99 : 2 : CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs));
100 : :
101 : : /* Two requests. Only first one can send */
102 : 2 : spdk_sock_request_queue(sock, req1);
103 : 2 : spdk_sock_request_queue(sock, req2);
104 : 2 : MOCK_SET(sendmsg, 192);
105 : 2 : cb_arg1 = false;
106 : 2 : cb_arg2 = false;
107 : 2 : rc = uring_sock_flush(sock);
108 : 2 : CU_ASSERT(rc == 192);
109 [ - + ]: 2 : CU_ASSERT(cb_arg1 == true);
110 [ - + ]: 2 : CU_ASSERT(cb_arg2 == false);
111 : 2 : CU_ASSERT(TAILQ_FIRST(&sock->queued_reqs) == req2);
112 [ - + ]: 2 : TAILQ_REMOVE(&sock->queued_reqs, req2, internal.link);
113 : 2 : CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs));
114 : :
115 : : /* One request. Partial send. */
116 : 2 : spdk_sock_request_queue(sock, req1);
117 : 2 : MOCK_SET(sendmsg, 10);
118 : 2 : cb_arg1 = false;
119 : 2 : rc = uring_sock_flush(sock);
120 : 2 : CU_ASSERT(rc == 10);
121 [ - + ]: 2 : CU_ASSERT(cb_arg1 == false);
122 : 2 : CU_ASSERT(TAILQ_FIRST(&sock->queued_reqs) == req1);
123 : :
124 : : /* Do a second flush that partial sends again. */
125 : 2 : MOCK_SET(sendmsg, 52);
126 : 2 : cb_arg1 = false;
127 : 2 : rc = uring_sock_flush(sock);
128 : 2 : CU_ASSERT(rc == 52);
129 [ - + ]: 2 : CU_ASSERT(cb_arg1 == false);
130 : 2 : CU_ASSERT(TAILQ_FIRST(&sock->queued_reqs) == req1);
131 : :
132 : : /* Flush the rest of the data */
133 : 2 : MOCK_SET(sendmsg, 130);
134 : 2 : cb_arg1 = false;
135 : 2 : rc = uring_sock_flush(sock);
136 : 2 : CU_ASSERT(rc == 130);
137 [ - + ]: 2 : CU_ASSERT(cb_arg1 == true);
138 : 2 : CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs));
139 : :
140 : 2 : free(req1);
141 : 2 : free(req2);
142 : 2 : }
143 : :
144 : : static void
145 : 2 : flush_server(void)
146 : : {
147 : 2 : struct spdk_uring_sock_group_impl group = {};
148 : 2 : struct spdk_uring_sock usock = {};
149 : 2 : struct spdk_sock *sock = &usock.base;
150 : : struct spdk_sock_request *req1, *req2;
151 : 1 : bool cb_arg1, cb_arg2;
152 : : int rc;
153 : :
154 : : /* Set up data structures */
155 : 2 : TAILQ_INIT(&sock->queued_reqs);
156 : 2 : TAILQ_INIT(&sock->pending_reqs);
157 : 2 : sock->group_impl = &group.base;
158 : 2 : usock.write_task.sock = &usock;
159 : 2 : usock.group = &group;
160 : :
161 : 2 : req1 = calloc(1, sizeof(struct spdk_sock_request) + 2 * sizeof(struct iovec));
162 [ - + ]: 2 : SPDK_CU_ASSERT_FATAL(req1 != NULL);
163 : 2 : SPDK_SOCK_REQUEST_IOV(req1, 0)->iov_base = (void *)100;
164 : 2 : SPDK_SOCK_REQUEST_IOV(req1, 0)->iov_len = 64;
165 : 2 : SPDK_SOCK_REQUEST_IOV(req1, 1)->iov_base = (void *)200;
166 : 2 : SPDK_SOCK_REQUEST_IOV(req1, 1)->iov_len = 64;
167 : 2 : req1->iovcnt = 2;
168 : 2 : req1->cb_fn = _req_cb;
169 : 2 : req1->cb_arg = &cb_arg1;
170 : :
171 : 2 : req2 = calloc(1, sizeof(struct spdk_sock_request) + 2 * sizeof(struct iovec));
172 [ - + ]: 2 : SPDK_CU_ASSERT_FATAL(req2 != NULL);
173 : 2 : SPDK_SOCK_REQUEST_IOV(req2, 0)->iov_base = (void *)100;
174 : 2 : SPDK_SOCK_REQUEST_IOV(req2, 0)->iov_len = 32;
175 : 2 : SPDK_SOCK_REQUEST_IOV(req2, 1)->iov_base = (void *)200;
176 : 2 : SPDK_SOCK_REQUEST_IOV(req2, 1)->iov_len = 32;
177 : 2 : req2->iovcnt = 2;
178 : 2 : req2->cb_fn = _req_cb;
179 : 2 : req2->cb_arg = &cb_arg2;
180 : :
181 : : /* we should not call _sock_flush directly, since it will finally
182 : : * call liburing related functions */
183 : :
184 : : /* Simple test - a request with a 2 element iovec
185 : : * that is fully completed. */
186 : 2 : spdk_sock_request_queue(sock, req1);
187 : 2 : cb_arg1 = false;
188 : 2 : rc = spdk_sock_prep_reqs(sock, usock.write_task.iovs, 0, NULL, NULL);
189 : 2 : CU_ASSERT(rc == 2);
190 : 2 : sock_complete_write_reqs(sock, 128, 0);
191 [ - + ]: 2 : CU_ASSERT(cb_arg1 == true);
192 : 2 : CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs));
193 : :
194 : : /* Two requests, where both can be fully completed. */
195 : 2 : spdk_sock_request_queue(sock, req1);
196 : 2 : spdk_sock_request_queue(sock, req2);
197 : 2 : cb_arg1 = false;
198 : 2 : cb_arg2 = false;
199 : 2 : rc = spdk_sock_prep_reqs(sock, usock.write_task.iovs, 0, NULL, NULL);
200 : 2 : CU_ASSERT(rc == 4);
201 : 2 : sock_complete_write_reqs(sock, 192, 0);
202 [ - + ]: 2 : CU_ASSERT(cb_arg1 == true);
203 [ - + ]: 2 : CU_ASSERT(cb_arg2 == true);
204 : 2 : CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs));
205 : :
206 : :
207 : : /* One request that is partially sent. */
208 : 2 : spdk_sock_request_queue(sock, req1);
209 : 2 : cb_arg1 = false;
210 : 2 : rc = spdk_sock_prep_reqs(sock, usock.write_task.iovs, 0, NULL, NULL);
211 : 2 : CU_ASSERT(rc == 2);
212 : 2 : sock_complete_write_reqs(sock, 92, 0);
213 : 2 : CU_ASSERT(rc == 2);
214 [ - + ]: 2 : CU_ASSERT(cb_arg1 == false);
215 : 2 : CU_ASSERT(TAILQ_FIRST(&sock->queued_reqs) == req1);
216 : :
217 : : /* Get the second time partial sent result. */
218 : 2 : sock_complete_write_reqs(sock, 10, 0);
219 [ - + ]: 2 : CU_ASSERT(cb_arg1 == false);
220 : 2 : CU_ASSERT(TAILQ_FIRST(&sock->queued_reqs) == req1);
221 : :
222 : : /* Data is finally sent. */
223 : 2 : sock_complete_write_reqs(sock, 26, 0);
224 [ - + ]: 2 : CU_ASSERT(cb_arg1 == true);
225 : 2 : CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs));
226 : :
227 : 2 : free(req1);
228 : 2 : free(req2);
229 : 2 : }
230 : :
231 : : int
232 : 2 : main(int argc, char **argv)
233 : : {
234 : 2 : CU_pSuite suite = NULL;
235 : : unsigned int num_failures;
236 : :
237 : 2 : CU_initialize_registry();
238 : :
239 : 2 : suite = CU_add_suite("uring", NULL, NULL);
240 : :
241 : :
242 : 2 : CU_ADD_TEST(suite, flush_client);
243 : 2 : CU_ADD_TEST(suite, flush_server);
244 : :
245 : :
246 : 2 : num_failures = spdk_ut_run_tests(argc, argv, NULL);
247 : :
248 : 2 : CU_cleanup_registry();
249 : :
250 : 2 : return num_failures;
251 : : }
|