Răsfoiți Sursa

qapi: Add some type check tests

Demonstrate that the qapi generator silently parses confusing
types, which may cause other errors later on. Later patches
will update the expected results as the generator is made stricter.

Most of the new tests focus on blatant errors.  But
returns-whitelist is a case where we have historically allowed
returning something other than a JSON object from particular
commands; we have to keep that behavior to avoid breaking clients,
but it would be nicer to avoid adding such commands in the future,
because any return that is not an (array of) object cannot be
easily extended if future qemu wants to return additional
information.  The QMP protocol already documents that clients
should ignore unknown dictionary keys, but does not require
clients to have to handle more than one type of JSON object.

Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Eric Blake 10 ani în urmă
părinte
comite
0d8b9fb5f2
61 a modificat fișierele cu 119 adăugiri și 3 ștergeri
  1. 7 3
      tests/Makefile
  2. 0 0
      tests/qapi-schema/bad-data.err
  3. 1 0
      tests/qapi-schema/bad-data.exit
  4. 2 0
      tests/qapi-schema/bad-data.json
  5. 3 0
      tests/qapi-schema/bad-data.out
  6. 0 0
      tests/qapi-schema/data-array-empty.err
  7. 1 0
      tests/qapi-schema/data-array-empty.exit
  8. 2 0
      tests/qapi-schema/data-array-empty.json
  9. 3 0
      tests/qapi-schema/data-array-empty.out
  10. 0 0
      tests/qapi-schema/data-array-unknown.err
  11. 1 0
      tests/qapi-schema/data-array-unknown.exit
  12. 2 0
      tests/qapi-schema/data-array-unknown.json
  13. 3 0
      tests/qapi-schema/data-array-unknown.out
  14. 0 0
      tests/qapi-schema/data-int.err
  15. 1 0
      tests/qapi-schema/data-int.exit
  16. 2 0
      tests/qapi-schema/data-int.json
  17. 3 0
      tests/qapi-schema/data-int.out
  18. 0 0
      tests/qapi-schema/data-member-array-bad.err
  19. 1 0
      tests/qapi-schema/data-member-array-bad.exit
  20. 2 0
      tests/qapi-schema/data-member-array-bad.json
  21. 3 0
      tests/qapi-schema/data-member-array-bad.out
  22. 0 0
      tests/qapi-schema/data-member-array.err
  23. 1 0
      tests/qapi-schema/data-member-array.exit
  24. 4 0
      tests/qapi-schema/data-member-array.json
  25. 5 0
      tests/qapi-schema/data-member-array.out
  26. 0 0
      tests/qapi-schema/data-member-unknown.err
  27. 1 0
      tests/qapi-schema/data-member-unknown.exit
  28. 2 0
      tests/qapi-schema/data-member-unknown.json
  29. 3 0
      tests/qapi-schema/data-member-unknown.out
  30. 0 0
      tests/qapi-schema/data-unknown.err
  31. 1 0
      tests/qapi-schema/data-unknown.exit
  32. 2 0
      tests/qapi-schema/data-unknown.json
  33. 3 0
      tests/qapi-schema/data-unknown.out
  34. 0 0
      tests/qapi-schema/nested-struct-data.err
  35. 1 0
      tests/qapi-schema/nested-struct-data.exit
  36. 4 0
      tests/qapi-schema/nested-struct-data.json
  37. 3 0
      tests/qapi-schema/nested-struct-data.out
  38. 0 0
      tests/qapi-schema/nested-struct-returns.err
  39. 1 0
      tests/qapi-schema/nested-struct-returns.exit
  40. 3 0
      tests/qapi-schema/nested-struct-returns.json
  41. 3 0
      tests/qapi-schema/nested-struct-returns.out
  42. 0 0
      tests/qapi-schema/returns-alternate.err
  43. 1 0
      tests/qapi-schema/returns-alternate.exit
  44. 3 0
      tests/qapi-schema/returns-alternate.json
  45. 4 0
      tests/qapi-schema/returns-alternate.out
  46. 0 0
      tests/qapi-schema/returns-array-bad.err
  47. 1 0
      tests/qapi-schema/returns-array-bad.exit
  48. 2 0
      tests/qapi-schema/returns-array-bad.json
  49. 3 0
      tests/qapi-schema/returns-array-bad.out
  50. 0 0
      tests/qapi-schema/returns-int.err
  51. 1 0
      tests/qapi-schema/returns-int.exit
  52. 2 0
      tests/qapi-schema/returns-int.json
  53. 3 0
      tests/qapi-schema/returns-int.out
  54. 0 0
      tests/qapi-schema/returns-unknown.err
  55. 1 0
      tests/qapi-schema/returns-unknown.exit
  56. 2 0
      tests/qapi-schema/returns-unknown.json
  57. 3 0
      tests/qapi-schema/returns-unknown.out
  58. 0 0
      tests/qapi-schema/returns-whitelist.err
  59. 1 0
      tests/qapi-schema/returns-whitelist.exit
  60. 11 0
      tests/qapi-schema/returns-whitelist.json
  61. 7 0
      tests/qapi-schema/returns-whitelist.out

