1 /* Copyright (c) 2010-2013, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
19 static const char test_md1
[] =
21 "-----BEGIN RSA PUBLIC KEY-----\n"
22 "MIGJAoGBAMjlHH/daN43cSVRaHBwgUfnszzAhg98EvivJ9Qxfv51mvQUxPjQ07es\n"
23 "gV/3n8fyh3Kqr/ehi9jxkdgSRfSnmF7giaHL1SLZ29kA7KtST+pBvmTpDtHa3ykX\n"
24 "Xorc7hJvIyTZoc1HU+5XSynj3gsBE5IGK1ZRzrNS688LnuZMVp1tAgMBAAE=\n"
25 "-----END RSA PUBLIC KEY-----\n";
27 static const char test_md2
[] =
29 "-----BEGIN RSA PUBLIC KEY-----\n"
30 "MIGJAoGBAMIixIowh2DyPmDNMDwBX2DHcYcqdcH1zdIQJZkyV6c6rQHnvbcaDoSg\n"
31 "jgFSLJKpnGmh71FVRqep+yVB0zI1JY43kuEnXry2HbZCD9UDo3d3n7t015X5S7ON\n"
32 "bSSYtQGPwOr6Epf96IF6DoQxy4iDnPUAlejuhAG51s1y6/rZQ3zxAgMBAAE=\n"
33 "-----END RSA PUBLIC KEY-----\n";
35 static const char test_md3
[] =
36 "@last-listed 2009-06-22\n"
38 "-----BEGIN RSA PUBLIC KEY-----\n"
39 "MIGJAoGBAMH3340d4ENNGrqx7UxT+lB7x6DNUKOdPEOn4teceE11xlMyZ9TPv41c\n"
40 "qj2fRZzfxlc88G/tmiaHshmdtEpklZ740OFqaaJVj4LjPMKFNE+J7Xc1142BE9Ci\n"
41 "KgsbjGYe2RY261aADRWLetJ8T9QDMm+JngL4288hc8pq1uB/3TAbAgMBAAE=\n"
42 "-----END RSA PUBLIC KEY-----\n"
43 "p accept 1-700,800-1000\n"
44 "family nodeX nodeY nodeZ\n";
47 test_md_cache(void *data
)
49 or_options_t
*options
= NULL
;
50 microdesc_cache_t
*mc
= NULL
;
51 smartlist_t
*added
= NULL
, *wanted
= NULL
;
52 microdesc_t
*md1
, *md2
, *md3
;
53 char d1
[DIGEST256_LEN
], d2
[DIGEST256_LEN
], d3
[DIGEST256_LEN
];
54 const char *test_md3_noannotation
= strchr(test_md3
, '\n')+1;
55 time_t time1
, time2
, time3
;
56 char *fn
= NULL
, *s
= NULL
;
59 options
= get_options_mutable();
63 time2
= time(NULL
) - 2*24*60*60;
64 time3
= time(NULL
) - 15*24*60*60;
66 /* Possibly, turn this into a test setup/cleanup pair */
67 tor_free(options
->DataDirectory
);
68 options
->DataDirectory
= tor_strdup(get_fname("md_datadir_test"));
70 tt_int_op(0, ==, mkdir(options
->DataDirectory
));
72 tt_int_op(0, ==, mkdir(options
->DataDirectory
, 0700));
75 tt_assert(!strcmpstart(test_md3_noannotation
, "onion-key"));
77 crypto_digest256(d1
, test_md1
, strlen(test_md1
), DIGEST_SHA256
);
78 crypto_digest256(d2
, test_md2
, strlen(test_md1
), DIGEST_SHA256
);
79 crypto_digest256(d3
, test_md3_noannotation
, strlen(test_md3_noannotation
),
82 mc
= get_microdesc_cache();
84 added
= microdescs_add_to_cache(mc
, test_md1
, NULL
, SAVED_NOWHERE
, 0,
86 tt_int_op(1, ==, smartlist_len(added
));
87 md1
= smartlist_get(added
, 0);
88 smartlist_free(added
);
91 wanted
= smartlist_new();
92 added
= microdescs_add_to_cache(mc
, test_md2
, NULL
, SAVED_NOWHERE
, 0,
94 /* Should fail, since we didn't list test_md2's digest in wanted */
95 tt_int_op(0, ==, smartlist_len(added
));
96 smartlist_free(added
);
99 smartlist_add(wanted
, tor_memdup(d2
, DIGEST256_LEN
));
100 smartlist_add(wanted
, tor_memdup(d3
, DIGEST256_LEN
));
101 added
= microdescs_add_to_cache(mc
, test_md2
, NULL
, SAVED_NOWHERE
, 0,
103 /* Now it can work. md2 should have been added */
104 tt_int_op(1, ==, smartlist_len(added
));
105 md2
= smartlist_get(added
, 0);
106 /* And it should have gotten removed from 'wanted' */
107 tt_int_op(smartlist_len(wanted
), ==, 1);
108 test_mem_op(smartlist_get(wanted
, 0), ==, d3
, DIGEST256_LEN
);
109 smartlist_free(added
);
112 added
= microdescs_add_to_cache(mc
, test_md3
, NULL
,
113 SAVED_NOWHERE
, 0, -1, NULL
);
114 /* Must fail, since SAVED_NOWHERE precludes annotations */
115 tt_int_op(0, ==, smartlist_len(added
));
116 smartlist_free(added
);
119 added
= microdescs_add_to_cache(mc
, test_md3_noannotation
, NULL
,
120 SAVED_NOWHERE
, 0, time3
, NULL
);
121 /* Now it can work */
122 tt_int_op(1, ==, smartlist_len(added
));
123 md3
= smartlist_get(added
, 0);
124 smartlist_free(added
);
127 /* Okay. We added 1...3. Let's poke them to see how they look, and make
128 * sure they're really in the journal. */
129 tt_ptr_op(md1
, ==, microdesc_cache_lookup_by_digest256(mc
, d1
));
130 tt_ptr_op(md2
, ==, microdesc_cache_lookup_by_digest256(mc
, d2
));
131 tt_ptr_op(md3
, ==, microdesc_cache_lookup_by_digest256(mc
, d3
));
133 tt_int_op(md1
->last_listed
, ==, time1
);
134 tt_int_op(md2
->last_listed
, ==, time2
);
135 tt_int_op(md3
->last_listed
, ==, time3
);
137 tt_int_op(md1
->saved_location
, ==, SAVED_IN_JOURNAL
);
138 tt_int_op(md2
->saved_location
, ==, SAVED_IN_JOURNAL
);
139 tt_int_op(md3
->saved_location
, ==, SAVED_IN_JOURNAL
);
141 tt_int_op(md1
->bodylen
, ==, strlen(test_md1
));
142 tt_int_op(md2
->bodylen
, ==, strlen(test_md2
));
143 tt_int_op(md3
->bodylen
, ==, strlen(test_md3_noannotation
));
144 test_mem_op(md1
->body
, ==, test_md1
, strlen(test_md1
));
145 test_mem_op(md2
->body
, ==, test_md2
, strlen(test_md2
));
146 test_mem_op(md3
->body
, ==, test_md3_noannotation
,
147 strlen(test_md3_noannotation
));
149 tor_asprintf(&fn
, "%s"PATH_SEPARATOR
"cached-microdescs.new",
150 options
->DataDirectory
);
151 s
= read_file_to_str(fn
, RFTS_BIN
, NULL
);
153 test_mem_op(md1
->body
, ==, s
+ md1
->off
, md1
->bodylen
);
154 test_mem_op(md2
->body
, ==, s
+ md2
->off
, md2
->bodylen
);
155 test_mem_op(md3
->body
, ==, s
+ md3
->off
, md3
->bodylen
);
157 tt_ptr_op(md1
->family
, ==, NULL
);
158 tt_ptr_op(md3
->family
, !=, NULL
);
159 tt_int_op(smartlist_len(md3
->family
), ==, 3);
160 tt_str_op(smartlist_get(md3
->family
, 0), ==, "nodeX");
162 /* Now rebuild the cache! */
163 tt_int_op(microdesc_cache_rebuild(mc
, 1), ==, 0);
165 tt_int_op(md1
->saved_location
, ==, SAVED_IN_CACHE
);
166 tt_int_op(md2
->saved_location
, ==, SAVED_IN_CACHE
);
167 tt_int_op(md3
->saved_location
, ==, SAVED_IN_CACHE
);
169 /* The journal should be empty now */
171 s
= read_file_to_str(fn
, RFTS_BIN
, NULL
);
172 tt_str_op(s
, ==, "");
176 /* read the cache. */
177 tor_asprintf(&fn
, "%s"PATH_SEPARATOR
"cached-microdescs",
178 options
->DataDirectory
);
179 s
= read_file_to_str(fn
, RFTS_BIN
, NULL
);
180 test_mem_op(md1
->body
, ==, s
+ md1
->off
, strlen(test_md1
));
181 test_mem_op(md2
->body
, ==, s
+ md2
->off
, strlen(test_md2
));
182 test_mem_op(md3
->body
, ==, s
+ md3
->off
, strlen(test_md3_noannotation
));
184 /* Okay, now we are going to forget about the cache entirely, and reload it
186 microdesc_free_all();
187 mc
= get_microdesc_cache();
188 md1
= microdesc_cache_lookup_by_digest256(mc
, d1
);
189 md2
= microdesc_cache_lookup_by_digest256(mc
, d2
);
190 md3
= microdesc_cache_lookup_by_digest256(mc
, d3
);
194 test_mem_op(md1
->body
, ==, s
+ md1
->off
, strlen(test_md1
));
195 test_mem_op(md2
->body
, ==, s
+ md2
->off
, strlen(test_md2
));
196 test_mem_op(md3
->body
, ==, s
+ md3
->off
, strlen(test_md3_noannotation
));
198 tt_int_op(md1
->last_listed
, ==, time1
);
199 tt_int_op(md2
->last_listed
, ==, time2
);
200 tt_int_op(md3
->last_listed
, ==, time3
);
202 /* Okay, now we are going to clear out everything older than a week old.
203 * In practice, that means md3 */
204 microdesc_cache_clean(mc
, time(NULL
)-7*24*60*60, 1/*force*/);
205 tt_ptr_op(md1
, ==, microdesc_cache_lookup_by_digest256(mc
, d1
));
206 tt_ptr_op(md2
, ==, microdesc_cache_lookup_by_digest256(mc
, d2
));
207 tt_ptr_op(NULL
, ==, microdesc_cache_lookup_by_digest256(mc
, d3
));
208 md3
= NULL
; /* it's history now! */
210 /* rebuild again, make sure it stays gone. */
211 tt_int_op(microdesc_cache_rebuild(mc
, 1), ==, 0);
212 tt_ptr_op(md1
, ==, microdesc_cache_lookup_by_digest256(mc
, d1
));
213 tt_ptr_op(md2
, ==, microdesc_cache_lookup_by_digest256(mc
, d2
));
214 tt_ptr_op(NULL
, ==, microdesc_cache_lookup_by_digest256(mc
, d3
));
216 /* Re-add md3, and make sure we can rebuild the cache. */
217 added
= microdescs_add_to_cache(mc
, test_md3_noannotation
, NULL
,
218 SAVED_NOWHERE
, 0, time3
, NULL
);
219 tt_int_op(1, ==, smartlist_len(added
));
220 md3
= smartlist_get(added
, 0);
221 smartlist_free(added
);
223 tt_int_op(md1
->saved_location
, ==, SAVED_IN_CACHE
);
224 tt_int_op(md2
->saved_location
, ==, SAVED_IN_CACHE
);
225 tt_int_op(md3
->saved_location
, ==, SAVED_IN_JOURNAL
);
227 tt_int_op(microdesc_cache_rebuild(mc
, 1), ==, 0);
228 tt_int_op(md3
->saved_location
, ==, SAVED_IN_CACHE
);
232 tor_free(options
->DataDirectory
);
233 microdesc_free_all();
235 smartlist_free(added
);
237 SMARTLIST_FOREACH(wanted
, char *, cp
, tor_free(cp
));
238 smartlist_free(wanted
);
243 struct testcase_t microdesc_tests
[] = {
244 { "cache", test_md_cache
, TT_FORK
, NULL
, NULL
},