diff options
Diffstat (limited to 'org.genivi.commonapi.core.verification/src/CMAttributeSubscription.cpp')
-rw-r--r-- | org.genivi.commonapi.core.verification/src/CMAttributeSubscription.cpp | 661 |
1 files changed, 621 insertions, 40 deletions
diff --git a/org.genivi.commonapi.core.verification/src/CMAttributeSubscription.cpp b/org.genivi.commonapi.core.verification/src/CMAttributeSubscription.cpp index d7e9c9d..4a0c01c 100644 --- a/org.genivi.commonapi.core.verification/src/CMAttributeSubscription.cpp +++ b/org.genivi.commonapi.core.verification/src/CMAttributeSubscription.cpp @@ -18,14 +18,18 @@ #include "CommonAPI/CommonAPI.hpp" #include "v1_0/commonapi/communication/TestInterfaceProxy.hpp" #include "v1_0/commonapi/communication/TestInterfaceStubDefault.hpp" +#include "v1_0/commonapi/communication/DaemonStubDefault.hpp" +#include "stub/CMAttributesStub.h" -const std::string serviceId = "service-sample"; +const std::string daemonId = "service-sample"; const std::string clientId = "client-sample"; +const std::string serviceId = "test-service"; const std::string domain = "local"; const std::string testAddress = "commonapi.communication.TestInterface"; +const std::string daemonAddress = "commonapi.communication.Daemon"; -const unsigned int wt = 500000; +const unsigned int wt = 100000; typedef std::shared_ptr<v1_0::commonapi::communication::TestInterfaceProxy<>> ProxyPtr; @@ -33,6 +37,8 @@ std::mutex mut; std::deque<uint32_t> data_queue; std::condition_variable data_cond; +using namespace v1_0::commonapi::communication; + class SubscriptionHandler { public: @@ -65,7 +71,17 @@ public: /* for test purposes, magic value 99 unsubscribes the attribute. */ if (val == 99) { - cancelSubscribe(); + + // We can't call cancleSubscribe() within the async handler + // because it lead to a dead lock with the SomeIP-binding. + // Therefore we unsubscribe within the main thread of the test case! + // + // The reason for the dead lock is because within the async handler + // the connection thread is holding the Connection::sendReceiveMutex_ + // which will locked again when calling Connection::removeEventHandler + // which is implicitly called when unsubscribing! + + // cancelSubscribe(); } } @@ -93,6 +109,10 @@ public: return testAttribute_; } + void resetSubcriptedTestAttribute() { + testAttribute_ = 0; + } + std::deque<uint8_t> myQueue_; private: @@ -138,6 +158,67 @@ private: uint8_t notOkAttribute_; }; +class ThreeCallbackHandler { +public: + ThreeCallbackHandler() : + callbackCounter_1_(0), + callbackCounter_2_(0), + callbackCounter_3_(0), + callbackValue_1_(0), + callbackValue_2_(0), + callbackValue_3_(0) { + + } + + void callback_1(const uint8_t& val) { + callbackCounter_1_++; + callbackValue_1_ = val; + } + + void callback_2(const uint8_t& val) { + callbackCounter_2_++; + callbackValue_2_ = val; + } + + void callback_3(const uint8_t& val) { + callbackCounter_3_++; + callbackValue_3_ = val; + } + + uint8_t getCallbackCounter_1() { + return callbackCounter_1_; + } + + uint8_t getCallbackCounter_2() { + return callbackCounter_2_; + } + + uint8_t getCallbackCounter_3() { + return callbackCounter_3_; + } + + uint8_t getCallbackValue_1() { + return callbackValue_1_; + } + + uint8_t getCallbackValue_2() { + return callbackValue_2_; + } + + uint8_t getCallbackValue_3() { + return callbackValue_3_; + } + +private: + uint8_t callbackCounter_1_; + uint8_t callbackCounter_2_; + uint8_t callbackCounter_3_; + + uint8_t callbackValue_1_; + uint8_t callbackValue_2_; + uint8_t callbackValue_3_; +}; + void testSubscription(ProxyPtr pp) { SubscriptionHandler subscriptionHandler(pp); @@ -169,19 +250,29 @@ protected: runtime_ = CommonAPI::Runtime::get(); ASSERT_TRUE((bool)runtime_); - testProxy_ = runtime_->buildProxy<v1_0::commonapi::communication::TestInterfaceProxy>(domain, testAddress, clientId); + testProxy_ = runtime_->buildProxy<TestInterfaceProxy>(domain, testAddress, clientId); ASSERT_TRUE((bool)testProxy_); - testStub_ = std::make_shared<v1_0::commonapi::communication::TestInterfaceStubDefault>(); + testStub_ = std::make_shared<TestInterfaceStubDefault>(); + + deregisterService_ = false; } void TearDown() { + // secure, that service is deregistered by finishing the test + if (deregisterService_) { + bool isUnregistered = runtime_->unregisterService(domain, + TestInterfaceStubDefault::StubInterface::getInterface(), testAddress); + ASSERT_TRUE(isUnregistered); + } } std::shared_ptr<CommonAPI::Runtime> runtime_; - std::shared_ptr<v1_0::commonapi::communication::TestInterfaceProxy<>> testProxy_; - std::shared_ptr<v1_0::commonapi::communication::TestInterfaceStubDefault> testStub_; + std::shared_ptr<TestInterfaceProxy<>> testProxy_; + std::shared_ptr<TestInterfaceStubDefault> testStub_; + + bool deregisterService_; }; class Environment: public ::testing::Environment { @@ -191,12 +282,17 @@ public: } virtual void SetUp() { + stubDaemon_ = std::make_shared<DaemonStubDefault>(); + CommonAPI::Runtime::get()->registerService(domain, daemonAddress, stubDaemon_, daemonId); } virtual void TearDown() { + CommonAPI::Runtime::get()->unregisterService(domain, DaemonStubDefault::StubInterface::getInterface(), + daemonAddress); } private: + std::shared_ptr<DaemonStubDefault> stubDaemon_; }; /** @@ -210,35 +306,58 @@ private: */ TEST_F(CMAttributeSubscription, SubscriptionStandard) { + deregisterService_ = true; + + uint8_t defaultValue = 33; + + // initialize test stub with default value + testStub_->setTestAttributeAttribute(defaultValue); + bool serviceRegistered = runtime_->registerService(domain, testAddress, testStub_, serviceId); ASSERT_TRUE(serviceRegistered); - for(unsigned int i = 0; !testProxy_->isAvailable() && i < 100; ++i) { - usleep(10000); - } + testProxy_->isAvailableBlocking(); ASSERT_TRUE(testProxy_->isAvailable()); SubscriptionHandler subscriptionHandler(testProxy_); - std::function<void (const uint8_t&)> myCallback = std::bind(&SubscriptionHandler::myCallback, &subscriptionHandler, std::placeholders::_1); - //CommonAPI::Event<uint8_t>::Subscription subscribedListener = - testProxy_->getTestAttributeAttribute().getChangedEvent().subscribe(myCallback); + std::function<void (const uint8_t&)> myCallback = + std::bind(&SubscriptionHandler::myCallback, &subscriptionHandler, std::placeholders::_1); + + CommonAPI::Event<uint8_t>::Subscription subscribedListener = + testProxy_->getTestAttributeAttribute().getChangedEvent().subscribe(myCallback); const uint8_t testNumber = 10; for (uint8_t i=1; i<testNumber+1; i++) { - testStub_->setTestAttributeAttribute(i); + usleep(100000); + testStub_->setTestAttributeAttribute(i); } usleep(wt); - ASSERT_EQ(subscriptionHandler.myQueue_.size(), testNumber); + ASSERT_EQ(subscriptionHandler.myQueue_.size(), testNumber + 1); // + 1 due to the reason, that by subscribtion the current value is returned - uint8_t t = 1; + uint8_t t = 0; for(std::deque<uint8_t>::iterator it = subscriptionHandler.myQueue_.begin(); it != subscriptionHandler.myQueue_.end(); ++it) { - EXPECT_EQ(*it, t); - t++; + if (t == 0) { + EXPECT_EQ(*it, defaultValue); + t++; + } else { + EXPECT_EQ(*it, t); + t++; + } } - runtime_->unregisterService(domain, v1_0::commonapi::communication::TestInterfaceStubDefault::StubInterface::getInterface(), testAddress); + + testProxy_->getTestAttributeAttribute().getChangedEvent().unsubscribe(subscribedListener); + + bool isUnregistered = runtime_->unregisterService(domain, + TestInterfaceStubDefault::StubInterface::getInterface(), testAddress); + ASSERT_TRUE(isUnregistered); + + usleep(wt); + + deregisterService_ = !isUnregistered; } + /** * @test Subscription test with subscription on available-event. * - Subscribe for available-event. @@ -252,7 +371,8 @@ TEST_F(CMAttributeSubscription, SubscriptionOnAvailable) { SubscriptionHandler subscriptionHandler(testProxy_); - std::function<void (CommonAPI::AvailabilityStatus)> callbackAvailabilityStatus = std::bind(&SubscriptionHandler::receiveServiceAvailable, &subscriptionHandler, std::placeholders::_1); + std::function<void (CommonAPI::AvailabilityStatus)> callbackAvailabilityStatus = + std::bind(&SubscriptionHandler::receiveServiceAvailable, &subscriptionHandler, std::placeholders::_1); testProxy_->getProxyStatusEvent().subscribe(callbackAvailabilityStatus); testStub_->setTestAttributeAttribute(1); @@ -262,11 +382,14 @@ TEST_F(CMAttributeSubscription, SubscriptionOnAvailable) { bool serviceRegistered = runtime_->registerService(domain, testAddress, testStub_, serviceId); ASSERT_TRUE(serviceRegistered); usleep(wt); + testProxy_->isAvailableBlocking(); + ASSERT_TRUE(testProxy_->isAvailable()); testStub_->setTestAttributeAttribute(2); usleep(wt); ASSERT_EQ(subscriptionHandler.getSubscriptedTestAttribute(), 2); - bool serviceUnregistered = runtime_->unregisterService(domain, v1_0::commonapi::communication::TestInterfaceStubDefault::StubInterface::getInterface(), testAddress); + bool serviceUnregistered = runtime_->unregisterService(domain, + TestInterfaceStubDefault::StubInterface::getInterface(), testAddress); ASSERT_TRUE(serviceUnregistered); usleep(wt); ASSERT_EQ(subscriptionHandler.getAvailabilityStatus(), CommonAPI::AvailabilityStatus::NOT_AVAILABLE); @@ -307,7 +430,8 @@ TEST_F(CMAttributeSubscription, SubscriptionMultithreading) { usleep(wt); - bool serviceUnregistered = runtime_->unregisterService(domain, v1_0::commonapi::communication::TestInterfaceStubDefault::StubInterface::getInterface(), testAddress); + bool serviceUnregistered = runtime_->unregisterService(domain, + TestInterfaceStubDefault::StubInterface::getInterface(), testAddress); ASSERT_TRUE(serviceUnregistered); uint32_t data = 0; @@ -354,15 +478,14 @@ TEST_F(CMAttributeSubscription, SubscriptionUnsubscribeFromCallback) { bool serviceRegistered = runtime_->registerService(domain, testAddress, testStub_, serviceId); ASSERT_TRUE(serviceRegistered); - for(unsigned int i = 0; !testProxy_->isAvailable() && i < 100; ++i) { - usleep(10000); - } + testProxy_->isAvailableBlocking(); ASSERT_TRUE(testProxy_->isAvailable()); SubscriptionHandler subscriptionHandler(testProxy_); - std::function<void (const uint8_t&)> myCallback = std::bind(&SubscriptionHandler::myCallback, &subscriptionHandler, std::placeholders::_1); - subscriptionHandler.startSubscribe(); + std::function<void (const uint8_t&)> myCallback = std::bind(&SubscriptionHandler::myCallback, + &subscriptionHandler, std::placeholders::_1); + subscriptionHandler.startSubscribe(); testStub_->setTestAttributeAttribute(42); usleep(wt); @@ -372,11 +495,16 @@ TEST_F(CMAttributeSubscription, SubscriptionUnsubscribeFromCallback) { usleep(wt); EXPECT_EQ(subscriptionHandler.getSubscriptedTestAttribute(), 99); + subscriptionHandler.cancelSubscribe(); + usleep(wt); + testStub_->setTestAttributeAttribute(250); usleep(wt); EXPECT_EQ(subscriptionHandler.getSubscriptedTestAttribute(), 99); - runtime_->unregisterService(domain, v1_0::commonapi::communication::TestInterfaceStubDefault::StubInterface::getInterface(), testAddress); + bool isUnregistered = runtime_->unregisterService(domain, + TestInterfaceStubDefault::StubInterface::getInterface(), testAddress); + ASSERT_TRUE(isUnregistered); } /** @@ -395,8 +523,10 @@ TEST_F(CMAttributeSubscription, SubscribeAndUnsubscribeTwoCallbacksCoexistent) { CommonAPI::Event<uint8_t>::Subscription subscribedListenerCallOk; CommonAPI::Event<uint8_t>::Subscription subscribedListenerCallNotOk; - std::function<void (uint8_t)> callbackOk = std::bind(&SubscribeUnsubscribeHandler::okCallback, &subUnsubHandler, std::placeholders::_1); - std::function<void (uint8_t)> callbackNotOk = std::bind(&SubscribeUnsubscribeHandler::notOkCallback, &subUnsubHandler, std::placeholders::_1); + std::function<void (uint8_t)> callbackOk = + std::bind(&SubscribeUnsubscribeHandler::okCallback, &subUnsubHandler, std::placeholders::_1); + std::function<void (uint8_t)> callbackNotOk = + std::bind(&SubscribeUnsubscribeHandler::notOkCallback, &subUnsubHandler, std::placeholders::_1); subscribedListenerCallOk = testProxy_->getTestAttributeAttribute().getChangedEvent().subscribe(callbackOk); subscribedListenerCallNotOk = testProxy_->getTestAttributeAttribute().getChangedEvent().subscribe(callbackNotOk); @@ -408,7 +538,10 @@ TEST_F(CMAttributeSubscription, SubscribeAndUnsubscribeTwoCallbacksCoexistent) { bool serviceRegistered = runtime_->registerService(domain, testAddress, testStub_, serviceId); ASSERT_TRUE(serviceRegistered); - usleep(wt); + + testProxy_->isAvailableBlocking(); + ASSERT_TRUE(testProxy_->isAvailable()); + testStub_->setTestAttributeAttribute(2); usleep(wt); EXPECT_EQ(subUnsubHandler.getSubscribedOkAttribute(), 2); @@ -422,7 +555,7 @@ TEST_F(CMAttributeSubscription, SubscribeAndUnsubscribeTwoCallbacksCoexistent) { EXPECT_EQ(subUnsubHandler.getSubscribedOkAttribute(), 2); EXPECT_EQ(subUnsubHandler.getSubscribedNotOkAttribute(), 2); - bool serviceUnregistered = runtime_->unregisterService(domain, v1_0::commonapi::communication::TestInterfaceStubDefault::StubInterface::getInterface(), testAddress); + bool serviceUnregistered = runtime_->unregisterService(domain, TestInterfaceStubDefault::StubInterface::getInterface(), testAddress); ASSERT_TRUE(serviceUnregistered); usleep(wt); } @@ -442,12 +575,16 @@ TEST_F(CMAttributeSubscription, SubscribeAndUnsubscribeImmediatelyUnsubscribing) CommonAPI::Event<uint8_t>::Subscription subscribedListenerCallOk; CommonAPI::Event<uint8_t>::Subscription subscribedListenerCallNotOk; - std::function<void (uint8_t)> callbackOk = std::bind(&SubscribeUnsubscribeHandler::okCallback, &subUnsubHandler, std::placeholders::_1); - std::function<void (uint8_t)> callbackNotOk = std::bind(&SubscribeUnsubscribeHandler::notOkCallback, &subUnsubHandler, std::placeholders::_1); + std::function<void (uint8_t)> callbackOk = + std::bind(&SubscribeUnsubscribeHandler::okCallback, &subUnsubHandler, std::placeholders::_1); + std::function<void (uint8_t)> callbackNotOk = + std::bind(&SubscribeUnsubscribeHandler::notOkCallback, &subUnsubHandler, std::placeholders::_1); bool serviceRegistered = runtime_->registerService(domain, testAddress, testStub_, serviceId); ASSERT_TRUE(serviceRegistered); - usleep(wt); + + testProxy_->isAvailableBlocking(); + ASSERT_TRUE(testProxy_->isAvailable()); // subscribe ok callback subscribedListenerCallOk = testProxy_->getTestAttributeAttribute().getChangedEvent().subscribe(callbackOk); @@ -470,7 +607,7 @@ TEST_F(CMAttributeSubscription, SubscribeAndUnsubscribeImmediatelyUnsubscribing) testProxy_->getTestAttributeAttribute().getChangedEvent().unsubscribe(subscribedListenerCallNotOk); testProxy_->getTestAttributeAttribute().getChangedEvent().unsubscribe(subscribedListenerCallOk); - bool serviceUnregistered = runtime_->unregisterService(domain, v1_0::commonapi::communication::TestInterfaceStubDefault::StubInterface::getInterface(), testAddress); + bool serviceUnregistered = runtime_->unregisterService(domain, TestInterfaceStubDefault::StubInterface::getInterface(), testAddress); ASSERT_TRUE(serviceUnregistered); usleep(wt); } @@ -495,12 +632,16 @@ TEST_F(CMAttributeSubscription, SubscribeAndUnsubscribeSequentially) { CommonAPI::Event<uint8_t>::Subscription subscribedListenerCallOk; CommonAPI::Event<uint8_t>::Subscription subscribedListenerCallNotOk; - std::function<void (uint8_t)> callbackOk = std::bind(&SubscribeUnsubscribeHandler::okCallback, &subUnsubHandler, std::placeholders::_1); - std::function<void (uint8_t)> callbackNotOk = std::bind(&SubscribeUnsubscribeHandler::notOkCallback, &subUnsubHandler, std::placeholders::_1); + std::function<void (uint8_t)> callbackOk = + std::bind(&SubscribeUnsubscribeHandler::okCallback, &subUnsubHandler, std::placeholders::_1); + std::function<void (uint8_t)> callbackNotOk = + std::bind(&SubscribeUnsubscribeHandler::notOkCallback, &subUnsubHandler, std::placeholders::_1); bool serviceRegistered = runtime_->registerService(domain, testAddress, testStub_, serviceId); ASSERT_TRUE(serviceRegistered); - usleep(wt); + + testProxy_->isAvailableBlocking(); + ASSERT_TRUE(testProxy_->isAvailable()); // subscribe ok and notOk callback subscribedListenerCallOk = testProxy_->getTestAttributeAttribute().getChangedEvent().subscribe(callbackOk); @@ -527,11 +668,451 @@ TEST_F(CMAttributeSubscription, SubscribeAndUnsubscribeSequentially) { EXPECT_EQ(subUnsubHandler.getSubscribedOkAttribute(), 12); EXPECT_EQ(subUnsubHandler.getSubscribedNotOkAttribute(), 14); - bool serviceUnregistered = runtime_->unregisterService(domain, v1_0::commonapi::communication::TestInterfaceStubDefault::StubInterface::getInterface(), testAddress); + bool serviceUnregistered = runtime_->unregisterService(domain, TestInterfaceStubDefault::StubInterface::getInterface(), testAddress); ASSERT_TRUE(serviceUnregistered); usleep(wt); } + +/** + * @test Test of behaviour in case unsubscribe is called two times + * - set default value + * - register service + * - subscribe for the attribute + * - current value must be communicated to the proxy + * - value of attribute is changed + * - changed value must be communicated to the proxy + * - proxy unsubscribes for the attribute + * - value of attribute is changed + * - changed value must not be communicated to the proxy + * - proxy unsubscribes again for the attribute + * - value of attribute is changed + * - changed value must not be communicated to the proxy + * - unregister service + */ +TEST_F(CMAttributeSubscription, SubscribeAndUnsubscribeUnsubscribe) { + + testStub_->setTestAttributeAttribute(42); + + bool serviceRegistered = runtime_->registerService(domain, testAddress, testStub_, serviceId); + ASSERT_TRUE(serviceRegistered); + + testProxy_->isAvailableBlocking(); + ASSERT_TRUE(testProxy_->isAvailable()); + + SubscriptionHandler subscriptionHandler(testProxy_); + std::function<void (const uint8_t&)> myCallback = + std::bind(&SubscriptionHandler::myCallback, &subscriptionHandler, std::placeholders::_1); + + CommonAPI::Event<uint8_t>::Subscription subscribedListener = + testProxy_->getTestAttributeAttribute().getChangedEvent().subscribe(myCallback); + + usleep(wt); + + // check for initial value + EXPECT_EQ(subscriptionHandler.getSubscriptedTestAttribute(), 42); + + testStub_->setTestAttributeAttribute(12); + usleep(wt); + + // check for changed value + EXPECT_EQ(subscriptionHandler.getSubscriptedTestAttribute(), 12); + + testProxy_->getTestAttributeAttribute().getChangedEvent().unsubscribe(subscribedListener); + + testStub_->setTestAttributeAttribute(24); + usleep(wt); + + // value must not be changed + EXPECT_EQ(subscriptionHandler.getSubscriptedTestAttribute(), 12); + + testProxy_->getTestAttributeAttribute().getChangedEvent().unsubscribe(subscribedListener); + + testStub_->setTestAttributeAttribute(26); + usleep(wt); + + // value must not be changed + EXPECT_EQ(subscriptionHandler.getSubscriptedTestAttribute(), 12); + + bool serviceUnregistered = runtime_->unregisterService(domain, TestInterfaceStubDefault::StubInterface::getInterface(), testAddress); + ASSERT_TRUE(serviceUnregistered); + usleep(wt); +} + +/** + * @test Test of subscribing in case that service is not available + * - set default value + * - subscribe for the attribute + * - no value is communicated to the proxy + * - register service + * - current value must be communicated to the proxy + * - value of attribute is changed + * - changed value must be communicated to the proxy + * - unregister service + */ +TEST_F(CMAttributeSubscription, SubscribeServiceNotAvailable) { + + deregisterService_ = true; + + uint8_t defaultValue = 33; + + // initialize test stub with default value + testStub_->setTestAttributeAttribute(defaultValue); + + // subscribe for attribute change by the proxy + SubscriptionHandler subscriptionHandler(testProxy_); + std::function<void (const uint8_t&)> myCallback = + std::bind(&SubscriptionHandler::myCallback, &subscriptionHandler, std::placeholders::_1); + + testProxy_->getTestAttributeAttribute().getChangedEvent().subscribe(myCallback); + + usleep(wt); + EXPECT_EQ(subscriptionHandler.getSubscriptedTestAttribute(), 0); + + // register service + bool serviceRegistered = runtime_->registerService(domain, testAddress, testStub_, serviceId); + ASSERT_TRUE(serviceRegistered); + + testProxy_->isAvailableBlocking(); + ASSERT_TRUE(testProxy_->isAvailable()); + + usleep(wt); + + // check received attribute value + EXPECT_EQ(subscriptionHandler.getSubscriptedTestAttribute(), defaultValue); + + int8_t newValue = 123; + + testStub_->setTestAttributeAttribute(newValue); + usleep(wt); + + EXPECT_EQ(subscriptionHandler.getSubscriptedTestAttribute(), newValue); + + bool isUnregistered = runtime_->unregisterService(domain, + TestInterfaceStubDefault::StubInterface::getInterface(), testAddress); + ASSERT_TRUE(isUnregistered); + + deregisterService_ = !isUnregistered; +} + +/** + * @test Test of unregister a service in case a proxy is subscribed for an attribute of this service. + * During the unregistered time of the service the value of the attribute is changed. + * - register service + * - proxy subscribes for an attribute of the service + * - value of attribute is set + * - changed value must be communicated to the proxy + * - unregister service + * - value of attribute is changed + * - changed value must not be communicated to the proxy + * - register service + * - current attribute value must be communicated to the proxy + * - value of attribute is changed + * - changed value must be communicated to the proxy + * - unregister service + */ +TEST_F(CMAttributeSubscription, SubscribeUnregisterSetValueRegisterService) { + deregisterService_ = true; + + uint8_t firstValue = 35; + uint8_t secondValue = 43; + uint8_t thirdValue = 198; + + // register service + bool serviceRegistered = runtime_->registerService(domain, testAddress, testStub_, serviceId); + ASSERT_TRUE(serviceRegistered); + + testProxy_->isAvailableBlocking(); + ASSERT_TRUE(testProxy_->isAvailable()); + + // subscribe for attribute change by the proxy + SubscriptionHandler subscriptionHandler(testProxy_); + std::function<void (const uint8_t&)> myCallback = + std::bind(&SubscriptionHandler::myCallback, &subscriptionHandler, std::placeholders::_1); + + testProxy_->getTestAttributeAttribute().getChangedEvent().subscribe(myCallback); + + // initialize test stub with default value + testStub_->setTestAttributeAttribute(firstValue); + usleep(wt); + + // check received attribute value + EXPECT_EQ(subscriptionHandler.getSubscriptedTestAttribute(), firstValue); + + bool isUnregistered = runtime_->unregisterService(domain, + TestInterfaceStubDefault::StubInterface::getInterface(), testAddress); + ASSERT_TRUE(isUnregistered); + deregisterService_ = !isUnregistered; + + testStub_->setTestAttributeAttribute(secondValue); + usleep(wt); + + EXPECT_EQ(subscriptionHandler.getSubscriptedTestAttribute(), firstValue); + + // register service + serviceRegistered = runtime_->registerService(domain, testAddress, testStub_, serviceId); + ASSERT_TRUE(serviceRegistered); + + usleep(wt); + + EXPECT_EQ(subscriptionHandler.getSubscriptedTestAttribute(), secondValue); + + testStub_->setTestAttributeAttribute(thirdValue); + usleep(wt); + + EXPECT_EQ(subscriptionHandler.getSubscriptedTestAttribute(), thirdValue); + + isUnregistered = runtime_->unregisterService(domain, + TestInterfaceStubDefault::StubInterface::getInterface(), testAddress); + ASSERT_TRUE(isUnregistered); + + deregisterService_ = !isUnregistered; +} + +/** + * @test Test of unregister a service in case a proxy is subscribed for an attribute of this service. + * During the unregistered time of the service the value of the attribute is not changed. + * - register service + * - proxy subscribes for an attribute of the service + * - value of attribute is set + * - changed value must be communicated to the proxy + * - unregister service + * - register service + * - current attribute value must be communicated to the proxy + * - value of attribute is changed + * - changed value must be communicated to the proxy + * - unregister service + */ +TEST_F(CMAttributeSubscription, SubscribeUnregisterNoValueSetRegisterService) { + + deregisterService_ = true; + + uint8_t firstValue = 35; + uint8_t secondValue = 43; + + // register service + bool serviceRegistered = runtime_->registerService(domain, testAddress, testStub_, serviceId); + ASSERT_TRUE(serviceRegistered); + + testProxy_->isAvailableBlocking(); + ASSERT_TRUE(testProxy_->isAvailable()); + + // subscribe for attribute change by the proxy + SubscriptionHandler subscriptionHandler(testProxy_); + std::function<void (const uint8_t&)> myCallback = + std::bind(&SubscriptionHandler::myCallback, &subscriptionHandler, std::placeholders::_1); + + testProxy_->getTestAttributeAttribute().getChangedEvent().subscribe(myCallback); + + // initialize test stub with default value + testStub_->setTestAttributeAttribute(firstValue); + usleep(wt); + + // check received attribute value + EXPECT_EQ(subscriptionHandler.getSubscriptedTestAttribute(), firstValue); + + bool isUnregistered = runtime_->unregisterService(domain, + TestInterfaceStubDefault::StubInterface::getInterface(), testAddress); + ASSERT_TRUE(isUnregistered); + + subscriptionHandler.resetSubcriptedTestAttribute(); + EXPECT_EQ(subscriptionHandler.getSubscriptedTestAttribute(), 0); + + // register service + serviceRegistered = runtime_->registerService(domain, testAddress, testStub_, serviceId); + ASSERT_TRUE(serviceRegistered); + + usleep(wt); + + EXPECT_EQ(subscriptionHandler.getSubscriptedTestAttribute(), firstValue); + + testStub_->setTestAttributeAttribute(secondValue); + usleep(wt); + + EXPECT_EQ(subscriptionHandler.getSubscriptedTestAttribute(), secondValue); + + isUnregistered = runtime_->unregisterService(domain, + TestInterfaceStubDefault::StubInterface::getInterface(), testAddress); + ASSERT_TRUE(isUnregistered); + + deregisterService_ = !isUnregistered; +} + +/** + * @test Test of subscribing a second proxy a little bit later + * - proxy subscribes for an attribute of the service + * - register service + * - initial value must be communicated to the proxy + * - create a second proxy + * - second proxy subscribes for the same attribute of the service + * - current attribute value must be communicated to the proxy + * - value of attribute is changed + * - changed value must be communicated to both proxies + * - unregister service + */ +TEST_F(CMAttributeSubscription, SubscribeSecondProxyLater) { + + deregisterService_ = true; + + uint8_t defaultValue = 33; + + // initialize test stub with default value + testStub_->setTestAttributeAttribute(defaultValue); + + // subscribe for attribute change by the proxy + SubscriptionHandler subscriptionHandler(testProxy_); + std::function<void (const uint8_t&)> myCallback = + std::bind(&SubscriptionHandler::myCallback, &subscriptionHandler, std::placeholders::_1); + + testProxy_->getTestAttributeAttribute().getChangedEvent().subscribe(myCallback); + + // register service + bool serviceRegistered = runtime_->registerService(domain, testAddress, testStub_, serviceId); + ASSERT_TRUE(serviceRegistered); + + testProxy_->isAvailableBlocking(); + ASSERT_TRUE(testProxy_->isAvailable()); + + usleep(wt); + + // check received attribute value + EXPECT_EQ(subscriptionHandler.getSubscriptedTestAttribute(), defaultValue); + + // create second proxy + std::shared_ptr<TestInterfaceProxy<>> secondTestProxy = + runtime_->buildProxy<TestInterfaceProxy>(domain, testAddress, clientId); + ASSERT_TRUE((bool)secondTestProxy); + + SubscriptionHandler secondSubscriptionHandler(secondTestProxy); + std::function<void (const uint8_t&)> secondMyCallback = + std::bind(&SubscriptionHandler::myCallback, &secondSubscriptionHandler, std::placeholders::_1); + + secondTestProxy->getTestAttributeAttribute().getChangedEvent().subscribe(secondMyCallback); + + usleep(wt); + + EXPECT_EQ(secondSubscriptionHandler.getSubscriptedTestAttribute(), defaultValue); + + int8_t newValue = 123; + + testStub_->setTestAttributeAttribute(newValue); + usleep(wt); + + EXPECT_EQ(subscriptionHandler.getSubscriptedTestAttribute(), newValue); + EXPECT_EQ(secondSubscriptionHandler.getSubscriptedTestAttribute(), newValue); + + bool isUnregistered = runtime_->unregisterService(domain, + TestInterfaceStubDefault::StubInterface::getInterface(), testAddress); + ASSERT_TRUE(isUnregistered); + + deregisterService_ = !isUnregistered; +} + +/** + * @test Test of subscribing three callbacks before registering the service + * - proxy subscribes three callbacks for an attribute of the service + * - register service + * - initial value must be communicated to every callback + */ +TEST_F(CMAttributeSubscription, SubscribeThreeCallbacksServiceNotAvailable) { + + deregisterService_ = true; + + ThreeCallbackHandler threeCallbackHandler; + + uint8_t defaultValue = 33; + + // initialize test stub with default value + testStub_->setTestAttributeAttribute(defaultValue); + + std::function<void (const uint8_t&)> myCallback1 = + std::bind(&ThreeCallbackHandler::callback_1, &threeCallbackHandler, std::placeholders::_1); + std::function<void (const uint8_t&)> myCallback2 = + std::bind(&ThreeCallbackHandler::callback_2, &threeCallbackHandler, std::placeholders::_1); + std::function<void (const uint8_t&)> myCallback3 = + std::bind(&ThreeCallbackHandler::callback_3, &threeCallbackHandler, std::placeholders::_1); + + testProxy_->getTestAttributeAttribute().getChangedEvent().subscribe(myCallback1); + testProxy_->getTestAttributeAttribute().getChangedEvent().subscribe(myCallback2); + testProxy_->getTestAttributeAttribute().getChangedEvent().subscribe(myCallback3); + + usleep(wt); + + // register service + bool serviceRegistered = runtime_->registerService(domain, testAddress, testStub_, serviceId); + ASSERT_TRUE(serviceRegistered); + + testProxy_->isAvailableBlocking(); + ASSERT_TRUE(testProxy_->isAvailable()); + + usleep(100000); + + EXPECT_EQ(1, threeCallbackHandler.getCallbackCounter_1()); + EXPECT_EQ(1, threeCallbackHandler.getCallbackCounter_2()); + EXPECT_EQ(1, threeCallbackHandler.getCallbackCounter_3()); + + EXPECT_EQ(defaultValue, threeCallbackHandler.getCallbackValue_1()); + EXPECT_EQ(defaultValue, threeCallbackHandler.getCallbackValue_2()); + EXPECT_EQ(defaultValue, threeCallbackHandler.getCallbackValue_3()); + + bool isUnregistered = runtime_->unregisterService(domain, + TestInterfaceStubDefault::StubInterface::getInterface(), testAddress); + ASSERT_TRUE(isUnregistered); + + deregisterService_ = !isUnregistered; +} + +/** + * @test Test of subscribing three callbacks after registering the service + * - register service + * - proxy subscribes three callbacks for an attribute of the service + * - initial value must be communicated to every callback + */ +TEST_F(CMAttributeSubscription, SubscribeThreeCallbacksServiceAvailable) { + deregisterService_ = true; + + uint8_t defaultValue = 35; + + ThreeCallbackHandler threeCallbackHandler; + + testStub_->setTestAttributeAttribute(defaultValue); + usleep(wt); + + // register service + bool serviceRegistered = runtime_->registerService(domain, testAddress, testStub_, serviceId); + ASSERT_TRUE(serviceRegistered); + + testProxy_->isAvailableBlocking(); + ASSERT_TRUE(testProxy_->isAvailable()); + + std::function<void (const uint8_t&)> myCallback1 = + std::bind(&ThreeCallbackHandler::callback_1, &threeCallbackHandler, std::placeholders::_1); + std::function<void (const uint8_t&)> myCallback2 = + std::bind(&ThreeCallbackHandler::callback_2, &threeCallbackHandler, std::placeholders::_1); + std::function<void (const uint8_t&)> myCallback3 = + std::bind(&ThreeCallbackHandler::callback_3, &threeCallbackHandler, std::placeholders::_1); + + testProxy_->getTestAttributeAttribute().getChangedEvent().subscribe(myCallback1); + testProxy_->getTestAttributeAttribute().getChangedEvent().subscribe(myCallback2); + testProxy_->getTestAttributeAttribute().getChangedEvent().subscribe(myCallback3); + + usleep(100000); + + EXPECT_EQ(1, threeCallbackHandler.getCallbackCounter_1()); + EXPECT_EQ(1, threeCallbackHandler.getCallbackCounter_2()); + EXPECT_EQ(1, threeCallbackHandler.getCallbackCounter_3()); + + EXPECT_EQ(defaultValue, threeCallbackHandler.getCallbackValue_1()); + EXPECT_EQ(defaultValue, threeCallbackHandler.getCallbackValue_2()); + EXPECT_EQ(defaultValue, threeCallbackHandler.getCallbackValue_3()); + + bool isUnregistered = runtime_->unregisterService(domain, + TestInterfaceStubDefault::StubInterface::getInterface(), testAddress); + ASSERT_TRUE(isUnregistered); + + deregisterService_ = !isUnregistered; +} + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); ::testing::AddGlobalTestEnvironment(new Environment()); |