skip to content
==> tests/args.c <==
1/* args.rs's defaults, full, backends and errors, one for one. */
2#define _XOPEN_SOURCE 700 /* sexc compiles tests without the package's cflags (reported) */
3#include "mesh/args.h"
4#include "mesh/check.h"
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <unistd.h>
10
11/* The CUDA flags are tested as `--backend cuda` (the default on Linux). */
12static int p(const char *line, mesh_args *a, char **err) {
13    char buf[1024];
14    if (strstr(line, "--backend")) snprintf(buf, sizeof buf, "%s", line);
15    else snprintf(buf, sizeof buf, "--backend cuda %s", line);
16    char *argv[64];
17    int argc = 0;
18    for (char *t = strtok(buf, " "); t; t = strtok(NULL, " ")) argv[argc++] = t;
19    *err = NULL;
20    return mesh_args_parse(argc, argv, a, err);
21}
22
23static int bad(const char *line, const char *contains) {
24    mesh_args a;
25    char *err;
26    int r = p(line, &a, &err);
27    mesh_args_free(&a);
28    int ok = r == -1 && (!contains || (err && strstr(err, contains)));
29    if (!ok) fprintf(stderr, "accepted or wrong error for %s: %s\n", line, err ? err : "-");
30    free(err);
31    return ok;
32}
33
34int main(void) {
35    mesh_args a;
36    char *err;
37    CHECK_I(p("", &a, &err), 0);
38    CHECK_S(a.control, "127.0.0.1:7700");
39    CHECK_S(a.http, "0.0.0.0:8088");
40    CHECK(!a.cluster);
41    CHECK_S(a.nvjitlink, "/usr/local/cuda/lib64");
42    CHECK_S(a.programs, "out/programs");
43    CHECK(!a.state && !a.autoload);
44    mesh_args_free(&a);
45    CHECK_I(p("--nvjitlink /opt/x", &a, &err), 0);
46    CHECK_S(a.nvjitlink, "/opt/x");
47    mesh_args_free(&a);
48    CHECK_I(p("--programs /p --state /s --autoload", &a, &err), 0);
49    CHECK(!strcmp(a.programs, "/p") && !strcmp(a.state, "/s") && a.autoload);
50    mesh_args_free(&a);
51
52    CHECK_I(p("--sms 24 --control 127.0.0.1:17700 --http 127.0.0.1:18080 --system 0 --peer 127.0.0.1:17701 --fleet-state f", &a, &err), 0);
53    CHECK(a.has_sms && a.sms == 24 && a.has_system && a.system == 0);
54    mcc_topology t = mcc_pair_dialer("127.0.0.1:17701");
55    CHECK(a.cluster && mcc_topology_eq(&a.topo, &t));
56    CHECK_S(a.jobs_state, "f.jobs");
57    CHECK_S(a.blobs, "f.blobs");
58    mcc_topology_free(&t);
59    mesh_args_free(&a);
60    CHECK_I(p("--system 1 --peer-listen 0.0.0.0:7701 --fleet-state f", &a, &err), 0);
61    t = mcc_pair_listener("0.0.0.0:7701");
62    CHECK(mcc_topology_eq(&a.topo, &t));
63    mcc_topology_free(&t);
64    mesh_args_free(&a);
65    CHECK(bad("--system 1 --peer-listen 0.0.0.0:7701", "--fleet-state"));
66    CHECK(bad("--fleet-state f", NULL));
67    char path[64];
68    snprintf(path, sizeof path, "/tmp/meshd-args-%d.conf", (int)getpid());
69    FILE *f = fopen(path, "w");
70    fputs("systems = 3\n0.peer = h:1\n1.peer = h:2\n2.peer = g:3\n", f);
71    fclose(f);
72    char line[256];
73    snprintf(line, sizeof line, "--cluster %s --system 1 --fleet-state f", path);
74    CHECK_I(p(line, &a, &err), 0);
75    CHECK(a.topo.me == 1 && a.topo.n == 3 && a.topo.listen && !strcmp(a.topo.listen, "h:2") && a.topo.ndial == 1 && a.topo.dial_k[0] == 2 &&
76          !strcmp(a.topo.dial_addr[0], "g:3"));
77    CHECK(a.has_keys && !strcmp(ms_get(&a.keys, "2.peer"), "g:3"));
78    mesh_args_free(&a);
79    snprintf(line, sizeof line, "--cluster %s --system 3 --fleet-state f", path);
80    CHECK(bad(line, NULL));
81    snprintf(line, sizeof line, "--cluster %s", path);
82    CHECK(bad(line, "--cluster needs --system K"));
83    snprintf(line, sizeof line, "--cluster %s --peer h:1 --system 0", path);
84    CHECK(bad(line, "--peer: --cluster given already (one of --cluster, --peer, --peer-listen)"));
85    unlink(path);
86    CHECK(bad("--cluster /nonexistent/x --system 0", "--cluster /nonexistent/x: No such file or directory (os error 2)"));
87
88    CHECK_I(mesh_args_parse(0, NULL, &a, &err), 0);
89    CHECK_U(a.backend, MESH_DEFAULT_BACKEND);
90    mesh_args_free(&a);
91    CHECK_I(p("--backend metal", &a, &err), 0);
92    CHECK_U(a.backend, MESH_BACKEND_METAL);
93    mesh_args_free(&a);
94    CHECK_I(p("--backend cuda --sms 8", &a, &err), 0);
95    CHECK_U(a.backend, MESH_BACKEND_CUDA);
96    mesh_args_free(&a);
97    CHECK(bad("--backend vulkan", "--backend \"vulkan\": cuda, metal or wasm"));
98    CHECK(bad("--backend", "--backend needs a value"));
99    const char *cuda[5] = {"--sms 8", "--nvjitlink /x", "--isolation mps", "--cuda-lib /x", "--mps-pool 2"};
100    for (int i = 0; i < 5; i++) {
101        snprintf(line, sizeof line, "--backend metal %s", cuda[i]);
102        CHECK(bad(line, "CUDA flag"));
103    }
104    CHECK(bad("--backend wasm --sms 8", "--sms: a CUDA flag; --backend wasm has no such setting (no silent ignoring)"));
105    CHECK_I(p("--backend metal --programs /p", &a, &err), 0);
106    CHECK_S(a.programs, "/p");
107    mesh_args_free(&a);
108
109    CHECK(bad("--sms", "--sms needs a value"));
110    CHECK(bad("--sms 0", "--sms must be > 0"));
111    CHECK(bad("--sms x", "--sms: bad number \"x\""));
112    CHECK(bad("--bogus", "unknown flag \"--bogus\"\nusage: meshd"));
113    const char *gone[5] = {"--ptx x.ptx", "--entry mesh", "--nodes 4", "--run train", "--lr 0.1"};
114    for (int i = 0; i < 5; i++) CHECK(bad(gone[i], NULL));
115    CHECK(bad("--system 0", "--system needs --cluster FILE"));
116    CHECK(bad("--system 1 --peer h:1", "--peer is for --system 0"));
117    CHECK(bad("--system 0 --peer-listen h:1", "--peer-listen is for --system 1"));
118    CHECK(bad("--isolation green", "--isolation \"green\": blink or mps"));
119    CHECK(bad("--mps-dir /tmp/x", "--mps-dir and --mps-pool are for --isolation mps"));
120    CHECK(bad("--mps-pool 2", NULL));
121    CHECK(bad("--help", "usage: meshd [--backend"));
122    CHECK_I(p("--isolation mps --mps-pool 2", &a, &err), 0);
123    CHECK(a.has_mps_pool && a.mps_pool == 2);
124    mesh_args_free(&a);
125    CHECK_I(p("--isolation mps --mps-dir /tmp/x", &a, &err), 0);
126    CHECK(a.isolation == MESH_ISOLATION_MODE_MPS && !strcmp(a.mps_dir, "/tmp/x"));
127    mesh_args_free(&a);
128    CHECK_I(p("", &a, &err), 0);
129    CHECK(a.isolation == MESH_ISOLATION_MODE_BLINK);
130    mesh_args_free(&a);
131    return mesh_check_done();
132}