ctdb-tests: Add test for ctdb_io.c
[samba.git] / ctdb / tests / src / ctdb_io_test.c
1 /*
2    ctdb_io tests
3
4    Copyright (C) Christof Schmitt 2019
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "replace.h"
21 #include "system/filesys.h"
22
23 #include <assert.h>
24
25 #include "common/ctdb_io.c"
26
27 void ctdb_set_error(struct ctdb_context *ctdb, const char *fmt, ...)
28 {
29         va_list ap;
30         va_start(ap, fmt);
31         vprintf(fmt, ap);
32         assert(false);
33 }
34
35 static void test_setup(ctdb_queue_cb_fn_t cb,
36                        int *pfd,
37                        struct ctdb_context **pctdb)
38 {
39         int pipefd[2], ret;
40         struct ctdb_context *ctdb;
41         struct ctdb_queue *queue;
42
43         ret = pipe(pipefd);
44         assert(ret == 0);
45
46         ctdb = talloc_zero(NULL, struct ctdb_context);
47         assert(ctdb != NULL);
48
49         ctdb->ev = tevent_context_init(NULL);
50
51         queue = ctdb_queue_setup(ctdb, ctdb, pipefd[0], 0, cb,
52                                  NULL, "test queue");
53         assert(queue != NULL);
54
55         *pctdb = ctdb;
56         *pfd = pipefd[1];
57 }
58
59 static const size_t test1_req_len = 8;
60 static const char *test1_req = "abcdefgh";
61
62 static void test1_callback(uint8_t *data, size_t length, void *private_data)
63 {
64         uint32_t len;
65
66         len = *(uint32_t *)data;
67         assert(len == sizeof(uint32_t) + test1_req_len);
68
69         assert(length == sizeof(uint32_t) + test1_req_len);
70         assert(memcmp(data  + sizeof(len), test1_req, test1_req_len) == 0);
71 }
72
73 static void test1(void)
74 {
75         struct ctdb_context *ctdb;
76         int fd, ret;
77         uint32_t pkt_size;
78
79         test_setup(test1_callback, &fd, &ctdb);
80
81         pkt_size = sizeof(uint32_t) + test1_req_len;
82         ret = write(fd, &pkt_size, sizeof(pkt_size));
83         assert(ret == sizeof(pkt_size));
84
85         ret = write(fd, test1_req, test1_req_len);
86         assert(ret == test1_req_len);
87
88         tevent_loop_once(ctdb->ev);
89
90         TALLOC_FREE(ctdb);
91 }
92
93 static const size_t test2_req_len[] = { 900, 24, 600 };
94
95 static int test2_cb_num = 0;
96
97 static void test2_callback(uint8_t *data, size_t length, void *private_data)
98 {
99         uint32_t len;
100
101         len = *(uint32_t *)data;
102         assert(len == sizeof(uint32_t) + test2_req_len[test2_cb_num]);
103         assert(length == sizeof(uint32_t) + test2_req_len[test2_cb_num]);
104
105         test2_cb_num++;
106 }
107
108 static void test2(void)
109 {
110         struct ctdb_context *ctdb;
111         int fd, ret, i;
112         uint32_t pkt_size;
113         char req[1024] = { 0 };
114
115         for (i = 0; i < sizeof(req); i++) {
116                 req[i] = i % CHAR_MAX;
117         }
118
119         test_setup(test2_callback, &fd, &ctdb);
120
121         /*
122          * request 0
123          */
124
125         pkt_size = sizeof(uint32_t) + test2_req_len[0];
126         ret = write(fd, &pkt_size, sizeof(pkt_size));
127         assert(ret == sizeof(pkt_size));
128
129         ret = write(fd, req, test2_req_len[0]);
130         assert(ret == test2_req_len[0]);
131
132         /*
133          * request 1
134          */
135         pkt_size = sizeof(uint32_t) + test2_req_len[1];
136         ret = write(fd, &pkt_size, sizeof(pkt_size));
137         assert(ret == sizeof(pkt_size));
138
139         /*
140          * Omit the last byte to avoid buffer processing.
141          */
142         ret = write(fd, req, test2_req_len[1] - 1);
143         assert(ret == test2_req_len[1] - 1);
144
145         tevent_loop_once(ctdb->ev);
146
147         /*
148          * Write the missing byte now.
149          */
150         ret = write(fd, &req[test2_req_len[1] - 1], 1);
151         assert(ret == 1);
152
153         /*
154          * request 2
155          */
156         pkt_size = sizeof(uint32_t) + test2_req_len[2];
157         ret = write(fd, &pkt_size, sizeof(pkt_size));
158         assert(ret == sizeof(pkt_size));
159
160         ret = write(fd, req, test2_req_len[2]);
161         assert(ret == test2_req_len[2]);
162
163         tevent_loop_once(ctdb->ev);
164         tevent_loop_once(ctdb->ev);
165
166         assert(test2_cb_num == 2);
167
168         TALLOC_FREE(ctdb);
169 }
170
171 int main(int argc, const char **argv)
172 {
173         int num;
174
175         if (argc != 2) {
176                 fprintf(stderr, "%s <testnum>\n", argv[0]);
177                 exit(1);
178         }
179
180
181         num = atoi(argv[1]);
182         switch (num) {
183         case 1:
184                 test1();
185                 break;
186
187         case 2:
188                 test2();
189                 break;
190
191         default:
192                 fprintf(stderr, "Unknown test number %s\n", argv[1]);
193         }
194
195         return 0;
196 }