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

ensc / r-tftpd / 6107939931

07 Sep 2023 08:58AM UTC coverage: 70.376% (+0.3%) from 70.111%
6107939931

push

github

ensc
version 0.3.0

1720 of 2444 relevant lines covered (70.38%)

388.0 hits per line

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

92.24
/src/test.rs
1
mod httpd;
2

3
use std::io::Write;
4
use std::path::Path;
5

6
use super::*;
7

8
fn create_file(p: &std::path::Path, fname: &str, mut sz: usize) -> std::io::Result<()>
10✔
9
{
10
    let mut f = std::fs::File::create(p.join(fname))?;
10✔
11

12
    while sz > 0 {
66✔
13
        let buf = rand::random::<[u8; 4096]>();
56✔
14
        let w_sz = buf.len().min(sz);
56✔
15

16
        f.write_all(&buf[0..w_sz])?;
66✔
17

18
        sz -= w_sz;
56✔
19
    }
20

21
    Ok(())
10✔
22
}
10✔
23

24
fn abort_server(addr: std::net::SocketAddr)
2✔
25
{
26
    let mut l_addr = addr;
2✔
27
    l_addr.set_port(0);
2✔
28

29
    let sock = std::net::UdpSocket::bind(l_addr).unwrap();
2✔
30
    sock.send_to(b"QQ", addr).unwrap();
2✔
31
}
2✔
32

