Uh oh!
There was an error while loading. Please reload this page.
AVRO-4304: [java][python] Add shared must-reject binary interop vectors - #3932
AVRO-4304: [java][python] Add shared must-reject binary interop vectors#3932iemejia wants to merge 3 commits into
Conversation
Decoder hardening across the SDKs now rejects a range of malformed binary encodings, but there is no shared cross-language fixture guaranteeing that every SDK rejects the same malformed inputs identically, so the SDKs can drift (one accepts what another rejects). Add a shared set of must-reject vectors under share/test, each a schema plus a raw binary payload that a conformant decoder must reject with a bounded, well-defined error rather than accepting it, crashing, or exhausting memory. Seed it with cases already fixed per SDK: overlong varints, Long.MIN_VALUE array block counts, negative bytes/string lengths, and out-of-range union branch and enum symbol indices. Add a Java harness that loads the vectors and asserts each is rejected on both the classic and fast reader paths. Payloads are stored as hex and the schema as a JSON string so the fixtures are language neutral and can be wired into every SDK's test suite.
Wire the Python SDK into the shared cross-SDK must-reject binary decoding fixtures added under share/test/data/binary-rejections.json. The harness loads each vector (a schema plus a raw binary payload) and asserts the Avro binary decoder rejects it with a bounded AvroException rather than accepting it or crashing, guaranteeing the Python SDK rejects the same malformed inputs as the other language SDKs and does not drift.
There was a problem hiding this comment.
Pull request overview
Adds a shared, cross-language “must-reject” fixture of malformed Avro binary payloads and introduces thin Java/Python test harnesses to assert that decoders reject those payloads with bounded errors (preventing cross-SDK drift in decoder hardening behavior).
Changes:
- Added
share/test/data/binary-rejections.jsoncontaining seed malformed binary vectors (schema + hex payload + category). - Added a Java parameterized test harness that loads the shared vectors and asserts both classic and fast-reader paths reject them.
- Added a Python unittest harness that locates the shared vectors in a source checkout and asserts the decoder rejects each payload with
AvroException.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| share/test/data/binary-rejections.json | Introduces the shared cross-SDK reject-vector manifest (schema + hex payloads). |
| lang/py/avro/test/test_binary_decoding_rejections.py | Python harness that loads the shared vectors and asserts bounded decoder rejection. |
| lang/java/avro/src/test/java/org/apache/avro/TestBinaryDecodingRejections.java | Java harness that loads the shared vectors and asserts rejection on classic + fast reader paths. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Address review feedback on the Java reject-vector harness: - fromHex now rejects odd-length hex strings and invalid hex characters instead of silently truncating, so a malformed fixture fails loudly rather than decoding a different payload than intended. - Drop the try/catch that re-threw the assertion via fail(getMessage()), which discarded the original AssertionError (and any Error) context. The assertThrows failure now propagates directly with full detail.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
Suppressed comments (2)
lang/java/avro/src/test/java/org/apache/avro/TestBinaryDecodingRejections.java:114
Schema.Parser().parse(schemaJson)happens insidedecode()which is executed insideassertThrows(Exception.class, ...). This means an invalid fixture schema (SchemaParseException) would still satisfy the assertion and be reported as a “pass”, even though decoding was never exercised. Also,assertThrows(Exception.class, …)accepts anyException(e.g.NullPointerException), which weakens the “bounded, well-defined Avro/IO error” intent of the harness.
private static void decode(String schemaJson, byte[] bytes, boolean fastReader) throws IOException {
Schema schema = new Schema.Parser().parse(schemaJson);
GenericData data = new GenericData();
data.setFastReaderEnabled(fastReader);
GenericDatumReader<Object> reader = new GenericDatumReader<>(schema, schema, data);
lang/py/avro/test/test_binary_decoding_rejections.py:63
- The fixture is read with
manifest.read_text()without an explicit encoding, which can break on systems whose default locale encoding is not UTF-8. Also, schema/hex parsing happens beforesubTest, so a single malformed vector would fail the whole test without identifying the offending vector in the test output.
manifest = _find_manifest()
vectors = json.loads(manifest.read_text())["vectors"]
self.assertTrue(vectors, "no reject vectors found")
for vector in vectors:
name = vector["name"]
uros-b
commented
Aug 19, 2026
+1, LGTM! Thank you @iemejia! |
What is the purpose of the change
Decoder hardening across the SDKs now rejects a range of malformed binary
encodings (overlong varints,
Long.MIN_VALUEcollection block counts,out-of-range union branch and enum symbol indices, negative bytes/string
lengths), but there is no shared cross-language fixture guaranteeing that every
SDK rejects the same malformed inputs identically, so the SDKs can drift (one
accepts what another rejects).
This adds a shared set of must-reject vectors under
share/test/data/binary-rejections.json, each a schema plus a raw binarypayload (hex) that a conformant decoder must reject with a bounded,
well-defined error rather than accepting it, crashing, or exhausting memory.
It seeds the set with cases already fixed per SDK, and wires thin per-SDK
harnesses (Java and Python) that load the vectors and assert rejection.
The shared fixture is a single cross-language artifact, so it is kept together
with its first consumers here; additional SDK harnesses can be added later as
small changes on top of the merged fixture.
Verifying this change
This change added tests and can be verified as follows:
share/test/data/binary-rejections.jsonwith 9 seed vectors.TestBinaryDecodingRejections, which asserts eachvector is rejected on both the classic and fast reader paths.
test_binary_decoding_rejections.py, which assertseach vector is rejected with a bounded
AvroException.Documentation
fixtures)
self-describing
descriptionfield explaining the format and intent)