@@ -128,3 +128,127 @@ def test_get_features_for_entity(redis_online_store: RedisOnlineStore, feature_v
128128 assert "feature_view_1:feature_11" in features
129129 assert features ["feature_view_1:feature_10" ].int32_val == 1
130130 assert features ["feature_view_1:feature_11" ].int32_val == 2
131+
132+
133+ def test_get_features_for_entity_with_memoryview (
134+ redis_online_store : RedisOnlineStore , feature_view
135+ ):
136+ """Test that _get_features_for_entity handles memoryview inputs correctly.
137+
138+ Redis may return memoryview objects instead of bytes in some cases.
139+ The optimized code should handle both without unnecessary conversions.
140+ """
141+ requested_features = [
142+ "feature_view_1:feature_10" ,
143+ "feature_view_1:feature_11" ,
144+ "_ts:feature_view_1" ,
145+ ]
146+ # Create memoryview objects to simulate redis returning memoryview
147+ val1_bytes = ValueProto (int32_val = 100 ).SerializeToString ()
148+ val2_bytes = ValueProto (int32_val = 200 ).SerializeToString ()
149+ ts_bytes = Timestamp (seconds = 1234567890 , nanos = 123456789 ).SerializeToString ()
150+
151+ values = [
152+ memoryview (val1_bytes ),
153+ memoryview (val2_bytes ),
154+ memoryview (ts_bytes ),
155+ ]
156+
157+ timestamp , features = redis_online_store ._get_features_for_entity (
158+ values = values ,
159+ feature_view = feature_view .name ,
160+ requested_features = requested_features ,
161+ )
162+ assert features ["feature_view_1:feature_10" ].int32_val == 100
163+ assert features ["feature_view_1:feature_11" ].int32_val == 200
164+ assert timestamp is not None
165+
166+
167+ def test_get_features_for_entity_with_none_values (
168+ redis_online_store : RedisOnlineStore , feature_view
169+ ):
170+ """Test that _get_features_for_entity handles None values correctly."""
171+ requested_features = [
172+ "feature_view_1:feature_10" ,
173+ "feature_view_1:feature_11" ,
174+ "_ts:feature_view_1" ,
175+ ]
176+ values = [
177+ ValueProto (int32_val = 1 ).SerializeToString (),
178+ None , # Missing feature value
179+ Timestamp ().SerializeToString (),
180+ ]
181+
182+ timestamp , features = redis_online_store ._get_features_for_entity (
183+ values = values ,
184+ feature_view = feature_view .name ,
185+ requested_features = requested_features ,
186+ )
187+ assert features ["feature_view_1:feature_10" ].int32_val == 1
188+ # None value should result in empty ValueProto
189+ assert features ["feature_view_1:feature_11" ].WhichOneof ("val" ) is None
190+
191+
192+ def test_convert_redis_values_to_protobuf_multiple_entities (
193+ redis_online_store : RedisOnlineStore , feature_view
194+ ):
195+ """Test batch conversion with multiple entities."""
196+ requested_features = [
197+ "feature_view_1:feature_10" ,
198+ "feature_view_1:feature_11" ,
199+ "_ts:feature_view_1" ,
200+ ]
201+ # Multiple entity values
202+ values = [
203+ [
204+ ValueProto (int32_val = 1 ).SerializeToString (),
205+ ValueProto (int32_val = 2 ).SerializeToString (),
206+ Timestamp (seconds = 1000 ).SerializeToString (),
207+ ],
208+ [
209+ ValueProto (int32_val = 10 ).SerializeToString (),
210+ ValueProto (int32_val = 20 ).SerializeToString (),
211+ Timestamp (seconds = 2000 ).SerializeToString (),
212+ ],
213+ [
214+ ValueProto (int32_val = 100 ).SerializeToString (),
215+ ValueProto (int32_val = 200 ).SerializeToString (),
216+ Timestamp (seconds = 3000 ).SerializeToString (),
217+ ],
218+ ]
219+
220+ results = redis_online_store ._convert_redis_values_to_protobuf (
221+ redis_values = values ,
222+ feature_view = feature_view .name ,
223+ requested_features = requested_features ,
224+ )
225+
226+ assert len (results ) == 3
227+ assert results [0 ][1 ]["feature_view_1:feature_10" ].int32_val == 1
228+ assert results [1 ][1 ]["feature_view_1:feature_10" ].int32_val == 10
229+ assert results [2 ][1 ]["feature_view_1:feature_10" ].int32_val == 100
230+
231+
232+ def test_get_features_for_entity_with_all_none_values (
233+ redis_online_store : RedisOnlineStore , feature_view
234+ ):
235+ """Test that None feature values result in empty ValueProto objects."""
236+ requested_features = [
237+ "feature_view_1:feature_10" ,
238+ "_ts:feature_view_1" ,
239+ ]
240+ # All None values except timestamp
241+ values = [
242+ None ,
243+ Timestamp ().SerializeToString (),
244+ ]
245+
246+ timestamp , features = redis_online_store ._get_features_for_entity (
247+ values = values ,
248+ feature_view = feature_view .name ,
249+ requested_features = requested_features ,
250+ )
251+ # Even with None value, an empty ValueProto is created
252+ assert features is not None
253+ assert "feature_view_1:feature_10" in features
254+ assert features ["feature_view_1:feature_10" ].WhichOneof ("val" ) is None
0 commit comments