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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
use super::logic;
use crate::v0::endpoints::proposals::requests::ProposalsByVoteplanIdAndIndex;
use crate::v0::{context::SharedContext, result::HandlerResult};
use warp::{Rejection, Reply};

pub async fn get_proposal(
    id: i32,
    voting_group: String,
    context: SharedContext,
) -> Result<impl Reply, Rejection> {
    Ok(HandlerResult(
        logic::get_proposal(id, voting_group, context).await,
    ))
}

pub async fn get_all_proposals(
    voting_group: String,
    context: SharedContext,
) -> Result<impl Reply, Rejection> {
    Ok(HandlerResult(
        logic::get_all_proposals(voting_group, context).await,
    ))
}

pub async fn get_proposals_by_voteplan_id_and_index(
    body: ProposalsByVoteplanIdAndIndex,
    context: SharedContext,
) -> Result<impl Reply, Rejection> {
    Ok(HandlerResult(
        logic::get_proposals_by_voteplan_id_and_index(body, context).await,
    ))
}

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

    use crate::v0::endpoints::proposals::requests::ProposalVoteplanIdAndIndexes;
    use crate::{
        db::models::proposals::FullProposalInfo,
        v0::context::test::new_test_shared_context_from_url,
    };
    use pretty_assertions::assert_eq;
    use vit_servicing_station_tests::common::data::ArbitrarySnapshotGenerator;
    use vit_servicing_station_tests::common::startup::db::DbBuilder;
    use warp::Filter;

    #[tokio::test]
    async fn get_proposal_by_id_handler() {
        // build context
        let mut gen = ArbitrarySnapshotGenerator::default();

        let snapshot = gen.snapshot();

        let db_url = DbBuilder::new()
            .with_snapshot(&snapshot)
            .build_async()
            .await
            .unwrap();
        let shared_context = new_test_shared_context_from_url(&db_url);
        let filter_context = shared_context.clone();
        let with_context = warp::any().map(move || filter_context.clone());

        let proposal = snapshot.proposals().into_iter().next().unwrap();

        // build filter
        let filter = warp::path!(i32 / String)
            .and(warp::get())
            .and(with_context)
            .and_then(get_proposal);

        let result = warp::test::request()
            .method("GET")
            .path(&format!(
                "/{}/{}",
                proposal.proposal.proposal_id, proposal.group_id
            ))
            .reply(&filter)
            .await;
        assert_eq!(result.status(), warp::http::StatusCode::OK);
        println!("{}", String::from_utf8(result.body().to_vec()).unwrap());
        let result_proposal: FullProposalInfo =
            serde_json::from_str(&String::from_utf8(result.body().to_vec()).unwrap()).unwrap();
        assert_eq!(
            serde_json::to_value(&proposal).unwrap(),
            serde_json::to_value(result_proposal).unwrap()
        );
    }

    #[tokio::test]
    async fn get_all_proposals_handler() {
        // build context
        let mut gen = ArbitrarySnapshotGenerator::default();

        let snapshot = gen.snapshot();

        let db_url = DbBuilder::new()
            .with_snapshot(&snapshot)
            .build_async()
            .await
            .unwrap();
        let shared_context = new_test_shared_context_from_url(&db_url);
        let filter_context = shared_context.clone();
        let with_context = warp::any().map(move || filter_context.clone());

        let proposals = snapshot.proposals();
        let first_proposal = proposals.into_iter().next().unwrap();
        let proposals: Vec<_> = snapshot
            .proposals()
            .into_iter()
            .filter(|p| p.group_id == first_proposal.group_id)
            .collect();

        // build filter
        let filter = warp::any()
            .and(warp::path!(String))
            .and(warp::get())
            .and(with_context)
            .and_then(get_all_proposals);

        let result = warp::test::request()
            .method("GET")
            .path(&format!("/{}", first_proposal.group_id))
            .reply(&filter)
            .await;
        assert_eq!(result.status(), warp::http::StatusCode::OK);
        let result_proposals: Vec<FullProposalInfo> =
            serde_json::from_str(&String::from_utf8(result.body().to_vec()).unwrap()).unwrap();
        assert_eq!(
            serde_json::to_value(proposals).unwrap(),
            serde_json::to_value(result_proposals).unwrap()
        );
    }

    #[tokio::test]
    async fn get_proposal_by_voteplan_id_and_index() {
        // build context
        let mut gen = ArbitrarySnapshotGenerator::default();

        let snapshot = gen.snapshot();

        let db_url = DbBuilder::new()
            .with_snapshot(&snapshot)
            .build_async()
            .await
            .unwrap();
        let shared_context = new_test_shared_context_from_url(&db_url);

        let filter_context = shared_context.clone();
        let with_context = warp::any().map(move || filter_context.clone());

        let proposal = snapshot.proposals().into_iter().next().unwrap();

        // build filter
        let filter = warp::any()
            .and(warp::post())
            .and(warp::body::json())
            .and(with_context)
            .and_then(get_proposals_by_voteplan_id_and_index);

        let request = ProposalVoteplanIdAndIndexes {
            vote_plan_id: proposal.voteplan.chain_voteplan_id.clone(),
            indexes: vec![proposal.voteplan.chain_proposal_index],
        };

        let result = warp::test::request()
            .method("POST")
            .json(&vec![request])
            .reply(&filter)
            .await;

        assert_eq!(result.status(), warp::http::StatusCode::OK);
        let result_proposals: Vec<FullProposalInfo> =
            serde_json::from_str(&String::from_utf8(result.body().to_vec()).unwrap()).unwrap();
        assert_eq!(
            serde_json::to_value(vec![proposal]).unwrap(),
            serde_json::to_value(result_proposals).unwrap()
        );
    }
}