PageRenderTime 25ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/reftable/readwrite_test.c

https://bitbucket.org/grubix/git
C | 851 lines | 696 code | 133 blank | 22 comment | 63 complexity | 9ba00de904f9ea0c3738d0e903390fdc MD5 | raw file
Possible License(s): Apache-2.0, BSD-2-Clause, GPL-2.0, LGPL-2.1
  1. /*
  2. Copyright 2020 Google LLC
  3. Use of this source code is governed by a BSD-style
  4. license that can be found in the LICENSE file or at
  5. https://developers.google.com/open-source/licenses/bsd
  6. */
  7. #include "system.h"
  8. #include "basics.h"
  9. #include "block.h"
  10. #include "blocksource.h"
  11. #include "constants.h"
  12. #include "reader.h"
  13. #include "record.h"
  14. #include "test_framework.h"
  15. #include "reftable-tests.h"
  16. #include "reftable-writer.h"
  17. static const int update_index = 5;
  18. static void test_buffer(void)
  19. {
  20. struct strbuf buf = STRBUF_INIT;
  21. struct reftable_block_source source = { NULL };
  22. struct reftable_block out = { NULL };
  23. int n;
  24. uint8_t in[] = "hello";
  25. strbuf_add(&buf, in, sizeof(in));
  26. block_source_from_strbuf(&source, &buf);
  27. EXPECT(block_source_size(&source) == 6);
  28. n = block_source_read_block(&source, &out, 0, sizeof(in));
  29. EXPECT(n == sizeof(in));
  30. EXPECT(!memcmp(in, out.data, n));
  31. reftable_block_done(&out);
  32. n = block_source_read_block(&source, &out, 1, 2);
  33. EXPECT(n == 2);
  34. EXPECT(!memcmp(out.data, "el", 2));
  35. reftable_block_done(&out);
  36. block_source_close(&source);
  37. strbuf_release(&buf);
  38. }
  39. static void write_table(char ***names, struct strbuf *buf, int N,
  40. int block_size, uint32_t hash_id)
  41. {
  42. struct reftable_write_options opts = {
  43. .block_size = block_size,
  44. .hash_id = hash_id,
  45. };
  46. struct reftable_writer *w =
  47. reftable_new_writer(&strbuf_add_void, buf, &opts);
  48. struct reftable_ref_record ref = { NULL };
  49. int i = 0, n;
  50. struct reftable_log_record log = { NULL };
  51. const struct reftable_stats *stats = NULL;
  52. *names = reftable_calloc(sizeof(char *) * (N + 1));
  53. reftable_writer_set_limits(w, update_index, update_index);
  54. for (i = 0; i < N; i++) {
  55. uint8_t hash[GIT_SHA256_RAWSZ] = { 0 };
  56. char name[100];
  57. int n;
  58. set_test_hash(hash, i);
  59. snprintf(name, sizeof(name), "refs/heads/branch%02d", i);
  60. ref.refname = name;
  61. ref.update_index = update_index;
  62. ref.value_type = REFTABLE_REF_VAL1;
  63. ref.value.val1 = hash;
  64. (*names)[i] = xstrdup(name);
  65. n = reftable_writer_add_ref(w, &ref);
  66. EXPECT(n == 0);
  67. }
  68. for (i = 0; i < N; i++) {
  69. uint8_t hash[GIT_SHA256_RAWSZ] = { 0 };
  70. char name[100];
  71. int n;
  72. set_test_hash(hash, i);
  73. snprintf(name, sizeof(name), "refs/heads/branch%02d", i);
  74. log.refname = name;
  75. log.update_index = update_index;
  76. log.value_type = REFTABLE_LOG_UPDATE;
  77. log.value.update.new_hash = hash;
  78. log.value.update.message = "message";
  79. n = reftable_writer_add_log(w, &log);
  80. EXPECT(n == 0);
  81. }
  82. n = reftable_writer_close(w);
  83. EXPECT(n == 0);
  84. stats = reftable_writer_stats(w);
  85. for (i = 0; i < stats->ref_stats.blocks; i++) {
  86. int off = i * opts.block_size;
  87. if (off == 0) {
  88. off = header_size(
  89. (hash_id == GIT_SHA256_FORMAT_ID) ? 2 : 1);
  90. }
  91. EXPECT(buf->buf[off] == 'r');
  92. }
  93. EXPECT(stats->log_stats.blocks > 0);
  94. reftable_writer_free(w);
  95. }
  96. static void test_log_buffer_size(void)
  97. {
  98. struct strbuf buf = STRBUF_INIT;
  99. struct reftable_write_options opts = {
  100. .block_size = 4096,
  101. };
  102. int err;
  103. int i;
  104. struct reftable_log_record
  105. log = { .refname = "refs/heads/master",
  106. .update_index = 0xa,
  107. .value_type = REFTABLE_LOG_UPDATE,
  108. .value = { .update = {
  109. .name = "Han-Wen Nienhuys",
  110. .email = "hanwen@google.com",
  111. .tz_offset = 100,
  112. .time = 0x5e430672,
  113. .message = "commit: 9\n",
  114. } } };
  115. struct reftable_writer *w =
  116. reftable_new_writer(&strbuf_add_void, &buf, &opts);
  117. /* This tests buffer extension for log compression. Must use a random
  118. hash, to ensure that the compressed part is larger than the original.
  119. */
  120. uint8_t hash1[GIT_SHA1_RAWSZ], hash2[GIT_SHA1_RAWSZ];
  121. for (i = 0; i < GIT_SHA1_RAWSZ; i++) {
  122. hash1[i] = (uint8_t)(rand() % 256);
  123. hash2[i] = (uint8_t)(rand() % 256);
  124. }
  125. log.value.update.old_hash = hash1;
  126. log.value.update.new_hash = hash2;
  127. reftable_writer_set_limits(w, update_index, update_index);
  128. err = reftable_writer_add_log(w, &log);
  129. EXPECT_ERR(err);
  130. err = reftable_writer_close(w);
  131. EXPECT_ERR(err);
  132. reftable_writer_free(w);
  133. strbuf_release(&buf);
  134. }
  135. static void test_log_overflow(void)
  136. {
  137. struct strbuf buf = STRBUF_INIT;
  138. char msg[256] = { 0 };
  139. struct reftable_write_options opts = {
  140. .block_size = ARRAY_SIZE(msg),
  141. };
  142. int err;
  143. struct reftable_log_record
  144. log = { .refname = "refs/heads/master",
  145. .update_index = 0xa,
  146. .value_type = REFTABLE_LOG_UPDATE,
  147. .value = { .update = {
  148. .name = "Han-Wen Nienhuys",
  149. .email = "hanwen@google.com",
  150. .tz_offset = 100,
  151. .time = 0x5e430672,
  152. .message = msg,
  153. } } };
  154. struct reftable_writer *w =
  155. reftable_new_writer(&strbuf_add_void, &buf, &opts);
  156. uint8_t hash1[GIT_SHA1_RAWSZ] = {1}, hash2[GIT_SHA1_RAWSZ] = { 2 };
  157. memset(msg, 'x', sizeof(msg) - 1);
  158. log.value.update.old_hash = hash1;
  159. log.value.update.new_hash = hash2;
  160. reftable_writer_set_limits(w, update_index, update_index);
  161. err = reftable_writer_add_log(w, &log);
  162. EXPECT(err == REFTABLE_ENTRY_TOO_BIG_ERROR);
  163. reftable_writer_free(w);
  164. strbuf_release(&buf);
  165. }
  166. static void test_log_write_read(void)
  167. {
  168. int N = 2;
  169. char **names = reftable_calloc(sizeof(char *) * (N + 1));
  170. int err;
  171. struct reftable_write_options opts = {
  172. .block_size = 256,
  173. };
  174. struct reftable_ref_record ref = { NULL };
  175. int i = 0;
  176. struct reftable_log_record log = { NULL };
  177. int n;
  178. struct reftable_iterator it = { NULL };
  179. struct reftable_reader rd = { NULL };
  180. struct reftable_block_source source = { NULL };
  181. struct strbuf buf = STRBUF_INIT;
  182. struct reftable_writer *w =
  183. reftable_new_writer(&strbuf_add_void, &buf, &opts);
  184. const struct reftable_stats *stats = NULL;
  185. reftable_writer_set_limits(w, 0, N);
  186. for (i = 0; i < N; i++) {
  187. char name[256];
  188. struct reftable_ref_record ref = { NULL };
  189. snprintf(name, sizeof(name), "b%02d%0*d", i, 130, 7);
  190. names[i] = xstrdup(name);
  191. ref.refname = name;
  192. ref.update_index = i;
  193. err = reftable_writer_add_ref(w, &ref);
  194. EXPECT_ERR(err);
  195. }
  196. for (i = 0; i < N; i++) {
  197. uint8_t hash1[GIT_SHA1_RAWSZ], hash2[GIT_SHA1_RAWSZ];
  198. struct reftable_log_record log = { NULL };
  199. set_test_hash(hash1, i);
  200. set_test_hash(hash2, i + 1);
  201. log.refname = names[i];
  202. log.update_index = i;
  203. log.value_type = REFTABLE_LOG_UPDATE;
  204. log.value.update.old_hash = hash1;
  205. log.value.update.new_hash = hash2;
  206. err = reftable_writer_add_log(w, &log);
  207. EXPECT_ERR(err);
  208. }
  209. n = reftable_writer_close(w);
  210. EXPECT(n == 0);
  211. stats = reftable_writer_stats(w);
  212. EXPECT(stats->log_stats.blocks > 0);
  213. reftable_writer_free(w);
  214. w = NULL;
  215. block_source_from_strbuf(&source, &buf);
  216. err = init_reader(&rd, &source, "file.log");
  217. EXPECT_ERR(err);
  218. err = reftable_reader_seek_ref(&rd, &it, names[N - 1]);
  219. EXPECT_ERR(err);
  220. err = reftable_iterator_next_ref(&it, &ref);
  221. EXPECT_ERR(err);
  222. /* end of iteration. */
  223. err = reftable_iterator_next_ref(&it, &ref);
  224. EXPECT(0 < err);
  225. reftable_iterator_destroy(&it);
  226. reftable_ref_record_release(&ref);
  227. err = reftable_reader_seek_log(&rd, &it, "");
  228. EXPECT_ERR(err);
  229. i = 0;
  230. while (1) {
  231. int err = reftable_iterator_next_log(&it, &log);
  232. if (err > 0) {
  233. break;
  234. }
  235. EXPECT_ERR(err);
  236. EXPECT_STREQ(names[i], log.refname);
  237. EXPECT(i == log.update_index);
  238. i++;
  239. reftable_log_record_release(&log);
  240. }
  241. EXPECT(i == N);
  242. reftable_iterator_destroy(&it);
  243. /* cleanup. */
  244. strbuf_release(&buf);
  245. free_names(names);
  246. reader_close(&rd);
  247. }
  248. static void test_log_zlib_corruption(void)
  249. {
  250. struct reftable_write_options opts = {
  251. .block_size = 256,
  252. };
  253. struct reftable_iterator it = { 0 };
  254. struct reftable_reader rd = { 0 };
  255. struct reftable_block_source source = { 0 };
  256. struct strbuf buf = STRBUF_INIT;
  257. struct reftable_writer *w =
  258. reftable_new_writer(&strbuf_add_void, &buf, &opts);
  259. const struct reftable_stats *stats = NULL;
  260. uint8_t hash1[GIT_SHA1_RAWSZ] = { 1 };
  261. uint8_t hash2[GIT_SHA1_RAWSZ] = { 2 };
  262. char message[100] = { 0 };
  263. int err, i, n;
  264. struct reftable_log_record log = {
  265. .refname = "refname",
  266. .value_type = REFTABLE_LOG_UPDATE,
  267. .value = {
  268. .update = {
  269. .new_hash = hash1,
  270. .old_hash = hash2,
  271. .name = "My Name",
  272. .email = "myname@invalid",
  273. .message = message,
  274. },
  275. },
  276. };
  277. for (i = 0; i < sizeof(message) - 1; i++)
  278. message[i] = (uint8_t)(rand() % 64 + ' ');
  279. reftable_writer_set_limits(w, 1, 1);
  280. err = reftable_writer_add_log(w, &log);
  281. EXPECT_ERR(err);
  282. n = reftable_writer_close(w);
  283. EXPECT(n == 0);
  284. stats = reftable_writer_stats(w);
  285. EXPECT(stats->log_stats.blocks > 0);
  286. reftable_writer_free(w);
  287. w = NULL;
  288. /* corrupt the data. */
  289. buf.buf[50] ^= 0x99;
  290. block_source_from_strbuf(&source, &buf);
  291. err = init_reader(&rd, &source, "file.log");
  292. EXPECT_ERR(err);
  293. err = reftable_reader_seek_log(&rd, &it, "refname");
  294. EXPECT(err == REFTABLE_ZLIB_ERROR);
  295. reftable_iterator_destroy(&it);
  296. /* cleanup. */
  297. strbuf_release(&buf);
  298. reader_close(&rd);
  299. }
  300. static void test_table_read_write_sequential(void)
  301. {
  302. char **names;
  303. struct strbuf buf = STRBUF_INIT;
  304. int N = 50;
  305. struct reftable_iterator it = { NULL };
  306. struct reftable_block_source source = { NULL };
  307. struct reftable_reader rd = { NULL };
  308. int err = 0;
  309. int j = 0;
  310. write_table(&names, &buf, N, 256, GIT_SHA1_FORMAT_ID);
  311. block_source_from_strbuf(&source, &buf);
  312. err = init_reader(&rd, &source, "file.ref");
  313. EXPECT_ERR(err);
  314. err = reftable_reader_seek_ref(&rd, &it, "");
  315. EXPECT_ERR(err);
  316. while (1) {
  317. struct reftable_ref_record ref = { NULL };
  318. int r = reftable_iterator_next_ref(&it, &ref);
  319. EXPECT(r >= 0);
  320. if (r > 0) {
  321. break;
  322. }
  323. EXPECT(0 == strcmp(names[j], ref.refname));
  324. EXPECT(update_index == ref.update_index);
  325. j++;
  326. reftable_ref_record_release(&ref);
  327. }
  328. EXPECT(j == N);
  329. reftable_iterator_destroy(&it);
  330. strbuf_release(&buf);
  331. free_names(names);
  332. reader_close(&rd);
  333. }
  334. static void test_table_write_small_table(void)
  335. {
  336. char **names;
  337. struct strbuf buf = STRBUF_INIT;
  338. int N = 1;
  339. write_table(&names, &buf, N, 4096, GIT_SHA1_FORMAT_ID);
  340. EXPECT(buf.len < 200);
  341. strbuf_release(&buf);
  342. free_names(names);
  343. }
  344. static void test_table_read_api(void)
  345. {
  346. char **names;
  347. struct strbuf buf = STRBUF_INIT;
  348. int N = 50;
  349. struct reftable_reader rd = { NULL };
  350. struct reftable_block_source source = { NULL };
  351. int err;
  352. int i;
  353. struct reftable_log_record log = { NULL };
  354. struct reftable_iterator it = { NULL };
  355. write_table(&names, &buf, N, 256, GIT_SHA1_FORMAT_ID);
  356. block_source_from_strbuf(&source, &buf);
  357. err = init_reader(&rd, &source, "file.ref");
  358. EXPECT_ERR(err);
  359. err = reftable_reader_seek_ref(&rd, &it, names[0]);
  360. EXPECT_ERR(err);
  361. err = reftable_iterator_next_log(&it, &log);
  362. EXPECT(err == REFTABLE_API_ERROR);
  363. strbuf_release(&buf);
  364. for (i = 0; i < N; i++) {
  365. reftable_free(names[i]);
  366. }
  367. reftable_iterator_destroy(&it);
  368. reftable_free(names);
  369. reader_close(&rd);
  370. strbuf_release(&buf);
  371. }
  372. static void test_table_read_write_seek(int index, int hash_id)
  373. {
  374. char **names;
  375. struct strbuf buf = STRBUF_INIT;
  376. int N = 50;
  377. struct reftable_reader rd = { NULL };
  378. struct reftable_block_source source = { NULL };
  379. int err;
  380. int i = 0;
  381. struct reftable_iterator it = { NULL };
  382. struct strbuf pastLast = STRBUF_INIT;
  383. struct reftable_ref_record ref = { NULL };
  384. write_table(&names, &buf, N, 256, hash_id);
  385. block_source_from_strbuf(&source, &buf);
  386. err = init_reader(&rd, &source, "file.ref");
  387. EXPECT_ERR(err);
  388. EXPECT(hash_id == reftable_reader_hash_id(&rd));
  389. if (!index) {
  390. rd.ref_offsets.index_offset = 0;
  391. } else {
  392. EXPECT(rd.ref_offsets.index_offset > 0);
  393. }
  394. for (i = 1; i < N; i++) {
  395. int err = reftable_reader_seek_ref(&rd, &it, names[i]);
  396. EXPECT_ERR(err);
  397. err = reftable_iterator_next_ref(&it, &ref);
  398. EXPECT_ERR(err);
  399. EXPECT(0 == strcmp(names[i], ref.refname));
  400. EXPECT(REFTABLE_REF_VAL1 == ref.value_type);
  401. EXPECT(i == ref.value.val1[0]);
  402. reftable_ref_record_release(&ref);
  403. reftable_iterator_destroy(&it);
  404. }
  405. strbuf_addstr(&pastLast, names[N - 1]);
  406. strbuf_addstr(&pastLast, "/");
  407. err = reftable_reader_seek_ref(&rd, &it, pastLast.buf);
  408. if (err == 0) {
  409. struct reftable_ref_record ref = { NULL };
  410. int err = reftable_iterator_next_ref(&it, &ref);
  411. EXPECT(err > 0);
  412. } else {
  413. EXPECT(err > 0);
  414. }
  415. strbuf_release(&pastLast);
  416. reftable_iterator_destroy(&it);
  417. strbuf_release(&buf);
  418. for (i = 0; i < N; i++) {
  419. reftable_free(names[i]);
  420. }
  421. reftable_free(names);
  422. reader_close(&rd);
  423. }
  424. static void test_table_read_write_seek_linear(void)
  425. {
  426. test_table_read_write_seek(0, GIT_SHA1_FORMAT_ID);
  427. }
  428. static void test_table_read_write_seek_linear_sha256(void)
  429. {
  430. test_table_read_write_seek(0, GIT_SHA256_FORMAT_ID);
  431. }
  432. static void test_table_read_write_seek_index(void)
  433. {
  434. test_table_read_write_seek(1, GIT_SHA1_FORMAT_ID);
  435. }
  436. static void test_table_refs_for(int indexed)
  437. {
  438. int N = 50;
  439. char **want_names = reftable_calloc(sizeof(char *) * (N + 1));
  440. int want_names_len = 0;
  441. uint8_t want_hash[GIT_SHA1_RAWSZ];
  442. struct reftable_write_options opts = {
  443. .block_size = 256,
  444. };
  445. struct reftable_ref_record ref = { NULL };
  446. int i = 0;
  447. int n;
  448. int err;
  449. struct reftable_reader rd;
  450. struct reftable_block_source source = { NULL };
  451. struct strbuf buf = STRBUF_INIT;
  452. struct reftable_writer *w =
  453. reftable_new_writer(&strbuf_add_void, &buf, &opts);
  454. struct reftable_iterator it = { NULL };
  455. int j;
  456. set_test_hash(want_hash, 4);
  457. for (i = 0; i < N; i++) {
  458. uint8_t hash[GIT_SHA1_RAWSZ];
  459. char fill[51] = { 0 };
  460. char name[100];
  461. uint8_t hash1[GIT_SHA1_RAWSZ];
  462. uint8_t hash2[GIT_SHA1_RAWSZ];
  463. struct reftable_ref_record ref = { NULL };
  464. memset(hash, i, sizeof(hash));
  465. memset(fill, 'x', 50);
  466. /* Put the variable part in the start */
  467. snprintf(name, sizeof(name), "br%02d%s", i, fill);
  468. name[40] = 0;
  469. ref.refname = name;
  470. set_test_hash(hash1, i / 4);
  471. set_test_hash(hash2, 3 + i / 4);
  472. ref.value_type = REFTABLE_REF_VAL2;
  473. ref.value.val2.value = hash1;
  474. ref.value.val2.target_value = hash2;
  475. /* 80 bytes / entry, so 3 entries per block. Yields 17
  476. */
  477. /* blocks. */
  478. n = reftable_writer_add_ref(w, &ref);
  479. EXPECT(n == 0);
  480. if (!memcmp(hash1, want_hash, GIT_SHA1_RAWSZ) ||
  481. !memcmp(hash2, want_hash, GIT_SHA1_RAWSZ)) {
  482. want_names[want_names_len++] = xstrdup(name);
  483. }
  484. }
  485. n = reftable_writer_close(w);
  486. EXPECT(n == 0);
  487. reftable_writer_free(w);
  488. w = NULL;
  489. block_source_from_strbuf(&source, &buf);
  490. err = init_reader(&rd, &source, "file.ref");
  491. EXPECT_ERR(err);
  492. if (!indexed) {
  493. rd.obj_offsets.is_present = 0;
  494. }
  495. err = reftable_reader_seek_ref(&rd, &it, "");
  496. EXPECT_ERR(err);
  497. reftable_iterator_destroy(&it);
  498. err = reftable_reader_refs_for(&rd, &it, want_hash);
  499. EXPECT_ERR(err);
  500. j = 0;
  501. while (1) {
  502. int err = reftable_iterator_next_ref(&it, &ref);
  503. EXPECT(err >= 0);
  504. if (err > 0) {
  505. break;
  506. }
  507. EXPECT(j < want_names_len);
  508. EXPECT(0 == strcmp(ref.refname, want_names[j]));
  509. j++;
  510. reftable_ref_record_release(&ref);
  511. }
  512. EXPECT(j == want_names_len);
  513. strbuf_release(&buf);
  514. free_names(want_names);
  515. reftable_iterator_destroy(&it);
  516. reader_close(&rd);
  517. }
  518. static void test_table_refs_for_no_index(void)
  519. {
  520. test_table_refs_for(0);
  521. }
  522. static void test_table_refs_for_obj_index(void)
  523. {
  524. test_table_refs_for(1);
  525. }
  526. static void test_write_empty_table(void)
  527. {
  528. struct reftable_write_options opts = { 0 };
  529. struct strbuf buf = STRBUF_INIT;
  530. struct reftable_writer *w =
  531. reftable_new_writer(&strbuf_add_void, &buf, &opts);
  532. struct reftable_block_source source = { NULL };
  533. struct reftable_reader *rd = NULL;
  534. struct reftable_ref_record rec = { NULL };
  535. struct reftable_iterator it = { NULL };
  536. int err;
  537. reftable_writer_set_limits(w, 1, 1);
  538. err = reftable_writer_close(w);
  539. EXPECT(err == REFTABLE_EMPTY_TABLE_ERROR);
  540. reftable_writer_free(w);
  541. EXPECT(buf.len == header_size(1) + footer_size(1));
  542. block_source_from_strbuf(&source, &buf);
  543. err = reftable_new_reader(&rd, &source, "filename");
  544. EXPECT_ERR(err);
  545. err = reftable_reader_seek_ref(rd, &it, "");
  546. EXPECT_ERR(err);
  547. err = reftable_iterator_next_ref(&it, &rec);
  548. EXPECT(err > 0);
  549. reftable_iterator_destroy(&it);
  550. reftable_reader_free(rd);
  551. strbuf_release(&buf);
  552. }
  553. static void test_write_object_id_min_length(void)
  554. {
  555. struct reftable_write_options opts = {
  556. .block_size = 75,
  557. };
  558. struct strbuf buf = STRBUF_INIT;
  559. struct reftable_writer *w =
  560. reftable_new_writer(&strbuf_add_void, &buf, &opts);
  561. uint8_t hash[GIT_SHA1_RAWSZ] = {42};
  562. struct reftable_ref_record ref = {
  563. .update_index = 1,
  564. .value_type = REFTABLE_REF_VAL1,
  565. .value.val1 = hash,
  566. };
  567. int err;
  568. int i;
  569. reftable_writer_set_limits(w, 1, 1);
  570. /* Write the same hash in many refs. If there is only 1 hash, the
  571. * disambiguating prefix is length 0 */
  572. for (i = 0; i < 256; i++) {
  573. char name[256];
  574. snprintf(name, sizeof(name), "ref%05d", i);
  575. ref.refname = name;
  576. err = reftable_writer_add_ref(w, &ref);
  577. EXPECT_ERR(err);
  578. }
  579. err = reftable_writer_close(w);
  580. EXPECT_ERR(err);
  581. EXPECT(reftable_writer_stats(w)->object_id_len == 2);
  582. reftable_writer_free(w);
  583. strbuf_release(&buf);
  584. }
  585. static void test_write_object_id_length(void)
  586. {
  587. struct reftable_write_options opts = {
  588. .block_size = 75,
  589. };
  590. struct strbuf buf = STRBUF_INIT;
  591. struct reftable_writer *w =
  592. reftable_new_writer(&strbuf_add_void, &buf, &opts);
  593. uint8_t hash[GIT_SHA1_RAWSZ] = {42};
  594. struct reftable_ref_record ref = {
  595. .update_index = 1,
  596. .value_type = REFTABLE_REF_VAL1,
  597. .value.val1 = hash,
  598. };
  599. int err;
  600. int i;
  601. reftable_writer_set_limits(w, 1, 1);
  602. /* Write the same hash in many refs. If there is only 1 hash, the
  603. * disambiguating prefix is length 0 */
  604. for (i = 0; i < 256; i++) {
  605. char name[256];
  606. snprintf(name, sizeof(name), "ref%05d", i);
  607. ref.refname = name;
  608. ref.value.val1[15] = i;
  609. err = reftable_writer_add_ref(w, &ref);
  610. EXPECT_ERR(err);
  611. }
  612. err = reftable_writer_close(w);
  613. EXPECT_ERR(err);
  614. EXPECT(reftable_writer_stats(w)->object_id_len == 16);
  615. reftable_writer_free(w);
  616. strbuf_release(&buf);
  617. }
  618. static void test_write_empty_key(void)
  619. {
  620. struct reftable_write_options opts = { 0 };
  621. struct strbuf buf = STRBUF_INIT;
  622. struct reftable_writer *w =
  623. reftable_new_writer(&strbuf_add_void, &buf, &opts);
  624. struct reftable_ref_record ref = {
  625. .refname = "",
  626. .update_index = 1,
  627. .value_type = REFTABLE_REF_DELETION,
  628. };
  629. int err;
  630. reftable_writer_set_limits(w, 1, 1);
  631. err = reftable_writer_add_ref(w, &ref);
  632. EXPECT(err == REFTABLE_API_ERROR);
  633. err = reftable_writer_close(w);
  634. EXPECT(err == REFTABLE_EMPTY_TABLE_ERROR);
  635. reftable_writer_free(w);
  636. strbuf_release(&buf);
  637. }
  638. static void test_write_key_order(void)
  639. {
  640. struct reftable_write_options opts = { 0 };
  641. struct strbuf buf = STRBUF_INIT;
  642. struct reftable_writer *w =
  643. reftable_new_writer(&strbuf_add_void, &buf, &opts);
  644. struct reftable_ref_record refs[2] = {
  645. {
  646. .refname = "b",
  647. .update_index = 1,
  648. .value_type = REFTABLE_REF_SYMREF,
  649. .value = {
  650. .symref = "target",
  651. },
  652. }, {
  653. .refname = "a",
  654. .update_index = 1,
  655. .value_type = REFTABLE_REF_SYMREF,
  656. .value = {
  657. .symref = "target",
  658. },
  659. }
  660. };
  661. int err;
  662. reftable_writer_set_limits(w, 1, 1);
  663. err = reftable_writer_add_ref(w, &refs[0]);
  664. EXPECT_ERR(err);
  665. err = reftable_writer_add_ref(w, &refs[1]);
  666. EXPECT(err == REFTABLE_API_ERROR);
  667. reftable_writer_close(w);
  668. reftable_writer_free(w);
  669. strbuf_release(&buf);
  670. }
  671. static void test_corrupt_table_empty(void)
  672. {
  673. struct strbuf buf = STRBUF_INIT;
  674. struct reftable_block_source source = { NULL };
  675. struct reftable_reader rd = { NULL };
  676. int err;
  677. block_source_from_strbuf(&source, &buf);
  678. err = init_reader(&rd, &source, "file.log");
  679. EXPECT(err == REFTABLE_FORMAT_ERROR);
  680. }
  681. static void test_corrupt_table(void)
  682. {
  683. uint8_t zeros[1024] = { 0 };
  684. struct strbuf buf = STRBUF_INIT;
  685. struct reftable_block_source source = { NULL };
  686. struct reftable_reader rd = { NULL };
  687. int err;
  688. strbuf_add(&buf, zeros, sizeof(zeros));
  689. block_source_from_strbuf(&source, &buf);
  690. err = init_reader(&rd, &source, "file.log");
  691. EXPECT(err == REFTABLE_FORMAT_ERROR);
  692. strbuf_release(&buf);
  693. }
  694. int readwrite_test_main(int argc, const char *argv[])
  695. {
  696. RUN_TEST(test_log_zlib_corruption);
  697. RUN_TEST(test_corrupt_table);
  698. RUN_TEST(test_corrupt_table_empty);
  699. RUN_TEST(test_log_write_read);
  700. RUN_TEST(test_write_key_order);
  701. RUN_TEST(test_table_read_write_seek_linear_sha256);
  702. RUN_TEST(test_log_buffer_size);
  703. RUN_TEST(test_table_write_small_table);
  704. RUN_TEST(test_buffer);
  705. RUN_TEST(test_table_read_api);
  706. RUN_TEST(test_table_read_write_sequential);
  707. RUN_TEST(test_table_read_write_seek_linear);
  708. RUN_TEST(test_table_read_write_seek_index);
  709. RUN_TEST(test_table_refs_for_no_index);
  710. RUN_TEST(test_table_refs_for_obj_index);
  711. RUN_TEST(test_write_empty_key);
  712. RUN_TEST(test_write_empty_table);
  713. RUN_TEST(test_log_overflow);
  714. RUN_TEST(test_write_object_id_length);
  715. RUN_TEST(test_write_object_id_min_length);
  716. return 0;
  717. }