2121Related issue: https://github.com/feast-dev/feast/issues/6013
2222"""
2323
24+ import json
2425import time
2526
2627import pytest
@@ -146,7 +147,7 @@ def test_bytes_list_val(self):
146147 assert result == [b"\x00 \x01 " , b"\x02 \x03 " ]
147148
148149 def test_unix_timestamp_list_val (self ):
149- v = Value (int64_list_val = Int64List (val = [1609459200 , 1609545600 ]))
150+ v = Value (unix_timestamp_list_val = Int64List (val = [1609459200 , 1609545600 ]))
150151 result = _value_to_native (v )
151152 assert result == [1609459200 , 1609545600 ]
152153
@@ -447,6 +448,24 @@ def test_float_val_precision_matches_message_to_dict(self):
447448 == standard_result ["results" ][0 ]["values" ]
448449 )
449450
451+ def test_set_types_return_flat_list (self ):
452+ """set types (string_set_val, int64_set_val, etc.) return flat lists.
453+
454+ Note: proto_json.patch() does not explicitly handle _set_ types — they fall
455+ through to the else branch and return the raw proto object, which MessageToDict
456+ then serializes as {"val": [...]}. Our implementation normalizes these to flat
457+ lists, which is more useful for API consumers and consistent with list types.
458+ """
459+ response = GetOnlineFeaturesResponse ()
460+ fv = response .results .add ()
461+ fv .values .append (Value (string_set_val = StringSet (val = ["a" , "b" , "c" ])))
462+ fv .statuses .append (FieldStatus .PRESENT )
463+
464+ result = convert_response_to_dict (response )
465+ values = result ["results" ][0 ]["values" ]
466+ assert isinstance (values [0 ], list ), "set type should be a flat list"
467+ assert set (values [0 ]) == {"a" , "b" , "c" }
468+
450469 def test_bytes_values_match_patched_message_to_dict (self ):
451470 """Ensure bytes serialization matches proto_json.patch() format (raw bytes)."""
452471 response = GetOnlineFeaturesResponse ()
@@ -463,6 +482,37 @@ def test_bytes_values_match_patched_message_to_dict(self):
463482 )
464483
465484
485+ class TestJsonSerializability :
486+ """Ensure convert_response_to_dict output is always JSON-serializable."""
487+
488+ def test_complex_types_are_json_serializable (self ):
489+ """map_val, list_val, set_val must not leave proto objects in the output."""
490+ response = GetOnlineFeaturesResponse ()
491+ fv = response .results .add ()
492+
493+ # map_val
494+ m = Map ()
495+ m .val ["k" ].CopyFrom (Value (int64_val = 1 ))
496+ fv .values .append (Value (map_val = m ))
497+
498+ # list_val (RepeatedValue)
499+ inner = RepeatedValue ()
500+ inner .val .append (Value (string_val = "a" ))
501+ fv .values .append (Value (list_val = inner ))
502+
503+ # int64_set_val
504+ fv .values .append (Value (int64_set_val = Int64Set (val = [10 , 20 ])))
505+
506+ fv .statuses .extend (
507+ [FieldStatus .PRESENT , FieldStatus .PRESENT , FieldStatus .PRESENT ]
508+ )
509+
510+ result = convert_response_to_dict (response )
511+ # must not raise
512+ serialized = json .dumps (result )
513+ assert serialized # non-empty
514+
515+
466516class TestPerformance :
467517 """Performance tests to validate the optimization claim."""
468518
0 commit comments