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.");
79 LogDebug("...signaled.");
83 if (expectedTimeout) {
84 RUNNER_ASSERT(list.size() == 0);
86 RUNNER_ASSERT(list.size() == 1);
93 SharedMemory::Remove(SHM_KEY);
95 Catch(SharedMemory::Exception::RemoveFailed) {
100 DPL::Semaphore::Remove(SEM_NAME);
102 Catch(DPL::Semaphore::Exception::RemoveFailed) {
107 typedef DPL::TypeListDecl<int, int, char, int[64]>::Type TestTypeList;
108 typedef DPL::TypeListDecl<int, int, char, int[63]>::Type TestTypeList2;
109 typedef DPL::TypeListDecl<int, int, char, int[63], int>::Type TestTypeList3;
111 typedef SharedObject<TestTypeList> TestSharedObject;
112 typedef SharedObject<TestTypeList2> TestSharedObject2;
113 typedef SharedObject<TestTypeList3> TestSharedObject3;
115 typedef std::shared_ptr<TestSharedObject> TestSharedObjectPtr;
117 const int INIT_EVENT = 0;
118 const int DESTROY_EVENT = 1;
120 int g_values[TestTypeList::Size];
123 * helper listening controller
125 template <typename SharedType>
126 class ListeningController :
127 public DPL::Controller<DPL::TypeListDecl<int>::Type>
130 explicit ListeningController(DPL::WaitableEvent* waitable);
131 ~ListeningController();
133 virtual void OnEventReceived(const int &event);
135 virtual void OnEvent(const int /*event*/) {}
138 std::shared_ptr<SharedType> m_so;
139 DPL::Thread m_thread;
140 DPL::WaitableEvent* m_waitable;
143 template <typename SharedType>
144 ListeningController<SharedType>::ListeningController(
145 DPL::WaitableEvent* waitable) :
150 SwitchToThread(&m_thread);
151 PostEvent(INIT_EVENT);
154 template <typename SharedType>
155 ListeningController<SharedType>::~ListeningController()
160 template <typename SharedType>
161 void ListeningController<SharedType>::OnEventReceived(const int& event)
163 if (event == INIT_EVENT) {
164 m_so = SharedObjectFactory<SharedType>::Create(SHM_KEY, SEM_NAME);
166 m_waitable->Signal();
167 } else if (event == DESTROY_EVENT) {
168 LogDebug("Destroying shared object");
171 // deregister, destroy ad notify main thread
174 m_waitable->Signal();
181 typedef DPL::TypeListDecl<size_t, bool>::Type SharedTypeList;
183 class TestSharedObject4;
184 typedef std::shared_ptr<TestSharedObject4> TestSharedObject4Ptr;
186 class TestSharedObject4 : public SharedObject<SharedTypeList>
195 static TestSharedObject4Ptr Create()
197 return SharedObjectFactory<TestSharedObject4>::Create(SHM_KEY, SEM_NAME);
206 explicit TestSharedObject4(const std::string& semaphore) :
207 SharedObject<SharedTypeList>(semaphore)
213 SetPropertyInternal<BOOLEAN>(false);
215 friend class SharedObjectFactory<TestSharedObject4>;
217 } // anonymus namespace
219 //////////////////////////////////////////////
221 RUNNER_TEST(SharedMemory_002_AccessByType)
225 SharedData<TestTypeList> str;
228 str.Embedded<0, int>::value = 4;
229 str.Embedded<1, int>::value = 5;
230 str.Embedded<2, char>::value = 'd';
231 str.Embedded<3, int[64]>::value[0] = 1;
232 str.Embedded<3, int[64]>::value[1] = 20;
234 RUNNER_ASSERT((str.Embedded<0, int>::value) == 4);
235 RUNNER_ASSERT((str.Embedded<1, int>::value) == 5);
236 RUNNER_ASSERT((str.Embedded<2, char>::value) == 'd');
237 RUNNER_ASSERT((str.Embedded<3, int[64]>::value[0]) == 1);
238 RUNNER_ASSERT((str.Embedded<3, int[64]>::value[1]) == 20);
241 //////////////////////////////////////////////
243 RUNNER_TEST(SharedMemory_003_AccessByIndex)
247 SharedData<TestTypeList> str;
249 str.Embedded<0, TestTypeList::Element<0>::Type>::value = 4;
250 str.Embedded<1, TestTypeList::Element<1>::Type>::value = 5;
251 str.Embedded<2, TestTypeList::Element<2>::Type>::value = 'd';
252 str.Embedded<3, TestTypeList::Element<3>::Type>::value[0] = 1;
253 str.Embedded<3, TestTypeList::Element<3>::Type>::value[1] = 20;
256 (str.Embedded<0, TestTypeList::Element<0>::Type>::value) == 4);
258 (str.Embedded<1, TestTypeList::Element<1>::Type>::value) == 5);
260 (str.Embedded<2, TestTypeList::Element<2>::Type>::value) == 'd');
262 (str.Embedded<3, TestTypeList::Element<3>::Type>::value[0]) == 1);
264 (str.Embedded<3, TestTypeList::Element<3>::Type>::value[1]) == 20);
267 //////////////////////////////////////////////
269 RUNNER_TEST(SharedMemory_004_SimplifiedAccess)
273 SharedData<TestTypeList> str;
275 // access via PropertyRef
276 str.PropertyRef<1>() = 3;
277 RUNNER_ASSERT(str.PropertyRef<1>() == 3);
279 int (&array)[64] = str.PropertyRef<3>();
281 RUNNER_ASSERT(str.PropertyRef<3>()[0] == 2);
283 str.PropertyRef<3>()[1] = 19;
284 RUNNER_ASSERT(str.PropertyRef<3>()[1] == 19);
287 str.SHARED_PROPERTY(0) = 2;
288 RUNNER_ASSERT(str.SHARED_PROPERTY(0) == 2);
290 str.SHARED_PROPERTY(2) = 'c';
291 RUNNER_ASSERT(str.SHARED_PROPERTY(2) == 'c');
293 str.SHARED_PROPERTY(3)[2] = 10;
294 RUNNER_ASSERT(str.SHARED_PROPERTY(3)[2] == 10);
297 RUNNER_ASSERT((str.Embedded<0, int>::value) == 2);
298 RUNNER_ASSERT((str.Embedded<1, int>::value) == 3);
299 RUNNER_ASSERT((str.Embedded<2, char>::value) == 'c');
300 RUNNER_ASSERT((str.Embedded<3, int[64]>::value[0]) == 2);
301 RUNNER_ASSERT((str.Embedded<3, int[64]>::value[1]) == 19);
302 RUNNER_ASSERT((str.Embedded<3, int[64]>::value[2]) == 10);
305 //////////////////////////////////////////////
315 typedef std::shared_ptr<SharedMemory::Segment<SharedStruct> > SharedStructPtr;
317 RUNNER_TEST(SharedMemory_010_BaseShmTest)
321 typedef std::unique_ptr<SharedMemory> SharedMemoryPtr;
326 shm.Reset(SharedMemory::Create<SharedStruct>(SHM_KEY, false));
328 Catch(SharedMemory::Exception::NotFound) {
329 shm.Reset(SharedMemory::Create<SharedStruct>(SHM_KEY, true, true));
332 SharedStructPtr str = shm->Attach<SharedStruct>();
336 str->Data()->c = '3';
337 str->Data()->d[0] = 4;
338 str->Data()->d[1] = 5;
341 SharedMemoryPtr shm2;
343 shm2.Reset(SharedMemory::Create<SharedStruct>(SHM_KEY, false));
345 Catch(SharedMemory::Exception::NotFound) {
346 shm2.Reset(SharedMemory::Create<SharedStruct>(SHM_KEY, true, true));
349 SharedStructPtr str2 = shm2->Attach<SharedStruct>();
350 SharedStructPtr str3 = shm2->Attach<SharedStruct>();
352 RUNNER_ASSERT(str2->Data()->a == 1);
353 RUNNER_ASSERT(str2->Data()->b == 2);
354 RUNNER_ASSERT(str2->Data()->c == '3');
355 RUNNER_ASSERT(str2->Data()->d[0] == 4);
356 RUNNER_ASSERT(str2->Data()->d[1] == 5);
358 RUNNER_ASSERT(str3->Data()->a == 1);
359 RUNNER_ASSERT(str3->Data()->b == 2);
360 RUNNER_ASSERT(str3->Data()->c == '3');
361 RUNNER_ASSERT(str3->Data()->d[0] == 4);
362 RUNNER_ASSERT(str3->Data()->d[1] == 5);
365 str2->Data()->c = 'c';
366 str2->Data()->d[0] = 0;
367 RUNNER_ASSERT(str3->Data()->a == 1);
368 RUNNER_ASSERT(str3->Data()->b == 4);
369 RUNNER_ASSERT(str3->Data()->c == 'c');
370 RUNNER_ASSERT(str3->Data()->d[0] == 0);
371 RUNNER_ASSERT(str3->Data()->d[1] == 5);
374 //////////////////////////////////////////////
376 RUNNER_TEST(SharedMemory_020_SharedObjectTest)
380 typedef SharedObject<SharedTypeList> MySharedObj;
382 MySharedObj::Ptr so =
383 SharedObjectFactory<MySharedObj>::Create(SHM_KEY, SEM_NAME);
385 RUNNER_ASSERT((so->GetProperty<0, size_t>()) == 0);
386 so->SetProperty<0, size_t>(4);
387 RUNNER_ASSERT((so->GetProperty<0, size_t>()) == 4);
390 //////////////////////////////////////////////
392 class InitTestSharedObject : public TestSharedObject
395 explicit InitTestSharedObject(const std::string& semaphore) :
396 TestSharedObject(semaphore) {}
398 virtual void Init(); // from SharedObject
401 friend class SharedObjectFactory<InitTestSharedObject>;
404 void InitTestSharedObject::Init()
406 SetPropertyInternal<0>(1);
407 SetPropertyInternal<1>(2);
408 SetPropertyInternal<2>('c');
411 RUNNER_TEST(SharedMemory_021_InitTest)
413 RemoveIpcs(); // we need non existing shm
415 std::shared_ptr<InitTestSharedObject> sho =
416 SharedObjectFactory<InitTestSharedObject>::Create(
418 RUNNER_ASSERT((sho->GetProperty<0, int>()) == 1);
419 RUNNER_ASSERT((sho->GetProperty<1, int>()) == 2);
420 RUNNER_ASSERT((sho->GetProperty<2, char>()) == 'c');
423 //////////////////////////////////////////////
425 class VersionTestSO1 : public TestSharedObject
428 explicit VersionTestSO1(const std::string& semaphore) :
429 TestSharedObject(semaphore) {}
431 virtual SizeType GetVersion() const
434 } // from SharedObject
437 friend class SharedObjectFactory<VersionTestSO1>;
440 class VersionTestSO2 : public TestSharedObject
443 explicit VersionTestSO2(const std::string& semaphore) :
444 TestSharedObject(semaphore) {}
446 virtual SizeType GetVersion() const
449 } // from SharedObject
452 friend class SharedObjectFactory<VersionTestSO2>;
455 RUNNER_TEST(SharedMemory_022_InvalidVersionTest)
457 RemoveIpcs(); // we need non existing shm
459 std::shared_ptr<VersionTestSO1> sho =
460 SharedObjectFactory<VersionTestSO1>::Create(SHM_KEY, SEM_NAME);
463 std::shared_ptr<VersionTestSO2> sho2 =
464 SharedObjectFactory<VersionTestSO2>::Create(SHM_KEY, SEM_NAME);
466 RUNNER_ASSERT_MSG(false, "Invalid shm version has been accepted");
468 Catch(SharedObjectBase::Exception::InvalidVersion) {
473 //////////////////////////////////////////////
475 RUNNER_TEST(SharedMemory_023_InvalidSizeTest)
477 RemoveIpcs(); // we need non existing shm
479 typedef SharedObject<TestTypeList> SO1;
480 typedef SharedObject<TestTypeList2> SO2;
482 SO1::Ptr sho = SharedObjectFactory<SO1>::Create(SHM_KEY, SEM_NAME);
485 SO2::Ptr sho2 = SharedObjectFactory<SO2>::Create(SHM_KEY, SEM_NAME);
487 RUNNER_ASSERT_MSG(false, "Invalid shm size has been accepted");
489 Catch(SharedObjectBase::Exception::InvalidSize) {
494 //////////////////////////////////////////////
496 class MagicTestSO1 : public TestSharedObject
499 explicit MagicTestSO1(const std::string& semaphore) :
500 TestSharedObject(semaphore) {}
503 virtual MagicType GetMagicNumber() const
509 friend class SharedObjectFactory<MagicTestSO1>;
512 class MagicTestSO2 : public TestSharedObject
515 explicit MagicTestSO2(const std::string& semaphore) :
516 TestSharedObject(semaphore) {}
519 virtual MagicType GetMagicNumber() const
525 friend class SharedObjectFactory<MagicTestSO2>;
528 RUNNER_TEST(SharedMemory_024_InvalidMagicTest)
530 RemoveIpcs(); // we need non existing shm
532 std::shared_ptr<MagicTestSO1> sho =
533 SharedObjectFactory<MagicTestSO1>::Create(SHM_KEY, SEM_NAME);
536 std::shared_ptr<MagicTestSO2> sho2 =
537 SharedObjectFactory<MagicTestSO2>::Create(SHM_KEY, SEM_NAME);
539 RUNNER_ASSERT_MSG(false, "Invalid shm magic number has been accepted");
541 Catch(SharedObjectBase::Exception::InvalidMagicNumber) {
546 //////////////////////////////////////////////
549 * Listening shared object
551 class EnumTestSO1 : public TestSharedObject
554 void SetWaitable(DPL::WaitableEvent* waitable)
556 m_waitable = waitable;
560 explicit EnumTestSO1(const std::string& semaphore) :
561 TestSharedObject(semaphore),
566 virtual void PropertyChanged(size_t propertyEnum);
569 friend class SharedObjectFactory<EnumTestSO1>;
571 DPL::WaitableEvent* m_waitable;
574 void EnumTestSO1::PropertyChanged(size_t propertyEnum)
576 if (propertyEnum == 1) {
577 LogDebug("Property enum " << propertyEnum << " correctly set");
578 g_enumTestCorrect = true;
580 if (propertyEnum == 4) {
581 // This is bad. We only have 4 types
582 LogError("Property enum " << propertyEnum << " should be skipped");
583 g_enumTestIncorrect = true;
585 // confirm property change notification
586 m_waitable->Signal();
589 class EnumController : public ListeningController<EnumTestSO1>
592 explicit EnumController(DPL::WaitableEvent* waitable) :
593 ListeningController<EnumTestSO1>(waitable) {}
595 virtual void OnEvent(const int event);
598 void EnumController::OnEvent(const int event)
600 if (event == INIT_EVENT) {
601 m_so->SetWaitable(m_waitable);
606 * Writing shared object with correct size but different number of types
608 class EnumTestSO2 : public TestSharedObject3
611 explicit EnumTestSO2(const std::string& semaphore) :
612 TestSharedObject3(semaphore) {}
615 friend class SharedObjectFactory<EnumTestSO2>;
618 RUNNER_TEST(SharedMemory_025_InvalidEnumTest)
620 RemoveIpcs(); // we need non existing shm
622 g_enumTestCorrect = false;
623 g_enumTestIncorrect = false;
625 DPL::WaitableEvent waitable;
627 // create listening controller and wait until it registers
628 EnumController controller(&waitable);
630 LogDebug("Listening controller created");
632 // create writing shared object
633 std::shared_ptr<EnumTestSO2> sho2 =
634 SharedObjectFactory<EnumTestSO2>::Create(SHM_KEY, SEM_NAME);
635 DPL::WaitableHandleIndexList list;
637 // write property and wait for confirmation
638 sho2->SetProperty<1>(2);
641 // write incorrect property and wait for confirmation
643 sho2->SetProperty<4>(2);
644 Wait(waitable, true);
646 // schedule listener deregistration and wait for confirmation
647 controller.PostEvent(DESTROY_EVENT);
651 RUNNER_ASSERT(g_enumTestCorrect == true);
652 RUNNER_ASSERT(g_enumTestIncorrect == false);
655 //////////////////////////////////////////////
657 class MultiThreadSO : public TestSharedObject
660 void TestAndSetProperty();
663 explicit MultiThreadSO(const std::string& semaphore) :
664 TestSharedObject(semaphore) {}
667 friend class SharedObjectFactory<MultiThreadSO>;
670 void MultiThreadSO::TestAndSetProperty()
672 ScopedFlaggedLock lock(*this);
674 int value = PropertyRef<0, int>();
675 DPL::Thread::MicroSleep(100);
676 SetPropertyInternal<0>(value + 1);
679 class ShmController : public ListeningController<MultiThreadSO>
682 explicit ShmController(DPL::WaitableEvent* event) :
683 ListeningController<MultiThreadSO>(event), m_counter(0)
686 virtual void OnEventReceived(const int& event);
692 void ShmController::OnEventReceived(const int& event)
694 if (event == INIT_EVENT) {
695 m_so = SharedObjectFactory<MultiThreadSO>::Create(SHM_KEY, SEM_NAME);
697 } else if (event == DESTROY_EVENT) {
698 LogDebug("Destroying shared object");
699 // deregister, destroy ad notify main thread
701 m_waitable->Signal();
702 } else if (event == 2) {
703 m_so->TestAndSetProperty();
705 if (m_counter >= TEST_AND_SET_REPEATS) {
706 LogDebug("Max tests reached. Finishing thread");
707 PostEvent(DESTROY_EVENT);
714 RUNNER_TEST(SharedMemory_030_MultithreadTest)
716 RemoveIpcs(); // we need non existing shm
718 typedef SharedObject<TestTypeList> SHO;
719 SHO::Ptr sho = SharedObjectFactory<SHO>::Create(SHM_KEY, SEM_NAME);
721 ShmController* controller[MAX_THREADS];
722 DPL::WaitableEvent finalEvent[MAX_THREADS];
724 for (size_t i = 0; i < MAX_THREADS; ++i) {
725 controller[i] = new ShmController(&finalEvent[i]);
728 for (size_t i = 0; i < MAX_THREADS; ++i) {
732 for (size_t i = 0; i < MAX_THREADS; ++i) {
733 delete controller[i];
734 controller[i] = NULL;
737 int value = sho->GetProperty<0, int>();
738 LogDebug("Final value is " << value << ", expected " <<
739 MAX_THREADS * TEST_AND_SET_REPEATS);
740 RUNNER_ASSERT(value == MAX_THREADS * TEST_AND_SET_REPEATS);
743 //////////////////////////////////////////////
745 class MyModel10 : public DPL::Model
748 explicit MyModel10(const TestSharedObject4Ptr& shared_object) :
749 DPL::Model(), boolValue(this, shared_object) {}
751 SharedProperty<bool, TestSharedObject4::BOOLEAN, TestSharedObject4>
756 * Listening controller
758 class ShmController3 : public ListeningController<TestSharedObject4>
761 explicit ShmController3(DPL::WaitableEvent* event) :
762 ListeningController<TestSharedObject4>(event)
765 virtual void OnEvent(const int event);
767 void OnValueChanged(const DPL::PropertyEvent<bool>& event);
770 typedef std::unique_ptr<MyModel10> MyModelPtr;
772 // model with property bound to shared object
776 void ShmController3::OnEvent(const int event)
778 if (event == INIT_EVENT) {
779 m_model.Reset(new MyModel10(m_so));
780 m_model->boolValue.AddListener(
781 DPL::FastDelegate<void (const DPL::PropertyEvent<bool>&)>(
783 &ShmController3::OnValueChanged));
784 } else if (event == DESTROY_EVENT) {
785 m_model->boolValue.RemoveListener(
786 DPL::FastDelegate<void (const DPL::PropertyEvent<bool>&)>(
788 &ShmController3::OnValueChanged));
793 void ShmController3::OnValueChanged(const DPL::PropertyEvent<bool>& event)
797 m_model->boolValue.Set(false);
799 LogError("Expected value = true, got false");
802 m_waitable->Signal();
805 RUNNER_TEST(SharedMemory_050_SharedProperty)
810 DPL::WaitableEvent waitable;
811 // listener controller
812 ShmController3 controller(&waitable);
815 TestSharedObject4Ptr sharedObject = TestSharedObject4::Create();
817 for (size_t i = 0; i < SHARED_PROP_REPEATS; ++i) {
818 sharedObject->SetProperty<TestSharedObject4::BOOLEAN>(true);
820 result = sharedObject->GetProperty<TestSharedObject4::BOOLEAN,
822 RUNNER_ASSERT(result == false);
824 controller.PostEvent(DESTROY_EVENT);
828 //////////////////////////////////////////////
830 class MyModel2 : public DPL::Model
833 explicit MyModel2(const TestSharedObjectPtr& shared_object) :
834 counter(this, shared_object) {}
836 SharedProperty<int, 0, TestSharedObject> counter;
839 class SPController : public ListeningController<TestSharedObject>
842 explicit SPController(DPL::WaitableEvent* event) :
843 ListeningController<TestSharedObject>(event), m_repeats(1) {}
845 virtual void OnEvent(const int event);
847 void OnValueChanged1(const DPL::PropertyEvent<int>& event);
848 void OnValueChanged2(const DPL::PropertyEvent<int>& event);
851 std::unique_ptr<MyModel2> m_model1;
852 std::unique_ptr<MyModel2> m_model2;
855 std::shared_ptr<TestSharedObject> m_so2;
858 void SPController::OnEvent(const int event)
860 if (event == INIT_EVENT) {
861 m_so2 = SharedObjectFactory<TestSharedObject>::Create(SHM_KEY,
864 // create and register 2 models sharing the same property
865 m_model1.Reset(new MyModel2(m_so));
866 m_model2.Reset(new MyModel2(m_so2));
867 m_model1->counter.AddListener(
868 DPL::FastDelegate<void (const DPL::PropertyEvent<int>&)>(
870 &SPController::OnValueChanged1));
871 m_model2->counter.AddListener(
872 DPL::FastDelegate<void (const DPL::PropertyEvent<int>&)>(
874 &SPController::OnValueChanged2));
875 m_model1->counter.Set(1);
876 } else if (event == DESTROY_EVENT) {
877 m_model1->counter.RemoveListener(
878 DPL::FastDelegate<void (const DPL::PropertyEvent<int>&)>(
880 &SPController::OnValueChanged1));
881 m_model2->counter.RemoveListener(
882 DPL::FastDelegate<void (const DPL::PropertyEvent<int>&)>(
884 &SPController::OnValueChanged2));
892 void SPController::OnValueChanged1(const DPL::PropertyEvent<int>& event)
894 if (m_repeats >= SINGLE_PROCESS_REPEATS) {
895 PostEvent(DESTROY_EVENT);
899 LogDebug("[1] Value changed to " << event.value);
901 m_model1->counter.Set(event.value + 1);
904 void SPController::OnValueChanged2(const DPL::PropertyEvent<int>& event)
906 if (m_repeats >= SINGLE_PROCESS_REPEATS) {
907 PostEvent(DESTROY_EVENT);
911 LogDebug("[2] Value changed to " << event.value);
913 m_model2->counter.Set(event.value + 1);
916 RUNNER_TEST(SharedMemory_060_SingleProcess)
920 DPL::WaitableEvent waitable;
921 SPController controller(&waitable);
922 TestSharedObjectPtr sho = SharedObjectFactory<TestSharedObject>::Create(
929 // wait for destruction
932 int value = sho->GetProperty<0, int>();
934 LogDebug("final value: " << value);
937 RUNNER_ASSERT(value == SINGLE_PROCESS_REPEATS);
940 //////////////////////////////////////////////
942 class ListenerTestController : public ListeningController<TestSharedObject>,
943 public ISharedObjectListener<0, int>,
944 public ISharedObjectListener<1, int>,
945 public ISharedObjectListener<2, char>,
946 public ISharedObjectListener<3, int[64]>
949 explicit ListenerTestController(DPL::WaitableEvent* event) :
950 ListeningController<TestSharedObject>(event) {}
952 ~ListenerTestController();
954 virtual void OnEvent(const int event);
956 virtual void ValueChanged(size_t propertyEnum,
958 const void* info = NULL);
959 virtual void ValueChanged(size_t propertyEnum,
961 const void* info = NULL);
962 virtual void ValueChanged(size_t propertyEnum,
963 const int(&value)[64],
964 const void* info = NULL);
967 ListenerTestController::~ListenerTestController()
970 void ListenerTestController::OnEvent(const int event)
972 if (event == INIT_EVENT) {
973 // add self as a listener to shared object
974 m_so->AddListener<0, int>(this);
975 m_so->AddListener<1, int>(this);
976 m_so->AddListener<2, char>(this);
977 m_so->AddListener<3, int[64]>(this);
978 } else if (event == DESTROY_EVENT) {
979 // remove self from listener list
980 m_so->RemoveListener<0, int>(this);
981 m_so->RemoveListener<1, int>(this);
982 m_so->RemoveListener<2, char>(this);
983 m_so->RemoveListener<3, int[64]>(this);
987 void ListenerTestController::ValueChanged(size_t propertyEnum,
989 const void* /*info*/)
991 LogDebug("ValueChanged(int) " << propertyEnum << " " << value);
992 if ((propertyEnum == 0 &&
993 value == 1) || (propertyEnum == 1 && value == 2))
995 g_values[propertyEnum]++;
996 if (g_values[propertyEnum] == 3) {
997 m_waitable->Signal();
1002 void ListenerTestController::ValueChanged(size_t propertyEnum,
1004 const void* /*info*/)
1006 LogDebug("ValueChanged(char) " << propertyEnum << " " << value);
1007 if (propertyEnum == 2 && value == 'c') {
1008 g_values[propertyEnum]++;
1009 if (g_values[propertyEnum] == 3) {
1010 m_waitable->Signal();
1015 void ListenerTestController::ValueChanged(size_t propertyEnum,
1016 const int(&value)[64],
1017 const void* /*info*/)
1019 LogDebug("ValueChanged(int[64]) " << propertyEnum << " " << value[5]);
1020 if (propertyEnum == 3 && value[5] == 5) {
1021 g_values[propertyEnum]++;
1022 if (g_values[propertyEnum] == 3) {
1023 m_waitable->Signal();
1028 RUNNER_TEST(SharedMemory_070_SharedObjectListeners)
1032 // setup global flags
1033 for (size_t i = 0; i < TestTypeList::Size; ++i) {
1037 // create shared object
1038 TestSharedObjectPtr sho = SharedObjectFactory<TestSharedObject>::Create(
1041 // create 1st listener and wait for it
1042 DPL::WaitableEvent waitable;
1043 ListenerTestController c1(&waitable);
1046 // create 2nd listener and wait for it
1047 ListenerTestController c2(&waitable);
1050 // create 3rd listener and wait for it
1051 ListenerTestController c3(&waitable);
1054 // set properties and wait for result
1055 sho->SetProperty<0, int>(1);
1058 RUNNER_ASSERT(g_values[0] == 3);
1060 sho->SetProperty<1, int>(2);
1063 RUNNER_ASSERT(g_values[1] == 3);
1065 sho->SetProperty<2, char>('c');
1068 RUNNER_ASSERT(g_values[2] == 3);
1071 memset(array, 0, 64 * sizeof(array[0]));
1073 sho->SetProperty<3, int[64]>(array);
1076 RUNNER_ASSERT(g_values[3] == 3);
1078 // finalize listeners
1079 c1.PostEvent(DESTROY_EVENT);
1082 c2.PostEvent(DESTROY_EVENT);
1085 c3.PostEvent(DESTROY_EVENT);
1089 //////////////////////////////////////////////
1092 * class simulating DB access
1094 class DAO : public DPL::Noncopyable
1097 DAO() : m_boolValue(false) {}
1099 void SetBoolValue(const bool& value)
1101 m_boolValue = value;
1104 bool GetBoolValue() const
1114 * Model with property having set delegate defined
1116 class MyModel3 : public DPL::Model
1119 typedef SharedPropertyEx<bool,
1120 TestSharedObject4::BOOLEAN,
1121 TestSharedObject4> PropertyType;
1123 MyModel3(const TestSharedObject4Ptr& shared_object, DAO* dao) :
1126 PropertyType::SetDelegate(dao, &DAO::SetBoolValue))
1129 PropertyType boolValue;
1132 RUNNER_TEST(SharedMemory_090_SetPropertyDelegate)
1139 // create shared object
1140 TestSharedObject4Ptr sho = TestSharedObject4::Create();
1142 // set property but call dao delegate within semaphore
1143 sho->SetProperty<TestSharedObject4::BOOLEAN>(
1145 MyModel3::PropertyType::SetDelegate(&dao, &DAO::SetBoolValue));
1148 RUNNER_ASSERT(dao.GetBoolValue() == true);
1150 // check shared object value
1151 bool shoValue = sho->GetProperty<TestSharedObject4::BOOLEAN, bool>();
1152 RUNNER_ASSERT(shoValue == true);
1154 // try the same with shared property
1155 MyModel3 model(sho, &dao);
1158 model.boolValue.Set(false);
1161 RUNNER_ASSERT(dao.GetBoolValue() == false);
1164 shoValue = sho->GetProperty<TestSharedObject4::BOOLEAN, bool>();
1165 RUNNER_ASSERT(shoValue == false);
1167 // check property value
1168 RUNNER_ASSERT(model.boolValue.Get() == false);
1171 //////////////////////////////////////////////
1174 * Lazy initialization test shared object
1176 class LazySharedObject : public SharedObject<TestTypeList>
1179 LazySharedObject() :
1184 explicit LazySharedObject(const std::string& semaphore) :
1185 SharedObject<TestTypeList>(semaphore)
1197 friend class SharedObjectFactory<LazySharedObject>;
1202 void LazySharedObject::Init()
1204 SetPropertyInternal<0>(42);
1208 RUNNER_TEST(SharedMemory_100_LazyInit)
1212 typedef std::shared_ptr<LazySharedObject> LazySharedObjectPtr;
1214 // create shared object
1215 LazySharedObjectPtr sho = SharedObjectFactory<LazySharedObject>::Create(
1218 RUNNER_ASSERT(sho->IsRead() == false);
1220 // get property causing lazy init
1221 int value = sho->GetProperty<0, int>();
1223 RUNNER_ASSERT(sho->IsRead() == true);
1224 RUNNER_ASSERT(value == 42);
1226 // create another object
1227 LazySharedObjectPtr sho2 = SharedObjectFactory<LazySharedObject>::Create(
1230 RUNNER_ASSERT(sho2->IsRead() == false);
1232 // get property NOT causing lazy init
1233 value = sho2->GetProperty<0, int>();
1235 RUNNER_ASSERT(sho2->IsRead() == false);
1236 RUNNER_ASSERT(value == 42);
1238 // destroy both objects
1242 // create shared object
1243 LazySharedObjectPtr sho3 = SharedObjectFactory<LazySharedObject>::Create(
1246 RUNNER_ASSERT(sho3->IsRead() == false);
1248 // set property causing lazy init
1249 sho3->SetProperty<0>(43);
1250 value = sho3->GetProperty<0, int>();
1252 RUNNER_ASSERT(sho3->IsRead() == true);
1253 RUNNER_ASSERT(value == 43);
1256 //////////////////////////////////////////////
1258 bool SetCondition(const int& readValue, int& setValue);
1259 bool SetCondition(const int& readValue, int& setValue)
1261 LogDebug("Condition delegate called with read value = " << readValue <<
1262 " and set value = " << setValue);
1264 if (readValue > 3) {
1265 LogDebug("Condition is false");
1269 LogDebug("Condition is true");
1270 if (4 == setValue) {
1272 LogDebug("Changing set value to " << setValue);
1277 void SetDelegate(const int& readValue);
1278 void SetDelegate(const int& readValue)
1280 LogDebug("Set delegate called " << readValue);
1284 RUNNER_TEST(SharedMemory_120_ConditionalSet)
1288 TestSharedObjectPtr sho = SharedObjectFactory<TestSharedObject>::Create(
1292 g_delegateCalls = 0;
1294 RUNNER_ASSERT(0 == (sho->GetProperty<0, int>()));
1296 DPL::FastDelegate<bool (const int&, int&)> condition(&SetCondition);
1297 DPL::FastDelegate<void (const int&)> delegate(&SetDelegate);
1299 bool succeeded = false;
1301 succeeded = sho->ConditionalSetProperty<0>(-2, condition);
1303 RUNNER_ASSERT(succeeded);
1304 RUNNER_ASSERT(-2 == (sho->GetProperty<0, int>()));
1306 succeeded = sho->ConditionalSetProperty<0>(4, condition, delegate);
1308 RUNNER_ASSERT(succeeded);
1309 RUNNER_ASSERT(10 == (sho->GetProperty<0, int>()));
1310 RUNNER_ASSERT(1 == g_delegateCalls);
1312 succeeded = sho->ConditionalSetProperty<0>(5, condition);
1314 RUNNER_ASSERT(!succeeded);
1315 RUNNER_ASSERT(10 == (sho->GetProperty<0, int>()));
1317 succeeded = sho->ConditionalSetProperty<0>(666, condition, delegate);
1319 RUNNER_ASSERT(!succeeded);
1320 RUNNER_ASSERT(10 == (sho->GetProperty<0, int>()));
1321 RUNNER_ASSERT(1 == g_delegateCalls);
1324 //////////////////////////////////////////////
1327 * Shared object used by multiple threads as a singleton.
1329 class MTSharedObject : public SharedObject<TestTypeList>
1332 explicit MTSharedObject(const std::string& semaphore) :
1333 SharedObject<TestTypeList>(semaphore)
1339 friend class SharedObjectFactory<MTSharedObject>;
1342 typedef std::shared_ptr<MTSharedObject> MTSharedObjectPtr;
1344 void MTSharedObject::Clear()
1349 SetProperty<2>(static_cast<char>(0));
1350 SetProperty<3>(array);
1354 * Shared object singleton
1356 class SharedObjectSingleton
1359 static MTSharedObjectPtr Instance();
1360 static void Destroy();
1363 static MTSharedObjectPtr m_sho;
1364 static DPL::Mutex m_mutex;
1367 MTSharedObjectPtr SharedObjectSingleton::m_sho;
1368 DPL::Mutex SharedObjectSingleton::m_mutex;
1370 MTSharedObjectPtr SharedObjectSingleton::Instance()
1372 DPL::Mutex::ScopedLock lock(&m_mutex);
1374 m_sho = SharedObjectFactory<MTSharedObject>::Create(SHM_KEY, SEM_NAME);
1379 void SharedObjectSingleton::Destroy()
1381 DPL::Mutex::ScopedLock lock(&m_mutex);
1386 * Listening controller
1388 class ShmController4 : public ListeningController<MTSharedObject>,
1389 public ISharedObjectListener<0, int>,
1390 public ISharedObjectListener<1, int>,
1391 public ISharedObjectListener<2, char>,
1392 public ISharedObjectListener<3, int[64]>
1397 REMOVE_LISTENERS = 3,
1398 DESTROY_SINGLETON = 4
1401 explicit ShmController4(DPL::WaitableEvent* event) :
1402 ListeningController<MTSharedObject>(event),
1406 virtual void OnEventReceived(const int& event);
1408 virtual void ValueChanged(size_t propertyEnum,
1410 const void* info = NULL);
1411 virtual void ValueChanged(size_t propertyEnum,
1413 const void* info = NULL);
1414 virtual void ValueChanged(size_t propertyEnum,
1415 const int(&value)[64],
1416 const void* info = NULL);
1418 bool NotRegistered();
1424 static unsigned int seed = time(NULL);
1427 void ShmController4::ValueChanged(size_t propertyEnum,
1429 const void* /*info*/)
1431 LogDebug("ValueChanged(int) " << propertyEnum << " " << value);
1432 if ((propertyEnum == 0 && value == 1) ||
1433 (propertyEnum == 1 && value == 11))
1435 m_waitable->Signal();
1439 void ShmController4::ValueChanged(size_t propertyEnum,
1441 const void* /*info*/)
1443 LogDebug("ValueChanged(char) " << propertyEnum << " " << value);
1444 if (propertyEnum == 2 && value == 'a') {
1445 m_waitable->Signal();
1449 void ShmController4::ValueChanged(size_t propertyEnum,
1450 const int(&value)[64],
1451 const void* /*info*/)
1453 LogDebug("ValueChanged(int[64]) " << propertyEnum << " " << value[5]);
1454 if (propertyEnum == 3 && value[0] == 0 && value[1] == 1 && value[2] == 2) {
1455 m_waitable->Signal();
1459 void ShmController4::Sleep()
1461 DPL::Thread::GetCurrentThread()->MiliSleep(
1462 rand_r(&seed) % MAX_SINGLETON_LISTENER_DELAY);
1465 void ShmController4::OnEventReceived(const int& event)
1469 m_so = SharedObjectSingleton::Instance();
1470 m_waitable->Signal();
1474 LogDebug("Destroying shared object");
1475 // deregister, destroy and notify main thread
1477 m_waitable->Signal();
1481 // add listener and notify
1482 m_so->AddListener<0, int>(this);
1484 m_so->AddListener<1, int>(this);
1486 m_so->AddListener<2, char>(this);
1488 m_so->AddListener<3, int[64]>(this);
1490 m_waitable->Signal();
1493 case REMOVE_LISTENERS:
1494 // remove listener and notify
1495 m_so->RemoveListener<0, int>(this);
1497 m_so->RemoveListener<1, int>(this);
1499 m_so->RemoveListener<2, char>(this);
1501 m_so->RemoveListener<3, int[64]>(this);
1503 m_waitable->Signal();
1506 case DESTROY_SINGLETON:
1507 SharedObjectSingleton::Destroy();
1508 m_waitable->Signal();
1512 LogError("Unsupported event received: " << event);
1516 void MultipleWait(DPL::WaitableEvent(&event)[MAX_THREADS]);
1517 void MultipleWait(DPL::WaitableEvent(&event)[MAX_THREADS])
1519 for (size_t i = 0; i < MAX_THREADS; ++i) {
1525 * Try to remove property listener. If there's no such listener an exception
1528 #define LISTENER_ASSERT(property) \
1530 singleton->RemoveListener<(property)>(controller[i]); \
1531 LogError("Controller " << i << " is still listening for property " \
1533 RUNNER_ASSERT_MSG(false, "No listeners expected"); \
1535 Catch(MTSharedObject::Exception::ListenerNotFound) { \
1536 RUNNER_ASSERT(true); \
1540 RUNNER_TEST(SharedMemory_130_SharedObjectSingleton)
1542 RemoveIpcs(); // we need non existing shm
1544 // writer shared object
1545 TestSharedObjectPtr sho = SharedObjectFactory<TestSharedObject>::Create(
1548 ShmController4* controller[MAX_THREADS];
1549 DPL::WaitableEvent waitable[MAX_THREADS];
1551 const int array[64] = { 0, 1, 2 };
1553 // Create and wait for notification. Make sure that the thread/controller 0
1555 LogInfo("Creating controllers");
1556 for (size_t i = 0; i < MAX_THREADS; ++i) {
1557 controller[i] = new ShmController4(&waitable[i]);
1561 // singleton will be created by thread/controller 0 by now
1562 MTSharedObjectPtr singleton = SharedObjectSingleton::Instance();
1564 for (size_t repeats = 0; repeats < SINGLETON_TEST_REPEATS; ++repeats) {
1565 LogInfo("%%%%%%%%%%%%%%%%%%%%%");
1566 LogInfo("Iteration " << repeats + 1 << " of " << SINGLETON_TEST_REPEATS);
1570 LogInfo("Adding listeners");
1571 for (size_t i = 0; i < MAX_THREADS; ++i) {
1572 controller[i]->PostEvent(ShmController4::ADD_LISTENERS);
1574 // wait for listeners
1575 MultipleWait(waitable);
1577 RUNNER_ASSERT((singleton->GetProperty<0, int>()) == 0);
1578 RUNNER_ASSERT((singleton->GetProperty<1, int>()) == 0);
1579 RUNNER_ASSERT((singleton->GetProperty<2, char>()) == 0);
1581 int checkArray[64] = {};
1582 singleton->GetProperty<3>(checkArray);
1583 RUNNER_ASSERT(checkArray[0] == 0);
1584 RUNNER_ASSERT(checkArray[1] == 0);
1585 RUNNER_ASSERT(checkArray[2] == 0);
1588 LogInfo("Setting property 0");
1589 sho->SetProperty<0>(1);
1590 // wait for confirmations
1591 MultipleWait(waitable);
1594 LogInfo("Setting property 1");
1595 sho->SetProperty<1>(11);
1596 // wait for confirmations
1597 MultipleWait(waitable);
1600 LogInfo("Setting property 2");
1601 sho->SetProperty<2>('a');
1602 // wait for confirmations
1603 MultipleWait(waitable);
1606 LogInfo("Setting property 3");
1607 sho->SetProperty<3>(array);
1608 // wait for confirmations
1609 MultipleWait(waitable);
1612 LogInfo("Removing listeners");
1613 for (size_t i = 0; i < MAX_THREADS; ++i) {
1614 controller[i]->PostEvent(ShmController4::REMOVE_LISTENERS);
1616 // wait for listeners
1617 MultipleWait(waitable);
1619 // check if listeners array is empty
1620 LogInfo("Checking listeners");
1621 for (size_t i = 0; i < MAX_THREADS; ++i) {
1628 RUNNER_ASSERT((singleton->GetProperty<0, int>()) == 1);
1629 RUNNER_ASSERT((singleton->GetProperty<1, int>()) == 11);
1630 RUNNER_ASSERT((singleton->GetProperty<2, char>()) == 'a');
1631 singleton->GetProperty<3>(checkArray);
1632 RUNNER_ASSERT(checkArray[0] == 0);
1633 RUNNER_ASSERT(checkArray[1] == 1);
1634 RUNNER_ASSERT(checkArray[2] == 2);
1639 // Destroy controllers and wait for confirmation. Make sure that
1640 // thread/controller 0 is destroyed in the end
1641 LogInfo("Destroying controllers");
1642 for (int i = MAX_THREADS - 1; i >= 0; --i) {
1643 controller[i]->PostEvent(DESTROY_EVENT);
1647 * Destroy singleton before thread that created it finishes.
1648 * This is to properly close all waitable handles opened by
1649 * SharedObject in thread 0.
1651 LogInfo("Destroying singleton");
1652 controller[i]->PostEvent(ShmController4::DESTROY_SINGLETON);
1655 delete controller[i];
1659 #undef LISTENER_ASSERT
1662 * test preconditions & postconditions:
1663 * - no existing shared memory with given SHM_KEY
1664 * - no existing semaphore of given SEM_NAME
1666 RUNNER_TEST(SharedMemory_001_Preconditions) {
1670 RUNNER_TEST(SharedMemory_999_Postconditions) {