Angus Salkeld f3bc7d0109 Flatten the v2 API
This is a squashed commit of work done by Doug and myself.
Thanks Doug!

Author: Angus Salkeld <asalkeld@redhat.com>

    Add a Statistics class
    Note this is a bit different to the spec
    (http://wiki.openstack.org/Ceilometer/blueprints/APIv2)
    As wsme doen't really like different types been returned from
    the same method.

    I have:
    GET /v2/meters/<meter> - raw samples
    GET /v2/meters/<meter>/statistics - for the stats

    Make the error reporting better for invalid fields
    Try and protect from passing in the wrong arguments into the db api
    Also get_resources() takes start/stop_timestamp not start/stop.
    Fix most of the duration test cases (overlapping ones are still broken)
    Add some log messages to warn of unimplemented queries
    Fix the start/end timestamp passed into calc_duration()
    Make the query op default to 'eq'
    Fix v2 event list paths
    Remove v2 list projects tests
    Re-Add the duration
    Implement get_meter_statistics() for sqlalchemy.
    Add tests for get_meter_statistics()
    Fix the latest pep8 1.4 issues

Author: Doug Hellmann <doug.hellmann@dreamhost.com>
    fixme comment
    Fix duration calculation
    fix event listing tests
    remove obsolete list tests
    update resource listing tests
    remove obsolete list tests
    fix max statistics tests for projects
    fix max tests for resource queries
    fix tests for stats using project filter
    Fix sum tests for resource queries
    Fix the statistics calculation in the mongo driver to handle getting
    no data back from the query.
    Update the queries in the test code.
    enable logging for wsme in the tests to help with debugging
    always include all query fields to keep values aligned
    only include the start and end timestamp keywords wanted by the EventFilter
    update url used in acl tests
    update tests for listing meters
    convert prints to logging calls and add a few todo/fixme notes
    add some debugging and error checking to _query_to_kwargs
    add q argument to get_json() to make it easier to pass queries to the service
    do not stub out controller we have deleted
    fix whitespace issues to make pep8 happy

Change-Id: I1b9a4c26fb8cc74ae1a002f93b84db05d0b20192
Blueprint: api-aggregate-average
Blueprint: api-server-pecan-wsme
2013-01-19 16:57:57 +11:00

170 lines
5.5 KiB
Python

# -*- encoding: utf-8 -*-
#
# Copyright © 2012 New Dream Network, LLC (DreamHost)
#
# Author: Doug Hellmann <doug.hellmann@dreamhost.com>
#
# 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.
"""Base classes for API tests.
"""
import json
import os
import urllib
import unittest
import flask
from pecan import set_config
from pecan.testing import load_test_app
import mox
import stubout
from ceilometer import storage
from ceilometer.api.v1 import app as v1_app
from ceilometer.api.v1 import blueprint as v1_blueprint
from ceilometer.api.controllers import v2
from ceilometer.openstack.common import cfg
from ceilometer.tests import db as db_test_base
class TestBase(db_test_base.TestBase):
"""Use only for v1 API tests.
"""
def setUp(self):
super(TestBase, self).setUp()
self.app = v1_app.make_app(enable_acl=False, attach_storage=False)
self.app.register_blueprint(v1_blueprint.blueprint)
self.test_app = self.app.test_client()
@self.app.before_request
def attach_storage_connection():
flask.request.storage_conn = self.conn
def get(self, path, headers=None, **kwds):
if kwds:
query = path + '?' + urllib.urlencode(kwds)
else:
query = path
rv = self.test_app.get(query, headers=headers)
if rv.status_code == 200 and rv.content_type == 'application/json':
try:
data = json.loads(rv.data)
except ValueError:
print 'RAW DATA:', rv
raise
return data
return rv
class FunctionalTest(unittest.TestCase):
"""
Used for functional tests of Pecan controllers where you need to
test your literal application and its integration with the
framework.
"""
DBNAME = 'testdb'
PATH_PREFIX = ''
SOURCE_DATA = {'test_source': {'somekey': '666'}}
def setUp(self):
cfg.CONF.database_connection = 'test://localhost/%s' % self.DBNAME
self.conn = storage.get_connection(cfg.CONF)
# Don't want to use drop_database() because we
# may end up running out of spidermonkey instances.
# http://davisp.lighthouseapp.com/projects/26898/tickets/22
self.conn.conn[self.DBNAME].clear()
# Determine where we are so we can set up paths in the config
root_dir = os.path.abspath(os.path.join(os.path.dirname(__file__),
'..',
'..',
)
)
self.config = {
'app': {
'root': 'ceilometer.api.controllers.root.RootController',
'modules': ['ceilometer.api'],
'static_root': '%s/public' % root_dir,
'template_path': '%s/ceilometer/api/templates' % root_dir,
},
'logging': {
'loggers': {
'root': {'level': 'INFO', 'handlers': ['console']},
'wsme': {'level': 'INFO', 'handlers': ['console']},
'ceilometer': {'level': 'DEBUG',
'handlers': ['console'],
},
},
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'simple'
}
},
'formatters': {
'simple': {
'format': ('%(asctime)s %(levelname)-5.5s [%(name)s]'
'[%(threadName)s] %(message)s')
}
},
},
}
self.mox = mox.Mox()
self.stubs = stubout.StubOutForTesting()
self.app = self._make_app()
def _make_app(self):
return load_test_app(self.config)
def tearDown(self):
self.mox.UnsetStubs()
self.stubs.UnsetAll()
self.stubs.SmartUnsetAll()
self.mox.VerifyAll()
set_config({}, overwrite=True)
def get_json(self, path, expect_errors=False, headers=None,
q=[], **params):
full_path = self.PATH_PREFIX + path
query_params = {'q.field': [],
'q.value': [],
'q.op': [],
}
for query in q:
for name in ['field', 'op', 'value']:
query_params['q.%s' % name].append(query.get(name, ''))
all_params = {}
all_params.update(params)
if q:
all_params.update(query_params)
print 'GET: %s %r' % (full_path, all_params)
response = self.app.get(full_path,
params=all_params,
headers=headers,
expect_errors=expect_errors)
if not expect_errors:
response = response.json
print 'GOT:', response
return response