LCOV - code coverage report
Current view: top level - test - test_conscache.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 214 214 100.0 %
Date: 2021-11-24 03:28:48 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /* Copyright (c) 2017-2021, The Tor Project, Inc. */
       2             : /* See LICENSE for licensing information */
       3             : 
       4             : #include "core/or/or.h"
       5             : #include "app/config/config.h"
       6             : #include "feature/dircache/conscache.h"
       7             : #include "lib/encoding/confline.h"
       8             : #include "test/test.h"
       9             : 
      10             : #ifdef HAVE_UTIME_H
      11             : #include <utime.h>
      12             : #endif
      13             : 
      14             : static void
      15           1 : test_conscache_open_failure(void *arg)
      16             : {
      17           1 :   (void) arg;
      18             :   /* Try opening a directory that doesn't exist and which we shouldn't be
      19             :    * able to create. */
      20           1 :   consensus_cache_t *cache = consensus_cache_open("a/b/c/d/e/f/g", 128);
      21           1 :   tt_ptr_op(cache, OP_EQ, NULL);
      22             : 
      23           1 :  done:
      24           1 :   ;
      25           1 : }
      26             : 
      27             : static void
      28           1 : test_conscache_simple_usage(void *arg)
      29             : {
      30           1 :   (void)arg;
      31           1 :   consensus_cache_entry_t *ent = NULL, *ent2 = NULL;
      32             : 
      33             :   /* Make a temporary datadir for these tests */
      34           1 :   char *ddir_fname = tor_strdup(get_fname_rnd("datadir_cache"));
      35           1 :   tor_free(get_options_mutable()->CacheDirectory);
      36           1 :   get_options_mutable()->CacheDirectory = tor_strdup(ddir_fname);
      37           1 :   check_private_dir(ddir_fname, CPD_CREATE, NULL);
      38           1 :   consensus_cache_t *cache = consensus_cache_open("cons", 128);
      39             : 
      40           1 :   tt_assert(cache);
      41             : 
      42             :   /* Create object; make sure it exists. */
      43           1 :   config_line_t *labels = NULL;
      44           1 :   config_line_append(&labels, "Hello", "world");
      45           1 :   config_line_append(&labels, "Adios", "planetas");
      46           1 :   ent = consensus_cache_add(cache,
      47             :                             labels, (const uint8_t *)"A\0B\0C", 5);
      48           1 :   config_free_lines(labels);
      49           1 :   labels = NULL;
      50           1 :   tt_assert(ent);
      51             : 
      52             :   /* Make a second object */
      53           1 :   config_line_append(&labels, "Hello", "mundo");
      54           1 :   config_line_append(&labels, "Adios", "planets");
      55           1 :   ent2 = consensus_cache_add(cache,
      56             :                              labels, (const uint8_t *)"xyzzy", 5);
      57           1 :   config_free_lines(labels);
      58           1 :   labels = NULL;
      59           1 :   tt_assert(ent2);
      60           1 :   tt_assert(! consensus_cache_entry_is_mapped(ent2));
      61           1 :   consensus_cache_entry_decref(ent2);
      62           1 :   ent2 = NULL;
      63             : 
      64             :   /* Check get_value */
      65           1 :   tt_ptr_op(NULL, OP_EQ, consensus_cache_entry_get_value(ent, "hebbo"));
      66           1 :   tt_str_op("world", OP_EQ, consensus_cache_entry_get_value(ent, "Hello"));
      67             : 
      68             :   /* Check find_first */
      69           1 :   ent2 = consensus_cache_find_first(cache, "Hello", "world!");
      70           1 :   tt_ptr_op(ent2, OP_EQ, NULL);
      71           1 :   ent2 = consensus_cache_find_first(cache, "Hello", "world");
      72           1 :   tt_ptr_op(ent2, OP_EQ, ent);
      73           1 :   ent2 = consensus_cache_find_first(cache, "Hello", "mundo");
      74           1 :   tt_ptr_op(ent2, OP_NE, ent);
      75             : 
      76           1 :   tt_assert(! consensus_cache_entry_is_mapped(ent));
      77             : 
      78             :   /* Check get_body */
      79           1 :   const uint8_t *bp = NULL;
      80           1 :   size_t sz = 0;
      81           1 :   int r = consensus_cache_entry_get_body(ent, &bp, &sz);
      82           1 :   tt_int_op(r, OP_EQ, 0);
      83           1 :   tt_u64_op(sz, OP_EQ, 5);
      84           1 :   tt_mem_op(bp, OP_EQ, "A\0B\0C", 5);
      85           1 :   tt_assert(consensus_cache_entry_is_mapped(ent));
      86             : 
      87             :   /* Free and re-create the cache, to rescan the directory. */
      88           1 :   consensus_cache_free(cache);
      89           1 :   consensus_cache_entry_decref(ent);
      90           1 :   cache = consensus_cache_open("cons", 128);
      91             : 
      92             :   /* Make sure the entry is still there */
      93           1 :   ent = consensus_cache_find_first(cache, "Hello", "mundo");
      94           1 :   tt_assert(ent);
      95           1 :   ent2 = consensus_cache_find_first(cache, "Adios", "planets");
      96           1 :   tt_ptr_op(ent, OP_EQ, ent2);
      97           1 :   consensus_cache_entry_incref(ent);
      98           1 :   tt_assert(! consensus_cache_entry_is_mapped(ent));
      99           1 :   r = consensus_cache_entry_get_body(ent, &bp, &sz);
     100           1 :   tt_int_op(r, OP_EQ, 0);
     101           1 :   tt_u64_op(sz, OP_EQ, 5);
     102           1 :   tt_mem_op(bp, OP_EQ, "xyzzy", 5);
     103           1 :   tt_assert(consensus_cache_entry_is_mapped(ent));
     104             : 
     105             :   /* There should be two entries total. */
     106           1 :   smartlist_t *entries = smartlist_new();
     107           1 :   consensus_cache_find_all(entries, cache, NULL, NULL);
     108           1 :   int n = smartlist_len(entries);
     109           1 :   smartlist_free(entries);
     110           1 :   tt_int_op(n, OP_EQ, 2);
     111             : 
     112           1 :  done:
     113           1 :   consensus_cache_entry_decref(ent);
     114           1 :   tor_free(ddir_fname);
     115           1 :   consensus_cache_free(cache);
     116           1 : }
     117             : 
     118             : static void
     119           1 : test_conscache_cleanup(void *arg)
     120             : {
     121           1 :   (void)arg;
     122           1 :   const int N = 20;
     123           2 :   consensus_cache_entry_t **ents =
     124           1 :     tor_calloc(N, sizeof(consensus_cache_entry_t*));
     125             : 
     126             :   /* Make a temporary datadir for these tests */
     127           1 :   char *ddir_fname = tor_strdup(get_fname_rnd("datadir_cache"));
     128           1 :   tor_free(get_options_mutable()->CacheDirectory);
     129           1 :   get_options_mutable()->CacheDirectory = tor_strdup(ddir_fname);
     130           1 :   check_private_dir(ddir_fname, CPD_CREATE, NULL);
     131           1 :   consensus_cache_t *cache = consensus_cache_open("cons", 128);
     132             : 
     133           1 :   tt_assert(cache);
     134             : 
     135             :   /* Create a bunch of entries. */
     136             :   int i;
     137          21 :   for (i = 0; i < N; ++i) {
     138          20 :     config_line_t *labels = NULL;
     139          20 :     char num[8];
     140          20 :     tor_snprintf(num, sizeof(num), "%d", i);
     141          20 :     config_line_append(&labels, "test-id", "cleanup");
     142          20 :     config_line_append(&labels, "index", num);
     143          20 :     size_t bodylen = i * 3;
     144          20 :     uint8_t *body = tor_malloc(bodylen);
     145          20 :     memset(body, i, bodylen);
     146          20 :     ents[i] = consensus_cache_add(cache, labels, body, bodylen);
     147          20 :     tor_free(body);
     148          20 :     config_free_lines(labels);
     149          20 :     tt_assert(ents[i]);
     150             :     /* We're still holding a reference to each entry at this point. */
     151             :   }
     152             : 
     153             :   /* Page all of the entries into RAM */
     154          21 :   for (i = 0; i < N; ++i) {
     155          20 :     const uint8_t *bp;
     156          20 :     size_t sz;
     157          20 :     tt_assert(! consensus_cache_entry_is_mapped(ents[i]));
     158          20 :     consensus_cache_entry_get_body(ents[i], &bp, &sz);
     159          20 :     tt_assert(consensus_cache_entry_is_mapped(ents[i]));
     160             :   }
     161             : 
     162             :   /* Mark some of the entries as deletable. */
     163           3 :   for (i = 7; i < N; i += 7) {
     164           2 :     consensus_cache_entry_mark_for_removal(ents[i]);
     165           2 :     tt_assert(consensus_cache_entry_is_mapped(ents[i]));
     166             :   }
     167             : 
     168             :   /* Mark some of the entries as aggressively unpaged. */
     169           7 :   for (i = 3; i < N; i += 3) {
     170           6 :     consensus_cache_entry_mark_for_aggressive_release(ents[i]);
     171           6 :     tt_assert(consensus_cache_entry_is_mapped(ents[i]));
     172             :   }
     173             : 
     174             :   /* Incref some of the entries again */
     175          11 :   for (i = 0; i < N; i += 2) {
     176          10 :     consensus_cache_entry_incref(ents[i]);
     177             :   }
     178             : 
     179             :   /* Now we're going to decref everything. We do so at a specific time.  I'm
     180             :    * picking the moment when I was writing this test, at 2017-04-05 12:16:48
     181             :    * UTC. */
     182           1 :   const time_t example_time = 1491394608;
     183           1 :   update_approx_time(example_time);
     184          22 :   for (i = 0; i < N; ++i) {
     185          20 :     consensus_cache_entry_decref(ents[i]);
     186          20 :     if (i % 2) {
     187          10 :       ents[i] = NULL; /* We're no longer holding any reference here. */
     188             :     }
     189             :   }
     190             : 
     191             :   /* At this point, the aggressively-released items with refcount 1 should
     192             :    * be unmapped. Nothing should be deleted. */
     193           1 :   consensus_cache_entry_t *e_tmp;
     194           1 :   e_tmp = consensus_cache_find_first(cache, "index", "3");
     195           1 :   tt_assert(e_tmp);
     196           1 :   tt_assert(! consensus_cache_entry_is_mapped(e_tmp));
     197           1 :   e_tmp = consensus_cache_find_first(cache, "index", "5");
     198           1 :   tt_assert(e_tmp);
     199           1 :   tt_assert(consensus_cache_entry_is_mapped(e_tmp));
     200           1 :   e_tmp = consensus_cache_find_first(cache, "index", "6");
     201           1 :   tt_assert(e_tmp);
     202           1 :   tt_assert(consensus_cache_entry_is_mapped(e_tmp));
     203           1 :   e_tmp = consensus_cache_find_first(cache, "index", "7");
     204           1 :   tt_ptr_op(e_tmp, OP_EQ, NULL); // not found because pending deletion.
     205             : 
     206             :   /* Delete the pending-deletion items. */
     207           1 :   consensus_cache_delete_pending(cache, 0);
     208             :   {
     209           1 :     smartlist_t *entries = smartlist_new();
     210           1 :     consensus_cache_find_all(entries, cache, NULL, NULL);
     211           1 :     int n = smartlist_len(entries);
     212           1 :     smartlist_free(entries);
     213           1 :     tt_int_op(n, OP_EQ, 20 - 2); /* 1 entry was deleted; 1 is not-found. */
     214             :   }
     215           1 :   e_tmp = consensus_cache_find_first(cache, "index", "7"); // refcnt == 1...
     216           1 :   tt_ptr_op(e_tmp, OP_EQ, NULL); // so deleted.
     217           1 :   e_tmp = consensus_cache_find_first(cache, "index", "14"); // refcnt == 2
     218           1 :   tt_ptr_op(e_tmp, OP_EQ, NULL); // not deleted; but not found.
     219             : 
     220             :   /* Now do lazy unmapping. */
     221             :   // should do nothing.
     222           1 :   consensus_cache_unmap_lazy(cache, example_time - 10);
     223           1 :   e_tmp = consensus_cache_find_first(cache, "index", "11");
     224           1 :   tt_assert(e_tmp);
     225           1 :   tt_assert(consensus_cache_entry_is_mapped(e_tmp));
     226             :   // should actually unmap
     227           1 :   consensus_cache_unmap_lazy(cache, example_time + 10);
     228           1 :   e_tmp = consensus_cache_find_first(cache, "index", "11");
     229           1 :   tt_assert(e_tmp);
     230           1 :   tt_assert(! consensus_cache_entry_is_mapped(e_tmp));
     231             :   // This one will still be mapped, since it has a reference.
     232           1 :   e_tmp = consensus_cache_find_first(cache, "index", "16");
     233           1 :   tt_assert(e_tmp);
     234           1 :   tt_assert(consensus_cache_entry_is_mapped(e_tmp));
     235             : 
     236          21 :   for (i = 0; i < N; ++i) {
     237          20 :     consensus_cache_entry_decref(ents[i]);
     238          20 :     ents[i] = NULL;
     239             :   }
     240             : 
     241             :   /* Free and re-create the cache, to rescan the directory. Make sure the
     242             :    * deleted thing is still deleted, along with the other deleted thing. */
     243           1 :   consensus_cache_free(cache);
     244           1 :   cache = consensus_cache_open("cons", 128);
     245             :   {
     246           1 :     smartlist_t *entries = smartlist_new();
     247           1 :     consensus_cache_find_all(entries, cache, NULL, NULL);
     248           1 :     int n = smartlist_len(entries);
     249           1 :     smartlist_free(entries);
     250           1 :     tt_int_op(n, OP_EQ, 18);
     251             :   }
     252             : 
     253           1 :  done:
     254          21 :   for (i = 0; i < N; ++i) {
     255          20 :     consensus_cache_entry_decref(ents[i]);
     256             :   }
     257           1 :   tor_free(ents);
     258           1 :   tor_free(ddir_fname);
     259           1 :   consensus_cache_free(cache);
     260           1 : }
     261             : 
     262             : static void
     263           1 : test_conscache_filter(void *arg)
     264             : {
     265           1 :   (void)arg;
     266           1 :   const int N = 30;
     267           1 :   smartlist_t *lst = NULL;
     268             : 
     269             :   /* Make a temporary datadir for these tests */
     270           1 :   char *ddir_fname = tor_strdup(get_fname_rnd("datadir_cache"));
     271           1 :   tor_free(get_options_mutable()->CacheDirectory);
     272           1 :   get_options_mutable()->CacheDirectory = tor_strdup(ddir_fname);
     273           1 :   check_private_dir(ddir_fname, CPD_CREATE, NULL);
     274           1 :   consensus_cache_t *cache = consensus_cache_open("cons", 128);
     275             : 
     276           1 :   tt_assert(cache);
     277             : 
     278             :   /* Create a bunch of entries with different labels */
     279             :   int i;
     280          31 :   for (i = 0; i < N; ++i) {
     281          30 :     config_line_t *labels = NULL;
     282          30 :     char num[8];
     283          30 :     tor_snprintf(num, sizeof(num), "%d", i);
     284          30 :     config_line_append(&labels, "test-id", "filter");
     285          30 :     config_line_append(&labels, "index", num);
     286          30 :     tor_snprintf(num, sizeof(num), "%d", i % 3);
     287          30 :     config_line_append(&labels, "mod3", num);
     288          30 :     tor_snprintf(num, sizeof(num), "%d", i % 5);
     289          30 :     config_line_append(&labels, "mod5", num);
     290             : 
     291          30 :     size_t bodylen = i * 3;
     292          30 :     uint8_t *body = tor_malloc(bodylen);
     293          30 :     memset(body, i, bodylen);
     294          30 :     consensus_cache_entry_t *ent =
     295          30 :       consensus_cache_add(cache, labels, body, bodylen);
     296          30 :     tor_free(body);
     297          30 :     config_free_lines(labels);
     298          30 :     tt_assert(ent);
     299          30 :     consensus_cache_entry_decref(ent);
     300             :   }
     301             : 
     302           1 :   lst = smartlist_new();
     303             :   /* Find nothing. */
     304           1 :   consensus_cache_find_all(lst, cache, "mod5", "5");
     305           1 :   tt_int_op(smartlist_len(lst), OP_EQ, 0);
     306             :   /* Find everything. */
     307           1 :   consensus_cache_find_all(lst, cache, "test-id", "filter");
     308           1 :   tt_int_op(smartlist_len(lst), OP_EQ, N);
     309             : 
     310             :   /* Now filter to find the entries that have i%3 == 1 */
     311           1 :   consensus_cache_filter_list(lst, "mod3", "1");
     312           1 :   tt_int_op(smartlist_len(lst), OP_EQ, 10);
     313             :   /* Now filter to find the entries that also have i%5 == 3 */
     314           1 :   consensus_cache_filter_list(lst, "mod5", "3");
     315           1 :   tt_int_op(smartlist_len(lst), OP_EQ, 2);
     316             :   /* So now we have those entries for which i%15 == 13. */
     317             : 
     318           1 :   consensus_cache_entry_t *ent1 = smartlist_get(lst, 0);
     319           1 :   consensus_cache_entry_t *ent2 = smartlist_get(lst, 1);
     320           1 :   const char *idx1 = consensus_cache_entry_get_value(ent1, "index");
     321           1 :   const char *idx2 = consensus_cache_entry_get_value(ent2, "index");
     322           1 :   tt_assert( (!strcmp(idx1, "28") && !strcmp(idx2, "13")) ||
     323             :              (!strcmp(idx1, "13") && !strcmp(idx2, "28")) );
     324             : 
     325           1 :  done:
     326           1 :   tor_free(ddir_fname);
     327           1 :   consensus_cache_free(cache);
     328           1 :   smartlist_free(lst);
     329           1 : }
     330             : 
     331             : #define ENT(name)                                               \
     332             :   { #name, test_conscache_ ## name, TT_FORK, NULL, NULL }
     333             : 
     334             : struct testcase_t conscache_tests[] = {
     335             :   ENT(open_failure),
     336             :   ENT(simple_usage),
     337             :   ENT(cleanup),
     338             :   ENT(filter),
     339             :   END_OF_TESTCASES
     340             : };

Generated by: LCOV version 1.14