Under python 3 with ordering randomized we cannot depend on the JSON output matching exactly. Instead we de-serialize the data structure that was written and compare the structures, which will always match. Change-Id: I134b62413a7cde25f3efda6a2452c1e3d11d41d0 Signed-off-by: Doug Hellmann <doug@doughellmann.com>
		
			
				
	
	
		
			978 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			978 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# Copyright 2013 OpenStack Foundation
 | 
						|
# Copyright (C) 2013 Yahoo! Inc.
 | 
						|
# 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 argparse
 | 
						|
from collections import OrderedDict
 | 
						|
import hashlib
 | 
						|
import logging
 | 
						|
import os
 | 
						|
import sys
 | 
						|
import traceback
 | 
						|
import uuid
 | 
						|
 | 
						|
import fixtures
 | 
						|
from keystoneauth1 import exceptions as ks_exc
 | 
						|
from keystoneauth1 import fixture as ks_fixture
 | 
						|
import mock
 | 
						|
from requests_mock.contrib import fixture as rm_fixture
 | 
						|
import six
 | 
						|
 | 
						|
from glanceclient.common import utils
 | 
						|
from glanceclient import exc
 | 
						|
from glanceclient import shell as openstack_shell
 | 
						|
from glanceclient.tests.unit.v2.fixtures import image_show_fixture
 | 
						|
from glanceclient.tests.unit.v2.fixtures import image_versions_fixture
 | 
						|
from glanceclient.tests import utils as testutils
 | 
						|
 | 
						|
# NOTE (esheffield) Used for the schema caching tests
 | 
						|
from glanceclient.v2 import schemas as schemas
 | 
						|
import json
 | 
						|
 | 
						|
 | 
						|
DEFAULT_IMAGE_URL = 'http://127.0.0.1:9292/'
 | 
						|
DEFAULT_IMAGE_URL_INTERNAL = 'http://127.0.0.1:9191/'
 | 
						|
DEFAULT_USERNAME = 'username'
 | 
						|
DEFAULT_PASSWORD = 'password'
 | 
						|
DEFAULT_TENANT_ID = 'tenant_id'
 | 
						|
DEFAULT_TENANT_NAME = 'tenant_name'
 | 
						|
DEFAULT_PROJECT_ID = '0123456789'
 | 
						|
DEFAULT_USER_DOMAIN_NAME = 'user_domain_name'
 | 
						|
DEFAULT_UNVERSIONED_AUTH_URL = 'http://127.0.0.1:5000/'
 | 
						|
DEFAULT_V2_AUTH_URL = '%sv2.0' % DEFAULT_UNVERSIONED_AUTH_URL
 | 
						|
DEFAULT_V3_AUTH_URL = '%sv3' % DEFAULT_UNVERSIONED_AUTH_URL
 | 
						|
DEFAULT_AUTH_TOKEN = ' 3bcc3d3a03f44e3d8377f9247b0ad155'
 | 
						|
TEST_SERVICE_URL = 'http://127.0.0.1:5000/'
 | 
						|
DEFAULT_SERVICE_TYPE = 'image'
 | 
						|
DEFAULT_ENDPOINT_TYPE = 'public'
 | 
						|
 | 
						|
FAKE_V2_ENV = {'OS_USERNAME': DEFAULT_USERNAME,
 | 
						|
               'OS_PASSWORD': DEFAULT_PASSWORD,
 | 
						|
               'OS_TENANT_NAME': DEFAULT_TENANT_NAME,
 | 
						|
               'OS_AUTH_URL': DEFAULT_V2_AUTH_URL,
 | 
						|
               'OS_IMAGE_URL': DEFAULT_IMAGE_URL}
 | 
						|
 | 
						|
FAKE_V3_ENV = {'OS_USERNAME': DEFAULT_USERNAME,
 | 
						|
               'OS_PASSWORD': DEFAULT_PASSWORD,
 | 
						|
               'OS_PROJECT_ID': DEFAULT_PROJECT_ID,
 | 
						|
               'OS_USER_DOMAIN_NAME': DEFAULT_USER_DOMAIN_NAME,
 | 
						|
               'OS_AUTH_URL': DEFAULT_V3_AUTH_URL,
 | 
						|
               'OS_IMAGE_URL': DEFAULT_IMAGE_URL}
 | 
						|
 | 
						|
FAKE_V4_ENV = {'OS_USERNAME': DEFAULT_USERNAME,
 | 
						|
               'OS_PASSWORD': DEFAULT_PASSWORD,
 | 
						|
               'OS_PROJECT_ID': DEFAULT_PROJECT_ID,
 | 
						|
               'OS_USER_DOMAIN_NAME': DEFAULT_USER_DOMAIN_NAME,
 | 
						|
               'OS_AUTH_URL': DEFAULT_V3_AUTH_URL,
 | 
						|
               'OS_SERVICE_TYPE': DEFAULT_SERVICE_TYPE,
 | 
						|
               'OS_ENDPOINT_TYPE': DEFAULT_ENDPOINT_TYPE,
 | 
						|
               'OS_AUTH_TOKEN': DEFAULT_AUTH_TOKEN}
 | 
						|
 | 
						|
TOKEN_ID = uuid.uuid4().hex
 | 
						|
 | 
						|
V2_TOKEN = ks_fixture.V2Token(token_id=TOKEN_ID)
 | 
						|
V2_TOKEN.set_scope()
 | 
						|
_s = V2_TOKEN.add_service('image', name='glance')
 | 
						|
_s.add_endpoint(DEFAULT_IMAGE_URL)
 | 
						|
 | 
						|
V3_TOKEN = ks_fixture.V3Token()
 | 
						|
V3_TOKEN.set_project_scope()
 | 
						|
_s = V3_TOKEN.add_service('image', name='glance')
 | 
						|
_s.add_standard_endpoints(public=DEFAULT_IMAGE_URL,
 | 
						|
                          internal=DEFAULT_IMAGE_URL_INTERNAL)
 | 
						|
 | 
						|
 | 
						|
