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
 }