• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tox-rs / tox / 6967930078

23 Nov 2023 09:37AM UTC coverage: 94.849% (-0.03%) from 94.876%
6967930078

Pull #477

github

web-flow
Merge 4d4ecdd60 into 5ab95a61f
Pull Request #477: Add functions for tox crate version information

0 of 10 new or added lines in 1 file covered. (0.0%)

13 existing lines in 7 files now uncovered.

16813 of 17726 relevant lines covered (94.85%)

1.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

72.92
/tox_node/src/node_config.rs
1
use std::collections::HashMap;
2
use std::convert::TryInto;
3
use std::net::{SocketAddr, ToSocketAddrs};
4
use std::num::ParseIntError;
5
use std::str::FromStr;
6

7
use clap::{
8
    builder::{ArgPredicate, PossibleValue},
9
    value_parser, Arg, ArgAction, ArgGroup, ArgMatches, Command, ValueEnum,
10
};
11
use config::{Config, File as CfgFile, FileFormat as CfgFileFormat};
12
use hex::FromHex;
13
use itertools::Itertools;
14
use serde::{de, Deserialize, Deserializer};
15
use serde_yaml::Value;
16
use tox::crypto::*;
17
use tox::packet::dht::packed_node::PackedNode;
18
use tox::packet::dht::BOOSTRAP_SERVER_MAX_MOTD_LENGTH;
19

20
/// Config for threading.
21
#[derive(Clone, Copy, PartialEq, Eq, Debug, Deserialize)]
22
pub enum Threads {
23
    /// Detect number of threads automatically by the number of CPU cores.
24
    Auto,
25
    /// Exact number of threads.
26
    N(u16),
27
}
28

29
impl FromStr for Threads {
30
    type Err = ParseIntError;
31

32
    fn from_str(s: &str) -> Result<Self, Self::Err> {
1✔
33
        if s == "auto" {
1✔
34
            Ok(Threads::Auto)
×
35
        } else {
36
            u16::from_str(s).map(Threads::N)
1✔
37
        }
38
    }
39
}
40

41
/// Specifies where to write logs.
42
#[derive(Clone, Copy, PartialEq, Eq, Debug, Deserialize)]
43
pub enum LogType {
44
    Stderr,
45
    Stdout,
46
    #[cfg(unix)]
47
    Syslog,
48
    None,
49
}
50

51
impl ValueEnum for LogType {
UNCOV
52
    fn value_variants<'a>() -> &'a [Self] {
×
53
        use self::LogType::*;
54
        &[
×
55
            Stderr,
×
56
            Stdout,
×
57
            #[cfg(unix)]
×
58
            Syslog,
×
59
            None,
×
60
        ]
61
    }
62

63
    fn to_possible_value<'a>(&self) -> Option<PossibleValue> {
1✔
64
        use self::LogType::*;
65
        Some(match self {
2✔
66
            Stderr => PossibleValue::new("Stderr"),
1✔
67
            Stdout => PossibleValue::new("Stdout"),
1✔
68
            #[cfg(unix)]
×
69
            Syslog => PossibleValue::new("Syslog"),
1✔
70
            None => PossibleValue::new("None"),
1✔
71
        })
72
    }
73
}
74

75
/// Bootstrap node with generic string address which might be either IP address
76
/// or DNS name.
77
#[derive(Clone, PartialEq, Eq, Debug, Deserialize)]
78
pub struct BootstrapNode {
79
    /// `PublicKey` of the node.
80
    #[serde(deserialize_with = "de_from_hex")]
81
    pk: PublicKey,
82
    /// Generic string address which might be either IP address or DNS name.
83
    addr: String,
84
}
85

86
impl BootstrapNode {
87
    /// Resolve string address of the node to possible multiple `SocketAddr`s.
88
    pub fn resolve(&self) -> impl Iterator<Item = PackedNode> {
×
89
        let pk = self.pk.clone();
×
90
        let addrs = match self.addr.to_socket_addrs() {
×
91
            Ok(addrs) => addrs,
×
92
            Err(e) => {
×
93
                warn!("Failed to resolve bootstrap node address '{}': {}", self.addr, e);
×
94
                Vec::new().into_iter()
×
95
            }
96
        };
97
        addrs.map(move |addr| PackedNode::new(addr, pk.clone()))
×
98
    }
99
}
100

