diff --git a/azext_iot/central/params.py b/azext_iot/central/params.py index 6e1168d8c..c62d6c933 100644 --- a/azext_iot/central/params.py +++ b/azext_iot/central/params.py @@ -65,7 +65,7 @@ def load_central_arguments(self, _): context.argument( "central_dns_suffix", options_list=["--central-dns-suffix", "--central-api-uri"], - help="The IoT Central DNS suffix associated with your application. Default value is: azureiotcentral.com", + help="The IoT Central DNS suffix associated with your application.", ) context.argument( "device_id", @@ -324,7 +324,7 @@ def load_central_arguments(self, _): "sasTtl", options_list=["--sas-ttl"], help="The amount of time the device’s request to upload a file is valid before it expires." - " ISO 8601 duration standard. Default 1h.", + " ISO 8601 duration standard. Default: 1h.", ) with self.argument_context("iot central file-upload-config update") as context: @@ -347,7 +347,7 @@ def load_central_arguments(self, _): "sasTtl", options_list=["--sas-ttl"], help="The amount of time the device’s request to upload a file is valid before it expires." - " ISO 8601 duration standard. Default 1h.", + " ISO 8601 duration standard. Default: 1h.", ) with self.argument_context("iot central organization") as context: @@ -433,7 +433,7 @@ def load_central_arguments(self, _): "batch_type", options_list=["--batch-type", "--bt"], default=False, - help="Specify if batching is done on a number of devices or a percentage of the total. Default: False", + help="Specify if batching is done on a number of devices or a percentage of the total.", ) context.argument( "batch", @@ -511,7 +511,7 @@ def load_central_arguments(self, _): "filter", options_list=["--filter", "-f"], default=None, - help="IoT Central Query Language based filter, more details from: ", + help="IoT Central Query Language based filter, more details from: aka.ms/iotcquery", ) context.argument( "source", diff --git a/azext_iot/monitor/telemetry.py b/azext_iot/monitor/telemetry.py index 6b5b249a1..becc1888f 100644 --- a/azext_iot/monitor/telemetry.py +++ b/azext_iot/monitor/telemetry.py @@ -77,9 +77,9 @@ def start_multiple_monitors( # TODO: remove when deprecating # pylint: disable=no-member tasks = ( - asyncio.Task.all_tasks() - if sys.version_info < (3, 9) - else asyncio.all_tasks() + asyncio.Task.all_tasks(loop) + if sys.version_info < (3, 7) + else asyncio.all_tasks(loop) ) for t in tasks: # pylint: disable=no-member t.cancel() diff --git a/azext_iot/tests/central/__init__.py b/azext_iot/tests/central/__init__.py index c02605cef..c06f3fc80 100644 --- a/azext_iot/tests/central/__init__.py +++ b/azext_iot/tests/central/__init__.py @@ -5,24 +5,38 @@ # -------------------------------------------------------------------------------------------- import json -import os import time from typing import Tuple from azure.cli.core.azclierror import CLIInternalError from azext_iot.tests import CaptureOutputLiveScenarioTest from azext_iot.tests.conftest import get_context_path +from azext_iot.tests.generators import generate_generic_id +from azext_iot.tests.settings import DynamoSettings from azext_iot.common import utility from azext_iot.central.models.enum import Role, UserTypePreview, UserTypeV1, ApiVersion -APP_ID = os.environ.get("azext_iot_central_app_id") -APP_PRIMARY_KEY = os.environ.get("azext_iot_central_primarykey") -APP_SCOPE_ID = os.environ.get("azext_iot_central_scope_id") -DEVICE_ID = os.environ.get("azext_iot_central_device_id") -TOKEN = os.environ.get("azext_iot_central_token") -DNS_SUFFIX = os.environ.get("azext_iot_central_dns_suffix") -STORAGE_CSTRING = os.environ.get("azext_iot_central_storage_cstring") -STORAGE_CONTAINER = os.environ.get("azext_iot_central_storage_container") +DEFAULT_CONTAINER = "devices" +CENTRAL_SETTINGS = [ + "azext_iot_testrg", + "azext_iot_central_app_id", + "azext_iot_central_primarykey", + "azext_iot_central_scope_id", + "azext_iot_central_token", + "azext_iot_central_dns_suffix", + "azext_iot_central_storage_cstring", + "azext_iot_central_storage_container" +] +settings = DynamoSettings(opt_env_set=CENTRAL_SETTINGS) +APP_RG = settings.env.azext_iot_testrg + +# Storage Account +DEFAULT_CONTAINER = "central" +STORAGE_CONTAINER = settings.env.azext_iot_central_storage_container or DEFAULT_CONTAINER +STORAGE_CSTRING = settings.env.azext_iot_central_storage_cstring +STORAGE_NAME = None if settings.env.azext_iot_central_storage_cstring else "iotstore" + generate_generic_id()[:4] + +# Device templates device_template_path = get_context_path(__file__, "json/device_template_int_test.json") device_template_path_preview = get_context_path( __file__, "json/device_template_int_test_preview.json" @@ -34,15 +48,71 @@ class CentralLiveScenarioTest(CaptureOutputLiveScenarioTest): def __init__(self, test_scenario): super(CentralLiveScenarioTest, self).__init__(test_scenario) - - def cmd(self, command, api_version=None, checks=None, expect_failure=False): - command = self._appendOptionalArgsToCommand( - command, token=TOKEN, dns_suffix=DNS_SUFFIX, api_version=api_version - ) + self._create_app() + self.storage_container = STORAGE_CONTAINER + self.storage_cstring = STORAGE_CSTRING + self.storage_account_name = STORAGE_NAME + self.token = None + self.dns_suffix = None + + def cmd( + self, + command, + api_version=None, + checks=None, + expect_failure=False, + include_opt_args=True + ): + if include_opt_args: + command = self._appendOptionalArgsToCommand( + command, api_version=api_version + ) return super().cmd(command, checks=checks, expect_failure=expect_failure) - def cmd_withoutParams(self, command, checks=None, expect_failure=False): - return super().cmd(command, checks=checks, expect_failure=expect_failure) + def _create_app(self): + """ + Create an Iot Central Application if a name is not given in the pytest configuration. + + Will populate the following variables based on given pytest configuration: + - app_primary_key + - token + - dns_suffix + """ + self.app_id = settings.env.azext_iot_central_app_id or "test-app-" + generate_generic_id() + self.app_rg = APP_RG + self._scope_id = settings.env.azext_iot_central_scope_id + + # only populate these if given in the test configuration variables + self.app_primary_key = settings.env.azext_iot_central_primarykey + self.dns_suffix = settings.env.azext_iot_central_dns_suffix + self.token = settings.env.azext_iot_central_token + + # Create Central App if it does not exist. Note that app_primary_key will be nullified since + # there is no current way to get the app_primary_key and not all tests can be executed. + if not settings.env.azext_iot_central_app_id: + if not APP_RG: + raise Exception("Tests need either app name or resource group.") + + self.cmd( + "iot central app create -n {} -g {} -s {} --mi-system-assigned -l {}".format( + self.app_id, + self.app_rg, + self.app_id, + "westus" + ), + include_opt_args=False + ) + self.app_primary_key = None + # Will be repopulated with get_app_scope_id for tests that need it + self._scope_id = None + + # Get Central App RG if needed (for storage account creation) + elif not APP_RG: + self.app_rg = self.cmd( + "iot central app show -n {}".format( + self.app_id, + ) + ).get_output_in_json()["resourceGroup"] def _create_device(self, api_version, **kwargs) -> Tuple[str, str]: """ @@ -54,7 +124,7 @@ def _create_device(self, api_version, **kwargs) -> Tuple[str, str]: device_name = self.create_random_name(prefix="aztest", length=24) command = "iot central device create --app-id {} -d {} --device-name {}".format( - APP_ID, device_id, device_name + self.app_id, device_id, device_name ) checks = [ @@ -86,8 +156,26 @@ def _create_device(self, api_version, **kwargs) -> Tuple[str, str]: checks.append(self.check("simulated", simulated)) self.cmd(command, api_version=api_version, checks=checks) + return (device_id, device_name) + def get_app_scope_id(self, api_version): + """ + Scope ID is taken from device credentials. If needed, create and delete a throwaway device + so we can see the scope id. + """ + if not self._scope_id: + (device_id, _) = self._create_device(api_version=api_version) + self._scope_id = self.cmd( + "iot central device show-credentials -n {} -d {}".format( + self.app_id, device_id + ) + ).get_output_in_json()["idScope"] + + self._delete_device(api_version=api_version, device_id=device_id) + + return self._scope_id + def _create_users(self, api_version): users = [] @@ -95,7 +183,7 @@ def _create_users(self, api_version): user_id = self.create_random_name(prefix="aztest", length=24) email = user_id + "@microsoft.com" command = "iot central user create --app-id {} --user-id {} -r {} --email {}".format( - APP_ID, + self.app_id, user_id, role.name, email, @@ -122,19 +210,18 @@ def _create_users(self, api_version): def _delete_user(self, api_version, user_id) -> None: self.cmd( - "iot central user delete --app-id {} --user-id {}".format(APP_ID, user_id), + "iot central user delete --app-id {} --user-id {}".format(self.app_id, user_id), api_version=api_version, checks=[self.check("result", "success")], ) def _create_api_tokens(self, api_version): - tokens = [] for role in Role: token_id = self.create_random_name(prefix="aztest", length=24) command = ( "iot central api-token create --app-id {} --token-id {} -r {}".format( - APP_ID, + self.app_id, token_id, role.name, ) @@ -155,14 +242,14 @@ def _create_api_tokens(self, api_version): def _delete_api_token(self, api_version, token_id) -> None: self.cmd( "iot central api-token delete --app-id {} --token-id {}".format( - APP_ID, token_id + self.app_id, token_id ), api_version=api_version, checks=[self.check("result", "success")], ) def _wait_for_provisioned(self, api_version, device_id): - command = "iot central device show --app-id {} -d {}".format(APP_ID, device_id) + command = "iot central device show --app-id {} -d {}".format(self.app_id, device_id) while True: result = self.cmd(command, api_version=api_version) @@ -178,7 +265,7 @@ def _wait_for_provisioned(self, api_version, device_id): def _delete_device(self, api_version, device_id) -> None: command = "iot central device delete --app-id {} -d {} ".format( - APP_ID, device_id + self.app_id, device_id ) self.cmd( @@ -199,7 +286,7 @@ def _create_device_template(self, api_version): template_id = template_name + "id" command = "iot central device-template create --app-id {} --device-template-id {} -k '{}'".format( - APP_ID, + self.app_id, template_id, device_template_path_preview if api_version == ApiVersion.preview.value @@ -223,9 +310,6 @@ def _create_device_template(self, api_version): def _delete_device_template(self, api_version, template_id): attempts = range(0, 10) - command = "iot central device-template delete --app-id {} --device-template-id {}".format( - APP_ID, template_id - ) # retry logic to delete the template error = None @@ -233,7 +317,9 @@ def _delete_device_template(self, api_version, template_id): try: error = None self.cmd( - command, + command="iot central device-template delete --app-id {} --device-template-id {}".format( + self.app_id, template_id + ), api_version=api_version, checks=[self.check("result", "success")], ) @@ -241,9 +327,9 @@ def _delete_device_template(self, api_version, template_id): except Exception as e: error = e # delete associated devices if any. - command = "iot central device list --app-id {}".format(APP_ID) devices = self.cmd( - command, api_version=api_version + command="iot central device list --app-id {}".format(self.app_id), + api_version=api_version ).get_output_in_json() if devices: @@ -256,7 +342,7 @@ def _delete_device_template(self, api_version, template_id): if device_template == template_id: self.cmd( "iot central device delete --app-id {} --device-id {}".format( - APP_ID, device["id"] + self.app_id, device["id"] ), api_version=api_version, ) @@ -268,18 +354,18 @@ def _delete_device_template(self, api_version, template_id): ) def _list_device_groups(self, api_version): - command = "iot central device-group list --app-id {}".format(APP_ID) + command = "iot central device-group list --app-id {}".format(self.app_id) return self.cmd(command, api_version=api_version).get_output_in_json() def _list_roles(self, api_version): return self.cmd( - "iot central role list --app-id {}".format(APP_ID), api_version=api_version + "iot central role list --app-id {}".format(self.app_id), api_version=api_version ).get_output_in_json() def _get_credentials(self, api_version, device_id): return self.cmd( "iot central device show-credentials --app-id {} -d {}".format( - APP_ID, device_id + self.app_id, device_id ), api_version=api_version, ).get_output_in_json() @@ -297,7 +383,7 @@ def _get_validate_messages_output( " --et {} " " --duration {} " " --mm {} -y --style json".format( - APP_ID, device_id, enqueued_time, duration, max_messages + self.app_id, device_id, enqueued_time, duration, max_messages ), asserts, ) @@ -315,7 +401,7 @@ def _get_monitor_events_output( output = self.command_execute_assert( "iot central diagnostics monitor-events -n {} -d {} --et {} --to 1 -y".format( - APP_ID, device_id, enqueued_time + self.app_id, device_id, enqueued_time ), asserts, ) @@ -326,9 +412,10 @@ def _get_monitor_events_output( return output def _create_fileupload(self, api_version, account_name=None, sasttl=None): + self._populate_storage_cstring() command = ( 'iot central file-upload-config create --app-id {} -s "{}" -c "{}"'.format( - APP_ID, STORAGE_CSTRING, STORAGE_CONTAINER + self.app_id, self.storage_cstring, self.storage_container ) ) @@ -341,8 +428,8 @@ def _create_fileupload(self, api_version, account_name=None, sasttl=None): command, api_version=api_version, checks=[ - self.check("connectionString", STORAGE_CSTRING), - self.check("container", STORAGE_CONTAINER), + self.check("connectionString", self.storage_cstring), + self.check("container", self.storage_container), self.check("account", None if account_name is None else account_name), self.check("state", "pending"), self.check( @@ -352,7 +439,7 @@ def _create_fileupload(self, api_version, account_name=None, sasttl=None): ).get_output_in_json() def _delete_fileupload(self, api_version): - command = "iot central file-upload-config delete --app-id {}".format(APP_ID) + command = "iot central file-upload-config delete --app-id {}".format(self.app_id) self.cmd( command, api_version=api_version, @@ -364,7 +451,7 @@ def _delete_fileupload(self, api_version): def _create_organization(self, api_version): org_id = self.create_random_name(prefix="aztest", length=24) command = "iot central organization create --app-id {} --org-id {}".format( - APP_ID, org_id + self.app_id, org_id ) return self.cmd( @@ -377,7 +464,7 @@ def _create_organization(self, api_version): def _delete_organization(self, api_version, org_id): command = "iot central organization delete --app-id {} --org-id {}".format( - APP_ID, org_id + self.app_id, org_id ) self.cmd( command, @@ -388,16 +475,17 @@ def _delete_organization(self, api_version, org_id): ) def _create_destination(self, api_version, dest_id): + self._populate_storage_cstring() self.kwargs["authorization"] = json.dumps( { "type": "connectionString", - "connectionString": STORAGE_CSTRING, - "containerName": STORAGE_CONTAINER, + "connectionString": self.storage_cstring, + "containerName": self.storage_container, } ) command = "iot central export destination create --app-id {} \ --dest-id {} --type {} --name '{}' --authorization '{}'".format( - APP_ID, + self.app_id, dest_id, "blobstorage@v1", "Blob Storage", @@ -410,7 +498,7 @@ def _create_destination(self, api_version, dest_id): def _delete_destination(self, api_version, dest_id): command = ( "iot central export destination delete --app-id {} --dest-id {}".format( - APP_ID, dest_id + self.app_id, dest_id ) ) self.cmd(command, api_version=api_version) @@ -422,7 +510,7 @@ def _create_export(self, api_version, export_id, dest_id): command = "iot central export create --app-id {} --export-id {} --name {} \ --filter {} --source {} --enabled {} --enrichments '{}' --destinations '{}'".format( - APP_ID, + self.app_id, export_id, '"Test Export"', '"SELECT * FROM devices WHERE $simulated = true"', @@ -437,12 +525,60 @@ def _create_export(self, api_version, export_id, dest_id): def _delete_export(self, api_version, export_id): command = "iot central export delete --app-id {} --export-id {}".format( - APP_ID, export_id + self.app_id, export_id ) self.cmd(command, api_version=api_version) + def _create_storage_account(self): + """ + Create a storage account and container if the storage connection string was not provided and + a storage account was not created yet. Populate the following variables if needed: + - storage_account_name + - storage_container + - storage_cstring + """ + if not self.storage_cstring: + self.cmd( + "storage account create -n {} -g {}".format( + self.storage_account_name, self.app_rg + ), + include_opt_args=False + ) + self._populate_storage_cstring() + self.cmd( + "storage container create -n {} --connection-string '{}'".format( + self.storage_container, self.storage_cstring + ), + include_opt_args=False + ) + + def _populate_storage_cstring(self): + """ + Method to populate storage_cstring + """ + if not self.storage_cstring: + self.storage_cstring = self.cmd( + "storage account show-connection-string -n {} -g {}".format( + self.storage_account_name, self.app_rg + ), + include_opt_args=False + ).get_output_in_json()["connectionString"] + + def _delete_storage_account(self): + """ + Delete the storage account if it was created. The variable storage_account_name will only + be populated if a storage account was created and thus must be deleted at the end of the test. + """ + if self.storage_account_name: + self.cmd( + "storage account delete -n {} -g {} -y".format( + self.storage_account_name, APP_RG + ), + include_opt_args=False + ) + def _wait_for_storage_configured(self, api_version): - command = "iot central file-upload-config show --app-id {}".format(APP_ID) + command = "iot central file-upload-config show --app-id {}".format(self.app_id) while True: try: @@ -464,13 +600,21 @@ def _wait_for_storage_configured(self, api_version): time.sleep(10) def _appendOptionalArgsToCommand( - self, command: str, token: str, dns_suffix: str, api_version: str + self, command: str, api_version: str ): - if token: - command += ' --token "{}"'.format(token) - if dns_suffix: - command += ' --central-dns-suffix "{}"'.format(dns_suffix) + if self.token: + command += ' --token "{}"'.format(self.token) + if self.dns_suffix: + command += ' --central-dns-suffix "{}"'.format(self.dns_suffix) if api_version: command += " --api-version {}".format(api_version) return command + + def tearDown(self): + if not settings.env.azext_iot_central_app_id: + self.cmd( + "iot central app delete -n {} -g {} -y".format( + self.app_id, self.app_rg + ) + ) diff --git a/azext_iot/tests/central/test_iot_central_devices_int.py b/azext_iot/tests/central/test_iot_central_devices_int.py index a836287a3..a897340da 100644 --- a/azext_iot/tests/central/test_iot_central_devices_int.py +++ b/azext_iot/tests/central/test_iot_central_devices_int.py @@ -12,15 +12,8 @@ from azext_iot.tests import helpers from azext_iot.tests.central import ( CentralLiveScenarioTest, - APP_ID, - APP_PRIMARY_KEY, - APP_SCOPE_ID, - DEVICE_ID, ) -if not all([APP_ID]): - raise ValueError("Set azext_iot_central_app_id to run central integration tests.") - class TestIotCentralDevices(CentralLiveScenarioTest): @pytest.fixture(autouse=True) @@ -51,7 +44,7 @@ def test_central_device_twin_show_fail(self): # Verify incorrect device-id throws error command = "iot central device twin show --app-id {} --device-id incorrect-device".format( - APP_ID + self.app_id ) self.cmd(command, expect_failure=True) @@ -69,7 +62,7 @@ def test_central_device_c2d_purge_success(self): command = ( "iot central device c2d-message purge --app-id {} --device-id {}".format( - APP_ID, device_id + self.app_id, device_id ) ) @@ -93,7 +86,7 @@ def test_central_device_twin_show_success(self): time.sleep(60) command = "iot central device twin show --app-id {} --device-id {}".format( - APP_ID, device_id + self.app_id, device_id ) self.cmd( @@ -110,27 +103,27 @@ def test_central_device_twin_show_success(self): template_id=template_id, api_version=self._api_version ) - @pytest.mark.skipif( - not APP_SCOPE_ID, reason="empty azext_iot_central_scope_id env var" - ) - @pytest.mark.skipif( - not APP_PRIMARY_KEY, reason="empty azext_iot_central_primarykey env var" - ) def test_device_connect(self): + if self.app_primary_key is None: + pytest.skip( + "Cannot test without primary key. Currently there is no way of retrieving the app " + "primary key from the IoT Central App." + ) + app_scope_id = self.get_app_scope_id(api_version=self._api_version) device_id = "testDevice" command = "iot central device compute-device-key --pk {} -d {}".format( - APP_PRIMARY_KEY, device_id + self.app_primary_key, device_id ) - device_primary_key = self.cmd_withoutParams(command).get_output_in_json() + device_primary_key = self.cmd(command, include_opt_args=False).get_output_in_json() credentials = { - "idScope": APP_SCOPE_ID, + "idScope": app_scope_id, "symmetricKey": {"primaryKey": device_primary_key}, } device_client = helpers.dps_connect_device(device_id, credentials) - command = "iot central device show --app-id {} -d {}".format(APP_ID, device_id) + command = "iot central device show --app-id {} -d {}".format(self.app_id, device_id) self.cmd( command, @@ -143,17 +136,16 @@ def test_device_connect(self): assert device_client.connected def test_central_device_methods_CRUD(self): - # list devices and get count start_device_list = self.cmd( - "iot central device list --app-id {}".format(APP_ID), + "iot central device list --app-id {}".format(self.app_id), api_version=self._api_version, ).get_output_in_json() start_dev_count = len(start_device_list) (device_id, device_name) = self._create_device(api_version=self._api_version) - command = "iot central device show --app-id {} -d {}".format(APP_ID, device_id) + command = "iot central device show --app-id {} -d {}".format(self.app_id, device_id) checks = [ self.check("displayName", device_name), self.check("id", device_id), @@ -167,7 +159,7 @@ def test_central_device_methods_CRUD(self): self.cmd(command, api_version=self._api_version, checks=checks) created_device_list = self.cmd( - "iot central device list --app-id {}".format(APP_ID), + "iot central device list --app-id {}".format(self.app_id), api_version=self._api_version, ).get_output_in_json() @@ -186,7 +178,7 @@ def test_central_device_methods_CRUD(self): new_device_name = f"{device_name}_new" command = "iot central device update --app-id {} -d {} --device-name {}".format( - APP_ID, + self.app_id, device_id, new_device_name, ) @@ -200,7 +192,7 @@ def test_central_device_methods_CRUD(self): self._delete_device(device_id=device_id, api_version=self._api_version) deleted_device_list = self.cmd( - "iot central device list --app-id {}".format(APP_ID), + "iot central device list --app-id {}".format(self.app_id), api_version=self._api_version, ).get_output_in_json() @@ -220,7 +212,7 @@ def test_central_device_template_methods_CRUD(self): # list device templates and get count start_device_template_list = self.cmd( - "iot central device-template list --app-id {}".format(APP_ID), + "iot central device-template list --app-id {}".format(self.app_id), api_version=self._api_version, ).get_output_in_json() @@ -231,7 +223,7 @@ def test_central_device_template_methods_CRUD(self): ) command = "iot central device-template show --app-id {} --device-template-id {}".format( - APP_ID, template_id + self.app_id, template_id ) result = self.cmd( @@ -245,7 +237,7 @@ def test_central_device_template_methods_CRUD(self): assert self._get_template_id(json_result) == template_id created_device_template_list = self.cmd( - "iot central device-template list --app-id {}".format(APP_ID), + "iot central device-template list --app-id {}".format(self.app_id), api_version=self._api_version, ).get_output_in_json() @@ -286,7 +278,7 @@ def test_central_device_template_methods_CRUD(self): updated_contents = json_result["capabilityModel"]["contents"] command = ( "iot central device-template update --app-id {} --dtid {} -k '{}'".format( - APP_ID, + self.app_id, template_id, json.dumps(json_result) .replace("{", "{{") @@ -308,7 +300,7 @@ def test_central_device_template_methods_CRUD(self): ) deleted_device_template_list = self.cmd( - "iot central device-template list --app-id {}".format(APP_ID), + "iot central device-template list --app-id {}".format(self.app_id), api_version=self._api_version, ).get_output_in_json() @@ -357,7 +349,7 @@ def test_central_device_registration_info_registered(self): ) command = "iot central device registration-info --app-id {} -d {}".format( - APP_ID, device_id + self.app_id, device_id ) result = self.cmd(command, api_version=self._api_version) @@ -400,11 +392,10 @@ def test_central_device_registration_info_registered(self): assert dps_state.get("error") == "Device is not yet provisioned." def test_central_device_registration_info_unassociated(self): - (device_id, device_name) = self._create_device(api_version=self._api_version) command = "iot central device registration-info --app-id {} -d {}".format( - APP_ID, device_id + self.app_id, device_id ) result = self.cmd(command, api_version=self._api_version) @@ -445,13 +436,9 @@ def test_central_device_registration_info_unassociated(self): == "Device does not have a valid template associated with it." ) - @pytest.mark.skipif( - not DEVICE_ID, reason="empty azext_iot_central_device_id env var" - ) def test_central_device_registration_summary(self): - command = "iot central diagnostics registration-summary --app-id {}".format( - APP_ID + self.app_id ) result = self.cmd(command, api_version=self._api_version) @@ -464,7 +451,6 @@ def test_central_device_registration_summary(self): assert len(json_result) == 4 def test_central_device_should_start_failover_and_failback(self): - # created device template & device (template_id, _) = self._create_device_template(api_version=self._api_version) (device_id, _) = self._create_device( @@ -473,7 +459,7 @@ def test_central_device_should_start_failover_and_failback(self): command = ( "iot central device show-credentials --device-id {} --app-id {}".format( - device_id, APP_ID + device_id, self.app_id ) ) @@ -484,7 +470,7 @@ def test_central_device_should_start_failover_and_failback(self): # connect & disconnect device & wait to be provisioned self._connect_gettwin_disconnect_wait_tobeprovisioned(device_id, credentials) command = "iot central device manual-failover --app-id {} --device-id {} --ttl {}".format( - APP_ID, device_id, 5 + self.app_id, device_id, 5 ) # initiating failover @@ -499,7 +485,7 @@ def test_central_device_should_start_failover_and_failback(self): command = ( "iot central device manual-failback --app-id {} --device-id {}".format( - APP_ID, device_id + self.app_id, device_id ) ) @@ -514,7 +500,7 @@ def test_central_device_should_start_failover_and_failback(self): # initiating failover again to see if hub identifier after failbackreturned to original state command = "iot central device manual-failover --app-id {} --device-id {} --ttl {}".format( - APP_ID, device_id, 5 + self.app_id, device_id, 5 ) result = self.cmd(command, api_version=self._api_version) @@ -537,7 +523,7 @@ def test_central_device_should_start_failover_and_failback(self): def _list_device_groups(self): return self.cmd( - "iot central device-group list --app-id {}".format(APP_ID), + "iot central device-group list --app-id {}".format(self.app_id), api_version=self._api_version, ).get_output_in_json() diff --git a/azext_iot/tests/central/test_iot_central_int.py b/azext_iot/tests/central/test_iot_central_int.py index ea0fe29a5..a50b99d99 100644 --- a/azext_iot/tests/central/test_iot_central_int.py +++ b/azext_iot/tests/central/test_iot_central_int.py @@ -13,18 +13,12 @@ from azext_iot.tests import helpers from azext_iot.tests.central import ( CentralLiveScenarioTest, - APP_ID, - STORAGE_CSTRING, - STORAGE_CONTAINER, DEFAULT_FILE_UPLOAD_TTL, sync_command_params, ) import pytest -if not all([APP_ID]): - raise ValueError("Set azext_iot_central_app_id to run central integration tests.") - IS_1_1_PREVIEW = True @@ -40,6 +34,16 @@ def fixture_api_version(self, request): print("Testing 1.1-preview") yield + @pytest.fixture(scope='class', autouse=True) + def setUpSuite(self): + self._create_storage_account() + + @pytest.fixture(scope='class', autouse=True) + def tearDownSuite(self): + yield + if self.storage_account_name: + self._delete_storage_account() + def __init__(self, test_scenario): super(TestIotCentral, self).__init__(test_scenario=test_scenario) @@ -66,7 +70,7 @@ def test_central_monitor_events(self): # Test with invalid app-id command = "iot central diagnostics monitor-events --app-id {} -y".format( - APP_ID + "zzz" + self.app_id + "zzz" ) self.cmd(command, api_version=self._api_version, expect_failure=True) @@ -210,11 +214,11 @@ def test_central_user_methods_CRUD(self): users = self._create_users(api_version=self._api_version) command = "iot central user show --app-id {} --user-id {}".format( - APP_ID, users[0].get("id") + self.app_id, users[0].get("id") ) self.cmd(command, api_version=self._api_version) - command = "iot central user list --app-id {}".format(APP_ID) + command = "iot central user list --app-id {}".format(self.app_id) result = self.cmd(command, api_version=self._api_version).get_output_in_json() for user in users: @@ -224,7 +228,7 @@ def test_central_user_methods_CRUD(self): current_role = user["roles"][0]["role"] new_role = [x for x in get_enum_values(Role) if x != current_role][0] command = "iot central user update --app-id {} --email {} --role {} --user-id {}".format( - APP_ID, user["email"], new_role, user["id"] + self.app_id, user["email"], new_role, user["id"] ) checks = [self.check("roles[0].role", new_role)] self.cmd(command, api_version=self._api_version, checks=checks) @@ -236,12 +240,12 @@ def test_central_user_methods_CRUD(self): def test_central_api_token_methods_CRD(self): tokens = self._create_api_tokens(api_version=self._api_version) command = "iot central api-token show --app-id {} --token-id {}".format( - APP_ID, tokens[0].get("id") + self.app_id, tokens[0].get("id") ) self.cmd(command, api_version=self._api_version) command = "iot central api-token list --app-id {}".format( - APP_ID, + self.app_id, ) result = self.cmd(command, api_version=self._api_version).get_output_in_json() @@ -275,13 +279,13 @@ def test_central_run_command_root_level(self): self._wait_for_provisioned(device_id=device_id, api_version=self._api_version) command = "iot central device command run -n {} -d {} --cn {} -k '{}'".format( - APP_ID, device_id, command_name, sync_command_params + self.app_id, device_id, command_name, sync_command_params ) run_command_result = self.cmd(command, api_version=self._api_version) command = "iot central device command history -n {} -d {} --cn {}".format( - APP_ID, device_id, command_name + self.app_id, device_id, command_name ) show_command_result = self.cmd(command, api_version=self._api_version) @@ -313,13 +317,13 @@ def test_central_run_command_component(self): command = ( "iot central device command run -n {} -d {} -i {} --cn {} -k '{}'".format( - APP_ID, device_id, interface_id, command_name, sync_command_params + self.app_id, device_id, interface_id, command_name, sync_command_params ) ) run_command_result = self.cmd(command, api_version=self._api_version) command = "iot central device command history -n {} -d {} -i {} --cn {}".format( - APP_ID, device_id, interface_id, command_name + self.app_id, device_id, interface_id, command_name ) show_command_result = self.cmd(command, api_version=self._api_version) @@ -339,10 +343,6 @@ def test_central_run_command_component(self): # check that run result and show result indeed match assert run_result["response"] == show_result["value"][0]["response"] - @pytest.mark.skipif( - not STORAGE_CSTRING or not STORAGE_CONTAINER, - reason="empty azext_iot_central_storage_cstring or azext_iot_central_storage_container env var", - ) @pytest.mark.xfail( condition=not IS_1_1_PREVIEW, reason="Api version not supported", @@ -363,7 +363,7 @@ def test_central_fileupload_methods_CRUD_required(self): # UPDATE command = ( "iot central file-upload-config update --app-id {} --sas-ttl {}".format( - APP_ID, "PT4H" + self.app_id, "PT4H" ) ) self.cmd(command, api_version=self._api_version) @@ -374,15 +374,11 @@ def test_central_fileupload_methods_CRUD_required(self): # DELETE self._delete_fileupload(api_version=self._api_version) # check deleting state - command = "iot central file-upload-config show -n {}".format(APP_ID) + command = "iot central file-upload-config show -n {}".format(self.app_id) result = self.cmd(command, api_version=self._api_version).get_output_in_json() assert result["state"] == "deleting" self._wait_for_storage_configured(api_version=self._api_version) - @pytest.mark.skipif( - not STORAGE_CSTRING or not STORAGE_CONTAINER, - reason="empty azext_iot_central_storage_cstring or azext_iot_central_storage_container env var", - ) def test_central_fileupload_methods_CRUD_optional(self): ACCOUNT_NAME = "account" SAS_TTL = "PT2H" @@ -400,7 +396,7 @@ def test_central_fileupload_methods_CRUD_optional(self): # UPDATE command = ( "iot central file-upload-config update --app-id {} --sas-ttl {}".format( - APP_ID, "PT4H" + self.app_id, "PT4H" ) ) self.cmd(command, api_version=self._api_version) @@ -411,7 +407,7 @@ def test_central_fileupload_methods_CRUD_optional(self): self._delete_fileupload(api_version=self._api_version) # check deleting state - command = "iot central file-upload-config show -n {}".format(APP_ID) + command = "iot central file-upload-config show -n {}".format(self.app_id) result = self.cmd(command, api_version=self._api_version).get_output_in_json() assert result["state"] == "deleting" self._wait_for_storage_configured(api_version=self._api_version) @@ -423,24 +419,20 @@ def test_central_fileupload_methods_CRUD_optional(self): def test_central_organization_methods_CRUD(self): org = self._create_organization(api_version=self._api_version) command = "iot central organization show -n {} --org-id {}".format( - APP_ID, org["id"] + self.app_id, org["id"] ) result = self.cmd(command, api_version=self._api_version).get_output_in_json() assert result["id"] == org["id"] # UPDATE command = "iot central organization update --app-id {} --org-id {} --org-name {}".format( - APP_ID, org["id"], "new_name" + self.app_id, org["id"], "new_name" ) checks = [self.check("displayName", "new_name")] self.cmd(command, api_version=self._api_version, checks=checks) # DELETE self._delete_organization(org_id=org["id"], api_version=self._api_version) - @pytest.mark.skipif( - not STORAGE_CSTRING or not STORAGE_CONTAINER, - reason="empty azext_iot_central_storage_cstring or azext_iot_central_storage_container env var", - ) @pytest.mark.xfail( condition=not IS_1_1_PREVIEW, reason="Api version not supported", @@ -450,7 +442,7 @@ def test_central_destination_export_methods_CRD(self): export_id = "aztestexport001" dest = self._create_destination(api_version=self._api_version, dest_id=dest_id) command = "iot central export destination show -n {} --dest-id {}".format( - APP_ID, dest["id"] + self.app_id, dest["id"] ) result = self.cmd(command, api_version=self._api_version).get_output_in_json() assert result["id"] == dest["id"] @@ -459,7 +451,7 @@ def test_central_destination_export_methods_CRD(self): api_version=self._api_version, export_id=export_id, dest_id=dest_id ) command = "iot central export show -n {} --export-id {}".format( - APP_ID, export["id"] + self.app_id, export["id"] ) export_result = self.cmd( command, api_version=self._api_version @@ -480,7 +472,7 @@ def test_central_query_methods_run(self): ) command = 'iot central query -n {} --query-string "{}"'.format( - APP_ID, + self.app_id, "SELECT TOP 1 testDefaultCapability FROM dtmi:intTestDeviceTemplateid WHERE WITHIN_WINDOW(PT1H)", ) response = self.cmd(command, api_version=self._api_version).get_output_in_json()