diff --git a/Development/nmos/configuration_api.cpp b/Development/nmos/configuration_api.cpp index 90f30635a..ea85ba7b8 100644 --- a/Development/nmos/configuration_api.cpp +++ b/Development/nmos/configuration_api.cpp @@ -737,12 +737,12 @@ namespace nmos }); // PUT /rolePaths/{rolePath}/bulkProperties - invokes set_properties_by_path method - configuration_api.support(U("/rolePaths/") + nmos::patterns::rolePath.pattern + U("/bulkProperties/?"), methods::PUT, [&model, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, validate_validation_fingerprint, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, &gate_](http_request req, http_response res, const string_t&, const route_parameters& parameters) + configuration_api.support(U("/rolePaths/") + nmos::patterns::rolePath.pattern + U("/bulkProperties/?"), methods::PUT, [&model, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, validate_validation_fingerprint, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed, &gate_](http_request req, http_response res, const string_t&, const route_parameters& parameters) { const auto role_path = parameters.at(nmos::patterns::rolePath.name); const nmos::api_version version = nmos::parse_api_version(parameters.at(nmos::patterns::version.name)); - return details::extract_json(req, gate_).then([res, &model, role_path, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, validate_validation_fingerprint, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, version, &gate_](value body) mutable + return details::extract_json(req, gate_).then([res, &model, role_path, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, validate_validation_fingerprint, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed, version, &gate_](value body) mutable { auto lock = model.write_lock(); auto& resources = model.control_protocol_resources; @@ -762,7 +762,7 @@ namespace nmos const auto& restore_mode = nmos::fields::nc::restore_mode(arguments); const auto& backup_data_set = nmos::fields::nc::data_set(arguments); - method_result = set_properties_by_path(resources, *resource, backup_data_set, recurse, static_cast(restore_mode), get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, validate_validation_fingerprint, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object); + method_result = set_properties_by_path(resources, *resource, backup_data_set, recurse, static_cast(restore_mode), get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, validate_validation_fingerprint, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); code = status_codes::OK; diff --git a/Development/nmos/configuration_methods.cpp b/Development/nmos/configuration_methods.cpp index 5d795d369..1e1babcab 100644 --- a/Development/nmos/configuration_methods.cpp +++ b/Development/nmos/configuration_methods.cpp @@ -113,12 +113,12 @@ namespace nmos } const auto& object_properties_holders = nmos::fields::nc::values(backup_data_set); - const auto object_properties_set_validation = apply_backup_data_set(resources, resource, object_properties_holders, recurse, restore_mode, true, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object); + const auto object_properties_set_validation = apply_backup_data_set(resources, resource, object_properties_holders, recurse, restore_mode, true, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, nullptr); return nmos::nc::details::make_method_result({ nmos::nc_method_status::ok }, object_properties_set_validation); } - web::json::value set_properties_by_path(nmos::resources& resources, const nmos::resource& resource, const web::json::value& backup_data_set, bool recurse, nmos::nc_restore_mode::restore_mode restore_mode, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, nmos::validate_validation_fingerprint_handler validate_validation_fingerprint, nmos::get_read_only_modification_allow_list_handler get_read_only_modification_allow_list, nmos::remove_device_model_object_handler remove_device_model_object, nmos::create_device_model_object_handler create_device_model_object) + web::json::value set_properties_by_path(nmos::resources& resources, const nmos::resource& resource, const web::json::value& backup_data_set, bool recurse, nmos::nc_restore_mode::restore_mode restore_mode, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, nmos::validate_validation_fingerprint_handler validate_validation_fingerprint, nmos::get_read_only_modification_allow_list_handler get_read_only_modification_allow_list, nmos::remove_device_model_object_handler remove_device_model_object, nmos::create_device_model_object_handler create_device_model_object, nmos::control_protocol_property_changed_handler property_changed) { if (validate_validation_fingerprint) { @@ -131,7 +131,7 @@ namespace nmos } const auto& object_properties_holders = nmos::fields::nc::values(backup_data_set); - const auto object_properties_set_validation = apply_backup_data_set(resources, resource, object_properties_holders, recurse, restore_mode, false, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object); + const auto object_properties_set_validation = apply_backup_data_set(resources, resource, object_properties_holders, recurse, restore_mode, false, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); return nmos::nc::details::make_method_result({ nmos::nc_method_status::ok }, object_properties_set_validation); } diff --git a/Development/nmos/configuration_methods.h b/Development/nmos/configuration_methods.h index 46df83cda..ca10fa361 100644 --- a/Development/nmos/configuration_methods.h +++ b/Development/nmos/configuration_methods.h @@ -19,7 +19,7 @@ namespace nmos web::json::value validate_set_properties_by_path(nmos::resources& resources, const nmos::resource& resource, const web::json::value& backup_data_set, bool recurse, nmos::nc_restore_mode::restore_mode restore_mode, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, nmos::validate_validation_fingerprint_handler validate_validation_fingerprint, nmos::get_read_only_modification_allow_list_handler get_read_only_modification_allow_list, nmos::remove_device_model_object_handler remove_device_model_object, nmos::create_device_model_object_handler create_device_model_object); - web::json::value set_properties_by_path(nmos::resources& resources, const nmos::resource& resource, const web::json::value& backup_data_set, bool recurse, nmos::nc_restore_mode::restore_mode restore_mode, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, nmos::validate_validation_fingerprint_handler validate_validation_fingerprint, nmos::get_read_only_modification_allow_list_handler get_read_only_modification_allow_list, nmos::remove_device_model_object_handler remove_device_model_object, nmos::create_device_model_object_handler create_device_model_object); + web::json::value set_properties_by_path(nmos::resources& resources, const nmos::resource& resource, const web::json::value& backup_data_set, bool recurse, nmos::nc_restore_mode::restore_mode restore_mode, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, nmos::validate_validation_fingerprint_handler validate_validation_fingerprint, nmos::get_read_only_modification_allow_list_handler get_read_only_modification_allow_list, nmos::remove_device_model_object_handler remove_device_model_object, nmos::create_device_model_object_handler create_device_model_object, nmos::control_protocol_property_changed_handler property_changed); } #endif diff --git a/Development/nmos/configuration_utils.cpp b/Development/nmos/configuration_utils.cpp index 7c90457f0..f297db97d 100644 --- a/Development/nmos/configuration_utils.cpp +++ b/Development/nmos/configuration_utils.cpp @@ -54,7 +54,7 @@ namespace nmos return false; } - web::json::value modify_device_model_object(nmos::resources& resources, const nmos::resource& resource, const web::json::array& target_role_path, const web::json::value& target_object_properties_holder, nmos::nc_restore_mode::restore_mode restore_mode, bool validate, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, nmos::get_read_only_modification_allow_list_handler get_read_only_modification_allow_list) + web::json::value modify_device_model_object(nmos::resources& resources, const nmos::resource& resource, const web::json::array& target_role_path, const web::json::value& target_object_properties_holder, nmos::nc_restore_mode::restore_mode restore_mode, bool validate, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, nmos::get_read_only_modification_allow_list_handler get_read_only_modification_allow_list, nmos::control_protocol_property_changed_handler property_changed) { const auto& class_id = nc::details::parse_class_id(nmos::fields::nc::class_id(resource.data)); @@ -171,6 +171,12 @@ namespace nmos { resource_.data[nmos::fields::nc::name(property_descriptor)] = value; + // notify application code that the specified property has changed + if (property_changed) + { + property_changed(resource, nmos::fields::nc::name(property_descriptor), -1); + } + }, nc::make_property_changed_event(nmos::fields::nc::oid(resource.data), {{property_id, nmos::nc_property_change_type::type::value_changed, value}})); } } @@ -194,7 +200,7 @@ namespace nmos return nmos::make_object_properties_set_validation(target_role_path, object_status, property_restore_notices.as_array(), U("OK")); } - web::json::value modify_rebuildable_block(nmos::resources& resources, object_properties_map& object_properties_holder_map, const nmos::resource& resource, const web::json::array& target_role_path, const web::json::value& block_object_properties_holder, bool validate, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::remove_device_model_object_handler remove_device_model_object, nmos::create_device_model_object_handler create_device_model_object) + web::json::value modify_rebuildable_block(nmos::resources& resources, object_properties_map& object_properties_holder_map, const nmos::resource& resource, const web::json::array& target_role_path, const web::json::value& block_object_properties_holder, bool validate, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::remove_device_model_object_handler remove_device_model_object, nmos::create_device_model_object_handler create_device_model_object, nmos::control_protocol_property_changed_handler property_changed) { auto object_properties_set_validations = web::json::value::array(); @@ -544,6 +550,12 @@ namespace nmos { resource.data[nmos::fields::nc::members] = modified_members; + // notify application code that the specified property has changed + if (property_changed) + { + property_changed(resource, nmos::fields::nc::members, -1); + } + }, nc::make_property_changed_event(nmos::fields::nc::oid(resource.data), { { nmos::nc_block_members_property_id, nmos::nc_property_change_type::type::value_changed, modified_members } })); } @@ -681,7 +693,7 @@ namespace nmos return web::json::value_from_elements(target_object_properties_holders).as_array(); } - web::json::value apply_backup_data_set(nmos::resources& resources, const nmos::resource& resource, const web::json::array& object_properties_holders, bool recurse, nmos::nc_restore_mode::restore_mode restore_mode, bool validate, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, nmos::get_read_only_modification_allow_list_handler get_read_only_modification_allow_list, nmos::remove_device_model_object_handler remove_device_model_object, nmos::create_device_model_object_handler create_device_model_object) + web::json::value apply_backup_data_set(nmos::resources& resources, const nmos::resource& resource, const web::json::array& object_properties_holders, bool recurse, nmos::nc_restore_mode::restore_mode restore_mode, bool validate, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, nmos::get_read_only_modification_allow_list_handler get_read_only_modification_allow_list, nmos::remove_device_model_object_handler remove_device_model_object, nmos::create_device_model_object_handler create_device_model_object, nmos::control_protocol_property_changed_handler property_changed) { auto object_properties_set_validation_values = web::json::value::array(); @@ -753,7 +765,7 @@ namespace nmos { // Process this block to add / remove device model objects as members of this block // the object properties holder for any added objects will be erased from the object_properties_holder_map to avoid double processing - const auto child_object_properties_set_validations = details::modify_rebuildable_block(resources, object_properties_holder_map, *r, role_path, object_properties_holder, validate, get_control_protocol_class_descriptor, remove_device_model_object, create_device_model_object); + const auto child_object_properties_set_validations = details::modify_rebuildable_block(resources, object_properties_holder_map, *r, role_path, object_properties_holder, validate, get_control_protocol_class_descriptor, remove_device_model_object, create_device_model_object, property_changed); for (const auto& validation_values : child_object_properties_set_validations.as_array()) { web::json::push_back(object_properties_set_validation_values, validation_values); @@ -769,7 +781,7 @@ namespace nmos } else { - const auto object_properties_set_validation = details::modify_device_model_object(resources, *r, role_path, object_properties_holder, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list); + const auto object_properties_set_validation = details::modify_device_model_object(resources, *r, role_path, object_properties_holder, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, property_changed); web::json::push_back(object_properties_set_validation_values, object_properties_set_validation); } diff --git a/Development/nmos/configuration_utils.h b/Development/nmos/configuration_utils.h index 8157d4173..cf7357a1b 100644 --- a/Development/nmos/configuration_utils.h +++ b/Development/nmos/configuration_utils.h @@ -13,7 +13,7 @@ namespace nmos namespace details { - web::json::value modify_rebuildable_block(nmos::resources& resources, object_properties_map& object_properties_holder_map, const nmos::resource& resource, const web::json::array& target_role_path, const web::json::value& block_object_properties_holder, bool validate, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::remove_device_model_object_handler remove_device_model_object, nmos::create_device_model_object_handler create_device_model_object); + web::json::value modify_rebuildable_block(nmos::resources& resources, object_properties_map& object_properties_holder_map, const nmos::resource& resource, const web::json::array& target_role_path, const web::json::value& block_object_properties_holder, bool validate, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::remove_device_model_object_handler remove_device_model_object, nmos::create_device_model_object_handler create_device_model_object, nmos::control_protocol_property_changed_handler property_changed); } // Check to see if role_path is sub path of parent_role_path @@ -27,7 +27,7 @@ namespace nmos // Get object_properties_holder for specified target_role_path web::json::array get_object_properties_holder(const web::json::array& object_properties_holders, const web::json::array& target_role_path); - web::json::value apply_backup_data_set(nmos::resources& resources, const nmos::resource& resource, const web::json::array& object_properties_holders, bool recurse, nmos::nc_restore_mode::restore_mode restore_mode, bool validate, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, nmos::get_read_only_modification_allow_list_handler get_read_only_modification_allow_list, nmos::remove_device_model_object_handler remove_device_model_object, nmos::create_device_model_object_handler create_device_model_object); + web::json::value apply_backup_data_set(nmos::resources& resources, const nmos::resource& resource, const web::json::array& object_properties_holders, bool recurse, nmos::nc_restore_mode::restore_mode restore_mode, bool validate, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, nmos::get_read_only_modification_allow_list_handler get_read_only_modification_allow_list, nmos::remove_device_model_object_handler remove_device_model_object, nmos::create_device_model_object_handler create_device_model_object, nmos::control_protocol_property_changed_handler property_changed); web::json::value get_property_holder(const web::json::value& object_properties_holder, const nmos::nc_property_id& property_id); } diff --git a/Development/nmos/control_protocol_state.cpp b/Development/nmos/control_protocol_state.cpp index 8e6b90762..8f68b6eb4 100644 --- a/Development/nmos/control_protocol_state.cpp +++ b/Development/nmos/control_protocol_state.cpp @@ -217,9 +217,9 @@ namespace nmos return result; }; } - nmos::experimental::control_protocol_method_handler make_nc_set_properties_by_path_handler(get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, validate_validation_fingerprint_handler validate_validation_fingerprint, get_read_only_modification_allow_list_handler get_read_only_modification_allow_list, remove_device_model_object_handler remove_device_model_object, create_device_model_object_handler create_device_model_object) + nmos::experimental::control_protocol_method_handler make_nc_set_properties_by_path_handler(get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, validate_validation_fingerprint_handler validate_validation_fingerprint, get_read_only_modification_allow_list_handler get_read_only_modification_allow_list, remove_device_model_object_handler remove_device_model_object, create_device_model_object_handler create_device_model_object, nmos::control_protocol_property_changed_handler property_changed) { - return [get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, validate_validation_fingerprint, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object](nmos::resources& resources, const nmos::resource& resource, const web::json::value& arguments, bool is_deprecated, slog::base_gate& gate) + return [get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, validate_validation_fingerprint, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed](nmos::resources& resources, const nmos::resource& resource, const web::json::value& arguments, bool is_deprecated, slog::base_gate& gate) { bool recurse = nmos::fields::nc::recurse(arguments); const auto& restore_mode = nmos::fields::nc::restore_mode(arguments); @@ -233,7 +233,7 @@ namespace nmos auto result = nc::details::make_method_result_error({ nmos::nc_method_status::method_not_implemented }, U("callbacks not implemented")); if (get_read_only_modification_allow_list && remove_device_model_object && create_device_model_object) { - result = set_properties_by_path(resources, resource, data_set, recurse, static_cast(restore_mode), get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, validate_validation_fingerprint, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object); + result = set_properties_by_path(resources, resource, data_set, recurse, static_cast(restore_mode), get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, validate_validation_fingerprint, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); const auto& status = nmos::fields::nc::status(result); if (!web::http::is_error_status_code((web::http::status_code)status) && is_deprecated) @@ -429,7 +429,7 @@ namespace nmos { { nc_bulk_properties_manager_get_properties_by_path_method_id, details::make_nc_get_properties_by_path_handler(make_get_control_protocol_class_descriptor_handler(*this), make_get_control_protocol_datatype_descriptor_handler(*this), create_validation_fingerprint)}, { nc_bulk_properties_manager_validate_set_properties_by_path_method_id, details::make_nc_validate_set_properties_by_path_handler(make_get_control_protocol_class_descriptor_handler(*this), make_get_control_protocol_datatype_descriptor_handler(*this), validate_validation_fingerprint, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object) }, - { nc_bulk_properties_manager_set_properties_by_path_method_id, details::make_nc_set_properties_by_path_handler(make_get_control_protocol_class_descriptor_handler(*this), make_get_control_protocol_datatype_descriptor_handler(*this), validate_validation_fingerprint, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object) } + { nc_bulk_properties_manager_set_properties_by_path_method_id, details::make_nc_set_properties_by_path_handler(make_get_control_protocol_class_descriptor_handler(*this), make_get_control_protocol_datatype_descriptor_handler(*this), validate_validation_fingerprint, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed) } }), to_vector(nc::make_bulk_properties_manager_events())) } }; diff --git a/Development/nmos/test/configuration_methods_test.cpp b/Development/nmos/test/configuration_methods_test.cpp index f360777bb..6828032f7 100644 --- a/Development/nmos/test/configuration_methods_test.cpp +++ b/Development/nmos/test/configuration_methods_test.cpp @@ -106,3 +106,93 @@ BST_TEST_CASE(testGetPropertiesByPath) BST_CHECK(create_validation_fingerprint_called); } } + +//////////////////////////////////////////////////////////////////////////////////////////// +BST_TEST_CASE(testSetPropertiesByPath) +{ + using web::json::value_of; + using web::json::value; + + nmos::resources resources; + nmos::experimental::control_protocol_state control_protocol_state; + nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor = nmos::make_get_control_protocol_class_descriptor_handler(control_protocol_state); + nmos::get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor = nmos::make_get_control_protocol_datatype_descriptor_handler(control_protocol_state); + + bool validate_validation_fingerprint_called = false; + bool property_changed_called = false; + // callback stubs + nmos::validate_validation_fingerprint_handler validate_validation_fingerprint = [&](const nmos::resources& resources, const nmos::resource& resource, const utility::string_t& validation_fingerprint) + { + validate_validation_fingerprint_called = true; + return true; + }; + + nmos::get_read_only_modification_allow_list_handler get_read_only_modification_allow_list = [&](const nmos::resources& resources, const nmos::resource& resource, const std::vector& role_path, const std::vector& property_ids) + { + return property_ids; + }; + + nmos::control_protocol_property_changed_handler property_changed = [&](const nmos::resource& resource, const utility::string_t& property_name, int index) + { + property_changed_called = true; + }; + + nmos::remove_device_model_object_handler remove_device_model_object = nullptr; + nmos::create_device_model_object_handler create_device_model_object = nullptr; + + // Create Device Model + // root + auto root_block = nmos::make_root_block(); + auto oid = nmos::root_block_oid; + // root, ClassManager + auto class_manager = nmos::make_class_manager(++oid, control_protocol_state); + auto receiver_block_oid = ++oid; + // root, receivers + auto receivers = nmos::make_block(receiver_block_oid, nmos::root_block_oid, U("receivers"), U("Receivers"), U("Receivers block")); + nmos::make_rebuildable(receivers); + // root, receivers, mon1 + auto monitor1 = nmos::make_receiver_monitor(++oid, true, receiver_block_oid, U("mon1"), U("monitor 1"), U("monitor 1"), value_of({ {nmos::nc::details::make_touchpoint_nmos({nmos::ncp_touchpoint_resource_types::receiver, U("id_1")})} })); + // make monitor1 rebuildable + nmos::make_rebuildable(monitor1); + + auto monitor_class_id = nmos::nc::details::parse_class_id(nmos::fields::nc::class_id(monitor1.data)); + // root, receivers, mon2 + auto monitor2 = nmos::make_receiver_monitor(++oid, true, receiver_block_oid, U("mon2"), U("monitor 2"), U("monitor 2"), value_of({ {nmos::nc::details::make_touchpoint_nmos({nmos::ncp_touchpoint_resource_types::receiver, U("id_2")})} })); + nmos::nc::push_back(receivers, monitor1); + // add example-control to root-block + nmos::nc::push_back(receivers, monitor2); + // add stereo-gain to root-block + nmos::nc::push_back(root_block, receivers); + // add class-manager to root-block + nmos::nc::push_back(root_block, class_manager); + + // insert root block and all sub control protocol resources to resource list + nmos::nc::insert_root(resources, root_block); + + { + // create a backup dataset + value object_properties_holders = value::array(); + value property_holders = value::array(); + web::json::push_back(property_holders, nmos::nc::details::make_property_holder(nmos::nc_object_user_label_property_id, false, value::string(U("test string")))); + const auto role_path = get_role_path(resources, monitor1); + web::json::push_back(object_properties_holders, nmos::nc::details::make_object_properties_holder(role_path, property_holders.as_array(), value::array().as_array(), value::array().as_array(), false)); + + auto bulk_properties_holder = nmos::nc::details::make_bulk_properties_holder(U(""), object_properties_holders); + + validate_validation_fingerprint_called = false; + property_changed_called = false; + + const auto target_role_path = value_of({ U("root") }); + const auto& resource = nmos::nc::find_resource_by_role_path(resources, target_role_path.as_array()); + auto method_result = set_properties_by_path(resources, *resource, bulk_properties_holder, true, nmos::nc_restore_mode::modify, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, validate_validation_fingerprint, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); + BST_REQUIRE_EQUAL(nmos::nc_method_status::ok, nmos::fields::nc::status(method_result)); + + const auto& object_property_set_validations = nmos::fields::nc::value(method_result); + + BST_REQUIRE_EQUAL(1, object_property_set_validations.size()); + + BST_CHECK(validate_validation_fingerprint_called); + BST_CHECK(property_changed_called); + } +} + diff --git a/Development/nmos/test/configuration_utils_test.cpp b/Development/nmos/test/configuration_utils_test.cpp index 55474e1ee..88543fcc2 100644 --- a/Development/nmos/test/configuration_utils_test.cpp +++ b/Development/nmos/test/configuration_utils_test.cpp @@ -5,6 +5,7 @@ #include "nmos/control_protocol_typedefs.h" #include "nmos/control_protocol_utils.h" #include "nmos/configuration_handlers.h" +#include "nmos/configuration_methods.h" #include "nmos/configuration_resources.h" #include "nmos/configuration_utils.h" #include "nmos/is12_versions.h" @@ -362,9 +363,7 @@ BST_TEST_CASE(testApplyBackupDataSet) auto monitor2 = nmos::make_receiver_monitor(++oid, true, receiver_block_oid, U("mon2"), U("monitor 2"), U("monitor 2"), value_of({ {nmos::nc::details::make_touchpoint_nmos({nmos::ncp_touchpoint_resource_types::receiver, U("id_2")})} })); auto monitor_2_oid = oid; nmos::nc::push_back(receivers, monitor1); - // add example-control to root-block nmos::nc::push_back(receivers, monitor2); - // add stereo-gain to root-block nmos::nc::push_back(root_block, receivers); // add class-manager to root-block nmos::nc::push_back(root_block, class_manager); @@ -375,8 +374,14 @@ BST_TEST_CASE(testApplyBackupDataSet) bool get_read_only_modification_allow_list_called = false; bool remove_device_model_object_called = false; bool create_device_model_object_called = false; + bool property_changed_called = false; // callback stubs + nmos::control_protocol_property_changed_handler property_changed = [&](const nmos::resource& resource, const utility::string_t& property_name, int index) + { + property_changed_called = true; + }; + nmos::get_read_only_modification_allow_list_handler get_read_only_modification_allow_list = [&](const nmos::resources& resources, const nmos::resource& resource, const std::vector& target_role_path, const std::vector& property_ids) { get_read_only_modification_allow_list_called = true; @@ -401,6 +406,11 @@ BST_TEST_CASE(testApplyBackupDataSet) return nmos::control_protocol_resource({ nmos::is12_versions::v1_0, nmos::types::nc_block, std::move(data), true }); }; + // Capture initial state of device model so we can reset after each check + const auto& root_resource = nmos::nc::find_resource_by_role_path(resources, value_of({ U("root") }).as_array()); + auto initial_backup_dataset = nmos::get_properties_by_path(resources, *root_resource, true, false, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, nullptr); + auto& initial_object_properties_holders = nmos::fields::nc::values(nmos::fields::nc::value(initial_backup_dataset)); + const auto enabled_property_descriptor = nmos::nc::details::make_property_descriptor(U("enabled"), nmos::nc_worker_enabled_property_id, nmos::fields::nc::enabled, U("NcBoolean"), false, false, false, false, web::json::value::null()); const auto class_id_property_descriptor = nmos::nc::details::make_property_descriptor(U("classId"), nmos::nc_object_class_id_property_id, nmos::fields::nc::class_id, U("NcClassId"), true, false, false, false, web::json::value::null()); { @@ -416,11 +426,11 @@ BST_TEST_CASE(testApplyBackupDataSet) push_back(object_properties_holders, object_properties_holder); const auto target_role_path = value_of({ U("root"), U("receivers")}); bool recurse = true; - bool validate = true; + bool validate = false; const auto restore_mode = nmos::nc_restore_mode::restore_mode::modify; const auto& resource = nmos::nc::find_resource_by_role_path(resources, target_role_path.as_array()); - auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object); + auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); // expectation is there will be a result for each of the object_properties_holders i.e. one BST_REQUIRE_EQUAL(1, output.as_array().size()); @@ -434,6 +444,10 @@ BST_TEST_CASE(testApplyBackupDataSet) BST_CHECK(!get_read_only_modification_allow_list_called); BST_CHECK(!remove_device_model_object_called); BST_CHECK(!create_device_model_object_called); + BST_CHECK(property_changed_called); + + // reset device model to initial state + nmos::apply_backup_data_set(resources, *resource, initial_object_properties_holders, recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); } const auto connection_status_property_descriptor = nmos::nc::details::make_property_descriptor(U("connectionStatusMessage"), nmos::nc_receiver_monitor_connection_status_message_property_id, nmos::fields::nc::connection_status_message, U("NcString"), true, false, false, false, web::json::value::null()); { @@ -442,6 +456,7 @@ BST_TEST_CASE(testApplyBackupDataSet) get_read_only_modification_allow_list_called = false; remove_device_model_object_called = false; create_device_model_object_called = false; + property_changed_called = false; // Create Object Properties Holder auto object_properties_holders = value::array(); @@ -456,10 +471,10 @@ BST_TEST_CASE(testApplyBackupDataSet) const auto target_role_path = value_of({ U("root"), U("receivers") }); bool recurse = true; const auto restore_mode = nmos::nc_restore_mode::restore_mode::rebuild; - bool validate = true; + bool validate = false; const auto& resource = nmos::nc::find_resource_by_role_path(resources, target_role_path.as_array()); - auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object); + auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); // expectation is there will be a result for each of the object_properties_holders i.e. one BST_REQUIRE_EQUAL(1, output.as_array().size()); @@ -474,6 +489,10 @@ BST_TEST_CASE(testApplyBackupDataSet) BST_CHECK(get_read_only_modification_allow_list_called); BST_CHECK(!remove_device_model_object_called); BST_CHECK(!create_device_model_object_called); + BST_CHECK(property_changed_called); + + // reset device model to initial state + nmos::apply_backup_data_set(resources, *resource, initial_object_properties_holders, recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); } { // Check error generated when attempting to change a read only property of non-rebuidable object in Rebuild mode @@ -481,6 +500,7 @@ BST_TEST_CASE(testApplyBackupDataSet) get_read_only_modification_allow_list_called = false; remove_device_model_object_called = false; create_device_model_object_called = false; + property_changed_called = false; // Create Object Properties Holder auto object_properties_holders = value::array(); @@ -498,7 +518,7 @@ BST_TEST_CASE(testApplyBackupDataSet) bool validate = true; const auto& resource = nmos::nc::find_resource_by_role_path(resources, target_role_path.as_array()); - const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object); + const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); // expectation is there will be a result for each of the object_properties_holders i.e. one BST_REQUIRE_EQUAL(1, output.as_array().size()); @@ -518,11 +538,10 @@ BST_TEST_CASE(testApplyBackupDataSet) BST_CHECK_EQUAL(nmos::nc_property_restore_notice_type::error, nmos::fields::nc::notice_type(notice)); BST_CHECK_NE(U(""), nmos::fields::nc::notice_message(notice)); - // expecting callback to get_read_only_modification_allow_list_called - // but not to modify_rebuildable_block_called BST_CHECK(!get_read_only_modification_allow_list_called); BST_CHECK(!remove_device_model_object_called); BST_CHECK(!create_device_model_object_called); + BST_CHECK(!property_changed_called); } { // Check an error is caused by trying to modify a read only property in Modify mode @@ -530,6 +549,7 @@ BST_TEST_CASE(testApplyBackupDataSet) get_read_only_modification_allow_list_called = false; remove_device_model_object_called = false; create_device_model_object_called = false; + property_changed_called = false; // Change a read only property in Rebuild mode // Create Object Properties Holder @@ -537,7 +557,7 @@ BST_TEST_CASE(testApplyBackupDataSet) const auto role_path = value_of({ U("root"), U("receivers"), U("mon1") }); auto property_holders = value::array(); // This is a read only property - push_back(property_holders, nmos::nc::details::make_property_holder(nmos::nc_receiver_monitor_connection_status_message_property_id, connection_status_property_descriptor, value(U("change this value")))); + push_back(property_holders, nmos::nc::details::make_property_holder(nmos::nc_receiver_monitor_connection_status_message_property_id, connection_status_property_descriptor, nmos::nc_connection_status::partially_healthy)); // This is a writable property push_back(property_holders, nmos::nc::details::make_property_holder(nmos::nc_worker_enabled_property_id, enabled_property_descriptor, value::boolean(false))); const auto object_properties_holder = nmos::nc::details::make_object_properties_holder(role_path.as_array(), property_holders.as_array(), value::array().as_array(), value::array().as_array(), false); @@ -546,10 +566,10 @@ BST_TEST_CASE(testApplyBackupDataSet) const auto target_role_path = value_of({ U("root"), U("receivers") }); bool recurse = true; const auto restore_mode = nmos::nc_restore_mode::restore_mode::modify; - bool validate = true; + bool validate = false; const auto& resource = nmos::nc::find_resource_by_role_path(resources, target_role_path.as_array()); - const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object); + const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); // expectation is there will be a result for each of the object_properties_holders i.e. one BST_REQUIRE_EQUAL(1, output.as_array().size()); @@ -573,6 +593,10 @@ BST_TEST_CASE(testApplyBackupDataSet) BST_CHECK(!get_read_only_modification_allow_list_called); BST_CHECK(!remove_device_model_object_called); BST_CHECK(!create_device_model_object_called); + BST_CHECK(property_changed_called); + + // reset device model to initial state + nmos::apply_backup_data_set(resources, *resource, initial_object_properties_holders, recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); } const auto block_members_property_descriptor = nmos::nc::details::make_property_descriptor(U("members"), nmos::nc_block_members_property_id, nmos::fields::nc::members, U("NcBlockMemberDescriptor"), true, false, true, false, web::json::value::null()); { @@ -581,6 +605,7 @@ BST_TEST_CASE(testApplyBackupDataSet) get_read_only_modification_allow_list_called = false; remove_device_model_object_called = false; create_device_model_object_called = false; + property_changed_called = false; // Create Object Properties Holder auto object_properties_holders = value::array(); @@ -593,11 +618,11 @@ BST_TEST_CASE(testApplyBackupDataSet) push_back(object_properties_holders, nmos::nc::details::make_object_properties_holder(role_path.as_array(), property_holders.as_array(), value::array().as_array(), value::array().as_array(), false)); const auto target_role_path = value_of({ U("root"), U("receivers") }); bool recurse = true; - bool validate = true; + bool validate = false; const auto restore_mode = nmos::nc_restore_mode::restore_mode::rebuild; const auto& resource = nmos::nc::find_resource_by_role_path(resources, target_role_path.as_array()); - const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object); + const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); // expectation is there will be a result for each of the object_properties_holders i.e. one BST_REQUIRE_EQUAL(1, output.as_array().size()); @@ -610,6 +635,10 @@ BST_TEST_CASE(testApplyBackupDataSet) BST_CHECK(!get_read_only_modification_allow_list_called); BST_CHECK(remove_device_model_object_called); BST_CHECK(!create_device_model_object_called); + BST_CHECK(property_changed_called); + + // reset device model to initial state + nmos::apply_backup_data_set(resources, *resource, initial_object_properties_holders, recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); } const auto oid_property_descriptor = nmos::nc::details::make_property_descriptor(U("oid"), nmos::nc_object_oid_property_id, nmos::fields::nc::oid, U("NcOid"), true, false, false, false, web::json::value::null()); { @@ -618,6 +647,7 @@ BST_TEST_CASE(testApplyBackupDataSet) get_read_only_modification_allow_list_called = false; remove_device_model_object_called = false; create_device_model_object_called = false; + property_changed_called = false; auto monitor_3_oid = 999; // Create Object Properties Holder for Block, with a Property Holder for the block members @@ -648,11 +678,11 @@ BST_TEST_CASE(testApplyBackupDataSet) } const auto target_role_path = value_of({ U("root"), U("receivers") }); bool recurse = true; - bool validate = true; + bool validate = false; const auto restore_mode = nmos::nc_restore_mode::restore_mode::rebuild; const auto& resource = nmos::nc::find_resource_by_role_path(resources, target_role_path.as_array()); - const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object); + const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); // expectation is there will be a result for each of the object_properties_holders i.e. one for the block and one each for the monitors BST_REQUIRE_EQUAL(3, output.as_array().size()); @@ -683,6 +713,7 @@ BST_TEST_CASE(testApplyBackupDataSet) BST_CHECK(!get_read_only_modification_allow_list_called); BST_CHECK(!remove_device_model_object_called); BST_CHECK(create_device_model_object_called); + BST_CHECK(property_changed_called); } { // Check that role paths outside of the scope of the target role path are errored @@ -690,6 +721,7 @@ BST_TEST_CASE(testApplyBackupDataSet) get_read_only_modification_allow_list_called = false; remove_device_model_object_called = false; create_device_model_object_called = false; + property_changed_called = false; // Create Object Properties Holder auto object_properties_holders = value::array(); @@ -702,11 +734,11 @@ BST_TEST_CASE(testApplyBackupDataSet) push_back(object_properties_holders, nmos::nc::details::make_object_properties_holder(role_path.as_array(), property_holders.as_array(), value::array().as_array(), value::array().as_array(), false)); const auto target_role_path = value_of({ U("root"), U("receivers") }); bool recurse = true; - bool validate = true; + bool validate = false; const auto restore_mode = nmos::nc_restore_mode::restore_mode::rebuild; const auto& resource = nmos::nc::find_resource_by_role_path(resources, target_role_path.as_array()); - const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object); + const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); // expectation no object_properties_holders as not in the restore scope BST_REQUIRE_EQUAL(0, output.as_array().size()); @@ -714,6 +746,7 @@ BST_TEST_CASE(testApplyBackupDataSet) BST_CHECK(!get_read_only_modification_allow_list_called); BST_CHECK(!remove_device_model_object_called); BST_CHECK(!create_device_model_object_called); + BST_CHECK(!property_changed_called); } } @@ -760,6 +793,7 @@ BST_TEST_CASE(testApplyBackupDataSet_WithoutCallbacks) nmos::get_read_only_modification_allow_list_handler get_read_only_modification_allow_list; nmos::remove_device_model_object_handler remove_device_model_object; nmos::create_device_model_object_handler create_device_model_object; + nmos::control_protocol_property_changed_handler property_changed; const auto enabled_property_descriptor = nmos::nc::details::make_property_descriptor(U("enabled"), nmos::nc_worker_enabled_property_id, nmos::fields::nc::enabled, U("NcBoolean"), false, false, false, false, web::json::value::null()); { @@ -779,7 +813,7 @@ BST_TEST_CASE(testApplyBackupDataSet_WithoutCallbacks) const auto restore_mode = nmos::nc_restore_mode::restore_mode::modify; const auto& resource = nmos::nc::find_resource_by_role_path(resources, target_role_path.as_array()); - const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object); + const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); // expectation is there will be a result for each of the object_properties_holders i.e. one BST_REQUIRE_EQUAL(1, output.as_array().size()); @@ -806,7 +840,7 @@ BST_TEST_CASE(testApplyBackupDataSet_WithoutCallbacks) const auto restore_mode = nmos::nc_restore_mode::restore_mode::rebuild; const auto& resource = nmos::nc::find_resource_by_role_path(resources, target_role_path.as_array()); - const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object); + const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); // expectation is there will be a result for each of the object_properties_holders i.e. one BST_REQUIRE_EQUAL(1, output.as_array().size()); @@ -836,7 +870,7 @@ BST_TEST_CASE(testApplyBackupDataSet_WithoutCallbacks) bool validate = true; const auto& resource = nmos::nc::find_resource_by_role_path(resources, target_role_path.as_array()); - const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object); + const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); // expectation is there will be a result for each of the object_properties_holders i.e. one BST_REQUIRE_EQUAL(1, output.as_array().size()); @@ -872,7 +906,7 @@ BST_TEST_CASE(testApplyBackupDataSet_WithoutCallbacks) const auto restore_mode = nmos::nc_restore_mode::restore_mode::rebuild; const auto& resource = nmos::nc::find_resource_by_role_path(resources, target_role_path.as_array()); - const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object); + const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); // expectation is there will be a result for each of the object_properties_holder BST_CHECK_EQUAL(2, output.as_array().size()); @@ -938,8 +972,14 @@ BST_TEST_CASE(testApplyBackupDataSet_AddDeviceModelObject) bool get_read_only_modification_allow_list_called = false; bool remove_device_model_object_called = false; bool create_device_model_object_called = false; + bool property_changed_called = false; // callback stubs + nmos::control_protocol_property_changed_handler property_changed = [&](const nmos::resource& resource, const utility::string_t& property_name, int index) + { + property_changed_called = true; + }; + nmos::get_read_only_modification_allow_list_handler get_read_only_modification_allow_list = [&](const nmos::resources& resources, const nmos::resource& resource, const std::vector& target_role_path, const std::vector& property_ids) { get_read_only_modification_allow_list_called = true; @@ -973,6 +1013,7 @@ BST_TEST_CASE(testApplyBackupDataSet_AddDeviceModelObject) get_read_only_modification_allow_list_called = false; remove_device_model_object_called = false; create_device_model_object_called = false; + property_changed_called = false; // Create Object Properties Holder for Block, with a Property Holder for the block members auto object_properties_holders = value::array(); @@ -1006,7 +1047,7 @@ BST_TEST_CASE(testApplyBackupDataSet_AddDeviceModelObject) const auto restore_mode = nmos::nc_restore_mode::restore_mode::rebuild; const auto& resource = nmos::nc::find_resource_by_role_path(resources, target_role_path.as_array()); - const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object); + const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); // expectation is there will be a result for each of the object_properties_holders i.e. one for the block and one each for the monitors BST_REQUIRE_EQUAL(3, output.as_array().size()); @@ -1034,6 +1075,7 @@ BST_TEST_CASE(testApplyBackupDataSet_AddDeviceModelObject) BST_CHECK(!get_read_only_modification_allow_list_called); BST_CHECK(!remove_device_model_object_called); BST_CHECK(!create_device_model_object_called); + BST_CHECK(!property_changed_called); } { // Check new oid is generated for new device model object @@ -1041,6 +1083,7 @@ BST_TEST_CASE(testApplyBackupDataSet_AddDeviceModelObject) get_read_only_modification_allow_list_called = false; remove_device_model_object_called = false; create_device_model_object_called = false; + property_changed_called = false; auto monitor_3_oid = 999; // Create Object Properties Holder for Block, with a Property Holder for the block members @@ -1075,7 +1118,7 @@ BST_TEST_CASE(testApplyBackupDataSet_AddDeviceModelObject) const auto restore_mode = nmos::nc_restore_mode::restore_mode::rebuild; const auto& resource = nmos::nc::find_resource_by_role_path(resources, target_role_path.as_array()); - const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object); + const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); // expectation is there will be a result for each of the object_properties_holders i.e. one for the block and one each for the monitors BST_REQUIRE_EQUAL(3, output.as_array().size()); @@ -1117,6 +1160,7 @@ BST_TEST_CASE(testApplyBackupDataSet_AddDeviceModelObject) BST_CHECK(!get_read_only_modification_allow_list_called); BST_CHECK(!remove_device_model_object_called); BST_CHECK(create_device_model_object_called); + BST_CHECK(!property_changed_called); } } @@ -1165,8 +1209,14 @@ BST_TEST_CASE(testApplyBackupDataSet_NegativeTests) bool get_read_only_modification_allow_list_called = false; bool remove_device_model_object_called = false; bool create_device_model_object_called = false; + bool property_changed_called = true; // callback stubs + nmos::control_protocol_property_changed_handler property_changed = [&](const nmos::resource& resource, const utility::string_t& property_name, int index) + { + property_changed_called = true; + }; + nmos::get_read_only_modification_allow_list_handler get_read_only_modification_allow_list = [&](const nmos::resources& resources, const nmos::resource& resource, const std::vector& target_role_path, const std::vector& property_ids) { get_read_only_modification_allow_list_called = true; @@ -1195,6 +1245,7 @@ BST_TEST_CASE(testApplyBackupDataSet_NegativeTests) get_read_only_modification_allow_list_called = false; remove_device_model_object_called = false; create_device_model_object_called = false; + property_changed_called = false; // Create Object Properties Holder auto object_properties_holders = value::array(); @@ -1211,8 +1262,7 @@ BST_TEST_CASE(testApplyBackupDataSet_NegativeTests) const auto restore_mode = nmos::nc_restore_mode::restore_mode::rebuild; const auto& resource = nmos::nc::find_resource_by_role_path(resources, target_role_path.as_array()); - const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object); - + const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); // expectation is there will be a result for each of the object_properties_holders i.e. one BST_REQUIRE_EQUAL(1, output.as_array().size()); const auto& object_properties_set_validation = output.as_array().at(0); @@ -1229,6 +1279,7 @@ BST_TEST_CASE(testApplyBackupDataSet_NegativeTests) BST_CHECK(!get_read_only_modification_allow_list_called); BST_CHECK(remove_device_model_object_called); BST_CHECK(!create_device_model_object_called); + BST_CHECK(!property_changed_called); } { // Check on remove_device_model_object_called error all other object properties holders are processed @@ -1236,6 +1287,7 @@ BST_TEST_CASE(testApplyBackupDataSet_NegativeTests) get_read_only_modification_allow_list_called = false; remove_device_model_object_called = false; create_device_model_object_called = false; + property_changed_called = false; // Create Object Properties Holder auto object_properties_holders = value::array(); @@ -1259,7 +1311,7 @@ BST_TEST_CASE(testApplyBackupDataSet_NegativeTests) const auto restore_mode = nmos::nc_restore_mode::restore_mode::rebuild; const auto& resource = nmos::nc::find_resource_by_role_path(resources, target_role_path.as_array()); - const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object); + const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); // expectation is there will be a result for each of the object_properties_holders BST_CHECK_EQUAL(2, output.as_array().size()); @@ -1292,6 +1344,7 @@ BST_TEST_CASE(testApplyBackupDataSet_NegativeTests) get_read_only_modification_allow_list_called = false; remove_device_model_object_called = false; create_device_model_object_called = false; + property_changed_called = false; auto monitor_3_oid = 999; // Create Object Properties Holder for Block, with a Property Holder for the block members @@ -1332,7 +1385,7 @@ BST_TEST_CASE(testApplyBackupDataSet_NegativeTests) const auto restore_mode = nmos::nc_restore_mode::restore_mode::rebuild; const auto& resource = nmos::nc::find_resource_by_role_path(resources, target_role_path.as_array()); - const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object); + const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); // expectation is there will be a result for each of the object_properties_holders i.e. one for the block and one each for the monitors BST_CHECK_EQUAL(4, output.as_array().size()); @@ -1370,6 +1423,7 @@ BST_TEST_CASE(testApplyBackupDataSet_NegativeTests) BST_CHECK(!get_read_only_modification_allow_list_called); BST_CHECK(!remove_device_model_object_called); BST_CHECK(create_device_model_object_called); + BST_CHECK(!property_changed_called); } { // Check duplicate block object properties holders are handled @@ -1377,6 +1431,7 @@ BST_TEST_CASE(testApplyBackupDataSet_NegativeTests) get_read_only_modification_allow_list_called = false; remove_device_model_object_called = false; create_device_model_object_called = false; + property_changed_called = false; // Create Object Properties Holder auto object_properties_holders = value::array(); @@ -1406,7 +1461,7 @@ BST_TEST_CASE(testApplyBackupDataSet_NegativeTests) const auto restore_mode = nmos::nc_restore_mode::restore_mode::rebuild; const auto& resource = nmos::nc::find_resource_by_role_path(resources, target_role_path.as_array()); - const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object); + const auto output = nmos::apply_backup_data_set(resources, *resource, object_properties_holders.as_array(), recurse, restore_mode, validate, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_read_only_modification_allow_list, remove_device_model_object, create_device_model_object, property_changed); // expectation is there will be a result for each of the object_properties_holders BST_CHECK_EQUAL(3, output.as_array().size()); @@ -1474,8 +1529,14 @@ BST_TEST_CASE(testModifyRebuildableBlock) bool get_read_only_modification_allow_list_called = false; bool remove_device_model_object_called = false; bool create_device_model_object_called = false; + bool property_changed_called = true; // callback stubs + nmos::control_protocol_property_changed_handler property_changed = [&](const nmos::resource& resource, const utility::string_t& property_name, int index) + { + property_changed_called = true; + }; + nmos::get_read_only_modification_allow_list_handler get_read_only_modification_allow_list = [&](const nmos::resources& resources, const nmos::resource& resource, const std::vector& target_role_path, const std::vector& property_ids) { get_read_only_modification_allow_list_called = true; @@ -1503,12 +1564,13 @@ BST_TEST_CASE(testModifyRebuildableBlock) const auto oid_property_descriptor = nmos::nc::details::make_property_descriptor(U("oid"), nmos::nc_object_oid_property_id, nmos::fields::nc::oid, U("NcOid"), true, false, false, false, web::json::value::null()); const auto class_id_property_descriptor = nmos::nc::details::make_property_descriptor(U("classId"), nmos::nc_object_class_id_property_id, nmos::fields::nc::class_id, U("NcClassId"), true, false, false, false, web::json::value::null()); - // No class id specified in the objet properties holder for new monitor causes an error + // No class id specified in the object properties holder for new monitor causes an error { auto monitor_3_oid = 999; // Create Object Properties Holder for Block, with a Property Holder for the block members auto object_properties_holders = value::array(); auto block_property_holders = value::array(); + property_changed_called = false; const auto role_path = value_of({ U("root"), U("receivers") }); { auto members = value::array(); @@ -1548,7 +1610,7 @@ BST_TEST_CASE(testModifyRebuildableBlock) const auto resource = nmos::nc::find_resource_by_role_path(resources, target_role_path.as_array()); // allowed member classes specified for block but no class_id property holder in the new monitor object properties holder - const auto object_set_validations = nmos::details::modify_rebuildable_block(resources, object_properties_holder_map, *resource, target_role_path.as_array(), block_object_properties_holder, validate, get_control_protocol_class_descriptor, remove_device_model_object, create_device_model_object); + const auto object_set_validations = nmos::details::modify_rebuildable_block(resources, object_properties_holder_map, *resource, target_role_path.as_array(), block_object_properties_holder, validate, get_control_protocol_class_descriptor, remove_device_model_object, create_device_model_object, property_changed); BST_REQUIRE_EQUAL(object_set_validations.size(), 2); { @@ -1560,6 +1622,7 @@ BST_TEST_CASE(testModifyRebuildableBlock) const auto& object_properties_set_validation = object_set_validations.at(1); BST_CHECK_EQUAL(nmos::nc_restore_validation_status::failed, nmos::fields::nc::status(object_properties_set_validation)); } + BST_CHECK(!property_changed_called); } // add class id to the property holders, but use a disallowed class id @@ -1568,6 +1631,7 @@ BST_TEST_CASE(testModifyRebuildableBlock) // Create Object Properties Holder for Block, with a Property Holder for the block members auto object_properties_holders = value::array(); auto block_property_holders = value::array(); + property_changed_called = false; const auto role_path = value_of({ U("root"), U("receivers") }); { auto members = value::array(); @@ -1607,7 +1671,7 @@ BST_TEST_CASE(testModifyRebuildableBlock) const auto resource = nmos::nc::find_resource_by_role_path(resources, target_role_path.as_array()); // allowed member classes specified for block but class_id property holder has disallowed class_id - const auto object_set_validations = nmos::details::modify_rebuildable_block(resources, object_properties_holder_map, *resource, target_role_path.as_array(), block_object_properties_holder, validate, get_control_protocol_class_descriptor, remove_device_model_object, create_device_model_object); + const auto object_set_validations = nmos::details::modify_rebuildable_block(resources, object_properties_holder_map, *resource, target_role_path.as_array(), block_object_properties_holder, validate, get_control_protocol_class_descriptor, remove_device_model_object, create_device_model_object, property_changed); BST_REQUIRE_EQUAL(object_set_validations.size(), 2); { @@ -1619,6 +1683,7 @@ BST_TEST_CASE(testModifyRebuildableBlock) const auto& object_properties_set_validation = object_set_validations.at(1); BST_CHECK_EQUAL(nmos::nc_restore_validation_status::failed, nmos::fields::nc::status(object_properties_set_validation)); } + BST_CHECK(!property_changed_called); } // add class id to the property holders, and use an allowed class id @@ -1627,6 +1692,7 @@ BST_TEST_CASE(testModifyRebuildableBlock) // Create Object Properties Holder for Block, with a Property Holder for the block members auto object_properties_holders = value::array(); auto block_property_holders = value::array(); + property_changed_called = false; const auto role_path = value_of({ U("root"), U("receivers") }); { auto members = value::array(); @@ -1653,7 +1719,7 @@ BST_TEST_CASE(testModifyRebuildableBlock) push_back(object_properties_holders, nmos::nc::details::make_object_properties_holder(monitor_3_role_path.as_array(), monitor3_property_holders.as_array(), value::array().as_array(), value::array().as_array(), false)); } const auto target_role_path = value_of({ U("root"), U("receivers") }); - bool validate = true; + bool validate = false; const value restore_mode{ nmos::nc_restore_mode::restore_mode::rebuild }; nmos::object_properties_map object_properties_holder_map; @@ -1665,8 +1731,8 @@ BST_TEST_CASE(testModifyRebuildableBlock) } const auto resource = nmos::nc::find_resource_by_role_path(resources, target_role_path.as_array()); - // allowed member classes specified for block but class_id property holder has disallowed class_id - const auto object_set_validations = nmos::details::modify_rebuildable_block(resources, object_properties_holder_map, *resource, target_role_path.as_array(), block_object_properties_holder, validate, get_control_protocol_class_descriptor, remove_device_model_object, create_device_model_object); + // allowed member classes specified for block and class_id property holder is allowed class_id + const auto object_set_validations = nmos::details::modify_rebuildable_block(resources, object_properties_holder_map, *resource, target_role_path.as_array(), block_object_properties_holder, validate, get_control_protocol_class_descriptor, remove_device_model_object, create_device_model_object, property_changed); BST_REQUIRE_EQUAL(object_set_validations.size(), 2); { @@ -1678,5 +1744,6 @@ BST_TEST_CASE(testModifyRebuildableBlock) const auto& object_properties_set_validation = object_set_validations.at(1); BST_CHECK_EQUAL(nmos::nc_restore_validation_status::ok, nmos::fields::nc::status(object_properties_set_validation)); } + BST_CHECK(property_changed_called); } }