cw_multi_test/
app_builder.rs

1//! AppBuilder helps you set up your test blockchain environment step by step [App].
2
3use crate::featured::staking::{Distribution, DistributionKeeper, StakeKeeper, Staking};
4use crate::{
5    App, Bank, BankKeeper, FailingModule, Gov, GovFailingModule, Ibc, IbcFailingModule, Module,
6    Router, Stargate, StargateFailing, Wasm, WasmKeeper,
7};
8use cosmwasm_std::testing::{mock_env, MockApi, MockStorage};
9use cosmwasm_std::{Api, BlockInfo, CustomMsg, CustomQuery, Empty, Storage};
10use serde::de::DeserializeOwned;
11use std::fmt::Debug;
12
13/// This is essential to create a custom app with custom module.
14///
15/// # Example
16///
17/// ```
18/// # use cosmwasm_std::Empty;
19/// # use cw_multi_test::{no_init, BasicAppBuilder, FailingModule, Module};
20/// # type MyHandler = FailingModule<Empty, Empty, Empty>;
21/// # type MyExecC = Empty;
22/// # type MyQueryC = Empty;
23///
24/// let mut app = BasicAppBuilder::<MyExecC, MyQueryC>::new_custom()
25///                   .with_custom(MyHandler::default())
26///                   .build(no_init);
27/// ```
28/// This type alias is crucial for constructing a custom app with specific modules.
29/// It provides a streamlined approach to building and configuring an App tailored to
30/// particular testing needs or scenarios.
31pub type BasicAppBuilder<ExecC, QueryC> = AppBuilder<
32    BankKeeper,
33    MockApi,
34    MockStorage,
35    FailingModule<ExecC, QueryC, Empty>,
36    WasmKeeper<ExecC, QueryC>,
37    StakeKeeper,
38    DistributionKeeper,
39    IbcFailingModule,
40    GovFailingModule,
41    StargateFailing,
42>;
43
44/// The chain builder.
45///
46/// Utility structure for building a chain in stages.
47/// When particular properties are not explicitly set, then default values are used.
48pub struct AppBuilder<Bank, Api, Storage, Custom, Wasm, Staking, Distr, Ibc, Gov, Stargate> {
49    api: Api,
50    block: BlockInfo,
51    storage: Storage,
52    bank: Bank,
53    wasm: Wasm,
54    custom: Custom,
55    staking: Staking,
56    distribution: Distr,
57    ibc: Ibc,
58    gov: Gov,
59    stargate: Stargate,
60}
61
62impl Default
63    for AppBuilder<
64        BankKeeper,
65        MockApi,
66        MockStorage,
67        FailingModule<Empty, Empty, Empty>,
68        WasmKeeper<Empty, Empty>,
69        StakeKeeper,
70        DistributionKeeper,
71        IbcFailingModule,
72        GovFailingModule,
73        StargateFailing,
74    >
75{
76    /// Creates a chain with default settings.
77    ///
78    /// # Examples
79    ///
80    /// ```
81    /// use cw_multi_test::{no_init, AppBuilder};
82    ///
83    /// let app = AppBuilder::default().build(no_init);
84    ///
85    /// let sender_addr = app.api().addr_make("sender");
86    /// assert!(sender_addr.as_str().starts_with("cosmwasm1"));
87    /// ```
88    fn default() -> Self {
89        Self::new()
90    }
91}
92
93impl
94    AppBuilder<
95        BankKeeper,
96        MockApi,
97        MockStorage,
98        FailingModule<Empty, Empty, Empty>,
99        WasmKeeper<Empty, Empty>,
100        StakeKeeper,
101        DistributionKeeper,
102        IbcFailingModule,
103        GovFailingModule,
104        StargateFailing,
105    >
106{
107    /// Creates a builder with default components working with empty exec and query messages.
108    ///
109    /// # Examples
110    ///
111    /// ```
112    /// use cw_multi_test::{no_init, AppBuilder};
113    ///
114    /// let app = AppBuilder::new().build(no_init);
115    ///
116    /// let sender_addr = app.api().addr_make("sender");
117    /// assert!(sender_addr.as_str().starts_with("cosmwasm1"));
118    /// ```
119    pub fn new() -> Self {
120        AppBuilder {
121            api: MockApi::default(),
122            block: mock_env().block,
123            storage: MockStorage::new(),
124            bank: BankKeeper::new(),
125            wasm: WasmKeeper::new(),
126            custom: FailingModule::new(),
127            staking: StakeKeeper::new(),
128            distribution: DistributionKeeper::new(),
129            ibc: IbcFailingModule::new(),
130            gov: GovFailingModule::new(),
131            stargate: StargateFailing,
132        }
133    }
134}
135
136impl<ExecC, QueryC>
137    AppBuilder<
138        BankKeeper,
139        MockApi,
140        MockStorage,
141        FailingModule<ExecC, QueryC, Empty>,
142        WasmKeeper<ExecC, QueryC>,
143        StakeKeeper,
144        DistributionKeeper,
145        IbcFailingModule,
146        GovFailingModule,
147        StargateFailing,
148    >
149where
150    ExecC: CustomMsg + DeserializeOwned + 'static,
151    QueryC: Debug + CustomQuery + DeserializeOwned + 'static,
152{
153    /// Creates builder with default components designed to work with custom exec and query
154    /// messages.
155    pub fn new_custom() -> Self {
156        AppBuilder {
157            api: MockApi::default(),
158            block: mock_env().block,
159            storage: MockStorage::new(),
160            bank: BankKeeper::new(),
161            wasm: WasmKeeper::new(),
162            custom: FailingModule::new(),
163            staking: StakeKeeper::new(),
164            distribution: DistributionKeeper::new(),
165            ibc: IbcFailingModule::new(),
166            gov: GovFailingModule::new(),
167            stargate: StargateFailing,
168        }
169    }
170}
171
172impl<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT, StargateT>
173    AppBuilder<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT, StargateT>
174where
175    CustomT: Module,
176    WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
177{
178    /// Overwrites the default wasm executor.
179    ///
180    /// At this point it is needed that new wasm implements some `Wasm` trait, but it doesn't need
181    /// to be bound to Bank or Custom yet - as those may change. The cross-components validation is
182    /// done on final building.
183    pub fn with_wasm<NewWasm: Wasm<CustomT::ExecT, CustomT::QueryT>>(
184        self,
185        wasm: NewWasm,
186    ) -> AppBuilder<BankT, ApiT, StorageT, CustomT, NewWasm, StakingT, DistrT, IbcT, GovT, StargateT>
187    {
188        let AppBuilder {
189            bank,
190            api,
191            storage,
192            custom,
193            block,
194            staking,
195            distribution,
196            ibc,
197            gov,
198            stargate,
199            ..
200        } = self;
201
202        AppBuilder {
203            api,
204            block,
205            storage,
206            bank,
207            wasm,
208            custom,
209            staking,
210            distribution,
211            ibc,
212            gov,
213            stargate,
214        }
215    }
216
217    /// Overwrites the default bank interface.
218    pub fn with_bank<NewBank: Bank>(
219        self,
220        bank: NewBank,
221    ) -> AppBuilder<NewBank, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT, StargateT>
222    {
223        let AppBuilder {
224            wasm,
225            api,
226            storage,
227            custom,
228            block,
229            staking,
230            distribution,
231            ibc,
232            gov,
233            stargate,
234            ..
235        } = self;
236
237        AppBuilder {
238            api,
239            block,
240            storage,
241            bank,
242            wasm,
243            custom,
244            staking,
245            distribution,
246            ibc,
247            gov,
248            stargate,
249        }
250    }
251
252    /// Overwrites the default api interface.
253    pub fn with_api<NewApi: Api>(
254        self,
255        api: NewApi,
256    ) -> AppBuilder<BankT, NewApi, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT, StargateT>
257    {
258        let AppBuilder {
259            wasm,
260            bank,
261            storage,
262            custom,
263            block,
264            staking,
265            distribution,
266            ibc,
267            gov,
268            stargate,
269            ..
270        } = self;
271
272        AppBuilder {
273            api,
274            block,
275            storage,
276            bank,
277            wasm,
278            custom,
279            staking,
280            distribution,
281            ibc,
282            gov,
283            stargate,
284        }
285    }
286
287    /// Overwrites the default storage interface.
288    pub fn with_storage<NewStorage: Storage>(
289        self,
290        storage: NewStorage,
291    ) -> AppBuilder<BankT, ApiT, NewStorage, CustomT, WasmT, StakingT, DistrT, IbcT, GovT, StargateT>
292    {
293        let AppBuilder {
294            wasm,
295            api,
296            bank,
297            custom,
298            block,
299            staking,
300            distribution,
301            ibc,
302            gov,
303            stargate,
304            ..
305        } = self;
306
307        AppBuilder {
308            api,
309            block,
310            storage,
311            bank,
312            wasm,
313            custom,
314            staking,
315            distribution,
316            ibc,
317            gov,
318            stargate,
319        }
320    }
321
322    /// Overwrites the default handler for custom messages.
323    ///
324    /// At this point it is needed that new custom implements some `Module` trait, but it doesn't need
325    /// to be bound to ExecC or QueryC yet - as those may change. The cross-components validation is
326    /// done on final building.
327    pub fn with_custom<NewCustom: Module>(
328        self,
329        custom: NewCustom,
330    ) -> AppBuilder<BankT, ApiT, StorageT, NewCustom, WasmT, StakingT, DistrT, IbcT, GovT, StargateT>
331    {
332        let AppBuilder {
333            wasm,
334            bank,
335            api,
336            storage,
337            block,
338            staking,
339            distribution,
340            ibc,
341            gov,
342            stargate,
343            ..
344        } = self;
345
346        AppBuilder {
347            api,
348            block,
349            storage,
350            bank,
351            wasm,
352            custom,
353            staking,
354            distribution,
355            ibc,
356            gov,
357            stargate,
358        }
359    }
360
361    /// Overwrites the default staking interface.
362    pub fn with_staking<NewStaking: Staking>(
363        self,
364        staking: NewStaking,
365    ) -> AppBuilder<BankT, ApiT, StorageT, CustomT, WasmT, NewStaking, DistrT, IbcT, GovT, StargateT>
366    {
367        let AppBuilder {
368            wasm,
369            api,
370            storage,
371            custom,
372            block,
373            bank,
374            distribution,
375            ibc,
376            gov,
377            stargate,
378            ..
379        } = self;
380
381        AppBuilder {
382            api,
383            block,
384            storage,
385            bank,
386            wasm,
387            custom,
388            staking,
389            distribution,
390            ibc,
391            gov,
392            stargate,
393        }
394    }
395
396    /// Overwrites the default distribution interface.
397    pub fn with_distribution<NewDistribution: Distribution>(
398        self,
399        distribution: NewDistribution,
400    ) -> AppBuilder<
401        BankT,
402        ApiT,
403        StorageT,
404        CustomT,
405        WasmT,
406        StakingT,
407        NewDistribution,
408        IbcT,
409        GovT,
410        StargateT,
411    > {
412        let AppBuilder {
413            wasm,
414            api,
415            storage,
416            custom,
417            block,
418            staking,
419            bank,
420            ibc,
421            gov,
422            stargate,
423            ..
424        } = self;
425
426        AppBuilder {
427            api,
428            block,
429            storage,
430            bank,
431            wasm,
432            custom,
433            staking,
434            distribution,
435            ibc,
436            gov,
437            stargate,
438        }
439    }
440
441    /// Overwrites the default ibc interface.
442    ///
443    /// If you wish to simply ignore/drop all returned IBC Messages,
444    /// you can use the `IbcAcceptingModule` type:
445    /// ```text
446    /// builder.with_ibc(IbcAcceptingModule::new())
447    /// ```
448    pub fn with_ibc<NewIbc: Ibc>(
449        self,
450        ibc: NewIbc,
451    ) -> AppBuilder<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, NewIbc, GovT, StargateT>
452    {
453        let AppBuilder {
454            wasm,
455            api,
456            storage,
457            custom,
458            block,
459            staking,
460            bank,
461            distribution,
462            gov,
463            stargate,
464            ..
465        } = self;
466
467        AppBuilder {
468            api,
469            block,
470            storage,
471            bank,
472            wasm,
473            custom,
474            staking,
475            stargate,
476            distribution,
477            ibc,
478            gov,
479        }
480    }
481
482    /// Overwrites the default governance module.
483    ///
484    /// # Examples
485    ///
486    /// ```
487    /// use cw_multi_test::{no_init, AppBuilder, GovAcceptingModule};
488    ///
489    /// let app = AppBuilder::default()
490    ///     .with_gov(GovAcceptingModule::new())
491    ///     .build(no_init);
492    ///
493    /// // use the app with accepting governance module in your test
494    /// ```
495    pub fn with_gov<NewGov: Gov>(
496        self,
497        gov: NewGov,
498    ) -> AppBuilder<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, NewGov, StargateT>
499    {
500        let AppBuilder {
501            wasm,
502            api,
503            storage,
504            custom,
505            block,
506            staking,
507            bank,
508            distribution,
509            ibc,
510            stargate,
511            ..
512        } = self;
513
514        AppBuilder {
515            api,
516            block,
517            storage,
518            bank,
519            wasm,
520            custom,
521            staking,
522            distribution,
523            ibc,
524            gov,
525            stargate,
526        }
527    }
528
529    /// Overwrites the default stargate interface.
530    pub fn with_stargate<NewStargate: Stargate>(
531        self,
532        stargate: NewStargate,
533    ) -> AppBuilder<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT, NewStargate>
534    {
535        let AppBuilder {
536            wasm,
537            api,
538            storage,
539            custom,
540            block,
541            staking,
542            bank,
543            distribution,
544            ibc,
545            gov,
546            ..
547        } = self;
548
549        AppBuilder {
550            api,
551            block,
552            storage,
553            bank,
554            wasm,
555            custom,
556            staking,
557            distribution,
558            ibc,
559            gov,
560            stargate,
561        }
562    }
563
564    /// Overwrites the initial block.
565    pub fn with_block(mut self, block: BlockInfo) -> Self {
566        self.block = block;
567        self
568    }
569
570    /// Builds the final [App] with initialization.
571    ///
572    /// At this point all component types have to be properly related to each other.
573    pub fn build<F>(
574        self,
575        init_fn: F,
576    ) -> App<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT, StargateT>
577    where
578        BankT: Bank,
579        ApiT: Api,
580        StorageT: Storage,
581        CustomT: Module,
582        WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
583        StakingT: Staking,
584        DistrT: Distribution,
585        IbcT: Ibc,
586        GovT: Gov,
587        StargateT: Stargate,
588        F: FnOnce(
589            &mut Router<BankT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT, StargateT>,
590            &ApiT,
591            &mut dyn Storage,
592        ),
593    {
594        // build the final application
595        let mut app = App {
596            router: Router {
597                wasm: self.wasm,
598                bank: self.bank,
599                custom: self.custom,
600                staking: self.staking,
601                distribution: self.distribution,
602                ibc: self.ibc,
603                gov: self.gov,
604                stargate: self.stargate,
605            },
606            api: self.api,
607            block: self.block,
608            storage: self.storage,
609        };
610        // execute initialization provided by the caller
611        app.init_modules(init_fn);
612        // return already initialized application
613        app
614    }
615}