@@ -441,6 +441,82 @@ def test_online_retrieval_with_event_timestamps(
441441 )
442442
443443
444+ @pytest .mark .integration
445+ @pytest .mark .universal_online_stores
446+ @pytest .mark .goserver
447+ @pytest .mark .parametrize ("full_feature_names" , [True , False ], ids = lambda v : str (v ))
448+ def test_stream_feature_view_online_retrieval (
449+ environment , universal_data_sources , feature_server_endpoint , full_feature_names
450+ ):
451+ """
452+ Tests materialization and online retrieval for stream feature views.
453+
454+ This test is separate from test_online_retrieval since combining feature views and
455+ stream feature views into a single test resulted in test flakiness. This is tech
456+ debt that should be resolved soon.
457+ """
458+ # Set up feature store.
459+ fs = environment .feature_store
460+ entities , datasets , data_sources = universal_data_sources
461+ feature_views = construct_universal_feature_views (data_sources )
462+ pushable_feature_view = feature_views .pushed_locations
463+ fs .apply ([location (), pushable_feature_view ])
464+
465+ # Materialize.
466+ fs .materialize (
467+ environment .start_date - timedelta (days = 1 ),
468+ environment .end_date + timedelta (days = 1 ),
469+ )
470+
471+ # Get online features by randomly sampling 10 entities that exist in the batch source.
472+ sample_locations = datasets .location_df .sample (10 )["location_id" ]
473+ entity_rows = [
474+ {"location_id" : sample_location } for sample_location in sample_locations
475+ ]
476+
477+ feature_refs = [
478+ "pushable_location_stats:temperature" ,
479+ ]
480+ unprefixed_feature_refs = [f .rsplit (":" , 1 )[- 1 ] for f in feature_refs if ":" in f ]
481+
482+ online_features_dict = get_online_features_dict (
483+ environment = environment ,
484+ endpoint = feature_server_endpoint ,
485+ features = feature_refs ,
486+ entity_rows = entity_rows ,
487+ full_feature_names = full_feature_names ,
488+ )
489+
490+ # Check that the response has the expected set of keys.
491+ keys = set (online_features_dict .keys ())
492+ expected_keys = set (
493+ f .replace (":" , "__" ) if full_feature_names else f .split (":" )[- 1 ]
494+ for f in feature_refs
495+ ) | {"location_id" }
496+ assert (
497+ keys == expected_keys
498+ ), f"Response keys are different from expected: { keys - expected_keys } (extra) and { expected_keys - keys } (missing)"
499+
500+ # Check that the feature values match.
501+ tc = unittest .TestCase ()
502+ for i , entity_row in enumerate (entity_rows ):
503+ df_features = get_latest_feature_values_from_location_df (
504+ entity_row , datasets .location_df
505+ )
506+
507+ assert df_features ["location_id" ] == online_features_dict ["location_id" ][i ]
508+ for unprefixed_feature_ref in unprefixed_feature_refs :
509+ tc .assertAlmostEqual (
510+ df_features [unprefixed_feature_ref ],
511+ online_features_dict [
512+ response_feature_name (
513+ unprefixed_feature_ref , feature_refs , full_feature_names
514+ )
515+ ][i ],
516+ delta = 0.0001 ,
517+ )
518+
519+
444520@pytest .mark .integration
445521@pytest .mark .universal_online_stores
446522@pytest .mark .goserver
@@ -859,6 +935,10 @@ def get_latest_feature_values_for_location_df(entity_row, origin_df, destination
859935 }
860936
861937
938+ def get_latest_feature_values_from_location_df (entity_row , location_df ):
939+ return get_latest_row (entity_row , location_df , "location_id" , "location_id" )
940+
941+
862942def assert_feature_service_correctness (
863943 environment ,
864944 endpoint ,
0 commit comments