1use std::{
7 collections::{BTreeMap, HashMap, VecDeque},
8 sync::{Arc, Mutex, MutexGuard},
9};
10
11use linera_base::{
12 abi::{ContractAbi, ServiceAbi},
13 data_types::{
14 Amount, ApplicationPermissions, BlockHeight, Resources, SendMessageRequest, Timestamp,
15 },
16 ensure, http,
17 identifiers::{Account, AccountOwner, ApplicationId, ChainId, MessageId, ModuleId, StreamName},
18 ownership::{
19 AccountPermissionError, ChainOwnership, ChangeApplicationPermissionsError, CloseChainError,
20 },
21};
22use serde::Serialize;
23
24use crate::{Contract, DataBlobHash, KeyValueStore, ViewStorageContext};
25
26struct ExpectedCreateApplicationCall {
27 module_id: ModuleId,
28 parameters: Vec<u8>,
29 argument: Vec<u8>,
30 required_application_ids: Vec<ApplicationId>,
31 application_id: ApplicationId,
32}
33
34pub struct MockContractRuntime<Application>
36where
37 Application: Contract,
38{
39 application_parameters: Option<Application::Parameters>,
40 application_id: Option<ApplicationId<Application::Abi>>,
41 application_creator_chain_id: Option<ChainId>,
42 chain_id: Option<ChainId>,
43 authenticated_signer: Option<Option<AccountOwner>>,
44 block_height: Option<BlockHeight>,
45 round: Option<u32>,
46 message_id: Option<Option<MessageId>>,
47 message_is_bouncing: Option<Option<bool>>,
48 authenticated_caller_id: Option<Option<ApplicationId>>,
49 timestamp: Option<Timestamp>,
50 chain_balance: Option<Amount>,
51 owner_balances: Option<HashMap<AccountOwner, Amount>>,
52 chain_ownership: Option<ChainOwnership>,
53 can_close_chain: Option<bool>,
54 can_change_application_permissions: Option<bool>,
55 call_application_handler: Option<CallApplicationHandler>,
56 send_message_requests: Arc<Mutex<Vec<SendMessageRequest<Application::Message>>>>,
57 outgoing_transfers: HashMap<Account, Amount>,
58 created_events: BTreeMap<StreamName, Vec<Vec<u8>>>,
59 events: BTreeMap<(ChainId, StreamName, u32), Vec<u8>>,
60 claim_requests: Vec<ClaimRequest>,
61 expected_service_queries: VecDeque<(ApplicationId, String, String)>,
62 expected_http_requests: VecDeque<(http::Request, http::Response)>,
63 expected_read_data_blob_requests: VecDeque<(DataBlobHash, Vec<u8>)>,
64 expected_assert_data_blob_exists_requests: VecDeque<(DataBlobHash, Option<()>)>,
65 expected_open_chain_calls: VecDeque<(ChainOwnership, ApplicationPermissions, Amount, ChainId)>,
66 expected_create_application_calls: VecDeque<ExpectedCreateApplicationCall>,
67 key_value_store: KeyValueStore,
68}
69
70impl<Application> Default for MockContractRuntime<Application>
71where
72 Application: Contract,
73{
74 fn default() -> Self {
75 MockContractRuntime::new()
76 }
77}
78
79impl<Application> MockContractRuntime<Application>
80where
81 Application: Contract,
82{
83 pub fn new() -> Self {
85 MockContractRuntime {
86 application_parameters: None,
87 application_id: None,
88 application_creator_chain_id: None,
89 chain_id: None,
90 authenticated_signer: None,
91 block_height: None,
92 round: None,
93 message_id: None,
94 message_is_bouncing: None,
95 authenticated_caller_id: None,
96 timestamp: None,
97 chain_balance: None,
98 owner_balances: None,
99 chain_ownership: None,
100 can_close_chain: None,
101 can_change_application_permissions: None,
102 call_application_handler: None,
103 send_message_requests: Arc::default(),
104 outgoing_transfers: HashMap::new(),
105 created_events: BTreeMap::new(),
106 events: BTreeMap::new(),
107 claim_requests: Vec::new(),
108 expected_service_queries: VecDeque::new(),
109 expected_http_requests: VecDeque::new(),
110 expected_read_data_blob_requests: VecDeque::new(),
111 expected_assert_data_blob_exists_requests: VecDeque::new(),
112 expected_open_chain_calls: VecDeque::new(),
113 expected_create_application_calls: VecDeque::new(),
114 key_value_store: KeyValueStore::mock().to_mut(),
115 }
116 }
117
118 pub fn key_value_store(&self) -> KeyValueStore {
120 self.key_value_store.clone()
121 }
122
123 pub fn root_view_storage_context(&self) -> ViewStorageContext {
125 ViewStorageContext::new_unsafe(self.key_value_store(), Vec::new(), ())
126 }
127
128 pub fn with_application_parameters(
130 mut self,
131 application_parameters: Application::Parameters,
132 ) -> Self {
133 self.application_parameters = Some(application_parameters);
134 self
135 }
136
137 pub fn set_application_parameters(
139 &mut self,
140 application_parameters: Application::Parameters,
141 ) -> &mut Self {
142 self.application_parameters = Some(application_parameters);
143 self
144 }
145
146 pub fn application_parameters(&mut self) -> Application::Parameters {
148 self.application_parameters.clone().expect(
149 "Application parameters have not been mocked, \
150 please call `MockContractRuntime::set_application_parameters` first",
151 )
152 }
153
154 pub fn with_application_id(mut self, application_id: ApplicationId<Application::Abi>) -> Self {
156 self.application_id = Some(application_id);
157 self
158 }
159
160 pub fn set_application_id(
162 &mut self,
163 application_id: ApplicationId<Application::Abi>,
164 ) -> &mut Self {
165 self.application_id = Some(application_id);
166 self
167 }
168
169 pub fn application_id(&mut self) -> ApplicationId<Application::Abi> {
171 self.application_id.expect(
172 "Application ID has not been mocked, \
173 please call `MockContractRuntime::set_application_id` first",
174 )
175 }
176
177 pub fn with_application_creator_chain_id(mut self, chain_id: ChainId) -> Self {
179 self.application_creator_chain_id = Some(chain_id);
180 self
181 }
182
183 pub fn set_application_creator_chain_id(&mut self, chain_id: ChainId) -> &mut Self {
185 self.application_creator_chain_id = Some(chain_id);
186 self
187 }
188
189 pub fn application_creator_chain_id(&mut self) -> ChainId {
191 self.application_creator_chain_id.expect(
192 "Application creator chain ID has not been mocked, \
193 please call `MockContractRuntime::set_application_creator_chain_id` first",
194 )
195 }
196
197 pub fn with_chain_id(mut self, chain_id: ChainId) -> Self {
199 self.chain_id = Some(chain_id);
200 self
201 }
202
203 pub fn set_chain_id(&mut self, chain_id: ChainId) -> &mut Self {
205 self.chain_id = Some(chain_id);
206 self
207 }
208
209 pub fn chain_id(&mut self) -> ChainId {
211 self.chain_id.expect(
212 "Chain ID has not been mocked, \
213 please call `MockContractRuntime::set_chain_id` first",
214 )
215 }
216
217 pub fn with_authenticated_signer(
219 mut self,
220 authenticated_signer: impl Into<Option<AccountOwner>>,
221 ) -> Self {
222 self.authenticated_signer = Some(authenticated_signer.into());
223 self
224 }
225
226 pub fn set_authenticated_signer(
228 &mut self,
229 authenticated_signer: impl Into<Option<AccountOwner>>,
230 ) -> &mut Self {
231 self.authenticated_signer = Some(authenticated_signer.into());
232 self
233 }
234
235 pub fn authenticated_signer(&mut self) -> Option<AccountOwner> {
237 self.authenticated_signer.expect(
238 "Authenticated signer has not been mocked, \
239 please call `MockContractRuntime::set_authenticated_signer` first",
240 )
241 }
242
243 pub fn with_block_height(mut self, block_height: BlockHeight) -> Self {
245 self.block_height = Some(block_height);
246 self
247 }
248
249 pub fn set_block_height(&mut self, block_height: BlockHeight) -> &mut Self {
251 self.block_height = Some(block_height);
252 self
253 }
254
255 pub fn with_round(mut self, round: u32) -> Self {
257 self.round = Some(round);
258 self
259 }
260
261 pub fn set_round(&mut self, round: u32) -> &mut Self {
263 self.round = Some(round);
264 self
265 }
266
267 pub fn block_height(&mut self) -> BlockHeight {
269 self.block_height.expect(
270 "Block height has not been mocked, \
271 please call `MockContractRuntime::set_block_height` first",
272 )
273 }
274
275 pub fn with_message_id(mut self, message_id: impl Into<Option<MessageId>>) -> Self {
277 self.message_id = Some(message_id.into());
278 self
279 }
280
281 pub fn set_message_id(&mut self, message_id: impl Into<Option<MessageId>>) -> &mut Self {
283 self.message_id = Some(message_id.into());
284 self
285 }
286
287 pub fn message_id(&mut self) -> Option<MessageId> {
290 self.message_id.expect(
291 "Message ID has not been mocked, \
292 please call `MockContractRuntime::set_message_id` first",
293 )
294 }
295
296 pub fn with_message_is_bouncing(
298 mut self,
299 message_is_bouncing: impl Into<Option<bool>>,
300 ) -> Self {
301 self.message_is_bouncing = Some(message_is_bouncing.into());
302 self
303 }
304
305 pub fn set_message_is_bouncing(
307 &mut self,
308 message_is_bouncing: impl Into<Option<bool>>,
309 ) -> &mut Self {
310 self.message_is_bouncing = Some(message_is_bouncing.into());
311 self
312 }
313
314 pub fn message_is_bouncing(&mut self) -> Option<bool> {
317 self.message_is_bouncing.expect(
318 "`message_is_bouncing` flag has not been mocked, \
319 please call `MockContractRuntime::set_message_is_bouncing` first",
320 )
321 }
322
323 pub fn with_authenticated_caller_id(
325 mut self,
326 authenticated_caller_id: impl Into<Option<ApplicationId>>,
327 ) -> Self {
328 self.authenticated_caller_id = Some(authenticated_caller_id.into());
329 self
330 }
331
332 pub fn set_authenticated_caller_id(
334 &mut self,
335 authenticated_caller_id: impl Into<Option<ApplicationId>>,
336 ) -> &mut Self {
337 self.authenticated_caller_id = Some(authenticated_caller_id.into());
338 self
339 }
340
341 pub fn authenticated_caller_id(&mut self) -> Option<ApplicationId> {
344 self.authenticated_caller_id.expect(
345 "Authenticated caller ID has not been mocked, \
346 please call `MockContractRuntime::set_authenticated_caller_id` first",
347 )
348 }
349
350 pub fn check_account_permission(
352 &mut self,
353 owner: AccountOwner,
354 ) -> Result<(), AccountPermissionError> {
355 ensure!(
356 self.authenticated_signer() == Some(owner)
357 || self.authenticated_caller_id().map(AccountOwner::from) == Some(owner),
358 AccountPermissionError::NotPermitted(owner)
359 );
360 Ok(())
361 }
362
363 pub fn with_system_time(mut self, timestamp: Timestamp) -> Self {
365 self.timestamp = Some(timestamp);
366 self
367 }
368
369 pub fn set_system_time(&mut self, timestamp: Timestamp) -> &mut Self {
371 self.timestamp = Some(timestamp);
372 self
373 }
374
375 pub fn system_time(&mut self) -> Timestamp {
377 self.timestamp.expect(
378 "System time has not been mocked, \
379 please call `MockContractRuntime::set_system_time` first",
380 )
381 }
382
383 pub fn with_chain_balance(mut self, chain_balance: Amount) -> Self {
385 self.chain_balance = Some(chain_balance);
386 self
387 }
388
389 pub fn set_chain_balance(&mut self, chain_balance: Amount) -> &mut Self {
391 self.chain_balance = Some(chain_balance);
392 self
393 }
394
395 pub fn chain_balance(&mut self) -> Amount {
397 *self.chain_balance_mut()
398 }
399
400 fn chain_balance_mut(&mut self) -> &mut Amount {
402 self.chain_balance.as_mut().expect(
403 "Chain balance has not been mocked, \
404 please call `MockContractRuntime::set_chain_balance` first",
405 )
406 }
407
408 pub fn with_owner_balances(
410 mut self,
411 owner_balances: impl IntoIterator<Item = (AccountOwner, Amount)>,
412 ) -> Self {
413 self.owner_balances = Some(owner_balances.into_iter().collect());
414 self
415 }
416
417 pub fn set_owner_balances(
419 &mut self,
420 owner_balances: impl IntoIterator<Item = (AccountOwner, Amount)>,
421 ) -> &mut Self {
422 self.owner_balances = Some(owner_balances.into_iter().collect());
423 self
424 }
425
426 pub fn with_owner_balance(mut self, owner: AccountOwner, balance: Amount) -> Self {
428 self.set_owner_balance(owner, balance);
429 self
430 }
431
432 pub fn set_owner_balance(&mut self, owner: AccountOwner, balance: Amount) -> &mut Self {
434 self.owner_balances
435 .get_or_insert_with(HashMap::new)
436 .insert(owner, balance);
437 self
438 }
439
440 pub fn owner_balance(&mut self, owner: AccountOwner) -> Amount {
442 *self.owner_balance_mut(owner)
443 }
444
445 fn owner_balance_mut(&mut self, owner: AccountOwner) -> &mut Amount {
447 self.owner_balances
448 .as_mut()
449 .expect(
450 "Owner balances have not been mocked, \
451 please call `MockContractRuntime::set_owner_balances` first",
452 )
453 .get_mut(&owner)
454 .unwrap_or_else(|| {
455 panic!(
456 "Balance for owner {owner} was not mocked, \
457 please include a balance for them in the call to \
458 `MockContractRuntime::set_owner_balances`"
459 )
460 })
461 }
462
463 pub fn send_message(&mut self, destination: ChainId, message: Application::Message) {
465 self.prepare_message(message).send_to(destination)
466 }
467
468 pub fn prepare_message(
470 &mut self,
471 message: Application::Message,
472 ) -> MessageBuilder<Application::Message> {
473 MessageBuilder::new(message, self.send_message_requests.clone())
474 }
475
476 pub fn created_send_message_requests(
478 &self,
479 ) -> MutexGuard<'_, Vec<SendMessageRequest<Application::Message>>> {
480 self.send_message_requests
481 .try_lock()
482 .expect("Unit test should be single-threaded")
483 }
484
485 pub fn transfer(&mut self, source: AccountOwner, destination: Account, amount: Amount) {
488 self.debit(source, amount);
489
490 if Some(destination.chain_id) == self.chain_id {
491 self.credit(destination.owner, amount);
492 } else {
493 let destination_entry = self.outgoing_transfers.entry(destination).or_default();
494 *destination_entry = destination_entry
495 .try_add(amount)
496 .expect("Outgoing transfer value overflow");
497 }
498 }
499
500 fn debit(&mut self, source: AccountOwner, amount: Amount) {
503 let source_balance = if source == AccountOwner::CHAIN {
504 self.chain_balance_mut()
505 } else {
506 self.owner_balance_mut(source)
507 };
508
509 *source_balance = source_balance
510 .try_sub(amount)
511 .expect("Insufficient funds in source account");
512 }
513
514 fn credit(&mut self, destination: AccountOwner, amount: Amount) {
517 let destination_balance = if destination == AccountOwner::CHAIN {
518 self.chain_balance_mut()
519 } else {
520 self.owner_balance_mut(destination)
521 };
522
523 *destination_balance = destination_balance
524 .try_add(amount)
525 .expect("Account balance overflow");
526 }
527
528 pub fn outgoing_transfers(&self) -> &HashMap<Account, Amount> {
530 &self.outgoing_transfers
531 }
532
533 pub fn claim(&mut self, source: Account, destination: Account, amount: Amount) {
535 if Some(source.chain_id) == self.chain_id {
536 self.debit(source.owner, amount);
537
538 if Some(destination.chain_id) == self.chain_id {
539 self.credit(destination.owner, amount);
540 }
541 }
542
543 self.claim_requests.push(ClaimRequest {
544 source,
545 amount,
546 destination,
547 });
548 }
549
550 pub fn claim_requests(&self) -> &[ClaimRequest] {
552 &self.claim_requests
553 }
554
555 pub fn with_chain_ownership(mut self, chain_ownership: ChainOwnership) -> Self {
557 self.chain_ownership = Some(chain_ownership);
558 self
559 }
560
561 pub fn set_chain_ownership(&mut self, chain_ownership: ChainOwnership) -> &mut Self {
563 self.chain_ownership = Some(chain_ownership);
564 self
565 }
566
567 pub fn chain_ownership(&mut self) -> ChainOwnership {
569 self.chain_ownership.clone().expect(
570 "Chain ownership has not been mocked, \
571 please call `MockContractRuntime::set_chain_ownership` first",
572 )
573 }
574
575 pub fn with_can_close_chain(mut self, can_close_chain: bool) -> Self {
577 self.can_close_chain = Some(can_close_chain);
578 self
579 }
580
581 pub fn set_can_close_chain(&mut self, can_close_chain: bool) -> &mut Self {
583 self.can_close_chain = Some(can_close_chain);
584 self
585 }
586
587 pub fn with_can_change_application_permissions(
590 mut self,
591 can_change_application_permissions: bool,
592 ) -> Self {
593 self.can_change_application_permissions = Some(can_change_application_permissions);
594 self
595 }
596
597 pub fn set_can_change_application_permissions(
600 &mut self,
601 can_change_application_permissions: bool,
602 ) -> &mut Self {
603 self.can_change_application_permissions = Some(can_change_application_permissions);
604 self
605 }
606
607 pub fn close_chain(&mut self) -> Result<(), CloseChainError> {
610 let authorized = self.can_close_chain.expect(
611 "Authorization to close the chain has not been mocked, \
612 please call `MockContractRuntime::set_can_close_chain` first",
613 );
614
615 if authorized {
616 Ok(())
617 } else {
618 Err(CloseChainError::NotPermitted)
619 }
620 }
621
622 pub fn change_application_permissions(
625 &mut self,
626 application_permissions: ApplicationPermissions,
627 ) -> Result<(), ChangeApplicationPermissionsError> {
628 let authorized = self.can_change_application_permissions.expect(
629 "Authorization to change the application permissions has not been mocked, \
630 please call `MockContractRuntime::set_can_change_application_permissions` first",
631 );
632
633 if authorized {
634 let application_id = self
635 .application_id
636 .expect("The application doesn't have an ID!")
637 .forget_abi();
638 self.can_close_chain = Some(application_permissions.can_close_chain(&application_id));
639 self.can_change_application_permissions =
640 Some(application_permissions.can_change_application_permissions(&application_id));
641 Ok(())
642 } else {
643 Err(ChangeApplicationPermissionsError::NotPermitted)
644 }
645 }
646
647 pub fn add_expected_open_chain_call(
649 &mut self,
650 ownership: ChainOwnership,
651 application_permissions: ApplicationPermissions,
652 balance: Amount,
653 chain_id: ChainId,
654 ) {
655 self.expected_open_chain_calls.push_back((
656 ownership,
657 application_permissions,
658 balance,
659 chain_id,
660 ));
661 }
662
663 pub fn open_chain(
666 &mut self,
667 ownership: ChainOwnership,
668 application_permissions: ApplicationPermissions,
669 balance: Amount,
670 ) -> ChainId {
671 let (expected_ownership, expected_permissions, expected_balance, chain_id) = self
672 .expected_open_chain_calls
673 .pop_front()
674 .expect("Unexpected open_chain call");
675 assert_eq!(ownership, expected_ownership);
676 assert_eq!(application_permissions, expected_permissions);
677 assert_eq!(balance, expected_balance);
678 chain_id
679 }
680
681 pub fn add_expected_create_application_call<Parameters, InstantiationArgument>(
683 &mut self,
684 module_id: ModuleId,
685 parameters: &Parameters,
686 argument: &InstantiationArgument,
687 required_application_ids: Vec<ApplicationId>,
688 application_id: ApplicationId,
689 ) where
690 Parameters: Serialize,
691 InstantiationArgument: Serialize,
692 {
693 let parameters = serde_json::to_vec(parameters)
694 .expect("Failed to serialize `Parameters` type for a cross-application call");
695 let argument = serde_json::to_vec(argument).expect(
696 "Failed to serialize `InstantiationArgument` type for a cross-application call",
697 );
698 self.expected_create_application_calls
699 .push_back(ExpectedCreateApplicationCall {
700 module_id,
701 parameters,
702 argument,
703 required_application_ids,
704 application_id,
705 });
706 }
707
708 pub fn create_application<Abi, Parameters, InstantiationArgument>(
710 &mut self,
711 module_id: ModuleId,
712 parameters: &Parameters,
713 argument: &InstantiationArgument,
714 required_application_ids: Vec<ApplicationId>,
715 ) -> ApplicationId<Abi>
716 where
717 Abi: ContractAbi,
718 Parameters: Serialize,
719 InstantiationArgument: Serialize,
720 {
721 let ExpectedCreateApplicationCall {
722 module_id: expected_module_id,
723 parameters: expected_parameters,
724 argument: expected_argument,
725 required_application_ids: expected_required_app_ids,
726 application_id,
727 } = self
728 .expected_create_application_calls
729 .pop_front()
730 .expect("Unexpected create_application call");
731 let parameters = serde_json::to_vec(parameters)
732 .expect("Failed to serialize `Parameters` type for a cross-application call");
733 let argument = serde_json::to_vec(argument).expect(
734 "Failed to serialize `InstantiationArgument` type for a cross-application call",
735 );
736 assert_eq!(module_id, expected_module_id);
737 assert_eq!(parameters, expected_parameters);
738 assert_eq!(argument, expected_argument);
739 assert_eq!(required_application_ids, expected_required_app_ids);
740 application_id.with_abi::<Abi>()
741 }
742
743 pub fn with_call_application_handler(
745 mut self,
746 handler: impl FnMut(bool, ApplicationId, Vec<u8>) -> Vec<u8> + 'static,
747 ) -> Self {
748 self.call_application_handler = Some(Box::new(handler));
749 self
750 }
751
752 pub fn set_call_application_handler(
754 &mut self,
755 handler: impl FnMut(bool, ApplicationId, Vec<u8>) -> Vec<u8> + 'static,
756 ) -> &mut Self {
757 self.call_application_handler = Some(Box::new(handler));
758 self
759 }
760
761 pub fn call_application<A: ContractAbi + Send>(
763 &mut self,
764 authenticated: bool,
765 application: ApplicationId<A>,
766 call: &A::Operation,
767 ) -> A::Response {
768 let call_bytes = A::serialize_operation(call)
769 .expect("Failed to serialize `Operation` in test runtime cross-application call");
770
771 let handler = self.call_application_handler.as_mut().expect(
772 "Handler for `call_application` has not been mocked, \
773 please call `MockContractRuntime::set_call_application_handler` first",
774 );
775 let response_bytes = handler(authenticated, application.forget_abi(), call_bytes);
776
777 A::deserialize_response(response_bytes)
778 .expect("Failed to deserialize `Response` in test runtime cross-application call")
779 }
780
781 pub fn emit(&mut self, name: StreamName, value: &Application::EventValue) -> u32 {
783 let value = bcs::to_bytes(value).expect("Failed to serialize event value");
784 let entry = self.created_events.entry(name).or_default();
785 entry.push(value);
786 entry.len() as u32 - 1
787 }
788
789 pub fn add_event(&mut self, chain_id: ChainId, name: StreamName, index: u32, value: &[u8]) {
791 self.events.insert((chain_id, name, index), value.to_vec());
792 }
793
794 pub fn read_event(
798 &mut self,
799 chain_id: ChainId,
800 name: StreamName,
801 index: u32,
802 ) -> Application::EventValue {
803 let value = self
804 .events
805 .get(&(chain_id, name, index))
806 .expect("Event not found");
807 bcs::from_bytes(value).expect("Failed to deserialize event value")
808 }
809
810 pub fn subscribe_to_events(
812 &mut self,
813 _chain_id: ChainId,
814 _application_id: ApplicationId,
815 _name: StreamName,
816 ) {
817 }
819
820 pub fn unsubscribe_from_events(
822 &mut self,
823 _chain_id: ChainId,
824 _application_id: ApplicationId,
825 _name: StreamName,
826 ) {
827 }
829
830 pub fn add_expected_service_query<A: ServiceAbi + Send>(
832 &mut self,
833 application_id: ApplicationId<A>,
834 query: A::Query,
835 response: A::QueryResponse,
836 ) {
837 let query = serde_json::to_string(&query).expect("Failed to serialize query");
838 let response = serde_json::to_string(&response).expect("Failed to serialize response");
839 self.expected_service_queries
840 .push_back((application_id.forget_abi(), query, response));
841 }
842
843 pub fn add_expected_http_request(&mut self, request: http::Request, response: http::Response) {
845 self.expected_http_requests.push_back((request, response));
846 }
847
848 pub fn add_expected_read_data_blob_requests(&mut self, hash: DataBlobHash, response: Vec<u8>) {
850 self.expected_read_data_blob_requests
851 .push_back((hash, response));
852 }
853
854 pub fn add_expected_assert_data_blob_exists_requests(
856 &mut self,
857 hash: DataBlobHash,
858 response: Option<()>,
859 ) {
860 self.expected_assert_data_blob_exists_requests
861 .push_back((hash, response));
862 }
863
864 pub fn query_service<A: ServiceAbi + Send>(
872 &mut self,
873 application_id: ApplicationId<A>,
874 query: A::Query,
875 ) -> A::QueryResponse {
876 let maybe_query = self.expected_service_queries.pop_front();
877 let (expected_id, expected_query, response) =
878 maybe_query.expect("Unexpected service query");
879 assert_eq!(application_id.forget_abi(), expected_id);
880 let query = serde_json::to_string(&query).expect("Failed to serialize query");
881 assert_eq!(query, expected_query);
882 serde_json::from_str(&response).expect("Failed to deserialize response")
883 }
884
885 pub fn http_request(&mut self, request: http::Request) -> http::Response {
893 let maybe_request = self.expected_http_requests.pop_front();
894 let (expected_request, response) = maybe_request.expect("Unexpected HTTP request");
895 assert_eq!(request, expected_request);
896 response
897 }
898
899 pub fn assert_before(&mut self, timestamp: Timestamp) {
905 assert!(self.timestamp.is_some_and(|t| t < timestamp))
906 }
907
908 pub fn read_data_blob(&mut self, hash: &DataBlobHash) -> Vec<u8> {
910 let maybe_request = self.expected_read_data_blob_requests.pop_front();
911 let (expected_hash, response) = maybe_request.expect("Unexpected read_data_blob request");
912 assert_eq!(*hash, expected_hash);
913 response
914 }
915
916 pub fn assert_data_blob_exists(&mut self, hash: DataBlobHash) {
918 let maybe_request = self.expected_assert_data_blob_exists_requests.pop_front();
919 let (expected_blob_hash, response) =
920 maybe_request.expect("Unexpected assert_data_blob_exists request");
921 assert_eq!(hash, expected_blob_hash);
922 response.expect("Blob does not exist!");
923 }
924
925 pub fn validation_round(&mut self) -> Option<u32> {
927 self.round
928 }
929}
930
931pub type CallApplicationHandler = Box<dyn FnMut(bool, ApplicationId, Vec<u8>) -> Vec<u8>>;
933
934#[must_use]
937pub struct MessageBuilder<Message>
938where
939 Message: Serialize,
940{
941 authenticated: bool,
942 is_tracked: bool,
943 grant: Resources,
944 message: Message,
945 send_message_requests: Arc<Mutex<Vec<SendMessageRequest<Message>>>>,
946}
947
948impl<Message> MessageBuilder<Message>
949where
950 Message: Serialize,
951{
952 pub(crate) fn new(
954 message: Message,
955 send_message_requests: Arc<Mutex<Vec<SendMessageRequest<Message>>>>,
956 ) -> Self {
957 MessageBuilder {
958 authenticated: false,
959 is_tracked: false,
960 grant: Resources::default(),
961 message,
962 send_message_requests,
963 }
964 }
965
966 pub fn with_tracking(mut self) -> Self {
969 self.is_tracked = true;
970 self
971 }
972
973 pub fn with_authentication(mut self) -> Self {
975 self.authenticated = true;
976 self
977 }
978
979 pub fn with_grant(mut self, grant: Resources) -> Self {
981 self.grant = grant;
982 self
983 }
984
985 pub fn send_to(self, destination: ChainId) {
987 let request = SendMessageRequest {
988 destination,
989 authenticated: self.authenticated,
990 is_tracked: self.is_tracked,
991 grant: self.grant,
992 message: self.message,
993 };
994
995 self.send_message_requests
996 .try_lock()
997 .expect("Unit test should be single-threaded")
998 .push(request);
999 }
1000}
1001
1002#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1004pub struct ClaimRequest {
1005 source: Account,
1006 destination: Account,
1007 amount: Amount,
1008}