Mercurial > hg > orthanc
comparison OrthancServer/UnitTestsSources/MemoryCacheTests.cpp @ 4044:d25f4c0fa160 framework
splitting code into OrthancFramework and OrthancServer
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 10 Jun 2020 20:30:34 +0200 |
parents | UnitTestsSources/MemoryCacheTests.cpp@0540b54324f1 |
children | 05b8fd21089c |
comparison
equal
deleted
inserted
replaced
4043:6c6239aec462 | 4044:d25f4c0fa160 |
---|---|
1 /** | |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium | |
6 * | |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU General Public License as | |
9 * published by the Free Software Foundation, either version 3 of the | |
10 * License, or (at your option) any later version. | |
11 * | |
12 * In addition, as a special exception, the copyright holders of this | |
13 * program give permission to link the code of its release with the | |
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it | |
15 * that use the same license as the "OpenSSL" library), and distribute | |
16 * the linked executables. You must obey the GNU General Public License | |
17 * in all respects for all of the code used other than "OpenSSL". If you | |
18 * modify file(s) with this exception, you may extend this exception to | |
19 * your version of the file(s), but you are not obligated to do so. If | |
20 * you do not wish to do so, delete this exception statement from your | |
21 * version. If you delete this exception statement from all source files | |
22 * in the program, then also delete it here. | |
23 * | |
24 * This program is distributed in the hope that it will be useful, but | |
25 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
27 * General Public License for more details. | |
28 * | |
29 * You should have received a copy of the GNU General Public License | |
30 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
31 **/ | |
32 | |
33 | |
34 #include "PrecompiledHeadersUnitTests.h" | |
35 #include "gtest/gtest.h" | |
36 | |
37 #include <memory> | |
38 #include <algorithm> | |
39 #include <boost/thread.hpp> | |
40 #include <boost/lexical_cast.hpp> | |
41 | |
42 #include "../Core/Cache/MemoryCache.h" | |
43 #include "../Core/Cache/MemoryStringCache.h" | |
44 #include "../Core/Cache/SharedArchive.h" | |
45 #include "../Core/IDynamicObject.h" | |
46 #include "../Core/Logging.h" | |
47 #include "../OrthancServer/StorageCommitmentReports.h" | |
48 | |
49 | |
50 TEST(LRU, Basic) | |
51 { | |
52 Orthanc::LeastRecentlyUsedIndex<std::string> r; | |
53 | |
54 r.Add("d"); | |
55 r.Add("a"); | |
56 r.Add("c"); | |
57 r.Add("b"); | |
58 | |
59 r.MakeMostRecent("a"); | |
60 r.MakeMostRecent("d"); | |
61 r.MakeMostRecent("b"); | |
62 r.MakeMostRecent("c"); | |
63 r.MakeMostRecent("d"); | |
64 r.MakeMostRecent("c"); | |
65 | |
66 ASSERT_EQ("a", r.GetOldest()); | |
67 ASSERT_EQ("a", r.RemoveOldest()); | |
68 ASSERT_EQ("b", r.GetOldest()); | |
69 ASSERT_EQ("b", r.RemoveOldest()); | |
70 ASSERT_EQ("d", r.GetOldest()); | |
71 ASSERT_EQ("d", r.RemoveOldest()); | |
72 ASSERT_EQ("c", r.GetOldest()); | |
73 ASSERT_EQ("c", r.RemoveOldest()); | |
74 | |
75 ASSERT_TRUE(r.IsEmpty()); | |
76 | |
77 ASSERT_THROW(r.GetOldest(), Orthanc::OrthancException); | |
78 ASSERT_THROW(r.RemoveOldest(), Orthanc::OrthancException); | |
79 } | |
80 | |
81 | |
82 TEST(LRU, Payload) | |
83 { | |
84 Orthanc::LeastRecentlyUsedIndex<std::string, int> r; | |
85 | |
86 r.Add("a", 420); | |
87 r.Add("b", 421); | |
88 r.Add("c", 422); | |
89 r.Add("d", 423); | |
90 | |
91 r.MakeMostRecent("a"); | |
92 r.MakeMostRecent("d"); | |
93 r.MakeMostRecent("b"); | |
94 r.MakeMostRecent("c"); | |
95 r.MakeMostRecent("d"); | |
96 r.MakeMostRecent("c"); | |
97 | |
98 ASSERT_TRUE(r.Contains("b")); | |
99 ASSERT_EQ(421, r.Invalidate("b")); | |
100 ASSERT_FALSE(r.Contains("b")); | |
101 | |
102 int p; | |
103 ASSERT_TRUE(r.Contains("a", p)); ASSERT_EQ(420, p); | |
104 ASSERT_TRUE(r.Contains("c", p)); ASSERT_EQ(422, p); | |
105 ASSERT_TRUE(r.Contains("d", p)); ASSERT_EQ(423, p); | |
106 | |
107 ASSERT_EQ("a", r.GetOldest()); | |
108 ASSERT_EQ(420, r.GetOldestPayload()); | |
109 ASSERT_EQ("a", r.RemoveOldest(p)); ASSERT_EQ(420, p); | |
110 | |
111 ASSERT_EQ("d", r.GetOldest()); | |
112 ASSERT_EQ(423, r.GetOldestPayload()); | |
113 ASSERT_EQ("d", r.RemoveOldest(p)); ASSERT_EQ(423, p); | |
114 | |
115 ASSERT_EQ("c", r.GetOldest()); | |
116 ASSERT_EQ(422, r.GetOldestPayload()); | |
117 ASSERT_EQ("c", r.RemoveOldest(p)); ASSERT_EQ(422, p); | |
118 | |
119 ASSERT_TRUE(r.IsEmpty()); | |
120 } | |
121 | |
122 | |
123 TEST(LRU, PayloadUpdate) | |
124 { | |
125 Orthanc::LeastRecentlyUsedIndex<std::string, int> r; | |
126 | |
127 r.Add("a", 420); | |
128 r.Add("b", 421); | |
129 r.Add("d", 423); | |
130 | |
131 r.MakeMostRecent("a", 424); | |
132 r.MakeMostRecent("d", 421); | |
133 | |
134 ASSERT_EQ("b", r.GetOldest()); | |
135 ASSERT_EQ(421, r.GetOldestPayload()); | |
136 r.RemoveOldest(); | |
137 | |
138 ASSERT_EQ("a", r.GetOldest()); | |
139 ASSERT_EQ(424, r.GetOldestPayload()); | |
140 r.RemoveOldest(); | |
141 | |
142 ASSERT_EQ("d", r.GetOldest()); | |
143 ASSERT_EQ(421, r.GetOldestPayload()); | |
144 r.RemoveOldest(); | |
145 | |
146 ASSERT_TRUE(r.IsEmpty()); | |
147 } | |
148 | |
149 | |
150 | |
151 TEST(LRU, PayloadUpdateBis) | |
152 { | |
153 Orthanc::LeastRecentlyUsedIndex<std::string, int> r; | |
154 | |
155 r.AddOrMakeMostRecent("a", 420); | |
156 r.AddOrMakeMostRecent("b", 421); | |
157 r.AddOrMakeMostRecent("d", 423); | |
158 r.AddOrMakeMostRecent("a", 424); | |
159 r.AddOrMakeMostRecent("d", 421); | |
160 | |
161 ASSERT_EQ("b", r.GetOldest()); | |
162 ASSERT_EQ(421, r.GetOldestPayload()); | |
163 r.RemoveOldest(); | |
164 | |
165 ASSERT_EQ("a", r.GetOldest()); | |
166 ASSERT_EQ(424, r.GetOldestPayload()); | |
167 r.RemoveOldest(); | |
168 | |
169 ASSERT_EQ("d", r.GetOldest()); | |
170 ASSERT_EQ(421, r.GetOldestPayload()); | |
171 r.RemoveOldest(); | |
172 | |
173 ASSERT_TRUE(r.IsEmpty()); | |
174 } | |
175 | |
176 TEST(LRU, GetAllKeys) | |
177 { | |
178 Orthanc::LeastRecentlyUsedIndex<std::string, int> r; | |
179 std::vector<std::string> keys; | |
180 | |
181 r.AddOrMakeMostRecent("a", 420); | |
182 r.GetAllKeys(keys); | |
183 | |
184 ASSERT_EQ(1u, keys.size()); | |
185 ASSERT_EQ("a", keys[0]); | |
186 | |
187 r.AddOrMakeMostRecent("b", 421); | |
188 r.GetAllKeys(keys); | |
189 | |
190 ASSERT_EQ(2u, keys.size()); | |
191 ASSERT_TRUE(std::find(keys.begin(), keys.end(),"a") != keys.end()); | |
192 ASSERT_TRUE(std::find(keys.begin(), keys.end(),"b") != keys.end()); | |
193 } | |
194 | |
195 | |
196 | |
197 namespace | |
198 { | |
199 class Integer : public Orthanc::IDynamicObject | |
200 { | |
201 private: | |
202 std::string& log_; | |
203 int value_; | |
204 | |
205 public: | |
206 Integer(std::string& log, int v) : log_(log), value_(v) | |
207 { | |
208 } | |
209 | |
210 virtual ~Integer() ORTHANC_OVERRIDE | |
211 { | |
212 LOG(INFO) << "Removing cache entry for " << value_; | |
213 log_ += boost::lexical_cast<std::string>(value_) + " "; | |
214 } | |
215 }; | |
216 | |
217 class IntegerProvider : public Orthanc::Deprecated::ICachePageProvider | |
218 { | |
219 public: | |
220 std::string log_; | |
221 | |
222 virtual Orthanc::IDynamicObject* Provide(const std::string& s) ORTHANC_OVERRIDE | |
223 { | |
224 LOG(INFO) << "Providing " << s; | |
225 return new Integer(log_, boost::lexical_cast<int>(s)); | |
226 } | |
227 }; | |
228 } | |
229 | |
230 | |
231 TEST(MemoryCache, Basic) | |
232 { | |
233 IntegerProvider provider; | |
234 | |
235 { | |
236 Orthanc::Deprecated::MemoryCache cache(provider, 3); | |
237 cache.Access("42"); // 42 -> exit | |
238 cache.Access("43"); // 43, 42 -> exit | |
239 cache.Access("45"); // 45, 43, 42 -> exit | |
240 cache.Access("42"); // 42, 45, 43 -> exit | |
241 cache.Access("43"); // 43, 42, 45 -> exit | |
242 cache.Access("47"); // 45 is removed; 47, 43, 42 -> exit | |
243 cache.Access("44"); // 42 is removed; 44, 47, 43 -> exit | |
244 cache.Access("42"); // 43 is removed; 42, 44, 47 -> exit | |
245 // Closing the cache: 47, 44, 42 are successively removed | |
246 } | |
247 | |
248 ASSERT_EQ("45 42 43 47 44 42 ", provider.log_); | |
249 } | |
250 | |
251 | |
252 | |
253 | |
254 | |
255 namespace | |
256 { | |
257 class S : public Orthanc::IDynamicObject | |
258 { | |
259 private: | |
260 std::string value_; | |
261 | |
262 public: | |
263 S(const std::string& value) : value_(value) | |
264 { | |
265 } | |
266 | |
267 const std::string& GetValue() const | |
268 { | |
269 return value_; | |
270 } | |
271 }; | |
272 } | |
273 | |
274 | |
275 TEST(LRU, SharedArchive) | |
276 { | |
277 std::string first, second; | |
278 Orthanc::SharedArchive a(3); | |
279 first = a.Add(new S("First item")); | |
280 second = a.Add(new S("Second item")); | |
281 | |
282 for (int i = 1; i < 100; i++) | |
283 { | |
284 a.Add(new S("Item " + boost::lexical_cast<std::string>(i))); | |
285 | |
286 // Continuously protect the two first items | |
287 { | |
288 Orthanc::SharedArchive::Accessor accessor(a, first); | |
289 ASSERT_TRUE(accessor.IsValid()); | |
290 ASSERT_EQ("First item", dynamic_cast<S&>(accessor.GetItem()).GetValue()); | |
291 } | |
292 | |
293 { | |
294 Orthanc::SharedArchive::Accessor accessor(a, second); | |
295 ASSERT_TRUE(accessor.IsValid()); | |
296 ASSERT_EQ("Second item", dynamic_cast<S&>(accessor.GetItem()).GetValue()); | |
297 } | |
298 | |
299 { | |
300 Orthanc::SharedArchive::Accessor accessor(a, "nope"); | |
301 ASSERT_FALSE(accessor.IsValid()); | |
302 ASSERT_THROW(accessor.GetItem(), Orthanc::OrthancException); | |
303 } | |
304 } | |
305 | |
306 std::list<std::string> i; | |
307 a.List(i); | |
308 | |
309 size_t count = 0; | |
310 for (std::list<std::string>::const_iterator | |
311 it = i.begin(); it != i.end(); it++) | |
312 { | |
313 if (*it == first || | |
314 *it == second) | |
315 { | |
316 count++; | |
317 } | |
318 } | |
319 | |
320 ASSERT_EQ(2u, count); | |
321 } | |
322 | |
323 | |
324 TEST(MemoryStringCache, Basic) | |
325 { | |
326 Orthanc::MemoryStringCache c; | |
327 ASSERT_THROW(c.SetMaximumSize(0), Orthanc::OrthancException); | |
328 | |
329 c.SetMaximumSize(2); | |
330 | |
331 std::string v; | |
332 ASSERT_FALSE(c.Fetch(v, "hello")); | |
333 | |
334 c.Add("hello", "a"); | |
335 ASSERT_TRUE(c.Fetch(v, "hello")); ASSERT_EQ("a", v); | |
336 ASSERT_FALSE(c.Fetch(v, "hello2")); | |
337 ASSERT_FALSE(c.Fetch(v, "hello3")); | |
338 | |
339 c.Add("hello2", "b"); | |
340 ASSERT_TRUE(c.Fetch(v, "hello")); ASSERT_EQ("a", v); | |
341 ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); | |
342 ASSERT_FALSE(c.Fetch(v, "hello3")); | |
343 | |
344 c.Add("hello3", "too large value"); | |
345 ASSERT_TRUE(c.Fetch(v, "hello")); ASSERT_EQ("a", v); | |
346 ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); | |
347 ASSERT_FALSE(c.Fetch(v, "hello3")); | |
348 | |
349 c.Add("hello3", "c"); | |
350 ASSERT_FALSE(c.Fetch(v, "hello")); // Recycled | |
351 ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); | |
352 ASSERT_TRUE(c.Fetch(v, "hello3")); ASSERT_EQ("c", v); | |
353 } | |
354 | |
355 | |
356 TEST(MemoryStringCache, Invalidate) | |
357 { | |
358 Orthanc::MemoryStringCache c; | |
359 c.Add("hello", "a"); | |
360 c.Add("hello2", "b"); | |
361 | |
362 std::string v; | |
363 ASSERT_TRUE(c.Fetch(v, "hello")); ASSERT_EQ("a", v); | |
364 ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); | |
365 | |
366 c.Invalidate("hello"); | |
367 ASSERT_FALSE(c.Fetch(v, "hello")); | |
368 ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); | |
369 } | |
370 | |
371 | |
372 TEST(StorageCommitmentReports, Basic) | |
373 { | |
374 Orthanc::StorageCommitmentReports reports(2); | |
375 ASSERT_EQ(2u, reports.GetMaxSize()); | |
376 | |
377 { | |
378 Orthanc::StorageCommitmentReports::Accessor accessor(reports, "nope"); | |
379 ASSERT_EQ("nope", accessor.GetTransactionUid()); | |
380 ASSERT_FALSE(accessor.IsValid()); | |
381 ASSERT_THROW(accessor.GetReport(), Orthanc::OrthancException); | |
382 } | |
383 | |
384 reports.Store("a", new Orthanc::StorageCommitmentReports::Report("aet_a")); | |
385 reports.Store("b", new Orthanc::StorageCommitmentReports::Report("aet_b")); | |
386 reports.Store("c", new Orthanc::StorageCommitmentReports::Report("aet_c")); | |
387 | |
388 { | |
389 Orthanc::StorageCommitmentReports::Accessor accessor(reports, "a"); | |
390 ASSERT_FALSE(accessor.IsValid()); | |
391 } | |
392 | |
393 { | |
394 Orthanc::StorageCommitmentReports::Accessor accessor(reports, "b"); | |
395 ASSERT_TRUE(accessor.IsValid()); | |
396 ASSERT_EQ("aet_b", accessor.GetReport().GetRemoteAet()); | |
397 ASSERT_EQ(Orthanc::StorageCommitmentReports::Report::Status_Pending, | |
398 accessor.GetReport().GetStatus()); | |
399 } | |
400 | |
401 { | |
402 Orthanc::StorageCommitmentReports::Accessor accessor(reports, "c"); | |
403 ASSERT_EQ("aet_c", accessor.GetReport().GetRemoteAet()); | |
404 ASSERT_TRUE(accessor.IsValid()); | |
405 } | |
406 | |
407 { | |
408 std::unique_ptr<Orthanc::StorageCommitmentReports::Report> report | |
409 (new Orthanc::StorageCommitmentReports::Report("aet")); | |
410 report->AddSuccess("class1", "instance1"); | |
411 report->AddFailure("class2", "instance2", | |
412 Orthanc::StorageCommitmentFailureReason_ReferencedSOPClassNotSupported); | |
413 report->MarkAsComplete(); | |
414 reports.Store("a", report.release()); | |
415 } | |
416 | |
417 { | |
418 Orthanc::StorageCommitmentReports::Accessor accessor(reports, "a"); | |
419 ASSERT_TRUE(accessor.IsValid()); | |
420 ASSERT_EQ("aet", accessor.GetReport().GetRemoteAet()); | |
421 ASSERT_EQ(Orthanc::StorageCommitmentReports::Report::Status_Failure, | |
422 accessor.GetReport().GetStatus()); | |
423 } | |
424 | |
425 { | |
426 Orthanc::StorageCommitmentReports::Accessor accessor(reports, "b"); | |
427 ASSERT_FALSE(accessor.IsValid()); | |
428 } | |
429 | |
430 { | |
431 Orthanc::StorageCommitmentReports::Accessor accessor(reports, "c"); | |
432 ASSERT_TRUE(accessor.IsValid()); | |
433 } | |
434 | |
435 { | |
436 std::unique_ptr<Orthanc::StorageCommitmentReports::Report> report | |
437 (new Orthanc::StorageCommitmentReports::Report("aet")); | |
438 report->AddSuccess("class1", "instance1"); | |
439 report->MarkAsComplete(); | |
440 reports.Store("a", report.release()); | |
441 } | |
442 | |
443 { | |
444 Orthanc::StorageCommitmentReports::Accessor accessor(reports, "a"); | |
445 ASSERT_TRUE(accessor.IsValid()); | |
446 ASSERT_EQ("aet", accessor.GetReport().GetRemoteAet()); | |
447 ASSERT_EQ(Orthanc::StorageCommitmentReports::Report::Status_Success, | |
448 accessor.GetReport().GetStatus()); | |
449 } | |
450 | |
451 { | |
452 Orthanc::StorageCommitmentReports::Accessor accessor(reports, "b"); | |
453 ASSERT_FALSE(accessor.IsValid()); | |
454 } | |
455 | |
456 { | |
457 Orthanc::StorageCommitmentReports::Accessor accessor(reports, "c"); | |
458 ASSERT_TRUE(accessor.IsValid()); | |
459 } | |
460 } |