Skip to content

Commit b1072c9

Browse files
committed
Irondrop: migrate from file based loogging to dir
* Generate and add more tests, Fix some failures and remove monkey code.
1 parent 2b8ce49 commit b1072c9

24 files changed

Lines changed: 2010 additions & 152 deletions

‎README.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ IronDrop has extensive documentation covering its architecture, API, and feature
242242
243243
## Testing
244244
245-
IronDrop is rigorously tested with **106 comprehensive tests across 15 test files** covering all aspects of functionality.
245+
IronDrop is rigorously tested with **179 comprehensive tests across 16 test files** covering all aspects of functionality.
246246
247247
### Test Categories
248248
- **Integration Tests** (8 tests): End-to-end functionality and HTTP handling
@@ -278,7 +278,7 @@ IronDrop is licensed under the [MIT License](./LICENSE).
278278
<div align="center">
279279
<p>
280280
<strong>Made with ❤️ and 🦀 in Rust</strong><br>
281-
<em>Zero dependencies • Production ready • Battle tested with 106 comprehensive tests</em>
281+
<em>Zero dependencies • Production ready • Battle tested with 179 comprehensive tests</em>
282282
</p>
283283
<p>
284284
<a href="https://github.com/dev-harsh1998/IronDrop">⭐ Star us on GitHub</a>

‎config/irondrop.ini‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,19 @@ verbose = true
193193
# 💡 Good for production monitoring without overwhelming detail
194194
detailed = true
195195

196+
# 📁 Log Directory - Where to save log files (optional)
197+
# • If not specified, logs go to console only
198+
# • Directory must exist and be writable
199+
# • Log files are automatically timestamped: irondrop_<timestamp>.log
200+
#
201+
# 💡 Examples:
202+
# • log_dir = /var/log/irondrop
203+
# • log_dir = ./logs
204+
# • log_dir = /home/user/irondrop-logs
205+
#
206+
# ⚠️ Note: Make sure the directory exists before starting IronDrop!
207+
# log_dir = /var/log/irondrop
208+
196209
# ===============================================================================
197210
# 📚 CONFIGURATION EXAMPLES
198211
# ===============================================================================

‎doc/ARCHITECTURE.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ tests/
179179
├── test_1gb_upload.sh # Large file upload testing
180180
└── test_executable_portability.sh # Portability validation
181181
182-
Total: 59 tests across 13 test files
182+
Total: 179 tests across 16 test files
183183
```
184184

185185
## Search System Architecture

‎doc/README.md‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Recent updates include direct streaming uploads and the ultra-compact search mod
2626
- Security architecture and defense-in-depth implementation
2727
- Performance characteristics and scalability considerations
2828
- Template system design and asset pipeline
29-
- Testing architecture with 106 comprehensive tests across 15 test files
29+
- Testing architecture with 125 comprehensive tests across 16 test files
3030

3131
**Key Sections:**
3232
- Core module breakdown with line counts and responsibilities
@@ -91,7 +91,7 @@ Native zero-dependency template engine: variables, conditionals, embedded assets
9191
**Purpose**: Comprehensive testing suite documentation and validation procedures
9292

9393
**Contents:**
94-
- **Complete Test Coverage**: 106 tests across 15 test files covering all functionality
94+
- **Complete Test Coverage**: 179 tests across 16 test files covering all functionality
9595
- **Test Categories**: Core server, integration, edge cases, memory optimization, performance, stress testing, streaming
9696
- **Security Testing**: Path traversal prevention, input validation, authentication mechanisms
9797
- **Performance Benchmarks**: Memory efficiency targets, upload speed thresholds, stress test metrics
@@ -339,7 +339,7 @@ IronDrop v2.5 introduces a **production-ready file upload system** with enterpri
339339
- **⚡ Performance**: Handles unlimited file sizes with constant memory usage and concurrent processing
340340
- **🎨 Professional UI**: Integrated upload interface accessible at `/upload` with real-time feedback
341341
- **🛡️ Robust Validation**: Multi-layer security including extension filtering, size limits, and malformed data rejection
342-
- **🧪 Battle-Tested**: 106 tests across 15 test files covering edge cases, security scenarios, and performance stress testing
342+
- **🧪 Battle-Tested**: 179 tests across 16 test files covering edge cases, security scenarios, and performance stress testing
343343

344344
### 🔍 **Advanced Search System** (New in v2.5)
345345
IronDrop v2.5 introduces a **dual-mode search engine** optimized for directories of any size:
@@ -625,7 +625,7 @@ Every module is documented and formatted with `cargo fmt` and `clippy -- -D warn
625625

