blob: 910704df054c2db732353c02a5f28cbedcf20747 [file] [log] [blame]
Mickey Sweatt527b0492016-03-02 11:07:48 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3* Copyright (c) 2016 Regents of the University of California.
4*
5* This file is part of the nTorrent codebase.
6*
7* nTorrent is free software: you can redistribute it and/or modify it under the
8* terms of the GNU Lesser General Public License as published by the Free Software
9* Foundation, either version 3 of the License, or (at your option) any later version.
10*
11* nTorrent is distributed in the hope that it will be useful, but WITHOUT ANY
12* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14*
15* You should have received copies of the GNU General Public License and GNU Lesser
16* General Public License along with nTorrent, e.g., in COPYING.md file. If not, see
17* <http://www.gnu.org/licenses/>.
18*
19* See AUTHORS for complete list of nTorrent authors and contributors.
20*/
21
22#include "boost-test.hpp"
23
24#include "torrent-manager.hpp"
25#include "torrent-file.hpp"
26
Mickey Sweattafda1f12016-04-04 17:15:11 -070027#include <set>
28
Mickey Sweatt527b0492016-03-02 11:07:48 -080029#include <boost/filesystem.hpp>
30
31#include <ndn-cxx/util/io.hpp>
32
33namespace ndn {
34namespace ntorrent {
35namespace tests {
36
37using std::vector;
38using ndn::Name;
39
40namespace fs = boost::filesystem;
41
42class TestTorrentManager : public TorrentManager {
43 public:
44 TestTorrentManager(const ndn::Name& torrentFileName,
45 const std::string& filePath)
46 : TorrentManager(torrentFileName, filePath)
47 {}
48
49 std::vector<TorrentFile> torrentSegments() const {
50 return m_torrentSegments;
51 }
52
53 std::vector<FileManifest> fileManifests() const {
54 return m_fileManifests;
55 }
56
57 std::vector<bool> fileState(const ndn::Name& manifestName) {
Mickey Sweattafda1f12016-04-04 17:15:11 -070058 auto fout = m_fileStates[manifestName].first;
59 if (nullptr != fout) {
60 fout->flush();
61 }
Mickey Sweatt527b0492016-03-02 11:07:48 -080062 return m_fileStates[manifestName].second;
63 }
Mickey Sweattafda1f12016-04-04 17:15:11 -070064
65 bool writeData(const Data& data) {
66 return TorrentManager::writeData(data);
67 }
Mickey Sweatt527b0492016-03-02 11:07:48 -080068};
69
70BOOST_AUTO_TEST_SUITE(TestTorrentManagerInitialize)
71
72BOOST_AUTO_TEST_CASE(CheckInitializeComplete)
73{
74 vector<FileManifest> manifests;
75 vector<TorrentFile> torrentSegments;
76 std::string filePath = "tests/testdata/";
77 // get torrent files and manifests
78 {
79 auto temp = TorrentFile::generate("tests/testdata/foo",
80 1024,
81 1024,
82 1024,
83 false);
84 torrentSegments = temp.first;
85 auto temp1 = temp.second;
86 for (const auto& ms : temp1) {
Mickey Sweattafda1f12016-04-04 17:15:11 -070087 manifests.insert(manifests.end(), ms.first.begin(), ms.first.end());
Mickey Sweatt527b0492016-03-02 11:07:48 -080088 }
89 }
90 // write the torrent segments and manifests to disk
91 std::string dirPath = ".appdata/foo/";
92 boost::filesystem::create_directories(dirPath);
93 std::string torrentPath = dirPath + "torrent_files/";
94 boost::filesystem::create_directory(torrentPath);
95 auto fileNum = 0;
96 for (const auto& t : torrentSegments) {
97 fileNum++;
98 auto filename = torrentPath + to_string(fileNum);
99 io::save(t, filename);
100 }
101 fileNum = 0;
102 auto manifestPath = dirPath + "manifests/";
103 boost::filesystem::create_directory(manifestPath);
104 for (const auto& m : manifests) {
105 fileNum++;
106 auto filename = manifestPath + to_string(fileNum);
107 io::save(m, filename);
108 }
109 // Initialize and verify
110 TestTorrentManager manager("/NTORRENT/foo/torrent-file/sha256digest=02c737fd4c6e7de4b4825b089f39700c2dfa8fd2bb2b91f09201e357c4463253",
111 filePath);
112 manager.Initialize();
113
114 // Check that the torrent segments and file manifests match (content and order)
115 BOOST_CHECK(manager.torrentSegments() == torrentSegments);
116 BOOST_CHECK(manager.fileManifests() == manifests);
117 // next check the data packet state vectors
118 for (auto m : manager.fileManifests()) {
119 auto fileState = manager.fileState(m.getFullName());
120 BOOST_CHECK(fileState.size() == m.catalog().size());
121 for (auto s : fileState) {
122 BOOST_CHECK(s);
123 }
124 }
125 fs::remove_all(dirPath);
126}
127
128BOOST_AUTO_TEST_CASE(CheckInitializeEmpty)
129{
130 TestTorrentManager manager("/NTORRENT/foo/torrent-file/sha256digest=02c737fd4c6e7de4b4825b089f39700c2dfa8fd2bb2b91f09201e357c4463253",
131 "tests/testdata/");
132 manager.Initialize();
133 BOOST_CHECK(manager.torrentSegments() == vector<TorrentFile>());
134 BOOST_CHECK(manager.fileManifests() == vector<FileManifest>());
135}
136
137BOOST_AUTO_TEST_CASE(CheckInitializeNoManifests)
138{
139 vector<TorrentFile> torrentSegments;
140 std::string filePath = "tests/testdata/";
141 // get torrent files and manifests
142 {
143 auto temp = TorrentFile::generate("tests/testdata/foo",
144 1024,
145 1024,
146 1024,
147 false);
148 torrentSegments = temp.first;
149 }
150 // write the torrent segments but no manifests to disk
151 std::string dirPath = ".appdata/foo/";
152 boost::filesystem::create_directories(dirPath);
153 std::string torrentPath = dirPath + "torrent_files/";
154 boost::filesystem::create_directory(torrentPath);
155 auto fileNum = 0;
156 for (const auto& t : torrentSegments) {
157 fileNum++;
158 auto filename = torrentPath + to_string(fileNum);
159 io::save(t, filename);
160 }
161 // Initialize and verify
162 TestTorrentManager manager("/NTORRENT/foo/torrent-file/sha256digest=02c737fd4c6e7de4b4825b089f39700c2dfa8fd2bb2b91f09201e357c4463253",
163 filePath);
164 manager.Initialize();
165
166 // Check that the torrent segments and file manifests match (content and order)
167 BOOST_CHECK(manager.torrentSegments() == torrentSegments);
168 BOOST_CHECK(manager.fileManifests() == vector<FileManifest>());
169
170 fs::remove_all(dirPath);
171}
172
173BOOST_AUTO_TEST_CASE(CheckInitializeMissingManifests)
174{
175 vector<FileManifest> manifests;
176 vector<TorrentFile> torrentSegments;
177 std::string filePath = "tests/testdata/";
178 // get torrent files and manifests
179 {
180 auto temp = TorrentFile::generate("tests/testdata/foo",
181 1024,
182 1024,
183 1024,
184 false);
185 torrentSegments = temp.first;
186 auto temp1 = temp.second;
187 temp1.pop_back(); // remove the manifests for the last file
Mickey Sweattafda1f12016-04-04 17:15:11 -0700188 for (const auto& ms : temp1) {
189 manifests.insert(manifests.end(), ms.first.begin(), ms.first.end());
Mickey Sweatt527b0492016-03-02 11:07:48 -0800190 }
191 }
192 // write the torrent segments and manifests to disk
193 std::string dirPath = ".appdata/foo/";
194 boost::filesystem::create_directories(dirPath);
195 std::string torrentPath = dirPath + "torrent_files/";
196 boost::filesystem::create_directories(torrentPath);
197 auto fileNum = 0;
198 for (const auto& t : torrentSegments) {
199 fileNum++;
200 auto filename = torrentPath + to_string(fileNum);
201 io::save(t, filename);
Mickey Sweatt527b0492016-03-02 11:07:48 -0800202 }
203 fileNum = 0;
204 auto manifestPath = dirPath + "manifests/";
205 boost::filesystem::create_directory(manifestPath);
206 for (const auto& m : manifests) {
207 fileNum++;
208 auto filename = manifestPath + to_string(fileNum);
209 io::save(m, filename);
210 }
211 // Initialize and verify
212 TestTorrentManager manager("/NTORRENT/foo/torrent-file/sha256digest=02c737fd4c6e7de4b4825b089f39700c2dfa8fd2bb2b91f09201e357c4463253",
213 filePath);
214 manager.Initialize();
215
216 // Check that the torrent segments and file manifests match (content and order)
217 BOOST_CHECK(manager.torrentSegments() == torrentSegments);
218 BOOST_CHECK(manager.fileManifests() == manifests);
219 // next check the data packet state vectors
220 for (auto m : manager.fileManifests()) {
221 auto fileState = manager.fileState(m.getFullName());
222 BOOST_CHECK(fileState.size() == m.catalog().size());
223 for (auto s : fileState) {
224 BOOST_CHECK(s);
225 }
226 }
227 fs::remove_all(dirPath);
228}
229
230BOOST_AUTO_TEST_SUITE_END()
231
Mickey Sweattafda1f12016-04-04 17:15:11 -0700232BOOST_AUTO_TEST_SUITE(CheckTorrentManagerUtilities)
233
234BOOST_AUTO_TEST_CASE(CheckWriteDataComplete)
235{
236 vector<FileManifest> manifests;
237 vector<TorrentFile> torrentSegments;
238 // for each file, the data packets
239 std::vector<vector<Data>> fileData;
240 std::string filePath = "tests/testdata/temp";
241 // get torrent files and manifests
242 {
243 auto temp = TorrentFile::generate("tests/testdata/foo",
244 1024,
245 1024,
246 1024,
247 true);
248 torrentSegments = temp.first;
249 auto temp1 = temp.second;
250 for (const auto& ms : temp1) {
251 manifests.insert(manifests.end(), ms.first.begin(), ms.first.end());
252 fileData.push_back(ms.second);
253 }
254 }
255 // write the torrent segments and manifests to disk
256 std::string dirPath = ".appdata/foo/";
257 boost::filesystem::create_directories(dirPath);
258 std::string torrentPath = dirPath + "torrent_files/";
259 boost::filesystem::create_directories(torrentPath);
260 auto fileNum = 0;
261 for (const auto& t : torrentSegments) {
262 fileNum++;
263 auto filename = torrentPath + to_string(fileNum);
264 io::save(t, filename);
265 }
266 fileNum = 0;
267 auto manifestPath = dirPath + "manifests/";
268 boost::filesystem::create_directory(manifestPath);
269 for (const auto& m : manifests) {
270 fileNum++;
271 auto filename = manifestPath + to_string(fileNum);
272 io::save(m, filename);
273 }
274 // Initialize manager
275 TestTorrentManager manager("/NTORRENT/foo/torrent-file/sha256digest=02c737fd4c6e7de4b4825b089f39700c2dfa8fd2bb2b91f09201e357c4463253",
276 filePath);
277 manager.Initialize();
278 // check that initially there is no data on disk
279 for (auto m : manager.fileManifests()) {
280 auto fileState = manager.fileState(m.getFullName());
281 BOOST_CHECK(fileState.empty());
282 }
283 // write all data to disk (for each file manifest)
284 auto manifest_it = manifests.begin();
285 for (auto& data : fileData) {
286 for (auto& d : data) {
287 BOOST_CHECK(manager.writeData(d));
288 }
289 // check that the state is updated appropriately
290 auto fileState = manager.fileState(manifest_it->getFullName());
291 for (auto s : fileState) {
292 BOOST_CHECK(s);
293 }
294 ++manifest_it;
295 }
296 // get the file names (ascending)
297 std::set<std::string> fileNames;
298 for (auto i = fs::recursive_directory_iterator(filePath + "/foo");
299 i != fs::recursive_directory_iterator();
300 ++i) {
301 fileNames.insert(i->path().string());
302 }
303 // verify file by file that the data packets are written correctly
304 auto f_it = fileData.begin();
305 for (auto f : fileNames) {
306 // read file from disk
307 std::vector<uint8_t> file_bytes;
308 fs::ifstream is(f, fs::ifstream::binary | fs::ifstream::in);
309 is >> std::noskipws;
310 std::istream_iterator<uint8_t> start(is), end;
311 file_bytes.insert(file_bytes.end(), start, end);
312 std::vector<uint8_t> data_bytes;
313 // get content from data packets
314 for (const auto& d : *f_it) {
315 auto content = d.getContent();
316 data_bytes.insert(data_bytes.end(), content.value_begin(), content.value_end());
317 }
318 BOOST_CHECK(data_bytes == file_bytes);
319 ++f_it;
320 }
321 fs::remove_all(filePath);
322 fs::remove_all(".appdata");
323}
324
325
326BOOST_AUTO_TEST_SUITE_END()
327
Mickey Sweatt527b0492016-03-02 11:07:48 -0800328} // namespace tests
329} // namespace nTorrent
330} // namespace ndn