==> tests/snap.c <==1/* crates/mesh-top/tests/snap.rs, ported: snapshot parsing against mesh-abi's constants (framing,
2 * sections, fields, the host block) and the trace reply. */
3#include "mesh/check.h"
4#include "mesh/top_snap.h"
5
6#include <stdlib.h>
7#include <string.h>
8
9static void parts(uint8_t *head, mt_section secs[2], uint8_t *host) {
10 memset(head, 0, MESH_H_BYTES);
11 mt_put_u32(head, MESH_H_EPOCH, 9);
12 mt_section a = mt_section_new(3, 2, 0x41); /* an odd view length: padded to 0x44 */
13 mt_put_str(mt_section_entry(&a), MESH_PT_NAME, MESH_NAME_BYTES, "life");
14 mt_put_u32(mt_section_entry(&a), MESH_PT_STATE, MESH_ST_RUNNING);
15 mt_put_u64(mt_section_entry(&a), MESH_PT_PTX_HASH, 0x123456789abcdef0u);
16 mt_put_u32(mt_section_ctl(&a), MESH_P_ONLINE, 2);
17 mt_put_u32(mt_section_ctl(&a), MESH_P_COUNTERS + 4, 77);
18 mt_put_str(mt_section_ext(&a), MESH_PX_COUNTER_NAMES + MESH_NAME_BYTES, MESH_NAME_BYTES, "births");
19 mt_put_u32(mt_section_ext(&a), MESH_PX_FIELD_COUNT, 3);
20 const char *names[3] = {"gen", "rate", "tail"};
21 uint32_t types[3] = {MESH_FT_U32, MESH_FT_F32, MESH_FT_U64};
22 uint32_t offs[3] = {0, 4, 0x3c};
23 for (size_t i = 0; i < 3; i++) {
24 size_t at = MESH_PX_FIELDS + MESH_FIELD_BYTES * i;
25 mt_put_str(mt_section_ext(&a), at + MESH_FD_NAME, MESH_FD_NAME_MAX + 1, names[i]);
26 mt_put_u32(mt_section_ext(&a), at + MESH_FD_TYPE, types[i]);
27 mt_put_u32(mt_section_ext(&a), at + MESH_FD_OFF, offs[i]);
28 }
29 mt_put_u32(mt_section_node_rec(&a, 1), MESH_N_SM, 33);
30 mt_put_u64(mt_section_node_rec(&a, 1), MESH_N_BUSY_NS, 0x100000002u);
31 mt_put_u32(mt_section_view(&a), 0, 42);
32 mt_put_f32(mt_section_view(&a), 4, 1.5f);
33 mt_section_view(&a)[0x40] = 0xab;
34 mt_section b = mt_section_new(0, 0, 0);
35 mt_put_str(mt_section_entry(&b), MESH_PT_NAME, MESH_NAME_BYTES, "idle");
36 mt_put_u32(mt_section_entry(&b), MESH_PT_STATE, MESH_ST_LOADED);
37 memset(host, 0, MESH_SNAP_HOST);
38 mt_put_str(host, MESH_S_HOSTNAME, 32, "dgx-00");
39 mt_put_f32(host, MESH_S_RATES + 4 * 3, 1234.5f);
40 mt_put_u64(host, MESH_S_LOCK_STEP, (uint64_t)1 << 40);
41 mt_put_str(host, MESH_S_LOCK_NAME, MESH_NAME_BYTES, "train");
42 host[MESH_S_LOCK_VIEW + 31] = 7;
43 secs[0] = a;
44 secs[1] = b;
45}
46
47static bool parses(const uint8_t *b, size_t len, char **err) {
48 mt_snapshot s;
49 *err = NULL;
50 bool ok = mt_snapshot_parse(b, len, &s, err);
51 if (ok) mt_snapshot_free(&s);
52 return ok;
53}
54
55int main(void) {
56 static uint8_t head[MESH_H_BYTES], host[MESH_SNAP_HOST];
57 mt_section secs[2];
58 parts(head, secs, host);
59 mt_snapshot s = mt_snapshot_assemble(head, secs, 2, host);
60 CHECK_U(s.nsections, 2);
61 CHECK_U(mt_section_slot(&s.sections[0]), 0);
62 CHECK_U(mt_section_slot(&s.sections[1]), 3);
63 CHECK_U(s.len, MESH_SN_HEAD_BYTES + MESH_H_BYTES + mesh_section_bytes(0, 0) + mesh_section_bytes(2, 0x41) + MESH_SNAP_HOST);
64 CHECK_U(mt_snapshot_head(&s, MESH_H_EPOCH), 9);
65 const mt_section *p = mt_snapshot_by_name(&s, "life");
66 CHECK(p != NULL);
67 CHECK_U(mt_section_slot(p), 3);
68 CHECK_S(mt_section_state_name(p), "running");
69 CHECK(mt_section_running(p));
70 CHECK_U(mt_section_nodes(p), 2);
71 CHECK_U(mt_section_ptx_hash(p), 0x123456789abcdef0u);
72 char cn[64];
73 CHECK_U(mt_section_counter(p, 1), 77);
74 mt_section_counter_name(p, 1, cn);
75 CHECK_S(cn, "births");
76 mt_section_counter_name(p, 0, cn);
77 CHECK_S(cn, "");
78 mt_field f[MESH_MAX_FIELDS];
79 CHECK_U(mt_section_fields(p, f), 3);
80 char v[64];
81 CHECK_S(f[0].name, "gen");
82 mt_section_field_value(p, &f[0], v, sizeof v);
83 CHECK_S(v, "42");
84 mt_section_field_value(p, &f[1], v, sizeof v);
85 CHECK_S(v, "1.500000");
86 mt_section_field_value(p, &f[2], v, sizeof v); /* a u64 at 0x3c needs 0x44 bytes; only 0x41 were copied */
87 CHECK_S(v, "-");
88 CHECK_U(mt_section_view_len(p), 0x41);
89 CHECK_U(mt_section_view(p)[0x40], 0xab);
90 CHECK_U(mt_section_view_u32(p, 0x40), 0);
91 mt_node n = mt_section_node(p, 1);
92 CHECK_U(n.sm, 33);
93 CHECK_U(n.busy_ns, 0x100000002u);
94 CHECK_U(mt_section_node(p, 5).sm, 0);
95 CHECK_U(mt_snapshot_nodes_online(&s), 2);
96 CHECK(!mt_section_running(mt_snapshot_by_slot(&s, 0)));
97 char hn[97];
98 mt_snapshot_hostname(&s, hn);
99 CHECK_S(hn, "dgx-00");
100 CHECK(mt_snapshot_rate(&s, 3) == 1234.5f);
101 char ln[64];
102 uint64_t step;
103 uint8_t view[32];
104 mt_snapshot_lock_pair(&s, ln, &step, view);
105 CHECK_S(ln, "train");
106 CHECK_U(step, (uint64_t)1 << 40);
107 CHECK_U(view[31], 7);
108
109 /* Bad framing is refused. */
110 char *err;
111 uint8_t *good = malloc(s.len);
112 memcpy(good, s.bytes, s.len);
113 size_t len = s.len;
114 CHECK(parses(good, len, &err));
115 CHECK(!parses(good, len - 4, &err));
116 free(err);
117 uint8_t zeros[64] = {0};
118 CHECK(!parses(zeros, 64, &err));
119 free(err);
120 size_t first = MESH_SN_HEAD_BYTES + MESH_H_BYTES;
121 struct {
122 size_t at;
123 uint32_t v;
124 } bad[] = {{MESH_SN_VERSION, 1}, {MESH_SN_COUNT, 1}, {MESH_SN_COUNT, 3}, {first + MESH_SC_BYTES, 0x999},
125 {first + MESH_SC_NODES, 40}, {first + MESH_SC_SLOT, 3}, {MESH_SN_HOST_AT, 0x200}};
126 for (size_t i = 0; i < sizeof bad / sizeof bad[0]; i++) {
127 uint8_t *b = malloc(len);
128 memcpy(b, good, len);
129 mt_put_u32(b, bad[i].at, bad[i].v);
130 CHECK(!parses(b, len, &err));
131 if (i == 0) CHECK(err && strstr(err, "version"));
132 free(err);
133 free(b);
134 }
135 free(good);
136 mt_snapshot empty = mt_snapshot_assemble(head, NULL, 0, host);
137 CHECK_U(empty.nsections, 0);
138 mt_snapshot_free(&empty);
139 mt_snapshot_free(&s);
140 mt_section_free(&secs[0]);
141 mt_section_free(&secs[1]);
142
143 /* The trace reply. */
144 size_t per = 8 + (size_t)MESH_TRACE_PER_PROG * MESH_TRACE_BYTES;
145 uint8_t *t = calloc(2, per);
146 uint8_t *ring = t + 8;
147 mt_put_u32(t, 0, 2);
148 mt_put_u32(t, 4, 130);
149 for (uint32_t k = 0; k < 130; k++) {
150 size_t at = MESH_TRACE_BYTES * (k % MESH_TRACE_PER_PROG);
151 mt_put_u32(ring, at, 2 | (k % 3) << 8 | MESH_OP_TASK << 16);
152 mt_put_u32(ring, at + 4, k);
153 mt_put_u32(ring, at + 8, (UINT32_MAX - 500) + 10 * k);
154 mt_put_u32(ring, at + 12, (UINT32_MAX - 500) + 10 * k + 1000 + k);
155 }
156 uint8_t *t5 = t + per;
157 mt_put_u32(t5, 0, 5);
158 mt_put_u32(t5, 4, 3);
159 mt_put_u32(t5 + 8, 0, 5 | 1 << 8 | 4 << 16);
160 mt_trace_prog *v2;
161 size_t nv;
162 CHECK(mt_parse_trace(t, 2 * per, &v2, &nv, &err));
163 CHECK_U(nv, 2);
164 CHECK(v2[0].slot == 2 && v2[0].n == 130 && v2[0].nrecs == 128);
165 CHECK(v2[0].recs[0].ticket == 2 && v2[0].recs[127].ticket == 129);
166 CHECK(v2[0].recs[0].node == 2 && v2[0].recs[0].op == MESH_OP_TASK && mt_rec_ns(&v2[0].recs[0]) == 1002);
167 CHECK_U(v2[1].nrecs, 3);
168 CHECK(v2[1].recs[0].slot == 5 && v2[1].recs[0].node == 1 && v2[1].recs[0].op == 4);
169 double p50;
170 CHECK(mt_quantile_us(v2[0].recs, v2[0].nrecs, 0.5, &p50) && p50 >= 1.06 && p50 < 1.07);
171 CHECK(!mt_quantile_us(NULL, 0, 0.5, &p50));
172 mt_trace_free(v2, nv);
173 CHECK(!mt_parse_trace(t, 2 * per - 1, &v2, &nv, &err));
174 free(err);
175 mt_put_u32(t, 0, 99);
176 CHECK(!mt_parse_trace(t, 2 * per, &v2, &nv, &err));
177 free(err);
178 free(t);
179 return mesh_check_done();
180}