1use crate::errors::XandApiClientError;
2use crate::{
3 models::{Paginated, Paging, TransactionUpdate},
4 Result, TransactionStatusStream, VoteProposal, XandApiClientTrait,
5};
6use futures::{stream, StreamExt};
7use pseudo::Mock;
8use std::time::Duration;
9use xand_address::Address;
10use xand_api_proto::proto_models::{
11 AdministrativeTransaction, Blockstamp, CidrBlock, HealthResponse, PendingCreateRequest,
12 PendingRedeemRequest, Proposal, TotalIssuance, Transaction, TransactionFilter, TransactionId,
13 TransactionStatus, ValidatorEmissionProgress, ValidatorEmissionRate, XandTransaction,
14};
15
16type TxUpdateStream = Result<Vec<Result<TransactionUpdate>>>;
17
18#[derive(Clone)]
19#[allow(clippy::module_name_repetitions)]
20pub struct MockXandApiClient {
21 pub submits: Mock<(Address, XandTransaction), TxUpdateStream>,
23 pub balance: Mock<String, Result<Option<u128>>>,
24 pub pending_create_requests: Mock<(), Result<Paginated<Vec<PendingCreateRequest>>>>,
25 pub pending_redeem_requests: Mock<(), Result<Paginated<Vec<PendingRedeemRequest>>>>,
26 pub transaction_details: Mock<TransactionId, Result<Transaction>>,
27 pub total_issuance: Mock<(), Result<TotalIssuance>>,
28 pub delay: Option<Duration>,
29}
30
31impl MockXandApiClient {
32 #[must_use]
33 pub fn with_delay(self, delay: Duration) -> Self {
34 Self {
35 delay: Some(delay),
36 ..self
37 }
38 }
39
40 async fn pause(&self) {
41 if let Some(d) = self.delay {
42 tokio::time::sleep(d).await;
43 }
44 }
45}
46
47impl Default for MockXandApiClient {
48 fn default() -> Self {
49 MockXandApiClient {
50 submits: Mock::new(Ok(Vec::default())),
51 balance: Mock::new(Ok(Some(0_u128))),
52 pending_create_requests: Mock::new(Ok(Paginated::default())),
53 pending_redeem_requests: Mock::new(Ok(Paginated::default())),
54 transaction_details: Mock::new(Err(XandApiClientError::NotFound { message: "Mock XandApiClient has not been configured to return information about this transaction.".to_string() })),
55 total_issuance: Mock::new(Ok(TotalIssuance { total_issued: 0, blockstamp: Blockstamp {
56 block_number: 0,
57 unix_timestamp_ms: 0,
58 is_stale: false
59 } })),
60 delay: None,
61 }
62 }
63}
64
65#[async_trait::async_trait]
66impl XandApiClientTrait for MockXandApiClient {
67 async fn submit_transaction(
68 &self,
69 address: Address,
70 txn: XandTransaction,
71 ) -> Result<TransactionStatusStream> {
72 self.pause().await;
73 let reply = self.submits.call((address, txn));
74 if let Ok(reply) = reply {
75 Ok(TransactionStatusStream {
76 stream: stream::iter(reply).boxed(),
77 })
78 } else {
79 Err(reply.unwrap_err())
80 }
81 }
82
83 async fn get_transaction_details(&self, id: &TransactionId) -> Result<Transaction> {
84 self.pause().await;
85 self.transaction_details.call(id.clone())
86 }
87
88 async fn get_transaction_history(
89 &self,
90 _paging: Option<Paging>,
91 _filter: &TransactionFilter,
92 ) -> Result<Paginated<Vec<Transaction>>> {
93 unimplemented!()
94 }
95
96 async fn get_balance(&self, address: &str) -> Result<Option<u128>> {
97 self.pause().await;
98 self.balance.call(address.to_string())
99 }
100
101 async fn get_total_issuance(&self) -> Result<TotalIssuance> {
102 self.total_issuance.call(())
103 }
104
105 async fn get_address_transactions(
106 &self,
107 _address: &str,
108 _paging: Option<Paging>,
109 ) -> Result<Paginated<Vec<Transaction>>> {
110 unimplemented!()
111 }
112
113 async fn get_current_block(&self) -> Result<Blockstamp> {
114 unimplemented!()
115 }
116
117 async fn get_pending_create_requests(
118 &self,
119 _paging: Option<Paging>,
120 ) -> Result<Paginated<Vec<PendingCreateRequest>>> {
121 self.pause().await;
122 self.pending_create_requests.call(())
123 }
124
125 async fn get_pending_redeem_requests(
126 &self,
127 _paging: Option<Paging>,
128 ) -> Result<Paginated<Vec<PendingRedeemRequest>>> {
129 self.pause().await;
130 self.pending_redeem_requests.call(())
131 }
132
133 async fn propose_action(
134 &self,
135 _issuer: Address,
136 _admin_txn: AdministrativeTransaction,
137 ) -> Result<TransactionStatusStream, XandApiClientError> {
138 unimplemented!()
139 }
140
141 async fn vote_on_proposal(
142 &self,
143 _issuer: Address,
144 _vote_proposal: VoteProposal,
145 ) -> Result<TransactionStatusStream, XandApiClientError> {
146 unimplemented!()
147 }
148
149 async fn get_proposal(&self, _id: u32) -> Result<Proposal, XandApiClientError> {
150 unimplemented!()
151 }
152
153 async fn get_all_proposals(&self) -> Result<Vec<Proposal>, XandApiClientError> {
154 unimplemented!()
155 }
156
157 async fn get_members(&self) -> Result<Vec<Address>, XandApiClientError> {
158 unimplemented!()
159 }
160
161 async fn get_authority_keys(&self) -> Result<Vec<Address>, XandApiClientError> {
162 unimplemented!()
163 }
164
165 async fn get_trustee(&self) -> Result<Address, XandApiClientError> {
166 unimplemented!()
167 }
168
169 async fn get_allowlist(&self) -> Result<Vec<(Address, CidrBlock)>, XandApiClientError> {
170 unimplemented!()
171 }
172
173 async fn get_limited_agent(&self) -> Result<Option<Address>, XandApiClientError> {
174 unimplemented!()
175 }
176
177 async fn get_validator_emission_rate(&self) -> Result<ValidatorEmissionRate> {
178 unimplemented!()
179 }
180
181 async fn get_validator_emission_progress(
182 &self,
183 _address: Address,
184 ) -> Result<ValidatorEmissionProgress> {
185 unimplemented!()
186 }
187
188 async fn get_pending_create_request_expire_time(&self) -> Result<u64> {
189 unimplemented!()
190 }
191
192 async fn check_health(&self) -> Result<HealthResponse> {
193 unimplemented!()
194 }
195}
196
197#[must_use]
198pub fn committed_status() -> TransactionUpdate {
199 TransactionUpdate {
200 status: TransactionStatus::Committed,
201 id: xand_api_proto::proto_models::TransactionId::default(),
202 }
203}
204
205#[must_use]
206pub fn finalized_status() -> TransactionUpdate {
207 TransactionUpdate {
208 status: TransactionStatus::Finalized,
209 id: xand_api_proto::proto_models::TransactionId::default(),
210 }
211}