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>
37 RUNNER_TEST_GROUP_INIT(DPL)
42 const SharedMemory::Key SHM_KEY = 12345;
43 const char* SEM_NAME = "/wrt_engine_shared_object_semaphore";
44 const size_t VERSION = 1;
46 const size_t MAX_THREADS = 10;
47 const size_t TEST_AND_SET_REPEATS = 100;
49 const size_t SHARED_PROP_REPEATS = 3;
51 const size_t SINGLETON_TEST_REPEATS = 3;
53 // maximum random delay in singleton listener addition/removal
54 const size_t MAX_SINGLETON_LISTENER_DELAY = 50;
56 const int SINGLE_PROCESS_REPEATS = 50;
59 * 5 seconds expected timeout for waitable events
60 * 30 seconds unexpected timeout for waitable events
61 * We don't want to block tests
63 const size_t EXPECTED_WAITABLE_TIMEOUT = 5 * 1000;
64 const size_t UNEXPECTED_WAITABLE_TIMEOUT = 30 * 1000;
66 bool g_enumTestCorrect = false;
67 bool g_enumTestIncorrect = false;
68 size_t g_delegateCalls = 0;
70 void Wait(DPL::WaitableEvent& event, bool expectedTimeout = false)
72 WrtLogD("WaitForSingleHandle...");
73 DPL::WaitableHandleIndexList list = DPL::WaitForSingleHandle(
76 EXPECTED_WAITABLE_TIMEOUT : UNEXPECTED_WAITABLE_TIMEOUT);
77 if (list.size() == 0) {
78 WrtLogD("...timeout.");
80 WrtLogD("...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();
168 } else if (event == DESTROY_EVENT) {
169 WrtLogD("Destroying shared object");
172 // deregister, destroy ad notify main thread
175 m_waitable->Signal();
182 typedef DPL::TypeListDecl<size_t, bool>::Type SharedTypeList;
184 class TestSharedObject4;
185 typedef std::shared_ptr<TestSharedObject4> TestSharedObject4Ptr;
187 class TestSharedObject4 : public SharedObject<SharedTypeList>
196 static TestSharedObject4Ptr Create()
198 return SharedObjectFactory<TestSharedObject4>::Create(SHM_KEY, SEM_NAME);
207 explicit TestSharedObject4(const std::string& semaphore) :
208 SharedObject<SharedTypeList>(semaphore)
214 SetPropertyInternal<BOOLEAN>(false);
216 friend class SharedObjectFactory<TestSharedObject4>;
218 } // anonymus namespace
220 //////////////////////////////////////////////
222 RUNNER_TEST(SharedMemory_002_AccessByType)
226 SharedData<TestTypeList> str;
229 str.Embedded<0, int>::value = 4;
230 str.Embedded<1, int>::value = 5;
231 str.Embedded<2, char>::value = 'd';
232 str.Embedded<3, int[64]>::value[0] = 1;
233 str.Embedded<3, int[64]>::value[1] = 20;
235 RUNNER_ASSERT((str.Embedded<0, int>::value) == 4);
236 RUNNER_ASSERT((str.Embedded<1, int>::value) == 5);
237 RUNNER_ASSERT((str.Embedded<2, char>::value) == 'd');
238 RUNNER_ASSERT((str.Embedded<3, int[64]>::value[0]) == 1);
239 RUNNER_ASSERT((str.Embedded<3, int[64]>::value[1]) == 20);
242 //////////////////////////////////////////////
244 RUNNER_TEST(SharedMemory_003_AccessByIndex)
248 SharedData<TestTypeList> str;
250 str.Embedded<0, TestTypeList::Element<0>::Type>::value = 4;
251 str.Embedded<1, TestTypeList::Element<1>::Type>::value = 5;
252 str.Embedded<2, TestTypeList::Element<2>::Type>::value = 'd';
253 str.Embedded<3, TestTypeList::Element<3>::Type>::value[0] = 1;
254 str.Embedded<3, TestTypeList::Element<3>::Type>::value[1] = 20;
257 (str.Embedded<0, TestTypeList::Element<0>::Type>::value) == 4);
259 (str.Embedded<1, TestTypeList::Element<1>::Type>::value) == 5);
261 (str.Embedded<2, TestTypeList::Element<2>::Type>::value) == 'd');
263 (str.Embedded<3, TestTypeList::Element<3>::Type>::value[0]) == 1);
265 (str.Embedded<3, TestTypeList::Element<3>::Type>::value[1]) == 20);
268 //////////////////////////////////////////////
270 RUNNER_TEST(SharedMemory_004_SimplifiedAccess)
274 SharedData<TestTypeList> str;
276 // access via PropertyRef
277 str.PropertyRef<1>() = 3;
278 RUNNER_ASSERT(str.PropertyRef<1>() == 3);
280 int (&array)[64] = str.PropertyRef<3>();
282 RUNNER_ASSERT(str.PropertyRef<3>()[0] == 2);
284 str.PropertyRef<3>()[1] = 19;
285 RUNNER_ASSERT(str.PropertyRef<3>()[1] == 19);
288 str.SHARED_PROPERTY(0) = 2;
289 RUNNER_ASSERT(str.SHARED_PROPERTY(0) == 2);
291 str.SHARED_PROPERTY(2) = 'c';
292 RUNNER_ASSERT(str.SHARED_PROPERTY(2) == 'c');
294 str.SHARED_PROPERTY(3)[2] = 10;
295 RUNNER_ASSERT(str.SHARED_PROPERTY(3)[2] == 10);
298 RUNNER_ASSERT((str.Embedded<0, int>::value) == 2);
299 RUNNER_ASSERT((str.Embedded<1, int>::value) == 3);
300 RUNNER_ASSERT((str.Embedded<2, char>::value) == 'c');
301 RUNNER_ASSERT((str.Embedded<3, int[64]>::value[0]) == 2);
302 RUNNER_ASSERT((str.Embedded<3, int[64]>::value[1]) == 19);
303 RUNNER_ASSERT((str.Embedded<3, int[64]>::value[2]) == 10);
306 //////////////////////////////////////////////
316 typedef std::shared_ptr<SharedMemory::Segment<SharedStruct> > SharedStructPtr;
318 RUNNER_TEST(SharedMemory_010_BaseShmTest)
322 typedef std::unique_ptr<SharedMemory> SharedMemoryPtr;
327 shm.Reset(SharedMemory::Create<SharedStruct>(SHM_KEY, false));
329 Catch(SharedMemory::Exception::NotFound) {
330 shm.Reset(SharedMemory::Create<SharedStruct>(SHM_KEY, true, true));
333 SharedStructPtr str = shm->Attach<SharedStruct>();
337 str->Data()->c = '3';
338 str->Data()->d[0] = 4;
339 str->Data()->d[1] = 5;
342 SharedMemoryPtr shm2;
344 shm2.Reset(SharedMemory::Create<SharedStruct>(SHM_KEY, false));
346 Catch(SharedMemory::Exception::NotFound) {
347 shm2.Reset(SharedMemory::Create<SharedStruct>(SHM_KEY, true, true));
350 SharedStructPtr str2 = shm2->Attach<SharedStruct>();
351 SharedStructPtr str3 = shm2->Attach<SharedStruct>();
353 RUNNER_ASSERT(str2->Data()->a == 1);
354 RUNNER_ASSERT(str2->Data()->b == 2);
355 RUNNER_ASSERT(str2->Data()->c == '3');
356 RUNNER_ASSERT(str2->Data()->d[0] == 4);
357 RUNNER_ASSERT(str2->Data()->d[1] == 5);
359 RUNNER_ASSERT(str3->Data()->a == 1);
360 RUNNER_ASSERT(str3->Data()->b == 2);
361 RUNNER_ASSERT(str3->Data()->c == '3');
362 RUNNER_ASSERT(str3->Data()->d[0] == 4);
363 RUNNER_ASSERT(str3->Data()->d[1] == 5);
366 str2->Data()->c = 'c';
367 str2->Data()->d[0] = 0;
368 RUNNER_ASSERT(str3->Data()->a == 1);
369 RUNNER_ASSERT(str3->Data()->b == 4);
370 RUNNER_ASSERT(str3->Data()->c == 'c');
371 RUNNER_ASSERT(str3->Data()->d[0] == 0);
372 RUNNER_ASSERT(str3->Data()->d[1] == 5);
375 //////////////////////////////////////////////
377 RUNNER_TEST(SharedMemory_020_SharedObjectTest)
381 typedef SharedObject<SharedTypeList> MySharedObj;
383 MySharedObj::Ptr so =
384 SharedObjectFactory<MySharedObj>::Create(SHM_KEY, SEM_NAME);
386 RUNNER_ASSERT((so->GetProperty<0, size_t>()) == 0);
387 so->SetProperty<0, size_t>(4);
388 RUNNER_ASSERT((so->GetProperty<0, size_t>()) == 4);
391 //////////////////////////////////////////////
393 class InitTestSharedObject : public TestSharedObject
396 explicit InitTestSharedObject(const std::string& semaphore) :
397 TestSharedObject(semaphore) {}
399 virtual void Init(); // from SharedObject
402 friend class SharedObjectFactory<InitTestSharedObject>;
405 void InitTestSharedObject::Init()
407 SetPropertyInternal<0>(1);
408 SetPropertyInternal<1>(2);
409 SetPropertyInternal<2>('c');
412 RUNNER_TEST(SharedMemory_021_InitTest)
414 RemoveIpcs(); // we need non existing shm
416 std::shared_ptr<InitTestSharedObject> sho =
417 SharedObjectFactory<InitTestSharedObject>::Create(
419 RUNNER_ASSERT((sho->GetProperty<0, int>()) == 1);
420 RUNNER_ASSERT((sho->GetProperty<1, int>()) == 2);
421 RUNNER_ASSERT((sho->GetProperty<2, char>()) == 'c');
424 //////////////////////////////////////////////
426 class VersionTestSO1 : public TestSharedObject
429 explicit VersionTestSO1(const std::string& semaphore) :
430 TestSharedObject(semaphore) {}
432 virtual SizeType GetVersion() const
435 } // from SharedObject
438 friend class SharedObjectFactory<VersionTestSO1>;
441 class VersionTestSO2 : public TestSharedObject
444 explicit VersionTestSO2(const std::string& semaphore) :
445 TestSharedObject(semaphore) {}
447 virtual SizeType GetVersion() const
450 } // 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
510 friend class SharedObjectFactory<MagicTestSO1>;
513 class MagicTestSO2 : public TestSharedObject
516 explicit MagicTestSO2(const std::string& semaphore) :
517 TestSharedObject(semaphore) {}
520 virtual MagicType GetMagicNumber() const
526 friend class SharedObjectFactory<MagicTestSO2>;
529 RUNNER_TEST(SharedMemory_024_InvalidMagicTest)
531 RemoveIpcs(); // we need non existing shm
533 std::shared_ptr<MagicTestSO1> sho =
534 SharedObjectFactory<MagicTestSO1>::Create(SHM_KEY, SEM_NAME);
537 std::shared_ptr<MagicTestSO2> sho2 =
538 SharedObjectFactory<MagicTestSO2>::Create(SHM_KEY, SEM_NAME);
540 RUNNER_ASSERT_MSG(false, "Invalid shm magic number has been accepted");
542 Catch(SharedObjectBase::Exception::InvalidMagicNumber) {
547 //////////////////////////////////////////////
550 * Listening shared object
552 class EnumTestSO1 : public TestSharedObject
555 void SetWaitable(DPL::WaitableEvent* waitable)
557 m_waitable = waitable;
561 explicit EnumTestSO1(const std::string& semaphore) :
562 TestSharedObject(semaphore),
567 virtual void PropertyChanged(size_t propertyEnum);
570 friend class SharedObjectFactory<EnumTestSO1>;
572 DPL::WaitableEvent* m_waitable;
575 void EnumTestSO1::PropertyChanged(size_t propertyEnum)
577 if (propertyEnum == 1) {
578 WrtLogD("Property enum %i correctly set", propertyEnum);
579 g_enumTestCorrect = true;
581 if (propertyEnum == 4) {
582 // This is bad. We only have 4 types
583 WrtLogE("Property enum %i should be skipped", propertyEnum);
584 g_enumTestIncorrect = true;
586 // confirm property change notification
587 m_waitable->Signal();
590 class EnumController : public ListeningController<EnumTestSO1>
593 explicit EnumController(DPL::WaitableEvent* waitable) :
594 ListeningController<EnumTestSO1>(waitable) {}
596 virtual void OnEvent(const int event);
599 void EnumController::OnEvent(const int event)
601 if (event == INIT_EVENT) {
602 m_so->SetWaitable(m_waitable);
607 * Writing shared object with correct size but different number of types
609 class EnumTestSO2 : public TestSharedObject3
612 explicit EnumTestSO2(const std::string& semaphore) :
613 TestSharedObject3(semaphore) {}
616 friend class SharedObjectFactory<EnumTestSO2>;
619 RUNNER_TEST(SharedMemory_025_InvalidEnumTest)
621 RemoveIpcs(); // we need non existing shm
623 g_enumTestCorrect = false;
624 g_enumTestIncorrect = false;
626 DPL::WaitableEvent waitable;
628 // create listening controller and wait until it registers
629 EnumController controller(&waitable);
631 WrtLogD("Listening controller created");
633 // create writing shared object
634 std::shared_ptr<EnumTestSO2> sho2 =
635 SharedObjectFactory<EnumTestSO2>::Create(SHM_KEY, SEM_NAME);
636 DPL::WaitableHandleIndexList list;
638 // write property and wait for confirmation
639 sho2->SetProperty<1>(2);
642 // write incorrect property and wait for confirmation
644 sho2->SetProperty<4>(2);
645 Wait(waitable, true);
647 // schedule listener deregistration and wait for confirmation
648 controller.PostEvent(DESTROY_EVENT);
652 RUNNER_ASSERT(g_enumTestCorrect == true);
653 RUNNER_ASSERT(g_enumTestIncorrect == false);
656 //////////////////////////////////////////////
658 class MultiThreadSO : public TestSharedObject
661 void TestAndSetProperty();
664 explicit MultiThreadSO(const std::string& semaphore) :
665 TestSharedObject(semaphore) {}
668 friend class SharedObjectFactory<MultiThreadSO>;
671 void MultiThreadSO::TestAndSetProperty()
673 ScopedFlaggedLock lock(*this);
675 int value = PropertyRef<0, int>();
676 DPL::Thread::MicroSleep(100);
677 SetPropertyInternal<0>(value + 1);
680 class ShmController : public ListeningController<MultiThreadSO>
683 explicit ShmController(DPL::WaitableEvent* event) :
684 ListeningController<MultiThreadSO>(event), m_counter(0)
687 virtual void OnEventReceived(const int& event);
693 void ShmController::OnEventReceived(const int& event)
695 if (event == INIT_EVENT) {
696 m_so = SharedObjectFactory<MultiThreadSO>::Create(SHM_KEY, SEM_NAME);
698 } else if (event == DESTROY_EVENT) {
699 WrtLogD("Destroying shared object");
700 // deregister, destroy ad notify main thread
702 m_waitable->Signal();
703 } else if (event == 2) {
704 m_so->TestAndSetProperty();
706 if (m_counter >= TEST_AND_SET_REPEATS) {
707 WrtLogD("Max tests reached. Finishing thread");
708 PostEvent(DESTROY_EVENT);
715 RUNNER_TEST(SharedMemory_030_MultithreadTest)
717 RemoveIpcs(); // we need non existing shm
719 typedef SharedObject<TestTypeList> SHO;
720 SHO::Ptr sho = SharedObjectFactory<SHO>::Create(SHM_KEY, SEM_NAME);
722 ShmController* controller[MAX_THREADS];
723 DPL::WaitableEvent finalEvent[MAX_THREADS];
725 for (size_t i = 0; i < MAX_THREADS; ++i) {
726 controller[i] = new ShmController(&finalEvent[i]);
729 for (size_t i = 0; i < MAX_THREADS; ++i) {
733 for (size_t i = 0; i < MAX_THREADS; ++i) {
734 delete controller[i];
735 controller[i] = NULL;
738 int value = sho->GetProperty<0, int>();
739 WrtLogD("Final value is %i, expected %i",
740 value, MAX_THREADS * TEST_AND_SET_REPEATS);
741 RUNNER_ASSERT(value == MAX_THREADS * TEST_AND_SET_REPEATS);
744 //////////////////////////////////////////////
746 class MyModel10 : public DPL::Model
749 explicit MyModel10(const TestSharedObject4Ptr& shared_object) :
750 DPL::Model(), boolValue(this, shared_object) {}
752 SharedProperty<bool, TestSharedObject4::BOOLEAN, TestSharedObject4>
757 * Listening controller
759 class ShmController3 : public ListeningController<TestSharedObject4>
762 explicit ShmController3(DPL::WaitableEvent* event) :
763 ListeningController<TestSharedObject4>(event)
766 virtual void OnEvent(const int event);
768 void OnValueChanged(const DPL::PropertyEvent<bool>& event);
771 typedef std::unique_ptr<MyModel10> MyModelPtr;
773 // model with property bound to shared object
777 void ShmController3::OnEvent(const int event)
779 if (event == INIT_EVENT) {
780 m_model.Reset(new MyModel10(m_so));
781 m_model->boolValue.AddListener(
782 std::bind(&ShmController3::OnValueChanged, this));
783 } else if (event == DESTROY_EVENT) {
784 m_model->boolValue.RemoveListener(
785 std::bind(&ShmController3::OnValueChanged, this));
790 void ShmController3::OnValueChanged(const DPL::PropertyEvent<bool>& event)
794 m_model->boolValue.Set(false);
796 WrtLogE("Expected value = true, got false");
799 m_waitable->Signal();
802 RUNNER_TEST(SharedMemory_050_SharedProperty)
807 DPL::WaitableEvent waitable;
808 // listener controller
809 ShmController3 controller(&waitable);
812 TestSharedObject4Ptr sharedObject = TestSharedObject4::Create();
814 for (size_t i = 0; i < SHARED_PROP_REPEATS; ++i) {
815 sharedObject->SetProperty<TestSharedObject4::BOOLEAN>(true);
817 result = sharedObject->GetProperty<TestSharedObject4::BOOLEAN,
819 RUNNER_ASSERT(result == false);
821 controller.PostEvent(DESTROY_EVENT);
825 //////////////////////////////////////////////
827 class MyModel2 : public DPL::Model
830 explicit MyModel2(const TestSharedObjectPtr& shared_object) :
831 counter(this, shared_object) {}
833 SharedProperty<int, 0, TestSharedObject> counter;
836 class SPController : public ListeningController<TestSharedObject>
839 explicit SPController(DPL::WaitableEvent* event) :
840 ListeningController<TestSharedObject>(event), m_repeats(1) {}
842 virtual void OnEvent(const int event);
844 void OnValueChanged1(const DPL::PropertyEvent<int>& event);
845 void OnValueChanged2(const DPL::PropertyEvent<int>& event);
848 std::unique_ptr<MyModel2> m_model1;
849 std::unique_ptr<MyModel2> m_model2;
852 std::shared_ptr<TestSharedObject> m_so2;
855 void SPController::OnEvent(const int event)
857 if (event == INIT_EVENT) {
858 m_so2 = SharedObjectFactory<TestSharedObject>::Create(SHM_KEY,
861 // create and register 2 models sharing the same property
862 m_model1.Reset(new MyModel2(m_so));
863 m_model2.Reset(new MyModel2(m_so2));
864 m_model1->counter.AddListener(
865 std::bind(&SPController::OnValueChanged1, this));
866 m_model2->counter.AddListener(
867 std::bind(&SPController::OnValueChanged2, this));
868 m_model1->counter.Set(1);
869 } else if (event == DESTROY_EVENT) {
870 m_model1->counter.RemoveListener(
871 std::bind(&SPController::OnValueChanged1, this));
872 m_model2->counter.RemoveListener(
873 std::bind(&SPController::OnValueChanged2, this));
881 void SPController::OnValueChanged1(const DPL::PropertyEvent<int>& event)
883 if (m_repeats >= SINGLE_PROCESS_REPEATS) {
884 PostEvent(DESTROY_EVENT);
888 WrtLogD("[1] Value changed to %s", event.value);
890 m_model1->counter.Set(event.value + 1);
893 void SPController::OnValueChanged2(const DPL::PropertyEvent<int>& event)
895 if (m_repeats >= SINGLE_PROCESS_REPEATS) {
896 PostEvent(DESTROY_EVENT);
900 WrtLogD("[2] Value changed to %i", event.value);
902 m_model2->counter.Set(event.value + 1);
905 RUNNER_TEST(SharedMemory_060_SingleProcess)
909 DPL::WaitableEvent waitable;
910 SPController controller(&waitable);
911 TestSharedObjectPtr sho = SharedObjectFactory<TestSharedObject>::Create(
918 // wait for destruction
921 int value = sho->GetProperty<0, int>();
923 WrtLogD("final value: %i", value);
926 RUNNER_ASSERT(value == SINGLE_PROCESS_REPEATS);
929 //////////////////////////////////////////////
931 class ListenerTestController : public ListeningController<TestSharedObject>,
932 public ISharedObjectListener<0, int>,
933 public ISharedObjectListener<1, int>,
934 public ISharedObjectListener<2, char>,
935 public ISharedObjectListener<3, int[64]>
938 explicit ListenerTestController(DPL::WaitableEvent* event) :
939 ListeningController<TestSharedObject>(event) {}
941 ~ListenerTestController();
943 virtual void OnEvent(const int event);
945 virtual void ValueChanged(size_t propertyEnum,
947 const void* info = NULL);
948 virtual void ValueChanged(size_t propertyEnum,
950 const void* info = NULL);
951 virtual void ValueChanged(size_t propertyEnum,
952 const int(&value)[64],
953 const void* info = NULL);
956 ListenerTestController::~ListenerTestController()
959 void ListenerTestController::OnEvent(const int event)
961 if (event == INIT_EVENT) {
962 // add self as a listener to shared object
963 m_so->AddListener<0, int>(this);
964 m_so->AddListener<1, int>(this);
965 m_so->AddListener<2, char>(this);
966 m_so->AddListener<3, int[64]>(this);
967 } else if (event == DESTROY_EVENT) {
968 // remove self from listener list
969 m_so->RemoveListener<0, int>(this);
970 m_so->RemoveListener<1, int>(this);
971 m_so->RemoveListener<2, char>(this);
972 m_so->RemoveListener<3, int[64]>(this);
976 void ListenerTestController::ValueChanged(size_t propertyEnum,
978 const void* /*info*/)
980 WrtLogD("ValueChanged(int) %u %i", propertyEnum, value);
981 if ((propertyEnum == 0 &&
982 value == 1) || (propertyEnum == 1 && value == 2))
984 g_values[propertyEnum]++;
985 if (g_values[propertyEnum] == 3) {
986 m_waitable->Signal();
991 void ListenerTestController::ValueChanged(size_t propertyEnum,
993 const void* /*info*/)
995 WrtLogD("ValueChanged(char) %u %i", propertyEnum, value);
996 if (propertyEnum == 2 && value == 'c') {
997 g_values[propertyEnum]++;
998 if (g_values[propertyEnum] == 3) {
999 m_waitable->Signal();
1004 void ListenerTestController::ValueChanged(size_t propertyEnum,
1005 const int(&value)[64],
1006 const void* /*info*/)
1008 WrtLogD("ValueChanged(int[64]) %u %i", propertyEnum, value[5]);
1009 if (propertyEnum == 3 && value[5] == 5) {
1010 g_values[propertyEnum]++;
1011 if (g_values[propertyEnum] == 3) {
1012 m_waitable->Signal();
1017 RUNNER_TEST(SharedMemory_070_SharedObjectListeners)
1021 // setup global flags
1022 for (size_t i = 0; i < TestTypeList::Size; ++i) {
1026 // create shared object
1027 TestSharedObjectPtr sho = SharedObjectFactory<TestSharedObject>::Create(
1030 // create 1st listener and wait for it
1031 DPL::WaitableEvent waitable;
1032 ListenerTestController c1(&waitable);
1035 // create 2nd listener and wait for it
1036 ListenerTestController c2(&waitable);
1039 // create 3rd listener and wait for it
1040 ListenerTestController c3(&waitable);
1043 // set properties and wait for result
1044 sho->SetProperty<0, int>(1);
1047 RUNNER_ASSERT(g_values[0] == 3);
1049 sho->SetProperty<1, int>(2);
1052 RUNNER_ASSERT(g_values[1] == 3);
1054 sho->SetProperty<2, char>('c');
1057 RUNNER_ASSERT(g_values[2] == 3);
1060 memset(array, 0, 64 * sizeof(array[0]));
1062 sho->SetProperty<3, int[64]>(array);
1065 RUNNER_ASSERT(g_values[3] == 3);
1067 // finalize listeners
1068 c1.PostEvent(DESTROY_EVENT);
1071 c2.PostEvent(DESTROY_EVENT);
1074 c3.PostEvent(DESTROY_EVENT);
1078 //////////////////////////////////////////////
1081 * class simulating DB access
1083 class DAO : public DPL::Noncopyable
1086 DAO() : m_boolValue(false) {}
1088 void SetBoolValue(const bool& value)
1090 m_boolValue = value;
1093 bool GetBoolValue() const
1103 * Model with property having set delegate defined
1105 class MyModel3 : public DPL::Model
1108 typedef SharedPropertyEx<bool,
1109 TestSharedObject4::BOOLEAN,
1110 TestSharedObject4> PropertyType;
1112 MyModel3(const TestSharedObject4Ptr& shared_object, DAO* dao) :
1115 PropertyType::SetDelegate(dao, &DAO::SetBoolValue))
1118 PropertyType boolValue;
1121 RUNNER_TEST(SharedMemory_090_SetPropertyDelegate)
1128 // create shared object
1129 TestSharedObject4Ptr sho = TestSharedObject4::Create();
1131 // set property but call dao delegate within semaphore
1132 sho->SetProperty<TestSharedObject4::BOOLEAN>(
1134 MyModel3::PropertyType::SetDelegate(&dao, &DAO::SetBoolValue));
1137 RUNNER_ASSERT(dao.GetBoolValue() == true);
1139 // check shared object value
1140 bool shoValue = sho->GetProperty<TestSharedObject4::BOOLEAN, bool>();
1141 RUNNER_ASSERT(shoValue == true);
1143 // try the same with shared property
1144 MyModel3 model(sho, &dao);
1147 model.boolValue.Set(false);
1150 RUNNER_ASSERT(dao.GetBoolValue() == false);
1153 shoValue = sho->GetProperty<TestSharedObject4::BOOLEAN, bool>();
1154 RUNNER_ASSERT(shoValue == false);
1156 // check property value
1157 RUNNER_ASSERT(model.boolValue.Get() == false);
1160 //////////////////////////////////////////////
1163 * Lazy initialization test shared object
1165 class LazySharedObject : public SharedObject<TestTypeList>
1168 LazySharedObject() :
1173 explicit LazySharedObject(const std::string& semaphore) :
1174 SharedObject<TestTypeList>(semaphore)
1186 friend class SharedObjectFactory<LazySharedObject>;
1191 void LazySharedObject::Init()
1193 SetPropertyInternal<0>(42);
1197 RUNNER_TEST(SharedMemory_100_LazyInit)
1201 typedef std::shared_ptr<LazySharedObject> LazySharedObjectPtr;
1203 // create shared object
1204 LazySharedObjectPtr sho = SharedObjectFactory<LazySharedObject>::Create(
1207 RUNNER_ASSERT(sho->IsRead() == false);
1209 // get property causing lazy init
1210 int value = sho->GetProperty<0, int>();
1212 RUNNER_ASSERT(sho->IsRead() == true);
1213 RUNNER_ASSERT(value == 42);
1215 // create another object
1216 LazySharedObjectPtr sho2 = SharedObjectFactory<LazySharedObject>::Create(
1219 RUNNER_ASSERT(sho2->IsRead() == false);
1221 // get property NOT causing lazy init
1222 value = sho2->GetProperty<0, int>();
1224 RUNNER_ASSERT(sho2->IsRead() == false);
1225 RUNNER_ASSERT(value == 42);
1227 // destroy both objects
1231 // create shared object
1232 LazySharedObjectPtr sho3 = SharedObjectFactory<LazySharedObject>::Create(
1235 RUNNER_ASSERT(sho3->IsRead() == false);
1237 // set property causing lazy init
1238 sho3->SetProperty<0>(43);
1239 value = sho3->GetProperty<0, int>();
1241 RUNNER_ASSERT(sho3->IsRead() == true);
1242 RUNNER_ASSERT(value == 43);
1245 //////////////////////////////////////////////
1247 bool SetCondition(const int& readValue, int& setValue);
1248 bool SetCondition(const int& readValue, int& setValue)
1250 WrtLogD("Condition delegate called with read value = %i and set value = %i",
1251 readValue, setValue);
1253 if (readValue > 3) {
1254 WrtLogD("Condition is false");
1258 WrtLogD("Condition is true");
1259 if (4 == setValue) {
1261 WrtLogD("Changing set value to %i", setValue);
1266 void SetDelegate(const int& readValue);
1267 void SetDelegate(const int& readValue)
1269 WrtLogD("Set delegate called %i", readValue);
1273 RUNNER_TEST(SharedMemory_120_ConditionalSet)
1277 TestSharedObjectPtr sho = SharedObjectFactory<TestSharedObject>::Create(
1281 g_delegateCalls = 0;
1283 RUNNER_ASSERT(0 == (sho->GetProperty<0, int>()));
1285 std::function<bool (const int&, int&)> condition = SetCondition;
1286 std::function<void (const int&)> delegate = SetDelegate;
1288 bool succeeded = false;
1290 succeeded = sho->ConditionalSetProperty<0>(-2, condition);
1292 RUNNER_ASSERT(succeeded);
1293 RUNNER_ASSERT(-2 == (sho->GetProperty<0, int>()));
1295 succeeded = sho->ConditionalSetProperty<0>(4, condition, delegate);
1297 RUNNER_ASSERT(succeeded);
1298 RUNNER_ASSERT(10 == (sho->GetProperty<0, int>()));
1299 RUNNER_ASSERT(1 == g_delegateCalls);
1301 succeeded = sho->ConditionalSetProperty<0>(5, condition);
1303 RUNNER_ASSERT(!succeeded);
1304 RUNNER_ASSERT(10 == (sho->GetProperty<0, int>()));
1306 succeeded = sho->ConditionalSetProperty<0>(666, condition, delegate);
1308 RUNNER_ASSERT(!succeeded);
1309 RUNNER_ASSERT(10 == (sho->GetProperty<0, int>()));
1310 RUNNER_ASSERT(1 == g_delegateCalls);
1313 //////////////////////////////////////////////
1316 * Shared object used by multiple threads as a singleton.
1318 class MTSharedObject : public SharedObject<TestTypeList>
1321 explicit MTSharedObject(const std::string& semaphore) :
1322 SharedObject<TestTypeList>(semaphore)
1328 friend class SharedObjectFactory<MTSharedObject>;
1331 typedef std::shared_ptr<MTSharedObject> MTSharedObjectPtr;
1333 void MTSharedObject::Clear()
1338 SetProperty<2>(static_cast<char>(0));
1339 SetProperty<3>(array);
1343 * Shared object singleton
1345 class SharedObjectSingleton
1348 static MTSharedObjectPtr Instance();
1349 static void Destroy();
1352 static MTSharedObjectPtr m_sho;
1353 static std::mutex m_mutex;
1356 MTSharedObjectPtr SharedObjectSingleton::m_sho;
1357 std::mutex SharedObjectSingleton::m_mutex;
1359 MTSharedObjectPtr SharedObjectSingleton::Instance()
1361 std::lock_guard<std::mutex> lock(m_mutex);
1363 m_sho = SharedObjectFactory<MTSharedObject>::Create(SHM_KEY, SEM_NAME);
1368 void SharedObjectSingleton::Destroy()
1370 std::lock_guard<std::mutex> lock(m_mutex);
1375 * Listening controller
1377 class ShmController4 : public ListeningController<MTSharedObject>,
1378 public ISharedObjectListener<0, int>,
1379 public ISharedObjectListener<1, int>,
1380 public ISharedObjectListener<2, char>,
1381 public ISharedObjectListener<3, int[64]>
1386 REMOVE_LISTENERS = 3,
1387 DESTROY_SINGLETON = 4
1390 explicit ShmController4(DPL::WaitableEvent* event) :
1391 ListeningController<MTSharedObject>(event),
1395 virtual void OnEventReceived(const int& event);
1397 virtual void ValueChanged(size_t propertyEnum,
1399 const void* info = NULL);
1400 virtual void ValueChanged(size_t propertyEnum,
1402 const void* info = NULL);
1403 virtual void ValueChanged(size_t propertyEnum,
1404 const int(&value)[64],
1405 const void* info = NULL);
1407 bool NotRegistered();
1413 static unsigned int seed = time(NULL);
1416 void ShmController4::ValueChanged(size_t propertyEnum,
1418 const void* /*info*/)
1420 WrtLogD("ValueChanged(int) %u %i", propertyEnum, value);
1421 if ((propertyEnum == 0 && value == 1) ||
1422 (propertyEnum == 1 && value == 11))
1424 m_waitable->Signal();
1428 void ShmController4::ValueChanged(size_t propertyEnum,
1430 const void* /*info*/)
1432 WrtLogD("ValueChanged(char) %u %i", propertyEnum, value);
1433 if (propertyEnum == 2 && value == 'a') {
1434 m_waitable->Signal();
1438 void ShmController4::ValueChanged(size_t propertyEnum,
1439 const int(&value)[64],
1440 const void* /*info*/)
1442 WrtLogD("ValueChanged(int[64]) %u %i", propertyEnum, value[5]);
1443 if (propertyEnum == 3 && value[0] == 0 && value[1] == 1 && value[2] == 2) {
1444 m_waitable->Signal();
1448 void ShmController4::Sleep()
1450 DPL::Thread::GetCurrentThread()->MiliSleep(
1451 rand_r(&seed) % MAX_SINGLETON_LISTENER_DELAY);
1454 void ShmController4::OnEventReceived(const int& event)
1458 m_so = SharedObjectSingleton::Instance();
1459 m_waitable->Signal();
1463 WrtLogD("Destroying shared object");
1464 // deregister, destroy and notify main thread
1466 m_waitable->Signal();
1470 // add listener and notify
1471 m_so->AddListener<0, int>(this);
1473 m_so->AddListener<1, int>(this);
1475 m_so->AddListener<2, char>(this);
1477 m_so->AddListener<3, int[64]>(this);
1479 m_waitable->Signal();
1482 case REMOVE_LISTENERS:
1483 // remove listener and notify
1484 m_so->RemoveListener<0, int>(this);
1486 m_so->RemoveListener<1, int>(this);
1488 m_so->RemoveListener<2, char>(this);
1490 m_so->RemoveListener<3, int[64]>(this);
1492 m_waitable->Signal();
1495 case DESTROY_SINGLETON:
1496 SharedObjectSingleton::Destroy();
1497 m_waitable->Signal();
1501 WrtLogE("Unsupported event received: %i", event);
1505 void MultipleWait(DPL::WaitableEvent(&event)[MAX_THREADS]);
1506 void MultipleWait(DPL::WaitableEvent(&event)[MAX_THREADS])
1508 for (size_t i = 0; i < MAX_THREADS; ++i) {
1514 * Try to remove property listener. If there's no such listener an exception
1517 #define LISTENER_ASSERT(property) \
1519 singleton->RemoveListener<(property)>(controller[i]); \
1520 WrtLogE("Controller %i is still listening for property %s" \
1522 RUNNER_ASSERT_MSG(false, "No listeners expected"); \
1524 Catch(MTSharedObject::Exception::ListenerNotFound) { \
1525 RUNNER_ASSERT(true); \
1529 RUNNER_TEST(SharedMemory_130_SharedObjectSingleton)
1531 RemoveIpcs(); // we need non existing shm
1533 // writer shared object
1534 TestSharedObjectPtr sho = SharedObjectFactory<TestSharedObject>::Create(
1537 ShmController4* controller[MAX_THREADS];
1538 DPL::WaitableEvent waitable[MAX_THREADS];
1540 const int array[64] = { 0, 1, 2 };
1542 // Create and wait for notification. Make sure that the thread/controller 0
1544 WrtLogD("Creating controllers");
1545 for (size_t i = 0; i < MAX_THREADS; ++i) {
1546 controller[i] = new ShmController4(&waitable[i]);
1550 // singleton will be created by thread/controller 0 by now
1551 MTSharedObjectPtr singleton = SharedObjectSingleton::Instance();
1553 for (size_t repeats = 0; repeats < SINGLETON_TEST_REPEATS; ++repeats) {
1554 WrtLogD("%%%%%%%%%%%%%%%%%%%%%");
1555 WrtLogD("Iteration %u of %u", repeats + 1, SINGLETON_TEST_REPEATS);
1559 WrtLogD("Adding listeners");
1560 for (size_t i = 0; i < MAX_THREADS; ++i) {
1561 controller[i]->PostEvent(ShmController4::ADD_LISTENERS);
1563 // wait for listeners
1564 MultipleWait(waitable);
1566 RUNNER_ASSERT((singleton->GetProperty<0, int>()) == 0);
1567 RUNNER_ASSERT((singleton->GetProperty<1, int>()) == 0);
1568 RUNNER_ASSERT((singleton->GetProperty<2, char>()) == 0);
1570 int checkArray[64] = {};
1571 singleton->GetProperty<3>(checkArray);
1572 RUNNER_ASSERT(checkArray[0] == 0);
1573 RUNNER_ASSERT(checkArray[1] == 0);
1574 RUNNER_ASSERT(checkArray[2] == 0);
1577 WrtLogD("Setting property 0");
1578 sho->SetProperty<0>(1);
1579 // wait for confirmations
1580 MultipleWait(waitable);
1583 WrtLogD("Setting property 1");
1584 sho->SetProperty<1>(11);
1585 // wait for confirmations
1586 MultipleWait(waitable);
1589 WrtLogD("Setting property 2");
1590 sho->SetProperty<2>('a');
1591 // wait for confirmations
1592 MultipleWait(waitable);
1595 WrtLogD("Setting property 3");
1596 sho->SetProperty<3>(array);
1597 // wait for confirmations
1598 MultipleWait(waitable);
1601 WrtLogD("Removing listeners");
1602 for (size_t i = 0; i < MAX_THREADS; ++i) {
1603 controller[i]->PostEvent(ShmController4::REMOVE_LISTENERS);
1605 // wait for listeners
1606 MultipleWait(waitable);
1608 // check if listeners array is empty
1609 WrtLogD("Checking listeners");
1610 for (size_t i = 0; i < MAX_THREADS; ++i) {
1617 RUNNER_ASSERT((singleton->GetProperty<0, int>()) == 1);
1618 RUNNER_ASSERT((singleton->GetProperty<1, int>()) == 11);
1619 RUNNER_ASSERT((singleton->GetProperty<2, char>()) == 'a');
1620 singleton->GetProperty<3>(checkArray);
1621 RUNNER_ASSERT(checkArray[0] == 0);
1622 RUNNER_ASSERT(checkArray[1] == 1);
1623 RUNNER_ASSERT(checkArray[2] == 2);
1628 // Destroy controllers and wait for confirmation. Make sure that
1629 // thread/controller 0 is destroyed in the end
1630 WrtLogD("Destroying controllers");
1631 for (int i = MAX_THREADS - 1; i >= 0; --i) {
1632 controller[i]->PostEvent(DESTROY_EVENT);
1636 * Destroy singleton before thread that created it finishes.
1637 * This is to properly close all waitable handles opened by
1638 * SharedObject in thread 0.
1640 WrtLogD("Destroying singleton");
1641 controller[i]->PostEvent(ShmController4::DESTROY_SINGLETON);
1644 delete controller[i];
1648 #undef LISTENER_ASSERT
1651 * test preconditions & postconditions:
1652 * - no existing shared memory with given SHM_KEY
1653 * - no existing semaphore of given SEM_NAME
1655 RUNNER_TEST(SharedMemory_001_Preconditions) {
1659 RUNNER_TEST(SharedMemory_999_Postconditions) {