### Test Add and Get Entry Source: https://docs.rs/yamldap/latest/src/yamldap/directory/storage.rs.html Demonstrates adding an LDAP entry to the directory and retrieving it, including case-insensitive lookups and existence checks. ```rust fn test_directory_add_and_get_entry() { let schema = YamlSchema::default(); let directory = Directory::new("dc=test,dc=com".to_string(), schema); let mut entry = LdapEntry::new("cn=test,dc=test,dc=com".to_string()); entry.add_attribute( "cn".to_string(), vec![crate::directory::entry::AttributeValue::String( "test".to_string(), )], crate::directory::entry::AttributeSyntax::String, ); directory.add_entry(entry.clone()); // Test get_entry let retrieved = directory.get_entry("cn=test,dc=test,dc=com"); assert!(retrieved.is_some()); assert_eq!(retrieved.unwrap().dn, "cn=test,dc=test,dc=com"); // Test case insensitive lookup let retrieved = directory.get_entry("CN=TEST,DC=TEST,DC=COM"); assert!(retrieved.is_some()); // Test entry_exists assert!(directory.entry_exists("cn=test,dc=test,dc=com")); assert!(directory.entry_exists("CN=TEST,DC=TEST,DC=COM")); assert!(!directory.entry_exists("cn=nonexistent,dc=test,dc=com")); } ``` -------------------------------- ### Test Server Run with Hot Reload Enabled Source: https://docs.rs/yamldap/latest/src/yamldap/server/mod.rs.html Tests starting the server with hot reloading enabled. It uses a background task and a timeout to verify that the server starts without blocking indefinitely. ```rust #[tokio::test] #[ignore] // This test hangs in CI async fn test_server_run_with_hot_reload() { let yaml_file = create_test_yaml_file(); let config = Config { yaml_file: yaml_file.path().to_path_buf(), bind_address: "127.0.0.1:0".parse().unwrap(), // Use port 0 for testing base_dn: None, allow_anonymous: false, hot_reload: true, log_level: tracing::Level::INFO, ad_compat: false, }; let server = Server::new(config).await.unwrap(); // Start server in background let handle = tokio::spawn(async move { // The server.run() method runs forever, so we just test that it starts let _ = tokio::time::timeout(std::time::Duration::from_millis(100), server.run()).await; }); // Give it time to start tokio::time::sleep(std::time::Duration::from_millis(50)).await; // Clean up handle.abort(); } ``` -------------------------------- ### Server Run Loop with Hot-Reload Source: https://docs.rs/yamldap/latest/src/yamldap/server/mod.rs.html Starts the main server loop, binds to the configured address, and handles incoming TCP connections. It also sets up a hot-reloading mechanism for the directory configuration if enabled. ```rust pub async fn run(self) -> crate::Result<()> { // Set up hot-reload if enabled let reload_rx = if self.config.hot_reload { info!("Hot-reload enabled, watching YAML file for changes"); let (_watcher, rx) = YamlWatcher::new(&self.config.yaml_file)?; Some(rx) } else { None }; // Start hot-reload handler if enabled if let Some(mut rx) = reload_rx { let yaml_path = self.config.yaml_file.clone(); let directory = Arc::clone(&self.directory); tokio::spawn(async move { while rx.changed().await.is_ok() { info!("Reloading YAML directory file..."); match yaml::parse_directory_file(&yaml_path).await { Ok((yaml_dir, schema)) => { let new_directory = Directory::from_yaml(yaml_dir, schema); match directory.write() { Ok(mut dir) => { *dir = new_directory; info!("Successfully reloaded directory"); } Err(e) => { error!( "Failed to acquire write lock for directory reload: {}", e ); } } } Err(e) => { error!("Failed to reload YAML file: {}", e); } } } }); } let listener = TcpListener::bind(&self.config.bind_address).await?; info!("LDAP server listening on {}", self.config.bind_address); loop { match listener.accept().await { Ok((socket, addr)) => { info!("New connection from {}", addr); let directory = Arc::clone(&self.directory); let auth_handler = Arc::clone(&self.auth_handler); let ad_compat = self.config.ad_compat; tokio::spawn(async move { // Create a read-only snapshot of the directory for this connection let dir_snapshot = match directory.read() { Ok(dir) => Arc::new(dir.clone()), Err(e) => { error!("Failed to read directory: {}", e); return; } }; if let Err(e) = connection::handle_connection( socket, dir_snapshot, auth_handler, ad_compat, ) .await { error!("Connection error: {}", e); } }); } Err(e) => { error!("Failed to accept connection: {}", e); } } } } ``` -------------------------------- ### Rust LDAP Search with AND Filter Source: https://docs.rs/yamldap/latest/src/yamldap/ldap/operations.rs.html Demonstrates an LDAP search using an AND filter to combine multiple criteria. This example searches for entries that are both 'person' and have a specific 'uid'. ```rust let operation = LdapOperation::Search { base_dn: "dc=example,dc=com".to_string(), scope: SearchScope::WholeSubtree, filter: "(&(objectClass=person)(uid=user1))".to_string(), attributes: vec![], }; ``` -------------------------------- ### Perform LDAP Search with Specific Filter Source: https://docs.rs/yamldap/latest/src/yamldap/ldap/operations.rs.html Illustrates how to perform an LDAP search operation using a specific filter to retrieve entries. This example focuses on a simple filter and asserts that only the expected entry is returned. ```rust fn test_search_with_specific_filter() { let directory = create_test_directory(); let auth_handler = AuthHandler::new(false); let operation = LdapOperation::Search { base_dn: "dc=example,dc=com".to_string(), scope: SearchScope::WholeSubtree, filter: "(uid=user1)".to_string(), // Simple filter since complex ones aren't parsed attributes: vec![], }; let responses = handle_operation(1, operation, &directory, &auth_handler, true, false); // Should find only user1 assert_eq!(responses.len(), 2); // 1 entry + done match &responses[0].protocol_op { LdapProtocolOp::SearchResultEntry { dn, .. } => { assert_eq!(dn, "cn=user1,ou=users,dc=example,dc=com"); } _ => panic!("Expected SearchResultEntry"), } } ``` -------------------------------- ### Accessing Server Fields via Pattern Matching Source: https://docs.rs/yamldap/latest/src/yamldap/server/mod.rs.html This snippet illustrates how to access fields of the Server struct using pattern matching. Note that this specific example is commented out as it's intended to show structure rather than be directly compilable. ```rust let _size = mem::size_of::(); // Test that we can access the fields through pattern matching // (This won't compile but shows the structure exists) } } ``` -------------------------------- ### Server Run Function Source: https://docs.rs/yamldap/latest/yamldap/server/struct.Server.html Asynchronously runs the server. This function takes ownership of the `Server` instance and starts its operation. It returns a `Result` indicating success or failure during execution. ```rust pub async fn run(self) -> Result<()> ``` -------------------------------- ### Getting Metadata with and_then Source: https://docs.rs/yamldap/latest/yamldap/type.Result.html Shows how to use `and_then` to chain operations, such as getting file metadata and then its modification time. This example highlights error propagation for file system operations. ```rust use std::{io::ErrorKind, path::Path}; // Note: on Windows "/" maps to "C:\\" let root_modified_time = Path::new("/").metadata().and_then(|md| md.modified()); assert!(root_modified_time.is_ok()); let should_fail = Path::new("/bad/path").metadata().and_then(|md| md.modified()); assert!(should_fail.is_err()); assert_eq!(should_fail.unwrap_err().kind(), ErrorKind::NotFound); ``` -------------------------------- ### Server Initialization Source: https://docs.rs/yamldap/latest/src/yamldap/server/mod.rs.html Creates a new Server instance, loading the directory from a YAML file and setting up the authentication handler. This is the entry point for setting up the server's state. ```rust pub async fn new(config: Config) -> crate::Result { // Load directory from YAML let (yaml_dir, schema) = yaml::parse_directory_file(&config.yaml_file).await?; let directory = Directory::from_yaml(yaml_dir, schema); info!("Loaded directory with base DN: {}", directory.base_dn); let auth_handler = AuthHandler::new(config.allow_anonymous); Ok(Self { config, directory: Arc::new(RwLock::new(directory)), auth_handler: Arc::new(auth_handler), }) } ``` -------------------------------- ### Getting a Default Value with unwrap_or Source: https://docs.rs/yamldap/latest/yamldap/type.Result.html Shows how to use `unwrap_or` to get the `Ok` value or a provided default if the `Result` is `Err`. Arguments are eagerly evaluated. ```rust let default = 2; let x: Result = Ok(9); assert_eq!(x.unwrap_or(default), 9); let x: Result = Err("error"); assert_eq!(x.unwrap_or(default), default); ``` -------------------------------- ### Create Directory from YAML Configuration Source: https://docs.rs/yamldap/latest/src/yamldap/directory/storage.rs.html Demonstrates how to initialize a Directory with base DN, object classes, and attributes defined in a YAML structure. Verifies base DN and entry existence. ```rust use std::collections::HashMap; // Create a YAML directory structure let yaml_dir = YamlDirectory { directory: crate::yaml::schema::DirectoryConfig { base_dn: "dc=example,dc=com".to_string(), }, schema: None, entries: vec![ crate::yaml::YamlEntry { dn: "dc=example,dc=com".to_string(), object_class: vec!["dcObject".to_string(), "organization".to_string()], attributes: { let mut attrs = HashMap::new(); attrs.insert( "dc".to_string(), serde_yaml::Value::String("example".to_string()), ); attrs }, }, crate::yaml::YamlEntry { dn: "cn=admin,dc=example,dc=com".to_string(), object_class: vec!["person".to_string()], attributes: { let mut attrs = HashMap::new(); attrs.insert( "cn".to_string(), serde_yaml::Value::String("admin".to_string()), ); attrs }, }, ], }; let schema = YamlSchema::default(); let directory = Directory::from_yaml(yaml_dir, schema); // Verify the base DN assert_eq!(directory.base_dn, "dc=example,dc=com"); // Verify entries were added assert!(directory.entry_exists("dc=example,dc=com")); assert!(directory.entry_exists("cn=admin,dc=example,dc=com")); // Verify entry content let admin_entry = directory.get_entry("cn=admin,dc=example,dc=com").unwrap(); assert_eq!(admin_entry.dn, "cn=admin,dc=example,dc=com"); assert!(admin_entry.has_attribute("cn")); assert!(admin_entry.has_attribute("objectClass")); ``` -------------------------------- ### Initialize New Directory Source: https://docs.rs/yamldap/latest/src/yamldap/directory/storage.rs.html Creates a new, empty directory with a specified base DN and schema. Indexes are initialized for efficient lookups. ```rust pub fn new(base_dn: String, schema: YamlSchema) -> Self { Self { base_dn, entries: Arc::new(DashMap::new()), schema, uid_index: AttributeIndex::new(), cn_index: AttributeIndex::new(), objectclass_index: ObjectClassIndex::new(), } } ``` -------------------------------- ### Test Directory Initialization Source: https://docs.rs/yamldap/latest/src/yamldap/directory/storage.rs.html Ensures a new `Directory` is created with the correct base DN and an empty entry set. ```rust fn test_directory_new() { let schema = YamlSchema::default(); let directory = Directory::new("dc=test,dc=com".to_string(), schema.clone()); assert_eq!(directory.base_dn, "dc=test,dc=com"); assert_eq!(directory.entries.len(), 0); } ``` -------------------------------- ### Test Server Run without Hot Reload Enabled Source: https://docs.rs/yamldap/latest/src/yamldap/server/mod.rs.html Tests starting the server with hot reloading disabled. Similar to the hot reload test, it uses a background task and timeout to confirm the server starts. ```rust #[tokio::test] #[ignore] // This test hangs in CI async fn test_server_run_without_hot_reload() { let yaml_file = create_test_yaml_file(); let config = Config { yaml_file: yaml_file.path().to_path_buf(), bind_address: "127.0.0.1:0".parse().unwrap(), // Use port 0 for testing base_dn: None, allow_anonymous: true, hot_reload: false, log_level: tracing::Level::INFO, ad_compat: false, }; let server = Server::new(config).await.unwrap(); // Start server in background let handle = tokio::spawn(async move { // The server.run() method runs forever, so we just test that it starts let _ = tokio::time::timeout(std::time::Duration::from_millis(100), server.run()).await; }); // Give it time to start tokio::time::sleep(std::time::Duration::from_millis(50)).await; // Clean up handle.abort(); } ``` -------------------------------- ### AuthHandler::type_id Method Source: https://docs.rs/yamldap/latest/yamldap/directory/auth/struct.AuthHandler.html Gets the TypeId of the AuthHandler. This is part of the Any trait implementation. ```rust fn type_id(&self) -> TypeId ``` -------------------------------- ### Add and Search Directory Entries Source: https://docs.rs/yamldap/latest/src/yamldap/directory/storage.rs.html Demonstrates adding child and grandchild entries to a directory and then performing a search to verify their existence. Asserts the count and DNs of the retrieved entries. ```rust let mut directory = Directory::new("dc=test,dc=com".to_string(), YamlSchema::default()); let child = LdapEntry::new("ou=users,dc=test,dc=com".to_string()); directory.add_entry(child); // Add grandchild let grandchild = LdapEntry::new("cn=user1,ou=users,dc=test,dc=com".to_string()); directory.add_entry(grandchild); let results = directory.search_entries("dc=test,dc=com", SearchScope::WholeSubtree, |_| true); assert_eq!(results.len(), 3); let dns: Vec = results.iter().map(|e| e.dn.clone()).collect(); assert!(dns.contains(&"dc=test,dc=com".to_string())); assert!(dns.contains(&"ou=users,dc=test,dc=com".to_string())); assert!(dns.contains(&"cn=user1,ou=users,dc=test,dc=com".to_string())); ``` -------------------------------- ### Get Argument Group ID Source: https://docs.rs/yamldap/latest/yamldap/config/struct.CliArgs.html Reports the ArgGroup::id for this set of arguments. ```rust pub fn group_id() -> Option ``` -------------------------------- ### Create Directory from YAML Configuration Source: https://docs.rs/yamldap/latest/src/yamldap/directory/storage.rs.html Illustrates initializing a Directory object from a structured YAML configuration. Verifies the base DN and the existence and attributes of an added entry. ```rust let schema = YamlSchema::default(); let yaml_dir = crate::yaml::YamlDirectory { directory: crate::yaml::schema::DirectoryConfig { base_dn: "dc=yaml,dc=com".to_string(), }, schema: None, entries: vec![crate::yaml::YamlEntry { dn: "cn=test,dc=yaml,dc=com".to_string(), object_class: vec!["person".to_string()], attributes: [( "cn".to_string(), serde_yaml::Value::String("test".to_string()), )] .into_iter() .collect(), }], }; let directory = Directory::from_yaml(yaml_dir, schema); assert_eq!(directory.base_dn, "dc=yaml,dc=com"); assert!(directory.entry_exists("cn=test,dc=yaml,dc=com")); let entry = directory.get_entry("cn=test,dc=yaml,dc=com").unwrap(); assert!(entry.has_attribute("cn")); assert!(entry.has_attribute("objectClass")); ``` -------------------------------- ### LdapEntry Get Attribute Source: https://docs.rs/yamldap/latest/src/yamldap/directory/entry.rs.html Retrieves an attribute from the LdapEntry by name, performing a case-insensitive lookup. ```rust 90 pub fn get_attribute(&self, name: &str) -> Option<&LdapAttribute> { 91 self.attributes.get(&name.to_lowercase()) 92 } 93 ``` -------------------------------- ### Test Server Creation with Default Configuration Source: https://docs.rs/yamldap/latest/src/yamldap/server/mod.rs.html Tests the initialization of the Server with a valid YAML file and default settings. Asserts that the base DN and anonymous access settings are correctly applied. ```rust #[tokio::test] async fn test_server_new() { let yaml_file = create_test_yaml_file(); let config = Config { yaml_file: yaml_file.path().to_path_buf(), bind_address: "127.0.0.1:389".parse().unwrap(), base_dn: None, allow_anonymous: false, hot_reload: false, log_level: tracing::Level::INFO, ad_compat: false, }; let server = Server::new(config).await.unwrap(); assert!(server.directory.read().unwrap().base_dn == "dc=test,dc=com"); assert!(!server.auth_handler.is_anonymous_allowed()); } ``` -------------------------------- ### unwrap_or_else Example Source: https://docs.rs/yamldap/latest/yamldap/type.Result.html Demonstrates the use of unwrap_or_else with a closure to provide a default value when the Result is an Err. ```rust assert_eq!(Ok(2).unwrap_or_else(count), 2); assert_eq!(Err("foo").unwrap_or_else(count), 3); ``` -------------------------------- ### Test Directory Creation Source: https://docs.rs/yamldap/latest/src/yamldap/ldap/bind.rs.html Helper function to create a sample Directory with a test user for testing bind operations. ```rust use super::*; use crate::directory::entry::{AttributeSyntax, AttributeValue, LdapEntry}; fn create_test_directory() -> Directory { let schema = crate::yaml::YamlSchema::default(); let directory = Directory::new("dc=example,dc=com".to_string(), schema); // Add a test user let mut entry = LdapEntry::new("cn=test,dc=example,dc=com".to_string()); entry.add_attribute( "userPassword".to_string(), vec![AttributeValue::String("password".to_string())], AttributeSyntax::String, ); directory.add_entry(entry); directory } ``` -------------------------------- ### Termination for Result Source: https://docs.rs/yamldap/latest/yamldap/type.Result.html Implementation of the Termination trait for Result, used to get a status code representation. ```rust impl Termination for Result where T: Termination, E: Debug, ``` -------------------------------- ### Get All Known Attributes Source: https://docs.rs/yamldap/latest/yamldap/yaml/schema/struct.YamlSchema.html Retrieves a set of all attribute names defined within the YamlSchema. Useful for validation or introspection of the schema. ```rust pub fn get_all_known_attributes(&self) -> HashSet ``` -------------------------------- ### Create Test LDAP Directory Source: https://docs.rs/yamldap/latest/src/yamldap/ldap/operations.rs.html Sets up a sample LDAP directory with an organizational unit, test users, and the base DN entry. This function is useful for testing LDAP operations. ```rust fn create_test_directory() -> Directory { let schema = crate::yaml::YamlSchema::default(); let directory = Directory::new("dc=example,dc=com".to_string(), schema); // Add the ou=users organizational unit let mut ou_users = LdapEntry::new("ou=users,dc=example,dc=com".to_string()); ou_users.add_attribute( "ou".to_string(), vec![AttributeValue::String("users".to_string())], AttributeSyntax::String, ); ou_users.object_classes = vec!["organizationalUnit".to_string()]; ou_users.add_attribute( "objectClass".to_string(), vec![AttributeValue::String("organizationalUnit".to_string())], AttributeSyntax::String, ); directory.add_entry(ou_users); // Add test users let mut user1 = LdapEntry::new("cn=user1,ou=users,dc=example,dc=com".to_string()); user1.add_attribute( "cn".to_string(), vec![AttributeValue::String("user1".to_string())], AttributeSyntax::String, ); user1.add_attribute( "uid".to_string(), vec![AttributeValue::String("user1".to_string())], AttributeSyntax::String, ); user1.add_attribute( "userPassword".to_string(), vec![AttributeValue::String("password1".to_string())], AttributeSyntax::String, ); user1.add_attribute( "mail".to_string(), vec![AttributeValue::String("user1@example.com".to_string())], AttributeSyntax::String, ); user1.object_classes = vec![ "inetOrgPerson".to_string(), "person".to_string(), "top".to_string(), ]; user1.add_attribute( "objectClass".to_string(), vec![ AttributeValue::String("inetOrgPerson".to_string()), AttributeValue::String("person".to_string()), AttributeValue::String("top".to_string()), ], AttributeSyntax::String, ); directory.add_entry(user1); let mut user2 = LdapEntry::new("cn=user2,ou=users,dc=example,dc=com".to_string()); user2.add_attribute( "cn".to_string(), vec![AttributeValue::String("user2".to_string())], AttributeSyntax::String, ); user2.add_attribute( "uid".to_string(), vec![AttributeValue::String("user2".to_string())], AttributeSyntax::String, ); user2.object_classes = vec!["inetOrgPerson".to_string(), "person".to_string()]; user2.add_attribute( "objectClass".to_string(), vec![ AttributeValue::String("inetOrgPerson".to_string()), AttributeValue::String("person".to_string()), ], AttributeSyntax::String, ); directory.add_entry(user2); // Add OU entry let mut ou = LdapEntry::new("ou=users,dc=example,dc=com".to_string()); ou.add_attribute( "ou".to_string(), vec![AttributeValue::String("users".to_string())], AttributeSyntax::String, ); ou.object_classes = vec!["organizationalUnit".to_string()]; ou.add_attribute( "objectClass".to_string(), vec![AttributeValue::String("organizationalUnit".to_string())], AttributeSyntax::String, ); directory.add_entry(ou); // Add base DN entry let mut base = LdapEntry::new("dc=example,dc=com".to_string()); base.object_classes = vec!["top".to_string(), "domain".to_string()]; base.add_attribute( "objectClass".to_string(), vec![ AttributeValue::String("top".to_string()), AttributeValue::String("domain".to_string()), ], AttributeSyntax::String, ); base.add_attribute( "dc".to_string(), vec![AttributeValue::String("example".to_string())], AttributeSyntax::String, ); directory.add_entry(base); directory } ``` -------------------------------- ### Directory::new Source: https://docs.rs/yamldap/latest/src/yamldap/directory/storage.rs.html Creates a new, empty Directory with the specified base DN and schema. Initializes internal structures for storing entries and indexes. ```APIDOC ## Directory::new ### Description Creates a new, empty Directory with the specified base DN and schema. Initializes internal structures for storing entries and indexes. ### Signature ```rust pub fn new(base_dn: String, schema: YamlSchema) -> Self ``` ### Parameters * `base_dn` (String) - The base distinguished name for the directory. * `schema` (YamlSchema) - The schema to be used for the directory. ``` -------------------------------- ### Test YamlWatcher Specific Modify Kinds Source: https://docs.rs/yamldap/latest/src/yamldap/yaml/watcher.rs.html This snippet is incomplete and appears to be the start of a test for specific modification event kinds. ```rust fn test_is_relevant_event_specific_modify_kinds() { let watcher = YamlWatcher { _watcher: RecommendedWatcher::new(|_| {}, Config::default()).unwrap(), rx: mpsc::channel().1, }; ``` -------------------------------- ### Insert and Find Directory Entries Source: https://docs.rs/yamldap/latest/src/yamldap/directory/index.rs.html Demonstrates inserting various attributes (string, multi-line string, special characters) and then finding them using the directory index. Ensure the index is initialized before use. ```rust index.insert("email", "test@example.com", "cn=test,dc=example,dc=com"); index.insert("description", "Line 1\nLine 2", "cn=test,dc=example,dc=com"); index.insert("cn", "O'Brien", "cn=O'Brien,dc=example,dc=com"); assert!(index.find("email", "test@example.com").is_some()); assert!(index.find("description", "Line 1\nLine 2").is_some()); assert!(index.find("cn", "O'Brien").is_some()); ``` -------------------------------- ### Test Reading Integer with Invalid Tag Source: https://docs.rs/yamldap/latest/src/yamldap/ldap/simple_protocol.rs.html Tests the `read_integer` function when the buffer starts with an incorrect tag, expecting an `InvalidData` error. ```rust #[test] fn test_read_integer_invalid_tag() { let buf = vec![0x03]; // Wrong tag let mut cursor = Cursor::new(buf.as_ref()); let result = SimpleLdapCodec::read_integer(&mut cursor); assert!(result.is_err()); assert_eq!(result.unwrap_err().kind(), io::ErrorKind::InvalidData); } ``` -------------------------------- ### Directory::new Constructor Source: https://docs.rs/yamldap/latest/yamldap/directory/storage/struct.Directory.html Creates a new `Directory` instance with a specified base DN and schema. ```rust pub fn new(base_dn: String, schema: YamlSchema) -> Self ``` -------------------------------- ### unsafe unwrap_err_unchecked on Err Source: https://docs.rs/yamldap/latest/yamldap/type.Result.html Shows how to use unwrap_err_unchecked to get the Err value without a safety check. Calling on an Ok is undefined behavior. ```rust let x: Result = Err("emergency failure"); assert_eq!(unsafe { x.unwrap_err_unchecked() }, "emergency failure"); ``` -------------------------------- ### LdapEntry Initialization Source: https://docs.rs/yamldap/latest/src/yamldap/directory/entry.rs.html Creates a new LdapEntry with a given distinguished name. ```rust 65impl LdapEntry { 66 pub fn new(dn: String) -> Self { 67 Self { 68 dn, 69 attributes: HashMap::new(), 70 object_classes: Vec::new(), 71 } 72 } 73 ``` -------------------------------- ### unsafe unwrap_unchecked on Ok Source: https://docs.rs/yamldap/latest/yamldap/type.Result.html Shows how to use unwrap_unchecked to get the Ok value without a safety check. Calling on an Err is undefined behavior. ```rust let x: Result = Ok(2); assert_eq!(unsafe { x.unwrap_unchecked() }, 2); ``` -------------------------------- ### Directory::from_yaml Source: https://docs.rs/yamldap/latest/src/yamldap/directory/storage.rs.html Constructs a Directory from a YamlDirectory structure, populating it with entries defined in the YAML and applying the provided schema. This is a convenient way to initialize a directory from configuration. ```APIDOC ## Directory::from_yaml ### Description Constructs a Directory from a YamlDirectory structure, populating it with entries defined in the YAML and applying the provided schema. This is a convenient way to initialize a directory from configuration. ### Signature ```rust pub fn from_yaml(yaml_dir: YamlDirectory, schema: YamlSchema) -> Self ``` ### Parameters * `yaml_dir` (YamlDirectory) - The YAML directory structure containing base DN and entries. * `schema` (YamlSchema) - The schema to be used for the directory. ``` -------------------------------- ### LDAP Entry Creation from Empty YAML Values Source: https://docs.rs/yamldap/latest/src/yamldap/directory/entry.rs.html Demonstrates creating an `LdapEntry` from a `YamlEntry` with empty or null attribute values. Verifies that such attributes are not added to the final entry. ```rust let yaml_entry = crate::yaml::YamlEntry { dn: "cn=test,dc=example,dc=com".to_string(), object_class: vec!["top".to_string()], attributes: [ ("empty".to_string(), serde_yaml::Value::Null), ("emptySeq".to_string(), serde_yaml::Value::Sequence(vec![])), ] .into_iter() .collect(), }; let entry: LdapEntry = yaml_entry.into(); // Empty values should not create attributes assert!(!entry.has_attribute("empty")); assert!(!entry.has_attribute("emptySeq")); // Only objectClass should be present assert_eq!(entry.attributes.len(), 1); assert!(entry.has_attribute("objectClass")); ``` -------------------------------- ### Test Reading String with Invalid Tag Source: https://docs.rs/yamldap/latest/src/yamldap/ldap/simple_protocol.rs.html Tests the `read_string` function when the provided buffer starts with an incorrect tag, expecting an `InvalidData` error. ```rust #[test] fn test_read_string_invalid_tag() { let buf = vec![0x05]; // Wrong tag let mut cursor = Cursor::new(buf.as_ref()); let result = SimpleLdapCodec::read_string(&mut cursor); assert!(result.is_err()); assert_eq!(result.unwrap_err().kind(), io::ErrorKind::InvalidData); } ``` -------------------------------- ### Object Class Index Initialization Source: https://docs.rs/yamldap/latest/src/yamldap/directory/index.rs.html Tests the `new` and `default` constructors for `ObjectClassIndex`. Both should result in an empty index. ```rust #[test] fn test_object_class_index_new() { let index = ObjectClassIndex::new(); assert_eq!(index.index.len(), 0); } #[test] fn test_object_class_index_default() { let index = ObjectClassIndex::default(); assert_eq!(index.index.len(), 0); } ``` -------------------------------- ### Test Decoding Partial Message Source: https://docs.rs/yamldap/latest/src/yamldap/ldap/simple_protocol.rs.html Tests the `decode` method with a buffer containing only the start of a message (SEQUENCE tag and length) but no content, expecting `None`. ```rust #[test] fn test_decode_partial_message() { let mut codec = SimpleLdapCodec; let mut buf = BytesMut::from(&[0x30, 0x10][..]); // SEQUENCE with length 16 but no content let result = codec.decode(&mut buf).unwrap(); assert!(result.is_none()); } ``` -------------------------------- ### Unwrap Err Value Source: https://docs.rs/yamldap/latest/yamldap/type.Result.html Use `unwrap_err()` to get the contained `Err` value. This method panics if the `Result` is an `Ok`. It is useful when you expect an error and want to handle it. ```rust let x: Result = Ok(2); x.unwrap_err(); // panics with `2` ``` ```rust let x: Result = Err("emergency failure"); assert_eq!(x.unwrap_err(), "emergency failure"); ``` -------------------------------- ### Handle StartTLS Extended Operation Source: https://docs.rs/yamldap/latest/src/yamldap/ldap/operations.rs.html Tests the StartTLS extended operation. This operation is not supported and should return an 'Unavailable' error. ```rust #[test] fn test_extended_operation_start_tls() { let directory = create_test_directory(); let auth_handler = AuthHandler::new(false); // Test StartTLS extended operation let operation = LdapOperation::Extended { name: "1.3.6.1.4.1.1466.20037".to_string(), value: None, }; let responses = handle_operation(1, operation, &directory, &auth_handler, true, false); assert_eq!( responses.len(), 1, "Extended operation should return one response" ); match &responses[0].protocol_op { LdapProtocolOp::ExtendedResponse { result, name, value, } => { assert_eq!(result.result_code, LdapResultCode::Unavailable); assert!(result .diagnostic_message .contains("StartTLS is not supported")); assert_eq!(name.as_ref().unwrap(), "1.3.6.1.4.1.1466.20037"); assert!(value.is_none()); } _ => panic!("Expected ExtendedResponse"), } } ``` -------------------------------- ### Unwrap or Default Value Source: https://docs.rs/yamldap/latest/yamldap/type.Result.html Use `unwrap_or_default()` to get the contained `Ok` value or the default value for the type if it's an `Err`. This is useful for providing fallback values. ```rust let good_year_from_input = "1909"; let bad_year_from_input = "190blarg"; let good_year = good_year_from_input.parse().unwrap_or_default(); let bad_year = bad_year_from_input.parse().unwrap_or_default(); assert_eq!(1909, good_year); assert_eq!(0, bad_year); ``` -------------------------------- ### Server New Function Source: https://docs.rs/yamldap/latest/yamldap/server/struct.Server.html Asynchronously creates a new `Server` instance. Requires a `Config` object for initialization. Returns a `Result` which can be `Ok(Self)` on success or an error. ```rust pub async fn new(config: Config) -> Result ``` -------------------------------- ### Unwrap Ok Value Source: https://docs.rs/yamldap/latest/yamldap/type.Result.html Use `unwrap()` to get the contained `Ok` value. This method will panic if the `Result` is an `Err`. It is generally discouraged in favor of safer alternatives. ```rust let x: Result = Ok(2); assert_eq!(x.unwrap(), 2); ``` -------------------------------- ### LDAP Bind Authentication Variants Source: https://docs.rs/yamldap/latest/src/yamldap/ldap/protocol.rs.html Demonstrates the usage of Simple and Anonymous bind authentication methods. ```Rust #[test] fn test_bind_authentication_variants() { let simple = BindAuthentication::Simple("password".to_string()); match simple { BindAuthentication::Simple(pwd) => assert_eq!(pwd, "password"), _ => panic!("Expected Simple authentication"), } let anon = BindAuthentication::Anonymous; match anon { BindAuthentication::Anonymous => {} // No assertion needed for Anonymous _ => panic!("Expected Anonymous authentication"), } } ``` -------------------------------- ### Test Search Whole Subtree Scope Source: https://docs.rs/yamldap/latest/src/yamldap/directory/storage.rs.html Initializes a directory and adds entries to prepare for a `SearchScope::WholeSubtree` test. ```rust fn test_directory_search_whole_subtree() { let schema = YamlSchema::default(); let directory = Directory::new("dc=test,dc=com".to_string(), schema); // Add base let base = LdapEntry::new("dc=test,dc=com".to_string()); directory.add_entry(base); // Add child ``` -------------------------------- ### Product of Results Example Source: https://docs.rs/yamldap/latest/yamldap/type.Result.html Demonstrates how to calculate the product of elements in an iterator where each element is a `Result`. The operation short-circuits and returns the first `Err` encountered, or the product if all elements are `Ok`. ```rust let nums = vec!["5", "10", "1", "2"]; let total: Result = nums.iter().map(|w| w.parse::()).product(); assert_eq!(total, Ok(100)); let nums = vec!["5", "10", "one", "2"]; let total: Result = nums.iter().map(|w| w.parse::()).product(); assert!(total.is_err()); ``` -------------------------------- ### Build Command for Instantiation Source: https://docs.rs/yamldap/latest/yamldap/config/struct.CliArgs.html Builds a clap Command object that can be used to instantiate CliArgs. ```rust pub fn command<'b>() -> Command ``` -------------------------------- ### Directory::from_yaml Constructor Source: https://docs.rs/yamldap/latest/yamldap/directory/storage/struct.Directory.html Constructs a `Directory` instance from YAML data and a provided schema. ```rust pub fn from_yaml(yaml_dir: YamlDirectory, schema: YamlSchema) -> Self ``` -------------------------------- ### Get All Unique Attribute Names Source: https://docs.rs/yamldap/latest/src/yamldap/directory/storage.rs.html Collects and returns a set of all unique attribute names present across all entries in the directory. Includes standard attributes like 'objectclass' and 'dn'. ```rust pub fn get_all_existing_attributes(&self) -> std::collections::HashSet { let mut attributes = std::collections::HashSet::new(); // Always include standard attributes attributes.insert("objectclass".to_string()); attributes.insert("dn".to_string()); // Collect attributes from all entries for entry in self.entries.iter() { for attr_name in entry.attributes.keys() { attributes.insert(attr_name.to_lowercase()); } } attributes } ``` -------------------------------- ### Sum of Results Example Source: https://docs.rs/yamldap/latest/yamldap/type.Result.html Illustrates summing elements from an iterator of `Result` types. The summation stops and returns the first `Err` if any element is an `Err`, otherwise it returns the sum of all `Ok` values. ```rust let f = |&x: &i32| if x < 0 { Err("Negative element found") } else { Ok(x) }; let v = vec![1, 2]; let res: Result = v.iter().map(f).sum(); assert_eq!(res, Ok(3)); let v = vec![1, -2]; let res: Result = v.iter().map(f).sum(); assert_eq!(res, Err("Negative element found")); ``` -------------------------------- ### Initialize YAML Watcher with Symbolic Link Source: https://docs.rs/yamldap/latest/src/yamldap/yaml/watcher.rs.html Demonstrates the ability to create a YAML watcher that monitors a file through a symbolic link. Ensures that the watcher can be successfully initialized when the target path is a symlink. ```rust use std::os::unix::fs::symlink; let temp_dir = tempfile::tempdir().unwrap(); let real_file = temp_dir.path().join("real.yaml"); let symlink_file = temp_dir.path().join("link.yaml"); std::fs::write(&real_file, "test: data").unwrap(); symlink(&real_file, &symlink_file).unwrap(); // Should be able to watch through symlink let result = YamlWatcher::new(&symlink_file); assert!(result.is_ok()); ``` -------------------------------- ### Safely Get Ok Value (Never Panics) Source: https://docs.rs/yamldap/latest/yamldap/type.Result.html Use `into_ok()` to retrieve the `Ok` value without panicking. This experimental API is a compile-time safeguard against future panics if the error type changes. ```rust fn only_good_news() -> Result { Ok("this is fine".into()) } let s: String = only_good_news().into_ok(); println!("{s}"); ``` -------------------------------- ### Get All Known Attributes from YamlSchema Source: https://docs.rs/yamldap/latest/src/yamldap/yaml/schema.rs.html Retrieves a set of all attribute names known to the schema, including standard LDAP attributes, object class attributes, and custom attributes. Attributes are returned in lowercase. ```rust impl YamlSchema { /// Get all known attributes from the schema pub fn get_all_known_attributes(&self) -> std::collections::HashSet { let mut attributes = std::collections::HashSet::new(); // Add standard LDAP attributes that are always available attributes.insert("objectclass".to_string()); attributes.insert("dn".to_string()); // Add attributes from all object classes for attrs in self.object_classes.values() { for attr in attrs { attributes.insert(attr.to_lowercase()); } } // Add custom attributes for attr_name in self.custom_attributes.keys() { attributes.insert(attr_name.to_lowercase()); } attributes } } ``` -------------------------------- ### LdapEntry Methods Source: https://docs.rs/yamldap/latest/yamldap/directory/entry/struct.LdapEntry.html Provides methods for interacting with LdapEntry instances, such as creating new entries, adding attributes, and retrieving attribute information. ```APIDOC ## Implementations ### impl LdapEntry #### pub fn new(dn: String) -> Self Creates a new LdapEntry with the given distinguished name. #### pub fn add_attribute(&mut self, name: String, values: Vec, syntax: AttributeSyntax) Adds an attribute to the LdapEntry. Requires the attribute name, its values, and its syntax. #### pub fn get_attribute(&self, name: &str) -> Option<&LdapAttribute> Retrieves an attribute by its name. Returns `Some(&LdapAttribute)` if found, otherwise `None`. #### pub fn has_attribute(&self, name: &str) -> bool Checks if the LdapEntry has an attribute with the specified name. Returns `true` if it exists, `false` otherwise. #### pub fn matches_dn(&self, dn: &str) -> bool Checks if the entry's distinguished name matches the provided DN string. ``` -------------------------------- ### Safely Get Err Value (Never Panics) Source: https://docs.rs/yamldap/latest/yamldap/type.Result.html Use `into_err()` to retrieve the `Err` value without panicking. This experimental API acts as a compile-time safeguard against future panics if the success type changes. ```rust fn only_bad_news() -> Result { Err("Oops, it failed".into()) } let error: String = only_bad_news().into_err(); println!("{error}"); ``` -------------------------------- ### Initialize YamlWatcher and Spawn Task Source: https://docs.rs/yamldap/latest/src/yamldap/yaml/watcher.rs.html Creates a new YamlWatcher, sets up file watching with a specified poll interval, and spawns a Tokio task to handle events. Returns the watcher and a receiver for reload signals. ```rust pub fn new(path: &Path) -> Result<(Self, watch::Receiver<()>)> { let (tx, rx) = mpsc::channel(); let (reload_tx, reload_rx) = watch::channel(()); let mut watcher = RecommendedWatcher::new( move |res: notify::Result| { if let Err(e) = tx.send(res) { error!("Failed to send file watch event: {}", e); } }, Config::default().with_poll_interval(Duration::from_secs(2)), ) .map_err(|e| { crate::YamlLdapError::Io(std::io::Error::other(format!( "Failed to create file watcher: {}", e ))) })?; // Watch the parent directory for better compatibility let parent_dir = path.parent().unwrap_or(Path::new(".")); watcher .watch(parent_dir, RecursiveMode::NonRecursive) .map_err(|e| { crate::YamlLdapError::Io(std::io::Error::other(format!( "Failed to watch directory: {}", e ))) })?; let watched_path = path.to_path_buf(); let reload_tx_clone = reload_tx.clone(); // Spawn a task to handle file events tokio::spawn(async move { let yaml_watcher = YamlWatcher { _watcher: watcher, rx, }; yaml_watcher.run(watched_path, reload_tx_clone).await; }); Ok(( YamlWatcher { _watcher: RecommendedWatcher::new(|_| {}, Config::default()).unwrap(), rx: mpsc::channel().1, }, reload_rx, )) } ``` -------------------------------- ### Expect Err Value with Custom Panic Message Source: https://docs.rs/yamldap/latest/yamldap/type.Result.html Use `expect_err()` to get the contained `Err` value. This method panics if the `Result` is an `Ok`, including the provided message and the `Ok` value in the panic output. ```rust let x: Result = Ok(10); x.expect_err("Testing expect_err"); // panics with `Testing expect_err: 10` ``` -------------------------------- ### LDAP Entry with Unicode DN Source: https://docs.rs/yamldap/latest/src/yamldap/directory/entry.rs.html Illustrates creating an LdapEntry with a DN that includes Unicode characters. Verifies exact DN matching. ```rust // Test DN with Unicode characters let unicode_dn = "cn=用户,ou=组织,dc=例子,dc=com"; let entry = LdapEntry::new(unicode_dn.to_string()); assert_eq!(entry.dn, unicode_dn); assert!(entry.matches_dn(unicode_dn)); ``` -------------------------------- ### Try Parse Command-Line Arguments Source: https://docs.rs/yamldap/latest/yamldap/config/struct.CliArgs.html Attempts to parse command-line arguments from the environment. Returns a Result, yielding an Error if parsing fails. ```rust pub fn try_parse() -> Result ``` -------------------------------- ### Creating a New LDAP Entry Source: https://docs.rs/yamldap/latest/src/yamldap/directory/entry.rs.html Initializes a new LDAP entry with a specified distinguished name (DN). ```rust let entry = LdapEntry::new("cn=test,dc=example,dc=com".to_string()); assert_eq!(entry.dn, "cn=test,dc=example,dc=com"); assert!(entry.attributes.is_empty()); assert!(entry.object_classes.is_empty()); ``` -------------------------------- ### Create Test YAML File Source: https://docs.rs/yamldap/latest/src/yamldap/server/mod.rs.html Helper function to create a temporary YAML file for testing server configurations. It writes basic LDAP schema and entry data to the file. ```rust fn create_test_yaml_file() -> tempfile::NamedTempFile { use std::io::Write; let mut file = tempfile::NamedTempFile::new().unwrap(); writeln!(file, "base_dn: dc=test,dc=com").unwrap(); writeln!(file, "schema:").unwrap(); writeln!(file, " attributes:").unwrap(); writeln!(file, " cn:").unwrap(); writeln!(file, " syntax: string").unwrap(); writeln!(file, " multi_valued: false").unwrap(); writeln!(file, "entries:").unwrap(); writeln!(file, " - dn: cn=test,dc=test,dc=com").unwrap(); writeln!(file, " objectClass: [top, person]").unwrap(); writeln!(file, " cn: test").unwrap(); file.flush().unwrap(); file } ```