Branch data Line data Source code
1 : : #include "sute.h"
2 : :
3 : : /**
4 : : * Run background scenario with SIGTERM and verify output template.
5 : : */
6 : 2 : static Return test0033_1(void)
7 : : {
8 : 2 : INITTEST;
9 : :
10 : 2 : const char *arguments = "--progress --database=0033_interrupt_resume.db tests/fixtures/diffs/";
11 : 2 : const char *filename = "templates/0033_001.txt";
12 : 2 : const char *cleanup_path = "0033_interrupt_resume.db";
13 : :
14 : 2 : m_create(char,stdout_result,MEMORY_STRING);
15 : 2 : m_create(char,stderr_result,MEMORY_STRING);
16 : 2 : m_create(char,stdout_pattern,MEMORY_STRING);
17 : 2 : m_create(char,stderr_pattern,MEMORY_STRING);
18 : :
19 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTING","true"));
20 : :
21 : 2 : ASSERT(SUCCESS == runit_background(
22 : : arguments,
23 : : stdout_result,
24 : : stderr_result,
25 : : SUCCESS|HALTED,
26 : : ALLOW_BOTH,
27 : : 0U,
28 : : 5000U,
29 : : SIGTERM,
30 : : 1U));
31 : :
32 : 2 : ASSERT(SUCCESS == get_file_content(filename,stdout_pattern));
33 : 2 : ASSERT(SUCCESS == match_pattern(stdout_result,stdout_pattern,filename));
34 : :
35 : 2 : ASSERT(SUCCESS == m_copy_literal(stderr_pattern,"\\A\\Z"));
36 : 2 : ASSERT(SUCCESS == match_pattern(stderr_result,stderr_pattern));
37 : :
38 : 2 : ASSERT(SUCCESS == delete_path(cleanup_path));
39 : :
40 : 2 : m_del(stderr_pattern);
41 : 2 : m_del(stdout_pattern);
42 : 2 : m_del(stderr_result);
43 : 2 : m_del(stdout_result);
44 : :
45 : 2 : RETURN_STATUS;
46 : : }
47 : :
48 : : /**
49 : : * Run background scenario with SIGINT and verify output template.
50 : : */
51 : 2 : static Return test0033_2(void)
52 : : {
53 : 2 : INITTEST;
54 : :
55 : 2 : const char *arguments = "--progress --database=0033_interrupt_resume.db tests/fixtures/diffs/";
56 : 2 : const char *filename = "templates/0033_002.txt";
57 : 2 : const char *cleanup_path = "0033_interrupt_resume.db";
58 : :
59 : 2 : m_create(char,stdout_result,MEMORY_STRING);
60 : 2 : m_create(char,stderr_result,MEMORY_STRING);
61 : 2 : m_create(char,stdout_pattern,MEMORY_STRING);
62 : 2 : m_create(char,stderr_pattern,MEMORY_STRING);
63 : :
64 : 2 : ASSERT(SUCCESS == set_environment_variable("TESTING","true"));
65 : :
66 : 2 : ASSERT(SUCCESS == runit_background(
67 : : arguments,
68 : : stdout_result,
69 : : stderr_result,
70 : : SUCCESS|HALTED,
71 : : ALLOW_BOTH,
72 : : 0U,
73 : : 5000U,
74 : : SIGINT,
75 : : 1U));
76 : :
77 : 2 : ASSERT(SUCCESS == get_file_content(filename,stdout_pattern));
78 : 2 : ASSERT(SUCCESS == match_pattern(stdout_result,stdout_pattern,filename));
79 : :
80 : 2 : ASSERT(SUCCESS == m_copy_literal(stderr_pattern,"\\A\\Z"));
81 : 2 : ASSERT(SUCCESS == match_pattern(stderr_result,stderr_pattern));
82 : :
83 : 2 : ASSERT(SUCCESS == delete_path(cleanup_path));
84 : :
85 : 2 : m_del(stderr_pattern);
86 : 2 : m_del(stdout_pattern);
87 : 2 : m_del(stderr_result);
88 : 2 : m_del(stdout_result);
89 : :
90 : 2 : RETURN_STATUS;
91 : : }
92 : :
93 : : /**
94 : : * Interrupt hashing of hugetestfile, resume with --update, and verify SHA512.
95 : : */
96 : 2 : static Return test0033_3(void)
97 : : {
98 : 2 : INITTEST;
99 : :
100 : 2 : const char *relative_path = "hugetestfile";
101 : 2 : const char *first_run_template = "templates/0033_003_1.txt";
102 : 2 : const char *second_run_template = "templates/0033_003_2.txt";
103 : :
104 : 2 : m_create(char,stdout_result,MEMORY_STRING);
105 : 2 : m_create(char,stderr_result,MEMORY_STRING);
106 : 2 : m_create(char,stdout_pattern,MEMORY_STRING);
107 : 2 : m_create(char,stderr_pattern,MEMORY_STRING);
108 : 2 : m_create(char,huge_file_path,MEMORY_STRING);
109 : :
110 : : /*
111 : : * Step 1: Prepare isolated test data in TMPDIR and start from a clean DB
112 : : */
113 : 2 : struct stat huge_file_stat = {0};
114 : 2 : ASSERT(SUCCESS == prepare_huge_fixture(huge_file_path,&huge_file_stat));
115 : :
116 : : /*
117 : : * Use the real file size from the prepared fixture as
118 : : * an upper bound for the interrupted offset assertions below
119 : : */
120 : 2 : ASSERT(huge_file_stat.st_size > 0);
121 : :
122 : 2 : const char *arguments = "--progress --database=0033_interrupt_resume.db tests/fixtures/huge";
123 : :
124 : : /*
125 : : * Step 2: Run in background, wait until hashing reaches wait-point 2,
126 : : * then deliver SIGINT. The process must exit as SUCCESS|HALTED
127 : : */
128 : 2 : ASSERT(SUCCESS == runit_background(
129 : : arguments,
130 : : stdout_result,
131 : : stderr_result,
132 : : SUCCESS|HALTED,
133 : : ALLOW_BOTH,
134 : : 0U,
135 : : 5000U,
136 : : SIGINT,
137 : : 2U));
138 : :
139 : : /*
140 : : * Step 3: Validate first-run output.
141 : : * It must contain the interruption scenario messages and no stderr output
142 : : */
143 : 2 : ASSERT(SUCCESS == get_file_content(first_run_template,stdout_pattern));
144 : 2 : ASSERT(SUCCESS == match_pattern(stdout_result,stdout_pattern,first_run_template));
145 : :
146 : 2 : ASSERT(SUCCESS == m_copy_literal(stderr_pattern,"\\A\\Z"));
147 : 2 : ASSERT(SUCCESS == match_pattern(stderr_result,stderr_pattern));
148 : :
149 : 2 : sqlite3_int64 interrupted_offset = 0;
150 : 2 : int interrupted_md_context_bytes = 0;
151 : :
152 : : /*
153 : : * Step 4: Read intermediate resume state from DB.
154 : : * The interrupted offset must be inside (0, real_file_size),
155 : : * and mdContext blob must be non-empty for resume.
156 : : */
157 : 2 : ASSERT(SUCCESS == read_resume_state_from_db("0033_interrupt_resume.db",relative_path,&interrupted_offset,&interrupted_md_context_bytes));
158 : :
159 : 2 : ASSERT(interrupted_offset > 0);
160 : 2 : ASSERT(interrupted_offset < (sqlite3_int64)huge_file_stat.st_size);
161 : :
162 : 2 : ASSERT(interrupted_md_context_bytes > 0);
163 : :
164 : : /*
165 : : * Step 5: Resume hashing with --update and verify second-run output
166 : : */
167 : 2 : arguments = "--update --progress --database=0033_interrupt_resume.db tests/fixtures/huge";
168 : 2 : ASSERT(SUCCESS == runit(arguments,stdout_result,stderr_result,COMPLETED,ALLOW_BOTH));
169 : :
170 : 2 : ASSERT(SUCCESS == get_file_content(second_run_template,stdout_pattern));
171 : 2 : ASSERT(SUCCESS == match_pattern(stdout_result,stdout_pattern,second_run_template));
172 : :
173 : 2 : ASSERT(SUCCESS == m_copy_literal(stderr_pattern,"\\A\\Z"));
174 : 2 : ASSERT(SUCCESS == match_pattern(stderr_result,stderr_pattern));
175 : :
176 : 2 : sqlite3_int64 final_offset = -1;
177 : 2 : unsigned char db_sha512[SHA512_DIGEST_LENGTH] = {0};
178 : 2 : unsigned char expected_sha512[SHA512_DIGEST_LENGTH] = {0};
179 : :
180 : : /*
181 : : * Step 6: Verify final DB state after resume.
182 : : * Offset must be reset to 0 and the stored SHA512 must match file content
183 : : */
184 : 2 : ASSERT(SUCCESS == read_final_sha512_from_db("0033_interrupt_resume.db",relative_path,&final_offset,db_sha512));
185 : :
186 : 2 : ASSERT(0 == final_offset);
187 : :
188 : 2 : ASSERT(SUCCESS == compute_file_sha512_monocypher(m_text(huge_file_path),expected_sha512));
189 : 2 : ASSERT(0 == memcmp(db_sha512,expected_sha512,(size_t)SHA512_DIGEST_LENGTH));
190 : :
191 : : /* Step 7: Cleanup temporary test artifacts */
192 : 2 : ASSERT(SUCCESS == delete_path("0033_interrupt_resume.db"));
193 : 2 : ASSERT(SUCCESS == delete_path("tests/fixtures/huge"));
194 : :
195 : 2 : m_del(huge_file_path);
196 : 2 : m_del(stderr_pattern);
197 : 2 : m_del(stdout_pattern);
198 : 2 : m_del(stderr_result);
199 : 2 : m_del(stdout_result);
200 : :
201 : 2 : RETURN_STATUS;
202 : : }
203 : :
204 : : /**
205 : : * Interrupt hashing, modify file metadata, and verify restart from beginning
206 : : */
207 : 2 : static Return test0033_4(void)
208 : : {
209 : 2 : INITTEST;
210 : :
211 : 2 : const char *db_filename = "0033_interrupt_rehash.db";
212 : 2 : const char *relative_path = "hugetestfile";
213 : 2 : const char *first_run_template = "templates/0033_004_1.txt";
214 : 2 : const char *second_run_template = "templates/0033_004_2.txt";
215 : :
216 : 2 : m_create(char,stdout_result,MEMORY_STRING);
217 : 2 : m_create(char,stderr_result,MEMORY_STRING);
218 : 2 : m_create(char,stdout_pattern,MEMORY_STRING);
219 : 2 : m_create(char,stderr_pattern,MEMORY_STRING);
220 : 2 : m_create(char,huge_file_path,MEMORY_STRING);
221 : :
222 : 2 : ASSERT(SUCCESS == prepare_huge_fixture(huge_file_path,NULL));
223 : :
224 : 2 : const char *arguments = "--progress --database=0033_interrupt_rehash.db tests/fixtures/huge";
225 : :
226 : 2 : ASSERT(SUCCESS == runit_background(
227 : : arguments,
228 : : stdout_result,
229 : : stderr_result,
230 : : SUCCESS|HALTED,
231 : : ALLOW_BOTH,
232 : : 0U,
233 : : 5000U,
234 : : SIGINT,
235 : : 2U));
236 : :
237 : 2 : ASSERT(SUCCESS == get_file_content(first_run_template,stdout_pattern));
238 : 2 : ASSERT(SUCCESS == match_pattern(stdout_result,stdout_pattern,first_run_template));
239 : 2 : ASSERT(SUCCESS == m_copy_literal(stderr_pattern,"\\A\\Z"));
240 : 2 : ASSERT(SUCCESS == match_pattern(stderr_result,stderr_pattern));
241 : :
242 : 2 : sqlite3_int64 interrupted_offset = 0;
243 : 2 : int interrupted_md_context_bytes = 0;
244 : :
245 : 2 : ASSERT(SUCCESS == read_resume_state_from_db(db_filename,relative_path,&interrupted_offset,&interrupted_md_context_bytes));
246 : 2 : ASSERT(interrupted_offset > 0);
247 : 2 : ASSERT(interrupted_md_context_bytes > 0);
248 : :
249 : 2 : ASSERT(SUCCESS == append_byte_to_file(huge_file_path,(unsigned char)'X'));
250 : :
251 : 2 : arguments = "--update --progress --database=0033_interrupt_rehash.db tests/fixtures/huge";
252 : 2 : ASSERT(SUCCESS == runit(arguments,stdout_result,stderr_result,COMPLETED,ALLOW_BOTH));
253 : :
254 : 2 : ASSERT(SUCCESS == get_file_content(second_run_template,stdout_pattern));
255 : 2 : ASSERT(SUCCESS == match_pattern(stdout_result,stdout_pattern,second_run_template));
256 : 2 : ASSERT(SUCCESS == m_copy_literal(stderr_pattern,"\\A\\Z"));
257 : 2 : ASSERT(SUCCESS == match_pattern(stderr_result,stderr_pattern));
258 : :
259 : 2 : const char *expected_paths[] =
260 : : {
261 : : "hugetestfile"
262 : : };
263 : :
264 : 2 : ASSERT(SUCCESS == db_paths_match(db_filename,expected_paths,(int)(sizeof(expected_paths) / sizeof(expected_paths[0]))));
265 : 2 : ASSERT(SUCCESS == delete_path("0033_interrupt_rehash.db"));
266 : 2 : ASSERT(SUCCESS == delete_path("tests/fixtures/huge"));
267 : :
268 : 2 : m_del(huge_file_path);
269 : 2 : m_del(stderr_pattern);
270 : 2 : m_del(stdout_pattern);
271 : 2 : m_del(stderr_result);
272 : 2 : m_del(stdout_result);
273 : :
274 : 2 : RETURN_STATUS;
275 : : }
276 : :
277 : : /**
278 : : * Background interruption tests grouped as a separate suite.
279 : : */
280 : 2 : Return test0033(void)
281 : : {
282 : 2 : INITTEST;
283 : :
284 : 2 : SLOWTEST;
285 : :
286 : 2 : TEST(test0033_1,"Background run receives SIGTERM and exits with HALTED");
287 : 2 : TEST(test0033_2,"Background run receives SIGINT and exits with HALTED");
288 : 2 : TEST(test0033_3,"Random interruption on hugetestfile with resume and SHA512 verification");
289 : 2 : TEST(test0033_4,"Interrupted hash with file change restarts rehash from the beginning");
290 : :
291 : 2 : RETURN_STATUS;
292 : : }
|