Skip to content

Commit

Permalink
Fix the response to the restconf depth parameter
Browse files Browse the repository at this point in the history
RFC 8040 section B.3.2 gives examples of how to respond to the
depth parameter on a restconf query. The current output is
not consistent with the example output.
  • Loading branch information
gcampbell512 authored and carlgsmith committed Sep 26, 2024
1 parent aca7a46 commit f1b4942
Show file tree
Hide file tree
Showing 2 changed files with 233 additions and 21 deletions.
14 changes: 12 additions & 2 deletions rest.c
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,7 @@ rest_api_get (int flags, const char *path, const char *if_none_match, const char
char *resp = NULL;
int schflags = 0;
int qdepth, rdepth;
int param_depth = 0;
int diff;

/* If a request is made to /restconf/data (in which case the path is now empty) it is analogous to a
Expand Down Expand Up @@ -767,7 +768,7 @@ rest_api_get (int flags, const char *path, const char *if_none_match, const char
if (qmark)
{
/* Parse the query and attach to the tree */
if (!sch_query_to_gnode (g_schema, qschema, qnode, qmark, schflags, &schflags))
if (!sch_query_to_gnode (g_schema, qschema, qnode, qmark, schflags, &schflags, &param_depth))
{
rc = HTTP_CODE_BAD_REQUEST;
error_tag = REST_E_TAG_INVALID_VALUE;
Expand Down Expand Up @@ -821,6 +822,12 @@ rest_api_get (int flags, const char *path, const char *if_none_match, const char
sch_traverse_tree (g_schema, rschema, rnode, schflags | SCH_F_TRIM_DEFAULTS, 0);
}

if ((schflags & SCH_F_DEPTH) && param_depth)
{
rnode = get_response_node (tree, rdepth);
sch_trim_tree_by_depth (g_schema, rschema, rnode, schflags, param_depth);
}

/* Convert the result to JSON */
rnode = get_response_node (tree, rdepth);
if (rnode)
Expand Down Expand Up @@ -856,7 +863,10 @@ rest_api_get (int flags, const char *path, const char *if_none_match, const char
}
else
{
json = json_object();
if ((schflags & SCH_F_DEPTH) && qschema && qnode)
json = sch_gnode_to_json (g_schema, qschema, qnode, schflags);
else
json = json_object();
}

json_string = json_dumps (json, JSON_ENCODE_ANY);
Expand Down
240 changes: 221 additions & 19 deletions tests/test_query.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ def test_restconf_query_depth_1_trunk():
assert response.status_code == 200
assert len(response.content) > 0
print(json.dumps(response.json(), indent=4, sort_keys=True))
assert response.json() == json.loads("""{}""")
assert response.json() == json.loads("""{"settings": {}}""")


def test_restconf_query_depth_1_list():
Expand All @@ -231,7 +231,18 @@ def test_restconf_query_depth_1_list():
assert response.status_code == 200
assert len(response.content) > 0
print(json.dumps(response.json(), indent=4, sort_keys=True))
assert response.json() == json.loads("""{}""")
assert response.json() == json.loads("""
{
"users": [
{}
]
}
""") or response.json() == json.loads("""
{
"users": [
]
}
""")


def test_restconf_query_depth_2_trunk():
Expand All @@ -252,6 +263,8 @@ def test_restconf_query_depth_2_trunk():
"enable": true,
"priority": 1,
"readonly": "yes",
"time": {},
"users": [],
"volume": "1"
}
}
Expand All @@ -273,13 +286,13 @@ def test_restconf_query_depth_2_list():
{
"users": [
{
"name": "alfred",
"active": true,
"age": 87,
"active": true
"name": "alfred"
}
]
}
""")
""")