33
#[derive(Debug)]
×
34
enum FileSpec {
35
    Content(&'static str, usize),
×
36
    Link(&'static str, &'static str, &'static str),
×
37

38
    TestPlain(&'static str),
×
39
    TestProxy(&'static str, &'static str, &'static str),
×
40
}
41

42
impl FileSpec {
43
    pub fn create(&self, dir: &Path, host: Option<&str>) -> std::io::Result<()> {
42✔
44
        match (self, host) {
42✔
45
            (Self::Content(name, sz), _)        => create_file(dir, name, *sz),
10✔
46
            (Self::Link(name, dst, proto), Some(host))        =>
18✔
47
                std::os::unix::fs::symlink(format!("http{proto}://{host}/{dst}"), dir.join(name)),
18✔
48
            (Self::Link(_, _, _), _)                => Ok(()),
×
49

50
            (Self::TestPlain(_), _) |
51
            (Self::TestProxy(_, _, _), _)        => Ok(()),
14✔
52
        }
53
    }
42✔
54

55
    pub const fn is_available(&self) -> bool {
216✔
56
        match self {
216✔
57
            Self::Content(_, _) |
58
            Self::TestPlain(_)                => true,
76✔
59
            Self::Link(_, _, _) |
60
            Self::TestProxy(_, _, _)        => cfg!(feature = "proxy"),
140✔
61
        }
62
    }
216✔
63

64
    pub const fn get_file_name(&self) -> &str {
174✔
65
        match self {
174✔
66
            Self::Content(name, _) |
46✔
67
            Self::Link(name, _, _) |
72✔
68
            Self::TestPlain(name) |
16✔
69
            Self::TestProxy(name, _, _)                => name,
174✔
70
        }
71
    }
174✔
72

73
    pub const fn get_reference(&self) -> &str {
174✔
74
        match self {
174✔
75
            Self::Content(name, _) |
46✔
76
            Self::Link(_, name, _) |
72✔
77
            Self::TestPlain(name) |
16✔
78
            Self::TestProxy(_, name, _)                => name,
174✔
79
        }
80
    }
174✔
81
}
82

83
const FILES: &[FileSpec] = &[
84
    FileSpec::Content("input_0",            0),
85
    FileSpec::Content("input_511",        511),
86
    FileSpec::Content("input_512",        512),
87
    FileSpec::Content("input_513",        513),
88
    FileSpec::Content("input_100000",  100000),
89

90
    FileSpec::Link("proxy_0",      "input_0",      ""),
91
    FileSpec::Link("proxy_511",    "input_511",    "+nocache"),
92
    FileSpec::Link("proxy_511_0",  "input_511",    "+nocache"),
93
    FileSpec::Link("proxy_511_1",  "input_511",    ""),
94
    FileSpec::Link("proxy_511_2",  "input_511",    ""),
95
    FileSpec::Link("proxy_511_3",  "input_511",    "+nocache"),
96
    FileSpec::Link("proxy_512",    "input_512",    "+nocompress"),
97
    FileSpec::Link("proxy_513",    "input_513",    "+nocache+nocompress"),
98
    FileSpec::Link("proxy_100000", "input_100000", ""),
99

100
    FileSpec::TestPlain("input_513"),
101
    FileSpec::TestPlain("input_513"),
102

103
    FileSpec::TestProxy("proxy_511",    "input_511",    "+nocache"),
104
    FileSpec::TestProxy("proxy_511",    "input_511",    ""),
105
    FileSpec::TestProxy("proxy_511",    "input_511",    "+nocache"),
106
    FileSpec::TestProxy("proxy_511",    "input_511",    ""),
107
    FileSpec::TestProxy("proxy_511",    "input_511",    ""),
108
];
109

110
async fn run_test(ip: std::net::IpAddr)
4✔
111
{
352✔
112
    use tokio::time::timeout;
113
    use tokio::process::Command;
114
    use tempfile::TempDir;
115
    use std::process::Stdio;
116

117
    let dir = TempDir::new().unwrap();
2✔
118

119
    let script = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
2✔
120
        .join("scripts/run-tftp");
121

122
    let mut http_server = httpd::Server::create(dir.path());
2✔
123

124
    for f in FILES.iter().filter(|f| f.is_available()) {
86✔
125
        f.create(dir.path(), http_server.as_ref().and_then(|s| s.get_host())).unwrap()
84✔
126
    }
127

128
    let env = Environment {
2✔
129
        dir:                        dir.path().into(),
2✔
130
        cache_dir:                std::env::temp_dir(),
2✔
131
        fallback_uri:                None,
2✔
132
        max_block_size:                1500,
133
        max_window_size:        64,
134
        max_connections:        1,
135
        timeout:                Duration::from_secs(3),
2✔
136
        no_rfc2347:                false,
137
        wrq_devnull:                true,
138

139
        #[cfg(feature = "proxy")]
140
        allow_uri:                true,
141
    };
142

143
    let addr = std::net::SocketAddr::new(ip, 0);
2✔
144
    let listen = std::net::UdpSocket::bind(addr).unwrap();
2✔
145
    let addr = listen.local_addr().unwrap();
2✔
146

147
    http_server.as_mut().map(|s| s.wait_for_ready());
4✔
148

149
    let h_server = tokio::task::spawn(timeout(Duration::from_secs(5),
4✔
150
                                              run(env, Either::B(listen.into()))));
4✔
151
    let mut instance = 0;
2✔
152
    let mut do_abort = false;
2✔
153

154
    loop {
14✔
155
        for f in FILES.iter().filter(|f| f.is_available()) {
356✔
156
            debug!("running {f:?} test");
174✔
157

158
            let client = Command::new(&script)
1,740✔
159
                .arg(addr.ip().to_string())
174✔
160
                .arg(addr.port().to_string())
174✔
161
                .arg(f.get_file_name())
174✔
162
                .arg(f.get_reference())
174✔
163
                .arg(instance.to_string())
174✔
164
                .stdin(Stdio::null())
174✔
165
                .current_dir(dir.path())
174✔
166
                .output()
167
                .await
518✔
168
                .expect("run-tftp failed");
174✔
169

170
            if !client.stderr.is_empty() {
174✔
171
                warn!("run-tftp stderr:\n{}", String::from_utf8_lossy(&client.stderr));
×
172
            }
173

174
            if !client.stdout.is_empty() {
174✔
175
                debug!("run-tftp stdout:\n{}", String::from_utf8_lossy(&client.stdout));
×
176
            }
177

178
            match client.status.code() {
174✔
179
                Some(0)                => {},
180
                Some(23)        => {
181
                    println!("run-tftp #{} skipped", instance);
4✔
182
                    break;
183
                },
184
                Some(42)        => {
185
                    do_abort = true;
2✔
186
                    break;
2✔
187
                }
188
                _                => panic!("run-tftpd failed: {:?}", client),
×
189
            }
190
        }
174✔
191

192
        if do_abort {
14✔
193
            abort_server(addr);
2✔
194
            break;
195
        }
196

197
        instance += 1
12✔
198
    }
199

200
    h_server.await
4✔
201
        .expect("tftp server timed out")
202
        .expect("tftp server failed")
203
        .unwrap();
204

205
    #[cfg(feature = "proxy")]
206
    crate::fetcher::Cache::close().await;
4✔
207
}
4✔
208

209
// switching tokio runtime between tests breaks the Cache singleton
210
static TEST_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
211
static LOG_LOCK: std::sync::Mutex<bool> = std::sync::Mutex::new(false);
212

213
pub fn init_logging() {
3✔
214
    let mut log = LOG_LOCK.lock().unwrap();
3✔
215

216
    if !*log {
3✔
217
        tracing_subscriber::fmt()
9✔
218
            .with_env_filter(tracing_subscriber::EnvFilter::from_env("RUST_TEST_LOG"))
3✔
219
            .with_writer(tracing_subscriber::fmt::writer::TestWriter::new())
3✔
220
            .init();
221

222
        *log = true;
3✔
223
    }
224
}
3✔
225

226
#[tokio::test]
177✔
227
async fn test_ipv4() {
2✔
228
    let _g = TEST_LOCK.lock().unwrap();
1✔
229

230
    init_logging();
1✔
231

232
    run_test(std::net::Ipv4Addr::LOCALHOST.into()).await;
176✔
233
}
3✔
234

235
#[tokio::test]
177✔
236
async fn test_ipv6() {
2✔
237
    let _g = TEST_LOCK.lock().unwrap();
1✔
238

239
    init_logging();
1✔
240

241
    run_test(std::net::Ipv6Addr::LOCALHOST.into()).await;
176✔
242
}
3✔
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

© 2026 Coveralls, Inc