2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
20 * @brief Implementation file for test cases for shared data framework
26 #include <dpl/semaphore.h>
27 #include <dpl/test_runner.h>
28 #include <dpl/thread.h>
29 #include <dpl/controller.h>
30 #include <dpl/generic_event.h>
32 #include <dpl/shared_object.h>
33 #include <dpl/shared_property.h>
36 RUNNER_TEST_GROUP_INIT(DPL)
41 const SharedMemory::Key SHM_KEY = 12345;
42 const char* SEM_NAME = "/wrt_engine_shared_object_semaphore";
43 const size_t VERSION = 1;
45 const size_t MAX_THREADS = 10;
46 const size_t TEST_AND_SET_REPEATS = 100;
48 const size_t SHARED_PROP_REPEATS = 3;
50 const size_t SINGLETON_TEST_REPEATS = 3;
52 // maximum random delay in singleton listener addition/removal
53 const size_t MAX_SINGLETON_LISTENER_DELAY = 50;
55 const int SINGLE_PROCESS_REPEATS = 50;
58 * 5 seconds expected timeout for waitable events
59 * 30 seconds unexpected timeout for waitable events
60 * We don't want to block tests
62 const size_t EXPECTED_WAITABLE_TIMEOUT = 5*1000;
63 const size_t UNEXPECTED_WAITABLE_TIMEOUT = 30*1000;
65 bool g_enumTestCorrect = false;
66 bool g_enumTestIncorrect = false;
67 size_t g_delegateCalls = 0;
69 void Wait(DPL::WaitableEvent& event, bool expectedTimeout = false)
71 LogDebug("WaitForSingleHandle...");
72 DPL::WaitableHandleIndexList list = DPL::WaitForSingleHandle(
75 EXPECTED_WAITABLE_TIMEOUT : UNEXPECTED_WAITABLE_TIMEOUT);
76 if (list.size() == 0) {
77 LogDebug("...timeout.");
80 LogDebug("...signaled.");
84 if (expectedTimeout) {
85 RUNNER_ASSERT(list.size() == 0);
87 RUNNER_ASSERT(list.size() == 1);
94 SharedMemory::Remove(SHM_KEY);
96 Catch(SharedMemory::Exception::RemoveFailed) {
101 DPL::Semaphore::Remove(SEM_NAME);
103 Catch(DPL::Semaphore::Exception::RemoveFailed) {
108 typedef DPL::TypeListDecl<int, int, char, int[64]>::Type TestTypeList;
109 typedef DPL::TypeListDecl<int, int, char, int[63]>::Type TestTypeList2;
110 typedef DPL::TypeListDecl<int, int, char, int[63], int>::Type TestTypeList3;
112 typedef SharedObject<TestTypeList> TestSharedObject;
113 typedef SharedObject<TestTypeList2> TestSharedObject2;
114 typedef SharedObject<TestTypeList3> TestSharedObject3;
116 typedef std::shared_ptr<TestSharedObject> TestSharedObjectPtr;
118 const int INIT_EVENT = 0;
119 const int DESTROY_EVENT = 1;
121 int g_values[TestTypeList::Size];
124 * helper listening controller
126 template <typename SharedType>
127 class ListeningController :
128 public DPL::Controller<DPL::TypeListDecl<int>::Type>
131 explicit ListeningController(DPL::WaitableEvent* waitable);
132 ~ListeningController();
134 virtual void OnEventReceived(const int &event);
136 virtual void OnEvent(const int /*event*/) {}
139 std::shared_ptr<SharedType> m_so;
140 DPL::Thread m_thread;
141 DPL::WaitableEvent* m_waitable;
144 template <typename SharedType>
145 ListeningController<SharedType>::ListeningController(
146 DPL::WaitableEvent* waitable) :
151 SwitchToThread(&m_thread);
152 PostEvent(INIT_EVENT);
155 template <typename SharedType>
156 ListeningController<SharedType>::~ListeningController()
161 template <typename SharedType>
162 void ListeningController<SharedType>::OnEventReceived(const int& event)
164 if (event == INIT_EVENT) {
165 m_so = SharedObjectFactory<SharedType>::Create(SHM_KEY, SEM_NAME);
167 m_waitable->Signal();
169 else if (event == DESTROY_EVENT) {
170 LogDebug("Destroying shared object");
173 // deregister, destroy ad notify main thread
176 m_waitable->Signal();
184 typedef DPL::TypeListDecl<size_t, bool>::Type SharedTypeList;
186 class TestSharedObject4;
187 typedef std::shared_ptr<TestSharedObject4> TestSharedObject4Ptr;
189 class TestSharedObject4 : public SharedObject<SharedTypeList>
198 static TestSharedObject4Ptr Create()
200 return SharedObjectFactory<TestSharedObject4>::Create(SHM_KEY, SEM_NAME);
209 explicit TestSharedObject4(const std::string& semaphore) :
210 SharedObject<SharedTypeList>(semaphore)
217 SetPropertyInternal<BOOLEAN>(false);
219 friend class SharedObjectFactory<TestSharedObject4>;
224 } // anonymus namespace
226 //////////////////////////////////////////////
228 RUNNER_TEST(SharedMemory_002_AccessByType)
232 SharedData<TestTypeList> str;
235 str.Embedded<0, int>::value = 4;
236 str.Embedded<1, int>::value = 5;
237 str.Embedded<2, char>::value = 'd';
238 str.Embedded<3, int[64]>::value[0] = 1;
239 str.Embedded<3, int[64]>::value[1] = 20;
241 RUNNER_ASSERT((str.Embedded<0, int>::value) == 4);
242 RUNNER_ASSERT((str.Embedded<1, int>::value) == 5);
243 RUNNER_ASSERT((str.Embedded<2, char>::value) == 'd');
244 RUNNER_ASSERT((str.Embedded<3, int[64]>::value[0]) == 1);
245 RUNNER_ASSERT((str.Embedded<3, int[64]>::value[1]) == 20);
248 //////////////////////////////////////////////
250 RUNNER_TEST(SharedMemory_003_AccessByIndex)
254 SharedData<TestTypeList> str;
256 str.Embedded<0, TestTypeList::Element<0>::Type>::value = 4;
257 str.Embedded<1, TestTypeList::Element<1>::Type>::value = 5;
258 str.Embedded<2, TestTypeList::Element<2>::Type>::value = 'd';
259 str.Embedded<3, TestTypeList::Element<3>::Type>::value[0] = 1;
260 str.Embedded<3, TestTypeList::Element<3>::Type>::value[1] = 20;
263 (str.Embedded<0, TestTypeList::Element<0>::Type>::value) == 4);
265 (str.Embedded<1, TestTypeList::Element<1>::Type>::value) == 5);
267 (str.Embedded<2, TestTypeList::Element<2>::Type>::value) == 'd');
269 (str.Embedded<3, TestTypeList::Element<3>::Type>::value[0]) == 1);
271 (str.Embedded<3, TestTypeList::Element<3>::Type>::value[1]) == 20);
274 //////////////////////////////////////////////
276 RUNNER_TEST(SharedMemory_004_SimplifiedAccess)
280 SharedData<TestTypeList> str;
282 // access via PropertyRef
283 str.PropertyRef<1>() = 3;
284 RUNNER_ASSERT(str.PropertyRef<1>() == 3);
286 int (&array)[64] = str.PropertyRef<3>();
288 RUNNER_ASSERT(str.PropertyRef<3>()[0] == 2);
290 str.PropertyRef<3>()[1] = 19;
291 RUNNER_ASSERT(str.PropertyRef<3>()[1] == 19);
294 str.SHARED_PROPERTY(0) = 2;
295 RUNNER_ASSERT(str.SHARED_PROPERTY(0) == 2);
297 str.SHARED_PROPERTY(2) = 'c';
298 RUNNER_ASSERT(str.SHARED_PROPERTY(2) == 'c');
300 str.SHARED_PROPERTY(3)[2] = 10;
301 RUNNER_ASSERT(str.SHARED_PROPERTY(3)[2] == 10);
304 RUNNER_ASSERT((str.Embedded<0, int>::value) == 2);
305 RUNNER_ASSERT((str.Embedded<1, int>::value) == 3);
306 RUNNER_ASSERT((str.Embedded<2, char>::value) == 'c');
307 RUNNER_ASSERT((str.Embedded<3, int[64]>::value[0]) == 2);
308 RUNNER_ASSERT((str.Embedded<3, int[64]>::value[1]) == 19);
309 RUNNER_ASSERT((str.Embedded<3, int[64]>::value[2]) == 10);
312 //////////////////////////////////////////////
322 typedef std::shared_ptr<SharedMemory::Segment<SharedStruct> > SharedStructPtr;
324 RUNNER_TEST(SharedMemory_010_BaseShmTest)
328 typedef std::unique_ptr<SharedMemory> SharedMemoryPtr;
333 shm.Reset(SharedMemory::Create<SharedStruct>(SHM_KEY, false));
335 Catch (SharedMemory::Exception::NotFound) {
336 shm.Reset(SharedMemory::Create<SharedStruct>(SHM_KEY, true, true));
339 SharedStructPtr str = shm->Attach<SharedStruct>();
343 str->Data()->c = '3';
344 str->Data()->d[0] = 4;
345 str->Data()->d[1] = 5;
348 SharedMemoryPtr shm2;
350 shm2.Reset(SharedMemory::Create<SharedStruct>(SHM_KEY, false));
352 Catch (SharedMemory::Exception::NotFound) {
353 shm2.Reset(SharedMemory::Create<SharedStruct>(SHM_KEY, true, true));
356 SharedStructPtr str2 = shm2->Attach<SharedStruct>();
357 SharedStructPtr str3 = shm2->Attach<SharedStruct>();
359 RUNNER_ASSERT(str2->Data()->a == 1);
360 RUNNER_ASSERT(str2->Data()->b == 2);
361 RUNNER_ASSERT(str2->Data()->c == '3');
362 RUNNER_ASSERT(str2->Data()->d[0] == 4);
363 RUNNER_ASSERT(str2->Data()->d[1] == 5);
365 RUNNER_ASSERT(str3->Data()->a == 1);
366 RUNNER_ASSERT(str3->Data()->b == 2);
367 RUNNER_ASSERT(str3->Data()->c == '3');
368 RUNNER_ASSERT(str3->Data()->d[0] == 4);
369 RUNNER_ASSERT(str3->Data()->d[1] == 5);
372 str2->Data()->c = 'c';
373 str2->Data()->d[0] = 0;
374 RUNNER_ASSERT(str3->Data()->a == 1);
375 RUNNER_ASSERT(str3->Data()->b == 4);
376 RUNNER_ASSERT(str3->Data()->c == 'c');
377 RUNNER_ASSERT(str3->Data()->d[0] == 0);
378 RUNNER_ASSERT(str3->Data()->d[1] == 5);
381 //////////////////////////////////////////////
383 RUNNER_TEST(SharedMemory_020_SharedObjectTest)
387 typedef SharedObject<SharedTypeList> MySharedObj;
389 MySharedObj::Ptr so =
390 SharedObjectFactory<MySharedObj>::Create(SHM_KEY, SEM_NAME);
392 RUNNER_ASSERT((so->GetProperty<0, size_t>()) == 0);
393 so->SetProperty<0,size_t>(4);
394 RUNNER_ASSERT((so->GetProperty<0, size_t>()) == 4);
397 //////////////////////////////////////////////
399 class InitTestSharedObject : public TestSharedObject
402 explicit InitTestSharedObject(const std::string& semaphore) :
403 TestSharedObject(semaphore) {}
405 virtual void Init(); // from SharedObject
408 friend class SharedObjectFactory<InitTestSharedObject>;
411 void InitTestSharedObject::Init()
413 SetPropertyInternal<0>(1);
414 SetPropertyInternal<1>(2);
415 SetPropertyInternal<2>('c');
418 RUNNER_TEST(SharedMemory_021_InitTest)
420 RemoveIpcs(); // we need non existing shm
422 std::shared_ptr<InitTestSharedObject> sho =
423 SharedObjectFactory<InitTestSharedObject>::Create(
425 RUNNER_ASSERT((sho->GetProperty<0,int>()) == 1);
426 RUNNER_ASSERT((sho->GetProperty<1,int>()) == 2);
427 RUNNER_ASSERT((sho->GetProperty<2,char>()) == 'c');
430 //////////////////////////////////////////////
432 class VersionTestSO1 : public TestSharedObject
435 explicit VersionTestSO1(const std::string& semaphore) :
436 TestSharedObject(semaphore) {}
438 virtual SizeType GetVersion() const { return 1; } // from SharedObject
441 friend class SharedObjectFactory<VersionTestSO1>;
444 class VersionTestSO2 : public TestSharedObject
447 explicit VersionTestSO2(const std::string& semaphore) :
448 TestSharedObject(semaphore) {}
450 virtual SizeType GetVersion() const { return 2; } // from SharedObject
453 friend class SharedObjectFactory<VersionTestSO2>;
456 RUNNER_TEST(SharedMemory_022_InvalidVersionTest)
458 RemoveIpcs(); // we need non existing shm
460 std::shared_ptr<VersionTestSO1> sho =
461 SharedObjectFactory<VersionTestSO1>::Create(SHM_KEY, SEM_NAME);
464 std::shared_ptr<VersionTestSO2> sho2 =
465 SharedObjectFactory<VersionTestSO2>::Create(SHM_KEY, SEM_NAME);
467 RUNNER_ASSERT_MSG(false, "Invalid shm version has been accepted");
469 Catch(SharedObjectBase::Exception::InvalidVersion) {
474 //////////////////////////////////////////////
476 RUNNER_TEST(SharedMemory_023_InvalidSizeTest)
478 RemoveIpcs(); // we need non existing shm
480 typedef SharedObject<TestTypeList> SO1;
481 typedef SharedObject<TestTypeList2> SO2;
483 SO1::Ptr sho = SharedObjectFactory<SO1>::Create(SHM_KEY, SEM_NAME);
486 SO2::Ptr sho2 = SharedObjectFactory<SO2>::Create(SHM_KEY, SEM_NAME);
488 RUNNER_ASSERT_MSG(false, "Invalid shm size has been accepted");
490 Catch(SharedObjectBase::Exception::InvalidSize) {
495 //////////////////////////////////////////////
497 class MagicTestSO1 : public TestSharedObject
500 explicit MagicTestSO1(const std::string& semaphore) :
501 TestSharedObject(semaphore) {}
504 virtual MagicType GetMagicNumber() const { return 661; }
507 friend class SharedObjectFactory<MagicTestSO1>;
510 class MagicTestSO2 : public TestSharedObject
513 explicit MagicTestSO2(const std::string& semaphore) :
514 TestSharedObject(semaphore) {}
517 virtual MagicType GetMagicNumber() const { return 662; }
520 friend class SharedObjectFactory<MagicTestSO2>;
523 RUNNER_TEST(SharedMemory_024_InvalidMagicTest)
525 RemoveIpcs(); // we need non existing shm
527 std::shared_ptr<MagicTestSO1> sho =
528 SharedObjectFactory<MagicTestSO1>::Create(SHM_KEY, SEM_NAME);
531 std::shared_ptr<MagicTestSO2> sho2 =
532 SharedObjectFactory<MagicTestSO2>::Create(SHM_KEY, SEM_NAME);
534 RUNNER_ASSERT_MSG(false, "Invalid shm magic number has been accepted");
536 Catch(SharedObjectBase::Exception::InvalidMagicNumber) {
541 //////////////////////////////////////////////
544 * Listening shared object
546 class EnumTestSO1 : public TestSharedObject
549 void SetWaitable(DPL::WaitableEvent* waitable) { m_waitable = waitable; }
552 explicit EnumTestSO1(const std::string& semaphore) :
553 TestSharedObject(semaphore) {}
555 virtual void PropertyChanged(size_t propertyEnum);
558 friend class SharedObjectFactory<EnumTestSO1>;
560 DPL::WaitableEvent* m_waitable;
563 void EnumTestSO1::PropertyChanged(size_t propertyEnum)
565 if (propertyEnum == 1)
567 LogDebug("Property enum " << propertyEnum << " correctly set");
568 g_enumTestCorrect = true;
570 if (propertyEnum == 4)
572 // This is bad. We only have 4 types
573 LogError("Property enum " << propertyEnum << " should be skipped");
574 g_enumTestIncorrect = true;
576 // confirm property change notification
577 m_waitable->Signal();
580 class EnumController : public ListeningController<EnumTestSO1>
583 explicit EnumController(DPL::WaitableEvent* waitable) :
584 ListeningController<EnumTestSO1>(waitable) {}
586 virtual void OnEvent(const int event);
589 void EnumController::OnEvent(const int event)
591 if (event == INIT_EVENT) {
592 m_so->SetWaitable(m_waitable);
597 * Writing shared object with correct size but different number of types
599 class EnumTestSO2 : public TestSharedObject3
602 explicit EnumTestSO2(const std::string& semaphore) :
603 TestSharedObject3(semaphore) {}
606 friend class SharedObjectFactory<EnumTestSO2>;
609 RUNNER_TEST(SharedMemory_025_InvalidEnumTest)
611 RemoveIpcs(); // we need non existing shm
613 g_enumTestCorrect = false;
614 g_enumTestIncorrect = false;
616 DPL::WaitableEvent waitable;
618 // create listening controller and wait until it registers
619 EnumController controller(&waitable);
621 LogDebug("Listening controller created");
623 // create writing shared object
624 std::shared_ptr<EnumTestSO2> sho2 =
625 SharedObjectFactory<EnumTestSO2>::Create(SHM_KEY, SEM_NAME);
626 DPL::WaitableHandleIndexList list;
628 // write property and wait for confirmation
629 sho2->SetProperty<1>(2);
632 // write incorrect property and wait for confirmation
634 sho2->SetProperty<4>(2);
635 Wait(waitable, true);
637 // schedule listener deregistration and wait for confirmation
638 controller.PostEvent(DESTROY_EVENT);
642 RUNNER_ASSERT(g_enumTestCorrect == true);
643 RUNNER_ASSERT(g_enumTestIncorrect == false);
646 //////////////////////////////////////////////
648 class MultiThreadSO : public TestSharedObject
651 void TestAndSetProperty();
654 explicit MultiThreadSO(const std::string& semaphore) :
655 TestSharedObject(semaphore) {}
658 friend class SharedObjectFactory<MultiThreadSO>;
661 void MultiThreadSO::TestAndSetProperty()
663 ScopedFlaggedLock lock(*this);
665 int value = PropertyRef<0,int>();
666 DPL::Thread::MicroSleep(100);
667 SetPropertyInternal<0>(value+1);
670 class ShmController : public ListeningController<MultiThreadSO>
673 explicit ShmController(DPL::WaitableEvent* event) :
674 ListeningController<MultiThreadSO>(event), m_counter(0)
677 virtual void OnEventReceived(const int& event);
683 void ShmController::OnEventReceived(const int& event)
685 if (event == INIT_EVENT) {
686 m_so = SharedObjectFactory<MultiThreadSO>::Create(SHM_KEY, SEM_NAME);
689 else if (event == DESTROY_EVENT) {
690 LogDebug("Destroying shared object");
691 // deregister, destroy ad notify main thread
693 m_waitable->Signal();
695 else if (event == 2){
696 m_so->TestAndSetProperty();
698 if (m_counter >= TEST_AND_SET_REPEATS) {
699 LogDebug("Max tests reached. Finishing thread");
700 PostEvent(DESTROY_EVENT);
707 RUNNER_TEST(SharedMemory_030_MultithreadTest)
709 RemoveIpcs(); // we need non existing shm
711 typedef SharedObject<TestTypeList> SHO;
712 SHO::Ptr sho = SharedObjectFactory<SHO>::Create(SHM_KEY, SEM_NAME);
714 ShmController* controller[MAX_THREADS];
715 DPL::WaitableEvent finalEvent[MAX_THREADS];
717 for (size_t i=0;i<MAX_THREADS;++i) {
718 controller[i] = new ShmController(&finalEvent[i]);
721 for (size_t i=0;i<MAX_THREADS;++i) {
725 for (size_t i=0;i<MAX_THREADS;++i) {
726 delete controller[i];
727 controller[i] = NULL;
730 int value = sho->GetProperty<0,int>();
731 LogDebug("Final value is " << value << ", expected " <<
732 MAX_THREADS * TEST_AND_SET_REPEATS);
733 RUNNER_ASSERT(value == MAX_THREADS * TEST_AND_SET_REPEATS);
736 //////////////////////////////////////////////
738 class MyModel10: public DPL::Model
741 explicit MyModel10(const TestSharedObject4Ptr& shared_object)
742 : DPL::Model(), boolValue(this, shared_object) {}
744 SharedProperty<bool, TestSharedObject4::BOOLEAN, TestSharedObject4>
749 * Listening controller
751 class ShmController3: public ListeningController<TestSharedObject4>
754 explicit ShmController3(DPL::WaitableEvent* event) :
755 ListeningController<TestSharedObject4>(event)
758 virtual void OnEvent(const int event);
760 void OnValueChanged(const DPL::PropertyEvent<bool>& event);
763 typedef std::unique_ptr<MyModel10> MyModelPtr;
765 // model with property bound to shared object
769 void ShmController3::OnEvent(const int event)
771 if (event == INIT_EVENT) {
772 m_model.Reset(new MyModel10(m_so));
773 m_model->boolValue.AddListener(
774 DPL::FastDelegate<void (const DPL::PropertyEvent<bool>&)>(
776 &ShmController3::OnValueChanged));
777 } else if (event == DESTROY_EVENT) {
778 m_model->boolValue.RemoveListener(
779 DPL::FastDelegate<void (const DPL::PropertyEvent<bool>&)>(
781 &ShmController3::OnValueChanged));
786 void ShmController3::OnValueChanged(const DPL::PropertyEvent<bool>& event)
790 m_model->boolValue.Set(false);
792 LogError("Expected value = true, got false");
795 m_waitable->Signal();
798 RUNNER_TEST(SharedMemory_050_SharedProperty)
803 DPL::WaitableEvent waitable;
804 // listener controller
805 ShmController3 controller(&waitable);
808 TestSharedObject4Ptr sharedObject = TestSharedObject4::Create();
810 for (size_t i = 0; i < SHARED_PROP_REPEATS; ++i) {
811 sharedObject->SetProperty<TestSharedObject4::BOOLEAN>(true);
813 result = sharedObject->GetProperty<TestSharedObject4::BOOLEAN,
815 RUNNER_ASSERT(result == false);
817 controller.PostEvent(DESTROY_EVENT);
821 //////////////////////////////////////////////
823 class MyModel2: public DPL::Model
826 explicit MyModel2(const TestSharedObjectPtr& shared_object) :
827 counter(this, shared_object) {}
829 SharedProperty<int, 0, TestSharedObject> counter;
832 class SPController : public ListeningController<TestSharedObject>
835 explicit SPController(DPL::WaitableEvent* event) :
836 ListeningController<TestSharedObject>(event), m_repeats(1) {}
838 virtual void OnEvent(const int event);
840 void OnValueChanged1(const DPL::PropertyEvent<int>& event);
841 void OnValueChanged2(const DPL::PropertyEvent<int>& event);
844 std::unique_ptr<MyModel2> m_model1;
845 std::unique_ptr<MyModel2> m_model2;
848 std::shared_ptr<TestSharedObject> m_so2;
851 void SPController::OnEvent(const int event)
853 if (event == INIT_EVENT) {
854 m_so2 = SharedObjectFactory<TestSharedObject>::Create(SHM_KEY,
857 // create and register 2 models sharing the same property
858 m_model1.Reset(new MyModel2(m_so));
859 m_model2.Reset(new MyModel2(m_so2));
860 m_model1->counter.AddListener(
861 DPL::FastDelegate<void (const DPL::PropertyEvent<int>&)>(
863 &SPController::OnValueChanged1));
864 m_model2->counter.AddListener(
865 DPL::FastDelegate<void (const DPL::PropertyEvent<int>&)>(
867 &SPController::OnValueChanged2));
868 m_model1->counter.Set(1);
870 else if (event == DESTROY_EVENT) {
871 m_model1->counter.RemoveListener(
872 DPL::FastDelegate<void (const DPL::PropertyEvent<int>&)>(
874 &SPController::OnValueChanged1));
875 m_model2->counter.RemoveListener(
876 DPL::FastDelegate<void (const DPL::PropertyEvent<int>&)>(
878 &SPController::OnValueChanged2));
886 void SPController::OnValueChanged1(const DPL::PropertyEvent<int>& event)
888 if (m_repeats >= SINGLE_PROCESS_REPEATS) {
889 PostEvent(DESTROY_EVENT);
893 LogDebug("[1] Value changed to " << event.value);
895 m_model1->counter.Set(event.value+1);
898 void SPController::OnValueChanged2(const DPL::PropertyEvent<int>& event)
900 if (m_repeats >= SINGLE_PROCESS_REPEATS) {
901 PostEvent(DESTROY_EVENT);
905 LogDebug("[2] Value changed to " << event.value);
907 m_model2->counter.Set(event.value+1);
910 RUNNER_TEST(SharedMemory_060_SingleProcess)
914 DPL::WaitableEvent waitable;
915 SPController controller(&waitable);
916 TestSharedObjectPtr sho = SharedObjectFactory<TestSharedObject>::Create(
923 // wait for destruction
926 int value = sho->GetProperty<0,int>();
928 LogDebug("final value: " << value);
931 RUNNER_ASSERT(value == SINGLE_PROCESS_REPEATS);
934 //////////////////////////////////////////////
936 class ListenerTestController: public ListeningController<TestSharedObject>,
937 public ISharedObjectListener<0,int>,
938 public ISharedObjectListener<1,int>,
939 public ISharedObjectListener<2,char>,
940 public ISharedObjectListener<3,int[64]>
943 explicit ListenerTestController(DPL::WaitableEvent* event) :
944 ListeningController<TestSharedObject>(event) {}
946 ~ListenerTestController();
948 virtual void OnEvent(const int event);
950 virtual void ValueChanged(size_t propertyEnum,
952 const void* info = NULL);
953 virtual void ValueChanged(size_t propertyEnum,
955 const void* info = NULL);
956 virtual void ValueChanged(size_t propertyEnum,
957 const int(& value)[64],
958 const void* info = NULL);
961 ListenerTestController::~ListenerTestController()
964 void ListenerTestController::OnEvent(const int event)
966 if (event == INIT_EVENT) {
967 // add self as a listener to shared object
968 m_so->AddListener<0,int>(this);
969 m_so->AddListener<1,int>(this);
970 m_so->AddListener<2,char>(this);
971 m_so->AddListener<3,int[64]>(this);
973 else if (event == DESTROY_EVENT) {
974 // remove self from listener list
975 m_so->RemoveListener<0,int>(this);
976 m_so->RemoveListener<1,int>(this);
977 m_so->RemoveListener<2,char>(this);
978 m_so->RemoveListener<3,int[64]>(this);
982 void ListenerTestController::ValueChanged(size_t propertyEnum,
984 const void* /*info*/)
986 LogDebug("ValueChanged(int) " << propertyEnum << " " << value);
987 if ((propertyEnum == 0 && value == 1) || (propertyEnum == 1 && value == 2))
989 g_values[propertyEnum]++;
990 if (g_values[propertyEnum] == 3) {
991 m_waitable->Signal();
996 void ListenerTestController::ValueChanged(size_t propertyEnum,
998 const void* /*info*/)
1000 LogDebug("ValueChanged(char) " << propertyEnum << " " << value);
1001 if (propertyEnum == 2 && value == 'c')
1003 g_values[propertyEnum]++;
1004 if (g_values[propertyEnum] == 3) {
1005 m_waitable->Signal();
1010 void ListenerTestController::ValueChanged(size_t propertyEnum,
1011 const int(& value)[64],
1012 const void* /*info*/)
1014 LogDebug("ValueChanged(int[64]) " << propertyEnum << " " << value[5]);
1015 if (propertyEnum == 3 && value[5] == 5)
1017 g_values[propertyEnum]++;
1018 if (g_values[propertyEnum] == 3) {
1019 m_waitable->Signal();
1024 RUNNER_TEST(SharedMemory_070_SharedObjectListeners)
1028 // setup global flags
1029 for (size_t i=0;i<TestTypeList::Size;++i) {
1033 // create shared object
1034 TestSharedObjectPtr sho = SharedObjectFactory<TestSharedObject>::Create(
1037 // create 1st listener and wait for it
1038 DPL::WaitableEvent waitable;
1039 ListenerTestController c1(&waitable);
1042 // create 2nd listener and wait for it
1043 ListenerTestController c2(&waitable);
1046 // create 3rd listener and wait for it
1047 ListenerTestController c3(&waitable);
1050 // set properties and wait for result
1051 sho->SetProperty<0,int>(1);
1054 RUNNER_ASSERT(g_values[0] == 3);
1056 sho->SetProperty<1,int>(2);
1059 RUNNER_ASSERT(g_values[1] == 3);
1061 sho->SetProperty<2,char>('c');
1064 RUNNER_ASSERT(g_values[2] == 3);
1067 memset(array,64*sizeof(array[0]),0);
1069 sho->SetProperty<3,int[64]>(array);
1072 RUNNER_ASSERT(g_values[3] == 3);
1074 // finalize listeners
1075 c1.PostEvent(DESTROY_EVENT);
1078 c2.PostEvent(DESTROY_EVENT);
1081 c3.PostEvent(DESTROY_EVENT);
1085 //////////////////////////////////////////////
1088 * class simulating DB access
1090 class DAO : public DPL::Noncopyable
1093 DAO() : m_boolValue(false) {}
1095 void SetBoolValue(const bool& value) { m_boolValue = value; }
1097 bool GetBoolValue() const { return m_boolValue; }
1104 * Model with property having set delegate defined
1106 class MyModel3: public DPL::Model
1109 typedef SharedPropertyEx<bool,
1110 TestSharedObject4::BOOLEAN,
1111 TestSharedObject4> PropertyType;
1113 MyModel3(const TestSharedObject4Ptr& shared_object, DAO* dao) :
1116 PropertyType::SetDelegate(dao, &DAO::SetBoolValue))
1120 PropertyType boolValue;
1123 RUNNER_TEST(SharedMemory_090_SetPropertyDelegate)
1130 // create shared object
1131 TestSharedObject4Ptr sho = TestSharedObject4::Create();
1133 // set property but call dao delegate within semaphore
1134 sho->SetProperty<TestSharedObject4::BOOLEAN>(
1136 MyModel3::PropertyType::SetDelegate(&dao, &DAO::SetBoolValue));
1139 RUNNER_ASSERT(dao.GetBoolValue() == true);
1141 // check shared object value
1142 bool shoValue = sho->GetProperty<TestSharedObject4::BOOLEAN, bool>();
1143 RUNNER_ASSERT(shoValue == true);
1145 // try the same with shared property
1146 MyModel3 model(sho, &dao);
1149 model.boolValue.Set(false);
1152 RUNNER_ASSERT(dao.GetBoolValue() == false);
1155 shoValue = sho->GetProperty<TestSharedObject4::BOOLEAN, bool>();
1156 RUNNER_ASSERT(shoValue == false);
1158 // check property value
1159 RUNNER_ASSERT(model.boolValue.Get() == false);
1162 //////////////////////////////////////////////
1165 * Lazy initialization test shared object
1167 class LazySharedObject : public SharedObject<TestTypeList>
1170 explicit LazySharedObject(const std::string& semaphore) :
1171 SharedObject<TestTypeList>(semaphore)
1178 bool IsRead() const { return m_read; }
1181 friend class SharedObjectFactory<LazySharedObject>;
1186 void LazySharedObject::Init()
1188 SetPropertyInternal<0>(42);
1192 RUNNER_TEST(SharedMemory_100_LazyInit)
1196 typedef std::shared_ptr<LazySharedObject> LazySharedObjectPtr;
1198 // create shared object
1199 LazySharedObjectPtr sho = SharedObjectFactory<LazySharedObject>::Create(
1202 RUNNER_ASSERT(sho->IsRead() == false);
1204 // get property causing lazy init
1205 int value = sho->GetProperty<0, int>();
1207 RUNNER_ASSERT(sho->IsRead() == true);
1208 RUNNER_ASSERT(value == 42);
1210 // create another object
1211 LazySharedObjectPtr sho2 = SharedObjectFactory<LazySharedObject>::Create(
1214 RUNNER_ASSERT(sho2->IsRead() == false);
1216 // get property NOT causing lazy init
1217 value = sho2->GetProperty<0, int>();
1219 RUNNER_ASSERT(sho2->IsRead() == false);
1220 RUNNER_ASSERT(value == 42);
1222 // destroy both objects
1226 // create shared object
1227 LazySharedObjectPtr sho3 = SharedObjectFactory<LazySharedObject>::Create(
1230 RUNNER_ASSERT(sho3->IsRead() == false);
1232 // set property causing lazy init
1233 sho3->SetProperty<0>(43);
1234 value = sho3->GetProperty<0, int>();
1236 RUNNER_ASSERT(sho3->IsRead() == true);
1237 RUNNER_ASSERT(value == 43);
1241 //////////////////////////////////////////////
1243 bool SetCondition(const int& readValue, int& setValue);
1244 bool SetCondition(const int& readValue, int& setValue)
1246 LogDebug("Condition delegate called with read value = " << readValue <<
1247 " and set value = " << setValue);
1249 if (readValue > 3) {
1250 LogDebug("Condition is false");
1254 LogDebug("Condition is true");
1255 if (4 == setValue) {
1257 LogDebug("Changing set value to " << setValue);
1262 void SetDelegate(const int& readValue);
1263 void SetDelegate(const int& readValue)
1265 LogDebug("Set delegate called " << readValue);
1269 RUNNER_TEST(SharedMemory_120_ConditionalSet)
1273 TestSharedObjectPtr sho = SharedObjectFactory<TestSharedObject>::Create(
1277 g_delegateCalls = 0;
1279 RUNNER_ASSERT(0 == (sho->GetProperty<0,int>()));
1281 DPL::FastDelegate<bool (const int&, int&)> condition(&SetCondition);
1282 DPL::FastDelegate<void (const int&)> delegate(&SetDelegate);
1284 bool succeeded = false;
1286 succeeded = sho->ConditionalSetProperty<0>(-2, condition);
1288 RUNNER_ASSERT(succeeded);
1289 RUNNER_ASSERT(-2 == (sho->GetProperty<0,int>()));
1291 succeeded = sho->ConditionalSetProperty<0>(4, condition, delegate);
1293 RUNNER_ASSERT(succeeded);
1294 RUNNER_ASSERT(10 == (sho->GetProperty<0,int>()));
1295 RUNNER_ASSERT(1 == g_delegateCalls);
1297 succeeded = sho->ConditionalSetProperty<0>(5, condition);
1299 RUNNER_ASSERT(!succeeded);
1300 RUNNER_ASSERT(10 == (sho->GetProperty<0,int>()));
1302 succeeded = sho->ConditionalSetProperty<0>(666, condition, delegate);
1304 RUNNER_ASSERT(!succeeded);
1305 RUNNER_ASSERT(10 == (sho->GetProperty<0,int>()));
1306 RUNNER_ASSERT(1 == g_delegateCalls);
1309 //////////////////////////////////////////////
1312 * Shared object used by multiple threads as a singleton.
1314 class MTSharedObject : public SharedObject<TestTypeList>
1317 explicit MTSharedObject(const std::string& semaphore) :
1318 SharedObject<TestTypeList>(semaphore)
1325 friend class SharedObjectFactory<MTSharedObject>;
1328 typedef std::shared_ptr<MTSharedObject> MTSharedObjectPtr;
1330 void MTSharedObject::Clear()
1335 SetProperty<2>(static_cast<char>(0));
1336 SetProperty<3>(array);
1340 * Shared object singleton
1342 class SharedObjectSingleton
1345 static MTSharedObjectPtr Instance();
1346 static void Destroy();
1349 static MTSharedObjectPtr m_sho;
1350 static DPL::Mutex m_mutex;
1353 MTSharedObjectPtr SharedObjectSingleton::m_sho;
1354 DPL::Mutex SharedObjectSingleton::m_mutex;
1356 MTSharedObjectPtr SharedObjectSingleton::Instance()
1358 DPL::Mutex::ScopedLock lock(&m_mutex);
1360 m_sho = SharedObjectFactory<MTSharedObject>::Create(SHM_KEY, SEM_NAME);
1365 void SharedObjectSingleton::Destroy()
1367 DPL::Mutex::ScopedLock lock(&m_mutex);
1372 * Listening controller
1374 class ShmController4 : public ListeningController<MTSharedObject>,
1375 public ISharedObjectListener<0,int>,
1376 public ISharedObjectListener<1,int>,
1377 public ISharedObjectListener<2,char>,
1378 public ISharedObjectListener<3,int[64]>
1383 REMOVE_LISTENERS = 3,
1384 DESTROY_SINGLETON = 4
1387 explicit ShmController4(DPL::WaitableEvent* event) :
1388 ListeningController<MTSharedObject>(event)
1391 virtual void OnEventReceived(const int& event);
1393 virtual void ValueChanged(size_t propertyEnum,
1395 const void* info = NULL);
1396 virtual void ValueChanged(size_t propertyEnum,
1398 const void* info = NULL);
1399 virtual void ValueChanged(size_t propertyEnum,
1400 const int(& value)[64],
1401 const void* info = NULL);
1403 bool NotRegistered();
1411 void ShmController4::ValueChanged(size_t propertyEnum,
1413 const void* /*info*/)
1415 LogDebug("ValueChanged(int) " << propertyEnum << " " << value);
1416 if ((propertyEnum == 0 && value == 1) ||
1417 (propertyEnum == 1 && value == 11))
1419 m_waitable->Signal();
1423 void ShmController4::ValueChanged(size_t propertyEnum,
1425 const void* /*info*/)
1427 LogDebug("ValueChanged(char) " << propertyEnum << " " << value);
1428 if (propertyEnum == 2 && value == 'a') {
1429 m_waitable->Signal();
1433 void ShmController4::ValueChanged(size_t propertyEnum,
1434 const int(& value)[64],
1435 const void* /*info*/)
1437 LogDebug("ValueChanged(int[64]) " << propertyEnum << " " << value[5]);
1438 if (propertyEnum == 3 && value[0] == 0 && value[1] == 1 && value[2] == 2) {
1439 m_waitable->Signal();
1443 void ShmController4::Sleep()
1445 DPL::Thread::GetCurrentThread()->MiliSleep(
1446 rand() % MAX_SINGLETON_LISTENER_DELAY);
1449 void ShmController4::OnEventReceived(const int& event)
1453 m_so = SharedObjectSingleton::Instance();
1454 m_waitable->Signal();
1458 LogDebug("Destroying shared object");
1459 // deregister, destroy and notify main thread
1461 m_waitable->Signal();
1465 // add listener and notify
1466 m_so->AddListener<0,int>(this);
1468 m_so->AddListener<1,int>(this);
1470 m_so->AddListener<2,char>(this);
1472 m_so->AddListener<3,int[64]>(this);
1474 m_waitable->Signal();
1477 case REMOVE_LISTENERS:
1478 // remove listener and notify
1479 m_so->RemoveListener<0,int>(this);
1481 m_so->RemoveListener<1,int>(this);
1483 m_so->RemoveListener<2,char>(this);
1485 m_so->RemoveListener<3,int[64]>(this);
1487 m_waitable->Signal();
1490 case DESTROY_SINGLETON:
1491 SharedObjectSingleton::Destroy();
1492 m_waitable->Signal();
1496 LogError("Unsupported event received: " << event);
1500 void MultipleWait(DPL::WaitableEvent (& event)[MAX_THREADS]);
1501 void MultipleWait(DPL::WaitableEvent (& event)[MAX_THREADS])
1503 for (size_t i=0;i<MAX_THREADS;++i) {
1509 * Try to remove property listener. If there's no such listener an exception
1512 #define LISTENER_ASSERT(property) \
1514 singleton->RemoveListener<(property)>(controller[i]); \
1515 LogError("Controller " << i << " is still listening for property " \
1517 RUNNER_ASSERT_MSG(false, "No listeners expected"); \
1519 Catch (MTSharedObject::Exception::ListenerNotFound) { \
1520 RUNNER_ASSERT(true); \
1524 RUNNER_TEST(SharedMemory_130_SharedObjectSingleton)
1526 RemoveIpcs(); // we need non existing shm
1530 // writer shared object
1531 TestSharedObjectPtr sho = SharedObjectFactory<TestSharedObject>::Create(
1534 ShmController4* controller[MAX_THREADS];
1535 DPL::WaitableEvent waitable[MAX_THREADS];
1537 const int array[64] = {0,1,2};
1539 // Create and wait for notification. Make sure that the thread/controller 0
1541 LogInfo("Creating controllers");
1542 for (size_t i=0;i<MAX_THREADS;++i) {
1543 controller[i] = new ShmController4(&waitable[i]);
1547 // singleton will be created by thread/controller 0 by now
1548 MTSharedObjectPtr singleton = SharedObjectSingleton::Instance();
1550 for (size_t repeats = 0;repeats < SINGLETON_TEST_REPEATS;++repeats) {
1551 LogInfo("%%%%%%%%%%%%%%%%%%%%%");
1552 LogInfo("Iteration " << repeats+1 << " of " << SINGLETON_TEST_REPEATS);
1556 LogInfo("Adding listeners");
1557 for (size_t i=0;i<MAX_THREADS;++i) {
1558 controller[i]->PostEvent(ShmController4::ADD_LISTENERS);
1560 // wait for listeners
1561 MultipleWait(waitable);
1563 RUNNER_ASSERT((singleton->GetProperty<0,int>()) == 0);
1564 RUNNER_ASSERT((singleton->GetProperty<1,int>()) == 0);
1565 RUNNER_ASSERT((singleton->GetProperty<2,char>()) == 0);
1567 int checkArray[64] = {};
1568 singleton->GetProperty<3>(checkArray);
1569 RUNNER_ASSERT(checkArray[0] == 0);
1570 RUNNER_ASSERT(checkArray[1] == 0);
1571 RUNNER_ASSERT(checkArray[2] == 0);
1574 LogInfo("Setting property 0");
1575 sho->SetProperty<0>(1);
1576 // wait for confirmations
1577 MultipleWait(waitable);
1580 LogInfo("Setting property 1");
1581 sho->SetProperty<1>(11);
1582 // wait for confirmations
1583 MultipleWait(waitable);
1586 LogInfo("Setting property 2");
1587 sho->SetProperty<2>('a');
1588 // wait for confirmations
1589 MultipleWait(waitable);
1592 LogInfo("Setting property 3");
1593 sho->SetProperty<3>(array);
1594 // wait for confirmations
1595 MultipleWait(waitable);
1598 LogInfo("Removing listeners");
1599 for (size_t i=0;i<MAX_THREADS;++i) {
1600 controller[i]->PostEvent(ShmController4::REMOVE_LISTENERS);
1602 // wait for listeners
1603 MultipleWait(waitable);
1605 // check if listeners array is empty
1606 LogInfo("Checking listeners");
1607 for (size_t i=0;i<MAX_THREADS;++i) {
1614 RUNNER_ASSERT((singleton->GetProperty<0,int>()) == 1);
1615 RUNNER_ASSERT((singleton->GetProperty<1,int>()) == 11);
1616 RUNNER_ASSERT((singleton->GetProperty<2,char>()) == 'a');
1617 singleton->GetProperty<3>(checkArray);
1618 RUNNER_ASSERT(checkArray[0] == 0);
1619 RUNNER_ASSERT(checkArray[1] == 1);
1620 RUNNER_ASSERT(checkArray[2] == 2);
1625 // Destroy controllers and wait for confirmation. Make sure that
1626 // thread/controller 0 is destroyed in the end
1627 LogInfo("Destroying controllers");
1628 for (int i=MAX_THREADS-1;i>=0;--i) {
1629 controller[i]->PostEvent(DESTROY_EVENT);
1633 * Destroy singleton before thread that created it finishes.
1634 * This is to properly close all waitable handles opened by
1635 * SharedObject in thread 0.
1637 LogInfo("Destroying singleton");
1638 controller[i]->PostEvent(ShmController4::DESTROY_SINGLETON);
1641 delete controller[i];
1645 #undef LISTENER_ASSERT
1648 * test preconditions & postconditions:
1649 * - no existing shared memory with given SHM_KEY
1650 * - no existing semaphore of given SEM_NAME
1652 RUNNER_TEST(SharedMemory_001_Preconditions) {
1656 RUNNER_TEST(SharedMemory_999_Postconditions) {