MultiDiskAdaptorTest.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. #include "MultiDiskAdaptor.h"
  2. #include <string>
  3. #include <cerrno>
  4. #include <cstring>
  5. #include <cppunit/extensions/HelperMacros.h>
  6. #include "FileEntry.h"
  7. #include "Exception.h"
  8. #include "a2io.h"
  9. #include "array_fun.h"
  10. #include "TestUtil.h"
  11. #include "DiskWriter.h"
  12. namespace aria2 {
  13. class MultiDiskAdaptorTest:public CppUnit::TestFixture {
  14. CPPUNIT_TEST_SUITE(MultiDiskAdaptorTest);
  15. CPPUNIT_TEST(testWriteData);
  16. CPPUNIT_TEST(testReadData);
  17. CPPUNIT_TEST(testCutTrailingGarbage);
  18. CPPUNIT_TEST(testSize);
  19. CPPUNIT_TEST(testUtime);
  20. CPPUNIT_TEST(testResetDiskWriterEntries);
  21. CPPUNIT_TEST_SUITE_END();
  22. private:
  23. SharedHandle<MultiDiskAdaptor> adaptor;
  24. public:
  25. void setUp() {
  26. adaptor.reset(new MultiDiskAdaptor());
  27. adaptor->setPieceLength(2);
  28. }
  29. void testWriteData();
  30. void testReadData();
  31. void testCutTrailingGarbage();
  32. void testSize();
  33. void testUtime();
  34. void testResetDiskWriterEntries();
  35. };
  36. CPPUNIT_TEST_SUITE_REGISTRATION( MultiDiskAdaptorTest );
  37. std::vector<SharedHandle<FileEntry> > createEntries() {
  38. SharedHandle<FileEntry> array[] = {
  39. SharedHandle<FileEntry>(new FileEntry(A2_TEST_OUT_DIR"/file0.txt", 0, 0)),
  40. SharedHandle<FileEntry>(new FileEntry(A2_TEST_OUT_DIR"/file1.txt", 15, 0)),
  41. SharedHandle<FileEntry>(new FileEntry(A2_TEST_OUT_DIR"/file2.txt", 7, 15)),
  42. SharedHandle<FileEntry>(new FileEntry(A2_TEST_OUT_DIR"/file3.txt", 0, 22)),
  43. SharedHandle<FileEntry>(new FileEntry(A2_TEST_OUT_DIR"/file4.txt", 2, 22)),
  44. SharedHandle<FileEntry>(new FileEntry(A2_TEST_OUT_DIR"/file5.txt", 0, 24)),
  45. SharedHandle<FileEntry>(new FileEntry(A2_TEST_OUT_DIR"/file6.txt", 3, 24)),
  46. SharedHandle<FileEntry>(new FileEntry(A2_TEST_OUT_DIR"/file7.txt", 0, 27)),
  47. SharedHandle<FileEntry>(new FileEntry(A2_TEST_OUT_DIR"/file8.txt", 2, 27)),
  48. };
  49. // 1 1 2 2 3
  50. // 0....5....0....5....0....5....0
  51. // ++--++--++--++--++--++--++--++--
  52. // | file0
  53. // *************** file1
  54. // ******* file2
  55. // | file3
  56. // ** flie4
  57. // | file5
  58. // *** file6
  59. // |file7
  60. // ** file8
  61. std::vector<SharedHandle<FileEntry> > entries(vbegin(array), vend(array));
  62. for(std::vector<SharedHandle<FileEntry> >::const_iterator i = entries.begin();
  63. i != entries.end(); ++i) {
  64. File((*i)->getPath()).remove();
  65. }
  66. return entries;
  67. }
  68. void MultiDiskAdaptorTest::testResetDiskWriterEntries()
  69. {
  70. {
  71. std::vector<SharedHandle<FileEntry> > fileEntries = createEntries();
  72. adaptor->setFileEntries(fileEntries.begin(), fileEntries.end());
  73. // In openFile(), resetDiskWriterEntries() are called.
  74. adaptor->openFile();
  75. std::vector<SharedHandle<DiskWriterEntry> > entries =
  76. adaptor->getDiskWriterEntries();
  77. CPPUNIT_ASSERT(entries[0]->getDiskWriter());
  78. CPPUNIT_ASSERT(entries[1]->getDiskWriter());
  79. CPPUNIT_ASSERT(entries[2]->getDiskWriter());
  80. CPPUNIT_ASSERT(entries[3]->getDiskWriter());
  81. CPPUNIT_ASSERT(entries[4]->getDiskWriter());
  82. CPPUNIT_ASSERT(entries[5]->getDiskWriter());
  83. adaptor->closeFile();
  84. }
  85. {
  86. std::vector<SharedHandle<FileEntry> > fileEntries = createEntries();
  87. fileEntries[0]->setRequested(false);
  88. adaptor->setFileEntries(fileEntries.begin(), fileEntries.end());
  89. // In openFile(), resetDiskWriterEntries() are called.
  90. adaptor->openFile();
  91. std::vector<SharedHandle<DiskWriterEntry> > entries =
  92. adaptor->getDiskWriterEntries();
  93. // Because entries[1] spans entries[0]
  94. CPPUNIT_ASSERT(entries[0]->getDiskWriter());
  95. CPPUNIT_ASSERT(entries[1]->getDiskWriter());
  96. CPPUNIT_ASSERT(entries[2]->getDiskWriter());
  97. CPPUNIT_ASSERT(entries[3]->getDiskWriter());
  98. CPPUNIT_ASSERT(entries[4]->getDiskWriter());
  99. CPPUNIT_ASSERT(entries[5]->getDiskWriter());
  100. adaptor->closeFile();
  101. }
  102. {
  103. std::vector<SharedHandle<FileEntry> > fileEntries = createEntries();
  104. fileEntries[0]->setRequested(false);
  105. fileEntries[1]->setRequested(false);
  106. adaptor->setFileEntries(fileEntries.begin(), fileEntries.end());
  107. // In openFile(), resetDiskWriterEntries() are called.
  108. adaptor->openFile();
  109. std::vector<SharedHandle<DiskWriterEntry> > entries =
  110. adaptor->getDiskWriterEntries();
  111. CPPUNIT_ASSERT(!entries[0]->getDiskWriter());
  112. // Because entries[2] spans entries[1]
  113. CPPUNIT_ASSERT(entries[1]->getDiskWriter());
  114. CPPUNIT_ASSERT(entries[1]->needsFileAllocation());
  115. CPPUNIT_ASSERT(entries[2]->getDiskWriter());
  116. CPPUNIT_ASSERT(entries[3]->getDiskWriter());
  117. CPPUNIT_ASSERT(entries[4]->getDiskWriter());
  118. CPPUNIT_ASSERT(entries[5]->getDiskWriter());
  119. adaptor->closeFile();
  120. }
  121. {
  122. std::vector<SharedHandle<FileEntry> > fileEntries = createEntries();
  123. fileEntries[3]->setRequested(false);
  124. adaptor->setFileEntries(fileEntries.begin(), fileEntries.end());
  125. // In openFile(), resetDiskWriterEntries() are called.
  126. adaptor->openFile();
  127. std::vector<SharedHandle<DiskWriterEntry> > entries =
  128. adaptor->getDiskWriterEntries();
  129. CPPUNIT_ASSERT(entries[0]->getDiskWriter());
  130. CPPUNIT_ASSERT(entries[1]->getDiskWriter());
  131. CPPUNIT_ASSERT(entries[2]->getDiskWriter());
  132. // Because entries[4] spans entries[3]
  133. CPPUNIT_ASSERT(entries[3]->getDiskWriter());
  134. CPPUNIT_ASSERT(entries[3]->needsFileAllocation());
  135. CPPUNIT_ASSERT(entries[4]->getDiskWriter());
  136. CPPUNIT_ASSERT(entries[5]->getDiskWriter());
  137. adaptor->closeFile();
  138. }
  139. {
  140. std::vector<SharedHandle<FileEntry> > fileEntries = createEntries();
  141. fileEntries[4]->setRequested(false);
  142. adaptor->setFileEntries(fileEntries.begin(), fileEntries.end());
  143. // In openFile(), resetDiskWriterEntries() are called.
  144. adaptor->openFile();
  145. std::vector<SharedHandle<DiskWriterEntry> > entries =
  146. adaptor->getDiskWriterEntries();
  147. CPPUNIT_ASSERT(entries[0]->getDiskWriter());
  148. CPPUNIT_ASSERT(entries[1]->getDiskWriter());
  149. CPPUNIT_ASSERT(entries[2]->getDiskWriter());
  150. CPPUNIT_ASSERT(entries[3]->getDiskWriter());
  151. // entries[3] is 0 length. No overrap with entries[4]
  152. CPPUNIT_ASSERT(!entries[4]->getDiskWriter());
  153. CPPUNIT_ASSERT(entries[5]->getDiskWriter());
  154. adaptor->closeFile();
  155. }
  156. {
  157. std::vector<SharedHandle<FileEntry> > fileEntries = createEntries();
  158. fileEntries[3]->setRequested(false);
  159. fileEntries[4]->setRequested(false);
  160. adaptor->setFileEntries(fileEntries.begin(), fileEntries.end());
  161. // In openFile(), resetDiskWriterEntries() are called.
  162. adaptor->openFile();
  163. std::vector<SharedHandle<DiskWriterEntry> > entries =
  164. adaptor->getDiskWriterEntries();
  165. CPPUNIT_ASSERT(entries[0]->getDiskWriter());
  166. CPPUNIT_ASSERT(entries[1]->getDiskWriter());
  167. CPPUNIT_ASSERT(entries[2]->getDiskWriter());
  168. CPPUNIT_ASSERT(!entries[3]->getDiskWriter());
  169. CPPUNIT_ASSERT(!entries[4]->getDiskWriter());
  170. CPPUNIT_ASSERT(entries[5]->getDiskWriter());
  171. adaptor->closeFile();
  172. }
  173. {
  174. std::vector<SharedHandle<FileEntry> > fileEntries = createEntries();
  175. for(size_t i = 5; i < 9; ++i) {
  176. fileEntries[i]->setRequested(false);
  177. }
  178. adaptor->setFileEntries(fileEntries.begin(), fileEntries.end());
  179. // In openFile(), resetDiskWriterEntries() are called.
  180. adaptor->openFile();
  181. std::vector<SharedHandle<DiskWriterEntry> > entries =
  182. adaptor->getDiskWriterEntries();
  183. CPPUNIT_ASSERT(entries[0]->getDiskWriter());
  184. CPPUNIT_ASSERT(entries[1]->getDiskWriter());
  185. CPPUNIT_ASSERT(entries[2]->getDiskWriter());
  186. CPPUNIT_ASSERT(entries[3]->getDiskWriter());
  187. CPPUNIT_ASSERT(entries[4]->getDiskWriter());
  188. CPPUNIT_ASSERT(!entries[5]->getDiskWriter());
  189. adaptor->closeFile();
  190. }
  191. {
  192. std::vector<SharedHandle<FileEntry> > fileEntries = createEntries();
  193. for(size_t i = 1; i < 9; ++i) {
  194. fileEntries[i]->setRequested(false);
  195. }
  196. adaptor->setFileEntries(fileEntries.begin(), fileEntries.end());
  197. adaptor->openFile();
  198. std::vector<SharedHandle<DiskWriterEntry> > entries =
  199. adaptor->getDiskWriterEntries();
  200. CPPUNIT_ASSERT(entries[0]->getDiskWriter());
  201. CPPUNIT_ASSERT(!entries[1]->getDiskWriter());
  202. CPPUNIT_ASSERT(!entries[2]->getDiskWriter());
  203. CPPUNIT_ASSERT(!entries[3]->getDiskWriter());
  204. CPPUNIT_ASSERT(!entries[4]->getDiskWriter());
  205. CPPUNIT_ASSERT(!entries[5]->getDiskWriter());
  206. adaptor->closeFile();
  207. }
  208. {
  209. std::vector<SharedHandle<FileEntry> > fileEntries = createEntries();
  210. for(size_t i = 2; i < 9; ++i) {
  211. fileEntries[i]->setRequested(false);
  212. }
  213. adaptor->setFileEntries(fileEntries.begin(), fileEntries.end());
  214. adaptor->openFile();
  215. std::vector<SharedHandle<DiskWriterEntry> > entries =
  216. adaptor->getDiskWriterEntries();
  217. CPPUNIT_ASSERT(entries[0]->getDiskWriter());
  218. CPPUNIT_ASSERT(entries[1]->getDiskWriter());
  219. // entries[1] spans entries[2]
  220. CPPUNIT_ASSERT(entries[2]->getDiskWriter());
  221. CPPUNIT_ASSERT(!entries[2]->needsFileAllocation());
  222. CPPUNIT_ASSERT(!entries[3]->getDiskWriter());
  223. CPPUNIT_ASSERT(!entries[4]->getDiskWriter());
  224. CPPUNIT_ASSERT(!entries[5]->getDiskWriter());
  225. adaptor->closeFile();
  226. }
  227. {
  228. std::vector<SharedHandle<FileEntry> > fileEntries = createEntries();
  229. for(size_t i = 0; i < 6; ++i) {
  230. fileEntries[i]->setRequested(false);
  231. }
  232. fileEntries[8]->setRequested(false);
  233. adaptor->setFileEntries(fileEntries.begin(), fileEntries.end());
  234. adaptor->openFile();
  235. std::vector<SharedHandle<DiskWriterEntry> > entries =
  236. adaptor->getDiskWriterEntries();
  237. CPPUNIT_ASSERT(!entries[0]->getDiskWriter());
  238. CPPUNIT_ASSERT(!entries[1]->getDiskWriter());
  239. CPPUNIT_ASSERT(!entries[2]->getDiskWriter());
  240. CPPUNIT_ASSERT(!entries[3]->getDiskWriter());
  241. CPPUNIT_ASSERT(!entries[4]->getDiskWriter());
  242. // entries[6] spans entries[5] in the current implementation.
  243. CPPUNIT_ASSERT(entries[5]->getDiskWriter());
  244. CPPUNIT_ASSERT(entries[6]->getDiskWriter());
  245. CPPUNIT_ASSERT(entries[7]->getDiskWriter());
  246. // entries[6] spans entries[8]
  247. CPPUNIT_ASSERT(entries[8]->getDiskWriter());
  248. adaptor->closeFile();
  249. }
  250. }
  251. void readFile(const std::string& filename, char* buf, int bufLength) {
  252. FILE* f = fopen(filename.c_str(), "r");
  253. if(f == NULL) {
  254. CPPUNIT_FAIL(strerror(errno));
  255. }
  256. int retval = fread(buf, bufLength, 1, f);
  257. fclose(f);
  258. if(retval != 1) {
  259. CPPUNIT_FAIL("return value is not 1");
  260. }
  261. }
  262. void MultiDiskAdaptorTest::testWriteData() {
  263. std::vector<SharedHandle<FileEntry> > fileEntries(createEntries());
  264. adaptor->setFileEntries(fileEntries.begin(), fileEntries.end());
  265. adaptor->openFile();
  266. std::string msg = "12345";
  267. adaptor->writeData((const unsigned char*)msg.c_str(), msg.size(), 0);
  268. adaptor->closeFile();
  269. CPPUNIT_ASSERT(File(A2_TEST_OUT_DIR"/file0.txt").isFile());
  270. char buf[128];
  271. readFile(A2_TEST_OUT_DIR"/file1.txt", buf, 5);
  272. buf[5] = '\0';
  273. CPPUNIT_ASSERT_EQUAL(msg, std::string(buf));
  274. adaptor->openFile();
  275. std::string msg2 = "67890ABCDEF";
  276. adaptor->writeData((const unsigned char*)msg2.c_str(), msg2.size(), 5);
  277. adaptor->closeFile();
  278. readFile(A2_TEST_OUT_DIR"/file1.txt", buf, 15);
  279. buf[15] = '\0';
  280. CPPUNIT_ASSERT_EQUAL(std::string("1234567890ABCDE"), std::string(buf));
  281. readFile(A2_TEST_OUT_DIR"/file2.txt", buf, 1);
  282. buf[1] = '\0';
  283. CPPUNIT_ASSERT_EQUAL(std::string("F"), std::string(buf));
  284. adaptor->openFile();
  285. std::string msg3 = "12345123456712";
  286. adaptor->writeData((const unsigned char*)msg3.c_str(), msg3.size(), 10);
  287. adaptor->closeFile();
  288. readFile(A2_TEST_OUT_DIR"/file1.txt", buf, 15);
  289. buf[15] = '\0';
  290. CPPUNIT_ASSERT_EQUAL(std::string("123456789012345"), std::string(buf));
  291. readFile(A2_TEST_OUT_DIR"/file2.txt", buf, 7);
  292. buf[7] = '\0';
  293. CPPUNIT_ASSERT_EQUAL(std::string("1234567"), std::string(buf));
  294. CPPUNIT_ASSERT(File(A2_TEST_OUT_DIR"/file3.txt").isFile());
  295. readFile(A2_TEST_OUT_DIR"/file4.txt", buf, 2);
  296. buf[2] = '\0';
  297. CPPUNIT_ASSERT_EQUAL(std::string("12"), std::string(buf));
  298. CPPUNIT_ASSERT(File(A2_TEST_OUT_DIR"/file5.txt").isFile());
  299. }
  300. void MultiDiskAdaptorTest::testReadData() {
  301. SharedHandle<FileEntry> entry1(new FileEntry(A2_TEST_DIR"/file1r.txt", 15, 0));
  302. SharedHandle<FileEntry> entry2(new FileEntry(A2_TEST_DIR"/file2r.txt", 7, 15));
  303. SharedHandle<FileEntry> entry3(new FileEntry(A2_TEST_DIR"/file3r.txt", 3, 22));
  304. std::vector<SharedHandle<FileEntry> > entries;
  305. entries.push_back(entry1);
  306. entries.push_back(entry2);
  307. entries.push_back(entry3);
  308. adaptor->setFileEntries(entries.begin(), entries.end());
  309. adaptor->enableReadOnly();
  310. adaptor->openFile();
  311. unsigned char buf[128];
  312. adaptor->readData(buf, 15, 0);
  313. buf[15] = '\0';
  314. CPPUNIT_ASSERT_EQUAL(std::string("1234567890ABCDE"), std::string((char*)buf));
  315. adaptor->readData(buf, 10, 6);
  316. buf[10] = '\0';
  317. CPPUNIT_ASSERT_EQUAL(std::string("7890ABCDEF"), std::string((char*)buf));
  318. adaptor->readData(buf, 4, 20);
  319. buf[4] = '\0';
  320. CPPUNIT_ASSERT_EQUAL(std::string("KLMN"), std::string((char*)buf));
  321. adaptor->readData(buf, 25, 0);
  322. buf[25] = '\0';
  323. CPPUNIT_ASSERT_EQUAL(std::string("1234567890ABCDEFGHIJKLMNO"), std::string((char*)buf));
  324. }
  325. void MultiDiskAdaptorTest::testCutTrailingGarbage()
  326. {
  327. std::string dir = A2_TEST_OUT_DIR;
  328. std::string prefix = "aria2_MultiDiskAdaptorTest_testCutTrailingGarbage_";
  329. SharedHandle<FileEntry> entries[] = {
  330. SharedHandle<FileEntry>(new FileEntry(dir+"/"+prefix+"1", 256, 0)),
  331. SharedHandle<FileEntry>(new FileEntry(dir+"/"+prefix+"2", 512, 256))
  332. };
  333. for(size_t i = 0; i < A2_ARRAY_LEN(entries); ++i) {
  334. createFile(entries[i]->getPath(), entries[i]->getLength()+100);
  335. }
  336. std::vector<SharedHandle<FileEntry> > fileEntries
  337. (vbegin(entries), vend(entries));
  338. MultiDiskAdaptor adaptor;
  339. adaptor.setFileEntries(fileEntries.begin(), fileEntries.end());
  340. adaptor.setMaxOpenFiles(1);
  341. adaptor.setPieceLength(1);
  342. adaptor.openFile();
  343. adaptor.cutTrailingGarbage();
  344. CPPUNIT_ASSERT_EQUAL((int64_t)256,
  345. File(entries[0]->getPath()).size());
  346. CPPUNIT_ASSERT_EQUAL((int64_t)512,
  347. File(entries[1]->getPath()).size());
  348. }
  349. void MultiDiskAdaptorTest::testSize()
  350. {
  351. std::string dir = A2_TEST_OUT_DIR;
  352. std::string prefix = "aria2_MultiDiskAdaptorTest_testSize_";
  353. SharedHandle<FileEntry> entries[] = {
  354. SharedHandle<FileEntry>(new FileEntry(dir+"/"+prefix+"1", 1, 0)),
  355. SharedHandle<FileEntry>(new FileEntry(dir+"/"+prefix+"2", 1, 1))
  356. };
  357. for(size_t i = 0; i < A2_ARRAY_LEN(entries); ++i) {
  358. createFile(entries[i]->getPath(), entries[i]->getLength());
  359. }
  360. std::vector<SharedHandle<FileEntry> > fileEntries
  361. (vbegin(entries), vend(entries));
  362. MultiDiskAdaptor adaptor;
  363. adaptor.setFileEntries(fileEntries.begin(), fileEntries.end());
  364. adaptor.setMaxOpenFiles(1);
  365. adaptor.setPieceLength(1);
  366. adaptor.openFile();
  367. CPPUNIT_ASSERT_EQUAL((off_t)2, adaptor.size());
  368. }
  369. void MultiDiskAdaptorTest::testUtime()
  370. {
  371. std::string storeDir = A2_TEST_OUT_DIR"/aria2_MultiDiskAdaptorTest_testUtime";
  372. SharedHandle<FileEntry> entries[] = {
  373. SharedHandle<FileEntry>(new FileEntry(storeDir+"/requested", 0, 0)),
  374. SharedHandle<FileEntry>(new FileEntry(storeDir+"/notFound", 0, 0)),
  375. SharedHandle<FileEntry>(new FileEntry(storeDir+"/notRequested", 0, 0)),
  376. SharedHandle<FileEntry>(new FileEntry(storeDir+"/anotherRequested", 0, 0)),
  377. };
  378. createFile(entries[0]->getPath(), entries[0]->getLength());
  379. File(entries[1]->getPath()).remove();
  380. createFile(entries[2]->getPath(), entries[2]->getLength());
  381. createFile(entries[3]->getPath(), entries[3]->getLength());
  382. entries[2]->setRequested(false);
  383. std::vector<SharedHandle<FileEntry> > fileEntries
  384. (vbegin(entries), vend(entries));
  385. MultiDiskAdaptor adaptor;
  386. adaptor.setFileEntries(fileEntries.begin(), fileEntries.end());
  387. time_t atime = (time_t) 100000;
  388. time_t mtime = (time_t) 200000;
  389. CPPUNIT_ASSERT_EQUAL((size_t)2, adaptor.utime(Time(atime), Time(mtime)));
  390. CPPUNIT_ASSERT_EQUAL((time_t)mtime,
  391. File(entries[0]->getPath()).getModifiedTime().getTime());
  392. CPPUNIT_ASSERT_EQUAL((time_t)mtime,
  393. File(entries[3]->getPath()).getModifiedTime().getTime());
  394. CPPUNIT_ASSERT((time_t)mtime !=
  395. File(entries[2]->getPath()).getModifiedTime().getTime());
  396. }
  397. } // namespace aria2