class ShellTest(testutils.TestCase):
 | 
						|
    # auth environment to use
 | 
						|
    auth_env = FAKE_V2_ENV.copy()
 | 
						|
    # expected auth plugin to invoke
 | 
						|
    token_url = DEFAULT_V2_AUTH_URL + '/tokens'
 | 
						|
 | 
						|
    # Patch os.environ to avoid required auth info
 | 
						|
    def make_env(self, exclude=None):
 | 
						|
        env = dict((k, v) for k, v in self.auth_env.items() if k != exclude)
 | 
						|
        self.useFixture(fixtures.MonkeyPatch('os.environ', env))
 | 
						|
 | 
						|
    def setUp(self):
 | 
						|
        super(ShellTest, self).setUp()
 | 
						|
        global _old_env
 | 
						|
        _old_env, os.environ = os.environ, self.auth_env
 | 
						|
 | 
						|
        self.requests = self.useFixture(rm_fixture.Fixture())
 | 
						|
 | 
						|
        json_list = ks_fixture.DiscoveryList(DEFAULT_UNVERSIONED_AUTH_URL)
 | 
						|
        self.requests.get(DEFAULT_UNVERSIONED_AUTH_URL,
 | 
						|
                          json=json_list,
 | 
						|
                          status_code=300)
 | 
						|
 | 
						|
        json_v2 = {'version': ks_fixture.V2Discovery(DEFAULT_V2_AUTH_URL)}
 | 
						|
        self.requests.get(DEFAULT_V2_AUTH_URL, json=json_v2)
 | 
						|
 | 
						|
        json_v3 = {'version': ks_fixture.V3Discovery(DEFAULT_V3_AUTH_URL)}
 | 
						|
        self.requests.get(DEFAULT_V3_AUTH_URL, json=json_v3)
 | 
						|
 | 
						|
        self.v2_auth = self.requests.post(DEFAULT_V2_AUTH_URL + '/tokens',
 | 
						|
                                          json=V2_TOKEN)
 | 
						|
 | 
						|
        headers = {'X-Subject-Token': TOKEN_ID}
 | 
						|
        self.v3_auth = self.requests.post(DEFAULT_V3_AUTH_URL + '/auth/tokens',
 | 
						|
                                          headers=headers,
 | 
						|
                                          json=V3_TOKEN)
 | 
						|
 | 
						|
        global shell, _shell, assert_called, assert_called_anytime
 | 
						|
        _shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        shell = lambda cmd: _shell.main(cmd.split())
 | 
						|
 | 
						|
    def tearDown(self):
 | 
						|
        super(ShellTest, self).tearDown()
 | 
						|
        global _old_env
 | 
						|
        os.environ = _old_env
 | 
						|
 | 
						|
    def shell(self, argstr, exitcodes=(0,)):
 | 
						|
        orig = sys.stdout
 | 
						|
        orig_stderr = sys.stderr
 | 
						|
        try:
 | 
						|
            sys.stdout = six.StringIO()
 | 
						|
            sys.stderr = six.StringIO()
 | 
						|
            _shell = openstack_shell.OpenStackImagesShell()
 | 
						|
            _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 test_fixup_subcommand(self):
 | 
						|
        arglist = [u'image-list', u'--help']
 | 
						|
        if six.PY2:
 | 
						|
            expected_arglist = [b'image-list', u'--help']
 | 
						|
        elif six.PY3:
 | 
						|
            expected_arglist = [u'image-list', u'--help']
 | 
						|
 | 
						|
        openstack_shell.OpenStackImagesShell._fixup_subcommand(
 | 
						|
            arglist, arglist
 | 
						|
        )
 | 
						|
        self.assertEqual(expected_arglist, arglist)
 | 
						|
 | 
						|
    def test_fixup_subcommand_with_options_preceding(self):
 | 
						|
        arglist = [u'--os-auth-token', u'abcdef', u'image-list', u'--help']
 | 
						|
        unknown = arglist[2:]
 | 
						|
        if six.PY2:
 | 
						|
            expected_arglist = [
 | 
						|
                u'--os-auth-token', u'abcdef', b'image-list', u'--help'
 | 
						|
            ]
 | 
						|
        elif six.PY3:
 | 
						|
            expected_arglist = [
 | 
						|
                u'--os-auth-token', u'abcdef', u'image-list', u'--help'
 | 
						|
            ]
 | 
						|
 | 
						|
        openstack_shell.OpenStackImagesShell._fixup_subcommand(
 | 
						|
            unknown, arglist
 | 
						|
        )
 | 
						|
        self.assertEqual(expected_arglist, arglist)
 | 
						|
 | 
						|
    def test_help_unknown_command(self):
 | 
						|
        shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        argstr = '--os-image-api-version 2 help foofoo'
 | 
						|
        self.assertRaises(exc.CommandError, shell.main, argstr.split())
 | 
						|
 | 
						|
    @mock.patch('sys.stdout', six.StringIO())
 | 
						|
    @mock.patch('sys.stderr', six.StringIO())
 | 
						|
    @mock.patch('sys.argv', ['glance', 'help', 'foofoo'])
 | 
						|
    def test_no_stacktrace_when_debug_disabled(self):
 | 
						|
        with mock.patch.object(traceback, 'print_exc') as mock_print_exc:
 | 
						|
            try:
 | 
						|
                openstack_shell.main()
 | 
						|
            except SystemExit:
 | 
						|
                pass
 | 
						|
            self.assertFalse(mock_print_exc.called)
 | 
						|
 | 
						|
    @mock.patch('sys.stdout', six.StringIO())
 | 
						|
    @mock.patch('sys.stderr', six.StringIO())
 | 
						|
    @mock.patch('sys.argv', ['glance', 'help', 'foofoo'])
 | 
						|
    def test_stacktrace_when_debug_enabled_by_env(self):
 | 
						|
        old_environment = os.environ.copy()
 | 
						|
        os.environ = {'GLANCECLIENT_DEBUG': '1'}
 | 
						|
        try:
 | 
						|
            with mock.patch.object(traceback, 'print_exc') as mock_print_exc:
 | 
						|
                try:
 | 
						|
                    openstack_shell.main()
 | 
						|
                except SystemExit:
 | 
						|
                    pass
 | 
						|
                self.assertTrue(mock_print_exc.called)
 | 
						|
        finally:
 | 
						|
            os.environ = old_environment
 | 
						|
 | 
						|
    @mock.patch('sys.stdout', six.StringIO())
 | 
						|
    @mock.patch('sys.stderr', six.StringIO())
 | 
						|
    @mock.patch('sys.argv', ['glance', '--debug', 'help', 'foofoo'])
 | 
						|
    def test_stacktrace_when_debug_enabled(self):
 | 
						|
        with mock.patch.object(traceback, 'print_exc') as mock_print_exc:
 | 
						|
            try:
 | 
						|
                openstack_shell.main()
 | 
						|
            except SystemExit:
 | 
						|
                pass
 | 
						|
            self.assertTrue(mock_print_exc.called)
 | 
						|
 | 
						|
    def test_help(self):
 | 
						|
        shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        argstr = '--os-image-api-version 2 help'
 | 
						|
        with mock.patch.object(shell, '_get_keystone_auth_plugin') as et_mock:
 | 
						|
            actual = shell.main(argstr.split())
 | 
						|
            self.assertEqual(0, actual)
 | 
						|
            self.assertFalse(et_mock.called)
 | 
						|
 | 
						|
    def test_blank_call(self):
 | 
						|
        shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        with mock.patch.object(shell, '_get_keystone_auth_plugin') as et_mock:
 | 
						|
            actual = shell.main('')
 | 
						|
            self.assertEqual(0, actual)
 | 
						|
            self.assertFalse(et_mock.called)
 | 
						|
 | 
						|
    def test_help_on_subcommand_error(self):
 | 
						|
        self.assertRaises(exc.CommandError, shell,
 | 
						|
                          '--os-image-api-version 2 help bad')
 | 
						|
 | 
						|
    def test_help_v2_no_schema(self):
 | 
						|
        shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        argstr = '--os-image-api-version 2 help image-create'
 | 
						|
        with mock.patch.object(shell, '_get_keystone_auth_plugin') as et_mock:
 | 
						|
            actual = shell.main(argstr.split())
 | 
						|
            self.assertEqual(0, actual)
 | 
						|
            self.assertNotIn('<unavailable>', actual)
 | 
						|
            self.assertFalse(et_mock.called)
 | 
						|
 | 
						|
        argstr = '--os-image-api-version 2 help md-namespace-create'
 | 
						|
        with mock.patch.object(shell, '_get_keystone_auth_plugin') as et_mock:
 | 
						|
            actual = shell.main(argstr.split())
 | 
						|
            self.assertEqual(0, actual)
 | 
						|
            self.assertNotIn('<unavailable>', actual)
 | 
						|
            self.assertFalse(et_mock.called)
 | 
						|
 | 
						|
        argstr = '--os-image-api-version 2 help md-resource-type-associate'
 | 
						|
        with mock.patch.object(shell, '_get_keystone_auth_plugin') as et_mock:
 | 
						|
            actual = shell.main(argstr.split())
 | 
						|
            self.assertEqual(0, actual)
 | 
						|
            self.assertNotIn('<unavailable>', actual)
 | 
						|
            self.assertFalse(et_mock.called)
 | 
						|
 | 
						|
    def test_get_base_parser(self):
 | 
						|
        test_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        # NOTE(stevemar): Use the current sys.argv for base_parser since it
 | 
						|
        # doesn't matter for this test, it just needs to initialize the CLI
 | 
						|
        actual_parser = test_shell.get_base_parser(sys.argv)
 | 
						|
        description = 'Command-line interface to the OpenStack Images API.'
 | 
						|
        expected = argparse.ArgumentParser(
 | 
						|
            prog='glance', usage=None,
 | 
						|
            description=description,
 | 
						|
            conflict_handler='error',
 | 
						|
            add_help=False,
 | 
						|
            formatter_class=openstack_shell.HelpFormatter,)
 | 
						|
        # NOTE(guochbo): Can't compare ArgumentParser instances directly
 | 
						|
        # Convert ArgumentPaser to string first.
 | 
						|
        self.assertEqual(str(expected), str(actual_parser))
 | 
						|
 | 
						|
    @mock.patch.object(openstack_shell.OpenStackImagesShell,
 | 
						|
                       '_get_versioned_client')
 | 
						|
    def test_cert_and_key_args_interchangeable(self,
 | 
						|
                                               mock_versioned_client):
 | 
						|
        # make sure --os-cert and --os-key are passed correctly
 | 
						|
        args = ('--os-image-api-version 2 '
 | 
						|
                '--os-cert mycert '
 | 
						|
                '--os-key mykey image-list')
 | 
						|
        shell(args)
 | 
						|
        assert mock_versioned_client.called
 | 
						|
        ((api_version, args), kwargs) = mock_versioned_client.call_args
 | 
						|
        self.assertEqual('mycert', args.os_cert)
 | 
						|
        self.assertEqual('mykey', args.os_key)
 | 
						|
 | 
						|
    @mock.patch('glanceclient.v1.client.Client')
 | 
						|
    def test_no_auth_with_token_and_image_url_with_v1(self, v1_client):
 | 
						|
        # test no authentication is required if both token and endpoint url
 | 
						|
        # are specified
 | 
						|
        args = ('--os-image-api-version 1 --os-auth-token mytoken'
 | 
						|
                ' --os-image-url https://image:1234/v1 image-list')
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        glance_shell.main(args.split())
 | 
						|
        assert v1_client.called
 | 
						|
        (args, kwargs) = v1_client.call_args
 | 
						|
        self.assertEqual('mytoken', kwargs['token'])
 | 
						|
        self.assertEqual('https://image:1234', args[0])
 | 
						|
 | 
						|
    @mock.patch('glanceclient.v2.client.Client')
 | 
						|
    def test_no_auth_with_token_and_image_url_with_v2(self, v2_client):
 | 
						|
        # test no authentication is required if both token and endpoint url
 | 
						|
        # are specified
 | 
						|
        args = ('--os-image-api-version 2 --os-auth-token mytoken '
 | 
						|
                '--os-image-url https://image:1234 image-list')
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        glance_shell.main(args.split())
 | 
						|
        self.assertTrue(v2_client.called)
 | 
						|
        (args, kwargs) = v2_client.call_args
 | 
						|
        self.assertEqual('mytoken', kwargs['token'])
 | 
						|
        self.assertEqual('https://image:1234', args[0])
 | 
						|
 | 
						|
    def _assert_auth_plugin_args(self):
 | 
						|
        # make sure our auth plugin is invoked with the correct args
 | 
						|
        self.assertFalse(self.v3_auth.called)
 | 
						|
 | 
						|
        body = json.loads(self.v2_auth.last_request.body)
 | 
						|
 | 
						|
        self.assertEqual(self.auth_env['OS_TENANT_NAME'],
 | 
						|
                         body['auth']['tenantName'])
 | 
						|
        self.assertEqual(self.auth_env['OS_USERNAME'],
 | 
						|
                         body['auth']['passwordCredentials']['username'])
 | 
						|
        self.assertEqual(self.auth_env['OS_PASSWORD'],
 | 
						|
                         body['auth']['passwordCredentials']['password'])
 | 
						|
 | 
						|
    @mock.patch.object(openstack_shell.OpenStackImagesShell, '_cache_schemas',
 | 
						|
                       return_value=False)
 | 
						|
    @mock.patch('glanceclient.v2.client.Client')
 | 
						|
    def test_auth_plugin_invocation_without_version(self,
 | 
						|
                                                    v2_client,
 | 
						|
                                                    cache_schemas):
 | 
						|
 | 
						|
        cli2 = mock.MagicMock()
 | 
						|
        v2_client.return_value = cli2
 | 
						|
        cli2.http_client.get.return_value = (None, {'versions':
 | 
						|
                                                    [{'id': 'v2'}]})
 | 
						|
 | 
						|
        args = 'image-list'
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        glance_shell.main(args.split())
 | 
						|
        # NOTE(flaper87): this currently calls auth twice since it'll
 | 
						|
        # authenticate to get the version list *and* to execute the command.
 | 
						|
        # This is not the ideal behavior and it should be fixed in a follow
 | 
						|
        # up patch.
 | 
						|
 | 
						|
    @mock.patch('glanceclient.v1.client.Client')
 | 
						|
    def test_auth_plugin_invocation_with_v1(self, v1_client):
 | 
						|
        args = '--os-image-api-version 1 image-list'
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        glance_shell.main(args.split())
 | 
						|
        self.assertEqual(0, self.v2_auth.call_count)
 | 
						|
 | 
						|
    @mock.patch('glanceclient.v2.client.Client')
 | 
						|
    def test_auth_plugin_invocation_with_v2(self,
 | 
						|
                                            v2_client):
 | 
						|
        args = '--os-image-api-version 2 image-list'
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        glance_shell.main(args.split())
 | 
						|
        self.assertEqual(0, self.v2_auth.call_count)
 | 
						|
 | 
						|
    @mock.patch('glanceclient.v1.client.Client')
 | 
						|
    def test_auth_plugin_invocation_with_unversioned_auth_url_with_v1(
 | 
						|
            self, v1_client):
 | 
						|
        args = ('--os-image-api-version 1 --os-auth-url %s image-list' %
 | 
						|
                DEFAULT_UNVERSIONED_AUTH_URL)
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        glance_shell.main(args.split())
 | 
						|
 | 
						|
    @mock.patch('glanceclient.v2.client.Client')
 | 
						|
    @mock.patch.object(openstack_shell.OpenStackImagesShell, '_cache_schemas',
 | 
						|
                       return_value=False)
 | 
						|
    def test_auth_plugin_invocation_with_unversioned_auth_url_with_v2(
 | 
						|
            self, v2_client, cache_schemas):
 | 
						|
        args = ('--os-auth-url %s --os-image-api-version 2 '
 | 
						|
                'image-list') % DEFAULT_UNVERSIONED_AUTH_URL
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        glance_shell.main(args.split())
 | 
						|
 | 
						|
    @mock.patch('glanceclient.Client')
 | 
						|
    def test_endpoint_token_no_auth_req(self, mock_client):
 | 
						|
 | 
						|
        def verify_input(version=None, endpoint=None, *args, **kwargs):
 | 
						|
            self.assertIn('token', kwargs)
 | 
						|
            self.assertEqual(TOKEN_ID, kwargs['token'])
 | 
						|
            self.assertEqual(DEFAULT_IMAGE_URL, endpoint)
 | 
						|
            return mock.MagicMock()
 | 
						|
 | 
						|
        mock_client.side_effect = verify_input
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        args = ['--os-image-api-version', '2',
 | 
						|
                '--os-auth-token', TOKEN_ID,
 | 
						|
                '--os-image-url', DEFAULT_IMAGE_URL,
 | 
						|
                'image-list']
 | 
						|
 | 
						|
        glance_shell.main(args)
 | 
						|
        self.assertEqual(1, mock_client.call_count)
 | 
						|
 | 
						|
    @mock.patch('sys.stdin', side_effect=mock.MagicMock)
 | 
						|
    @mock.patch('getpass.getpass', side_effect=EOFError)
 | 
						|
    @mock.patch('glanceclient.v2.client.Client')
 | 
						|
    def test_password_prompted_ctrlD_with_v2(self, v2_client,
 | 
						|
                                             mock_getpass, mock_stdin):
 | 
						|
        cli2 = mock.MagicMock()
 | 
						|
        v2_client.return_value = cli2
 | 
						|
        cli2.http_client.get.return_value = (None, {'versions': []})
 | 
						|
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        self.make_env(exclude='OS_PASSWORD')
 | 
						|
        # We should get Command Error because we mock Ctl-D.
 | 
						|
        self.assertRaises(exc.CommandError, glance_shell.main, ['image-list'])
 | 
						|
        # Make sure we are actually prompted.
 | 
						|
        mock_getpass.assert_called_with('OS Password: ')
 | 
						|
 | 
						|
    @mock.patch(
 | 
						|
        'glanceclient.shell.OpenStackImagesShell._get_keystone_auth_plugin')
 | 
						|
    @mock.patch.object(openstack_shell.OpenStackImagesShell, '_cache_schemas',
 | 
						|
                       return_value=False)
 | 
						|
    def test_no_auth_with_proj_name(self, cache_schemas, session):
 | 
						|
        with mock.patch('glanceclient.v2.client.Client'):
 | 
						|
            args = ('--os-project-name myname '
 | 
						|
                    '--os-project-domain-name mydomain '
 | 
						|
                    '--os-project-domain-id myid '
 | 
						|
                    '--os-image-api-version 2 image-list')
 | 
						|
            glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
            glance_shell.main(args.split())
 | 
						|
            ((args), kwargs) = session.call_args
 | 
						|
            self.assertEqual('myname', kwargs['project_name'])
 | 
						|
            self.assertEqual('mydomain', kwargs['project_domain_name'])
 | 
						|
            self.assertEqual('myid', kwargs['project_domain_id'])
 | 
						|
 | 
						|
    @mock.patch.object(openstack_shell.OpenStackImagesShell, 'main')
 | 
						|
    def test_shell_keyboard_interrupt(self, mock_glance_shell):
 | 
						|
        # Ensure that exit code is 130 for KeyboardInterrupt
 | 
						|
        try:
 | 
						|
            mock_glance_shell.side_effect = KeyboardInterrupt()
 | 
						|
            openstack_shell.main()
 | 
						|
        except SystemExit as ex:
 | 
						|
            self.assertEqual(130, ex.code)
 | 
						|
 | 
						|
    @mock.patch('glanceclient.common.utils.exit', side_effect=utils.exit)
 | 
						|
    def test_shell_illegal_version(self, mock_exit):
 | 
						|
        # Only int versions are allowed on cli
 | 
						|
        shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        argstr = '--os-image-api-version 1.1 image-list'
 | 
						|
        try:
 | 
						|
            shell.main(argstr.split())
 | 
						|
        except SystemExit as ex:
 | 
						|
            self.assertEqual(1, ex.code)
 | 
						|
        msg = ("Invalid API version parameter. "
 | 
						|
               "Supported values are %s" % openstack_shell.SUPPORTED_VERSIONS)
 | 
						|
        mock_exit.assert_called_with(msg=msg)
 | 
						|
 | 
						|
    @mock.patch('glanceclient.common.utils.exit', side_effect=utils.exit)
 | 
						|
    def test_shell_unsupported_version(self, mock_exit):
 | 
						|
        # Test an integer version which is not supported (-1)
 | 
						|
        shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        argstr = '--os-image-api-version -1 image-list'
 | 
						|
        try:
 | 
						|
            shell.main(argstr.split())
 | 
						|
        except SystemExit as ex:
 | 
						|
            self.assertEqual(1, ex.code)
 | 
						|
        msg = ("Invalid API version parameter. "
 | 
						|
               "Supported values are %s" % openstack_shell.SUPPORTED_VERSIONS)
 | 
						|
        mock_exit.assert_called_with(msg=msg)
 | 
						|
 | 
						|
    @mock.patch.object(openstack_shell.OpenStackImagesShell,
 | 
						|
                       'get_subcommand_parser')
 | 
						|
    def test_shell_import_error_with_mesage(self, mock_parser):
 | 
						|
        msg = 'Unable to import module xxx'
 | 
						|
        mock_parser.side_effect = ImportError('%s' % msg)
 | 
						|
        shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        argstr = '--os-image-api-version 2 image-list'
 | 
						|
        try:
 | 
						|
            shell.main(argstr.split())
 | 
						|
            self.fail('No import error returned')
 | 
						|
        except ImportError as e:
 | 
						|
            self.assertEqual(msg, str(e))
 | 
						|
 | 
						|
    @mock.patch.object(openstack_shell.OpenStackImagesShell,
 | 
						|
                       'get_subcommand_parser')
 | 
						|
    def test_shell_import_error_default_message(self, mock_parser):
 | 
						|
        mock_parser.side_effect = ImportError
 | 
						|
        shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        argstr = '--os-image-api-version 2 image-list'
 | 
						|
        try:
 | 
						|
            shell.main(argstr.split())
 | 
						|
            self.fail('No import error returned')
 | 
						|
        except ImportError as e:
 | 
						|
            msg = 'Unable to import module. Re-run with --debug for more info.'
 | 
						|
            self.assertEqual(msg, str(e))
 | 
						|
 | 
						|
    @mock.patch('glanceclient.v2.client.Client')
 | 
						|
    @mock.patch('glanceclient.v1.images.ImageManager.list')
 | 
						|
    def test_shell_v1_fallback_from_v2(self, v1_imgs, v2_client):
 | 
						|
        self.make_env()
 | 
						|
        cli2 = mock.MagicMock()
 | 
						|
        v2_client.return_value = cli2
 | 
						|
        cli2.http_client.get.return_value = (None, {'versions': []})
 | 
						|
        args = 'image-list'
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        glance_shell.main(args.split())
 | 
						|
        self.assertFalse(cli2.schemas.get.called)
 | 
						|
        self.assertTrue(v1_imgs.called)
 | 
						|
 | 
						|
    @mock.patch.object(openstack_shell.OpenStackImagesShell,
 | 
						|
                       '_cache_schemas')
 | 
						|
    @mock.patch('glanceclient.v2.client.Client')
 | 
						|
    def test_shell_no_fallback_from_v2(self, v2_client, cache_schemas):
 | 
						|
        self.make_env()
 | 
						|
        cli2 = mock.MagicMock()
 | 
						|
        v2_client.return_value = cli2
 | 
						|
        cli2.http_client.get.return_value = (None,
 | 
						|
                                             {'versions': [{'id': 'v2'}]})
 | 
						|
        cache_schemas.return_value = False
 | 
						|
        args = 'image-list'
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        glance_shell.main(args.split())
 | 
						|
        self.assertTrue(cli2.images.list.called)
 | 
						|
 | 
						|
    @mock.patch('glanceclient.v1.client.Client')
 | 
						|
    def test_auth_plugin_invocation_without_username_with_v1(self, v1_client):
 | 
						|
        self.make_env(exclude='OS_USERNAME')
 | 
						|
        args = '--os-image-api-version 2 image-list'
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        self.assertRaises(exc.CommandError, glance_shell.main, args.split())
 | 
						|
 | 
						|
    @mock.patch('glanceclient.v2.client.Client')
 | 
						|
    def test_auth_plugin_invocation_without_username_with_v2(self, v2_client):
 | 
						|
        self.make_env(exclude='OS_USERNAME')
 | 
						|
        args = '--os-image-api-version 2 image-list'
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        self.assertRaises(exc.CommandError, glance_shell.main, args.split())
 | 
						|
 | 
						|
    @mock.patch('glanceclient.v1.client.Client')
 | 
						|
    def test_auth_plugin_invocation_without_auth_url_with_v1(self, v1_client):
 | 
						|
        self.make_env(exclude='OS_AUTH_URL')
 | 
						|
        args = '--os-image-api-version 1 image-list'
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        self.assertRaises(exc.CommandError, glance_shell.main, args.split())
 | 
						|
 | 
						|
    @mock.patch('glanceclient.v2.client.Client')
 | 
						|
    def test_auth_plugin_invocation_without_auth_url_with_v2(self, v2_client):
 | 
						|
        self.make_env(exclude='OS_AUTH_URL')
 | 
						|
        args = '--os-image-api-version 2 image-list'
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        self.assertRaises(exc.CommandError, glance_shell.main, args.split())
 | 
						|
 | 
						|
    @mock.patch('glanceclient.v1.client.Client')
 | 
						|
    def test_auth_plugin_invocation_without_tenant_with_v1(self, v1_client):
 | 
						|
        if 'OS_TENANT_NAME' in os.environ:
 | 
						|
            self.make_env(exclude='OS_TENANT_NAME')
 | 
						|
        if 'OS_PROJECT_ID' in os.environ:
 | 
						|
            self.make_env(exclude='OS_PROJECT_ID')
 | 
						|
        args = '--os-image-api-version 1 image-list'
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        self.assertRaises(exc.CommandError, glance_shell.main, args.split())
 | 
						|
 | 
						|
    @mock.patch('glanceclient.v2.client.Client')
 | 
						|
    @mock.patch.object(openstack_shell.OpenStackImagesShell, '_cache_schemas',
 | 
						|
                       return_value=False)
 | 
						|
    def test_auth_plugin_invocation_without_tenant_with_v2(self, v2_client,
 | 
						|
                                                           cache_schemas):
 | 
						|
        if 'OS_TENANT_NAME' in os.environ:
 | 
						|
            self.make_env(exclude='OS_TENANT_NAME')
 | 
						|
        if 'OS_PROJECT_ID' in os.environ:
 | 
						|
            self.make_env(exclude='OS_PROJECT_ID')
 | 
						|
        args = '--os-image-api-version 2 image-list'
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        self.assertRaises(exc.CommandError, glance_shell.main, args.split())
 | 
						|
 | 
						|
    @mock.patch('sys.argv', ['glance'])
 | 
						|
    @mock.patch('sys.stdout', six.StringIO())
 | 
						|
    @mock.patch('sys.stderr', six.StringIO())
 | 
						|
    def test_main_noargs(self):
 | 
						|
        # Ensure that main works with no command-line arguments
 | 
						|
        try:
 | 
						|
            openstack_shell.main()
 | 
						|
        except SystemExit:
 | 
						|
            self.fail('Unexpected SystemExit')
 | 
						|
 | 
						|
        # We expect the normal v2 usage as a result
 | 
						|
        expected = ['Command-line interface to the OpenStack Images API',
 | 
						|
                    'image-list',
 | 
						|
                    'image-deactivate',
 | 
						|
                    'location-add']
 | 
						|
        for output in expected:
 | 
						|
            self.assertIn(output,
 | 
						|
                          sys.stdout.getvalue())
 | 
						|
 | 
						|
    @mock.patch('glanceclient.v2.client.Client')
 | 
						|
    @mock.patch('glanceclient.v1.shell.do_image_list')
 | 
						|
    @mock.patch('glanceclient.shell.logging.basicConfig')
 | 
						|
    def test_setup_debug(self, conf, func, v2_client):
 | 
						|
        cli2 = mock.MagicMock()
 | 
						|
        v2_client.return_value = cli2
 | 
						|
        cli2.http_client.get.return_value = (None, {'versions': []})
 | 
						|
        args = '--debug image-list'
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        glance_shell.main(args.split())
 | 
						|
        glance_logger = logging.getLogger('glanceclient')
 | 
						|
        self.assertEqual(glance_logger.getEffectiveLevel(), logging.DEBUG)
 | 
						|
        conf.assert_called_with(level=logging.DEBUG)
 | 
						|
 | 
						|
 | 
						|