+ 7 - 3
tests/Makefile

@@ -215,10 +215,14 @@ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
 	double-type.json bad-base.json bad-type-bool.json bad-type-int.json \
 	double-type.json bad-base.json bad-type-bool.json bad-type-int.json \
 	bad-type-dict.json double-data.json unknown-expr-key.json \
 	bad-type-dict.json double-data.json unknown-expr-key.json \
 	redefined-type.json redefined-command.json redefined-builtin.json \
 	redefined-type.json redefined-command.json redefined-builtin.json \
-	redefined-event.json command-int.json event-max.json \
+	redefined-event.json command-int.json bad-data.json event-max.json \
 	type-bypass.json type-bypass-no-gen.json type-bypass-bad-gen.json \
 	type-bypass.json type-bypass-no-gen.json type-bypass-bad-gen.json \
-	missing-colon.json missing-comma-list.json \
-	missing-comma-object.json non-objects.json \
+	data-array-empty.json data-array-unknown.json data-int.json \
+	data-unknown.json data-member-unknown.json data-member-array.json \
+	data-member-array-bad.json returns-array-bad.json returns-int.json \
+	returns-unknown.json returns-alternate.json returns-whitelist.json \
+	missing-colon.json missing-comma-list.json missing-comma-object.json \
+	nested-struct-data.json nested-struct-returns.json non-objects.json \
 	qapi-schema-test.json quoted-structural-chars.json \
 	qapi-schema-test.json quoted-structural-chars.json \
 	trailing-comma-list.json trailing-comma-object.json \
 	trailing-comma-list.json trailing-comma-object.json \
 	unclosed-list.json unclosed-object.json unclosed-string.json \
 	unclosed-list.json unclosed-object.json unclosed-string.json \

+ 0 - 0
tests/qapi-schema/bad-data.err


+ 1 - 0
tests/qapi-schema/bad-data.exit

@@ -0,0 +1 @@
+0

+ 2 - 0
tests/qapi-schema/bad-data.json

@@ -0,0 +1,2 @@
+# FIXME: we should ensure 'data' is a dictionary for all but enums
+{ 'command': 'oops', 'data': [ ] }

+ 3 - 0
tests/qapi-schema/bad-data.out

@@ -0,0 +1,3 @@
+[OrderedDict([('command', 'oops'), ('data', [])])]
+[]
+[]

+ 0 - 0
tests/qapi-schema/data-array-empty.err


+ 1 - 0
tests/qapi-schema/data-array-empty.exit

@@ -0,0 +1 @@
+0

+ 2 - 0
tests/qapi-schema/data-array-empty.json

@@ -0,0 +1,2 @@
+# FIXME: we should reject an array for data if it does not contain a known type
+{ 'command': 'oops', 'data': { 'empty': [ ] } }

+ 3 - 0
tests/qapi-schema/data-array-empty.out

@@ -0,0 +1,3 @@
+[OrderedDict([('command', 'oops'), ('data', OrderedDict([('empty', [])]))])]
+[]
+[]

+ 0 - 0
tests/qapi-schema/data-array-unknown.err


+ 1 - 0
tests/qapi-schema/data-array-unknown.exit

@@ -0,0 +1 @@
+0

+ 2 - 0
tests/qapi-schema/data-array-unknown.json

@@ -0,0 +1,2 @@
+# FIXME: we should reject an array for data if it does not contain a known type
+{ 'command': 'oops', 'data': { 'array': [ 'NoSuchType' ] } }

+ 3 - 0
tests/qapi-schema/data-array-unknown.out

@@ -0,0 +1,3 @@
+[OrderedDict([('command', 'oops'), ('data', OrderedDict([('array', ['NoSuchType'])]))])]
+[]
+[]

+ 0 - 0
tests/qapi-schema/data-int.err


+ 1 - 0
tests/qapi-schema/data-int.exit

@@ -0,0 +1 @@
+0

+ 2 - 0
tests/qapi-schema/data-int.json

@@ -0,0 +1,2 @@
+# FIXME: we should reject commands where data is not an array or complex type
+{ 'command': 'oops', 'data': 'int' }

+ 3 - 0
tests/qapi-schema/data-int.out

@@ -0,0 +1,3 @@
+[OrderedDict([('command', 'oops'), ('data', 'int')])]
+[]
+[]

