Skip to content

Commit b533944

Browse files
MS-05 Device Model Object Validation Util (#471)
* validate_resource utility * Throw exception on badly constructed Device Model object * Apply suggestions from code review * Remove boolean return from void function * Update Development/nmos/control_protocol_utils.cpp * Add guard when getting a property * Validate control protocol object methods. * Update Development/nmos/control_protocol_utils.h --------- Co-authored-by: Simon Lo <simon.lo@sony.com>
1 parent 9d228e9 commit b533944

File tree

4 files changed

+126
-2
lines changed

4 files changed

+126
-2
lines changed

Development/nmos/control_protocol_methods.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ namespace nmos
2424

2525
// find the relevant nc_property_descriptor
2626
const auto& property = nc::find_property_descriptor(details::parse_property_id(property_id), details::parse_class_id(nmos::fields::nc::class_id(resource.data)), get_control_protocol_class_descriptor);
27-
if (!property.is_null())
27+
if (!property.is_null() && resource.data.has_field(nmos::fields::nc::name(property)))
2828
{
2929
return details::make_method_result({is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok}, resource.data.at(nmos::fields::nc::name(property)));
3030
}

Development/nmos/control_protocol_utils.cpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -985,6 +985,28 @@ namespace nmos
985985
}
986986
}
987987