class ShellTestWithKeystoneV3Auth(ShellTest):
 | 
						|
    # auth environment to use
 | 
						|
    auth_env = FAKE_V3_ENV.copy()
 | 
						|
    token_url = DEFAULT_V3_AUTH_URL + '/auth/tokens'
 | 
						|
 | 
						|
    def _assert_auth_plugin_args(self):
 | 
						|
        self.assertFalse(self.v2_auth.called)
 | 
						|
 | 
						|
        body = json.loads(self.v3_auth.last_request.body)
 | 
						|
        user = body['auth']['identity']['password']['user']
 | 
						|
 | 
						|
        self.assertEqual(self.auth_env['OS_USERNAME'], user['name'])
 | 
						|
        self.assertEqual(self.auth_env['OS_PASSWORD'], user['password'])
 | 
						|
        self.assertEqual(self.auth_env['OS_USER_DOMAIN_NAME'],
 | 
						|
                         user['domain']['name'])
 | 
						|
        self.assertEqual(self.auth_env['OS_PROJECT_ID'],
 | 
						|
                         body['auth']['scope']['project']['id'])
 | 
						|
 | 
						|
    @mock.patch('glanceclient.v1.client.Client')
 | 
						|
    def test_auth_plugin_invocation_with_v1(self, v1_client):
 | 
						|
        args = '--os-image-api-version 1 image-list'
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        glance_shell.main(args.split())
 | 
						|
        self.assertEqual(0, self.v3_auth.call_count)
 | 
						|
 | 
						|
    @mock.patch('glanceclient.v2.client.Client')
 | 
						|
    def test_auth_plugin_invocation_with_v2(self, v2_client):
 | 
						|
        args = '--os-image-api-version 2 image-list'
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        glance_shell.main(args.split())
 | 
						|
        self.assertEqual(0, self.v3_auth.call_count)
 | 
						|
 | 
						|
    @mock.patch('keystoneauth1.discover.Discover',
 | 
						|
                side_effect=ks_exc.ClientException())
 | 
						|
    def test_api_discovery_failed_with_unversioned_auth_url(self,
 | 
						|
                                                            discover):
 | 
						|
        args = ('--os-image-api-version 2 --os-auth-url %s image-list'
 | 
						|
                % DEFAULT_UNVERSIONED_AUTH_URL)
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        self.assertRaises(exc.CommandError, glance_shell.main, args.split())
 | 
						|
 | 
						|
    def test_bash_completion(self):
 | 
						|
        stdout, stderr = self.shell('--os-image-api-version 2 bash_completion')
 | 
						|
        # just check we have some output
 | 
						|
        required = [
 | 
						|
            '--status',
 | 
						|
            'image-create',
 | 
						|
            'help',
 | 
						|
            '--size']
 | 
						|
        for r in required:
 | 
						|
            self.assertIn(r, stdout.split())
 | 
						|
        avoided = [
 | 
						|
            'bash_completion',
 | 
						|
            'bash-completion']
 | 
						|
        for r in avoided:
 | 
						|
            self.assertNotIn(r, stdout.split())
 | 
						|
 | 
						|
 | 
						|