101
fn de_from_hex<'de, D>(deserializer: D) -> Result<PublicKey, D::Error>
×
102
where
103
    D: Deserializer<'de>,
104
{
105
    let s = String::deserialize(deserializer)?;
×
106

107
    let bootstrap_pk_bytes: [u8; 32] =
×
108
        FromHex::from_hex(s).map_err(|e| de::Error::custom(format!("Can't make bytes from hex string {:?}", e)))?;
×
109
    Ok(PublicKey::from(bootstrap_pk_bytes))
×
110
}
111

112
fn de_threads<'de, D>(deserializer: D) -> Result<Threads, D::Error>
×
113
where
114
    D: Deserializer<'de>,
115
{
116
    let s = String::deserialize(deserializer)?;
×
117

118
    Threads::from_str(&s).map_err(|e| de::Error::custom(format!("threads: {:?}", e)))
×
119
}
120

121
/// Config parsed from command line arguments.
122
#[derive(Clone, Debug, Deserialize)]
123
pub struct NodeConfig {
124
    /// UDP address to run DHT node
125
    #[serde(rename = "udp-address")]
126
    #[serde(default)]
127
    pub udp_addr: Option<SocketAddr>,
128
    /// TCP addresses to run TCP relay
129
    #[serde(rename = "tcp-addresses")]
130
    #[serde(default)]
131
    pub tcp_addrs: Vec<SocketAddr>,
132
    /// Maximum number of active TCP connections relay can hold.
133
    #[serde(rename = "tcp-connections-limit")]
134
    pub tcp_connections_limit: usize,
135
    /// DHT SecretKey
136
    #[serde(skip_deserializing)]
137
    pub sk: Option<SecretKey>,
138
    /// True if the SecretKey was passed as an argument instead of environment
139
    /// variable. Necessary to print a warning since the logger backend is not
140
    /// initialized when we parse arguments.
141
    #[serde(skip_deserializing)]
142
    pub sk_passed_as_arg: bool,
143
    /// Path to the file where DHT keys are stored.
144
    /// Required with config.
145
    #[serde(rename = "keys-file")]
146
    pub keys_file: Option<String>,
147
    /// List of bootstrap nodes.
148
    #[serde(rename = "bootstrap-nodes")]
149
    #[serde(default)]
150
    pub bootstrap_nodes: Vec<BootstrapNode>,
151
    /// Number of threads for execution.
152
    #[serde(deserialize_with = "de_threads")]
153
    pub threads: Threads,
154
    /// Specifies where to write logs.
155
    #[serde(rename = "log-type")]
156
    pub log_type: LogType,
157
    /// Message of the day
158
    pub motd: String,
159
    /// Whether LAN discovery is enabled
160
    #[serde(rename = "lan-discovery")]
161
    pub lan_discovery_enabled: bool,
162
    /// Unused fields while parsing config file
163
    #[serde(flatten)]
164
    pub unused: HashMap<String, Value>,
165
}
166

167
fn create_sk_arg() -> Arg {
1✔
168
    Arg::new("secret-key")
1✔
169
        .short('s')
170
        .long("secret-key")
171
        .help(
172
            "DHT secret key. Note that you should not pass the key via \
173
               arguments due to security reasons. Use this argument for \
174
               test purposes only. In the real world use the environment \
175
               variable instead",
176
        )
177
        .num_args(1)
178
        .conflicts_with("keys-file")
179
        .env("TOX_SECRET_KEY")
180
        .hide(true)
181
}
182

183
fn create_keys_file_arg() -> Arg {
1✔
184
    Arg::new("keys-file")
1✔
185
        .short('k')
186
        .long("keys-file")
187
        .help("Path to the file where DHT keys are stored")
188
        .num_args(1)
189
        .required_unless_present("secret-key")
190
        .conflicts_with("secret-key")
191
}
192