+ 0 - 0
tests/qapi-schema/data-member-array-bad.err


+ 1 - 0
tests/qapi-schema/data-member-array-bad.exit

@@ -0,0 +1 @@
+0

+ 2 - 0
tests/qapi-schema/data-member-array-bad.json

@@ -0,0 +1,2 @@
+# FIXME: we should reject data if it does not contain a valid array type
+{ 'command': 'oops', 'data': { 'member': [ { 'nested': 'str' } ] } }

+ 3 - 0
tests/qapi-schema/data-member-array-bad.out

@@ -0,0 +1,3 @@
+[OrderedDict([('command', 'oops'), ('data', OrderedDict([('member', [OrderedDict([('nested', 'str')])])]))])]
+[]
+[]

+ 0 - 0
tests/qapi-schema/data-member-array.err


+ 1 - 0
tests/qapi-schema/data-member-array.exit

@@ -0,0 +1 @@
+0

+ 4 - 0
tests/qapi-schema/data-member-array.json

@@ -0,0 +1,4 @@
+# valid array members
+{ 'enum': 'abc', 'data': [ 'a', 'b', 'c' ] }
+{ 'type': 'def', 'data': { 'array': [ 'abc' ] } }
+{ 'command': 'okay', 'data': { 'member1': [ 'int' ], 'member2': [ 'def' ] } }

+ 5 - 0
tests/qapi-schema/data-member-array.out

@@ -0,0 +1,5 @@
+[OrderedDict([('enum', 'abc'), ('data', ['a', 'b', 'c'])]),
+ OrderedDict([('type', 'def'), ('data', OrderedDict([('array', ['abc'])]))]),
+ OrderedDict([('command', 'okay'), ('data', OrderedDict([('member1', ['int']), ('member2', ['def'])]))])]
+[{'enum_name': 'abc', 'enum_values': ['a', 'b', 'c']}]
+[OrderedDict([('type', 'def'), ('data', OrderedDict([('array', ['abc'])]))])]

+ 0 - 0
tests/qapi-schema/data-member-unknown.err


+ 1 - 0
tests/qapi-schema/data-member-unknown.exit

@@ -0,0 +1 @@
+0

+ 2 - 0
tests/qapi-schema/data-member-unknown.json

@@ -0,0 +1,2 @@
+# FIXME: we should reject data if it does not contain a known type
+{ 'command': 'oops', 'data': { 'member': 'NoSuchType' } }

+ 3 - 0
tests/qapi-schema/data-member-unknown.out

@@ -0,0 +1,3 @@
+[OrderedDict([('command', 'oops'), ('data', OrderedDict([('member', 'NoSuchType')]))])]
+[]
+[]

+ 0 - 0
tests/qapi-schema/data-unknown.err


+ 1 - 0
tests/qapi-schema/data-unknown.exit

@@ -0,0 +1 @@
+0

+ 2 - 0
tests/qapi-schema/data-unknown.json

@@ -0,0 +1,2 @@
+# FIXME: we should reject data if it does not contain a known type
+{ 'command': 'oops', 'data': 'NoSuchType' }

+ 3 - 0
tests/qapi-schema/data-unknown.out

@@ -0,0 +1,3 @@
+[OrderedDict([('command', 'oops'), ('data', 'NoSuchType')])]
+[]
+[]

+ 0 - 0
tests/qapi-schema/nested-struct-data.err


+ 1 - 0
tests/qapi-schema/nested-struct-data.exit

@@ -0,0 +1 @@
+0

+ 4 - 0
tests/qapi-schema/nested-struct-data.json

@@ -0,0 +1,4 @@
+# FIXME: inline subtypes collide with our desired future use of defaults
+{ 'command': 'foo',
+  'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' },
+  'returns': {} }

+ 3 - 0
tests/qapi-schema/nested-struct-data.out

@@ -0,0 +1,3 @@
+[OrderedDict([('command', 'foo'), ('data', OrderedDict([('a', OrderedDict([('string', 'str'), ('integer', 'int')])), ('b', 'str')])), ('returns', OrderedDict())])]
+[]
+[]

+ 0 - 0
tests/qapi-schema/nested-struct-returns.err


+ 1 - 0
tests/qapi-schema/nested-struct-returns.exit

@@ -0,0 +1 @@
+0

+ 3 - 0
tests/qapi-schema/nested-struct-returns.json

@@ -0,0 +1,3 @@
+# FIXME: inline subtypes collide with our desired future use of defaults
+{ 'command': 'foo',
+  'returns': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } }

+ 3 - 0
tests/qapi-schema/nested-struct-returns.out