class ShellTestWithNoOSImageURLPublic(ShellTestWithKeystoneV3Auth):
 | 
						|
    # auth environment to use
 | 
						|
    # default uses public
 | 
						|
    auth_env = FAKE_V4_ENV.copy()
 | 
						|
 | 
						|
    def setUp(self):
 | 
						|
        super(ShellTestWithNoOSImageURLPublic, self).setUp()
 | 
						|
        self.image_url = DEFAULT_IMAGE_URL
 | 
						|
        self.requests.get(DEFAULT_IMAGE_URL + 'v2/images',
 | 
						|
                          text='{"images": []}')
 | 
						|
 | 
						|
    @mock.patch('glanceclient.v1.client.Client')
 | 
						|
    def test_auth_plugin_invocation_with_v1(self, v1_client):
 | 
						|
        args = '--os-image-api-version 1 image-list'
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        glance_shell.main(args.split())
 | 
						|
        self.assertEqual(1, self.v3_auth.call_count)
 | 
						|
        self._assert_auth_plugin_args()
 | 
						|
 | 
						|
    @mock.patch('glanceclient.v2.client.Client')
 | 
						|
    def test_auth_plugin_invocation_with_v2(self, v2_client):
 | 
						|
        args = '--os-image-api-version 2 image-list'
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        glance_shell.main(args.split())
 | 
						|
        self.assertEqual(1, self.v3_auth.call_count)
 | 
						|
        self._assert_auth_plugin_args()
 | 
						|
 | 
						|
    @mock.patch('glanceclient.v2.client.Client')
 | 
						|
    def test_endpoint_from_interface(self, v2_client):
 | 
						|
        args = ('--os-image-api-version 2 image-list')
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        glance_shell.main(args.split())
 | 
						|
        assert v2_client.called
 | 
						|
        (args, kwargs) = v2_client.call_args
 | 
						|
        self.assertEqual(self.image_url, kwargs['endpoint_override'])
 | 
						|
 | 
						|
    def test_endpoint_real_from_interface(self):
 | 
						|
        args = ('--os-image-api-version 2 image-list')
 | 
						|
        glance_shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        glance_shell.main(args.split())
 | 
						|
        self.assertEqual(self.requests.request_history[2].url,
 | 
						|
                         self.image_url + "v2/images?limit=20&"
 | 
						|
                         "sort_key=name&sort_dir=asc")
 | 
						|
 | 
						|
 | 
						|
