149 lines
5.7 KiB
Python
149 lines
5.7 KiB
Python
# Copyright 2017 IBM Corp.
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import mock
|
|
|
|
import fixtures as fx
|
|
import testtools
|
|
|
|
from nova.tests import fixtures
|
|
from nova.tests.unit import conf_fixture
|
|
|
|
"""Test request logging middleware under various conditions.
|
|
|
|
The request logging middleware is needed when running under something
|
|
other than eventlet. While Nova grew up on eventlet, and it's wsgi
|
|
server, it meant that our user facing data (the log stream) was a mix
|
|
of what Nova was emitting, and what eventlet.wsgi was emitting on our
|
|
behalf. When running under uwsgi we want to make sure that we have
|
|
equivalent coverage.
|
|
|
|
All these tests use GET / to hit an endpoint that doesn't require the
|
|
database setup. We have to do a bit of mocking to make that work.
|
|
"""
|
|
|
|
|
|
class TestRequestLogMiddleware(testtools.TestCase):
|
|
|
|
def setUp(self):
|
|
super(TestRequestLogMiddleware, self).setUp()
|
|
# this is the minimal set of magic mocks needed to convince
|
|
# the API service it can start on it's own without a database.
|
|
mocks = ['nova.objects.Service.get_by_host_and_binary',
|
|
'nova.objects.Service.create']
|
|
self.stdlog = fixtures.StandardLogging()
|
|
self.useFixture(self.stdlog)
|
|
for m in mocks:
|
|
p = mock.patch(m)
|
|
self.addCleanup(p.stop)
|
|
p.start()
|
|
|
|
@mock.patch('nova.api.openstack.requestlog.RequestLog._should_emit')
|
|
def test_logs_requests(self, emit):
|
|
"""Ensure requests are logged.
|
|
|
|
Make a standard request for / and ensure there is a log entry.
|
|
"""
|
|
|
|
emit.return_value = True
|
|
self.useFixture(conf_fixture.ConfFixture())
|
|
self.useFixture(fixtures.RPCFixture('nova.test'))
|
|
api = self.useFixture(fixtures.OSAPIFixture()).api
|
|
|
|
resp = api.api_request('/', strip_version=True)
|
|
log1 = ('INFO [nova.api.openstack.requestlog] 127.0.0.1 '
|
|
'"GET /v2" status: 204 len: 0 microversion: - time:')
|
|
self.assertIn(log1, self.stdlog.logger.output)
|
|
|
|
# the content length might vary, but the important part is
|
|
# what we log is what we return to the user (which turns out
|
|
# to excitingly not be the case with eventlet!)
|
|
content_length = resp.headers['content-length']
|
|
|
|
log2 = ('INFO [nova.api.openstack.requestlog] 127.0.0.1 '
|
|
'"GET /" status: 200 len: %s' % content_length)
|
|
self.assertIn(log2, self.stdlog.logger.output)
|
|
|
|
@mock.patch('nova.api.openstack.requestlog.RequestLog._should_emit')
|
|
def test_logs_mv(self, emit):
|
|
"""Ensure logs register microversion if passed.
|
|
|
|
This makes sure that microversion logging actually shows up
|
|
when appropriate.
|
|
"""
|
|
|
|
emit.return_value = True
|
|
self.useFixture(conf_fixture.ConfFixture())
|
|
# NOTE(sdague): all these tests are using the
|
|
self.useFixture(
|
|
fx.MonkeyPatch(
|
|
'nova.api.openstack.compute.versions.'
|
|
'Versions.support_api_request_version',
|
|
True))
|
|
|
|
self.useFixture(fixtures.RPCFixture('nova.test'))
|
|
|
|
api = self.useFixture(fixtures.OSAPIFixture()).api
|
|
api.microversion = '2.25'
|
|
|
|
resp = api.api_request('/', strip_version=True)
|
|
content_length = resp.headers['content-length']
|
|
|
|
log1 = ('INFO [nova.api.openstack.requestlog] 127.0.0.1 '
|
|
'"GET /" status: 200 len: %s microversion: 2.25 time:' %
|
|
content_length)
|
|
self.assertIn(log1, self.stdlog.logger.output)
|
|
|
|
@mock.patch('nova.api.openstack.compute.versions.Versions.index')
|
|
@mock.patch('nova.api.openstack.requestlog.RequestLog._should_emit')
|
|
def test_logs_under_exception(self, emit, v_index):
|
|
"""Ensure that logs still emit under unexpected failure.
|
|
|
|
If we get an unexpected failure all the way up to the top, we should
|
|
still have a record of that request via the except block.
|
|
"""
|
|
|
|
emit.return_value = True
|
|
v_index.side_effect = Exception("Unexpected Error")
|
|
self.useFixture(conf_fixture.ConfFixture())
|
|
self.useFixture(fixtures.RPCFixture('nova.test'))
|
|
api = self.useFixture(fixtures.OSAPIFixture()).api
|
|
|
|
api.api_request('/', strip_version=True)
|
|
log1 = ('INFO [nova.api.openstack.requestlog] 127.0.0.1 "GET /"'
|
|
' status: 500 len: 0 microversion: - time:')
|
|
self.assertIn(log1, self.stdlog.logger.output)
|
|
|
|
@mock.patch('nova.api.openstack.requestlog.RequestLog._should_emit')
|
|
def test_no_log_under_eventlet(self, emit):
|
|
"""Ensure that logs don't end up under eventlet.
|
|
|
|
We still set the _should_emit return value directly to prevent
|
|
the situation where eventlet is removed from tests and this
|
|
preventing that.
|
|
|
|
NOTE(sdague): this test can be deleted when eventlet is no
|
|
longer supported for the wsgi stack in Nova.
|
|
"""
|
|
|
|
emit.return_value = False
|
|
self.useFixture(conf_fixture.ConfFixture())
|
|
self.useFixture(fixtures.RPCFixture('nova.test'))
|
|
api = self.useFixture(fixtures.OSAPIFixture()).api
|
|
|
|
api.api_request('/', strip_version=True)
|
|
self.assertNotIn("nova.api.openstack.requestlog",
|
|
self.stdlog.logger.output)
|