test_consdiff.c (40817B)
1 /* Copyright (c) 2014, Daniel Martà 2 * Copyright (c) 2014-2021, The Tor Project, Inc. */ 3 /* See LICENSE for licensing information */ 4 5 #define CONSDIFF_PRIVATE 6 7 #include "core/or/or.h" 8 #include "test/test.h" 9 10 #include "feature/dircommon/consdiff.h" 11 #include "lib/memarea/memarea.h" 12 #include "test/log_test_helpers.h" 13 14 #define tt_str_eq_line(a,b) \ 15 tt_assert(line_str_eq((b),(a))) 16 17 static int 18 consensus_split_lines_(smartlist_t *out, const char *s, memarea_t *area) 19 { 20 size_t len = strlen(s); 21 return consensus_split_lines(out, s, len, area); 22 } 23 24 static int 25 consensus_compute_digest_(const char *cons, 26 consensus_digest_t *digest_out) 27 { 28 size_t len = strlen(cons); 29 char *tmp = tor_memdup(cons, len); 30 // We use memdup here to ensure that the input is NOT nul-terminated. 31 // This makes it likelier for us to spot bugs. 32 int r = consensus_compute_digest(tmp, len, digest_out); 33 tor_free(tmp); 34 return r; 35 } 36 37 static int 38 consensus_compute_digest_as_signed_(const char *cons, 39 consensus_digest_t *digest_out) 40 { 41 size_t len = strlen(cons); 42 char *tmp = tor_memdup(cons, len); 43 // We use memdup here to ensure that the input is NOT nul-terminated. 44 // This makes it likelier for us to spot bugs. 45 int r = consensus_compute_digest_as_signed(tmp, len, digest_out); 46 tor_free(tmp); 47 return r; 48 } 49 50 static void 51 test_consdiff_smartlist_slice(void *arg) 52 { 53 smartlist_t *sl = smartlist_new(); 54 smartlist_slice_t *sls; 55 int items[6] = {0,0,0,0,0,0}; 56 57 /* Create a regular smartlist. */ 58 (void)arg; 59 smartlist_add(sl, &items[1]); 60 smartlist_add(sl, &items[2]); 61 smartlist_add(sl, &items[3]); 62 smartlist_add(sl, &items[4]); 63 smartlist_add(sl, &items[5]); 64 65 /* See if the slice was done correctly. */ 66 sls = smartlist_slice(sl, 2, 5); 67 tt_ptr_op(sl, OP_EQ, sls->list); 68 tt_ptr_op(&items[3], OP_EQ, smartlist_get(sls->list, sls->offset)); 69 tt_ptr_op(&items[5], OP_EQ, 70 smartlist_get(sls->list, sls->offset + (sls->len-1))); 71 tor_free(sls); 72 73 /* See that using -1 as the end does get to the last element. */ 74 sls = smartlist_slice(sl, 2, -1); 75 tt_ptr_op(sl, OP_EQ, sls->list); 76 tt_ptr_op(&items[3], OP_EQ, smartlist_get(sls->list, sls->offset)); 77 tt_ptr_op(&items[5], OP_EQ, 78 smartlist_get(sls->list, sls->offset + (sls->len-1))); 79 80 done: 81 tor_free(sls); 82 smartlist_free(sl); 83 } 84 85 static void 86 test_consdiff_smartlist_slice_string_pos(void *arg) 87 { 88 smartlist_t *sl = smartlist_new(); 89 smartlist_slice_t *sls; 90 memarea_t *area = memarea_new(); 91 92 /* Create a regular smartlist. */ 93 (void)arg; 94 consensus_split_lines_(sl, "a\nd\nc\na\nb\n", area); 95 96 /* See that smartlist_slice_string_pos respects the bounds of the slice. */ 97 sls = smartlist_slice(sl, 2, 5); 98 cdline_t a_line = { "a", 1 }; 99 tt_int_op(3, OP_EQ, smartlist_slice_string_pos(sls, &a_line)); 100 cdline_t d_line = { "d", 1 }; 101 tt_int_op(-1, OP_EQ, smartlist_slice_string_pos(sls, &d_line)); 102 103 done: 104 tor_free(sls); 105 smartlist_free(sl); 106 memarea_drop_all(area); 107 } 108 109 static void 110 test_consdiff_lcs_lengths(void *arg) 111 { 112 smartlist_t *sl1 = smartlist_new(); 113 smartlist_t *sl2 = smartlist_new(); 114 smartlist_slice_t *sls1, *sls2; 115 int *lengths1, *lengths2; 116 memarea_t *area = memarea_new(); 117 118 /* Expected lcs lengths in regular and reverse order. */ 119 int e_lengths1[] = { 0, 1, 2, 3, 3, 4 }; 120 int e_lengths2[] = { 0, 1, 1, 2, 3, 4 }; 121 122 (void)arg; 123 consensus_split_lines_(sl1, "a\nb\nc\nd\ne\n", area); 124 consensus_split_lines_(sl2, "a\nc\nd\ni\ne\n", area); 125 126 sls1 = smartlist_slice(sl1, 0, -1); 127 sls2 = smartlist_slice(sl2, 0, -1); 128 129 lengths1 = lcs_lengths(sls1, sls2, 1); 130 lengths2 = lcs_lengths(sls1, sls2, -1); 131 tt_mem_op(e_lengths1, OP_EQ, lengths1, sizeof(int) * 6); 132 tt_mem_op(e_lengths2, OP_EQ, lengths2, sizeof(int) * 6); 133 134 done: 135 tor_free(lengths1); 136 tor_free(lengths2); 137 tor_free(sls1); 138 tor_free(sls2); 139 smartlist_free(sl1); 140 smartlist_free(sl2); 141 memarea_drop_all(area); 142 } 143 144 static void 145 test_consdiff_trim_slices(void *arg) 146 { 147 smartlist_t *sl1 = smartlist_new(); 148 smartlist_t *sl2 = smartlist_new(); 149 smartlist_t *sl3 = smartlist_new(); 150 smartlist_t *sl4 = smartlist_new(); 151 smartlist_slice_t *sls1, *sls2, *sls3, *sls4; 152 memarea_t *area = memarea_new(); 153 154 (void)arg; 155 consensus_split_lines_(sl1, "a\nb\nb\nb\nd\n", area); 156 consensus_split_lines_(sl2, "a\nc\nc\nc\nd\n", area); 157 consensus_split_lines_(sl3, "a\nb\nb\nb\na\n", area); 158 consensus_split_lines_(sl4, "c\nb\nb\nb\nc\n", area); 159 sls1 = smartlist_slice(sl1, 0, -1); 160 sls2 = smartlist_slice(sl2, 0, -1); 161 sls3 = smartlist_slice(sl3, 0, -1); 162 sls4 = smartlist_slice(sl4, 0, -1); 163 164 /* They should be trimmed by one line at each end. */ 165 tt_int_op(5, OP_EQ, sls1->len); 166 tt_int_op(5, OP_EQ, sls2->len); 167 trim_slices(sls1, sls2); 168 tt_int_op(3, OP_EQ, sls1->len); 169 tt_int_op(3, OP_EQ, sls2->len); 170 171 /* They should not be trimmed at all. */ 172 tt_int_op(5, OP_EQ, sls3->len); 173 tt_int_op(5, OP_EQ, sls4->len); 174 trim_slices(sls3, sls4); 175 tt_int_op(5, OP_EQ, sls3->len); 176 tt_int_op(5, OP_EQ, sls4->len); 177 178 done: 179 tor_free(sls1); 180 tor_free(sls2); 181 tor_free(sls3); 182 tor_free(sls4); 183 smartlist_free(sl1); 184 smartlist_free(sl2); 185 smartlist_free(sl3); 186 smartlist_free(sl4); 187 memarea_drop_all(area); 188 } 189 190 static void 191 test_consdiff_set_changed(void *arg) 192 { 193 smartlist_t *sl1 = smartlist_new(); 194 smartlist_t *sl2 = smartlist_new(); 195 bitarray_t *changed1 = bitarray_init_zero(4); 196 bitarray_t *changed2 = bitarray_init_zero(4); 197 smartlist_slice_t *sls1, *sls2; 198 memarea_t *area = memarea_new(); 199 200 (void)arg; 201 consensus_split_lines_(sl1, "a\nb\na\na\n", area); 202 consensus_split_lines_(sl2, "a\na\na\na\n", area); 203 204 /* Length of sls1 is 0. */ 205 sls1 = smartlist_slice(sl1, 0, 0); 206 sls2 = smartlist_slice(sl2, 1, 3); 207 set_changed(changed1, changed2, sls1, sls2); 208 209 /* The former is not changed, the latter changes all of its elements. */ 210 tt_assert(!bitarray_is_set(changed1, 0)); 211 tt_assert(!bitarray_is_set(changed1, 1)); 212 tt_assert(!bitarray_is_set(changed1, 2)); 213 tt_assert(!bitarray_is_set(changed1, 3)); 214 215 tt_assert(!bitarray_is_set(changed2, 0)); 216 tt_assert(bitarray_is_set(changed2, 1)); 217 tt_assert(bitarray_is_set(changed2, 2)); 218 tt_assert(!bitarray_is_set(changed2, 3)); 219 bitarray_clear(changed2, 1); 220 bitarray_clear(changed2, 2); 221 222 /* Length of sls1 is 1 and its element is in sls2. */ 223 tor_free(sls1); 224 sls1 = smartlist_slice(sl1, 0, 1); 225 set_changed(changed1, changed2, sls1, sls2); 226 227 /* The latter changes all elements but the (first) common one. */ 228 tt_assert(!bitarray_is_set(changed1, 0)); 229 tt_assert(!bitarray_is_set(changed1, 1)); 230 tt_assert(!bitarray_is_set(changed1, 2)); 231 tt_assert(!bitarray_is_set(changed1, 3)); 232 233 tt_assert(!bitarray_is_set(changed2, 0)); 234 tt_assert(!bitarray_is_set(changed2, 1)); 235 tt_assert(bitarray_is_set(changed2, 2)); 236 tt_assert(!bitarray_is_set(changed2, 3)); 237 bitarray_clear(changed2, 2); 238 239 /* Length of sls1 is 1 and its element is not in sls2. */ 240 tor_free(sls1); 241 sls1 = smartlist_slice(sl1, 1, 2); 242 set_changed(changed1, changed2, sls1, sls2); 243 244 /* The former changes its element, the latter changes all elements. */ 245 tt_assert(!bitarray_is_set(changed1, 0)); 246 tt_assert(bitarray_is_set(changed1, 1)); 247 tt_assert(!bitarray_is_set(changed1, 2)); 248 tt_assert(!bitarray_is_set(changed1, 3)); 249 250 tt_assert(!bitarray_is_set(changed2, 0)); 251 tt_assert(bitarray_is_set(changed2, 1)); 252 tt_assert(bitarray_is_set(changed2, 2)); 253 tt_assert(!bitarray_is_set(changed2, 3)); 254 255 done: 256 bitarray_free(changed1); 257 bitarray_free(changed2); 258 smartlist_free(sl1); 259 smartlist_free(sl2); 260 tor_free(sls1); 261 tor_free(sls2); 262 memarea_drop_all(area); 263 } 264 265 static void 266 test_consdiff_calc_changes(void *arg) 267 { 268 smartlist_t *sl1 = smartlist_new(); 269 smartlist_t *sl2 = smartlist_new(); 270 smartlist_slice_t *sls1, *sls2; 271 bitarray_t *changed1 = bitarray_init_zero(4); 272 bitarray_t *changed2 = bitarray_init_zero(4); 273 memarea_t *area = memarea_new(); 274 275 (void)arg; 276 consensus_split_lines_(sl1, "a\na\na\na\n", area); 277 consensus_split_lines_(sl2, "a\na\na\na\n", area); 278 279 sls1 = smartlist_slice(sl1, 0, -1); 280 sls2 = smartlist_slice(sl2, 0, -1); 281 calc_changes(sls1, sls2, changed1, changed2); 282 283 /* Nothing should be set to changed. */ 284 tt_assert(!bitarray_is_set(changed1, 0)); 285 tt_assert(!bitarray_is_set(changed1, 1)); 286 tt_assert(!bitarray_is_set(changed1, 2)); 287 tt_assert(!bitarray_is_set(changed1, 3)); 288 289 tt_assert(!bitarray_is_set(changed2, 0)); 290 tt_assert(!bitarray_is_set(changed2, 1)); 291 tt_assert(!bitarray_is_set(changed2, 2)); 292 tt_assert(!bitarray_is_set(changed2, 3)); 293 294 smartlist_clear(sl2); 295 consensus_split_lines_(sl2, "a\nb\na\nb\n", area); 296 tor_free(sls1); 297 tor_free(sls2); 298 sls1 = smartlist_slice(sl1, 0, -1); 299 sls2 = smartlist_slice(sl2, 0, -1); 300 calc_changes(sls1, sls2, changed1, changed2); 301 302 /* Two elements are changed. */ 303 tt_assert(!bitarray_is_set(changed1, 0)); 304 tt_assert(bitarray_is_set(changed1, 1)); 305 tt_assert(bitarray_is_set(changed1, 2)); 306 tt_assert(!bitarray_is_set(changed1, 3)); 307 bitarray_clear(changed1, 1); 308 bitarray_clear(changed1, 2); 309 310 tt_assert(!bitarray_is_set(changed2, 0)); 311 tt_assert(bitarray_is_set(changed2, 1)); 312 tt_assert(!bitarray_is_set(changed2, 2)); 313 tt_assert(bitarray_is_set(changed2, 3)); 314 bitarray_clear(changed1, 1); 315 bitarray_clear(changed1, 3); 316 317 smartlist_clear(sl2); 318 consensus_split_lines_(sl2, "b\nb\nb\nb\n", area); 319 tor_free(sls1); 320 tor_free(sls2); 321 sls1 = smartlist_slice(sl1, 0, -1); 322 sls2 = smartlist_slice(sl2, 0, -1); 323 calc_changes(sls1, sls2, changed1, changed2); 324 325 /* All elements are changed. */ 326 tt_assert(bitarray_is_set(changed1, 0)); 327 tt_assert(bitarray_is_set(changed1, 1)); 328 tt_assert(bitarray_is_set(changed1, 2)); 329 tt_assert(bitarray_is_set(changed1, 3)); 330 331 tt_assert(bitarray_is_set(changed2, 0)); 332 tt_assert(bitarray_is_set(changed2, 1)); 333 tt_assert(bitarray_is_set(changed2, 2)); 334 tt_assert(bitarray_is_set(changed2, 3)); 335 336 done: 337 bitarray_free(changed1); 338 bitarray_free(changed2); 339 smartlist_free(sl1); 340 smartlist_free(sl2); 341 tor_free(sls1); 342 tor_free(sls2); 343 memarea_drop_all(area); 344 } 345 346 static void 347 test_consdiff_get_id_hash(void *arg) 348 { 349 (void)arg; 350 351 cdline_t line1 = { "r name", 6 }; 352 cdline_t line2 = { "r name _hash_isnt_base64 etc", 28 }; 353 cdline_t line3 = { "r name hash+valid+base64 etc", 28 }; 354 cdline_t tmp; 355 356 /* No hash. */ 357 tt_int_op(-1, OP_EQ, get_id_hash(&line1, &tmp)); 358 /* The hash contains characters that are not base64. */ 359 tt_int_op(-1, OP_EQ, get_id_hash(&line2, &tmp)); 360 361 /* valid hash. */ 362 tt_int_op(0, OP_EQ, get_id_hash(&line3, &tmp)); 363 tt_ptr_op(tmp.s, OP_EQ, line3.s + 7); 364 tt_uint_op(tmp.len, OP_EQ, line3.len - 11); 365 366 done: 367 ; 368 } 369 370 static void 371 test_consdiff_is_valid_router_entry(void *arg) 372 { 373 /* Doesn't start with "r ". */ 374 (void)arg; 375 cdline_t line0 = { "foo", 3 }; 376 tt_int_op(0, OP_EQ, is_valid_router_entry(&line0)); 377 378 /* These are already tested with get_id_hash, but make sure it's run 379 * properly. */ 380 381 cdline_t line1 = { "r name", 6 }; 382 cdline_t line2 = { "r name _hash_isnt_base64 etc", 28 }; 383 cdline_t line3 = { "r name hash+valid+base64 etc", 28 }; 384 tt_int_op(0, OP_EQ, is_valid_router_entry(&line1)); 385 tt_int_op(0, OP_EQ, is_valid_router_entry(&line2)); 386 tt_int_op(1, OP_EQ, is_valid_router_entry(&line3)); 387 388 done: 389 ; 390 } 391 392 static void 393 test_consdiff_next_router(void *arg) 394 { 395 smartlist_t *sl = smartlist_new(); 396 memarea_t *area = memarea_new(); 397 (void)arg; 398 smartlist_add_linecpy(sl, area, "foo"); 399 smartlist_add_linecpy(sl, area, 400 "r name hash+longer+than+27+chars+and+valid+base64 etc"); 401 smartlist_add_linecpy(sl, area, "foo"); 402 smartlist_add_linecpy(sl, area, "foo"); 403 smartlist_add_linecpy(sl, area, 404 "r name hash+longer+than+27+chars+and+valid+base64 etc"); 405 smartlist_add_linecpy(sl, area, "foo"); 406 407 /* Not currently on a router entry line, finding the next one. */ 408 tt_int_op(1, OP_EQ, next_router(sl, 0)); 409 tt_int_op(4, OP_EQ, next_router(sl, 2)); 410 411 /* Already at the beginning of a router entry line, ignore it. */ 412 tt_int_op(4, OP_EQ, next_router(sl, 1)); 413 414 /* There are no more router entries, so return the line after the last. */ 415 tt_int_op(6, OP_EQ, next_router(sl, 4)); 416 tt_int_op(6, OP_EQ, next_router(sl, 5)); 417 418 done: 419 smartlist_free(sl); 420 memarea_drop_all(area); 421 } 422 423 static int 424 base64cmp_wrapper(const char *a, const char *b) 425 { 426 cdline_t aa = { a, a ? (uint32_t) strlen(a) : 0 }; 427 cdline_t bb = { b, b ? (uint32_t) strlen(b) : 0 }; 428 return base64cmp(&aa, &bb); 429 } 430 431 static void 432 test_consdiff_base64cmp(void *arg) 433 { 434 /* NULL arguments. */ 435 (void)arg; 436 tt_int_op(0, OP_EQ, base64cmp_wrapper(NULL, NULL)); 437 tt_int_op(-1, OP_EQ, base64cmp_wrapper(NULL, "foo")); 438 tt_int_op(1, OP_EQ, base64cmp_wrapper("bar", NULL)); 439 440 /* Nil base64 values. */ 441 tt_int_op(0, OP_EQ, base64cmp_wrapper("", "")); 442 tt_int_op(0, OP_EQ, base64cmp_wrapper("_", "&")); 443 444 /* Exact same valid strings. */ 445 tt_int_op(0, OP_EQ, base64cmp_wrapper("abcABC/+", "abcABC/+")); 446 /* Both end with an invalid base64 char other than '\0'. */ 447 tt_int_op(0, OP_EQ, base64cmp_wrapper("abcABC/+ ", "abcABC/+ ")); 448 /* Only one ends with an invalid base64 char other than '\0'. */ 449 tt_int_op(-1, OP_EQ, base64cmp_wrapper("abcABC/+ ", "abcABC/+a")); 450 451 /* Comparisons that would return differently with strcmp(). */ 452 tt_int_op(strcmp("/foo", "Afoo"), OP_LT, 0); 453 tt_int_op(base64cmp_wrapper("/foo", "Afoo"), OP_GT, 0); 454 tt_int_op(strcmp("Afoo", "0foo"), OP_GT, 0); 455 tt_int_op(base64cmp_wrapper("Afoo", "0foo"), OP_LT, 0); 456 457 /* Comparisons that would return the same as with strcmp(). */ 458 tt_int_op(strcmp("afoo", "Afoo"), OP_GT, 0); 459 tt_int_op(base64cmp_wrapper("afoo", "Afoo"), OP_GT, 0); 460 461 /* Different lengths */ 462 tt_int_op(base64cmp_wrapper("afoo", "afooo"), OP_LT, 0); 463 tt_int_op(base64cmp_wrapper("afooo", "afoo"), OP_GT, 0); 464 465 done: 466 ; 467 } 468 469 static void 470 test_consdiff_gen_ed_diff(void *arg) 471 { 472 smartlist_t *cons1=NULL, *cons2=NULL, *diff=NULL; 473 int i; 474 memarea_t *area = memarea_new(); 475 setup_capture_of_logs(LOG_WARN); 476 477 (void)arg; 478 cons1 = smartlist_new(); 479 cons2 = smartlist_new(); 480 481 /* Identity hashes are not sorted properly, return NULL. */ 482 smartlist_add_linecpy(cons1, area, "r name bbbbbbbbbbbbbbbbbbbbbbbbbbb etc"); 483 smartlist_add_linecpy(cons1, area, "foo"); 484 smartlist_add_linecpy(cons1, area, "r name aaaaaaaaaaaaaaaaaaaaaaaaaaa etc"); 485 smartlist_add_linecpy(cons1, area, "bar"); 486 487 smartlist_add_linecpy(cons2, area, "r name aaaaaaaaaaaaaaaaaaaaaaaaaaa etc"); 488 smartlist_add_linecpy(cons2, area, "foo"); 489 smartlist_add_linecpy(cons2, area, "r name ccccccccccccccccccccccccccc etc"); 490 smartlist_add_linecpy(cons2, area, "bar"); 491 492 diff = gen_ed_diff(cons1, cons2, area); 493 tt_ptr_op(NULL, OP_EQ, diff); 494 expect_single_log_msg_containing("Refusing to generate consensus diff " 495 "because the base consensus doesn't have its router entries sorted " 496 "properly."); 497 498 /* Same, but now with the second consensus. */ 499 mock_clean_saved_logs(); 500 diff = gen_ed_diff(cons2, cons1, area); 501 tt_ptr_op(NULL, OP_EQ, diff); 502 expect_single_log_msg_containing("Refusing to generate consensus diff " 503 "because the target consensus doesn't have its router entries sorted " 504 "properly."); 505 506 /* Same as the two above, but with the reversed thing immediately after a 507 match. (The code handles this differently) */ 508 smartlist_del(cons1, 0); 509 smartlist_add_linecpy(cons1, area, "r name aaaaaaaaaaaaaaaaaaaaaaaaaaa etc"); 510 511 mock_clean_saved_logs(); 512 diff = gen_ed_diff(cons1, cons2, area); 513 tt_ptr_op(NULL, OP_EQ, diff); 514 expect_single_log_msg_containing("Refusing to generate consensus diff " 515 "because the base consensus doesn't have its router entries sorted " 516 "properly."); 517 518 mock_clean_saved_logs(); 519 diff = gen_ed_diff(cons2, cons1, area); 520 tt_ptr_op(NULL, OP_EQ, diff); 521 expect_single_log_msg_containing("Refusing to generate consensus diff " 522 "because the target consensus doesn't have its router entries sorted " 523 "properly."); 524 525 /* Identity hashes are repeated, return NULL. */ 526 smartlist_clear(cons1); 527 528 smartlist_add_linecpy(cons1, area, "r name bbbbbbbbbbbbbbbbbbbbbbbbbbb etc"); 529 smartlist_add_linecpy(cons1, area, "foo"); 530 smartlist_add_linecpy(cons1, area, "r name bbbbbbbbbbbbbbbbbbbbbbbbbbb etc"); 531 smartlist_add_linecpy(cons1, area, "bar"); 532 533 mock_clean_saved_logs(); 534 diff = gen_ed_diff(cons1, cons2, area); 535 tt_ptr_op(NULL, OP_EQ, diff); 536 expect_single_log_msg_containing("Refusing to generate consensus diff " 537 "because the base consensus doesn't have its router entries sorted " 538 "properly."); 539 540 /* We have to add a line that is just a dot, return NULL. */ 541 smartlist_clear(cons1); 542 smartlist_clear(cons2); 543 544 smartlist_add_linecpy(cons1, area, "foo1"); 545 smartlist_add_linecpy(cons1, area, "foo2"); 546 547 smartlist_add_linecpy(cons2, area, "foo1"); 548 smartlist_add_linecpy(cons2, area, "."); 549 smartlist_add_linecpy(cons2, area, "foo2"); 550 551 mock_clean_saved_logs(); 552 diff = gen_ed_diff(cons1, cons2, area); 553 tt_ptr_op(NULL, OP_EQ, diff); 554 expect_single_log_msg_containing("Cannot generate consensus diff " 555 "because one of the lines to be added is \".\"."); 556 557 #define MAX_LINE_COUNT (10000) 558 /* Too many lines to be fed to the quadratic-time function. */ 559 smartlist_clear(cons1); 560 smartlist_clear(cons2); 561 562 for (i=0; i < MAX_LINE_COUNT; ++i) smartlist_add_linecpy(cons1, area, "a"); 563 for (i=0; i < MAX_LINE_COUNT; ++i) smartlist_add_linecpy(cons1, area, "b"); 564 565 mock_clean_saved_logs(); 566 diff = gen_ed_diff(cons1, cons2, area); 567 568 tt_ptr_op(NULL, OP_EQ, diff); 569 expect_single_log_msg_containing("Refusing to generate consensus diff " 570 "because we found too few common router ids."); 571 572 /* We have dot lines, but they don't interfere with the script format. */ 573 smartlist_clear(cons1); 574 smartlist_clear(cons2); 575 576 smartlist_add_linecpy(cons1, area, "foo1"); 577 smartlist_add_linecpy(cons1, area, "."); 578 smartlist_add_linecpy(cons1, area, "."); 579 smartlist_add_linecpy(cons1, area, "foo2"); 580 581 smartlist_add_linecpy(cons2, area, "foo1"); 582 smartlist_add_linecpy(cons2, area, "."); 583 smartlist_add_linecpy(cons2, area, "foo2"); 584 585 diff = gen_ed_diff(cons1, cons2, area); 586 tt_ptr_op(NULL, OP_NE, diff); 587 smartlist_free(diff); 588 589 /* Empty diff tests. */ 590 smartlist_clear(cons1); 591 smartlist_clear(cons2); 592 593 diff = gen_ed_diff(cons1, cons2, area); 594 tt_ptr_op(NULL, OP_NE, diff); 595 tt_int_op(0, OP_EQ, smartlist_len(diff)); 596 smartlist_free(diff); 597 598 smartlist_add_linecpy(cons1, area, "foo"); 599 smartlist_add_linecpy(cons1, area, "bar"); 600 601 smartlist_add_linecpy(cons2, area, "foo"); 602 smartlist_add_linecpy(cons2, area, "bar"); 603 604 diff = gen_ed_diff(cons1, cons2, area); 605 tt_ptr_op(NULL, OP_NE, diff); 606 tt_int_op(0, OP_EQ, smartlist_len(diff)); 607 smartlist_free(diff); 608 609 /* Everything is deleted. */ 610 smartlist_clear(cons2); 611 612 diff = gen_ed_diff(cons1, cons2, area); 613 tt_ptr_op(NULL, OP_NE, diff); 614 tt_int_op(1, OP_EQ, smartlist_len(diff)); 615 tt_str_eq_line("1,2d", smartlist_get(diff, 0)); 616 617 smartlist_free(diff); 618 619 /* Everything is added. */ 620 diff = gen_ed_diff(cons2, cons1, area); 621 tt_ptr_op(NULL, OP_NE, diff); 622 tt_int_op(4, OP_EQ, smartlist_len(diff)); 623 tt_str_eq_line("0a", smartlist_get(diff, 0)); 624 tt_str_eq_line("foo", smartlist_get(diff, 1)); 625 tt_str_eq_line("bar", smartlist_get(diff, 2)); 626 tt_str_eq_line(".", smartlist_get(diff, 3)); 627 628 smartlist_free(diff); 629 630 /* Everything is changed. */ 631 smartlist_add_linecpy(cons2, area, "foo2"); 632 smartlist_add_linecpy(cons2, area, "bar2"); 633 diff = gen_ed_diff(cons1, cons2, area); 634 tt_ptr_op(NULL, OP_NE, diff); 635 tt_int_op(4, OP_EQ, smartlist_len(diff)); 636 tt_str_eq_line("1,2c", smartlist_get(diff, 0)); 637 tt_str_eq_line("foo2", smartlist_get(diff, 1)); 638 tt_str_eq_line("bar2", smartlist_get(diff, 2)); 639 tt_str_eq_line(".", smartlist_get(diff, 3)); 640 641 smartlist_free(diff); 642 643 /* Test 'a', 'c' and 'd' together. See that it is done in reverse order. */ 644 smartlist_clear(cons1); 645 smartlist_clear(cons2); 646 consensus_split_lines_(cons1, "A\nB\nC\nD\nE\n", area); 647 consensus_split_lines_(cons2, "A\nC\nO\nE\nU\n", area); 648 diff = gen_ed_diff(cons1, cons2, area); 649 tt_ptr_op(NULL, OP_NE, diff); 650 tt_int_op(7, OP_EQ, smartlist_len(diff)); 651 tt_str_eq_line("5a", smartlist_get(diff, 0)); 652 tt_str_eq_line("U", smartlist_get(diff, 1)); 653 tt_str_eq_line(".", smartlist_get(diff, 2)); 654 tt_str_eq_line("4c", smartlist_get(diff, 3)); 655 tt_str_eq_line("O", smartlist_get(diff, 4)); 656 tt_str_eq_line(".", smartlist_get(diff, 5)); 657 tt_str_eq_line("2d", smartlist_get(diff, 6)); 658 659 smartlist_free(diff); 660 661 smartlist_clear(cons1); 662 smartlist_clear(cons2); 663 consensus_split_lines_(cons1, "B\n", area); 664 consensus_split_lines_(cons2, "A\nB\n", area); 665 diff = gen_ed_diff(cons1, cons2, area); 666 tt_ptr_op(NULL, OP_NE, diff); 667 tt_int_op(3, OP_EQ, smartlist_len(diff)); 668 tt_str_eq_line("0a", smartlist_get(diff, 0)); 669 tt_str_eq_line("A", smartlist_get(diff, 1)); 670 tt_str_eq_line(".", smartlist_get(diff, 2)); 671 672 /* TODO: small real use-cases, i.e. consensuses. */ 673 674 done: 675 teardown_capture_of_logs(); 676 smartlist_free(cons1); 677 smartlist_free(cons2); 678 smartlist_free(diff); 679 memarea_drop_all(area); 680 } 681 682 static void 683 test_consdiff_apply_ed_diff(void *arg) 684 { 685 smartlist_t *cons1=NULL, *cons2=NULL, *diff=NULL; 686 memarea_t *area = memarea_new(); 687 (void)arg; 688 cons1 = smartlist_new(); 689 diff = smartlist_new(); 690 setup_capture_of_logs(LOG_WARN); 691 692 consensus_split_lines_(cons1, "A\nB\nC\nD\nE\n", area); 693 694 /* Command without range. */ 695 smartlist_add_linecpy(diff, area, "a"); 696 cons2 = apply_ed_diff(cons1, diff, 0); 697 tt_ptr_op(NULL, OP_EQ, cons2); 698 smartlist_clear(diff); 699 expect_single_log_msg_containing("an ed command was missing a line number"); 700 701 /* Range without command. */ 702 smartlist_add_linecpy(diff, area, "1"); 703 mock_clean_saved_logs(); 704 cons2 = apply_ed_diff(cons1, diff, 0); 705 tt_ptr_op(NULL, OP_EQ, cons2); 706 expect_single_log_msg_containing("a line with no ed command was found"); 707 708 smartlist_clear(diff); 709 710 /* Range without end. */ 711 smartlist_add_linecpy(diff, area, "1,"); 712 mock_clean_saved_logs(); 713 cons2 = apply_ed_diff(cons1, diff, 0); 714 tt_ptr_op(NULL, OP_EQ, cons2); 715 expect_single_log_msg_containing("an ed command was missing a range " 716 "end line number."); 717 718 smartlist_clear(diff); 719 720 /* Incoherent ranges. */ 721 smartlist_add_linecpy(diff, area, "1,1"); 722 mock_clean_saved_logs(); 723 cons2 = apply_ed_diff(cons1, diff, 0); 724 tt_ptr_op(NULL, OP_EQ, cons2); 725 expect_single_log_msg_containing("an invalid range was found"); 726 727 smartlist_clear(diff); 728 729 smartlist_add_linecpy(diff, area, "3,2"); 730 mock_clean_saved_logs(); 731 cons2 = apply_ed_diff(cons1, diff, 0); 732 tt_ptr_op(NULL, OP_EQ, cons2); 733 expect_single_log_msg_containing("an invalid range was found"); 734 735 smartlist_clear(diff); 736 737 /* Unexpected range for add command. */ 738 smartlist_add_linecpy(diff, area, "1,2a"); 739 mock_clean_saved_logs(); 740 cons2 = apply_ed_diff(cons1, diff, 0); 741 tt_ptr_op(NULL, OP_EQ, cons2); 742 expect_single_log_msg_containing("add lines after a range"); 743 744 smartlist_clear(diff); 745 746 /* $ for a non-delete command. */ 747 smartlist_add_linecpy(diff, area, "1,$c"); 748 mock_clean_saved_logs(); 749 cons2 = apply_ed_diff(cons1, diff, 0); 750 tt_ptr_op(NULL, OP_EQ, cons2); 751 expect_single_log_msg_containing("it wanted to use $ with a command " 752 "other than delete"); 753 754 smartlist_clear(diff); 755 756 /* Script is not in reverse order. */ 757 smartlist_add_linecpy(diff, area, "1d"); 758 smartlist_add_linecpy(diff, area, "3d"); 759 mock_clean_saved_logs(); 760 cons2 = apply_ed_diff(cons1, diff, 0); 761 tt_ptr_op(NULL, OP_EQ, cons2); 762 expect_single_log_msg_containing("its commands are not properly sorted"); 763 764 smartlist_clear(diff); 765 766 /* Script contains unrecognised commands longer than one char. */ 767 smartlist_add_linecpy(diff, area, "1foo"); 768 mock_clean_saved_logs(); 769 cons2 = apply_ed_diff(cons1, diff, 0); 770 tt_ptr_op(NULL, OP_EQ, cons2); 771 expect_single_log_msg_containing("an ed command longer than one char was " 772 "found"); 773 774 smartlist_clear(diff); 775 776 /* Script contains unrecognised commands. */ 777 smartlist_add_linecpy(diff, area, "1e"); 778 mock_clean_saved_logs(); 779 cons2 = apply_ed_diff(cons1, diff, 0); 780 tt_ptr_op(NULL, OP_EQ, cons2); 781 expect_single_log_msg_containing("an unrecognised ed command was found"); 782 783 smartlist_clear(diff); 784 785 /* Command that should be followed by at least one line and a ".", but 786 * isn't. */ 787 smartlist_add_linecpy(diff, area, "0a"); 788 mock_clean_saved_logs(); 789 cons2 = apply_ed_diff(cons1, diff, 0); 790 tt_ptr_op(NULL, OP_EQ, cons2); 791 expect_single_log_msg_containing("it has an ed command that tries to " 792 "insert zero lines."); 793 794 /* Now it is followed by a ".", but it inserts zero lines. */ 795 smartlist_add_linecpy(diff, area, "."); 796 mock_clean_saved_logs(); 797 cons2 = apply_ed_diff(cons1, diff, 0); 798 tt_ptr_op(NULL, OP_EQ, cons2); 799 expect_single_log_msg_containing("it has an ed command that tries to " 800 "insert zero lines."); 801 802 smartlist_clear(diff); 803 804 /* Now it it inserts something, but has no terminator. */ 805 smartlist_add_linecpy(diff, area, "0a"); 806 smartlist_add_linecpy(diff, area, "hello"); 807 mock_clean_saved_logs(); 808 cons2 = apply_ed_diff(cons1, diff, 0); 809 tt_ptr_op(NULL, OP_EQ, cons2); 810 expect_single_log_msg_containing("lines to be inserted that don't end with " 811 "a \".\"."); 812 813 smartlist_clear(diff); 814 815 /* Ranges must be numeric only and cannot contain spaces. */ 816 smartlist_add_linecpy(diff, area, "0, 4d"); 817 mock_clean_saved_logs(); 818 cons2 = apply_ed_diff(cons1, diff, 0); 819 tt_ptr_op(NULL, OP_EQ, cons2); 820 expect_single_log_msg_containing("an ed command was missing a range " 821 "end line number."); 822 823 smartlist_clear(diff); 824 825 /* '+' is not a number. */ 826 smartlist_add_linecpy(diff, area, "+0,4d"); 827 mock_clean_saved_logs(); 828 cons2 = apply_ed_diff(cons1, diff, 0); 829 tt_ptr_op(NULL, OP_EQ, cons2); 830 expect_single_log_msg_containing("an ed command was missing a line number"); 831 832 smartlist_clear(diff); 833 834 /* range duplication */ 835 smartlist_add_linecpy(diff, area, "0,4d,5d"); 836 mock_clean_saved_logs(); 837 cons2 = apply_ed_diff(cons1, diff, 0); 838 tt_ptr_op(NULL, OP_EQ, cons2); 839 expect_single_log_msg_containing("an ed command longer than one char was " 840 "found"); 841 842 smartlist_clear(diff); 843 844 /* space before command */ 845 smartlist_add_linecpy(diff, area, "0,4 d"); 846 mock_clean_saved_logs(); 847 cons2 = apply_ed_diff(cons1, diff, 0); 848 tt_ptr_op(NULL, OP_EQ, cons2); 849 expect_single_log_msg_containing("an ed command longer than one char was " 850 "found"); 851 852 smartlist_clear(diff); 853 854 /* space inside number */ 855 smartlist_add_linecpy(diff, area, "0,4 5d"); 856 mock_clean_saved_logs(); 857 cons2 = apply_ed_diff(cons1, diff, 0); 858 tt_ptr_op(NULL, OP_EQ, cons2); 859 expect_single_log_msg_containing("an ed command longer than one char was " 860 "found"); 861 862 smartlist_clear(diff); 863 864 /* Test appending text, 'a'. */ 865 consensus_split_lines_(diff, "3a\nU\nO\n.\n0a\nV\n.\n", area); 866 cons2 = apply_ed_diff(cons1, diff, 0); 867 tt_ptr_op(NULL, OP_NE, cons2); 868 tt_int_op(8, OP_EQ, smartlist_len(cons2)); 869 tt_str_eq_line("V", smartlist_get(cons2, 0)); 870 tt_str_eq_line("A", smartlist_get(cons2, 1)); 871 tt_str_eq_line("B", smartlist_get(cons2, 2)); 872 tt_str_eq_line("C", smartlist_get(cons2, 3)); 873 tt_str_eq_line("U", smartlist_get(cons2, 4)); 874 tt_str_eq_line("O", smartlist_get(cons2, 5)); 875 tt_str_eq_line("D", smartlist_get(cons2, 6)); 876 tt_str_eq_line("E", smartlist_get(cons2, 7)); 877 878 smartlist_clear(diff); 879 smartlist_free(cons2); 880 881 /* Test deleting text, 'd'. */ 882 consensus_split_lines_(diff, "4d\n1,2d\n", area); 883 cons2 = apply_ed_diff(cons1, diff, 0); 884 tt_ptr_op(NULL, OP_NE, cons2); 885 tt_int_op(2, OP_EQ, smartlist_len(cons2)); 886 tt_str_eq_line("C", smartlist_get(cons2, 0)); 887 tt_str_eq_line("E", smartlist_get(cons2, 1)); 888 889 smartlist_clear(diff); 890 smartlist_free(cons2); 891 892 /* Test changing text, 'c'. */ 893 consensus_split_lines_(diff, "4c\nT\nX\n.\n1,2c\nM\n.\n", area); 894 cons2 = apply_ed_diff(cons1, diff, 0); 895 tt_ptr_op(NULL, OP_NE, cons2); 896 tt_int_op(5, OP_EQ, smartlist_len(cons2)); 897 tt_str_eq_line("M", smartlist_get(cons2, 0)); 898 tt_str_eq_line("C", smartlist_get(cons2, 1)); 899 tt_str_eq_line("T", smartlist_get(cons2, 2)); 900 tt_str_eq_line("X", smartlist_get(cons2, 3)); 901 tt_str_eq_line("E", smartlist_get(cons2, 4)); 902 903 smartlist_clear(diff); 904 smartlist_free(cons2); 905 906 /* Test 'a', 'd' and 'c' together. */ 907 consensus_split_lines_(diff, "4c\nT\nX\n.\n2d\n0a\nM\n.\n", area); 908 cons2 = apply_ed_diff(cons1, diff, 0); 909 tt_ptr_op(NULL, OP_NE, cons2); 910 tt_int_op(6, OP_EQ, smartlist_len(cons2)); 911 tt_str_eq_line("M", smartlist_get(cons2, 0)); 912 tt_str_eq_line("A", smartlist_get(cons2, 1)); 913 tt_str_eq_line("C", smartlist_get(cons2, 2)); 914 tt_str_eq_line("T", smartlist_get(cons2, 3)); 915 tt_str_eq_line("X", smartlist_get(cons2, 4)); 916 tt_str_eq_line("E", smartlist_get(cons2, 5)); 917 918 done: 919 teardown_capture_of_logs(); 920 smartlist_free(cons1); 921 smartlist_free(cons2); 922 smartlist_free(diff); 923 memarea_drop_all(area); 924 } 925 926 static void 927 test_consdiff_gen_diff(void *arg) 928 { 929 char *cons1_str=NULL, *cons2_str=NULL; 930 smartlist_t *cons1=NULL, *cons2=NULL, *diff=NULL; 931 consensus_digest_t digests1, digests2; 932 memarea_t *area = memarea_new(); 933 (void)arg; 934 cons1 = smartlist_new(); 935 cons2 = smartlist_new(); 936 937 /* Identity hashes are not sorted properly, return NULL. 938 * Already tested in gen_ed_diff, but see that a NULL ed diff also makes 939 * gen_diff return NULL. */ 940 cons1_str = tor_strdup( 941 "network-status-version foo\n" 942 "r name bbbbbbbbbbbbbbbbb etc\nfoo\n" 943 "r name aaaaaaaaaaaaaaaaa etc\nbar\n" 944 "directory-signature foo bar\nbar\n" 945 ); 946 cons2_str = tor_strdup( 947 "network-status-version foo\n" 948 "r name aaaaaaaaaaaaaaaaa etc\nfoo\n" 949 "r name ccccccccccccccccc etc\nbar\n" 950 "directory-signature foo bar\nbar\n" 951 ); 952 953 tt_int_op(0, OP_EQ, 954 consensus_compute_digest_as_signed_(cons1_str, &digests1)); 955 tt_int_op(0, OP_EQ, 956 consensus_compute_digest_(cons2_str, &digests2)); 957 958 consensus_split_lines_(cons1, cons1_str, area); 959 consensus_split_lines_(cons2, cons2_str, area); 960 961 diff = consdiff_gen_diff(cons1, cons2, &digests1, &digests2, area); 962 tt_ptr_op(NULL, OP_EQ, diff); 963 964 /* Check that the headers are done properly. */ 965 tor_free(cons1_str); 966 cons1_str = tor_strdup( 967 "network-status-version foo\n" 968 "r name ccccccccccccccccc etc\nfoo\n" 969 "r name eeeeeeeeeeeeeeeee etc\nbar\n" 970 "directory-signature foo bar\nbar\n" 971 ); 972 tt_int_op(0, OP_EQ, 973 consensus_compute_digest_as_signed_(cons1_str, &digests1)); 974 smartlist_clear(cons1); 975 consensus_split_lines_(cons1, cons1_str, area); 976 diff = consdiff_gen_diff(cons1, cons2, &digests1, &digests2, area); 977 tt_ptr_op(NULL, OP_NE, diff); 978 tt_int_op(11, OP_EQ, smartlist_len(diff)); 979 tt_assert(line_str_eq(smartlist_get(diff, 0), 980 "network-status-diff-version 1")); 981 tt_assert(line_str_eq(smartlist_get(diff, 1), "hash " 982 "95D70F5A3CC65F920AA8B44C4563D7781A082674329661884E19E94B79D539C2 " 983 "7AFECEFA4599BA33D603653E3D2368F648DF4AC4723929B0F7CF39281596B0C1")); 984 tt_assert(line_str_eq(smartlist_get(diff, 2), "6,$d")); 985 tt_assert(line_str_eq(smartlist_get(diff, 3), "3,4c")); 986 tt_assert(line_str_eq(smartlist_get(diff, 4), "bar")); 987 tt_assert(line_str_eq(smartlist_get(diff, 5), 988 "directory-signature foo bar")); 989 tt_assert(line_str_eq(smartlist_get(diff, 6), 990 ".")); 991 tt_assert(line_str_eq(smartlist_get(diff, 7), "1a")); 992 tt_assert(line_str_eq(smartlist_get(diff, 8), 993 "r name aaaaaaaaaaaaaaaaa etc")); 994 tt_assert(line_str_eq(smartlist_get(diff, 9), "foo")); 995 tt_assert(line_str_eq(smartlist_get(diff, 10), ".")); 996 997 /* TODO: small real use-cases, i.e. consensuses. */ 998 999 done: 1000 tor_free(cons1_str); 1001 tor_free(cons2_str); 1002 smartlist_free(cons1); 1003 smartlist_free(cons2); 1004 smartlist_free(diff); 1005 memarea_drop_all(area); 1006 } 1007 1008 static void 1009 test_consdiff_apply_diff(void *arg) 1010 { 1011 smartlist_t *cons1=NULL, *diff=NULL; 1012 char *cons1_str=NULL, *cons2 = NULL; 1013 consensus_digest_t digests1; 1014 (void)arg; 1015 memarea_t *area = memarea_new(); 1016 cons1 = smartlist_new(); 1017 diff = smartlist_new(); 1018 setup_capture_of_logs(LOG_INFO); 1019 1020 cons1_str = tor_strdup( 1021 "network-status-version foo\n" 1022 "r name ccccccccccccccccc etc\nfoo\n" 1023 "r name eeeeeeeeeeeeeeeee etc\nbar\n" 1024 "directory-signature foo bar\nbar\n" 1025 ); 1026 tt_int_op(0, OP_EQ, 1027 consensus_compute_digest_(cons1_str, &digests1)); 1028 consensus_split_lines_(cons1, cons1_str, area); 1029 1030 /* diff doesn't have enough lines. */ 1031 cons2 = consdiff_apply_diff(cons1, diff, &digests1); 1032 tt_ptr_op(NULL, OP_EQ, cons2); 1033 expect_single_log_msg_containing("too short"); 1034 1035 /* first line doesn't match format-version string. */ 1036 smartlist_add_linecpy(diff, area, "foo-bar"); 1037 smartlist_add_linecpy(diff, area, "header-line"); 1038 mock_clean_saved_logs(); 1039 cons2 = consdiff_apply_diff(cons1, diff, &digests1); 1040 tt_ptr_op(NULL, OP_EQ, cons2); 1041 expect_single_log_msg_containing("format is not known"); 1042 1043 /* The first word of the second header line is not "hash". */ 1044 smartlist_clear(diff); 1045 smartlist_add_linecpy(diff, area, "network-status-diff-version 1"); 1046 smartlist_add_linecpy(diff, area, "word a b"); 1047 smartlist_add_linecpy(diff, area, "x"); 1048 mock_clean_saved_logs(); 1049 cons2 = consdiff_apply_diff(cons1, diff, &digests1); 1050 tt_ptr_op(NULL, OP_EQ, cons2); 1051 expect_single_log_msg_containing("does not include the necessary digests"); 1052 1053 /* Wrong number of words after "hash". */ 1054 smartlist_clear(diff); 1055 smartlist_add_linecpy(diff, area, "network-status-diff-version 1"); 1056 smartlist_add_linecpy(diff, area, "hash a b c"); 1057 mock_clean_saved_logs(); 1058 cons2 = consdiff_apply_diff(cons1, diff, &digests1); 1059 tt_ptr_op(NULL, OP_EQ, cons2); 1060 expect_single_log_msg_containing("does not include the necessary digests"); 1061 1062 /* base16 digests do not have the expected length. */ 1063 smartlist_clear(diff); 1064 smartlist_add_linecpy(diff, area, "network-status-diff-version 1"); 1065 smartlist_add_linecpy(diff, area, "hash aaa bbb"); 1066 mock_clean_saved_logs(); 1067 cons2 = consdiff_apply_diff(cons1, diff, &digests1); 1068 tt_ptr_op(NULL, OP_EQ, cons2); 1069 expect_single_log_msg_containing("includes base16-encoded digests of " 1070 "incorrect size"); 1071 1072 /* base16 digests contain non-base16 characters. */ 1073 smartlist_clear(diff); 1074 smartlist_add_linecpy(diff, area, "network-status-diff-version 1"); 1075 smartlist_add_linecpy(diff, area, "hash" 1076 " ????????????????????????????????????????????????????????????????" 1077 " ----------------------------------------------------------------"); 1078 mock_clean_saved_logs(); 1079 cons2 = consdiff_apply_diff(cons1, diff, &digests1); 1080 tt_ptr_op(NULL, OP_EQ, cons2); 1081 expect_single_log_msg_containing("includes malformed digests"); 1082 1083 /* Invalid ed diff. 1084 * As tested in apply_ed_diff, but check that apply_diff does return NULL if 1085 * the ed diff can't be applied. */ 1086 smartlist_clear(diff); 1087 smartlist_add_linecpy(diff, area, "network-status-diff-version 1"); 1088 smartlist_add_linecpy(diff, area, "hash" 1089 /* sha3 of cons1. */ 1090 " 06646D6CF563A41869D3B02E73254372AE3140046C5E7D83C9F71E54976AF9B4" 1091 /* sha256 of cons2. */ 1092 " 635D34593020C08E5ECD865F9986E29D50028EFA62843766A8197AD228A7F6AA"); 1093 smartlist_add_linecpy(diff, area, "foobar"); 1094 mock_clean_saved_logs(); 1095 cons2 = consdiff_apply_diff(cons1, diff, &digests1); 1096 tt_ptr_op(NULL, OP_EQ, cons2); 1097 expect_single_log_msg_containing("because an ed command was missing a line " 1098 "number"); 1099 1100 /* Base consensus doesn't match its digest as found in the diff. */ 1101 smartlist_clear(diff); 1102 smartlist_add_linecpy(diff, area, "network-status-diff-version 1"); 1103 smartlist_add_linecpy(diff, area, "hash" 1104 /* bogus sha256. */ 1105 " 3333333333333333333333333333333333333333333333333333333333333333" 1106 /* sha256 of cons2. */ 1107 " 635D34593020C08E5ECD865F9986E29D50028EFA62843766A8197AD228A7F6AA"); 1108 mock_clean_saved_logs(); 1109 cons2 = consdiff_apply_diff(cons1, diff, &digests1); 1110 tt_ptr_op(NULL, OP_EQ, cons2); 1111 expect_log_msg_containing("base consensus doesn't match the digest " 1112 "as found"); 1113 1114 /* Resulting consensus doesn't match its digest as found in the diff. */ 1115 smartlist_clear(diff); 1116 smartlist_add_linecpy(diff, area, "network-status-diff-version 1"); 1117 smartlist_add_linecpy(diff, area, "hash" 1118 /* sha3 of cons1. */ 1119 " 06646D6CF563A41869D3B02E73254372AE3140046C5E7D83C9F71E54976AF9B4" 1120 /* bogus sha3. */ 1121 " 3333333333333333333333333333333333333333333333333333333333333333"); 1122 mock_clean_saved_logs(); 1123 cons2 = consdiff_apply_diff(cons1, diff, &digests1); 1124 tt_ptr_op(NULL, OP_EQ, cons2); 1125 expect_log_msg_containing("resulting consensus doesn't match the " 1126 "digest as found"); 1127 1128 #if 0 1129 /* XXXX No longer possible, since we aren't using the other algorithm. */ 1130 /* Resulting consensus digest cannot be computed */ 1131 smartlist_clear(diff); 1132 smartlist_add_linecpy(diff, area, "network-status-diff-version 1"); 1133 smartlist_add_linecpy(diff, area, "hash" 1134 /* sha3 of cons1. */ 1135 " 06646D6CF563A41869D3B02E73254372AE3140046C5E7D83C9F71E54976AF9B4" 1136 /* bogus sha3. */ 1137 " 3333333333333333333333333333333333333333333333333333333333333333"); 1138 smartlist_add_linecpy(diff, area, "1,2d"); // remove starting line 1139 mock_clean_saved_logs(); 1140 cons2 = consdiff_apply_diff(cons1, diff, &digests1); 1141 tt_ptr_op(NULL, OP_EQ, cons2); 1142 expect_log_msg_containing("Could not compute digests of the consensus " 1143 "resulting from applying a consensus diff."); 1144 #endif /* 0 */ 1145 1146 /* Very simple test, only to see that nothing errors. */ 1147 smartlist_clear(diff); 1148 smartlist_add_linecpy(diff, area, "network-status-diff-version 1"); 1149 smartlist_add_linecpy(diff, area, "hash" 1150 /* sha3 of cons1. */ 1151 " 06646D6CF563A41869D3B02E73254372AE3140046C5E7D83C9F71E54976AF9B4" 1152 /* sha3 of cons2. */ 1153 " 90A418881B2FCAB3D9E60EE02E4D666D56CFA38F8A3B7AA3E0ADBA530DDA9353"); 1154 smartlist_add_linecpy(diff, area, "3c"); 1155 smartlist_add_linecpy(diff, area, "sample"); 1156 smartlist_add_linecpy(diff, area, "."); 1157 cons2 = consdiff_apply_diff(cons1, diff, &digests1); 1158 tt_ptr_op(NULL, OP_NE, cons2); 1159 tt_str_op( 1160 "network-status-version foo\n" 1161 "r name ccccccccccccccccc etc\nsample\n" 1162 "r name eeeeeeeeeeeeeeeee etc\nbar\n" 1163 "directory-signature foo bar\nbar\n", OP_EQ, 1164 cons2); 1165 tor_free(cons2); 1166 1167 /* Check that lowercase letters in base16-encoded digests work too. */ 1168 smartlist_clear(diff); 1169 smartlist_add_linecpy(diff, area, "network-status-diff-version 1"); 1170 smartlist_add_linecpy(diff, area, "hash" 1171 /* sha3 of cons1. */ 1172 " 06646d6cf563a41869d3b02e73254372ae3140046c5e7d83c9f71e54976af9b4" 1173 /* sha3 of cons2. */ 1174 " 90a418881b2fcab3d9e60ee02e4d666d56cfa38f8a3b7aa3e0adba530dda9353"); 1175 smartlist_add_linecpy(diff, area, "3c"); 1176 smartlist_add_linecpy(diff, area, "sample"); 1177 smartlist_add_linecpy(diff, area, "."); 1178 cons2 = consdiff_apply_diff(cons1, diff, &digests1); 1179 tt_ptr_op(NULL, OP_NE, cons2); 1180 tt_str_op( 1181 "network-status-version foo\n" 1182 "r name ccccccccccccccccc etc\nsample\n" 1183 "r name eeeeeeeeeeeeeeeee etc\nbar\n" 1184 "directory-signature foo bar\nbar\n", OP_EQ, 1185 cons2); 1186 tor_free(cons2); 1187 1188 smartlist_clear(diff); 1189 1190 done: 1191 teardown_capture_of_logs(); 1192 tor_free(cons1_str); 1193 smartlist_free(cons1); 1194 smartlist_free(diff); 1195 memarea_drop_all(area); 1196 } 1197 1198 #define CONSDIFF_LEGACY(name) \ 1199 { #name, test_consdiff_ ## name , 0, NULL, NULL } 1200 1201 struct testcase_t consdiff_tests[] = { 1202 CONSDIFF_LEGACY(smartlist_slice), 1203 CONSDIFF_LEGACY(smartlist_slice_string_pos), 1204 CONSDIFF_LEGACY(lcs_lengths), 1205 CONSDIFF_LEGACY(trim_slices), 1206 CONSDIFF_LEGACY(set_changed), 1207 CONSDIFF_LEGACY(calc_changes), 1208 CONSDIFF_LEGACY(get_id_hash), 1209 CONSDIFF_LEGACY(is_valid_router_entry), 1210 CONSDIFF_LEGACY(next_router), 1211 CONSDIFF_LEGACY(base64cmp), 1212 CONSDIFF_LEGACY(gen_ed_diff), 1213 CONSDIFF_LEGACY(apply_ed_diff), 1214 CONSDIFF_LEGACY(gen_diff), 1215 CONSDIFF_LEGACY(apply_diff), 1216 END_OF_TESTCASES 1217 };