==> 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}