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, ApplicationDescription, ApplicationPermissions, BlockHeight, Bytecode, Resources,
15 SendMessageRequest, Timestamp,
16 },
17 ensure, http,
18 identifiers::{
19 Account, AccountOwner, ApplicationId, BlobId, ChainId, DataBlobHash, ModuleId, StreamName,
20 },
21 ownership::{AccountPermissionError, ChainOwnership, ManageChainError},
22 vm::VmRuntime,
23};
24use serde::Serialize;
25
26use crate::{Contract, KeyValueStore, ViewStorageContext};
27
28struct ExpectedPublishModuleCall {
29 contract: Bytecode,
30 service: Bytecode,
31 vm_runtime: VmRuntime,
32 module_id: ModuleId,
33}
34
35struct ExpectedCreateApplicationCall {
36 module_id: ModuleId,
37 parameters: Vec<u8>,
38 argument: Vec<u8>,
39 required_application_ids: Vec<ApplicationId>,
40 application_id: ApplicationId,
41}
42
43struct ExpectedCreateDataBlobCall {
44 bytes: Vec<u8>,
45 blob_id: BlobId,
46}
47
48pub struct MockContractRuntime<Application>
50where
51 Application: Contract,
52{
53 application_parameters: Option<Application::Parameters>,
54 application_id: Option<ApplicationId<Application::Abi>>,
55 application_creator_chain_id: Option<ChainId>,
56 application_descriptions: HashMap<ApplicationId, ApplicationDescription>,
57 chain_id: Option<ChainId>,
58 authenticated_owner: Option<Option<AccountOwner>>,
59 block_height: Option<BlockHeight>,
60 round: Option<u32>,
61 message_is_bouncing: Option<Option<bool>>,
62 message_origin_chain_id: Option<Option<ChainId>>,
63 authenticated_caller_id: Option<Option<ApplicationId>>,
64 timestamp: Option<Timestamp>,
65 chain_balance: Option<Amount>,
66 owner_balances: Option<HashMap<AccountOwner, Amount>>,
67 chain_ownership: Option<ChainOwnership>,
68 application_permissions: Option<ApplicationPermissions>,
69 can_manage_chain: Option<bool>,
70 call_application_handler: Option<CallApplicationHandler>,
71 send_message_requests: Arc<Mutex<Vec<SendMessageRequest<Application::Message>>>>,
72 outgoing_transfers: HashMap<Account, Amount>,
73 created_events: BTreeMap<StreamName, Vec<Vec<u8>>>,
74 events: BTreeMap<(ChainId, StreamName, u32), Vec<u8>>,
75 claim_requests: Vec<ClaimRequest>,
76 expected_service_queries: VecDeque<(ApplicationId, String, String)>,
77 expected_http_requests: VecDeque<(http::Request, http::Response)>,
78 expected_read_data_blob_requests: VecDeque<(DataBlobHash, Vec<u8>)>,
79 expected_assert_data_blob_exists_requests: VecDeque<(DataBlobHash, Option<()>)>,
80 expected_has_empty_storage_requests: VecDeque<(ApplicationId, bool)>,
81 expected_open_chain_calls: VecDeque<(ChainOwnership, ApplicationPermissions, Amount, ChainId)>,
82 expected_publish_module_calls: VecDeque<ExpectedPublishModuleCall>,
83 expected_create_application_calls: VecDeque<ExpectedCreateApplicationCall>,
84 expected_create_data_blob_calls: VecDeque<ExpectedCreateDataBlobCall>,
85 key_value_store: KeyValueStore,
86}
87
88impl<Application> Default for MockContractRuntime<Application>
89where
90 Application: Contract,
91{
92 fn default() -> Self {
93 MockContractRuntime::new()
94 }
95}
96
97impl<Application> MockContractRuntime<Application>
98where
99 Application: Contract,
100{
101 pub fn new() -> Self {
103 MockContractRuntime {
104 application_parameters: None,
105 application_id: None,
106 application_creator_chain_id: None,
107 application_descriptions: HashMap::new(),
108 chain_id: None,
109 authenticated_owner: None,
110 block_height: None,
111 round: None,
112 message_is_bouncing: None,
113 message_origin_chain_id: None,
114 authenticated_caller_id: None,
115 timestamp: None,
116 chain_balance: None,
117 owner_balances: None,
118 chain_ownership: None,
119 application_permissions: None,
120 can_manage_chain: None,
121 call_application_handler: None,
122 send_message_requests: Arc::default(),
123 outgoing_transfers: HashMap::new(),
124 created_events: BTreeMap::new(),
125 events: BTreeMap::new(),
126 claim_requests: Vec::new(),
127 expected_service_queries: VecDeque::new(),
128 expected_http_requests: VecDeque::new(),
129 expected_read_data_blob_requests: VecDeque::new(),
130 expected_assert_data_blob_exists_requests: VecDeque::new(),
131 expected_has_empty_storage_requests: VecDeque::new(),
132 expected_open_chain_calls: VecDeque::new(),
133 expected_publish_module_calls: VecDeque::new(),
134 expected_create_application_calls: VecDeque::new(),
135 expected_create_data_blob_calls: VecDeque::new(),
136 key_value_store: KeyValueStore::mock().to_mut(),
137 }
138 }
139
140 pub fn key_value_store(&self) -> KeyValueStore {
142 self.key_value_store.clone()
143 }
144
145 pub fn root_view_storage_context(&self) -> ViewStorageContext {
147 ViewStorageContext::new_unchecked(self.key_value_store(), Vec::new(), ())
148 }
149
150 pub fn with_application_parameters(
152 mut self,
153 application_parameters: Application::Parameters,
154 ) -> Self {
155 self.application_parameters = Some(application_parameters);
156 self
157 }
158
159 pub fn set_application_parameters(
161 &mut self,
162 application_parameters: Application::Parameters,
163 ) -> &mut Self {
164 self.application_parameters = Some(application_parameters);
165 self
166 }
167
168 pub fn application_parameters(&mut self) -> Application::Parameters {
170 self.application_parameters.clone().expect(
171 "Application parameters have not been mocked, \
172 please call `MockContractRuntime::set_application_parameters` first",
173 )
174 }
175
176 pub fn with_application_id(mut self, application_id: ApplicationId<Application::Abi>) -> Self {
178 self.application_id = Some(application_id);
179 self
180 }
181
182 pub fn set_application_id(
184 &mut self,
185 application_id: ApplicationId<Application::Abi>,
186 ) -> &mut Self {
187 self.application_id = Some(application_id);
188 self
189 }
190
191 pub fn application_id(&mut self) -> ApplicationId<Application::Abi> {
193 self.application_id.expect(
194 "Application ID has not been mocked, \
195 please call `MockContractRuntime::set_application_id` first",
196 )
197 }
198
199 pub fn with_application_creator_chain_id(mut self, chain_id: ChainId) -> Self {
201 self.application_creator_chain_id = Some(chain_id);
202 self
203 }
204
205 pub fn set_application_creator_chain_id(&mut self, chain_id: ChainId) -> &mut Self {
207 self.application_creator_chain_id = Some(chain_id);
208 self
209 }
210
211 pub fn application_creator_chain_id(&mut self) -> ChainId {
213 self.application_creator_chain_id.expect(
214 "Application creator chain ID has not been mocked, \
215 please call `MockContractRuntime::set_application_creator_chain_id` first",
216 )
217 }
218
219 pub fn with_application_description(
221 mut self,
222 application_id: ApplicationId,
223 description: ApplicationDescription,
224 ) -> Self {
225 self.application_descriptions
226 .insert(application_id, description);
227 self
228 }
229
230 pub fn set_application_description(
232 &mut self,
233 application_id: ApplicationId,
234 description: ApplicationDescription,
235 ) -> &mut Self {
236 self.application_descriptions
237 .insert(application_id, description);
238 self
239 }
240
241 pub fn read_application_description(
243 &mut self,
244 application_id: ApplicationId,
245 ) -> ApplicationDescription {
246 self.application_descriptions
247 .get(&application_id)
248 .cloned()
249 .unwrap_or_else(|| {
250 panic!(
251 "Application description for {application_id:?} has not been mocked, \
252 please call `MockContractRuntime::set_application_description` first"
253 )
254 })
255 }
256
257 pub fn with_chain_id(mut self, chain_id: ChainId) -> Self {
259 self.chain_id = Some(chain_id);
260 self
261 }
262
263 pub fn set_chain_id(&mut self, chain_id: ChainId) -> &mut Self {
265 self.chain_id = Some(chain_id);
266 self
267 }
268
269 pub fn chain_id(&mut self) -> ChainId {
271 self.chain_id.expect(
272 "Chain ID has not been mocked, \
273 please call `MockContractRuntime::set_chain_id` first",
274 )
275 }
276
277 pub fn with_authenticated_owner(
279 mut self,
280 authenticated_owner: impl Into<Option<AccountOwner>>,
281 ) -> Self {
282 self.authenticated_owner = Some(authenticated_owner.into());
283 self
284 }
285
286 pub fn set_authenticated_owner(
288 &mut self,
289 authenticated_owner: impl Into<Option<AccountOwner>>,
290 ) -> &mut Self {
291 self.authenticated_owner = Some(authenticated_owner.into());
292 self
293 }
294
295 pub fn authenticated_owner(&mut self) -> Option<AccountOwner> {
297 self.authenticated_owner.expect(
298 "Authenticated owner has not been mocked, \
299 please call `MockContractRuntime::set_authenticated_owner` first",
300 )
301 }
302
303 pub fn with_block_height(mut self, block_height: BlockHeight) -> Self {
305 self.block_height = Some(block_height);
306 self
307 }
308
309 pub fn set_block_height(&mut self, block_height: BlockHeight) -> &mut Self {
311 self.block_height = Some(block_height);
312 self
313 }
314
315 pub fn with_round(mut self, round: u32) -> Self {
317 self.round = Some(round);
318 self
319 }
320
321 pub fn set_round(&mut self, round: u32) -> &mut Self {
323 self.round = Some(round);
324 self
325 }
326
327 pub fn block_height(&mut self) -> BlockHeight {
329 self.block_height.expect(
330 "Block height has not been mocked, \
331 please call `MockContractRuntime::set_block_height` first",
332 )
333 }
334
335 pub fn with_message_is_bouncing(
337 mut self,
338 message_is_bouncing: impl Into<Option<bool>>,
339 ) -> Self {
340 self.message_is_bouncing = Some(message_is_bouncing.into());
341 self
342 }
343
344 pub fn set_message_is_bouncing(
346 &mut self,
347 message_is_bouncing: impl Into<Option<bool>>,
348 ) -> &mut Self {
349 self.message_is_bouncing = Some(message_is_bouncing.into());
350 self
351 }
352
353 pub fn message_is_bouncing(&mut self) -> Option<bool> {
356 self.message_is_bouncing.expect(
357 "`message_is_bouncing` flag has not been mocked, \
358 please call `MockContractRuntime::set_message_is_bouncing` first",
359 )
360 }
361
362 pub fn set_message_origin_chain_id(
364 &mut self,
365 message_origin_chain_id: impl Into<Option<ChainId>>,
366 ) -> &mut Self {
367 self.message_origin_chain_id = Some(message_origin_chain_id.into());
368 self
369 }
370
371 pub fn message_origin_chain_id(&mut self) -> Option<ChainId> {
374 self.message_origin_chain_id.expect(
375 "`message_origin_chain_id` has not been mocked, \
376 please call `MockContractRuntime::set_message_origin_chain_id` first",
377 )
378 }
379
380 pub fn with_authenticated_caller_id(
382 mut self,
383 authenticated_caller_id: impl Into<Option<ApplicationId>>,
384 ) -> Self {
385 self.authenticated_caller_id = Some(authenticated_caller_id.into());
386 self
387 }
388
389 pub fn set_authenticated_caller_id(
391 &mut self,
392 authenticated_caller_id: impl Into<Option<ApplicationId>>,
393 ) -> &mut Self {
394 self.authenticated_caller_id = Some(authenticated_caller_id.into());
395 self
396 }
397
398 pub fn authenticated_caller_id(&mut self) -> Option<ApplicationId> {
401 self.authenticated_caller_id.expect(
402 "Authenticated caller ID has not been mocked, \
403 please call `MockContractRuntime::set_authenticated_caller_id` first",
404 )
405 }
406
407 pub fn check_account_permission(
409 &mut self,
410 owner: AccountOwner,
411 ) -> Result<(), AccountPermissionError> {
412 ensure!(
413 self.authenticated_owner() == Some(owner)
414 || self.authenticated_caller_id().map(AccountOwner::from) == Some(owner),
415 AccountPermissionError::NotPermitted(owner)
416 );
417 Ok(())
418 }
419
420 pub fn with_system_time(mut self, timestamp: Timestamp) -> Self {
422 self.timestamp = Some(timestamp);
423 self
424 }
425
426 pub fn set_system_time(&mut self, timestamp: Timestamp) -> &mut Self {
428 self.timestamp = Some(timestamp);
429 self
430 }
431
432 pub fn system_time(&mut self) -> Timestamp {
434 self.timestamp.expect(
435 "System time has not been mocked, \
436 please call `MockContractRuntime::set_system_time` first",
437 )
438 }
439
440 pub fn with_chain_balance(mut self, chain_balance: Amount) -> Self {
442 self.chain_balance = Some(chain_balance);
443 self
444 }
445
446 pub fn set_chain_balance(&mut self, chain_balance: Amount) -> &mut Self {
448 self.chain_balance = Some(chain_balance);
449 self
450 }
451
452 pub fn chain_balance(&mut self) -> Amount {
454 *self.chain_balance_mut()
455 }
456
457 fn chain_balance_mut(&mut self) -> &mut Amount {
459 self.chain_balance.as_mut().expect(
460 "Chain balance has not been mocked, \
461 please call `MockContractRuntime::set_chain_balance` first",
462 )
463 }
464
465 pub fn with_owner_balances(
467 mut self,
468 owner_balances: impl IntoIterator<Item = (AccountOwner, Amount)>,
469 ) -> Self {
470 self.owner_balances = Some(owner_balances.into_iter().collect());
471 self
472 }
473
474 pub fn set_owner_balances(
476 &mut self,
477 owner_balances: impl IntoIterator<Item = (AccountOwner, Amount)>,
478 ) -> &mut Self {
479 self.owner_balances = Some(owner_balances.into_iter().collect());
480 self
481 }
482
483 pub fn with_owner_balance(mut self, owner: AccountOwner, balance: Amount) -> Self {
485 self.set_owner_balance(owner, balance);
486 self
487 }
488
489 pub fn set_owner_balance(&mut self, owner: AccountOwner, balance: Amount) -> &mut Self {
491 self.owner_balances
492 .get_or_insert_with(HashMap::new)
493 .insert(owner, balance);
494 self
495 }
496
497 pub fn owner_balance(&mut self, owner: AccountOwner) -> Amount {
499 *self.owner_balance_mut(owner)
500 }
501
502 fn owner_balance_mut(&mut self, owner: AccountOwner) -> &mut Amount {
504 self.owner_balances
505 .as_mut()
506 .expect(
507 "Owner balances have not been mocked, \
508 please call `MockContractRuntime::set_owner_balances` first",
509 )
510 .get_mut(&owner)
511 .unwrap_or_else(|| {
512 panic!(
513 "Balance for owner {owner} was not mocked, \
514 please include a balance for them in the call to \
515 `MockContractRuntime::set_owner_balances`"
516 )
517 })
518 }
519
520 pub fn send_message(&mut self, destination: ChainId, message: Application::Message) {
522 self.prepare_message(message).send_to(destination)
523 }
524
525 pub fn prepare_message(
527 &mut self,
528 message: Application::Message,
529 ) -> MessageBuilder<Application::Message> {
530 MessageBuilder::new(message, self.send_message_requests.clone())
531 }
532
533 pub fn created_send_message_requests(
535 &self,
536 ) -> MutexGuard<'_, Vec<SendMessageRequest<Application::Message>>> {
537 self.send_message_requests
538 .try_lock()
539 .expect("Unit test should be single-threaded")
540 }
541
542 pub fn transfer(&mut self, source: AccountOwner, destination: Account, amount: Amount) {
545 self.debit(source, amount);
546
547 if Some(destination.chain_id) == self.chain_id {
548 self.credit(destination.owner, amount);
549 } else {
550 let destination_entry = self.outgoing_transfers.entry(destination).or_default();
551 *destination_entry = destination_entry
552 .try_add(amount)
553 .expect("Outgoing transfer value overflow");
554 }
555 }
556
557 fn debit(&mut self, source: AccountOwner, amount: Amount) {
560 let source_balance = if source == AccountOwner::CHAIN {
561 self.chain_balance_mut()
562 } else {
563 self.owner_balance_mut(source)
564 };
565
566 *source_balance = source_balance
567 .try_sub(amount)
568 .expect("Insufficient funds in source account");
569 }
570
571 fn credit(&mut self, destination: AccountOwner, amount: Amount) {
574 let destination_balance = if destination == AccountOwner::CHAIN {
575 self.chain_balance_mut()
576 } else {
577 self.owner_balance_mut(destination)
578 };
579
580 *destination_balance = destination_balance
581 .try_add(amount)
582 .expect("Account balance overflow");
583 }
584
585 pub fn outgoing_transfers(&self) -> &HashMap<Account, Amount> {
587 &self.outgoing_transfers
588 }
589
590 pub fn claim(&mut self, source: Account, destination: Account, amount: Amount) {
592 if Some(source.chain_id) == self.chain_id {
593 self.debit(source.owner, amount);
594
595 if Some(destination.chain_id) == self.chain_id {
596 self.credit(destination.owner, amount);
597 }
598 }
599
600 self.claim_requests.push(ClaimRequest {
601 source,
602 amount,
603 destination,
604 });
605 }
606
607 pub fn claim_requests(&self) -> &[ClaimRequest] {
609 &self.claim_requests
610 }
611
612 pub fn with_chain_ownership(mut self, chain_ownership: ChainOwnership) -> Self {
614 self.chain_ownership = Some(chain_ownership);
615 self
616 }
617
618 pub fn set_chain_ownership(&mut self, chain_ownership: ChainOwnership) -> &mut Self {
620 self.chain_ownership = Some(chain_ownership);
621 self
622 }
623
624 pub fn chain_ownership(&mut self) -> ChainOwnership {
626 self.chain_ownership.clone().expect(
627 "Chain ownership has not been mocked, \
628 please call `MockContractRuntime::set_chain_ownership` first",
629 )
630 }
631
632 pub fn with_application_permissions(
634 mut self,
635 application_permissions: ApplicationPermissions,
636 ) -> Self {
637 self.application_permissions = Some(application_permissions);
638 self
639 }
640
641 pub fn set_application_permissions(
643 &mut self,
644 application_permissions: ApplicationPermissions,
645 ) -> &mut Self {
646 self.application_permissions = Some(application_permissions);
647 self
648 }
649
650 pub fn application_permissions(&mut self) -> ApplicationPermissions {
652 self.application_permissions.clone().expect(
653 "Application permissions have not been mocked, \
654 please call `MockContractRuntime::set_application_permissions` first",
655 )
656 }
657
658 pub fn with_can_manage_chain(mut self, can_manage_chain: bool) -> Self {
661 self.can_manage_chain = Some(can_manage_chain);
662 self
663 }
664
665 pub fn set_can_manage_chain(&mut self, can_manage_chain: bool) -> &mut Self {
668 self.can_manage_chain = Some(can_manage_chain);
669 self
670 }
671
672 pub fn close_chain(&mut self) -> Result<(), ManageChainError> {
675 let authorized = self.can_manage_chain.expect(
676 "Authorization to manage the chain has not been mocked, \
677 please call `MockContractRuntime::set_can_manage_chain` first",
678 );
679
680 if authorized {
681 Ok(())
682 } else {
683 Err(ManageChainError::NotPermitted)
684 }
685 }
686
687 pub fn change_ownership(&mut self, ownership: ChainOwnership) -> Result<(), ManageChainError> {
690 let authorized = self.can_manage_chain.expect(
691 "Authorization to manage the chain has not been mocked, \
692 please call `MockContractRuntime::set_can_manage_chain` first",
693 );
694
695 if authorized {
696 self.chain_ownership = Some(ownership);
697 Ok(())
698 } else {
699 Err(ManageChainError::NotPermitted)
700 }
701 }
702
703 pub fn change_application_permissions(
706 &mut self,
707 application_permissions: ApplicationPermissions,
708 ) -> Result<(), ManageChainError> {
709 let authorized = self.can_manage_chain.expect(
710 "Authorization to manage the chain has not been mocked, \
711 please call `MockContractRuntime::set_can_manage_chain` first",
712 );
713
714 if authorized {
715 let application_id = self
716 .application_id
717 .expect("The application doesn't have an ID!")
718 .forget_abi();
719 self.can_manage_chain = Some(application_permissions.can_manage_chain(&application_id));
720 Ok(())
721 } else {
722 Err(ManageChainError::NotPermitted)
723 }
724 }
725
726 pub fn add_expected_open_chain_call(
728 &mut self,
729 ownership: ChainOwnership,
730 application_permissions: ApplicationPermissions,
731 balance: Amount,
732 chain_id: ChainId,
733 ) {
734 self.expected_open_chain_calls.push_back((
735 ownership,
736 application_permissions,
737 balance,
738 chain_id,
739 ));
740 }
741
742 pub fn open_chain(
745 &mut self,
746 ownership: ChainOwnership,
747 application_permissions: ApplicationPermissions,
748 balance: Amount,
749 ) -> ChainId {
750 let (expected_ownership, expected_permissions, expected_balance, chain_id) = self
751 .expected_open_chain_calls
752 .pop_front()
753 .expect("Unexpected open_chain call");
754 assert_eq!(ownership, expected_ownership);
755 assert_eq!(application_permissions, expected_permissions);
756 assert_eq!(balance, expected_balance);
757 chain_id
758 }
759
760 pub fn add_expected_publish_module_call(
762 &mut self,
763 contract: Bytecode,
764 service: Bytecode,
765 vm_runtime: VmRuntime,
766 module_id: ModuleId,
767 ) {
768 self.expected_publish_module_calls
769 .push_back(ExpectedPublishModuleCall {
770 contract,
771 service,
772 vm_runtime,
773 module_id,
774 });
775 }
776
777 pub fn add_expected_create_application_call<Parameters, InstantiationArgument>(
779 &mut self,
780 module_id: ModuleId,
781 parameters: &Parameters,
782 argument: &InstantiationArgument,
783 required_application_ids: Vec<ApplicationId>,
784 application_id: ApplicationId,
785 ) where
786 Parameters: Serialize,
787 InstantiationArgument: Serialize,
788 {
789 let parameters = serde_json::to_vec(parameters)
790 .expect("Failed to serialize `Parameters` type for a cross-application call");
791 let argument = serde_json::to_vec(argument).expect(
792 "Failed to serialize `InstantiationArgument` type for a cross-application call",
793 );
794 self.expected_create_application_calls
795 .push_back(ExpectedCreateApplicationCall {
796 module_id,
797 parameters,
798 argument,
799 required_application_ids,
800 application_id,
801 });
802 }
803
804 pub fn add_expected_create_data_blob_call(&mut self, bytes: Vec<u8>, blob_id: BlobId) {
806 self.expected_create_data_blob_calls
807 .push_back(ExpectedCreateDataBlobCall { bytes, blob_id });
808 }
809
810 pub fn publish_module(
812 &mut self,
813 contract: Bytecode,
814 service: Bytecode,
815 vm_runtime: VmRuntime,
816 ) -> ModuleId {
817 let ExpectedPublishModuleCall {
818 contract: expected_contract,
819 service: expected_service,
820 vm_runtime: expected_vm_runtime,
821 module_id,
822 } = self
823 .expected_publish_module_calls
824 .pop_front()
825 .expect("Unexpected publish_module call");
826 assert_eq!(contract, expected_contract);
827 assert_eq!(service, expected_service);
828 assert_eq!(vm_runtime, expected_vm_runtime);
829 module_id
830 }
831
832 pub fn create_application<Abi, Parameters, InstantiationArgument>(
834 &mut self,
835 module_id: ModuleId,
836 parameters: &Parameters,
837 argument: &InstantiationArgument,
838 required_application_ids: Vec<ApplicationId>,
839 ) -> ApplicationId<Abi>
840 where
841 Abi: ContractAbi,
842 Parameters: Serialize,
843 InstantiationArgument: Serialize,
844 {
845 let ExpectedCreateApplicationCall {
846 module_id: expected_module_id,
847 parameters: expected_parameters,
848 argument: expected_argument,
849 required_application_ids: expected_required_app_ids,
850 application_id,
851 } = self
852 .expected_create_application_calls
853 .pop_front()
854 .expect("Unexpected create_application call");
855 let parameters = serde_json::to_vec(parameters)
856 .expect("Failed to serialize `Parameters` type for a cross-application call");
857 let argument = serde_json::to_vec(argument).expect(
858 "Failed to serialize `InstantiationArgument` type for a cross-application call",
859 );
860 assert_eq!(module_id, expected_module_id);
861 assert_eq!(parameters, expected_parameters);
862 assert_eq!(argument, expected_argument);
863 assert_eq!(required_application_ids, expected_required_app_ids);
864 application_id.with_abi::<Abi>()
865 }
866
867 pub fn create_data_blob(&mut self, bytes: &[u8]) -> DataBlobHash {
869 let ExpectedCreateDataBlobCall {
870 bytes: expected_bytes,
871 blob_id,
872 } = self
873 .expected_create_data_blob_calls
874 .pop_front()
875 .expect("Unexpected create_data_blob call");
876 assert_eq!(bytes, &expected_bytes);
877 DataBlobHash(blob_id.hash)
878 }
879
880 pub fn with_call_application_handler(
882 mut self,
883 handler: impl FnMut(bool, ApplicationId, Vec<u8>) -> Vec<u8> + 'static,
884 ) -> Self {
885 self.call_application_handler = Some(Box::new(handler));
886 self
887 }
888
889 pub fn set_call_application_handler(
891 &mut self,
892 handler: impl FnMut(bool, ApplicationId, Vec<u8>) -> Vec<u8> + 'static,
893 ) -> &mut Self {
894 self.call_application_handler = Some(Box::new(handler));
895 self
896 }
897
898 pub fn call_application<A: ContractAbi + Send>(
900 &mut self,
901 authenticated: bool,
902 application: ApplicationId<A>,
903 call: &A::Operation,
904 ) -> A::Response {
905 let call_bytes = <A as ContractAbi>::serialize_operation(call)
906 .expect("Failed to serialize `Operation` in test runtime cross-application call");
907
908 let handler = self.call_application_handler.as_mut().expect(
909 "Handler for `call_application` has not been mocked, \
910 please call `MockContractRuntime::set_call_application_handler` first",
911 );
912 let response_bytes = handler(authenticated, application.forget_abi(), call_bytes);
913
914 A::deserialize_response(response_bytes)
915 .expect("Failed to deserialize `Response` in test runtime cross-application call")
916 }
917
918 pub fn emit(&mut self, name: StreamName, value: &Application::EventValue) -> u32 {
920 let value = bcs::to_bytes(value).expect("Failed to serialize event value");
921 let entry = self.created_events.entry(name).or_default();
922 entry.push(value);
923 entry.len() as u32 - 1
924 }
925
926 pub fn add_event(&mut self, chain_id: ChainId, name: StreamName, index: u32, value: &[u8]) {
928 self.events.insert((chain_id, name, index), value.to_vec());
929 }
930
931 pub fn read_event(
935 &mut self,
936 chain_id: ChainId,
937 name: StreamName,
938 index: u32,
939 ) -> Application::EventValue {
940 let value = self
941 .events
942 .get(&(chain_id, name, index))
943 .expect("Event not found");
944 bcs::from_bytes(value).expect("Failed to deserialize event value")
945 }
946
947 pub fn subscribe_to_events(
949 &mut self,
950 _chain_id: ChainId,
951 _application_id: ApplicationId,
952 _name: StreamName,
953 ) {
954 }
956
957 pub fn unsubscribe_from_events(
959 &mut self,
960 _chain_id: ChainId,
961 _application_id: ApplicationId,
962 _name: StreamName,
963 ) {
964 }
966
967 pub fn add_expected_service_query<A: ServiceAbi + Send>(
969 &mut self,
970 application_id: ApplicationId<A>,
971 query: A::Query,
972 response: A::QueryResponse,
973 ) {
974 let query = serde_json::to_string(&query).expect("Failed to serialize query");
975 let response = serde_json::to_string(&response).expect("Failed to serialize response");
976 self.expected_service_queries
977 .push_back((application_id.forget_abi(), query, response));
978 }
979
980 pub fn add_expected_http_request(&mut self, request: http::Request, response: http::Response) {
982 self.expected_http_requests.push_back((request, response));
983 }
984
985 pub fn add_expected_read_data_blob_requests(&mut self, hash: DataBlobHash, response: Vec<u8>) {
987 self.expected_read_data_blob_requests
988 .push_back((hash, response));
989 }
990
991 pub fn add_expected_assert_data_blob_exists_requests(
993 &mut self,
994 hash: DataBlobHash,
995 response: Option<()>,
996 ) {
997 self.expected_assert_data_blob_exists_requests
998 .push_back((hash, response));
999 }
1000
1001 pub fn add_expected_has_empty_storage_requests(
1003 &mut self,
1004 application: ApplicationId,
1005 response: bool,
1006 ) {
1007 self.expected_has_empty_storage_requests
1008 .push_back((application, response));
1009 }
1010
1011 pub fn query_service<A: ServiceAbi + Send>(
1019 &mut self,
1020 application_id: ApplicationId<A>,
1021 query: &A::Query,
1022 ) -> A::QueryResponse {
1023 let maybe_query = self.expected_service_queries.pop_front();
1024 let (expected_id, expected_query, response) =
1025 maybe_query.expect("Unexpected service query");
1026 assert_eq!(application_id.forget_abi(), expected_id);
1027 let query = serde_json::to_string(query).expect("Failed to serialize query");
1028 assert_eq!(query, expected_query);
1029 serde_json::from_str(&response).expect("Failed to deserialize response")
1030 }
1031
1032 pub fn http_request(&mut self, request: http::Request) -> http::Response {
1040 let maybe_request = self.expected_http_requests.pop_front();
1041 let (expected_request, response) = maybe_request.expect("Unexpected HTTP request");
1042 assert_eq!(request, expected_request);
1043 response
1044 }
1045
1046 pub fn assert_before(&mut self, timestamp: Timestamp) {
1052 assert!(self.timestamp.is_some_and(|t| t < timestamp))
1053 }
1054
1055 pub fn read_data_blob(&mut self, hash: DataBlobHash) -> Vec<u8> {
1057 let maybe_request = self.expected_read_data_blob_requests.pop_front();
1058 let (expected_hash, response) = maybe_request.expect("Unexpected read_data_blob request");
1059 assert_eq!(hash, expected_hash);
1060 response
1061 }
1062
1063 pub fn assert_data_blob_exists(&mut self, hash: DataBlobHash) {
1065 let maybe_request = self.expected_assert_data_blob_exists_requests.pop_front();
1066 let (expected_blob_hash, response) =
1067 maybe_request.expect("Unexpected assert_data_blob_exists request");
1068 assert_eq!(hash, expected_blob_hash);
1069 response.expect("Blob does not exist!");
1070 }
1071
1072 pub fn has_empty_storage(&mut self, application: ApplicationId) -> bool {
1074 let maybe_request = self.expected_has_empty_storage_requests.pop_front();
1075 let (expected_application_id, response) =
1076 maybe_request.expect("Unexpected has_empty_storage request");
1077 assert_eq!(application, expected_application_id);
1078 response
1079 }
1080
1081 pub fn validation_round(&mut self) -> Option<u32> {
1083 self.round
1084 }
1085}
1086
1087pub type CallApplicationHandler = Box<dyn FnMut(bool, ApplicationId, Vec<u8>) -> Vec<u8>>;
1089
1090#[must_use]
1093pub struct MessageBuilder<Message>
1094where
1095 Message: Serialize,
1096{
1097 authenticated: bool,
1098 is_tracked: bool,
1099 grant: Resources,
1100 message: Message,
1101 send_message_requests: Arc<Mutex<Vec<SendMessageRequest<Message>>>>,
1102}
1103
1104impl<Message> MessageBuilder<Message>
1105where
1106 Message: Serialize,
1107{
1108 pub(crate) fn new(
1110 message: Message,
1111 send_message_requests: Arc<Mutex<Vec<SendMessageRequest<Message>>>>,
1112 ) -> Self {
1113 MessageBuilder {
1114 authenticated: false,
1115 is_tracked: false,
1116 grant: Resources::default(),
1117 message,
1118 send_message_requests,
1119 }
1120 }
1121
1122 pub fn with_tracking(mut self) -> Self {
1125 self.is_tracked = true;
1126 self
1127 }
1128
1129 pub fn with_authentication(mut self) -> Self {
1131 self.authenticated = true;
1132 self
1133 }
1134
1135 pub fn with_grant(mut self, grant: Resources) -> Self {
1137 self.grant = grant;
1138 self
1139 }
1140
1141 pub fn send_to(self, destination: ChainId) {
1143 let request = SendMessageRequest {
1144 destination,
1145 authenticated: self.authenticated,
1146 is_tracked: self.is_tracked,
1147 grant: self.grant,
1148 message: self.message,
1149 };
1150
1151 self.send_message_requests
1152 .try_lock()
1153 .expect("Unit test should be single-threaded")
1154 .push(request);
1155 }
1156}
1157
1158#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1160pub struct ClaimRequest {
1161 source: Account,
1162 destination: Account,
1163 amount: Amount,
1164}