From: coderhyme Date: Thu, 22 Oct 2015 04:24:25 +0000 (-0700) Subject: Fix issues of RCSResourceObject X-Git-Tag: 1.2.0+RC1~872 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8310ed98e88468180a9534d9b0e632dddb15965d;p=platform%2Fupstream%2Fiotivity.git Fix issues of RCSResourceObject Fix data race for handlers with shared_ptr which has guaranteed atomic operations for setting and loading. LockGuard's destructor is now noexcept(false) and it will emit an exception if and only if the destruction is not caused by stack unwinding. Some minor issues of the test are fixed. Change-Id: I12ccb6adb4849642d266f7af5b1e28a2f6d35f83 Signed-off-by: coderhyme Reviewed-on: https://gerrit.iotivity.org/gerrit/3929 Tested-by: jenkins-iotivity Reviewed-by: Habib Virji --- diff --git a/service/resource-encapsulation/android/service/src/main/java/org/iotivity/service/server/RcsResourceObject.java b/service/resource-encapsulation/android/service/src/main/java/org/iotivity/service/server/RcsResourceObject.java index f890404..915004e 100644 --- a/service/resource-encapsulation/android/service/src/main/java/org/iotivity/service/server/RcsResourceObject.java +++ b/service/resource-encapsulation/android/service/src/main/java/org/iotivity/service/server/RcsResourceObject.java @@ -224,6 +224,8 @@ public final class RcsResourceObject extends RcsObject { * * @throws RcsIllegalStateException * if not in locked state + * @throws RcsPlatformException + * if auto notify failed */ public void apply() throws RcsIllegalStateException { if (mCurrentAttributes == null) { diff --git a/service/resource-encapsulation/android/service/src/main/jni/JniRcsLockedAttributes.cpp b/service/resource-encapsulation/android/service/src/main/jni/JniRcsLockedAttributes.cpp index 98273c9..ad05590 100644 --- a/service/resource-encapsulation/android/service/src/main/jni/JniRcsLockedAttributes.cpp +++ b/service/resource-encapsulation/android/service/src/main/jni/JniRcsLockedAttributes.cpp @@ -25,6 +25,7 @@ #include "JniRcsValue.h" #include "Log.h" #include "Verify.h" +#include "JavaExceptions.h" #include "RCSResourceObject.h" @@ -153,7 +154,15 @@ Java_org_iotivity_service_server_RcsLockedAttributes_nativeApply auto res = getResource(env, resourceObject); VERIFY_NO_EXC(env); - writeNativeAttributesFromMap(env, cacheObj, res->getAttributes()); + try + { + RCSResourceObject::LockGuard lock(res); + writeNativeAttributesFromMap(env, cacheObj, res->getAttributes()); + } + catch (const RCSPlatformException& e) + { + throwPlatformException(env, e); + } } JNIEXPORT void JNICALL @@ -163,7 +172,8 @@ Java_org_iotivity_service_server_RcsLockedAttributes_nativeLock auto res = getResource(env, resourceObject); VERIFY_NO_EXC(env); - setSafeNativeHandle< RCSResourceObject::LockGuard >(env, obj, res); + setSafeNativeHandle< RCSResourceObject::LockGuard >(env, obj, + res, RCSResourceObject::AutoNotifyPolicy::NEVER); } JNIEXPORT void JNICALL diff --git a/service/resource-encapsulation/android/service/src/main/jni/JniRcsResourceObject.cpp b/service/resource-encapsulation/android/service/src/main/jni/JniRcsResourceObject.cpp index 4354032..fe47ef8 100644 --- a/service/resource-encapsulation/android/service/src/main/jni/JniRcsResourceObject.cpp +++ b/service/resource-encapsulation/android/service/src/main/jni/JniRcsResourceObject.cpp @@ -32,6 +32,7 @@ #include "RCSResourceObject.h" #include "RCSResponse.h" +#include "RCSRequest.h" #include "RequestHandler.h" #define LOG_TAG "JNI-RCSResourceObject" @@ -503,7 +504,7 @@ Java_org_iotivity_service_server_RcsResourceObject_nativeGetAttributes auto res = getResource(env, obj); VERIFY_NO_EXC_RET_DEF(env); - RCSResourceObject::LockGuard lock{ res }; + RCSResourceObject::LockGuard lock{ res, RCSResourceObject::AutoNotifyPolicy::NEVER }; return newAttributesObject(env, res->getAttributes()); } diff --git a/service/resource-encapsulation/include/RCSResourceObject.h b/service/resource-encapsulation/include/RCSResourceObject.h index 40044c6..d062b3a 100644 --- a/service/resource-encapsulation/include/RCSResourceObject.h +++ b/service/resource-encapsulation/include/RCSResourceObject.h @@ -30,9 +30,8 @@ #include #include -#include -#include -#include +#include "RCSResourceAttributes.h" +#include "RCSResponse.h" namespace OC { @@ -44,6 +43,8 @@ namespace OIC namespace Service { + class RCSRequest; + /** * @brief Thrown when lock has not been acquired. * @@ -443,12 +444,12 @@ namespace OIC private: RCSResourceObject(uint8_t, RCSResourceAttributes&&); - OCEntityHandlerResult entityHandler(std::shared_ptr< OC::OCResourceRequest >); + OCEntityHandlerResult entityHandler(const std::shared_ptr< OC::OCResourceRequest >&); - OCEntityHandlerResult handleRequest(std::shared_ptr< OC::OCResourceRequest >); - OCEntityHandlerResult handleRequestGet(std::shared_ptr< OC::OCResourceRequest >); - OCEntityHandlerResult handleRequestSet(std::shared_ptr< OC::OCResourceRequest >); - OCEntityHandlerResult handleObserve(std::shared_ptr< OC::OCResourceRequest >); + OCEntityHandlerResult handleRequest(const std::shared_ptr< OC::OCResourceRequest >&); + OCEntityHandlerResult handleRequestGet(const std::shared_ptr< OC::OCResourceRequest >&); + OCEntityHandlerResult handleRequestSet(const std::shared_ptr< OC::OCResourceRequest >&); + OCEntityHandlerResult handleObserve(const std::shared_ptr< OC::OCResourceRequest >&); void expectOwnLock() const; @@ -473,8 +474,8 @@ namespace OIC RCSResourceAttributes m_resourceAttributes; - GetRequestHandler m_getRequestHandler; - SetRequestHandler m_setRequestHandler; + std::shared_ptr< GetRequestHandler > m_getRequestHandler; + std::shared_ptr< SetRequestHandler > m_setRequestHandler; AutoNotifyPolicy m_autoNotifyPolicy; SetRequestHandlerPolicy m_setRequestHandlerPolicy; @@ -495,8 +496,10 @@ namespace OIC * the RCSResourceObject it is given. When control leaves the scope in which the LockGuard * object was created, the LockGuard is destructed and the attributes is unlocked. * - * Additionally when this is destructed, it tries to notify depending on AutoNotifyPolicy - * of the RCSResourceObject. + * Additionally when it is destructed and only when destructed not by stack unwinding + * caused by an exception, it tries to notify depending on AutoNotifyPolicy. + * + * @note The destrcutor can throw an exception if auto notify failed. */ class RCSResourceObject::LockGuard { @@ -519,7 +522,13 @@ namespace OIC * @overload */ LockGuard(const RCSResourceObject::Ptr, AutoNotifyPolicy); - ~LockGuard(); + + /** + * @throws RCSPlatformException If auto notify operation failed. + * + * @note The exception will never be thrown while stack unwinding. + */ + ~LockGuard() noexcept(false); LockGuard(const LockGuard&) = delete; LockGuard(LockGuard&&) = delete; diff --git a/service/resource-encapsulation/src/serverBuilder/src/RCSResourceObject.cpp b/service/resource-encapsulation/src/serverBuilder/src/RCSResourceObject.cpp index a68901a..6137df1 100644 --- a/service/resource-encapsulation/src/serverBuilder/src/RCSResourceObject.cpp +++ b/service/resource-encapsulation/src/serverBuilder/src/RCSResourceObject.cpp @@ -18,20 +18,21 @@ // //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -#include +#include "RCSResourceObject.h" #include #include #include -#include -#include -#include -#include -#include +#include "RequestHandler.h" +#include "AssertUtils.h" +#include "AtomicHelper.h" +#include "ResourceAttributesConverter.h" +#include "ResourceAttributesUtils.h" +#include "RCSRequest.h" -#include -#include +#include "logger.h" +#include "OCPlatform.h" #define LOG_TAG "RCSResourceObject" @@ -56,7 +57,7 @@ namespace template OCEntityHandlerResult sendResponse(RCSResourceObject& resource, - std::shared_ptr< OC::OCResourceRequest > ocRequest, RESPONSE&& response) + const std::shared_ptr< OC::OCResourceRequest >& ocRequest, RESPONSE&& response) { auto ocResponse = response.getHandler()->buildResponse(resource); ocResponse->setRequestHandle(ocRequest->getRequestHandle()); @@ -78,7 +79,7 @@ namespace } RCSResourceAttributes getAttributesFromOCRequest( - std::shared_ptr< OC::OCResourceRequest > request) + const std::shared_ptr< OC::OCResourceRequest >& request) { return ResourceAttributesConverter::fromOCRepresentation( request->getResourceRepresentation()); @@ -87,11 +88,12 @@ namespace template< typename HANDLER, typename RESPONSE = typename std::decay::type::result_type > RESPONSE invokeHandler(RCSResourceAttributes& attrs, - std::shared_ptr< OC::OCResourceRequest > ocRequest, HANDLER&& handler) + const std::shared_ptr< OC::OCResourceRequest >& ocRequest, + std::shared_ptr< HANDLER > handler) { if (handler) { - return handler(RCSRequest{ ocRequest->getResourceUri() }, attrs); + return (*handler)(RCSRequest{ ocRequest->getResourceUri() }, attrs); } return RESPONSE::defaultAction(); @@ -100,7 +102,7 @@ namespace typedef void (RCSResourceObject::* AutoNotifyFunc) (bool, RCSResourceObject::AutoNotifyPolicy) const; - std::function createAutoNotifyInvoker(AutoNotifyFunc autoNotifyFunc, + std::function createAutoNotifyInvoker(AutoNotifyFunc autoNotifyFunc, const RCSResourceObject& resourceObject, const RCSResourceAttributes& resourceAttributes, RCSResourceObject::AutoNotifyPolicy autoNotifyPolicy) { @@ -337,12 +339,12 @@ namespace OIC void RCSResourceObject::setGetRequestHandler(GetRequestHandler h) { - m_getRequestHandler = std::move(h); + m_getRequestHandler = std::make_shared< GetRequestHandler >(std::move(h)); } void RCSResourceObject::setSetRequestHandler(SetRequestHandler h) { - m_setRequestHandler = std::move(h); + m_setRequestHandler = std::make_shared< SetRequestHandler >(std::move(h)); } void RCSResourceObject::notify() const @@ -422,7 +424,7 @@ namespace OIC } OCEntityHandlerResult RCSResourceObject::entityHandler( - std::shared_ptr< OC::OCResourceRequest > request) + const std::shared_ptr< OC::OCResourceRequest >& request) { OC_LOG(WARNING, LOG_TAG, "entityHandler"); if (!request) @@ -457,7 +459,7 @@ namespace OIC } OCEntityHandlerResult RCSResourceObject::handleRequest( - std::shared_ptr< OC::OCResourceRequest > request) + const std::shared_ptr< OC::OCResourceRequest >& request) { assert(request != nullptr); @@ -475,7 +477,7 @@ namespace OIC } OCEntityHandlerResult RCSResourceObject::handleRequestGet( - std::shared_ptr< OC::OCResourceRequest > request) + const std::shared_ptr< OC::OCResourceRequest >& request) { assert(request != nullptr); @@ -518,7 +520,7 @@ namespace OIC } OCEntityHandlerResult RCSResourceObject::handleRequestSet( - std::shared_ptr< OC::OCResourceRequest > request) + const std::shared_ptr< OC::OCResourceRequest >& request) { assert(request != nullptr); @@ -538,7 +540,7 @@ namespace OIC } OCEntityHandlerResult RCSResourceObject::handleObserve( - std::shared_ptr< OC::OCResourceRequest >) + const std::shared_ptr< OC::OCResourceRequest >&) { if (!isObservable()) { @@ -583,9 +585,9 @@ namespace OIC init(); } - RCSResourceObject::LockGuard::~LockGuard() + RCSResourceObject::LockGuard::~LockGuard() noexcept(false) { - if (m_autoNotifyFunc) m_autoNotifyFunc(); + if (!std::uncaught_exception() && m_autoNotifyFunc) m_autoNotifyFunc(); if (m_isOwningLock) { diff --git a/service/resource-encapsulation/src/serverBuilder/unittests/RCSResourceObjectTest.cpp b/service/resource-encapsulation/src/serverBuilder/unittests/RCSResourceObjectTest.cpp index ba441fd..33431bb 100644 --- a/service/resource-encapsulation/src/serverBuilder/unittests/RCSResourceObjectTest.cpp +++ b/service/resource-encapsulation/src/serverBuilder/unittests/RCSResourceObjectTest.cpp @@ -18,11 +18,11 @@ // //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -#include +#include "UnitTestHelper.h" -#include +#include "RCSResourceObject.h" -#include +#include "OCPlatform.h" using namespace std; using namespace std::placeholders; @@ -38,7 +38,7 @@ typedef OCStackResult (*NotifyAllObservers)(OCResourceHandle); constexpr char RESOURCE_URI[]{ "a/test" }; constexpr char RESOURCE_TYPE[]{ "resourcetype" }; constexpr char KEY[]{ "key" }; -constexpr int value{ 100 }; +constexpr int VALUE{ 100 }; TEST(ResourceObjectBuilderCreateTest, ThrowIfUriIsInvalid) { @@ -122,10 +122,10 @@ TEST_F(ResourceObjectTest, AccessAttributesWithLock) { RCSResourceObject::LockGuard lock{ server }; auto& attr = server->getAttributes(); - attr[KEY] = value; + attr[KEY] = VALUE; } - ASSERT_EQ(value, server->getAttribute(KEY)); + ASSERT_EQ(VALUE, server->getAttribute(KEY)); } TEST_F(ResourceObjectTest, ThrowIfTryToAccessAttributesWithoutGuard) @@ -137,10 +137,10 @@ TEST_F(ResourceObjectTest, SettingAttributesWithinGuardDoesntCauseDeadLock) { { RCSResourceObject::LockGuard guard{ server }; - server->setAttribute(KEY, value); + server->setAttribute(KEY, VALUE); } - ASSERT_EQ(value, server->getAttribute(KEY)); + ASSERT_EQ(VALUE, server->getAttribute(KEY)); } TEST_F(ResourceObjectTest, SettingNestedAttributesIsSameToGettingNestedAttributes) @@ -197,23 +197,23 @@ TEST_F(AutoNotifyTest, AutoNotifyPolicyCanBeSet) TEST_F(AutoNotifyTest, WithUpdatedPolicy_NeverBeNotifiedIfAttributeIsNotChanged) { server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED); - server->setAttribute(KEY, value); + server->setAttribute(KEY, VALUE); mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >( OC::OCPlatform::notifyAllObservers)); - server->setAttribute(KEY, value); + server->setAttribute(KEY, VALUE); } TEST_F(AutoNotifyTest, WithUpdatedPolicy_WillBeNotifiedIfAttributeIsChanged) { server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED); - server->setAttribute(KEY, value); + server->setAttribute(KEY, VALUE); mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >( OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK); - server->setAttribute(KEY, value + 1); + server->setAttribute(KEY, VALUE + 1); } TEST_F(AutoNotifyTest, WithUpdatedPolicy_WillBeNotifiedIfValueIsAdded) @@ -224,7 +224,7 @@ TEST_F(AutoNotifyTest, WithUpdatedPolicy_WillBeNotifiedIfValueIsAdded) mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >( OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK); - server->setAttribute(newKey, value); + server->setAttribute(newKey, VALUE); } TEST_F(AutoNotifyTest, WithNeverPolicy_NeverBeNotifiedEvenIfAttributeIsChanged) @@ -235,13 +235,13 @@ TEST_F(AutoNotifyTest, WithNeverPolicy_NeverBeNotifiedEvenIfAttributeIsChanged) OC::OCPlatform::notifyAllObservers)); RCSResourceObject::LockGuard lock{ server }; - server->setAttribute(KEY, value); + server->setAttribute(KEY, VALUE); } TEST_F(AutoNotifyTest, WithUpdatePolicy_WillBeNotifiedIfAttributeIsDeleted) { server->setAutoNotifyPolicy(RCSResourceObject::AutoNotifyPolicy::UPDATED); - server->setAttribute(KEY, value); + server->setAttribute(KEY, VALUE); mocks.ExpectCallFuncOverload(static_cast< NotifyAllObservers >( OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK); @@ -261,7 +261,7 @@ TEST_F(AutoNotifyWithGuardTest, GuardFollowsServerPolicyByDefault) OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK); RCSResourceObject::LockGuard guard{ server }; - server->setAttribute(KEY, value); + server->setAttribute(KEY, VALUE); } TEST_F(AutoNotifyWithGuardTest, GuardCanOverridePolicy) @@ -272,7 +272,7 @@ TEST_F(AutoNotifyWithGuardTest, GuardCanOverridePolicy) OC::OCPlatform::notifyAllObservers)); RCSResourceObject::LockGuard guard{ server, RCSResourceObject::AutoNotifyPolicy::NEVER }; - server->getAttributes()[KEY] = value; + server->getAttributes()[KEY] = VALUE; } TEST_F(AutoNotifyWithGuardTest, GuardInvokesNotifyWhenDestroyed) @@ -284,13 +284,13 @@ TEST_F(AutoNotifyWithGuardTest, GuardInvokesNotifyWhenDestroyed) { RCSResourceObject::LockGuard guard{ server, RCSResourceObject::AutoNotifyPolicy::ALWAYS }; - server->setAttribute(KEY, value); + server->setAttribute(KEY, VALUE); } mocks.NeverCallFuncOverload(static_cast< NotifyAllObservers >( OC::OCPlatform::notifyAllObservers)).Return(OC_STACK_OK); - server->setAttribute(KEY, value); + server->setAttribute(KEY, VALUE); } @@ -396,7 +396,7 @@ TEST_F(ResourceObjectHandlingRequestTest, SendResponseWithRCSResponseResults) TEST_F(ResourceObjectHandlingRequestTest, SendSetResponseWithCustomAttrs) { constexpr int errorCode{ 1999 }; - constexpr char value[]{ "value" }; + constexpr char value[]{ "VALUE" }; server->setSetRequestHandler( [](const RCSRequest&, RCSResourceAttributes&) -> RCSSetResponse @@ -419,6 +419,7 @@ TEST_F(ResourceObjectHandlingRequestTest, SendSetResponseWithCustomAttrs) } + class SetRequestHandlerPolicyTest: public ResourceObjectHandlingRequestTest { public: @@ -428,14 +429,7 @@ public: OCRepresentation createOCRepresentation() { OCRepresentation ocRep; - - vector interface{"oic.if.baseline"}; - vector type{"core.light"}; - - ocRep.setUri(RESOURCE_URI); - ocRep.setResourceInterfaces(interface); - ocRep.setResourceTypes(type); - + ocRep[KEY] = VALUE; return ocRep; } @@ -460,31 +454,28 @@ TEST_F(SetRequestHandlerPolicyTest, SetRequestHandlerPolicyCanBeSet) server->getSetRequestHandlerPolicy()); } -TEST_F(SetRequestHandlerPolicyTest, WithNeverPolicy_NotAddedIfReceivedNewKeyValuePair) +TEST_F(SetRequestHandlerPolicyTest, WithNeverPolicy_DeniedIfKeyIsNew) { - OCRepresentation ocRep = createOCRepresentation(); - ocRep.setValue("NewKey", value); server->setSetRequestHandlerPolicy(RCSResourceObject::SetRequestHandlerPolicy::NEVER); - handler(createRequest(OC_REST_PUT, ocRep)); + handler(createRequest(OC_REST_PUT, createOCRepresentation())); RCSResourceObject::LockGuard guard{ server }; - ASSERT_FALSE((server->getAttributes()).contains("NewKey")); + ASSERT_FALSE(server->getAttributes().contains(KEY)); } -TEST_F(SetRequestHandlerPolicyTest, WithAcceptancePolicy_WillBeAddedIfReceivedNewKeyValuePair) +TEST_F(SetRequestHandlerPolicyTest, WithAcceptancePolicy_AcceptedEvenIfKeyIsNew) { - OCRepresentation ocRep = createOCRepresentation(); - ocRep.setValue("NewKey", value); server->setSetRequestHandlerPolicy(RCSResourceObject::SetRequestHandlerPolicy::ACCEPTANCE); - handler(createRequest(OC_REST_PUT, ocRep)); + handler(createRequest(OC_REST_PUT, createOCRepresentation())); RCSResourceObject::LockGuard guard{ server }; - ASSERT_TRUE((server->getAttributes()).contains("NewKey")); + ASSERT_TRUE(server->getAttributes().contains(KEY)); } + class ResourceObjectSynchronizationTest: public ResourceObjectHandlingRequestTest { public: @@ -580,6 +571,7 @@ TEST_F(ResourceObjectSynchronizationTest, MultipleAccessToServerResourceWithRequ } + class AttributeUpdatedListenerTest: public ResourceObjectHandlingRequestTest { public: @@ -589,98 +581,80 @@ public: OCRepresentation createOCRepresentation(void) { OCRepresentation ocRep; - - vector interface{"oic.if.baseline"}; - vector type{"core.light"}; - - ocRep.setUri(RESOURCE_URI); - ocRep.setResourceInterfaces(interface); - ocRep.setResourceTypes(type); - ocRep[KEY] = value; - + ocRep[KEY] = VALUE; return ocRep; } - void initMocks() +protected: + void SetUp() { - ResourceObjectHandlingRequestTest::initMocks(); + ResourceObjectHandlingRequestTest::SetUp(); mocks.OnCallFunc(OCPlatform::sendResponse).Return(OC_STACK_OK); + + server->setAttribute(KEY, 0); } }; -class FunctionsForAttributeUpdatedListener +class AttributeUpdatedListener { public: - virtual void fCalled(const OIC::Service::RCSResourceAttributes::Value&, - const OIC::Service::RCSResourceAttributes::Value&)=0; - virtual void fNotCalled(const OIC::Service::RCSResourceAttributes::Value&, + virtual void onUpdated(const OIC::Service::RCSResourceAttributes::Value&, const OIC::Service::RCSResourceAttributes::Value&)=0; }; -TEST_F(AttributeUpdatedListenerTest, AddListenerRunsAddedFunction) -{ - FunctionsForAttributeUpdatedListener *ptrMock = - mocks.Mock(); - server->setAttribute(KEY, 0); +TEST_F(AttributeUpdatedListenerTest, RemoveListenerReturnsFalseIfListenerIsNotAdded) +{ + ASSERT_FALSE(server->removeAttributeUpdatedListener(KEY)); +} - mocks.ExpectCall(ptrMock, FunctionsForAttributeUpdatedListener::fCalled); +TEST_F(AttributeUpdatedListenerTest, RemoveListenerReturnsTrueIfListenerIsAdded) +{ + auto listener = mocks.Mock< AttributeUpdatedListener >(); server->addAttributeUpdatedListener(KEY, - (std::bind(&FunctionsForAttributeUpdatedListener::fCalled, ptrMock, _1, _2))); + std::bind(&AttributeUpdatedListener::onUpdated, listener, _1, _2)); - handler(createRequest(OC_REST_PUT, createOCRepresentation())); + ASSERT_TRUE(server->removeAttributeUpdatedListener(KEY)); } -TEST_F(AttributeUpdatedListenerTest, AddListenerRunsAccordingToLastAddedFunction) +TEST_F(AttributeUpdatedListenerTest, AddListenerRunsAddedFunction) { - FunctionsForAttributeUpdatedListener *ptrMock = - mocks.Mock(); + auto listener = mocks.Mock< AttributeUpdatedListener >(); - string duplicateKEY(KEY); - server->setAttribute(KEY, 0); - - mocks.ExpectCall(ptrMock, FunctionsForAttributeUpdatedListener::fCalled); - mocks.NeverCall(ptrMock, FunctionsForAttributeUpdatedListener::fNotCalled); - - server->addAttributeUpdatedListener(duplicateKEY, - (std::bind(&FunctionsForAttributeUpdatedListener::fNotCalled, ptrMock, _1, _2))); server->addAttributeUpdatedListener(KEY, - (std::bind(&FunctionsForAttributeUpdatedListener::fCalled, ptrMock, _1, _2))); + std::bind(&AttributeUpdatedListener::onUpdated, listener, _1, _2)); + + mocks.ExpectCall(listener, AttributeUpdatedListener::onUpdated); handler(createRequest(OC_REST_PUT, createOCRepresentation())); } -TEST_F(AttributeUpdatedListenerTest, RemoveListenerReturnsTrueIfListenerIsNotAdded) +TEST_F(AttributeUpdatedListenerTest, ListenerWithSameKeyOverridesPreviousOne) { - ASSERT_FALSE(server->removeAttributeUpdatedListener(KEY)); -} + auto first = mocks.Mock< AttributeUpdatedListener >(); + auto second = mocks.Mock< AttributeUpdatedListener >(); -TEST_F(AttributeUpdatedListenerTest, RemoveListenerReturnsTrueIfListenerIsAdded) -{ - FunctionsForAttributeUpdatedListener *ptrMock = - mocks.Mock(); + mocks.NeverCall(first, AttributeUpdatedListener::onUpdated); + mocks.ExpectCall(second, AttributeUpdatedListener::onUpdated); server->addAttributeUpdatedListener(KEY, - (std::bind(&FunctionsForAttributeUpdatedListener::fNotCalled, ptrMock, _1, _2))); + std::bind(&AttributeUpdatedListener::onUpdated, first, _1, _2)); + server->addAttributeUpdatedListener(KEY, + std::bind(&AttributeUpdatedListener::onUpdated, second, _1, _2)); - ASSERT_TRUE(server->removeAttributeUpdatedListener(KEY)); + handler(createRequest(OC_REST_PUT, createOCRepresentation())); } -TEST_F(AttributeUpdatedListenerTest, RemoveListenerNeverRunsRemovedFunc) +TEST_F(AttributeUpdatedListenerTest, RemovedListenerNotBeInvoked) { - FunctionsForAttributeUpdatedListener *ptrMock = - mocks.Mock(); + auto listener = mocks.Mock< AttributeUpdatedListener >(); + server->addAttributeUpdatedListener(KEY, + std::bind(&AttributeUpdatedListener::onUpdated, listener, _1, _2)); - mocks.NeverCall(ptrMock, FunctionsForAttributeUpdatedListener::fNotCalled); + mocks.NeverCall(listener, AttributeUpdatedListener::onUpdated); - server->setAttribute(KEY, 0); - server->addAttributeUpdatedListener(KEY, - (std::bind(&FunctionsForAttributeUpdatedListener::fNotCalled, ptrMock, _1, _2))); server->removeAttributeUpdatedListener(KEY); handler(createRequest(OC_REST_PUT, createOCRepresentation())); } - - -