erpc_scanner/
work.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//! Items to store metadata for/of circuit creation
//!
//! In the context of ```Scanner```,
//!
//! [IncompleteWork] is the information about
//! the guard relay and the exit relay of the two hop circuit to verify
//! if those relays are **partitioned** or **not partitioned**
//!
//! [CompletedWork] is the end result of using the [IncompleteWork] to
//! perform the circuit creation attempt

/// The metadata about the two hop circuit we want to create.
///
/// It represents the two hop circuit that needs to be created where ```source_relay```
/// represents the guard relay of the two hop and ```destination_relay``` represents
/// the exit relay of the two hop circuit
#[derive(Debug, Clone)]
pub struct IncompleteWork {
    /// Metadata to identify the source relay
    pub source_relay: String,

    /// Metadata to identify the destination relay
    pub destination_relay: String,
}

impl IncompleteWork {
    /// Create ```IncompleteWork``` from a ```source_relay``` and ```destination_relay``` that
    /// can be converted to String
    pub fn from<T: ToString>(source_relay: T, destination_relay: T) -> Self {
        Self {
            source_relay: source_relay.to_string(),
            destination_relay: destination_relay.to_string(),
        }
    }
    /// Check whether the given relay fingerprint is of the source relay of IncompleteWork
    pub fn is_source_relay<T: AsRef<str>>(
        &self,
        relay_fingerprint: T,
    ) -> bool {
        relay_fingerprint.as_ref() == self.source_relay
    }

    /// Check whether the given relay fingerprint is of the destination relay of IncompleteWork
    pub fn is_destination_relay<T: AsRef<str>>(
        &self,
        relay_fingerprint: T,
    ) -> bool {
        relay_fingerprint.as_ref() == self.destination_relay
    }
}

/// The end result of two hop circuit creation attempt between
/// a guard relay and an exit relay represented by
/// ```source_relay``` and ```destination_relay``` respectively
#[derive(Debug, Clone)]
pub struct CompletedWork {
    /// Fingerprint to identify the source relay
    pub source_relay: String,

    /// Fingerprint to identify the destination relay
    pub destination_relay: String,

    /// Shows how the work was completed, was it a success or failure
    pub status: CompletedWorkStatus,

    /// The Unix epoch at which the test was performed
    pub timestamp: u64,
}

/// The status of completion of [CompletedWork]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CompletedWorkStatus {
    /// The circuit creation attempt successful
    Success,

    /// The circuit creation attempt failed with an error
    Failure(String),
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_incomplete_work_creation() {
        let incomplete_work = IncompleteWork::from("relay1", "relay2");

        assert_eq!(incomplete_work.source_relay, "relay1");
        assert_eq!(incomplete_work.destination_relay, "relay2");
    }

    #[test]
    fn test_incomplete_work_relay_check() {
        let incomplete_work = IncompleteWork::from("relay1", "relay2");

        assert!(incomplete_work.is_source_relay("relay1"));
        assert!(!incomplete_work.is_source_relay("relay2"));

        assert!(incomplete_work.is_destination_relay("relay2"));
        assert!(!incomplete_work.is_destination_relay("relay1"));
    }

    #[test]
    fn test_completed_work_success() {
        let completed_work = CompletedWork {
            source_relay: "relay1".to_string(),
            destination_relay: "relay2".to_string(),
            status: CompletedWorkStatus::Success,
            timestamp: 12345,
        };

        assert_eq!(completed_work.source_relay, "relay1");
        assert_eq!(completed_work.destination_relay, "relay2");
        assert!(matches!(
            completed_work.status,
            CompletedWorkStatus::Success
        ));
        assert_eq!(completed_work.timestamp, 12345);
    }

    #[test]
    fn test_completed_work_failure() {
        let error_message = "Circuit build failed".to_string();
        let completed_work = CompletedWork {
            source_relay: "relay1".to_string(),
            destination_relay: "relay2".to_string(),
            status: CompletedWorkStatus::Failure(error_message.clone()),
            timestamp: 12345,
        };

        assert_eq!(completed_work.source_relay, "relay1");
        assert_eq!(completed_work.destination_relay, "relay2");

        match completed_work.status {
            CompletedWorkStatus::Failure(msg) => {
                assert_eq!(msg, error_message)
            }
            CompletedWorkStatus::Success => panic!("Expected Failure status"),
        }

        assert_eq!(completed_work.timestamp, 12345);
    }

    #[test]
    fn test_work_status_equality() {
        assert_eq!(CompletedWorkStatus::Success, CompletedWorkStatus::Success);

        let failure1 = CompletedWorkStatus::Failure("Error1".to_string());
        let failure2 = CompletedWorkStatus::Failure("Error1".to_string());
        let failure3 = CompletedWorkStatus::Failure("Error2".to_string());

        assert_eq!(failure1, failure2);
        assert_ne!(failure1, failure3);
        assert_ne!(CompletedWorkStatus::Success, failure1);
    }
}