1
// Copyright (C) Moondance Labs Ltd.
2
// This file is part of Tanssi.
3

            
4
// Tanssi 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
// Tanssi 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 Tanssi.  If not, see <http://www.gnu.org/licenses/>
16

            
17
use crate::{
18
    assignment::{Assignment, ChainNumCollators},
19
    tests::Test,
20
};
21

            
22
#[test]
23
1
fn select_chains_not_enough_to_reach_min_container() {
24
1
    // 10 collators when the orchestrator needs 2 and the containers need 10 result in no containers having collators
25
1
    let container_chains = vec![
26
1
        ChainNumCollators {
27
1
            para_id: 1000.into(),
28
1
            min_collators: 2,
29
1
            max_collators: 5,
30
1
            parathread: false,
31
1
        },
32
1
        ChainNumCollators {
33
1
            para_id: 2000.into(),
34
1
            min_collators: 10,
35
1
            max_collators: 10,
36
1
            parathread: false,
37
1
        },
38
1
        ChainNumCollators {
39
1
            para_id: 2001.into(),
40
1
            min_collators: 10,
41
1
            max_collators: 10,
42
1
            parathread: false,
43
1
        },
44
1
    ];
45
1
    let new_assigned = Assignment::<Test>::select_chains_with_collators(10, &container_chains);
46
1
    assert_eq!(new_assigned, vec![(1000.into(), 5),]);
47
1
}
48

            
49
#[test]
50
1
fn select_chains_not_enough_to_reach_min_orchestrator() {
51
1
    // 1 collator when the orchestrator needs 2 results in 1 collators being assigned to orchestrator
52
1
    let container_chains = vec![ChainNumCollators {
53
1
        para_id: 1000.into(),
54
1
        min_collators: 2,
55
1
        max_collators: 5,
56
1
        parathread: false,
57
1
    }];
58
1
    let new_assigned = Assignment::<Test>::select_chains_with_collators(1, &container_chains);
59
1
    assert_eq!(new_assigned, vec![(1000.into(), 1),]);
60
1
}
61

            
62
#[test]
63
1
fn select_chains_not_enough_for_all_min() {
64
1
    // Need 6 collators to support 3 chains, only have 5. The last chain will be removed and the remaining collator
65
1
    // will be assigned to orchestrator.
66
1
    let container_chains = vec![
67
1
        ChainNumCollators {
68
1
            para_id: 1000.into(),
69
1
            min_collators: 2,
70
1
            max_collators: 5,
71
1
            parathread: false,
72
1
        },
73
1
        ChainNumCollators {
74
1
            para_id: 2000.into(),
75
1
            min_collators: 2,
76
1
            max_collators: 2,
77
1
            parathread: false,
78
1
        },
79
1
        ChainNumCollators {
80
1
            para_id: 2001.into(),
81
1
            min_collators: 2,
82
1
            max_collators: 2,
83
1
            parathread: false,
84
1
        },
85
1
    ];
86
1
    let new_assigned = Assignment::<Test>::select_chains_with_collators(5, &container_chains);
87
1
    assert_eq!(new_assigned, vec![(1000.into(), 3), (2000.into(), 2),]);
88
1
}
89

            
90
#[test]
91
1
fn select_chains_not_enough_for_all_max() {
92
1
    // Need 6 collators to support 3 chains at min, but 15 collators to support them at max.
93
1
    // The last chain will be removed and the remaining collator
94
1
    let container_chains = vec![
95
1
        ChainNumCollators {
96
1
            para_id: 1000.into(),
97
1
            min_collators: 2,
98
1
            max_collators: 5,
99
1
            parathread: false,
100
1
        },
101
1
        ChainNumCollators {
102
1
            para_id: 2000.into(),
103
1
            min_collators: 2,
104
1
            max_collators: 5,
105
1
            parathread: false,
106
1
        },
107
1
        ChainNumCollators {
108
1
            para_id: 2001.into(),
109
1
            min_collators: 2,
110
1
            max_collators: 5,
111
1
            parathread: false,
112
1
        },
113
1
    ];
114
1
    let new_assigned = Assignment::<Test>::select_chains_with_collators(7, &container_chains);
115
1
    assert_eq!(
116
1
        new_assigned,
117
1
        vec![(1000.into(), 3), (2000.into(), 2), (2001.into(), 2),]
118
1
    );
119
1
    let new_assigned = Assignment::<Test>::select_chains_with_collators(10, &container_chains);
120
1
    assert_eq!(
121
1
        new_assigned,
122
1
        vec![(1000.into(), 5), (2000.into(), 3), (2001.into(), 2),]
123
1
    );
124
1
    let new_assigned = Assignment::<Test>::select_chains_with_collators(13, &container_chains);
125
1
    assert_eq!(
126
1
        new_assigned,
127
1
        vec![(1000.into(), 5), (2000.into(), 5), (2001.into(), 3),]
128
1
    );
129
1
    let new_assigned = Assignment::<Test>::select_chains_with_collators(15, &container_chains);
130
1
    assert_eq!(
131
1
        new_assigned,
132
1
        vec![(1000.into(), 5), (2000.into(), 5), (2001.into(), 5),]
133
1
    );
134
1
}
135

            
136
#[test]
137
1
fn select_chains_more_than_max() {
138
1
    // When the number of collators is greater than the sum of the max, all the chains are assigned max collators
139
1
    let container_chains = vec![
140
1
        ChainNumCollators {
141
1
            para_id: 1000.into(),
142
1
            min_collators: 2,
143
1
            max_collators: 5,
144
1
            parathread: false,
145
1
        },
146
1
        ChainNumCollators {
147
1
            para_id: 2000.into(),
148
1
            min_collators: 2,
149
1
            max_collators: 5,
150
1
            parathread: false,
151
1
        },
152
1
        ChainNumCollators {
153
1
            para_id: 2001.into(),
154
1
            min_collators: 2,
155
1
            max_collators: 5,
156
1
            parathread: false,
157
1
        },
158
1
    ];
159
1
    let new_assigned = Assignment::<Test>::select_chains_with_collators(20, &container_chains);
160
1
    assert_eq!(
161
1
        new_assigned,
162
1
        vec![(1000.into(), 5), (2000.into(), 5), (2001.into(), 5),]
163
1
    );
164
1
}
165

            
166
#[test]
167
1
fn select_chains_not_enough_to_reach_min_container_but_enough_for_parathread() {
168
1
    // Chain 2000 has more priority than parathread 3000, but we do not have enough min collators so the container
169
1
    // chain gets 0 collator and the parathread gets 1
170
1
    let container_chains = vec![
171
1
        ChainNumCollators {
172
1
            para_id: 1000.into(),
173
1
            min_collators: 2,
174
1
            max_collators: 5,
175
1
            parathread: false,
176
1
        },
177
1
        ChainNumCollators {
178
1
            para_id: 2000.into(),
179
1
            min_collators: 2,
180
1
            max_collators: 2,
181
1
            parathread: false,
182
1
        },
183
1
        ChainNumCollators {
184
1
            para_id: 3000.into(),
185
1
            min_collators: 1,
186
1
            max_collators: 1,
187
1
            parathread: true,
188
1
        },
189
1
    ];
190
1
    let new_assigned = Assignment::<Test>::select_chains_with_collators(3, &container_chains);
191
1
    assert_eq!(new_assigned, vec![(1000.into(), 2), (3000.into(), 1)]);
192
1
}
193

            
194
#[test]
195
1
fn select_chains_solochain() {
196
1
    // In solochain mode, orchestrator chain has 0 collators. This shouldn't cause any panics.
197
1
    let container_chains = vec![
198
1
        ChainNumCollators {
199
1
            para_id: 1000.into(),
200
1
            min_collators: 0,
201
1
            max_collators: 0,
202
1
            parathread: false,
203
1
        },
204
1
        ChainNumCollators {
205
1
            para_id: 2000.into(),
206
1
            min_collators: 2,
207
1
            max_collators: 5,
208
1
            parathread: false,
209
1
        },
210
1
        ChainNumCollators {
211
1
            para_id: 2001.into(),
212
1
            min_collators: 2,
213
1
            max_collators: 5,
214
1
            parathread: false,
215
1
        },
216
1
    ];
217
1
    let new_assigned = Assignment::<Test>::select_chains_with_collators(5, &container_chains);
218
1
    assert_eq!(
219
1
        new_assigned,
220
1
        vec![(1000.into(), 0), (2000.into(), 3), (2001.into(), 2)]
221
1
    );
222
1
}
223

            
224
#[test]
225
1
fn select_chains_solochain_zero_collators() {
226
1
    // In solochain mode, there can be 0 collators. This shouldn't cause any panics.
227
1
    let container_chains = vec![ChainNumCollators {
228
1
        para_id: 1000.into(),
229
1
        min_collators: 0,
230
1
        max_collators: 0,
231
1
        parathread: false,
232
1
    }];
233
1
    let new_assigned = Assignment::<Test>::select_chains_with_collators(0, &container_chains);
234
1
    assert_eq!(new_assigned, vec![(1000.into(), 0)]);
235
1
}