Skip to content

Commit 42d8264

Browse files
committed
Test new API: serialization tests for invalid arg
A while ago we decided that it's best to research each of the individuals attributes one by one and identify what level of validation it needs compared to how we use it: #1366 (comment). This work is ongoing and there are a couple of commits already merged for this: - 6c5d970 - f20664d - 41afb1e We want to be able to test the attributes validation against known bad values. The way we want to do that is with table testing we have added using decorators for our metadata classes defined in New API: #1416. This gives us an easy way to add new cases for each of the attributes and not depend on external files. Signed-off-by: Martin Vrachev <[email protected]>
1 parent c45aac7 commit 42d8264

File tree

1 file changed

+107
-3
lines changed

1 file changed

+107
-3
lines changed

tests/test_metadata_serialization.py

Lines changed: 107 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
import unittest
1313
import copy
1414

15-
from typing import Dict, Callable
15+
from typing import Dict, Callable, Optional, Mapping, Any
16+
from datetime import datetime
1617

1718
from tests import utils
1819

1920
from tuf.api.metadata import (
21+
Signed,
2022
Root,
2123
Snapshot,
2224
Timestamp,
@@ -50,18 +52,89 @@ def wrapper(test_cls: "TestSerialization"):
5052

5153
class TestSerialization(unittest.TestCase):
5254

55+
# Snapshot instances with meta = {} are valid, but for a full valid
56+
# repository it's required that meta has at least one element inside it.
57+
invalid_signed: DataSet = {
58+
"no _type": '{"spec_version": "1.0.0", "expires": "2030-01-01T00:00:00Z", "meta": {}}',
59+
"no spec_version": '{"_type": "signed", "version": 1, "expires": "2030-01-01T00:00:00Z", "meta": {}}',
60+
"no version": '{"_type": "signed", "spec_version": "1.0.0", "expires": "2030-01-01T00:00:00Z", "meta": {}}',
61+
"no expires": '{"_type": "signed", "spec_version": "1.0.0", "version": 1, "meta": {}}',
62+
"empty str _type":
63+
'{"_type": "", "spec_version": "1.0.0", "version": 1, "expires": "2030-01-01T00:00:00Z", "meta": {}}',
64+
"empty str spec_version":
65+
'{"_type": "signed", "spec_version": "", "version": 1, "expires": "2030-01-01T00:00:00Z", "meta": {}}',
66+
"_type wrong type":
67+
'{"_type": "foo", "spec_version": "1.0.0", "version": 1, "expires": "2030-01-01T00:00:00Z", "meta": {}}',
68+
"version wrong type":
69+
'{"_type": "signed", "spec_version": "1.0.0", "version": "a", "expires": "2030-01-01T00:00:00Z", "meta": {}}',
70+
"invalid spec_version str":
71+
'{"_type": "signed", "spec_version": "abc", "version": 1, "expires": "2030-01-01T00:00:00Z", "meta": {}}',
72+
"two digit spec_version":
73+
'{"_type": "signed", "spec_version": "1.2.a", "version": 1, "expires": "2030-01-01T00:00:00Z", "meta": {}}',
74+
"no digit spec_version":
75+
'{"_type": "signed", "spec_version": "a.b.c", "version": 1, "expires": "2030-01-01T00:00:00Z", "meta": {}}',
76+
"different major spec_version":
77+
'{"_type": "signed", "spec_version": "0.0.0", "version": 1, "expires": "2030-01-01T00:00:00Z", "meta": {}}',
78+
"version 0":
79+
'{"_type": "signed", "spec_version": "1.0.0", "version": 0, "expires": "2030-01-01T00:00:00Z", "meta": {}}',
80+
"version below 0":
81+
'{"_type": "signed", "spec_version": "1.0.0", "version": -1, "expires": "2030-01-01T00:00:00Z", "meta": {}}',
82+
"wrong datetime string":
83+
'{"_type": "signed", "spec_version": "1.0.0", "version": 1, "expires": "abc", "meta": {}}',
84+
}
85+
86+
@run_sub_tests_with_dataset(invalid_signed)
87+
def test_invalid_signed_serialization(self, test_case_data: Dict[str, str]):
88+
case_dict = json.loads(test_case_data)
89+
with self.assertRaises((KeyError, ValueError, TypeError)):
90+
Snapshot.from_dict(copy.deepcopy(case_dict))
91+
92+
5393
valid_keys: DataSet = {
5494
"all": '{"keytype": "rsa", "scheme": "rsassa-pss-sha256", \
5595
"keyval": {"public": "foo"}}',
5696
}
5797

5898
@run_sub_tests_with_dataset(valid_keys)
59-
def test_key_serialization(self, test_case_data: str):
99+
def test_valid_key_serialization(self, test_case_data: str):
60100
case_dict = json.loads(test_case_data)
61101
key = Key.from_dict("id", copy.copy(case_dict))
62102
self.assertDictEqual(case_dict, key.to_dict())
63103

64104

