Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Travis integration testing #102

Merged
merged 14 commits into from
Nov 23, 2018
56 changes: 38 additions & 18 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,30 +1,50 @@
sudo: required
language: rust
# Dependencies of kcov, used by coverage
sudo: required
dist: trusty
addons:
apt:
packages:
- libssl-dev

os:
- linux
- osx
apt:
packages:
- libssl-dev

cache: cargo
rust:
- stable
- beta
- nightly

- stable
- beta
- nightly
os:
- linux
- osx
matrix:
allow_failures:
- rust: nightly

services:
- docker
before_install:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
docker pull greenmail/standalone:1.5.8 &&
docker run -d -e GREENMAIL_OPTS='-Dgreenmail.setup.test.all -Dgreenmail.hostname=0.0.0.0 -Dgreenmail.auth.disabled -Dgreenmail.verbose' -p 3025:3025 -p 3110:3110 -p 3143:3143 -p 3465:3465 -p 3993:3993 -p 3995:3995 greenmail/standalone:1.5.8;
fi
script:
- cargo clean
- cargo check --all-targets
- cargo test
- cargo test --doc
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
cargo test --tests;
else
cargo test --lib;
fi

before_cache: |
if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_RUST_VERSION" == nightly ]]; then
RUSTFLAGS="--cfg procmacro2_semver_exempt" cargo install cargo-tarpaulin
fi

after_failure:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker logs (docker ps -q); fi

