==> tests/plan.c <==1/* fleet.rs reconcile_plans, and seed. */
2#include "mesh/check.h"
3#include "mesh/fleet_plan.h"
4#include "mesh/mt.h"
5
6#include <stdlib.h>
7
8static mfd_doc doc(void) {
9 mfd_doc d = {.version = 7, .term = 3};
10 mesh_needs n = msn_default();
11 mfd_prog h = mfd_prog_new("hello", 0xabc, true, &n);
12 h.reset = 2;
13 mfd_prog_put(&d, "hello", h);
14 mfd_prog t = mfd_prog_new("train-b", 0x123, true, &n);
15 t.lockstep = true;
16 t.has_prev = true;
17 t.prev_dir = mt_strdup("train");
18 t.prev_hash = 0x99;
19 mfd_prog_put(&d, "train", t);
20 mesh_needs_free(&n);
21 return d;
22}
23
24static bool no_skip(void *ctx, const char *n, uint64_t h) { return (void)ctx, (void)n, (void)h, false; }
25static bool skip_hello(void *ctx, const char *n, uint64_t h) { return (void)ctx, (void)h, strcmp(n, "hello") == 0; }
26
27static mfl_action act(mfl_kind k, const char *name, const char *dir, uint64_t hash, bool run, uint32_t from) {
28 return (mfl_action){k, (char *)name, (char *)dir, hash, run, from};
29}
30
31static void expect(mfl_actions got, const mfl_action *want, size_t n) {
32 CHECK_U(got.n, n);
33 for (size_t i = 0; i < n && i < got.n; i++) CHECK(mfl_action_eq(&got.v[i], &want[i]));
34 mfl_actions_free(&got);
35}
36
37static void free_all(mfl_actual *a, size_t n) {
38 for (size_t i = 0; i < n; i++) mfl_actual_free(&a[i]);
39}
40
41int main(void) {
42 mfd_doc d = doc();
43 /* Nothing here: load both. */
44 mfl_action w1[] = {act(MFL_LOAD, "hello", "hello", 0xabc, true, 0), act(MFL_LOAD, "train", "train-b", 0x123, true, 0)};
45 expect(mfl_plan(&d, NULL, 0, no_skip, NULL, NULL, NULL, 0, 0), w1, 2);
46 /* Something extra (unload first), hello stopped and behind on resets, train on its previous image. */
47 mfl_actual a[] = {mfl_actual_new("pipesrc", "pipesrc", 1, false, 0, true), mfl_actual_new("hello", "hello", 0xabc, false, 0, false),
48 mfl_actual_new("train", "train", 0x99, true, 0x123, true)};
49 mfl_action w2[] = {act(MFL_UNLOAD, "pipesrc", NULL, 0, false, 0), act(MFL_ROLLBACK, "train", NULL, 0, false, 0), act(MFL_RUN, "hello", NULL, 0, true, 0),
50 act(MFL_RESET, "hello", NULL, 0, false, 0)};
51 expect(mfl_plan(&d, a, 3, no_skip, NULL, NULL, NULL, 0, 0), w2, 4);
52 free_all(a, 3);
53 /* train elsewhere: an upgrade by bytes; a skipped program is left alone; resets applied. */
54 mfl_actual b[] = {mfl_actual_new("hello", "hello", 0xabc, false, 0, true), mfl_actual_new("train", "train", 0x55, true, 0x66, true)};
55 const char *rn[] = {"hello"};
56 uint32_t rg[] = {2};
57 mfl_action w3[] = {act(MFL_UPGRADE, "train", "train-b", 0x123, false, 0)};
58 expect(mfl_plan(&d, b, 2, skip_hello, NULL, rn, rg, 1, 0), w3, 1);
59 free_all(b, 2);
60 /* In sync. */
61 mfl_actual c[] = {mfl_actual_new("hello", "hello", 0xabc, false, 0, true), mfl_actual_new("train", "train", 0x123, false, 0, true)};
62 expect(mfl_plan(&d, c, 2, no_skip, NULL, rn, rg, 1, 0), NULL, 0);
63 /* A failed program that should run is started again. */
64 c[0].failed = true;
65 mfl_action w4[] = {act(MFL_RUN, "hello", NULL, 0, true, 0)};
66 expect(mfl_plan(&d, c, 2, no_skip, NULL, rn, rg, 1, 0), w4, 1);
67 c[0].failed = false;
68 /* Placed elsewhere: not loaded here, unloaded if it is. */
69 mfd_doc e = mfd_doc_clone(&d);
70 mfd_prog *h = mfd_prog_get(&e, "hello");
71 h->at = ml_some((uint32_t[]){1, 2}, 2);
72 mfl_action w5[] = {act(MFL_UNLOAD, "hello", NULL, 0, false, 0)};
73 expect(mfl_plan(&e, c, 2, no_skip, NULL, rn, rg, 1, 0), w5, 1);
74 expect(mfl_plan(&e, c, 2, no_skip, NULL, rn, rg, 1, 1), NULL, 0);
75 free_all(c, 2);
76 /* A migration from 2 to 1: the target loads it with the view, the source keeps it as it is. */
77 ml_opt_free(&h->at);
78 h->at = ml_some((uint32_t[]){1}, 1);
79 h->has_from = true;
80 h->from = 2;
81 mfl_actual only_train[] = {mfl_actual_new("train", "train", 0x123, false, 0, true)};
82 mfl_action w6[] = {act(MFL_MIGRATE, "hello", "hello", 0xabc, true, 2)};
83 expect(mfl_plan(&e, only_train, 1, no_skip, NULL, rn, rg, 1, 1), w6, 1);
84 free_all(only_train, 1);
85 mfl_actual stopped[] = {mfl_actual_new("hello", "hello", 0xabc, false, 0, false), mfl_actual_new("train", "train", 0x123, false, 0, true)};
86 expect(mfl_plan(&e, stopped, 2, no_skip, NULL, rn, rg, 1, 2), NULL, 0);
87 expect(mfl_plan(&e, stopped, 2, no_skip, NULL, rn, rg, 1, 3), w5, 1);
88 free_all(stopped, 2);
89 mfd_doc_free(&e);
90 mfd_doc_free(&d);
91 return mesh_check_done();
92}