105+
invalid_keys: DataSet = {
106+
"no keyid": '{"keytype": "rsa", "scheme": "rsassa-pss-sha256", "keyval": {"public": "abc"}}',
107+
"no keytype": '{"keyid": "id", "scheme": "rsassa-pss-sha256", "keyval": {"public": "foo"}}',
108+
"no scheme": '{"keyid": "id", "keytype": "rsa", "keyval": {"public": "foo"}}',
109+
"no keyval": '{"keyid": "id", "keytype": "rsa", "scheme": "rsassa-pss-sha256"}',
110+
"keyid wrong type": '{"keyid": 1, "keytype": "rsa", "scheme": "rsassa-pss-sha256", "keyval": {"public": "abc"}}',
111+
"keytype wrong type": '{"keyid": "id", "keytype": 1, "scheme": "rsassa-pss-sha256", "keyval": {"public": "abc"}}',
112+
"scheme wrong type": '{"keyid": "id", "keytype": "rsa", "scheme": 1, "keyval": {"public": "abc"}}',
113+
"keyval wrong type": '{"keyid": "id", "keytype": "rsa", "scheme": "rsassa-pss-sha256", "keyval": 1}',
114+
}
115+
116+
@run_sub_tests_with_dataset(invalid_keys)
117+
def test_invalid_key_serialization(self, test_case_data: Dict[str, str]):
118+
case_dict = json.loads(test_case_data)
119+
with self.assertRaises((TypeError, KeyError)):
120+
keyid = case_dict.pop("keyid")
121+
Key.from_dict(keyid, copy.copy(case_dict))
122+
123+
invalid_roles: DataSet = {
124+
"no threshold": '{"keyids": ["keyid"]}',
125+
"no keyids": '{"threshold": 3}',
126+
"wrong threshold type": '{"keyids": ["keyid"], "threshold": "a"}',
127+
"threshold below 1": '{"keyids": ["keyid"], "threshold": 0}',
128+
"duplicate keyids": '{"keyids": ["keyid", "keyid"], "threshold": 3}',
129+
}
130+
131+
@run_sub_tests_with_dataset(invalid_roles)
132+
def test_invalid_role_serialization(self, test_case_data: Dict[str, str]):
133+
case_dict = json.loads(test_case_data)
134+
with self.assertRaises((KeyError, TypeError, ValueError)):
135+
Role.from_dict(copy.deepcopy(case_dict))
136+
137+
65138
valid_roles: DataSet = {
66139
"all": '{"keyids": ["keyid"], "threshold": 3}'
67140
}
@@ -92,9 +165,26 @@ def test_root_serialization(self, test_case_data: str):
92165
root = Root.from_dict(copy.deepcopy(case_dict))
93166
self.assertDictEqual(case_dict, root.to_dict())
94167

168+
169+
invalid_metafiles: DataSet = {
170+
"wrong length type": '{"version": 1, "length": "a", "hashes": {"sha256" : "abc"}}',
171+
"length 0": '{"version": 1, "length": 0, "hashes": {"sha256" : "abc"}}',
172+
"length below 0": '{"version": 1, "length": -1, "hashes": {"sha256" : "abc"}}',
173+
"empty hashes dict": '{"version": 1, "length": 1, "hashes": {}}',
174+
"hashes wrong type": '{"version": 1, "length": 1, "hashes": 1}',
175+
"hashes values wrong type": '{"version": 1, "length": 1, "hashes": {"sha256": 1}}',
176+
}
177+
178+
@run_sub_tests_with_dataset(invalid_metafiles)
179+
def test_invalid_metafile_serialization(self, test_case_data: Dict[str, str]):
180+
case_dict = json.loads(test_case_data)
181+
with self.assertRaises((TypeError, ValueError, AttributeError)):
182+
MetaFile.from_dict(copy.deepcopy(case_dict))
183+
184+
95185
valid_metafiles: DataSet = {
96186
"all": '{"hashes": {"sha256" : "abc"}, "length": 12, "version": 1}',
97-
"no length": '{"hashes": {"sha256" : "abc"}, "version": 1 }',
187+
"no length": '{"hashes": {"sha256" : "abc"}, "version": 1}',
98188
"no hashes": '{"length": 12, "version": 1}'
99189
}
100190

@@ -159,6 +249,20 @@ def test_delegation_serialization(self, test_case_data: str):
159249
self.assertDictEqual(case_dict, delegation.to_dict())
160250

161251

252+
invalid_targetfiles: DataSet = {
253+
"no hashes": '{"length": 1}',
254+
"no length": '{"hashes": {"sha256": "abc"}}'
255+
# The remaining cases are the same as for invalid_hashes and
256+
# invalid_length datasets.
257+
}
258+
259+
@run_sub_tests_with_dataset(invalid_targetfiles)
260+
def test_invalid_targetfile_serialization(self, test_case_data: Dict[str, str]):
261+
case_dict = json.loads(test_case_data)
262+
with self.assertRaises(KeyError):
263+
TargetFile.from_dict(copy.deepcopy(case_dict))
264+
265+
162266
valid_targetfiles: DataSet = {
163267
"all": '{"length": 12, "hashes": {"sha256" : "abc"}, \
164268
"custom" : {"foo": "bar"} }',

0 commit comments

Comments
 (0)