626626
### Comprehensive Test Suite
627627

628-
The project includes **106 comprehensive tests across 15 test files** covering all aspects of functionality, with complete upload system validation:
628+
The project includes **179 comprehensive tests across 16 test files** covering all aspects of functionality, with complete upload system validation:
629629

630630
```bash
631631
# Run all tests (covers upload, download, security, concurrency)
@@ -977,7 +977,7 @@ UI system and template integration:
977977

978978
### 🧪 **Testing & Quality Assurance**
979979

980-
IronDrop includes **59 comprehensive tests across 13 test files** covering:
980+
IronDrop includes **179 comprehensive tests across 16 test files** covering:
981981

982982
- **Core Server Tests** (19 tests): HTTP handling, directory listing, authentication
983983
- **Upload System Tests** (29 tests): File uploads, validation, concurrent handling
@@ -1005,7 +1005,7 @@ cargo test multipart_test # Multipart parser
10051005
| **Source Files** | 15 | Rust modules with clear separation of concerns |
10061006
| **Lines of Code** | 3000+ | Production-ready implementation |
10071007
| **Template Files** | 10 | Professional UI with HTML/CSS/JS separation |
1008-
| **Test Cases** | 59 across 13 files | Comprehensive coverage including security tests |
1008+
| **Test Cases** | 179 across 16 files | Comprehensive coverage including security tests |
10091009
| **Documentation Pages** | 10 | Complete technical documentation suite |
10101010

10111011
---
@@ -1069,7 +1069,7 @@ We welcome contributions! Here's how to get started:
10691069

10701070
### **For Developers**
10711071
- **Pure Rust**: No external dependencies, everything built from scratch
1072-
- **Comprehensive Tests**: 59 tests across 13 files ensure reliability and stability
1072+
- **Comprehensive Tests**: 179 tests across 16 files ensure reliability and stability
10731073
- **Clean Architecture**: Well-documented, modular codebase
10741074
- **Performance Focus**: Custom thread pool and optimized file streaming
10751075

‎doc/SEARCH_FEATURE.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ let engine = SearchEngine::new(
388388

389389
### Test Coverage
390390

391-
The search functionality includes comprehensive tests as part of IronDrop's 59-test suite across 13 test files:
391+
The search functionality includes comprehensive tests as part of IronDrop's 125-test suite across 16 test files:
392392

393393
1. **Ultra-Compact Search Tests** (`tests/ultra_compact_test.rs` - 4 tests):
394394
- RadixIndex memory efficiency with 10M entries

‎doc/TESTING_DOCUMENTATION.md‎

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# IronDrop Testing Documentation
22

3-
Version 2.6 - Test Suite Overview
3+
Version 2.6.2 - Test Suite Overview
44

55
## Overview
66

7-
IronDrop includes a test suite covering functionality, security scenarios, and performance-related paths.
7+
IronDrop includes a comprehensive test suite with **179 tests** covering functionality, security scenarios, performance validation, and concurrent operations. Recent improvements include enhanced path parsing, Unicode support, and race condition fixes.
88

99
## Test Architecture
1010

@@ -22,17 +22,22 @@ IronDrop includes a test suite covering functionality, security scenarios, and p
2222
| Category | Test Files | Test Count | Coverage |
2323
|----------|------------|------------|----------|
2424
| **Core Server & Unit Tests** | `lib.rs` (unit tests) | 41 | Core functionality, HTTP handling, utilities |
25-
| **Configuration System** | `config_test.rs` | 12 | INI parsing, precedence, validation |
26-
| **Direct Upload System** | `direct_upload_test.rs` | 8 | File uploads, streaming, validation |
27-
| **Integration Testing** | `integration_test.rs` | 8 | Authentication, security, HTTP compliance |
28-
| **Monitoring & Stats** | `monitor_test.rs` | 2 | Health endpoints, metrics tracking |
29-
| **Rate Limiting** | `rate_limiter_memory_test.rs` | 5 | Memory management, cleanup, limits |
25+
| **Configuration System** | `config_test.rs` | 16 | INI parsing, precedence, validation, edge cases |
26+
| **Direct Upload System** | `direct_upload_test.rs` | 15 | File uploads, streaming, concurrent operations, race conditions |
27+
| **Integration Testing** | `integration_test.rs` | 14 | Authentication, security, HTTP compliance, edge cases |
28+
| **Memory & Performance** | `memory_leak_fix_test.rs` | 19 | Memory management, leak prevention, cleanup |
29+
| **HTTP Parser** | `http_parser_test.rs` | 13 | Version parsing, malformed requests, edge cases |
30+
| **Middleware** | `middleware_test.rs` | 13 | Authentication, security, request processing |
3031
| **Template System** | `template_embedding_test.rs`, `templates_escape_test.rs` | 7 | Embedded templates, escaping, assets |
32+
| **Template Utilities** | `response_utils_test.rs` | 2 | Response generation, template processing |
3133
| **Ultra-Compact Search** | `ultra_compact_test.rs` | 5 | Memory efficiency, search performance |
32-
| **Middleware** | `middleware_test.rs` | 5 | Basic auth middleware |
33-
| **HTTP Parser** | `http_parser_test.rs` | 3 | Version, separators, chunked handling |
34+
| **Rate Limiting** | `rate_limiter_memory_test.rs` | 5 | Memory management, cleanup, limits |
35+
| **Monitoring & Stats** | `monitor_test.rs` | 2 | Health endpoints, metrics tracking |
36+
| **Utilities** | `utils_test.rs`, `utils_parse_path_test.rs` | 23 | Path parsing, Unicode encoding, special characters |
3437
| **Request Body** | `http_requestbody_test.rs` | 1 | Size and emptiness |
35-
| **Utilities** | `utils_test.rs`, `utils_parse_path_test.rs` | 4 | Encoding, parsing, path utilities |
38+
| **Logging** | `log_dir_test.rs` | 3 | Directory creation, permissions |
39+
40+
**Total Tests: 179**
3641

3742
## Detailed Test Coverage
3843

@@ -177,7 +182,7 @@ fn test_demonstrate_memory_savings() // Compares memory usage vs alternatives
177182

178183
## Running Tests
179184

180-
### Basic Test Execution (current totals: 106 tests across 15 files)
185+
### Basic Test Execution (current totals: 179 tests across 16 files)
181186

182187
```bash
183188
# Run all tests
@@ -367,6 +372,35 @@ fn test_new_feature() {
367372
- Code formatting validation
368373
- Documentation completeness
369374

375+
## Recent Improvements (v2.6.2)
376+
377+
### Critical Fixes and Enhancements
378+
379+
**Path Parsing Improvements**
380+
- Fixed `get_request_path` function to correctly handle HTTP request paths with internal spaces
381+
- Enhanced logic to find space before "HTTP/" instead of using first space occurrence
382+
- Added proper whitespace trimming for edge cases with trailing spaces
383+
- All 9 path parsing tests now pass, including complex whitespace scenarios
384+
385+
**Unicode and Special Character Support**
386+
- Enhanced `percent_encode_path` function with comprehensive character encoding
387+
- Added support for Unicode characters (non-ASCII) in file paths
388+
- Implemented proper handling of empty paths and root paths
389+
- Extended encoding for special characters requiring URL encoding
390+
- All 14 utility tests now pass with full Unicode compliance
391+
392+
**Concurrent Upload Race Condition Fix**
393+
- Identified and resolved critical race condition in `generate_unique_filename` method
394+
- Replaced non-atomic file existence checks with atomic `create_new()` operations
395+
- Prevents multiple threads from creating files with same name simultaneously
396+
- All 15 direct upload tests now pass, including concurrent upload scenarios
397+
398+
**Test Suite Stability**
399+
- Achieved 100% test pass rate across all 179 tests
400+
- Enhanced test reliability under concurrent execution
401+
- Improved error handling and edge case coverage
402+
- Added comprehensive validation for boundary conditions
403+
370404
## Future Test Enhancements
371405

372406
### Planned Additions

‎src/cli.rs‎

Lines changed: 42 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@ pub struct Cli {
6868
#[arg(long, value_parser = validate_config_file)]
6969
pub config_file: Option<String>,
7070

71-
/// Log file path - Redirect all logging output to a file instead of stdout. If not provided, logs go to stdout 📝
72-
#[arg(long, value_parser = validate_log_file)]
73-
pub log_file: Option<String>,
71+
/// Log directory path - Directory where timestamped log files will be created. If not provided, logs go to stdout 📝
72+
#[arg(long, value_parser = validate_log_dir)]
73+
pub log_dir: Option<PathBuf>,
7474
}
7575

7676
/// Validate upload size (minimum 1 MB, no upper limit for direct streaming)
@@ -112,54 +112,6 @@ fn validate_config_file(s: &str) -> Result<String, String> {
112112
}
113113
}
114114

