Commit 2be18635 authored by MrMan's avatar MrMan

Working E2E tests

parent 1bd64779
Pipeline #50085632 passed with stage
in 7 minutes and 7 seconds
......@@ -76,9 +76,11 @@ If you'd like to contribute to `postmgr`, use the following steps:
3. `make diesel-cli` to install diesel CLI if it's not already installed
4. `make dev-setup` to get set up
5. Make your changes
6. Run the test suite (`make test`) and make sure they pass (the more test you've added, the more likely your MR will succeed)
6. Run the test suite (`make test`, `make test-e2e`) and make sure they pass (the more test you've added, the more likely your MR will succeed)
7. Make a merge request against this repository
For more information on testing, see `docs/testing.md`
[postfix]: http://www.postfix.org/
[do-dont-run-your-own-mailserver]: https://www.digitalocean.com/community/tutorials/why-you-may-not-want-to-run-your-own-mail-server
[mailu]: https://github.com/Mailu/Mailu/
......
# Testing #
## Debugging E2E tests ##
To run the E2E tests without output suppression:
```
$ cargo test -- --ignored --nocapture
```
......@@ -18,25 +18,17 @@ use std::io::{Write, BufRead, BufReader};
use self::rand::{thread_rng, Rng};
use self::rand::distributions::Alphanumeric;
use self::rand::seq::sample_iter;
// use self::new_tokio_smtp::command::Noop;
// use self::mail::{
// Domain,
// smtp::{
// ConnectionConfig,
// ConnectionBuilder,
// },
// };
pub const DOMAIN_NAME: &'static str = "localhost";
pub const POSTMASTER_AT_LOCALHOST: &'static str = "[email protected]";
pub const CR_LF_END: &'static str = "\r\n.\r\n";
pub const AUTH_SUCCESS_MSG: &'static str = "Authentication succeeded";
pub const AUTH_SUCCESS_CODE: &'static str = "235";
pub const SMTP_SUCCESS_PARTIAL_CODE: &'static str = "250-";
pub const SMTP_SUCCESS_FINISH_CODE: &'static str = "250 ";
pub const SMTP_AUTH_LOGIN_CODE: &'static str = "334";
pub const SMTP_B64_USERNAME_PROMPT: &'static str = "VXNlcm5hbWU6";
pub const SMTP_B64_PASSWORD_PROMPT: &'static str = "UGFzc3dvcmQ6";
pub const SMTP_AUTH_CHALLENGE_CODE: &'static str = "334";
// pub const AUTH_SUCCESS_MSG: &'static str = "Authentication succeeded";
// pub const SMTP_B64_USERNAME_PROMPT: &'static str = "VXNlcm5hbWU6";
// pub const SMTP_B64_PASSWORD_PROMPT: &'static str = "UGFzc3dvcmQ6";
// Get available port
// https://elliotekj.com/2017/07/25/find-available-tcp-port-rust/
......@@ -183,8 +175,8 @@ impl Drop for DockerizedPostmgr {
}
}
/// Read an EHLO & verify the response
pub fn read_ehlo(reader: &mut BufReader<TcpStream>) -> &mut BufReader<TcpStream> {
/// Read the server hello
pub fn read_server_hello(reader: &mut BufReader<TcpStream>) -> &mut BufReader<TcpStream> {
let mut line = String::new();
reader.read_line(&mut line).unwrap();
println!("EHLO response: [{}]", line.trim());
......@@ -200,8 +192,9 @@ pub fn send_mail_from(
mut stream: TcpStream,
mut reader: BufReader<TcpStream>
) -> (TcpStream, BufReader<TcpStream>) {
let cmd = format!("MAIL FROM: {}\n", address);
let cmd = format!("MAIL FROM: <{}>\n", address);
stream.write(cmd.as_bytes()).unwrap();
println!("SENT [{}]", cmd);
let mut line = String::new();
reader.read_line(&mut line).unwrap();
......@@ -217,8 +210,9 @@ pub fn send_rcpt_to(
mut stream: TcpStream,
mut reader: BufReader<TcpStream>
) -> (TcpStream, BufReader<TcpStream>) {
let cmd = format!("RCPT TO: {}\n", recipient);
let cmd = format!("RCPT TO: <{}>\n", recipient);
stream.write(cmd.as_bytes()).unwrap();
println!("SENT [{}]", cmd);
let mut line = String::new();
reader.read_line(&mut line).unwrap();
......@@ -283,7 +277,7 @@ pub fn send_ehlo(
}
/// Perform login with a given username and password
pub fn login_with_username_password(
pub fn plain_login_with_username_password(
username: &str,
password: &str,
mut stream: TcpStream,
......@@ -291,57 +285,32 @@ pub fn login_with_username_password(
) -> (TcpStream, BufReader<TcpStream>) {
let mut line = String::new();
// Send AUTH LOGIN
let cmd = format!("AUTH LOGIN\n");
// Send AUTH PLAIN
let cmd = format!("AUTH PLAIN\n");
stream.write(cmd.as_bytes()).unwrap();
// Read response
reader.read_line(&mut line).unwrap();
println!("AUTH LOGIN response: [{}]", line.trim());
println!("AUTH PLAIN response: [{}]", line.trim());
// Postfix sends 334 to start asking for username
assert!(
line.contains(SMTP_AUTH_LOGIN_CODE) && line.contains(SMTP_B64_USERNAME_PROMPT),
"AUTH LOGIN command succeeded"
line.contains(SMTP_AUTH_CHALLENGE_CODE),
"AUTH PLAIN command succeeded"
);
line.clear();
// Send username
let cmd = format!("{}\n", base64::encode(&username));
// Send username and password
let creds = format!("\0{}\0{}", &username, &password);
let cmd = format!("{}\n", base64::encode(&creds));
stream.write(cmd.as_bytes()).unwrap();
reader.read_line(&mut line).unwrap();
println!("response to username: [{}]", line.trim());
println!("response to username & password send: [{}]", line.trim());
assert!(
line.contains(SMTP_AUTH_LOGIN_CODE) && line.contains(SMTP_B64_PASSWORD_PROMPT),
"username (username address) sent successfully"
line.contains(AUTH_SUCCESS_CODE)
"credentials sent successfully"
);
line.clear();
// Send password
let cmd = format!("{}\n", base64::encode(&password));
stream.write(cmd.as_bytes()).unwrap();
// Read response
reader.read_line(&mut line).unwrap();
println!("response to password sent: [{}]", line.trim());
assert!(line.contains(AUTH_SUCCESS_CODE) && line.contains(AUTH_SUCCESS_MSG), "Message successfully queued");
(stream, reader)
}
// /// Create a connection to a post mgr server
// pub fn create_postmgr_conn(postmgr: &DockerizedPostmgr) -> ConnectionConfig<Noop> {
// let domain = Domain::from_unchecked(String::from(postmgr.domain_name));
// ConnectionBuilder::new(
// SocketAddr::from(postmgr.host, postmgr.submission_port),
// domain,
// ).build()
// }
// pub fn create_authenticated_postmgr_conn(
// postmgr: &DockerizedPostmgr,
// username: &str,
// password: &str
// ) -> ConnectionConfig {
// }
......@@ -10,12 +10,12 @@ use common::{
DOMAIN_NAME,
POSTMASTER_AT_LOCALHOST,
read_ehlo,
read_server_hello,
send_ehlo,
send_test_message,
send_rcpt_to,
send_mail_from,
login_with_username_password,
plain_login_with_username_password,
};
#[test]
......@@ -30,7 +30,7 @@ pub fn test_connect() {
let mut reader = BufReader::new(stream.try_clone().unwrap());
// Read the response (connection should send SMTP response)
read_ehlo(&mut reader);
read_server_hello(&mut reader);
}
#[test]
......@@ -40,12 +40,14 @@ pub fn test_email_send() {
// Start postmgr in a docker container
let postmgr = DockerizedPostmgr::new().start();
// Connect to the postmgr over port 25
let stream = TcpStream::connect(postmgr.get_smtp_address()).unwrap();
let mut reader = BufReader::new(stream.try_clone().unwrap());
// Connect to the postmgr over (unprotected) port 25
let (stream, mut reader) = postmgr.connect_tcp().unwrap();
// Ensure EHLO was received
read_ehlo(&mut reader);
read_server_hello(&mut reader);
// Send a client EHLO
let (stream, reader) = send_ehlo(DOMAIN_NAME, stream, reader);
// MAIL FROM
let (stream, reader) = send_mail_from(POSTMASTER_AT_LOCALHOST, stream, reader);
......@@ -57,9 +59,8 @@ pub fn test_email_send() {
#[test]
#[ignore]
///T est user creation & interaction over basic SMTP relay
pub fn test_user_creation() {
/// Test user creation & interaction over basic SMTP relay
pub fn test_user_create_and_login() {
// Start postmgr in a docker container
let postmgr = DockerizedPostmgr::new().start();
......@@ -81,15 +82,15 @@ pub fn test_user_creation() {
let (stream, mut reader) = postmgr.connect_tcp().unwrap();
// Ensure EHLO was received
read_ehlo(&mut reader);
read_server_hello(&mut reader);
// Send a client EHLO
let (stream, reader) = send_ehlo(DOMAIN_NAME, stream, reader);
// Login with username/pw
// Login with username/pw for the new user
let user = fixtures::test_user();
login_with_username_password(
&user.username,
plain_login_with_username_password(
&format!("{}@{}", &user.username, &user.domain),
&user.password,
stream,
reader,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment