~allenap/maas/xxx-a-thon

« back to all changes in this revision

Viewing changes to src/maasserver/tests/test_service_monitor.py

  • Committer: Gavin Panella
  • Date: 2016-03-22 21:14:34 UTC
  • mfrom: (4657.1.157 maas)
  • Revision ID: gavin.panella@canonical.com-20160322211434-xzuovio86zvzo2js
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2016 Canonical Ltd.  This software is licensed under the
 
2
# GNU Affero General Public License version 3 (see the file LICENSE).
 
3
 
 
4
"""Tests for service monitoring in the regiond."""
 
5
 
 
6
__all__ = []
 
7
 
 
8
import random
 
9
 
 
10
from crochet import wait_for
 
11
from maasserver import service_monitor as service_monitor_module
 
12
from maasserver.enum import SERVICE_STATUS
 
13
from maasserver.models.service import Service
 
14
from maasserver.service_monitor import (
 
15
    service_monitor,
 
16
    ServiceMonitorService,
 
17
)
 
18
from maasserver.testing.testcase import MAASTransactionServerTestCase
 
19
from maasserver.utils.orm import transactional
 
20
from maasserver.utils.threads import deferToDatabase
 
21
from maastesting.factory import factory
 
22
from maastesting.matchers import (
 
23
    MockCalledOnceWith,
 
24
    MockNotCalled,
 
25
)
 
26
from maastesting.testcase import MAASTestCase
 
27
from maastesting.twisted import TwistedLoggerFixture
 
28
from mock import (
 
29
    Mock,
 
30
    sentinel,
 
31
)
 
32
from provisioningserver.utils.service_monitor import (
 
33
    SERVICE_STATE,
 
34
    ServiceState,
 
35
)
 
36
from provisioningserver.utils.twisted import DeferredValue
 
37
from testtools.matchers import MatchesStructure
 
38
from twisted.internet.defer import (
 
39
    fail,
 
40
    inlineCallbacks,
 
41
    succeed,
 
42
)
 
43
from twisted.internet.task import Clock
 
44
 
 
45
 
 
46
wait_for_reactor = wait_for(30)  # 30 seconds.
 
47
 
 
48
 
 
49
class TestGlobalServiceMonitor(MAASTestCase):
 
50
 
 
51
    def test__includes_all_services(self):
 
52
        self.assertItemsEqual(
 
53
            ["bind9", "proxy"], service_monitor._services.keys())
 
54
 
 
55
 
 
56
class TestServiceMonitorService(MAASTransactionServerTestCase):
 
57
 
 
58
    def pick_service(self):
 
59
        return random.choice(list(service_monitor._services.values()))
 
60
 
 
61
    def test_init_sets_up_timer_correctly(self):
 
62
        monitor_service = ServiceMonitorService(
 
63
            sentinel.advertisingService, sentinel.clock)
 
64
        self.assertThat(monitor_service, MatchesStructure.byEquality(
 
65
            call=(monitor_service.monitorServices, (), {}),
 
66
            step=(60), advertisingService=sentinel.advertisingService,
 
67
            clock=sentinel.clock))
 
68
 
 
69
    def test_monitorServices_does_not_do_anything_in_dev_environment(self):
 
70
        # Belt-n-braces make sure we're in a development environment.
 
71
        self.assertTrue(service_monitor_module.is_dev_environment())
 
72
 
 
73
        monitor_service = ServiceMonitorService(
 
74
            sentinel.advertisingService, Clock())
 
75
        mock_ensureServices = self.patch(service_monitor, "ensureServices")
 
76
        with TwistedLoggerFixture() as logger:
 
77
            monitor_service.monitorServices()
 
78
        self.assertThat(mock_ensureServices, MockNotCalled())
 
79
        self.assertDocTestMatches(
 
80
            "Skipping check of services; they're not running under the "
 
81
            "supervision of systemd.", logger.output)
 
82
 
 
83
    def test_monitorServices_calls_ensureServices(self):
 
84
        # Pretend we're in a production environment.
 
85
        self.patch(
 
86
            service_monitor_module, "is_dev_environment").return_value = False
 
87
 
 
88
        monitor_service = ServiceMonitorService(
 
89
            sentinel.advertisingService, Clock())
 
90
        mock_ensureServices = self.patch(service_monitor, "ensureServices")
 
91
        monitor_service.monitorServices()
 
92
        self.assertThat(
 
93
            mock_ensureServices,
 
94
            MockCalledOnceWith())
 
95
 
 
96
    def test_monitorServices_handles_failure(self):
 
97
        # Pretend we're in a production environment.
 
98
        self.patch(
 
99
            service_monitor_module, "is_dev_environment").return_value = False
 
100
 
 
101
        monitor_service = ServiceMonitorService(
 
102
            sentinel.advertisingService, Clock())
 
103
        mock_ensureServices = self.patch(service_monitor, "ensureServices")
 
104
        mock_ensureServices.return_value = fail(factory.make_exception())
 
105
        with TwistedLoggerFixture() as logger:
 
106
            monitor_service.monitorServices()
 
107
        self.assertDocTestMatches("""\
 
108
            Failed to monitor services and update database.
 
109
            Traceback (most recent call last):
 
110
            ...""", logger.output)
 
111
 
 
112
    @inlineCallbacks
 
113
    def test_updates_services_in_database(self):
 
114
        # Pretend we're in a production environment.
 
115
        self.patch(
 
116
            service_monitor_module, "is_dev_environment").return_value = False
 
117
 
 
118
        service = self.pick_service()
 
119
        state = ServiceState(SERVICE_STATE.ON, "running")
 
120
        mock_ensureServices = self.patch(service_monitor, "ensureServices")
 
121
        mock_ensureServices.return_value = succeed({
 
122
            service.name: state
 
123
        })
 
124
 
 
125
        advertisingService = Mock()
 
126
        advertisingService.processId = DeferredValue()
 
127
        monitor_service = ServiceMonitorService(
 
128
            advertisingService, Clock())
 
129
        yield monitor_service.startService()
 
130
 
 
131
        region = yield deferToDatabase(
 
132
            transactional(factory.make_RegionController))
 
133
        region_process = yield deferToDatabase(
 
134
            transactional(factory.make_RegionControllerProcess), region)
 
135
        advertisingService.processId.set(region_process.id)
 
136
        yield monitor_service.stopService()
 
137
 
 
138
        service = yield deferToDatabase(
 
139
            transactional(Service.objects.get), node=region, name=service.name)
 
140
        self.assertThat(
 
141
            service,
 
142
            MatchesStructure.byEquality(
 
143
                name=service.name, status=SERVICE_STATUS.RUNNING,
 
144
                status_info=""))
 
145
 
 
146
    @inlineCallbacks
 
147
    def test__buildServices_builds_services_list(self):
 
148
        monitor_service = ServiceMonitorService(
 
149
            sentinel.advertisingService, Clock())
 
150
        service = self.pick_service()
 
151
        state = ServiceState(SERVICE_STATE.ON, "running")
 
152
        observed_services = yield monitor_service._buildServices({
 
153
            service.name: state
 
154
        })
 
155
        expected_services = [{
 
156
            "name": service.name,
 
157
            "status": "running",
 
158
            "status_info": "",
 
159
        }]
 
160
        self.assertEquals(expected_services, observed_services)