after_success:
- if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_RUST_VERSION" == "stable" ]]; then
bash <(curl https://raw.githubusercontent.com/xd009642/tarpaulin/master/travis-install.sh);
cargo tarpaulin --ciserver travis-ci --coveralls $TRAVIS_JOB_ID;
after_success: |
if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_RUST_VERSION" == nightly ]]; then
cargo tarpaulin --out Xml;
bash <(curl -s https://codecov.io/bash);
fi
8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,11 @@ bufstream = "0.1"
imap-proto = "0.6"
nom = "4.0"
base64 = "0.10"

[dev-dependencies]
lettre = "0.9"
lettre_email = "0.9"

[patch.crates-io]
lettre = { git = "https://github.com/lettre/lettre.git" }
lettre_email = { git = "https://github.com/lettre/lettre.git" }
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,17 @@ fn fetch_inbox_top() -> imap::error::Result<Option<String>> {
}
```

## Running the test suite

To run the integration tests, you need to have [GreenMail
running](http://www.icegreen.com/greenmail/#deploy_docker_standalone). The
easiest way to do that is with Docker:

```console
$ docker pull greenmail/standalone:1.5.8
$ docker run -t -i -e GREENMAIL_OPTS='-Dgreenmail.setup.test.all -Dgreenmail.hostname=0.0.0.0 -Dgreenmail.auth.disabled -Dgreenmail.verbose' -p 3025:3025 -p 3110:3110 -p 3143:3143 -p 3465:3465 -p 3993:3993 -p 3995:3995 greenmail/standalone:1.5.8
```

## License

Licensed under either of
Expand Down
11 changes: 11 additions & 0 deletions README.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@

{{readme}}

## Running the test suite

To run the integration tests, you need to have [GreenMail
running](http://www.icegreen.com/greenmail/#deploy_docker_standalone). The
easiest way to do that is with Docker:

```console
$ docker pull greenmail/standalone:1.5.8
$ docker run -t -i -e GREENMAIL_OPTS='-Dgreenmail.setup.test.all -Dgreenmail.hostname=0.0.0.0 -Dgreenmail.auth.disabled -Dgreenmail.verbose' -p 3025:3025 -p 3110:3110 -p 3143:3143 -p 3465:3465 -p 3993:3993 -p 3995:3995 greenmail/standalone:1.5.8
```

## License

Licensed under either of
Expand Down
5 changes: 4 additions & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,7 @@ build: false

test_script:
- cargo check --all-targets
- cargo test
- cargo test --lib
- cargo test --doc
- cargo test --examples
# note that we are not running integration tests!
216 changes: 216 additions & 0 deletions tests/imap_integration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
extern crate imap;
extern crate lettre;
extern crate lettre_email;
extern crate native_tls;

use lettre::Transport;
use std::net::TcpStream;

fn tls() -> native_tls::TlsConnector {
native_tls::TlsConnector::builder()
.danger_accept_invalid_certs(true)
.build()
.unwrap()
}

fn session(user: &str) -> imap::Session<native_tls::TlsStream<TcpStream>> {
let mut s = imap::connect("127.0.0.1:3993", "imap.example.com", &tls())
.unwrap()
.login(user, user)
.unwrap();
s.debug = true;
s
}

fn smtp(user: &str) -> lettre::SmtpTransport {
let creds = lettre::smtp::authentication::Credentials::new(user.to_string(), user.to_string());
lettre::SmtpClient::new(
"127.0.0.1:3465",
lettre::ClientSecurity::Wrapper(lettre::ClientTlsParameters {
connector: tls(),
domain: "smpt.example.com".to_string(),
}),
)
.unwrap()
.credentials(creds)
.transport()
}

#[test]
fn connect_insecure() {
imap::connect_insecure("127.0.0.1:3143").unwrap();
}

#[test]
#[ignore]
fn connect_insecure_then_secure() {
// ignored because of https://github.com/greenmail-mail-test/greenmail/issues/135
imap::connect_insecure("127.0.0.1:3143")
.unwrap()
.secure("imap.example.com", &tls())
.unwrap();
}

#[test]
fn connect_secure() {
imap::connect("127.0.0.1:3993", "imap.example.com", &tls()).unwrap();
}

#[test]
fn login() {
session("readonly-test@localhost");
}

#[test]
fn logout() {
let mut s = session("readonly-test@localhost");
s.logout().unwrap();
}

#[test]
#[ignore]
fn inbox_zero() {
// https://github.com/djc/tokio-imap/issues/34
let mut s = session("readonly-test@localhost");
s.select("INBOX").unwrap();
let inbox = s.search("ALL").unwrap();
assert_eq!(inbox.len(), 0);
}

#[test]
fn inbox() {
let to = "inbox@localhost";

// first log in so we'll see the unsolicited e-mails
let mut c = session(to);
c.select("INBOX").unwrap();

// then send the e-mail
let mut s = smtp(to);
let e = lettre_email::Email::builder()
.from("sender@localhost")
.to(to)
.subject("My first e-mail")
.text("Hello world from SMTP")
.build()
.unwrap();
s.send(e.into()).unwrap();

// now we should see the e-mail!
let inbox = c.search("ALL").unwrap();
// and the one message should have the first message sequence number
assert_eq!(inbox.len(), 1);
assert!(inbox.contains(&1));

// we should also get two unsolicited responses: Exists and Recent
c.noop().unwrap();
let mut unsolicited = Vec::new();
while let Ok(m) = c.unsolicited_responses.try_recv() {
unsolicited.push(m);
}
assert_eq!(unsolicited.len(), 2);
assert!(unsolicited
.iter()
.any(|m| m == &imap::types::UnsolicitedResponse::Exists(1)));
assert!(unsolicited
.iter()
.any(|m| m == &imap::types::UnsolicitedResponse::Recent(1)));

// let's see that we can also fetch the e-mail
let fetch = c.fetch("1", "(ALL UID)").unwrap();
assert_eq!(fetch.len(), 1);
let fetch = &fetch[0];
assert_eq!(fetch.message, 1);
assert_ne!(fetch.uid, None);
assert_eq!(fetch.size, Some(138));
let e = fetch.envelope().unwrap();
assert_eq!(e.subject, Some("My first e-mail"));
assert_ne!(e.from, None);
assert_eq!(e.from.as_ref().unwrap().len(), 1);
let from = &e.from.as_ref().unwrap()[0];
assert_eq!(from.mailbox, Some("sender"));
assert_eq!(from.host, Some("localhost"));
assert_ne!(e.to, None);
assert_eq!(e.to.as_ref().unwrap().len(), 1);
let to = &e.to.as_ref().unwrap()[0];
assert_eq!(to.mailbox, Some("inbox"));
assert_eq!(to.host, Some("localhost"));

// and let's delete it to clean up
c.store("1", "+FLAGS (\\Deleted)").unwrap();
c.expunge().unwrap();

// the e-mail should be gone now
// TODO: https://github.com/djc/tokio-imap/issues/34
// let inbox = c.search("ALL").unwrap();
// assert_eq!(inbox.len(), 0);
}

#[test]
fn inbox_uid() {
let to = "inbox-uid@localhost";

// first log in so we'll see the unsolicited e-mails
let mut c = session(to);
c.select("INBOX").unwrap();

// then send the e-mail
let mut s = smtp(to);
let e = lettre_email::Email::builder()
.from("sender@localhost")
.to(to)
.subject("My first e-mail")
.text("Hello world from SMTP")
.build()
.unwrap();
s.send(e.into()).unwrap();

// now we should see the e-mail!
let inbox = c.uid_search("ALL").unwrap();
// and the one message should have the first message sequence number
assert_eq!(inbox.len(), 1);
let uid = inbox.into_iter().next().unwrap();

// we should also get two unsolicited responses: Exists and Recent
c.noop().unwrap();
let mut unsolicited = Vec::new();
while let Ok(m) = c.unsolicited_responses.try_recv() {
unsolicited.push(m);
}
assert_eq!(unsolicited.len(), 2);
assert!(unsolicited
.iter()
.any(|m| m == &imap::types::UnsolicitedResponse::Exists(1)));
assert!(unsolicited
.iter()
.any(|m| m == &imap::types::UnsolicitedResponse::Recent(1)));

// let's see that we can also fetch the e-mail
let fetch = c.uid_fetch(format!("{}", uid), "(ALL UID)").unwrap();
assert_eq!(fetch.len(), 1);
let fetch = &fetch[0];
assert_eq!(fetch.uid, Some(uid));
let e = fetch.envelope().unwrap();
assert_eq!(e.subject, Some("My first e-mail"));

// and let's delete it to clean up
c.uid_store(format!("{}", uid), "+FLAGS (\\Deleted)")
.unwrap();
c.expunge().unwrap();

// the e-mail should be gone now
// TODO: https://github.com/djc/tokio-imap/issues/34
// let inbox = c.search("ALL").unwrap();
// assert_eq!(inbox.len(), 0);
}

#[test]
#[ignore]
fn list() {
let mut s = session("readonly-test@localhost");
s.select("INBOX").unwrap();
let subdirs = s.list(None, Some("%")).unwrap();
assert_eq!(subdirs.len(), 0);

// TODO: make a subdir
}