зеркало из https://github.com/microsoft/azure-cli.git
Merge branch 'master' of https://github.com/tjprescott/azure-cli into StorageAccountMergeAttempt2
# Conflicts: # azure-cli.pyproj # src/command_modules/azure-cli-resource/azure/cli/command_modules/resource/__init__.py # testall.bat
This commit is contained in:
Коммит
a40fcbdb90
|
@ -12,7 +12,7 @@
|
|||
<OutputPath>.</OutputPath>
|
||||
<ProjectTypeGuids>{888888a0-9f3d-457c-b088-3a5042f75d52}</ProjectTypeGuids>
|
||||
<LaunchProvider>Standard Python launcher</LaunchProvider>
|
||||
<InterpreterId>{1dd9c42b-5980-42ce-a2c3-46d3bf0eede4}</InterpreterId>
|
||||
<InterpreterId>{54f4b6dc-0859-46dc-99bb-b275c9d0aca3}</InterpreterId>
|
||||
<InterpreterVersion>3.5</InterpreterVersion>
|
||||
<EnableNativeCodeDebugging>False</EnableNativeCodeDebugging>
|
||||
<CommandLineArguments>
|
||||
|
@ -36,6 +36,10 @@
|
|||
<Compile Include="azure\cli\extensions\transform.py" />
|
||||
<Compile Include="azure\cli\extensions\__init__.py" />
|
||||
<Compile Include="azure\cli\main.py" />
|
||||
<Compile Include="azure\cli\tests\test_add_resourcegroup_transform.py" />
|
||||
<Compile Include="command_modules\azure-cli-resource\azure\cli\command_modules\resource\tests\test_api_check.py">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="azure\cli\parser.py" />
|
||||
<Compile Include="azure\cli\tests\test_add_resourcegroup_transform.py" />
|
||||
<Compile Include="azure\cli\tests\test_parser.py" />
|
||||
|
@ -178,6 +182,19 @@
|
|||
<Content Include="command_modules\azure-cli-taskhelp\requirements.txt" />
|
||||
<Content Include="command_modules\azure-cli-vm\requirements.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Interpreter Include="..\env\">
|
||||
<Id>{54f4b6dc-0859-46dc-99bb-b275c9d0aca3}</Id>
|
||||
<BaseInterpreter>{2af0f10d-7135-4994-9156-5d01c9c11b7e}</BaseInterpreter>
|
||||
<Version>3.5</Version>
|
||||
<Description>env (Python 3.5)</Description>
|
||||
<InterpreterPath>Scripts\python.exe</InterpreterPath>
|
||||
<WindowsInterpreterPath>Scripts\pythonw.exe</WindowsInterpreterPath>
|
||||
<LibraryPath>Lib\</LibraryPath>
|
||||
<PathEnvironmentVariable>PYTHONPATH</PathEnvironmentVariable>
|
||||
<Architecture>X86</Architecture>
|
||||
</Interpreter>
|
||||
</ItemGroup>
|
||||
<Import Project="$(PtvsTargetsFile)" Condition="Exists($(PtvsTargetsFile))" />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.Common.targets" Condition="!Exists($(PtvsTargetsFile))" />
|
||||
</Project>
|
11
setup.py
11
setup.py
|
@ -21,13 +21,14 @@ from codecs import open
|
|||
from setuptools import setup
|
||||
|
||||
VERSION = '0.0.32'
|
||||
INSTALL_FROM_PUBLIC = False
|
||||
|
||||
PRIVATE_PYPI_URL_ENV_NAME = 'AZURE_CLI_PRIVATE_PYPI_URL'
|
||||
PRIVATE_PYPI_URL = os.environ.get(PRIVATE_PYPI_URL_ENV_NAME)
|
||||
PRIVATE_PYPI_HOST_ENV_NAME = 'AZURE_CLI_PRIVATE_PYPI_HOST'
|
||||
PRIVATE_PYPI_HOST = os.environ.get(PRIVATE_PYPI_HOST_ENV_NAME)
|
||||
|
||||
INSTALL_FROM_PRIVATE = bool(PRIVATE_PYPI_URL and PRIVATE_PYPI_HOST)
|
||||
|
||||
# If we have source, validate that our version numbers match
|
||||
# This should prevent uploading releases with mismatched versions.
|
||||
try:
|
||||
|
@ -83,10 +84,7 @@ def _post_install(dir):
|
|||
from subprocess import check_call
|
||||
# Upgrade/update will install if it doesn't exist.
|
||||
# We do this so these components are updated when the user updates the CLI.
|
||||
if INSTALL_FROM_PUBLIC:
|
||||
pip.main(['install', '--upgrade', 'azure-cli-component', '--disable-pip-version-check'])
|
||||
check_call(['az', 'component', 'update', '-n', 'profile'])
|
||||
else:
|
||||
if INSTALL_FROM_PRIVATE:
|
||||
# use private PyPI server.
|
||||
if not PRIVATE_PYPI_URL:
|
||||
raise RuntimeError('{} environment variable not set.'.format(PRIVATE_PYPI_URL_ENV_NAME))
|
||||
|
@ -96,6 +94,9 @@ def _post_install(dir):
|
|||
PRIVATE_PYPI_URL, '--trusted-host', PRIVATE_PYPI_HOST,
|
||||
'--disable-pip-version-check'])
|
||||
check_call(['az', 'component', 'update', '-n', 'profile', '-p'])
|
||||
else:
|
||||
pip.main(['install', '--upgrade', 'azure-cli-component', '--disable-pip-version-check'])
|
||||
check_call(['az', 'component', 'update', '-n', 'profile'])
|
||||
|
||||
class OnInstall(install):
|
||||
def run(self):
|
||||
|
|
|
@ -326,15 +326,15 @@ class CredsCache(object):
|
|||
self.adal_token_cache = adal.TokenCache(json.dumps(real_token))
|
||||
return self.adal_token_cache
|
||||
|
||||
def save_service_principal_cred(self, client_id, secret, tenant):
|
||||
def save_service_principal_cred(self, service_principal_id, secret, tenant):
|
||||
entry = {
|
||||
_SERVICE_PRINCIPAL_ID: client_id,
|
||||
_SERVICE_PRINCIPAL_ID: service_principal_id,
|
||||
_SERVICE_PRINCIPAL_TENANT: tenant,
|
||||
_ACCESS_TOKEN: secret
|
||||
}
|
||||
|
||||
matched = [x for x in self._service_principal_creds
|
||||
if client_id == x[_SERVICE_PRINCIPAL_ID] and
|
||||
if service_principal_id == x[_SERVICE_PRINCIPAL_ID] and
|
||||
tenant == x[_SERVICE_PRINCIPAL_TENANT]]
|
||||
state_changed = False
|
||||
if matched:
|
||||
|
|
|
@ -226,26 +226,181 @@ class Test_Profile(unittest.TestCase):
|
|||
self.assertEqual(mock_read_cred_file.call_count, 1)
|
||||
self.assertEqual(mock_persist_creds.call_count, 1)
|
||||
|
||||
def test_find_subscriptions_thru_username_password(self):
|
||||
finder = SubscriptionFinder(lambda _,_2:AuthenticationContextStub(Test_Profile),
|
||||
@mock.patch('adal.AuthenticationContext', autospec=True)
|
||||
def test_find_subscriptions_thru_username_password(self, mock_auth_context):
|
||||
mock_auth_context.acquire_token_with_username_password.return_value = self.token_entry1
|
||||
mock_auth_context.acquire_token.return_value = self.token_entry1
|
||||
mock_arm_client = mock.MagicMock()
|
||||
mock_arm_client.tenants.list.return_value = [TenantStub(self.tenant_id)]
|
||||
mock_arm_client.subscriptions.list.return_value = [self.subscription1]
|
||||
finder = SubscriptionFinder(lambda _,_2: mock_auth_context,
|
||||
None,
|
||||
lambda _: ArmClientStub(Test_Profile))
|
||||
subs = finder.find_from_user_account('foo', 'bar')
|
||||
self.assertEqual([self.subscription1], subs)
|
||||
lambda _: mock_arm_client)
|
||||
|
||||
def test_find_through_interactive_flow(self):
|
||||
finder = SubscriptionFinder(lambda _,_2:AuthenticationContextStub(Test_Profile),
|
||||
#action
|
||||
subs = finder.find_from_user_account(self.user1, 'bar')
|
||||
|
||||
#assert
|
||||
self.assertEqual([self.subscription1], subs)
|
||||
mock_auth_context.acquire_token_with_username_password.assert_called_once_with(
|
||||
'https://management.core.windows.net/', self.user1, 'bar', mock.ANY)
|
||||
mock_auth_context.acquire_token.assert_called_once_with(
|
||||
'https://management.core.windows.net/', self.user1, mock.ANY)
|
||||
|
||||
@mock.patch('adal.AuthenticationContext', autospec=True)
|
||||
def test_find_subscriptions_through_interactive_flow(self, mock_auth_context):
|
||||
test_nonsense_code = {'message':'magic code for you'}
|
||||
mock_auth_context.acquire_user_code.return_value = test_nonsense_code
|
||||
mock_auth_context.acquire_token_with_device_code.return_value = self.token_entry1
|
||||
mock_arm_client = mock.MagicMock()
|
||||
mock_arm_client.tenants.list.return_value = [TenantStub(self.tenant_id)]
|
||||
mock_arm_client.subscriptions.list.return_value = [self.subscription1]
|
||||
finder = SubscriptionFinder(lambda _,_2: mock_auth_context,
|
||||
None,
|
||||
lambda _: ArmClientStub(Test_Profile))
|
||||
lambda _: mock_arm_client)
|
||||
|
||||
#action
|
||||
subs = finder.find_through_interactive_flow()
|
||||
|
||||
#assert
|
||||
self.assertEqual([self.subscription1], subs)
|
||||
|
||||
def test_find_from_service_principal_id(self):
|
||||
finder = SubscriptionFinder(lambda _,_2:AuthenticationContextStub(Test_Profile),
|
||||
mock_auth_context.acquire_user_code.assert_called_once_with(
|
||||
'https://management.core.windows.net/', mock.ANY)
|
||||
mock_auth_context.acquire_token_with_device_code.assert_called_once_with(
|
||||
'https://management.core.windows.net/', test_nonsense_code, mock.ANY)
|
||||
mock_auth_context.acquire_token.assert_called_once_with(
|
||||
'https://management.core.windows.net/', self.user1, mock.ANY)
|
||||
|
||||
@mock.patch('adal.AuthenticationContext', autospec=True)
|
||||
def test_find_subscriptions_from_service_principal_id(self, mock_auth_context):
|
||||
mock_auth_context.acquire_token_with_client_credentials.return_value = self.token_entry1
|
||||
mock_arm_client = mock.MagicMock()
|
||||
mock_arm_client.subscriptions.list.return_value = [self.subscription1]
|
||||
finder = SubscriptionFinder(lambda _,_2:mock_auth_context,
|
||||
None,
|
||||
lambda _: ArmClientStub(Test_Profile))
|
||||
lambda _: mock_arm_client)
|
||||
#action
|
||||
subs = finder.find_from_service_principal_id('my app', 'my secret', self.tenant_id)
|
||||
|
||||
#assert
|
||||
self.assertEqual([self.subscription1], subs)
|
||||
mock_arm_client.tenants.list.assert_not_called()
|
||||
mock_auth_context.acquire_token.assert_not_called()
|
||||
mock_auth_context.acquire_token_with_client_credentials.assert_called_once_with(
|
||||
'https://management.core.windows.net/', 'my app', 'my secret')
|
||||
|
||||
@mock.patch('azure.cli._profile._read_file_content', autospec=True)
|
||||
def test_credscache_load_tokens_and_sp_creds(self, mock_read_file):
|
||||
test_sp = {
|
||||
"servicePrincipalId": "myapp",
|
||||
"servicePrincipalTenant": "mytenant",
|
||||
"accessToken": "Secret"
|
||||
}
|
||||
mock_read_file.return_value = json.dumps([self.token_entry1, test_sp])
|
||||
|
||||
#action
|
||||
creds_cache = CredsCache()
|
||||
|
||||
#assert
|
||||
token_entries = [entry for _, entry in creds_cache.adal_token_cache.read_items()]
|
||||
self.assertEqual(token_entries, [self.token_entry1])
|
||||
self.assertEqual(creds_cache._service_principal_creds,[test_sp])
|
||||
|
||||
@mock.patch('azure.cli._profile._read_file_content', autospec=True)
|
||||
@mock.patch('azure.cli._profile.codecs_open', autospec=True)
|
||||
def test_credscache_add_new_sp_creds(self, mock_open_for_write, mock_read_file):
|
||||
test_sp = {
|
||||
"servicePrincipalId": "myapp",
|
||||
"servicePrincipalTenant": "mytenant",
|
||||
"accessToken": "Secret"
|
||||
}
|
||||
test_sp2 = {
|
||||
"servicePrincipalId": "myapp2",
|
||||
"servicePrincipalTenant": "mytenant2",
|
||||
"accessToken": "Secret2"
|
||||
}
|
||||
mock_open_for_write.return_value = FileHandleStub()
|
||||
mock_read_file.return_value = json.dumps([self.token_entry1, test_sp])
|
||||
creds_cache = CredsCache()
|
||||
|
||||
#action
|
||||
creds_cache.save_service_principal_cred(
|
||||
test_sp2['servicePrincipalId'],
|
||||
test_sp2['accessToken'],
|
||||
test_sp2['servicePrincipalTenant'])
|
||||
|
||||
#assert
|
||||
token_entries = [entry for _, entry in creds_cache.adal_token_cache.read_items()]
|
||||
self.assertEqual(token_entries, [self.token_entry1])
|
||||
self.assertEqual(creds_cache._service_principal_creds,[test_sp, test_sp2])
|
||||
mock_open_for_write.assert_called_with(mock.ANY, 'w', encoding='ascii')
|
||||
|
||||
@mock.patch('azure.cli._profile._read_file_content', autospec=True)
|
||||
@mock.patch('azure.cli._profile.codecs_open', autospec=True)
|
||||
def test_credscache_remove_creds(self, mock_open_for_write, mock_read_file):
|
||||
test_sp = {
|
||||
"servicePrincipalId": "myapp",
|
||||
"servicePrincipalTenant": "mytenant",
|
||||
"accessToken": "Secret"
|
||||
}
|
||||
mock_open_for_write.return_value = FileHandleStub()
|
||||
mock_read_file.return_value = json.dumps([self.token_entry1, test_sp])
|
||||
creds_cache = CredsCache()
|
||||
|
||||
#action #1, logout a user
|
||||
creds_cache.remove_cached_creds(self.user1)
|
||||
|
||||
#assert #1
|
||||
token_entries = [entry for _, entry in creds_cache.adal_token_cache.read_items()]
|
||||
self.assertEqual(token_entries, [])
|
||||
|
||||
#action #2 logout a service principal
|
||||
creds_cache.remove_cached_creds('myapp')
|
||||
|
||||
#assert #2
|
||||
self.assertEqual(creds_cache._service_principal_creds,[])
|
||||
|
||||
mock_open_for_write.assert_called_with(mock.ANY, 'w', encoding='ascii')
|
||||
self.assertEqual(mock_open_for_write.call_count, 2)
|
||||
|
||||
@mock.patch('azure.cli._profile._read_file_content', autospec=True)
|
||||
@mock.patch('azure.cli._profile.codecs_open', autospec=True)
|
||||
@mock.patch('adal.AuthenticationContext', autospec=True)
|
||||
def test_credscache_new_token_added_by_adal(self, mock_adal_auth_context, mock_open_for_write, mock_read_file):
|
||||
token_entry2 = {
|
||||
"accessToken": "new token",
|
||||
"userId": self.user1
|
||||
}
|
||||
def acquire_token_side_effect(*args):
|
||||
creds_cache.adal_token_cache.has_state_changed = True
|
||||
return token_entry2
|
||||
def get_auth_context(authority, **kwargs):
|
||||
mock_adal_auth_context.cache = kwargs['cache']
|
||||
return mock_adal_auth_context
|
||||
|
||||
mock_adal_auth_context.acquire_token.side_effect = acquire_token_side_effect
|
||||
mock_open_for_write.return_value = FileHandleStub()
|
||||
mock_read_file.return_value = json.dumps([self.token_entry1])
|
||||
creds_cache = CredsCache(auth_ctx_factory=get_auth_context)
|
||||
token = creds_cache.retrieve_token_for_user(self.user1, self.tenant_id)
|
||||
|
||||
#action
|
||||
mock_adal_auth_context.acquire_token.assert_called_once_with(
|
||||
'https://management.core.windows.net/',
|
||||
self.user1,
|
||||
mock.ANY)
|
||||
|
||||
#assert
|
||||
mock_open_for_write.assert_called_with(mock.ANY, 'w', encoding='ascii')
|
||||
self.assertEqual(token, 'new token')
|
||||
|
||||
class FileHandleStub:
|
||||
def write(self, content):
|
||||
pass
|
||||
def __enter__(self):
|
||||
return self
|
||||
def __exit__(self, _2, _3, _4):
|
||||
pass
|
||||
|
||||
class SubscriptionStub:
|
||||
def __init__(self, id, display_name, state, tenant_id):
|
||||
|
@ -254,47 +409,9 @@ class SubscriptionStub:
|
|||
self.state = state
|
||||
self.tenant_id = tenant_id
|
||||
|
||||
class AuthenticationContextStub:
|
||||
def __init__(self, test_profile_cls, return_token1=True):
|
||||
#we need to reference some pre-defined test artifacts in Test_Profile
|
||||
self._test_profile_cls = test_profile_cls
|
||||
if not return_token1:
|
||||
raise ValueError('Please update to return other test tokens')
|
||||
|
||||
def acquire_token_with_username_password(self, _, _2, _3, _4):
|
||||
return self._test_profile_cls.token_entry1
|
||||
|
||||
def acquire_token_with_device_code(self, _, _2, _3):
|
||||
return self._test_profile_cls.token_entry1
|
||||
|
||||
def acquire_token_with_client_credentials(self, _, _2, _3):
|
||||
return self._test_profile_cls.token_entry1
|
||||
|
||||
def acquire_token(self, _, _2, _3):
|
||||
return self._test_profile_cls.token_entry1
|
||||
|
||||
def acquire_user_code(self, _, _2):
|
||||
return {'message': 'secret code for you'}
|
||||
|
||||
class ArmClientStub:
|
||||
class TenantStub:
|
||||
def __init__(self, tenant_id):
|
||||
self.tenant_id = tenant_id
|
||||
|
||||
class OperationsStub:
|
||||
def __init__(self, list_result):
|
||||
self._list_result = list_result
|
||||
|
||||
def list(self):
|
||||
return self._list_result
|
||||
|
||||
def __init__(self, test_profile_cls, use_tenant1_and_subscription1=True):
|
||||
self._test_profile_cls = test_profile_cls
|
||||
if use_tenant1_and_subscription1:
|
||||
self.tenants = ArmClientStub.OperationsStub([ArmClientStub.TenantStub(test_profile_cls.tenant_id)])
|
||||
self.subscriptions = ArmClientStub.OperationsStub([test_profile_cls.subscription1])
|
||||
else:
|
||||
raise ValueError('Please update to return other test subscriptions')
|
||||
class TenantStub:
|
||||
def __init__(self, tenant_id):
|
||||
self.tenant_id = tenant_id
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -6,8 +6,8 @@ from azure.cli._locale import L
|
|||
command_table = CommandTable()
|
||||
|
||||
def _resource_client_factory(*args): # pylint: disable=unused-argument
|
||||
from azure.mgmt.resource.resources import (ResourceManagementClient,
|
||||
ResourceManagementClientConfiguration)
|
||||
from azure.mgmt.resource.resources import (ResourceManagementClient,
|
||||
ResourceManagementClientConfiguration)
|
||||
return get_mgmt_service_client(ResourceManagementClient, ResourceManagementClientConfiguration)
|
||||
|
||||
@command_table.command('resource group list', description=L('List resource groups'))
|
||||
|
@ -38,7 +38,7 @@ def list_groups(args):
|
|||
help=L('the resource type in format: <provider-namespace>/<type>'),
|
||||
required=True)
|
||||
@command_table.option('--api-version -o', help=L('the API version of the resource provider'))
|
||||
@command_table.option('--parent',
|
||||
@command_table.option('--parent', default='',
|
||||
help=L('the name of the parent resource (if needed), ' + \
|
||||
'in <parent-type>/<parent-name> format'))
|
||||
def show_resource(args):
|
||||
|
@ -56,9 +56,8 @@ def show_resource(args):
|
|||
raise IncorrectUsageError(
|
||||
L('API version is required and could not be resolved for resource {}'
|
||||
.format(full_type)))
|
||||
|
||||
results = rmc.resources.get(
|
||||
resource_group_name=args.get('resource_group'),
|
||||
resource_group_name=args.get('resourcegroup'),
|
||||
resource_name=args.get('name'),
|
||||
resource_provider_namespace=provider_namespace,
|
||||
resource_type=resource_type,
|
||||
|
@ -88,18 +87,12 @@ def _resolve_api_version(args, rmc):
|
|||
raise IncorrectUsageError('Parameter --parent must be in <type>/<name> format.')
|
||||
|
||||
resource_type = "{}/{}".format(parent_type, resource_type)
|
||||
else:
|
||||
resource_type = resource_type
|
||||
provider = rmc.providers.get(provider_namespace)
|
||||
for t in provider.resource_types:
|
||||
if t.resource_type == resource_type:
|
||||
# Return first non-preview version
|
||||
for version in t.api_versions:
|
||||
if not version.find('preview'):
|
||||
return version
|
||||
# No non-preview version found. Take first preview version
|
||||
try:
|
||||
return t.api_versions[0]
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
rt = [t for t in provider.resource_types if t.resource_type == resource_type]
|
||||
if not rt:
|
||||
raise IncorrectUsageError('Resource type {} not found.'.format(full_type))
|
||||
if len(rt) == 1 and rt[0].api_versions:
|
||||
npv = [v for v in rt[0].api_versions if "preview" not in v]
|
||||
return npv[0] if npv else rt[0].api_versions[0]
|
||||
return None
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
import unittest
|
||||
try:
|
||||
from unittest.mock import MagicMock
|
||||
except ImportError:
|
||||
from mock import MagicMock
|
||||
|
||||
from azure.cli.command_modules.resource import _resolve_api_version as resolve_api_version
|
||||
|
||||
class TestApiCheck(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
pass
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_resolve_api_max_priority_option(self):
|
||||
""" Verifies the --api-version parameter has maximum priority. """
|
||||
args = {'api-version': '2015-01-01', 'resource-type': 'Mock/test'}
|
||||
self.assertEqual(resolve_api_version(args, self._get_mock_client()), "2015-01-01")
|
||||
|
||||
def test_resolve_api_provider_backup(self):
|
||||
""" Verifies provider is used as backup if api-version not specified. """
|
||||
args = {'resource-type': 'Mock/test'}
|
||||
self.assertEqual(resolve_api_version(args, self._get_mock_client()), "2016-01-01")
|
||||
|
||||
def test_resolve_api_provider_with_parent_backup(self):
|
||||
""" Verifies provider (with parent) is used as backup if api-version not specified. """
|
||||
args = {'resource-type': 'Mock/bar', 'parent': 'foo/testfoo123'}
|
||||
self.assertEqual(resolve_api_version(args, self._get_mock_client()), "1999-01-01")
|
||||
|
||||
def test_resolve_api_all_previews(self):
|
||||
""" Verifies most recent preview version returned only if there are no non-preview versions. """
|
||||
args = {'resource-type': 'Mock/preview'}
|
||||
self.assertEqual(resolve_api_version(args, self._get_mock_client()), "2005-01-01-preview")
|
||||
|
||||
def _get_mock_client(self):
|
||||
client = MagicMock()
|
||||
provider = MagicMock()
|
||||
provider.resource_types = [
|
||||
self._get_mock_resource_type('skip', ['2000-01-01-preview', '2000-01-01']),
|
||||
self._get_mock_resource_type('test', ['2016-01-01-preview', '2016-01-01']),
|
||||
self._get_mock_resource_type('foo/bar', ['1999-01-01-preview', '1999-01-01']),
|
||||
self._get_mock_resource_type('preview', ['2005-01-01-preview', '2004-01-01-preview'])
|
||||
]
|
||||
client.providers.get.return_value = provider
|
||||
return client
|
||||
|
||||
def _get_mock_resource_type(self, name, api_versions):
|
||||
rt = MagicMock()
|
||||
rt.resource_type = name
|
||||
rt.api_versions = api_versions
|
||||
return rt
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Загрузка…
Ссылка в новой задаче