Passed
Pull Request — master (#78)
by
unknown
05:53
created

build.tests.unit.test_models.TestDeployer.setUp()   B

Complexity

Conditions 1

Size

Total Lines 116
Code Lines 84

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 84
nop 1
dl 0
loc 116
ccs 22
cts 22
cp 1
crap 1
rs 7.5236
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
"""Tests for the models module."""
2
3 1
from unittest import TestCase
4 1
from unittest.mock import patch, MagicMock, call
5
6 1
from collections import Counter
7
8 1
from apscheduler.jobstores.base import JobLookupError
9 1
from apscheduler.triggers.date import DateTrigger
10 1
from datetime import datetime, timedelta
11 1
import pytz
12 1
from kytos.lib.helpers import get_controller_mock
13 1
from napps.kytos.maintenance.models import MaintenanceDeployer
14 1
from napps.kytos.maintenance.models import MaintenanceWindow as MW, Status, Scheduler
15 1
from napps.kytos.maintenance.models import MaintenanceStart, MaintenanceEnd
16 1
TIME_FMT = "%Y-%m-%dT%H:%M:%S%z"
17
18
19 1
class TestMW(TestCase):
20
    """Test of the MaintenanceWindow class."""
21
22
    # pylint: disable=protected-access
23
24 1
    def setUp(self):
25
        """Initialize before tests are executed."""
26 1
        self.controller = get_controller_mock()
27 1
        self.start = datetime.now(pytz.utc)
28 1
        self.start += timedelta(days=1)
29 1
        self.end = self.start + timedelta(hours=6)
30 1
        self.switches = [
31
            "01:23:45:67:89:ab:cd:ef"
32
        ]
33 1
        self.maintenance = MW(
34
            start=self.start,
35
            end=self.end,
36
            switches=self.switches
37
        )
38
39 1
    def test_as_dict(self):
40
        """Test as_dict method."""
41 1
        mw_dict = self.maintenance.dict()
42 1
        expected_dict = {
43
            'description': '',
44
            'start': self.start,
45
            'end': self.end,
46
            'id': self.maintenance.id,
47
            'switches': self.switches,
48
            'interfaces': [],
49
            'links': [],
50
            'status': Status.PENDING,
51
            'inserted_at': None,
52
            'updated_at': None,
53
        }
54 1
        self.assertEqual(mw_dict, expected_dict)
55
56 1
    def test_start_in_past(self):
57 1
        start = datetime.now(pytz.utc) - timedelta(days=1)
58
59 1
        self.assertRaises(ValueError, MW,
60
            start=start,
61
            end=self.end,
62
            switches=self.switches,
63
        )
64
65 1
    def test_end_before_start(self):
66 1
        end = datetime.now(pytz.utc) - timedelta(days=1)
67
68 1
        self.assertRaises(ValueError, MW,
69
            start=self.start,
70
            end=end,
71
            switches=self.switches,
72
        )
73
74 1
    def test_items_empty(self):
75
76 1
        self.assertRaises(ValueError, MW,
77
            start=self.start,
78
            end=self.end,
79
        )
80
81 1
class TestDeployer(TestCase):
82
    """Test of the MaintenanceDeployer class."""
83 1
    def setUp(self):
84 1
        self.controller = get_controller_mock()
85 1
        self.start = datetime.now(pytz.utc)
86 1
        self.start += timedelta(days=1)
87 1
        self.end = self.start + timedelta(hours=6)
88 1
        self.switches = [
89
            "01:23:45:67:89:ab:cd:ef"
90
        ]
91 1
        self.maintenance = MW(
92
            start=self.start,
93
            end=self.end,
94
            switches=self.switches
95
        )
96
97 1
        self.deployer = MaintenanceDeployer(self.controller, Counter(), Counter(), Counter())
98
        # Initialize Switches
99 1
        self.controller.switches = {
100
            '01:23:45:67:89:ab:cd:ef': MagicMock(
101
                id='01:23:45:67:89:ab:cd:ef',
102
                interfaces = {},
103
            ),
104
            '01:23:45:67:65:ab:cd:ef': MagicMock(
105
                id='01:23:45:67:65:ab:cd:ef',
106
                interfaces = {},
107
            ),
108
            '01:23:45:67:66:ab:cd:ef': MagicMock(
109
                id='01:23:45:67:66:ab:cd:ef',
110
                interfaces = {},
111
            ),
112
        }
113
        # Initialize Interfaces
114 1
        self.controller.switches['01:23:45:67:89:ab:cd:ef'].interfaces = {
115
            0: MagicMock(
116
                id = '01:23:45:67:89:ab:cd:ef:0',
117
                switch = self.controller.switches['01:23:45:67:89:ab:cd:ef'],
118
                link = None,
119
            ),
120
            1: MagicMock(
121
                id = '01:23:45:67:89:ab:cd:ef:1',
122
                switch = self.controller.switches['01:23:45:67:89:ab:cd:ef'],
123
                link = None,
124
            ),
125
            2: MagicMock(
126
                id = '01:23:45:67:89:ab:cd:ef:2',
127
                switch = self.controller.switches['01:23:45:67:89:ab:cd:ef'],
128
                link = None,
129
            ),
130
        }
131
132 1
        self.controller.switches['01:23:45:67:65:ab:cd:ef'].interfaces = {
133
            0: MagicMock(
134
                id = '01:23:45:67:65:ab:cd:ef:0',
135
                switch = self.controller.switches['01:23:45:67:65:ab:cd:ef'],
136
                link = None,
137
            ),
138
            1: MagicMock(
139
                id = '01:23:45:67:65:ab:cd:ef:1',
140
                switch = self.controller.switches['01:23:45:67:65:ab:cd:ef'],
141
                link = None,
142
            ),
143
            2: MagicMock(
144
                id = '01:23:45:67:65:ab:cd:ef:2',
145
                switch = self.controller.switches['01:23:45:67:65:ab:cd:ef'],
146
                link = None,
147
            ),
148
        }
149
150 1
        self.controller.switches['01:23:45:67:66:ab:cd:ef'].interfaces = {
151
            0: MagicMock(
152
                id = '01:23:45:67:66:ab:cd:ef:0',
153
                switch = self.controller.switches['01:23:45:67:66:ab:cd:ef'],
154
                link = None,
155
            ),
156
            1: MagicMock(
157
                id = '01:23:45:67:66:ab:cd:ef:1',
158
                switch = self.controller.switches['01:23:45:67:66:ab:cd:ef'],
159
                link = None,
160
            ),
161
            2: MagicMock(
162
                id = '01:23:45:67:66:ab:cd:ef:2',
163
                switch = self.controller.switches['01:23:45:67:66:ab:cd:ef'],
164
                link = None,
165
            ),
166
        }
167
168
        # Initialize Links
169 1
        self.link_1 = MagicMock(
170
            id = 'link_1',
171
            endpoint_a = self.controller.switches['01:23:45:67:89:ab:cd:ef'].interfaces[0],
172
            endpoint_b = self.controller.switches['01:23:45:67:65:ab:cd:ef'].interfaces[0],
173
        )
174 1
        self.controller.switches['01:23:45:67:89:ab:cd:ef'].interfaces[0].link = self.link_1
175 1
        self.controller.switches['01:23:45:67:65:ab:cd:ef'].interfaces[0].link = self.link_1
176
177 1
        self.link_2 = MagicMock(
178
            id = 'link_2',
179
            endpoint_a = self.controller.switches['01:23:45:67:89:ab:cd:ef'].interfaces[1],
180
            endpoint_b = self.controller.switches['01:23:45:67:66:ab:cd:ef'].interfaces[0],
181
        )
182 1
        self.controller.switches['01:23:45:67:89:ab:cd:ef'].interfaces[1].link = self.link_2
183 1
        self.controller.switches['01:23:45:67:66:ab:cd:ef'].interfaces[0].link = self.link_2
184
185 1
        self.link_3 = MagicMock(
186
            id = 'link_3',
187
            endpoint_a = self.controller.switches['01:23:45:67:66:ab:cd:ef'].interfaces[1],
188
            endpoint_b = self.controller.switches['01:23:45:67:66:ab:cd:ef'].interfaces[2],
189
        )
190 1
        self.controller.switches['01:23:45:67:66:ab:cd:ef'].interfaces[1].link = self.link_3
191 1
        self.controller.switches['01:23:45:67:66:ab:cd:ef'].interfaces[2].link = self.link_3
192
193
194 1
        self.controller.napps[('kytos', 'topology')] = MagicMock(
195
            links = {
196
                'link_1': self.link_1,
197
                'link_2': self.link_2,
198
                'link_3': self.link_3,
199
            }
200
        )
201
202 1
    def test_mw_case_1(self):
203
        """Test deploying a maintenance window to switches."""
204 1
        buffer_put_mock = MagicMock()
205 1
        self.controller.buffers.app.put = buffer_put_mock
206 1
        maintenance = self.maintenance.copy(
207
            update = {
208
                'switches': [
209
                    '01:23:45:67:89:ab:cd:ef',
210
                    '01:23:45:67:65:ab:cd:ef'
211
                ],
212
                'interfaces': [],
213
                'links': [],
214
            }
215
        )
216 1
        self.deployer.start_mw(maintenance)
217 1
        args, kwargs = buffer_put_mock.call_args
218 1
        event = args[0]
219 1
        assert event.name == 'kytos/topology.interruption.start'
220 1
        assert event.content['type'] == 'maintenance'
221 1
        assert sorted(event.content['switches']) == [
222
            '01:23:45:67:65:ab:cd:ef',
223
            '01:23:45:67:89:ab:cd:ef',
224
        ]
225 1
        assert sorted(event.content['interfaces']) == [
226
            '01:23:45:67:65:ab:cd:ef:0',
227
            '01:23:45:67:65:ab:cd:ef:1',
228
            '01:23:45:67:65:ab:cd:ef:2',
229
            '01:23:45:67:89:ab:cd:ef:0',
230
            '01:23:45:67:89:ab:cd:ef:1',
231
            '01:23:45:67:89:ab:cd:ef:2',
232
        ]
233 1
        assert sorted(event.content['links']) == [
234
            'link_1',
235
            'link_2',
236
        ]
237
238
        # Check whats in maintenance
239
        # Switches
240 1
        assert not self.deployer.switch_not_in_maintenance(self.controller.switches['01:23:45:67:89:ab:cd:ef'])
241 1
        assert not self.deployer.switch_not_in_maintenance(self.controller.switches['01:23:45:67:65:ab:cd:ef'])
242 1
        assert     self.deployer.switch_not_in_maintenance(self.controller.switches['01:23:45:67:66:ab:cd:ef'])
243
        # Interfaces
244 1
        for interface in self.controller.switches['01:23:45:67:89:ab:cd:ef'].interfaces.values():
245 1
            assert not self.deployer.interface_not_in_maintenance(interface)
246 1
        for interface in self.controller.switches['01:23:45:67:65:ab:cd:ef'].interfaces.values():
247 1
            assert not self.deployer.interface_not_in_maintenance(interface)
248 1
        for interface in self.controller.switches['01:23:45:67:66:ab:cd:ef'].interfaces.values():
249 1
            assert     self.deployer.interface_not_in_maintenance(interface)
250
        # Links
251 1
        assert not self.deployer.link_not_in_maintenance(self.link_1)
252 1
        assert not self.deployer.link_not_in_maintenance(self.link_2)
253 1
        assert     self.deployer.link_not_in_maintenance(self.link_3)
254
255 1
        self.deployer.end_mw(maintenance)
256 1
        args, kwargs = buffer_put_mock.call_args
257 1
        event = args[0]
258 1
        assert event.name == 'kytos/topology.interruption.end'
259 1
        assert event.content['type'] == 'maintenance'
260 1
        assert sorted(event.content['switches']) == [
261
            '01:23:45:67:65:ab:cd:ef',
262
            '01:23:45:67:89:ab:cd:ef',
263
        ]
264 1
        assert sorted(event.content['interfaces']) == [
265
            '01:23:45:67:65:ab:cd:ef:0',
266
            '01:23:45:67:65:ab:cd:ef:1',
267
            '01:23:45:67:65:ab:cd:ef:2',
268
            '01:23:45:67:89:ab:cd:ef:0',
269
            '01:23:45:67:89:ab:cd:ef:1',
270
            '01:23:45:67:89:ab:cd:ef:2',
271
        ]
272 1
        assert sorted(event.content['links']) == [
273
            'link_1',
274
            'link_2',
275
        ]
276
        # Check whats in maintenance
277
        # Switches
278 1
        assert     self.deployer.switch_not_in_maintenance(self.controller.switches['01:23:45:67:89:ab:cd:ef'])
279 1
        assert     self.deployer.switch_not_in_maintenance(self.controller.switches['01:23:45:67:65:ab:cd:ef'])
280 1
        assert     self.deployer.switch_not_in_maintenance(self.controller.switches['01:23:45:67:66:ab:cd:ef'])
281
        # Interfaces
282 1
        for interface in self.controller.switches['01:23:45:67:89:ab:cd:ef'].interfaces.values():
283 1
            assert     self.deployer.interface_not_in_maintenance(interface)
284 1
        for interface in self.controller.switches['01:23:45:67:65:ab:cd:ef'].interfaces.values():
285 1
            assert     self.deployer.interface_not_in_maintenance(interface)
286 1
        for interface in self.controller.switches['01:23:45:67:66:ab:cd:ef'].interfaces.values():
287 1
            assert     self.deployer.interface_not_in_maintenance(interface)
288
        # Links
289 1
        assert     self.deployer.link_not_in_maintenance(self.link_1)
290 1
        assert     self.deployer.link_not_in_maintenance(self.link_2)
291 1
        assert     self.deployer.link_not_in_maintenance(self.link_3)
292
293 1
    def test_mw_case_2(self):
294
        """Test deploying a maintenance window to interfaces."""
295 1
        buffer_put_mock = MagicMock()
296 1
        self.controller.buffers.app.put = buffer_put_mock
297
        
298 1
        maintenance = self.maintenance.copy(
299
            update = {
300
                'switches': [],
301
                'interfaces': [
302
                    '01:23:45:67:65:ab:cd:ef:0',
303
                    '01:23:45:67:89:ab:cd:ef:0',
304
                    '01:23:45:67:89:ab:cd:ef:1',
305
                ],
306
                'links': [],
307
            }
308
        )
309 1
        self.deployer.start_mw(maintenance)
310 1
        args, kwargs = buffer_put_mock.call_args
311 1
        event = args[0]
312 1
        assert event.name == 'kytos/topology.interruption.start'
313 1
        assert event.content['type'] == 'maintenance'
314 1
        assert sorted(event.content['switches']) == []
315 1
        assert sorted(event.content['interfaces']) == [
316
            '01:23:45:67:65:ab:cd:ef:0',
317
            '01:23:45:67:89:ab:cd:ef:0',
318
            '01:23:45:67:89:ab:cd:ef:1',
319
        ]
320 1
        assert sorted(event.content['links']) == [
321
            'link_1',
322
            'link_2',
323
        ]
324
325
        # Check whats in maintenance
326
        # Switches
327 1
        assert     self.deployer.switch_not_in_maintenance(self.controller.switches['01:23:45:67:89:ab:cd:ef'])
328 1
        assert     self.deployer.switch_not_in_maintenance(self.controller.switches['01:23:45:67:65:ab:cd:ef'])
329 1
        assert     self.deployer.switch_not_in_maintenance(self.controller.switches['01:23:45:67:66:ab:cd:ef'])
330
        # Interfaces
331
332 1
        assert not self.deployer.interface_not_in_maintenance(self.controller.switches['01:23:45:67:89:ab:cd:ef'].interfaces[0])
333 1
        assert not self.deployer.interface_not_in_maintenance(self.controller.switches['01:23:45:67:89:ab:cd:ef'].interfaces[1])
334 1
        assert     self.deployer.interface_not_in_maintenance(self.controller.switches['01:23:45:67:89:ab:cd:ef'].interfaces[2])
335
336 1
        assert not self.deployer.interface_not_in_maintenance(self.controller.switches['01:23:45:67:65:ab:cd:ef'].interfaces[0])
337 1
        assert     self.deployer.interface_not_in_maintenance(self.controller.switches['01:23:45:67:65:ab:cd:ef'].interfaces[1])
338 1
        assert     self.deployer.interface_not_in_maintenance(self.controller.switches['01:23:45:67:65:ab:cd:ef'].interfaces[2])
339
340 1
        for interface in self.controller.switches['01:23:45:67:66:ab:cd:ef'].interfaces.values():
341 1
            assert     self.deployer.interface_not_in_maintenance(interface)
342
343
        # Links
344 1
        assert not self.deployer.link_not_in_maintenance(self.link_1)
345 1
        assert not self.deployer.link_not_in_maintenance(self.link_2)
346 1
        assert     self.deployer.link_not_in_maintenance(self.link_3)
347
348 1
        self.deployer.end_mw(maintenance)
349 1
        args, kwargs = buffer_put_mock.call_args
350 1
        event = args[0]
351 1
        assert event.name == 'kytos/topology.interruption.end'
352 1
        assert event.content['type'] == 'maintenance'
353 1
        assert sorted(event.content['switches']) == []
354 1
        assert sorted(event.content['switches']) == []
355 1
        assert sorted(event.content['interfaces']) == [
356
            '01:23:45:67:65:ab:cd:ef:0',
357
            '01:23:45:67:89:ab:cd:ef:0',
358
            '01:23:45:67:89:ab:cd:ef:1',
359
        ]
360 1
        assert sorted(event.content['links']) == [
361
            'link_1',
362
            'link_2',
363
        ]
364
        # Check whats in maintenance
365
        # Switches
366 1
        assert     self.deployer.switch_not_in_maintenance(self.controller.switches['01:23:45:67:89:ab:cd:ef'])
367 1
        assert     self.deployer.switch_not_in_maintenance(self.controller.switches['01:23:45:67:65:ab:cd:ef'])
368 1
        assert     self.deployer.switch_not_in_maintenance(self.controller.switches['01:23:45:67:66:ab:cd:ef'])
369
        # Interfaces
370 1
        for interface in self.controller.switches['01:23:45:67:89:ab:cd:ef'].interfaces.values():
371 1
            assert     self.deployer.interface_not_in_maintenance(interface)
372 1
        for interface in self.controller.switches['01:23:45:67:65:ab:cd:ef'].interfaces.values():
373 1
            assert     self.deployer.interface_not_in_maintenance(interface)
374 1
        for interface in self.controller.switches['01:23:45:67:66:ab:cd:ef'].interfaces.values():
375 1
            assert     self.deployer.interface_not_in_maintenance(interface)
376
        # Links
377 1
        assert     self.deployer.link_not_in_maintenance(self.link_1)
378 1
        assert     self.deployer.link_not_in_maintenance(self.link_2)
379 1
        assert     self.deployer.link_not_in_maintenance(self.link_3)
380
381 1
    def test_mw_case_3(self):
382
        """Test deploying a maintenance window to links."""
383 1
        buffer_put_mock = MagicMock()
384 1
        self.controller.buffers.app.put = buffer_put_mock
385 1
        maintenance = self.maintenance.copy(
386
            update = {
387
                'switches': [],
388
                'interfaces': [],
389
                'links': ['link_1', 'link_2'],
390
            }
391
        )
392 1
        self.deployer.start_mw(maintenance)
393 1
        args, kwargs = buffer_put_mock.call_args
394 1
        event = args[0]
395 1
        assert event.name == 'kytos/topology.interruption.start'
396 1
        assert event.content['type'] == 'maintenance'
397 1
        assert sorted(event.content['switches']) == []
398 1
        assert sorted(event.content['interfaces']) == []
399 1
        assert sorted(event.content['links']) == [
400
            'link_1',
401
            'link_2',
402
        ]
403
404
        # Check whats in maintenance
405
        # Switches
406 1
        assert     self.deployer.switch_not_in_maintenance(self.controller.switches['01:23:45:67:89:ab:cd:ef'])
407 1
        assert     self.deployer.switch_not_in_maintenance(self.controller.switches['01:23:45:67:65:ab:cd:ef'])
408 1
        assert     self.deployer.switch_not_in_maintenance(self.controller.switches['01:23:45:67:66:ab:cd:ef'])
409
        # Interfaces
410 1
        for interface in self.controller.switches['01:23:45:67:89:ab:cd:ef'].interfaces.values():
411 1
            assert     self.deployer.interface_not_in_maintenance(interface)
412 1
        for interface in self.controller.switches['01:23:45:67:65:ab:cd:ef'].interfaces.values():
413 1
            assert     self.deployer.interface_not_in_maintenance(interface)
414 1
        for interface in self.controller.switches['01:23:45:67:66:ab:cd:ef'].interfaces.values():
415 1
            assert     self.deployer.interface_not_in_maintenance(interface)
416
        # Links
417 1
        assert not self.deployer.link_not_in_maintenance(self.link_1)
418 1
        assert not self.deployer.link_not_in_maintenance(self.link_2)
419 1
        assert     self.deployer.link_not_in_maintenance(self.link_3)
420
421 1
        self.deployer.end_mw(maintenance)
422 1
        args, kwargs = buffer_put_mock.call_args
423 1
        event = args[0]
424 1
        assert event.name == 'kytos/topology.interruption.end'
425 1
        assert event.content['type'] == 'maintenance'
426 1
        assert sorted(event.content['switches']) == []
427 1
        assert sorted(event.content['interfaces']) == []
428 1
        assert sorted(event.content['links']) == [
429
            'link_1',
430
            'link_2',
431
        ]
432
        # Check whats in maintenance
433
        # Switches
434 1
        assert     self.deployer.switch_not_in_maintenance(self.controller.switches['01:23:45:67:89:ab:cd:ef'])
435 1
        assert     self.deployer.switch_not_in_maintenance(self.controller.switches['01:23:45:67:65:ab:cd:ef'])
436 1
        assert     self.deployer.switch_not_in_maintenance(self.controller.switches['01:23:45:67:66:ab:cd:ef'])
437
        # Interfaces
438 1
        for interface in self.controller.switches['01:23:45:67:89:ab:cd:ef'].interfaces.values():
439 1
            assert     self.deployer.interface_not_in_maintenance(interface)
440 1
        for interface in self.controller.switches['01:23:45:67:65:ab:cd:ef'].interfaces.values():
441 1
            assert     self.deployer.interface_not_in_maintenance(interface)
442 1
        for interface in self.controller.switches['01:23:45:67:66:ab:cd:ef'].interfaces.values():
443 1
            assert     self.deployer.interface_not_in_maintenance(interface)
444
        # Links
445 1
        assert     self.deployer.link_not_in_maintenance(self.link_1)
446 1
        assert     self.deployer.link_not_in_maintenance(self.link_2)
447 1
        assert     self.deployer.link_not_in_maintenance(self.link_3)
448
449
450 1
class TestScheduler(TestCase):
451
    """Test of the Scheduler Class"""
452
    
453 1
    def setUp(self) -> None:
454 1
        self.maintenance_deployer = MagicMock()
455 1
        self.db_controller = MagicMock()
456 1
        self.task_scheduler = MagicMock()
457
        
458 1
        self.now = datetime.now(pytz.utc)
459
460 1
        self.window = MW.construct(
461
            id = 'Test Window',
462
            description = '',
463
            start = self.now + timedelta(hours=1),
464
            end = self.now + timedelta(hours=2),
465
            status = 'pending',
466
            switches = [],
467
            interfaces = [],
468
            links = [],
469
            updated_at = self.now - timedelta(days=1),
470
            inserted_at = self.now - timedelta(days=1),
471
        )
472
473 1
        self.scheduler = Scheduler(self.maintenance_deployer, self.db_controller, self.task_scheduler)
474
475 1
    def test_start(self):
476
477 1
        pending_window = self.window.copy(
478
            update={'id': 'pending window', 'status': 'pending'}
479
        )
480 1
        running_window = self.window.copy(
481
            update={'id': 'running window', 'status': 'running'}
482
        )
483 1
        finished_window = self.window.copy(
484
            update={'id': 'finished window', 'status': 'finished'}
485
        )
486
487 1
        expected_schedule_calls = [
488
            call(MaintenanceStart(self.scheduler, 'pending window'),
489
            'date', id='pending window-start',
490
            run_date = pending_window.start),
491
            call(MaintenanceEnd(self.scheduler, 'running window'),
492
            'date', id='running window-end',
493
            run_date = running_window.end),
494
        ]
495
496 1
        self.db_controller.get_windows.return_value = [
497
            pending_window,
498
            running_window,
499
            finished_window,
500
        ]
501 1
        self.scheduler.start()
502
503 1
        resultant_schedule_calls = self.task_scheduler.add_job.call_args_list
504 1
        self.assertEqual(resultant_schedule_calls, expected_schedule_calls)
505
506 1
        self.maintenance_deployer.start_mw.assert_called_once_with(running_window)
507
508 1
    def test_shutdown(self):
509 1
        pending_window = self.window.copy(
510
            update={'id': 'pending window', 'status': 'pending'}
511
        )
512 1
        running_window = self.window.copy(
513
            update={'id': 'running window', 'status': 'running'}
514
        )
515 1
        finished_window = self.window.copy(
516
            update={'id': 'finished window', 'status': 'finished'}
517
        )
518
519 1
        self.db_controller.get_windows.return_value = [
520
            pending_window,
521
            running_window,
522
            finished_window,
523
        ]
524
525 1
        remove_job_effects = {
526
            'pending window-start': False,
527
            'pending window-end': True,
528
            'running window-start': True,
529
            'running window-end': False,
530
            'finished window-start': True,
531
            'finished window-end': True,
532
        }
533
534 1
        def side_effect(job_id):
535 1
            effect = remove_job_effects[job_id]
536 1
            if effect:
537 1
                raise JobLookupError(job_id)
538
            else:
539 1
                return None
540
541 1
        self.task_scheduler.remove_job.side_effect = side_effect
542
543 1
        self.scheduler.shutdown()
544
545 1
        self.maintenance_deployer.end_mw.assert_called_once_with(running_window)
546
547 1
    def test_update(self):
548 1
        pending_window = self.window.copy(
549
            update={'id': 'pending window', 'status': 'pending'}
550
        )
551 1
        running_window = self.window.copy(
552
            update={'id': 'running window', 'status': 'running'}
553
        )
554 1
        finished_window = self.window.copy(
555
            update={'id': 'finished window', 'status': 'finished'}
556
        )
557
558 1
        modify_job_effects = {
559
            'pending window-start': (False, DateTrigger(pending_window.start)),
560
            'pending window-end': (True, DateTrigger(pending_window.end)),
561
            'running window-start': (True, DateTrigger(running_window.start)),
562
            'running window-end': (False, DateTrigger(running_window.end)),
563
            'finished window-start': (True, DateTrigger(finished_window.start)),
564
            'finished window-end': (True, DateTrigger(finished_window.end)),
565
        }
566
567 1
        def side_effect(job_id, trigger):
568
            throw, expected_trigger = modify_job_effects[job_id]
569
            self.assertEqual(trigger.run_date, expected_trigger.run_date)
570
            if throw:
571
                raise JobLookupError(job_id)
572
            else:
573
                return None
574
        
575 1
        self.task_scheduler.modify_job.side_effect = side_effect
576
577 1
        self.scheduler.update(pending_window)
578 1
        self.scheduler.update(running_window)
579 1
        self.scheduler.update(finished_window)
580
581 1
    def test_maintenance_start(self):
582
583 1
        pending_window = self.window.copy(
584
            update={'id': 'pending window', 'status': 'pending'}
585
        )
586 1
        next_window = self.window.copy(
587
            update={'id': 'pending window', 'status': 'running'}
588
        )
589
590 1
        self.db_controller.start_window.return_value = next_window
591 1
        start = MaintenanceStart(self.scheduler, pending_window.id)
592 1
        start()
593 1
        self.maintenance_deployer.start_mw.assert_called_once_with(next_window)
594
595 1
        self.task_scheduler.add_job.assert_called_once_with(
596
            MaintenanceEnd(self.scheduler, pending_window.id),
597
            'date',
598
            id='pending window-end',
599
            run_date=pending_window.end
600
        )
601
602 1
    def test_maintenance_end(self):
603
604 1
        running_window = self.window.copy(
605
            update={'id': 'running window', 'status': 'running'}
606
        )
607 1
        next_window = self.window.copy(
608
            update={'id': 'running window', 'status': 'finished'}
609
        )
610
611 1
        self.db_controller.end_window.return_value = next_window
612 1
        end = MaintenanceEnd(self.scheduler, running_window.id)
613 1
        end()
614 1
        self.maintenance_deployer.end_mw.assert_called_once_with(next_window)
615
616