diff options
Diffstat (limited to 'tests/libknot/test_control.c')
-rw-r--r-- | tests/libknot/test_control.c | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/tests/libknot/test_control.c b/tests/libknot/test_control.c new file mode 100644 index 0000000..3846f31 --- /dev/null +++ b/tests/libknot/test_control.c @@ -0,0 +1,221 @@ +/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <string.h> +#include <sys/wait.h> +#include <unistd.h> +#include <tap/basic.h> +#include <tap/files.h> + +#define CTL_BUFF_SIZE 18 +#include "libknot/control/control.c" + +#define fake_ok(condition, msg, ...) \ + if (!(condition)) { \ + if (msg != NULL) { \ + printf("error: " msg "\n", ##__VA_ARGS__); \ + } \ + exit(-1); \ + } + +static void ctl_client(const char *socket, size_t argc, knot_ctl_data_t *argv) +{ + knot_ctl_t *ctl = knot_ctl_alloc(); + fake_ok(ctl != NULL, "Allocate control"); + + int ret; + for (int i = 0; i < 20; i++) { + ret = knot_ctl_connect(ctl, socket); + if (ret == KNOT_EOK) { + break; + } + usleep(100000); + } + fake_ok(ret == KNOT_EOK, "Connect to socket"); + + diag("BEGIN: Client -> Server"); + + if (argc > 0) { + for (size_t i = 0; i < argc; i++) { + if (argv[i][KNOT_CTL_IDX_CMD] != NULL && + argv[i][KNOT_CTL_IDX_CMD][0] == '\0') { + ret = knot_ctl_send(ctl, KNOT_CTL_TYPE_BLOCK, NULL); + fake_ok(ret == KNOT_EOK, "Client send data block end type"); + } else { + ret = knot_ctl_send(ctl, KNOT_CTL_TYPE_DATA, &argv[i]); + fake_ok(ret == KNOT_EOK, "Client send data %zu", i); + } + } + } + + ret = knot_ctl_send(ctl, KNOT_CTL_TYPE_END, NULL); + fake_ok(ret == KNOT_EOK, "Client send final data"); + + diag("END: Client -> Server"); + diag("BEGIN: Client <- Server"); + + size_t count = 0; + knot_ctl_data_t data; + knot_ctl_type_t type = KNOT_CTL_TYPE_DATA; + while ((ret = knot_ctl_receive(ctl, &type, &data)) == KNOT_EOK) { + if (type == KNOT_CTL_TYPE_END) { + break; + } + if (argv[count][KNOT_CTL_IDX_CMD] != NULL && + argv[count][KNOT_CTL_IDX_CMD][0] == '\0') { + fake_ok(type == KNOT_CTL_TYPE_BLOCK, "Receive block end type"); + } else { + fake_ok(type == KNOT_CTL_TYPE_DATA, "Check data type"); + for (size_t i = 0; i < KNOT_CTL_IDX__COUNT; i++) { + fake_ok((data[i] == NULL && argv[count][i] == NULL) || + (data[i] != NULL && argv[count][i] != NULL), + "Client compare input item occupation %zu", i); + if (data[i] == NULL) { + continue; + } + + fake_ok(strcmp(data[i], argv[count][i]) == 0, + "Client compare input item '%s", argv[count][i]); + } + } + count++; + } + fake_ok(ret == KNOT_EOK, "Receive OK check"); + fake_ok(type == KNOT_CTL_TYPE_END, "Receive EOF type"); + fake_ok(count == argc, "Client compare input count '%zu'", argc); + + diag("END: Client <- Server"); + + knot_ctl_close(ctl); + knot_ctl_free(ctl); +} + +static void ctl_server(const char *socket, size_t argc, knot_ctl_data_t *argv) +{ + knot_ctl_t *ctl = knot_ctl_alloc(); + ok(ctl != NULL, "Allocate control"); + + int ret = knot_ctl_bind(ctl, socket); + is_int(KNOT_EOK, ret, "Bind control socket"); + + ret = knot_ctl_accept(ctl); + is_int(KNOT_EOK, ret, "Accept a connection"); + + diag("BEGIN: Server <- Client"); + + size_t count = 0; + knot_ctl_data_t data; + knot_ctl_type_t type = KNOT_CTL_TYPE_DATA; + while ((ret = knot_ctl_receive(ctl, &type, &data)) == KNOT_EOK) { + if (type == KNOT_CTL_TYPE_END) { + break; + } + if (argv[count][KNOT_CTL_IDX_CMD] != NULL && + argv[count][KNOT_CTL_IDX_CMD][0] == '\0') { + ok(type == KNOT_CTL_TYPE_BLOCK, "Receive block end type"); + } else { + ok(type == KNOT_CTL_TYPE_DATA, "Check data type"); + for (size_t i = 0; i < KNOT_CTL_IDX__COUNT; i++) { + ok((data[i] == NULL && argv[count][i] == NULL) || + (data[i] != NULL && argv[count][i] != NULL), + "Server compare input item occupation %zu", i); + if (data[i] == NULL) { + continue; + } + + ok(strcmp(data[i], argv[count][i]) == 0, + "Server compare input item '%s", argv[count][i]); + } + } + count++; + } + is_int(KNOT_EOK, ret, "Receive OK check"); + ok(type == KNOT_CTL_TYPE_END, "Receive EOF type"); + ok(count == argc, "Server compare input count '%zu'", argc); + + diag("END: Server <- Client"); + diag("BEGIN: Server -> Client"); + + if (argc > 0) { + for (size_t i = 0; i < argc; i++) { + if (argv[i][KNOT_CTL_IDX_CMD] != NULL && + argv[i][KNOT_CTL_IDX_CMD][0] == '\0') { + ret = knot_ctl_send(ctl, KNOT_CTL_TYPE_BLOCK, NULL); + is_int(KNOT_EOK, ret, "Client send data block end type"); + } else { + ret = knot_ctl_send(ctl, KNOT_CTL_TYPE_DATA, &argv[i]); + is_int(KNOT_EOK, ret, "Server send data %zu", i); + } + } + } + + ret = knot_ctl_send(ctl, KNOT_CTL_TYPE_END, NULL); + is_int(KNOT_EOK, ret, "Server send final data"); + + diag("END: Server -> Client"); + + knot_ctl_close(ctl); + knot_ctl_unbind(ctl); + knot_ctl_free(ctl); +} + +static void test_client_server_client(void) +{ + char *socket = test_mktemp(); + ok(socket != NULL, "Make a temporary socket file '%s'", socket); + + size_t data_len = 5; + knot_ctl_data_t data[] = { + { "command", "error", "section", "item", "identifier", + "zone", "owner", "ttl", "type", "data" }, + { [KNOT_CTL_IDX_DATA] = "\x01\x02" }, + { [KNOT_CTL_IDX_CMD] = "\0" }, // This means block end in this test! + { NULL }, + { [KNOT_CTL_IDX_ERROR] = "Ultra long message" } + }; + + // Fork a client process. + pid_t child_pid = fork(); + if (child_pid == -1) { + ok(child_pid >= 0, "Process fork"); + return; + } + if (child_pid == 0) { + ctl_client(socket, data_len, data); + free(socket); + return; + } else { + ctl_server(socket, data_len, data); + } + + int status = 0; + wait(&status); + ok(WIFEXITED(status), "Wait for client"); + + test_rm_rf(socket); + free(socket); +} + +int main(int argc, char *argv[]) +{ + plan_lazy(); + + diag("Client -> Server -> Client"); + test_client_server_client(); + + return 0; +} |