python-troveclient/troveclient/tests/test_shell.py

367 lines
13 KiB
Python

#
# 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 io
import re
import sys
from unittest import mock
import fixtures
from keystoneauth1 import fixture
import requests_mock
import testtools
import uuid
import troveclient.client
from troveclient import exceptions
import troveclient.shell
try:
import json
except ImportError:
import simplejson as json
V2_URL = "http://no.where/v2.0"
V3_URL = "http://no.where/v3"
FAKE_V2_ENV = {'OS_USERNAME': uuid.uuid4().hex,
'OS_PASSWORD': uuid.uuid4().hex,
'OS_TENANT_ID': uuid.uuid4().hex,
'OS_AUTH_URL': V2_URL}
FAKE_V3_ENV = {'OS_USERNAME': uuid.uuid4().hex,
'OS_PASSWORD': uuid.uuid4().hex,
'OS_PROJECT_ID': uuid.uuid4().hex,
'OS_USER_DOMAIN_NAME': uuid.uuid4().hex,
'OS_AUTH_URL': V3_URL}
UPDATED = '2013-03-06T00:00:00Z'
TEST_SERVICE_CATALOG = [{
"endpoints": [{
"adminURL": "http://no.where/admin",
"region": "RegionOne",
"internalURL": "http://no.where/internal",
"publicURL": "http://no.where/v1.0"
}],
"type": "database",
"name": "trove"
}]
def _create_ver_list(versions):
return {'versions': {'values': versions}}
class ShellTest(testtools.TestCase):
version_id = 'v2.0'
links = [{'href': 'http://no.where/v2.0', 'rel': 'self'}]
v2_version = fixture.V2Discovery(V2_URL)
v2_version.updated_str = UPDATED
v2_auth_response = json.dumps({
"access": {
"token": {
"expires": "2020-01-01T00:00:10.000123Z",
"id": 'fakeToken',
"tenant": {
"id": uuid.uuid4().hex
},
},
"user": {
"id": uuid.uuid4().hex
},
"serviceCatalog": TEST_SERVICE_CATALOG,
},
})
def make_env(self, exclude=None, fake_env=FAKE_V2_ENV):
env = dict((k, v) for k, v in fake_env.items() if k != exclude)
self.useFixture(fixtures.MonkeyPatch('os.environ', env))
def setUp(self):
super(ShellTest, self).setUp()
self.useFixture(fixtures.MonkeyPatch(
'troveclient.client.get_client_class',
mock.MagicMock))
def shell(self, argstr, exitcodes=(0,)):
orig = sys.stdout
orig_stderr = sys.stderr
try:
sys.stdout = io.StringIO()
sys.stderr = io.StringIO()
_shell = troveclient.shell.OpenStackTroveShell()
_shell.main(argstr.split())
except SystemExit:
exc_type, exc_value, exc_traceback = sys.exc_info()
self.assertIn(exc_value.code, exitcodes)
finally:
stdout = sys.stdout.getvalue()
sys.stdout.close()
sys.stdout = orig
stderr = sys.stderr.getvalue()
sys.stderr.close()
sys.stderr = orig_stderr
return (stdout, stderr)
def register_keystone_discovery_fixture(self, mreq):
mreq.register_uri('GET', V2_URL,
json=_create_ver_list([self.v2_version]),
status_code=200)
def test_help_unknown_command(self):
self.assertRaises(exceptions.CommandError, self.shell, 'help foofoo')
def test_help(self):
required = [
'.*?^usage: ',
'.*?^See "trove help COMMAND" for help on a specific command',
]
stdout, stderr = self.shell('help')
for r in required:
self.assertThat(
(stdout + stderr),
testtools.matchers.MatchesRegex(r, re.DOTALL | re.MULTILINE))
def test_no_username(self):
required = ('You must provide a username'
' via either --os-username or'
' env[OS_USERNAME]')
self.make_env(exclude='OS_USERNAME')
try:
self.shell('list')
except exceptions.CommandError as message:
self.assertEqual(required, message.args[0])
else:
self.fail('CommandError not raised')
def test_no_auth_url(self):
required = ('You must provide an auth url'
' via either --os-auth-url or env[OS_AUTH_URL] '
'or specify an auth_system which defines a default '
'url with --os-auth-system or env[OS_AUTH_SYSTEM]',)
self.make_env(exclude='OS_AUTH_URL')
try:
self.shell('list')
except exceptions.CommandError as message:
self.assertEqual(required, message.args)
else:
self.fail('CommandError not raised')
@mock.patch('keystoneauth1.discover.get_version_data',
return_value=[{'status': 'stable', 'id': version_id,
'links': links}])
@mock.patch('troveclient.v1.datastores.DatastoreVersions.list')
@requests_mock.Mocker()
def test_datastore_version_list(self, mock_discover,
mock_list, mock_requests):
expected = '\n'.join([
'+----+------+',
'| ID | Name |',
'+----+------+',
'+----+------+',
''
])
self.make_env()
self.register_keystone_discovery_fixture(mock_requests)
mock_requests.register_uri('POST', "http://no.where/v2.0/tokens",
text=self.v2_auth_response)
stdout, stderr = self.shell('datastore-version-list XXX')
self.assertEqual(expected, (stdout + stderr))
@mock.patch('keystoneauth1.discover.get_version_data',
return_value=[{'status': 'stable', 'id': version_id,
'links': links}])
@mock.patch('troveclient.v1.datastores.Datastores.list')
@requests_mock.Mocker()
def test_get_datastore_list(self, mock_discover,
mock_list, mock_requests):
expected = '\n'.join([
'+----+------+',
'| ID | Name |',
'+----+------+',
'+----+------+',
''
])
self.make_env()
self.register_keystone_discovery_fixture(mock_requests)
mock_requests.register_uri('POST', "http://no.where/v2.0/tokens",
text=self.v2_auth_response)
stdout, stderr = self.shell('datastore-list')
self.assertEqual(expected, (stdout + stderr))
class ShellTestKeystoneV3(ShellTest):
version_id = 'v3'
links = [{'href': 'http://no.where/v3', 'rel': 'self'}]
v3_version = fixture.V3Discovery(V3_URL)
v3_version.updated_str = UPDATED
test_service_catalog = [{
"endpoints": [{
"url": "http://no.where/v1.0/",
"region": "RegionOne",
"interface": "public"
}, {
"url": "http://no.where/v1.0",
"region": "RegionOne",
"interface": "internal"
}, {
"url": "http://no.where/v1.0",
"region": "RegionOne",
"interface": "admin"
}],
"type": "database",
"name": "trove"
}]
service_catalog2 = [{
"endpoints": [{
"url": "http://no.where/vXYZ",
"region": "RegionOne",
"interface": "public"
}],
"type": "database",
"name": "trove"
}]
v3_auth_response = json.dumps({
"token": {
"methods": [
"token",
"password"
],
"expires_at": "2020-01-01T00:00:10.000123Z",
"project": {
"domain": {
"id": uuid.uuid4().hex,
"name": uuid.uuid4().hex
},
"id": uuid.uuid4().hex,
"name": uuid.uuid4().hex
},
"user": {
"domain": {
"id": uuid.uuid4().hex,
"name": uuid.uuid4().hex
},
"id": uuid.uuid4().hex,
"name": uuid.uuid4().hex
},
"issued_at": "2013-05-29T16:55:21.468960Z",
"catalog": test_service_catalog
},
})
def make_env(self, exclude=None, fake_env=FAKE_V3_ENV):
if 'OS_AUTH_URL' in fake_env:
fake_env.update({'OS_AUTH_URL': 'http://no.where/v3'})
env = dict((k, v) for k, v in fake_env.items() if k != exclude)
self.useFixture(fixtures.MonkeyPatch('os.environ', env))
def register_keystone_discovery_fixture(self, mreq):
v3_url = "http://no.where/v3"
v3_version = fixture.V3Discovery(v3_url)
mreq.register_uri('GET', v3_url, json=_create_ver_list([v3_version]),
status_code=200)
def test_no_project_id(self):
required = (
'You must provide a '
'project_id or project_name (with '
'project_domain_name or project_domain_id) via '
' --os-project-id (env[OS_PROJECT_ID])'
' --os-project-name (env[OS_PROJECT_NAME]),'
' --os-project-domain-id '
'(env[OS_PROJECT_DOMAIN_ID])'
' --os-project-domain-name '
'(env[OS_PROJECT_DOMAIN_NAME])'
)
self.make_env(exclude='OS_PROJECT_ID')
try:
self.shell('list')
except exceptions.CommandError as message:
self.assertEqual(required, message.args[0])
else:
self.fail('CommandError not raised')
@mock.patch('keystoneauth1.discover.get_version_data',
return_value=[{'status': 'stable', 'id': version_id,
'links': links}])
@mock.patch('troveclient.v1.datastores.DatastoreVersions.list')
@requests_mock.Mocker()
def test_datastore_version_list(self, mock_discover,
mock_list, mock_requests):
expected = '\n'.join([
'+----+------+',
'| ID | Name |',
'+----+------+',
'+----+------+',
''
])
self.make_env()
self.register_keystone_discovery_fixture(mock_requests)
mock_requests.register_uri('POST', "http://no.where/v3/auth/tokens",
headers={'X-Subject-Token': 'fakeToken'},
text=self.v3_auth_response)
stdout, stderr = self.shell('datastore-version-list XXX')
self.assertEqual(expected, (stdout + stderr))
@mock.patch('keystoneauth1.discover.get_version_data',
return_value=[{'status': 'stable', 'id': version_id,
'links': links}])
@mock.patch('troveclient.v1.datastores.Datastores.list')
@requests_mock.Mocker()
def test_get_datastore_list(self, mock_discover,
mock_list, mock_requests):
expected = '\n'.join([
'+----+------+',
'| ID | Name |',
'+----+------+',
'+----+------+',
''
])
self.make_env()
self.register_keystone_discovery_fixture(mock_requests)
mock_requests.register_uri('POST', "http://no.where/v3/auth/tokens",
headers={'X-Subject-Token': 'fakeToken'},
text=self.v3_auth_response)
stdout, stderr = self.shell('datastore-list')
self.assertEqual(expected, (stdout + stderr))
@mock.patch('keystoneauth1.discover.get_version_data',
return_value=[{'status': 'stable', 'id': version_id,
'links': links}])
@requests_mock.Mocker()
def test_invalid_client_version(self, mock_discover,
mock_requests):
response = json.loads(self.v3_auth_response)
response['token']['catalog'] = self.service_catalog2
self.make_env()
self.register_keystone_discovery_fixture(mock_requests)
mock_requests.register_uri('POST', "http://no.where/v3/auth/tokens",
headers={'X-Subject-Token': 'fakeToken'},
text=json.dumps(response))
try:
self.shell('datastore-list')
except exceptions.UnsupportedVersion:
pass
else:
self.fail('UnsupportedVersion not raised')