@@ -16,12 +16,14 @@ def _reset_app_config_between_tests() -> Generator:
1616 # ensure clean state before each test
1717 try :
1818 AppConfig ()._configuration = None # type: ignore[attr-defined]
19+ AppConfig ()._quota_limiters = [] # type: ignore[attr-defined]
1920 except Exception :
2021 pass
2122 yield
2223 # ensure clean state after each test
2324 try :
2425 AppConfig ()._configuration = None # type: ignore[attr-defined]
26+ AppConfig ()._quota_limiters = [] # type: ignore[attr-defined]
2527 except Exception :
2628 pass
2729
@@ -78,10 +80,18 @@ def test_default_configuration() -> None:
7880 # try to read property
7981 _ = cfg .conversation_cache_configuration # pylint: disable=pointless-statement
8082
83+ with pytest .raises (Exception , match = "logic error: configuration is not loaded" ):
84+ # try to read property
85+ _ = cfg .quota_handlers_configuration # pylint: disable=pointless-statement
86+
8187 with pytest .raises (Exception , match = "logic error: configuration is not loaded" ):
8288 # try to read property
8389 _ = cfg .conversation_cache # pylint: disable=pointless-statement
8490
91+ with pytest .raises (Exception , match = "logic error: configuration is not loaded" ):
92+ # try to read property
93+ _ = cfg .quota_limiters # pylint: disable=pointless-statement
94+
8595
8696def test_configuration_is_singleton () -> None :
8797 """Test that configuration is singleton."""
@@ -675,3 +685,124 @@ def test_configuration_with_in_memory_conversation_cache(tmpdir: Path) -> None:
675685 assert cfg .conversation_cache_configuration .memory is not None
676686 assert cfg .conversation_cache is not None
677687 assert isinstance (cfg .conversation_cache , InMemoryCache )
688+
689+
690+ def test_configuration_with_quota_handlers_no_storage (tmpdir : Path ) -> None :
691+ """Test loading configuration from YAML file with quota handlers configuration."""
692+ cfg_filename = tmpdir / "config.yaml"
693+ with open (cfg_filename , "w" , encoding = "utf-8" ) as fout :
694+ fout .write (
695+ """
696+ name: test service
697+ service:
698+ host: localhost
699+ port: 8080
700+ auth_enabled: false
701+ workers: 1
702+ color_log: true
703+ access_log: true
704+ llama_stack:
705+ use_as_library_client: false
706+ url: http://localhost:8321
707+ api_key: test-key
708+ user_data_collection:
709+ feedback_enabled: false
710+ quota_handlers:
711+ limiters:
712+ - name: user_monthly_limits
713+ type: user_limiter
714+ initial_quota: 10
715+ quota_increase: 10
716+ period: "2 seconds"
717+ - name: cluster_monthly_limits
718+ type: cluster_limiter
719+ initial_quota: 100
720+ quota_increase: 10
721+ period: "10 seconds"
722+ scheduler:
723+ # scheduler ticks in seconds
724+ period: 1
725+ """
726+ )
727+
728+ cfg = AppConfig ()
729+ cfg .load_configuration (str (cfg_filename ))
730+
731+ assert cfg .quota_handlers_configuration is not None
732+ assert cfg .quota_handlers_configuration .sqlite is None
733+ assert cfg .quota_handlers_configuration .postgres is None
734+ assert cfg .quota_handlers_configuration .limiters is not None
735+ assert cfg .quota_handlers_configuration .scheduler is not None
736+
737+ # check the quota limiters configuration
738+ assert len (cfg .quota_limiters ) == 0
739+
740+ # check the scheduler configuration
741+ assert cfg .quota_handlers_configuration .scheduler .period == 1
742+
743+
744+ def test_configuration_with_quota_handlers (tmpdir : Path ) -> None :
745+ """Test loading configuration from YAML file with quota handlers configuration."""
746+ cfg_filename = tmpdir / "config.yaml"
747+ with open (cfg_filename , "w" , encoding = "utf-8" ) as fout :
748+ fout .write (
749+ """
750+ name: test service
751+ service:
752+ host: localhost
753+ port: 8080
754+ auth_enabled: false
755+ workers: 1
756+ color_log: true
757+ access_log: true
758+ llama_stack:
759+ use_as_library_client: false
760+ url: http://localhost:8321
761+ api_key: test-key
762+ user_data_collection:
763+ feedback_enabled: false
764+ quota_handlers:
765+ sqlite:
766+ db_path: ":memory:"
767+ limiters:
768+ - name: user_monthly_limits
769+ type: user_limiter
770+ initial_quota: 10
771+ quota_increase: 10
772+ period: "2 seconds"
773+ - name: cluster_monthly_limits
774+ type: cluster_limiter
775+ initial_quota: 100
776+ quota_increase: 10
777+ period: "10 seconds"
778+ scheduler:
779+ # scheduler ticks in seconds
780+ period: 1
781+ """
782+ )
783+
784+ cfg = AppConfig ()
785+ cfg .load_configuration (str (cfg_filename ))
786+
787+ assert cfg .quota_handlers_configuration is not None
788+ assert cfg .quota_handlers_configuration .sqlite is not None
789+ assert cfg .quota_handlers_configuration .postgres is None
790+ assert cfg .quota_handlers_configuration .limiters is not None
791+ assert cfg .quota_handlers_configuration .scheduler is not None
792+
793+ # check the storage
794+ assert cfg .quota_handlers_configuration .sqlite .db_path == ":memory:"
795+
796+ # check the quota limiters configuration
797+ assert len (cfg .quota_limiters ) == 2
798+ assert (
799+ str (cfg .quota_limiters [0 ])
800+ == "UserQuotaLimiter: initial quota: 10 increase by: 10"
801+ )
802+ assert (
803+ str (cfg .quota_limiters [1 ])
804+ == "ClusterQuotaLimiter: initial quota: 100 increase by: 10"
805+ )
806+
807+ # check the scheduler configuration
808+ assert cfg .quota_handlers_configuration .scheduler .period == 1
0 commit comments