Merge "Allow to specify CLI arguments"

This commit is contained in:
Jenkins 2017-07-27 07:15:56 +00:00 committed by Gerrit Code Review
commit 65ff274f9f
15 changed files with 136 additions and 88 deletions

8
.gitignore vendored
View File

@ -3,13 +3,13 @@
doc/build/*
dist
build
cover
.coverage
cover/
.coverage.*
*.egg
*.egg-info
.eggs/
.testrepository
.tox
.testrepository/
.tox/
ChangeLog
MANIFEST
AUTHORS

View File

@ -30,7 +30,7 @@ def get_wsgi_app():
return deploy.loadapp(
'config:%s/log-api-paste.ini' % config_dir,
relative_to='../../',
relative_to='./',
name='main'
)

View File

@ -12,6 +12,8 @@
# License for the specific language governing permissions and limitations
# under the License.
import sys
from oslo_log import log
from monasca_log_api import conf
@ -21,9 +23,17 @@ CONF = conf.CONF
LOG = log.getLogger(__name__)
_CONF_LOADED = False
_GUNICORN_MARKER = 'gunicorn'
def parse_args():
def _is_running_under_gunicorn():
"""Evaluates if api runs under gunicorn"""
content = filter(lambda x: x != sys.executable and _GUNICORN_MARKER in x,
sys.argv or [])
return len(list(content) if not isinstance(content, list) else content) > 0
def parse_args(argv=None):
global _CONF_LOADED
if _CONF_LOADED:
LOG.debug('Configuration has been already loaded')
@ -32,11 +42,10 @@ def parse_args():
log.set_defaults()
log.register_options(CONF)
CONF(args=[],
# NOTE(trebskit) this disables any oslo.cfg CLI
# opts as gunicorn has some trouble with them
# i.e. gunicorn's argparse clashes with the one
# defined inside oslo.cfg
argv = (argv if argv is not None else sys.argv[1:])
args = ([] if _is_running_under_gunicorn() else argv or [])
CONF(args=args,
prog='log-api',
project='monasca',
version=version.version_str,

View File

@ -20,23 +20,16 @@ import string
import falcon
from falcon import testing
import fixtures
import mock
from oslo_config import fixture as oo_cfg
from oslo_context import fixture as oo_ctx
from oslotest import base as os_test
from oslotest import base as oslotest_base
import six
from monasca_log_api.api.core import request
from monasca_log_api import conf
def mock_config(test):
conf.register_opts()
return test.useFixture(oo_cfg.Config(conf=conf.CONF))
def mock_context(test):
return test.useFixture(oo_ctx.ClearRequestContext())
from monasca_log_api import config
class MockedAPI(falcon.API):
@ -125,19 +118,59 @@ UNICODE_MESSAGES = [
]
class DisableStatsdMixin(object):
class DisableStatsdFixture(fixtures.Fixture):
def setUp(self):
super(DisableStatsdMixin, self).setUp()
self.statsd_patch = mock.patch('monascastatsd.Connection')
self.statsd_check = self.statsd_patch.start()
super(DisableStatsdFixture, self).setUp()
statsd_patch = mock.patch('monascastatsd.Connection')
statsd_patch.start()
self.addCleanup(statsd_patch.stop)
class BaseTestCase(DisableStatsdMixin, os_test.BaseTestCase):
pass
class ConfigFixture(oo_cfg.Config):
"""Mocks configuration"""
def __init__(self):
super(ConfigFixture, self).__init__(config.CONF)
def setUp(self):
super(ConfigFixture, self).setUp()
self.addCleanup(self._clean_config_loaded_flag)
conf.register_opts()
self._set_defaults()
config.parse_args(argv=[]) # prevent oslo from parsing test args
@staticmethod
def _clean_config_loaded_flag():
config._CONF_LOADED = False
def _set_defaults(self):
self.conf.set_default('kafka_url', '127.0.0.1', 'kafka_healthcheck')
self.conf.set_default('kafka_url', '127.0.0.1', 'log_publisher')
class BaseTestCase(oslotest_base.BaseTestCase):
def setUp(self):
super(BaseTestCase, self).setUp()
self.useFixture(ConfigFixture())
self.useFixture(DisableStatsdFixture())
self.useFixture(oo_ctx.ClearRequestContext())
@staticmethod
def conf_override(**kw):
"""Override flag variables for a test."""
group = kw.pop('group', None)
for k, v in kw.items():
config.CONF.set_override(k, v, group)
@staticmethod
def conf_default(**kw):
"""Override flag variables for a test."""
group = kw.pop('group', None)
for k, v in kw.items():
config.CONF.set_default(k, v, group)
class BaseApiTestCase(BaseTestCase, testing.TestBase):
api_class = MockedAPI
def before(self):
self.conf = mock_config(self)

View File

@ -0,0 +1,40 @@
# Copyright 2017 FUJITSU LIMITED
#
# 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
from monasca_log_api import config
from monasca_log_api.tests import base
class TestConfig(base.BaseTestCase):
@mock.patch('monasca_log_api.config.sys')
def test_should_return_true_if_runs_under_gunicorn(self, sys_patch):
sys_patch.argv = [
'/bin/gunicorn',
'--capture-output',
'--paste',
'etc/monasca/log-api-paste.ini',
'--workers',
'1'
]
sys_patch.executable = '/bin/python'
self.assertTrue(config._is_running_under_gunicorn())
@mock.patch('monasca_log_api.config.sys')
def test_should_return_false_if_runs_without_gunicorn(self, sys_patch):
sys_patch.argv = ['/bin/monasca-log-api']
sys_patch.executable = '/bin/python'
self.assertFalse(config._is_running_under_gunicorn())

View File

@ -24,8 +24,8 @@ ENDPOINT = '/healthcheck'
class TestApiHealthChecks(base.BaseApiTestCase):
def before(self):
super(TestApiHealthChecks, self).before()
self.resource = healthchecks.HealthChecks()
self.api.add_route(
ENDPOINT,

View File

@ -29,14 +29,9 @@ class KafkaCheckLogicTest(base.BaseTestCase):
'kafka_topics': mocked_topics
}
def __init__(self, *args, **kwargs):
super(KafkaCheckLogicTest, self).__init__(*args, **kwargs)
self._conf = None
def setUp(self):
super(KafkaCheckLogicTest, self).setUp()
self._conf = base.mock_config(self)
self._conf.config(group='kafka_healthcheck', **self.mock_config)
self.conf_default(group='kafka_healthcheck', **self.mock_config)
@mock.patch('monasca_log_api.healthcheck.kafka_check.client.KafkaClient')
def test_should_fail_kafka_unavailable(self, kafka_client):

View File

@ -20,6 +20,7 @@ import ujson
import unittest
import mock
from oslo_config import cfg
from oslo_log import log
import six
@ -33,10 +34,6 @@ EPOCH_START = datetime.datetime(1970, 1, 1)
class TestSendMessage(base.BaseTestCase):
def setUp(self):
self.conf = base.mock_config(self)
return super(TestSendMessage, self).setUp()
@mock.patch('monasca_log_api.reference.common.log_publisher.producer'
'.KafkaProducer')
def test_should_not_send_empty_message(self, _):
@ -133,16 +130,16 @@ class TestSendMessage(base.BaseTestCase):
instance.send_message(msg)
instance._kafka_publisher.publish.assert_called_once_with(
self.conf.conf.log_publisher.topics[0],
cfg.CONF.log_publisher.topics[0],
[ujson.dumps(msg, ensure_ascii=False).encode('utf-8')])
@mock.patch('monasca_log_api.reference.common.log_publisher.producer'
'.KafkaProducer')
def test_should_send_message_multiple_topics(self, _):
topics = ['logs', 'analyzer', 'tester']
self.conf.config(topics=topics,
max_message_size=5000,
group='log_publisher')
self.conf_override(topics=topics,
max_message_size=5000,
group='log_publisher')
instance = log_publisher.LogPublisher()
instance._kafka_publisher = mock.Mock()
@ -210,7 +207,7 @@ class TestSendMessage(base.BaseTestCase):
expected_message = expected_message.encode('utf-8')
instance._kafka_publisher.publish.assert_called_with(
self.conf.conf.log_publisher.topics[0],
cfg.CONF.log_publisher.topics[0],
[expected_message]
)
except Exception:
@ -228,14 +225,6 @@ class TestTruncation(base.BaseTestCase):
}
}), 'utf8')) - 2
def __init__(self, *args, **kwargs):
super(TestTruncation, self).__init__(*args, **kwargs)
self._conf = None
def setUp(self):
super(TestTruncation, self).setUp()
self._conf = base.mock_config(self)
def test_should_not_truncate_message_if_size_is_smaller(self, _):
diff_size = random.randint(1, 100)
self._run_truncate_test(log_size_factor=-diff_size,
@ -269,7 +258,7 @@ class TestTruncation(base.BaseTestCase):
expected_log_message_size = log_size - truncate_by
self._conf.config(
self.conf_override(
group='log_publisher',
max_message_size=max_message_size
)

View File

@ -196,7 +196,7 @@ class TestApiLogs(base.BaseApiTestCase):
max_log_size = 1000
content_length = max_log_size - 100
self.conf.config(max_log_size=max_log_size, group='service')
self.conf_override(max_log_size=max_log_size, group='service')
self.simulate_request(
'/log/single',
@ -217,7 +217,7 @@ class TestApiLogs(base.BaseApiTestCase):
max_log_size = 1000
content_length = max_log_size + 100
self.conf.config(max_log_size=max_log_size, group='service')
self.conf_override(max_log_size=max_log_size, group='service')
self.simulate_request(
'/log/single',
@ -238,7 +238,7 @@ class TestApiLogs(base.BaseApiTestCase):
max_log_size = 1000
content_length = max_log_size
self.conf.config(max_log_size=max_log_size, group='service')
self.conf_override(max_log_size=max_log_size, group='service')
self.simulate_request(
'/log/single',

View File

@ -203,9 +203,6 @@ class TestApiLogsMonitoring(base.BaseApiTestCase):
class TestApiLogs(base.BaseApiTestCase):
def before(self):
self.conf = base.mock_config(self)
@mock.patch('monasca_log_api.reference.v3.common.bulk_processor.'
'BulkProcessor')
def test_should_pass_cross_tenant_id(self, bulk_processor):

View File

@ -20,10 +20,6 @@ from monasca_log_api.tests import base
class TestMonitoring(base.BaseTestCase):
def setUp(self):
super(TestMonitoring, self).setUp()
base.mock_config(self)
@mock.patch('monasca_log_api.monitoring.client.monascastatsd')
def test_should_use_default_dimensions_if_none_specified(self,
monascastatsd):

View File

@ -22,11 +22,6 @@ from monasca_log_api.tests import base
class TestRequest(base.BaseTestCase):
def setUp(self):
super(TestRequest, self).setUp()
base.mock_config(self)
base.mock_context(self)
def test_use_context_from_request(self):
req = request.Request(
testing.create_environ(

View File

@ -30,13 +30,8 @@ class IsDelegate(base.BaseTestCase):
def __init__(self, *args, **kwargs):
super(IsDelegate, self).__init__(*args, **kwargs)
self._conf = None
self._roles = ['admin']
def setUp(self):
super(IsDelegate, self).setUp()
self._conf = base.mock_config(self)
def test_is_delegate_ok_role(self):
self.assertTrue(validation.validate_is_delegate(self._roles))
@ -277,9 +272,6 @@ class ContentTypeValidations(base.BaseTestCase):
class PayloadSizeValidations(base.BaseTestCase):
def setUp(self):
super(PayloadSizeValidations, self).setUp()
self.conf = base.mock_config(self)
def test_should_fail_missing_header(self):
content_length = None
@ -294,8 +286,8 @@ class PayloadSizeValidations(base.BaseTestCase):
def test_should_pass_limit_not_exceeded(self):
content_length = 120
max_log_size = 240
self.conf.config(max_log_size=max_log_size,
group='service')
self.conf_override(max_log_size=max_log_size,
group='service')
req = mock.Mock()
req.content_length = content_length
@ -305,8 +297,8 @@ class PayloadSizeValidations(base.BaseTestCase):
def test_should_fail_limit_exceeded(self):
content_length = 120
max_log_size = 60
self.conf.config(max_log_size=max_log_size,
group='service')
self.conf_override(max_log_size=max_log_size,
group='service')
req = mock.Mock()
req.content_length = content_length
@ -320,8 +312,8 @@ class PayloadSizeValidations(base.BaseTestCase):
def test_should_fail_limit_equal(self):
content_length = 120
max_log_size = 120
self.conf.config(max_log_size=max_log_size,
group='service')
self.conf_override(max_log_size=max_log_size,
group='service')
req = mock.Mock()
req.content_length = content_length

View File

@ -24,12 +24,8 @@ def _get_versioned_url(version_id):
class TestApiVersions(base.BaseApiTestCase):
def __init__(self, *args, **kwargs):
self.versions = None
super(TestApiVersions, self).__init__(*args, **kwargs)
def before(self):
super(TestApiVersions, self).before()
self.versions = versions.Versions()
self.api.add_route("/version/", self.versions)
self.api.add_route("/version/{version_id}", self.versions)

View File

@ -0,0 +1,6 @@
---
other:
- |
Enabled possibility of specifying the CLI arguments, when launching
monasca-log-api, for cases where API is not deployed using Gunicorn
server.