net: lwm2m: fix observation path list ordering
under certain conditions the current implementation did not maintain the desired sort order. Signed-off-by: Pascal Brogle <pascal.brogle@husqvarnagroup.com>
This commit is contained in:
parent
35bd427927
commit
6ac281887c
6 changed files with 639 additions and 36 deletions
|
@ -1499,7 +1499,9 @@ int lwm2m_engine_add_path_to_list(sys_slist_t *lwm2m_path_list, sys_slist_t *lwm
|
||||||
new_entry->path = *path;
|
new_entry->path = *path;
|
||||||
if (!sys_slist_is_empty(lwm2m_path_list)) {
|
if (!sys_slist_is_empty(lwm2m_path_list)) {
|
||||||
|
|
||||||
/* Keep list Ordered by Object ID/ Object instance/ resource ID */
|
/* Keep list Ordered by Object ID / Object instance / resource ID /
|
||||||
|
* Resource Instance ID
|
||||||
|
*/
|
||||||
SYS_SLIST_FOR_EACH_CONTAINER(lwm2m_path_list, entry, node) {
|
SYS_SLIST_FOR_EACH_CONTAINER(lwm2m_path_list, entry, node) {
|
||||||
if (entry->path.level == LWM2M_PATH_LEVEL_NONE ||
|
if (entry->path.level == LWM2M_PATH_LEVEL_NONE ||
|
||||||
lwm2m_obj_path_equal(&entry->path, &new_entry->path)) {
|
lwm2m_obj_path_equal(&entry->path, &new_entry->path)) {
|
||||||
|
@ -1508,39 +1510,63 @@ int lwm2m_engine_add_path_to_list(sys_slist_t *lwm2m_path_list, sys_slist_t *lwm
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry->path.obj_id > path->obj_id) {
|
/*
|
||||||
/* New entry have smaller Object ID */
|
* algorithm assumes that list is already properly sorted and that
|
||||||
add_before_current = true;
|
* there are no duplicates. general idea:
|
||||||
} else if (entry->path.obj_id == path->obj_id &&
|
* - if at any level up to new entry's path level, IDs below the level
|
||||||
entry->path.level > path->level) {
|
* match and the ID of the new entry at that level is smaller,
|
||||||
add_before_current = true;
|
* insert before.
|
||||||
} else if (entry->path.obj_id == path->obj_id &&
|
* - if all IDs of the new entry match the existing entry, insert before.
|
||||||
entry->path.level == path->level) {
|
* Because of sorting and no duplicates, the existing entry must have
|
||||||
if (path->level >= LWM2M_PATH_LEVEL_OBJECT_INST &&
|
* higher path level and come after the new entry.
|
||||||
entry->path.obj_inst_id > path->obj_inst_id) {
|
*/
|
||||||
/*
|
switch (new_entry->path.level) {
|
||||||
* New have same Object ID
|
case LWM2M_PATH_LEVEL_OBJECT:
|
||||||
* but smaller Object Instance ID
|
add_before_current = new_entry->path.obj_id <= entry->path.obj_id;
|
||||||
*/
|
break;
|
||||||
add_before_current = true;
|
|
||||||
} else if (path->level >= LWM2M_PATH_LEVEL_RESOURCE &&
|
case LWM2M_PATH_LEVEL_OBJECT_INST:
|
||||||
entry->path.obj_inst_id == path->obj_inst_id &&
|
add_before_current =
|
||||||
entry->path.res_id > path->res_id) {
|
(new_entry->path.obj_id < entry->path.obj_id) ||
|
||||||
/*
|
|
||||||
* Object ID and Object Instance id same
|
(entry->path.level >= LWM2M_PATH_LEVEL_OBJECT_INST &&
|
||||||
* but Resource ID is smaller
|
entry->path.obj_id == new_entry->path.obj_id &&
|
||||||
*/
|
new_entry->path.obj_inst_id <= entry->path.obj_inst_id);
|
||||||
add_before_current = true;
|
break;
|
||||||
} else if (path->level >= LWM2M_PATH_LEVEL_RESOURCE_INST &&
|
|
||||||
entry->path.obj_inst_id == path->obj_inst_id &&
|
case LWM2M_PATH_LEVEL_RESOURCE:
|
||||||
entry->path.res_id == path->res_id &&
|
add_before_current =
|
||||||
entry->path.res_inst_id > path->res_inst_id) {
|
(new_entry->path.obj_id < entry->path.obj_id) ||
|
||||||
/*
|
|
||||||
* Object ID, Object Instance id & Resource ID same
|
(entry->path.level >= LWM2M_PATH_LEVEL_OBJECT_INST &&
|
||||||
* but Resource instance ID is smaller
|
entry->path.obj_id == new_entry->path.obj_id &&
|
||||||
*/
|
new_entry->path.obj_inst_id < entry->path.obj_inst_id) ||
|
||||||
add_before_current = true;
|
|
||||||
}
|
(entry->path.level >= LWM2M_PATH_LEVEL_RESOURCE &&
|
||||||
|
entry->path.obj_id == new_entry->path.obj_id &&
|
||||||
|
entry->path.obj_inst_id == new_entry->path.obj_inst_id &&
|
||||||
|
new_entry->path.res_id <= entry->path.res_id);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LWM2M_PATH_LEVEL_RESOURCE_INST:
|
||||||
|
add_before_current =
|
||||||
|
(new_entry->path.obj_id < entry->path.obj_id) ||
|
||||||
|
|
||||||
|
(entry->path.level >= LWM2M_PATH_LEVEL_OBJECT_INST &&
|
||||||
|
entry->path.obj_id == new_entry->path.obj_id &&
|
||||||
|
new_entry->path.obj_inst_id < entry->path.obj_inst_id) ||
|
||||||
|
|
||||||
|
(entry->path.level >= LWM2M_PATH_LEVEL_RESOURCE &&
|
||||||
|
entry->path.obj_id == new_entry->path.obj_id &&
|
||||||
|
entry->path.obj_inst_id == new_entry->path.obj_inst_id &&
|
||||||
|
new_entry->path.res_id < entry->path.res_id) ||
|
||||||
|
|
||||||
|
(entry->path.level >= LWM2M_PATH_LEVEL_RESOURCE_INST &&
|
||||||
|
entry->path.obj_id == new_entry->path.obj_id &&
|
||||||
|
entry->path.obj_inst_id == new_entry->path.obj_inst_id &&
|
||||||
|
entry->path.res_id == new_entry->path.res_id &&
|
||||||
|
new_entry->path.res_inst_id <= entry->path.res_inst_id);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (add_before_current) {
|
if (add_before_current) {
|
||||||
|
|
|
@ -61,13 +61,29 @@ struct lwm2m_obj_path_list {
|
||||||
void lwm2m_engine_path_list_init(sys_slist_t *lwm2m_path_list, sys_slist_t *lwm2m_free_list,
|
void lwm2m_engine_path_list_init(sys_slist_t *lwm2m_path_list, sys_slist_t *lwm2m_free_list,
|
||||||
struct lwm2m_obj_path_list path_object_buf[],
|
struct lwm2m_obj_path_list path_object_buf[],
|
||||||
uint8_t path_object_size);
|
uint8_t path_object_size);
|
||||||
/* Add new Path to the list */
|
/**
|
||||||
|
* Add new path to the list while maintaining hierarchical sort order
|
||||||
|
*
|
||||||
|
* @param lwm2m_path_list sorted path list
|
||||||
|
* @param lwm2m_free_list free list
|
||||||
|
* @param path path to be added
|
||||||
|
* @return 0 on success or a negative error code
|
||||||
|
*/
|
||||||
int lwm2m_engine_add_path_to_list(sys_slist_t *lwm2m_path_list, sys_slist_t *lwm2m_free_list,
|
int lwm2m_engine_add_path_to_list(sys_slist_t *lwm2m_path_list, sys_slist_t *lwm2m_free_list,
|
||||||
struct lwm2m_obj_path *path);
|
struct lwm2m_obj_path *path);
|
||||||
|
|
||||||
int lwm2m_get_path_reference_ptr(struct lwm2m_engine_obj *obj, struct lwm2m_obj_path *path,
|
int lwm2m_get_path_reference_ptr(struct lwm2m_engine_obj *obj, struct lwm2m_obj_path *path,
|
||||||
void **ref);
|
void **ref);
|
||||||
/* Remove paths when parent already exist in the list. */
|
|
||||||
|
/**
|
||||||
|
* Remove paths when parent already exists in the list
|
||||||
|
*
|
||||||
|
* @note Path list must be sorted
|
||||||
|
* @see lwm2m_engine_add_path_to_list()
|
||||||
|
*
|
||||||
|
* @param lwm2m_path_list sorted path list
|
||||||
|
* @param lwm2m_free_list free list
|
||||||
|
*/
|
||||||
void lwm2m_engine_clear_duplicate_path(sys_slist_t *lwm2m_path_list, sys_slist_t *lwm2m_free_list);
|
void lwm2m_engine_clear_duplicate_path(sys_slist_t *lwm2m_path_list, sys_slist_t *lwm2m_free_list);
|
||||||
|
|
||||||
/* Resources */
|
/* Resources */
|
||||||
|
|
12
tests/net/lib/lwm2m/engine/CMakeLists.txt
Normal file
12
tests/net/lib/lwm2m/engine/CMakeLists.txt
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.20.0)
|
||||||
|
|
||||||
|
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||||
|
project(lwm2m_engine)
|
||||||
|
|
||||||
|
target_include_directories(app PRIVATE
|
||||||
|
${ZEPHYR_BASE}/subsys/net/lib/lwm2m
|
||||||
|
)
|
||||||
|
FILE(GLOB app_sources src/*.c)
|
||||||
|
target_sources(app PRIVATE ${app_sources})
|
11
tests/net/lib/lwm2m/engine/prj.conf
Normal file
11
tests/net/lib/lwm2m/engine/prj.conf
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
CONFIG_NETWORKING=y
|
||||||
|
CONFIG_NET_TEST=y
|
||||||
|
CONFIG_ZTEST=y
|
||||||
|
CONFIG_ZTEST_NEW_API=y
|
||||||
|
|
||||||
|
CONFIG_ENTROPY_GENERATOR=y
|
||||||
|
CONFIG_TEST_RANDOM_GENERATOR=y
|
||||||
|
CONFIG_NEWLIB_LIBC=y
|
||||||
|
|
||||||
|
CONFIG_LWM2M=y
|
||||||
|
CONFIG_LWM2M_COAP_MAX_MSG_SIZE=512
|
532
tests/net/lib/lwm2m/engine/src/lwm2m_observation.c
Normal file
532
tests/net/lib/lwm2m/engine/src/lwm2m_observation.c
Normal file
|
@ -0,0 +1,532 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 GARDENA GmbH
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lwm2m_engine.h"
|
||||||
|
#include "lwm2m_util.h"
|
||||||
|
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/ztest.h>
|
||||||
|
|
||||||
|
#define TEST_VERBOSE 0
|
||||||
|
|
||||||
|
#if TEST_VERBOSE
|
||||||
|
#define TEST_VERBOSE_PRINT(fmt, ...) TC_PRINT(fmt, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define TEST_VERBOSE_PRINT(fmt, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static bool lwm2m_path_object_equal_upto(struct lwm2m_obj_path *path,
|
||||||
|
struct lwm2m_obj_path *compare_path, uint8_t level)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (level >= LWM2M_PATH_LEVEL_OBJECT && path->obj_id != compare_path->obj_id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (level >= LWM2M_PATH_LEVEL_OBJECT_INST &&
|
||||||
|
path->obj_inst_id != compare_path->obj_inst_id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (level >= LWM2M_PATH_LEVEL_RESOURCE && path->res_id != compare_path->res_id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (level >= LWM2M_PATH_LEVEL_RESOURCE_INST &&
|
||||||
|
path->res_inst_id != compare_path->res_inst_id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assert_path_list_order(sys_slist_t *lwm2m_path_list)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct lwm2m_obj_path_list *prev = NULL;
|
||||||
|
struct lwm2m_obj_path_list *entry, *tmp;
|
||||||
|
|
||||||
|
uint16_t obj_id_max;
|
||||||
|
uint16_t obj_inst_id_max;
|
||||||
|
uint16_t res_id_max;
|
||||||
|
uint16_t res_inst_id_max;
|
||||||
|
|
||||||
|
char next_path_str[LWM2M_MAX_PATH_STR_LEN];
|
||||||
|
char prev_path_str[LWM2M_MAX_PATH_STR_LEN];
|
||||||
|
|
||||||
|
if (sys_slist_is_empty(lwm2m_path_list)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(lwm2m_path_list, entry, tmp, node) {
|
||||||
|
if (prev) {
|
||||||
|
if (entry->path.level > prev->path.level) {
|
||||||
|
|
||||||
|
lwm2m_path_to_string(next_path_str, sizeof(next_path_str),
|
||||||
|
&entry->path, entry->path.level);
|
||||||
|
lwm2m_path_to_string(prev_path_str, sizeof(prev_path_str),
|
||||||
|
&prev->path, prev->path.level);
|
||||||
|
|
||||||
|
bool is_after = false;
|
||||||
|
|
||||||
|
if (prev->path.level >= LWM2M_PATH_LEVEL_OBJECT) {
|
||||||
|
is_after = entry->path.obj_id >= prev->path.obj_id;
|
||||||
|
}
|
||||||
|
if (is_after && prev->path.level >= LWM2M_PATH_LEVEL_OBJECT_INST &&
|
||||||
|
entry->path.obj_id == prev->path.obj_id) {
|
||||||
|
is_after =
|
||||||
|
entry->path.obj_inst_id >= prev->path.obj_inst_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_after && prev->path.level >= LWM2M_PATH_LEVEL_RESOURCE &&
|
||||||
|
entry->path.obj_inst_id == prev->path.obj_inst_id) {
|
||||||
|
is_after = entry->path.res_id >= prev->path.res_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_after &&
|
||||||
|
prev->path.level >= LWM2M_PATH_LEVEL_RESOURCE_INST &&
|
||||||
|
entry->path.res_id == prev->path.res_id) {
|
||||||
|
is_after =
|
||||||
|
entry->path.res_inst_id >= prev->path.res_inst_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
zassert_true(is_after, "Next element %s must be before previous %s",
|
||||||
|
next_path_str, prev_path_str);
|
||||||
|
} else if (entry->path.level == prev->path.level) {
|
||||||
|
|
||||||
|
if (entry->path.level >= LWM2M_PATH_LEVEL_OBJECT) {
|
||||||
|
zassert_true(entry->path.obj_id >= obj_id_max,
|
||||||
|
"Next element has object %d which is smaller "
|
||||||
|
"than previous max object %d",
|
||||||
|
entry->path.obj_id, obj_id_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->path.level >= LWM2M_PATH_LEVEL_OBJECT_INST) {
|
||||||
|
if (!lwm2m_path_object_equal_upto(
|
||||||
|
&entry->path, &prev->path,
|
||||||
|
LWM2M_PATH_LEVEL_OBJECT)) {
|
||||||
|
/* reset max id when path changed */
|
||||||
|
obj_inst_id_max = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
zassert_true(entry->path.obj_inst_id >= obj_inst_id_max,
|
||||||
|
"Next element has object instance %d which is "
|
||||||
|
"smaller "
|
||||||
|
"than previous max object instance %d",
|
||||||
|
entry->path.obj_inst_id, obj_inst_id_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->path.level >= LWM2M_PATH_LEVEL_RESOURCE) {
|
||||||
|
if (!lwm2m_path_object_equal_upto(
|
||||||
|
&entry->path, &prev->path,
|
||||||
|
LWM2M_PATH_LEVEL_OBJECT_INST)) {
|
||||||
|
/* reset max id when path changed */
|
||||||
|
res_id_max = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
zassert_true(
|
||||||
|
entry->path.res_id >= res_id_max,
|
||||||
|
"Next element has resource %d which is smaller "
|
||||||
|
"than previous max resource %d",
|
||||||
|
entry->path.res_id, res_id_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->path.level >= LWM2M_PATH_LEVEL_RESOURCE_INST) {
|
||||||
|
if (!lwm2m_path_object_equal_upto(
|
||||||
|
&entry->path, &prev->path,
|
||||||
|
LWM2M_PATH_LEVEL_RESOURCE)) {
|
||||||
|
/* reset max id when path changed */
|
||||||
|
res_inst_id_max = 0;
|
||||||
|
}
|
||||||
|
zassert_true(entry->path.res_inst_id >= res_inst_id_max,
|
||||||
|
"Next element has resource instance %d which "
|
||||||
|
"is smaller "
|
||||||
|
"than previous max resource instance %d",
|
||||||
|
entry->path.res_inst_id, res_inst_id_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else { /* entry->path.level < prev->path.level */
|
||||||
|
if (entry->path.level >= LWM2M_PATH_LEVEL_OBJECT) {
|
||||||
|
zassert_true(entry->path.obj_id >= obj_id_max,
|
||||||
|
"Next element has object %d which is smaller "
|
||||||
|
"than previous max object %d",
|
||||||
|
entry->path.obj_id, obj_id_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->path.level >= LWM2M_PATH_LEVEL_OBJECT_INST) {
|
||||||
|
zassert_true(entry->path.obj_inst_id >= obj_inst_id_max,
|
||||||
|
"Next element has object instance %d which is "
|
||||||
|
"smaller "
|
||||||
|
"than previous max object instance %d",
|
||||||
|
entry->path.obj_inst_id, obj_inst_id_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->path.level >= LWM2M_PATH_LEVEL_RESOURCE) {
|
||||||
|
zassert_true(
|
||||||
|
entry->path.res_id >= res_id_max,
|
||||||
|
"Next element has resource %d which is smaller "
|
||||||
|
"than previous max resource %d",
|
||||||
|
entry->path.res_id, res_id_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->path.level >= LWM2M_PATH_LEVEL_RESOURCE_INST) {
|
||||||
|
zassert_true(entry->path.res_inst_id >= res_inst_id_max,
|
||||||
|
"Next element has resource instance %d which "
|
||||||
|
"is bigger "
|
||||||
|
"than previous max resource instance %d",
|
||||||
|
entry->path.res_inst_id, res_inst_id_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
zassert_true(!lwm2m_path_object_equal_upto(
|
||||||
|
&entry->path, &prev->path, entry->path.level),
|
||||||
|
"Next element equals previous up to level %d "
|
||||||
|
"and thus must be before previous",
|
||||||
|
entry->path.level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->path.level >= LWM2M_PATH_LEVEL_OBJECT) {
|
||||||
|
obj_id_max = entry->path.obj_id;
|
||||||
|
} else {
|
||||||
|
obj_id_max = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->path.level >= LWM2M_PATH_LEVEL_OBJECT_INST &&
|
||||||
|
(prev == NULL || entry->path.obj_id == prev->path.obj_id)) {
|
||||||
|
obj_inst_id_max = entry->path.obj_inst_id;
|
||||||
|
} else {
|
||||||
|
obj_inst_id_max = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->path.level >= LWM2M_PATH_LEVEL_RESOURCE &&
|
||||||
|
(prev == NULL || entry->path.obj_id == prev->path.obj_id) &&
|
||||||
|
(prev == NULL || entry->path.obj_inst_id == prev->path.obj_inst_id)) {
|
||||||
|
res_id_max = entry->path.res_id;
|
||||||
|
} else {
|
||||||
|
res_id_max = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->path.level >= LWM2M_PATH_LEVEL_RESOURCE_INST &&
|
||||||
|
(prev == NULL || entry->path.obj_id == prev->path.obj_id) &&
|
||||||
|
(prev == NULL || entry->path.obj_inst_id == prev->path.obj_inst_id) &&
|
||||||
|
(prev == NULL || entry->path.res_id == prev->path.res_id)) {
|
||||||
|
res_inst_id_max = entry->path.res_inst_id;
|
||||||
|
} else {
|
||||||
|
res_inst_id_max = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev = entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void print_path_list(sys_slist_t *lwm2m_path_list, const char *name)
|
||||||
|
{
|
||||||
|
struct lwm2m_obj_path_list *entry, *tmp;
|
||||||
|
|
||||||
|
if (name != NULL) {
|
||||||
|
TEST_VERBOSE_PRINT("Path List %s:\n", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(lwm2m_path_list, entry, tmp, node) {
|
||||||
|
char buf[LWM2M_MAX_PATH_STR_LEN];
|
||||||
|
|
||||||
|
lwm2m_path_to_string(buf, LWM2M_MAX_PATH_STR_LEN, &entry->path, entry->path.level);
|
||||||
|
TEST_VERBOSE_PRINT("- %s\n", buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void run_insertion_test(char const *insert_path_str[], int insertions_count,
|
||||||
|
char const *expected_path_str[])
|
||||||
|
{
|
||||||
|
/* GIVEN: different paths */
|
||||||
|
struct lwm2m_obj_path_list lwm2m_path_list_buf[insertions_count];
|
||||||
|
sys_slist_t lwm2m_path_list;
|
||||||
|
sys_slist_t lwm2m_path_free_list;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
lwm2m_engine_path_list_init(&lwm2m_path_list, &lwm2m_path_free_list, lwm2m_path_list_buf,
|
||||||
|
insertions_count);
|
||||||
|
|
||||||
|
/* WHEN: inserting each path */
|
||||||
|
struct lwm2m_obj_path insert_path;
|
||||||
|
char name[20];
|
||||||
|
|
||||||
|
for (int i = 0; i < insertions_count; ++i) {
|
||||||
|
ret = lwm2m_string_to_path(insert_path_str[i], &insert_path, '/');
|
||||||
|
zassert_true(ret >= 0, "Conversion to path #%d failed", i);
|
||||||
|
|
||||||
|
ret = lwm2m_engine_add_path_to_list(&lwm2m_path_list, &lwm2m_path_free_list,
|
||||||
|
&insert_path);
|
||||||
|
|
||||||
|
sprintf(name, "Insertion: %d", i);
|
||||||
|
print_path_list(&lwm2m_path_list, name);
|
||||||
|
zassert_true(ret >= 0, "Insertion #%d failed", i);
|
||||||
|
/* THEN: path order is maintained */
|
||||||
|
assert_path_list_order(&lwm2m_path_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
print_path_list(&lwm2m_path_list, "Final");
|
||||||
|
|
||||||
|
/* AND: final list matches expectation */
|
||||||
|
struct lwm2m_obj_path_list *entry, *tmp;
|
||||||
|
int path_num = 0;
|
||||||
|
|
||||||
|
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&lwm2m_path_list, entry, tmp, node) {
|
||||||
|
struct lwm2m_obj_path expected_path;
|
||||||
|
|
||||||
|
lwm2m_string_to_path(expected_path_str[path_num++], &expected_path, '/');
|
||||||
|
zassert_mem_equal(&entry->path, &expected_path, sizeof(struct lwm2m_obj_path),
|
||||||
|
"Path #%d did not match expectation", path_num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ZTEST(lwm2m_observation, test_add_path_to_list)
|
||||||
|
{
|
||||||
|
/* clang-format off */
|
||||||
|
char const *insert_path_str[] = {
|
||||||
|
LWM2M_PATH(2),
|
||||||
|
LWM2M_PATH(1),
|
||||||
|
LWM2M_PATH(1, 2),
|
||||||
|
LWM2M_PATH(1, 1),
|
||||||
|
LWM2M_PATH(1, 1, 10),
|
||||||
|
LWM2M_PATH(1, 1, 10, 10),
|
||||||
|
LWM2M_PATH(1, 1, 10, 9),
|
||||||
|
LWM2M_PATH(1, 2, 10, 11),
|
||||||
|
|
||||||
|
LWM2M_PATH(100),
|
||||||
|
|
||||||
|
LWM2M_PATH(41),
|
||||||
|
LWM2M_PATH(43, 3),
|
||||||
|
LWM2M_PATH(45, 2, 2),
|
||||||
|
LWM2M_PATH(47, 1, 1, 1),
|
||||||
|
|
||||||
|
LWM2M_PATH(57, 1, 1, 1),
|
||||||
|
LWM2M_PATH(55, 2, 2),
|
||||||
|
LWM2M_PATH(53, 3),
|
||||||
|
LWM2M_PATH(51),
|
||||||
|
};
|
||||||
|
|
||||||
|
char const *expected_path_str[] = {
|
||||||
|
LWM2M_PATH(1),
|
||||||
|
LWM2M_PATH(1, 1),
|
||||||
|
LWM2M_PATH(1, 1, 10),
|
||||||
|
LWM2M_PATH(1, 1, 10, 9),
|
||||||
|
LWM2M_PATH(1, 1, 10, 10),
|
||||||
|
LWM2M_PATH(1, 2),
|
||||||
|
LWM2M_PATH(1, 2, 10, 11),
|
||||||
|
LWM2M_PATH(2),
|
||||||
|
LWM2M_PATH(41),
|
||||||
|
LWM2M_PATH(43, 3),
|
||||||
|
LWM2M_PATH(45, 2, 2),
|
||||||
|
LWM2M_PATH(47, 1, 1, 1),
|
||||||
|
LWM2M_PATH(51),
|
||||||
|
LWM2M_PATH(53, 3),
|
||||||
|
LWM2M_PATH(55, 2, 2),
|
||||||
|
LWM2M_PATH(57, 1, 1, 1),
|
||||||
|
LWM2M_PATH(100),
|
||||||
|
};
|
||||||
|
/* clang-format on */
|
||||||
|
|
||||||
|
run_insertion_test(insert_path_str, ARRAY_SIZE(insert_path_str), expected_path_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZTEST(lwm2m_observation, test_add_path_to_list_inverse_non_overlapping)
|
||||||
|
{
|
||||||
|
/* clang-format off */
|
||||||
|
char const *insert_path_str[] = {
|
||||||
|
LWM2M_PATH(41),
|
||||||
|
LWM2M_PATH(43, 3),
|
||||||
|
LWM2M_PATH(45, 2, 2),
|
||||||
|
LWM2M_PATH(47, 1, 1, 1),
|
||||||
|
};
|
||||||
|
|
||||||
|
char const *expected_path_str[] = {
|
||||||
|
LWM2M_PATH(41),
|
||||||
|
LWM2M_PATH(43, 3),
|
||||||
|
LWM2M_PATH(45, 2, 2),
|
||||||
|
LWM2M_PATH(47, 1, 1, 1),
|
||||||
|
};
|
||||||
|
/* clang-format on */
|
||||||
|
|
||||||
|
run_insertion_test(insert_path_str, ARRAY_SIZE(insert_path_str), expected_path_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZTEST(lwm2m_observation, test_add_path_to_list_inverse_non_overlapping_2)
|
||||||
|
{
|
||||||
|
/* clang-format off */
|
||||||
|
char const *insert_path_str[] = {
|
||||||
|
LWM2M_PATH(57, 1, 1, 1),
|
||||||
|
LWM2M_PATH(55, 2, 2),
|
||||||
|
LWM2M_PATH(53, 3),
|
||||||
|
LWM2M_PATH(51),
|
||||||
|
};
|
||||||
|
|
||||||
|
char const *expected_path_str[] = {
|
||||||
|
LWM2M_PATH(51),
|
||||||
|
LWM2M_PATH(53, 3),
|
||||||
|
LWM2M_PATH(55, 2, 2),
|
||||||
|
LWM2M_PATH(57, 1, 1, 1),
|
||||||
|
};
|
||||||
|
/* clang-format on */
|
||||||
|
|
||||||
|
run_insertion_test(insert_path_str, ARRAY_SIZE(insert_path_str), expected_path_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZTEST(lwm2m_observation, test_add_path_to_list_object_before_resource_inst)
|
||||||
|
{
|
||||||
|
/* clang-format off */
|
||||||
|
char const *insert_path_str[] = {
|
||||||
|
LWM2M_PATH(1, 1, 1, 1),
|
||||||
|
LWM2M_PATH(1),
|
||||||
|
};
|
||||||
|
|
||||||
|
char const *expected_path_str[6] = {
|
||||||
|
LWM2M_PATH(1),
|
||||||
|
LWM2M_PATH(1, 1, 1, 1),
|
||||||
|
};
|
||||||
|
/* clang-format on */
|
||||||
|
|
||||||
|
run_insertion_test(insert_path_str, ARRAY_SIZE(insert_path_str), expected_path_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZTEST(lwm2m_observation, test_add_path_to_list_object_inst_before_resource_inst)
|
||||||
|
{
|
||||||
|
/* clang-format off */
|
||||||
|
char const *insert_path_str[] = {
|
||||||
|
LWM2M_PATH(1, 1, 1, 1),
|
||||||
|
LWM2M_PATH(1, 1),
|
||||||
|
};
|
||||||
|
|
||||||
|
char const *expected_path_str[6] = {
|
||||||
|
LWM2M_PATH(1, 1),
|
||||||
|
LWM2M_PATH(1, 1, 1, 1),
|
||||||
|
};
|
||||||
|
/* clang-format on */
|
||||||
|
|
||||||
|
run_insertion_test(insert_path_str, ARRAY_SIZE(insert_path_str), expected_path_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZTEST(lwm2m_observation, test_add_path_to_list_resource_before_resource_inst)
|
||||||
|
{
|
||||||
|
/* clang-format off */
|
||||||
|
char const *insert_path_str[] = {
|
||||||
|
LWM2M_PATH(1, 1, 1, 1),
|
||||||
|
LWM2M_PATH(1, 1, 1),
|
||||||
|
};
|
||||||
|
|
||||||
|
char const *expected_path_str[] = {
|
||||||
|
LWM2M_PATH(1, 1, 1),
|
||||||
|
LWM2M_PATH(1, 1, 1, 1),
|
||||||
|
};
|
||||||
|
/* clang-format on */
|
||||||
|
|
||||||
|
run_insertion_test(insert_path_str, ARRAY_SIZE(insert_path_str), expected_path_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZTEST(lwm2m_observation, test_add_path_to_list_resource_order)
|
||||||
|
{
|
||||||
|
/* clang-format off */
|
||||||
|
char const *insert_path_str[] = {
|
||||||
|
LWM2M_PATH(32765, 1, 6, 0),
|
||||||
|
LWM2M_PATH(32765, 1, 6, 1),
|
||||||
|
LWM2M_PATH(32765, 1, 6),
|
||||||
|
LWM2M_PATH(32765, 1, 5),
|
||||||
|
LWM2M_PATH(32765, 1, 5, 2),
|
||||||
|
LWM2M_PATH(32765, 1, 5, 1),
|
||||||
|
};
|
||||||
|
|
||||||
|
char const *expected_path_str[] = {
|
||||||
|
LWM2M_PATH(32765, 1, 5),
|
||||||
|
LWM2M_PATH(32765, 1, 5, 1),
|
||||||
|
LWM2M_PATH(32765, 1, 5, 2),
|
||||||
|
LWM2M_PATH(32765, 1, 6),
|
||||||
|
LWM2M_PATH(32765, 1, 6, 0),
|
||||||
|
LWM2M_PATH(32765, 1, 6, 1),
|
||||||
|
};
|
||||||
|
/* clang-format on */
|
||||||
|
|
||||||
|
run_insertion_test(insert_path_str, ARRAY_SIZE(insert_path_str), expected_path_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZTEST(lwm2m_observation, test_add_path_to_list_resource_before_instance)
|
||||||
|
{
|
||||||
|
/* clang-format off */
|
||||||
|
char const *insert_path_str[] = {
|
||||||
|
LWM2M_PATH(32765, 1, 6, 0),
|
||||||
|
LWM2M_PATH(32765, 1, 6, 1),
|
||||||
|
LWM2M_PATH(32765, 1, 6),
|
||||||
|
};
|
||||||
|
|
||||||
|
char const *expected_path_str[6] = {
|
||||||
|
LWM2M_PATH(32765, 1, 6),
|
||||||
|
LWM2M_PATH(32765, 1, 6, 0),
|
||||||
|
LWM2M_PATH(32765, 1, 6, 1),
|
||||||
|
};
|
||||||
|
/* clang-format on */
|
||||||
|
|
||||||
|
run_insertion_test(insert_path_str, ARRAY_SIZE(insert_path_str), expected_path_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZTEST(lwm2m_observation, test_add_path_to_list_resource_inverse)
|
||||||
|
{
|
||||||
|
/* clang-format off */
|
||||||
|
char const *insert_path_str[] = {
|
||||||
|
LWM2M_PATH(1, 1, 1, 1),
|
||||||
|
LWM2M_PATH(1, 1, 1),
|
||||||
|
LWM2M_PATH(1, 1),
|
||||||
|
LWM2M_PATH(1),
|
||||||
|
};
|
||||||
|
|
||||||
|
char const *expected_path_str[] = {
|
||||||
|
LWM2M_PATH(1),
|
||||||
|
LWM2M_PATH(1, 1),
|
||||||
|
LWM2M_PATH(1, 1, 1),
|
||||||
|
LWM2M_PATH(1, 1, 1, 1),
|
||||||
|
};
|
||||||
|
/* clang-format on */
|
||||||
|
|
||||||
|
run_insertion_test(insert_path_str, ARRAY_SIZE(insert_path_str), expected_path_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZTEST(lwm2m_observation, test_add_path_to_list_obj_after_resource)
|
||||||
|
{
|
||||||
|
/* clang-format off */
|
||||||
|
char const *insert_path_str[] = {
|
||||||
|
LWM2M_PATH(1),
|
||||||
|
LWM2M_PATH(1, 1),
|
||||||
|
LWM2M_PATH(1, 1, 1),
|
||||||
|
LWM2M_PATH(1, 2),
|
||||||
|
};
|
||||||
|
|
||||||
|
char const *expected_path_str[] = {
|
||||||
|
LWM2M_PATH(1),
|
||||||
|
LWM2M_PATH(1, 1),
|
||||||
|
LWM2M_PATH(1, 1, 1),
|
||||||
|
LWM2M_PATH(1, 2),
|
||||||
|
};
|
||||||
|
/* clang-format on */
|
||||||
|
|
||||||
|
run_insertion_test(insert_path_str, ARRAY_SIZE(insert_path_str), expected_path_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZTEST(lwm2m_observation, test_add_path_to_list_duplicate)
|
||||||
|
{
|
||||||
|
/* clang-format off */
|
||||||
|
char const *insert_path_str[] = {
|
||||||
|
LWM2M_PATH(1),
|
||||||
|
LWM2M_PATH(1, 1),
|
||||||
|
LWM2M_PATH(1),
|
||||||
|
};
|
||||||
|
|
||||||
|
char const *expected_path_str[] = {
|
||||||
|
LWM2M_PATH(1),
|
||||||
|
LWM2M_PATH(1, 1),
|
||||||
|
};
|
||||||
|
/* clang-format on */
|
||||||
|
|
||||||
|
run_insertion_test(insert_path_str, ARRAY_SIZE(insert_path_str), expected_path_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZTEST_SUITE(lwm2m_observation, NULL, NULL, NULL, NULL, NULL);
|
6
tests/net/lib/lwm2m/engine/testcase.yaml
Normal file
6
tests/net/lib/lwm2m/engine/testcase.yaml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
common:
|
||||||
|
depends_on: netif
|
||||||
|
tests:
|
||||||
|
net.lwm2m.engine:
|
||||||
|
platform_allow: native_posix
|
||||||
|
tags: lwm2m net
|
Loading…
Add table
Add a link
Reference in a new issue