summaryrefslogtreecommitdiffstats
path: root/tests/libknot/test_control.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/libknot/test_control.c')
-rw-r--r--tests/libknot/test_control.c221
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;
+}