skip to content
==> tests/mock.c <==
1/* crates/mesh-top tests/snap.rs mock_snapshot_round_trips, plus the control port spoken raw
2 * (the client's own tests drive it through the endpoint thread). */
3#include "mesh/check.h"
4#include "mesh/top_mock.h"
5
6#include <arpa/inet.h>
7#include <netinet/in.h>
8#include <stdlib.h>
9#include <string.h>
10#include <sys/socket.h>
11#include <unistd.h>
12
13static void round_trips(void) {
14    mt_mock_world w;
15    mt_mock_world_init(&w, "m", MESH_PEER_NONE);
16    mt_snapshot s = mt_mock_synth(&w);
17    mt_snapshot again;
18    char *err = NULL;
19    CHECK(mt_snapshot_parse(s.bytes, s.len, &again, &err));
20    const char *want[5] = {"doom", "train", "infer", "http", "hello"};
21    CHECK_U(again.nsections, 5);
22    for (size_t i = 0; i < 5 && i < again.nsections; i++) {
23        char name[3 * MESH_NAME_BYTES + 1];
24        mt_section_name(&again.sections[i], name);
25        CHECK_S(name, want[i]);
26    }
27    CHECK_U(mt_section_view_len(mt_snapshot_by_name(&again, "doom")), MESH_DOOM_SNAP_BYTES);
28    CHECK(memcmp(mt_section_view(mt_snapshot_by_name(&again, "hello")), "HELO", 4) == 0);
29    mt_snapshot_free(&again);
30    mt_snapshot_free(&s);
31    mt_mock_world_free(&w);
32}
33
34static int dial(const char *addr) {
35    const char *colon = strrchr(addr, ':');
36    struct sockaddr_in sa = {.sin_family = AF_INET, .sin_port = htons((uint16_t)atoi(colon + 1))};
37    inet_pton(AF_INET, "127.0.0.1", &sa.sin_addr);
38    int fd = socket(AF_INET, SOCK_STREAM, 0);
39    if (connect(fd, (struct sockaddr *)&sa, sizeof sa) != 0) {
40        close(fd);
41        return -1;
42    }
43    return fd;
44}
45
46static bool read_n(int fd, uint8_t *b, size_t n) {
47    while (n) {
48        ssize_t k = recv(fd, b, n, 0);
49        if (k <= 0) return false;
50        b += k;
51        n -= (size_t)k;
52    }
53    return true;
54}
55
56static uint8_t *framed(int fd, const char *req, size_t *len) {
57    send(fd, req, strlen(req), 0);
58    uint8_t h[4];
59    if (!read_n(fd, h, 4)) return NULL;
60    *len = (size_t)h[0] | (size_t)h[1] << 8 | (size_t)h[2] << 16 | (size_t)h[3] << 24;
61    uint8_t *b = malloc(*len + 1);
62    if (!read_n(fd, b, *len)) {
63        free(b);
64        return NULL;
65    }
66    b[*len] = 0;
67    return b;
68}
69
70static void line(int fd, const char *req, char *out, size_t cap) {
71    send(fd, req, strlen(req), 0);
72    size_t n = 0;
73    while (n + 1 < cap) {
74        char c;
75        if (recv(fd, &c, 1, 0) != 1 || c == '\n') break;
76        out[n++] = c;
77    }
78    out[n] = 0;
79}
80
81static void server(void) {
82    mt_mock *m = mt_mock_start("127.0.0.1:0", "mock-a", 0);
83    CHECK(m != NULL);
84    if (!m) return;
85    int fd = dial(mt_mock_addr(m));
86    CHECK(fd >= 0);
87    size_t len;
88    uint8_t *b = framed(fd, "snap\n", &len);
89    CHECK(b != NULL);
90    mt_snapshot s;
91    char *err = NULL;
92    CHECK(b && mt_snapshot_parse(b, len, &s, &err));
93    if (b && !err) {
94        char host[97];
95        mt_snapshot_hostname(&s, host);
96        CHECK_S(host, "mock-a");
97        CHECK_U(s.nsections, 5);
98        mt_snapshot_free(&s);
99    }
100    free(b);
101    char t[128];
102    line(fd, "stop train\n", t, sizeof t);
103    CHECK_S(t, "ok");
104    b = framed(fd, "http /hi\n", &len);
105    CHECK(b && strncmp((char *)b, "HTTP/1.0 200 OK", 15) == 0);
106    free(b);
107    line(fd, "bogus\n", t, sizeof t);
108    CHECK(strncmp(t, "err", 3) == 0);
109    b = framed(fd, "catalog\n", &len);
110    CHECK(b != NULL);
111    if (b) {
112        char want[256] = "";
113        for (int i = 0; i < MT_MOCK_CATALOG_LEN; i++) strcat(strcat(want, MT_MOCK_CATALOG[i]), "\n");
114        CHECK_S((char *)b, want);
115    }
116    free(b);
117    b = framed(fd, "programs\n", &len);
118    CHECK(b && strstr((char *)b, "\n4 hello running 2 ") && strstr((char *)b, "fields hello magic last_arg last_result"));
119    free(b);
120    mt_mock_lock(m);
121    CHECK_U(mt_mock_prog_named(mt_mock_world_of(m), "train")->state, MESH_ST_LOADED);
122    mt_mock_unlock(m);
123    CHECK(mt_mock_saw(m, "http /hi"));
124    CHECK(!mt_mock_saw(m, "http /nope"));
125    mt_mock_stop(m);
126    char c;
127    CHECK(recv(fd, &c, 1, 0) <= 0); /* the server closed us */
128    close(fd);
129}
130
131int main(void) {
132    mt_clock_virtual(true, 1000000000000u);
133    round_trips();
134    server();
135    return mesh_check_done();
136}