1#include <IO/WriteBufferAIO.h>
2#include <Core/Defines.h>
3
4#include <filesystem>
5#include <iostream>
6#include <fstream>
7#include <streambuf>
8#include <cstdlib>
9#include <functional>
10
11namespace
12{
13
14namespace fs = std::filesystem;
15
16void run();
17[[noreturn]] void die(const std::string & msg);
18void runTest(unsigned int num, const std::function<bool()> & func);
19std::string createTmpFile();
20std::string generateString(size_t n);
21
22bool test1();
23bool test2();
24bool test3();
25bool test4();
26bool test5();
27bool test6();
28bool test7();
29bool test8();
30bool test9();
31bool test10();
32
33void run()
34{
35 const std::vector<std::function<bool()>> tests =
36 {
37 test1,
38 test2,
39 test3,
40 test4,
41 test5,
42 test6,
43 test7,
44 test8,
45 test9,
46 test10
47 };
48
49 unsigned int num = 0;
50 for (const auto & test : tests)
51 {
52 ++num;
53 runTest(num, test);
54 }
55}
56
57void die(const std::string & msg)
58{
59 std::cout << msg;
60 ::exit(EXIT_FAILURE);
61}
62
63void runTest(unsigned int num, const std::function<bool()> & func)
64{
65 bool ok;
66
67 try
68 {
69 ok = func();
70 }
71 catch (const DB::Exception & ex)
72 {
73 ok = false;
74 std::cout << "Caught exception " << ex.displayText() << "\n";
75 }
76 catch (const std::exception & ex)
77 {
78 ok = false;
79 std::cout << "Caught exception " << ex.what() << "\n";
80 }
81
82 if (ok)
83 std::cout << "Test " << num << " passed\n";
84 else
85 std::cout << "Test " << num << " failed\n";
86}
87
88std::string createTmpFile()
89{
90 char pattern[] = "/tmp/fileXXXXXX";
91 char * dir = ::mkdtemp(pattern);
92 if (dir == nullptr)
93 die("Could not create directory");
94
95 return std::string(dir) + "/foo";
96}
97
98std::string generateString(size_t n)
99{
100 static const std::string symbols = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
101
102 std::string buf;
103 buf.reserve(n);
104
105 for (size_t i = 0; i < n; ++i)
106 buf += symbols[i % symbols.length()];
107
108 return buf;
109}
110
111bool test1()
112{
113 std::string filename = createTmpFile();
114
115 size_t n = 10 * DEFAULT_AIO_FILE_BLOCK_SIZE;
116
117 std::string buf = generateString(n);
118
119 {
120 DB::WriteBufferAIO out(filename, 3 * DEFAULT_AIO_FILE_BLOCK_SIZE);
121
122 if (out.getFileName() != filename)
123 return false;
124 if (out.getFD() == -1)
125 return false;
126
127 out.write(buf.data(), buf.length());
128 }
129
130 std::ifstream in(filename.c_str());
131 if (!in.is_open())
132 die("Could not open file");
133
134 std::string received{ std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>() };
135
136 in.close();
137 fs::remove_all(fs::path(filename).parent_path().string());
138
139 return (received == buf);
140}
141
142bool test2()
143{
144 std::string filename = createTmpFile();
145
146 size_t n = 10 * DEFAULT_AIO_FILE_BLOCK_SIZE;
147
148 std::string buf = generateString(n);
149
150 {
151 DB::WriteBufferAIO out(filename, 3 * DEFAULT_AIO_FILE_BLOCK_SIZE);
152
153 if (out.getFileName() != filename)
154 return false;
155 if (out.getFD() == -1)
156 return false;
157
158 out.write(buf.data(), buf.length() / 2);
159 out.seek(DEFAULT_AIO_FILE_BLOCK_SIZE, SEEK_CUR);
160 out.write(&buf[buf.length() / 2], buf.length() / 2);
161 }
162
163 std::ifstream in(filename.c_str());
164 if (!in.is_open())
165 die("Could not open file");
166
167 std::string received{ std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>() };
168
169 in.close();
170 fs::remove_all(fs::path(filename).parent_path().string());
171
172 if (received.substr(0, buf.length() / 2) != buf.substr(0, buf.length() / 2))
173 return false;
174 if (received.substr(buf.length() / 2, DEFAULT_AIO_FILE_BLOCK_SIZE) != std::string(DEFAULT_AIO_FILE_BLOCK_SIZE, '\0'))
175 return false;
176 if (received.substr(buf.length() / 2 + DEFAULT_AIO_FILE_BLOCK_SIZE) != buf.substr(buf.length() / 2))
177 return false;
178
179 return true;
180}
181
182bool test3()
183{
184 std::string filename = createTmpFile();
185
186 size_t n = 10 * DEFAULT_AIO_FILE_BLOCK_SIZE;
187
188 std::string buf = generateString(n);
189
190 {
191 DB::WriteBufferAIO out(filename, 3 * DEFAULT_AIO_FILE_BLOCK_SIZE);
192
193 if (out.getFileName() != filename)
194 return false;
195 if (out.getFD() == -1)
196 return false;
197
198 out.write(buf.data(), buf.length());
199
200 off_t pos1 = out.getPositionInFile();
201
202 out.truncate(buf.length() / 2);
203
204 off_t pos2 = out.getPositionInFile();
205
206 if (pos1 != pos2)
207 return false;
208 }
209
210 std::ifstream in(filename.c_str());
211 if (!in.is_open())
212 die("Could not open file");
213
214 std::string received{ std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>() };
215
216 in.close();
217 fs::remove_all(fs::path(filename).parent_path().string());
218
219 return (received == buf.substr(0, buf.length() / 2));
220}
221
222bool test4()
223{
224 std::string filename = createTmpFile();
225
226 size_t n = 10 * DEFAULT_AIO_FILE_BLOCK_SIZE;
227
228 std::string buf = generateString(n);
229
230 {
231 DB::WriteBufferAIO out(filename, 3 * DEFAULT_AIO_FILE_BLOCK_SIZE);
232
233 if (out.getFileName() != filename)
234 return false;
235 if (out.getFD() == -1)
236 return false;
237
238 out.write(buf.data(), buf.length());
239
240 off_t pos1 = out.getPositionInFile();
241
242 out.truncate(3 * buf.length() / 2);
243
244 off_t pos2 = out.getPositionInFile();
245
246 if (pos1 != pos2)
247 return false;
248 }
249
250 std::ifstream in(filename.c_str());
251 if (!in.is_open())
252 die("Could not open file");
253
254 std::string received{ std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>() };
255
256 in.close();
257 fs::remove_all(fs::path(filename).parent_path().string());
258
259 if (received.substr(0, buf.length()) != buf)
260 return false;
261
262 if (received.substr(buf.length()) != std::string(buf.length() / 2, '\0'))
263 return false;
264
265 return true;
266}
267
268bool test5()
269{
270 std::string filename = createTmpFile();
271
272 size_t n = 10 * DEFAULT_AIO_FILE_BLOCK_SIZE;
273
274 std::string buf = generateString(n);
275
276 {
277 DB::WriteBufferAIO out(filename, 3 * DEFAULT_AIO_FILE_BLOCK_SIZE);
278
279 if (out.getFileName() != filename)
280 return false;
281 if (out.getFD() == -1)
282 return false;
283
284 out.seek(1, SEEK_SET);
285 out.write(buf.data(), buf.length());
286 }
287
288 std::ifstream in(filename.c_str());
289 if (!in.is_open())
290 die("Could not open file");
291
292 std::string received{ std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>() };
293
294 in.close();
295 fs::remove_all(fs::path(filename).parent_path().string());
296
297 return received.substr(1) == buf;
298}
299
300bool test6()
301{
302 std::string filename = createTmpFile();
303
304 size_t n = 10 * DEFAULT_AIO_FILE_BLOCK_SIZE;
305
306 std::string buf = generateString(n);
307
308 std::string buf2 = "1111111111";
309
310 {
311 DB::WriteBufferAIO out(filename, 3 * DEFAULT_AIO_FILE_BLOCK_SIZE);
312
313 if (out.getFileName() != filename)
314 return false;
315 if (out.getFD() == -1)
316 return false;
317
318 out.seek(3, SEEK_SET);
319 out.write(buf.data(), buf.length());
320 out.seek(-2 * DEFAULT_AIO_FILE_BLOCK_SIZE, SEEK_CUR);
321 out.write(buf2.data(), buf2.length());
322 }
323
324 std::ifstream in(filename.c_str());
325 if (!in.is_open())
326 die("Could not open file");
327
328 std::string received{ std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>() };
329
330 in.close();
331 fs::remove_all(fs::path(filename).parent_path().string());
332
333 if (received.substr(3, 8 * DEFAULT_AIO_FILE_BLOCK_SIZE) != buf.substr(0, 8 * DEFAULT_AIO_FILE_BLOCK_SIZE))
334 return false;
335
336 if (received.substr(3 + 8 * DEFAULT_AIO_FILE_BLOCK_SIZE, 10) != buf2)
337 return false;
338
339 if (received.substr(13 + 8 * DEFAULT_AIO_FILE_BLOCK_SIZE) != buf.substr(10 + 8 * DEFAULT_AIO_FILE_BLOCK_SIZE))
340 return false;
341
342 return true;
343}
344
345bool test7()
346{
347 std::string filename = createTmpFile();
348
349 std::string buf2 = "11111111112222222222";
350
351 {
352 DB::WriteBufferAIO out(filename, DEFAULT_AIO_FILE_BLOCK_SIZE);
353
354 if (out.getFileName() != filename)
355 return false;
356 if (out.getFD() == -1)
357 return false;
358
359 out.seek(DEFAULT_AIO_FILE_BLOCK_SIZE - (buf2.length() / 2), SEEK_SET);
360 out.write(buf2.data(), buf2.length());
361 }
362
363 std::ifstream in(filename.c_str());
364 if (!in.is_open())
365 die("Could not open file");
366
367 std::string received{ std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>() };
368
369 if (received.length() != 4106)
370 return false;
371 if (received.substr(0, 4086) != std::string(4086, '\0'))
372 return false;
373 if (received.substr(4086, 20) != buf2)
374 return false;
375
376 in.close();
377 fs::remove_all(fs::path(filename).parent_path().string());
378
379 return true;
380}
381
382bool test8()
383{
384 std::string filename = createTmpFile();
385
386 std::string buf2 = "11111111112222222222";
387
388 {
389 DB::WriteBufferAIO out(filename, 2 * DEFAULT_AIO_FILE_BLOCK_SIZE);
390
391 if (out.getFileName() != filename)
392 return false;
393 if (out.getFD() == -1)
394 return false;
395
396 out.seek(2 * DEFAULT_AIO_FILE_BLOCK_SIZE - (buf2.length() / 2), SEEK_SET);
397 out.write(buf2.data(), buf2.length());
398 }
399
400 std::ifstream in(filename.c_str());
401 if (!in.is_open())
402 die("Could not open file");
403
404 std::string received{ std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>() };
405
406 if (received.length() != 8202)
407 return false;
408 if (received.substr(0, 8182) != std::string(8182, '\0'))
409 return false;
410 if (received.substr(8182, 20) != buf2)
411 return false;
412
413 in.close();
414 fs::remove_all(fs::path(filename).parent_path().string());
415
416 return true;
417}
418
419bool test9()
420{
421 std::string filename = createTmpFile();
422
423 size_t n = 3 * DEFAULT_AIO_FILE_BLOCK_SIZE;
424
425 std::string buf = generateString(n);
426
427 std::string buf2(DEFAULT_AIO_FILE_BLOCK_SIZE + 10, '1');
428
429 {
430 DB::WriteBufferAIO out(filename, 2 * DEFAULT_AIO_FILE_BLOCK_SIZE);
431
432 if (out.getFileName() != filename)
433 return false;
434 if (out.getFD() == -1)
435 return false;
436
437 out.seek(3, SEEK_SET);
438 out.write(buf.data(), buf.length());
439 out.seek(-DEFAULT_AIO_FILE_BLOCK_SIZE, SEEK_CUR);
440 out.write(buf2.data(), buf2.length());
441 }
442
443 std::ifstream in(filename.c_str());
444 if (!in.is_open())
445 die("Could not open file");
446
447 std::string received{ std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>() };
448
449 in.close();
450 fs::remove_all(fs::path(filename).parent_path().string());
451
452 if (received.substr(3, 2 * DEFAULT_AIO_FILE_BLOCK_SIZE) != buf.substr(0, 2 * DEFAULT_AIO_FILE_BLOCK_SIZE))
453 return false;
454
455 if (received.substr(3 + 2 * DEFAULT_AIO_FILE_BLOCK_SIZE, DEFAULT_AIO_FILE_BLOCK_SIZE + 10) != buf2)
456 return false;
457
458 return true;
459}
460
461bool test10()
462{
463 std::string filename = createTmpFile();
464
465 size_t n = 10 * DEFAULT_AIO_FILE_BLOCK_SIZE + 3;
466
467 std::string buf = generateString(n);
468
469 {
470 DB::WriteBufferAIO out(filename, 3 * DEFAULT_AIO_FILE_BLOCK_SIZE);
471
472 if (out.getFileName() != filename)
473 return false;
474 if (out.getFD() == -1)
475 return false;
476
477 out.write(buf.data(), buf.length());
478 }
479
480 std::ifstream in(filename.c_str());
481 if (!in.is_open())
482 die("Could not open file");
483
484 std::string received{ std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>() };
485
486 in.close();
487 fs::remove_all(fs::path(filename).parent_path().string());
488
489 return (received == buf);
490}
491
492}
493
494int main()
495{
496 run();
497 return 0;
498}
499