1
// Copyright 2019-2025 PureStake Inc.
2
// This file is part of Moonbeam.
3

            
4
// Moonbeam is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8

            
9
// Moonbeam is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13

            
14
// You should have received a copy of the GNU General Public License
15
// along with Moonbeam.  If not, see <http://www.gnu.org/licenses/>.
16

            
17
//! Unit testing
18

            
19
use crate::mock::{roll_to, ExtBuilder, MoonbeamOrbiters, RuntimeOrigin, System, Test};
20
use crate::{Error, Event};
21
use frame_support::{assert_noop, assert_ok};
22

            
23
#[test]
24
1
fn test_orbiter_rotation() {
25
1
	ExtBuilder::default()
26
1
		.with_balances(vec![(2, 20_000), (3, 20_000)])
27
1
		.with_min_orbiter_deposit(10_000)
28
1
		.build()
29
1
		.execute_with(|| {
30
1
			// Add a collator to the orbiter program
31
1
			assert_ok!(MoonbeamOrbiters::add_collator(RuntimeOrigin::root(), 1),);
32
			// Register two orbiters
33
1
			assert_ok!(MoonbeamOrbiters::orbiter_register(RuntimeOrigin::signed(2)),);
34
1
			assert_ok!(MoonbeamOrbiters::collator_add_orbiter(
35
1
				RuntimeOrigin::signed(1),
36
1
				2
37
1
			),);
38
1
			assert_ok!(MoonbeamOrbiters::orbiter_register(RuntimeOrigin::signed(3)),);
39
1
			assert_ok!(MoonbeamOrbiters::collator_add_orbiter(
40
1
				RuntimeOrigin::signed(1),
41
1
				3
42
1
			),);
43

            
44
			// Roll to second round
45
1
			roll_to(4);
46
1
			System::assert_last_event(
47
1
				Event::<Test>::OrbiterRotation {
48
1
					collator: 1,
49
1
					old_orbiter: None,
50
1
					new_orbiter: Some(2),
51
1
				}
52
1
				.into(),
53
1
			);
54
1

            
55
1
			// New orbiter should be active for rounds 2 and 3
56
1
			assert_eq!(crate::OrbiterPerRound::<Test>::get(2, 1), Some(2));
57
1
			assert_eq!(crate::OrbiterPerRound::<Test>::get(3, 1), Some(2));
58

            
59
			// Roll to fourth round
60
1
			roll_to(8);
61
1
			System::assert_last_event(
62
1
				Event::<Test>::OrbiterRotation {
63
1
					collator: 1,
64
1
					old_orbiter: Some(2),
65
1
					new_orbiter: Some(3),
66
1
				}
67
1
				.into(),
68
1
			);
69
1

            
70
1
			// New orbiter should be active for rounds 4 and 5
71
1
			assert_eq!(crate::OrbiterPerRound::<Test>::get(4, 1), Some(3));
72
1
			assert_eq!(crate::OrbiterPerRound::<Test>::get(5, 1), Some(3));
73

            
74
			// Roll to sixth round, we should come back to the first orbiter
75
1
			roll_to(12);
76
1
			System::assert_last_event(
77
1
				Event::<Test>::OrbiterRotation {
78
1
					collator: 1,
79
1
					old_orbiter: Some(3),
80
1
					new_orbiter: Some(2),
81
1
				}
82
1
				.into(),
83
1
			);
84
1
		});
85
1
}
86

            
87
#[test]
88
1
fn test_collator_add_orbiter() {
89
1
	ExtBuilder::default()
90
1
		.with_balances(vec![(2, 20_000), (3, 20_000), (4, 20_000)])
91
1
		.with_min_orbiter_deposit(10_000)
92
1
		.build()
93
1
		.execute_with(|| {
94
1
			// Add a collator to the orbiter program
95
1
			assert_ok!(MoonbeamOrbiters::add_collator(RuntimeOrigin::root(), 1),);
96
			// Register some orbiters
97
1
			assert_ok!(MoonbeamOrbiters::orbiter_register(RuntimeOrigin::signed(2)),);
98
1
			assert_ok!(MoonbeamOrbiters::orbiter_register(RuntimeOrigin::signed(3)),);
99
1
			assert_ok!(MoonbeamOrbiters::orbiter_register(RuntimeOrigin::signed(4)),);
100

            
101
			// Try to add an orbiter to a collator pool
102
			// Should fail because collator not exist
103
1
			assert_noop!(
104
1
				MoonbeamOrbiters::collator_add_orbiter(RuntimeOrigin::signed(99), 2),
105
1
				Error::<Test>::CollatorNotFound
106
1
			);
107

            
108
			// Try to add an orbiter to a collator pool
109
			// Should fail because orbiter not exist
110
1
			assert_noop!(
111
1
				MoonbeamOrbiters::collator_add_orbiter(RuntimeOrigin::signed(1), 99),
112
1
				Error::<Test>::OrbiterDepositNotFound
113
1
			);
114

            
115
			// Try to add an orbiter to a collator pool, should success
116
1
			assert_ok!(MoonbeamOrbiters::collator_add_orbiter(
117
1
				RuntimeOrigin::signed(1),
118
1
				2
119
1
			),);
120
1
			System::assert_last_event(
121
1
				Event::<Test>::OrbiterJoinCollatorPool {
122
1
					collator: 1,
123
1
					orbiter: 2,
124
1
				}
125
1
				.into(),
126
1
			);
127
1

            
128
1
			// Try to add the same orbiter again, should fail
129
1
			assert_noop!(
130
1
				MoonbeamOrbiters::collator_add_orbiter(RuntimeOrigin::signed(1), 2),
131
1
				Error::<Test>::OrbiterAlreadyInPool
132
1
			);
133

            
134
			// Try to add a second orbiter to the collator pool, should success
135
1
			assert_ok!(MoonbeamOrbiters::collator_add_orbiter(
136
1
				RuntimeOrigin::signed(1),
137
1
				3
138
1
			),);
139
1
			System::assert_last_event(
140
1
				Event::<Test>::OrbiterJoinCollatorPool {
141
1
					collator: 1,
142
1
					orbiter: 3,
143
1
				}
144
1
				.into(),
145
1
			);
146
1

            
147
1
			// Try to add a third orbiter to the collator pool, should fail
148
1
			assert_noop!(
149
1
				MoonbeamOrbiters::collator_add_orbiter(RuntimeOrigin::signed(1), 4),
150
1
				Error::<Test>::CollatorPoolTooLarge
151
1
			);
152
1
		});
153
1
}
154

            
155
#[test]
156
1
fn test_collator_remove_orbiter() {
157
1
	ExtBuilder::default()
158
1
		.with_balances(vec![(2, 20_000)])
159
1
		.with_min_orbiter_deposit(10_000)
160
1
		.build()
161
1
		.execute_with(|| {
162
1
			// Add a collator to the orbiter program
163
1
			assert_ok!(MoonbeamOrbiters::add_collator(RuntimeOrigin::root(), 1),);
164
			// Register an orbiter
165
1
			assert_ok!(MoonbeamOrbiters::orbiter_register(RuntimeOrigin::signed(2)),);
166
1
			assert_ok!(MoonbeamOrbiters::collator_add_orbiter(
167
1
				RuntimeOrigin::signed(1),
168
1
				2
169
1
			),);
170

            
171
			// Try to remove an orbiter to a collator pool
172
			// Should fail because collator not exist
173
1
			assert_noop!(
174
1
				MoonbeamOrbiters::collator_remove_orbiter(RuntimeOrigin::signed(99), 2),
175
1
				Error::<Test>::CollatorNotFound
176
1
			);
177

            
178
			// Try to remove an orbiter to a collator pool
179
			// Should fail because orbiter not exist
180
1
			assert_noop!(
181
1
				MoonbeamOrbiters::collator_remove_orbiter(RuntimeOrigin::signed(1), 99),
182
1
				Error::<Test>::OrbiterNotFound
183
1
			);
184

            
185
			// Try to remove an orbiter to a collator pool, should success
186
1
			assert_ok!(MoonbeamOrbiters::collator_remove_orbiter(
187
1
				RuntimeOrigin::signed(1),
188
1
				2
189
1
			),);
190
1
			System::assert_last_event(
191
1
				Event::<Test>::OrbiterLeaveCollatorPool {
192
1
					collator: 1,
193
1
					orbiter: 2,
194
1
				}
195
1
				.into(),
196
1
			);
197
1

            
198
1
			// Try to remove the same orbiter again, should fail
199
1
			assert_noop!(
200
1
				MoonbeamOrbiters::collator_remove_orbiter(RuntimeOrigin::signed(1), 2),
201
1
				Error::<Test>::OrbiterNotFound
202
1
			);
203
1
		});
204
1
}
205

            
206
#[test]
207
1
fn test_collator_remove_orbiter_then_add_orbiter() {
208
1
	ExtBuilder::default()
209
1
		.with_balances(vec![(2, 20_000), (3, 20_000)])
210
1
		.with_min_orbiter_deposit(10_000)
211
1
		.build()
212
1
		.execute_with(|| {
213
1
			// Add a collator to the orbiter program
214
1
			assert_ok!(MoonbeamOrbiters::add_collator(RuntimeOrigin::root(), 1),);
215
			// Register an orbiter
216
1
			assert_ok!(MoonbeamOrbiters::orbiter_register(RuntimeOrigin::signed(2)),);
217
1
			assert_ok!(MoonbeamOrbiters::collator_add_orbiter(
218
1
				RuntimeOrigin::signed(1),
219
1
				2
220
1
			),);
221

            
222
			// Try to remove an orbiter to a collator pool, should success
223
1
			assert_ok!(MoonbeamOrbiters::collator_remove_orbiter(
224
1
				RuntimeOrigin::signed(1),
225
1
				2
226
1
			),);
227
1
			System::assert_last_event(
228
1
				Event::<Test>::OrbiterLeaveCollatorPool {
229
1
					collator: 1,
230
1
					orbiter: 2,
231
1
				}
232
1
				.into(),
233
1
			);
234
1

            
235
1
			// Try to register another orbiter, should success
236
1
			assert_ok!(MoonbeamOrbiters::orbiter_register(RuntimeOrigin::signed(3)),);
237
1
			assert_ok!(MoonbeamOrbiters::collator_add_orbiter(
238
1
				RuntimeOrigin::signed(1),
239
1
				3
240
1
			),);
241
1
			System::assert_last_event(
242
1
				Event::<Test>::OrbiterJoinCollatorPool {
243
1
					collator: 1,
244
1
					orbiter: 3,
245
1
				}
246
1
				.into(),
247
1
			);
248
1
		});
249
1
}
250

            
251
#[test]
252
1
fn test_orbiter_register_fail_if_insufficient_balance() {
253
1
	ExtBuilder::default()
254
1
		.with_min_orbiter_deposit(10_000)
255
1
		.build()
256
1
		.execute_with(|| {
257
1
			assert_noop!(
258
1
				MoonbeamOrbiters::orbiter_register(RuntimeOrigin::signed(1)),
259
1
				pallet_balances::Error::<Test>::InsufficientBalance
260
1
			);
261
1
		});
262
1
}
263

            
264
#[test]
265
1
fn test_orbiter_register_ok() {
266
1
	ExtBuilder::default()
267
1
		.with_balances(vec![(1, 20_000)])
268
1
		.with_min_orbiter_deposit(10_000)
269
1
		.build()
270
1
		.execute_with(|| {
271
1
			assert!(MoonbeamOrbiters::orbiter(1).is_none());
272
1
			assert_ok!(MoonbeamOrbiters::orbiter_register(RuntimeOrigin::signed(1)),);
273
1
			assert!(MoonbeamOrbiters::orbiter(1).is_some());
274
1
			System::assert_has_event(
275
1
				pallet_balances::Event::<Test>::Reserved {
276
1
					who: 1,
277
1
					amount: 10_000,
278
1
				}
279
1
				.into(),
280
1
			);
281
1
			System::assert_last_event(
282
1
				Event::<Test>::OrbiterRegistered {
283
1
					account: 1,
284
1
					deposit: 10_000,
285
1
				}
286
1
				.into(),
287
1
			);
288
1
		});
289
1
}
290

            
291
#[test]
292
1
fn test_add_collator() {
293
1
	ExtBuilder::default().build().execute_with(|| {
294
1
		assert_ok!(MoonbeamOrbiters::add_collator(RuntimeOrigin::root(), 1),);
295
1
		assert_noop!(
296
1
			MoonbeamOrbiters::add_collator(RuntimeOrigin::root(), 1),
297
1
			Error::<Test>::CollatorAlreadyAdded
298
1
		);
299
1
	});
300
1
}
301

            
302
#[test]
303
1
fn test_orbiter_unregister() {
304
1
	ExtBuilder::default()
305
1
		.with_balances(vec![(2, 20_000)])
306
1
		.with_min_orbiter_deposit(10_000)
307
1
		.build()
308
1
		.execute_with(|| {
309
1
			// Add a collator
310
1
			assert_ok!(MoonbeamOrbiters::add_collator(RuntimeOrigin::root(), 1),);
311
			// Register an orbiter
312
1
			assert_ok!(MoonbeamOrbiters::orbiter_register(RuntimeOrigin::signed(2)),);
313

            
314
			// Try to unregister an orbiter with wrong hint
315
			// Should fail because there is 1 collator pool and we provide 0
316
1
			assert_noop!(
317
1
				MoonbeamOrbiters::orbiter_unregister(RuntimeOrigin::signed(2), 0),
318
1
				Error::<Test>::CollatorsPoolCountTooLow
319
1
			);
320

            
321
			// Try to unregister an orbiter with right hint, should success
322
1
			assert!(MoonbeamOrbiters::orbiter(2).is_some());
323
1
			assert_ok!(MoonbeamOrbiters::orbiter_unregister(
324
1
				RuntimeOrigin::signed(2),
325
1
				1
326
1
			),);
327
1
			assert!(MoonbeamOrbiters::orbiter(2).is_none());
328
1
			System::assert_has_event(
329
1
				pallet_balances::Event::<Test>::Unreserved {
330
1
					who: 2,
331
1
					amount: 10_000,
332
1
				}
333
1
				.into(),
334
1
			);
335
1
			System::assert_last_event(Event::<Test>::OrbiterUnregistered { account: 2 }.into());
336
1
		});
337
1
}