class ShellTestWithNoOSImageURLInternal(ShellTestWithNoOSImageURLPublic):
 | 
						|
    # auth environment to use
 | 
						|
    # this uses internal
 | 
						|
    FAKE_V5_ENV = FAKE_V4_ENV.copy()
 | 
						|
    FAKE_V5_ENV['OS_ENDPOINT_TYPE'] = 'internal'
 | 
						|
    auth_env = FAKE_V5_ENV.copy()
 | 
						|
 | 
						|
    def setUp(self):
 | 
						|
        super(ShellTestWithNoOSImageURLPublic, self).setUp()
 | 
						|
        self.image_url = DEFAULT_IMAGE_URL_INTERNAL
 | 
						|
        self.requests.get(DEFAULT_IMAGE_URL_INTERNAL + 'v2/images',
 | 
						|
                          text='{"images": []}')
 | 
						|
 | 
						|
 | 
						|
class ShellCacheSchemaTest(testutils.TestCase):
 | 
						|
    def setUp(self):
 | 
						|
        super(ShellCacheSchemaTest, self).setUp()
 | 
						|
        self._mock_client_setup()
 | 
						|
        self._mock_shell_setup()
 | 
						|
        self.cache_dir = '/dir_for_cached_schema'
 | 
						|
        self.os_auth_url = 'http://localhost:5000/v2'
 | 
						|
        url_hex = hashlib.sha1(self.os_auth_url.encode('utf-8')).hexdigest()
 | 
						|
        self.prefix_path = (self.cache_dir + '/' + url_hex)
 | 
						|
        self.cache_files = [self.prefix_path + '/image_schema.json',
 | 
						|
                            self.prefix_path + '/namespace_schema.json',
 | 
						|
                            self.prefix_path + '/resource_type_schema.json']
 | 
						|
 | 
						|
    def tearDown(self):
 | 
						|
        super(ShellCacheSchemaTest, self).tearDown()
 | 
						|
 | 
						|
    def _mock_client_setup(self):
 | 
						|
        self.schema_dict = {
 | 
						|
            'name': 'image',
 | 
						|
            'properties': {
 | 
						|
                'name': {'type': 'string', 'description': 'Name of image'},
 | 
						|
            },
 | 
						|
        }
 | 
						|
 | 
						|
        self.client = mock.Mock()
 | 
						|
        schema_odict = OrderedDict(self.schema_dict)
 | 
						|
        self.client.schemas.get.return_value = schemas.Schema(schema_odict)
 | 
						|
 | 
						|
    def _mock_shell_setup(self):
 | 
						|
        self.shell = openstack_shell.OpenStackImagesShell()
 | 
						|
        self.shell._get_versioned_client = mock.create_autospec(
 | 
						|
            self.shell._get_versioned_client, return_value=self.client,
 | 
						|
            spec_set=True
 | 
						|
        )
 | 
						|
 | 
						|
    def _make_args(self, args):
 | 
						|
        class Args(object):
 | 
						|
            def __init__(self, entries):
 | 
						|
                self.__dict__.update(entries)
 | 
						|
 | 
						|
        return Args(args)
 | 
						|
 | 
						|
    @mock.patch('six.moves.builtins.open', new=mock.mock_open(), create=True)
 | 
						|
    @mock.patch('os.path.exists', return_value=True)
 | 
						|
    def test_cache_schemas_gets_when_forced(self, exists_mock):
 | 
						|
        options = {
 | 
						|
            'get_schema': True,
 | 
						|
            'os_auth_url': self.os_auth_url
 | 
						|
        }
 | 
						|
        schema_odict = OrderedDict(self.schema_dict)
 | 
						|
 | 
						|
        args = self._make_args(options)
 | 
						|
        client = self.shell._get_versioned_client('2', args)
 | 
						|
        self.shell._cache_schemas(args, client, home_dir=self.cache_dir)
 | 
						|
 | 
						|
        self.assertEqual(12, open.mock_calls.__len__())
 | 
						|
        self.assertEqual(mock.call(self.cache_files[0], 'w'),
 | 
						|
                         open.mock_calls[0])
 | 
						|
        self.assertEqual(mock.call(self.cache_files[1], 'w'),
 | 
						|
                         open.mock_calls[4])
 | 
						|
        actual = json.loads(open.mock_calls[2][1][0])
 | 
						|
        self.assertEqual(schema_odict, actual)
 | 
						|
        actual = json.loads(open.mock_calls[6][1][0])
 | 
						|
        self.assertEqual(schema_odict, actual)
 | 
						|
 | 
						|
    @mock.patch('six.moves.builtins.open', new=mock.mock_open(), create=True)
 | 
						|
    @mock.patch('os.path.exists', side_effect=[True, False, False, False])
 | 
						|
    def test_cache_schemas_gets_when_not_exists(self, exists_mock):
 | 
						|
        options = {
 | 
						|
            'get_schema': False,
 | 
						|
            'os_auth_url': self.os_auth_url
 | 
						|
        }
 | 
						|
        schema_odict = OrderedDict(self.schema_dict)
 | 
						|
 | 
						|
        args = self._make_args(options)
 | 
						|
        client = self.shell._get_versioned_client('2', args)
 | 
						|
        self.shell._cache_schemas(args, client, home_dir=self.cache_dir)
 | 
						|
 | 
						|
        self.assertEqual(12, open.mock_calls.__len__())
 | 
						|
        self.assertEqual(mock.call(self.cache_files[0], 'w'),
 | 
						|
                         open.mock_calls[0])
 | 
						|
        self.assertEqual(mock.call(self.cache_files[1], 'w'),
 | 
						|
                         open.mock_calls[4])
 | 
						|
        actual = json.loads(open.mock_calls[2][1][0])
 | 
						|
        self.assertEqual(schema_odict, actual)
 | 
						|
        actual = json.loads(open.mock_calls[6][1][0])
 | 
						|
        self.assertEqual(schema_odict, actual)
 | 
						|
 | 
						|
    @mock.patch('six.moves.builtins.open', new=mock.mock_open(), create=True)
 | 
						|
    @mock.patch('os.path.exists', return_value=True)
 | 
						|
    def test_cache_schemas_leaves_when_present_not_forced(self, exists_mock):
 | 
						|
        options = {
 | 
						|
            'get_schema': False,
 | 
						|
            'os_auth_url': self.os_auth_url
 | 
						|
        }
 | 
						|
 | 
						|
        client = mock.MagicMock()
 | 
						|
        self.shell._cache_schemas(self._make_args(options),
 | 
						|
                                  client, home_dir=self.cache_dir)
 | 
						|
 | 
						|
        exists_mock.assert_has_calls([
 | 
						|
            mock.call(self.prefix_path),
 | 
						|
            mock.call(self.cache_files[0]),
 | 
						|
            mock.call(self.cache_files[1]),
 | 
						|
            mock.call(self.cache_files[2])
 | 
						|
        ])
 | 
						|
        self.assertEqual(4, exists_mock.call_count)
 | 
						|
        self.assertEqual(0, open.mock_calls.__len__())
 | 
						|
 | 
						|
    @mock.patch('six.moves.builtins.open', new=mock.mock_open(), create=True)
 | 
						|
    @mock.patch('os.path.exists', return_value=True)
 | 
						|
    def test_cache_schemas_leaves_auto_switch(self, exists_mock):
 | 
						|
        options = {
 | 
						|
            'get_schema': True,
 | 
						|
            'os_auth_url': self.os_auth_url
 | 
						|
        }
 | 
						|
 | 
						|
        self.client.schemas.get.return_value = Exception()
 | 
						|
 | 
						|
        client = mock.MagicMock()
 | 
						|
        switch_version = self.shell._cache_schemas(self._make_args(options),
 | 
						|
                                                   client,
 | 
						|
                                                   home_dir=self.cache_dir)
 | 
						|
        self.assertEqual(True, switch_version)
 | 
						|
 | 
						|
 | 
						|