@@ -0,0 +1,3 @@
+[OrderedDict([('command', 'foo'), ('returns', OrderedDict([('a', OrderedDict([('string', 'str'), ('integer', 'int')])), ('b', 'str')]))])]
+[]
+[]

+ 0 - 0
tests/qapi-schema/returns-alternate.err


+ 1 - 0
tests/qapi-schema/returns-alternate.exit

@@ -0,0 +1 @@
+0

+ 3 - 0
tests/qapi-schema/returns-alternate.json

@@ -0,0 +1,3 @@
+# FIXME: we should reject returns if it is an alternate type
+{ 'alternate': 'Alt', 'data': { 'a': 'int', 'b': 'str' } }
+{ 'command': 'oops', 'returns': 'Alt' }

+ 4 - 0
tests/qapi-schema/returns-alternate.out

@@ -0,0 +1,4 @@
+[OrderedDict([('alternate', 'Alt'), ('data', OrderedDict([('a', 'int'), ('b', 'str')]))]),
+ OrderedDict([('command', 'oops'), ('returns', 'Alt')])]
+[{'enum_name': 'AltKind', 'enum_values': None}]
+[]

+ 0 - 0
tests/qapi-schema/returns-array-bad.err


+ 1 - 0
tests/qapi-schema/returns-array-bad.exit

@@ -0,0 +1 @@
+0

+ 2 - 0
tests/qapi-schema/returns-array-bad.json

@@ -0,0 +1,2 @@
+# FIXME: we should reject an array return that is not a single type
+{ 'command': 'oops', 'returns': [ 'str', 'str' ] }

+ 3 - 0
tests/qapi-schema/returns-array-bad.out

@@ -0,0 +1,3 @@
+[OrderedDict([('command', 'oops'), ('returns', ['str', 'str'])])]
+[]
+[]

+ 0 - 0
tests/qapi-schema/returns-int.err


+ 1 - 0
tests/qapi-schema/returns-int.exit

@@ -0,0 +1 @@
+0

+ 2 - 0
tests/qapi-schema/returns-int.json

@@ -0,0 +1,2 @@
+# It is okay (although not extensible) to return a non-dictionary
+{ 'command': 'okay', 'returns': 'int' }

+ 3 - 0
tests/qapi-schema/returns-int.out

@@ -0,0 +1,3 @@
+[OrderedDict([('command', 'okay'), ('returns', 'int')])]
+[]
+[]

+ 0 - 0
tests/qapi-schema/returns-unknown.err


+ 1 - 0
tests/qapi-schema/returns-unknown.exit

@@ -0,0 +1 @@
+0

+ 2 - 0
tests/qapi-schema/returns-unknown.json

@@ -0,0 +1,2 @@
+# FIXME: we should reject returns if it does not contain a known type
+{ 'command': 'oops', 'returns': 'NoSuchType' }

+ 3 - 0
tests/qapi-schema/returns-unknown.out

@@ -0,0 +1,3 @@
+[OrderedDict([('command', 'oops'), ('returns', 'NoSuchType')])]
+[]
+[]

+ 0 - 0
tests/qapi-schema/returns-whitelist.err


+ 1 - 0
tests/qapi-schema/returns-whitelist.exit

@@ -0,0 +1 @@
+0

+ 11 - 0
tests/qapi-schema/returns-whitelist.json

@@ -0,0 +1,11 @@
+# FIXME: we should enforce that 'returns' be a dict or array of dict unless whitelisted
+{ 'command': 'human-monitor-command',
+  'data': {'command-line': 'str', '*cpu-index': 'int'},
+  'returns': 'str' }
+{ 'enum': 'TpmModel', 'data': [ 'tpm-tis' ] }
+{ 'command': 'query-tpm-models', 'returns': ['TpmModel'] }
+{ 'command': 'guest-get-time',
+  'returns': 'int' }
+
+{ 'command': 'no-way-this-will-get-whitelisted',
+  'returns': [ 'int' ] }

+ 7 - 0
tests/qapi-schema/returns-whitelist.out

@@ -0,0 +1,7 @@
+[OrderedDict([('command', 'human-monitor-command'), ('data', OrderedDict([('command-line', 'str'), ('*cpu-index', 'int')])), ('returns', 'str')]),
+ OrderedDict([('enum', 'TpmModel'), ('data', ['tpm-tis'])]),
+ OrderedDict([('command', 'query-tpm-models'), ('returns', ['TpmModel'])]),
+ OrderedDict([('command', 'guest-get-time'), ('returns', 'int')]),
+ OrderedDict([('command', 'no-way-this-will-get-whitelisted'), ('returns', ['int'])])]
+[{'enum_name': 'TpmModel', 'enum_values': ['tpm-tis']}]
+[]