Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use builder to create Config #109

Merged
merged 2 commits into from
Oct 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions src/config/builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use super::{Config, ConnectionConfig, Filter, Local};

/// Builder for a [`Config`]
#[derive(Debug)]
pub struct Builder {
pub local: Local,
pub filters: Vec<Filter>,
pub connections: ConnectionConfig,
}

impl Builder {
/// Returns a [`Builder`] with empty values.
pub fn empty() -> Self {
Builder {
local: Local { port: 0 },
filters: vec![],
connections: ConnectionConfig::Server { endpoints: vec![] },
}
}

pub fn with_local(self, local: Local) -> Self {
Builder { local, ..self }
}

pub fn with_filters(self, filters: Vec<Filter>) -> Self {
Builder { filters, ..self }
}

pub fn with_connections(self, connections: ConnectionConfig) -> Self {
Builder {
connections,
..self
}
}

pub fn build(self) -> Config {
Config {
local: self.local,
filters: self.filters,
connections: self.connections,
phantom: None,
}
}
}
20 changes: 20 additions & 0 deletions src/config/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use crate::extensions::Error as FilterRegistryError;
use std::fmt::{self, Display, Formatter};

/// Validation failure for a Config
#[derive(Debug, PartialEq)]
pub enum ValidationError {
NotUnique(String),
FilterInvalid(FilterRegistryError),
}

impl Display for ValidationError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
ValidationError::NotUnique(field) => write!(f, "field {} is not unique", field),
ValidationError::FilterInvalid(reason) => {
write!(f, "filter configuration is invalid: {}", reason)
}
}
}
}
109 changes: 46 additions & 63 deletions src/config.rs → src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,21 @@
* limitations under the License.
*/

use crate::extensions::Error as FilterRegistryError;
use std::collections::HashSet;
use std::fmt;
use std::io;
use std::marker::PhantomData;
use std::net::SocketAddr;

use base64_serde::base64_serde_type;
use serde::export::Formatter;
use serde::{Deserialize, Serialize};

base64_serde_type!(Base64Standard, base64::STANDARD);
mod builder;
mod error;

/// Validation failure for a Config
#[derive(Debug, PartialEq)]
pub enum ValidationError {
NotUnique(String),
FilterInvalid(FilterRegistryError),
}
pub use builder::Builder;
pub use error::ValidationError;

impl fmt::Display for ValidationError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ValidationError::NotUnique(field) => write!(f, "field {} is not unique", field),
ValidationError::FilterInvalid(reason) => {
write!(f, "filter configuration is invalid: {}", reason)
}
}
}
}
base64_serde_type!(Base64Standard, base64::STANDARD);

/// Config is the configuration for either a Client or Server proxy
#[derive(Debug, Deserialize, Serialize)]
Expand All @@ -52,6 +38,10 @@ pub struct Config {
pub filters: Vec<Filter>,
#[serde(flatten)]
pub connections: ConnectionConfig,

// Limit struct creation to the builder. We use an Optional<Phantom>
// so that we can create instances though deserialization.
pub(super) phantom: Option<PhantomData<()>>,
}

