build_public_link_test.c (9892B)
1 #include <kit/build_coord.h> 2 3 #include "lib/kit_unit.h" 4 5 #include <string.h> 6 7 static KitUnit g_u; 8 9 #define EXPECT(c, ...) CU_EXPECT(&g_u, c, __VA_ARGS__) 10 11 typedef struct TestConn { 12 int unused; 13 } TestConn; 14 15 typedef struct TestTransport { 16 TestConn conn; 17 const uint8_t* replies[16]; 18 size_t reply_lens[16]; 19 size_t nreplies; 20 size_t next_reply; 21 uint8_t writes[16][256]; 22 size_t write_lens[16]; 23 size_t nwrites; 24 int dialed; 25 int closed; 26 } TestTransport; 27 28 const char* kit_debug_getenv(const char* name) { 29 if (kit_slice_eq_cstr(kit_slice_cstr(name), KIT_BUILD_ENV_SOCK)) 30 return "client-test"; 31 return NULL; 32 } 33 34 static void put_u8(uint8_t* buf, size_t* n, uint8_t v) { buf[(*n)++] = v; } 35 36 static void put_u16(uint8_t* buf, size_t* n, uint16_t v) { 37 put_u8(buf, n, (uint8_t)(v & 0xffu)); 38 put_u8(buf, n, (uint8_t)((v >> 8) & 0xffu)); 39 } 40 41 static void put_u64(uint8_t* buf, size_t* n, uint64_t v) { 42 size_t i; 43 for (i = 0; i < 8u; ++i) put_u8(buf, n, (uint8_t)(v >> (8u * i))); 44 } 45 46 static void put_bytes(uint8_t* buf, size_t* n, const void* data, size_t len) { 47 if (len) memcpy(buf + *n, data, len); 48 *n += len; 49 } 50 51 static void put_slice(uint8_t* buf, size_t* n, KitSlice s) { 52 put_u16(buf, n, (uint16_t)s.len); 53 put_bytes(buf, n, s.data, s.len); 54 } 55 56 static void fill_id(uint8_t id[KIT_BUILD_HASH_LEN], uint8_t seed) { 57 size_t i; 58 for (i = 0; i < KIT_BUILD_HASH_LEN; ++i) id[i] = (uint8_t)(seed + i); 59 } 60 61 static size_t resp_config(uint8_t* buf, KitSlice value) { 62 size_t n = 0; 63 put_u8(buf, &n, 0); 64 put_slice(buf, &n, value); 65 return n; 66 } 67 68 static size_t resp_source(uint8_t* buf, uint8_t seed, KitSlice path) { 69 uint8_t id[KIT_BUILD_HASH_LEN]; 70 size_t n = 0; 71 fill_id(id, seed); 72 put_u8(buf, &n, 0); 73 put_bytes(buf, &n, id, sizeof id); 74 put_slice(buf, &n, path); 75 return n; 76 } 77 78 static size_t resp_glob_path(uint8_t* buf, KitSlice path) { 79 size_t n = 0; 80 put_u8(buf, &n, 0); 81 put_u16(buf, &n, 1); 82 put_slice(buf, &n, path); 83 return n; 84 } 85 86 static size_t resp_status(uint8_t* buf, uint8_t status) { 87 size_t n = 0; 88 put_u8(buf, &n, status); 89 return n; 90 } 91 92 static size_t resp_need(uint8_t* buf, uint8_t seed, KitSlice path) { 93 uint8_t id[KIT_BUILD_HASH_LEN]; 94 size_t n = 0; 95 fill_id(id, seed); 96 put_u8(buf, &n, 0); 97 put_bytes(buf, &n, id, sizeof id); 98 put_slice(buf, &n, path); 99 return n; 100 } 101 102 static size_t resp_submit(uint8_t* buf, uint64_t token) { 103 size_t n = 0; 104 put_u8(buf, &n, 0); 105 put_u64(buf, &n, token); 106 return n; 107 } 108 109 static int t_dial(void* user, KitSlice endpoint, KitBuildConn** out) { 110 TestTransport* t = (TestTransport*)user; 111 if (!kit_slice_eq(endpoint, KIT_SLICE_LIT("client-test")) || !out) return 1; 112 t->dialed++; 113 *out = (KitBuildConn*)&t->conn; 114 return 0; 115 } 116 117 static int t_read(void* user, KitBuildConn* conn, uint8_t* buf, size_t cap, 118 size_t* n) { 119 TestTransport* t = (TestTransport*)user; 120 (void)conn; 121 if (!buf || !n || t->next_reply >= t->nreplies || 122 t->reply_lens[t->next_reply] > cap) 123 return 1; 124 memcpy(buf, t->replies[t->next_reply], t->reply_lens[t->next_reply]); 125 *n = t->reply_lens[t->next_reply]; 126 t->next_reply++; 127 return 0; 128 } 129 130 static int t_write(void* user, KitBuildConn* conn, const uint8_t* buf, 131 size_t n) { 132 TestTransport* t = (TestTransport*)user; 133 (void)conn; 134 if (!buf || t->nwrites >= 16 || n > sizeof t->writes[0]) return 1; 135 memcpy(t->writes[t->nwrites], buf, n); 136 t->write_lens[t->nwrites] = n; 137 t->nwrites++; 138 return 0; 139 } 140 141 static void t_close(void* user, KitBuildConn* conn) { 142 TestTransport* t = (TestTransport*)user; 143 (void)conn; 144 t->closed++; 145 } 146 147 static int glob_count(void* user, KitSlice path) { 148 int* n = (int*)user; 149 if (kit_slice_eq(path, KIT_SLICE_LIT("src/a.c"))) ++*n; 150 return 0; 151 } 152 153 static void test_client_transport(void) { 154 TestTransport tt; 155 KitBuildTransport tr; 156 KitBuildClient* client = NULL; 157 uint8_t r0[64], r1[128], r2[64], r3[4], r4[128], r5[32], r6[128]; 158 KitSlice value; 159 int present = 0; 160 uint8_t blob[KIT_BUILD_HASH_LEN]; 161 KitBuildKV kv; 162 KitSlice argv; 163 KitBuildRequest req; 164 KitBuildResult result; 165 KitBuildNeedToken token; 166 int nglob = 0; 167 168 memset(&tt, 0, sizeof tt); 169 memset(&tr, 0, sizeof tr); 170 tr.dial = t_dial; 171 tr.read_frame = t_read; 172 tr.write_frame = t_write; 173 tr.close = t_close; 174 tr.user = &tt; 175 tt.replies[tt.nreplies] = r0; 176 tt.reply_lens[tt.nreplies++] = resp_config(r0, KIT_SLICE_LIT("debug")); 177 tt.replies[tt.nreplies] = r1; 178 tt.reply_lens[tt.nreplies++] = 179 resp_source(r1, 0x10, KIT_SLICE_LIT("/work/src/main.c")); 180 tt.replies[tt.nreplies] = r2; 181 tt.reply_lens[tt.nreplies++] = resp_glob_path(r2, KIT_SLICE_LIT("src/a.c")); 182 tt.replies[tt.nreplies] = r3; 183 tt.reply_lens[tt.nreplies++] = resp_status(r3, 3); 184 tt.replies[tt.nreplies] = r4; 185 tt.reply_lens[tt.nreplies++] = 186 resp_need(r4, 0x20, KIT_SLICE_LIT("/out/lib")); 187 tt.replies[tt.nreplies] = r5; 188 tt.reply_lens[tt.nreplies++] = resp_submit(r5, 42); 189 tt.replies[tt.nreplies] = r6; 190 tt.reply_lens[tt.nreplies++] = 191 resp_need(r6, 0x30, KIT_SLICE_LIT("/out/tool")); 192 193 EXPECT(kit_build_client_open(&g_u.ctx, &tr, &client) == KIT_OK && client && 194 tt.dialed == 1, 195 "client open dials env endpoint"); 196 EXPECT(kit_build_client_config_get(client, KIT_SLICE_LIT("mode"), 197 KIT_SLICE_NULL, 0, &value, &present) == 198 KIT_OK && 199 present && kit_slice_eq(value, KIT_SLICE_LIT("debug")), 200 "client config get"); 201 EXPECT(kit_build_client_source(client, KIT_SLICE_LIT("src/main.c"), blob, 202 &value) == KIT_OK && 203 blob[0] == 0x10 && 204 kit_slice_eq(value, KIT_SLICE_LIT("/work/src/main.c")), 205 "client source"); 206 EXPECT(kit_build_client_glob(client, KIT_SLICE_LIT("src/*.c"), glob_count, 207 &nglob) == KIT_OK && 208 nglob == 1, 209 "client glob stream"); 210 211 kv.key = KIT_SLICE_LIT("opt"); 212 kv.value = KIT_SLICE_LIT("2"); 213 argv = KIT_SLICE_LIT("--fast"); 214 memset(&req, 0, sizeof req); 215 req.target = KIT_SLICE_LIT("//lib:core"); 216 req.config = &kv; 217 req.nconfig = 1; 218 req.argv = &argv; 219 req.argc = 1; 220 EXPECT(kit_build_client_need(client, &req, &result) == KIT_OK && 221 result.output_tree[0] == 0x20 && 222 strcmp(result.path, "/out/lib") == 0, 223 "client need"); 224 EXPECT(kit_build_client_need_submit(client, &req, &token) == KIT_OK && 225 token.id == 42, 226 "client need submit"); 227 EXPECT(kit_build_client_need_await(client, token, &result) == KIT_OK && 228 result.output_tree[0] == 0x30 && 229 strcmp(result.path, "/out/tool") == 0, 230 "client need await"); 231 EXPECT(tt.nwrites == 6 && tt.writes[0][0] == 1 && tt.writes[1][0] == 2 && 232 tt.writes[2][0] == 3 && tt.writes[3][0] == 4 && 233 tt.writes[4][0] == 5 && tt.writes[5][0] == 6, 234 "client request command order"); 235 kit_build_client_close(client); 236 EXPECT(tt.closed == 1, "client close"); 237 } 238 239 static void test_public_symbols(void) { 240 KitBuildStats stats; 241 KitBuildClient* client = (KitBuildClient*)1; 242 KitBuildNeedToken token; 243 KitBuildResult result; 244 KitBuildTestResult test_result; 245 KitSlice value; 246 int present = 1; 247 248 memset(&stats, 0xff, sizeof stats); 249 kit_build_stats(NULL, &stats); 250 EXPECT(stats.deep_hits == 0 && stats.shallow_hits == 0 && 251 stats.recipes_run == 0 && stats.materialize_misses == 0 && 252 stats.object_fetches == 0 && stats.trace_pulls == 0 && 253 stats.test_runs == 0 && stats.test_cache_hits == 0 && 254 stats.test_failures == 0, 255 "stats null handle clears output"); 256 EXPECT(kit_build(NULL, NULL, NULL) == KIT_INVALID, "kit_build rejects nulls"); 257 EXPECT(kit_build_test(NULL, NULL, NULL) == KIT_INVALID, 258 "kit_build_test rejects nulls"); 259 memset(&test_result, 0, sizeof test_result); 260 test_result.status = KIT_TEST_FAIL; 261 EXPECT(test_result.status == KIT_TEST_FAIL && 262 sizeof test_result.stdout_blob == KIT_BUILD_HASH_LEN && 263 sizeof test_result.stderr_blob == KIT_BUILD_HASH_LEN, 264 "test result public fields link"); 265 EXPECT(kit_build_coordinator_open(NULL, NULL, KIT_SLICE_NULL, NULL, NULL) == 266 KIT_INVALID, 267 "coordinator open rejects nulls"); 268 EXPECT(kit_build_traces_export(NULL, NULL) == KIT_ERR, 269 "trace export fails explicitly"); 270 EXPECT(kit_build_traces_import(NULL, NULL, NULL) == KIT_ERR, 271 "trace import fails explicitly"); 272 273 EXPECT(kit_build_client_open(NULL, NULL, &client) == KIT_INVALID && 274 client == NULL, 275 "client open rejects invalid args"); 276 EXPECT(kit_build_client_config_get(NULL, KIT_SLICE_LIT("x"), KIT_SLICE_NULL, 277 0, &value, &present) == KIT_INVALID && 278 value.s == NULL && value.len == 0 && present == 0, 279 "client config rejects invalid args"); 280 EXPECT(kit_build_client_source(NULL, KIT_SLICE_LIT("x"), result.output_tree, 281 &value) == KIT_INVALID, 282 "client source rejects invalid args"); 283 EXPECT(kit_build_client_glob(NULL, KIT_SLICE_LIT("*"), NULL, NULL) == 284 KIT_INVALID, 285 "client glob rejects invalid args"); 286 EXPECT(kit_build_client_need(NULL, NULL, &result) == KIT_INVALID, 287 "client need rejects invalid args"); 288 EXPECT(kit_build_client_need_submit(NULL, NULL, &token) == KIT_INVALID && 289 token.id == 0, 290 "client need-submit rejects invalid args"); 291 token.id = 7; 292 EXPECT(kit_build_client_need_await(NULL, token, &result) == KIT_INVALID, 293 "client need-await rejects invalid args"); 294 kit_build_client_close(NULL); 295 } 296 297 int main(void) { 298 kit_unit_init(&g_u); 299 test_public_symbols(); 300 test_client_transport(); 301 kit_unit_summary(&g_u, "build_public_link_test"); 302 return kit_unit_status(&g_u); 303 }