class ShellTestRequests(testutils.TestCase):
 | 
						|
    """Shell tests using the requests mock library."""
 | 
						|
    def _make_args(self, args):
 | 
						|
        # NOTE(venkatesh): this conversion from a dict to an object
 | 
						|
        # is required because the test_shell.do_xxx(gc, args) methods
 | 
						|
        # expects the args to be attributes of an object. If passed as
 | 
						|
        # dict directly, it throws an AttributeError.
 | 
						|
        class Args(object):
 | 
						|
            def __init__(self, entries):
 | 
						|
                self.__dict__.update(entries)
 | 
						|
 | 
						|
        return Args(args)
 | 
						|
 | 
						|
    def setUp(self):
 | 
						|
        super(ShellTestRequests, self).setUp()
 | 
						|
        self._old_env = os.environ
 | 
						|
        os.environ = {}
 | 
						|
 | 
						|
    def tearDown(self):
 | 
						|
        super(ShellTestRequests, self).tearDown()
 | 
						|
        os.environ = self._old_env
 | 
						|
 | 
						|
    def test_download_has_no_stray_output_to_stdout(self):
 | 
						|
        """Regression test for bug 1488914"""
 | 
						|
        saved_stdout = sys.stdout
 | 
						|
        try:
 | 
						|
            sys.stdout = output = testutils.FakeNoTTYStdout()
 | 
						|
            id = image_show_fixture['id']
 | 
						|
            self.requests = self.useFixture(rm_fixture.Fixture())
 | 
						|
            self.requests.get('http://example.com/versions',
 | 
						|
                              json=image_versions_fixture)
 | 
						|
 | 
						|
            headers = {'Content-Length': '4',
 | 
						|
                       'Content-type': 'application/octet-stream'}
 | 
						|
            fake = testutils.FakeResponse(headers, six.StringIO('DATA'))
 | 
						|
            self.requests.get('http://example.com/v1/images/%s' % id,
 | 
						|
                              raw=fake)
 | 
						|
 | 
						|
            self.requests.get('http://example.com/v1/images/detail'
 | 
						|
                              '?sort_key=name&sort_dir=asc&limit=20')
 | 
						|
 | 
						|
            headers = {'X-Image-Meta-Id': id}
 | 
						|
            self.requests.head('http://example.com/v1/images/%s' % id,
 | 
						|
                               headers=headers)
 | 
						|
 | 
						|
            with mock.patch.object(openstack_shell.OpenStackImagesShell,
 | 
						|
                                   '_cache_schemas') as mocked_cache_schema:
 | 
						|
                mocked_cache_schema.return_value = True
 | 
						|
                shell = openstack_shell.OpenStackImagesShell()
 | 
						|
                argstr = ('--os-auth-token faketoken '
 | 
						|
                          '--os-image-url http://example.com '
 | 
						|
                          'image-download %s' % id)
 | 
						|
                shell.main(argstr.split())
 | 
						|
                self.assertTrue(mocked_cache_schema.called)
 | 
						|
            # Ensure we have *only* image data
 | 
						|
            self.assertEqual('DATA', output.getvalue())
 | 
						|
        finally:
 | 
						|
            sys.stdout = saved_stdout
 | 
						|
 | 
						|
    def test_v1_download_has_no_stray_output_to_stdout(self):
 | 
						|
        """Ensure no stray print statements corrupt the image"""
 | 
						|
        saved_stdout = sys.stdout
 | 
						|
        try:
 | 
						|
            sys.stdout = output = testutils.FakeNoTTYStdout()
 | 
						|
            id = image_show_fixture['id']
 | 
						|
 | 
						|
            self.requests = self.useFixture(rm_fixture.Fixture())
 | 
						|
            headers = {'X-Image-Meta-Id': id}
 | 
						|
            self.requests.head('http://example.com/v1/images/%s' % id,
 | 
						|
                               headers=headers)
 | 
						|
 | 
						|
            headers = {'Content-Length': '4',
 | 
						|
                       'Content-type': 'application/octet-stream'}
 | 
						|
            fake = testutils.FakeResponse(headers, six.StringIO('DATA'))
 | 
						|
            self.requests.get('http://example.com/v1/images/%s' % id,
 | 
						|
                              headers=headers, raw=fake)
 | 
						|
 | 
						|
            shell = openstack_shell.OpenStackImagesShell()
 | 
						|
            argstr = ('--os-image-api-version 1 --os-auth-token faketoken '
 | 
						|
                      '--os-image-url http://example.com '
 | 
						|
                      'image-download %s' % id)
 | 
						|
            shell.main(argstr.split())
 | 
						|
            # Ensure we have *only* image data
 | 
						|
            self.assertEqual('DATA', output.getvalue())
 | 
						|
        finally:
 | 
						|
            sys.stdout = saved_stdout
 | 
						|
 | 
						|
    def test_v2_download_has_no_stray_output_to_stdout(self):
 | 
						|
        """Ensure no stray print statements corrupt the image"""
 | 
						|
        saved_stdout = sys.stdout
 | 
						|
        try:
 | 
						|
            sys.stdout = output = testutils.FakeNoTTYStdout()
 | 
						|
            id = image_show_fixture['id']
 | 
						|
            headers = {'Content-Length': '4',
 | 
						|
                       'Content-type': 'application/octet-stream'}
 | 
						|
            fake = testutils.FakeResponse(headers, six.StringIO('DATA'))
 | 
						|
 | 
						|
            self.requests = self.useFixture(rm_fixture.Fixture())
 | 
						|
            self.requests.get('http://example.com/v2/images/%s/file' % id,
 | 
						|
                              headers=headers, raw=fake)
 | 
						|
 | 
						|
            shell = openstack_shell.OpenStackImagesShell()
 | 
						|
            argstr = ('--os-image-api-version 2 --os-auth-token faketoken '
 | 
						|
                      '--os-image-url http://example.com '
 | 
						|
                      'image-download %s' % id)
 | 
						|
            shell.main(argstr.split())
 | 
						|
            # Ensure we have *only* image data
 | 
						|
            self.assertEqual('DATA', output.getvalue())
 | 
						|
        finally:
 | 
						|
            sys.stdout = saved_stdout
 |