# HG changeset patch # User Sebastien Jodogne # Date 1591877527 -7200 # Node ID e241e5f3f088cb402812c72cc1fb3b07fef40492 # Parent 2a8bf0991be025f53ceed03beb8d7c62439928a3 moved LuaTests and MemoryCacheTests from OrthancServer to OrthancFramework diff -r 2a8bf0991be0 -r e241e5f3f088 CMakeLists.txt --- a/CMakeLists.txt Thu Jun 11 13:57:44 2020 +0200 +++ b/CMakeLists.txt Thu Jun 11 14:12:07 2020 +0200 @@ -122,6 +122,8 @@ OrthancFramework/UnitTestsSources/ImageTests.cpp OrthancFramework/UnitTestsSources/JpegLosslessTests.cpp OrthancFramework/UnitTestsSources/LoggingTests.cpp + OrthancFramework/UnitTestsSources/LuaTests.cpp + OrthancFramework/UnitTestsSources/MemoryCacheTests.cpp OrthancFramework/UnitTestsSources/RestApiTests.cpp OrthancFramework/UnitTestsSources/SQLiteChromiumTests.cpp OrthancFramework/UnitTestsSources/SQLiteTests.cpp @@ -132,9 +134,9 @@ set(ORTHANC_SERVER_UNIT_TESTS OrthancServer/UnitTestsSources/DatabaseLookupTests.cpp - OrthancServer/UnitTestsSources/LuaTests.cpp - OrthancServer/UnitTestsSources/MemoryCacheTests.cpp + OrthancServer/UnitTestsSources/LuaServerTests.cpp OrthancServer/UnitTestsSources/MultiThreadingTests.cpp + OrthancServer/UnitTestsSources/PluginsTests.cpp OrthancServer/UnitTestsSources/ServerIndexTests.cpp OrthancServer/UnitTestsSources/UnitTestsMain.cpp OrthancServer/UnitTestsSources/VersionsTests.cpp diff -r 2a8bf0991be0 -r e241e5f3f088 OrthancFramework/UnitTestsSources/LuaTests.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/UnitTestsSources/LuaTests.cpp Thu Jun 11 14:12:07 2020 +0200 @@ -0,0 +1,193 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1 +# include +#endif + +#include "gtest/gtest.h" + +#include "../Sources/OrthancException.h" +#include "../Sources/Toolbox.h" +#include "../Sources/Lua/LuaFunctionCall.h" + +#include + + +TEST(Lua, Existing) +{ + Orthanc::LuaContext lua; + lua.Execute("a={}"); + lua.Execute("function f() end"); + + ASSERT_TRUE(lua.IsExistingFunction("f")); + ASSERT_FALSE(lua.IsExistingFunction("a")); + ASSERT_FALSE(lua.IsExistingFunction("Dummy")); +} + + +TEST(Lua, ReturnJson) +{ + Json::Value b = Json::objectValue; + b["a"] = 42; + b["b"] = 44.37; + b["c"] = -43; + + Json::Value c = Json::arrayValue; + c.append("test3"); + c.append("test1"); + c.append("test2"); + + Json::Value a = Json::objectValue; + a["Hello"] = "World"; + a["List"] = Json::arrayValue; + a["List"].append(b); + a["List"].append(c); + + Orthanc::LuaContext lua; + + // This is the identity function (it simply returns its input) + lua.Execute("function identity(a) return a end"); + + { + Orthanc::LuaFunctionCall f(lua, "identity"); + f.PushJson("hello"); + Json::Value v; + f.ExecuteToJson(v, false); + ASSERT_EQ("hello", v.asString()); + } + + { + Orthanc::LuaFunctionCall f(lua, "identity"); + f.PushJson(42.25); + Json::Value v; + f.ExecuteToJson(v, false); + ASSERT_FLOAT_EQ(42.25f, v.asFloat()); + } + + { + Orthanc::LuaFunctionCall f(lua, "identity"); + f.PushJson(-42); + Json::Value v; + f.ExecuteToJson(v, false); + ASSERT_EQ(-42, v.asInt()); + } + + { + Orthanc::LuaFunctionCall f(lua, "identity"); + Json::Value vv = Json::arrayValue; + f.PushJson(vv); + Json::Value v; + f.ExecuteToJson(v, false); + ASSERT_EQ(Json::arrayValue, v.type()); + } + + { + Orthanc::LuaFunctionCall f(lua, "identity"); + Json::Value vv = Json::objectValue; + f.PushJson(vv); + Json::Value v; + f.ExecuteToJson(v, false); + // Lua does not make the distinction between empty lists and empty objects + ASSERT_EQ(Json::arrayValue, v.type()); + } + + { + Orthanc::LuaFunctionCall f(lua, "identity"); + f.PushJson(b); + Json::Value v; + f.ExecuteToJson(v, false); + ASSERT_EQ(Json::objectValue, v.type()); + ASSERT_FLOAT_EQ(42.0f, v["a"].asFloat()); + ASSERT_FLOAT_EQ(44.37f, v["b"].asFloat()); + ASSERT_FLOAT_EQ(-43.0f, v["c"].asFloat()); + } + + { + Orthanc::LuaFunctionCall f(lua, "identity"); + f.PushJson(c); + Json::Value v; + f.ExecuteToJson(v, false); + ASSERT_EQ(Json::arrayValue, v.type()); + ASSERT_EQ("test3", v[0].asString()); + ASSERT_EQ("test1", v[1].asString()); + ASSERT_EQ("test2", v[2].asString()); + } + + { + Orthanc::LuaFunctionCall f(lua, "identity"); + f.PushJson(a); + Json::Value v; + f.ExecuteToJson(v, false); + ASSERT_EQ("World", v["Hello"].asString()); + ASSERT_EQ(Json::intValue, v["List"][0]["a"].type()); + ASSERT_EQ(Json::realValue, v["List"][0]["b"].type()); + ASSERT_EQ(Json::intValue, v["List"][0]["c"].type()); + ASSERT_EQ(42, v["List"][0]["a"].asInt()); + ASSERT_FLOAT_EQ(44.37f, v["List"][0]["b"].asFloat()); + ASSERT_EQ(44, v["List"][0]["b"].asInt()); + ASSERT_EQ(-43, v["List"][0]["c"].asInt()); + ASSERT_EQ("test3", v["List"][1][0].asString()); + ASSERT_EQ("test1", v["List"][1][1].asString()); + ASSERT_EQ("test2", v["List"][1][2].asString()); + } + + { + Orthanc::LuaFunctionCall f(lua, "identity"); + f.PushJson(a); + Json::Value v; + f.ExecuteToJson(v, true); + ASSERT_EQ("World", v["Hello"].asString()); + ASSERT_EQ(Json::stringValue, v["List"][0]["a"].type()); + ASSERT_EQ(Json::stringValue, v["List"][0]["b"].type()); + ASSERT_EQ(Json::stringValue, v["List"][0]["c"].type()); + ASSERT_FLOAT_EQ(42.0f, boost::lexical_cast(v["List"][0]["a"].asString())); + ASSERT_FLOAT_EQ(44.37f, boost::lexical_cast(v["List"][0]["b"].asString())); + ASSERT_FLOAT_EQ(-43.0f, boost::lexical_cast(v["List"][0]["c"].asString())); + ASSERT_EQ("test3", v["List"][1][0].asString()); + ASSERT_EQ("test1", v["List"][1][1].asString()); + ASSERT_EQ("test2", v["List"][1][2].asString()); + } + + { + Orthanc::LuaFunctionCall f(lua, "DumpJson"); + f.PushJson(a); + std::string s; + f.ExecuteToString(s); + + Json::FastWriter writer; + std::string t = writer.write(a); + + ASSERT_EQ(s, t); + } +} diff -r 2a8bf0991be0 -r e241e5f3f088 OrthancFramework/UnitTestsSources/MemoryCacheTests.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/UnitTestsSources/MemoryCacheTests.cpp Thu Jun 11 14:12:07 2020 +0200 @@ -0,0 +1,371 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1 +# include +#endif + +#include "gtest/gtest.h" + +#include +#include +#include +#include + +#include "../Sources/Cache/MemoryCache.h" +#include "../Sources/Cache/MemoryStringCache.h" +#include "../Sources/Cache/SharedArchive.h" +#include "../Sources/IDynamicObject.h" +#include "../Sources/Logging.h" + + +TEST(LRU, Basic) +{ + Orthanc::LeastRecentlyUsedIndex r; + + r.Add("d"); + r.Add("a"); + r.Add("c"); + r.Add("b"); + + r.MakeMostRecent("a"); + r.MakeMostRecent("d"); + r.MakeMostRecent("b"); + r.MakeMostRecent("c"); + r.MakeMostRecent("d"); + r.MakeMostRecent("c"); + + ASSERT_EQ("a", r.GetOldest()); + ASSERT_EQ("a", r.RemoveOldest()); + ASSERT_EQ("b", r.GetOldest()); + ASSERT_EQ("b", r.RemoveOldest()); + ASSERT_EQ("d", r.GetOldest()); + ASSERT_EQ("d", r.RemoveOldest()); + ASSERT_EQ("c", r.GetOldest()); + ASSERT_EQ("c", r.RemoveOldest()); + + ASSERT_TRUE(r.IsEmpty()); + + ASSERT_THROW(r.GetOldest(), Orthanc::OrthancException); + ASSERT_THROW(r.RemoveOldest(), Orthanc::OrthancException); +} + + +TEST(LRU, Payload) +{ + Orthanc::LeastRecentlyUsedIndex r; + + r.Add("a", 420); + r.Add("b", 421); + r.Add("c", 422); + r.Add("d", 423); + + r.MakeMostRecent("a"); + r.MakeMostRecent("d"); + r.MakeMostRecent("b"); + r.MakeMostRecent("c"); + r.MakeMostRecent("d"); + r.MakeMostRecent("c"); + + ASSERT_TRUE(r.Contains("b")); + ASSERT_EQ(421, r.Invalidate("b")); + ASSERT_FALSE(r.Contains("b")); + + int p; + ASSERT_TRUE(r.Contains("a", p)); ASSERT_EQ(420, p); + ASSERT_TRUE(r.Contains("c", p)); ASSERT_EQ(422, p); + ASSERT_TRUE(r.Contains("d", p)); ASSERT_EQ(423, p); + + ASSERT_EQ("a", r.GetOldest()); + ASSERT_EQ(420, r.GetOldestPayload()); + ASSERT_EQ("a", r.RemoveOldest(p)); ASSERT_EQ(420, p); + + ASSERT_EQ("d", r.GetOldest()); + ASSERT_EQ(423, r.GetOldestPayload()); + ASSERT_EQ("d", r.RemoveOldest(p)); ASSERT_EQ(423, p); + + ASSERT_EQ("c", r.GetOldest()); + ASSERT_EQ(422, r.GetOldestPayload()); + ASSERT_EQ("c", r.RemoveOldest(p)); ASSERT_EQ(422, p); + + ASSERT_TRUE(r.IsEmpty()); +} + + +TEST(LRU, PayloadUpdate) +{ + Orthanc::LeastRecentlyUsedIndex r; + + r.Add("a", 420); + r.Add("b", 421); + r.Add("d", 423); + + r.MakeMostRecent("a", 424); + r.MakeMostRecent("d", 421); + + ASSERT_EQ("b", r.GetOldest()); + ASSERT_EQ(421, r.GetOldestPayload()); + r.RemoveOldest(); + + ASSERT_EQ("a", r.GetOldest()); + ASSERT_EQ(424, r.GetOldestPayload()); + r.RemoveOldest(); + + ASSERT_EQ("d", r.GetOldest()); + ASSERT_EQ(421, r.GetOldestPayload()); + r.RemoveOldest(); + + ASSERT_TRUE(r.IsEmpty()); +} + + + +TEST(LRU, PayloadUpdateBis) +{ + Orthanc::LeastRecentlyUsedIndex r; + + r.AddOrMakeMostRecent("a", 420); + r.AddOrMakeMostRecent("b", 421); + r.AddOrMakeMostRecent("d", 423); + r.AddOrMakeMostRecent("a", 424); + r.AddOrMakeMostRecent("d", 421); + + ASSERT_EQ("b", r.GetOldest()); + ASSERT_EQ(421, r.GetOldestPayload()); + r.RemoveOldest(); + + ASSERT_EQ("a", r.GetOldest()); + ASSERT_EQ(424, r.GetOldestPayload()); + r.RemoveOldest(); + + ASSERT_EQ("d", r.GetOldest()); + ASSERT_EQ(421, r.GetOldestPayload()); + r.RemoveOldest(); + + ASSERT_TRUE(r.IsEmpty()); +} + +TEST(LRU, GetAllKeys) +{ + Orthanc::LeastRecentlyUsedIndex r; + std::vector keys; + + r.AddOrMakeMostRecent("a", 420); + r.GetAllKeys(keys); + + ASSERT_EQ(1u, keys.size()); + ASSERT_EQ("a", keys[0]); + + r.AddOrMakeMostRecent("b", 421); + r.GetAllKeys(keys); + + ASSERT_EQ(2u, keys.size()); + ASSERT_TRUE(std::find(keys.begin(), keys.end(),"a") != keys.end()); + ASSERT_TRUE(std::find(keys.begin(), keys.end(),"b") != keys.end()); +} + + + +namespace +{ + class Integer : public Orthanc::IDynamicObject + { + private: + std::string& log_; + int value_; + + public: + Integer(std::string& log, int v) : log_(log), value_(v) + { + } + + virtual ~Integer() ORTHANC_OVERRIDE + { + LOG(INFO) << "Removing cache entry for " << value_; + log_ += boost::lexical_cast(value_) + " "; + } + }; + + class IntegerProvider : public Orthanc::Deprecated::ICachePageProvider + { + public: + std::string log_; + + virtual Orthanc::IDynamicObject* Provide(const std::string& s) ORTHANC_OVERRIDE + { + LOG(INFO) << "Providing " << s; + return new Integer(log_, boost::lexical_cast(s)); + } + }; +} + + +TEST(MemoryCache, Basic) +{ + IntegerProvider provider; + + { + Orthanc::Deprecated::MemoryCache cache(provider, 3); + cache.Access("42"); // 42 -> exit + cache.Access("43"); // 43, 42 -> exit + cache.Access("45"); // 45, 43, 42 -> exit + cache.Access("42"); // 42, 45, 43 -> exit + cache.Access("43"); // 43, 42, 45 -> exit + cache.Access("47"); // 45 is removed; 47, 43, 42 -> exit + cache.Access("44"); // 42 is removed; 44, 47, 43 -> exit + cache.Access("42"); // 43 is removed; 42, 44, 47 -> exit + // Closing the cache: 47, 44, 42 are successively removed + } + + ASSERT_EQ("45 42 43 47 44 42 ", provider.log_); +} + + + + + +namespace +{ + class S : public Orthanc::IDynamicObject + { + private: + std::string value_; + + public: + S(const std::string& value) : value_(value) + { + } + + const std::string& GetValue() const + { + return value_; + } + }; +} + + +TEST(LRU, SharedArchive) +{ + std::string first, second; + Orthanc::SharedArchive a(3); + first = a.Add(new S("First item")); + second = a.Add(new S("Second item")); + + for (int i = 1; i < 100; i++) + { + a.Add(new S("Item " + boost::lexical_cast(i))); + + // Continuously protect the two first items + { + Orthanc::SharedArchive::Accessor accessor(a, first); + ASSERT_TRUE(accessor.IsValid()); + ASSERT_EQ("First item", dynamic_cast(accessor.GetItem()).GetValue()); + } + + { + Orthanc::SharedArchive::Accessor accessor(a, second); + ASSERT_TRUE(accessor.IsValid()); + ASSERT_EQ("Second item", dynamic_cast(accessor.GetItem()).GetValue()); + } + + { + Orthanc::SharedArchive::Accessor accessor(a, "nope"); + ASSERT_FALSE(accessor.IsValid()); + ASSERT_THROW(accessor.GetItem(), Orthanc::OrthancException); + } + } + + std::list i; + a.List(i); + + size_t count = 0; + for (std::list::const_iterator + it = i.begin(); it != i.end(); it++) + { + if (*it == first || + *it == second) + { + count++; + } + } + + ASSERT_EQ(2u, count); +} + + +TEST(MemoryStringCache, Basic) +{ + Orthanc::MemoryStringCache c; + ASSERT_THROW(c.SetMaximumSize(0), Orthanc::OrthancException); + + c.SetMaximumSize(2); + + std::string v; + ASSERT_FALSE(c.Fetch(v, "hello")); + + c.Add("hello", "a"); + ASSERT_TRUE(c.Fetch(v, "hello")); ASSERT_EQ("a", v); + ASSERT_FALSE(c.Fetch(v, "hello2")); + ASSERT_FALSE(c.Fetch(v, "hello3")); + + c.Add("hello2", "b"); + ASSERT_TRUE(c.Fetch(v, "hello")); ASSERT_EQ("a", v); + ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); + ASSERT_FALSE(c.Fetch(v, "hello3")); + + c.Add("hello3", "too large value"); + ASSERT_TRUE(c.Fetch(v, "hello")); ASSERT_EQ("a", v); + ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); + ASSERT_FALSE(c.Fetch(v, "hello3")); + + c.Add("hello3", "c"); + ASSERT_FALSE(c.Fetch(v, "hello")); // Recycled + ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); + ASSERT_TRUE(c.Fetch(v, "hello3")); ASSERT_EQ("c", v); +} + + +TEST(MemoryStringCache, Invalidate) +{ + Orthanc::MemoryStringCache c; + c.Add("hello", "a"); + c.Add("hello2", "b"); + + std::string v; + ASSERT_TRUE(c.Fetch(v, "hello")); ASSERT_EQ("a", v); + ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); + + c.Invalidate("hello"); + ASSERT_FALSE(c.Fetch(v, "hello")); + ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); +} diff -r 2a8bf0991be0 -r e241e5f3f088 OrthancServer/UnitTestsSources/LuaServerTests.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/UnitTestsSources/LuaServerTests.cpp Thu Jun 11 14:12:07 2020 +0200 @@ -0,0 +1,208 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#include "PrecompiledHeadersUnitTests.h" +#include "gtest/gtest.h" + +#include "../../OrthancFramework/Sources/OrthancException.h" +#include "../../OrthancFramework/Sources/Toolbox.h" +#include "../../OrthancFramework/Sources/Lua/LuaFunctionCall.h" + +#include + +#include + +#if !defined(UNIT_TESTS_WITH_HTTP_CONNEXIONS) +# error "Please set UNIT_TESTS_WITH_HTTP_CONNEXIONS to 0 or 1" +#endif + + +TEST(Lua, Json) +{ + Orthanc::LuaContext lua; + + { + std::string command; + Orthanc::ServerResources::GetFileResource(command, Orthanc::ServerResources::LUA_TOOLBOX); + lua.Execute(command); + } + + lua.Execute("a={}"); + lua.Execute("a['x'] = 10"); + lua.Execute("a['y'] = {}"); + lua.Execute("a['y'][1] = 20"); + lua.Execute("a['y'][2] = 20"); + lua.Execute("PrintRecursive(a)"); + lua.Execute("function f(a) print(a.bool) return a.bool,20,30,40,50,60 end"); + + Json::Value v, vv, o; + //v["a"] = "b"; + v.append("hello"); + v.append("world"); + v.append("42"); + vv.append("sub"); + vv.append("set"); + v.append(vv); + o = Json::objectValue; + o["x"] = 10; + o["y"] = 20; + o["z"] = 20.5f; + v.append(o); + + { + Orthanc::LuaFunctionCall f(lua, "PrintRecursive"); + f.PushJson(v); + f.Execute(); + } + + { + Orthanc::LuaFunctionCall f(lua, "f"); + f.PushJson(o); + ASSERT_THROW(f.ExecutePredicate(), Orthanc::OrthancException); + } + + o["bool"] = false; + + { + Orthanc::LuaFunctionCall f(lua, "f"); + f.PushJson(o); + ASSERT_FALSE(f.ExecutePredicate()); + } + + o["bool"] = true; + + { + Orthanc::LuaFunctionCall f(lua, "f"); + f.PushJson(o); + ASSERT_TRUE(f.ExecutePredicate()); + } +} + + +TEST(Lua, Simple) +{ + Orthanc::LuaContext lua; + + { + std::string command; + Orthanc::ServerResources::GetFileResource(command, Orthanc::ServerResources::LUA_TOOLBOX); + lua.Execute(command); + } + + { + Orthanc::LuaFunctionCall f(lua, "PrintRecursive"); + f.PushString("hello"); + f.Execute(); + } + + { + Orthanc::LuaFunctionCall f(lua, "PrintRecursive"); + f.PushBoolean(true); + f.Execute(); + } + + { + Orthanc::LuaFunctionCall f(lua, "PrintRecursive"); + f.PushInteger(42); + f.Execute(); + } + + { + Orthanc::LuaFunctionCall f(lua, "PrintRecursive"); + f.PushDouble(3.1415); + f.Execute(); + } +} + + +TEST(Lua, Http) +{ + Orthanc::LuaContext lua; + +#if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1 + // The "http://www.orthanc-server.com/downloads/third-party/" does + // not automatically redirect to HTTPS, so we cas use it even if the + // OpenSSL/HTTPS support is disabled in curl + const std::string BASE = "http://www.orthanc-server.com/downloads/third-party/"; + +#if LUA_VERSION_NUM >= 502 + // Since Lua >= 5.2.0, the function "loadstring" has been replaced by "load" + lua.Execute("JSON = load(HttpGet('" + BASE + "JSON.lua')) ()"); +#else + lua.Execute("JSON = loadstring(HttpGet('" + BASE + "JSON.lua')) ()"); +#endif + + const std::string url(BASE + "Product.json"); +#endif + + std::string s; + lua.Execute(s, "print(HttpGet({}))"); + ASSERT_EQ("nil", Orthanc::Toolbox::StripSpaces(s)); + +#if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1 + lua.Execute(s, "print(string.len(HttpGet(\"" + url + "\")))"); + ASSERT_LE(100, boost::lexical_cast(Orthanc::Toolbox::StripSpaces(s))); + + // Parse a JSON file + lua.Execute(s, "print(JSON:decode(HttpGet(\"" + url + "\")) ['Product'])"); + ASSERT_EQ("OrthancClient", Orthanc::Toolbox::StripSpaces(s)); + +#if 0 + // This part of the test can only be executed if one instance of + // Orthanc is running on the localhost + + lua.Execute("modality = {}"); + lua.Execute("table.insert(modality, 'ORTHANC')"); + lua.Execute("table.insert(modality, 'localhost')"); + lua.Execute("table.insert(modality, 4242)"); + + lua.Execute(s, "print(HttpPost(\"http://localhost:8042/tools/execute-script\", \"print('hello world')\"))"); + ASSERT_EQ("hello world", Orthanc::Toolbox::StripSpaces(s)); + + lua.Execute(s, "print(JSON:decode(HttpPost(\"http://localhost:8042/tools/execute-script\", \"print('[10,42,1000]')\")) [2])"); + ASSERT_EQ("42", Orthanc::Toolbox::StripSpaces(s)); + + // Add/remove a modality with Lua + Json::Value v; + lua.Execute(s, "print(HttpGet('http://localhost:8042/modalities/lua'))"); + ASSERT_EQ(0, Orthanc::Toolbox::StripSpaces(s).size()); + lua.Execute(s, "print(HttpPut('http://localhost:8042/modalities/lua', JSON:encode(modality)))"); + lua.Execute(v, "print(HttpGet('http://localhost:8042/modalities/lua'))"); + ASSERT_TRUE(v.type() == Json::arrayValue); + lua.Execute(s, "print(HttpDelete('http://localhost:8042/modalities/lua'))"); + lua.Execute(s, "print(HttpGet('http://localhost:8042/modalities/lua'))"); + ASSERT_EQ(0, Orthanc::Toolbox::StripSpaces(s).size()); +#endif + +#endif +} diff -r 2a8bf0991be0 -r e241e5f3f088 OrthancServer/UnitTestsSources/LuaTests.cpp --- a/OrthancServer/UnitTestsSources/LuaTests.cpp Thu Jun 11 13:57:44 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,372 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1 -# include -#endif - -#include "PrecompiledHeadersUnitTests.h" -#include "gtest/gtest.h" - -#include "../../OrthancFramework/Sources/OrthancException.h" -#include "../../OrthancFramework/Sources/Toolbox.h" -#include "../../OrthancFramework/Sources/Lua/LuaFunctionCall.h" - -#include - -#include - -#if !defined(UNIT_TESTS_WITH_HTTP_CONNEXIONS) -#error "Please set UNIT_TESTS_WITH_HTTP_CONNEXIONS to 0 or 1" -#endif - - -TEST(Lua, Json) -{ - Orthanc::LuaContext lua; - -#if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK != 1 - { - std::string command; - Orthanc::ServerResources::GetFileResource(command, Orthanc::ServerResources::LUA_TOOLBOX); - lua.Execute(command); - } -#endif - - lua.Execute("a={}"); - lua.Execute("a['x'] = 10"); - lua.Execute("a['y'] = {}"); - lua.Execute("a['y'][1] = 20"); - lua.Execute("a['y'][2] = 20"); - -#if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK != 1 - lua.Execute("PrintRecursive(a)"); -#endif - - lua.Execute("function f(a) print(a.bool) return a.bool,20,30,40,50,60 end"); - - Json::Value v, vv, o; - //v["a"] = "b"; - v.append("hello"); - v.append("world"); - v.append("42"); - vv.append("sub"); - vv.append("set"); - v.append(vv); - o = Json::objectValue; - o["x"] = 10; - o["y"] = 20; - o["z"] = 20.5f; - v.append(o); - -#if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK != 1 - { - Orthanc::LuaFunctionCall f(lua, "PrintRecursive"); - f.PushJson(v); - f.Execute(); - } -#endif - - { - Orthanc::LuaFunctionCall f(lua, "f"); - f.PushJson(o); - ASSERT_THROW(f.ExecutePredicate(), Orthanc::OrthancException); - } - - o["bool"] = false; - - { - Orthanc::LuaFunctionCall f(lua, "f"); - f.PushJson(o); - ASSERT_FALSE(f.ExecutePredicate()); - } - - o["bool"] = true; - - { - Orthanc::LuaFunctionCall f(lua, "f"); - f.PushJson(o); - ASSERT_TRUE(f.ExecutePredicate()); - } -} - - -TEST(Lua, Existing) -{ - Orthanc::LuaContext lua; - lua.Execute("a={}"); - lua.Execute("function f() end"); - - ASSERT_TRUE(lua.IsExistingFunction("f")); - ASSERT_FALSE(lua.IsExistingFunction("a")); - ASSERT_FALSE(lua.IsExistingFunction("Dummy")); -} - - -#if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK != 1 -TEST(Lua, Simple) -{ - Orthanc::LuaContext lua; - - { - std::string command; - Orthanc::ServerResources::GetFileResource(command, Orthanc::ServerResources::LUA_TOOLBOX); - lua.Execute(command); - } - - { - Orthanc::LuaFunctionCall f(lua, "PrintRecursive"); - f.PushString("hello"); - f.Execute(); - } - - { - Orthanc::LuaFunctionCall f(lua, "PrintRecursive"); - f.PushBoolean(true); - f.Execute(); - } - - { - Orthanc::LuaFunctionCall f(lua, "PrintRecursive"); - f.PushInteger(42); - f.Execute(); - } - - { - Orthanc::LuaFunctionCall f(lua, "PrintRecursive"); - f.PushDouble(3.1415); - f.Execute(); - } -} -#endif - - -TEST(Lua, ReturnJson) -{ - Json::Value b = Json::objectValue; - b["a"] = 42; - b["b"] = 44.37; - b["c"] = -43; - - Json::Value c = Json::arrayValue; - c.append("test3"); - c.append("test1"); - c.append("test2"); - - Json::Value a = Json::objectValue; - a["Hello"] = "World"; - a["List"] = Json::arrayValue; - a["List"].append(b); - a["List"].append(c); - - Orthanc::LuaContext lua; - - // This is the identity function (it simply returns its input) - lua.Execute("function identity(a) return a end"); - - { - Orthanc::LuaFunctionCall f(lua, "identity"); - f.PushJson("hello"); - Json::Value v; - f.ExecuteToJson(v, false); - ASSERT_EQ("hello", v.asString()); - } - - { - Orthanc::LuaFunctionCall f(lua, "identity"); - f.PushJson(42.25); - Json::Value v; - f.ExecuteToJson(v, false); - ASSERT_FLOAT_EQ(42.25f, v.asFloat()); - } - - { - Orthanc::LuaFunctionCall f(lua, "identity"); - f.PushJson(-42); - Json::Value v; - f.ExecuteToJson(v, false); - ASSERT_EQ(-42, v.asInt()); - } - - { - Orthanc::LuaFunctionCall f(lua, "identity"); - Json::Value vv = Json::arrayValue; - f.PushJson(vv); - Json::Value v; - f.ExecuteToJson(v, false); - ASSERT_EQ(Json::arrayValue, v.type()); - } - - { - Orthanc::LuaFunctionCall f(lua, "identity"); - Json::Value vv = Json::objectValue; - f.PushJson(vv); - Json::Value v; - f.ExecuteToJson(v, false); - // Lua does not make the distinction between empty lists and empty objects - ASSERT_EQ(Json::arrayValue, v.type()); - } - - { - Orthanc::LuaFunctionCall f(lua, "identity"); - f.PushJson(b); - Json::Value v; - f.ExecuteToJson(v, false); - ASSERT_EQ(Json::objectValue, v.type()); - ASSERT_FLOAT_EQ(42.0f, v["a"].asFloat()); - ASSERT_FLOAT_EQ(44.37f, v["b"].asFloat()); - ASSERT_FLOAT_EQ(-43.0f, v["c"].asFloat()); - } - - { - Orthanc::LuaFunctionCall f(lua, "identity"); - f.PushJson(c); - Json::Value v; - f.ExecuteToJson(v, false); - ASSERT_EQ(Json::arrayValue, v.type()); - ASSERT_EQ("test3", v[0].asString()); - ASSERT_EQ("test1", v[1].asString()); - ASSERT_EQ("test2", v[2].asString()); - } - - { - Orthanc::LuaFunctionCall f(lua, "identity"); - f.PushJson(a); - Json::Value v; - f.ExecuteToJson(v, false); - ASSERT_EQ("World", v["Hello"].asString()); - ASSERT_EQ(Json::intValue, v["List"][0]["a"].type()); - ASSERT_EQ(Json::realValue, v["List"][0]["b"].type()); - ASSERT_EQ(Json::intValue, v["List"][0]["c"].type()); - ASSERT_EQ(42, v["List"][0]["a"].asInt()); - ASSERT_FLOAT_EQ(44.37f, v["List"][0]["b"].asFloat()); - ASSERT_EQ(44, v["List"][0]["b"].asInt()); - ASSERT_EQ(-43, v["List"][0]["c"].asInt()); - ASSERT_EQ("test3", v["List"][1][0].asString()); - ASSERT_EQ("test1", v["List"][1][1].asString()); - ASSERT_EQ("test2", v["List"][1][2].asString()); - } - - { - Orthanc::LuaFunctionCall f(lua, "identity"); - f.PushJson(a); - Json::Value v; - f.ExecuteToJson(v, true); - ASSERT_EQ("World", v["Hello"].asString()); - ASSERT_EQ(Json::stringValue, v["List"][0]["a"].type()); - ASSERT_EQ(Json::stringValue, v["List"][0]["b"].type()); - ASSERT_EQ(Json::stringValue, v["List"][0]["c"].type()); - ASSERT_FLOAT_EQ(42.0f, boost::lexical_cast(v["List"][0]["a"].asString())); - ASSERT_FLOAT_EQ(44.37f, boost::lexical_cast(v["List"][0]["b"].asString())); - ASSERT_FLOAT_EQ(-43.0f, boost::lexical_cast(v["List"][0]["c"].asString())); - ASSERT_EQ("test3", v["List"][1][0].asString()); - ASSERT_EQ("test1", v["List"][1][1].asString()); - ASSERT_EQ("test2", v["List"][1][2].asString()); - } - - { - Orthanc::LuaFunctionCall f(lua, "DumpJson"); - f.PushJson(a); - std::string s; - f.ExecuteToString(s); - - Json::FastWriter writer; - std::string t = writer.write(a); - - ASSERT_EQ(s, t); - } -} - - - -TEST(Lua, Http) -{ - Orthanc::LuaContext lua; - -#if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1 - // The "http://www.orthanc-server.com/downloads/third-party/" does - // not automatically redirect to HTTPS, so we cas use it even if the - // OpenSSL/HTTPS support is disabled in curl - const std::string BASE = "http://www.orthanc-server.com/downloads/third-party/"; - -#if LUA_VERSION_NUM >= 502 - // Since Lua >= 5.2.0, the function "loadstring" has been replaced by "load" - lua.Execute("JSON = load(HttpGet('" + BASE + "JSON.lua')) ()"); -#else - lua.Execute("JSON = loadstring(HttpGet('" + BASE + "JSON.lua')) ()"); -#endif - - const std::string url(BASE + "Product.json"); -#endif - - std::string s; - lua.Execute(s, "print(HttpGet({}))"); - ASSERT_EQ("nil", Orthanc::Toolbox::StripSpaces(s)); - -#if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1 - lua.Execute(s, "print(string.len(HttpGet(\"" + url + "\")))"); - ASSERT_LE(100, boost::lexical_cast(Orthanc::Toolbox::StripSpaces(s))); - - // Parse a JSON file - lua.Execute(s, "print(JSON:decode(HttpGet(\"" + url + "\")) ['Product'])"); - ASSERT_EQ("OrthancClient", Orthanc::Toolbox::StripSpaces(s)); - -#if 0 - // This part of the test can only be executed if one instance of - // Orthanc is running on the localhost - - lua.Execute("modality = {}"); - lua.Execute("table.insert(modality, 'ORTHANC')"); - lua.Execute("table.insert(modality, 'localhost')"); - lua.Execute("table.insert(modality, 4242)"); - - lua.Execute(s, "print(HttpPost(\"http://localhost:8042/tools/execute-script\", \"print('hello world')\"))"); - ASSERT_EQ("hello world", Orthanc::Toolbox::StripSpaces(s)); - - lua.Execute(s, "print(JSON:decode(HttpPost(\"http://localhost:8042/tools/execute-script\", \"print('[10,42,1000]')\")) [2])"); - ASSERT_EQ("42", Orthanc::Toolbox::StripSpaces(s)); - - // Add/remove a modality with Lua - Json::Value v; - lua.Execute(s, "print(HttpGet('http://localhost:8042/modalities/lua'))"); - ASSERT_EQ(0, Orthanc::Toolbox::StripSpaces(s).size()); - lua.Execute(s, "print(HttpPut('http://localhost:8042/modalities/lua', JSON:encode(modality)))"); - lua.Execute(v, "print(HttpGet('http://localhost:8042/modalities/lua'))"); - ASSERT_TRUE(v.type() == Json::arrayValue); - lua.Execute(s, "print(HttpDelete('http://localhost:8042/modalities/lua'))"); - lua.Execute(s, "print(HttpGet('http://localhost:8042/modalities/lua'))"); - ASSERT_EQ(0, Orthanc::Toolbox::StripSpaces(s).size()); -#endif - -#endif -} diff -r 2a8bf0991be0 -r e241e5f3f088 OrthancServer/UnitTestsSources/MemoryCacheTests.cpp --- a/OrthancServer/UnitTestsSources/MemoryCacheTests.cpp Thu Jun 11 13:57:44 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,460 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeadersUnitTests.h" -#include "gtest/gtest.h" - -#include -#include -#include -#include - -#include "../../OrthancFramework/Sources/Cache/MemoryCache.h" -#include "../../OrthancFramework/Sources/Cache/MemoryStringCache.h" -#include "../../OrthancFramework/Sources/Cache/SharedArchive.h" -#include "../../OrthancFramework/Sources/IDynamicObject.h" -#include "../../OrthancFramework/Sources/Logging.h" -#include "../Sources/StorageCommitmentReports.h" - - -TEST(LRU, Basic) -{ - Orthanc::LeastRecentlyUsedIndex r; - - r.Add("d"); - r.Add("a"); - r.Add("c"); - r.Add("b"); - - r.MakeMostRecent("a"); - r.MakeMostRecent("d"); - r.MakeMostRecent("b"); - r.MakeMostRecent("c"); - r.MakeMostRecent("d"); - r.MakeMostRecent("c"); - - ASSERT_EQ("a", r.GetOldest()); - ASSERT_EQ("a", r.RemoveOldest()); - ASSERT_EQ("b", r.GetOldest()); - ASSERT_EQ("b", r.RemoveOldest()); - ASSERT_EQ("d", r.GetOldest()); - ASSERT_EQ("d", r.RemoveOldest()); - ASSERT_EQ("c", r.GetOldest()); - ASSERT_EQ("c", r.RemoveOldest()); - - ASSERT_TRUE(r.IsEmpty()); - - ASSERT_THROW(r.GetOldest(), Orthanc::OrthancException); - ASSERT_THROW(r.RemoveOldest(), Orthanc::OrthancException); -} - - -TEST(LRU, Payload) -{ - Orthanc::LeastRecentlyUsedIndex r; - - r.Add("a", 420); - r.Add("b", 421); - r.Add("c", 422); - r.Add("d", 423); - - r.MakeMostRecent("a"); - r.MakeMostRecent("d"); - r.MakeMostRecent("b"); - r.MakeMostRecent("c"); - r.MakeMostRecent("d"); - r.MakeMostRecent("c"); - - ASSERT_TRUE(r.Contains("b")); - ASSERT_EQ(421, r.Invalidate("b")); - ASSERT_FALSE(r.Contains("b")); - - int p; - ASSERT_TRUE(r.Contains("a", p)); ASSERT_EQ(420, p); - ASSERT_TRUE(r.Contains("c", p)); ASSERT_EQ(422, p); - ASSERT_TRUE(r.Contains("d", p)); ASSERT_EQ(423, p); - - ASSERT_EQ("a", r.GetOldest()); - ASSERT_EQ(420, r.GetOldestPayload()); - ASSERT_EQ("a", r.RemoveOldest(p)); ASSERT_EQ(420, p); - - ASSERT_EQ("d", r.GetOldest()); - ASSERT_EQ(423, r.GetOldestPayload()); - ASSERT_EQ("d", r.RemoveOldest(p)); ASSERT_EQ(423, p); - - ASSERT_EQ("c", r.GetOldest()); - ASSERT_EQ(422, r.GetOldestPayload()); - ASSERT_EQ("c", r.RemoveOldest(p)); ASSERT_EQ(422, p); - - ASSERT_TRUE(r.IsEmpty()); -} - - -TEST(LRU, PayloadUpdate) -{ - Orthanc::LeastRecentlyUsedIndex r; - - r.Add("a", 420); - r.Add("b", 421); - r.Add("d", 423); - - r.MakeMostRecent("a", 424); - r.MakeMostRecent("d", 421); - - ASSERT_EQ("b", r.GetOldest()); - ASSERT_EQ(421, r.GetOldestPayload()); - r.RemoveOldest(); - - ASSERT_EQ("a", r.GetOldest()); - ASSERT_EQ(424, r.GetOldestPayload()); - r.RemoveOldest(); - - ASSERT_EQ("d", r.GetOldest()); - ASSERT_EQ(421, r.GetOldestPayload()); - r.RemoveOldest(); - - ASSERT_TRUE(r.IsEmpty()); -} - - - -TEST(LRU, PayloadUpdateBis) -{ - Orthanc::LeastRecentlyUsedIndex r; - - r.AddOrMakeMostRecent("a", 420); - r.AddOrMakeMostRecent("b", 421); - r.AddOrMakeMostRecent("d", 423); - r.AddOrMakeMostRecent("a", 424); - r.AddOrMakeMostRecent("d", 421); - - ASSERT_EQ("b", r.GetOldest()); - ASSERT_EQ(421, r.GetOldestPayload()); - r.RemoveOldest(); - - ASSERT_EQ("a", r.GetOldest()); - ASSERT_EQ(424, r.GetOldestPayload()); - r.RemoveOldest(); - - ASSERT_EQ("d", r.GetOldest()); - ASSERT_EQ(421, r.GetOldestPayload()); - r.RemoveOldest(); - - ASSERT_TRUE(r.IsEmpty()); -} - -TEST(LRU, GetAllKeys) -{ - Orthanc::LeastRecentlyUsedIndex r; - std::vector keys; - - r.AddOrMakeMostRecent("a", 420); - r.GetAllKeys(keys); - - ASSERT_EQ(1u, keys.size()); - ASSERT_EQ("a", keys[0]); - - r.AddOrMakeMostRecent("b", 421); - r.GetAllKeys(keys); - - ASSERT_EQ(2u, keys.size()); - ASSERT_TRUE(std::find(keys.begin(), keys.end(),"a") != keys.end()); - ASSERT_TRUE(std::find(keys.begin(), keys.end(),"b") != keys.end()); -} - - - -namespace -{ - class Integer : public Orthanc::IDynamicObject - { - private: - std::string& log_; - int value_; - - public: - Integer(std::string& log, int v) : log_(log), value_(v) - { - } - - virtual ~Integer() ORTHANC_OVERRIDE - { - LOG(INFO) << "Removing cache entry for " << value_; - log_ += boost::lexical_cast(value_) + " "; - } - }; - - class IntegerProvider : public Orthanc::Deprecated::ICachePageProvider - { - public: - std::string log_; - - virtual Orthanc::IDynamicObject* Provide(const std::string& s) ORTHANC_OVERRIDE - { - LOG(INFO) << "Providing " << s; - return new Integer(log_, boost::lexical_cast(s)); - } - }; -} - - -TEST(MemoryCache, Basic) -{ - IntegerProvider provider; - - { - Orthanc::Deprecated::MemoryCache cache(provider, 3); - cache.Access("42"); // 42 -> exit - cache.Access("43"); // 43, 42 -> exit - cache.Access("45"); // 45, 43, 42 -> exit - cache.Access("42"); // 42, 45, 43 -> exit - cache.Access("43"); // 43, 42, 45 -> exit - cache.Access("47"); // 45 is removed; 47, 43, 42 -> exit - cache.Access("44"); // 42 is removed; 44, 47, 43 -> exit - cache.Access("42"); // 43 is removed; 42, 44, 47 -> exit - // Closing the cache: 47, 44, 42 are successively removed - } - - ASSERT_EQ("45 42 43 47 44 42 ", provider.log_); -} - - - - - -namespace -{ - class S : public Orthanc::IDynamicObject - { - private: - std::string value_; - - public: - S(const std::string& value) : value_(value) - { - } - - const std::string& GetValue() const - { - return value_; - } - }; -} - - -TEST(LRU, SharedArchive) -{ - std::string first, second; - Orthanc::SharedArchive a(3); - first = a.Add(new S("First item")); - second = a.Add(new S("Second item")); - - for (int i = 1; i < 100; i++) - { - a.Add(new S("Item " + boost::lexical_cast(i))); - - // Continuously protect the two first items - { - Orthanc::SharedArchive::Accessor accessor(a, first); - ASSERT_TRUE(accessor.IsValid()); - ASSERT_EQ("First item", dynamic_cast(accessor.GetItem()).GetValue()); - } - - { - Orthanc::SharedArchive::Accessor accessor(a, second); - ASSERT_TRUE(accessor.IsValid()); - ASSERT_EQ("Second item", dynamic_cast(accessor.GetItem()).GetValue()); - } - - { - Orthanc::SharedArchive::Accessor accessor(a, "nope"); - ASSERT_FALSE(accessor.IsValid()); - ASSERT_THROW(accessor.GetItem(), Orthanc::OrthancException); - } - } - - std::list i; - a.List(i); - - size_t count = 0; - for (std::list::const_iterator - it = i.begin(); it != i.end(); it++) - { - if (*it == first || - *it == second) - { - count++; - } - } - - ASSERT_EQ(2u, count); -} - - -TEST(MemoryStringCache, Basic) -{ - Orthanc::MemoryStringCache c; - ASSERT_THROW(c.SetMaximumSize(0), Orthanc::OrthancException); - - c.SetMaximumSize(2); - - std::string v; - ASSERT_FALSE(c.Fetch(v, "hello")); - - c.Add("hello", "a"); - ASSERT_TRUE(c.Fetch(v, "hello")); ASSERT_EQ("a", v); - ASSERT_FALSE(c.Fetch(v, "hello2")); - ASSERT_FALSE(c.Fetch(v, "hello3")); - - c.Add("hello2", "b"); - ASSERT_TRUE(c.Fetch(v, "hello")); ASSERT_EQ("a", v); - ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); - ASSERT_FALSE(c.Fetch(v, "hello3")); - - c.Add("hello3", "too large value"); - ASSERT_TRUE(c.Fetch(v, "hello")); ASSERT_EQ("a", v); - ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); - ASSERT_FALSE(c.Fetch(v, "hello3")); - - c.Add("hello3", "c"); - ASSERT_FALSE(c.Fetch(v, "hello")); // Recycled - ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); - ASSERT_TRUE(c.Fetch(v, "hello3")); ASSERT_EQ("c", v); -} - - -TEST(MemoryStringCache, Invalidate) -{ - Orthanc::MemoryStringCache c; - c.Add("hello", "a"); - c.Add("hello2", "b"); - - std::string v; - ASSERT_TRUE(c.Fetch(v, "hello")); ASSERT_EQ("a", v); - ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); - - c.Invalidate("hello"); - ASSERT_FALSE(c.Fetch(v, "hello")); - ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); -} - - -TEST(StorageCommitmentReports, Basic) -{ - Orthanc::StorageCommitmentReports reports(2); - ASSERT_EQ(2u, reports.GetMaxSize()); - - { - Orthanc::StorageCommitmentReports::Accessor accessor(reports, "nope"); - ASSERT_EQ("nope", accessor.GetTransactionUid()); - ASSERT_FALSE(accessor.IsValid()); - ASSERT_THROW(accessor.GetReport(), Orthanc::OrthancException); - } - - reports.Store("a", new Orthanc::StorageCommitmentReports::Report("aet_a")); - reports.Store("b", new Orthanc::StorageCommitmentReports::Report("aet_b")); - reports.Store("c", new Orthanc::StorageCommitmentReports::Report("aet_c")); - - { - Orthanc::StorageCommitmentReports::Accessor accessor(reports, "a"); - ASSERT_FALSE(accessor.IsValid()); - } - - { - Orthanc::StorageCommitmentReports::Accessor accessor(reports, "b"); - ASSERT_TRUE(accessor.IsValid()); - ASSERT_EQ("aet_b", accessor.GetReport().GetRemoteAet()); - ASSERT_EQ(Orthanc::StorageCommitmentReports::Report::Status_Pending, - accessor.GetReport().GetStatus()); - } - - { - Orthanc::StorageCommitmentReports::Accessor accessor(reports, "c"); - ASSERT_EQ("aet_c", accessor.GetReport().GetRemoteAet()); - ASSERT_TRUE(accessor.IsValid()); - } - - { - std::unique_ptr report - (new Orthanc::StorageCommitmentReports::Report("aet")); - report->AddSuccess("class1", "instance1"); - report->AddFailure("class2", "instance2", - Orthanc::StorageCommitmentFailureReason_ReferencedSOPClassNotSupported); - report->MarkAsComplete(); - reports.Store("a", report.release()); - } - - { - Orthanc::StorageCommitmentReports::Accessor accessor(reports, "a"); - ASSERT_TRUE(accessor.IsValid()); - ASSERT_EQ("aet", accessor.GetReport().GetRemoteAet()); - ASSERT_EQ(Orthanc::StorageCommitmentReports::Report::Status_Failure, - accessor.GetReport().GetStatus()); - } - - { - Orthanc::StorageCommitmentReports::Accessor accessor(reports, "b"); - ASSERT_FALSE(accessor.IsValid()); - } - - { - Orthanc::StorageCommitmentReports::Accessor accessor(reports, "c"); - ASSERT_TRUE(accessor.IsValid()); - } - - { - std::unique_ptr report - (new Orthanc::StorageCommitmentReports::Report("aet")); - report->AddSuccess("class1", "instance1"); - report->MarkAsComplete(); - reports.Store("a", report.release()); - } - - { - Orthanc::StorageCommitmentReports::Accessor accessor(reports, "a"); - ASSERT_TRUE(accessor.IsValid()); - ASSERT_EQ("aet", accessor.GetReport().GetRemoteAet()); - ASSERT_EQ(Orthanc::StorageCommitmentReports::Report::Status_Success, - accessor.GetReport().GetStatus()); - } - - { - Orthanc::StorageCommitmentReports::Accessor accessor(reports, "b"); - ASSERT_FALSE(accessor.IsValid()); - } - - { - Orthanc::StorageCommitmentReports::Accessor accessor(reports, "c"); - ASSERT_TRUE(accessor.IsValid()); - } -} diff -r 2a8bf0991be0 -r e241e5f3f088 OrthancServer/UnitTestsSources/UnitTestsMain.cpp --- a/OrthancServer/UnitTestsSources/UnitTestsMain.cpp Thu Jun 11 13:57:44 2020 +0200 +++ b/OrthancServer/UnitTestsSources/UnitTestsMain.cpp Thu Jun 11 14:12:07 2020 +0200 @@ -32,18 +32,20 @@ #include "PrecompiledHeadersUnitTests.h" -#include "../../OrthancFramework/Sources/EnumerationDictionary.h" #include "gtest/gtest.h" -#include "../../OrthancFramework/Sources/Logging.h" -#include "../../OrthancFramework/Sources/Toolbox.h" -#include "../../OrthancFramework/Sources/OrthancException.h" +#include + +#include "../../OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.h" +#include "../../OrthancFramework/Sources/DicomParsing/ParsedDicomFile.h" +#include "../../OrthancFramework/Sources/DicomParsing/ToDcmtkBridge.h" +#include "../../OrthancFramework/Sources/EnumerationDictionary.h" #include "../../OrthancFramework/Sources/Images/Image.h" #include "../../OrthancFramework/Sources/Images/PngWriter.h" -#include "../../OrthancFramework/Sources/DicomParsing/ParsedDicomFile.h" -#include "../../OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.h" -#include "../../OrthancFramework/Sources/DicomParsing/ToDcmtkBridge.h" +#include "../../OrthancFramework/Sources/Logging.h" +#include "../../OrthancFramework/Sources/OrthancException.h" +#include "../../OrthancFramework/Sources/Toolbox.h" #include "../Plugins/Engine/PluginsEnumerations.h" #include "../Sources/DicomInstanceToStore.h" @@ -51,6 +53,7 @@ #include "../Sources/OrthancInitialization.h" #include "../Sources/ServerEnumerations.h" #include "../Sources/ServerToolbox.h" +#include "../Sources/StorageCommitmentReports.h" #include @@ -411,6 +414,98 @@ } +TEST(StorageCommitmentReports, Basic) +{ + Orthanc::StorageCommitmentReports reports(2); + ASSERT_EQ(2u, reports.GetMaxSize()); + + { + Orthanc::StorageCommitmentReports::Accessor accessor(reports, "nope"); + ASSERT_EQ("nope", accessor.GetTransactionUid()); + ASSERT_FALSE(accessor.IsValid()); + ASSERT_THROW(accessor.GetReport(), Orthanc::OrthancException); + } + + reports.Store("a", new Orthanc::StorageCommitmentReports::Report("aet_a")); + reports.Store("b", new Orthanc::StorageCommitmentReports::Report("aet_b")); + reports.Store("c", new Orthanc::StorageCommitmentReports::Report("aet_c")); + + { + Orthanc::StorageCommitmentReports::Accessor accessor(reports, "a"); + ASSERT_FALSE(accessor.IsValid()); + } + + { + Orthanc::StorageCommitmentReports::Accessor accessor(reports, "b"); + ASSERT_TRUE(accessor.IsValid()); + ASSERT_EQ("aet_b", accessor.GetReport().GetRemoteAet()); + ASSERT_EQ(Orthanc::StorageCommitmentReports::Report::Status_Pending, + accessor.GetReport().GetStatus()); + } + + { + Orthanc::StorageCommitmentReports::Accessor accessor(reports, "c"); + ASSERT_EQ("aet_c", accessor.GetReport().GetRemoteAet()); + ASSERT_TRUE(accessor.IsValid()); + } + + { + std::unique_ptr report + (new Orthanc::StorageCommitmentReports::Report("aet")); + report->AddSuccess("class1", "instance1"); + report->AddFailure("class2", "instance2", + Orthanc::StorageCommitmentFailureReason_ReferencedSOPClassNotSupported); + report->MarkAsComplete(); + reports.Store("a", report.release()); + } + + { + Orthanc::StorageCommitmentReports::Accessor accessor(reports, "a"); + ASSERT_TRUE(accessor.IsValid()); + ASSERT_EQ("aet", accessor.GetReport().GetRemoteAet()); + ASSERT_EQ(Orthanc::StorageCommitmentReports::Report::Status_Failure, + accessor.GetReport().GetStatus()); + } + + { + Orthanc::StorageCommitmentReports::Accessor accessor(reports, "b"); + ASSERT_FALSE(accessor.IsValid()); + } + + { + Orthanc::StorageCommitmentReports::Accessor accessor(reports, "c"); + ASSERT_TRUE(accessor.IsValid()); + } + + { + std::unique_ptr report + (new Orthanc::StorageCommitmentReports::Report("aet")); + report->AddSuccess("class1", "instance1"); + report->MarkAsComplete(); + reports.Store("a", report.release()); + } + + { + Orthanc::StorageCommitmentReports::Accessor accessor(reports, "a"); + ASSERT_TRUE(accessor.IsValid()); + ASSERT_EQ("aet", accessor.GetReport().GetRemoteAet()); + ASSERT_EQ(Orthanc::StorageCommitmentReports::Report::Status_Success, + accessor.GetReport().GetStatus()); + } + + { + Orthanc::StorageCommitmentReports::Accessor accessor(reports, "b"); + ASSERT_FALSE(accessor.IsValid()); + } + + { + Orthanc::StorageCommitmentReports::Accessor accessor(reports, "c"); + ASSERT_TRUE(accessor.IsValid()); + } +} + + + int main(int argc, char **argv) { Logging::Initialize();