skip to content
==> tests/shared.c <==
1/* Asking the driver (answered, dropped, timed out), the http relay's counting, link queues, fail-stop. */
2#define _XOPEN_SOURCE 700 /* sexc compiles tests without the package's cflags (reported) */
3#include "mesh/check.h"
4#include "mesh/log.h"
5#include "mesh/shared.h"
6
7#include <pthread.h>
8#include <stdlib.h>
9#include <string.h>
10
11static void *driver(void *arg) {
12    mesh_shared *sh = arg;
13    mesh_cmd c;
14    while (mesh_chan_recv(sh->cmd, &c, 2000) == MESH_CHAN_OK) {
15        if (c.k == MESH_CMD_ROLLBACK) mesh_reply_errf(c.reply, "no program \"%s\" (`programs` lists them)", c.name);
16        else if (c.k == MESH_CMD_REQ) mesh_reply_bytes(c.reply, "HTTP/1.0 200 OK\r\n\r\nhi", 21);
17        else if (c.k == MESH_CMD_RESET) { mesh_reply_drop(c.reply); }
18        else if (c.k == MESH_CMD_UNLOAD) { mesh_cmd_free(&c); return NULL; }
19        else mesh_reply_ok(c.reply, "blink 412");
20        c.reply = NULL;
21        mesh_cmd_free(&c);
22    }
23    return NULL;
24}
25
26int main(void) {
27    static _Atomic bool quit;
28    mesh_mailbox mb = mesh_mailbox_test();
29    mesh_shared *sh = mesh_shared_new(mb, "out/programs", false, 0, 1, &quit);
30    pthread_t th;
31    pthread_create(&th, NULL, driver, sh);
32    char *t;
33    mesh_cmd c = mesh_cmd_new(MESH_CMD_LOAD);
34    c.has_src = true;
35    c.src = mesh_src_catalog("hello");
36    CHECK(mesh_shared_ask(sh, c, 1000, &t));
37    CHECK_S(t, "blink 412");
38    free(t);
39    c = mesh_cmd_new(MESH_CMD_ROLLBACK);
40    c.name = mesh_xstrdup("x");
41    CHECK(!mesh_shared_ask(sh, c, 1000, &t));
42    CHECK_S(t, "no program \"x\" (`programs` lists them)");
43    free(t);
44    /* Dropped unanswered: at once, with the Rust's words. */
45    c = mesh_cmd_new(MESH_CMD_RESET);
46    int64_t t0 = mesh_mono_ms();
47    CHECK(!mesh_shared_ask(sh, c, 60000, &t));
48    CHECK_S(t, "no answer from the driver in 60s");
49    CHECK(mesh_mono_ms() - t0 < 1000);
50    free(t);
51    uint8_t *resp;
52    size_t rn;
53    char *err = NULL;
54    CHECK(mesh_shared_http(sh, (const uint8_t *)"GET /status HTTP/1.0\r\n\r\n", 24, &resp, &rn, &err));
55    CHECK(rn == 21 && memcmp(resp, "HTTP/1.0 200 OK", 15) == 0);
56    free(resp);
57    CHECK_U(mesh_host_block_get_u32(&sh->host, MESH_S_HTTP_REQUESTS), 1);
58    uint8_t snap[MESH_SNAP_HOST];
59    mesh_host_block_bytes(&sh->host, snap);
60    CHECK(memcmp(snap + MESH_S_LAST_HTTP, "GET /status HTTP/1.0\0", 21) == 0);
61    c = mesh_cmd_new(MESH_CMD_UNLOAD);
62    mesh_chan_send(sh->cmd, &c);
63    pthread_join(th, NULL);
64    /* Nobody listens: a timeout. */
65    c = mesh_cmd_new(MESH_CMD_PROG_RUN);
66    CHECK(!mesh_shared_ask(sh, c, 30, &t));
67    CHECK_S(t, "no answer from the driver in 30ms");
68    free(t);
69    /* Not in a fleet. */
70    CHECK(!mesh_shared_change(sh, "load x", 100, &t));
71    CHECK_S(t, "not in a fleet");
72    free(t);
73
74    /* Link queues: copies, bounded, broadcast to the linked ones only. */
75    const uint8_t f[3] = {MESH_F_BEAT, 1, 2};
76    CHECK(!mesh_shared_send_peer(sh, 1, f, 3));
77    sh->link_out[1] = mesh_link_queue_new(2);
78    sh->link_out[3] = mesh_link_queue_new(2);
79    CHECK(mesh_shared_send_peer(sh, 1, f, 3));
80    CHECK(mesh_shared_broadcast(sh, f, 3));
81    CHECK(!mesh_shared_send_peer(sh, 1, f, 3)); /* full */
82    CHECK(!mesh_shared_send_peer_wait(sh, 1, f, 3, 20));
83    mesh_link_frame x;
84    CHECK(mesh_chan_try_recv(sh->link_out[1], &x) == MESH_CHAN_OK && x.n == 3 && x.b[0] == MESH_F_BEAT);
85    free(x.b);
86    CHECK(mesh_shared_send_peer_wait(sh, 1, f, 3, 20));
87    CHECK_U(mesh_chan_len(sh->link_out[3]), 1);
88    mesh_log_set_fd(-1);
89    mesh_shared_fail_stop(sh, "disk full");
90    CHECK(atomic_load(&quit) && !mesh_shared_send_peer(sh, 3, f, 3));
91    mesh_shared_free(sh);
92    free(mb.base);
93    return mesh_check_done();
94}