skip to content
==> tests/frame.c <==
1/* The job frames: the eleven frames of jobs.rs's `ops_frames_and_the_merge`, encoded byte for byte
2 * as the Rust encodes them and decoded back; decode's answers to bad bodies. */
3#include "mesh/jobs/frame.h"
4#include "mesh/abi/peer_frames.h"
5#include "mesh/abi/peer_sizes.h"
6#include "mesh/check.h"
7#include "gold_frame.h"
8
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12
13static size_t unhexs(const char *h, uint8_t *out) {
14    size_t n = strlen(h) / 2;
15    for (size_t i = 0; i < n; i++) {
16        unsigned v;
17        sscanf(h + 2 * i, "%2x", &v);
18        out[i] = (uint8_t)v;
19    }
20    return n;
21}
22
23static mj_res res(uint64_t lease) {
24    mj_res r = {.lease = lease, .member = 2, .result = 9, .out = mxalloc(3), .out_len = 3};
25    memcpy(r.out, (uint8_t[]){1, 2, 3}, 3);
26    if (lease % 2 == 1) {
27        r.has_blob = true;
28        memset(r.blob.hash.b, (int)lease, 32);
29        r.blob.len = 9216;
30        r.blob.holders = 0xb;
31    }
32    return r;
33}
34
35static mj_ops the_ops(const mj_spec *s) {
36    mj_res r7 = res(7);
37    mj_ops ops = {0};
38    mj_ops_push(&ops, mj_op_submit(s));
39    mj_ops_push(&ops, mj_op_done(s->id, 3, &r7));
40    mj_ops_push(&ops, mj_op_done_run(s->id, 4, 6, 8, 1));
41    mj_ops_push(&ops, mj_op_fail(s->id, 9, 3, "boom"));
42    mj_ops_push(&ops, mj_op_fails(s->id, 2, 1));
43    mj_ops_push(&ops, mj_op_dupes(s->id, 4));
44    mj_ops_push(&ops, mj_op_finish(s->id, 77, 1));
45    mj_ops_push(&ops, mj_op_cancel(s->id, "x"));
46    mj_ops_push(&ops, mj_op_tone(s->id, 2, 1));
47    mj_res_free(&r7);
48    return ops;
49}
50
51static mj_held *held1(mj_job_id job) {
52    mj_held *h = mxalloc(sizeof *h);
53    *h = (mj_held){4, job, mstrdup("p"), mj_ranges_of(1, 5)};
54    return h;
55}
56
57int main(void) {
58    mj_setup su = {6, 0};
59    mj_spec s = {.id = (uint64_t)1 << 32 | 1, .program = mstrdup("p"), .op = 254, .items = mj_ranges_of(0, 10), .attempts = 3,
60                 .mode = MJ_MODE_COLLECT, .setup = mj_setup_clone(&su, 1), .nsetup = 1, .submitted_ms = 5, .members = 5};
61    mj_frame fr[11];
62    mj_prog *pg = mxalloc(sizeof *pg);
63    *pg = (mj_prog){mstrdup("p"), 2, 8};
64    fr[0] = mj_frame_avail(3, pg, 1, held1(s.id), 1);
65    fr[1] = mj_frame_state(3, MESH_JOBS_ST_DELTA, 4, 2, 0, the_ops(&s));
66    fr[2] = mj_frame_state(3, MESH_JOBS_ST_PART, 4, 2, 7, the_ops(&s));
67    fr[3] = mj_frame_ack(3, 4, true);
68    fr[4] = mj_frame_pull(3);
69    fr[5] = mj_frame_have(3, MESH_JOBS_HAVE_DELTA, 2, 9, 4, the_ops(&s), NULL, 0);
70    fr[6] = mj_frame_have(3, MESH_JOBS_HAVE_END, 3, 0, 0, (mj_ops){0}, held1(s.id), 1);
71    mj_tally tl[] = {{1, 4}, {2, 5}};
72    mj_ops fold = {0};
73    mj_ops_push(&fold, mj_op_fold(s.id, 9, tl, 2));
74    fr[7] = mj_frame_state(3, MESH_JOBS_ST_PART, 1, 0, 0, fold);
75    mj_lease_msg l = {.lease = 5, .job = s.id, .program = mstrdup("p"), .op = 254};
76    mj_setup ls[] = {{6, 0}, {3, 32}};
77    l.setup = mj_setup_clone(ls, 2);
78    l.nsetup = 2;
79    CHECK(mj_ranges_parse("1-4,9", &l.items, NULL));
80    fr[8] = mj_frame_lease(3, l);
81    fr[9] = mj_frame_cut(3, 5, 2);
82    mj_item_res *it = mxalloc(2 * sizeof *it);
83    it[0] = (mj_item_res){.lease = 5, .job = s.id, .item = 1, .status = MESH_JOBS_RS_FAIL, .out = (uint8_t *)mstrdup("why"), .out_len = 3};
84    it[1] = (mj_item_res){.lease = 5, .job = s.id, .item = 2, .status = MESH_JOBS_RS_OK, .result = 3, .has_blob = true};
85    memset(it[1].blob.hash.b, 7, 32);
86    it[1].blob.len = 9;
87    it[1].blob.holders = 5;
88    fr[10] = mj_frame_result(3, it, 2);
89    CHECK_U(sizeof GOLD_FRAMES / sizeof *GOLD_FRAMES, 11);
90    for (int i = 0; i < 11; i++) {
91        msb b = {0};
92        mj_frame_encode(&fr[i], &b);
93        static uint8_t want[8192];
94        size_t wn = unhexs(GOLD_FRAMES[i], want);
95        if (!CHECK(b.n == wn && memcmp(b.p, want, wn) == 0)) fprintf(stderr, "frame %d differs\n", i);
96        uint32_t len;
97        memcpy(&len, b.p + 1, 4);
98        CHECK_U(len, b.n - 1 - MESH_JOB_HEAD);
99        mj_frame d;
100        char *err = NULL;
101        CHECK(mj_frame_decode((uint8_t)b.p[0], b.p + 1 + MESH_JOB_HEAD, b.n - 1 - MESH_JOB_HEAD, &d, &err) && mj_frame_eq(&d, &fr[i]));
102        mj_frame c = mj_frame_clone(&d);
103        CHECK(mj_frame_eq(&c, &fr[i]));
104        mj_frame_free(&c);
105        mj_frame_free(&d);
106        msb_free(&b);
107    }
108    for (size_t i = 0; i < sizeof GOLD_BAD / sizeof *GOLD_BAD; i++) {
109        uint8_t b[128];
110        size_t n = unhexs(GOLD_BAD[i].hex, b);
111        mj_frame d;
112        char *err = NULL;
113        if (mj_frame_decode((uint8_t)GOLD_BAD[i].ty, b, n, &d, &err)) {
114            CHECK_S("ok", GOLD_BAD[i].answer);
115            mj_frame_free(&d);
116        } else {
117            CHECK_S(err, GOLD_BAD[i].answer);
118            free(err);
119        }
120    }
121    for (int i = 0; i < 11; i++) mj_frame_free(&fr[i]);
122    mj_spec_free(&s);
123    return mesh_check_done();
124}