xref: /unit/test/test_status.py (revision 2212:975ab1624784)
1import time
2
3import pytest
4from unit.applications.lang.python import TestApplicationPython
5from unit.option import option
6from unit.status import Status
7
8
9class TestStatus(TestApplicationPython):
10    prerequisites = {'modules': {'python': 'any'}}
11
12    def check_connections(self, accepted, active, idle, closed):
13        Status.get('/connections') == {
14            'accepted': accepted,
15            'active': active,
16            'idle': idle,
17            'closed': closed,
18        }
19
20    def app_default(self, name="empty", module="wsgi"):
21        return {
22            "type": self.get_application_type(),
23            "processes": {"spare": 0},
24            "path": option.test_dir + "/python/" + name,
25            "working_directory": option.test_dir + "/python/" + name,
26            "module": module,
27        }
28
29    def test_status(self):
30        assert 'error' in self.conf_delete('/status'), 'DELETE method'
31
32    def test_status_requests(self, skip_alert):
33        skip_alert(r'Python failed to import module "blah"')
34
35        assert 'success' in self.conf(
36            {
37                "listeners": {
38                    "*:7080": {"pass": "routes"},
39                    "*:7081": {"pass": "applications/empty"},
40                    "*:7082": {"pass": "applications/blah"},
41                },
42                "routes": [{"action": {"return": 200}}],
43                "applications": {
44                    "empty": self.app_default(),
45                    "blah": {
46                        "type": self.get_application_type(),
47                        "processes": {"spare": 0},
48                        "module": "blah",
49                    },
50                },
51            },
52        )
53
54        Status.init()
55
56        assert self.get()['status'] == 200
57        assert Status.get('/requests/total') == 1, '2xx'
58
59        assert self.get(port=7081)['status'] == 200
60        assert Status.get('/requests/total') == 2, '2xx app'
61
62        assert (
63            self.get(headers={'Host': '/', 'Connection': 'close'})['status']
64            == 400
65        )
66        assert Status.get('/requests/total') == 3, '4xx'
67
68        assert self.get(port=7082)['status'] == 503
69        assert Status.get('/requests/total') == 4, '5xx'
70
71        self.http(
72            b"""GET / HTTP/1.1
73Host: localhost
74
75GET / HTTP/1.1
76Host: localhost
77Connection: close
78
79""",
80            raw=True,
81        )
82        assert Status.get('/requests/total') == 6, 'pipeline'
83
84        sock = self.get(port=7081, no_recv=True)
85
86        time.sleep(1)
87
88        assert Status.get('/requests/total') == 7, 'no receive'
89
90        sock.close()
91
92    def test_status_connections(self):
93        assert 'success' in self.conf(
94            {
95                "listeners": {
96                    "*:7080": {"pass": "routes"},
97                    "*:7081": {"pass": "applications/delayed"},
98                },
99                "routes": [{"action": {"return": 200}}],
100                "applications": {
101                    "delayed": self.app_default("delayed"),
102                },
103            },
104        )
105
106        Status.init()
107
108        # accepted, closed
109
110        assert self.get()['status'] == 200
111        self.check_connections(1, 0, 0, 1)
112
113        # idle
114
115        sock = self.http(b'', raw=True, no_recv=True)
116        self.check_connections(2, 0, 1, 1)
117
118        self.get(sock=sock)
119        self.check_connections(2, 0, 0, 2)
120
121        # active
122
123        (_, sock) = self.get(
124            headers={
125                'Host': 'localhost',
126                'X-Delay': '2',
127                'Connection': 'close',
128            },
129            port=7081,
130            start=True,
131            read_timeout=1,
132        )
133        self.check_connections(3, 1, 0, 2)
134
135        self.get(sock=sock)
136        self.check_connections(3, 0, 0, 3)
137
138    def test_status_applications(self):
139        def check_applications(expert):
140            apps = list(self.conf_get('/status/applications').keys()).sort()
141            assert apps == expert.sort()
142
143        def check_application(name, running, starting, idle, active):
144            Status.get('/applications/' + name) == {
145                'processes': {
146                    'running': running,
147                    'starting': starting,
148                    'idle': idle,
149                },
150                'requests': {'active': active},
151            }
152
153        self.load('delayed')
154        Status.init()
155
156        check_applications(['delayed'])
157        check_application('delayed', 0, 0, 0, 0)
158
159        # idle
160
161        assert self.get()['status'] == 200
162        check_application('delayed', 1, 0, 1, 0)
163
164        assert 'success' in self.conf('4', 'applications/delayed/processes')
165        check_application('delayed', 4, 0, 4, 0)
166
167        # active
168
169        (_, sock) = self.get(
170            headers={
171                'Host': 'localhost',
172                'X-Delay': '2',
173                'Connection': 'close',
174            },
175            start=True,
176            read_timeout=1,
177        )
178        check_application('delayed', 4, 0, 3, 1)
179        sock.close()
180
181        # starting
182
183        assert 'success' in self.conf(
184            {
185                "listeners": {
186                    "*:7080": {"pass": "applications/restart"},
187                    "*:7081": {"pass": "applications/delayed"},
188                },
189                "routes": [],
190                "applications": {
191                    "restart": self.app_default("restart", "longstart"),
192                    "delayed": self.app_default("delayed"),
193                },
194            },
195        )
196        Status.init()
197
198        check_applications(['delayed', 'restart'])
199        check_application('restart', 0, 0, 0, 0)
200        check_application('delayed', 0, 0, 0, 0)
201
202        self.get(read_timeout=1)
203
204        check_application('restart', 0, 1, 0, 1)
205        check_application('delayed', 0, 0, 0, 0)
206
207    def test_status_proxy(self):
208        assert 'success' in self.conf(
209            {
210                "listeners": {
211                    "*:7080": {"pass": "routes"},
212                    "*:7081": {"pass": "applications/empty"},
213                },
214                "routes": [
215                    {
216                        "match": {"uri": "/"},
217                        "action": {"proxy": "http://127.0.0.1:7081"},
218                    }
219                ],
220                "applications": {
221                    "empty": self.app_default(),
222                },
223            },
224        )
225
226        Status.init()
227
228        assert self.get()['status'] == 200
229        self.check_connections(2, 0, 0, 2)
230        assert Status.get('/requests/total') == 2, 'proxy'
231