193
fn app() -> Command {
1✔
194
    Command::new(crate_name!())
14✔
195
        .version(crate_version!())
196
        .about(crate_description!())
197
        .args_conflicts_with_subcommands(true)
198
        .subcommand(Command::new("config")
2✔
199
            .arg(Arg::new("cfg-file")
2✔
200
                .index(1)
201
                .help("Load settings from saved config file. \
202
                    Config file format is YAML")
203
                .num_args(1)
204
                .required(true)))
2✔
205
        .subcommand(Command::new("derive-pk")
4✔
206
            .about("Derive PK from either --keys-file or from env:TOX_SECRET_KEY")
1✔
207
            .arg(create_sk_arg())
2✔
208
            .arg(create_keys_file_arg()))
3✔
209
        // here go args without subcommands
210
        .arg(create_sk_arg())
2✔
211
        .arg(create_keys_file_arg())
2✔
212
        .arg(Arg::new("udp-address")
4✔
213
            .short('u')
214
            .long("udp-address")
215
            .help("UDP address to run DHT node")
216
            .num_args(1)
1✔
217
            .value_parser(value_parser!(SocketAddr))
2✔
218
            .required_unless_present("tcp-address"))
1✔
219
        .arg(Arg::new("tcp-address")
5✔
220
            .short('t')
221
            .long("tcp-address")
222
            .help("TCP address to run TCP relay")
223
            .num_args(1..)
2✔
224
            .value_parser(value_parser!(SocketAddr))
2✔
225
            .action(clap::ArgAction::Append)
1✔
226
            .required_unless_present("udp-address"))
1✔
227
        .arg(Arg::new("tcp-connections-limit")
4✔
228
            .short('c')
229
            .long("tcp-connections-limit")
230
            .help("Maximum number of active TCP connections relay can hold. \
231
                   Defaults to 512 when tcp-address is specified")
232
            .requires("tcp-address")
233
            .num_args(1)
1✔
234
            .value_parser(value_parser!(usize))
2✔
235
            .default_value_if("tcp-address", ArgPredicate::IsPresent, Some("512")))
2✔
236
        .arg(Arg::new("bootstrap-node")
4✔
237
            .short('b')
238
            .long("bootstrap-node")
239
            .help("Node to perform initial bootstrap")
240
            .num_args(2)
241
            .action(clap::ArgAction::Append)
1✔
242
            .value_names(["public key", "address"]))
2✔
243
        .group(ArgGroup::new("req_flags")
2✔
244
            .args(["bootstrap-node", "tcp-address"])
1✔
245
            .multiple(true))
1✔
246
        .arg(Arg::new("threads")
4✔
247
            .short('j')
248
            .long("threads")
249
            .help("Number of threads to use. The value 'auto' means that the \
250
                   number of threads will be determined automatically by the \
251
                   number of CPU cores")
252
            .num_args(1)
1✔
253
            .value_parser(value_parser!(Threads))
2✔
254
            .default_value("1"))
1✔
255
        .arg(Arg::new("log-type")
4✔
256
            .short('l')
257
            .long("log-type")
258
            .help("Where to write logs")
259
            .num_args(1)
1✔
260
            .value_parser(value_parser!(LogType))
2✔
261
            .default_value("Stderr"))
1✔
262
        .arg(Arg::new("motd")
2✔
263
            .short('m')
264
            .long("motd")
265
            .help("Message of the day. Must be no longer than 256 bytes. May \
266
                   contain next variables placed in {{ }}:\n\
267
                   - start_date: time when the node was started\n\
268
                   - uptime: uptime in the format 'XX days XX hours XX minutes'\n")
269
            .num_args(1)
270
            .value_parser(|m: &str| {
1✔
271
                if m.len() > BOOSTRAP_SERVER_MAX_MOTD_LENGTH {
2✔
272
                    Err(format!("Message of the day must not be longer than {} bytes", BOOSTRAP_SERVER_MAX_MOTD_LENGTH))
1✔
273
                } else {
274
                    Ok(m.to_string())
1✔
275
                }
276
            })
277
            .default_value("This is tox-rs"))
1✔
278
        .arg(Arg::new("lan-discovery")
3✔
279
            .long("lan-discovery")
280
            .help("Enable LAN discovery (disabled by default)")
281
            .action(ArgAction::SetTrue))
2✔
282
}
283

284
/// Parse command line arguments.
285
pub fn cli_parse() -> NodeConfig {
×
286
    let matches = app().get_matches();
×
287

288
    match matches.subcommand() {
×
289
        Some(("derive-pk", m)) => run_derive_pk(m),
×
290
        Some(("config", m)) => run_config(m),
×
291
        _ => run_args(&matches),
×
292
    }
293
}
294

295
/// Parse settings from a saved file.
296
fn parse_config(config_path: &str) -> NodeConfig {
×
297
    let config_builder = Config::builder()
×
298
        .set_default("log-type", "Stderr")
299
        .expect("Can't set default value for `log-type`")
300
        .set_default("motd", "This is tox-rs")
301
        .expect("Can't set default value for `motd`")
302
        .set_default("lan-discovery", "False")
303
        .expect("Can't set default value for `lan-discovery`")
304
        .set_default("threads", "1")
305
        .expect("Can't set default value for `threads`")
306
        .set_default("tcp-connections-limit", "512")
307
        .expect("Can't set default value for `tcp-connections-limit`")
308
        .add_source(CfgFile::new(config_path, CfgFileFormat::Yaml));
×
309

310
    let config_file = match config_builder.build() {
×
311
        Ok(cfg) => cfg,
×
312
        Err(e) => panic!("Can't build config file {}", e),
×
313
    };
314

315
    let config: NodeConfig = config_file.try_deserialize().expect("Can't deserialize config");
×
316

317
    if config.keys_file.is_none() {
×
318
        panic!("Can't deserialize config: 'keys-file' is not set");
×
319
    }
320

UNCOV
321
    config
×
322
}
323

324
fn run_derive_pk(matches: &ArgMatches) -> ! {
×
325
    let sk_passed_as_arg = matches.contains_id("secret-key");
×
326
    if sk_passed_as_arg {
×
327
        panic!(
×
328
            "You should not pass the secret key via arguments due to \
329
               security reasons. Use the environment variable instead"
330
        );
331
    }
332

333
    let pk_from_arg = matches.get_one::<String>("secret-key").map(|s| {
×
334
        let sk_bytes: [u8; 32] = FromHex::from_hex(s).expect("Invalid DHT secret key");
×
335
        SecretKey::from(sk_bytes).public_key()
×
336
    });
337
    let pk_from_file = matches.get_one::<String>("keys-file").map(|keys_file| {
×
338
        let mut file = std::fs::File::open(keys_file).expect("Failed to read the keys file");
×
339

340
        let mut buf = [0; crypto_box::KEY_SIZE * 2];
×
341
        use std::io::Read;
342
        file.read_exact(&mut buf)
×
343
            .expect("Failed to read keys from the keys file");
344
        let pk_bytes: [u8; crypto_box::KEY_SIZE] = buf[..crypto_box::KEY_SIZE]
×
345
            .try_into()
346
            .expect("Failed to read public key from the keys file");
347
        let sk_bytes: [u8; crypto_box::KEY_SIZE] = buf[crypto_box::KEY_SIZE..]
×
348
            .try_into()
349
            .expect("Failed to read secret key from the keys file");
350
        let pk = PublicKey::from(pk_bytes);
×
351
        let sk = SecretKey::from(sk_bytes);
×
352
        assert!(
×
353
            pk == sk.public_key(),
×
354
            "The loaded public key does not correspond to the loaded secret key"
355
        );
UNCOV
356
        pk
×
357
    });
358

359
    let pk = pk_from_arg.or(pk_from_file).unwrap();
×
360

361
    println!("{}", hex::encode(pk).to_uppercase());
×
362

363
    // FIXME: use ExitCode::SUCCESS when stabilized
364
    // https://doc.rust-lang.org/std/process/struct.ExitCode.html
365
    std::process::exit(0)
×
366
}
367

368
fn run_config(matches: &ArgMatches) -> NodeConfig {
×
369
    let config_path = matches.get_one::<String>("cfg-file").unwrap();
×
370

371
    parse_config(config_path)
×
372
}
373

374
fn run_args(matches: &ArgMatches) -> NodeConfig {
1✔
375
    let udp_addr = matches.get_one::<SocketAddr>("udp-address").copied();
1✔
376

377
    let tcp_addrs: Vec<SocketAddr> = matches.get_many("tcp-address").unwrap_or_default().copied().collect();
1✔
378

379
    let tcp_connections_limit = matches
2✔
380
        .get_one::<usize>("tcp-connections-limit")
381
        .copied()
382
        .unwrap_or(512);
383

384
    let sk = matches.get_one::<String>("secret-key").map(|s| {
2✔
385
        let sk_bytes: [u8; 32] = FromHex::from_hex(s).expect("Invalid DHT secret key");
1✔
386
        SecretKey::from(sk_bytes)
1✔
387
    });
388

389
    let sk_passed_as_arg = matches.contains_id("secret-key");
2✔
390

391
    let keys_file = matches.get_one("keys-file").cloned();
1✔
392

393
    let bootstrap_nodes = matches
2✔
394
        .get_many::<String>("bootstrap-node")
395
        .into_iter()
396
        .flatten()
397
        .tuples()
398
        .map(|(pk, addr)| {
2✔
399
            // get PK bytes of the bootstrap node
400
            let bootstrap_pk_bytes: [u8; 32] = FromHex::from_hex(pk).expect("Invalid node key");
1✔
401
            // create PK from bytes
402
            let bootstrap_pk = PublicKey::from(bootstrap_pk_bytes);
1✔
403

404
            BootstrapNode {
1✔
405
                pk: bootstrap_pk,
1✔
406
                addr: addr.to_string(),
1✔
407
            }
408
        })
409
        .collect();
410

411
    let threads = matches.get_one("threads").copied().unwrap();
2✔
412

413
    let log_type = matches.get_one("log-type").copied().unwrap();
1✔
414

415
    let motd = matches.get_one("motd").cloned().unwrap();
1✔
416

417
    let lan_discovery_enabled = matches.get_flag("lan-discovery");
2✔
418

419
    NodeConfig {
420
        udp_addr,
421
        tcp_addrs,
422
        tcp_connections_limit,
423
        sk,
424
        sk_passed_as_arg,
425
        keys_file,
426
        bootstrap_nodes,
427
        threads,
428
        log_type,
429
        motd,
430
        lan_discovery_enabled,
431
        unused: HashMap::new(),
1✔
432
    }
433
}
434

435
#[cfg(test)]
436
mod tests {
437
    use super::*;
438

439
    #[test]
440
    fn args_udp_only() {
3✔
441
        let saddr = "127.0.0.1:33445";
1✔
442
        let matches = app().get_matches_from(vec!["tox-node", "--keys-file", "./keys", "--udp-address", saddr]);
1✔
443
        let config = run_args(&matches);
1✔
444
        assert_eq!(config.keys_file.unwrap(), "./keys");
2✔
445
        assert_eq!(config.udp_addr.unwrap(), saddr.parse().unwrap());
1✔
446
        assert!(config.tcp_addrs.is_empty());
1✔
447
        assert!(!config.lan_discovery_enabled);
1✔
448
    }
449

450
    #[test]
451
    fn args_tcp_only() {
3✔
452
        let saddr_1 = "127.0.0.1:33445";
2✔
453
        let saddr_2 = "127.0.0.1:33446";
1✔
454
        let matches = app().get_matches_from(vec![
2✔
455
            "tox-node",
456
            "--keys-file",
457
            "./keys",
458
            "--tcp-address",
459
            saddr_1,
460
            "--tcp-address",
461
            saddr_2,
462
        ]);
463
        let config = run_args(&matches);
1✔
464
        assert_eq!(config.keys_file.unwrap(), "./keys");
2✔
465
        assert!(config.udp_addr.is_none());
1✔
466
        assert_eq!(
2✔
467
            config.tcp_addrs,
468
            vec![saddr_1.parse().unwrap(), saddr_2.parse().unwrap()]
1✔
469
        );
470
        assert!(!config.lan_discovery_enabled);
1✔
471
    }
472

473
    #[test]
474
    fn args_udp_tcp() {
3✔
475
        let saddr_1 = "127.0.0.1:33445";
2✔
476
        let saddr_2 = "127.0.0.1:33446";
1✔
477
        let matches = app().get_matches_from(vec![
2✔
478
            "tox-node",
479
            "--keys-file",
480
            "./keys",
481
            "--udp-address",
482
            saddr_1,
483
            "--tcp-address",
484
            saddr_2,
485
        ]);
486
        let config = run_args(&matches);
1✔
487
        assert_eq!(config.keys_file.unwrap(), "./keys");
2✔
488
        assert_eq!(config.udp_addr.unwrap(), saddr_1.parse().unwrap());
1✔
489
        assert_eq!(config.tcp_addrs, vec![saddr_2.parse().unwrap()]);
1✔
490
        assert!(!config.lan_discovery_enabled);
1✔
491
    }
492

493
    #[test]
494
    fn args_udp_tcp_with_secret_key() {
3✔
495
        let saddr_1 = "127.0.0.1:33445";
2✔
496
        let saddr_2 = "127.0.0.1:33446";
1✔
497
        let sk = "d5ff9ceafe9e1145bc807dc94b4ee911a5878705b5f9ee68f6ccc51e498f313c";
1✔
498
        let matches = app().get_matches_from(vec![
2✔
499
            "tox-node",
500
            "--secret-key",
501
            sk,
502
            "--udp-address",
503
            saddr_1,
504
            "--tcp-address",
505
            saddr_2,
506
        ]);
507
        let config = run_args(&matches);
1✔
508
        assert!(config.sk_passed_as_arg);
1✔
509
        assert_eq!(config.udp_addr.unwrap(), saddr_1.parse().unwrap());
2✔
510
        assert_eq!(config.tcp_addrs, vec![saddr_2.parse().unwrap()]);
1✔
511
        assert!(!config.lan_discovery_enabled);
1✔
512
    }
513

514
    #[test]
515
    fn args_udp_or_tcp_required() {
3✔
516
        let matches = app().try_get_matches_from(vec!["tox-node", "--keys-file", "./keys"]);
1✔
517
        assert!(matches.is_err());
2✔
518
    }
519

520
    #[test]
521
    fn args_keys_file_or_secret_key_required() {
3✔
522
        let matches = app().try_get_matches_from(vec!["tox-node", "--udp-address", "127.0.0.1:33445"]);
1✔
523
        assert!(matches.is_err());
2✔
524
    }
525

526
    #[test]
527
    fn args_keys_file_and_secret_key_conflicts() {
3✔
528
        let matches = app().try_get_matches_from(vec![
2✔
529
            "tox-node",
530
            "--keys-file",
531
            "./keys",
532
            "--secret-key",
533
            "d5ff9ceafe9e1145bc807dc94b4ee911a5878705b5f9ee68f6ccc51e498f313c",
534
            "--udp-address",
535
            "127.0.0.1:33445",
536
        ]);
537
        assert!(matches.is_err());
2✔
538
    }
539

540
    #[test]
541
    fn args_motd() {
3✔
542
        let motd = "abcdef";
1✔
543
        let matches = app().get_matches_from(vec![
2✔
544
            "tox-node",
545
            "--keys-file",
546
            "./keys",
547
            "--udp-address",
548
            "127.0.0.1:33445",
549
            "--motd",
550
            motd,
1✔
551
        ]);
552
        let config = run_args(&matches);
1✔
553
        assert_eq!(config.motd, motd);
2✔
554
    }
555

556
    #[test]
557
    fn args_motd_too_long() {
3✔
558
        let motd = "x".repeat(BOOSTRAP_SERVER_MAX_MOTD_LENGTH + 1);
1✔
559
        let matches = app().try_get_matches_from(vec![
3✔
560
            "tox-node",
561
            "--keys-file",
562
            "./keys",
563
            "--udp-address",
564
            "127.0.0.1:33445",
565
            "--motd",
566
            &motd,
1✔
567
        ]);
568
        assert!(matches.is_err());
2✔
569
    }
570

571
    #[test]
572
    fn args_lan_discovery() {
3✔
573
        let matches = app().get_matches_from(vec![
2✔
574
            "tox-node",
575
            "--keys-file",
576
            "./keys",
577
            "--udp-address",
578
            "127.0.0.1:33445",
579
            "--lan-discovery",
580
        ]);
581
        let config = run_args(&matches);
1✔
582
        assert!(config.lan_discovery_enabled);
1✔
583
    }
584

585
    #[test]
586
    fn args_bootstrap_nodes() {
3✔
587
        let pk_1 = "F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67";
2✔
588
        let addr_1 = "node.tox.biribiri.org:33445";
1✔
589
        let pk_2 = "8E7D0B859922EF569298B4D261A8CCB5FEA14FB91ED412A7603A585A25698832";
1✔
590
        let addr_2 = "85.172.30.117:33445";
1✔
591
        let matches = app().get_matches_from(vec![
2✔
592
            "tox-node",
593
            "--keys-file",
594
            "./keys",
595
            "--udp-address",
596
            "127.0.0.1:33445",
597
            "--bootstrap-node",
598
            pk_1,
599
            addr_1,
600
            "--bootstrap-node",
601
            pk_2,
602
            addr_2,
603
        ]);
604
        let config = run_args(&matches);
1✔
605
        let node_1 = BootstrapNode {
606
            pk: {
607
                let pk_bytes = <[u8; 32]>::from_hex(pk_1).unwrap();
608
                PublicKey::from(pk_bytes)
609
            },
610
            addr: addr_1.into(),
1✔
611
        };
612
        let node_2 = BootstrapNode {
613
            pk: {
614
                let pk_bytes = <[u8; 32]>::from_hex(pk_2).unwrap();
615
                PublicKey::from(pk_bytes)
616
            },
617
            addr: addr_2.into(),
1✔
618
        };
619
        assert_eq!(config.bootstrap_nodes, vec![node_1, node_2]);
2✔
620
    }
621

622
    #[test]
623
    fn args_log_type() {
3✔
624
        let matches = app().get_matches_from(vec![
2✔
625
            "tox-node",
626
            "--keys-file",
627
            "./keys",
628
            "--udp-address",
629
            "127.0.0.1:33445",
630
            "--log-type",
631
            "None",
632
        ]);
633
        let config = run_args(&matches);
1✔
634
        assert_eq!(config.log_type, LogType::None);
2✔
635
    }
636

637
    #[test]
638
    fn args_tcp_connections_limit() {
3✔
639
        let matches = app().get_matches_from(vec![
2✔
640
            "tox-node",
641
            "--keys-file",
642
            "./keys",
643
            "--tcp-address",
644
            "127.0.0.1:33445",
645
            "--tcp-connections-limit",
646
            "42",
647
        ]);
648
        let config = run_args(&matches);
1✔
649
        assert_eq!(config.tcp_connections_limit, 42);
1✔
650
    }
651

652
    #[test]
653
    fn args_tcp_connections_limit_requires_tcp_addr() {
3✔
654
        let matches = app().try_get_matches_from(vec![
2✔
655
            "tox-node",
656
            "--keys-file",
657
            "./keys",
658
            "--udp-address",
659
            "127.0.0.1:33445",
660
            "--tcp-connections-limit",
661
            "42",
662
        ]);
663
        assert!(matches.is_err());
2✔
664
    }
665

666
    #[test]
667
    fn args_threads() {
3✔
668
        let matches = app().get_matches_from(vec![
2✔
669
            "tox-node",
670
            "--keys-file",
671
            "./keys",
672
            "--udp-address",
673
            "127.0.0.1:33445",
674
            "--threads",
675
            "42",
676
        ]);
677
        let config = run_args(&matches);
1✔
678
        assert_eq!(config.threads, Threads::N(42));
2✔
679
    }
680

681
    #[test]
682
    fn args_derive_pk_keys_file() {
3✔
683
        let matches = app().get_matches_from(vec!["tox-node", "derive-pk", "--keys-file", "./keys"]);
1✔
684
        let matches = matches.subcommand_matches("derive-pk").unwrap();
2✔
685
        assert_eq!("./keys", matches.get_one::<String>("keys-file").unwrap());
1✔
686
    }
687

688
    #[test]
689
    fn args_derive_pk_secret_key() {
3✔
690
        let sk_str = "d7f04a6db2c12f1eae0229c72e6bc429ca894541acc5f292da0e4d9a47827774";
1✔
691
        let matches = app().get_matches_from(vec!["tox-node", "derive-pk", "--secret-key", sk_str]);
1✔
692
        let matches = matches.subcommand_matches("derive-pk").unwrap();
2✔
693
        assert_eq!(sk_str, matches.get_one::<String>("secret-key").unwrap());
1✔
694
    }
695
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc