Skip to content

Commit

Permalink
test(http): [torrust#159] add tests for public http tracker
Browse files Browse the repository at this point in the history
  • Loading branch information
josecelano committed Jan 20, 2023
1 parent 41ad07f commit 1a558d2
Show file tree
Hide file tree
Showing 15 changed files with 272 additions and 46 deletions.
4 changes: 4 additions & 0 deletions src/http/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
//! Tracker HTTP/HTTPS Protocol:
//!
//! <https://wiki.theory.org/BitTorrentSpecification#Tracker_HTTP.2FHTTPS_Protocol>
//!
pub mod error;
pub mod filters;
pub mod handlers;
Expand Down
7 changes: 3 additions & 4 deletions src/http/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@ use std::collections::HashMap;
use std::io::Write;
use std::net::IpAddr;

use serde;
use serde::Serialize;
use serde::{self, Deserialize, Serialize};

use crate::protocol::info_hash::InfoHash;

#[derive(Serialize)]
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct Peer {
pub peer_id: String,
pub ip: IpAddr,
pub port: u16,
}

#[derive(Serialize)]
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct Announce {
pub interval: u32,
#[serde(rename = "min interval")]
Expand Down
16 changes: 15 additions & 1 deletion tests/api/client.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use reqwest::Response;

use super::connection_info::ConnectionInfo;
use crate::common::http::{get, Query, QueryParam, ReqwestQuery};
use crate::common::http::{Query, QueryParam, ReqwestQuery};

/// API Client
pub struct Client {
Expand Down Expand Up @@ -100,3 +100,17 @@ impl Client {
format!("http://{}{}{path}", &self.connection_info.bind_address, &self.base_path)
}
}

async fn get(path: &str, query: Option<Query>) -> Response {
match query {
Some(params) => reqwest::Client::builder()
.build()
.unwrap()
.get(path)
.query(&ReqwestQuery::from(params))
.send()
.await
.unwrap(),
None => reqwest::Client::builder().build().unwrap().get(path).send().await.unwrap(),
}
}
1 change: 0 additions & 1 deletion tests/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use torrust_tracker::tracker::Tracker;
pub mod asserts;
pub mod client;
pub mod connection_info;
pub mod fixtures;
pub mod server;

/// It forces a database error by dropping all tables.
Expand Down
File renamed without changes.
16 changes: 0 additions & 16 deletions tests/common/http.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,6 @@
use reqwest::Response;

pub type ReqwestQuery = Vec<ReqwestQueryParam>;
pub type ReqwestQueryParam = (String, String);

pub async fn get(path: &str, query: Option<Query>) -> Response {
match query {
Some(params) => reqwest::Client::builder()
.build()
.unwrap()
.get(path)
.query(&ReqwestQuery::from(params))
.send()
.await
.unwrap(),
None => reqwest::Client::builder().build().unwrap().get(path).send().await.unwrap(),
}
}

#[derive(Clone, Debug)]
pub struct ConnectionInfo {
pub bind_address: String,
Expand Down
1 change: 1 addition & 0 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod fixtures;
pub mod http;
8 changes: 8 additions & 0 deletions tests/http/asserts.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
use reqwest::Response;

use super::responses::Announce;

pub async fn assert_internal_server_error(response: Response) {
assert_eq!(response.status(), 200);
/* cspell:disable-next-line */
assert_eq!(response.text().await.unwrap(), "d14:failure reason21:internal server errore");
}

pub async fn assert_announce_response(response: Response, expected_announce_response: &Announce) {
assert_eq!(response.status(), 200);
let announce_response: Announce = serde_bencode::from_str(&response.text().await.unwrap()).unwrap();
assert_eq!(announce_response, *expected_announce_response);
}
29 changes: 14 additions & 15 deletions tests/http/client.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,34 @@
use reqwest::Response;

use super::connection_info::ConnectionInfo;
use crate::common::http::{get, Query};
use super::requests::AnnounceQuery;

/// HTTP Tracker Client
pub struct Client {
connection_info: ConnectionInfo,
base_path: String,
}

impl Client {
pub fn new(connection_info: ConnectionInfo) -> Self {
Self {
connection_info,
base_path: "/".to_string(),
}
Self { connection_info }
}

pub async fn announce(&self, params: Query) -> Response {
self.get("announce", params).await
pub async fn announce(&self, query: &AnnounceQuery) -> Response {
let path_with_query = format!("announce?{query}");
self.get(&path_with_query).await
}

pub async fn scrape(&self, params: Query) -> Response {
self.get("scrape", params).await
}

async fn get(&self, path: &str, params: Query) -> Response {
get(&self.base_url(path), Some(params)).await
pub async fn get(&self, path: &str) -> Response {
reqwest::Client::builder()
.build()
.unwrap()
.get(self.base_url(path))
.send()
.await
.unwrap()
}

fn base_url(&self, path: &str) -> String {
format!("http://{}{}{path}", &self.connection_info.bind_address, &self.base_path)
format!("http://{}/{path}", &self.connection_info.bind_address)
}
}
2 changes: 2 additions & 0 deletions tests/http/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
pub mod asserts;
pub mod client;
pub mod connection_info;
pub mod requests;
pub mod responses;
pub mod server;
104 changes: 104 additions & 0 deletions tests/http/requests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
use std::fmt;
use std::net::IpAddr;

use percent_encoding::NON_ALPHANUMERIC;
use serde_repr::Serialize_repr;

pub struct AnnounceQuery {
pub info_hash: ByteArray20,
pub peer_addr: IpAddr,
pub downloaded: BaseTenASCII,
pub uploaded: BaseTenASCII,
pub peer_id: ByteArray20,
pub port: PortNumber,
pub left: BaseTenASCII,
pub event: Option<Event>,
pub compact: Option<Compact>,
}

impl fmt::Display for AnnounceQuery {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.build())
}
}

/// HTTP Tracker Announce Request:
///
/// <https://wiki.theory.org/BitTorrentSpecification#Tracker_HTTP.2FHTTPS_Protocol>
///
/// Some parameters are not implemented yet.
impl AnnounceQuery {
/// It builds the URL query component for the announce request.
///
/// This custom URL query params encoding is needed because `reqwest` does not allow
/// bytes arrays in query parameters. More info on this issue:
///
/// <https://github.com/seanmonstar/reqwest/issues/1613>
pub fn build(&self) -> String {
let mut params = vec![
(
"info_hash",
percent_encoding::percent_encode(&self.info_hash, NON_ALPHANUMERIC).to_string(),
),
("peer_addr", self.peer_addr.to_string()),
("downloaded", self.downloaded.to_string()),
("uploaded", self.uploaded.to_string()),
(
"peer_id",
percent_encoding::percent_encode(&self.peer_id, NON_ALPHANUMERIC).to_string(),
),
("port", self.port.to_string()),
("left", self.left.to_string()),
];

if let Some(event) = &self.event {
params.push(("event", event.to_string()));
}

if let Some(compact) = &self.compact {
params.push(("compact", compact.to_string()));
}

params
.iter()
.map(|param| format!("{}={}", param.0, param.1))
.collect::<Vec<String>>()
.join("&")
}
}

pub type BaseTenASCII = u64;
pub type ByteArray20 = [u8; 20];
pub type PortNumber = u16;

pub enum Event {
//tarted,
//Stopped,
Completed,
}

impl fmt::Display for Event {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
//Event::Started => write!(f, "started"),
//Event::Stopped => write!(f, "stopped"),
Event::Completed => write!(f, "completed"),
}
}
}

#[derive(Serialize_repr, PartialEq, Debug)]
#[repr(u8)]
pub enum Compact {
//Accepted = 1,
NotAccepted = 0,
}

impl fmt::Display for Compact {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
//Compact::Accepted => write!(f, "1"),
Compact::NotAccepted => write!(f, "0"),
}
}
}
18 changes: 18 additions & 0 deletions tests/http/responses.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use serde::{self, Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct Announce {
pub complete: u32,
pub incomplete: u32,
pub interval: u32,
#[serde(rename = "min interval")]
pub min_interval: u32,
pub peers: Vec<DictionaryPeer>,
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct DictionaryPeer {
pub ip: String,
pub peer_id: String,
pub port: u16,
}
6 changes: 6 additions & 0 deletions tests/http/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use std::sync::Arc;

use torrust_tracker::config::{ephemeral_configuration, Configuration};
use torrust_tracker::jobs::http_tracker;
use torrust_tracker::protocol::info_hash::InfoHash;
use torrust_tracker::tracker::peer::Peer;
use torrust_tracker::tracker::statistics::Keeper;
use torrust_tracker::{ephemeral_instance_keys, logging, static_time, tracker};

Expand Down Expand Up @@ -61,4 +63,8 @@ impl Server {
pub fn get_connection_info(&self) -> ConnectionInfo {
self.connection_info.clone()
}

pub async fn add_torrent(&self, info_hash: &InfoHash, peer: &Peer) {
self.tracker.update_torrent_with_peer_and_get_stats(info_hash, peer).await;
}
}
Loading

0 comments on commit 1a558d2

Please sign in to comment.