Mercurial > hg > orthanc
diff UnitTests/ServerIndex.cpp @ 183:baada606da3c
databasewrapper
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 12 Nov 2012 14:52:30 +0100 |
parents | 93ff5babcaf8 |
children | d4e967d401d3 |
line wrap: on
line diff
--- a/UnitTests/ServerIndex.cpp Mon Nov 12 10:36:58 2012 +0100 +++ b/UnitTests/ServerIndex.cpp Mon Nov 12 14:52:30 2012 +0100 @@ -1,471 +1,48 @@ #include "gtest/gtest.h" +#include "../OrthancServer/DatabaseWrapper.h" + #include <ctype.h> - -#include "../Core/SQLite/Connection.h" -#include "../Core/Compression/ZlibCompressor.h" -#include "../Core/DicomFormat/DicomTag.h" -#include "../Core/DicomFormat/DicomArray.h" -#include "../Core/FileStorage.h" -#include "../OrthancCppClient/HttpClient.h" -#include "../Core/HttpServer/HttpHandler.h" -#include "../Core/OrthancException.h" -#include "../Core/Toolbox.h" -#include "../Core/Uuid.h" -#include "../OrthancServer/FromDcmtkBridge.h" -#include "../OrthancServer/OrthancInitialization.h" -#include "../OrthancServer/ServerIndex.h" -#include "EmbeddedResources.h" - #include <glog/logging.h> -#include <boost/thread.hpp> - - -namespace Orthanc -{ - enum CompressionType - { - CompressionType_None = 1, - CompressionType_Zlib = 2 - }; - - enum MetadataType - { - MetadataType_Instance_RemoteAet = 1, - MetadataType_Instance_IndexInSeries = 2, - MetadataType_Series_ExpectedNumberOfInstances = 3 - }; - - class IServerIndexListener - { - public: - virtual ~IServerIndexListener() - { - } - - virtual void SignalResourceDeleted(ResourceType type, - const std::string& parentPublicId) = 0; - - virtual void SignalFileDeleted(const std::string& fileUuid) = 0; - - }; - - namespace Internals - { - class SignalFileDeleted : public SQLite::IScalarFunction - { - private: - IServerIndexListener& listener_; - - public: - SignalFileDeleted(IServerIndexListener& listener) : - listener_(listener) - { - } - - virtual const char* GetName() const - { - return "SignalFileDeleted"; - } - - virtual unsigned int GetCardinality() const - { - return 1; - } - - virtual void Compute(SQLite::FunctionContext& context) - { - listener_.SignalFileDeleted(context.GetStringValue(0)); - } - }; - - class SignalResourceDeleted : public SQLite::IScalarFunction - { - public: - virtual const char* GetName() const - { - return "SignalResourceDeleted"; - } - - virtual unsigned int GetCardinality() const - { - return 2; - } - - virtual void Compute(SQLite::FunctionContext& context) - { - LOG(INFO) << "A resource has been removed, of type " - << context.GetIntValue(0) - << ", with parent " - << context.GetIntValue(1); - } - }; - } - class ServerIndexHelper - { - private: - IServerIndexListener& listener_; - SQLite::Connection db_; - boost::mutex mutex_; - - void Open(const std::string& path); - - public: - void SetGlobalProperty(const std::string& name, - const std::string& value) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT OR REPLACE INTO GlobalProperties VALUES(?, ?)"); - s.BindString(0, name); - s.BindString(1, value); - s.Run(); - } - - bool FindGlobalProperty(std::string& target, - const std::string& name) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT value FROM GlobalProperties WHERE name=?"); - s.BindString(0, name); - - if (!s.Step()) - { - return false; - } - else - { - target = s.ColumnString(0); - return true; - } - } - - std::string GetGlobalProperty(const std::string& name, - const std::string& defaultValue = "") - { - std::string s; - if (FindGlobalProperty(s, name)) - { - return s; - } - else - { - return defaultValue; - } - } - - int64_t CreateResource(const std::string& publicId, - ResourceType type) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO Resources VALUES(NULL, ?, ?, NULL)"); - s.BindInt(0, type); - s.BindString(1, publicId); - s.Run(); - return db_.GetLastInsertRowId(); - } - - bool FindResource(const std::string& publicId, - int64_t& id, - ResourceType& type) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT internalId, resourceType FROM Resources WHERE publicId=?"); - s.BindString(0, publicId); - - if (!s.Step()) - { - return false; - } - else - { - id = s.ColumnInt(0); - type = static_cast<ResourceType>(s.ColumnInt(1)); - - // Check whether there is a single resource with this public id - assert(!s.Step()); - - return true; - } - } - - void AttachChild(int64_t parent, - int64_t child) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "UPDATE Resources SET parentId = ? WHERE internalId = ?"); - s.BindInt(0, parent); - s.BindInt(1, child); - s.Run(); - } - - void DeleteResource(int64_t id) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM Resources WHERE internalId=?"); - s.BindInt(0, id); - s.Run(); - } - - void SetMetadata(int64_t id, - MetadataType type, - const std::string& value) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT OR REPLACE INTO Metadata VALUES(?, ?, ?)"); - s.BindInt(0, id); - s.BindInt(1, type); - s.BindString(2, value); - s.Run(); - } - - bool FindMetadata(std::string& target, - int64_t id, - MetadataType type) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT value FROM Metadata WHERE id=? AND type=?"); - s.BindInt(0, id); - s.BindInt(1, type); - - if (!s.Step()) - { - return false; - } - else - { - target = s.ColumnString(0); - return true; - } - } - - std::string GetMetadata(int64_t id, - MetadataType type, - const std::string& defaultValue = "") - { - std::string s; - if (FindMetadata(s, id, type)) - { - return s; - } - else - { - return defaultValue; - } - } +using namespace Orthanc; - void AttachFile(int64_t id, - const std::string& name, - const std::string& fileUuid, - size_t uncompressedSize, - CompressionType compressionType) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO AttachedFiles VALUES(?, ?, ?, ?, ?)"); - s.BindInt(0, id); - s.BindString(1, name); - s.BindString(2, fileUuid); - s.BindInt(3, uncompressedSize); - s.BindInt(4, compressionType); - s.Run(); - } - - bool FindFile(int64_t id, - const std::string& name, - std::string& fileUuid, - size_t& uncompressedSize, - CompressionType& compressionType) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT uuid, uncompressedSize, compressionType FROM AttachedFiles WHERE id=? AND name=?"); - s.BindInt(0, id); - s.BindString(1, name); - - if (!s.Step()) - { - return false; - } - else - { - fileUuid = s.ColumnString(0); - uncompressedSize = s.ColumnInt(1); - compressionType = static_cast<CompressionType>(s.ColumnInt(2)); - return true; - } - } - - void SetMainDicomTags(int64_t id, - const DicomMap& tags) - { - DicomArray flattened(tags); - for (size_t i = 0; i < flattened.GetSize(); i++) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO MainDicomTags VALUES(?, ?, ?, ?)"); - s.BindInt(0, id); - s.BindInt(1, flattened.GetElement(i).GetTag().GetGroup()); - s.BindInt(2, flattened.GetElement(i).GetTag().GetElement()); - s.BindString(3, flattened.GetElement(i).GetValue().AsString()); - s.Run(); - } - } - - void GetMainDicomTags(DicomMap& map, - int64_t id) - { - map.Clear(); - - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT * FROM MainDicomTags WHERE id=?"); - s.BindInt(0, id); - while (s.Step()) - { - map.SetValue(s.ColumnInt(1), - s.ColumnInt(2), - s.ColumnString(3)); - } - } - - - bool GetParentPublicId(std::string& result, - int64_t id) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT a.publicId FROM Resources AS a, Resources AS b " - "WHERE a.internalId = b.parentId AND b.internalId = ?"); - s.BindInt(0, id); - - if (s.Step()) - { - result = s.ColumnString(0); - return true; - } - else - { - return false; - } - } - - - void GetChildrenPublicId(std::list<std::string>& result, - int64_t id) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT a.publicId FROM Resources AS a, Resources AS b " - "WHERE a.parentId = b.internalId AND b.internalId = ?"); - s.BindInt(0, id); - - result.clear(); - - while (s.Step()) - { - result.push_back(s.ColumnString(0)); - } - } - - - int64_t GetTableRecordCount(const std::string& table) - { - char buf[128]; - sprintf(buf, "SELECT COUNT(*) FROM %s", table.c_str()); - SQLite::Statement s(db_, buf); - - assert(s.Step()); - int64_t c = s.ColumnInt(0); - assert(!s.Step()); - - return c; - } - - ServerIndexHelper(const std::string& path, - IServerIndexListener& listener) : - listener_(listener) - { - Open(path); - } - - ServerIndexHelper(IServerIndexListener& listener) : - listener_(listener) - { - Open(""); - } - }; - - - - void ServerIndexHelper::Open(const std::string& path) - { - if (path == "") - { - db_.OpenInMemory(); - } - else - { - db_.Open(path); - } - - if (!db_.DoesTableExist("GlobalProperties")) - { - LOG(INFO) << "Creating the database"; - std::string query; - EmbeddedResources::GetFileResource(query, EmbeddedResources::PREPARE_DATABASE_2); - db_.Execute(query); - } - - db_.Register(new Internals::SignalFileDeleted(listener_)); - db_.Register(new Internals::SignalResourceDeleted); - } - - +namespace +{ class ServerIndexListener : public IServerIndexListener { public: - virtual void SignalResourceDeleted(ResourceType type, - const std::string& parentPublicId) + std::set<std::string> deletedFiles_; + std::string ancestorId_; + ResourceType ancestorType_; + + void Reset() { + ancestorId_ = ""; + deletedFiles_.clear(); + } + + virtual void SignalRemainingAncestor(ResourceType type, + const std::string& publicId) + { + ancestorId_ = publicId; + ancestorType_ = type; } virtual void SignalFileDeleted(const std::string& fileUuid) { + deletedFiles_.insert(fileUuid); LOG(INFO) << "A file must be removed: " << fileUuid; } }; - - /* - class ServerIndex2 - { - private: - ServerIndexListener listener_; - ServerIndexHelper helper_; - - void Open(const std::string& storagePath) - { - boost::filesystem::path p = storagePath; - - try - { - boost::filesystem::create_directories(storagePath); - } - catch (boost::filesystem::filesystem_error) - { - } - - p /= "index"; - } - - public: - ServerIndexHelper(const std::string& storagePath) : - helper_(storagePath) - { - Open(storagePath); - } - }; - */ } - -using namespace Orthanc; - -TEST(ServerIndexHelper, Simple) +TEST(DatabaseWrapper, Simple) { ServerIndexListener listener; - /*Toolbox::RemoveFile("toto"); - ServerIndexHelper index("toto", listener);*/ - ServerIndexHelper index(listener); - - LOG(WARNING) << "ok"; + DatabaseWrapper index(listener); int64_t a[] = { index.CreateResource("a", ResourceType_Patient), // 0 @@ -514,10 +91,13 @@ ASSERT_EQ("e", l.front()); } + index.AttachFile(a[4], "_json", "my json file", 21, 42, CompressionType_Zlib); + index.AttachFile(a[4], "_dicom", "my dicom file", 42); + index.AttachFile(a[6], "_hello", "world", 44); + index.SetMetadata(a[4], MetadataType_Instance_RemoteAet, "PINNACLE"); - index.AttachFile(a[4], "_json", "my json file", 42, CompressionType_Zlib); - index.AttachFile(a[4], "_dicom", "my dicom file", 42, CompressionType_None); - index.SetMetadata(a[4], MetadataType_Instance_RemoteAet, "PINNACLE"); + ASSERT_EQ(21 + 42 + 44, index.GetTotalCompressedSize()); + ASSERT_EQ(42 + 42 + 44, index.GetTotalUncompressedSize()); DicomMap m; m.SetValue(0x0010, 0x0010, "PatientName"); @@ -541,23 +121,81 @@ ASSERT_EQ("World", index.GetGlobalProperty("Hello")); ASSERT_EQ("None", index.GetGlobalProperty("Hello2", "None")); - size_t us; + size_t us, cs; CompressionType ct; - ASSERT_TRUE(index.FindFile(a[4], "_json", s, us, ct)); + ASSERT_TRUE(index.FindFile(a[4], "_json", s, cs, us, ct)); ASSERT_EQ("my json file", s); + ASSERT_EQ(21, cs); ASSERT_EQ(42, us); ASSERT_EQ(CompressionType_Zlib, ct); + ASSERT_EQ(0, listener.deletedFiles_.size()); ASSERT_EQ(7, index.GetTableRecordCount("Resources")); - ASSERT_EQ(2, index.GetTableRecordCount("AttachedFiles")); + ASSERT_EQ(3, index.GetTableRecordCount("AttachedFiles")); ASSERT_EQ(1, index.GetTableRecordCount("Metadata")); ASSERT_EQ(1, index.GetTableRecordCount("MainDicomTags")); index.DeleteResource(a[0]); + + ASSERT_EQ(2, listener.deletedFiles_.size()); + ASSERT_NE(listener.deletedFiles_.end(), listener.deletedFiles_.find("my json file")); + ASSERT_NE(listener.deletedFiles_.end(), listener.deletedFiles_.find("my dicom file")); + ASSERT_EQ(2, index.GetTableRecordCount("Resources")); ASSERT_EQ(0, index.GetTableRecordCount("Metadata")); + ASSERT_EQ(1, index.GetTableRecordCount("AttachedFiles")); + ASSERT_EQ(0, index.GetTableRecordCount("MainDicomTags")); + index.DeleteResource(a[5]); + ASSERT_EQ(0, index.GetTableRecordCount("Resources")); ASSERT_EQ(0, index.GetTableRecordCount("AttachedFiles")); - ASSERT_EQ(0, index.GetTableRecordCount("MainDicomTags")); + ASSERT_EQ(1, index.GetTableRecordCount("GlobalProperties")); + + ASSERT_EQ(3, listener.deletedFiles_.size()); + ASSERT_NE(listener.deletedFiles_.end(), listener.deletedFiles_.find("world")); +} + + + + +TEST(DatabaseWrapper, Upward) +{ + ServerIndexListener listener; + DatabaseWrapper index(listener); + + int64_t a[] = { + index.CreateResource("a", ResourceType_Patient), // 0 + index.CreateResource("b", ResourceType_Study), // 1 + index.CreateResource("c", ResourceType_Series), // 2 + index.CreateResource("d", ResourceType_Instance), // 3 + index.CreateResource("e", ResourceType_Instance), // 4 + index.CreateResource("f", ResourceType_Study), // 5 + index.CreateResource("g", ResourceType_Series), // 6 + index.CreateResource("h", ResourceType_Series) // 7 + }; + + index.AttachChild(a[0], a[1]); + index.AttachChild(a[1], a[2]); + index.AttachChild(a[2], a[3]); + index.AttachChild(a[2], a[4]); + index.AttachChild(a[1], a[6]); + index.AttachChild(a[0], a[5]); + index.AttachChild(a[5], a[7]); + + listener.Reset(); + index.DeleteResource(a[3]); + ASSERT_EQ("c", listener.ancestorId_); + ASSERT_EQ(ResourceType_Series, listener.ancestorType_); + + listener.Reset(); + index.DeleteResource(a[4]); + ASSERT_EQ("b", listener.ancestorId_); + ASSERT_EQ(ResourceType_Study, listener.ancestorType_); + + listener.Reset(); + index.DeleteResource(a[7]); + ASSERT_EQ("a", listener.ancestorId_); + ASSERT_EQ(ResourceType_Patient, listener.ancestorType_); + + listener.Reset(); index.DeleteResource(a[6]); - ASSERT_EQ(0, index.GetTableRecordCount("Resources")); - ASSERT_EQ(1, index.GetTableRecordCount("GlobalProperties")); + ASSERT_EQ("", listener.ancestorId_); // No more ancestor }