Skip to content

Commit 20422f0

Browse files
matt2xumattnenterprise
authored andcommitted
Add more tests (#60)
* add docker with configuration of vsftpd to test more easily * update README * porting script from docker to travis * must run vsftpd inside the docker * improved Dockerfile and README * added & fixed tests * trying to make .travis.yml prettier
1 parent 215160b commit 20422f0

File tree

7 files changed

+157
-51
lines changed

7 files changed

+157
-51
lines changed

.travis.yml

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,39 @@
11
language: rust
2+
23
rust:
3-
# check it compiles on the latest stable compiler
4-
- stable
4+
# check it compiles on the latest stable compiler
5+
- stable
6+
57
before_install:
6-
- sudo apt-get update -qq
7-
- sudo apt-get install -yqq bc pure-ftpd
8-
- sudo groupadd ftp
9-
- sudo useradd -s /bin/false -d /home/ftp -m -c "anonymous ftp" -g ftp ftp
10-
- echo "no" | sudo tee /etc/pure-ftpd/conf/NoAnonymous
11-
- echo "yes" | sudo tee /etc/pure-ftpd/conf/AnonymousCanCreateDirs
12-
- sudo /etc/init.d/pure-ftpd restart
13-
- |
14-
pip install 'travis-cargo<0.2' --user &&
8+
|
9+
sudo apt-get update -qq &&
10+
sudo apt-get install -yqq vsftpd &&
11+
sudo useradd -s /bin/bash -d /home/ftp -m -c "Doe ftp user" -g ftp Doe &&
12+
echo "Doe:mumble" | sudo chpasswd &&
13+
echo "listen=yes
14+
anon_root=/home/ftp
15+
local_enable=yes
16+
local_umask=022
17+
pasv_enable=yes
18+
pasv_min_port=65000
19+
pasv_max_port=65010
20+
write_enable=yes
21+
log_ftp_protocol=yes" | sed -e "s/\s\+\(.*\)/\1/" | sudo tee /etc/vsftpd.conf &&
22+
sudo service vsftpd restart &&
23+
pip install "travis-cargo<0.2" --user &&
1524
export PATH=$HOME/.local/bin:$PATH
25+
1626
script:
17-
- |
27+
|
1828
travis-cargo build &&
19-
travis-cargo test &&
29+
travis-cargo test -- --features secure &&
2030
travis-cargo --only stable doc
31+
2132
after_success:
22-
# upload the documentation from the build with stable (automatically only actually
23-
# runs on the master branch, not individual PRs)
24-
- travis-cargo --only stable doc-upload
33+
# upload the documentation from the build with stable (automatically only actually
34+
# runs on the master branch, not individual PRs)
35+
- travis-cargo --only stable doc-upload
36+
2537
env:
2638
global:
2739
secure: E/K+u8fhwLNKDvjG6kiuDumrXY/RMZOMa7SS88qhsPKStdHjNmaCwUFUe76RJDzMCqeN31u2mUwvMfMK3xDShABQjoD/tze/KbV5v6VTeL4vplHwZh6TzwaYKKBtNxL1q47A8FSTNK9PUbT+gEIAEY9Nadho7wKrYfT+CQxcb2A=

README.md

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ FTP client for Rust
88

99
[Documentation](http://mattnenterprise.github.io/rust-ftp)
1010

11-
### Installation
11+
## Installation
1212

1313
Add ftp via your `Cargo.toml`
1414
```toml
@@ -22,7 +22,7 @@ FTPS support is disabled by default. To enable it `secure` should be activated i
2222
ftp = { version = "*", features = ["secure"] }
2323
```
2424

25-
### Usage
25+
## Usage
2626
```rust
2727
extern crate ftp;
2828

@@ -71,3 +71,43 @@ Unless you explicitly state otherwise, any contribution intentionally
7171
submitted for inclusion in the work by you, as defined in the Apache-2.0
7272
license, shall be dual licensed as above, without any additional terms or
7373
conditions.
74+
75+
## Development environment
76+
77+
All you need to develop rust-ftp and run the tests is Rust and Docker.
78+
The `tests` folder contains a `Dockerfile` that installs and configures
79+
the vsftpd server.
80+
81+
To create the Docker image:
82+
83+
```bash
84+
docker build -t ftp-server tests
85+
```
86+
87+
To start the FTP server that is tested against:
88+
89+
```bash
90+
tests/ftp-server.sh
91+
```
92+
93+
This script runs the `ftp-server` image in detached mode and starts the `vsftpd` daemon. It binds ports 21 (FTP) as well as the range 65000-65010 for passive connections.
94+
95+
Once you have an instance running, to run tests type:
96+
97+
```bash
98+
cargo test
99+
```
100+
101+
The following commands can be useful:
102+
```bash
103+
# List running containers of ftp-server image
104+
# (to include stopped containers use -a option)
105+
docker ps --filter ancestor=ftp-server
106+
107+
# To stop and remove a container
108+
docker stop container_name
109+
docker rm container_name
110+
111+
# To remove the image
112+
docker rmi ftp-server
113+
```

src/ftp.rs

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,15 @@ impl FtpStream {
7373
///
7474
/// ## Example
7575
///
76-
/// ```
76+
/// ```rust,no_run
7777
/// use ftp::FtpStream;
78-
/// use openssl::ssl::*;
78+
/// use ftp::openssl::ssl::*;
7979
///
8080
/// // Create an SslContext with a custom cert.
8181
/// let mut ctx = SslContext::new(SslMethod::Sslv23).unwrap();
8282
/// let _ = ctx.set_CA_file("/path/to/a/cert.pem").unwrap();
8383
/// let mut ftp_stream = FtpStream::connect("127.0.0.1:21").unwrap();
84-
/// let mut ftp_stream = ftp_stream.into_secure(ctx).unwrap();
84+
/// let mut ftp_stream = ftp_stream.into_secure(&ctx).unwrap();
8585
/// ```
8686
#[cfg(feature = "secure")]
8787
pub fn into_secure<T: IntoSsl + Clone>(mut self, ssl: T) -> Result<FtpStream> {
@@ -112,14 +112,18 @@ impl FtpStream {
112112
///
113113
/// ## Example
114114
///
115-
/// ```
115+
/// ```rust,no_run
116116
/// use ftp::FtpStream;
117+
/// use ftp::openssl::ssl::*;
118+
///
119+
/// // Create an SslContext with a custom cert.
120+
/// let mut ctx = SslContext::new(SslMethod::Sslv23).unwrap();
121+
/// let _ = ctx.set_CA_file("/path/to/a/cert.pem").unwrap();
117122
/// let mut ftp_stream = FtpStream::connect("127.0.0.1:21").unwrap();
118-
/// // Switch to the secure mode
119-
/// let (mut ftp_stream, _) = ftp_stream.secure();
123+
/// let mut ftp_stream = ftp_stream.into_secure(&ctx).unwrap();
120124
/// // Do all secret things
121125
/// // Switch back to the insecure mode
122-
/// let (mut ftp_stream, _) = ftp_stream.insecure();
126+
/// let mut ftp_stream = ftp_stream.into_insecure().unwrap();
123127
/// // Do all public things
124128
/// let _ = ftp_stream.quit();
125129
/// ```
@@ -306,21 +310,21 @@ impl FtpStream {
306310
/// to download from FTP and `reader` is the function which operates with the
307311
/// data stream opened.
308312
///
309-
/// ```ignore
310-
/// let result = conn.retr("take_this.txt", |stream| {
311-
/// let mut file = File::create("store_here.txt").unwrap();
312-
/// let mut buf = [0; 2048];
313-
///
314-
/// loop {
315-
/// match stream.read(&mut buf) {
316-
/// Ok(0) => break,
317-
/// Ok(n) => file.write_all(&buf[0..n]).unwrap(),
318-
/// Err(err) => return Err(err)
319-
/// };
320-
/// }
321-
///
322-
/// Ok(())
323-
/// });
313+
/// ```
314+
/// # use ftp::{FtpStream, FtpError};
315+
/// # use std::io::Cursor;
316+
/// # let mut conn = FtpStream::connect("127.0.0.1:21").unwrap();
317+
/// # conn.login("Doe", "mumble").and_then(|_| {
318+
/// # let mut reader = Cursor::new("hello, world!".as_bytes());
319+
/// # conn.put("retr.txt", &mut reader)
320+
/// # }).unwrap();
321+
/// assert!(conn.retr("retr.txt", |stream| {
322+
/// let mut buf = Vec::new();
323+
/// stream.read_to_end(&mut buf).map(|_|
324+
/// assert_eq!(buf, "hello, world!".as_bytes())
325+
/// ).map_err(|e| FtpError::ConnectionError(e))
326+
/// }).is_ok());
327+
/// # assert!(conn.rm("retr.txt").is_ok());
324328
/// ```
325329
pub fn retr<F>(&mut self, filename: &str, reader: F) -> Result<()>
326330
where F: Fn(&mut Read) -> Result<()> {
@@ -351,6 +355,20 @@ impl FtpStream {
351355
}
352356

353357
/// Simple way to retr a file from the server. This stores the file in memory.
358+
///
359+
/// ```
360+
/// # use ftp::{FtpStream, FtpError};
361+
/// # use std::io::Cursor;
362+
/// # let mut conn = FtpStream::connect("127.0.0.1:21").unwrap();
363+
/// # conn.login("Doe", "mumble").and_then(|_| {
364+
/// # let mut reader = Cursor::new("hello, world!".as_bytes());
365+
/// # conn.put("simple_retr.txt", &mut reader)
366+
/// # }).unwrap();
367+
/// let cursor = conn.simple_retr("simple_retr.txt").unwrap();
368+
/// // do something with bytes
369+
/// assert_eq!(cursor.into_inner(), "hello, world!".as_bytes());
370+
/// # assert!(conn.rm("simple_retr.txt").is_ok());
371+
/// ```
354372
pub fn simple_retr(&mut self, file_name: &str) -> Result<Cursor<Vec<u8>>> {
355373
let r = try!(self.simple_retr_(file_name));
356374
self.read_response(status::CLOSING_DATA_CONNECTION).map(|_| r)

src/lib.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@
2828
//!
2929
//! ### FTPS Usage
3030
//!
31-
//! ```ignore
31+
//! ```rust,no_run
3232
//! use ftp::FtpStream;
33-
//! use openssl::ssl::*;
33+
//! use ftp::openssl::ssl::*;
3434
//!
35-
//! let mut ftp_stream = FtpStream::connect("127.0.0.1:21").unwrap();
36-
//! let mut ctx = SslContext::new(SslMethod::Sslv23).unwrap();
37-
//! let mut ssl = Ssl::new(&ctx).unwrap();
35+
//! let ftp_stream = FtpStream::connect("127.0.0.1:21").unwrap();
36+
//! let ctx = SslContext::new(SslMethod::Sslv23).unwrap();
37+
//! let ssl = Ssl::new(&ctx).unwrap();
3838
//! // Switch to the secure mode
3939
//! let mut ftp_stream = ftp_stream.into_secure(ssl).unwrap();
4040
//! ftp_stream.login("anonymous", "anonymous").unwrap();
@@ -50,8 +50,9 @@
5050
#[macro_use] extern crate lazy_static;
5151
extern crate regex;
5252
extern crate chrono;
53+
5354
#[cfg(feature = "secure")]
54-
extern crate openssl;
55+
pub extern crate openssl;
5556

5657
mod ftp;
5758
mod data_stream;

tests/Dockerfile

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
FROM i386/ubuntu:latest
2+
3+
RUN apt-get update -qq &&\
4+
apt-get install -yqq vsftpd
5+
6+
RUN mkdir -p /var/run/vsftpd/empty &&\
7+
useradd -s /bin/bash -d /home/ftp -m -c "Doe ftp user" -g ftp Doe &&\
8+
echo "Doe:mumble"| chpasswd &&\
9+
echo "listen=yes\n\
10+
anon_root=/home/ftp\n\
11+
local_enable=yes\n\
12+
local_umask=022\n\
13+
pasv_enable=YES\n\
14+
pasv_min_port=65000\n\
15+
pasv_max_port=65010\n\
16+
write_enable=yes\n\
17+
log_ftp_protocol=yes" > /etc/vsftpd.conf &&\
18+
echo "/etc/init.d/vsftpd start" | tee -a /etc/bash.bashrc
19+
20+
CMD ["/bin/bash"]

tests/ftp-server.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/bin/sh
2+
3+
# run the ftp server instance in detached mode (in the background)
4+
# but also with TTY and interactive mode, so we can attach to it if we want to
5+
docker run -dti --privileged -p 21:21 -p 65000-65010:65000-65010 ftp-server

tests/lib.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,26 @@ use ftp::FtpStream;
88
#[test]
99
fn test_ftp() {
1010
let mut ftp_stream = FtpStream::connect("127.0.0.1:21").unwrap();
11-
let _ = ftp_stream.login("anonymous", "[email protected]").unwrap();
11+
let _ = ftp_stream.login("Doe", "mumble").unwrap();
1212

1313
ftp_stream.mkdir("test_dir").unwrap();
1414
ftp_stream.cwd("test_dir").unwrap();
1515
assert!(ftp_stream.pwd().unwrap().ends_with("/test_dir"));
1616

17-
// Store a file
18-
let file_data = format!("Some awesome file data man!!\n");
19-
let mut reader = Cursor::new(file_data.into_bytes());
17+
// store a file
18+
let file_data = "test data\n";
19+
let mut reader = Cursor::new(file_data.as_bytes());
2020
assert!(ftp_stream.put("test_file.txt", &mut reader).is_ok());
2121

22-
assert!(ftp_stream.quit().is_ok());
22+
// retrieve file
23+
assert!(ftp_stream.simple_retr("test_file.txt").map(|bytes|
24+
assert_eq!(bytes.into_inner(), file_data.as_bytes())).is_ok());
25+
26+
// remove file
27+
assert!(ftp_stream.rm("test_file.txt").is_ok());
28+
29+
// cleanup: go up, remove folder, and quit
30+
assert!(ftp_stream.cdup().and_then(|_|
31+
ftp_stream.rmdir("test_dir")).and_then(|_|
32+
ftp_stream.quit()).is_ok());
2333
}

0 commit comments

Comments
 (0)