summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYaroslav Mamykin (GitHub) <33784535+YarikMamykin@users.noreply.github.com>2019-09-20 23:21:40 +0300
committerJacob Keeler <jacob.keeler@livioradio.com>2019-09-20 16:21:40 -0400
commit5c7eef2b59c419be127da1bd0cc267884ee94182 (patch)
tree4fdc68001b57e6819414525f9fa76b04c6343ea4
parente833e65ec42ee9a99eb4488e5bff4f23d9789768 (diff)
downloadsdl_core-5c7eef2b59c419be127da1bd0cc267884ee94182.tar.gz
Fix merge module data incorrect behavior (#3017)
* Fix MergeModuleData invalid behavior * Rework MergeModuleData and MergeArray logic * Add unit tests
-rw-r--r--src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_helpers.h23
-rw-r--r--src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/interior_data_cache_impl.cc92
-rw-r--r--src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_helpers.cc82
-rw-r--r--src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/CMakeLists.txt4
-rw-r--r--src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/interior_data_cache_test.cc46
-rw-r--r--src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/rc_helpers_test.cc285
-rw-r--r--src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/resource_allocation_manager/CMakeLists.txt81
-rw-r--r--src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/resource_allocation_manager/resource_allocation_manager_impl_test.cc (renamed from src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/resource_allocation_manager_impl_test.cc)0
8 files changed, 521 insertions, 92 deletions
diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_helpers.h b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_helpers.h
index 7b249cb4b8..eed860fc7f 100644
--- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_helpers.h
+++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_helpers.h
@@ -146,6 +146,29 @@ class RCHelpers {
*/
static void RemoveRedundantGPSDataFromIVDataMsg(
smart_objects::SmartObject& msg_params);
+
+ /**
+ * @brief MergeModuleData all keys and values from first parameter and
+ * update and append keys and values from the second
+ * @param data1 - initial data
+ * @param data2 - updated data
+ * @return updated data1 with data2 keys and values
+ */
+ static smart_objects::SmartObject MergeModuleData(
+ const smart_objects::SmartObject& data1,
+ const smart_objects::SmartObject& data2);
+
+ /**
+ * @brief MergeArray merge two arrays if their elements contain an `id`
+ * parameter
+ * @param data1 - initial data
+ * @param data2 - updated data
+ * @return updated data1 with any values in data2 if the arrays can be merged,
+ * otherwise data2
+ */
+ static smart_objects::SmartObject MergeArray(
+ const smart_objects::SmartObject& data1,
+ const smart_objects::SmartObject& data2);
};
} // namespace rc_rpc_plugin
diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/interior_data_cache_impl.cc b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/interior_data_cache_impl.cc
index bcbc3ab11b..3e50818210 100644
--- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/interior_data_cache_impl.cc
+++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/interior_data_cache_impl.cc
@@ -35,6 +35,7 @@
#include <iostream>
#include <thread>
#include "application_manager/smart_object_keys.h"
+#include "rc_rpc_plugin/rc_helpers.h"
#include "utils/date_time.h"
#include "utils/logger.h"
@@ -46,95 +47,6 @@ InteriorDataCacheImpl::InteriorDataCacheImpl() {}
InteriorDataCacheImpl::~InteriorDataCacheImpl() {}
-/**
- * @brief MergeModuleData all keys and values from first parameter and
- * update and append keys and values from the second
- * @param data1 - initial data
- * @param data2 - updated data
- * @return updated data1 with data2 keys and values
- */
-smart_objects::SmartObject MergeModuleData(
- const smart_objects::SmartObject& data1,
- const smart_objects::SmartObject& data2);
-
-/**
- * @brief MergeArray merge two arrays if their elements contain an `id`
- * parameter
- * @param data1 - initial data
- * @param data2 - updated data
- * @return updated data1 with any values in data2 if the arrays can be merged,
- * otherwise data2
- */
-smart_objects::SmartObject MergeArray(const smart_objects::SmartObject& data1,
- const smart_objects::SmartObject& data2);
-
-smart_objects::SmartObject MergeModuleData(
- const smart_objects::SmartObject& data1,
- const smart_objects::SmartObject& data2) {
- smart_objects::SmartObject result = data1;
- auto it = data2.map_begin();
- for (; it != data2.map_end(); ++it) {
- const std::string& key = it->first;
- smart_objects::SmartObject& value = it->second;
- if (!result.keyExists(key) || value.getType() != result[key].getType()) {
- result[key] = value;
- continue;
- }
-
- // Merge maps and arrays with `id` param included, replace other types
- if (value.getType() == smart_objects::SmartType::SmartType_Map) {
- value = MergeModuleData(result[key], value);
- } else if (value.getType() == smart_objects::SmartType::SmartType_Array) {
- value = MergeArray(result[key], value);
- }
- result[key] = value;
- }
- return result;
-}
-
-smart_objects::SmartObject MergeArray(const smart_objects::SmartObject& data1,
- const smart_objects::SmartObject& data2) {
- // Merge data only in the case where each value in the array is an Object with
- // an ID included, otherwise replace
- bool array_contains_objects =
- !data2.empty() &&
- data2.getElement(0).getType() != smart_objects::SmartType::SmartType_Map;
- bool can_merge_arrays =
- array_contains_objects &&
- data2.getElement(0).keyExists(application_manager::strings::id);
- if (!can_merge_arrays) {
- return data2;
- }
-
- smart_objects::SmartObject result = data1;
- smart_objects::SmartArray* result_array = result.asArray();
- smart_objects::SmartArray* data_array = data2.asArray();
- auto data_it = data_array->begin();
- auto find_by_id = [](smart_objects::SmartArray* array,
- const smart_objects::SmartObject& id)
- -> smart_objects::SmartArray::iterator {
- auto it = std::find_if(array->begin(),
- array->end(),
- [&id](smart_objects::SmartObject& obj) -> bool {
- return obj[application_manager::strings::id] == id;
- });
- return it;
- };
-
- for (; data_it != data_array->end(); ++data_it) {
- const smart_objects::SmartObject element_id =
- (*data_it)[application_manager::strings::id];
- auto result_it = find_by_id(result_array, element_id);
-
- if (result_it != result_array->end()) {
- *result_it = MergeModuleData(*result_it, *data_it);
- } else {
- result_array->push_back(*data_it);
- }
- }
- return result;
-}
-
void InteriorDataCacheImpl::Add(const ModuleUid& module,
const smart_objects::SmartObject& module_data) {
LOG4CXX_TRACE(
@@ -146,7 +58,7 @@ void InteriorDataCacheImpl::Add(const ModuleUid& module,
cached_data_[module] = module_data;
return;
}
- cached_data_[module] = MergeModuleData(it->second, module_data);
+ cached_data_[module] = RCHelpers::MergeModuleData(it->second, module_data);
}
smart_objects::SmartObject InteriorDataCacheImpl::Retrieve(
diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_helpers.cc b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_helpers.cc
index e9e6620e25..8cf20948cf 100644
--- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_helpers.cc
+++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_helpers.cc
@@ -276,4 +276,86 @@ void RCHelpers::RemoveRedundantGPSDataFromIVDataMsg(
location_data = new_location_data;
}
}
+
+smart_objects::SmartObject RCHelpers::MergeModuleData(
+ const smart_objects::SmartObject& data1,
+ const smart_objects::SmartObject& data2) {
+ if (data1.getType() != smart_objects::SmartType::SmartType_Map ||
+ data2.getType() != smart_objects::SmartType::SmartType_Map) {
+ return data2;
+ }
+
+ smart_objects::SmartObject result = data1;
+
+ for (auto it = data2.map_begin(); it != data2.map_end(); ++it) {
+ const std::string& key = it->first;
+ smart_objects::SmartObject& value = it->second;
+ if (!result.keyExists(key) || value.getType() != result[key].getType()) {
+ result[key] = value;
+ continue;
+ }
+
+ // Merge maps and arrays with `id` param included, replace other types
+ if (value.getType() == smart_objects::SmartType::SmartType_Map) {
+ value = MergeModuleData(result[key], value);
+ } else if (value.getType() == smart_objects::SmartType::SmartType_Array) {
+ value = MergeArray(result[key], value);
+ }
+ result[key] = value;
+ }
+ return result;
+}
+
+smart_objects::SmartObject RCHelpers::MergeArray(
+ const smart_objects::SmartObject& data1,
+ const smart_objects::SmartObject& data2) {
+ // Merge data only in the case where each value in the array is an Object with
+ // an ID included, otherwise replace
+
+ if (data1.getType() != smart_objects::SmartType::SmartType_Array ||
+ data2.getType() != smart_objects::SmartType::SmartType_Array ||
+ data2.empty()) {
+ return data2;
+ }
+
+ auto& data2_array = *data2.asArray();
+ for (const auto& data_item : data2_array) {
+ if (data_item.getType() != smart_objects::SmartType_Map ||
+ !data_item.keyExists(application_manager::strings::id)) {
+ return data2;
+ }
+ }
+
+ smart_objects::SmartObject result = data1;
+ smart_objects::SmartArray* result_array = result.asArray();
+
+ auto find_by_id = [](smart_objects::SmartArray* array,
+ const smart_objects::SmartObject& id)
+ -> smart_objects::SmartArray::iterator {
+ return std::find_if(array->begin(),
+ array->end(),
+ [&id](const smart_objects::SmartObject& obj) -> bool {
+ return id == obj[application_manager::strings::id];
+ });
+ };
+
+ auto merge = [&result_array,
+ &find_by_id](const smart_objects::SmartObject& data) -> void {
+ auto element_id = data[application_manager::strings::id];
+ auto result_it = find_by_id(result_array, element_id);
+
+ if (result_array->end() != result_it) {
+ *result_it = RCHelpers::MergeModuleData(*result_it, data);
+ } else {
+ result_array->push_back(data);
+ }
+ };
+
+ for (const auto& data : data2_array) {
+ merge(data);
+ }
+
+ return result;
+}
+
} // namespace rc_rpc_plugin
diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/CMakeLists.txt b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/CMakeLists.txt
index 00ddcd7379..bd46bdf11f 100644
--- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/CMakeLists.txt
+++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/CMakeLists.txt
@@ -41,11 +41,10 @@ include_directories (
)
set (RC_TEST_SOURCES
-${CMAKE_CURRENT_SOURCE_DIR}/resource_allocation_manager_impl_test.cc
${CMAKE_CURRENT_SOURCE_DIR}/interior_data_cache_test.cc
${CMAKE_CURRENT_SOURCE_DIR}/rc_consent_manager_impl_test.cc
${CMAKE_CURRENT_SOURCE_DIR}/grid_test.cc
-${CMAKE_CURRENT_SOURCE_DIR}/mock_rc_helpers.cc
+${CMAKE_CURRENT_SOURCE_DIR}/rc_helpers_test.cc
)
set(RC_COMMANDS_TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/commands)
@@ -71,3 +70,4 @@ endif()
create_test("rc_commands_test" "${SOURCES}" "${LIBRARIES}" )
create_test("rc_plugin_test" "${RC_TEST_SOURCES}" "${LIBRARIES}")
+add_subdirectory(resource_allocation_manager)
diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/interior_data_cache_test.cc b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/interior_data_cache_test.cc
index e8d9f6e45d..40a6bdf41d 100644
--- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/interior_data_cache_test.cc
+++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/interior_data_cache_test.cc
@@ -29,6 +29,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE. */
+#include "application_manager/smart_object_keys.h"
#include "gtest/gtest.h"
#include "rc_rpc_plugin/interior_data_cache_impl.h"
@@ -38,6 +39,8 @@ class InteriorDataCacheTest : public ::testing::Test {};
namespace {
const uint32_t time_frame_alowed_requests = 1;
+const std::string kValueKey = "value";
+const std::string kArray = "array";
} // namespace
TEST_F(InteriorDataCacheTest,
@@ -177,4 +180,47 @@ TEST_F(InteriorDataCacheTest, Exist2ModuleTypesRemoveOneAnotherOneLeft) {
EXPECT_EQ(data2, retrieved_data2);
}
+TEST_F(InteriorDataCacheTest, CheckCacheDataMerge) {
+ using namespace smart_objects;
+ const std::string module_type_key = "random_module_type";
+ const std::string module_id = "random_module_id";
+ rc_rpc_plugin::ModuleUid module(module_type_key, module_id);
+
+ auto gen_smart_object = [](const std::string& id,
+ const std::string& value) -> SmartObject {
+ SmartObject result(SmartType_Map);
+ result[application_manager::strings::id] = id;
+ result[kValueKey] = value;
+ return result;
+ };
+
+ SmartObject data1;
+ SmartObject data1_array(SmartType_Array);
+ (*data1_array.asArray()) = SmartArray{gen_smart_object("id1", "value1"),
+ gen_smart_object("id2", "value2")};
+ data1[kArray] = data1_array;
+
+ SmartObject data2(SmartType_Map);
+ SmartObject data2_array(SmartType_Array);
+ (*data2_array.asArray()) = SmartArray{gen_smart_object("id1", "value3"),
+ gen_smart_object("id3", "value4")};
+ data2[kArray] = data2_array;
+
+ SmartObject expected_data(SmartType_Map);
+ SmartObject expected_array(SmartType_Array);
+ (*expected_array.asArray()) = SmartArray{gen_smart_object("id1", "value3"),
+ gen_smart_object("id2", "value2"),
+ gen_smart_object("id3", "value4")};
+ expected_data[kArray] = expected_array;
+
+ rc_rpc_plugin::InteriorDataCacheImpl cache;
+ cache.Add(module, data1);
+ cache.Add(module, data2);
+
+ const auto retrieved_data = cache.Retrieve(module);
+
+ EXPECT_TRUE(cache.Contains(module));
+ EXPECT_EQ(expected_data, retrieved_data);
+}
+
} // namespace rc_rpc_plugin_test
diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/rc_helpers_test.cc b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/rc_helpers_test.cc
new file mode 100644
index 0000000000..21876c4c19
--- /dev/null
+++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/rc_helpers_test.cc
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2019, Ford Motor Company
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Ford Motor Company nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE. */
+
+#include "rc_rpc_plugin/rc_helpers.h"
+#include <map>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <vector>
+#include "gtest/gtest.h"
+#include "rc_rpc_plugin/rc_module_constants.h"
+
+namespace {
+const std::string kKeyId = "id";
+const std::string kKeyStatus = "status";
+const std::string kKeyDensity = "density";
+const std::string kKeyValue = "value";
+const std::string kArray = "array";
+} // namespace
+
+namespace rc_rpc_plugin_test {
+
+using namespace rc_rpc_plugin;
+using namespace smart_objects;
+
+class RCHelpersTest : public ::testing::Test {
+ public:
+ /**
+ * @brief Generates smart object with next structure:
+ * {
+ * "status": "status<n>",
+ * "value": "value<n>",
+ * "id": "id<n>"
+ * }
+ * where <n> is number specified with 'object_number' param.
+ *
+ * @param int object_number - number of object
+ * @param bool use_id_key - defines, whether "id" key must be added to smart
+ * object
+ *
+ * @return smart_objects::SmartObject - generated smart object
+ */
+ smart_objects::SmartObject gen_smart_object(int object_number,
+ bool use_id_key) {
+ smart_objects::SmartObject result(smart_objects::SmartType_Map);
+ result[kKeyStatus] = kKeyStatus + std::to_string(object_number);
+ result[kKeyValue] = kKeyValue + std::to_string(object_number);
+ if (use_id_key) {
+ result[kKeyId] = kKeyId + std::to_string(object_number);
+ }
+ return result;
+ }
+};
+
+TEST_F(RCHelpersTest,
+ MergeModuleData_OneOfParamsNotSmartMap_ExpectDataReplacedWithNewOne) {
+ SmartObject data1(SmartType_Map);
+ SmartObject data2(SmartType_Array);
+
+ const auto result = RCHelpers::MergeModuleData(data1, data2);
+ EXPECT_NE(result, data1);
+ EXPECT_EQ(result, data2);
+}
+
+TEST_F(RCHelpersTest,
+ MergeModuleData_FirstObjectDontContainKey_ExpectDataAppendedWithNewOne) {
+ SmartObject data1(SmartType_Map);
+ SmartObject data2(SmartType_Map);
+
+ std::map<std::string, std::string> expected_keys_values = {
+ {"key1", "value1"}, {"key2", "value2"}};
+ auto it = expected_keys_values.begin();
+
+ data1[it->first] = it->second;
+ ++it;
+ data2[it->first] = it->second;
+
+ const auto result = RCHelpers::MergeModuleData(data1, data2);
+ for (auto& item : expected_keys_values) {
+ EXPECT_TRUE(result.keyExists(item.first));
+ EXPECT_EQ(result[item.first], expected_keys_values[item.first]);
+ }
+}
+
+TEST_F(
+ RCHelpersTest,
+ MergeModuleData_SecondObjectContainsDifferentValueType_ExpectDataReplacedWithNewOne) {
+ SmartObject data1(SmartType_Map);
+ SmartObject data2(SmartType_Map);
+
+ data1["key1"] = "value1";
+ data2["key1"] = 30;
+
+ const auto result = RCHelpers::MergeModuleData(data1, data2);
+ EXPECT_EQ(data2["key1"], result["key1"]);
+}
+
+TEST_F(RCHelpersTest, MergeModuleData_Recursive) {
+ SmartObject data1(SmartType_Map);
+ SmartObject data2(SmartType_Map);
+
+ data1["key1"]["subkey1"] = "subvalue1";
+ data2["key1"]["subkey2"] = 30;
+
+ const auto result = RCHelpers::MergeModuleData(data1, data2);
+ EXPECT_EQ(result["key1"]["subkey1"], data1["key1"]["subkey1"]);
+ EXPECT_EQ(result["key1"]["subkey2"], data2["key1"]["subkey2"]);
+}
+
+TEST_F(
+ RCHelpersTest,
+ MergeModuleData_MergeObjectsThatContainArrays_ExpectDataReplacedWithNewOne) {
+ SmartObject data1(SmartType_Map);
+ SmartObject data1_array(SmartType_Array);
+ (*data1_array.asArray()) =
+ SmartArray{gen_smart_object(1, true), gen_smart_object(2, false)};
+ data1[kArray] = data1_array;
+
+ SmartObject data2(SmartType_Map);
+ SmartObject data2_array(SmartType_Array);
+ (*data2_array.asArray()) =
+ SmartArray{gen_smart_object(3, true), gen_smart_object(4, false)};
+ data2[kArray] = data2_array;
+
+ SmartObject expected_result(SmartType_Map);
+ SmartObject expected_result_array(SmartType_Array);
+ (*expected_result_array.asArray()) =
+ SmartArray{data2[kArray].getElement(0), data2[kArray].getElement(1)};
+
+ expected_result[kArray] = expected_result_array;
+
+ const auto result = RCHelpers::MergeModuleData(data1, data2);
+ EXPECT_EQ(expected_result, result);
+}
+
+TEST_F(RCHelpersTest,
+ MergeArray_OneOfParamsNotSmartArray_ExpectDataReplacedWithSecond) {
+ SmartObject data1(SmartType_Array);
+ SmartObject data2(SmartType_Map);
+
+ const auto result = RCHelpers::MergeArray(data1, data2);
+ EXPECT_NE(result, data1);
+ EXPECT_EQ(result, data2);
+}
+
+TEST_F(RCHelpersTest, MergeArray_FirstArrayEmpty_ExpectDataReplacedWithSecond) {
+ SmartObject data1(SmartType_Array);
+ SmartObject data2(SmartType_Array);
+ for (int object : {0, 1}) {
+ data2.asArray()->emplace(data2.asArray()->begin(), SmartObject(object));
+ }
+
+ ASSERT_EQ(0u, data1.length());
+ ASSERT_EQ(2u, data2.length());
+
+ const auto result = RCHelpers::MergeArray(data1, data2);
+ EXPECT_NE(result, data1);
+ EXPECT_EQ(result, data2);
+}
+
+TEST_F(RCHelpersTest,
+ MergeArray_SecondArrayEmpty_ExpectDataReplacedWithSecond) {
+ SmartObject data1(SmartType_Array);
+ for (int object : {0, 1}) {
+ data1.asArray()->emplace(data1.asArray()->begin(), SmartObject(object));
+ }
+ SmartObject data2(SmartType_Array);
+
+ ASSERT_EQ(2u, data1.length());
+ ASSERT_EQ(0u, data2.length());
+
+ const auto result = RCHelpers::MergeArray(data1, data2);
+ EXPECT_NE(result, data1);
+ EXPECT_EQ(result, data2);
+}
+
+TEST_F(RCHelpersTest, MergeArray_SimpleArrays_ExpectDataReplacedWithSecond) {
+ SmartObject data1(SmartType_Array);
+ for (int object : {0, 1, 2, 3, 4, 5}) {
+ data1.asArray()->emplace(data1.asArray()->begin(), SmartObject(object));
+ }
+
+ SmartObject data2(SmartType_Array);
+ for (int object : {0, 1}) {
+ data2.asArray()->emplace(data2.asArray()->begin(), SmartObject(object));
+ }
+
+ ASSERT_EQ(6u, data1.length());
+ ASSERT_EQ(2u, data2.length());
+
+ const auto result = RCHelpers::MergeArray(data1, data2);
+ EXPECT_NE(result, data1);
+ EXPECT_EQ(result, data2);
+}
+
+TEST_F(RCHelpersTest,
+ MergeArray_ObjectsHaveNotEqualIds_ExpectDataAppendedWithNewOne) {
+ SmartObject data1 = gen_smart_object(1, true);
+ SmartObject data2 = gen_smart_object(2, true);
+
+ SmartObject array1(SmartType_Array);
+ array1.asArray()->push_back(data1);
+ SmartObject array2(SmartType_Array);
+ array2.asArray()->push_back(data2);
+
+ SmartObject expected_array(SmartType_Array);
+ expected_array.asArray()->push_back(data1);
+ expected_array.asArray()->push_back(data2);
+ ASSERT_EQ(2u, expected_array.length());
+
+ const auto result = RCHelpers::MergeArray(array1, array2);
+ EXPECT_EQ(expected_array, result);
+}
+
+TEST_F(RCHelpersTest,
+ MergeArray_SomeObjectsDontHaveIdKey_ExpectDataReplacedWithSecond) {
+ int object_number = 1;
+
+ SmartObject array1(SmartType_Array);
+ array1.asArray()->push_back(gen_smart_object(object_number++, true));
+
+ SmartObject array2(SmartType_Array);
+ array2.asArray()->push_back(gen_smart_object(object_number++, false));
+ array2.asArray()->push_back(gen_smart_object(object_number++, true));
+
+ const auto result = RCHelpers::MergeArray(array1, array2);
+ EXPECT_EQ(array2, result);
+}
+
+TEST_F(
+ RCHelpersTest,
+ MergeArray_SomeObjectsHaveEqualIds_ExpectDataWithSameIdUpdateValueOnlyNewDataAdded) {
+ SmartObject temp = gen_smart_object(1, true);
+
+ SmartObject data1(SmartType_Array);
+ auto& data1_array = *data1.asArray();
+
+ data1_array.push_back(temp);
+ data1_array.push_back(gen_smart_object(2, true));
+
+ SmartObject data2(SmartType_Array);
+ auto& data2_array = *data2.asArray();
+
+ temp[kKeyValue] = "CUSTOM VALUE";
+ data2_array.push_back(temp);
+ data2_array.push_back(gen_smart_object(3, true));
+
+ SmartObject expected_result(SmartType_Array);
+ expected_result.asArray()->push_back(temp);
+ expected_result.asArray()->push_back(data1_array[1]);
+ expected_result.asArray()->push_back(data2_array[1]);
+
+ const auto result = RCHelpers::MergeArray(data1, data2);
+ EXPECT_EQ(expected_result, result);
+}
+
+} // namespace rc_rpc_plugin_test
diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/resource_allocation_manager/CMakeLists.txt b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/resource_allocation_manager/CMakeLists.txt
new file mode 100644
index 0000000000..c665e98448
--- /dev/null
+++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/resource_allocation_manager/CMakeLists.txt
@@ -0,0 +1,81 @@
+# Copyright (c) 2019, Ford Motor Company
+# All rights reserved.
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+
+# Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+
+# Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided with the
+# distribution.
+
+# Neither the name of the copyright holders nor the names of their contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+include(${CMAKE_SOURCE_DIR}/tools/cmake/helpers/sources.cmake)
+
+include_directories (
+ ${GMOCK_INCLUDE_DIRECTORY}
+ ${COMPONENTS_DIR}/application_manager/test/include
+ ${COMPONENTS_DIR}/application_manager/rpc_plugins/rc_rpc_plugin/include
+ ${COMPONENTS_DIR}/application_manager/rpc_plugins/rc_rpc_plugin/test/include/
+ ${COMPONENTS_DIR}/include/test/application_manager/
+ ${COMPONENTS_DIR}/rc_rpc_plugin/test/include
+)
+
+set (RESOURCE_ALLOC_MANAGER_TEST_SOURCES
+${COMPONENTS_DIR}/application_manager/rpc_plugins/rc_rpc_plugin/src/interior_data_manager_impl.cc
+${COMPONENTS_DIR}/application_manager/rpc_plugins/rc_rpc_plugin/src/interior_data_cache_impl.cc
+${COMPONENTS_DIR}/application_manager/rpc_plugins/rc_rpc_plugin/src/resource_allocation_manager_impl.cc
+${COMPONENTS_DIR}/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_rpc_plugin.cc
+${COMPONENTS_DIR}/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_app_extension.cc
+${COMPONENTS_DIR}/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_consent_manager_impl.cc
+${COMPONENTS_DIR}/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_capabilities_manager_impl.cc
+${COMPONENTS_DIR}/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_command_factory.cc
+${COMPONENTS_DIR}/application_manager/rpc_plugins/rc_rpc_plugin/test/mock_rc_helpers.cc
+${CMAKE_CURRENT_SOURCE_DIR}/resource_allocation_manager_impl_test.cc
+)
+
+set(RC_COMMANDS_TEST_SOURCE_DIR ${COMPONENTS_DIR}/application_manager/rpc_plugins/rc_rpc_plugin/test/commands)
+set(RC_COMMANDS_SOURCE_DIR ${COMPONENTS_DIR}/application_manager/rpc_plugins/rc_rpc_plugin/src/commands)
+collect_sources(COMMANDS_SOURCES "${RC_COMMANDS_TEST_DIR}" "${RC_COMMANDS_TEST_SOURCE_DIR}")
+
+set(LIBRARIES
+ ApplicationManager
+ connectionHandler
+ SmartObjects
+ ProtocolHandler
+ MessageHelper
+ connectionHandler
+ Utils
+ Resumption
+ jsoncpp
+ gmock_main
+ dl
+)
+
+if(ENABLE_LOG)
+ list(APPEND LIBRARIES log4cxx -L${LOG4CXX_LIBS_DIRECTORY})
+ list(APPEND LIBRARIES apr-1 -L${APR_LIBS_DIRECTORY})
+ list(APPEND LIBRARIES aprutil-1 -L${APR_UTIL_LIBS_DIRECTORY})
+ list(APPEND LIBRARIES expat -L${EXPAT_LIBS_DIRECTORY})
+endif()
+
+create_test("resource_allocation_manager_test" "${COMMANDS_SOURCES}" "${LIBRARIES}" "${RESOURCE_ALLOC_MANAGER_TEST_SOURCES}")
+
diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/resource_allocation_manager_impl_test.cc b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/resource_allocation_manager/resource_allocation_manager_impl_test.cc
index 70ed832cb1..70ed832cb1 100644
--- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/resource_allocation_manager_impl_test.cc
+++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/resource_allocation_manager/resource_allocation_manager_impl_test.cc