Branch data Line data Source code
1 : : #include "sute.h"
2 : :
3 : : /**
4 : : * @brief Verify reporting and preservation of inaccessible paths
5 : : *
6 : : * Makes one file and one directory inaccessible, runs an update without
7 : : * `--db-drop-inaccessible`, and verifies that the expected inaccessible-path
8 : : * messages are produced while their database records are retained
9 : : */
10 : 2 : static Return test0029_1(void)
11 : : {
12 : 2 : INITTEST;
13 : :
14 : : // Create memory for the result
15 : 2 : m_create(char,result,MEMORY_STRING);
16 : 2 : m_create(char,pattern,MEMORY_STRING);
17 : :
18 : : // Preparation for tests
19 : 2 : ASSERT(SUCCESS == prepare_mutable_fixture("tests/fixtures/diffs/diff1"));
20 : :
21 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTING","false"));
22 : :
23 : 2 : const char *arguments = "--silent --database=database1.db tests/fixtures/diffs/diff1";
24 : :
25 : 2 : ASSERT(SUCCESS == runit(arguments,result,NULL,COMPLETED,ALLOW_BOTH));
26 : :
27 : 2 : ASSERT(result->length == 0);
28 : :
29 : 2 : ASSERT(SUCCESS == change_mode("tests/fixtures/diffs/diff1/1/AAA/ZAW/D/e/f/b_file.txt",0000));
30 : 2 : ASSERT(SUCCESS == change_mode("tests/fixtures/diffs/diff1/2/AAA/BBB/CZC",0000));
31 : :
32 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTING","true"));
33 : :
34 : 2 : arguments = "--update --check-level=QUICK --database=database1.db tests/fixtures/diffs/diff1";
35 : :
36 : 2 : ASSERT(SUCCESS == runit(arguments,result,NULL,COMPLETED,ALLOW_BOTH));
37 : :
38 : 2 : const char *filename = "templates/0029_001.txt";
39 : :
40 : 2 : ASSERT(SUCCESS == get_file_content(filename,pattern));
41 : 2 : ASSERT(SUCCESS == match_pattern(result,pattern,filename));
42 : :
43 : 2 : m_del(pattern);
44 : 2 : m_del(result);
45 : :
46 : : // Clean up test results
47 : 2 : ASSERT(SUCCESS == delete_path("database1.db"));
48 : 2 : ASSERT(SUCCESS == change_mode("tests/fixtures/diffs/diff1/1/AAA/ZAW/D/e/f/b_file.txt",0666));
49 : 2 : ASSERT(SUCCESS == change_mode("tests/fixtures/diffs/diff1/2/AAA/BBB/CZC",0777));
50 : 2 : ASSERT(SUCCESS == restore_mutable_fixture("tests/fixtures/diffs/diff1"));
51 : :
52 : 2 : RETURN_STATUS;
53 : : }
54 : :
55 : : /**
56 : : * @brief Verify removal of inaccessible records with --db-drop-inaccessible
57 : : *
58 : : * Makes one file and one directory inaccessible, enables
59 : : * `--db-drop-inaccessible`, and verifies that their database records are
60 : : * removed during the update. CLI and configuration runs use the same saved
61 : : * database and access restrictions, then check the same full output
62 : : */
63 : 2 : static Return test0029_2(void)
64 : : {
65 : 2 : INITTEST;
66 : :
67 : : // Create memory for the result
68 : 2 : m_create(char,result,MEMORY_STRING);
69 : 2 : const char *db_backup_filename = "0029_002.db";
70 : :
71 : : // Preparation for tests
72 : 2 : ASSERT(SUCCESS == prepare_mutable_fixture("tests/fixtures/diffs/diff1"));
73 : :
74 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTING","false"));
75 : :
76 : 2 : const char *arguments = "--silent --database=database2.db tests/fixtures/diffs/diff1";
77 : :
78 : 2 : ASSERT(SUCCESS == runit(arguments,result,NULL,COMPLETED,ALLOW_BOTH));
79 : :
80 : 2 : ASSERT(result->length == 0);
81 : :
82 : 2 : ASSERT(SUCCESS == change_mode("tests/fixtures/diffs/diff1/1/AAA/ZAW/D/e/f/b_file.txt",0000));
83 : 2 : ASSERT(SUCCESS == change_mode("tests/fixtures/diffs/diff1/2/AAA/BBB/CZC",0000));
84 : :
85 : : /* Preserve the prepared database before either update removes inaccessible records */
86 : 2 : ASSERT(SUCCESS == copy_path("database2.db",db_backup_filename));
87 : :
88 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTING","true"));
89 : :
90 : 2 : arguments = "--update --check-level=QUICK --db-drop-inaccessible --database=database2.db "
91 : : "tests/fixtures/diffs/diff1";
92 : :
93 : 2 : const char *filename = "templates/0029_002.txt";
94 : 2 : const struct argument_test_case cases[] = {
95 : : {arguments,COMPLETED,filename,STDERR_MUST_BE_EMPTY},
96 : : {0}
97 : : };
98 : 2 : ASSERT(SUCCESS == run_and_match_templates(cases,NULL,NULL));
99 : :
100 : : /* Restore only the database; access restrictions remain for the configuration run */
101 : 2 : ASSERT(SUCCESS == copy_path(db_backup_filename,"database2.db"));
102 : 2 : ASSERT(SUCCESS == copy_path("tests/templates/0029_002.conf","0029_002.conf"));
103 : 2 : const struct argument_test_case file_cases[] = {
104 : : {"--config=0029_002.conf",COMPLETED,filename,STDERR_MUST_BE_EMPTY},
105 : : {0}
106 : : };
107 : 2 : ASSERT(SUCCESS == run_and_match_templates(file_cases,NULL,NULL));
108 : 2 : call(delete_path_if_present("0029_002.conf"));
109 : 2 : call(delete_path_if_present(db_backup_filename));
110 : :
111 : 2 : m_del(result);
112 : :
113 : : // Clean up test results
114 : 2 : ASSERT(SUCCESS == delete_path("database2.db"));
115 : 2 : ASSERT(SUCCESS == change_mode("tests/fixtures/diffs/diff1/1/AAA/ZAW/D/e/f/b_file.txt",0666));
116 : 2 : ASSERT(SUCCESS == change_mode("tests/fixtures/diffs/diff1/2/AAA/BBB/CZC",0777));
117 : 2 : ASSERT(SUCCESS == restore_mutable_fixture("tests/fixtures/diffs/diff1"));
118 : :
119 : 2 : RETURN_STATUS;
120 : : }
121 : :
122 : : /**
123 : : * @brief Verify that an access-check failure for one regular file does not stop traversal
124 : : *
125 : : * Forces one early file to report FILE_ACCESS_ERROR during an update run, then
126 : : * changes a later file. The update for the later file proves that traversal
127 : : * continued after the access-check failure
128 : : */
129 : 2 : static Return test0029_3(void)
130 : : {
131 : 2 : INITTEST;
132 : :
133 : 2 : m_create(char,result,MEMORY_STRING);
134 : 2 : m_create(char,pattern,MEMORY_STRING);
135 : :
136 : 2 : const char *db_filename = "database3.db";
137 : 2 : const char *access_error_root_path = "tests/fixtures/diffs/diff1";
138 : 2 : const char *access_error_relative_path = "1/AAA/ZAW/D/e/f/b_file.txt";
139 : 2 : const char *changed_later_file_path = "tests/fixtures/diffs/diff1/4/AAA/BBB/CCC/a.txt";
140 : :
141 : 2 : ASSERT(SUCCESS == prepare_mutable_fixture("tests/fixtures/diffs/diff1"));
142 : :
143 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTING","false"));
144 : :
145 : 2 : const char *arguments = "--silent --database=database3.db tests/fixtures/diffs/diff1";
146 : :
147 : 2 : ASSERT(SUCCESS == runit(arguments,result,NULL,COMPLETED,ALLOW_BOTH));
148 : :
149 : 2 : ASSERT(result->length == 0);
150 : :
151 : 2 : ASSERT(SUCCESS == replase_to_string("access check failure must not stop traversal",changed_later_file_path));
152 : :
153 : 2 : ASSERT(SUCCESS == expect_file_access_from_root(
154 : : access_error_root_path,
155 : : access_error_relative_path,
156 : : R_OK,
157 : : FILE_ACCESS_ALLOWED));
158 : :
159 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTITALL_TEST_ENV_FILE_ACCESS_SUFFIX",access_error_relative_path));
160 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTITALL_TEST_ENV_FILE_ACCESS_STATUS","FILE_ACCESS_ERROR"));
161 : 2 : ASSERT(SUCCESS == expect_file_access_from_root(
162 : : access_error_root_path,
163 : : access_error_relative_path,
164 : : R_OK,
165 : : FILE_ACCESS_ERROR));
166 : :
167 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTING","true"));
168 : :
169 : 2 : arguments = "--update --check-level=QUICK --database=database3.db tests/fixtures/diffs/diff1";
170 : :
171 : 2 : ASSERT(SUCCESS == runit(arguments,result,NULL,COMPLETED,ALLOW_BOTH));
172 : :
173 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTITALL_TEST_ENV_FILE_ACCESS_SUFFIX",""));
174 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTITALL_TEST_ENV_FILE_ACCESS_STATUS",""));
175 : :
176 : 2 : const char *filename = "templates/0029_003.txt";
177 : :
178 : 2 : ASSERT(SUCCESS == get_file_content(filename,pattern));
179 : 2 : ASSERT(SUCCESS == match_pattern(result,pattern,filename));
180 : :
181 : 2 : m_del(pattern);
182 : 2 : m_del(result);
183 : :
184 : 2 : ASSERT(SUCCESS == delete_path(db_filename));
185 : 2 : ASSERT(SUCCESS == restore_mutable_fixture("tests/fixtures/diffs/diff1"));
186 : :
187 : 2 : RETURN_STATUS;
188 : : }
189 : :
190 : : /**
191 : : * @brief Verify that every root opening failure safely skips metadata cleanup
192 : : *
193 : : * Creates a baseline database, skips file traversal, and forces root opening
194 : : * to report access denied, not found, and an unexpected access error. Every
195 : : * update uses `--db-drop-inaccessible` and must still finish successfully
196 : : * without deleting file records. The complete output from every update is
197 : : * matched against the same PCRE2 template
198 : : */
199 : 2 : static Return test0029_4(void)
200 : : {
201 : 2 : INITTEST;
202 : :
203 : 2 : m_create(char,result,MEMORY_STRING);
204 : 2 : m_create(char,pattern,MEMORY_STRING);
205 : :
206 : 2 : const char *db_filename = "database4.db";
207 : 2 : const char *filename = "templates/0029_004.txt";
208 : 2 : const char *root_access_statuses[] = {
209 : : "FILE_ACCESS_DENIED",
210 : : "FILE_NOT_FOUND",
211 : : "FILE_ACCESS_ERROR"
212 : : };
213 : 2 : const size_t root_access_status_count =
214 : : sizeof(root_access_statuses) / sizeof(root_access_statuses[0]);
215 : 2 : int files_count_before = 0;
216 : :
217 : 2 : ASSERT(SUCCESS == prepare_mutable_fixture("tests/fixtures/diffs/diff1"));
218 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTING","false"));
219 : :
220 : 2 : const char *arguments = "--silent --database=database4.db tests/fixtures/diffs/diff1";
221 : :
222 : 2 : ASSERT(SUCCESS == runit(arguments,result,NULL,COMPLETED,ALLOW_BOTH));
223 : 2 : ASSERT(result->length == 0);
224 : 2 : ASSERT(SUCCESS == db_read_files_count(db_filename,&files_count_before));
225 : 2 : ASSERT(files_count_before > 0);
226 : :
227 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTING","true"));
228 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTITALL_TEST_ENV_SKIP_FILE_LIST","1"));
229 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTITALL_TEST_ENV_FILE_ACCESS_SUFFIX","diff1"));
230 : 2 : ASSERT(SUCCESS == get_file_content(filename,pattern));
231 : :
232 : 2 : arguments = "--update --check-level=QUICK --db-drop-inaccessible --database=database4.db "
233 : : "tests/fixtures/diffs/diff1";
234 : :
235 [ + + ]: 8 : for(size_t index = 0; index < root_access_status_count; index++)
236 : : {
237 : 6 : int files_count_after = 0;
238 : :
239 : 6 : ASSERT(SUCCESS == set_environment_variable(
240 : : "TESTITALL_TEST_ENV_FILE_ACCESS_STATUS",
241 : : root_access_statuses[index]));
242 : :
243 : 6 : ASSERT(SUCCESS == runit(arguments,result,NULL,COMPLETED,ALLOW_BOTH));
244 : 6 : ASSERT(SUCCESS == match_pattern(result,pattern,filename));
245 : :
246 : 6 : ASSERT(SUCCESS == db_read_files_count(db_filename,&files_count_after));
247 : 6 : ASSERT(files_count_after == files_count_before);
248 : : }
249 : :
250 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTITALL_TEST_ENV_SKIP_FILE_LIST",""));
251 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTITALL_TEST_ENV_FILE_ACCESS_SUFFIX",""));
252 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTITALL_TEST_ENV_FILE_ACCESS_STATUS",""));
253 : :
254 : 2 : m_del(pattern);
255 : 2 : m_del(result);
256 : :
257 : 2 : ASSERT(SUCCESS == delete_path(db_filename));
258 : 2 : ASSERT(SUCCESS == restore_mutable_fixture("tests/fixtures/diffs/diff1"));
259 : :
260 : 2 : RETURN_STATUS;
261 : : }
262 : :
263 : : /**
264 : : * @brief Verify that an unavailable PATH root does not stop later roots
265 : : *
266 : : * Forces the first of two traversal roots to fail during root opening. The
267 : : * unavailable root must be reported immediately and shown again in the final
268 : : * warning summary, while a file from the second root must still be written to
269 : : * the database. A configuration-file run repeats both checks with the same
270 : : * access failure after removing the database created by the CLI run
271 : : */
272 : 2 : static Return test0029_5(void)
273 : : {
274 : 2 : INITTEST;
275 : :
276 : 2 : const char *db_filename = "database5.db";
277 : 2 : const char *filename = "templates/0029_005.txt";
278 : 2 : const char *available_relative_path = "AAA/BBB/CCC/a.txt";
279 : 2 : bool available_path_exists = false;
280 : :
281 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTING","false"));
282 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTITALL_TEST_ENV_FILE_ACCESS_SUFFIX","diff1/1"));
283 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTITALL_TEST_ENV_FILE_ACCESS_STATUS","FILE_ACCESS_DENIED"));
284 : :
285 : 2 : const char *arguments = "--database=database5.db "
286 : : "tests/fixtures/diffs/diff1/1 tests/fixtures/diffs/diff1/4";
287 : 2 : const struct argument_test_case cases[] = {
288 : : {arguments,COMPLETED,filename,STDERR_MUST_BE_EMPTY},
289 : : {0}
290 : : };
291 : :
292 : 2 : ASSERT(SUCCESS == run_and_match_templates(cases,NULL,NULL));
293 : 2 : ASSERT(SUCCESS == db_relative_path_exists(db_filename,available_relative_path,&available_path_exists));
294 : 2 : ASSERT(available_path_exists == true);
295 : :
296 : : /* Preserve the unavailable-root condition for the configuration-file repeat */
297 : 2 : ASSERT(SUCCESS == delete_path(db_filename));
298 : 2 : ASSERT(SUCCESS == copy_from_origin("tests/templates/0029_005.conf",
299 : : "0029_005.conf",REQUIRE_SOURCE_EXISTS));
300 : 2 : const struct argument_test_case file_cases[] = {
301 : : {"--config=0029_005.conf",COMPLETED,filename,STDERR_MUST_BE_EMPTY},
302 : : {0}
303 : : };
304 : 2 : ASSERT(SUCCESS == run_and_match_templates(file_cases,NULL,NULL));
305 : 2 : available_path_exists = false;
306 : 2 : ASSERT(SUCCESS == db_relative_path_exists(db_filename,available_relative_path,&available_path_exists));
307 : 2 : ASSERT(available_path_exists == true);
308 : 2 : call(delete_path_if_present("0029_005.conf"));
309 : :
310 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTITALL_TEST_ENV_FILE_ACCESS_SUFFIX",""));
311 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTITALL_TEST_ENV_FILE_ACCESS_STATUS",""));
312 : :
313 : 2 : ASSERT(SUCCESS == delete_path(db_filename));
314 : :
315 : 2 : RETURN_STATUS;
316 : : }
317 : :
318 : : /**
319 : : * @brief Verify --db-drop-inaccessible does not override ignore scope
320 : : *
321 : : * Makes one file inaccessible and ignores the same relative path during update.
322 : : * Even with --db-drop-inaccessible, the ignored non-locked row must stay in the
323 : : * DB and must not be reported through inaccessible cleanup. CLI and configuration
324 : : * runs check the same full output and preserve the same database record
325 : : */
326 : 2 : static Return test0029_6(void)
327 : : {
328 : 2 : INITTEST;
329 : :
330 : 2 : m_create(char,result,MEMORY_STRING);
331 : :
332 : 2 : const char *db_filename = "database6.db";
333 : 2 : const char *ignored_relative_path = "1/AAA/ZAW/D/e/f/b_file.txt";
334 : 2 : bool ignored_path_exists = false;
335 : :
336 : 2 : ASSERT(SUCCESS == prepare_mutable_fixture("tests/fixtures/diffs/diff1"));
337 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTING","false"));
338 : :
339 : 2 : const char *arguments = "--silent --database=database6.db tests/fixtures/diffs/diff1";
340 : :
341 : 2 : ASSERT(SUCCESS == runit(arguments,result,NULL,COMPLETED,ALLOW_BOTH));
342 : 2 : ASSERT(result->length == 0);
343 : :
344 : 2 : ASSERT(SUCCESS == change_mode("tests/fixtures/diffs/diff1/1/AAA/ZAW/D/e/f/b_file.txt",0000));
345 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTING","true"));
346 : :
347 : 2 : arguments = "--update --check-level=QUICK --db-drop-inaccessible "
348 : : "--ignore=\"^1/AAA/ZAW/D/e/f/b_file\\.txt$\" "
349 : : "--database=database6.db tests/fixtures/diffs/diff1";
350 : :
351 : 2 : const char *filename = "templates/0029_006.txt";
352 : 2 : const struct argument_test_case cases[] = {
353 : : {arguments,COMPLETED,filename,STDERR_MUST_BE_EMPTY},
354 : : {0}
355 : : };
356 : 2 : ASSERT(SUCCESS == run_and_match_templates(cases,NULL,NULL));
357 : :
358 : 2 : ASSERT(SUCCESS == db_relative_path_exists(db_filename,ignored_relative_path,&ignored_path_exists));
359 : 2 : ASSERT(ignored_path_exists == true);
360 : :
361 : : /* The CLI update leaves the database unchanged, so reuse it with the same permissions */
362 : 2 : ASSERT(SUCCESS == copy_path("tests/templates/0029_006.conf","0029_006.conf"));
363 : 2 : const struct argument_test_case file_cases[] = {
364 : : {"--config=0029_006.conf",COMPLETED,filename,STDERR_MUST_BE_EMPTY},
365 : : {0}
366 : : };
367 : 2 : ASSERT(SUCCESS == run_and_match_templates(file_cases,NULL,NULL));
368 : 2 : ASSERT(SUCCESS == db_relative_path_exists(db_filename,ignored_relative_path,&ignored_path_exists));
369 : 2 : ASSERT(ignored_path_exists == true);
370 : 2 : call(delete_path_if_present("0029_006.conf"));
371 : :
372 : 2 : m_del(result);
373 : :
374 : 2 : ASSERT(SUCCESS == change_mode("tests/fixtures/diffs/diff1/1/AAA/ZAW/D/e/f/b_file.txt",0666));
375 : 2 : ASSERT(SUCCESS == delete_path(db_filename));
376 : 2 : ASSERT(SUCCESS == restore_mutable_fixture("tests/fixtures/diffs/diff1"));
377 : :
378 : 2 : RETURN_STATUS;
379 : : }
380 : :
381 : : /**
382 : : * @brief Run inaccessible-path behavior tests
383 : : *
384 : : * Covers preservation, explicit removal, unexpected file access-check failure,
385 : : * safe cleanup skipping, and continued traversal after a PATH root cannot be
386 : : * opened
387 : : */
388 : 2 : Return test0029(void)
389 : : {
390 : 2 : INITTEST;
391 : :
392 : 2 : TEST(test0029_1,"Inaccessible paths are reported and kept by default");
393 : 2 : TEST(test0029_2,"--db-drop-inaccessible drops inaccessible DB records");
394 : 2 : TEST(test0029_3,"Access-check failure for a regular file does not stop traversal");
395 : 2 : TEST(test0029_4,"Root opening failures skip metadata cleanup without deleting records");
396 : 2 : TEST(test0029_5,"Unavailable PATH root is remembered while later roots continue");
397 : 2 : TEST(test0029_6,"--db-drop-inaccessible does not override ignore scope");
398 : :
399 : 2 : RETURN_STATUS;
400 : : }
|