Add quickcheck tests; actually delete types.rs file

This commit is contained in:
Joakim Frostegård 2020-04-05 04:07:18 +02:00
parent 268235c8e1
commit c26fc942e3
6 changed files with 206 additions and 131 deletions

View file

@ -20,4 +20,8 @@ features = ["small_rng"]
[dependencies.mio]
version = "0.7"
features = ["udp", "os-poll", "os-util"]
features = ["udp", "os-poll", "os-util"]
[dev-dependencies]
quickcheck = "0.9"
quickcheck_macros = "0.9"

View file

@ -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)));
}
}

View file

@ -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);
}
}

View file

@ -29,4 +29,4 @@ fn main(){
tasks::clean_connections(&state);
tasks::clean_torrents(&state);
}
}
}

View file

@ -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<ConnectionKey, Time>;
#[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<PeerMapKey, Peer>;
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<InfoHash, TorrentData>;
#[derive(Clone)]
pub struct State {
pub connections: Arc<ConnectionMap>,
pub torrents: Arc<TorrentMap>,
}
impl State {
pub fn new() -> Self {
Self {
connections: Arc::new(DashMap::new()),
torrents: Arc::new(DashMap::new()),
}
}
}