def test_restconf_query_depth_3():
Expand Down Expand Up @@ -307,9 +320,9 @@ def test_restconf_query_depth_3():
},
"users": [
{
"name": "alfred",
"active": true,
"age": 87,
"active": true
"name": "alfred"
}
],
"volume": "1"
Expand All @@ -318,7 +331,153 @@ def test_restconf_query_depth_3():
""")


def test_restconf_query_depth_4():
def test_restconf_query_animals_animal_depth_1():
response = requests.get("{}{}/data/test/animals/animal?depth=1".format(server_uri, docroot), auth=server_auth, headers=get_restconf_headers)
assert response.status_code == 200
assert len(response.content) > 0
print(json.dumps(response.json(), indent=4, sort_keys=True))
assert response.json() == json.loads("""
{
"animal": [
{}
]
}
""") or response.json() == json.loads("""
{
"animal": [
]
}
""")


def test_restconf_query_animals_depth_2():
response = requests.get("{}{}/data/test/animals?depth=2".format(server_uri, docroot), auth=server_auth, headers=get_restconf_headers)
assert response.status_code == 200
assert len(response.content) > 0
print(json.dumps(response.json(), indent=4, sort_keys=True))
assert response.json() == json.loads("""
{
"animals": {
"animal": []
}
}
""")


def test_restconf_query_animals_animal_depth_2():
response = requests.get("{}{}/data/test/animals/animal?depth=2".format(server_uri, docroot), auth=server_auth, headers=get_restconf_headers)
assert response.status_code == 200
assert len(response.content) > 0
print(json.dumps(response.json(), indent=4, sort_keys=True))
assert response.json() == json.loads("""
{
"animal": [
{
"name": "cat",
"type": "animal-testing-types:big"
},
{
"colour": "brown",
"name": "dog"
},
{
"food": [],
"name": "hamster",
"type": "animal-testing-types:little"
},
{
"colour": "grey",
"name": "mouse",
"type": "animal-testing-types:little"
},
{
"colour": "blue",
"name": "parrot",
"toys": {},
"type": "animal-testing-types:big"
}
]
}
""")


def test_restconf_query_animals_depth_3():
response = requests.get("{}{}/data/test/animals?depth=3".format(server_uri, docroot), auth=server_auth, headers=get_restconf_headers)
assert response.status_code == 200
assert len(response.content) > 0
print(json.dumps(response.json(), indent=4, sort_keys=True))
assert response.json() == json.loads("""
{
"animals": {
"animal": [
{
"name": "cat",
"type": "animal-testing-types:big"
},
{
"colour": "brown",
"name": "dog"
},
{
"food": [],
"name": "hamster",
"type": "animal-testing-types:little"
},
{
"colour": "grey",
"name": "mouse",
"type": "animal-testing-types:little"
},
{
"colour": "blue",
"name": "parrot",
"toys": {},
"type": "animal-testing-types:big"
}
]
}
}
""")


def test_restconf_query_animals_animal_depth_3():
response = requests.get("{}{}/data/test/animals/animal?depth=3".format(server_uri, docroot), auth=server_auth, headers=get_restconf_headers)
assert response.status_code == 200
assert len(response.content) > 0
print(json.dumps(response.json(), indent=4, sort_keys=True))
assert response.json() == json.loads("""
{
"animal": [
{
"name": "cat",
"type": "animal-testing-types:big"
},
{
"colour": "brown",
"name": "dog"
},
{
"food": [],
"name": "hamster",
"type": "animal-testing-types:little"
},
{
"colour": "grey",
"name": "mouse",
"type": "animal-testing-types:little"
},
{
"colour": "blue",
"name": "parrot",
"toys": {},
"type": "animal-testing-types:big"
}
]
}
""")


def test_restconf_query_animals_depth_4():
response = requests.get("{}{}/data/test/animals?depth=4".format(server_uri, docroot), auth=server_auth, headers=get_restconf_headers)
assert response.status_code == 200
assert len(response.content) > 0
Expand All @@ -336,16 +495,7 @@ def test_restconf_query_depth_4():
"name": "dog"
},
{
"food": [
{
"name": "banana",
"type": "fruit"
},
{
"name": "nuts",
"type": "kibble"
}
],
"food": [],
"name": "hamster",
"type": "animal-testing-types:little"
},
Expand All @@ -357,6 +507,7 @@ def test_restconf_query_depth_4():
{
"colour": "blue",
"name": "parrot",
"toys": {},
"type": "animal-testing-types:big"
}
]
Expand All @@ -365,7 +516,58 @@ def test_restconf_query_depth_4():
""")


def test_restconf_query_depth_5():
def test_restconf_query_animals_animal_depth_4():
response = requests.get("{}{}/data/test/animals/animal?depth=4".format(server_uri, docroot), auth=server_auth, headers=get_restconf_headers)
assert response.status_code == 200
assert len(response.content) > 0
print(json.dumps(response.json(), indent=4, sort_keys=True))
assert response.json() == json.loads("""
{
"animal": [
{
"name": "cat",
"type": "animal-testing-types:big"
},
{
"colour": "brown",
"name": "dog"
},
{
"food": [
{
"name": "banana",
"type": "fruit"
},
{
"name": "nuts",
"type": "kibble"
}
],
"name": "hamster",
"type": "animal-testing-types:little"
},
{
"colour": "grey",
"name": "mouse",
"type": "animal-testing-types:little"
},
{
"colour": "blue",
"name": "parrot",
"toys": {
"toy": [
"puzzles",
"rings"
]
},
"type": "animal-testing-types:big"
}
]
}
""")


def test_restconf_query_animals_depth_5():
response = requests.get("{}{}/data/test/animals?depth=5".format(server_uri, docroot), auth=server_auth, headers=get_restconf_headers)
assert response.status_code == 200
assert len(response.content) > 0
Expand Down

0 comments on commit f1b4942

Please sign in to comment.