/*
 * Copyright (c) 2021-2022 Qualcomm Technologies, Inc.
 * All Rights Reserved.
 * Confidential and Proprietary - Qualcomm Technologies, Inc.
 */

#include <stddef.h>
#include <stdio.h>
#include "cdefs.h"
#include "IKVStore.h"
#include "CKVStore.h"
#include "qsee_log.h"
#include "qsee_env.h"

#define SUCCESS 0
#define FAILURE -1
#define TOTAL_KEYS 28
#define __1KB__ 1024
#define MAX_SIZE_ALLOWED (( 32 * __1KB__))
#define MAX_KEYS_FOR_TESTING 25
#define RESIDUAL_MAX_FILES 1000 // After all tests are run, max files that can be created to exhaust system resources.
#define KEY_SIZE   64

#define TEST_OK(xx)                                                                                \
{                                                                                                  \
  ret = xx;                                                                                        \
  if (Object_isERROR(ret)) {                                                                       \
    qsee_log(QSEE_LOG_MSG_ERROR, "****FAILED: %s:%u ret:%d\n", __FUNCTION__, __LINE__, ret);       \
    goto bail;                                                                                     \
  }                                                                                                \
}                                                                                                  \

#define TEST_TRUE(x, fmt, ...)                                  \
{                                                               \
  if (!(x)) {                                                   \
    qsee_log(QSEE_LOG_MSG_ERROR, "%s:%u " fmt, __FUNCTION__,    \
      __LINE__, ##__VA_ARGS__);                                 \
    ret = FAILURE;                                              \
    goto bail;                                                  \
  }                                                             \
}

static int run_createKey_test(Object keyStore)
{
  /* Access Key of a different client*/
  int32_t ret = Object_OK;
  Object keyHandle = Object_NULL;
  char buffer[] = "DummyDataForTesting";
  char key[64];
  char largeBuffer[MAX_SIZE_ALLOWED + 32 ];
  uint32_t bufferSize = 4096;
  IKVStoreKey_Info keyInfo = {0};
  uint32_t index = 0;


  /* For a partition size of 2044kB(= 4088 sectors of 512byte size), the upper limit
   * on the number of keys that can be created is 493. For this test, we will create 494 keys.
   * Creation of the 494th key must fail. They keys have a data buffer size of <4kB
   */
  qsee_log(QSEE_LOG_MSG_ERROR, "Starting test %s", __FUNCTION__);

  for(index = 0; index < MAX_KEYS_FOR_TESTING ; index ++) {
    snprintf(key, sizeof(key), "%s%u", "RPMBServiceKey0", index);


    if (bufferSize == MAX_SIZE_ALLOWED) {
      bufferSize = 4096;
    }
    memset(largeBuffer, 'A', bufferSize);

    ret = IKVStore_createNewKey(keyStore, (const uint8_t*)key, strlen(key), (const void*)largeBuffer,
                                bufferSize, IKVStore_NO_CRYPTO_RPMB_SERVICE, &keyHandle);

    qsee_log(QSEE_LOG_MSG_ERROR, "Key is %s ret is %d",(char*)key, ret);
    if (IKVStore_ERROR_KEY_ALREADY_EXISTS == ret) {
      TEST_OK(IKVStore_getKeyHandle(keyStore,(uint8_t*)key, strlen(key), &keyHandle));
      TEST_OK(IKVStoreKey_delete(keyHandle));
      Object_release(keyHandle);
      TEST_OK(IKVStore_createNewKey(keyStore, (uint8_t*)key, strlen(key), (const void*)largeBuffer, bufferSize,
                                    IKVStore_NO_CRYPTO_RPMB_SERVICE, &keyHandle));
    }
    TEST_OK(IKVStoreKey_getInfo(keyHandle, &keyInfo));
    qsee_log(QSEE_LOG_MSG_ERROR, "Key Data Size is %zu",keyInfo.dataSize);
    TEST_TRUE(keyInfo.dataSize == bufferSize, "KeyInfo.dataSize %u, bufferSize %u", keyInfo.dataSize, bufferSize);
    TEST_TRUE(keyInfo.flags == IKVStore_NO_CRYPTO_RPMB_SERVICE , "KeyInfo.flags %u", keyInfo.flags);
    Object_RELEASE_IF(keyHandle);
    memset(largeBuffer, 0, MAX_SIZE_ALLOWED + 32);
    bufferSize += 4096;
  }


  qsee_log(QSEE_LOG_MSG_ERROR, "Checking if we can write the same keys over again", index);
  // Retry creating the keys that were created before to see if it succeeds

  for(index = 0; index < MAX_KEYS_FOR_TESTING; index ++) {
    snprintf(key, sizeof(key), "%s%u", "RPMBServiceKey0", index);
    qsee_log(QSEE_LOG_MSG_ERROR, "Key is %s",(char*)key);
    TEST_TRUE(IKVStore_ERROR_KEY_ALREADY_EXISTS == (ret =
              IKVStore_createNewKey(keyStore, (const uint8_t*)key, strlen(key), (const void*)buffer,
                                    strlen(buffer), IKVStore_NO_CRYPTO_RPMB_SERVICE, &keyHandle)),
                                    "Ret is %d", ret);
  }

  /* Negative tests */
  // Passing incorrect parameters
  TEST_TRUE(IKVStore_ERROR_INVALID_PARAMETERS == (ret =
            IKVStore_createNewKey(keyStore, NULL, 0, (const void*)buffer, strlen(buffer),
                                   IKVStore_NO_CRYPTO_RPMB_SERVICE, &keyHandle)),
            "Ret is %d", ret);

  TEST_TRUE(IKVStore_ERROR_INVALID_PARAMETERS == (ret =
            IKVStore_createNewKey(keyStore, (const uint8_t*)key, strlen(key), NULL,
                                   0, IKVStore_NO_CRYPTO_RPMB_SERVICE, &keyHandle)),
            "Ret is %d", ret);

  TEST_TRUE(IKVStore_ERROR_INVALID_PARAMETERS == (ret =
            IKVStore_createNewKey(keyStore, (const uint8_t*)key, 0, (const void*)buffer,
                                   strlen(buffer), IKVStore_NO_CRYPTO_RPMB_SERVICE, &keyHandle)),
            "Ret is %d", ret);

  TEST_TRUE(IKVStore_ERROR_INVALID_PARAMETERS == (ret =
            IKVStore_createNewKey(keyStore, (const uint8_t*)key, strlen(key),
                                   (const void*)buffer, 0, IKVStore_NO_CRYPTO_RPMB_SERVICE, &keyHandle)),
            "Ret is %d", ret);

  memset(largeBuffer, 'A', MAX_SIZE_ALLOWED + 32);
  memset(key, 'B', 6);
  TEST_TRUE(IKVStore_ERROR_INVALID_PARAMETERS == (ret =
            IKVStore_createNewKey(keyStore, (const uint8_t*)key, strlen(key),
                                   (const void*)largeBuffer, strlen(largeBuffer),
                                   IKVStore_NO_CRYPTO_RPMB_SERVICE, &keyHandle)),
            "Ret is %d", ret);
  ret = SUCCESS;
bail:
    Object_RELEASE_IF(keyHandle);
    return ret;
}

static int run_kvstore_unit_tests(Object keyStore)
{
  int32_t ret = Object_OK;
  Object keyHandle = Object_NULL;
  Object keyHandle2 = Object_NULL;
  Object clientIterator = Object_NULL;
  IKVStoreKey_Info key_info = {0};

  uint8_t key[] = "SampleKeyForTesting";
  char buffer[] = "DummyDataForTesting";

  uint8_t key1[] = "FunDataForTesting";
  char buffer1[] = "DummyDataForTesting1";

  char outputBuffer[256];
  size_t opBufferLen;

  uint8_t opKey[KEY_SIZE];
  uint8_t opKey2[KEY_SIZE];

  size_t opKeyLen;
  size_t opKeyLen2;

  TEST_OK(IKVStore_getIterator(keyStore, &clientIterator));
  memset(opKey, 0 , KEY_SIZE);
  
  while (IKVStoreIterator_ERROR_END_KEY_LIST != (ret = IKVStoreIterator_getNextKey(clientIterator, (void *)&opKey, 256, &opKeyLen)))
  {
    TEST_OK(IKVStore_getKeyHandle(keyStore, opKey, opKeyLen, &keyHandle));
    TEST_OK(IKVStoreKey_delete(keyHandle));
    memset(opKey, 0 , KEY_SIZE);
    Object_RELEASE_IF(keyHandle);
  } 
  Object_RELEASE_IF(clientIterator);
  

  ret = IKVStore_createNewKey(keyStore, (uint8_t*)key, sizeof(key), (const void*)buffer, strlen(buffer),
                              IKVStore_NO_CRYPTO_RPMB_SERVICE, &keyHandle);
  if (ret == IKVStore_ERROR_KEY_ALREADY_EXISTS) {
    TEST_OK(IKVStore_getKeyHandle(keyStore,(uint8_t*)key, sizeof(key), &keyHandle));
    TEST_OK(IKVStoreKey_delete(keyHandle));
    Object_release(keyHandle);
    TEST_OK(IKVStore_createNewKey(keyStore, (uint8_t*)key, sizeof(key), (const void*)buffer1, strlen(buffer1),
                                  IKVStore_NO_CRYPTO_RPMB_SERVICE, &keyHandle));
  }

   ret = IKVStore_createNewKey(keyStore, (uint8_t*)key1, sizeof(key1), (const void*)buffer1, strlen(buffer1),
                                 IKVStore_NO_CRYPTO_RPMB_SERVICE, &keyHandle2);


  if (ret == IKVStore_ERROR_KEY_ALREADY_EXISTS) {
    TEST_OK(IKVStore_getKeyHandle(keyStore,(uint8_t*)key1, sizeof(key1), &keyHandle2));
    TEST_OK(IKVStoreKey_delete(keyHandle2));
    Object_release(keyHandle2);
    TEST_OK(IKVStore_createNewKey(keyStore, (uint8_t*)key1, sizeof(key1), (const void*)buffer1, strlen(buffer1),
                                  IKVStore_NO_CRYPTO_RPMB_SERVICE, &keyHandle2));
  }
  Object_release(keyHandle);

  TEST_OK(IKVStore_getKeyHandle(keyStore,(uint8_t*)key, sizeof(key), &keyHandle));
  TEST_OK(IKVStoreKey_getValue(keyHandle, 0, strlen(buffer), (void *)outputBuffer, sizeof(outputBuffer), &opBufferLen));
  TEST_OK((memcmp(outputBuffer, buffer, strlen(buffer))));
  TEST_OK(!(opBufferLen == strlen(buffer)));

  TEST_OK(IKVStoreKey_updateValue(keyHandle, (void*)buffer1, 10, 2));
  memset(outputBuffer, 0, sizeof(outputBuffer));
  opBufferLen = 0;
  TEST_OK(IKVStoreKey_getValue(keyHandle, 2 , 10, (void *)outputBuffer, sizeof(outputBuffer),&opBufferLen));
  qsee_log(QSEE_LOG_MSG_ERROR, "Data is  is %s %zu\n",(char*)outputBuffer, opBufferLen);
  TEST_OK(IKVStoreKey_getInfo(keyHandle, &key_info));
  TEST_TRUE(key_info.flags == IKVStore_NO_CRYPTO_RPMB_SERVICE, "key_info.flags %u", key_info.flags);
  TEST_OK(IKVStoreKey_delete(keyHandle));

  Object_release(keyHandle);

  TEST_OK(IKVStore_createNewKey(keyStore, (uint8_t*)key, sizeof(key), (const void*)buffer, strlen(buffer),
                               IKVStore_NO_CRYPTO_RPMB_SERVICE, &keyHandle));

  TEST_OK(IKVStore_getIterator(keyStore, &clientIterator));

  TEST_OK(IKVStoreIterator_getNextKey(clientIterator, (void *)&opKey, 256, &opKeyLen));
  qsee_log(QSEE_LOG_MSG_ERROR, "Key Name is %s %zu\n",(char*)opKey, opKeyLen);
  TEST_TRUE(opKeyLen == sizeof(key), "opKeyLen %u, key1 Len %u", opKeyLen, sizeof(key));
  TEST_OK(IKVStore_getKeyHandle(keyStore, opKey, opKeyLen, &keyHandle));
  TEST_OK(IKVStoreKey_delete(keyHandle));
  Object_release(keyHandle);

  TEST_OK(IKVStoreIterator_getNextKey(clientIterator, (void *)&opKey, 256, &opKeyLen));
  qsee_log(QSEE_LOG_MSG_ERROR, "Key Name is %s %zu\n",(char*)opKey, opKeyLen);
  TEST_TRUE(opKeyLen == sizeof(key1),  "opKeyLen %u, key1 Len %u", opKeyLen, sizeof(key1));

  TEST_OK(IKVStore_getKeyHandle(keyStore, opKey, opKeyLen, &keyHandle));
  TEST_OK(IKVStoreKey_delete(keyHandle));
  ret = IKVStoreIterator_getNextKey(clientIterator, (void *)&opKey, 256, &opKeyLen);
  TEST_TRUE(ret == IKVStoreIterator_ERROR_END_KEY_LIST, "Ret is %d", ret);
  Object_release(keyHandle);
  ret = SUCCESS;

bail:
  Object_RELEASE_IF(keyHandle);
  Object_RELEASE_IF(keyHandle2);
  Object_RELEASE_IF(clientIterator);

  qsee_log(QSEE_LOG_MSG_ERROR, "Test Status %d", ret);
  return ret;
}

static int run_kvstore_modifyKey_test(Object keyStore)
{
  Object keyHandle = Object_NULL;
  Object clientIterator = Object_NULL;
  uint32_t index = 0;
  IKVStoreKey_Info key_info = {0};
  int32_t ret = Object_OK;
  char opKey[KEY_SIZE];
  size_t opKeyLen;
  char buffer[] = "UpdatingDataForTesting";
  char updateBuffer[512];
  char opBuffer[64] = "";
  char ipBuffer[64] = "";
  size_t opBufferLen = 0;

  /*Negative test  Invalid Key*/
  snprintf(opKey, sizeof(opKey), "%s%u", "RPMBServiceNegativeKey0", index);
  ret = IKVStore_getKeyHandle(keyStore,(uint8_t*)opKey, strlen(opKey), &keyHandle);
  TEST_TRUE(ret == IKVStore_ERROR_KEY_NOT_FOUND, "Return is %d", ret);


  snprintf(opKey, sizeof(opKey), "%s%u", "RPMBServiceKey0", index);
  TEST_OK(IKVStore_getKeyHandle(keyStore,(uint8_t*)opKey, strlen(opKey), &keyHandle));
  TEST_OK(IKVStoreKey_getInfo(keyHandle, &key_info));
  TEST_TRUE(key_info.flags == IKVStore_NO_CRYPTO_RPMB_SERVICE, "Key Info flags %u", key_info.flags);
  TEST_TRUE(key_info.dataSize = 4096 + index, "Key Info data Size %u", key_info.dataSize);

  TEST_OK(IKVStoreKey_getValue(keyHandle, 0, strlen(buffer), opBuffer, sizeof(opBuffer), &opBufferLen));
  for (int i = 0; i < opBufferLen; i++) {
    TEST_TRUE(opBuffer[i] == 'A', "opBuffer[%u]: %u", i, opBuffer[i]);
  }

  /* Stress Test to fill the max capacity */
  for (index  = 0; index < (MAX_SIZE_ALLOWED) - 35 ; index++) {
    snprintf(updateBuffer, sizeof(updateBuffer), "%u%s%u%s%u%s%u", index, "Updating", index, "Data", index, "Test", index);
    qsee_log(QSEE_LOG_MSG_ERROR, "Buffer To Write is  %s %zu",(char*)updateBuffer, opBufferLen);
    TEST_OK(IKVStoreKey_updateValue(keyHandle, (void*)updateBuffer, strlen(updateBuffer), index));
    memset(opBuffer, 0, opBufferLen);
    TEST_OK(IKVStoreKey_getValue(keyHandle, index , strlen(updateBuffer), opBuffer, sizeof(opBuffer), &opBufferLen));
    qsee_log(QSEE_LOG_MSG_ERROR, "Buffer content is  %s %zu",(char*)opBuffer, opBufferLen);
    TEST_OK((memcmp(opBuffer, updateBuffer, strlen(updateBuffer))));
  }
  TEST_OK(IKVStoreKey_getInfo(keyHandle, &key_info));
  TEST_TRUE(key_info.dataSize == MAX_SIZE_ALLOWED, "key_info dataSize %u", key_info.dataSize);
  ret = IKVStoreKey_updateValue(keyHandle, (void*)updateBuffer, strlen(updateBuffer), index);
  TEST_TRUE(ret == IKVStore_ERROR_INVALID_PARAMETERS, "Return is %d", ret);

  /* Negative Test Invalid offset*/
  ret = IKVStoreKey_updateValue(keyHandle, (void*)buffer, strlen(buffer), (MAX_SIZE_ALLOWED - strlen(buffer) + 1));
  TEST_TRUE(ret == IKVStore_ERROR_INVALID_PARAMETERS, "Return is %d", ret);

  /* Buffer Len is 0, should return success but no further updates*/
  TEST_OK(IKVStoreKey_updateValue(keyHandle, (void*)ipBuffer, 0, 0));

  /* Large Buffer passed in fail*/
  char largeBuffer[MAX_SIZE_ALLOWED] = "";
  ret = IKVStoreKey_updateValue(keyHandle, (void*)largeBuffer, sizeof(largeBuffer), 0);
  TEST_TRUE(ret == IKVStore_ERROR_INVALID_PARAMETERS, "Return is %d", ret);

  ret = SUCCESS;
bail:
    Object_release(keyHandle);
    return ret;
}

static int run_kvstore_getInfo_test(Object keyStore)
{
  int32_t ret = Object_OK;
  Object keyHandle = Object_NULL;

  IKVStoreKey_Info key_info = {0};

  char outputBuffer[256] = {0};
  size_t opBufferLen;

  char opKey[KEY_SIZE] = {0};

  size_t opKeyLen;
  uint32_t index = 0;
  uint32_t iteration = 0;
  char buffer[256] = {0};
  uint32_t sectorCount = 0;

  /* Access Key of a different client*/
  char key[] = "RPMBServiceInvalidKey";
  ret = IKVStore_getKeyHandle(keyStore,(uint8_t*)key, strlen(key), &keyHandle);
  TEST_TRUE(ret == IKVStore_ERROR_KEY_NOT_FOUND, "Ret is %d", ret);

  char key2[] = "RPMBServiceKeyACL";
  ret = IKVStore_getKeyHandle(keyStore,(uint8_t*)key2, strlen(key), &keyHandle);

  TEST_TRUE(ret == IKVStore_ERROR_KEY_NOT_FOUND, "Ret is %d", ret);


  /*First time reads from sector, second time from cache*/
  for (iteration = 0; iteration < 2; iteration ++)
  {
    for (index = 0; index < MAX_KEYS_FOR_TESTING; index++)
    {
      if (index % 7 == 0) {
        sectorCount = 0;
      } else {
        sectorCount++;
      }
      snprintf(opKey, sizeof(opKey), "%s%u", "RPMBServiceKey0", index);
      qsee_log(QSEE_LOG_MSG_ERROR, "Key is %s",(char*)opKey);
      TEST_OK(IKVStore_getKeyHandle(keyStore,(uint8_t*)opKey, strlen(opKey), &keyHandle));
      TEST_OK(IKVStoreKey_getInfo(keyHandle, &key_info));
      TEST_TRUE(key_info.flags == IKVStore_NO_CRYPTO_RPMB_SERVICE, "Flags  is %u", key_info.flags);
      if (iteration == 0) {
        if (index == 0) {
          TEST_TRUE(key_info.dataSize == MAX_SIZE_ALLOWED, "Data Size is %zu", key_info.dataSize);
        } else {
          TEST_TRUE(key_info.dataSize == (4096 + (sectorCount * 4096)), "Data Size is %zu", key_info.dataSize);
       }
      }
      else {
        memset(buffer, 0, sizeof(buffer));
        snprintf(buffer, sizeof(buffer), "%u%s%u", index, "CreatingNewKeyAgainInGetInfo", index);
        TEST_TRUE(key_info.dataSize == strlen(buffer), "Data Size is %zu", key_info.dataSize);
      }
      /* Delete the key and recreate the key with different sizes and run get info test again */
      TEST_OK(IKVStoreKey_delete(keyHandle));
      Object_RELEASE_IF(keyHandle);

      snprintf(buffer, sizeof(buffer), "%u%s%u", index, "CreatingNewKeyAgainInGetInfo", index);
      TEST_OK(IKVStore_createNewKey(keyStore, (const uint8_t*)opKey, strlen(opKey), (const void*)buffer,
              strlen(buffer), IKVStore_NO_CRYPTO_RPMB_SERVICE, &keyHandle));

      TEST_OK(IKVStoreKey_getInfo(keyHandle, &key_info));
      TEST_TRUE(key_info.flags == IKVStore_NO_CRYPTO_RPMB_SERVICE, "Flags  is %u", key_info.flags);
      TEST_TRUE(key_info.dataSize == strlen(buffer), "Data Size  is %u", key_info.dataSize);
      TEST_OK(IKVStoreKey_getValue(keyHandle, 0 , key_info.dataSize, outputBuffer, sizeof(outputBuffer), &opBufferLen));
      TEST_TRUE(opBufferLen == strlen(buffer), "Data Size  is %u", opBufferLen);
      TEST_OK((memcmp(outputBuffer, buffer, key_info.dataSize)));
      Object_RELEASE_IF(keyHandle);
    }
  }
bail:
  Object_RELEASE_IF(keyHandle);
  return ret;
}

static int run_kvstore_getIterator_tests(Object keyStore)
{
  int32_t ret = Object_OK;
  Object keyHandle = Object_NULL;
  Object clientIterator = Object_NULL;
  uint32_t index = 0;
  IKVStoreKey_Info key_info = {0};
  char opKey[KEY_SIZE] = {0};
  size_t opKeyLen;
  uint32_t iterationCounter = 0;
  uint32_t keyCount = 0;
  char dataBuffer[64];

  qsee_log(QSEE_LOG_MSG_ERROR, "Starting tests %s", __FUNCTION__);
  TEST_OK(IKVStore_getIterator(keyStore, &clientIterator));

  /* This test relies on the 25 keys created by the createNewKey Test case*/
  while (1) {
    ret = IKVStoreIterator_getNextKey(clientIterator, (void *)&opKey, 64, &opKeyLen);
    if (index == MAX_KEYS_FOR_TESTING) {
      qsee_log(QSEE_LOG_MSG_ERROR, "Ret is %d, counter %d",ret, iterationCounter);
      iterationCounter++;
      index = 0;
      Object_release(clientIterator);

      TEST_OK(IKVStore_getIterator(keyStore, &clientIterator));
      if (iterationCounter == 2) {
        break;
      }
      else {
        /* Iterator and retrieve Keys again*/
        qsee_log(QSEE_LOG_MSG_ERROR, "Return from test is %d", ret);
        TEST_OK(IKVStoreIterator_getNextKey(clientIterator, (void *)&opKey, 64, &opKeyLen));
      }
    }
    else if (Object_isERROR(ret))
    {
      /*Hook to add tests for the case where client has no  keys*/
      TEST_TRUE(ret == IKVStoreIterator_ERROR_NO_KEYS, "Return is %d", ret);
      break;
    }
    qsee_log(QSEE_LOG_MSG_ERROR, "Key Name is %s %zu\n",(char*)opKey, opKeyLen);
    snprintf(dataBuffer, sizeof(dataBuffer), "%u%s%u", index, "CreatingNewKeyAgainInGetInfo", index);
    TEST_OK(IKVStore_getKeyHandle(keyStore,(uint8_t*)opKey, opKeyLen, &keyHandle));
    TEST_OK(IKVStoreKey_getInfo(keyHandle, &key_info));
    TEST_TRUE(key_info.flags == IKVStore_NO_CRYPTO_RPMB_SERVICE, "key_info flags is %u", key_info.flags);
    qsee_log(QSEE_LOG_MSG_ERROR, "Key Data Size %zu", key_info.dataSize);
    memset(opKey, 0, KEY_SIZE);
    index++;
    Object_release(keyHandle);
  }

bail:
  Object_RELEASE_IF(keyHandle);
  Object_RELEASE_IF(clientIterator);
  qsee_log(QSEE_LOG_MSG_ERROR, "Ending tests %s %d", __FUNCTION__, ret);
  return ret;
}

static int run_kvstore_getKeyIteratorDelete_test(Object keyStore)
{
  Object keyHandle = Object_NULL;
  Object clientIterator = Object_NULL;
  uint32_t index = 0;
  IKVStoreKey_Info key_info = {0};
  int32_t ret = Object_OK;
  char opKey[KEY_SIZE] = {0};
  size_t opKeyLen;
  uint32_t iterationCounter = 0;
  uint32_t keyCount = 0;
  char buffer[256] = {0};

  qsee_log(QSEE_LOG_MSG_ERROR, "Starting tests %s", __FUNCTION__);
  TEST_OK(IKVStore_getIterator(keyStore, &clientIterator));

  /* This test relies on the 25 keys created by the createNewKey Test case*/
  while (1) {
    ret = IKVStoreIterator_getNextKey(clientIterator, (void *)&opKey, 64, &opKeyLen);
    if (index == MAX_KEYS_FOR_TESTING) {
      qsee_log(QSEE_LOG_MSG_ERROR, "Ret is %d, counter %d",ret, iterationCounter);
      iterationCounter++;
      index = 0;
      Object_release(clientIterator);

      TEST_OK(IKVStore_getIterator(keyStore, &clientIterator));
      if (iterationCounter == 2) {
        break;
      }
      else {
        /* Iterator and retrieve Keys again*/
        qsee_log(QSEE_LOG_MSG_ERROR, "Return from test is %d", ret);
        TEST_OK(IKVStoreIterator_getNextKey(clientIterator, (void *)&opKey, 64, &opKeyLen));
      }
    }
    else if (Object_isERROR(ret))
    {
      /*Hook to add tests for the case where client has no  keys*/
      TEST_TRUE(ret == IKVStoreIterator_ERROR_NO_KEYS, "Return is %d", ret);
      break;
    }
    index++;
    qsee_log(QSEE_LOG_MSG_ERROR, "Key Name is %s %zu\n",(char*)opKey, opKeyLen);
    TEST_OK(IKVStore_getKeyHandle(keyStore,(uint8_t*)opKey, opKeyLen, &keyHandle));
    TEST_OK(IKVStoreKey_delete(keyHandle));
    memset(opKey, 0, KEY_SIZE);
    Object_release(keyHandle);

    /*Create a new Key with different Name, iterator total count should still be same*/
    if (iterationCounter == 1) {
      snprintf(opKey, sizeof(opKey), "%u%s%u", index, "RPMBServiceKey0", index);
    }
    else {
      snprintf(opKey, sizeof(opKey), "%u%u%s%u", index, index, "RPMBServiceKey0", index);
    }
    snprintf(buffer, sizeof(buffer), "%s%s%u", opKey, "DataForTesting", index);
    qsee_log(QSEE_LOG_MSG_ERROR, "New Key Name for create is %s", opKey);
    TEST_OK(IKVStore_createNewKey(keyStore, (const uint8_t*)opKey, strlen(opKey), (const void*)buffer,
                                  strlen(buffer), IKVStore_NO_CRYPTO_RPMB_SERVICE, &keyHandle));
    TEST_OK(IKVStoreKey_getInfo(keyHandle, &key_info));
    TEST_TRUE(strlen(buffer) == key_info.dataSize, "Data size is %u", key_info.dataSize);
    memset(opKey, 0, KEY_SIZE);

    Object_release(keyHandle);
  }

  Object_release(clientIterator);

  /* Ensure after deletion and recreating the keys, the count is same*/
  TEST_OK(IKVStore_getIterator(keyStore, &clientIterator));
  while (1)
  {
    ret = IKVStoreIterator_getNextKey(clientIterator, (void *)&opKey, 64, &opKeyLen);
    if (ret != IKVStoreIterator_ERROR_END_KEY_LIST) {
      keyCount++;
    }else {
      break;
    }
  }

  TEST_TRUE(keyCount == MAX_KEYS_FOR_TESTING, "KeyCount is %u", keyCount);
  ret = 0;

bail:
  Object_RELEASE_IF(keyHandle);
  Object_release(clientIterator);
  qsee_log(QSEE_LOG_MSG_ERROR, "Ending tests %s %d", __FUNCTION__, ret);
  return ret;
}

static int run_kvstore_cleanupFiles_test(Object keyStore)
{
  int32_t ret = Object_OK;
  Object keyHandle = Object_NULL;
  Object clientIterator = Object_NULL;
  char opKey[KEY_SIZE] = {0};
  size_t opKeyLen = 0;
  uint32_t keyCount = 0;

  TEST_OK(IKVStore_getIterator(keyStore, &clientIterator));

  while (keyCount < RESIDUAL_MAX_FILES) {
    memset(opKey, 0, sizeof(opKey));
    ret = IKVStoreIterator_getNextKey(clientIterator, (void *)&opKey, KEY_SIZE, &opKeyLen);
    if (ret == IKVStoreIterator_ERROR_END_KEY_LIST) {
      Object_RELEASE_IF(clientIterator);
      TEST_OK(IKVStore_getIterator(keyStore, &clientIterator));
    }
    ret = IKVStore_getKeyHandle(keyStore, (const uint8_t*)opKey, opKeyLen, &keyHandle);
    if (ret != IKVStore_ERROR_KEY_NOT_FOUND) {
      qsee_log(QSEE_LOG_MSG_ERROR, "Key is %s\n",(char*)opKey);
      ret = IKVStoreKey_delete(keyHandle);
      qsee_log(QSEE_LOG_MSG_ERROR,"Ret is %d\n", ret);
      Object_RELEASE_IF(keyHandle);
    }
    keyCount++;
  }
  Object_RELEASE_IF(clientIterator);
bail:
  Object_RELEASE_IF(keyHandle);
  Object_RELEASE_IF(clientIterator);
  return ret;
}
static int run_kvstore_storage_full_test(Object keyStore)
{
  int32_t ret = Object_OK;
  Object keyHandle = Object_NULL;
  uint32_t index = 0, iteration = 0;

  char buffer[] = "DummyDataForTesting";
  char key[KEY_SIZE];

  for(iteration = 0; iteration < 9; iteration++) {
    memset(key, 0, sizeof(key));
    for(index = 0; index < RESIDUAL_MAX_FILES; index ++) {
      snprintf(key, sizeof(key), "%s%u%u", "RSStress0", iteration,index);
      qsee_log(QSEE_LOG_MSG_ERROR, "Create Key is %s",(char*)key);

      TEST_OK(IKVStore_createNewKey(keyStore, (const uint8_t*)key, strlen(key), (const void*)buffer,
                                    strlen(buffer), IKVStore_NO_CRYPTO_RPMB_SERVICE, &keyHandle));
      TEST_OK(IKVStoreKey_delete(keyHandle));
      Object_RELEASE_IF(keyHandle);
    }
  }

  for (index = 0; index < RESIDUAL_MAX_FILES; index++) {
    snprintf(key, sizeof(key), "%s%u", "RSStress09",index);
    qsee_log(QSEE_LOG_MSG_ERROR, "Key is %s",(char*)key);
    TEST_OK(IKVStore_createNewKey(keyStore, (const uint8_t*)key, strlen(key), (const void*)buffer,
                                  strlen(buffer), IKVStore_NO_CRYPTO_RPMB_SERVICE, &keyHandle));
    Object_RELEASE_IF(keyHandle);
  }
bail:
  Object_RELEASE_IF(keyHandle);
  return ret;
}


static int32_t  run_kvstore_createInfoDeleteTest(Object keyStore)
{
  int32_t ret = Object_OK;
  Object rootCEnv = Object_NULL;
  Object clientEnv = Object_NULL;
  Object keyHandle = Object_NULL;

  uint32_t index = 0, idx1 = 0, idx2 = 0;

  /* Access Key of a different client*/
  char buffer[] = "DummyDataForTesting";
  char key[64];
  char largeBuffer[4096];
  uint32_t bufferSize = 4096;
  IKVStoreKey_Info keyInfo = {0};
  char opKey[64] = {0};
  size_t opKeyLen;
  char outputBuffer[256];
  size_t opBufferLen;

  for(index = 0; index < MAX_KEYS_FOR_TESTING ; index ++) {
    snprintf(key, sizeof(key), "%s%u", "RPMBServiceKey0", index);
    qsee_log(QSEE_LOG_MSG_ERROR,"Key is %s",(char*)key);
    memset(largeBuffer, 'A', bufferSize);

    TEST_OK(IKVStore_createNewKey(keyStore, (const uint8_t*)key, strlen(key), (const void*)largeBuffer,
                                  bufferSize, IKVStore_NO_CRYPTO_RPMB_SERVICE, &keyHandle));
    TEST_OK(IKVStoreKey_getInfo(keyHandle, &keyInfo));
    qsee_log(QSEE_LOG_MSG_ERROR, "Key Data Size is %zu",keyInfo.dataSize);
    TEST_TRUE(keyInfo.dataSize == bufferSize, "Ret %zu keyInfo.dataSize %zu bufferSize", keyInfo.dataSize, bufferSize);
    TEST_OK(!(keyInfo.flags == IKVStore_NO_CRYPTO_RPMB_SERVICE));
    Object_RELEASE_IF(keyHandle);
  }

  for(index = 0; index < MAX_KEYS_FOR_TESTING ; index++) {
    snprintf(key, sizeof(key), "%s%u", "RPMBServiceKey0", index);
    qsee_log(QSEE_LOG_MSG_ERROR, "Key Data Size is %zu",keyInfo.dataSize);
    TEST_OK(IKVStore_getKeyHandle(keyStore,(uint8_t*)key, strlen(key), &keyHandle));
    TEST_OK(IKVStoreKey_getInfo(keyHandle, &keyInfo));
    qsee_log(QSEE_LOG_MSG_ERROR, "Key Data Size is %zu",keyInfo.dataSize);
    TEST_TRUE(keyInfo.dataSize == bufferSize, "Ret %zu keyInfo.dataSize %zu bufferSize", keyInfo.dataSize, bufferSize);
    TEST_TRUE((keyInfo.flags == IKVStore_NO_CRYPTO_RPMB_SERVICE), "Flags is %u", keyInfo.flags);
    ret = IKVStoreKey_getValue(keyHandle, 5000, strlen(buffer), (void *)outputBuffer, sizeof(outputBuffer), &opBufferLen);
    TEST_TRUE(ret == IKVStore_ERROR_INVALID_PARAMETERS, "Ret is %d, ret");
    TEST_OK(IKVStoreKey_delete(keyHandle));
    ret = IKVStoreKey_getInfo(keyHandle, &keyInfo);
    TEST_TRUE(ret == IKVStore_ERROR_KEY_NOT_FOUND, "Ret is %d", ret);
    ret = IKVStoreKey_getValue(keyHandle, 0, strlen(buffer), (void *)outputBuffer, sizeof(outputBuffer), &opBufferLen);
    TEST_TRUE(ret == IKVStore_ERROR_KEY_NOT_FOUND, "Ret is %d", ret);
    ret = IKVStoreKey_updateValue(keyHandle, (void*)outputBuffer, strlen(outputBuffer), 0);
    TEST_TRUE(ret == IKVStore_ERROR_KEY_NOT_FOUND, "Ret is %d", ret);
    ret = IKVStoreKey_delete(keyHandle);
    TEST_TRUE(ret == IKVStore_ERROR_KEY_NOT_FOUND, "Ret is %d", ret);
    Object_RELEASE_IF(keyHandle);

    TEST_OK(IKVStore_createNewKey(keyStore, (const uint8_t*)key, strlen(key), (const void*)largeBuffer,
                                  bufferSize, IKVStore_NO_CRYPTO_RPMB_SERVICE, &keyHandle));
    TEST_OK(IKVStoreKey_getInfo(keyHandle, &keyInfo));
    qsee_log(QSEE_LOG_MSG_ERROR, "Key Data Size is %zu",keyInfo.dataSize);
    TEST_TRUE(keyInfo.dataSize == bufferSize, "Ret %zu keyInfo.dataSize %zu bufferSize", keyInfo.dataSize, bufferSize);
    TEST_OK(!(keyInfo.flags == IKVStore_NO_CRYPTO_RPMB_SERVICE));
    Object_RELEASE_IF(keyHandle);
  }
  ret = SUCCESS;

bail:
  return ret;
}

int run_kv_store_tests()
{
  int32_t ret = Object_OK;
  Object kvStoreObj = Object_NULL;

  TEST_OK(qsee_open(CKVStore_UID, &kvStoreObj));

  TEST_OK(run_kvstore_unit_tests(kvStoreObj));
  //TODO: Remove these tests from sampleapp, not needed for testing*/
  TEST_OK(run_createKey_test(kvStoreObj));
  TEST_OK(run_kvstore_modifyKey_test(kvStoreObj));
  TEST_OK(run_kvstore_getInfo_test(kvStoreObj));
  TEST_OK(run_kvstore_getIterator_tests(kvStoreObj));
  TEST_OK(run_kvstore_getKeyIteratorDelete_test(kvStoreObj));
  TEST_OK(run_kvstore_createInfoDeleteTest(kvStoreObj));
  TEST_OK(run_kvstore_storage_full_test(kvStoreObj));
  TEST_OK(run_kvstore_cleanupFiles_test(kvStoreObj));
bail:
   Object_RELEASE_IF(kvStoreObj);
   kvStoreObj = Object_NULL;
   return ret;
}
