blob: 7a874edfd3345ff07ffb14bede435a3000e15d22 [file] [log] [blame]
################################################################################
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#################################################################################
import tempfile
from pathlib import Path
import pytest
import yaml
from flink_agents.api.configuration import ConfigOption
from flink_agents.plan.configuration import AgentConfiguration
def test_load_configuration_from_file() -> None:
"""Test loading configuration from a YAML file."""
# Create a temporary YAML file with test data
test_data = {
"agent": {
"database": {
"host": "localhost",
"port": 5432,
"credentials": {"username": "admin", "password": "secret"},
},
"api": {"endpoint": "/api/v1", "timeout": 30.0},
"debug": True,
}
}
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
yaml.dump(test_data, f)
config_file = f.name
try:
# Load configuration
config = AgentConfiguration()
config.load_from_file(config_file)
# Test that nested configuration is properly flattened
assert config.get_str('database.host') == 'localhost'
assert config.get_int('database.port') == 5432
assert config.get_str('database.credentials.username') == 'admin'
assert config.get_str('database.credentials.password') == 'secret'
assert config.get_str('api.endpoint') == '/api/v1'
assert config.get_float('api.timeout') == 30.0
assert config.get_bool('debug') is True
finally:
config_file = Path(config_file)
config_file.unlink()
def test_load_configuration_without_path() -> None:
"""Test loading configuration without a path (should not change _conf_data)."""
config = AgentConfiguration()
# Initially _conf_data should be empty or unchanged
original_conf_data = config.get_conf_data().copy()
config.load_from_file(None)
# _conf_data should remain unchanged
assert config.get_conf_data() == original_conf_data
def test_load_configuration_with_invalid_file() -> None:
"""Test loading configuration with a non-existent file."""
config = AgentConfiguration()
with pytest.raises(FileNotFoundError):
config.load_from_file('/path/to/nonexistent/file.yaml')
def test_load_configuration_with_invalid_yaml() -> None:
"""Test loading configuration with invalid YAML content."""
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
f.write('invalid: yaml: content: [')
config_file = f.name
try:
config = AgentConfiguration()
with pytest.raises(yaml.YAMLError):
config.load_from_file(config_file)
finally:
config_file = Path(config_file)
config_file.unlink()
def test_get_int() -> None:
"""Test get_int method with various inputs."""
config = AgentConfiguration({'int_key': 42, 'str_key': '123', 'invalid_key': 'not_an_int'})
# Test normal integer value
assert config.get_int('int_key') == 42
# Test string that can be converted to int
assert config.get_int('str_key') == 123
# Test default value when key is not found
assert config.get_int('missing_key', 999) == 999
# Test default value when no default specified
assert config.get_int('missing_key') is None
# Test invalid value that cannot be converted to int
with pytest.raises(ValueError, match="Invalid value for invalid_key: not_an_int"):
config.get_int('invalid_key')
def test_get_float() -> None:
"""Test get_float method with various inputs."""
config = AgentConfiguration({'float_key': 3.14, 'int_key': 42, 'str_key': '2.5', 'invalid_key': 'not_a_float'})
# Test normal float value
assert config.get_float('float_key') == 3.14
# Test int value converted to float
assert config.get_float('int_key') == 42.0
# Test string that can be converted to float
assert config.get_float('str_key') == 2.5
# Test default value when key is not found
assert config.get_float('missing_key', 1.23) == 1.23
# Test default value when no default specified
assert config.get_float('missing_key') is None
# Test invalid value that cannot be converted to float
with pytest.raises(ValueError, match="Invalid value for invalid_key: not_a_float"):
config.get_float('invalid_key')
def test_get_bool() -> None:
"""Test get_bool method with various inputs."""
config = AgentConfiguration({'bool_key': True, 'false_key': False, 'str_key': 'true'})
# Test normal boolean values
assert config.get_bool('bool_key') is True
assert config.get_bool('false_key') is False
# Test default value when key is not found
assert config.get_bool('missing_key', True) is True
# Test default value when no default specified
assert config.get_bool('missing_key') is None
# Note: bool() in Python behaves differently than might be expected
# bool('true') is True, but that's Python behavior, not a bug in our code
assert config.get_bool('str_key') is True
def test_get_str() -> None:
"""Test get_str method with various inputs."""
config = AgentConfiguration({'str_key': 'hello', 'int_key': 42, 'float_key': 3.14})
# Test normal string value
assert config.get_str('str_key') == 'hello'
# Test int value converted to string
assert config.get_str('int_key') == '42'
# Test float value converted to string
assert config.get_str('float_key') == '3.14'
# Test default value when key is not found
assert config.get_str('missing_key', 'default') == 'default'
# Test default value when no default specified
assert config.get_str('missing_key') is None
# Test None value
assert config.get_str('none_key') is None
def test_get_with_config_option() -> None: # noqa: D103
data = {
"config.str": "config.value",
"config.int": 6789,
"config.float": "45.5",
"config.boolean": True,
}
config = AgentConfiguration(data)
str_option = ConfigOption("config.str", str, "default_str")
int_option = ConfigOption("config.int", int, 123)
float_option = ConfigOption("config.float", float, 0.0)
bool_option = ConfigOption("config.boolean", bool, False)
assert config.get(str_option) == "config.value"
assert config.get(int_option) == 6789
assert config.get(float_option) == 45.5
assert config.get(bool_option) is True
missing_option = ConfigOption("missing.key1", int, 22)
assert config.get(missing_option) == 22
missing_key = ConfigOption("missing.key2", int, None)
assert config.get(missing_key) is None
def test_get_with_default_value() -> None: # noqa: D103
default_str = ConfigOption("default.str", str, "default_value")
default_int = ConfigOption("default.int", int, 100)
default_double = ConfigOption("default.double", float, 2.5)
config = AgentConfiguration()
assert config.get(default_str) == "default_value"
assert config.get(default_int) == 100
assert config.get(default_double) == 2.5
def test_get_with_null_and_default() -> None: # noqa: D103
nullable_str = ConfigOption("nullable.str", str, "default")
config = AgentConfiguration()
config.set_str("nullable.str", None)
assert config.get(nullable_str) == "default"