skip to content
==> tests/op.c <==
1/* Ops: one of each kind encoded exactly as the Rust encodes them, decoded back, and decode's answers
2 * to bad bytes; parts of at most PART_BYTES. */
3#include "mesh/jobs/op.h"
4#include "mesh/check.h"
5#include "gold_op.h"
6
7#include <stdlib.h>
8#include <string.h>
9
10static size_t unhexs(const char *h, uint8_t *out) {
11    size_t n = strlen(h) / 2;
12    for (size_t i = 0; i < n; i++) {
13        unsigned v;
14        sscanf(h + 2 * i, "%2x", &v);
15        out[i] = (uint8_t)v;
16    }
17    return n;
18}
19
20static mj_res res(uint64_t lease) {
21    mj_res r = {.lease = lease, .member = 2, .result = 9, .out = mxalloc(3), .out_len = 3};
22    memcpy(r.out, (uint8_t[]){1, 2, 3}, 3);
23    if (lease % 2 == 1) {
24        r.has_blob = true;
25        memset(r.blob.hash.b, (int)lease, 32);
26        r.blob.len = 9216;
27        r.blob.holders = 0xb;
28    }
29    return r;
30}
31
32int main(void) {
33    mj_setup su = {6, 0};
34    mj_spec s = {.id = (uint64_t)1 << 32 | 1, .program = mstrdup("p"), .op = 254, .items = mj_ranges_of(0, 10), .attempts = 3,
35                 .mode = MJ_MODE_COLLECT, .setup = mj_setup_clone(&su, 1), .nsetup = 1, .submitted_ms = 5, .members = 5};
36    mj_res r7 = res(7);
37    mj_tally tl[] = {{1, 4}, {2, 5}};
38    mj_ops ops = {0};
39    mj_ops_push(&ops, mj_op_submit(&s));
40    mj_ops_push(&ops, mj_op_done(s.id, 3, &r7));
41    mj_ops_push(&ops, mj_op_done_run(s.id, 4, 6, 8, 1));
42    mj_ops_push(&ops, mj_op_fail(s.id, 9, 3, "boom"));
43    mj_ops_push(&ops, mj_op_fails(s.id, 2, 1));
44    mj_ops_push(&ops, mj_op_dupes(s.id, 4));
45    mj_ops_push(&ops, mj_op_finish(s.id, 77, 1));
46    mj_ops_push(&ops, mj_op_cancel(s.id, "x"));
47    mj_ops_push(&ops, mj_op_tone(s.id, 2, 1));
48    mj_ops_push(&ops, mj_op_fold(s.id, 9, tl, 2));
49    mj_ops_push(&ops, mj_op_forget(s.id));
50    msb enc = {0};
51    mj_encode_ops(ops.v, ops.n, &enc);
52    static uint8_t want[4096];
53    size_t wn = unhexs(GOLD_OPS, want);
54    CHECK_U(enc.n, wn);
55    CHECK(enc.n == wn && memcmp(enc.p, want, wn) == 0);
56    mj_ops back = {0};
57    char *err = NULL;
58    CHECK(mj_decode_ops(enc.p, enc.n, &back, &err) && mj_ops_eq(&back, &ops));
59    /* Clones are deep and equal. */
60    mj_ops c = mj_ops_clone(&ops);
61    CHECK(mj_ops_eq(&c, &ops));
62    mj_ops_free(&c);
63    /* Bad bytes: the Rust's messages. */
64    for (size_t i = 0; i < sizeof GOLD_BAD / sizeof *GOLD_BAD; i++) {
65        uint8_t b[256];
66        size_t n = unhexs(GOLD_BAD[i][1], b);
67        mj_ops v = {0};
68        char *e = NULL;
69        if (mj_decode_ops(b, n, &v, &e)) {
70            char got[32];
71            snprintf(got, sizeof got, "ok %zu", v.n);
72            CHECK_S(got, GOLD_BAD[i][2]);
73        } else {
74            CHECK_S(e, GOLD_BAD[i][2]);
75            free(e);
76        }
77        mj_ops_free(&v);
78    }
79    /* Parts: under PART_BYTES each until the op that crosses it; never an op split; at least one. */
80    mj_parts p = mj_parts_of(NULL, 0);
81    CHECK(p.n == 1 && p.v[0].n == 0);
82    mj_parts_free(&p);
83    mj_ops many = {0};
84    mj_res big = {.lease = 1, .out = mxalloc(1000), .out_len = 1000};
85    for (int i = 0; i < 3000; i++) mj_ops_push(&many, mj_op_done(1, (uint64_t)i, &big));
86    p = mj_parts_of(many.v, many.n);
87    CHECK_U(p.n, 3); /* 3000 x 1038 bytes = 3.0 MiB: two full parts and the rest */
88    size_t total = 0, nops = 0;
89    for (size_t i = 0; i < p.n; i++) {
90        mj_ops part = {0};
91        CHECK(mj_decode_ops(p.v[i].p, p.v[i].n, &part, NULL));
92        if (i + 1 < p.n) CHECK(p.v[i].n >= MESH_JOBS_PART_BYTES && p.v[i].n < MESH_JOBS_PART_BYTES + 1038);
93        total += p.v[i].n;
94        nops += part.n;
95        mj_ops_free(&part);
96    }
97    CHECK_U(nops, 3000);
98    CHECK_U(total, 3000u * 1038u);
99    mj_parts_free(&p);
100    mj_ops_free(&many);
101    mj_res_free(&big);
102    mj_ops_free(&back);
103    mj_ops_free(&ops);
104    mj_res_free(&r7);
105    mj_spec_free(&s);
106    msb_free(&enc);
107    return mesh_check_done();
108}