Skip to content

Commit

Permalink
check deserializer ignores declaration order
Browse files Browse the repository at this point in the history
Summary:
Verify that deserialize won't fail if field declaration order changes. Try two cases:
- thrift-py3 -> thrift-python migration: imagine we save serialized py3 data in a DB then deserialize it later in thrift-python
- thrift-python field order change: imagine we switch from id-key order to declaration order

Reviewed By: yoney

Differential Revision: D61406211

fbshipit-source-id: 51b3b47952b6321a59a8c561ca05fbfd6a738b2a
  • Loading branch information
ahilger authored and facebook-github-bot committed Aug 17, 2024
1 parent 1766eba commit 952a4a9
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 0 deletions.
16 changes: 16 additions & 0 deletions thrift/lib/py3/test/testing.thrift
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,22 @@ struct IOBufListStruct {
1: list<IOBuf> iobufs;
} (cpp.noncomparable)

// StructOrder* should have same fields when sorted in key order.
// They exist to test whether deserialize is insensitive to declartion order.
struct StructOrderRandom {
3: bool c;
4: bool d;
1: i64 a;
2: string b;
}

struct StructOrderSorted {
1: i64 a;
2: string b;
3: bool c;
4: bool d;
}

service ClientMetadataTestingService {
string getAgent();
string getHostname();
Expand Down
55 changes: 55 additions & 0 deletions thrift/lib/python/test/intercompatibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@


import unittest
from typing import Generator, Type

import testing.thrift_types as python_types
import testing.types as py3_types
from thrift.py3.serializer import serialize as py3_serialize
from thrift.python.serializer import deserialize, Protocol


class Py3CompatibilityTest(unittest.TestCase):
Expand Down Expand Up @@ -60,3 +63,55 @@ def test_init_python_union_with_py3_struct(self) -> None:
py3_easy = py3_types.easy(name="foo")
python_complex_union = python_types.ComplexUnion(easy_struct=py3_easy)
self.assertEqual("foo", python_complex_union.easy_struct.name)


class DeserializationCompatibilityTest(unittest.TestCase):
def assert_struct_ordering(
self, py3: py3_types.StructOrderRandom | python_types.StructOrderSorted
) -> None:
expected = python_types.StructOrderRandom(**dict(py3))
for proto in [Protocol.BINARY, Protocol.COMPACT, Protocol.JSON]:
py3_stored = py3_serialize(py3, protocol=proto)
python = deserialize(
python_types.StructOrderRandom, py3_stored, protocol=proto
)
self.assertEqual(python, expected, f"Protocol {proto}")

def gen_structs(
self,
kls: Type[py3_types.StructOrderRandom] | Type[python_types.StructOrderSorted],
) -> Generator[
py3_types.StructOrderRandom | python_types.StructOrderSorted, None, None
]:
yield kls(
a=0,
b="0",
c=False,
d=True,
)
yield kls(
a=3,
b="1234",
c=False,
d=True,
)
yield kls(
a=1,
b="0",
c=False,
d=True,
)

# Test that deserialize is insensitive to struct field declaration order.
# This struct has different field orders in py3, which uses declaration order,
# and in python, which uses id/key order. This test verifies that python deserialization
# is insensitive to the order of the fields in the serialized data.
def test_py3_migration_struct_ordering(self) -> None:
for struct in self.gen_structs(py3_types.StructOrderRandom):
self.assert_struct_ordering(struct)

# Test that would verify that python deserialization is insensitive to the order of the fields in the serialized data.
# It is not a *live* test until a diff that actually implements change from id-key order to declaration order.
def test_python_struct_ordering(self) -> None:
for struct in self.gen_structs(python_types.StructOrderSorted):
self.assert_struct_ordering(struct)

0 comments on commit 952a4a9

Please sign in to comment.