Skip to content

Commit

Permalink
feat: [#978] add semantic validation for configuration
Browse files Browse the repository at this point in the history
The section [core.provate_mode] can be inlcuded in the configration TOML
file only if the tracker is running in private mode (`private = true`).

This commits adds that validation and makes it possible to add more
semantic validations in the future.

Semantic validations are validations that depend on more than one value.
Like the one added, it could be any other incompatible combination.
  • Loading branch information
josecelano committed Aug 1, 2024
1 parent e8e935c commit ed40e4a
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/configuration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
//!
//! The current version for configuration is [`v2`].
pub mod v2;
pub mod validator;

use std::collections::HashMap;
use std::env;
Expand Down
11 changes: 11 additions & 0 deletions packages/configuration/src/v2/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};

use super::network::Network;
use crate::v2::database::Database;
use crate::validator::{SemanticValidationError, Validator};
use crate::{AnnouncePolicy, TrackerPolicy};

#[allow(clippy::struct_excessive_bools)]
Expand Down Expand Up @@ -131,3 +132,13 @@ impl PrivateMode {
true
}

Check warning on line 133 in packages/configuration/src/v2/core.rs

View check run for this annotation

Codecov / codecov/patch

packages/configuration/src/v2/core.rs#L133

Added line #L133 was not covered by tests
}

impl Validator for Core {
fn validate(&self) -> Result<(), SemanticValidationError> {
if self.private_mode.is_some() && !self.private {
return Err(SemanticValidationError::UselessPrivateModeSection);

Check warning on line 139 in packages/configuration/src/v2/core.rs

View check run for this annotation

Codecov / codecov/patch

packages/configuration/src/v2/core.rs#L137-L139

Added lines #L137 - L139 were not covered by tests
}

Ok(())
}

Check warning on line 143 in packages/configuration/src/v2/core.rs

View check run for this annotation

Codecov / codecov/patch

packages/configuration/src/v2/core.rs#L142-L143

Added lines #L142 - L143 were not covered by tests
}
7 changes: 7 additions & 0 deletions packages/configuration/src/v2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ use self::health_check_api::HealthCheckApi;
use self::http_tracker::HttpTracker;
use self::tracker_api::HttpApi;
use self::udp_tracker::UdpTracker;
use crate::validator::{SemanticValidationError, Validator};
use crate::{Error, Info, Metadata, Version};

/// This configuration version
Expand Down Expand Up @@ -394,6 +395,12 @@ impl Configuration {
}
}

impl Validator for Configuration {
fn validate(&self) -> Result<(), SemanticValidationError> {
self.core.validate()
}

Check warning on line 401 in packages/configuration/src/v2/mod.rs

View check run for this annotation

Codecov / codecov/patch

packages/configuration/src/v2/mod.rs#L399-L401

Added lines #L399 - L401 were not covered by tests
}

#[cfg(test)]
mod tests {

Expand Down
19 changes: 19 additions & 0 deletions packages/configuration/src/validator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//! Trait to validate semantic errors.
//!
//! Errors could involve more than one configuration option. Some configuration
//! combinations can be incompatible.
use thiserror::Error;

/// Errors that can occur validating the configuration.
#[derive(Error, Debug)]

Check warning on line 8 in packages/configuration/src/validator.rs

View check run for this annotation

Codecov / codecov/patch

packages/configuration/src/validator.rs#L8

Added line #L8 was not covered by tests
pub enum SemanticValidationError {
#[error("Private mode section in configuration can only be included when the tracker is running in private mode.")]
UselessPrivateModeSection,
}

pub trait Validator {
/// # Errors
///
/// Will return an error if the configuration is invalid.
fn validate(&self) -> Result<(), SemanticValidationError>;
}
9 changes: 9 additions & 0 deletions src/bootstrap/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use std::sync::Arc;

use torrust_tracker_clock::static_time;
use torrust_tracker_configuration::validator::Validator;
use torrust_tracker_configuration::Configuration;
use tracing::info;

Expand All @@ -24,10 +25,18 @@ use crate::core::Tracker;
use crate::shared::crypto::ephemeral_instance_keys;

/// It loads the configuration from the environment and builds the main domain [`Tracker`] struct.
///
/// # Panics
///
/// Setup can file if the configuration is invalid.
#[must_use]
pub fn setup() -> (Configuration, Arc<Tracker>) {
let configuration = initialize_configuration();

if let Err(e) = configuration.validate() {
panic!("Configuration error: {e}");

Check warning on line 37 in src/bootstrap/app.rs

View check run for this annotation

Codecov / codecov/patch

src/bootstrap/app.rs#L36-L37

Added lines #L36 - L37 were not covered by tests
}

let tracker = initialize_with_configuration(&configuration);

info!("Configuration:\n{}", configuration.clone().mask_secrets().to_json());
Expand Down

0 comments on commit ed40e4a

Please sign in to comment.