comparison UnitTests/UnitTestsMain.cpp @ 0:95226b754d9e

initial release
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 17 Sep 2018 11:34:55 +0200
parents
children 7e207ade2f1a
comparison
equal deleted inserted replaced
-1:000000000000 0:95226b754d9e
1 /**
2 * Transfers accelerator plugin for Orthanc
3 * Copyright (C) 2018 Osimis, Belgium
4 *
5 * This program is free software: you can redistribute it and/or
6 * modify it under the terms of the GNU Affero General Public License
7 * as published by the Free Software Foundation, either version 3 of
8 * the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 **/
18
19
20 #include "../Framework/DownloadArea.h"
21
22 #include <Core/Compression/GzipCompressor.h>
23 #include <Core/Logging.h>
24 #include <Core/OrthancException.h>
25 #include <gtest/gtest.h>
26
27
28 TEST(Toolbox, Enumerations)
29 {
30 using namespace OrthancPlugins;
31 ASSERT_EQ(BucketCompression_None, StringToBucketCompression(EnumerationToString(BucketCompression_None)));
32 ASSERT_EQ(BucketCompression_Gzip, StringToBucketCompression(EnumerationToString(BucketCompression_Gzip)));
33 ASSERT_THROW(StringToBucketCompression("None"), Orthanc::OrthancException);
34 }
35
36
37 TEST(Toolbox, Conversions)
38 {
39 ASSERT_EQ(2u, OrthancPlugins::ConvertToKilobytes(2048));
40 ASSERT_EQ(1u, OrthancPlugins::ConvertToKilobytes(1000));
41 ASSERT_EQ(0u, OrthancPlugins::ConvertToKilobytes(500));
42
43 ASSERT_EQ(2u, OrthancPlugins::ConvertToMegabytes(2048 * 1024));
44 ASSERT_EQ(1u, OrthancPlugins::ConvertToMegabytes(1000 * 1024));
45 ASSERT_EQ(0u, OrthancPlugins::ConvertToMegabytes(500 * 1024));
46 }
47
48
49 TEST(TransferBucket, Basic)
50 {
51 using namespace OrthancPlugins;
52
53 DicomInstanceInfo d1("d1", 10, "");
54 DicomInstanceInfo d2("d2", 20, "");
55 DicomInstanceInfo d3("d3", 30, "");
56 DicomInstanceInfo d4("d4", 40, "");
57
58 {
59 TransferBucket b;
60 ASSERT_EQ(0u, b.GetTotalSize());
61 ASSERT_EQ(0u, b.GetChunksCount());
62
63 b.AddChunk(d1, 0, 10);
64 b.AddChunk(d2, 0, 20);
65 ASSERT_THROW(b.AddChunk(d3, 0, 31), Orthanc::OrthancException);
66 ASSERT_THROW(b.AddChunk(d3, 1, 30), Orthanc::OrthancException);
67 b.AddChunk(d3, 0, 30);
68
69 ASSERT_EQ(60u, b.GetTotalSize());
70 ASSERT_EQ(3u, b.GetChunksCount());
71
72 ASSERT_EQ("d1", b.GetChunkInstanceId(0));
73 ASSERT_EQ(0u, b.GetChunkOffset(0));
74 ASSERT_EQ(10u, b.GetChunkSize(0));
75 ASSERT_EQ("d2", b.GetChunkInstanceId(1));
76 ASSERT_EQ(0u, b.GetChunkOffset(1));
77 ASSERT_EQ(20u, b.GetChunkSize(1));
78 ASSERT_EQ("d3", b.GetChunkInstanceId(2));
79 ASSERT_EQ(0u, b.GetChunkOffset(2));
80 ASSERT_EQ(30u, b.GetChunkSize(2));
81
82 std::string uri;
83 b.ComputePullUri(uri, BucketCompression_None);
84 ASSERT_EQ("/transfers/chunks/d1.d2.d3?offset=0&size=60&compression=none", uri);
85 b.ComputePullUri(uri, BucketCompression_Gzip);
86 ASSERT_EQ("/transfers/chunks/d1.d2.d3?offset=0&size=60&compression=gzip", uri);
87
88 b.Clear();
89 ASSERT_EQ(0u, b.GetTotalSize());
90 ASSERT_EQ(0u, b.GetChunksCount());
91
92 ASSERT_THROW(b.ComputePullUri(uri, BucketCompression_None), Orthanc::OrthancException); // Empty
93 }
94
95 {
96 TransferBucket b;
97 b.AddChunk(d1, 5, 5);
98 ASSERT_THROW(b.AddChunk(d2, 1, 7), Orthanc::OrthancException); // Can only skip bytes in 1st chunk
99 b.AddChunk(d2, 0, 20);
100 b.AddChunk(d3, 0, 7);
101 ASSERT_THROW(b.AddChunk(d4, 0, 10), Orthanc::OrthancException); // d2 was not complete
102
103 ASSERT_EQ(32u, b.GetTotalSize());
104 ASSERT_EQ(3u, b.GetChunksCount());
105
106 ASSERT_EQ("d1", b.GetChunkInstanceId(0));
107 ASSERT_EQ(5u, b.GetChunkOffset(0));
108 ASSERT_EQ(5u, b.GetChunkSize(0));
109 ASSERT_EQ("d2", b.GetChunkInstanceId(1));
110 ASSERT_EQ(0u, b.GetChunkOffset(1));
111 ASSERT_EQ(20u, b.GetChunkSize(1));
112 ASSERT_EQ("d3", b.GetChunkInstanceId(2));
113 ASSERT_EQ(0u, b.GetChunkOffset(2));
114 ASSERT_EQ(7u, b.GetChunkSize(2));
115
116 std::string uri;
117 b.ComputePullUri(uri, BucketCompression_None);
118 ASSERT_EQ("/transfers/chunks/d1.d2.d3?offset=5&size=32&compression=none", uri);
119 b.ComputePullUri(uri, BucketCompression_Gzip);
120 ASSERT_EQ("/transfers/chunks/d1.d2.d3?offset=5&size=32&compression=gzip", uri);
121
122 b.Clear();
123 ASSERT_EQ(0u, b.GetTotalSize());
124 ASSERT_EQ(0u, b.GetChunksCount());
125
126 b.AddChunk(d2, 1, 7);
127 ASSERT_EQ(7u, b.GetTotalSize());
128 ASSERT_EQ(1u, b.GetChunksCount());
129 }
130 }
131
132
133 TEST(TransferBucket, Serialization)
134 {
135 using namespace OrthancPlugins;
136
137 Json::Value s;
138
139 {
140 DicomInstanceInfo d1("d1", 10, "");
141 DicomInstanceInfo d2("d2", 20, "");
142 DicomInstanceInfo d3("d3", 30, "");
143
144 TransferBucket b;
145 b.AddChunk(d1, 5, 5);
146 b.AddChunk(d2, 0, 20);
147 b.AddChunk(d3, 0, 7);
148 b.Serialize(s);
149 }
150
151 {
152 TransferBucket b(s);
153
154 std::string uri;
155 b.ComputePullUri(uri, BucketCompression_None);
156 ASSERT_EQ("/transfers/chunks/d1.d2.d3?offset=5&size=32&compression=none", uri);
157 }
158 }
159
160
161 TEST(TransferScheduler, Empty)
162 {
163 using namespace OrthancPlugins;
164
165 TransferScheduler s;
166 ASSERT_EQ(0u, s.GetInstancesCount());
167 ASSERT_EQ(0u, s.GetTotalSize());
168
169 std::vector<DicomInstanceInfo> i;
170 s.ListInstances(i);
171 ASSERT_TRUE(i.empty());
172
173 std::vector<TransferBucket> b;
174 s.ComputePullBuckets(b, 10, 1000, "http://localhost/", BucketCompression_None);
175 ASSERT_TRUE(b.empty());
176
177 Json::Value v;
178 s.FormatPushTransaction(v, b, 10, 1000, BucketCompression_None);
179 ASSERT_TRUE(b.empty());
180 ASSERT_EQ(Json::objectValue, v.type());
181 ASSERT_TRUE(v.isMember("Buckets"));
182 ASSERT_TRUE(v.isMember("Compression"));
183 ASSERT_TRUE(v.isMember("Instances"));
184 ASSERT_EQ(Json::arrayValue, v["Buckets"].type());
185 ASSERT_EQ(Json::stringValue, v["Compression"].type());
186 ASSERT_EQ(Json::arrayValue, v["Instances"].type());
187 ASSERT_EQ(0u, v["Buckets"].size());
188 ASSERT_EQ("none", v["Compression"].asString());
189 ASSERT_EQ(0u, v["Instances"].size());
190 }
191
192
193 TEST(TransferScheduler, Basic)
194 {
195 using namespace OrthancPlugins;
196
197 DicomInstanceInfo d1("d1", 10, "md1");
198 DicomInstanceInfo d2("d2", 10, "md2");
199 DicomInstanceInfo d3("d3", 10, "md3");
200
201 TransferScheduler s;
202 s.AddInstance(d1);
203 s.AddInstance(d2);
204 s.AddInstance(d3);
205
206 std::vector<DicomInstanceInfo> i;
207 s.ListInstances(i);
208 ASSERT_EQ(3u, i.size());
209
210 std::vector<TransferBucket> b;
211 s.ComputePullBuckets(b, 10, 1000, "http://localhost/", BucketCompression_None);
212 ASSERT_EQ(3u, b.size());
213 ASSERT_EQ(1u, b[0].GetChunksCount());
214 ASSERT_EQ("d1", b[0].GetChunkInstanceId(0));
215 ASSERT_EQ(0u, b[0].GetChunkOffset(0));
216 ASSERT_EQ(10u, b[0].GetChunkSize(0));
217 ASSERT_EQ(1u, b[1].GetChunksCount());
218 ASSERT_EQ("d2", b[1].GetChunkInstanceId(0));
219 ASSERT_EQ(0u, b[1].GetChunkOffset(0));
220 ASSERT_EQ(10u, b[1].GetChunkSize(0));
221 ASSERT_EQ(1u, b[2].GetChunksCount());
222 ASSERT_EQ("d3", b[2].GetChunkInstanceId(0));
223 ASSERT_EQ(0u, b[2].GetChunkOffset(0));
224 ASSERT_EQ(10u, b[2].GetChunkSize(0));
225
226 Json::Value v;
227 s.FormatPushTransaction(v, b, 10, 1000, BucketCompression_Gzip);
228 ASSERT_EQ(3u, b.size());
229 ASSERT_EQ(3u, v["Buckets"].size());
230 ASSERT_EQ("gzip", v["Compression"].asString());
231 ASSERT_EQ(3u, v["Instances"].size());
232
233 for (Json::Value::ArrayIndex i = 0; i < 3; i++)
234 {
235 TransferBucket b(v["Buckets"][i]);
236 ASSERT_EQ(1u, b.GetChunksCount());
237 if (i == 0)
238 ASSERT_EQ("d1", b.GetChunkInstanceId(0));
239 else if (i == 1)
240 ASSERT_EQ("d2", b.GetChunkInstanceId(0));
241 else
242 ASSERT_EQ("d3", b.GetChunkInstanceId(0));
243
244 ASSERT_EQ(0u, b.GetChunkOffset(0));
245 ASSERT_EQ(10u, b.GetChunkSize(0));
246 }
247
248 for (Json::Value::ArrayIndex i = 0; i < 3; i++)
249 {
250 DicomInstanceInfo d(v["Instances"][i]);
251 if (i == 0)
252 {
253 ASSERT_EQ("d1", d.GetId());
254 ASSERT_EQ("md1", d.GetMD5());
255 }
256 else if (i == 1)
257 {
258 ASSERT_EQ("d2", d.GetId());
259 ASSERT_EQ("md2", d.GetMD5());
260 }
261 else
262 {
263 ASSERT_EQ("d3", d.GetId());
264 ASSERT_EQ("md3", d.GetMD5());
265 }
266
267 ASSERT_EQ(10u, d.GetSize());
268 }
269 }
270
271
272
273 TEST(TransferScheduler, Grouping)
274 {
275 using namespace OrthancPlugins;
276
277 DicomInstanceInfo d1("d1", 10, "md1");
278 DicomInstanceInfo d2("d2", 10, "md2");
279 DicomInstanceInfo d3("d3", 10, "md3");
280
281 TransferScheduler s;
282 s.AddInstance(d1);
283 s.AddInstance(d2);
284 s.AddInstance(d3);
285
286 {
287 std::vector<TransferBucket> b;
288 s.ComputePullBuckets(b, 20, 1000, "http://localhost/", BucketCompression_None);
289 ASSERT_EQ(2u, b.size());
290 ASSERT_EQ(2u, b[0].GetChunksCount());
291 ASSERT_EQ("d1", b[0].GetChunkInstanceId(0));
292 ASSERT_EQ("d2", b[0].GetChunkInstanceId(1));
293 ASSERT_EQ(1u, b[1].GetChunksCount());
294 ASSERT_EQ("d3", b[1].GetChunkInstanceId(0));
295 }
296
297 {
298 std::vector<TransferBucket> b;
299 s.ComputePullBuckets(b, 21, 1000, "http://localhost/", BucketCompression_None);
300 ASSERT_EQ(1u, b.size());
301 ASSERT_EQ(3u, b[0].GetChunksCount());
302 ASSERT_EQ("d1", b[0].GetChunkInstanceId(0));
303 ASSERT_EQ("d2", b[0].GetChunkInstanceId(1));
304 ASSERT_EQ("d3", b[0].GetChunkInstanceId(2));
305 }
306
307 {
308 std::string longBase(2048, '_');
309 std::vector<TransferBucket> b;
310 s.ComputePullBuckets(b, 21, 1000, longBase, BucketCompression_None);
311 ASSERT_EQ(3u, b.size());
312 ASSERT_EQ(1u, b[0].GetChunksCount());
313 ASSERT_EQ("d1", b[0].GetChunkInstanceId(0));
314 ASSERT_EQ(1u, b[1].GetChunksCount());
315 ASSERT_EQ("d2", b[1].GetChunkInstanceId(0));
316 ASSERT_EQ(1u, b[2].GetChunksCount());
317 ASSERT_EQ("d3", b[2].GetChunkInstanceId(0));
318 }
319 }
320
321
322 TEST(TransferScheduler, Splitting)
323 {
324 using namespace OrthancPlugins;
325
326 for (size_t i = 1; i < 20; i++)
327 {
328 DicomInstanceInfo dicom("dicom", i, "");
329
330 TransferScheduler s;
331 s.AddInstance(dicom);
332
333 {
334 std::vector<TransferBucket> b;
335 s.ComputePullBuckets(b, 1, 1000, "http://localhost/", BucketCompression_None);
336 ASSERT_EQ(1u, b.size());
337 ASSERT_EQ(1u, b[0].GetChunksCount());
338 ASSERT_EQ("dicom", b[0].GetChunkInstanceId(0));
339 ASSERT_EQ(0u, b[0].GetChunkOffset(0));
340 ASSERT_EQ(i, b[0].GetChunkSize(0));
341 }
342
343 for (size_t split = 1; split < 20; split++)
344 {
345 size_t count;
346 if (dicom.GetSize() % split != 0)
347 count = dicom.GetSize() / split + 1;
348 else
349 count = dicom.GetSize() / split;
350
351 std::vector<TransferBucket> b;
352 s.ComputePullBuckets(b, 1, split, "http://localhost/", BucketCompression_None);
353 ASSERT_EQ(count, b.size());
354
355 size_t size = dicom.GetSize() / count;
356 size_t offset = 0;
357 for (size_t j = 0; j < count; j++)
358 {
359 ASSERT_EQ(1u, b[j].GetChunksCount());
360 ASSERT_EQ("dicom", b[j].GetChunkInstanceId(0));
361 ASSERT_EQ(offset, b[j].GetChunkOffset(0));
362 if (j + 1 != count)
363 ASSERT_EQ(size, b[j].GetChunkSize(0));
364 else
365 ASSERT_EQ(dicom.GetSize() - (count - 1) * size, b[j].GetChunkSize(0));
366 offset += b[j].GetChunkSize(0);
367 }
368 }
369 }
370 }
371
372
373 TEST(DownloadArea, Basic)
374 {
375 using namespace OrthancPlugins;
376
377 std::string s1 = "Hello";
378 std::string s2 = "Hello, World!";
379
380 std::string md1, md2;
381 Orthanc::Toolbox::ComputeMD5(md1, s1);
382 Orthanc::Toolbox::ComputeMD5(md2, s2);
383
384 std::vector<DicomInstanceInfo> instances;
385 instances.push_back(DicomInstanceInfo("d1", s1.size(), md1));
386 instances.push_back(DicomInstanceInfo("d2", s2.size(), md2));
387
388 {
389 DownloadArea area(instances);
390 ASSERT_EQ(s1.size() + s2.size(), area.GetTotalSize());
391 ASSERT_THROW(area.CheckMD5(), Orthanc::OrthancException);
392
393 area.WriteInstance("d1", s1.c_str(), s1.size());
394 area.WriteInstance("d2", s2.c_str(), s2.size());
395
396 area.CheckMD5();
397 }
398
399 {
400 DownloadArea area(instances);
401 ASSERT_THROW(area.CheckMD5(), Orthanc::OrthancException);
402
403 {
404 TransferBucket b;
405 b.AddChunk(instances[0] /*d1*/, 0, 2);
406 area.WriteBucket(b, s1.c_str(), 2, BucketCompression_None);
407 }
408
409 {
410 TransferBucket b;
411 b.AddChunk(instances[0] /*d1*/, 2, 3);
412 b.AddChunk(instances[1] /*d2*/, 0, 4);
413 std::string s = s1.substr(2, 3) + s2.substr(0, 4);
414 area.WriteBucket(b, s.c_str(), s.size(), BucketCompression_None);
415 }
416
417 {
418 TransferBucket b;
419 b.AddChunk(instances[1] /*d2*/, 4, 9);
420 std::string s = s2.substr(4);
421 std::string t;
422 Orthanc::GzipCompressor compressor;
423 compressor.Compress(t, s.c_str(), s.size());
424 area.WriteBucket(b, t.c_str(), t.size(), BucketCompression_Gzip);
425 }
426
427 area.CheckMD5();
428 }
429 }
430
431
432
433 int main(int argc, char **argv)
434 {
435 ::testing::InitGoogleTest(&argc, argv);
436 Orthanc::Logging::Initialize();
437 Orthanc::Logging::EnableInfoLevel(true);
438 Orthanc::Logging::EnableTraceLevel(true);
439
440 int result = RUN_ALL_TESTS();
441
442 Orthanc::Logging::Finalize();
443
444 return result;
445 }