5bcb11b380
Change-Id: I4f9fd9518285c6bbd170159742a186eea6c58369
217 lines
7.3 KiB
Python
217 lines
7.3 KiB
Python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
|
|
# Copyright 2010 United States Government as represented by the
|
|
# Administrator of the National Aeronautics and Space Administration.
|
|
# 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.
|
|
|
|
"""Tests for Direct API."""
|
|
|
|
import json
|
|
|
|
import webob
|
|
|
|
from nova import context
|
|
from nova import exception
|
|
from nova import test
|
|
from nova.api import direct
|
|
|
|
|
|
class ArbitraryObject(object):
|
|
pass
|
|
|
|
|
|
class FakeService(object):
|
|
def echo(self, context, data):
|
|
return {'data': data}
|
|
|
|
def context(self, context):
|
|
return {'user': context.user_id,
|
|
'project': context.project_id}
|
|
|
|
def echo_data_directly(self, context, data):
|
|
return data
|
|
|
|
def invalid_return(self, context):
|
|
return ArbitraryObject()
|
|
|
|
|
|
class MyLimited(direct.Limited):
|
|
_allowed = ['var1', 'func1']
|
|
|
|
|
|
class MyProxy(object):
|
|
var1 = var2 = True
|
|
|
|
def func1(self):
|
|
return True
|
|
|
|
def func2(self):
|
|
return True
|
|
|
|
|
|
class DirectTestCase(test.TestCase):
|
|
def setUp(self):
|
|
super(DirectTestCase, self).setUp()
|
|
direct.register_service('fake', FakeService())
|
|
self.router = direct.PostParamsMiddleware(
|
|
direct.JsonParamsMiddleware(
|
|
direct.Router()))
|
|
self.auth_router = direct.DelegatedAuthMiddleware(self.router)
|
|
self.context = context.RequestContext('user1', 'proj1')
|
|
|
|
def tearDown(self):
|
|
direct.ROUTES = {}
|
|
super(DirectTestCase, self).tearDown()
|
|
|
|
def test_delegated_auth(self):
|
|
req = webob.Request.blank('/fake/context')
|
|
req.headers['X-OpenStack-User'] = 'user1'
|
|
req.headers['X-OpenStack-Project'] = 'proj1'
|
|
resp = req.get_response(self.auth_router)
|
|
self.assertEqual(resp.status_int, 200)
|
|
data = json.loads(resp.body)
|
|
self.assertEqual(data['user'], 'user1')
|
|
self.assertEqual(data['project'], 'proj1')
|
|
|
|
def test_json_params(self):
|
|
req = webob.Request.blank('/fake/echo')
|
|
req.environ['openstack.context'] = self.context
|
|
req.method = 'POST'
|
|
req.body = 'json=%s' % json.dumps({'data': 'foo'})
|
|
resp = req.get_response(self.router)
|
|
self.assertEqual(resp.status_int, 200)
|
|
resp_parsed = json.loads(resp.body)
|
|
self.assertEqual(resp_parsed['data'], 'foo')
|
|
|
|
def test_filter_json_params(self):
|
|
req = webob.Request.blank('/fake/echo')
|
|
req.environ['openstack.context'] = self.context
|
|
req.method = 'POST'
|
|
req.body = 'json=%s' % json.dumps({'data': 'foo',
|
|
'_underscored': 'ignoreMe',
|
|
'self': 'ignoreMe',
|
|
'context': 'ignoreMe'})
|
|
resp = req.get_response(self.router)
|
|
self.assertEqual(resp.status_int, 200)
|
|
resp_parsed = json.loads(resp.body)
|
|
self.assertEqual(resp_parsed['data'], 'foo')
|
|
self.assertNotIn('_underscored', resp_parsed)
|
|
self.assertNotIn('self', resp_parsed)
|
|
self.assertNotIn('context', resp_parsed)
|
|
|
|
def test_post_params(self):
|
|
req = webob.Request.blank('/fake/echo')
|
|
req.environ['openstack.context'] = self.context
|
|
req.method = 'POST'
|
|
req.body = 'data=foo'
|
|
resp = req.get_response(self.router)
|
|
self.assertEqual(resp.status_int, 200)
|
|
resp_parsed = json.loads(resp.body)
|
|
self.assertEqual(resp_parsed['data'], 'foo')
|
|
|
|
def test_filter_post_params(self):
|
|
req = webob.Request.blank('/fake/echo')
|
|
req.environ['openstack.context'] = self.context
|
|
req.method = 'POST'
|
|
req.body = 'data=foo&_underscored=ignoreMe&self=ignoreMe&context='\
|
|
'ignoreMe'
|
|
resp = req.get_response(self.router)
|
|
self.assertEqual(resp.status_int, 200)
|
|
resp_parsed = json.loads(resp.body)
|
|
self.assertEqual(resp_parsed['data'], 'foo')
|
|
self.assertNotIn('_underscored', resp_parsed)
|
|
self.assertNotIn('self', resp_parsed)
|
|
self.assertNotIn('context', resp_parsed)
|
|
|
|
def test_string_resp(self):
|
|
req = webob.Request.blank('/fake/echo_data_directly')
|
|
req.environ['openstack.context'] = self.context
|
|
req.method = 'POST'
|
|
req.body = 'data=foo'
|
|
resp = req.get_response(self.router)
|
|
self.assertEqual(resp.status_int, 200)
|
|
self.assertEqual(resp.body, 'foo')
|
|
|
|
def test_invalid(self):
|
|
req = webob.Request.blank('/fake/invalid_return')
|
|
req.environ['openstack.context'] = self.context
|
|
req.method = 'POST'
|
|
self.assertRaises(exception.Error, req.get_response, self.router)
|
|
|
|
def test_proxy(self):
|
|
proxy = direct.Proxy(self.router)
|
|
rv = proxy.fake.echo(self.context, data='baz')
|
|
self.assertEqual(rv['data'], 'baz')
|
|
|
|
|
|
class LimitedTestCase(test.TestCase):
|
|
def test_limited_class_getattr(self):
|
|
limited = MyLimited(MyProxy())
|
|
|
|
# Allowed are still visible
|
|
self.assertTrue(limited.func1())
|
|
self.assertTrue(limited.var1)
|
|
|
|
# Non-allowed are no longer visible
|
|
self.assertRaises(AttributeError, getattr, limited, 'func2')
|
|
self.assertRaises(AttributeError, getattr, limited, 'var2')
|
|
|
|
def test_limited_class_dir(self):
|
|
limited = MyLimited(MyProxy())
|
|
|
|
# Allowed are still visible
|
|
self.assertIn('func1', dir(limited))
|
|
self.assertIn('var1', dir(limited))
|
|
|
|
# Non-allowed are no longer visible
|
|
self.assertNotIn('func2', dir(limited))
|
|
self.assertNotIn('var2', dir(limited))
|
|
|
|
def test_limited_class_no_allowed(self):
|
|
|
|
# New MyLimited class with no _allowed variable
|
|
class MyLimited(direct.Limited):
|
|
pass
|
|
|
|
limited = MyLimited(MyProxy())
|
|
|
|
# Nothing in MyProxy object visible now
|
|
self.assertNotIn('func1', dir(limited))
|
|
self.assertNotIn('var1', dir(limited))
|
|
|
|
|
|
# NOTE(jkoelker): This fails using the EC2 api
|
|
#class DirectCloudTestCase(test_cloud.CloudTestCase):
|
|
# def setUp(self):
|
|
# super(DirectCloudTestCase, self).setUp()
|
|
# compute_handle = compute.API(image_service=self.cloud.image_service)
|
|
# volume_handle = volume.API()
|
|
# network_handle = network.API()
|
|
# direct.register_service('compute', compute_handle)
|
|
# direct.register_service('volume', volume_handle)
|
|
# direct.register_service('network', network_handle)
|
|
#
|
|
# self.router = direct.JsonParamsMiddleware(direct.Router())
|
|
# proxy = direct.Proxy(self.router)
|
|
# self.cloud.compute_api = proxy.compute
|
|
# self.cloud.volume_api = proxy.volume
|
|
# self.cloud.network_api = proxy.network
|
|
# compute_handle.volume_api = proxy.volume
|
|
# compute_handle.network_api = proxy.network
|
|
#
|
|
# def tearDown(self):
|
|
# super(DirectCloudTestCase, self).tearDown()
|
|
# direct.ROUTES = {}
|