Skip to content

Commit cff91d2

Browse files
authored
Merge pull request #12 from Wukong247/2025-08-14-add-integration-test-feature-flag
Add integration test feature flag
2 parents 695b09a + 5d1ac26 commit cff91d2

6 files changed

Lines changed: 112 additions & 4 deletions

File tree

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,8 @@ tokio-socks = "0.5.2"
2727
tokio-util = "0.7.15"
2828
tracing = "0.1.41"
2929
tracing-subscriber = "0.3.19"
30+
31+
32+
[features]
33+
default = []
34+
integration-test = []

src/indexer/tracker_indexer.rs

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use r2d2::Pool;
55
use tokio::{sync::mpsc::Sender, time::Instant};
66

77
use bitcoincore_rpc::bitcoin::absolute::{Height, LockTime};
8+
use std::str::FromStr;
89
use tracing::info;
910

1011
use super::rpc::BitcoinRpc;
@@ -38,7 +39,7 @@ pub async fn run(
3839
continue;
3940
}
4041

41-
if tx.output.len() < 2 {
42+
if tx.output.len() < 2 || tx.output.len() > 5 {
4243
continue;
4344
}
4445

@@ -96,13 +97,23 @@ fn extract_onion_address_from_script(script: &[u8]) -> Option<String> {
9697

9798
let data = &script[data_start..data_start + data_len];
9899
let decoded = String::from_utf8(data.to_vec()).ok()?;
100+
101+
#[cfg(not(feature = "integration-test"))]
99102
if is_valid_onion_address(&decoded) {
100103
Some(decoded)
101104
} else {
102105
None
103106
}
107+
108+
#[cfg(feature = "integration-test")]
109+
if is_valid_address(&decoded) {
110+
Some(decoded)
111+
} else {
112+
None
113+
}
104114
}
105115

116+
#[cfg(not(feature = "integration-test"))]
106117
fn is_valid_onion_address(s: &str) -> bool {
107118
let parts: Vec<&str> = s.split(':').collect();
108119
if parts.len() != 2 {
@@ -115,3 +126,61 @@ fn is_valid_onion_address(s: &str) -> bool {
115126
}
116127
matches!(port.parse::<u16>(), Ok(p) if p > 0)
117128
}
129+
130+
#[cfg(feature = "integration-test")]
131+
fn is_valid_address(s: &str) -> bool {
132+
let parts: Vec<&str> = s.split(':').collect();
133+
if parts.len() != 2 {
134+
return false;
135+
}
136+
137+
let ip = parts[0];
138+
let port = parts[1];
139+
140+
if std::net::Ipv4Addr::from_str(ip).is_err() {
141+
return false;
142+
}
143+
144+
matches!(port.parse::<u16>(), Ok(p) if p > 0)
145+
}
146+
147+
#[cfg(not(feature = "integration-test"))]
148+
#[cfg(test)]
149+
mod tests_onion {
150+
use super::*;
151+
152+
#[test]
153+
fn test_valid_onion_address() {
154+
assert!(is_valid_onion_address("example.onion:1234"));
155+
assert!(is_valid_onion_address("abc1234567890def.onion:65535"));
156+
}
157+
158+
#[test]
159+
fn test_invalid_onion_address() {
160+
assert!(!is_valid_onion_address("example.com:1234"));
161+
assert!(!is_valid_onion_address("example.onion:0"));
162+
assert!(!is_valid_onion_address("example.onion"));
163+
assert!(!is_valid_onion_address("127.0.0.1:8080"));
164+
}
165+
}
166+
167+
#[cfg(feature = "integration-test")]
168+
#[cfg(test)]
169+
mod tests_ipv4 {
170+
use super::*;
171+
172+
#[test]
173+
fn test_valid_ipv4_address() {
174+
assert!(is_valid_address("127.0.0.1:8080"));
175+
assert!(is_valid_address("192.168.1.1:65535"));
176+
}
177+
178+
#[test]
179+
fn test_invalid_ipv4_address() {
180+
assert!(!is_valid_address("example.onion:1234"));
181+
assert!(!is_valid_address("256.0.0.1:8080"));
182+
assert!(!is_valid_address("127.0.0.1:0"));
183+
assert!(!is_valid_address("127.0.0.1"));
184+
assert!(!is_valid_address("::1:8080"));
185+
}
186+
}

src/lib.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ mod utils;
2424
use diesel_migrations::{EmbeddedMigrations, MigrationHarness, embed_migrations};
2525
pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!();
2626

27+
#[cfg(not(feature = "integration-test"))]
2728
#[derive(Debug, Clone)]
2829
pub struct Config {
2930
pub rpc_url: String,
@@ -35,6 +36,15 @@ pub struct Config {
3536
pub datadir: String,
3637
}
3738

39+
#[cfg(feature = "integration-test")]
40+
#[derive(Debug, Clone)]
41+
pub struct Config {
42+
pub rpc_url: String,
43+
pub rpc_auth: Auth,
44+
pub address: String,
45+
pub datadir: String,
46+
}
47+
3848
fn run_migrations(pool: Arc<Pool<ConnectionManager<SqliteConnection>>>) {
3949
let mut conn = pool
4050
.get()
@@ -58,10 +68,12 @@ pub async fn start(cfg: Config) {
5868
run_migrations(pool.clone());
5969
info!("Connected to indexer db");
6070

71+
#[cfg(not(feature = "integration-test"))]
6172
tor::check_tor_status(cfg.control_port, &cfg.tor_auth_password)
6273
.await
6374
.expect("Failed to check Tor status");
6475

76+
#[cfg(not(feature = "integration-test"))]
6577
let hostname = match cfg.address.split_once(':') {
6678
Some((_, port)) => {
6779
let port = port.parse::<u16>().expect("Invalid port in address");
@@ -80,6 +92,9 @@ pub async fn start(cfg: Config) {
8092
}
8193
};
8294

95+
#[cfg(feature = "integration-test")]
96+
let hostname = cfg.address.clone();
97+
8398
info!("Tracker is listening at {}", hostname);
8499

85100
let (mut db_tx, db_rx) = mpsc::channel::<DbRequest>(10);
@@ -93,6 +108,7 @@ pub async fn start(cfg: Config) {
93108
db_tx.clone(),
94109
status_tx.clone(),
95110
cfg.address.clone(),
111+
#[cfg(not(feature = "integration-test"))]
96112
cfg.socks_port,
97113
hostname.clone(),
98114
)
@@ -125,6 +141,7 @@ pub async fn start(cfg: Config) {
125141
db_tx.clone(),
126142
status_tx.clone(),
127143
cfg.address.clone(),
144+
#[cfg(not(feature = "integration-test"))]
128145
cfg.socks_port,
129146
hostname.clone(),
130147
)
@@ -162,14 +179,15 @@ async fn spawn_server(
162179
db_tx: tokio::sync::mpsc::Sender<DbRequest>,
163180
status_tx: tokio::sync::mpsc::Sender<Status>,
164181
address: String,
165-
socks_port: u16,
182+
#[cfg(not(feature = "integration-test"))] socks_port: u16,
166183
hostname: String,
167184
) {
168185
info!("Spawning server instance");
169186
tokio::spawn(server::run(
170187
db_tx,
171188
status::Sender::Server(status_tx),
172189
address,
190+
#[cfg(not(feature = "integration-test"))]
173191
socks_port,
174192
hostname,
175193
));

src/main.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ async fn main() {
3030
(parts[0].to_string(), parts[1].to_string())
3131
};
3232

33+
#[cfg(not(feature = "integration-test"))]
3334
let cfg = Config {
3435
rpc_url: args.rpc,
3536
rpc_auth: Auth::UserPass(user, pass),
@@ -40,5 +41,13 @@ async fn main() {
4041
datadir: args.datadir,
4142
};
4243

44+
#[cfg(feature = "integration-test")]
45+
let cfg = Config {
46+
rpc_url: args.rpc,
47+
rpc_auth: Auth::UserPass(user, pass),
48+
address: args.address,
49+
datadir: args.datadir,
50+
};
51+
4352
start(cfg).await;
4453
}

src/server/tracker_monitor.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use std::time::Duration;
22

3+
#[cfg(feature = "integration-test")]
4+
use tokio::net::TcpStream;
35
use tokio::{
46
io::BufWriter,
57
sync::mpsc::Sender,
@@ -23,7 +25,7 @@ const COOLDOWN_PERIOD: u64 = 5;
2325
pub async fn monitor_systems(
2426
db_tx: Sender<DbRequest>,
2527
status_tx: status::Sender,
26-
socks_port: u16,
28+
#[cfg(not(feature = "integration-test"))] socks_port: u16,
2729
onion_address: String,
2830
port: u16,
2931
) -> Result<(), TrackerError> {
@@ -45,12 +47,16 @@ pub async fn monitor_systems(
4547

4648
let mut success = false;
4749
for attempt in 1..=3 {
50+
#[cfg(not(feature = "integration-test"))]
4851
let connect_result = Socks5Stream::connect(
4952
format!("127.0.0.1:{socks_port:?}").as_str(),
5053
address.clone(),
5154
)
5255
.await;
5356

57+
#[cfg(feature = "integration-test")]
58+
let connect_result = TcpStream::connect(address.clone()).await;
59+
5460
match connect_result {
5561
Ok(mut stream) => {
5662
success = true;

src/server/tracker_server.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub async fn run(
1919
db_tx: Sender<DbRequest>,
2020
status_tx: status::Sender,
2121
address: String,
22-
socks_port: u16,
22+
#[cfg(not(feature = "integration-test"))] socks_port: u16,
2323
onion_address: String,
2424
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
2525
let port = address
@@ -31,6 +31,7 @@ pub async fn run(
3131
tokio::spawn(monitor_systems(
3232
db_tx.clone(),
3333
status_tx.clone(),
34+
#[cfg(not(feature = "integration-test"))]
3435
socks_port,
3536
onion_address,
3637
port,

0 commit comments

Comments
 (0)