Skip to content

Commit 11259e8

Browse files
committed
test(api): [#142] improved api test coverage
1 parent 07364f4 commit 11259e8

File tree

3 files changed

+491
-56
lines changed

3 files changed

+491
-56
lines changed

src/tracker/auth.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use derive_more::{Display, Error};
44
use log::debug;
55
use rand::distributions::Alphanumeric;
66
use rand::{thread_rng, Rng};
7-
use serde::Serialize;
7+
use serde::{Deserialize, Serialize};
88

99
use crate::protocol::clock::{Current, DurationSinceUnixEpoch, Time, TimeNow};
1010
use crate::protocol::common::AUTH_KEY_LENGTH;
@@ -48,7 +48,7 @@ pub fn verify(auth_key: &Key) -> Result<(), Error> {
4848
}
4949
}
5050

51-
#[derive(Serialize, Debug, Eq, PartialEq, Clone)]
51+
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
5252
pub struct Key {
5353
pub key: String,
5454
pub valid_until: Option<DurationSinceUnixEpoch>,

tests/api/mod.rs

Lines changed: 131 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@ use std::sync::Arc;
55

66
use aquatic_udp_protocol::{AnnounceEvent, NumberOfBytes};
77
use reqwest::Response;
8-
use torrust_tracker::api::resource::auth_key::AuthKey;
9-
use torrust_tracker::api::resource::stats::Stats;
10-
use torrust_tracker::api::resource::torrent::{self, Torrent};
118
use torrust_tracker::config::Configuration;
129
use torrust_tracker::jobs::tracker_api;
1310
use torrust_tracker::protocol::clock::DurationSinceUnixEpoch;
@@ -51,14 +48,21 @@ pub fn tracker_configuration() -> Arc<Configuration> {
5148
#[derive(Clone)]
5249
pub struct ConnectionInfo {
5350
pub bind_address: String,
54-
pub api_token: String,
51+
pub api_token: Option<String>,
5552
}
5653

5754
impl ConnectionInfo {
58-
pub fn new(bind_address: &str, api_token: &str) -> Self {
55+
pub fn authenticated(bind_address: &str, api_token: &str) -> Self {
5956
Self {
6057
bind_address: bind_address.to_string(),
61-
api_token: api_token.to_string(),
58+
api_token: Some(api_token.to_string()),
59+
}
60+
}
61+
62+
pub fn anonymous(bind_address: &str) -> Self {
63+
Self {
64+
bind_address: bind_address.to_string(),
65+
api_token: None,
6266
}
6367
}
6468
}
@@ -73,7 +77,7 @@ pub async fn start_custom_api_server(configuration: Arc<Configuration>) -> Serve
7377
}
7478

7579
async fn start(configuration: Arc<Configuration>) -> Server {
76-
let connection_info = ConnectionInfo::new(
80+
let connection_info = ConnectionInfo::authenticated(
7781
&configuration.http_api.bind_address.clone(),
7882
&configuration.http_api.access_tokens.get_key_value("admin").unwrap().1.clone(),
7983
);
@@ -117,6 +121,10 @@ impl Server {
117121
self.connection_info.clone()
118122
}
119123

124+
pub fn get_bind_address(&self) -> String {
125+
self.connection_info.bind_address.clone()
126+
}
127+
120128
/// Add a torrent to the tracker
121129
pub async fn add_torrent(&self, info_hash: &InfoHash, peer: &Peer) {
122130
self.tracker.update_torrent_with_peer_and_get_stats(info_hash, peer).await;
@@ -127,53 +135,149 @@ pub struct Client {
127135
connection_info: ConnectionInfo,
128136
}
129137

138+
type ReqwestQuery = Vec<ReqwestQueryParam>;
139+
type ReqwestQueryParam = (String, String);
140+
141+
#[derive(Default, Debug)]
142+
pub struct Query {
143+
params: Vec<QueryParam>,
144+
}
145+
146+
impl Query {
147+
pub fn empty() -> Self {
148+
Self { params: vec![] }
149+
}
150+
151+
pub fn params(params: Vec<QueryParam>) -> Self {
152+
Self { params }
153+
}
154+
155+
pub fn add_param(&mut self, param: QueryParam) {
156+
self.params.push(param);
157+
}
158+
159+
fn with_token(token: &str) -> Self {
160+
Self {
161+
params: vec![QueryParam::new("token", token)],
162+
}
163+
}
164+
}
165+
166+
impl From<Query> for ReqwestQuery {
167+
fn from(url_search_params: Query) -> Self {
168+
url_search_params
169+
.params
170+
.iter()
171+
.map(|param| ReqwestQueryParam::from((*param).clone()))
172+
.collect()
173+
}
174+
}
175+
176+
#[derive(Clone, Debug)]
177+
pub struct QueryParam {
178+
name: String,
179+
value: String,
180+
}
181+
182+
impl QueryParam {
183+
pub fn new(name: &str, value: &str) -> Self {
184+
Self {
185+
name: name.to_string(),
186+
value: value.to_string(),
187+
}
188+
}
189+
}
190+
191+
impl From<QueryParam> for ReqwestQueryParam {
192+
fn from(param: QueryParam) -> Self {
193+
(param.name, param.value)
194+
}
195+
}
196+
130197
impl Client {
131198
pub fn new(connection_info: ConnectionInfo) -> Self {
132199
Self { connection_info }
133200
}
134201

135-
pub async fn generate_auth_key(&self, seconds_valid: i32) -> AuthKey {
136-
self.post(&format!("key/{}", &seconds_valid)).await.json().await.unwrap()
202+
pub async fn generate_auth_key(&self, seconds_valid: i32) -> Response {
203+
self.post(&format!("key/{}", &seconds_valid)).await
204+
}
205+
206+
pub async fn delete_auth_key(&self, key: &str) -> Response {
207+
self.delete(&format!("key/{}", &key)).await
208+
}
209+
210+
pub async fn reload_keys(&self) -> Response {
211+
self.get("keys/reload", Query::default()).await
137212
}
138213

139214
pub async fn whitelist_a_torrent(&self, info_hash: &str) -> Response {
140215
self.post(&format!("whitelist/{}", &info_hash)).await
141216
}
142217

143-
pub async fn get_torrent(&self, info_hash: &str) -> Torrent {
144-
self.get(&format!("torrent/{}", &info_hash))
145-
.await
146-
.json::<Torrent>()
147-
.await
148-
.unwrap()
218+
pub async fn remove_torrent_from_whitelist(&self, info_hash: &str) -> Response {
219+
self.delete(&format!("whitelist/{}", &info_hash)).await
149220
}
150221

151-
pub async fn get_torrents(&self) -> Vec<torrent::ListItem> {
152-
self.get("torrents").await.json::<Vec<torrent::ListItem>>().await.unwrap()
222+
pub async fn reload_whitelist(&self) -> Response {
223+
self.get("whitelist/reload", Query::default()).await
153224
}
154225

155-
pub async fn get_tracker_statistics(&self) -> Stats {
156-
self.get("stats").await.json::<Stats>().await.unwrap()
226+
pub async fn get_torrent(&self, info_hash: &str) -> Response {
227+
self.get(&format!("torrent/{}", &info_hash), Query::default()).await
157228
}
158229

159-
async fn get(&self, path: &str) -> Response {
230+
pub async fn get_torrents(&self, params: Query) -> Response {
231+
self.get("torrents", params).await
232+
}
233+
234+
pub async fn get_tracker_statistics(&self) -> Response {
235+
self.get("stats", Query::default()).await
236+
}
237+
238+
async fn get(&self, path: &str, params: Query) -> Response {
239+
let mut query: Query = params;
240+
241+
if let Some(token) = &self.connection_info.api_token {
242+
query.add_param(QueryParam::new("token", token));
243+
};
244+
160245
reqwest::Client::builder()
161246
.build()
162247
.unwrap()
163-
.get(self.url(path))
248+
.get(self.base_url(path))
249+
.query(&ReqwestQuery::from(query))
164250
.send()
165251
.await
166252
.unwrap()
167253
}
168254

169255
async fn post(&self, path: &str) -> Response {
170-
reqwest::Client::new().post(self.url(path).clone()).send().await.unwrap()
256+
reqwest::Client::new()
257+
.post(self.base_url(path).clone())
258+
.query(&ReqwestQuery::from(self.query_with_token()))
259+
.send()
260+
.await
261+
.unwrap()
262+
}
263+
264+
async fn delete(&self, path: &str) -> Response {
265+
reqwest::Client::new()
266+
.delete(self.base_url(path).clone())
267+
.query(&ReqwestQuery::from(self.query_with_token()))
268+
.send()
269+
.await
270+
.unwrap()
171271
}
172272

173-
fn url(&self, path: &str) -> String {
174-
format!(
175-
"http://{}/api/{path}?token={}",
176-
&self.connection_info.bind_address, &self.connection_info.api_token
177-
)
273+
fn base_url(&self, path: &str) -> String {
274+
format!("http://{}/api/{path}", &self.connection_info.bind_address)
275+
}
276+
277+
fn query_with_token(&self) -> Query {
278+
match &self.connection_info.api_token {
279+
Some(token) => Query::with_token(token),
280+
None => Query::default(),
281+
}
178282
}
179283
}

0 commit comments

Comments
 (0)