Mercurial > hg > orthanc
comparison OrthancFramework/UnitTestsSources/MemoryCacheTests.cpp @ 4059:e241e5f3f088 framework
moved LuaTests and MemoryCacheTests from OrthancServer to OrthancFramework
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 11 Jun 2020 14:12:07 +0200 |
parents | OrthancServer/UnitTestsSources/MemoryCacheTests.cpp@05b8fd21089c |
children | 0953b3dc3261 |
comparison
equal
deleted
inserted
replaced
4058:2a8bf0991be0 | 4059:e241e5f3f088 |
---|---|
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 #if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1 | |
35 # include <OrthancFramework.h> | |
36 #endif | |
37 | |
38 #include "gtest/gtest.h" | |
39 | |
40 #include <memory> | |
41 #include <algorithm> | |
42 #include <boost/thread.hpp> | |
43 #include <boost/lexical_cast.hpp> | |
44 | |
45 #include "../Sources/Cache/MemoryCache.h" | |
46 #include "../Sources/Cache/MemoryStringCache.h" | |
47 #include "../Sources/Cache/SharedArchive.h" | |
48 #include "../Sources/IDynamicObject.h" | |
49 #include "../Sources/Logging.h" | |
50 | |
51 | |
52 TEST(LRU, Basic) | |
53 { | |
54 Orthanc::LeastRecentlyUsedIndex<std::string> r; | |
55 | |
56 r.Add("d"); | |
57 r.Add("a"); | |
58 r.Add("c"); | |
59 r.Add("b"); | |
60 | |
61 r.MakeMostRecent("a"); | |
62 r.MakeMostRecent("d"); | |
63 r.MakeMostRecent("b"); | |
64 r.MakeMostRecent("c"); | |
65 r.MakeMostRecent("d"); | |
66 r.MakeMostRecent("c"); | |
67 | |
68 ASSERT_EQ("a", r.GetOldest()); | |
69 ASSERT_EQ("a", r.RemoveOldest()); | |
70 ASSERT_EQ("b", r.GetOldest()); | |
71 ASSERT_EQ("b", r.RemoveOldest()); | |
72 ASSERT_EQ("d", r.GetOldest()); | |
73 ASSERT_EQ("d", r.RemoveOldest()); | |
74 ASSERT_EQ("c", r.GetOldest()); | |
75 ASSERT_EQ("c", r.RemoveOldest()); | |
76 | |
77 ASSERT_TRUE(r.IsEmpty()); | |
78 | |
79 ASSERT_THROW(r.GetOldest(), Orthanc::OrthancException); | |
80 ASSERT_THROW(r.RemoveOldest(), Orthanc::OrthancException); | |
81 } | |
82 | |
83 | |
84 TEST(LRU, Payload) | |
85 { | |
86 Orthanc::LeastRecentlyUsedIndex<std::string, int> r; | |
87 | |
88 r.Add("a", 420); | |
89 r.Add("b", 421); | |
90 r.Add("c", 422); | |
91 r.Add("d", 423); | |
92 | |
93 r.MakeMostRecent("a"); | |
94 r.MakeMostRecent("d"); | |
95 r.MakeMostRecent("b"); | |
96 r.MakeMostRecent("c"); | |
97 r.MakeMostRecent("d"); | |
98 r.MakeMostRecent("c"); | |
99 | |
100 ASSERT_TRUE(r.Contains("b")); | |
101 ASSERT_EQ(421, r.Invalidate("b")); | |
102 ASSERT_FALSE(r.Contains("b")); | |
103 | |
104 int p; | |
105 ASSERT_TRUE(r.Contains("a", p)); ASSERT_EQ(420, p); | |
106 ASSERT_TRUE(r.Contains("c", p)); ASSERT_EQ(422, p); | |
107 ASSERT_TRUE(r.Contains("d", p)); ASSERT_EQ(423, p); | |
108 | |
109 ASSERT_EQ("a", r.GetOldest()); | |
110 ASSERT_EQ(420, r.GetOldestPayload()); | |
111 ASSERT_EQ("a", r.RemoveOldest(p)); ASSERT_EQ(420, p); | |
112 | |
113 ASSERT_EQ("d", r.GetOldest()); | |
114 ASSERT_EQ(423, r.GetOldestPayload()); | |
115 ASSERT_EQ("d", r.RemoveOldest(p)); ASSERT_EQ(423, p); | |
116 | |
117 ASSERT_EQ("c", r.GetOldest()); | |
118 ASSERT_EQ(422, r.GetOldestPayload()); | |
119 ASSERT_EQ("c", r.RemoveOldest(p)); ASSERT_EQ(422, p); | |
120 | |
121 ASSERT_TRUE(r.IsEmpty()); | |
122 } | |
123 | |
124 | |
125 TEST(LRU, PayloadUpdate) | |
126 { | |
127 Orthanc::LeastRecentlyUsedIndex<std::string, int> r; | |
128 | |
129 r.Add("a", 420); | |
130 r.Add("b", 421); | |
131 r.Add("d", 423); | |
132 | |
133 r.MakeMostRecent("a", 424); | |
134 r.MakeMostRecent("d", 421); | |
135 | |
136 ASSERT_EQ("b", r.GetOldest()); | |
137 ASSERT_EQ(421, r.GetOldestPayload()); | |
138 r.RemoveOldest(); | |
139 | |
140 ASSERT_EQ("a", r.GetOldest()); | |
141 ASSERT_EQ(424, r.GetOldestPayload()); | |
142 r.RemoveOldest(); | |
143 | |
144 ASSERT_EQ("d", r.GetOldest()); | |
145 ASSERT_EQ(421, r.GetOldestPayload()); | |
146 r.RemoveOldest(); | |
147 | |
148 ASSERT_TRUE(r.IsEmpty()); | |
149 } | |
150 | |
151 | |
152 | |
153 TEST(LRU, PayloadUpdateBis) | |
154 { | |
155 Orthanc::LeastRecentlyUsedIndex<std::string, int> r; | |
156 | |
157 r.AddOrMakeMostRecent("a", 420); | |
158 r.AddOrMakeMostRecent("b", 421); | |
159 r.AddOrMakeMostRecent("d", 423); | |
160 r.AddOrMakeMostRecent("a", 424); | |
161 r.AddOrMakeMostRecent("d", 421); | |
162 | |
163 ASSERT_EQ("b", r.GetOldest()); | |
164 ASSERT_EQ(421, r.GetOldestPayload()); | |
165 r.RemoveOldest(); | |
166 | |
167 ASSERT_EQ("a", r.GetOldest()); | |
168 ASSERT_EQ(424, r.GetOldestPayload()); | |
169 r.RemoveOldest(); | |
170 | |
171 ASSERT_EQ("d", r.GetOldest()); | |
172 ASSERT_EQ(421, r.GetOldestPayload()); | |
173 r.RemoveOldest(); | |
174 | |
175 ASSERT_TRUE(r.IsEmpty()); | |
176 } | |
177 | |
178 TEST(LRU, GetAllKeys) | |
179 { | |
180 Orthanc::LeastRecentlyUsedIndex<std::string, int> r; | |
181 std::vector<std::string> keys; | |
182 | |
183 r.AddOrMakeMostRecent("a", 420); | |
184 r.GetAllKeys(keys); | |
185 | |
186 ASSERT_EQ(1u, keys.size()); | |
187 ASSERT_EQ("a", keys[0]); | |
188 | |
189 r.AddOrMakeMostRecent("b", 421); | |
190 r.GetAllKeys(keys); | |
191 | |
192 ASSERT_EQ(2u, keys.size()); | |
193 ASSERT_TRUE(std::find(keys.begin(), keys.end(),"a") != keys.end()); | |
194 ASSERT_TRUE(std::find(keys.begin(), keys.end(),"b") != keys.end()); | |
195 } | |
196 | |
197 | |
198 | |
199 namespace | |
200 { | |
201 class Integer : public Orthanc::IDynamicObject | |
202 { | |
203 private: | |
204 std::string& log_; | |
205 int value_; | |
206 | |
207 public: | |
208 Integer(std::string& log, int v) : log_(log), value_(v) | |
209 { | |
210 } | |
211 | |
212 virtual ~Integer() ORTHANC_OVERRIDE | |
213 { | |
214 LOG(INFO) << "Removing cache entry for " << value_; | |
215 log_ += boost::lexical_cast<std::string>(value_) + " "; | |
216 } | |
217 }; | |
218 | |
219 class IntegerProvider : public Orthanc::Deprecated::ICachePageProvider | |
220 { | |
221 public: | |
222 std::string log_; | |
223 | |
224 virtual Orthanc::IDynamicObject* Provide(const std::string& s) ORTHANC_OVERRIDE | |
225 { | |
226 LOG(INFO) << "Providing " << s; | |
227 return new Integer(log_, boost::lexical_cast<int>(s)); | |
228 } | |
229 }; | |
230 } | |
231 | |
232 | |
233 TEST(MemoryCache, Basic) | |
234 { | |
235 IntegerProvider provider; | |
236 | |
237 { | |
238 Orthanc::Deprecated::MemoryCache cache(provider, 3); | |
239 cache.Access("42"); // 42 -> exit | |
240 cache.Access("43"); // 43, 42 -> exit | |
241 cache.Access("45"); // 45, 43, 42 -> exit | |
242 cache.Access("42"); // 42, 45, 43 -> exit | |
243 cache.Access("43"); // 43, 42, 45 -> exit | |
244 cache.Access("47"); // 45 is removed; 47, 43, 42 -> exit | |
245 cache.Access("44"); // 42 is removed; 44, 47, 43 -> exit | |
246 cache.Access("42"); // 43 is removed; 42, 44, 47 -> exit | |
247 // Closing the cache: 47, 44, 42 are successively removed | |
248 } | |
249 | |
250 ASSERT_EQ("45 42 43 47 44 42 ", provider.log_); | |
251 } | |
252 | |
253 | |
254 | |
255 | |
256 | |
257 namespace | |
258 { | |
259 class S : public Orthanc::IDynamicObject | |
260 { | |
261 private: | |
262 std::string value_; | |
263 | |
264 public: | |
265 S(const std::string& value) : value_(value) | |
266 { | |
267 } | |
268 | |
269 const std::string& GetValue() const | |
270 { | |
271 return value_; | |
272 } | |
273 }; | |
274 } | |
275 | |
276 | |
277 TEST(LRU, SharedArchive) | |
278 { | |
279 std::string first, second; | |
280 Orthanc::SharedArchive a(3); | |
281 first = a.Add(new S("First item")); | |
282 second = a.Add(new S("Second item")); | |
283 | |
284 for (int i = 1; i < 100; i++) | |
285 { | |
286 a.Add(new S("Item " + boost::lexical_cast<std::string>(i))); | |
287 | |
288 // Continuously protect the two first items | |
289 { | |
290 Orthanc::SharedArchive::Accessor accessor(a, first); | |
291 ASSERT_TRUE(accessor.IsValid()); | |
292 ASSERT_EQ("First item", dynamic_cast<S&>(accessor.GetItem()).GetValue()); | |
293 } | |
294 | |
295 { | |
296 Orthanc::SharedArchive::Accessor accessor(a, second); | |
297 ASSERT_TRUE(accessor.IsValid()); | |
298 ASSERT_EQ("Second item", dynamic_cast<S&>(accessor.GetItem()).GetValue()); | |
299 } | |
300 | |
301 { | |
302 Orthanc::SharedArchive::Accessor accessor(a, "nope"); | |
303 ASSERT_FALSE(accessor.IsValid()); | |
304 ASSERT_THROW(accessor.GetItem(), Orthanc::OrthancException); | |
305 } | |
306 } | |
307 | |
308 std::list<std::string> i; | |
309 a.List(i); | |
310 | |
311 size_t count = 0; | |
312 for (std::list<std::string>::const_iterator | |
313 it = i.begin(); it != i.end(); it++) | |
314 { | |
315 if (*it == first || | |
316 *it == second) | |
317 { | |
318 count++; | |
319 } | |
320 } | |
321 | |
322 ASSERT_EQ(2u, count); | |
323 } | |
324 | |
325 | |
326 TEST(MemoryStringCache, Basic) | |
327 { | |
328 Orthanc::MemoryStringCache c; | |
329 ASSERT_THROW(c.SetMaximumSize(0), Orthanc::OrthancException); | |
330 | |
331 c.SetMaximumSize(2); | |
332 | |
333 std::string v; | |
334 ASSERT_FALSE(c.Fetch(v, "hello")); | |
335 | |
336 c.Add("hello", "a"); | |
337 ASSERT_TRUE(c.Fetch(v, "hello")); ASSERT_EQ("a", v); | |
338 ASSERT_FALSE(c.Fetch(v, "hello2")); | |
339 ASSERT_FALSE(c.Fetch(v, "hello3")); | |
340 | |
341 c.Add("hello2", "b"); | |
342 ASSERT_TRUE(c.Fetch(v, "hello")); ASSERT_EQ("a", v); | |
343 ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); | |
344 ASSERT_FALSE(c.Fetch(v, "hello3")); | |
345 | |
346 c.Add("hello3", "too large value"); | |
347 ASSERT_TRUE(c.Fetch(v, "hello")); ASSERT_EQ("a", v); | |
348 ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); | |
349 ASSERT_FALSE(c.Fetch(v, "hello3")); | |
350 | |
351 c.Add("hello3", "c"); | |
352 ASSERT_FALSE(c.Fetch(v, "hello")); // Recycled | |
353 ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); | |
354 ASSERT_TRUE(c.Fetch(v, "hello3")); ASSERT_EQ("c", v); | |
355 } | |
356 | |
357 | |
358 TEST(MemoryStringCache, Invalidate) | |
359 { | |
360 Orthanc::MemoryStringCache c; | |
361 c.Add("hello", "a"); | |
362 c.Add("hello2", "b"); | |
363 | |
364 std::string v; | |
365 ASSERT_TRUE(c.Fetch(v, "hello")); ASSERT_EQ("a", v); | |
366 ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); | |
367 | |
368 c.Invalidate("hello"); | |
369 ASSERT_FALSE(c.Fetch(v, "hello")); | |
370 ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); | |
371 } |