TEST(PDMSetDeviceStaleTest, StaleDeviceNotinLinkedDevice)
{
    EXPECT_EQ(OC_STACK_OK, PDMInit(NULL));
    OicUuid_t uid1 = {{0,}};
    memcpy(&uid1.id, ID_11, sizeof(uid1.id));

    OicUuid_t uid2 = {{0,}};
    memcpy(&uid2.id, ID_12, sizeof(uid2.id));

    OicUuid_t uid3 = {{0,}};
    memcpy(&uid3.id, ID_13, sizeof(uid3.id));

    EXPECT_EQ(OC_STACK_OK, PDMAddDevice(&uid1));
    EXPECT_EQ(OC_STACK_OK, PDMAddDevice(&uid2));
    EXPECT_EQ(OC_STACK_OK, PDMAddDevice(&uid3));

    EXPECT_EQ(OC_STACK_OK, PDMLinkDevices(&uid1, &uid2));
    EXPECT_EQ(OC_STACK_OK, PDMLinkDevices(&uid2, &uid3));
    EXPECT_EQ(OC_STACK_OK, PDMLinkDevices(&uid1, &uid3));

    EXPECT_EQ(OC_STACK_OK,PDMSetDeviceStale(&uid1));

    OCUuidList_t *list1 = NULL;
    size_t noOfDevices1 = 0;
    EXPECT_EQ(OC_STACK_INVALID_PARAM, PDMGetLinkedDevices(&uid1, &list1, &noOfDevices1));

    OCUuidList_t *list2 = NULL;
    size_t noOfDevices2 = 0;
    EXPECT_EQ(OC_STACK_OK, PDMGetLinkedDevices(&uid2, &list2, &noOfDevices2));
    OCUuidList_t *ptr = list2;
    while(ptr)
    {
        EXPECT_FALSE(0 == memcmp(ptr->dev.id, uid1.id,sizeof(uid1.id)));
        ptr = ptr->next;
    }
    ptr = list2;
    while(ptr)
    {
        EXPECT_TRUE(0 == memcmp(ptr->dev.id, uid3.id,sizeof(uid3.id)));
        ptr = ptr->next;
    }

    OCUuidList_t *list3 = NULL;
    size_t noOfDevices3 = 0;
    EXPECT_EQ(OC_STACK_OK, PDMGetLinkedDevices(&uid3, &list3, &noOfDevices3));
    ptr = list3;
    while(ptr)
    {
        EXPECT_FALSE(0 == memcmp(ptr->dev.id, uid1.id,sizeof(uid1.id)));
        ptr = ptr->next;
    }

    ptr = list3;
    while(ptr)
    {
        EXPECT_TRUE(0 == memcmp(ptr->dev.id, uid2.id,sizeof(uid2.id)));
        ptr = ptr->next;
    }
}
TEST(PDMSetDeviceStaleTest, VALIDUUID)
{
    EXPECT_EQ(OC_STACK_OK, PDMInit(NULL));
    OicUuid_t uid1 = {{0,}};
    memcpy(&uid1.id, ID_9, sizeof(uid1.id));
    EXPECT_EQ(OC_STACK_OK, PDMAddDevice(&uid1));
    EXPECT_EQ(OC_STACK_OK,PDMSetDeviceStale(&uid1));
}
TEST(PDMSetDeviceStaleTest, StaleDeviceNotinDeviceList)
{
    EXPECT_EQ(OC_STACK_OK, PDMInit(NULL));
    OicUuid_t uid1 = {{0,}};
    memcpy(&uid1.id, ID_10, sizeof(uid1.id));
    EXPECT_EQ(OC_STACK_OK, PDMAddDevice(&uid1));
    EXPECT_EQ(OC_STACK_OK,PDMSetDeviceStale(&uid1));

    OCUuidList_t *list = NULL;
    size_t noOfDevcies = 0;
    EXPECT_EQ(OC_STACK_OK, PDMGetOwnedDevices(&list, &noOfDevcies));

    while (list)
    {
        EXPECT_FALSE(0 == memcmp(list->dev.id, uid1.id,sizeof(uid1.id)));
        list = list->next;
    }
}
static OCStackResult RemoveDeviceInfoFromLocal(const OCProvisionDev_t* pTargetDev)
{
    // Remove credential of revoked device from SVR database
    OCStackResult res = OC_STACK_ERROR;
    const OicSecCred_t *cred = NULL;
    cred = GetCredResourceData(&pTargetDev->doxm->deviceID);
    if (cred == NULL)
    {
        OIC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to get credential of remove device.");
        goto error;
    }

    res = RemoveCredential(&cred->subject);
    if (res != OC_STACK_RESOURCE_DELETED)
    {
        OIC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to remove credential.");
        goto error;
    }

    /**
     * Change the device status as stale status.
     * If all request are successed, this device information will be deleted.
     */
    res = PDMSetDeviceStale(&pTargetDev->doxm->deviceID);
    if (res != OC_STACK_OK)
    {
        OIC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to set device status as stale");
        goto error;
    }

    // TODO: We need to add new mechanism to clean up the stale state of the device.

    //Close the DTLS session of the removed device.
    CAEndpoint_t* endpoint = (CAEndpoint_t *)&pTargetDev->endpoint;
    endpoint->port = pTargetDev->securePort;
    CAResult_t caResult = CACloseDtlsSession(endpoint);
    if(CA_STATUS_OK != caResult)
    {
        OIC_LOG_V(WARNING, TAG, "OCRemoveDevice : Failed to close DTLS session : %d", caResult);
    }

error:
    return res;
}
/*
* Function to device revocation
* This function will remove credential of target device from all devices in subnet.
*
* @param[in] ctx Application context would be returned in result callback
* @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)
* @param[in] pTargetDev Device information to be revoked.
* @param[in] resultCallback callback provided by API user, callback will be called when
*            credential revocation is finished.
 * @return  OC_STACK_OK in case of success and other value otherwise.
*/
OCStackResult OCRemoveDevice(void* ctx, unsigned short waitTimeForOwnedDeviceDiscovery,
                            const OCProvisionDev_t* pTargetDev,
                            OCProvisionResultCB resultCallback)
{
    OIC_LOG(INFO, TAG, "IN OCRemoveDevice");
    OCStackResult res = OC_STACK_ERROR;
    if (!pTargetDev || 0 == waitTimeForOwnedDeviceDiscovery)
    {
        OIC_LOG(INFO, TAG, "OCRemoveDevice : Invalied parameters");
        return OC_STACK_INVALID_PARAM;
    }
    if (!resultCallback)
    {
        OIC_LOG(INFO, TAG, "OCRemoveDevice : NULL Callback");
        return OC_STACK_INVALID_CALLBACK;
    }

    // Send DELETE requests to linked devices
    OCStackResult resReq = OC_STACK_ERROR; // Check that we have to wait callback or not.
    resReq = SRPRemoveDevice(ctx, waitTimeForOwnedDeviceDiscovery, pTargetDev, resultCallback);
    if (OC_STACK_OK != resReq)
    {
        if (OC_STACK_CONTINUE == resReq)
        {
            OIC_LOG(DEBUG, TAG, "OCRemoveDevice : Revoked device has no linked device except PT.");
        }
        else
        {
            OIC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to invoke SRPRemoveDevice");
            res = resReq;
            goto error;
        }
    }

    // Remove credential of revoked device from SVR database
    const OicSecCred_t *cred = NULL;
    cred = GetCredResourceData(&pTargetDev->doxm->deviceID);
    if (cred == NULL)
    {
        OIC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to get credential of remove device.");
        goto error;
    }

    res = RemoveCredential(&cred->subject);
    if (res != OC_STACK_RESOURCE_DELETED)
    {
        OIC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to remove credential.");
        goto error;
    }

    /**
     * Change the device status as stale status.
     * If all request are successed, this device information will be deleted.
     */
    res = PDMSetDeviceStale(&pTargetDev->doxm->deviceID);
    if (res != OC_STACK_OK)
    {
        OIC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to set device status as stale");
        goto error;
    }

    // TODO: We need to add new mechanism to clean up the stale state of the device.

    res = resReq;

    //Close the DTLS session of the removed device.
    CAEndpoint_t* endpoint = (CAEndpoint_t *)&pTargetDev->endpoint;
    endpoint->port = pTargetDev->securePort;
    CAResult_t caResult = CACloseDtlsSession(endpoint);
    if(CA_STATUS_OK != caResult)
    {
        OIC_LOG_V(WARNING, TAG, "OCRemoveDevice : Failed to close DTLS session : %d", caResult);
    }

    /**
     * If there is no linked device, PM does not send any request.
     * So we should directly invoke the result callback to inform the result of OCRemoveDevice.
     */
    if(OC_STACK_CONTINUE == res)
    {
        if(resultCallback)
        {
            resultCallback(ctx, 0, NULL, false);
        }
        res = OC_STACK_OK;
    }

error:
    OIC_LOG(INFO, TAG, "OUT OCRemoveDevice");
    return res;
}
TEST(PDMSetDeviceStaleTest, NULLUUID)
{
    EXPECT_EQ(OC_STACK_OK, PDMInit(NULL));
    EXPECT_EQ(OC_STACK_INVALID_PARAM, PDMSetDeviceStale(NULL));
}