This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
pxz-hos-client-cpp-module/support/aws-sdk-cpp-master/aws-cpp-sdk-dynamodb-integration-tests/TableOperationTest.cpp

1463 lines
55 KiB
C++
Raw Normal View History

/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/external/gtest.h>
#include <aws/core/client/AsyncCallerContext.h>
#include <aws/core/client/ClientConfiguration.h>
#include <aws/core/client/CoreErrors.h>
#include <aws/core/auth/AWSCredentialsProviderChain.h>
#include <aws/core/http/HttpTypes.h>
#include <aws/core/utils/logging/LogMacros.h>
#include <aws/core/utils/memory/AWSMemory.h>
#include <aws/core/utils/UnreferencedParam.h>
#include <aws/core/utils/Outcome.h>
#include <aws/core/utils/memory/stl/AWSSet.h>
#include <aws/core/utils/memory/stl/AWSStringStream.h>
#include <aws/core/utils/ratelimiter/DefaultRateLimiter.h>
#include <aws/core/utils/threading/Executor.h>
#include <aws/dynamodb/DynamoDBClient.h>
#include <aws/dynamodb/DynamoDBErrors.h>
#include <aws/dynamodb/model/CreateTableRequest.h>
#include <aws/dynamodb/model/DeleteTableRequest.h>
#include <aws/dynamodb/model/DescribeTableRequest.h>
#include <aws/dynamodb/model/ListTablesRequest.h>
#include <aws/dynamodb/model/UpdateTableRequest.h>
#include <aws/dynamodb/model/PutItemRequest.h>
#include <aws/dynamodb/model/GetItemRequest.h>
#include <aws/dynamodb/model/ScanRequest.h>
#include <aws/dynamodb/model/UpdateItemRequest.h>
#include <aws/dynamodb/model/DeleteItemRequest.h>
#include <aws/testing/TestingEnvironment.h>
#include <aws/core/utils/UUID.h>
#include <algorithm>
using namespace Aws::Auth;
using namespace Aws::Http;
using namespace Aws::Client;
using namespace Aws::DynamoDB;
using namespace Aws::DynamoDB::Model;
#define TEST_TABLE_PREFIX "IntegrationTest_"
//fill these in before running the test.
static const char HASH_KEY_NAME[] = "HashKey";
static const char ENDPOINT_OVERRIDE[] = ""; // Use localhost:8000 for DynamoDb Local
static const char BASE_SIMPLE_TABLE[] = "Simple";
static const char BASE_THROUGHPUT_TABLE[] = "Throughput";
static const char BASE_CONDITION_TABLE[] = "ConditionCheck";
static const char BASE_VALIDATION_TABLE[] = "Validation";
static const char BASE_CRUD_TEST_TABLE[] = "Crud";
static const char BASE_CRUD_CALLBACKS_TEST_TABLE[] = "Crud_WithCallbacks";
static const char BASE_THROTTLED_TEST_TABLE[] = "Throttled";
static const char BASE_LIMITER_TEST_TABLE[] = "Limiter";
static const char BASE_ATTRIBUTEVALUE_TEST_TABLE[] = "AttributeValue";
static const char ALLOCATION_TAG[] = "TableOperationTest";
namespace {
static std::string DYNAMODB_INTEGRATION_TEST_ID;
Aws::String GetTablePrefix()
{
return Aws::Testing::GetAwsResourcePrefix() + TEST_TABLE_PREFIX + DYNAMODB_INTEGRATION_TEST_ID.c_str() + "_";
}
Aws::String BuildTableName(const char* baseName)
{
return GetTablePrefix() + baseName;
}
class TableOperationTest : public ::testing::Test {
public:
static std::shared_ptr<DynamoDBClient> m_client;
static std::shared_ptr<Aws::Utils::RateLimits::RateLimiterInterface> m_limiter;
Aws::Vector<GetItemOutcome> getItemResultsFromCallbackTest;
Aws::Vector<PutItemOutcome> putItemResultsFromCallbackTest;
Aws::Vector<DeleteItemOutcome> deleteItemResultsFromCallbackTest;
Aws::Vector<UpdateItemOutcome> updateItemResultsFromCallbackTest;
//the idea here, is that the test will kick off a bunch of requests and need to wait for them to finish.
//the test will call wait on the semaphore and when the callbacks have processed all 50 of the requests, they will
//signal allowing the test thread to continue on.
std::mutex getItemResultMutex;
std::condition_variable getItemResultSemaphore;
std::mutex putItemResultMutex;
std::condition_variable putItemResultSemaphore;
std::mutex deleteItemResultMutex;
std::condition_variable deleteItemResultSemaphore;
std::mutex updateItemResultMutex;
std::condition_variable updateItemResultSemaphore;
void GetItemOutcomeReceived(const DynamoDBClient* sender, const GetItemRequest& request, const GetItemOutcome& outcome, const std::shared_ptr<const AsyncCallerContext>& context)
{
AWS_UNREFERENCED_PARAM(sender);
AWS_UNREFERENCED_PARAM(request);
AWS_UNREFERENCED_PARAM(context);
std::lock_guard<std::mutex> locker(getItemResultMutex);
getItemResultsFromCallbackTest.push_back(outcome);
if (getItemResultsFromCallbackTest.size() == 50)
{
getItemResultSemaphore.notify_all();
}
}
void PutItemOutcomeReceived(const DynamoDBClient* sender, const PutItemRequest& request, const PutItemOutcome& outcome, const std::shared_ptr<const AsyncCallerContext>& context)
{
AWS_UNREFERENCED_PARAM(sender);
AWS_UNREFERENCED_PARAM(request);
AWS_UNREFERENCED_PARAM(context);
std::lock_guard<std::mutex> locker(putItemResultMutex);
putItemResultsFromCallbackTest.push_back(outcome);
if (putItemResultsFromCallbackTest.size() == 50)
{
putItemResultSemaphore.notify_all();
}
}
void DeleteItemOutcomeReceived(const DynamoDBClient* sender, const DeleteItemRequest& request, const DeleteItemOutcome& outcome, const std::shared_ptr<const AsyncCallerContext>& context)
{
AWS_UNREFERENCED_PARAM(sender);
AWS_UNREFERENCED_PARAM(request);
AWS_UNREFERENCED_PARAM(context);
std::lock_guard<std::mutex> locker(deleteItemResultMutex);
deleteItemResultsFromCallbackTest.push_back(outcome);
if (deleteItemResultsFromCallbackTest.size() == 50)
{
deleteItemResultSemaphore.notify_all();
}
}
void UpdateItemOutcomeReceived(const DynamoDBClient* sender, const UpdateItemRequest& request, const UpdateItemOutcome& outcome, const std::shared_ptr<const AsyncCallerContext>& context)
{
AWS_UNREFERENCED_PARAM(sender);
AWS_UNREFERENCED_PARAM(request);
AWS_UNREFERENCED_PARAM(context);
std::lock_guard<std::mutex> locker(updateItemResultMutex);
updateItemResultsFromCallbackTest.push_back(outcome);
if (updateItemResultsFromCallbackTest.size() == 50)
{
updateItemResultSemaphore.notify_all();
}
}
protected:
static void SetUpClient(Aws::Http::TransferLibType transferType)
{
// Create a client
ClientConfiguration config;
config.endpointOverride = ENDPOINT_OVERRIDE;
config.scheme = Scheme::HTTPS;
config.connectTimeoutMs = 30000;
config.requestTimeoutMs = 30000;
config.readRateLimiter = m_limiter;
config.writeRateLimiter = m_limiter;
config.httpLibOverride = transferType;
config.executor = Aws::MakeShared<Aws::Utils::Threading::PooledThreadExecutor>(ALLOCATION_TAG, 4);
config.disableExpectHeader = true;
//to test proxy functionality, uncomment the next two lines.
//config.proxyHost = "localhost";
//config.proxyPort = 8080;
m_client = Aws::MakeShared<DynamoDBClient>(ALLOCATION_TAG, config);
}
static void SetUpTestCase()
{
m_limiter = Aws::MakeShared<Aws::Utils::RateLimits::DefaultRateLimiter<>>(ALLOCATION_TAG, 200000);
SetUpClient(Aws::Http::TransferLibType::DEFAULT_CLIENT);
DYNAMODB_INTEGRATION_TEST_ID = Aws::String(Aws::Utils::UUID::RandomUUID()).c_str();
}
static void TearDownTestCase()
{
DeleteAllTables();
m_limiter = nullptr;
m_client = nullptr;
}
static void DeleteAllTables()
{
DeleteTable(BuildTableName(BASE_SIMPLE_TABLE));
DeleteTable(BuildTableName(BASE_THROUGHPUT_TABLE));
DeleteTable(BuildTableName(BASE_CONDITION_TABLE));
DeleteTable(BuildTableName(BASE_VALIDATION_TABLE));
DeleteTable(BuildTableName(BASE_CRUD_TEST_TABLE));
DeleteTable(BuildTableName(BASE_CRUD_CALLBACKS_TEST_TABLE));
DeleteTable(BuildTableName(BASE_THROTTLED_TEST_TABLE));
DeleteTable(BuildTableName(BASE_LIMITER_TEST_TABLE));
DeleteTable(BuildTableName(BASE_ATTRIBUTEVALUE_TEST_TABLE));
}
void CreateTable(Aws::String tableName, long readCap, long writeCap)
{
//create a table and verify it's output
CreateTableRequest createTableRequest;
AttributeDefinition hashKey;
hashKey.SetAttributeName(HASH_KEY_NAME);
hashKey.SetAttributeType(ScalarAttributeType::S);
createTableRequest.AddAttributeDefinitions(hashKey);
KeySchemaElement hashKeySchemaElement;
hashKeySchemaElement.WithAttributeName(HASH_KEY_NAME).WithKeyType(KeyType::HASH);
createTableRequest.AddKeySchema(hashKeySchemaElement);
ProvisionedThroughput provisionedThroughput;
provisionedThroughput.SetReadCapacityUnits(readCap);
provisionedThroughput.SetWriteCapacityUnits(writeCap);
createTableRequest.WithProvisionedThroughput(provisionedThroughput);
createTableRequest.WithTableName(tableName);
CreateTableOutcome createTableOutcome = m_client->CreateTable(createTableRequest);
if (createTableOutcome.IsSuccess())
{
ASSERT_EQ(tableName, createTableOutcome.GetResult().GetTableDescription().GetTableName());
}
else
{
ASSERT_EQ(createTableOutcome.GetError().GetErrorType(), DynamoDBErrors::RESOURCE_IN_USE);
}
//since we need to wait for the table to finish creating anyways,
//let's go ahead and test describe table api while we are at it.
WaitUntilActive(tableName);
}
static void DeleteTable(Aws::String tableName)
{
DeleteTableRequest deleteTableRequest;
deleteTableRequest.SetTableName(tableName);
DeleteTableOutcome deleteTableOutcome = m_client->DeleteTable(deleteTableRequest);
ASSERT_TRUE(deleteTableOutcome.IsSuccess());
}
DescribeTableResult WaitUntilActive(const Aws::String tableName)
{
DescribeTableRequest describeTableRequest;
describeTableRequest.SetTableName(tableName);
bool shouldContinue = true;
DescribeTableOutcome outcome = m_client->DescribeTable(describeTableRequest);
while (shouldContinue)
{
if (outcome.IsSuccess() && outcome.GetResult().GetTable().GetTableStatus() == TableStatus::ACTIVE)
{
break;
}
else
{
std::this_thread::sleep_for(std::chrono::seconds(1));
}
outcome = m_client->DescribeTable(describeTableRequest);
}
return outcome.GetResult();
}
};
std::shared_ptr<DynamoDBClient> TableOperationTest::m_client(nullptr);
std::shared_ptr<Aws::Utils::RateLimits::RateLimiterInterface> TableOperationTest::m_limiter(nullptr);
TEST_F(TableOperationTest, TestListTable)
{
AWS_LOGSTREAM_TRACE(ALLOCATION_TAG, "TestListTable")
Aws::String simpleTableName = BuildTableName(BASE_SIMPLE_TABLE);
CreateTable(simpleTableName, 10, 10);
Aws::Vector<Aws::String> filteredTableNames;
ListTablesRequest listTablesRequest;
listTablesRequest.SetLimit(10);
bool done = false;
while(!done)
{
ListTablesOutcome listTablesOutcome = m_client->ListTables(listTablesRequest);
EXPECT_TRUE(listTablesOutcome.IsSuccess());
auto tableNames = listTablesOutcome.GetResult().GetTableNames();
std::copy_if(tableNames.cbegin(),
tableNames.cend(),
std::back_inserter(filteredTableNames),
[](const Aws::String& tableName) { return tableName.find(GetTablePrefix()) == 0; });
listTablesRequest.SetExclusiveStartTableName(listTablesOutcome.GetResult().GetLastEvaluatedTableName());
done = listTablesRequest.GetExclusiveStartTableName().empty();
}
EXPECT_EQ(1uL, filteredTableNames.size());
if(filteredTableNames.size() > 0)
{
EXPECT_EQ(simpleTableName, filteredTableNames[0]);
}
}
TEST_F(TableOperationTest, TestUpdateThroughput)
{
AWS_LOGSTREAM_TRACE(ALLOCATION_TAG, "TestUpdateThroughput")
Aws::String simpleTableName = BuildTableName(BASE_THROUGHPUT_TABLE);
CreateTable(simpleTableName, 10, 10);
// Update the table and make sure it works.
long newReadCapacity = 15;
UpdateTableRequest updateTableRequest;
updateTableRequest.SetTableName(simpleTableName);
ProvisionedThroughput provisionedThroughput;
provisionedThroughput.SetReadCapacityUnits(newReadCapacity);
provisionedThroughput.SetWriteCapacityUnits(10); // TODO: Do we need this??
updateTableRequest.SetProvisionedThroughput(provisionedThroughput);
UpdateTableOutcome updateTableOutcome = m_client->UpdateTable(updateTableRequest);
DescribeTableResult describeTableResult = WaitUntilActive(simpleTableName);
//make sure update worked.
EXPECT_EQ(newReadCapacity, describeTableResult.GetTable().GetProvisionedThroughput().GetReadCapacityUnits());
}
TEST_F(TableOperationTest, TestConditionalCheckFailure)
{
AWS_LOGSTREAM_TRACE(ALLOCATION_TAG, "TestConditionalCheckFailure")
Aws::String simpleTableName = BuildTableName(BASE_CONDITION_TABLE);
CreateTable(simpleTableName, 10, 10);
AttributeValue homer;
homer.SetS("Homer");
AttributeValue bart;
bart.SetS("Bart");
AttributeValue lisa;
lisa.SetS("Lisa");
AttributeValue hashKeyAttribute;
hashKeyAttribute.SetS("TestItem");
PutItemRequest putRequest;
putRequest.SetTableName(simpleTableName);
putRequest.AddItem(HASH_KEY_NAME, hashKeyAttribute);
putRequest.AddItem("Simpson", homer);
m_client->PutItem(putRequest);
PutItemRequest badRequest;
badRequest.SetTableName(simpleTableName);
badRequest.AddItem(HASH_KEY_NAME, hashKeyAttribute);
badRequest.AddItem("Simpson", bart);
ExpectedAttributeValue expected;
expected.SetValue(lisa);
expected.SetComparisonOperator(ComparisonOperator::EQ);
badRequest.AddExpected("Simpson", expected);
PutItemOutcome result = m_client->PutItem(badRequest);
ASSERT_FALSE(result.IsSuccess());
#if ENABLE_CURL_CLIENT
ASSERT_FALSE(result.GetError().GetRemoteHostIpAddress().empty());
#endif
ASSERT_FALSE(result.GetError().GetRequestId().empty());
ASSERT_EQ(DynamoDBErrors::CONDITIONAL_CHECK_FAILED, result.GetError().GetErrorType());
}
TEST_F(TableOperationTest, TestValidationError)
{
AWS_LOGSTREAM_TRACE(ALLOCATION_TAG, "TestValidationError")
Aws::String simpleTableName = BuildTableName(BASE_VALIDATION_TABLE);
CreateTable(simpleTableName, 10, 10);
AttributeValue hashKeyAttribute;
hashKeyAttribute.SetS("someValue");
PutItemRequest request;
request.SetTableName(simpleTableName);
request.AddItem("TotallyNotTheHashKey", hashKeyAttribute);
PutItemOutcome result = m_client->PutItem(request);
ASSERT_FALSE(result.IsSuccess());
#if ENABLE_CURL_CLIENT
ASSERT_FALSE(result.GetError().GetRemoteHostIpAddress().empty());
#endif
ASSERT_FALSE(result.GetError().GetRequestId().empty());
ASSERT_EQ(DynamoDBErrors::VALIDATION, result.GetError().GetErrorType());
}
TEST_F(TableOperationTest, TestThrottling)
{
AWS_LOGSTREAM_TRACE(ALLOCATION_TAG, "TestThrottling")
Aws::String throttledTestTableName = BuildTableName(BASE_THROTTLED_TEST_TABLE);
CreateTable(throttledTestTableName, 1, 1);
// Blast the table until it throttles
Aws::String testValueColumnName = "TestValue";
Aws::Vector<PutItemOutcomeCallable> putItemResults;
Aws::StringStream ss;
// Under ideal circumstances, Dynamo can offer up to 300 secs of bursting, so we must exceed that
for (unsigned i = 0; i < 500; ++i)
{
ss << HASH_KEY_NAME << i;
PutItemRequest putItemRequest;
putItemRequest.SetTableName(throttledTestTableName);
AttributeValue hashKeyAttribute;
hashKeyAttribute.SetS(ss.str());
ss.str("");
putItemRequest.AddItem(HASH_KEY_NAME, hashKeyAttribute);
AttributeValue testValueAttribute;
ss << testValueColumnName << i;
testValueAttribute.SetS(ss.str());
putItemRequest.AddItem(testValueColumnName, testValueAttribute);
ss.str("");
putItemResults.push_back(m_client->PutItemCallable(putItemRequest));
}
int throttleCount = 0;
for (auto& putItemResult : putItemResults)
{
PutItemOutcome outcome = putItemResult.get();
if (!outcome.IsSuccess())
{
AWSError<DynamoDBErrors> error = outcome.GetError();
if (error.GetErrorType() == DynamoDBErrors::PROVISIONED_THROUGHPUT_EXCEEDED)
{
if (++throttleCount >= 10)
{
// Good, the client is doing what it is supposed to do. No need to beat a dead horse.
// TODO: We need to stop the in-flight requests before the client gets deleted
break;
}
}
else
{
FAIL() << "Unexpected Error: " << error.GetMessage();
}
}
}
}
TEST_F(TableOperationTest, TestCrudOperations)
{
AWS_LOGSTREAM_TRACE(ALLOCATION_TAG, "TestCrudOperations")
Aws::String crudTestTableName = BuildTableName(BASE_CRUD_TEST_TABLE);
CreateTable(crudTestTableName, 50, 50);
//now put 50 items in the table asynchronously
Aws::String testValueColumnName = "TestValue";
Aws::Vector<PutItemOutcomeCallable> putItemResults;
Aws::StringStream ss;
for (unsigned i = 0; i < 50; ++i)
{
ss << HASH_KEY_NAME << i;
PutItemRequest putItemRequest;
putItemRequest.SetTableName(crudTestTableName);
AttributeValue hashKeyAttribute;
hashKeyAttribute.SetS(ss.str());
ss.str("");
putItemRequest.AddItem(HASH_KEY_NAME, hashKeyAttribute);
AttributeValue testValueAttribute;
ss << testValueColumnName << i;
testValueAttribute.SetS(ss.str());
putItemRequest.AddItem(testValueColumnName, testValueAttribute);
ss.str("");
putItemResults.push_back(m_client->PutItemCallable(putItemRequest));
}
//wait for put operations to finish
//isn't c++ 11 nice!
for (auto& putItemResult : putItemResults)
{
putItemResult.get();
}
//now we get the items we were supposed to be putting and make sure
//they were put successfully.
Aws::Vector<GetItemOutcomeCallable> getItemOutcomes;
for (unsigned i = 0; i < 50; ++i)
{
GetItemRequest getItemRequest;
ss << HASH_KEY_NAME << i;
AttributeValue hashKey;
hashKey.SetS(ss.str());
getItemRequest.AddKey(HASH_KEY_NAME, hashKey);
getItemRequest.SetTableName(crudTestTableName);
Aws::Vector<Aws::String> attributesToGet;
attributesToGet.push_back(HASH_KEY_NAME);
attributesToGet.push_back(testValueColumnName);
ss.str("");
getItemOutcomes.push_back(m_client->GetItemCallable(getItemRequest));
}
//verify the values
for (unsigned i = 0; i < 50; ++i)
{
GetItemOutcome outcome = getItemOutcomes[i].get();
EXPECT_TRUE(outcome.IsSuccess());
GetItemResult result = outcome.GetResult();
ss << HASH_KEY_NAME << i;
Aws::Map<Aws::String, AttributeValue> returnedItemCollection = result.GetItem();
EXPECT_EQ(ss.str(), returnedItemCollection[HASH_KEY_NAME].GetS());
ss.str("");
ss << testValueColumnName << i;
EXPECT_EQ(ss.str(), returnedItemCollection[testValueColumnName].GetS());
ss.str("");
}
ScanRequest scanRequest;
scanRequest.WithTableName(crudTestTableName);
ScanOutcome scanOutcome = m_client->Scan(scanRequest);
EXPECT_TRUE(scanOutcome.IsSuccess());
EXPECT_EQ(50, scanOutcome.GetResult().GetCount());
//now update the existing values
Aws::Vector<UpdateItemOutcomeCallable> updateItemOutcomes;
for (unsigned i = 0; i < 50; ++i)
{
ss << HASH_KEY_NAME << i;
AttributeValue hashKeyAttribute;
hashKeyAttribute.SetS(ss.str());
UpdateItemRequest updateItemRequest;
updateItemRequest.SetTableName(crudTestTableName);
updateItemRequest.AddKey(HASH_KEY_NAME, AttributeValue(ss.str()));
ss.str("");
AttributeValueUpdate testValueAttribute;
ss << testValueColumnName << i * 2;
testValueAttribute.SetAction(AttributeAction::PUT);
AttributeValue valueAttribute;
valueAttribute.SetS(ss.str());
testValueAttribute.SetValue(valueAttribute);
updateItemRequest.AddAttributeUpdates(testValueColumnName, testValueAttribute);
ss.str("");
updateItemOutcomes.push_back(m_client->UpdateItemCallable(updateItemRequest));
}
//wait for operations to finish.
for (auto& updateItemOutcome : updateItemOutcomes)
{
updateItemOutcome.get();
}
//now get the items again, making sure they were properly
//updated.
getItemOutcomes.clear();
for (unsigned i = 0; i < 50; ++i)
{
GetItemRequest getItemRequest;
ss << HASH_KEY_NAME << i;
AttributeValue hashKey;
hashKey.SetS(ss.str());
getItemRequest.AddKey(HASH_KEY_NAME, hashKey);
getItemRequest.SetTableName(crudTestTableName);
Aws::Vector<Aws::String> attributesToGet;
attributesToGet.push_back(HASH_KEY_NAME);
attributesToGet.push_back(testValueColumnName);
ss.str("");
getItemOutcomes.push_back(m_client->GetItemCallable(getItemRequest));
}
//verify values.
for (unsigned i = 0; i < 50; ++i)
{
GetItemOutcome outcome = getItemOutcomes[i].get();
EXPECT_TRUE(outcome.IsSuccess());
GetItemResult result = outcome.GetResult();
ss << HASH_KEY_NAME << i;
Aws::Map<Aws::String, AttributeValue> returnedItemCollection = result.GetItem();
EXPECT_EQ(ss.str(), returnedItemCollection[HASH_KEY_NAME].GetS());
ss.str("");
ss << testValueColumnName << i * 2;
EXPECT_EQ(ss.str(), returnedItemCollection[testValueColumnName].GetS());
ss.str("");
}
//now delete all the items we added.
Aws::Vector<DeleteItemOutcomeCallable> deleteItemOutcomes;
for (unsigned i = 0; i < 50; ++i)
{
DeleteItemRequest deleteItemRequest;
ss << HASH_KEY_NAME << i;
AttributeValue hashKey;
hashKey.SetS(ss.str());
deleteItemRequest.AddKey(HASH_KEY_NAME, hashKey);
deleteItemRequest.SetTableName(crudTestTableName);
deleteItemRequest.SetReturnValues(ReturnValue::ALL_OLD);
ss.str("");
deleteItemOutcomes.push_back(m_client->DeleteItemCallable(deleteItemRequest));
}
//verify that we properly returned the old values.
unsigned count = 0;
for (DeleteItemOutcomeCallable& deleteItemOutcome : deleteItemOutcomes)
{
DeleteItemOutcome outcome = deleteItemOutcome.get();
EXPECT_TRUE(outcome.IsSuccess());
DeleteItemResult deleteItemResult = outcome.GetResult();
Aws::Map<Aws::String, AttributeValue> attributes = deleteItemResult.GetAttributes();
ss << HASH_KEY_NAME << count++;
EXPECT_EQ(ss.str(), attributes[HASH_KEY_NAME].GetS());
ss.str("");
}
}
TEST_F(TableOperationTest, TestCrudOperationsWithCallbacks)
{
AWS_LOGSTREAM_TRACE(ALLOCATION_TAG, "TestCrudOperationsWithCallbacks")
Aws::String crudCallbacksTestTableName = BuildTableName(BASE_CRUD_CALLBACKS_TEST_TABLE);
CreateTable(crudCallbacksTestTableName, 50, 50);
//registering a member function is ugly business even in modern c++
auto putItemHandler = std::bind(&TableOperationTest::PutItemOutcomeReceived, this, std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3, std::placeholders::_4);
auto getItemHandler = std::bind(&TableOperationTest::GetItemOutcomeReceived, this, std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3, std::placeholders::_4);
auto deleteItemHandler = std::bind(&TableOperationTest::DeleteItemOutcomeReceived, this, std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3, std::placeholders::_4);
auto updateItemHandler = std::bind(&TableOperationTest::UpdateItemOutcomeReceived, this, std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3, std::placeholders::_4);
//now put 50 items in the table asynchronously
Aws::String testValueColumnName = "TestValue";
Aws::StringStream ss;
for (unsigned i = 0; i < 50; ++i)
{
ss << HASH_KEY_NAME << i;
PutItemRequest putItemRequest;
putItemRequest.SetTableName(crudCallbacksTestTableName);
AttributeValue hashKeyAttribute;
hashKeyAttribute.SetS(ss.str());
ss.str("");
putItemRequest.AddItem(HASH_KEY_NAME, hashKeyAttribute);
AttributeValue testValueAttribute;
ss << testValueColumnName << i;
testValueAttribute.SetS(ss.str());
putItemRequest.AddItem(testValueColumnName, testValueAttribute);
ss.str("");
m_client->PutItemAsync(putItemRequest, putItemHandler);
}
//wait for the callbacks to finish.
std::unique_lock<std::mutex> putItemResultLock(putItemResultMutex);
putItemResultSemaphore.wait(putItemResultLock);
//now we get the items we were supposed to be putting and make sure
//they were put successfully.
for (unsigned i = 0; i < 50; ++i)
{
GetItemRequest getItemRequest;
ss << HASH_KEY_NAME << i;
AttributeValue hashKey;
hashKey.SetS(ss.str());
getItemRequest.AddKey(HASH_KEY_NAME, hashKey);
getItemRequest.SetTableName(crudCallbacksTestTableName);
Aws::Vector<Aws::String> attributesToGet;
attributesToGet.push_back(HASH_KEY_NAME);
attributesToGet.push_back(testValueColumnName);
ss.str("");
m_client->GetItemAsync(getItemRequest, getItemHandler);
}
//wait for the callbacks to finish.
std::unique_lock<std::mutex> getItemResultLock(getItemResultMutex);
getItemResultSemaphore.wait(getItemResultLock);
Aws::Map<Aws::String, Aws::String> getItemResults;
//The values are not in order, so let's verify the values by using a map.
for (unsigned i = 0; i < 50; ++i)
{
GetItemOutcome outcome = getItemResultsFromCallbackTest[i];
EXPECT_TRUE(outcome.IsSuccess());
GetItemResult result = outcome.GetResult();
Aws::Map<Aws::String, AttributeValue> returnedItemCollection = result.GetItem();
getItemResults[returnedItemCollection[HASH_KEY_NAME].GetS()] = returnedItemCollection[testValueColumnName].GetS();
}
for (unsigned i = 0; i < 50; ++i)
{
ss << HASH_KEY_NAME << i;
Aws::String hashKey = ss.str();
ss.str("");
ss << testValueColumnName << i;
EXPECT_EQ(ss.str(), getItemResults[hashKey]);
ss.str("");
}
ScanRequest scanRequest;
scanRequest.WithTableName(crudCallbacksTestTableName);
ScanOutcome scanOutcome = m_client->Scan(scanRequest);
EXPECT_TRUE(scanOutcome.IsSuccess());
EXPECT_EQ(50, scanOutcome.GetResult().GetCount());
//now update the existing values
for (unsigned i = 0; i < 50; ++i)
{
ss << HASH_KEY_NAME << i;
AttributeValue hashKeyAttribute;
hashKeyAttribute.SetS(ss.str());
UpdateItemRequest updateItemRequest;
updateItemRequest.SetTableName(crudCallbacksTestTableName);
updateItemRequest.AddKey(HASH_KEY_NAME, AttributeValue(ss.str()));
ss.str("");
AttributeValueUpdate testValueAttribute;
ss << testValueColumnName << i * 2;
testValueAttribute.SetAction(AttributeAction::PUT);
AttributeValue valueAttribute;
valueAttribute.SetS(ss.str());
testValueAttribute.SetValue(valueAttribute);
updateItemRequest.AddAttributeUpdates(testValueColumnName, testValueAttribute);
ss.str("");
m_client->UpdateItemAsync(updateItemRequest, updateItemHandler);
}
//wait for the callbacks to finish.
std::unique_lock<std::mutex> updateItemResultLock(updateItemResultMutex);
updateItemResultSemaphore.wait(updateItemResultLock);
//now get the items again, making sure they were properly
//updated.
getItemResultsFromCallbackTest.clear();
getItemResults.clear();
for (unsigned i = 0; i < 50; ++i)
{
GetItemRequest getItemRequest;
ss << HASH_KEY_NAME << i;
AttributeValue hashKey;
hashKey.SetS(ss.str());
getItemRequest.AddKey(HASH_KEY_NAME, hashKey);
getItemRequest.SetTableName(crudCallbacksTestTableName);
Aws::Vector<Aws::String> attributesToGet;
attributesToGet.push_back(HASH_KEY_NAME);
attributesToGet.push_back(testValueColumnName);
ss.str("");
m_client->GetItemAsync(getItemRequest, getItemHandler);
}
//wait for the callbacks to finish.
getItemResultSemaphore.wait(getItemResultLock);
//verify values.
for (unsigned i = 0; i < 50; ++i)
{
GetItemOutcome outcome = getItemResultsFromCallbackTest[i];
EXPECT_TRUE(outcome.IsSuccess());
GetItemResult result = outcome.GetResult();
Aws::Map<Aws::String, AttributeValue> returnedItemCollection = result.GetItem();
getItemResults[returnedItemCollection[HASH_KEY_NAME].GetS()] = returnedItemCollection[testValueColumnName].GetS();
}
for (unsigned i = 0; i < 50; ++i)
{
ss << HASH_KEY_NAME << i;
Aws::String hashKey = ss.str();
ss.str("");
ss << testValueColumnName << i * 2;
EXPECT_EQ(ss.str(), getItemResults[hashKey]);
ss.str("");
}
//now delete all the items we added.
for (unsigned i = 0; i < 50; ++i)
{
DeleteItemRequest deleteItemRequest;
ss << HASH_KEY_NAME << i;
AttributeValue hashKey;
hashKey.SetS(ss.str());
deleteItemRequest.AddKey(HASH_KEY_NAME, hashKey);
deleteItemRequest.SetTableName(crudCallbacksTestTableName);
deleteItemRequest.SetReturnValues(ReturnValue::ALL_OLD);
ss.str("");
m_client->DeleteItemAsync(deleteItemRequest, deleteItemHandler);
}
//wait for the callbacks to finish.
std::unique_lock<std::mutex> deleteItemResultLock(deleteItemResultMutex);
deleteItemResultSemaphore.wait(deleteItemResultLock);
//verify that we properly returned the old values.
Aws::Set<Aws::String> deletedKeys;
for (DeleteItemOutcome& deleteItemOutcome : deleteItemResultsFromCallbackTest)
{
EXPECT_TRUE(deleteItemOutcome.IsSuccess());
DeleteItemResult deleteItemResult = deleteItemOutcome.GetResult();
Aws::Map<Aws::String, AttributeValue> attributes = deleteItemResult.GetAttributes();
deletedKeys.insert(attributes[HASH_KEY_NAME].GetS());
}
for (unsigned i = 0; i < 50; ++i)
{
ss << HASH_KEY_NAME << i;
EXPECT_TRUE(deletedKeys.find(ss.str()) != deletedKeys.end());
ss.str("");
}
}
void PutBlobs(DynamoDBClient* client, uint32_t blobRowStartIndex)
{
Aws::String testValueColumnName = "TestBlob";
Aws::Vector<PutItemOutcomeCallable> putItemResults;
Aws::StringStream ss;
Aws::String limiterTestTableName = BuildTableName(BASE_LIMITER_TEST_TABLE);
for (unsigned i = blobRowStartIndex; i < blobRowStartIndex + 20; ++i)
{
PutItemRequest putItemRequest;
putItemRequest.SetTableName(limiterTestTableName);
ss.str("");
ss << HASH_KEY_NAME << i;
AttributeValue hashKeyAttribute;
hashKeyAttribute.SetS(ss.str());
putItemRequest.AddItem(HASH_KEY_NAME, hashKeyAttribute);
Aws::String blob(1000, 'a');
ss.str("");
ss << i << blob;
AttributeValue testValueAttribute;
testValueAttribute.SetS(ss.str());
putItemRequest.AddItem(testValueColumnName, testValueAttribute);
putItemResults.push_back(client->PutItemCallable(putItemRequest));
}
for (auto& putItemResult : putItemResults)
{
PutItemOutcome outcome = putItemResult.get();
ASSERT_TRUE(outcome.IsSuccess());
}
}
TEST_F(TableOperationTest, TestLimiter)
{
AWS_LOGSTREAM_TRACE(ALLOCATION_TAG, "TestLimiter")
using CLOCK = std::chrono::high_resolution_clock;
Aws::String limiterTestTableName = BuildTableName(BASE_LIMITER_TEST_TABLE);
CreateTable(limiterTestTableName, 100, 100);
// set limiter to 1k/sec
// each request is a Put of 1k of data + >600 from headers/misc and response data
// so we expect 20 requests to take at least 30 seconds
m_limiter->SetRate(1000, true);
auto startTime = CLOCK::now();
PutBlobs(m_client.get(), 0);
auto endTime = CLOCK::now();
auto timeDifference = endTime - startTime;
auto secondsElapsed = std::chrono::duration_cast<std::chrono::seconds>(timeDifference);
ASSERT_TRUE(secondsElapsed.count() >= 29);
// // try it with a much higher limit, should be fast
// m_limiter->SetRate(100000, true);
//
// auto startTime2 = CLOCK::now();
//
// PutBlobs(m_client.get(), 20);
//
// auto endTime2 = CLOCK::now();
//
// auto timeDifference2 = endTime2 - startTime2;
//
// auto secondsElapsed2 = std::chrono::duration_cast<std::chrono::seconds>(timeDifference2);
}
TEST_F(TableOperationTest, TestAttributeValues)
{
AWS_LOGSTREAM_TRACE(ALLOCATION_TAG, "TestAttributeValues")
Aws::String attributeValueTestTableName = BuildTableName(BASE_ATTRIBUTEVALUE_TEST_TABLE);
CreateTable(attributeValueTestTableName, 50, 50);
unsigned char buffer1[6] = { 20, 34, 54, 67, 10, 5 };
const Aws::Utils::ByteBuffer byteBuffer1(buffer1, 6);
unsigned char buffer2[6] = { 21, 35, 55, 68, 11, 6 };
const Aws::Utils::ByteBuffer byteBuffer2(buffer2, 6);
// create the Hash Key value
AttributeValue hashKey("TestValue");
// String Value
{
// Put
PutItemRequest putItemRequest;
putItemRequest.SetTableName(attributeValueTestTableName);
putItemRequest.AddItem(HASH_KEY_NAME, hashKey);
AttributeValue value;
value.SetS("String Value");
putItemRequest.AddItem("String", value);
PutItemOutcome putOutcome = m_client->PutItem(putItemRequest);
ASSERT_TRUE(putOutcome.IsSuccess());
// Get
GetItemRequest getItemRequest;
getItemRequest.AddKey(HASH_KEY_NAME, hashKey);
getItemRequest.SetTableName(attributeValueTestTableName);
Aws::Vector<Aws::String> attributesToGet;
attributesToGet.push_back(HASH_KEY_NAME);
attributesToGet.push_back("String Value");
GetItemOutcome getOutcome = m_client->GetItem(getItemRequest);
ASSERT_TRUE(getOutcome.IsSuccess());
// Parse
GetItemResult result = getOutcome.GetResult();
Aws::Map<Aws::String, AttributeValue> returnedItemCollection = result.GetItem();
//getItemResults[returnedItemCollection[HASH_KEY_NAME].GetS()] = returnedItemCollection[testValueColumnName].GetS();
//ReturnedItemCollection returnedItemCollection = result.GetItems();
EXPECT_EQ("TestValue", returnedItemCollection[HASH_KEY_NAME].GetS());
EXPECT_EQ("String Value", returnedItemCollection["String"].GetS());
}
// Number Value
{
// Update
UpdateItemRequest updateItemRequest;
updateItemRequest.SetTableName(attributeValueTestTableName);
updateItemRequest.AddKey(HASH_KEY_NAME, hashKey);
AttributeValue valueAttribute;
valueAttribute.SetN("1001");
AttributeValueUpdate testValueAttribute;
testValueAttribute.SetValue(valueAttribute);
updateItemRequest.AddAttributeUpdates("Number", testValueAttribute);
UpdateItemOutcome updateOutcome = m_client->UpdateItem(updateItemRequest);
ASSERT_TRUE(updateOutcome.IsSuccess());
// Get
GetItemRequest getItemRequest;
getItemRequest.AddKey(HASH_KEY_NAME, hashKey);
getItemRequest.SetTableName(attributeValueTestTableName);
Aws::Vector<Aws::String> attributesToGet;
attributesToGet.push_back(HASH_KEY_NAME);
GetItemOutcome getOutcome = m_client->GetItem(getItemRequest);
ASSERT_TRUE(getOutcome.IsSuccess());
// Parse
GetItemResult result = getOutcome.GetResult();
auto returnedItemCollection = result.GetItem();
EXPECT_EQ("TestValue", returnedItemCollection[HASH_KEY_NAME].GetS());
EXPECT_EQ("String Value", returnedItemCollection["String"].GetS());
EXPECT_EQ("1001", returnedItemCollection["Number"].GetN());
}
// Number Value (numeric type)
{
// Update
UpdateItemRequest updateItemRequest;
updateItemRequest.SetTableName(attributeValueTestTableName);
updateItemRequest.AddKey(HASH_KEY_NAME, hashKey);
AttributeValue valueAttribute;
valueAttribute.SetN(1001);
AttributeValueUpdate testValueAttribute;
testValueAttribute.SetValue(valueAttribute);
updateItemRequest.AddAttributeUpdates("Number", testValueAttribute);
UpdateItemOutcome updateOutcome = m_client->UpdateItem(updateItemRequest);
ASSERT_TRUE(updateOutcome.IsSuccess());
// Get
GetItemRequest getItemRequest;
getItemRequest.AddKey(HASH_KEY_NAME, hashKey);
getItemRequest.SetTableName(attributeValueTestTableName);
Aws::Vector<Aws::String> attributesToGet;
attributesToGet.push_back(HASH_KEY_NAME);
GetItemOutcome getOutcome = m_client->GetItem(getItemRequest);
ASSERT_TRUE(getOutcome.IsSuccess());
// Parse
GetItemResult result = getOutcome.GetResult();
auto returnedItemCollection = result.GetItem();
EXPECT_EQ("TestValue", returnedItemCollection[HASH_KEY_NAME].GetS());
EXPECT_EQ("String Value", returnedItemCollection["String"].GetS());
EXPECT_EQ("1001", returnedItemCollection["Number"].GetN());
}
// ByteBuffer
{
// Update
UpdateItemRequest updateItemRequest;
updateItemRequest.SetTableName(attributeValueTestTableName);
updateItemRequest.AddKey(HASH_KEY_NAME, hashKey);
AttributeValue valueAttribute;
valueAttribute.SetB(byteBuffer1);
AttributeValueUpdate testValueAttribute;
testValueAttribute.SetValue(valueAttribute);
updateItemRequest.AddAttributeUpdates("ByteBuffer", testValueAttribute);
UpdateItemOutcome updateOutcome = m_client->UpdateItem(updateItemRequest);
ASSERT_TRUE(updateOutcome.IsSuccess());
// Get
GetItemRequest getItemRequest;
getItemRequest.AddKey(HASH_KEY_NAME, hashKey);
getItemRequest.SetTableName(attributeValueTestTableName);
Aws::Vector<Aws::String> attributesToGet;
attributesToGet.push_back(HASH_KEY_NAME);
GetItemOutcome getOutcome = m_client->GetItem(getItemRequest);
ASSERT_TRUE(getOutcome.IsSuccess());
// Parse
GetItemResult result = getOutcome.GetResult();
auto returnedItemCollection = result.GetItem();
EXPECT_EQ("TestValue", returnedItemCollection[HASH_KEY_NAME].GetS());
EXPECT_EQ("String Value", returnedItemCollection["String"].GetS());
EXPECT_EQ("1001", returnedItemCollection["Number"].GetN());
EXPECT_EQ(byteBuffer1, returnedItemCollection["ByteBuffer"].GetB()); // on the 3rd day of xmas...
}
// StringSet
{
// Update
UpdateItemRequest updateItemRequest;
updateItemRequest.SetTableName(attributeValueTestTableName);
updateItemRequest.AddKey(HASH_KEY_NAME, hashKey);
const Aws::Vector<Aws::String> testStrings = { "test1", "test2" };
AttributeValue valueAttribute;
valueAttribute.SetSS(testStrings);
AttributeValueUpdate testValueAttribute;
testValueAttribute.SetValue(valueAttribute);
updateItemRequest.AddAttributeUpdates("String Set", testValueAttribute);
UpdateItemOutcome updateOutcome = m_client->UpdateItem(updateItemRequest);
ASSERT_TRUE(updateOutcome.IsSuccess());
// Get
GetItemRequest getItemRequest;
getItemRequest.AddKey(HASH_KEY_NAME, hashKey);
getItemRequest.SetTableName(attributeValueTestTableName);
Aws::Vector<Aws::String> attributesToGet;
attributesToGet.push_back(HASH_KEY_NAME);
GetItemOutcome getOutcome = m_client->GetItem(getItemRequest);
ASSERT_TRUE(getOutcome.IsSuccess());
// Parse
GetItemResult result = getOutcome.GetResult();
auto returnedItemCollection = result.GetItem();
EXPECT_EQ("TestValue", returnedItemCollection[HASH_KEY_NAME].GetS());
EXPECT_EQ("String Value", returnedItemCollection["String"].GetS());
EXPECT_EQ("1001", returnedItemCollection["Number"].GetN());
EXPECT_EQ(byteBuffer1, returnedItemCollection["ByteBuffer"].GetB());
auto ss = returnedItemCollection["String Set"].GetSS();
EXPECT_EQ(2u, ss.size());
EXPECT_NE(ss.end(), std::find(ss.begin(), ss.end(), "test1"));
EXPECT_NE(ss.end(), std::find(ss.begin(), ss.end(), "test2"));
}
// Number Set
{
// Update
UpdateItemRequest updateItemRequest;
updateItemRequest.SetTableName(attributeValueTestTableName);
updateItemRequest.AddKey(HASH_KEY_NAME, hashKey);
const Aws::Vector<Aws::String> testStrings = { "10", "20" };
AttributeValue valueAttribute;
valueAttribute.SetNS(testStrings);
AttributeValueUpdate testValueAttribute;
testValueAttribute.SetValue(valueAttribute);
updateItemRequest.AddAttributeUpdates("Number Set", testValueAttribute);
UpdateItemOutcome updateOutcome = m_client->UpdateItem(updateItemRequest);
ASSERT_TRUE(updateOutcome.IsSuccess());
// Get
GetItemRequest getItemRequest;
getItemRequest.AddKey(HASH_KEY_NAME, hashKey);
getItemRequest.SetTableName(attributeValueTestTableName);
Aws::Vector<Aws::String> attributesToGet;
attributesToGet.push_back(HASH_KEY_NAME);
GetItemOutcome getOutcome = m_client->GetItem(getItemRequest);
ASSERT_TRUE(getOutcome.IsSuccess());
// Parse
GetItemResult result = getOutcome.GetResult();
auto returnedItemCollection = result.GetItem();
EXPECT_EQ("TestValue", returnedItemCollection[HASH_KEY_NAME].GetS());
EXPECT_EQ("String Value", returnedItemCollection["String"].GetS());
EXPECT_EQ("1001", returnedItemCollection["Number"].GetN());
EXPECT_EQ(byteBuffer1, returnedItemCollection["ByteBuffer"].GetB());
auto ss = returnedItemCollection["String Set"].GetSS();
EXPECT_EQ(2u, ss.size());
EXPECT_NE(ss.end(), std::find(ss.begin(), ss.end(), "test1"));
EXPECT_NE(ss.end(), std::find(ss.begin(), ss.end(), "test2"));
auto ns = returnedItemCollection["Number Set"].GetNS();
EXPECT_EQ(2u, ns.size());
EXPECT_NE(ns.end(), std::find(ns.begin(), ns.end(), "10"));
EXPECT_NE(ns.end(), std::find(ns.begin(), ns.end(), "20"));
}
// ByteBuffer Set
{
// Update
UpdateItemRequest updateItemRequest;
updateItemRequest.SetTableName(attributeValueTestTableName);
updateItemRequest.AddKey(HASH_KEY_NAME, hashKey);
Aws::Vector<Aws::Utils::ByteBuffer> testBuffers = { byteBuffer1, byteBuffer2 };
AttributeValue valueAttribute;
valueAttribute.SetBS(testBuffers);
AttributeValueUpdate testValueAttribute;
testValueAttribute.SetValue(valueAttribute);
updateItemRequest.AddAttributeUpdates("ByteBuffer Set", testValueAttribute);
UpdateItemOutcome updateOutcome = m_client->UpdateItem(updateItemRequest);
ASSERT_TRUE(updateOutcome.IsSuccess());
// Get
GetItemRequest getItemRequest;
getItemRequest.AddKey(HASH_KEY_NAME, hashKey);
getItemRequest.SetTableName(attributeValueTestTableName);
Aws::Vector<Aws::String> attributesToGet;
attributesToGet.push_back(HASH_KEY_NAME);
GetItemOutcome getOutcome = m_client->GetItem(getItemRequest);
ASSERT_TRUE(getOutcome.IsSuccess());
// Parse
GetItemResult result = getOutcome.GetResult();
auto returnedItemCollection = result.GetItem();
EXPECT_EQ("TestValue", returnedItemCollection[HASH_KEY_NAME].GetS());
EXPECT_EQ("String Value", returnedItemCollection["String"].GetS());
EXPECT_EQ("1001", returnedItemCollection["Number"].GetN());
EXPECT_EQ(byteBuffer1, returnedItemCollection["ByteBuffer"].GetB());
auto ss = returnedItemCollection["String Set"].GetSS();
EXPECT_EQ(2u, ss.size());
EXPECT_NE(ss.end(), std::find(ss.begin(), ss.end(), "test1"));
EXPECT_NE(ss.end(), std::find(ss.begin(), ss.end(), "test2"));
auto ns = returnedItemCollection["Number Set"].GetNS();
EXPECT_EQ(2u, ns.size());
EXPECT_NE(ns.end(), std::find(ns.begin(), ns.end(), "10"));
EXPECT_NE(ns.end(), std::find(ns.begin(), ns.end(), "20"));
auto bs = returnedItemCollection["ByteBuffer Set"].GetBS();
EXPECT_EQ(2u, bs.size());
EXPECT_NE(bs.end(), std::find(bs.begin(), bs.end(), byteBuffer1));
EXPECT_NE(bs.end(), std::find(bs.begin(), bs.end(), byteBuffer2));
}
// Attribute Map
{
// Update
UpdateItemRequest updateItemRequest;
updateItemRequest.SetTableName(attributeValueTestTableName);
updateItemRequest.AddKey(HASH_KEY_NAME, hashKey);
AttributeValue valueAttribute;
auto barPtr = Aws::MakeShared<AttributeValue>("TableOperationTest", "bar");
valueAttribute.AddMEntry("foo", barPtr);
auto erniePtr = Aws::MakeShared<AttributeValue>("TableOperationTest", "ernie");
valueAttribute.AddMEntry("bert", erniePtr);
AttributeValueUpdate testValueAttribute;
testValueAttribute.SetValue(valueAttribute);
updateItemRequest.AddAttributeUpdates("Map", testValueAttribute);
UpdateItemOutcome updateOutcome = m_client->UpdateItem(updateItemRequest);
ASSERT_TRUE(updateOutcome.IsSuccess());
// Get
GetItemRequest getItemRequest;
getItemRequest.AddKey(HASH_KEY_NAME, hashKey);
getItemRequest.SetTableName(attributeValueTestTableName);
Aws::Vector<Aws::String> attributesToGet;
attributesToGet.push_back(HASH_KEY_NAME);
GetItemOutcome getOutcome = m_client->GetItem(getItemRequest);
ASSERT_TRUE(getOutcome.IsSuccess());
// Parse
GetItemResult result = getOutcome.GetResult();
auto returnedItemCollection = result.GetItem();
EXPECT_EQ("TestValue", returnedItemCollection[HASH_KEY_NAME].GetS());
EXPECT_EQ("String Value", returnedItemCollection["String"].GetS());
EXPECT_EQ("1001", returnedItemCollection["Number"].GetN());
EXPECT_EQ(byteBuffer1, returnedItemCollection["ByteBuffer"].GetB());
auto ss = returnedItemCollection["String Set"].GetSS();
EXPECT_EQ(2u, ss.size());
EXPECT_NE(ss.end(), std::find(ss.begin(), ss.end(), "test1"));
EXPECT_NE(ss.end(), std::find(ss.begin(), ss.end(), "test2"));
auto ns = returnedItemCollection["Number Set"].GetNS();
EXPECT_EQ(2u, ns.size());
EXPECT_NE(ns.end(), std::find(ns.begin(), ns.end(), "10"));
EXPECT_NE(ns.end(), std::find(ns.begin(), ns.end(), "20"));
auto bs = returnedItemCollection["ByteBuffer Set"].GetBS();
EXPECT_EQ(2u, bs.size());
EXPECT_NE(bs.end(), std::find(bs.begin(), bs.end(), byteBuffer1));
EXPECT_NE(bs.end(), std::find(bs.begin(), bs.end(), byteBuffer2));
const auto& m = returnedItemCollection["Map"].GetM();
EXPECT_EQ(2u, m.size());
ASSERT_NE(m.end(), m.find("foo"));
ASSERT_EQ("bar", m.find("foo")->second->GetS());
ASSERT_NE(m.end(), m.find("bert"));
ASSERT_EQ("ernie", m.find("bert")->second->GetS());
}
// Empty Map
{
// Update
UpdateItemRequest updateItemRequest;
updateItemRequest.SetTableName(attributeValueTestTableName);
updateItemRequest.AddKey(HASH_KEY_NAME, hashKey);
Aws::String updateExpression = "SET EmptyMap = :map";
updateItemRequest.SetUpdateExpression(updateExpression);
Aws::Map<Aws::String, Aws::DynamoDB::Model::AttributeValue> expressionAttributeValues;
AttributeValue mapValueAttribute;
Aws::Map<Aws::String, const std::shared_ptr<Aws::DynamoDB::Model::AttributeValue>> emptyMap;
mapValueAttribute.SetM(emptyMap);
expressionAttributeValues[":map"] = mapValueAttribute;
updateItemRequest.SetExpressionAttributeValues(expressionAttributeValues);
UpdateItemOutcome updateOutcome = m_client->UpdateItem(updateItemRequest);
ASSERT_TRUE(updateOutcome.IsSuccess());
// Get
GetItemRequest getItemRequest;
getItemRequest.AddKey(HASH_KEY_NAME, hashKey);
getItemRequest.SetTableName(attributeValueTestTableName);
GetItemOutcome getOutcome = m_client->GetItem(getItemRequest);
ASSERT_TRUE(getOutcome.IsSuccess());
// Parse
GetItemResult result = getOutcome.GetResult();
auto returnedItemCollection = result.GetItem();
ASSERT_TRUE(returnedItemCollection.find("EmptyMap") != returnedItemCollection.end());
auto map = returnedItemCollection["EmptyMap"].GetM();
ASSERT_EQ(0u, map.size());
}
// Attribute List
{
// Update
UpdateItemRequest updateItemRequest;
updateItemRequest.SetTableName(attributeValueTestTableName);
updateItemRequest.AddKey(HASH_KEY_NAME, hashKey);
AttributeValue valueAttribute;
valueAttribute.AddLItem(Aws::MakeShared<AttributeValue>("TableOperationTest", "foo"))
.AddLItem(Aws::MakeShared<AttributeValue>("TableOperationTest", "bar"));
AttributeValueUpdate testValueAttribute;
testValueAttribute.SetValue(valueAttribute);
updateItemRequest.AddAttributeUpdates("List", testValueAttribute);
UpdateItemOutcome updateOutcome = m_client->UpdateItem(updateItemRequest);
ASSERT_TRUE(updateOutcome.IsSuccess());
// Get
GetItemRequest getItemRequest;
getItemRequest.AddKey(HASH_KEY_NAME, hashKey);
getItemRequest.SetTableName(attributeValueTestTableName);
Aws::Vector<Aws::String> attributesToGet;
attributesToGet.push_back(HASH_KEY_NAME);
GetItemOutcome getOutcome = m_client->GetItem(getItemRequest);
ASSERT_TRUE(getOutcome.IsSuccess());
// Parse
GetItemResult result = getOutcome.GetResult();
auto returnedItemCollection = result.GetItem();
EXPECT_EQ("TestValue", returnedItemCollection[HASH_KEY_NAME].GetS());
EXPECT_EQ("String Value", returnedItemCollection["String"].GetS());
EXPECT_EQ("1001", returnedItemCollection["Number"].GetN());
EXPECT_EQ(byteBuffer1, returnedItemCollection["ByteBuffer"].GetB());
auto ss = returnedItemCollection["String Set"].GetSS();
EXPECT_EQ(2u, ss.size());
EXPECT_NE(ss.end(), std::find(ss.begin(), ss.end(), "test1"));
EXPECT_NE(ss.end(), std::find(ss.begin(), ss.end(), "test2"));
auto ns = returnedItemCollection["Number Set"].GetNS();
EXPECT_EQ(2u, ns.size());
EXPECT_NE(ns.end(), std::find(ns.begin(), ns.end(), "10"));
EXPECT_NE(ns.end(), std::find(ns.begin(), ns.end(), "20"));
auto bs = returnedItemCollection["ByteBuffer Set"].GetBS();
EXPECT_EQ(2u, bs.size());
EXPECT_NE(bs.end(), std::find(bs.begin(), bs.end(), byteBuffer1));
EXPECT_NE(bs.end(), std::find(bs.begin(), bs.end(), byteBuffer2));
const auto& m = returnedItemCollection["Map"].GetM();
EXPECT_EQ(2u, m.size());
ASSERT_NE(m.end(), m.find("foo"));
ASSERT_EQ("bar", m.find("foo")->second->GetS());
ASSERT_NE(m.end(), m.find("bert"));
ASSERT_EQ("ernie", m.find("bert")->second->GetS());
auto list = returnedItemCollection["List"].GetL();
ASSERT_EQ(2u, list.size());
ASSERT_EQ("foo", list[0]->GetS());
ASSERT_EQ("bar", list[1]->GetS());
}
// Empty List
{
// Update
UpdateItemRequest updateItemRequest;
updateItemRequest.SetTableName(attributeValueTestTableName);
updateItemRequest.AddKey(HASH_KEY_NAME, hashKey);
Aws::String updateExpression = "SET EmptyList = :list";
updateItemRequest.SetUpdateExpression(updateExpression);
Aws::Map<Aws::String, Aws::DynamoDB::Model::AttributeValue> expressionAttributeValues;
AttributeValue listValueAttribute;
Aws::Vector<std::shared_ptr<Aws::DynamoDB::Model::AttributeValue>> emptyList;
listValueAttribute.SetL(emptyList);
expressionAttributeValues[":list"] = listValueAttribute;
updateItemRequest.SetExpressionAttributeValues(expressionAttributeValues);
UpdateItemOutcome updateOutcome = m_client->UpdateItem(updateItemRequest);
ASSERT_TRUE(updateOutcome.IsSuccess());
// Get
GetItemRequest getItemRequest;
getItemRequest.AddKey(HASH_KEY_NAME, hashKey);
getItemRequest.SetTableName(attributeValueTestTableName);
GetItemOutcome getOutcome = m_client->GetItem(getItemRequest);
ASSERT_TRUE(getOutcome.IsSuccess());
// Parse
GetItemResult result = getOutcome.GetResult();
auto returnedItemCollection = result.GetItem();
ASSERT_TRUE(returnedItemCollection.find("EmptyList") != returnedItemCollection.end());
auto list = returnedItemCollection["EmptyList"].GetL();
ASSERT_EQ(0u, list.size());
}
// Bool
{
// Update
UpdateItemRequest updateItemRequest;
updateItemRequest.SetTableName(attributeValueTestTableName);
updateItemRequest.AddKey(HASH_KEY_NAME, hashKey);
AttributeValue valueAttribute;
valueAttribute.SetBool(true);
AttributeValueUpdate testValueAttribute;
testValueAttribute.SetValue(valueAttribute);
updateItemRequest.AddAttributeUpdates("Bool", testValueAttribute);
UpdateItemOutcome updateOutcome = m_client->UpdateItem(updateItemRequest);
ASSERT_TRUE(updateOutcome.IsSuccess());
// Get
GetItemRequest getItemRequest;
getItemRequest.AddKey(HASH_KEY_NAME, hashKey);
getItemRequest.SetTableName(attributeValueTestTableName);
Aws::Vector<Aws::String> attributesToGet;
attributesToGet.push_back(HASH_KEY_NAME);
GetItemOutcome getOutcome = m_client->GetItem(getItemRequest);
ASSERT_TRUE(getOutcome.IsSuccess());
// Parse
GetItemResult result = getOutcome.GetResult();
auto returnedItemCollection = result.GetItem();
EXPECT_TRUE(returnedItemCollection["Bool"].GetBool());
}
// Null
{
// Update
UpdateItemRequest updateItemRequest;
updateItemRequest.SetTableName(attributeValueTestTableName);
updateItemRequest.AddKey(HASH_KEY_NAME, hashKey);
AttributeValue valueAttribute;
valueAttribute.SetNull(true);
AttributeValueUpdate testValueAttribute;
testValueAttribute.SetValue(valueAttribute);
updateItemRequest.AddAttributeUpdates("Null", testValueAttribute);
UpdateItemOutcome updateOutcome = m_client->UpdateItem(updateItemRequest);
ASSERT_TRUE(updateOutcome.IsSuccess());
// Get
GetItemRequest getItemRequest;
getItemRequest.AddKey(HASH_KEY_NAME, hashKey);
getItemRequest.SetTableName(attributeValueTestTableName);
Aws::Vector<Aws::String> attributesToGet;
attributesToGet.push_back(HASH_KEY_NAME);
GetItemOutcome getOutcome = m_client->GetItem(getItemRequest);
ASSERT_TRUE(getOutcome.IsSuccess());
// Parse
GetItemResult result = getOutcome.GetResult();
auto returnedItemCollection = result.GetItem();
EXPECT_TRUE(returnedItemCollection["Null"].GetNull());
}
}
} // anonymous namespace