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
        },
31
1
        ChainNumCollators {
32
1
            para_id: 2000.into(),
33
1
            min_collators: 10,
34
1
            max_collators: 10,
35
1
        },
36
1
        ChainNumCollators {
37
1
            para_id: 2001.into(),
38
1
            min_collators: 10,
39
1
            max_collators: 10,
40
1
        },
41
1
    ];
42
1
    let new_assigned = Assignment::<Test>::select_chains_with_collators(10, &container_chains);
43
1
    assert_eq!(new_assigned, vec![(1000.into(), 5),]);
44
1
}
45

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

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

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

            
126
#[test]
127
1
fn select_chains_more_than_max() {
128
1
    // When the number of collators is greater than the sum of the max, all the chains are assigned max collators
129
1
    let container_chains = vec![
130
1
        ChainNumCollators {
131
1
            para_id: 1000.into(),
132
1
            min_collators: 2,
133
1
            max_collators: 5,
134
1
        },
135
1
        ChainNumCollators {
136
1
            para_id: 2000.into(),
137
1
            min_collators: 2,
138
1
            max_collators: 5,
139
1
        },
140
1
        ChainNumCollators {
141
1
            para_id: 2001.into(),
142
1
            min_collators: 2,
143
1
            max_collators: 5,
144
1
        },
145
1
    ];
146
1
    let new_assigned = Assignment::<Test>::select_chains_with_collators(20, &container_chains);
147
1
    assert_eq!(
148
1
        new_assigned,
149
1
        vec![(1000.into(), 5), (2000.into(), 5), (2001.into(), 5),]
150
1
    );
151
1
}
152

            
153
#[test]
154
1
fn select_chains_not_enough_to_reach_min_container_but_enough_for_parathread() {
155
1
    // Chain 2000 has more priority than parathread 3000, but we do not have enough min collators so the container
156
1
    // chain gets 0 collator and the parathread gets 1
157
1
    let container_chains = vec![
158
1
        ChainNumCollators {
159
1
            para_id: 1000.into(),
160
1
            min_collators: 2,
161
1
            max_collators: 5,
162
1
        },
163
1
        ChainNumCollators {
164
1
            para_id: 2000.into(),
165
1
            min_collators: 2,
166
1
            max_collators: 2,
167
1
        },
168
1
        ChainNumCollators {
169
1
            para_id: 3000.into(),
170
1
            min_collators: 1,
171
1
            max_collators: 1,
172
1
        },
173
1
    ];
174
1
    let new_assigned = Assignment::<Test>::select_chains_with_collators(3, &container_chains);
175
1
    assert_eq!(new_assigned, vec![(1000.into(), 2), (3000.into(), 1)]);
176
1
}
177

            
178
#[test]
179
1
fn select_chains_solochain() {
180
1
    // In solochain mode, orchestrator chain has 0 collators. This shouldn't cause any panics.
181
1
    let container_chains = vec![
182
1
        ChainNumCollators {
183
1
            para_id: 1000.into(),
184
1
            min_collators: 0,
185
1
            max_collators: 0,
186
1
        },
187
1
        ChainNumCollators {
188
1
            para_id: 2000.into(),
189
1
            min_collators: 2,
190
1
            max_collators: 5,
191
1
        },
192
1
        ChainNumCollators {
193
1
            para_id: 2001.into(),
194
1
            min_collators: 2,
195
1
            max_collators: 5,
196
1
        },
197
1
    ];
198
1
    let new_assigned = Assignment::<Test>::select_chains_with_collators(5, &container_chains);
199
1
    assert_eq!(
200
1
        new_assigned,
201
1
        vec![(1000.into(), 0), (2000.into(), 3), (2001.into(), 2)]
202
1
    );
203
1
}
204

            
205
#[test]
206
1
fn select_chains_solochain_zero_collators() {
207
1
    // In solochain mode, there can be 0 collators. This shouldn't cause any panics.
208
1
    let container_chains = vec![ChainNumCollators {
209
1
        para_id: 1000.into(),
210
1
        min_collators: 0,
211
1
        max_collators: 0,
212
1
    }];
213
1
    let new_assigned = Assignment::<Test>::select_chains_with_collators(0, &container_chains);
214
1
    assert_eq!(new_assigned, vec![(1000.into(), 0)]);
215
1
}