988+
// Validate that the resource has been correctly constructed according to the class_descriptor
989+
void validate_resource(const resource& resource, const experimental::control_class_descriptor& class_descriptor)
990+
{
991+
// Validate properties
992+
for (const auto& property_descriptor : class_descriptor.property_descriptors.as_array())
993+
{
994+
if ((resource.data.is_null()) || (!resource.data.has_field(nmos::fields::nc::name(property_descriptor))))
995+
{
996+
throw control_protocol_exception("missing control resource property: " + utility::us2s(nmos::fields::nc::name(property_descriptor)));
997+
}
998+
}
999+
1000+
// Validate methods
1001+
for (const auto& method_descriptor : class_descriptor.method_descriptors)
1002+
{
1003+
if (!method_descriptor.second)
1004+
{
1005+
throw control_protocol_exception("method not implemented: " + utility::us2s(nmos::fields::nc::name(method_descriptor.first)));
1006+
}
1007+
}
1008+
}
1009+
9881010
resources::const_iterator find_resource_by_role_path(const resources& resources, const web::json::array& role_path_)
9891011
{
9901012
auto role_path = role_path_;
@@ -1299,7 +1321,7 @@ namespace nmos
12991321
{
13001322
// A monitor is expected to go through a period of instability upon activation. Therefore, on monitor activation
13011323
// domain specific statuses offering an Inactive option MUST transition immediately to the Healthy state.
1302-
// Furthermore, after activation, as long as the monitor isn’t being deactivated, it MUST delay the reporting
1324+
// Furthermore, after activation, as long as the monitor isn't being deactivated, it MUST delay the reporting
13031325
// of non Healthy states for the duration specified by statusReportingDelay, and then transition to any other appropriate state.
13041326
const auto& found = find_resource(resources, utility::s2us(std::to_string(oid)));
13051327
if (resources.end() != found && nc::is_status_monitor(nc::details::parse_class_id(nmos::fields::nc::class_id(found->data))))

Development/nmos/control_protocol_utils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ namespace nmos
126126
// method parameters constraints validation, may throw nmos::control_protocol_exception
127127
void method_parameters_contraints_validation(const web::json::value& arguments, const web::json::value& nc_method_descriptor, get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor);
128128

129+
// Validate that the resource has been correctly constructed according to the class_descriptor
130+
void validate_resource(const resource& resource, const experimental::control_class_descriptor& class_descriptor);
131+
129132
resources::const_iterator find_touchpoint_resource(const resources& resources, const resource& resource);
130133

131134
// insert 'value changed', 'sequence item added', 'sequence item changed' or 'sequence item removed' notification events into all grains whose subscriptions match the specified version, type and "pre" or "post" values

Development/nmos/test/control_protocol_utils_test.cpp

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,3 +1254,102 @@ BST_TEST_CASE(testFindMembersByClassId)
12541254
BST_REQUIRE_EQUAL(example_class_id_2, nmos::nc::details::parse_class_id(nmos::fields::nc::class_id(members.at(0))));
12551255
}
12561256
}
1257+
1258+
BST_TEST_CASE(testValidateResourceProperties)
1259+
{
1260+
using web::json::value_of;
1261+
using web::json::value;
1262+
1263+
nmos::experimental::control_protocol_state control_protocol_state;
1264+
auto get_control_protocol_class_descriptor = nmos::make_get_control_protocol_class_descriptor_handler(control_protocol_state);
1265+
1266+
auto root_block = nmos::make_root_block();
1267+
auto oid = nmos::root_block_oid;
1268+
// root, ClassManager
1269+
auto class_manager = nmos::make_class_manager(++oid, control_protocol_state);
1270+
auto receiver_block_oid = ++oid;
1271+
// root, receivers
1272+
auto receivers = nmos::make_block(receiver_block_oid, nmos::root_block_oid, U("receivers"), U("Receivers"), U("Receivers block"));
1273+
1274+
// root, receivers, mon1
1275+
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")})} }));
1276+
1277+
auto block_class_descriptor = get_control_protocol_class_descriptor(nmos::nc_block_class_id);
1278+
1279+
BST_CHECK_NO_THROW(nmos::nc::validate_resource(root_block, block_class_descriptor));
1280+
BST_CHECK_NO_THROW(nmos::nc::validate_resource(receivers, block_class_descriptor));
1281+
1282+
auto class_manager_class_descriptor = get_control_protocol_class_descriptor(nmos::nc_class_manager_class_id);
1283+
1284+
BST_CHECK_NO_THROW(nmos::nc::validate_resource(class_manager, class_manager_class_descriptor));
1285+
1286+
auto receiver_monitor_class_descriptor = get_control_protocol_class_descriptor(nmos::nc_receiver_monitor_class_id);
1287+
1288+
BST_CHECK_NO_THROW(nmos::nc::validate_resource(monitor1, receiver_monitor_class_descriptor));
1289+
1290+
// Negative tests
1291+
BST_CHECK_THROW(nmos::nc::validate_resource(root_block, receiver_monitor_class_descriptor), nmos::control_protocol_exception);
1292+
BST_CHECK_THROW(nmos::nc::validate_resource(receivers, class_manager_class_descriptor), nmos::control_protocol_exception);
1293+
BST_CHECK_THROW(nmos::nc::validate_resource(class_manager, block_class_descriptor), nmos::control_protocol_exception);
1294+
BST_CHECK_THROW(nmos::nc::validate_resource(monitor1, block_class_descriptor), nmos::control_protocol_exception);
1295+
}
1296+
1297+
BST_TEST_CASE(testValidateResourceMethods)
1298+
{
1299+
using web::json::value_of;
1300+
using web::json::value;
1301+
1302+
nmos::experimental::control_protocol_state control_protocol_state;
1303+
auto get_control_protocol_class_descriptor = nmos::make_get_control_protocol_class_descriptor_handler(control_protocol_state);
1304+
1305+
auto root_block = nmos::make_root_block();
1306+
1307+
auto example_method_with_no_args = [](nmos::resources& resources, const nmos::resource& resource, const web::json::value& arguments, bool is_deprecated, slog::base_gate& gate)
1308+
{
1309+
return nmos::nc::details::make_method_result({ is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::nc_method_status::ok });
1310+
};
1311+
1312+
auto control_class_id = nmos::nc::make_class_id(nmos::nc_worker_class_id, 0, { 2 });
1313+
// Define class descriptor with method and associated method - should succeed on validate
1314+
{
1315+
std::vector<web::json::value> property_descriptors = {};
1316+
1317+
std::vector<nmos::experimental::method> method_descriptors =
1318+
{
1319+
{ nmos::experimental::make_control_class_method_descriptor(U("Example method with no arguments"), { 3, 1 }, U("MethodNoArgs"), U("NcMethodResult"), {}, false, example_method_with_no_args) }
1320+
};
1321+
1322+
auto control_class_descriptor = nmos::experimental::make_control_class_descriptor(U(""), nmos::nc::make_class_id(nmos::nc_worker_class_id, 0, { 2 }), U("ControlClass"), property_descriptors, method_descriptors, {});
1323+
1324+
auto make_control_object = [&](nmos::nc_oid oid)
1325+
{
1326+
auto data = nmos::nc::details::make_worker(control_class_id, oid, true, 1, U("role"), value::string(U("")), U(""), value::null(), value::null(), true);
1327+
return nmos::control_protocol_resource{ nmos::is12_versions::v1_0, nmos::types::nc_worker, std::move(data), true };
1328+
};
1329+
1330+
auto control_object = make_control_object(3);
1331+
1332+
BST_CHECK_NO_THROW(nmos::nc::validate_resource(control_object, control_class_descriptor));
1333+
}
1334+
// Define class descriptor with method with no associated method - should throw on validate
1335+
{
1336+
std::vector<web::json::value> property_descriptors = {};
1337+
1338+
std::vector<nmos::experimental::method> method_descriptors =
1339+
{
1340+
{ nmos::experimental::make_control_class_method_descriptor(U("Example method with no arguments"), { 3, 1 }, U("MethodNoArgs"), U("NcMethodResult"), {}, false, nullptr) }
1341+
};
1342+
1343+
auto control_class_descriptor = nmos::experimental::make_control_class_descriptor(U(""), nmos::nc::make_class_id(nmos::nc_worker_class_id, 0, { 2 }), U("ControlClass"), property_descriptors, method_descriptors, {});
1344+
1345+
auto make_control_object = [&](nmos::nc_oid oid)
1346+
{
1347+
auto data = nmos::nc::details::make_worker(control_class_id, oid, true, 1, U("role"), value::string(U("")), U(""), value::null(), value::null(), true);
1348+
return nmos::control_protocol_resource{ nmos::is12_versions::v1_0, nmos::types::nc_worker, std::move(data), true };
1349+
};
1350+
1351+
auto control_object = make_control_object(3);
1352+
1353+
BST_CHECK_THROW(nmos::nc::validate_resource(control_object, control_class_descriptor), nmos::control_protocol_exception);
1354+
}
1355+
}

0 commit comments

Comments
 (0)