changeset 7121:cf1f10a22505

added test DataSource.SequentialReader
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 14 Aug 2026 14:57:42 +0200
parents 0a8b8890f26d
children 22a427e39060
files OrthancFramework/Sources/DataSource/DataSourceSequentialReader.h OrthancFramework/UnitTestsSources/DataSourceTests.cpp
diffstat 2 files changed, 73 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancFramework/Sources/DataSource/DataSourceSequentialReader.h	Fri Aug 14 13:28:37 2026 +0200
+++ b/OrthancFramework/Sources/DataSource/DataSourceSequentialReader.h	Fri Aug 14 14:57:42 2026 +0200
@@ -101,8 +101,10 @@
       {
       }
 
-      // Note that "source" will never contain user data, those are handled at the level above
-      virtual IDynamicObject* Apply(DataSourceAnswer::Item* source) = 0;
+      // IMPORTANT: The disconnector is in charge of deleting the "source" object.
+      // If "source" is not properly destructed, deadlock will occur.
+      // Note that "source" will never contain user data, those are handled at the level above.
+      virtual IDynamicObject* Apply(DataSourceAnswer::Item* source /* takes ownership */) = 0;
     };
 
 
@@ -126,6 +128,7 @@
     void FillWindow();
 
   public:
+    // IMPORTANT: The "executor" must not be the same as that of "reader", otherwise deadlock will occur
     DataSourceSequentialReader(const boost::shared_ptr<IExecutorService>& executor,
                                const boost::shared_ptr<DataSourceReader>& reader,
                                IValueDisconnector* disconnector /* takes ownership */,
--- a/OrthancFramework/UnitTestsSources/DataSourceTests.cpp	Fri Aug 14 13:28:37 2026 +0200
+++ b/OrthancFramework/UnitTestsSources/DataSourceTests.cpp	Fri Aug 14 14:57:42 2026 +0200
@@ -28,6 +28,7 @@
 #endif
 
 #include "../Sources/DataSource/DataSourceReader.h"
+#include "../Sources/DataSource/DataSourceSequentialReader.h"
 #include "../Sources/MultiThreading/SequentialExecutorService.h"
 #include "../Sources/MultiThreading/ThreadPool.h"
 #include "../Sources/OrthancException.h"
@@ -128,10 +129,32 @@
       return 10;
     }
   };
+
+
+  class IntegerDisconnector : public DataSourceSequentialReader::IValueDisconnector
+  {
+  public:
+    virtual IDynamicObject* Apply(DataSourceAnswer::Item* source) ORTHANC_OVERRIDE
+    {
+      std::unique_ptr<DataSourceAnswer::Item> protection(source);
+
+      const IntegerIdentifier& id = dynamic_cast<const IntegerIdentifier&>(source->GetId());
+      const SingleValueObject<int>& value = dynamic_cast<const SingleValueObject<int>&>(*source->GetValue());
+
+      if (id.GetValue() != value.GetValue())
+      {
+        throw OrthancException(ErrorCode_InternalError);
+      }
+      else
+      {
+        return new SingleValueObject<int>(value.GetValue());
+      }
+    }
+  };
 }
 
 
-TEST(DataSource, Test)
+TEST(DataSource, ParallelReader)
 {
   boost::shared_ptr<ThreadPool> service(new ThreadPool);
   service->SetThreadsCount(4);
@@ -210,3 +233,47 @@
     }
   }
 }
+
+
+TEST(DataSource, SequentialReader)
+{
+  boost::shared_ptr<ThreadPool> serviceSource(new ThreadPool);
+  serviceSource->SetLoggingThreadName("SOURCE");
+  serviceSource->SetThreadsCount(4);
+  serviceSource->SetDequeueTimeout(5);  // Stop the test fast
+  serviceSource->Start();
+
+  boost::shared_ptr<ThreadPool> serviceSequential(new ThreadPool);
+  serviceSequential->SetLoggingThreadName("SEQ");
+  serviceSequential->SetThreadsCount(1);
+  serviceSequential->SetDequeueTimeout(5);  // Stop the test fast
+  serviceSequential->Start();
+
+  {
+    boost::shared_ptr<DataSourceReader> reader(new DataSourceReader(serviceSource, new IntegerDataSource));
+
+    DataSourceSequentialReader seq(serviceSequential, reader, new IntegerDisconnector, 4, 0);
+
+    for (int i = 0; i < 10; i++)
+    {
+      seq.Submit(new IntegerIdentifier(false, 10 + i, 10 - i));  // Produces out-of-order values
+    }
+
+    seq.Start();
+    ASSERT_THROW(seq.Submit(new IntegerIdentifier(false, 42, 0)), OrthancException);
+
+    for (int i = 0; i < 10; i++)
+    {
+      ASSERT_TRUE(seq.HasNext());
+
+      std::unique_ptr<DataSourceSequentialReader::Item> item(seq.Next());
+      ASSERT_TRUE(item.get() != NULL);
+
+      const SingleValueObject<int>& value = dynamic_cast<const SingleValueObject<int>&>(item->GetValue());
+      ASSERT_EQ(10 + i, value.GetValue());
+    }
+
+    ASSERT_FALSE(seq.HasNext());
+    ASSERT_THROW(seq.Next(), OrthancException);
+  }
+}