From c26fc942e3b832094b0aff6265b2f172aa42a120 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Frosteg=C3=A5rd?= Date: Sun, 5 Apr 2020 04:07:18 +0200 Subject: [PATCH] Add quickcheck tests; actually delete types.rs file --- Cargo.lock | 112 +++++++++++++++++++++++++++++++++++ aquatic/Cargo.toml | 6 +- aquatic/src/common.rs | 25 ++++++++ aquatic/src/handler.rs | 63 ++++++++++++++++++++ aquatic/src/main.rs | 2 +- aquatic/src/types.rs | 129 ----------------------------------------- 6 files changed, 206 insertions(+), 131 deletions(-) delete mode 100644 aquatic/src/types.rs diff --git a/Cargo.lock b/Cargo.lock index 94f3b2a..55fb5fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9,6 +9,15 @@ dependencies = [ "const-random", ] +[[package]] +name = "aho-corasick" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" +dependencies = [ + "memchr", +] + [[package]] name = "aquatic" version = "0.1.0" @@ -18,6 +27,8 @@ dependencies = [ "indexmap", "mio", "net2", + "quickcheck", + "quickcheck_macros", "rand", ] @@ -77,6 +88,16 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "log", + "regex", +] + [[package]] name = "getrandom" version = "0.1.14" @@ -127,6 +148,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "memchr" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" + [[package]] name = "mio" version = "0.7.0" @@ -193,6 +220,47 @@ version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63" +[[package]] +name = "proc-macro2" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quickcheck" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44883e74aa97ad63db83c4bf8ca490f02b2fc02f92575e720c8551e843c945f" +dependencies = [ + "env_logger", + "log", + "rand", + "rand_core", +] + +[[package]] +name = "quickcheck_macros" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608c156fd8e97febc07dc9c2e2c80bf74cfc6ef26893eae3daf8bc2bc94a4b7f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "quote" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" +dependencies = [ + "proc-macro2", +] + [[package]] name = "rand" version = "0.7.3" @@ -250,6 +318,24 @@ version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +[[package]] +name = "regex" +version = "1.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", + "thread_local", +] + +[[package]] +name = "regex-syntax" +version = "0.6.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" + [[package]] name = "socket2" version = "0.3.12" @@ -262,6 +348,32 @@ dependencies = [ "winapi", ] +[[package]] +name = "syn" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "thread_local" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" diff --git a/aquatic/Cargo.toml b/aquatic/Cargo.toml index cf5a09d..5964c37 100644 --- a/aquatic/Cargo.toml +++ b/aquatic/Cargo.toml @@ -20,4 +20,8 @@ features = ["small_rng"] [dependencies.mio] version = "0.7" -features = ["udp", "os-poll", "os-util"] \ No newline at end of file +features = ["udp", "os-poll", "os-util"] + +[dev-dependencies] +quickcheck = "0.9" +quickcheck_macros = "0.9" \ No newline at end of file diff --git a/aquatic/src/common.rs b/aquatic/src/common.rs index 9d281ac..6be43e5 100644 --- a/aquatic/src/common.rs +++ b/aquatic/src/common.rs @@ -130,4 +130,29 @@ impl State { torrents: Arc::new(DashMap::new()), } } +} + + +#[cfg(test)] +mod tests { + #[test] + fn test_peer_status_from_event_and_bytes_left(){ + use crate::common::*; + + use PeerStatus::*; + + let f = PeerStatus::from_event_and_bytes_left; + + assert_eq!(Stopped, f(AnnounceEvent::Stopped, NumberOfBytes(0))); + assert_eq!(Stopped, f(AnnounceEvent::Stopped, NumberOfBytes(1))); + + assert_eq!(Seeding, f(AnnounceEvent::Started, NumberOfBytes(0))); + assert_eq!(Leeching, f(AnnounceEvent::Started, NumberOfBytes(1))); + + assert_eq!(Seeding, f(AnnounceEvent::Completed, NumberOfBytes(0))); + assert_eq!(Leeching, f(AnnounceEvent::Completed, NumberOfBytes(1))); + + assert_eq!(Seeding, f(AnnounceEvent::None, NumberOfBytes(0))); + assert_eq!(Leeching, f(AnnounceEvent::None, NumberOfBytes(1))); + } } \ No newline at end of file diff --git a/aquatic/src/handler.rs b/aquatic/src/handler.rs index 286347f..b9cc7d6 100644 --- a/aquatic/src/handler.rs +++ b/aquatic/src/handler.rs @@ -181,4 +181,67 @@ pub fn create_torrent_scrape_statistics( completed: NumberOfDownloads(0), // No implementation planned leechers: NumberOfPeers(leechers) } +} + + +#[cfg(test)] +mod tests { + use std::time::Instant; + use std::net::IpAddr; + + use indexmap::IndexMap; + use quickcheck::{TestResult, quickcheck}; + + use super::*; + + fn gen_peer_map_key_and_value(i: u8) -> (PeerMapKey, Peer) { + let ip_address: IpAddr = "127.0.0.1".parse().unwrap(); + let peer_id = PeerId([i; 20]); + + let key = PeerMapKey { + ip: ip_address, + peer_id, + }; + let value = Peer { + connection_id: ConnectionId(0), + ip_address, + id: peer_id, + port: Port(1), + status: PeerStatus::Leeching, + last_announce: Time(Instant::now()), + }; + + (key, value) + } + + #[test] + fn test_extract_response_peers(){ + fn prop(data: (u8, u8)) -> TestResult { + let gen_num_peers = data.0; + let req_num_peers = data.1 as usize; + + let mut peer_map: PeerMap = IndexMap::new(); + + for i in 0..gen_num_peers { + let (key, value) = gen_peer_map_key_and_value(i); + + peer_map.insert(key, value); + } + + let num_returned = extract_response_peers( + &peer_map, + req_num_peers + ).len(); + + let mut success = num_returned <= req_num_peers; + + if req_num_peers >= gen_num_peers as usize { + success &= num_returned == gen_num_peers as usize; + } + + TestResult::from_bool(success) + } + + quickcheck(prop as fn((u8, u8)) -> TestResult); + } } \ No newline at end of file diff --git a/aquatic/src/main.rs b/aquatic/src/main.rs index d7915d6..5cd949a 100644 --- a/aquatic/src/main.rs +++ b/aquatic/src/main.rs @@ -29,4 +29,4 @@ fn main(){ tasks::clean_connections(&state); tasks::clean_torrents(&state); } -} \ No newline at end of file +} diff --git a/aquatic/src/types.rs b/aquatic/src/types.rs deleted file mode 100644 index 14a1f6a..0000000 --- a/aquatic/src/types.rs +++ /dev/null @@ -1,129 +0,0 @@ -use std::sync::Arc; -use std::sync::atomic::AtomicUsize; -use std::net::{SocketAddr, IpAddr}; -use std::time::Instant; - -use dashmap::DashMap; -use indexmap::IndexMap; - -pub use bittorrent_udp::types::*; - - -#[derive(Debug, Clone, Copy)] -pub struct Time(pub Instant); - - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ConnectionKey { - pub connection_id: ConnectionId, - pub socket_addr: SocketAddr -} - -pub type ConnectionMap = DashMap; - - -#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] -pub enum PeerStatus { - Seeding, - Leeching, - Stopped -} - -impl PeerStatus { - /// Determine peer status from announce event and number of bytes left. - /// - /// Likely, the last branch will be taken most of the time. - pub fn from_event_and_bytes_left( - event: AnnounceEvent, - bytes_left: NumberOfBytes - ) -> Self { - if event == AnnounceEvent::Stopped { - Self::Stopped - } else if bytes_left.0 == 0 { - Self::Seeding - } else { - Self::Leeching - } - } -} - -#[derive(Clone, Debug)] -pub struct Peer { - pub id: PeerId, - pub connection_id: ConnectionId, - pub ip_address: IpAddr, - pub port: Port, - pub status: PeerStatus, - pub last_announce: Time -} - - -impl Peer { - pub fn to_response_peer(&self) -> ResponsePeer { - ResponsePeer { - ip_address: self.ip_address, - port: self.port - } - } - pub fn from_announce_and_ip( - announce_request: &AnnounceRequest, - ip_address: IpAddr - ) -> Self { - Self { - id: announce_request.peer_id, - connection_id: announce_request.connection_id, - ip_address, - port: announce_request.port, - status: PeerStatus::from_event_and_bytes_left( - announce_request.event, - announce_request.bytes_left - ), - last_announce: Time(Instant::now()) - } - } -} - -#[derive(PartialEq, Eq, Hash, Clone)] -pub struct PeerMapKey { - pub ip: IpAddr, - pub peer_id: PeerId -} - - -pub type PeerMap = IndexMap; - -pub struct TorrentData { - pub peers: PeerMap, - pub num_seeders: AtomicUsize, - pub num_leechers: AtomicUsize, -} - - -impl Default for TorrentData { - fn default() -> Self { - Self { - peers: IndexMap::new(), - num_seeders: AtomicUsize::new(0), - num_leechers: AtomicUsize::new(0), - } - } -} - - -pub type TorrentMap = DashMap; - - -#[derive(Clone)] -pub struct State { - pub connections: Arc, - pub torrents: Arc, -} - -impl State { - pub fn new() -> Self { - Self { - connections: Arc::new(DashMap::new()), - torrents: Arc::new(DashMap::new()), - } - } -} \ No newline at end of file