/// Local is the local host configuration options
Expand Down Expand Up @@ -180,31 +170,29 @@ mod tests {
use serde_yaml::Value;

use crate::config::{
Config, ConnectionConfig, ConnectionId, EndPoint, LoadBalancerPolicy, Local,
Builder, Config, ConnectionConfig, ConnectionId, EndPoint, LoadBalancerPolicy, Local,
ValidationError,
};

#[test]
fn deserialise_client() {
let config = Config {
local: Local { port: 7000 },
filters: vec![],
connections: ConnectionConfig::Client {
let config = Builder::empty()
.with_local(Local { port: 7000 })
.with_connections(ConnectionConfig::Client {
addresses: vec!["127.0.0.1:25999".parse().unwrap()],
connection_id: "1234".into(),
lb_policy: Some(LoadBalancerPolicy::RoundRobin),
},
};
})
.build();
let yaml = serde_yaml::to_string(&config).unwrap();
println!("{}", yaml);
}

#[test]
fn deserialise_server() {
let config = Config {
local: Local { port: 7000 },
filters: vec![],
connections: ConnectionConfig::Server {
let config = Builder::empty()
.with_local(Local { port: 7000 })
.with_connections(ConnectionConfig::Server {
endpoints: vec![
EndPoint {
name: String::from("No.1"),
Expand All @@ -217,8 +205,8 @@ mod tests {
connection_ids: vec!["1234".into()],
},
],
},
};
})
.build();
let yaml = serde_yaml::to_string(&config).unwrap();
println!("{}", yaml);
}
Expand Down Expand Up @@ -336,45 +324,42 @@ server:
#[test]
fn validate() {
// client - valid
let config = Config {
local: Local { port: 7000 },
filters: vec![],
connections: ConnectionConfig::Client {
let config = Builder::empty()
.with_local(Local { port: 7000 })
.with_connections(ConnectionConfig::Client {
addresses: vec![
"127.0.0.1:25999".parse().unwrap(),
"127.0.0.1:25998".parse().unwrap(),
],
connection_id: "1234".into(),
lb_policy: Some(LoadBalancerPolicy::RoundRobin),
},
};
})
.build();

assert!(config.validate().is_ok());

// client - non unique address
let config = Config {
local: Local { port: 7000 },
filters: vec![],
connections: ConnectionConfig::Client {
let config = Builder::empty()
.with_local(Local { port: 7000 })
.with_connections(ConnectionConfig::Client {
addresses: vec![
"127.0.0.1:25999".parse().unwrap(),
"127.0.0.1:25999".parse().unwrap(),
],
connection_id: "1234".into(),
lb_policy: Some(LoadBalancerPolicy::RoundRobin),
},
};
})
.build();

assert_eq!(
ValidationError::NotUnique("connections.addresses".to_string()).to_string(),
config.validate().unwrap_err().to_string()
);

// server - valid
let config = Config {
local: Local { port: 7000 },
filters: vec![],
connections: ConnectionConfig::Server {
let config = Builder::empty()
.with_local(Local { port: 7000 })
.with_connections(ConnectionConfig::Server {
endpoints: vec![
EndPoint {
name: String::from("ONE"),
Expand All @@ -387,15 +372,14 @@ server:
connection_ids: vec!["1234".into()],
},
],
},
};
})
.build();
assert!(config.validate().is_ok());

// server - non unique endpoint names
let config = Config {
local: Local { port: 7000 },
filters: vec![],
connections: ConnectionConfig::Server {
let config = Builder::empty()
.with_local(Local { port: 7000 })
.with_connections(ConnectionConfig::Server {
endpoints: vec![
EndPoint {
name: String::from("SAME"),
Expand All @@ -408,19 +392,18 @@ server:
connection_ids: vec!["1234".into()],
},
],
},
};
})
.build();

assert_eq!(
ValidationError::NotUnique("endpoint.name".to_string()).to_string(),
config.validate().unwrap_err().to_string()
);

// server - non unique addresses
let config = Config {
local: Local { port: 7000 },
filters: vec![],
connections: ConnectionConfig::Server {
let config = Builder::empty()
.with_local(Local { port: 7000 })
.with_connections(ConnectionConfig::Server {
endpoints: vec![
EndPoint {
name: String::from("ONE"),
Expand All @@ -433,8 +416,8 @@ server:
connection_ids: vec!["1234".into()],
},
],
},
};
})
.build();

assert_eq!(
ValidationError::NotUnique("endpoint.address".to_string()).to_string(),
Expand Down
33 changes: 16 additions & 17 deletions src/extensions/filter_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ mod tests {
use std::str::from_utf8;

use crate::config;
use crate::config::{ConnectionConfig, EndPoint, Local};
use crate::config::{Builder, ConnectionConfig, EndPoint};
use crate::extensions::filters::DebugFilterFactory;
use crate::extensions::{default_registry, FilterFactory};
use crate::test_utils::{logger, noop_endpoint, TestFilter};
Expand All @@ -131,37 +131,36 @@ mod tests {
let provider = DebugFilterFactory::new(&log);

// everything is fine
let config = Arc::new(Config {
local: Local { port: 0 },
filters: vec![config::Filter {
let config = Builder::empty()
.with_filters(vec![config::Filter {
name: provider.name(),
config: Default::default(),
}],
connections: ConnectionConfig::Client {
}])
.with_connections(ConnectionConfig::Client {
addresses: vec!["127.0.0.1:2456".parse().unwrap()],
connection_id: "".into(),
lb_policy: None,
},
});
})
.build();

let registry = default_registry(&log);
let chain = FilterChain::try_create(config, &registry, &Registry::default()).unwrap();
let chain =
FilterChain::try_create(Arc::new(config), &registry, &Registry::default()).unwrap();
assert_eq!(1, chain.filters.len());

// uh oh, something went wrong
let config = Arc::new(Config {
local: Local { port: 0 },
filters: vec![config::Filter {
let config = Builder::empty()
.with_filters(vec![config::Filter {
name: "this is so wrong".to_string(),
config: Default::default(),
}],
connections: ConnectionConfig::Client {
}])
.with_connections(ConnectionConfig::Client {
addresses: vec!["127.0.0.1:2456".parse().unwrap()],
connection_id: "".into(),
lb_policy: None,
},
});
let result = FilterChain::try_create(config, &registry, &Registry::default());
})
.build();
let result = FilterChain::try_create(Arc::new(config), &registry, &Registry::default());
assert!(result.is_err());
}

Expand Down
Loading