mod error;
mod environment;
mod config;
mod builder;
mod toml_ext;
mod custom_values;
use std::fs::{self, File};
use std::collections::HashMap;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::process;
use std::env;
use toml;
pub use self::custom_values::Limits;
pub use toml::value::{Array, Table, Value, Datetime};
pub use self::error::ConfigError;
pub use self::environment::Environment;
pub use self::config::Config;
pub use self::builder::ConfigBuilder;
pub use logger::LoggingLevel;
crate use self::toml_ext::LoggedValue;
use logger;
use self::Environment::*;
use self::environment::CONFIG_ENV;
use logger::COLORS_ENV;
use self::toml_ext::parse_simple_toml_value;
use http::uncased::uncased_eq;
const CONFIG_FILENAME: &str = "Rocket.toml";
const GLOBAL_ENV_NAME: &str = "global";
const ENV_VAR_PREFIX: &str = "ROCKET_";
const PREHANDLED_VARS: [&str; 3] = ["ROCKET_CODEGEN_DEBUG", CONFIG_ENV, COLORS_ENV];
pub type Result<T> = ::std::result::Result<T, ConfigError>;
#[doc(hidden)]
#[derive(Debug, PartialEq)]
pub struct RocketConfig {
pub active_env: Environment,
config: HashMap<Environment, Config>,
}
impl RocketConfig {
pub fn read() -> Result<RocketConfig> {
let file = RocketConfig::find()?;
let mut handle = File::open(&file).map_err(|_| ConfigError::IoError)?;
let mut contents = String::new();
handle.read_to_string(&mut contents).map_err(|_| ConfigError::IoError)?;
RocketConfig::parse(contents, &file)
}
pub fn active_default_from(filename: Option<&Path>) -> Result<RocketConfig> {
let mut defaults = HashMap::new();
if let Some(path) = filename {
defaults.insert(Development, Config::default_from(Development, &path)?);
defaults.insert(Staging, Config::default_from(Staging, &path)?);
defaults.insert(Production, Config::default_from(Production, &path)?);
} else {
defaults.insert(Development, Config::default(Development));
defaults.insert(Staging, Config::default(Staging));
defaults.insert(Production, Config::default(Production));
}
let mut config = RocketConfig {
active_env: Environment::active()?,
config: defaults,
};
config.override_from_env()?;
Ok(config)
}
pub fn active_default() -> Result<RocketConfig> {
RocketConfig::active_default_from(None)
}
fn find() -> Result<PathBuf> {
let cwd = env::current_dir().map_err(|_| ConfigError::NotFound)?;
let mut current = cwd.as_path();
loop {
let manifest = current.join(CONFIG_FILENAME);
if fs::metadata(&manifest).is_ok() {
return Ok(manifest)
}
match current.parent() {
Some(p) => current = p,
None => break,
}
}
Err(ConfigError::NotFound)
}
#[inline]
fn get_mut(&mut self, env: Environment) -> &mut Config {
match self.config.get_mut(&env) {
Some(config) => config,
None => panic!("set(): {} config is missing.", env),
}
}
fn set_from_table(&mut self, env: Environment, kvs: &Table) -> Result<()> {
for (key, value) in kvs {
self.get_mut(env).set_raw(key, value)?;
}
Ok(())
}
pub fn get(&self, env: Environment) -> &Config {
match self.config.get(&env) {
Some(config) => config,
None => panic!("get(): {} config is missing.", env),
}
}
#[inline]
pub fn active(&self) -> &Config {
self.get(self.active_env)
}
fn override_from_env(&mut self) -> Result<()> {
for (key, val) in env::vars() {
if key.len() < ENV_VAR_PREFIX.len() {
continue
} else if !uncased_eq(&key[..ENV_VAR_PREFIX.len()], ENV_VAR_PREFIX) {
continue
}
if PREHANDLED_VARS.iter().any(|var| uncased_eq(&key, var)) {
continue
}
let key = key[ENV_VAR_PREFIX.len()..].to_lowercase();
let toml_val = match parse_simple_toml_value(&val) {
Ok(val) => val,
Err(e) => return Err(ConfigError::BadEnvVal(key, val, e))
};
for env in &Environment::ALL {
match self.get_mut(*env).set_raw(&key, &toml_val) {
Err(ConfigError::BadType(_, exp, actual, _)) => {
let e = format!("expected {}, but found {}", exp, actual);
return Err(ConfigError::BadEnvVal(key, val, e))
}
Err(e) => return Err(e),
Ok(_) => { }
}
}
}
Ok(())
}
fn parse<P: AsRef<Path>>(src: String, filename: P) -> Result<RocketConfig> {
use self::ConfigError::ParseError;
let path = filename.as_ref().to_path_buf();
let table = match src.parse::<toml::Value>() {
Ok(toml::Value::Table(table)) => table,
Ok(value) => {
let err = format!("expected a table, found {}", value.type_str());
return Err(ConfigError::ParseError(src, path, err, Some((1, 1))));
}
Err(e) => return Err(ParseError(src, path, e.to_string(), e.line_col()))
};
let mut config = RocketConfig::active_default_from(Some(filename.as_ref()))?;
let mut global = None;
for (entry, value) in table {
let kv_pairs = match value.as_table() {
Some(table) => table,
None => return Err(ConfigError::BadType(
entry, "a table", value.type_str(), Some(path.clone())
))
};
if entry.as_str() == GLOBAL_ENV_NAME {
global = Some(kv_pairs.clone());
continue;
}
match entry.as_str().parse() {
Ok(env) => config.set_from_table(env, kv_pairs)?,
Err(_) => Err(ConfigError::BadEntry(entry.clone(), path.clone()))?
}
}
if let Some(ref global_kv_pairs) = global {
for env in &Environment::ALL {
config.set_from_table(*env, global_kv_pairs)?;
}
}
config.override_from_env()?;
Ok(config)
}
}
crate fn init() -> Config {
let bail = |e: ConfigError| -> ! {
logger::init(LoggingLevel::Debug);
e.pretty_print();
process::exit(1)
};
use self::ConfigError::*;
let config = RocketConfig::read().unwrap_or_else(|e| {
match e {
| ParseError(..) | BadEntry(..) | BadEnv(..) | BadType(..) | Io(..)
| BadFilePath(..) | BadEnvVal(..) | UnknownKey(..)
| Missing(..) => bail(e),
IoError => warn!("Failed reading Rocket.toml. Using defaults."),
NotFound => { }
}
RocketConfig::active_default().unwrap_or_else(|e| bail(e))
});
config.active().clone()
}
#[cfg(test)]
mod test {
use std::env;
use std::sync::Mutex;
use super::{RocketConfig, Config, ConfigError, ConfigBuilder};
use super::{Environment, GLOBAL_ENV_NAME};
use super::environment::CONFIG_ENV;
use super::Environment::*;
use super::Result;
use ::logger::LoggingLevel;
const TEST_CONFIG_FILENAME: &'static str = "/tmp/testing/Rocket.toml";
lazy_static! {
static ref ENV_LOCK: Mutex<usize> = Mutex::new(0);
}
macro_rules! check_config {
($rconfig:expr, $econfig:expr) => (
let expected = $econfig.finalize().unwrap();
match $rconfig {
Ok(config) => assert_eq!(config.active(), &expected),
Err(e) => panic!("Config {} failed: {:?}", stringify!($rconfig), e)
}
);
($env:expr, $rconfig:expr, $econfig:expr) => (
let expected = $econfig.finalize().unwrap();
match $rconfig {
Ok(ref config) => assert_eq!(config.get($env), &expected),
Err(ref e) => panic!("Config {} failed: {:?}", stringify!($rconfig), e)
}
);
}
fn active_default() -> Result<RocketConfig> {
RocketConfig::active_default()
}
fn default_config(env: Environment) -> ConfigBuilder {
ConfigBuilder::new(env)
}
#[test]
fn test_defaults() {
let _env_lock = ENV_LOCK.lock().unwrap();
env::remove_var(CONFIG_ENV);
#[cfg(debug_assertions)] check_config!(active_default(), default_config(Development));
#[cfg(not(debug_assertions))] check_config!(active_default(), default_config(Production));
for env in &["development", "dev"] {
env::set_var(CONFIG_ENV, env);
check_config!(active_default(), default_config(Development));
}
for env in &["stage", "staging"] {
env::set_var(CONFIG_ENV, env);
check_config!(active_default(), default_config(Staging));
}
for env in &["prod", "production"] {
env::set_var(CONFIG_ENV, env);
check_config!(active_default(), default_config(Production));
}
}
#[test]
fn test_bad_environment_vars() {
let _env_lock = ENV_LOCK.lock().unwrap();
for env in &["", "p", "pr", "pro", "prodo", " prod", "dev ", "!dev!", "🚀 "] {
env::set_var(CONFIG_ENV, env);
let err = ConfigError::BadEnv(env.to_string());
assert!(active_default().err().map_or(false, |e| e == err));
}
env::remove_var(CONFIG_ENV);
for env in &["p", "pr", "pro", "prodo", "bad", "meow", "this", "that"] {
let toml_table = format!("[{}]\n", env);
let e_str = env.to_string();
let err = ConfigError::BadEntry(e_str, TEST_CONFIG_FILENAME.into());
assert!(RocketConfig::parse(toml_table, TEST_CONFIG_FILENAME)
.err().map_or(false, |e| e == err));
}
}
#[test]
fn test_good_full_config_files() {
let _env_lock = ENV_LOCK.lock().unwrap();
env::remove_var(CONFIG_ENV);
let config_str = r#"
address = "1.2.3.4"
port = 7810
workers = 21
log = "critical"
keep_alive = 0
secret_key = "8Xui8SN4mI+7egV/9dlfYYLGQJeEx4+DwmSQLwDVXJg="
template_dir = "mine"
json = true
pi = 3.14
"#;
let mut expected = default_config(Development)
.address("1.2.3.4")
.port(7810)
.workers(21)
.log_level(LoggingLevel::Critical)
.keep_alive(0)
.secret_key("8Xui8SN4mI+7egV/9dlfYYLGQJeEx4+DwmSQLwDVXJg=")
.extra("template_dir", "mine")
.extra("json", true)
.extra("pi", 3.14);
expected.environment = Development;
let dev_config = ["[dev]", config_str].join("\n");
let parsed = RocketConfig::parse(dev_config, TEST_CONFIG_FILENAME);
check_config!(Development, parsed, expected.clone());
check_config!(Staging, parsed, default_config(Staging));
check_config!(Production, parsed, default_config(Production));
expected.environment = Staging;
let stage_config = ["[stage]", config_str].join("\n");
let parsed = RocketConfig::parse(stage_config, TEST_CONFIG_FILENAME);
check_config!(Staging, parsed, expected.clone());
check_config!(Development, parsed, default_config(Development));
check_config!(Production, parsed, default_config(Production));
expected.environment = Production;
let prod_config = ["[prod]", config_str].join("\n");
let parsed = RocketConfig::parse(prod_config, TEST_CONFIG_FILENAME);
check_config!(Production, parsed, expected);
check_config!(Development, parsed, default_config(Development));
check_config!(Staging, parsed, default_config(Staging));
}
#[test]
fn test_good_address_values() {
let _env_lock = ENV_LOCK.lock().unwrap();
env::set_var(CONFIG_ENV, "dev");
check_config!(RocketConfig::parse(r#"
[development]
address = "localhost"
"#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Development).address("localhost")
});
check_config!(RocketConfig::parse(r#"
[development]
address = "127.0.0.1"
"#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Development).address("127.0.0.1")
});
check_config!(RocketConfig::parse(r#"
[development]
address = "::"
"#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Development).address("::")
});
check_config!(RocketConfig::parse(r#"
[dev]
address = "2001:db8::370:7334"
"#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Development).address("2001:db8::370:7334")
});
check_config!(RocketConfig::parse(r#"
[dev]
address = "0.0.0.0"
"#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Development).address("0.0.0.0")
});
}
#[test]
fn test_bad_address_values() {
let _env_lock = ENV_LOCK.lock().unwrap();
env::remove_var(CONFIG_ENV);
assert!(RocketConfig::parse(r#"
[development]
address = 0000
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#"
[development]
address = true
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#"
[development]
address = "........"
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#"
[staging]
address = "1.2.3.4:100"
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
}
#[test]
fn test_good_tls_values() {
let _env_lock = ENV_LOCK.lock().unwrap();
env::set_var(CONFIG_ENV, "dev");
assert!(RocketConfig::parse(r#"
[staging]
tls = { certs = "some/path.pem", key = "some/key.pem" }
"#.to_string(), TEST_CONFIG_FILENAME).is_ok());
assert!(RocketConfig::parse(r#"
[staging.tls]
certs = "some/path.pem"
key = "some/key.pem"
"#.to_string(), TEST_CONFIG_FILENAME).is_ok());
assert!(RocketConfig::parse(r#"
[global.tls]
certs = "some/path.pem"
key = "some/key.pem"
"#.to_string(), TEST_CONFIG_FILENAME).is_ok());
assert!(RocketConfig::parse(r#"
[global]
tls = { certs = "some/path.pem", key = "some/key.pem" }
"#.to_string(), TEST_CONFIG_FILENAME).is_ok());
}
#[test]
fn test_bad_tls_config() {
let _env_lock = ENV_LOCK.lock().unwrap();
env::remove_var(CONFIG_ENV);
assert!(RocketConfig::parse(r#"
[development]
tls = "hello"
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#"
[development]
tls = { certs = "some/path.pem" }
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#"
[development]
tls = { certs = "some/path.pem", key = "some/key.pem", extra = "bah" }
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#"
[staging]
tls = { cert = "some/path.pem", key = "some/key.pem" }
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
}
#[test]
fn test_good_port_values() {
let _env_lock = ENV_LOCK.lock().unwrap();
env::set_var(CONFIG_ENV, "stage");
check_config!(RocketConfig::parse(r#"
[stage]
port = 100
"#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).port(100)
});
check_config!(RocketConfig::parse(r#"
[stage]
port = 6000
"#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).port(6000)
});
check_config!(RocketConfig::parse(r#"
[stage]
port = 65535
"#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).port(65535)
});
}
#[test]
fn test_bad_port_values() {
let _env_lock = ENV_LOCK.lock().unwrap();
env::remove_var(CONFIG_ENV);
assert!(RocketConfig::parse(r#"
[development]
port = true
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#"
[production]
port = "hello"
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#"
[staging]
port = -1
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#"
[staging]
port = 65536
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#"
[staging]
port = 105836
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
}
#[test]
fn test_good_workers_values() {
let _env_lock = ENV_LOCK.lock().unwrap();
env::set_var(CONFIG_ENV, "stage");
check_config!(RocketConfig::parse(r#"
[stage]
workers = 1
"#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).workers(1)
});
check_config!(RocketConfig::parse(r#"
[stage]
workers = 300
"#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).workers(300)
});
check_config!(RocketConfig::parse(r#"
[stage]
workers = 65535
"#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).workers(65535)
});
}
#[test]
fn test_bad_workers_values() {
let _env_lock = ENV_LOCK.lock().unwrap();
env::remove_var(CONFIG_ENV);
assert!(RocketConfig::parse(r#"
[development]
workers = true
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#"
[production]
workers = "hello"
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#"
[staging]
workers = -1
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#"
[staging]
workers = 65536
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#"
[staging]
workers = 105836
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
}
#[test]
fn test_good_keep_alives() {
let _env_lock = ENV_LOCK.lock().unwrap();
env::set_var(CONFIG_ENV, "stage");
check_config!(RocketConfig::parse(r#"
[stage]
keep_alive = 10
"#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).keep_alive(10)
});
check_config!(RocketConfig::parse(r#"
[stage]
keep_alive = 0
"#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).keep_alive(0)
});
check_config!(RocketConfig::parse(r#"
[stage]
keep_alive = 348
"#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).keep_alive(348)
});
check_config!(RocketConfig::parse(r#"
[stage]
keep_alive = 0
"#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).keep_alive(0)
});
}
#[test]
fn test_bad_keep_alives() {
let _env_lock = ENV_LOCK.lock().unwrap();
env::remove_var(CONFIG_ENV);
assert!(RocketConfig::parse(r#"
[dev]
keep_alive = true
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#"
[dev]
keep_alive = -10
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#"
[dev]
keep_alive = "Some(10)"
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#"
[dev]
keep_alive = 4294967296
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
}
#[test]
fn test_good_log_levels() {
let _env_lock = ENV_LOCK.lock().unwrap();
env::set_var(CONFIG_ENV, "stage");
check_config!(RocketConfig::parse(r#"
[stage]
log = "normal"
"#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).log_level(LoggingLevel::Normal)
});
check_config!(RocketConfig::parse(r#"
[stage]
log = "debug"
"#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).log_level(LoggingLevel::Debug)
});
check_config!(RocketConfig::parse(r#"
[stage]
log = "critical"
"#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).log_level(LoggingLevel::Critical)
});
check_config!(RocketConfig::parse(r#"
[stage]
log = "off"
"#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).log_level(LoggingLevel::Off)
});
}
#[test]
fn test_bad_log_level_values() {
let _env_lock = ENV_LOCK.lock().unwrap();
env::remove_var(CONFIG_ENV);
assert!(RocketConfig::parse(r#"
[dev]
log = false
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#"
[development]
log = 0
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#"
[prod]
log = "no"
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
}
#[test]
fn test_good_secret_key() {
let _env_lock = ENV_LOCK.lock().unwrap();
env::set_var(CONFIG_ENV, "stage");
check_config!(RocketConfig::parse(r#"
[stage]
secret_key = "TpUiXK2d/v5DFxJnWL12suJKPExKR8h9zd/o+E7SU+0="
"#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).secret_key(
"TpUiXK2d/v5DFxJnWL12suJKPExKR8h9zd/o+E7SU+0="
)
});
check_config!(RocketConfig::parse(r#"
[stage]
secret_key = "jTyprDberFUiUFsJ3vcb1XKsYHWNBRvWAnXTlbTgGFU="
"#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).secret_key(
"jTyprDberFUiUFsJ3vcb1XKsYHWNBRvWAnXTlbTgGFU="
)
});
}
#[test]
fn test_bad_secret_key() {
let _env_lock = ENV_LOCK.lock().unwrap();
env::remove_var(CONFIG_ENV);
assert!(RocketConfig::parse(r#"
[dev]
secret_key = true
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#"
[dev]
secret_key = 1283724897238945234897
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#"
[dev]
secret_key = "abcv"
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
}
#[test]
fn test_bad_toml() {
let _env_lock = ENV_LOCK.lock().unwrap();
env::remove_var(CONFIG_ENV);
assert!(RocketConfig::parse(r#"
[dev
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#"
[dev]
1. = 2
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#"
[dev]
secret_key = "abcv" = other
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
}
#[test]
fn test_global_overrides() {
let _env_lock = ENV_LOCK.lock().unwrap();
for env in &Environment::ALL {
env::set_var(CONFIG_ENV, env.to_string());
check_config!(RocketConfig::parse(format!(r#"
[{}]
address = "::1"
"#, GLOBAL_ENV_NAME), TEST_CONFIG_FILENAME), {
default_config(*env).address("::1")
});
check_config!(RocketConfig::parse(format!(r#"
[{}]
database = "mysql"
"#, GLOBAL_ENV_NAME), TEST_CONFIG_FILENAME), {
default_config(*env).extra("database", "mysql")
});
check_config!(RocketConfig::parse(format!(r#"
[{}]
port = 3980
"#, GLOBAL_ENV_NAME), TEST_CONFIG_FILENAME), {
default_config(*env).port(3980)
});
}
}
#[test]
fn test_env_override() {
let _env_lock = ENV_LOCK.lock().unwrap();
let pairs = [
("log", "critical"), ("LOG", "debug"), ("PORT", "8110"),
("address", "1.2.3.4"), ("EXTRA_EXTRA", "true"), ("workers", "3")
];
let check_value = |key: &str, val: &str, config: &Config| {
match key {
"log" => assert_eq!(config.log_level, val.parse().unwrap()),
"port" => assert_eq!(config.port, val.parse().unwrap()),
"address" => assert_eq!(config.address, val),
"extra_extra" => assert_eq!(config.get_bool(key).unwrap(), true),
"workers" => assert_eq!(config.workers, val.parse().unwrap()),
_ => panic!("Unexpected key: {}", key)
}
};
for &(key, val) in &pairs {
env::set_var(format!("ROCKET_{}", key), val);
let rconfig = active_default().unwrap();
for env in &Environment::ALL {
env::set_var(CONFIG_ENV, env.to_string());
let rconfig = active_default().unwrap();
check_value(&*key.to_lowercase(), val, rconfig.active());
}
for env in &Environment::ALL {
check_value(&*key.to_lowercase(), val, rconfig.get(*env));
}
}
for &(key, _) in &pairs {
env::remove_var(format!("ROCKET_{}", key))
}
let toml = r#"
[dev]
address = "1.2.3.4"
[stage]
address = "2.3.4.5"
[prod]
address = "10.1.1.1"
[global]
address = "1.2.3.4"
port = 7810
workers = 21
log = "normal"
"#.to_string();
for &(key, val) in &pairs {
env::set_var(format!("ROCKET_{}", key), val);
let r = RocketConfig::parse(toml.clone(), TEST_CONFIG_FILENAME).unwrap();
check_value(&*key.to_lowercase(), val, r.active());
for env in &Environment::ALL {
check_value(&*key.to_lowercase(), val, r.get(*env));
}
}
for &(key, _) in &pairs {
env::remove_var(format!("ROCKET_{}", key))
}
}
}