115-
/// Validate log file path and ensure parent directory exists
116-
fn validate_log_file(s: &str) -> Result<String, String> {
117-
if s.is_empty() {
118-
return Err("Log file path cannot be empty".to_string());
119-
}
120-
121-
let path = PathBuf::from(s);
122-
123-
// Check if parent directory exists
124-
if let Some(parent) = path.parent() {
125-
if !parent.exists() {
126-
return Err(format!(
127-
"Log file parent directory does not exist: {}",
128-
parent.display()
129-
));
130-
}
131-
if !parent.is_dir() {
132-
return Err(format!(
133-
"Log file parent path is not a directory: {}",
134-
parent.display()
135-
));
136-
}
137-
}
138-
139-
// If file exists, check if it's writable
140-
if path.exists() {
141-
if path.is_dir() {
142-
return Err(format!("Log file path is a directory: {s}"));
143-
}
144-
// Try to open for append to check write permissions
145-
match std::fs::OpenOptions::new().append(true).open(&path) {
146-
Ok(_) => {}
147-
Err(e) => return Err(format!("Cannot write to log file {s}: {e}")),
148-
}
149-
} else {
150-
// Try to create the file to check write permissions
151-
match std::fs::File::create(&path) {
152-
Ok(_) => {
153-
// Remove the test file
154-
let _ = std::fs::remove_file(&path);
155-
}
156-
Err(e) => return Err(format!("Cannot create log file {s}: {e}")),
157-
}
158-
}
159-
160-
Ok(s.to_string())
161-
}
162-
163115
impl Cli {
164116
/// Validate the CLI configuration for security and consistency
165117
pub fn validate(&self) -> Result<(), AppError> {
@@ -243,7 +195,7 @@ mod tests {
243195
enable_upload: Some(false),
244196
max_upload_size: Some(100),
245197
config_file: None,
246-
log_file: None,
198+
log_dir: None,
247199
};
248200

249201
// Test conversion
@@ -278,7 +230,7 @@ mod tests {
278230
enable_upload: Some(true),
279231
max_upload_size: Some(100),
280232
config_file: None,
281-
log_file: None,
233+
log_dir: None,
282234
};
283235

284236
assert!(cli.validate().is_ok());
@@ -296,3 +248,40 @@ mod tests {
296248
assert!(file_cli.validate().is_err());
297249
}
298250
}
251+
252+
/// Validate log directory path and ensure it exists and is writable
253+
fn validate_log_dir(s: &str) -> Result<PathBuf, String> {
254+
if s.is_empty() {
255+
return Err("Log directory path cannot be empty".to_string());
256+
}
257+
258+
let path = PathBuf::from(s);
259+
260+
// Check if directory exists
261+
if !path.exists() {
262+
return Err(format!("Log directory does not exist: {}", path.display()));
263+
}
264+
265+
// Check if it's a directory
266+
if !path.is_dir() {
267+
return Err(format!(
268+
"Log directory path is not a directory: {}",
269+
path.display()
270+
));
271+
}
272+
273+
// Test write permissions by creating a temporary file
274+
let test_file = path.join(".irondrop_write_test");
275+
match std::fs::File::create(&test_file) {
276+
Ok(_) => {
277+
// Remove the test file
278+
let _ = std::fs::remove_file(&test_file);
279+
Ok(path)
280+
}
281+
Err(e) => Err(format!(
282+
"Cannot write to log directory {}: {}",
283+
path.display(),
284+
e
285+
)),
286+
}
287+
}

‎src/config/ini_parser.rs‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,10 @@ fn parse_file_size(value: &str) -> Option<u64> {
220220

221221
// Try parsing as float for decimal values like "1.5"
222222
if let Ok(num) = num_str.parse::<f64>() {
223+
// Reject negative numbers
224+
if num < 0.0 {
225+
return None;
226+
}
223227
return Some((num * suffix as f64) as u64);
224228
}
225229

@@ -249,6 +253,11 @@ mod tests {
249253
Some((2.5 * 1024.0 * 1024.0) as u64)
250254
);
251255
assert_eq!(parse_file_size("invalid"), None);
256+
257+
// Test invalid cases that should return None
258+
assert_eq!(parse_file_size("-1MB"), None);
259+
assert_eq!(parse_file_size("ABCMB"), None);
260+
assert_eq!(parse_file_size("100XB"), None);
252261
}
253262

254263
#[test]

0 commit comments

Comments
 (0)