From 8449323943d35d376a63f39ba50cd3f1a42935c3 Mon Sep 17 00:00:00 2001 From: Xiang Yan Date: Mon, 2 Nov 2020 10:55:56 -0800 Subject: [PATCH 1/4] revert creation takes full object change --- .../azure-ai-metricsadvisor/CHANGELOG.md | 18 +- .../azure-ai-metricsadvisor/README.md | 26 +- .../azure/ai/metricsadvisor/_helpers.py | 20 + .../_metrics_advisor_administration_client.py | 147 +++- ...ics_advisor_administration_client_async.py | 116 ++- .../azure/ai/metricsadvisor/models/_models.py | 18 - .../sample_alert_configuration_async.py | 81 +- .../async_samples/sample_data_feeds_async.py | 69 +- .../sample_detection_configuration_async.py | 25 +- .../samples/sample_alert_configuration.py | 5 +- .../samples/sample_data_feeds.py | 15 +- .../samples/sample_detection_configuration.py | 5 +- .../tests/async_tests/base_testcase_async.py | 334 ++++---- ...ds_async.test_create_simple_data_feed.yaml | 84 ++ .../async_tests/test_alert_config_async.py | 559 ++++++------ .../async_tests/test_data_feeds_async.py | 808 +++++++++--------- .../test_detection_config_async.py | 349 ++++---- .../tests/base_testcase.py | 337 ++++---- ...ta_feeds.test_create_simple_data_feed.yaml | 118 +++ .../tests/test_alert_config.py | 559 ++++++------ .../tests/test_data_feeds.py | 805 ++++++++--------- .../tests/test_detection_config.py | 349 ++++---- 22 files changed, 2561 insertions(+), 2286 deletions(-) create mode 100644 sdk/metricsadvisor/azure-ai-metricsadvisor/tests/async_tests/recordings/test_data_feeds_async.test_create_simple_data_feed.yaml create mode 100644 sdk/metricsadvisor/azure-ai-metricsadvisor/tests/recordings/test_data_feeds.test_create_simple_data_feed.yaml diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/CHANGELOG.md b/sdk/metricsadvisor/azure-ai-metricsadvisor/CHANGELOG.md index d790aa9b443b..91b6dd5f30df 100644 --- a/sdk/metricsadvisor/azure-ai-metricsadvisor/CHANGELOG.md +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/CHANGELOG.md @@ -4,9 +4,6 @@ **Breaking Changes** -- `create_data_feed` now takes as input a `DataFeed` object -- `create_metric_anomaly_detection_configuration` now takes as input an `AnomalyDetectionConfiguration` object -- `create_anomaly_detection_configuration` now takes as input an `AnomalyAlertConfiguration` object - `create_hook` now takes as input an `EmailHook` or `WebHook` - `Anomaly` has been renamed to `DataPointAnomaly` - `Incident` has been renamed to `AnomalyIncident` @@ -25,6 +22,21 @@ - `timestamp_list` has been renamed to `timestamps` on `MetricSeriesData` - `value_list` has been renamed to `values` on `MetricSeriesData` - `SeriesResult` has been renamed to `MetricEnrichedSeriesData` +- `create_anomaly_alert_configuration` has been renamed to `create_alert_configuration` +- `get_anomaly_alert_configuration` has been renamed to `get_alert_configuration` +- `delete_anomaly_alert_configuration` has been renamed to `delete_alert_configuration` +- `update_anomaly_alert_configuration` has been renamed to `update_alert_configuration` +- `list_anomaly_alert_configurations` has been renamed to `list_alert_configurations` +- `create_metric_anomaly_detection_configuration` has been renamed to `create_detection_configuration` +- `get_metric_anomaly_detection_configuration` has been renamed to `get_detection_configuration` +- `delete_metric_anomaly_detection_configuration` has been renamed to `delete_detection_configuration` +- `update_metric_anomaly_detection_configuration` has been renamed to `update_detection_configuration` +- `list_metric_anomaly_detection_configurations` has been renamed to `list_detection_configurations` +- `list_feedbacks` has been renamed to `list_feedback` +- `list_alerts_for_alert_configuration` has been renamed to `list_alerts` +- `list_anomalies_for_alert` & `list_anomalies_for_detection_configuration` have been grouped into `list_anomalies` +- `list_dimension_values_for_detection_configuration` has been renamed to `list_dimension_values` +- `list_incidents_for_alert` & `list_incidents_for_detection_configuration` have been grouped into `list_incidents` **New Features** diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/README.md b/sdk/metricsadvisor/azure-ai-metricsadvisor/README.md index 1ddbe23f125e..d2e7e1451e99 100644 --- a/sdk/metricsadvisor/azure-ai-metricsadvisor/README.md +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/README.md @@ -124,9 +124,6 @@ from azure.ai.metricsadvisor.models import ( DataFeedDimension, DataFeedOptions, DataFeedRollupSettings, - DataFeedMissingDataPointFillSettings, - DataFeedGranularity, - DataFeed ) service_endpoint = os.getenv("ENDPOINT") @@ -140,13 +137,13 @@ client = MetricsAdvisorAdministrationClient( MetricsAdvisorKeyCredential(subscription_key, api_key) ) -data_feed = DataFeed( +data_feed = client.create_data_feed( name="My data feed", source=SQLServerDataFeed( connection_string=sql_server_connection_string, query=query, ), - granularity=DataFeedGranularity("Daily"), + granularity="Daily", schema=DataFeedSchema( metrics=[ DataFeedMetric(name="cost", display_name="Cost"), @@ -158,9 +155,7 @@ data_feed = DataFeed( ], timestamp_column="Timestamp" ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 10, 1) - ), + ingestion_settings=datetime.datetime(2019, 10, 1), options=DataFeedOptions( data_feed_description="cost/revenue data feed", rollup_settings=DataFeedRollupSettings( @@ -175,9 +170,7 @@ data_feed = DataFeed( ) ) -my_sql_data_feed = client.create_data_feed(data_feed) - -return my_sql_data_feed +return data_feed ``` ### Check ingestion status @@ -220,7 +213,6 @@ from azure.ai.metricsadvisor.models import ( SmartDetectionCondition, SuppressCondition, MetricDetectionCondition, - AnomalyDetectionConfiguration ) service_endpoint = os.getenv("ENDPOINT") @@ -260,7 +252,7 @@ smart_detection_condition = SmartDetectionCondition( ) ) -anomaly_detection_config = AnomalyDetectionConfiguration( +detection_config = client.create_detection_configuration( name="my_detection_config", metric_id=metric_id, description="anomaly detection config for metric", @@ -271,9 +263,6 @@ anomaly_detection_config = AnomalyDetectionConfiguration( smart_detection_condition=smart_detection_condition ) ) - -detection_config = client.create_detection_configuration(anomaly_detection_config) - return detection_config ``` @@ -291,7 +280,6 @@ from azure.ai.metricsadvisor.models import ( SeverityCondition, MetricBoundaryCondition, MetricAnomalyAlertSnoozeCondition, - AnomalyAlertConfiguration ) service_endpoint = os.getenv("ENDPOINT") subscription_key = os.getenv("SUBSCRIPTION_KEY") @@ -304,7 +292,7 @@ client = MetricsAdvisorAdministrationClient( MetricsAdvisorKeyCredential(subscription_key, api_key) ) -anomaly_alert_configuration = AnomalyAlertConfiguration( +alert_config = client.create_alert_configuration( name="my alert config", description="alert config description", cross_metrics_operator="AND", @@ -347,8 +335,6 @@ anomaly_alert_configuration = AnomalyAlertConfiguration( hook_ids=[hook_id] ) -alert_config = client.create_anomaly_alert_configuration(anomaly_alert_configuration) - return alert_config ``` diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/_helpers.py b/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/_helpers.py index b11897df3031..19f33b3da543 100644 --- a/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/_helpers.py +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/_helpers.py @@ -15,6 +15,11 @@ from msrest import Serializer from azure.core.exceptions import HttpResponseError from .models import ( + DataFeedGranularityType, + DataFeedGranularity, + DataFeedSchema, + DataFeedMetric, + DataFeedIngestionSettings, AnomalyFeedback, ChangePointFeedback, CommentFeedback, @@ -125,6 +130,21 @@ def convert_to_generated_data_feed_type( :return: The generated model for the data source type """ + if isinstance(granularity, (DataFeedGranularityType, six.string_types)): + granularity = DataFeedGranularity( + granularity_type=granularity, + ) + + if isinstance(schema, list): + schema = DataFeedSchema( + metrics=[DataFeedMetric(name=metric_name) for metric_name in schema] + ) + + if isinstance(ingestion_settings, (datetime.datetime, six.string_types)): + ingestion_settings = DataFeedIngestionSettings( + ingestion_begin_time=ingestion_settings + ) + return generated_feed_type( data_source_parameter=source.__dict__, data_feed_name=name, diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/_metrics_advisor_administration_client.py b/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/_metrics_advisor_administration_client.py index 77ba10158cdd..a204321d06e4 100644 --- a/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/_metrics_advisor_administration_client.py +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/_metrics_advisor_administration_client.py @@ -19,6 +19,7 @@ from ._generated._azure_cognitive_service_metrics_advisor_restapi_open_ap_iv2 \ import AzureCognitiveServiceMetricsAdvisorRESTAPIOpenAPIV2 as _Client from ._generated.models import ( + AnomalyAlertingConfiguration as _AnomalyAlertingConfiguration, AzureApplicationInsightsDataFeed as _AzureApplicationInsightsDataFeed, AzureBlobDataFeed as _AzureBlobDataFeed, AzureCosmosDBDataFeed as _AzureCosmosDBDataFeed, @@ -45,6 +46,7 @@ PostgreSqlDataFeedPatch as _PostgreSqlDataFeedPatch, MongoDBDataFeedPatch as _MongoDBDataFeedPatch, SQLServerDataFeedPatch as _SQLServerDataFeedPatch, + AnomalyDetectionConfiguration as _AnomalyDetectionConfiguration, IngestionProgressResetOptions as _IngestionProgressResetOptions, IngestionStatusQueryOptions as _IngestionStatusQueryOptions, ) @@ -64,15 +66,52 @@ WebNotificationHook, AnomalyAlertConfiguration, AnomalyDetectionConfiguration, - DataFeedIngestionProgress + DataFeedIngestionProgress, + DataFeedIngestionProgress, + AzureApplicationInsightsDataFeed, + AzureBlobDataFeed, + AzureCosmosDBDataFeed, + AzureDataExplorerDataFeed, + AzureTableDataFeed, + HttpRequestDataFeed, + InfluxDBDataFeed, + MySqlDataFeed, + PostgreSqlDataFeed, + SQLServerDataFeed, + MongoDBDataFeed, + AzureDataLakeStorageGen2DataFeed, + ElasticsearchDataFeed ) if TYPE_CHECKING: from azure.core.paging import ItemPaged from ._metrics_advisor_key_credential import MetricsAdvisorKeyCredential from ._generated.models import IngestionStatus as DataFeedIngestionStatus - from .models._models import NotificationHook - + from .models._models import ( + MetricAlertConfiguration, + DataFeedGranularity, + DataFeedGranularityType, + DataFeedSchema, + DataFeedIngestionSettings, + NotificationHook, + MetricDetectionCondition + ) + +DataFeedSourceUnion = Union[ + AzureApplicationInsightsDataFeed, + AzureBlobDataFeed, + AzureCosmosDBDataFeed, + AzureDataExplorerDataFeed, + AzureTableDataFeed, + HttpRequestDataFeed, + InfluxDBDataFeed, + MySqlDataFeed, + PostgreSqlDataFeed, + SQLServerDataFeed, + MongoDBDataFeed, + AzureDataLakeStorageGen2DataFeed, + ElasticsearchDataFeed +] DATA_FEED = { "SqlServer": _SQLServerDataFeed, @@ -170,13 +209,22 @@ def __exit__(self, *args): @distributed_trace def create_alert_configuration( - self, alert_configuration, # type: AnomalyAlertConfiguration + self, name, # type: str + metric_alert_configurations, # type: List[MetricAlertConfiguration] + hook_ids, # type: List[str] **kwargs # type: Any ): # type: (...) -> AnomalyAlertConfiguration """Create an anomaly alert configuration. - :param alert_configuration: The alert configuration to create. - :type alert_configuration: ~azure.ai.metricsadvisor.models.AnomalyAlertConfiguration + :param str name: Name for the anomaly alert configuration. + :param metric_alert_configurations: Anomaly alert configurations. + :type metric_alert_configurations: list[~azure.ai.metricsadvisor.models.MetricAlertConfiguration] + :param list[str] hook_ids: Unique hook IDs. + :keyword cross_metrics_operator: Cross metrics operator should be specified when setting up multiple metric + alert configurations. Possible values include: "AND", "OR", "XOR". + :paramtype cross_metrics_operator: str or + ~azure.ai.metricsadvisor.models.MetricAnomalyAlertConfigurationsOperator + :keyword str description: Anomaly alert configuration description. :return: AnomalyAlertConfiguration :rtype: ~azure.ai.metricsadvisor.models.AnomalyAlertConfiguration :raises ~azure.core.exceptions.HttpResponseError: @@ -191,8 +239,17 @@ def create_alert_configuration( :caption: Create an anomaly alert configuration """ + cross_metrics_operator = kwargs.pop("cross_metrics_operator", None) response_headers = self._client.create_anomaly_alerting_configuration( # type: ignore - alert_configuration._to_generated(), + _AnomalyAlertingConfiguration( + name=name, + metric_alerting_configurations=[ + config._to_generated() for config in metric_alert_configurations + ], + hook_ids=hook_ids, + cross_metrics_operator=cross_metrics_operator, + description=kwargs.pop("description", None) + ), cls=lambda pipeline_response, _, response_headers: response_headers, **kwargs ) @@ -202,13 +259,32 @@ def create_alert_configuration( @distributed_trace def create_data_feed( - self, data_feed, # type: DataFeed + self, name, # type: str + source, # type: DataFeedSourceUnion + granularity, # type: Union[str, DataFeedGranularityType, DataFeedGranularity] + schema, # type: Union[List[str], DataFeedSchema] + ingestion_settings, # type: Union[datetime.datetime, DataFeedIngestionSettings] **kwargs # type: Any ): # type: (...) -> DataFeed """Create a new data feed. - :param data_feed: The data feed to create - :type data_feed: ~azure.ai.metricsadvisor.models.DataFeed + :param str name: Name for the data feed. + :param source: The source of the data feed + :type source: Union[AzureApplicationInsightsDataFeed, AzureBlobDataFeed, AzureCosmosDBDataFeed, + AzureDataExplorerDataFeed, AzureDataLakeStorageGen2DataFeed, AzureTableDataFeed, HttpRequestDataFeed, + InfluxDBDataFeed, MySqlDataFeed, PostgreSqlDataFeed, SQLServerDataFeed, MongoDBDataFeed, + ElasticsearchDataFeed] + :param granularity: Granularity type. If using custom granularity, you must instantiate a DataFeedGranularity. + :type granularity: Union[str, ~azure.ai.metricsadvisor.models.DataFeedGranularityType, + ~azure.ai.metricsadvisor.models.DataFeedGranularity] + :param schema: Data feed schema. Can be passed as a list of metric names as strings or as a DataFeedSchema + object if additional configuration is needed. + :type schema: Union[list[str], ~azure.ai.metricsadvisor.models.DataFeedSchema] + :param ingestion_settings: The data feed ingestions settings. Can be passed as a datetime to use for the + ingestion begin time or as a DataFeedIngestionSettings object if additional configuration is needed. + :type ingestion_settings: Union[~datetime.datetime, ~azure.ai.metricsadvisor.models.DataFeedIngestionSettings] + :keyword options: Data feed options. + :paramtype options: ~azure.ai.metricsadvisor.models.DataFeedOptions :return: DataFeed :rtype: ~azure.ai.metricsadvisor.models.DataFeed :raises ~azure.core.exceptions.HttpResponseError: @@ -223,15 +299,16 @@ def create_data_feed( :caption: Create a data feed """ - data_feed_type = DATA_FEED[data_feed.source.data_source_type] + options = kwargs.pop("options", None) + data_feed_type = DATA_FEED[source.data_source_type] data_feed_detail = convert_to_generated_data_feed_type( generated_feed_type=data_feed_type, - name=data_feed.name, - source=data_feed.source, - granularity=data_feed.granularity, - schema=data_feed.schema, - ingestion_settings=data_feed.ingestion_settings, - options=data_feed.options + name=name, + source=source, + granularity=granularity, + schema=schema, + ingestion_settings=ingestion_settings, + options=options ) response_headers = self._client.create_data_feed( # type: ignore @@ -285,13 +362,25 @@ def create_hook( @distributed_trace def create_detection_configuration( - self, detection_configuration, # type: AnomalyDetectionConfiguration + self, name, # type: str + metric_id, # type: str + whole_series_detection_condition, # type: MetricDetectionCondition **kwargs # type: Any ): # type: (...) -> AnomalyDetectionConfiguration """Create anomaly detection configuration. - :param detection_configuration: The detection configuration to create. - :type detection_configuration: ~azure.ai.metricsadvisor.models.AnomalyDetectionConfiguration + :param str name: The name for the anomaly detection configuration + :param str metric_id: Required. metric unique id. + :param whole_series_detection_condition: Required. + Conditions to detect anomalies in all time series of a metric. + :type whole_series_detection_condition: ~azure.ai.metricsadvisor.models.MetricDetectionCondition + :keyword str description: anomaly detection configuration description. + :keyword series_group_detection_conditions: detection configuration for series group. + :paramtype series_group_detection_conditions: + list[~azure.ai.metricsadvisor.models.MetricSeriesGroupDetectionCondition] + :keyword series_detection_conditions: detection configuration for specific series. + :paramtype series_detection_conditions: + list[~azure.ai.metricsadvisor.models.MetricSingleSeriesDetectionCondition] :return: AnomalyDetectionConfiguration :rtype: ~azure.ai.metricsadvisor.models.AnomalyDetectionConfiguration :raises ~azure.core.exceptions.HttpResponseError: @@ -306,8 +395,24 @@ def create_detection_configuration( :caption: Create an anomaly detection configuration """ + description = kwargs.pop("description", None) + series_group_detection_conditions = kwargs.pop("series_group_detection_conditions", None) + series_detection_conditions = kwargs.pop("series_detection_conditions", None) + config = _AnomalyDetectionConfiguration( + name=name, + metric_id=metric_id, + description=description, + whole_metric_configuration=whole_series_detection_condition._to_generated(), + dimension_group_override_configurations=[ + group._to_generated() for group in series_group_detection_conditions + ] if series_group_detection_conditions else None, + series_override_configurations=[ + series._to_generated() for series in series_detection_conditions] + if series_detection_conditions else None, + ) + response_headers = self._client.create_anomaly_detection_configuration( # type: ignore - detection_configuration._to_generated(), + config, cls=lambda pipeline_response, _, response_headers: response_headers, **kwargs ) diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/aio/_metrics_advisor_administration_client_async.py b/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/aio/_metrics_advisor_administration_client_async.py index e681d2332a2b..446d81ee309c 100644 --- a/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/aio/_metrics_advisor_administration_client_async.py +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/aio/_metrics_advisor_administration_client_async.py @@ -9,6 +9,7 @@ from typing import ( Any, + List, Union, cast ) @@ -19,6 +20,8 @@ from azure.core.async_paging import AsyncItemPaged from .._generated.aio import AzureCognitiveServiceMetricsAdvisorRESTAPIOpenAPIV2 as _ClientAsync from .._generated.models import ( + AnomalyAlertingConfiguration as _AnomalyAlertingConfiguration, + AnomalyDetectionConfiguration as _AnomalyDetectionConfiguration, IngestionStatus as DataFeedIngestionStatus, IngestionProgressResetOptions as _IngestionProgressResetOptions, IngestionStatusQueryOptions as _IngestionStatusQueryOptions, @@ -41,11 +44,18 @@ AnomalyAlertConfiguration, AnomalyDetectionConfiguration, DataFeedIngestionProgress, - NotificationHook + DataFeedGranularityType, + MetricAlertConfiguration, + DataFeedGranularity, + DataFeedSchema, + DataFeedIngestionSettings, + NotificationHook, + MetricDetectionCondition ) from .._metrics_advisor_administration_client import ( DATA_FEED, - DATA_FEED_PATCH + DATA_FEED_PATCH, + DataFeedSourceUnion ) @@ -106,13 +116,22 @@ async def close(self) -> None: @distributed_trace_async async def create_alert_configuration( - self, alert_configuration: AnomalyAlertConfiguration, + self, name: str, + metric_alert_configurations: List[MetricAlertConfiguration], + hook_ids: List[str], **kwargs: Any ) -> AnomalyAlertConfiguration: """Create an anomaly alert configuration. - :param alert_configuration: The alert configuration to create. - :type alert_configuration: ~azure.ai.metricsadvisor.models.AnomalyAlertConfiguration + :param str name: Name for the anomaly alert configuration. + :param metric_alert_configurations: Anomaly alert configurations. + :type metric_alert_configurations: list[~azure.ai.metricsadvisor.models.MetricAlertConfiguration] + :param list[str] hook_ids: Unique hook IDs. + :keyword cross_metrics_operator: Cross metrics operator should be specified when setting up multiple metric + alert configurations. Possible values include: "AND", "OR", "XOR". + :paramtype cross_metrics_operator: str or + ~azure.ai.metricsadvisor.models.MetricAnomalyAlertConfigurationsOperator + :keyword str description: Anomaly alert configuration description. :return: AnomalyAlertConfiguration :rtype: ~azure.ai.metricsadvisor.models.AnomalyAlertConfiguration :raises ~azure.core.exceptions.HttpResponseError: @@ -127,8 +146,17 @@ async def create_alert_configuration( :caption: Create an anomaly alert configuration """ + cross_metrics_operator = kwargs.pop("cross_metrics_operator", None) response_headers = await self._client.create_anomaly_alerting_configuration( - alert_configuration._to_generated(), + _AnomalyAlertingConfiguration( + name=name, + metric_alerting_configurations=[ + config._to_generated() for config in metric_alert_configurations + ], + hook_ids=hook_ids, + cross_metrics_operator=cross_metrics_operator, + description=kwargs.pop("description", None) + ), cls=lambda pipeline_response, _, response_headers: response_headers, **kwargs ) @@ -138,13 +166,32 @@ async def create_alert_configuration( @distributed_trace_async async def create_data_feed( - self, data_feed: DataFeed, + self, name: str, + source: DataFeedSourceUnion, + granularity: Union[str, DataFeedGranularityType, DataFeedGranularity], + schema: Union[List[str], DataFeedSchema], + ingestion_settings: Union[datetime.datetime, DataFeedIngestionSettings], **kwargs: Any ) -> DataFeed: """Create a new data feed. - :param data_feed: The data feed to create - :type data_feed: ~azure.ai.metricsadvisor.models.DataFeed + :param str name: Name for the data feed. + :param source: The source of the data feed + :type source: Union[AzureApplicationInsightsDataFeed, AzureBlobDataFeed, AzureCosmosDBDataFeed, + AzureDataExplorerDataFeed, AzureDataLakeStorageGen2DataFeed, AzureTableDataFeed, HttpRequestDataFeed, + InfluxDBDataFeed, MySqlDataFeed, PostgreSqlDataFeed, SQLServerDataFeed, MongoDBDataFeed, + ElasticsearchDataFeed] + :param granularity: Granularity type. If using custom granularity, you must instantiate a DataFeedGranularity. + :type granularity: Union[str, ~azure.ai.metricsadvisor.models.DataFeedGranularityType, + ~azure.ai.metricsadvisor.models.DataFeedGranularity] + :param schema: Data feed schema. Can be passed as a list of metric names as strings or as a DataFeedSchema + object if additional configuration is needed. + :type schema: Union[list[str], ~azure.ai.metricsadvisor.models.DataFeedSchema] + :param ingestion_settings: The data feed ingestions settings. Can be passed as a datetime to use for the + ingestion begin time or as a DataFeedIngestionSettings object if additional configuration is needed. + :type ingestion_settings: Union[~datetime.datetime, ~azure.ai.metricsadvisor.models.DataFeedIngestionSettings] + :keyword options: Data feed options. + :paramtype options: ~azure.ai.metricsadvisor.models.DataFeedOptions :return: DataFeed :rtype: ~azure.ai.metricsadvisor.models.DataFeed :raises ~azure.core.exceptions.HttpResponseError: @@ -159,15 +206,16 @@ async def create_data_feed( :caption: Create a data feed """ - data_feed_type = DATA_FEED[data_feed.source.data_source_type] + options = kwargs.pop("options", None) + data_feed_type = DATA_FEED[source.data_source_type] data_feed_detail = convert_to_generated_data_feed_type( generated_feed_type=data_feed_type, - name=data_feed.name, - source=data_feed.source, - granularity=data_feed.granularity, - schema=data_feed.schema, - ingestion_settings=data_feed.ingestion_settings, - options=data_feed.options + name=name, + source=source, + granularity=granularity, + schema=schema, + ingestion_settings=ingestion_settings, + options=options ) response_headers = await self._client.create_data_feed( @@ -223,13 +271,25 @@ async def create_hook( @distributed_trace_async async def create_detection_configuration( - self, detection_configuration: AnomalyDetectionConfiguration, + self, name: str, + metric_id: str, + whole_series_detection_condition: MetricDetectionCondition, **kwargs: Any ) -> AnomalyDetectionConfiguration: """Create anomaly detection configuration. - :param detection_configuration: The detection configuration to create. - :type detection_configuration: ~azure.ai.metricsadvisor.models.AnomalyDetectionConfiguration + :param str name: The name for the anomaly detection configuration + :param str metric_id: Required. metric unique id. + :param whole_series_detection_condition: Required. + Conditions to detect anomalies in all time series of a metric. + :type whole_series_detection_condition: ~azure.ai.metricsadvisor.models.MetricDetectionCondition + :keyword str description: anomaly detection configuration description. + :keyword series_group_detection_conditions: detection configuration for series group. + :paramtype series_group_detection_conditions: + list[~azure.ai.metricsadvisor.models.MetricSeriesGroupDetectionCondition] + :keyword series_detection_conditions: detection configuration for specific series. + :paramtype series_detection_conditions: + list[~azure.ai.metricsadvisor.models.MetricSingleSeriesDetectionCondition] :return: AnomalyDetectionConfiguration :rtype: ~azure.ai.metricsadvisor.models.AnomalyDetectionConfiguration :raises ~azure.core.exceptions.HttpResponseError: @@ -244,8 +304,24 @@ async def create_detection_configuration( :caption: Create an anomaly detection configuration """ + description = kwargs.pop("description", None) + series_group_detection_conditions = kwargs.pop("series_group_detection_conditions", None) + series_detection_conditions = kwargs.pop("series_detection_conditions", None) + config = _AnomalyDetectionConfiguration( + name=name, + metric_id=metric_id, + description=description, + whole_metric_configuration=whole_series_detection_condition._to_generated(), + dimension_group_override_configurations=[ + group._to_generated() for group in series_group_detection_conditions + ] if series_group_detection_conditions else None, + series_override_configurations=[ + series._to_generated() for series in series_detection_conditions] + if series_detection_conditions else None, + ) + response_headers = await self._client.create_anomaly_detection_configuration( - detection_configuration._to_generated(), + config, cls=lambda pipeline_response, _, response_headers: response_headers, **kwargs ) diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/models/_models.py b/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/models/_models.py index c3a7a220e1d6..30ffb86eef1a 100644 --- a/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/models/_models.py +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/models/_models.py @@ -59,8 +59,6 @@ ElasticsearchParameter as _ElasticsearchParameter, DimensionGroupIdentity as _DimensionGroupIdentity, SeriesIdentity as _SeriesIdentity, - AnomalyAlertingConfiguration as _AnomalyAlertingConfiguration, - AnomalyDetectionConfiguration as _AnomalyDetectionConfiguration, AnomalyAlertingConfigurationPatch as _AnomalyAlertingConfigurationPatch, AnomalyDetectionConfigurationPatch as _AnomalyDetectionConfigurationPatch ) @@ -78,22 +76,6 @@ RootCause, ) - DataFeedSourceUnion = Union[ - "AzureApplicationInsightsDataFeed", - "AzureBlobDataFeed", - "AzureCosmosDBDataFeed", - "AzureDataExplorerDataFeed", - "AzureTableDataFeed", - "HttpRequestDataFeed", - "InfluxDBDataFeed", - "MySqlDataFeed", - "PostgreSqlDataFeed", - "SQLServerDataFeed", - "MongoDBDataFeed", - "AzureDataLakeStorageGen2DataFeed", - "ElasticsearchDataFeed" - ] - class MetricAnomalyAlertScopeType(str, Enum): """Anomaly scope diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/samples/async_samples/sample_alert_configuration_async.py b/sdk/metricsadvisor/azure-ai-metricsadvisor/samples/async_samples/sample_alert_configuration_async.py index 59e5dde8932b..5c8a9139f826 100644 --- a/sdk/metricsadvisor/azure-ai-metricsadvisor/samples/async_samples/sample_alert_configuration_async.py +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/samples/async_samples/sample_alert_configuration_async.py @@ -40,7 +40,6 @@ async def sample_create_alert_config_async(): SeverityCondition, MetricBoundaryCondition, MetricAnomalyAlertSnoozeCondition, - AnomalyAlertConfiguration ) service_endpoint = os.getenv("METRICS_ADVISOR_ENDPOINT") subscription_key = os.getenv("METRICS_ADVISOR_SUBSCRIPTION_KEY") @@ -51,51 +50,49 @@ async def sample_create_alert_config_async(): client = MetricsAdvisorAdministrationClient(service_endpoint, MetricsAdvisorKeyCredential(subscription_key, api_key)) - alert_configuration = AnomalyAlertConfiguration( - name="my alert config", - description="alert config description", - cross_metrics_operator="AND", - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_configuration_id, - alert_scope=MetricAnomalyAlertScope( - scope_type="WholeSeries" - ), - alert_conditions=MetricAnomalyAlertConditions( - severity_condition=SeverityCondition( - min_alert_severity="Low", - max_alert_severity="High" - ) - ) - ), - MetricAlertConfiguration( - detection_configuration_id=detection_configuration_id, - alert_scope=MetricAnomalyAlertScope( - scope_type="TopN", - top_n_group_in_scope=TopNGroupScope( - top=10, - period=5, - min_top_count=5 + async with client: + alert_config = await client.create_anomaly_alert_configuration( + name="my alert config", + description="alert config description", + cross_metrics_operator="AND", + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_configuration_id, + alert_scope=MetricAnomalyAlertScope( + scope_type="WholeSeries" + ), + alert_conditions=MetricAnomalyAlertConditions( + severity_condition=SeverityCondition( + min_alert_severity="Low", + max_alert_severity="High" + ) ) ), - alert_conditions=MetricAnomalyAlertConditions( - metric_boundary_condition=MetricBoundaryCondition( - direction="Up", - upper=50 + MetricAlertConfiguration( + detection_configuration_id=detection_configuration_id, + alert_scope=MetricAnomalyAlertScope( + scope_type="TopN", + top_n_group_in_scope=TopNGroupScope( + top=10, + period=5, + min_top_count=5 + ) + ), + alert_conditions=MetricAnomalyAlertConditions( + metric_boundary_condition=MetricBoundaryCondition( + direction="Up", + upper=50 + ) + ), + alert_snooze_condition=MetricAnomalyAlertSnoozeCondition( + auto_snooze=2, + snooze_scope="Metric", + only_for_successive=True ) ), - alert_snooze_condition=MetricAnomalyAlertSnoozeCondition( - auto_snooze=2, - snooze_scope="Metric", - only_for_successive=True - ) - ), - ], - hook_ids=[hook_id] - ) - - async with client: - alert_config = await client.create_alert_configuration(alert_configuration) + ], + hook_ids=[hook_id] + ) return alert_config # [END create_alert_config_async] diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/samples/async_samples/sample_data_feeds_async.py b/sdk/metricsadvisor/azure-ai-metricsadvisor/samples/async_samples/sample_data_feeds_async.py index e9bc72c42574..fdfd744c737c 100644 --- a/sdk/metricsadvisor/azure-ai-metricsadvisor/samples/async_samples/sample_data_feeds_async.py +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/samples/async_samples/sample_data_feeds_async.py @@ -42,9 +42,6 @@ async def sample_create_data_feed_async(): DataFeedOptions, DataFeedRollupSettings, DataFeedMissingDataPointFillSettings, - DataFeedGranularity, - DataFeedIngestionSettings, - DataFeed ) service_endpoint = os.getenv("METRICS_ADVISOR_ENDPOINT") @@ -55,45 +52,41 @@ async def sample_create_data_feed_async(): client = MetricsAdvisorAdministrationClient(service_endpoint, MetricsAdvisorKeyCredential(subscription_key, api_key)) - data_feed = DataFeed( - name="My data feed", - source=SQLServerDataFeed( - connection_string=sql_server_connection_string, - query=query, - ), - granularity=DataFeedGranularity("Daily"), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost", display_name="Cost"), - DataFeedMetric(name="revenue", display_name="Revenue") - ], - dimensions=[ - DataFeedDimension(name="category", display_name="Category"), - DataFeedDimension(name="city", display_name="City") - ], - timestamp_column="Timestamp" - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 10, 1) - ), - options=DataFeedOptions( - data_feed_description="cost/revenue data feed", - rollup_settings=DataFeedRollupSettings( - rollup_type="AutoRollup", - rollup_method="Sum", - rollup_identification_value="__CUSTOM_SUM__" + async with client: + data_feed = await client.create_data_feed( + name="My data feed", + source=SQLServerDataFeed( + connection_string=sql_server_connection_string, + query=query, ), - missing_data_point_fill_settings=DataFeedMissingDataPointFillSettings( - fill_type="SmartFilling" + granularity="Daily", + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost", display_name="Cost"), + DataFeedMetric(name="revenue", display_name="Revenue") + ], + dimensions=[ + DataFeedDimension(name="category", display_name="Category"), + DataFeedDimension(name="city", display_name="City") + ], + timestamp_column="Timestamp" ), - access_mode="Private" + ingestion_settings=datetime.datetime(2019, 10, 1), + options=DataFeedOptions( + data_feed_description="cost/revenue data feed", + rollup_settings=DataFeedRollupSettings( + rollup_type="AutoRollup", + rollup_method="Sum", + rollup_identification_value="__CUSTOM_SUM__" + ), + missing_data_point_fill_settings=DataFeedMissingDataPointFillSettings( + fill_type="SmartFilling" + ), + access_mode="Private" + ) ) - ) - - async with client: - my_sql_data_feed = await client.create_data_feed(data_feed) - return my_sql_data_feed + return data_feed # [END create_data_feed_async] diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/samples/async_samples/sample_detection_configuration_async.py b/sdk/metricsadvisor/azure-ai-metricsadvisor/samples/async_samples/sample_detection_configuration_async.py index 6e6c02804c05..15ed0a47e410 100644 --- a/sdk/metricsadvisor/azure-ai-metricsadvisor/samples/async_samples/sample_detection_configuration_async.py +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/samples/async_samples/sample_detection_configuration_async.py @@ -37,7 +37,6 @@ async def sample_create_detection_config_async(): SmartDetectionCondition, SuppressCondition, MetricDetectionCondition, - AnomalyDetectionConfiguration ) service_endpoint = os.getenv("METRICS_ADVISOR_ENDPOINT") @@ -75,20 +74,18 @@ async def sample_create_detection_config_async(): ) ) - anomaly_detection_configuration = AnomalyDetectionConfiguration( - name="my_detection_config", - metric_id=metric_id, - description="anomaly detection config for metric", - whole_series_detection_condition=MetricDetectionCondition( - cross_conditions_operator="OR", - change_threshold_condition=change_threshold_condition, - hard_threshold_condition=hard_threshold_condition, - smart_detection_condition=smart_detection_condition - ) - ) - async with client: - detection_config = await client.create_detection_configuration(anomaly_detection_configuration) + detection_config = await client.create_metric_anomaly_detection_configuration( + name="my_detection_config", + metric_id=metric_id, + description="anomaly detection config for metric", + whole_series_detection_condition=MetricDetectionCondition( + cross_conditions_operator="OR", + change_threshold_condition=change_threshold_condition, + hard_threshold_condition=hard_threshold_condition, + smart_detection_condition=smart_detection_condition + ) + ) return detection_config # [END create_detection_config_async] diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/samples/sample_alert_configuration.py b/sdk/metricsadvisor/azure-ai-metricsadvisor/samples/sample_alert_configuration.py index c1a13321d621..91fcd8690fc7 100644 --- a/sdk/metricsadvisor/azure-ai-metricsadvisor/samples/sample_alert_configuration.py +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/samples/sample_alert_configuration.py @@ -38,7 +38,6 @@ def sample_create_alert_config(): SeverityCondition, MetricBoundaryCondition, MetricAnomalyAlertSnoozeCondition, - AnomalyAlertConfiguration ) service_endpoint = os.getenv("METRICS_ADVISOR_ENDPOINT") subscription_key = os.getenv("METRICS_ADVISOR_SUBSCRIPTION_KEY") @@ -49,7 +48,7 @@ def sample_create_alert_config(): client = MetricsAdvisorAdministrationClient(service_endpoint, MetricsAdvisorKeyCredential(subscription_key, api_key)) - alert_configuration = AnomalyAlertConfiguration( + alert_config = client.create_alert_configuration( name="my alert config", description="alert config description", cross_metrics_operator="AND", @@ -92,8 +91,6 @@ def sample_create_alert_config(): hook_ids=[hook_id] ) - alert_config = client.create_alert_configuration(alert_configuration) - return alert_config # [END create_alert_config] diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/samples/sample_data_feeds.py b/sdk/metricsadvisor/azure-ai-metricsadvisor/samples/sample_data_feeds.py index 013cd9679002..a318b991c8a5 100644 --- a/sdk/metricsadvisor/azure-ai-metricsadvisor/samples/sample_data_feeds.py +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/samples/sample_data_feeds.py @@ -40,9 +40,6 @@ def sample_create_data_feed(): DataFeedOptions, DataFeedRollupSettings, DataFeedMissingDataPointFillSettings, - DataFeedGranularity, - DataFeedIngestionSettings, - DataFeed ) service_endpoint = os.getenv("METRICS_ADVISOR_ENDPOINT") @@ -54,13 +51,13 @@ def sample_create_data_feed(): client = MetricsAdvisorAdministrationClient(service_endpoint, MetricsAdvisorKeyCredential(subscription_key, api_key)) - data_feed = DataFeed( + data_feed = client.create_data_feed( name="My data feed", source=SQLServerDataFeed( connection_string=sql_server_connection_string, query=query, ), - granularity=DataFeedGranularity("Daily"), + granularity="Daily", schema=DataFeedSchema( metrics=[ DataFeedMetric(name="cost", display_name="Cost"), @@ -72,9 +69,7 @@ def sample_create_data_feed(): ], timestamp_column="Timestamp" ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 10, 1) - ), + ingestion_settings=datetime.datetime(2019, 10, 1), options=DataFeedOptions( data_feed_description="cost/revenue data feed", rollup_settings=DataFeedRollupSettings( @@ -89,9 +84,7 @@ def sample_create_data_feed(): ) ) - my_sql_data_feed = client.create_data_feed(data_feed) - - return my_sql_data_feed + return data_feed # [END create_data_feed] diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/samples/sample_detection_configuration.py b/sdk/metricsadvisor/azure-ai-metricsadvisor/samples/sample_detection_configuration.py index bb56191c7b1b..b69ca5b3cb85 100644 --- a/sdk/metricsadvisor/azure-ai-metricsadvisor/samples/sample_detection_configuration.py +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/samples/sample_detection_configuration.py @@ -35,7 +35,6 @@ def sample_create_detection_config(): SmartDetectionCondition, SuppressCondition, MetricDetectionCondition, - AnomalyDetectionConfiguration ) service_endpoint = os.getenv("METRICS_ADVISOR_ENDPOINT") @@ -73,7 +72,7 @@ def sample_create_detection_config(): ) ) - detection_configuration = AnomalyDetectionConfiguration( + detection_config = client.create_detection_configuration( name="my_detection_config", metric_id=metric_id, description="anomaly detection config for metric", @@ -85,8 +84,6 @@ def sample_create_detection_config(): ) ) - detection_config = client.create_detection_configuration(detection_configuration) - return detection_config # [END create_detection_config] diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/async_tests/base_testcase_async.py b/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/async_tests/base_testcase_async.py index 50fc84012ea3..2ff2137724cb 100644 --- a/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/async_tests/base_testcase_async.py +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/async_tests/base_testcase_async.py @@ -47,9 +47,6 @@ HardThresholdCondition, EmailNotificationHook, WebNotificationHook, - DataFeed, - AnomalyDetectionConfiguration, - AnomalyAlertConfiguration ) @@ -181,48 +178,39 @@ def __init__(self, method_name): async def _create_data_feed(self, name): name = create_random_name(name) return await self.admin_client.create_data_feed( - DataFeed( - name=name, - source=SQLServerDataFeed( - connection_string=self.sql_server_connection_string, - query='select * from adsample2 where Timestamp = @StartTime' - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost"), - DataFeedMetric(name="revenue") - ], - dimensions=[ - DataFeedDimension(name="category"), - DataFeedDimension(name="city") - ], - timestamp_column="Timestamp" - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 10, 1), - ) - ) + name=name, + source=SQLServerDataFeed( + connection_string=self.sql_server_connection_string, + query="select * from adsample2 where Timestamp = @StartTime" + ), + granularity="Daily", + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost"), + DataFeedMetric(name="revenue") + ], + dimensions=[ + DataFeedDimension(name="category"), + DataFeedDimension(name="city") + ], + ), + ingestion_settings="2019-10-01T00:00:00Z", ) async def _create_data_feed_and_detection_config(self, name): data_feed = await self._create_data_feed(name) detection_config_name = create_random_name(name) detection_config = await self.admin_client.create_detection_configuration( - AnomalyDetectionConfiguration( - name=detection_config_name, - metric_id=data_feed.metric_ids[0], - description="testing", - whole_series_detection_condition=MetricDetectionCondition( - smart_detection_condition=SmartDetectionCondition( - sensitivity=50, - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=50, - min_ratio=50 - ) + name=detection_config_name, + metric_id=data_feed.metric_ids[0], + description="testing", + whole_series_detection_condition=MetricDetectionCondition( + smart_detection_condition=SmartDetectionCondition( + sensitivity=50, + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=50, + min_ratio=50 ) ) ) @@ -232,47 +220,45 @@ async def _create_data_feed_and_detection_config(self, name): async def _create_data_feed_for_update(self, name): data_feed_name = create_random_name(name) return await self.admin_client.create_data_feed( - DataFeed( - name=data_feed_name, - source=SQLServerDataFeed( - connection_string=self.sql_server_connection_string, - query='select * from adsample2 where Timestamp = @StartTime' - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost", display_name="display cost", description="the cost"), - DataFeedMetric(name="revenue", display_name="display revenue", description="the revenue") - ], - dimensions=[ - DataFeedDimension(name="category", display_name="display category"), - DataFeedDimension(name="city", display_name="display city") - ], - timestamp_column="Timestamp" + name=data_feed_name, + source=SQLServerDataFeed( + connection_string=self.sql_server_connection_string, + query=u"select * from adsample2 where Timestamp = @StartTime" + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost", display_name="display cost", description="the cost"), + DataFeedMetric(name="revenue", display_name="display revenue", description="the revenue") + ], + dimensions=[ + DataFeedDimension(name="category", display_name="display category"), + DataFeedDimension(name="city", display_name="display city") + ], + timestamp_column="Timestamp" + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 10, 1), + data_source_request_concurrency=0, + ingestion_retry_delay=-1, + ingestion_start_offset=-1, + stop_retry_after=-1, + ), + options=DataFeedOptions( + admin_emails=["yournamehere@microsoft.com"], + data_feed_description="my first data feed", + missing_data_point_fill_settings=DataFeedMissingDataPointFillSettings( + fill_type="SmartFilling" ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 10, 1), - data_source_request_concurrency=0, - ingestion_retry_delay=-1, - ingestion_start_offset=-1, - stop_retry_after=-1, + rollup_settings=DataFeedRollupSettings( + rollup_type="NoRollup", + rollup_method="None", ), - options=DataFeedOptions( - admin_emails=["yournamehere@microsoft.com"], - data_feed_description="my first data feed", - missing_data_point_fill_settings=DataFeedMissingDataPointFillSettings( - fill_type="SmartFilling" - ), - rollup_settings=DataFeedRollupSettings( - rollup_type="NoRollup", - rollup_method="None", - ), - viewer_emails=["viewers"], - access_mode="Private", - action_link_template="action link template" - ) + viewer_emails=["viewers"], + access_mode="Private", + action_link_template="action link template" ) ) @@ -281,57 +267,55 @@ async def _create_alert_config_for_update(self, name): detection_config, data_feed = await self._create_data_feed_and_detection_config(name) alert_config_name = create_random_name(name) alert_config = await self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - cross_metrics_operator="AND", - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="TopN", - top_n_group_in_scope=TopNGroupScope( - top=5, - period=10, - min_top_count=9 - ) - ), - alert_conditions=MetricAnomalyAlertConditions( - metric_boundary_condition=MetricBoundaryCondition( - direction="Both", - companion_metric_id=data_feed.metric_ids[0], - lower=1.0, - upper=5.0 - ) + name=alert_config_name, + cross_metrics_operator="AND", + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="TopN", + top_n_group_in_scope=TopNGroupScope( + top=5, + period=10, + min_top_count=9 ) ), - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="SeriesGroup", - series_group_in_scope={'city': 'Shenzhen'} - ), - alert_conditions=MetricAnomalyAlertConditions( - severity_condition=SeverityCondition( - min_alert_severity="Low", - max_alert_severity="High" - ) + alert_conditions=MetricAnomalyAlertConditions( + metric_boundary_condition=MetricBoundaryCondition( + direction="Both", + companion_metric_id=data_feed.metric_ids[0], + lower=1.0, + upper=5.0 ) + ) + ), + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="SeriesGroup", + series_group_in_scope={'city': 'Shenzhen'} ), - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="WholeSeries" - ), - alert_conditions=MetricAnomalyAlertConditions( - severity_condition=SeverityCondition( - min_alert_severity="Low", - max_alert_severity="High" - ) + alert_conditions=MetricAnomalyAlertConditions( + severity_condition=SeverityCondition( + min_alert_severity="Low", + max_alert_severity="High" ) ) - ], - hook_ids=[] - ) + ), + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="WholeSeries" + ), + alert_conditions=MetricAnomalyAlertConditions( + severity_condition=SeverityCondition( + min_alert_severity="Low", + max_alert_severity="High" + ) + ) + ) + ], + hook_ids=[] ) return alert_config, data_feed, detection_config @@ -339,63 +323,61 @@ async def _create_detection_config_for_update(self, name): data_feed = await self._create_data_feed(name) detection_config_name = create_random_name("testupdated") detection_config = await self.admin_client.create_detection_configuration( - AnomalyDetectionConfiguration( - name=detection_config_name, - metric_id=data_feed.metric_ids[0], - description="My test metric anomaly detection configuration", - whole_series_detection_condition=MetricDetectionCondition( - cross_conditions_operator="AND", - smart_detection_condition=SmartDetectionCondition( - sensitivity=50, - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=50, - min_ratio=50 - ) - ), - hard_threshold_condition=HardThresholdCondition( - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=5, - min_ratio=5 - ), - lower_bound=0, - upper_bound=100 - ), - change_threshold_condition=ChangeThresholdCondition( - change_percentage=50, - shift_point=30, - within_range=True, - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=2, - min_ratio=2 - ) + name=detection_config_name, + metric_id=data_feed.metric_ids[0], + description="My test metric anomaly detection configuration", + whole_series_detection_condition=MetricDetectionCondition( + cross_conditions_operator="AND", + smart_detection_condition=SmartDetectionCondition( + sensitivity=50, + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=50, + min_ratio=50 ) ), - series_detection_conditions=[MetricSingleSeriesDetectionCondition( - series_key={"city": "Shenzhen", "category": "Jewelry"}, - smart_detection_condition=SmartDetectionCondition( - anomaly_detector_direction="Both", - sensitivity=63, - suppress_condition=SuppressCondition( - min_number=1, - min_ratio=100 - ) + hard_threshold_condition=HardThresholdCondition( + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=5, + min_ratio=5 + ), + lower_bound=0, + upper_bound=100 + ), + change_threshold_condition=ChangeThresholdCondition( + change_percentage=50, + shift_point=30, + within_range=True, + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=2, + min_ratio=2 ) - )], - series_group_detection_conditions=[MetricSeriesGroupDetectionCondition( - series_group_key={"city": "Sao Paulo"}, - smart_detection_condition=SmartDetectionCondition( - anomaly_detector_direction="Both", - sensitivity=63, - suppress_condition=SuppressCondition( - min_number=1, - min_ratio=100 - ) + ) + ), + series_detection_conditions=[MetricSingleSeriesDetectionCondition( + series_key={"city": "Shenzhen", "category": "Jewelry"}, + smart_detection_condition=SmartDetectionCondition( + anomaly_detector_direction="Both", + sensitivity=63, + suppress_condition=SuppressCondition( + min_number=1, + min_ratio=100 ) - )] - ) + ) + )], + series_group_detection_conditions=[MetricSeriesGroupDetectionCondition( + series_group_key={"city": "Sao Paulo"}, + smart_detection_condition=SmartDetectionCondition( + anomaly_detector_direction="Both", + sensitivity=63, + suppress_condition=SuppressCondition( + min_number=1, + min_ratio=100 + ) + ) + )] ) return detection_config, data_feed diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/async_tests/recordings/test_data_feeds_async.test_create_simple_data_feed.yaml b/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/async_tests/recordings/test_data_feeds_async.test_create_simple_data_feed.yaml new file mode 100644 index 000000000000..c854c3ee6368 --- /dev/null +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/async_tests/recordings/test_data_feeds_async.test_create_simple_data_feed.yaml @@ -0,0 +1,84 @@ +interactions: +- request: + body: '{"dataSourceType": "SqlServer", "dataFeedName": "testfeed5b91433", "granularityName": + "Daily", "metrics": [{"metricName": "cost"}, {"metricName": "revenue"}], "dataStartFrom": + "2019-10-01T00:00:00.000Z", "startOffsetInSeconds": 0, "maxConcurrency": -1, + "minRetryIntervalInSeconds": -1, "stopRetryAfterInSeconds": -1, "dataSourceParameter": + {"connectionString": "connectionstring", "query": "select\u202f*\u202ffrom\u202fadsample2\u202fwhere\u202fTimestamp\u202f=\u202f@StartTime"}}' + headers: + Accept: + - application/json + Content-Length: + - '697' + Content-Type: + - application/json + User-Agent: + - azsdk-python-ai-metricsadvisor/1.0.0b2 Python/3.8.6 (Windows-10-10.0.19041-SP0) + method: POST + uri: https://js-metrics-advisor.cognitiveservices.azure.com/metricsadvisor/v1.0/dataFeeds + response: + body: + string: '' + headers: + apim-request-id: 85cae8a7-6d0a-42b3-8326-ee173825cc66 + content-length: '0' + date: Mon, 02 Nov 2020 18:32:58 GMT + location: https://js-metrics-advisor.cognitiveservices.azure.com/metricsadvisor/v1.0/dataFeeds/fd167d15-9468-479e-93dc-72866e19ee92 + strict-transport-security: max-age=31536000; includeSubDomains; preload + x-content-type-options: nosniff + x-envoy-upstream-service-time: '706' + x-request-id: 85cae8a7-6d0a-42b3-8326-ee173825cc66 + status: + code: 201 + message: Created + url: https://js-metrics-advisor.cognitiveservices.azure.com//metricsadvisor/v1.0/dataFeeds +- request: + body: null + headers: + Accept: + - application/json + User-Agent: + - azsdk-python-ai-metricsadvisor/1.0.0b2 Python/3.8.6 (Windows-10-10.0.19041-SP0) + method: GET + uri: https://js-metrics-advisor.cognitiveservices.azure.com/metricsadvisor/v1.0/dataFeeds/fd167d15-9468-479e-93dc-72866e19ee92 + response: + body: + string: "{\"dataFeedId\":\"fd167d15-9468-479e-93dc-72866e19ee92\",\"dataFeedName\":\"testfeed5b91433\",\"metrics\":[{\"metricId\":\"380425ae-1be1-40c3-b5a9-88f55641616e\",\"metricName\":\"cost\",\"metricDisplayName\":\"cost\",\"metricDescription\":\"\"},{\"metricId\":\"d09b80a5-3306-4c24-830b-5de1a5a98aa0\",\"metricName\":\"revenue\",\"metricDisplayName\":\"revenue\",\"metricDescription\":\"\"}],\"dimension\":[],\"dataStartFrom\":\"2019-10-01T00:00:00Z\",\"dataSourceType\":\"SqlServer\",\"timestampColumn\":\"\",\"startOffsetInSeconds\":0,\"maxQueryPerMinute\":30.0,\"granularityName\":\"Daily\",\"granularityAmount\":null,\"allUpIdentification\":null,\"needRollup\":\"NoRollup\",\"fillMissingPointType\":\"PreviousValue\",\"fillMissingPointValue\":0.0,\"rollUpMethod\":\"None\",\"rollUpColumns\":[],\"dataFeedDescription\":\"\",\"stopRetryAfterInSeconds\":-1,\"minRetryIntervalInSeconds\":-1,\"maxConcurrency\":-1,\"viewMode\":\"Private\",\"admins\":[\"krpratic@microsoft.com\"],\"viewers\":[],\"creator\":\"krpratic@microsoft.com\",\"status\":\"Active\",\"createdTime\":\"2020-11-02T18:32:58Z\",\"isAdmin\":true,\"actionLinkTemplate\":\"\",\"dataSourceParameter\":{\"connectionString\":\"connectionstring\",\"query\":\"select\u202F*\u202Ffrom\u202Fadsample2\u202Fwhere\u202FTimestamp\u202F=\u202F@StartTime\"}}" + headers: + apim-request-id: 046e09d4-a814-42f6-9047-66e5e67bfa9f + content-length: '1371' + content-type: application/json; charset=utf-8 + date: Mon, 02 Nov 2020 18:32:58 GMT + strict-transport-security: max-age=31536000; includeSubDomains; preload + x-content-type-options: nosniff + x-envoy-upstream-service-time: '127' + x-request-id: 046e09d4-a814-42f6-9047-66e5e67bfa9f + status: + code: 200 + message: OK + url: https://js-metrics-advisor.cognitiveservices.azure.com//metricsadvisor/v1.0/dataFeeds/fd167d15-9468-479e-93dc-72866e19ee92 +- request: + body: null + headers: + Accept: + - application/json + User-Agent: + - azsdk-python-ai-metricsadvisor/1.0.0b2 Python/3.8.6 (Windows-10-10.0.19041-SP0) + method: DELETE + uri: https://js-metrics-advisor.cognitiveservices.azure.com/metricsadvisor/v1.0/dataFeeds/fd167d15-9468-479e-93dc-72866e19ee92 + response: + body: + string: '' + headers: + apim-request-id: adfcd566-3e7c-4f4a-b9b8-16feced44189 + content-length: '0' + date: Mon, 02 Nov 2020 18:32:58 GMT + strict-transport-security: max-age=31536000; includeSubDomains; preload + x-content-type-options: nosniff + x-envoy-upstream-service-time: '271' + x-request-id: adfcd566-3e7c-4f4a-b9b8-16feced44189 + status: + code: 204 + message: No Content + url: https://js-metrics-advisor.cognitiveservices.azure.com//metricsadvisor/v1.0/dataFeeds/fd167d15-9468-479e-93dc-72866e19ee92 +version: 1 diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/async_tests/test_alert_config_async.py b/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/async_tests/test_alert_config_async.py index b15f22e74fe9..01277b34eb50 100644 --- a/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/async_tests/test_alert_config_async.py +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/async_tests/test_alert_config_async.py @@ -16,7 +16,6 @@ TopNGroupScope, SeverityCondition, MetricAnomalyAlertSnoozeCondition, - AnomalyAlertConfiguration ) from base_testcase_async import TestMetricsAdvisorAdministrationClientBaseAsync @@ -31,31 +30,29 @@ async def test_create_alert_config_top_n_alert_direction_both(self): async with self.admin_client: try: alert_config = await self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="TopN", - top_n_group_in_scope=TopNGroupScope( - top=5, - period=10, - min_top_count=9 - ) - ), - alert_conditions=MetricAnomalyAlertConditions( - metric_boundary_condition=MetricBoundaryCondition( - direction="Both", - companion_metric_id=data_feed.metric_ids[0], - lower=1.0, - upper=5.0 - ) + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="TopN", + top_n_group_in_scope=TopNGroupScope( + top=5, + period=10, + min_top_count=9 + ) + ), + alert_conditions=MetricAnomalyAlertConditions( + metric_boundary_condition=MetricBoundaryCondition( + direction="Both", + companion_metric_id=data_feed.metric_ids[0], + lower=1.0, + upper=5.0 ) ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -96,30 +93,28 @@ async def test_create_alert_config_top_n_alert_direction_down(self): async with self.admin_client: try: alert_config = await self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="TopN", - top_n_group_in_scope=TopNGroupScope( - top=5, - period=10, - min_top_count=9 - ) - ), - alert_conditions=MetricAnomalyAlertConditions( - metric_boundary_condition=MetricBoundaryCondition( - direction="Down", - companion_metric_id=data_feed.metric_ids[0], - lower=1.0, - ) + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="TopN", + top_n_group_in_scope=TopNGroupScope( + top=5, + period=10, + min_top_count=9 + ) + ), + alert_conditions=MetricAnomalyAlertConditions( + metric_boundary_condition=MetricBoundaryCondition( + direction="Down", + companion_metric_id=data_feed.metric_ids[0], + lower=1.0, ) ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -160,30 +155,28 @@ async def test_create_alert_config_top_n_alert_direction_up(self): async with self.admin_client: try: alert_config = await self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="TopN", - top_n_group_in_scope=TopNGroupScope( - top=5, - period=10, - min_top_count=9 - ) - ), - alert_conditions=MetricAnomalyAlertConditions( - metric_boundary_condition=MetricBoundaryCondition( - direction="Up", - companion_metric_id=data_feed.metric_ids[0], - upper=5.0, - ) + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="TopN", + top_n_group_in_scope=TopNGroupScope( + top=5, + period=10, + min_top_count=9 + ) + ), + alert_conditions=MetricAnomalyAlertConditions( + metric_boundary_condition=MetricBoundaryCondition( + direction="Up", + companion_metric_id=data_feed.metric_ids[0], + upper=5.0, ) ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -224,29 +217,27 @@ async def test_create_alert_config_top_n_severity_condition(self): async with self.admin_client: try: alert_config = await self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="TopN", - top_n_group_in_scope=TopNGroupScope( - top=5, - period=10, - min_top_count=9 - ) - ), - alert_conditions=MetricAnomalyAlertConditions( - severity_condition=SeverityCondition( - min_alert_severity="Low", - max_alert_severity="High" - ) + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="TopN", + top_n_group_in_scope=TopNGroupScope( + top=5, + period=10, + min_top_count=9 + ) + ), + alert_conditions=MetricAnomalyAlertConditions( + severity_condition=SeverityCondition( + min_alert_severity="Low", + max_alert_severity="High" ) ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -281,28 +272,26 @@ async def test_create_alert_config_snooze_condition(self): async with self.admin_client: try: alert_config = await self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="TopN", - top_n_group_in_scope=TopNGroupScope( - top=5, - period=10, - min_top_count=9 - ) - ), - alert_snooze_condition=MetricAnomalyAlertSnoozeCondition( - auto_snooze=5, - snooze_scope="Metric", - only_for_successive=True + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="TopN", + top_n_group_in_scope=TopNGroupScope( + top=5, + period=10, + min_top_count=9 ) + ), + alert_snooze_condition=MetricAnomalyAlertSnoozeCondition( + auto_snooze=5, + snooze_scope="Metric", + only_for_successive=True ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -338,26 +327,24 @@ async def test_create_alert_config_whole_series_alert_direction_both(self): async with self.admin_client: try: alert_config = await self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="WholeSeries", - ), - alert_conditions=MetricAnomalyAlertConditions( - metric_boundary_condition=MetricBoundaryCondition( - direction="Both", - companion_metric_id=data_feed.metric_ids[0], - lower=1.0, - upper=5.0 - ) + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="WholeSeries", + ), + alert_conditions=MetricAnomalyAlertConditions( + metric_boundary_condition=MetricBoundaryCondition( + direction="Both", + companion_metric_id=data_feed.metric_ids[0], + lower=1.0, + upper=5.0 ) ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -394,25 +381,23 @@ async def test_create_alert_config_whole_series_alert_direction_down(self): async with self.admin_client: try: alert_config = await self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="WholeSeries" - ), - alert_conditions=MetricAnomalyAlertConditions( - metric_boundary_condition=MetricBoundaryCondition( - direction="Down", - companion_metric_id=data_feed.metric_ids[0], - lower=1.0, - ) + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="WholeSeries" + ), + alert_conditions=MetricAnomalyAlertConditions( + metric_boundary_condition=MetricBoundaryCondition( + direction="Down", + companion_metric_id=data_feed.metric_ids[0], + lower=1.0, ) ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -449,25 +434,23 @@ async def test_create_alert_config_whole_series_alert_direction_up(self): async with self.admin_client: try: alert_config = await self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="WholeSeries" - ), - alert_conditions=MetricAnomalyAlertConditions( - metric_boundary_condition=MetricBoundaryCondition( - direction="Up", - companion_metric_id=data_feed.metric_ids[0], - upper=5.0, - ) + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="WholeSeries" + ), + alert_conditions=MetricAnomalyAlertConditions( + metric_boundary_condition=MetricBoundaryCondition( + direction="Up", + companion_metric_id=data_feed.metric_ids[0], + upper=5.0, ) ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -504,24 +487,22 @@ async def test_create_alert_config_whole_series_severity_condition(self): async with self.admin_client: try: alert_config = await self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="WholeSeries" - ), - alert_conditions=MetricAnomalyAlertConditions( - severity_condition=SeverityCondition( - min_alert_severity="Low", - max_alert_severity="High" - ) + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="WholeSeries" + ), + alert_conditions=MetricAnomalyAlertConditions( + severity_condition=SeverityCondition( + min_alert_severity="Low", + max_alert_severity="High" ) ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -552,27 +533,25 @@ async def test_create_alert_config_series_group_alert_direction_both(self): async with self.admin_client: try: alert_config = await self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="SeriesGroup", - series_group_in_scope={'city': 'Shenzhen'} - ), - alert_conditions=MetricAnomalyAlertConditions( - metric_boundary_condition=MetricBoundaryCondition( - direction="Both", - companion_metric_id=data_feed.metric_ids[0], - lower=1.0, - upper=5.0 - ) + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="SeriesGroup", + series_group_in_scope={'city': 'Shenzhen'} + ), + alert_conditions=MetricAnomalyAlertConditions( + metric_boundary_condition=MetricBoundaryCondition( + direction="Both", + companion_metric_id=data_feed.metric_ids[0], + lower=1.0, + upper=5.0 ) ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -610,26 +589,24 @@ async def test_create_alert_config_series_group_alert_direction_down(self): async with self.admin_client: try: alert_config = await self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="SeriesGroup", - series_group_in_scope={'city': 'Shenzhen'} - ), - alert_conditions=MetricAnomalyAlertConditions( - metric_boundary_condition=MetricBoundaryCondition( - direction="Down", - companion_metric_id=data_feed.metric_ids[0], - lower=1.0, - ) + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="SeriesGroup", + series_group_in_scope={'city': 'Shenzhen'} + ), + alert_conditions=MetricAnomalyAlertConditions( + metric_boundary_condition=MetricBoundaryCondition( + direction="Down", + companion_metric_id=data_feed.metric_ids[0], + lower=1.0, ) ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -667,26 +644,24 @@ async def test_create_alert_config_series_group_alert_direction_up(self): async with self.admin_client: try: alert_config = await self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="SeriesGroup", - series_group_in_scope={'city': 'Shenzhen'} - ), - alert_conditions=MetricAnomalyAlertConditions( - metric_boundary_condition=MetricBoundaryCondition( - direction="Up", - companion_metric_id=data_feed.metric_ids[0], - upper=5.0, - ) + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="SeriesGroup", + series_group_in_scope={'city': 'Shenzhen'} + ), + alert_conditions=MetricAnomalyAlertConditions( + metric_boundary_condition=MetricBoundaryCondition( + direction="Up", + companion_metric_id=data_feed.metric_ids[0], + upper=5.0, ) ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -724,25 +699,23 @@ async def test_create_alert_config_series_group_severity_condition(self): async with self.admin_client: try: alert_config = await self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="SeriesGroup", - series_group_in_scope={'city': 'Shenzhen'} - ), - alert_conditions=MetricAnomalyAlertConditions( - severity_condition=SeverityCondition( - min_alert_severity="Low", - max_alert_severity="High" - ) + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="SeriesGroup", + series_group_in_scope={'city': 'Shenzhen'} + ), + alert_conditions=MetricAnomalyAlertConditions( + severity_condition=SeverityCondition( + min_alert_severity="Low", + max_alert_severity="High" ) ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -774,57 +747,55 @@ async def test_create_alert_config_multiple_configurations(self): async with self.admin_client: try: alert_config = await self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - cross_metrics_operator="AND", - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="TopN", - top_n_group_in_scope=TopNGroupScope( - top=5, - period=10, - min_top_count=9 - ) - ), - alert_conditions=MetricAnomalyAlertConditions( - metric_boundary_condition=MetricBoundaryCondition( - direction="Both", - companion_metric_id=data_feed.metric_ids[0], - lower=1.0, - upper=5.0 - ) + name=alert_config_name, + cross_metrics_operator="AND", + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="TopN", + top_n_group_in_scope=TopNGroupScope( + top=5, + period=10, + min_top_count=9 ) ), - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="SeriesGroup", - series_group_in_scope={'city': 'Shenzhen'} - ), - alert_conditions=MetricAnomalyAlertConditions( - severity_condition=SeverityCondition( - min_alert_severity="Low", - max_alert_severity="High" - ) + alert_conditions=MetricAnomalyAlertConditions( + metric_boundary_condition=MetricBoundaryCondition( + direction="Both", + companion_metric_id=data_feed.metric_ids[0], + lower=1.0, + upper=5.0 ) + ) + ), + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="SeriesGroup", + series_group_in_scope={'city': 'Shenzhen'} ), - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="WholeSeries" - ), - alert_conditions=MetricAnomalyAlertConditions( - severity_condition=SeverityCondition( - min_alert_severity="Low", - max_alert_severity="High" - ) + alert_conditions=MetricAnomalyAlertConditions( + severity_condition=SeverityCondition( + min_alert_severity="Low", + max_alert_severity="High" ) ) - ], - hook_ids=[] - ) + ), + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="WholeSeries" + ), + alert_conditions=MetricAnomalyAlertConditions( + severity_condition=SeverityCondition( + min_alert_severity="Low", + max_alert_severity="High" + ) + ) + ) + ], + hook_ids=[] ) self.assertEqual(alert_config.cross_metrics_operator, "AND") self.assertIsNotNone(alert_config.id) diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/async_tests/test_data_feeds_async.py b/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/async_tests/test_data_feeds_async.py index 8b64333c6e4e..6de4794f1261 100644 --- a/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/async_tests/test_data_feeds_async.py +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/async_tests/test_data_feeds_async.py @@ -32,13 +32,42 @@ MySqlDataFeed, PostgreSqlDataFeed, ElasticsearchDataFeed, - DataFeed ) from base_testcase_async import TestMetricsAdvisorAdministrationClientBaseAsync class TestMetricsAdvisorAdministrationClientAsync(TestMetricsAdvisorAdministrationClientBaseAsync): + @AzureTestCase.await_prepared_test + async def test_create_simple_data_feed(self): + data_feed_name = self.create_random_name("testfeed") + async with self.admin_client: + try: + data_feed = await self.admin_client.create_data_feed( + name=data_feed_name, + source=SQLServerDataFeed( + connection_string=self.sql_server_connection_string, + query="select * from adsample2 where Timestamp = @StartTime" + ), + granularity="Daily", + schema=["cost", "revenue"], + ingestion_settings=datetime.datetime(2019, 10, 1) + ) + + self.assertIsNotNone(data_feed.id) + self.assertIsNotNone(data_feed.created_time) + self.assertIsNotNone(data_feed.name) + self.assertEqual(data_feed.source.data_source_type, "SqlServer") + self.assertIsNotNone(data_feed.source.connection_string) + self.assertIsNotNone(data_feed.source.query) + self.assertEqual(data_feed.granularity.granularity_type, "Daily") + self.assertEqual(data_feed.schema.metrics[0].name, "cost") + self.assertEqual(data_feed.schema.metrics[1].name, "revenue") + self.assertEqual(data_feed.ingestion_settings.ingestion_begin_time, + datetime.datetime(2019, 10, 1, tzinfo=tzutc())) + finally: + await self.admin_client.delete_data_feed(data_feed.id) + @AzureTestCase.await_prepared_test async def test_create_data_feed_from_sql_server(self): @@ -46,48 +75,47 @@ async def test_create_data_feed_from_sql_server(self): async with self.admin_client: try: data_feed = await self.admin_client.create_data_feed( - DataFeed( - name=data_feed_name, - source=SQLServerDataFeed( - connection_string=self.sql_server_connection_string, - query=u"select * from adsample2 where Timestamp = @StartTime" - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost", display_name="display cost", description="the cost"), - DataFeedMetric(name="revenue", display_name="display revenue", description="the revenue") - ], - dimensions=[ - DataFeedDimension(name="category", display_name="display category"), - DataFeedDimension(name="city", display_name="display city") - ], - timestamp_column="Timestamp" + name=data_feed_name, + source=SQLServerDataFeed( + connection_string=self.sql_server_connection_string, + query=u"select * from adsample2 where Timestamp = @StartTime" + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost", display_name="display cost", description="the cost"), + DataFeedMetric(name="revenue", display_name="display revenue", description="the revenue") + ], + dimensions=[ + DataFeedDimension(name="category", display_name="display category"), + DataFeedDimension(name="city", display_name="display city") + ], + timestamp_column="Timestamp" + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 10, 1), + data_source_request_concurrency=0, + ingestion_retry_delay=-1, + ingestion_start_offset=-1, + stop_retry_after=-1, + ), + options=DataFeedOptions( + admin_emails=["yournamehere@microsoft.com"], + data_feed_description="my first data feed", + missing_data_point_fill_settings=DataFeedMissingDataPointFillSettings( + fill_type="SmartFilling" ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 10, 1), - data_source_request_concurrency=0, - ingestion_retry_delay=-1, - ingestion_start_offset=-1, - stop_retry_after=-1, + rollup_settings=DataFeedRollupSettings( + rollup_type="NoRollup", + rollup_method="None", ), - options=DataFeedOptions( - admin_emails=["yournamehere@microsoft.com"], - data_feed_description="my first data feed", - missing_data_point_fill_settings=DataFeedMissingDataPointFillSettings( - fill_type="SmartFilling" - ), - rollup_settings=DataFeedRollupSettings( - rollup_type="NoRollup", - rollup_method="None", - ), - viewer_emails=["viewers"], - access_mode="Private", - action_link_template="action link template" - ) + viewer_emails=["viewers"], + access_mode="Private", + action_link_template="action link template" ) + ) self.assertIsNotNone(data_feed.id) self.assertIsNotNone(data_feed.created_time) @@ -138,51 +166,50 @@ async def test_create_data_feed_from_sql_server_with_custom_values(self): async with self.admin_client: try: data_feed = await self.admin_client.create_data_feed( - DataFeed( - name=data_feed_name, - source=SQLServerDataFeed( - connection_string=self.sql_server_connection_string, - query=u"select * from adsample2 where Timestamp = @StartTime" - ), - granularity=DataFeedGranularity( - granularity_type="Custom", - custom_granularity_value=20 - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost", display_name="display cost", description="the cost"), - DataFeedMetric(name="revenue", display_name="display revenue", description="the revenue") - ], - dimensions=[ - DataFeedDimension(name="category", display_name="display category"), - DataFeedDimension(name="city", display_name="display city") - ], - timestamp_column="Timestamp" + name=data_feed_name, + source=SQLServerDataFeed( + connection_string=self.sql_server_connection_string, + query=u"select * from adsample2 where Timestamp = @StartTime" + ), + granularity=DataFeedGranularity( + granularity_type="Custom", + custom_granularity_value=20 + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost", display_name="display cost", description="the cost"), + DataFeedMetric(name="revenue", display_name="display revenue", description="the revenue") + ], + dimensions=[ + DataFeedDimension(name="category", display_name="display category"), + DataFeedDimension(name="city", display_name="display city") + ], + timestamp_column="Timestamp" + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 10, 1), + data_source_request_concurrency=0, + ingestion_retry_delay=-1, + ingestion_start_offset=-1, + stop_retry_after=-1, + ), + options=DataFeedOptions( + admin_emails=["yournamehere@microsoft.com"], + data_feed_description="my first data feed", + missing_data_point_fill_settings=DataFeedMissingDataPointFillSettings( + fill_type="CustomValue", + custom_fill_value=10 ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 10, 1), - data_source_request_concurrency=0, - ingestion_retry_delay=-1, - ingestion_start_offset=-1, - stop_retry_after=-1, + rollup_settings=DataFeedRollupSettings( + rollup_type="AlreadyRollup", + rollup_method="Sum", + rollup_identification_value="sumrollup" ), - options=DataFeedOptions( - admin_emails=["yournamehere@microsoft.com"], - data_feed_description="my first data feed", - missing_data_point_fill_settings=DataFeedMissingDataPointFillSettings( - fill_type="CustomValue", - custom_fill_value=10 - ), - rollup_settings=DataFeedRollupSettings( - rollup_type="AlreadyRollup", - rollup_method="Sum", - rollup_identification_value="sumrollup" - ), - viewer_emails=["viewers"], - access_mode="Private", - action_link_template="action link template" - ) + viewer_emails=["viewers"], + access_mode="Private", + action_link_template="action link template" ) + ) self.assertIsNotNone(data_feed.id) self.assertIsNotNone(data_feed.created_time) @@ -234,30 +261,29 @@ async def test_create_data_feed_with_azure_table(self): async with self.admin_client: try: data_feed = await self.admin_client.create_data_feed( - DataFeed( - name=name, - source=AzureTableDataFeed( - connection_string=self.azure_table_connection_string, - query="PartitionKey ge '@StartTime' and PartitionKey lt '@EndTime'", - table="adsample" - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost"), - DataFeedMetric(name="revenue") - ], - dimensions=[ - DataFeedDimension(name="category"), - DataFeedDimension(name="city") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 10, 1), - ), - ) + name=name, + source=AzureTableDataFeed( + connection_string=self.azure_table_connection_string, + query="PartitionKey ge '@StartTime' and PartitionKey lt '@EndTime'", + table="adsample" + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost"), + DataFeedMetric(name="revenue") + ], + dimensions=[ + DataFeedDimension(name="category"), + DataFeedDimension(name="city") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 10, 1), + ), + ) self.assertIsNotNone(data_feed.id) @@ -276,30 +302,29 @@ async def test_create_data_feed_with_azure_blob(self): async with self.admin_client: try: data_feed = await self.admin_client.create_data_feed( - DataFeed( - name=name, - source=AzureBlobDataFeed( - connection_string=self.azure_blob_connection_string, - container="adsample", - blob_template="%Y/%m/%d/%h/JsonFormatV2.json" - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost"), - DataFeedMetric(name="revenue") - ], - dimensions=[ - DataFeedDimension(name="category"), - DataFeedDimension(name="city") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 10, 1), - ), - ) + name=name, + source=AzureBlobDataFeed( + connection_string=self.azure_blob_connection_string, + container="adsample", + blob_template="%Y/%m/%d/%h/JsonFormatV2.json" + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost"), + DataFeedMetric(name="revenue") + ], + dimensions=[ + DataFeedDimension(name="category"), + DataFeedDimension(name="city") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 10, 1), + ), + ) self.assertIsNotNone(data_feed.id) @@ -318,31 +343,30 @@ async def test_create_data_feed_with_azure_cosmos_db(self): async with self.admin_client: try: data_feed = await self.admin_client.create_data_feed( - DataFeed( - name=name, - source=AzureCosmosDBDataFeed( - connection_string=self.azure_cosmosdb_connection_string, - sql_query="'SELECT * FROM Items I where I.Timestamp >= @StartTime and I.Timestamp < @EndTime'", - database="adsample", - collection_id="adsample" - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost"), - DataFeedMetric(name="revenue") - ], - dimensions=[ - DataFeedDimension(name="category"), - DataFeedDimension(name="city") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 10, 1), - ), - ) + name=name, + source=AzureCosmosDBDataFeed( + connection_string=self.azure_cosmosdb_connection_string, + sql_query="'SELECT * FROM Items I where I.Timestamp >= @StartTime and I.Timestamp < @EndTime'", + database="adsample", + collection_id="adsample" + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost"), + DataFeedMetric(name="revenue") + ], + dimensions=[ + DataFeedDimension(name="category"), + DataFeedDimension(name="city") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 10, 1), + ), + ) self.assertIsNotNone(data_feed.id) @@ -362,29 +386,28 @@ async def test_create_data_feed_with_http_request_get(self): async with self.admin_client: try: data_feed = await self.admin_client.create_data_feed( - DataFeed( - name=name, - source=HttpRequestDataFeed( - url=self.http_request_get_url, - http_method="GET" - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost"), - DataFeedMetric(name="revenue") - ], - dimensions=[ - DataFeedDimension(name="category"), - DataFeedDimension(name="city") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 10, 1), - ), - ) + name=name, + source=HttpRequestDataFeed( + url=self.http_request_get_url, + http_method="GET" + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost"), + DataFeedMetric(name="revenue") + ], + dimensions=[ + DataFeedDimension(name="category"), + DataFeedDimension(name="city") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 10, 1), + ), + ) self.assertIsNotNone(data_feed.id) @@ -403,30 +426,29 @@ async def test_create_data_feed_with_http_request_post(self): async with self.admin_client: try: data_feed = await self.admin_client.create_data_feed( - DataFeed( - name=name, - source=HttpRequestDataFeed( - url=self.http_request_post_url, - http_method="POST", - payload="{'startTime': '@StartTime'}" - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost"), - DataFeedMetric(name="revenue") - ], - dimensions=[ - DataFeedDimension(name="category"), - DataFeedDimension(name="city") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 10, 1), - ), - ) + name=name, + source=HttpRequestDataFeed( + url=self.http_request_post_url, + http_method="POST", + payload="{'startTime': '@StartTime'}" + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost"), + DataFeedMetric(name="revenue") + ], + dimensions=[ + DataFeedDimension(name="category"), + DataFeedDimension(name="city") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 10, 1), + ), + ) self.assertIsNotNone(data_feed.id) @@ -449,31 +471,30 @@ async def test_create_data_feed_with_application_insights(self): "duration_avg_ms = avg(duration), duration_95th_ms = percentile(duration, 95), " \ "duration_max_ms = max(duration) by resultCode" data_feed = await self.admin_client.create_data_feed( - DataFeed( - name=name, - source=AzureApplicationInsightsDataFeed( - azure_cloud="Azure", - application_id="3706fe8b-98f1-47c7-bf69-b73b6e53274d", - api_key=self.application_insights_api_key, - query=query - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost"), - DataFeedMetric(name="revenue") - ], - dimensions=[ - DataFeedDimension(name="category"), - DataFeedDimension(name="city") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2020, 7, 1), - ), - ) + name=name, + source=AzureApplicationInsightsDataFeed( + azure_cloud="Azure", + application_id="3706fe8b-98f1-47c7-bf69-b73b6e53274d", + api_key=self.application_insights_api_key, + query=query + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost"), + DataFeedMetric(name="revenue") + ], + dimensions=[ + DataFeedDimension(name="category"), + DataFeedDimension(name="city") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2020, 7, 1), + ), + ) self.assertIsNotNone(data_feed.id) @@ -495,29 +516,28 @@ async def test_create_data_feed_with_data_explorer(self): query = "let StartDateTime = datetime(@StartTime); let EndDateTime = StartDateTime + 1d; " \ "adsample | where Timestamp >= StartDateTime and Timestamp < EndDateTime" data_feed = await self.admin_client.create_data_feed( - DataFeed( - name=name, - source=AzureDataExplorerDataFeed( - connection_string=self.azure_data_explorer_connection_string, - query=query - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost"), - DataFeedMetric(name="revenue") - ], - dimensions=[ - DataFeedDimension(name="category"), - DataFeedDimension(name="city") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 1, 1), - ), - ) + name=name, + source=AzureDataExplorerDataFeed( + connection_string=self.azure_data_explorer_connection_string, + query=query + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost"), + DataFeedMetric(name="revenue") + ], + dimensions=[ + DataFeedDimension(name="category"), + DataFeedDimension(name="city") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 1, 1), + ), + ) self.assertIsNotNone(data_feed.id) @@ -536,32 +556,31 @@ async def test_create_data_feed_with_influxdb(self): async with self.admin_client: try: data_feed = await self.admin_client.create_data_feed( - DataFeed( - name=name, - source=InfluxDBDataFeed( - connection_string=self.influxdb_connection_string, - database="adsample", - user_name="adreadonly", - password=self.influxdb_password, - query="'select * from adsample2 where Timestamp = @StartTime'" - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost"), - DataFeedMetric(name="revenue") - ], - dimensions=[ - DataFeedDimension(name="category"), - DataFeedDimension(name="city") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 1, 1), - ), - ) + name=name, + source=InfluxDBDataFeed( + connection_string=self.influxdb_connection_string, + database="adsample", + user_name="adreadonly", + password=self.influxdb_password, + query="'select * from adsample2 where Timestamp = @StartTime'" + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost"), + DataFeedMetric(name="revenue") + ], + dimensions=[ + DataFeedDimension(name="category"), + DataFeedDimension(name="city") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 1, 1), + ), + ) self.assertIsNotNone(data_feed.id) @@ -583,32 +602,31 @@ async def test_create_data_feed_with_datalake(self): async with self.admin_client: try: data_feed = await self.admin_client.create_data_feed( - DataFeed( - name=name, - source=AzureDataLakeStorageGen2DataFeed( - account_name="adsampledatalakegen2", - account_key=self.azure_datalake_account_key, - file_system_name="adsample", - directory_template="%Y/%m/%d", - file_template="adsample.json" - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost", display_name="Cost"), - DataFeedMetric(name="revenue", display_name="Revenue") - ], - dimensions=[ - DataFeedDimension(name="category", display_name="Category"), - DataFeedDimension(name="city", display_name="City") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 1, 1), - ), - ) + name=name, + source=AzureDataLakeStorageGen2DataFeed( + account_name="adsampledatalakegen2", + account_key=self.azure_datalake_account_key, + file_system_name="adsample", + directory_template="%Y/%m/%d", + file_template="adsample.json" + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost", display_name="Cost"), + DataFeedMetric(name="revenue", display_name="Revenue") + ], + dimensions=[ + DataFeedDimension(name="category", display_name="Category"), + DataFeedDimension(name="city", display_name="City") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 1, 1), + ), + ) self.assertIsNotNone(data_feed.id) @@ -630,30 +648,29 @@ async def test_create_data_feed_with_mongodb(self): async with self.admin_client: try: data_feed = await self.admin_client.create_data_feed( - DataFeed( - name=name, - source=MongoDBDataFeed( - connection_string=self.mongodb_connection_string, - database="adsample", - command='{"find": "adsample", "filter": { Timestamp: { $eq: @StartTime }} "batchSize": 2000,}' - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost"), - DataFeedMetric(name="revenue") - ], - dimensions=[ - DataFeedDimension(name="category"), - DataFeedDimension(name="city") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 1, 1), - ), - ) + name=name, + source=MongoDBDataFeed( + connection_string=self.mongodb_connection_string, + database="adsample", + command='{"find": "adsample", "filter": { Timestamp: { $eq: @StartTime }} "batchSize": 2000,}' + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost"), + DataFeedMetric(name="revenue") + ], + dimensions=[ + DataFeedDimension(name="category"), + DataFeedDimension(name="city") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 1, 1), + ), + ) self.assertIsNotNone(data_feed.id) @@ -673,29 +690,28 @@ async def test_create_data_feed_with_mysql(self): async with self.admin_client: try: data_feed = await self.admin_client.create_data_feed( - DataFeed( - name=name, - source=MySqlDataFeed( - connection_string=self.mysql_connection_string, - query="'select * from adsample2 where Timestamp = @StartTime'" - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost"), - DataFeedMetric(name="revenue") - ], - dimensions=[ - DataFeedDimension(name="category"), - DataFeedDimension(name="city") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 1, 1), - ), - ) + name=name, + source=MySqlDataFeed( + connection_string=self.mysql_connection_string, + query="'select * from adsample2 where Timestamp = @StartTime'" + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost"), + DataFeedMetric(name="revenue") + ], + dimensions=[ + DataFeedDimension(name="category"), + DataFeedDimension(name="city") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 1, 1), + ), + ) self.assertIsNotNone(data_feed.id) @@ -714,29 +730,28 @@ async def test_create_data_feed_with_postgresql(self): async with self.admin_client: try: data_feed = await self.admin_client.create_data_feed( - DataFeed( - name=name, - source=PostgreSqlDataFeed( - connection_string=self.postgresql_connection_string, - query="'select * from adsample2 where Timestamp = @StartTime'" - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost"), - DataFeedMetric(name="revenue") - ], - dimensions=[ - DataFeedDimension(name="category"), - DataFeedDimension(name="city") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 1, 1), - ), - ) + name=name, + source=PostgreSqlDataFeed( + connection_string=self.postgresql_connection_string, + query="'select * from adsample2 where Timestamp = @StartTime'" + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost"), + DataFeedMetric(name="revenue") + ], + dimensions=[ + DataFeedDimension(name="category"), + DataFeedDimension(name="city") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 1, 1), + ), + ) self.assertIsNotNone(data_feed.id) @@ -755,31 +770,30 @@ async def test_create_data_feed_with_elasticsearch(self): async with self.admin_client: try: data_feed = await self.admin_client.create_data_feed( - DataFeed( - name=name, - source=ElasticsearchDataFeed( - host="ad-sample-es.westus2.cloudapp.azure.com", - port="9200", - auth_header=self.elasticsearch_auth_header, - query="'select * from adsample where timestamp = @StartTime'" - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost", display_name="Cost"), - DataFeedMetric(name="revenue", display_name="Revenue") - ], - dimensions=[ - DataFeedDimension(name="category", display_name="Category"), - DataFeedDimension(name="city", display_name="City") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 1, 1), - ), - ) + name=name, + source=ElasticsearchDataFeed( + host="ad-sample-es.westus2.cloudapp.azure.com", + port="9200", + auth_header=self.elasticsearch_auth_header, + query="'select * from adsample where timestamp = @StartTime'" + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost", display_name="Cost"), + DataFeedMetric(name="revenue", display_name="Revenue") + ], + dimensions=[ + DataFeedDimension(name="category", display_name="Category"), + DataFeedDimension(name="city", display_name="City") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 1, 1), + ), + ) self.assertIsNotNone(data_feed.id) diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/async_tests/test_detection_config_async.py b/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/async_tests/test_detection_config_async.py index 06d85772d1c4..3dab875f5aa8 100644 --- a/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/async_tests/test_detection_config_async.py +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/async_tests/test_detection_config_async.py @@ -16,7 +16,6 @@ SuppressCondition, ChangeThresholdCondition, HardThresholdCondition, - AnomalyDetectionConfiguration ) from base_testcase_async import TestMetricsAdvisorAdministrationClientBaseAsync @@ -32,38 +31,36 @@ async def test_create_ad_config_whole_series_detection(self): try: detection_config_name = self.create_random_name("testdetectionconfigasync") config = await self.admin_client.create_detection_configuration( - AnomalyDetectionConfiguration( - name=detection_config_name, - metric_id=data_feed.metric_ids[0], - description="My test metric anomaly detection configuration", - whole_series_detection_condition=MetricDetectionCondition( - cross_conditions_operator="OR", - smart_detection_condition=SmartDetectionCondition( - sensitivity=50, - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=50, - min_ratio=50 - ) - ), - hard_threshold_condition=HardThresholdCondition( - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=5, - min_ratio=5 - ), - lower_bound=0, - upper_bound=100 + name=detection_config_name, + metric_id=data_feed.metric_ids[0], + description="My test metric anomaly detection configuration", + whole_series_detection_condition=MetricDetectionCondition( + cross_conditions_operator="OR", + smart_detection_condition=SmartDetectionCondition( + sensitivity=50, + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=50, + min_ratio=50 + ) + ), + hard_threshold_condition=HardThresholdCondition( + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=5, + min_ratio=5 ), - change_threshold_condition=ChangeThresholdCondition( - change_percentage=50, - shift_point=30, - within_range=True, - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=2, - min_ratio=2 - ) + lower_bound=0, + upper_bound=100 + ), + change_threshold_condition=ChangeThresholdCondition( + change_percentage=50, + shift_point=30, + within_range=True, + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=2, + min_ratio=2 ) ) ) @@ -114,63 +111,61 @@ async def test_create_ad_config_with_series_and_group_conds(self): try: detection_config_name = self.create_random_name("testdetectionconfigetasync") detection_config = await self.admin_client.create_detection_configuration( - AnomalyDetectionConfiguration( - name=detection_config_name, - metric_id=data_feed.metric_ids[0], - description="My test metric anomaly detection configuration", - whole_series_detection_condition=MetricDetectionCondition( - cross_conditions_operator="AND", - smart_detection_condition=SmartDetectionCondition( - sensitivity=50, - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=50, - min_ratio=50 - ) - ), - hard_threshold_condition=HardThresholdCondition( - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=5, - min_ratio=5 - ), - lower_bound=0, - upper_bound=100 - ), - change_threshold_condition=ChangeThresholdCondition( - change_percentage=50, - shift_point=30, - within_range=True, - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=2, - min_ratio=2 - ) + name=detection_config_name, + metric_id=data_feed.metric_ids[0], + description="My test metric anomaly detection configuration", + whole_series_detection_condition=MetricDetectionCondition( + cross_conditions_operator="AND", + smart_detection_condition=SmartDetectionCondition( + sensitivity=50, + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=50, + min_ratio=50 ) ), - series_detection_conditions=[MetricSingleSeriesDetectionCondition( - series_key={"city": "Shenzhen", "category": "Jewelry"}, - smart_detection_condition=SmartDetectionCondition( - anomaly_detector_direction="Both", - sensitivity=63, - suppress_condition=SuppressCondition( - min_number=1, - min_ratio=100 - ) + hard_threshold_condition=HardThresholdCondition( + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=5, + min_ratio=5 + ), + lower_bound=0, + upper_bound=100 + ), + change_threshold_condition=ChangeThresholdCondition( + change_percentage=50, + shift_point=30, + within_range=True, + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=2, + min_ratio=2 ) - )], - series_group_detection_conditions=[MetricSeriesGroupDetectionCondition( - series_group_key={"city": "Sao Paulo"}, - smart_detection_condition=SmartDetectionCondition( - anomaly_detector_direction="Both", - sensitivity=63, - suppress_condition=SuppressCondition( - min_number=1, - min_ratio=100 - ) + ) + ), + series_detection_conditions=[MetricSingleSeriesDetectionCondition( + series_key={"city": "Shenzhen", "category": "Jewelry"}, + smart_detection_condition=SmartDetectionCondition( + anomaly_detector_direction="Both", + sensitivity=63, + suppress_condition=SuppressCondition( + min_number=1, + min_ratio=100 ) - )] - ) + ) + )], + series_group_detection_conditions=[MetricSeriesGroupDetectionCondition( + series_group_key={"city": "Sao Paulo"}, + smart_detection_condition=SmartDetectionCondition( + anomaly_detector_direction="Both", + sensitivity=63, + suppress_condition=SuppressCondition( + min_number=1, + min_ratio=100 + ) + ) + )] ) self.assertIsNotNone(detection_config.id) @@ -233,18 +228,49 @@ async def test_create_ad_config_multiple_series_and_group_conds(self): try: detection_config_name = self.create_random_name("multipledetectionconfigsasync") detection_config = await self.admin_client.create_detection_configuration( - AnomalyDetectionConfiguration( - name=detection_config_name, - metric_id=data_feed.metric_ids[0], - description="My test metric anomaly detection configuration", - whole_series_detection_condition=MetricDetectionCondition( + name=detection_config_name, + metric_id=data_feed.metric_ids[0], + description="My test metric anomaly detection configuration", + whole_series_detection_condition=MetricDetectionCondition( + cross_conditions_operator="AND", + smart_detection_condition=SmartDetectionCondition( + sensitivity=50, + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=50, + min_ratio=50 + ) + ), + hard_threshold_condition=HardThresholdCondition( + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=5, + min_ratio=5 + ), + lower_bound=0, + upper_bound=100 + ), + change_threshold_condition=ChangeThresholdCondition( + change_percentage=50, + shift_point=30, + within_range=True, + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=2, + min_ratio=2 + ) + ) + ), + series_detection_conditions=[ + MetricSingleSeriesDetectionCondition( + series_key={"city": "Shenzhen", "category": "Jewelry"}, cross_conditions_operator="AND", smart_detection_condition=SmartDetectionCondition( - sensitivity=50, anomaly_detector_direction="Both", + sensitivity=63, suppress_condition=SuppressCondition( - min_number=50, - min_ratio=50 + min_number=1, + min_ratio=100 ) ), hard_threshold_condition=HardThresholdCondition( @@ -267,97 +293,64 @@ async def test_create_ad_config_multiple_series_and_group_conds(self): ) ) ), - series_detection_conditions=[ - MetricSingleSeriesDetectionCondition( - series_key={"city": "Shenzhen", "category": "Jewelry"}, - cross_conditions_operator="AND", - smart_detection_condition=SmartDetectionCondition( - anomaly_detector_direction="Both", - sensitivity=63, - suppress_condition=SuppressCondition( - min_number=1, - min_ratio=100 - ) - ), - hard_threshold_condition=HardThresholdCondition( - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=5, - min_ratio=5 - ), - lower_bound=0, - upper_bound=100 - ), - change_threshold_condition=ChangeThresholdCondition( - change_percentage=50, - shift_point=30, - within_range=True, - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=2, - min_ratio=2 - ) - ) - ), - MetricSingleSeriesDetectionCondition( - series_key={"city": "Osaka", "category": "Cell Phones"}, - cross_conditions_operator="AND", - smart_detection_condition=SmartDetectionCondition( - anomaly_detector_direction="Both", - sensitivity=63, - suppress_condition=SuppressCondition( - min_number=1, - min_ratio=100 - ) + MetricSingleSeriesDetectionCondition( + series_key={"city": "Osaka", "category": "Cell Phones"}, + cross_conditions_operator="AND", + smart_detection_condition=SmartDetectionCondition( + anomaly_detector_direction="Both", + sensitivity=63, + suppress_condition=SuppressCondition( + min_number=1, + min_ratio=100 ) ) - ], - series_group_detection_conditions=[ - MetricSeriesGroupDetectionCondition( - series_group_key={"city": "Sao Paulo"}, - cross_conditions_operator="AND", - smart_detection_condition=SmartDetectionCondition( - anomaly_detector_direction="Both", - sensitivity=63, - suppress_condition=SuppressCondition( - min_number=1, - min_ratio=100 - ) - ), - hard_threshold_condition=HardThresholdCondition( - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=5, - min_ratio=5 - ), - lower_bound=0, - upper_bound=100 - ), - change_threshold_condition=ChangeThresholdCondition( - change_percentage=50, - shift_point=30, - within_range=True, - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=2, - min_ratio=2 - ) + ) + ], + series_group_detection_conditions=[ + MetricSeriesGroupDetectionCondition( + series_group_key={"city": "Sao Paulo"}, + cross_conditions_operator="AND", + smart_detection_condition=SmartDetectionCondition( + anomaly_detector_direction="Both", + sensitivity=63, + suppress_condition=SuppressCondition( + min_number=1, + min_ratio=100 ) ), - MetricSeriesGroupDetectionCondition( - series_group_key={"city": "Seoul"}, - cross_conditions_operator="AND", - smart_detection_condition=SmartDetectionCondition( - anomaly_detector_direction="Both", - sensitivity=63, - suppress_condition=SuppressCondition( - min_number=1, - min_ratio=100 - ) + hard_threshold_condition=HardThresholdCondition( + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=5, + min_ratio=5 + ), + lower_bound=0, + upper_bound=100 + ), + change_threshold_condition=ChangeThresholdCondition( + change_percentage=50, + shift_point=30, + within_range=True, + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=2, + min_ratio=2 ) ) - ] - ) + ), + MetricSeriesGroupDetectionCondition( + series_group_key={"city": "Seoul"}, + cross_conditions_operator="AND", + smart_detection_condition=SmartDetectionCondition( + anomaly_detector_direction="Both", + sensitivity=63, + suppress_condition=SuppressCondition( + min_number=1, + min_ratio=100 + ) + ) + ) + ] ) self.assertIsNotNone(detection_config.id) diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/base_testcase.py b/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/base_testcase.py index dd8797f2ca99..bd0236ad5a06 100644 --- a/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/base_testcase.py +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/base_testcase.py @@ -42,9 +42,6 @@ HardThresholdCondition, EmailNotificationHook, WebNotificationHook, - DataFeed, - AnomalyDetectionConfiguration, - AnomalyAlertConfiguration ) @@ -177,48 +174,39 @@ def __init__(self, method_name): def _create_data_feed(self, name): name = create_random_name(name) return self.admin_client.create_data_feed( - DataFeed( - name=name, - source=SQLServerDataFeed( - connection_string=self.sql_server_connection_string, - query='select * from adsample2 where Timestamp = @StartTime' - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost"), - DataFeedMetric(name="revenue") - ], - dimensions=[ - DataFeedDimension(name="category"), - DataFeedDimension(name="city") - ], - timestamp_column="Timestamp" - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 10, 1), - ) - ) + name=name, + source=SQLServerDataFeed( + connection_string=self.sql_server_connection_string, + query="select * from adsample2 where Timestamp = @StartTime" + ), + granularity="Daily", + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost"), + DataFeedMetric(name="revenue") + ], + dimensions=[ + DataFeedDimension(name="category"), + DataFeedDimension(name="city") + ], + ), + ingestion_settings="2019-10-01T00:00:00Z", ) def _create_data_feed_and_detection_config(self, name): data_feed = self._create_data_feed(name) - detection_config_name = create_random_name(name) + detection_config_name = self.create_random_name(name) detection_config = self.admin_client.create_detection_configuration( - AnomalyDetectionConfiguration( - name=detection_config_name, - metric_id=data_feed.metric_ids[0], - description="testing", - whole_series_detection_condition=MetricDetectionCondition( - smart_detection_condition=SmartDetectionCondition( - sensitivity=50, - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=50, - min_ratio=50 - ) + name=detection_config_name, + metric_id=data_feed.metric_ids[0], + description="testing", + whole_series_detection_condition=MetricDetectionCondition( + smart_detection_condition=SmartDetectionCondition( + sensitivity=50, + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=50, + min_ratio=50 ) ) ) @@ -228,105 +216,102 @@ def _create_data_feed_and_detection_config(self, name): def _create_data_feed_for_update(self, name): data_feed_name = create_random_name(name) return self.admin_client.create_data_feed( - DataFeed( - name=data_feed_name, - source=SQLServerDataFeed( - connection_string=self.sql_server_connection_string, - query='select * from adsample2 where Timestamp = @StartTime' - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost", display_name="display cost", description="the cost"), - DataFeedMetric(name="revenue", display_name="display revenue", description="the revenue") - ], - dimensions=[ - DataFeedDimension(name="category", display_name="display category"), - DataFeedDimension(name="city", display_name="display city") - ], - timestamp_column="Timestamp" + name=data_feed_name, + source=SQLServerDataFeed( + connection_string=self.sql_server_connection_string, + query=u"select * from adsample2 where Timestamp = @StartTime" + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost", display_name="display cost", description="the cost"), + DataFeedMetric(name="revenue", display_name="display revenue", description="the revenue") + ], + dimensions=[ + DataFeedDimension(name="category", display_name="display category"), + DataFeedDimension(name="city", display_name="display city") + ], + timestamp_column="Timestamp" + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 10, 1), + data_source_request_concurrency=0, + ingestion_retry_delay=-1, + ingestion_start_offset=-1, + stop_retry_after=-1, + ), + options=DataFeedOptions( + admin_emails=["yournamehere@microsoft.com"], + data_feed_description="my first data feed", + missing_data_point_fill_settings=DataFeedMissingDataPointFillSettings( + fill_type="SmartFilling" ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 10, 1), - data_source_request_concurrency=0, - ingestion_retry_delay=-1, - ingestion_start_offset=-1, - stop_retry_after=-1, + rollup_settings=DataFeedRollupSettings( + rollup_type="NoRollup", + rollup_method="None", ), - options=DataFeedOptions( - admin_emails=["yournamehere@microsoft.com"], - data_feed_description="my first data feed", - missing_data_point_fill_settings=DataFeedMissingDataPointFillSettings( - fill_type="SmartFilling" - ), - rollup_settings=DataFeedRollupSettings( - rollup_type="NoRollup", - rollup_method="None", - ), - viewer_emails=["viewers"], - access_mode="Private", - action_link_template="action link template" - ) + viewer_emails=["viewers"], + access_mode="Private", + action_link_template="action link template" ) + ) def _create_alert_config_for_update(self, name): detection_config, data_feed = self._create_data_feed_and_detection_config(name) alert_config_name = create_random_name(name) alert_config = self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - cross_metrics_operator="AND", - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="TopN", - top_n_group_in_scope=TopNGroupScope( - top=5, - period=10, - min_top_count=9 - ) - ), - alert_conditions=MetricAnomalyAlertConditions( - metric_boundary_condition=MetricBoundaryCondition( - direction="Both", - companion_metric_id=data_feed.metric_ids[0], - lower=1.0, - upper=5.0 - ) + name=alert_config_name, + cross_metrics_operator="AND", + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="TopN", + top_n_group_in_scope=TopNGroupScope( + top=5, + period=10, + min_top_count=9 ) ), - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="SeriesGroup", - series_group_in_scope={'city': 'Shenzhen'} - ), - alert_conditions=MetricAnomalyAlertConditions( - severity_condition=SeverityCondition( - min_alert_severity="Low", - max_alert_severity="High" - ) + alert_conditions=MetricAnomalyAlertConditions( + metric_boundary_condition=MetricBoundaryCondition( + direction="Both", + companion_metric_id=data_feed.metric_ids[0], + lower=1.0, + upper=5.0 ) + ) + ), + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="SeriesGroup", + series_group_in_scope={'city': 'Shenzhen'} ), - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="WholeSeries" - ), - alert_conditions=MetricAnomalyAlertConditions( - severity_condition=SeverityCondition( - min_alert_severity="Low", - max_alert_severity="High" - ) + alert_conditions=MetricAnomalyAlertConditions( + severity_condition=SeverityCondition( + min_alert_severity="Low", + max_alert_severity="High" ) ) - ], - hook_ids=[] - ) + ), + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="WholeSeries" + ), + alert_conditions=MetricAnomalyAlertConditions( + severity_condition=SeverityCondition( + min_alert_severity="Low", + max_alert_severity="High" + ) + ) + ) + ], + hook_ids=[] ) return alert_config, data_feed, detection_config @@ -334,63 +319,61 @@ def _create_detection_config_for_update(self, name): data_feed = self._create_data_feed(name) detection_config_name = create_random_name("testupdated") detection_config = self.admin_client.create_detection_configuration( - AnomalyDetectionConfiguration( - name=detection_config_name, - metric_id=data_feed.metric_ids[0], - description="My test metric anomaly detection configuration", - whole_series_detection_condition=MetricDetectionCondition( - cross_conditions_operator="AND", - smart_detection_condition=SmartDetectionCondition( - sensitivity=50, - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=50, - min_ratio=50 - ) - ), - hard_threshold_condition=HardThresholdCondition( - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=5, - min_ratio=5 - ), - lower_bound=0, - upper_bound=100 - ), - change_threshold_condition=ChangeThresholdCondition( - change_percentage=50, - shift_point=30, - within_range=True, - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=2, - min_ratio=2 - ) + name=detection_config_name, + metric_id=data_feed.metric_ids[0], + description="My test metric anomaly detection configuration", + whole_series_detection_condition=MetricDetectionCondition( + cross_conditions_operator="AND", + smart_detection_condition=SmartDetectionCondition( + sensitivity=50, + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=50, + min_ratio=50 ) ), - series_detection_conditions=[MetricSingleSeriesDetectionCondition( - series_key={"city": "Shenzhen", "category": "Jewelry"}, - smart_detection_condition=SmartDetectionCondition( - anomaly_detector_direction="Both", - sensitivity=63, - suppress_condition=SuppressCondition( - min_number=1, - min_ratio=100 - ) + hard_threshold_condition=HardThresholdCondition( + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=5, + min_ratio=5 + ), + lower_bound=0, + upper_bound=100 + ), + change_threshold_condition=ChangeThresholdCondition( + change_percentage=50, + shift_point=30, + within_range=True, + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=2, + min_ratio=2 ) - )], - series_group_detection_conditions=[MetricSeriesGroupDetectionCondition( - series_group_key={"city": "Sao Paulo"}, - smart_detection_condition=SmartDetectionCondition( - anomaly_detector_direction="Both", - sensitivity=63, - suppress_condition=SuppressCondition( - min_number=1, - min_ratio=100 - ) + ) + ), + series_detection_conditions=[MetricSingleSeriesDetectionCondition( + series_key={"city": "Shenzhen", "category": "Jewelry"}, + smart_detection_condition=SmartDetectionCondition( + anomaly_detector_direction="Both", + sensitivity=63, + suppress_condition=SuppressCondition( + min_number=1, + min_ratio=100 ) - )] - ) + ) + )], + series_group_detection_conditions=[MetricSeriesGroupDetectionCondition( + series_group_key={"city": "Sao Paulo"}, + smart_detection_condition=SmartDetectionCondition( + anomaly_detector_direction="Both", + sensitivity=63, + suppress_condition=SuppressCondition( + min_number=1, + min_ratio=100 + ) + ) + )] ) return detection_config, data_feed diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/recordings/test_data_feeds.test_create_simple_data_feed.yaml b/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/recordings/test_data_feeds.test_create_simple_data_feed.yaml new file mode 100644 index 000000000000..af961d7eb434 --- /dev/null +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/recordings/test_data_feeds.test_create_simple_data_feed.yaml @@ -0,0 +1,118 @@ +interactions: +- request: + body: '{"dataSourceType": "SqlServer", "dataFeedName": "testfeed902c11b6", "granularityName": + "Daily", "metrics": [{"metricName": "cost"}, {"metricName": "revenue"}], "dataStartFrom": + "2019-10-01T00:00:00.000Z", "startOffsetInSeconds": 0, "maxConcurrency": -1, + "minRetryIntervalInSeconds": -1, "stopRetryAfterInSeconds": -1, "dataSourceParameter": + {"connectionString": "connectionstring", "query": "select\u202f*\u202ffrom\u202fadsample2\u202fwhere\u202fTimestamp\u202f=\u202f@StartTime"}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '698' + Content-Type: + - application/json + User-Agent: + - azsdk-python-ai-metricsadvisor/1.0.0b2 Python/3.8.6 (Windows-10-10.0.19041-SP0) + method: POST + uri: https://js-metrics-advisor.cognitiveservices.azure.com/metricsadvisor/v1.0/dataFeeds + response: + body: + string: '' + headers: + apim-request-id: + - a06b9aab-f4ca-43f5-af64-7666b5f41e1c + content-length: + - '0' + date: + - Mon, 02 Nov 2020 18:32:35 GMT + location: + - https://js-metrics-advisor.cognitiveservices.azure.com/metricsadvisor/v1.0/dataFeeds/c02e3ccf-8ade-4a34-825b-07519587b2cd + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '6071' + x-request-id: + - a06b9aab-f4ca-43f5-af64-7666b5f41e1c + status: + code: 201 + message: Created +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-ai-metricsadvisor/1.0.0b2 Python/3.8.6 (Windows-10-10.0.19041-SP0) + method: GET + uri: https://js-metrics-advisor.cognitiveservices.azure.com/metricsadvisor/v1.0/dataFeeds/c02e3ccf-8ade-4a34-825b-07519587b2cd + response: + body: + string: "{\"dataFeedId\":\"c02e3ccf-8ade-4a34-825b-07519587b2cd\",\"dataFeedName\":\"testfeed902c11b6\",\"metrics\":[{\"metricId\":\"5b562c6e-d5d1-45df-9dab-fc5800f4ac72\",\"metricName\":\"cost\",\"metricDisplayName\":\"cost\",\"metricDescription\":\"\"},{\"metricId\":\"19899f59-c3c9-422a-b655-2aa50a42cc0e\",\"metricName\":\"revenue\",\"metricDisplayName\":\"revenue\",\"metricDescription\":\"\"}],\"dimension\":[],\"dataStartFrom\":\"2019-10-01T00:00:00Z\",\"dataSourceType\":\"SqlServer\",\"timestampColumn\":\"\",\"startOffsetInSeconds\":0,\"maxQueryPerMinute\":30.0,\"granularityName\":\"Daily\",\"granularityAmount\":null,\"allUpIdentification\":null,\"needRollup\":\"NoRollup\",\"fillMissingPointType\":\"PreviousValue\",\"fillMissingPointValue\":0.0,\"rollUpMethod\":\"None\",\"rollUpColumns\":[],\"dataFeedDescription\":\"\",\"stopRetryAfterInSeconds\":-1,\"minRetryIntervalInSeconds\":-1,\"maxConcurrency\":-1,\"viewMode\":\"Private\",\"admins\":[\"krpratic@microsoft.com\"],\"viewers\":[],\"creator\":\"krpratic@microsoft.com\",\"status\":\"Active\",\"createdTime\":\"2020-11-02T18:32:35Z\",\"isAdmin\":true,\"actionLinkTemplate\":\"\",\"dataSourceParameter\":{\"connectionString\":\"connectionstring\",\"query\":\"select\u202F*\u202Ffrom\u202Fadsample2\u202Fwhere\u202FTimestamp\u202F=\u202F@StartTime\"}}" + headers: + apim-request-id: + - 7d790d06-a37a-4c53-927b-755b191bd455 + content-length: + - '1372' + content-type: + - application/json; charset=utf-8 + date: + - Mon, 02 Nov 2020 18:32:41 GMT + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '5305' + x-request-id: + - 7d790d06-a37a-4c53-927b-755b191bd455 + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + User-Agent: + - azsdk-python-ai-metricsadvisor/1.0.0b2 Python/3.8.6 (Windows-10-10.0.19041-SP0) + method: DELETE + uri: https://js-metrics-advisor.cognitiveservices.azure.com/metricsadvisor/v1.0/dataFeeds/c02e3ccf-8ade-4a34-825b-07519587b2cd + response: + body: + string: '' + headers: + apim-request-id: + - 510f7c35-08a5-4d49-9848-5afc98705e50 + content-length: + - '0' + date: + - Mon, 02 Nov 2020 18:32:41 GMT + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-content-type-options: + - nosniff + x-envoy-upstream-service-time: + - '401' + x-request-id: + - 510f7c35-08a5-4d49-9848-5afc98705e50 + status: + code: 204 + message: No Content +version: 1 diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/test_alert_config.py b/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/test_alert_config.py index aac1fea5958e..8d7809da164c 100644 --- a/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/test_alert_config.py +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/test_alert_config.py @@ -16,7 +16,6 @@ TopNGroupScope, SeverityCondition, MetricAnomalyAlertSnoozeCondition, - AnomalyAlertConfiguration ) from base_testcase import TestMetricsAdvisorAdministrationClientBase @@ -29,31 +28,29 @@ def test_create_alert_config_top_n_alert_direction_both(self): alert_config_name = self.create_random_name("testalert") try: alert_config = self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="TopN", - top_n_group_in_scope=TopNGroupScope( - top=5, - period=10, - min_top_count=9 - ) - ), - alert_conditions=MetricAnomalyAlertConditions( - metric_boundary_condition=MetricBoundaryCondition( - direction="Both", - companion_metric_id=data_feed.metric_ids[0], - lower=1.0, - upper=5.0 - ) + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="TopN", + top_n_group_in_scope=TopNGroupScope( + top=5, + period=10, + min_top_count=9 + ) + ), + alert_conditions=MetricAnomalyAlertConditions( + metric_boundary_condition=MetricBoundaryCondition( + direction="Both", + companion_metric_id=data_feed.metric_ids[0], + lower=1.0, + upper=5.0 ) ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -92,30 +89,28 @@ def test_create_alert_config_top_n_alert_direction_down(self): alert_config_name = self.create_random_name("testalert") try: alert_config = self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="TopN", - top_n_group_in_scope=TopNGroupScope( - top=5, - period=10, - min_top_count=9 - ) - ), - alert_conditions=MetricAnomalyAlertConditions( - metric_boundary_condition=MetricBoundaryCondition( - direction="Down", - companion_metric_id=data_feed.metric_ids[0], - lower=1.0, - ) + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="TopN", + top_n_group_in_scope=TopNGroupScope( + top=5, + period=10, + min_top_count=9 + ) + ), + alert_conditions=MetricAnomalyAlertConditions( + metric_boundary_condition=MetricBoundaryCondition( + direction="Down", + companion_metric_id=data_feed.metric_ids[0], + lower=1.0, ) ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -154,30 +149,28 @@ def test_create_alert_config_top_n_alert_direction_up(self): alert_config_name = self.create_random_name("testalert") try: alert_config = self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="TopN", - top_n_group_in_scope=TopNGroupScope( - top=5, - period=10, - min_top_count=9 - ) - ), - alert_conditions=MetricAnomalyAlertConditions( - metric_boundary_condition=MetricBoundaryCondition( - direction="Up", - companion_metric_id=data_feed.metric_ids[0], - upper=5.0, - ) + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="TopN", + top_n_group_in_scope=TopNGroupScope( + top=5, + period=10, + min_top_count=9 + ) + ), + alert_conditions=MetricAnomalyAlertConditions( + metric_boundary_condition=MetricBoundaryCondition( + direction="Up", + companion_metric_id=data_feed.metric_ids[0], + upper=5.0, ) ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -216,29 +209,27 @@ def test_create_alert_config_top_n_severity_condition(self): alert_config_name = self.create_random_name("testalert") try: alert_config = self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="TopN", - top_n_group_in_scope=TopNGroupScope( - top=5, - period=10, - min_top_count=9 - ) - ), - alert_conditions=MetricAnomalyAlertConditions( - severity_condition=SeverityCondition( - min_alert_severity="Low", - max_alert_severity="High" - ) + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="TopN", + top_n_group_in_scope=TopNGroupScope( + top=5, + period=10, + min_top_count=9 + ) + ), + alert_conditions=MetricAnomalyAlertConditions( + severity_condition=SeverityCondition( + min_alert_severity="Low", + max_alert_severity="High" ) ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -271,28 +262,26 @@ def test_create_alert_config_snooze_condition(self): alert_config_name = self.create_random_name("testalert") try: alert_config = self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="TopN", - top_n_group_in_scope=TopNGroupScope( - top=5, - period=10, - min_top_count=9 - ) - ), - alert_snooze_condition=MetricAnomalyAlertSnoozeCondition( - auto_snooze=5, - snooze_scope="Metric", - only_for_successive=True + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="TopN", + top_n_group_in_scope=TopNGroupScope( + top=5, + period=10, + min_top_count=9 ) + ), + alert_snooze_condition=MetricAnomalyAlertSnoozeCondition( + auto_snooze=5, + snooze_scope="Metric", + only_for_successive=True ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -326,26 +315,24 @@ def test_create_alert_config_whole_series_alert_direction_both(self): alert_config_name = self.create_random_name("testalert") try: alert_config = self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="WholeSeries", - ), - alert_conditions=MetricAnomalyAlertConditions( - metric_boundary_condition=MetricBoundaryCondition( - direction="Both", - companion_metric_id=data_feed.metric_ids[0], - lower=1.0, - upper=5.0 - ) + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="WholeSeries", + ), + alert_conditions=MetricAnomalyAlertConditions( + metric_boundary_condition=MetricBoundaryCondition( + direction="Both", + companion_metric_id=data_feed.metric_ids[0], + lower=1.0, + upper=5.0 ) ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -380,25 +367,23 @@ def test_create_alert_config_whole_series_alert_direction_down(self): alert_config_name = self.create_random_name("testalert") try: alert_config = self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="WholeSeries" - ), - alert_conditions=MetricAnomalyAlertConditions( - metric_boundary_condition=MetricBoundaryCondition( - direction="Down", - companion_metric_id=data_feed.metric_ids[0], - lower=1.0, - ) + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="WholeSeries" + ), + alert_conditions=MetricAnomalyAlertConditions( + metric_boundary_condition=MetricBoundaryCondition( + direction="Down", + companion_metric_id=data_feed.metric_ids[0], + lower=1.0, ) ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -433,25 +418,23 @@ def test_create_alert_config_whole_series_alert_direction_up(self): alert_config_name = self.create_random_name("testalert") try: alert_config = self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="WholeSeries" - ), - alert_conditions=MetricAnomalyAlertConditions( - metric_boundary_condition=MetricBoundaryCondition( - direction="Up", - companion_metric_id=data_feed.metric_ids[0], - upper=5.0, - ) + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="WholeSeries" + ), + alert_conditions=MetricAnomalyAlertConditions( + metric_boundary_condition=MetricBoundaryCondition( + direction="Up", + companion_metric_id=data_feed.metric_ids[0], + upper=5.0, ) ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -486,24 +469,22 @@ def test_create_alert_config_whole_series_severity_condition(self): alert_config_name = self.create_random_name("testalert") try: alert_config = self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="WholeSeries" - ), - alert_conditions=MetricAnomalyAlertConditions( - severity_condition=SeverityCondition( - min_alert_severity="Low", - max_alert_severity="High" - ) + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="WholeSeries" + ), + alert_conditions=MetricAnomalyAlertConditions( + severity_condition=SeverityCondition( + min_alert_severity="Low", + max_alert_severity="High" ) ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -532,27 +513,25 @@ def test_create_alert_config_series_group_alert_direction_both(self): alert_config_name = self.create_random_name("testalert") try: alert_config = self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="SeriesGroup", - series_group_in_scope={'city': 'Shenzhen'} - ), - alert_conditions=MetricAnomalyAlertConditions( - metric_boundary_condition=MetricBoundaryCondition( - direction="Both", - companion_metric_id=data_feed.metric_ids[0], - lower=1.0, - upper=5.0 - ) + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="SeriesGroup", + series_group_in_scope={'city': 'Shenzhen'} + ), + alert_conditions=MetricAnomalyAlertConditions( + metric_boundary_condition=MetricBoundaryCondition( + direction="Both", + companion_metric_id=data_feed.metric_ids[0], + lower=1.0, + upper=5.0 ) ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -588,26 +567,24 @@ def test_create_alert_config_series_group_alert_direction_down(self): alert_config_name = self.create_random_name("testalert") try: alert_config = self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="SeriesGroup", - series_group_in_scope={'city': 'Shenzhen'} - ), - alert_conditions=MetricAnomalyAlertConditions( - metric_boundary_condition=MetricBoundaryCondition( - direction="Down", - companion_metric_id=data_feed.metric_ids[0], - lower=1.0, - ) + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="SeriesGroup", + series_group_in_scope={'city': 'Shenzhen'} + ), + alert_conditions=MetricAnomalyAlertConditions( + metric_boundary_condition=MetricBoundaryCondition( + direction="Down", + companion_metric_id=data_feed.metric_ids[0], + lower=1.0, ) ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -643,26 +620,24 @@ def test_create_alert_config_series_group_alert_direction_up(self): alert_config_name = self.create_random_name("testalert") try: alert_config = self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="SeriesGroup", - series_group_in_scope={'city': 'Shenzhen'} - ), - alert_conditions=MetricAnomalyAlertConditions( - metric_boundary_condition=MetricBoundaryCondition( - direction="Up", - companion_metric_id=data_feed.metric_ids[0], - upper=5.0, - ) + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="SeriesGroup", + series_group_in_scope={'city': 'Shenzhen'} + ), + alert_conditions=MetricAnomalyAlertConditions( + metric_boundary_condition=MetricBoundaryCondition( + direction="Up", + companion_metric_id=data_feed.metric_ids[0], + upper=5.0, ) ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -698,25 +673,23 @@ def test_create_alert_config_series_group_severity_condition(self): alert_config_name = self.create_random_name("testalert") try: alert_config = self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="SeriesGroup", - series_group_in_scope={'city': 'Shenzhen'} - ), - alert_conditions=MetricAnomalyAlertConditions( - severity_condition=SeverityCondition( - min_alert_severity="Low", - max_alert_severity="High" - ) + name=alert_config_name, + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="SeriesGroup", + series_group_in_scope={'city': 'Shenzhen'} + ), + alert_conditions=MetricAnomalyAlertConditions( + severity_condition=SeverityCondition( + min_alert_severity="Low", + max_alert_severity="High" ) ) - ], - hook_ids=[] - ) + ) + ], + hook_ids=[] ) self.assertIsNone(alert_config.cross_metrics_operator) self.assertIsNotNone(alert_config.id) @@ -746,57 +719,55 @@ def test_create_alert_config_multiple_configurations(self): alert_config_name = self.create_random_name("testalert") try: alert_config = self.admin_client.create_alert_configuration( - AnomalyAlertConfiguration( - name=alert_config_name, - cross_metrics_operator="AND", - metric_alert_configurations=[ - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="TopN", - top_n_group_in_scope=TopNGroupScope( - top=5, - period=10, - min_top_count=9 - ) - ), - alert_conditions=MetricAnomalyAlertConditions( - metric_boundary_condition=MetricBoundaryCondition( - direction="Both", - companion_metric_id=data_feed.metric_ids[0], - lower=1.0, - upper=5.0 - ) + name=alert_config_name, + cross_metrics_operator="AND", + metric_alert_configurations=[ + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="TopN", + top_n_group_in_scope=TopNGroupScope( + top=5, + period=10, + min_top_count=9 ) ), - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="SeriesGroup", - series_group_in_scope={'city': 'Shenzhen'} - ), - alert_conditions=MetricAnomalyAlertConditions( - severity_condition=SeverityCondition( - min_alert_severity="Low", - max_alert_severity="High" - ) + alert_conditions=MetricAnomalyAlertConditions( + metric_boundary_condition=MetricBoundaryCondition( + direction="Both", + companion_metric_id=data_feed.metric_ids[0], + lower=1.0, + upper=5.0 ) + ) + ), + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="SeriesGroup", + series_group_in_scope={'city': 'Shenzhen'} ), - MetricAlertConfiguration( - detection_configuration_id=detection_config.id, - alert_scope=MetricAnomalyAlertScope( - scope_type="WholeSeries" - ), - alert_conditions=MetricAnomalyAlertConditions( - severity_condition=SeverityCondition( - min_alert_severity="Low", - max_alert_severity="High" - ) + alert_conditions=MetricAnomalyAlertConditions( + severity_condition=SeverityCondition( + min_alert_severity="Low", + max_alert_severity="High" ) ) - ], - hook_ids=[] - ) + ), + MetricAlertConfiguration( + detection_configuration_id=detection_config.id, + alert_scope=MetricAnomalyAlertScope( + scope_type="WholeSeries" + ), + alert_conditions=MetricAnomalyAlertConditions( + severity_condition=SeverityCondition( + min_alert_severity="Low", + max_alert_severity="High" + ) + ) + ) + ], + hook_ids=[] ) self.assertEqual(alert_config.cross_metrics_operator, "AND") self.assertIsNotNone(alert_config.id) diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/test_data_feeds.py b/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/test_data_feeds.py index b02e59382241..80b7c2646a4a 100644 --- a/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/test_data_feeds.py +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/test_data_feeds.py @@ -32,59 +32,84 @@ MySqlDataFeed, PostgreSqlDataFeed, ElasticsearchDataFeed, - DataFeed ) from base_testcase import TestMetricsAdvisorAdministrationClientBase class TestMetricsAdvisorAdministrationClient(TestMetricsAdvisorAdministrationClientBase): + def test_create_simple_data_feed(self): + data_feed_name = self.create_random_name("testfeed") + try: + data_feed = self.admin_client.create_data_feed( + name=data_feed_name, + source=SQLServerDataFeed( + connection_string=self.sql_server_connection_string, + query="select * from adsample2 where Timestamp = @StartTime" + ), + granularity="Daily", + schema=["cost", "revenue"], + ingestion_settings=datetime.datetime(2019, 10, 1) + ) + + self.assertIsNotNone(data_feed.id) + self.assertIsNotNone(data_feed.created_time) + self.assertIsNotNone(data_feed.name) + self.assertEqual(data_feed.source.data_source_type, "SqlServer") + self.assertIsNotNone(data_feed.source.connection_string) + self.assertIsNotNone(data_feed.source.query) + self.assertEqual(data_feed.granularity.granularity_type, "Daily") + self.assertEqual(data_feed.schema.metrics[0].name, "cost") + self.assertEqual(data_feed.schema.metrics[1].name, "revenue") + self.assertEqual(data_feed.ingestion_settings.ingestion_begin_time, + datetime.datetime(2019, 10, 1, tzinfo=tzutc())) + finally: + self.admin_client.delete_data_feed(data_feed.id) + def test_create_data_feed_from_sql_server(self): data_feed_name = self.create_random_name("testfeed") try: data_feed = self.admin_client.create_data_feed( - DataFeed( - name=data_feed_name, - source=SQLServerDataFeed( - connection_string=self.sql_server_connection_string, - query=u"select * from adsample2 where Timestamp = @StartTime" - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost", display_name="display cost", description="the cost"), - DataFeedMetric(name="revenue", display_name="display revenue", description="the revenue") - ], - dimensions=[ - DataFeedDimension(name="category", display_name="display category"), - DataFeedDimension(name="city", display_name="display city") - ], - timestamp_column="Timestamp" + name=data_feed_name, + source=SQLServerDataFeed( + connection_string=self.sql_server_connection_string, + query=u"select * from adsample2 where Timestamp = @StartTime" + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost", display_name="display cost", description="the cost"), + DataFeedMetric(name="revenue", display_name="display revenue", description="the revenue") + ], + dimensions=[ + DataFeedDimension(name="category", display_name="display category"), + DataFeedDimension(name="city", display_name="display city") + ], + timestamp_column="Timestamp" + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 10, 1), + data_source_request_concurrency=0, + ingestion_retry_delay=-1, + ingestion_start_offset=-1, + stop_retry_after=-1, + ), + options=DataFeedOptions( + admin_emails=["yournamehere@microsoft.com"], + data_feed_description="my first data feed", + missing_data_point_fill_settings=DataFeedMissingDataPointFillSettings( + fill_type="SmartFilling" ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 10, 1), - data_source_request_concurrency=0, - ingestion_retry_delay=-1, - ingestion_start_offset=-1, - stop_retry_after=-1, + rollup_settings=DataFeedRollupSettings( + rollup_type="NoRollup", + rollup_method="None", ), - options=DataFeedOptions( - admin_emails=["yournamehere@microsoft.com"], - data_feed_description="my first data feed", - missing_data_point_fill_settings=DataFeedMissingDataPointFillSettings( - fill_type="SmartFilling" - ), - rollup_settings=DataFeedRollupSettings( - rollup_type="NoRollup", - rollup_method="None", - ), - viewer_emails=["viewers"], - access_mode="Private", - action_link_template="action link template" - ) + viewer_emails=["viewers"], + access_mode="Private", + action_link_template="action link template" ) ) @@ -135,51 +160,50 @@ def test_create_data_feed_from_sql_server_with_custom_values(self): data_feed_name = self.create_random_name("testfeed") try: data_feed = self.admin_client.create_data_feed( - DataFeed( - name=data_feed_name, - source=SQLServerDataFeed( - connection_string=self.sql_server_connection_string, - query=u"select * from adsample2 where Timestamp = @StartTime" - ), - granularity=DataFeedGranularity( - granularity_type="Custom", - custom_granularity_value=20 - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost", display_name="display cost", description="the cost"), - DataFeedMetric(name="revenue", display_name="display revenue", description="the revenue") - ], - dimensions=[ - DataFeedDimension(name="category", display_name="display category"), - DataFeedDimension(name="city", display_name="display city") - ], - timestamp_column="Timestamp" + name=data_feed_name, + source=SQLServerDataFeed( + connection_string=self.sql_server_connection_string, + query=u"select * from adsample2 where Timestamp = @StartTime" + ), + granularity=DataFeedGranularity( + granularity_type="Custom", + custom_granularity_value=20 + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost", display_name="display cost", description="the cost"), + DataFeedMetric(name="revenue", display_name="display revenue", description="the revenue") + ], + dimensions=[ + DataFeedDimension(name="category", display_name="display category"), + DataFeedDimension(name="city", display_name="display city") + ], + timestamp_column="Timestamp" + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 10, 1), + data_source_request_concurrency=0, + ingestion_retry_delay=-1, + ingestion_start_offset=-1, + stop_retry_after=-1, + ), + options=DataFeedOptions( + admin_emails=["yournamehere@microsoft.com"], + data_feed_description="my first data feed", + missing_data_point_fill_settings=DataFeedMissingDataPointFillSettings( + fill_type="CustomValue", + custom_fill_value=10 ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 10, 1), - data_source_request_concurrency=0, - ingestion_retry_delay=-1, - ingestion_start_offset=-1, - stop_retry_after=-1, + rollup_settings=DataFeedRollupSettings( + rollup_type="AlreadyRollup", + rollup_method="Sum", + rollup_identification_value="sumrollup" ), - options=DataFeedOptions( - admin_emails=["yournamehere@microsoft.com"], - data_feed_description="my first data feed", - missing_data_point_fill_settings=DataFeedMissingDataPointFillSettings( - fill_type="CustomValue", - custom_fill_value=10 - ), - rollup_settings=DataFeedRollupSettings( - rollup_type="AlreadyRollup", - rollup_method="Sum", - rollup_identification_value="sumrollup" - ), - viewer_emails=["viewers"], - access_mode="Private", - action_link_template="action link template" - ) + viewer_emails=["viewers"], + access_mode="Private", + action_link_template="action link template" ) + ) self.assertIsNotNone(data_feed.id) self.assertIsNotNone(data_feed.created_time) @@ -229,30 +253,29 @@ def test_create_data_feed_with_azure_table(self): name = self.create_random_name("tablefeed") try: data_feed = self.admin_client.create_data_feed( - DataFeed( - name=name, - source=AzureTableDataFeed( - connection_string=self.azure_table_connection_string, - query="PartitionKey ge '@StartTime' and PartitionKey lt '@EndTime'", - table="adsample" - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost"), - DataFeedMetric(name="revenue") - ], - dimensions=[ - DataFeedDimension(name="category"), - DataFeedDimension(name="city") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 10, 1), - ), - ) + name=name, + source=AzureTableDataFeed( + connection_string=self.azure_table_connection_string, + query="PartitionKey ge '@StartTime' and PartitionKey lt '@EndTime'", + table="adsample" + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost"), + DataFeedMetric(name="revenue") + ], + dimensions=[ + DataFeedDimension(name="category"), + DataFeedDimension(name="city") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 10, 1), + ), + ) self.assertIsNotNone(data_feed.id) @@ -269,30 +292,29 @@ def test_create_data_feed_with_azure_blob(self): name = self.create_random_name("blobfeed") try: data_feed = self.admin_client.create_data_feed( - DataFeed( - name=name, - source=AzureBlobDataFeed( - connection_string=self.azure_blob_connection_string, - container="adsample", - blob_template="%Y/%m/%d/%h/JsonFormatV2.json" - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost"), - DataFeedMetric(name="revenue") - ], - dimensions=[ - DataFeedDimension(name="category"), - DataFeedDimension(name="city") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 10, 1), - ), - ) + name=name, + source=AzureBlobDataFeed( + connection_string=self.azure_blob_connection_string, + container="adsample", + blob_template="%Y/%m/%d/%h/JsonFormatV2.json" + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost"), + DataFeedMetric(name="revenue") + ], + dimensions=[ + DataFeedDimension(name="category"), + DataFeedDimension(name="city") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 10, 1), + ), + ) self.assertIsNotNone(data_feed.id) @@ -309,31 +331,30 @@ def test_create_data_feed_with_azure_cosmos_db(self): name = self.create_random_name("cosmosfeed") try: data_feed = self.admin_client.create_data_feed( - DataFeed( - name=name, - source=AzureCosmosDBDataFeed( - connection_string=self.azure_cosmosdb_connection_string, - sql_query="'SELECT * FROM Items I where I.Timestamp >= @StartTime and I.Timestamp < @EndTime'", - database="adsample", - collection_id="adsample" - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost"), - DataFeedMetric(name="revenue") - ], - dimensions=[ - DataFeedDimension(name="category"), - DataFeedDimension(name="city") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 10, 1), - ), - ) + name=name, + source=AzureCosmosDBDataFeed( + connection_string=self.azure_cosmosdb_connection_string, + sql_query="'SELECT * FROM Items I where I.Timestamp >= @StartTime and I.Timestamp < @EndTime'", + database="adsample", + collection_id="adsample" + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost"), + DataFeedMetric(name="revenue") + ], + dimensions=[ + DataFeedDimension(name="category"), + DataFeedDimension(name="city") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 10, 1), + ), + ) self.assertIsNotNone(data_feed.id) @@ -351,29 +372,28 @@ def test_create_data_feed_with_http_request_get(self): name = self.create_random_name("httprequestfeedget") try: data_feed = self.admin_client.create_data_feed( - DataFeed( - name=name, - source=HttpRequestDataFeed( - url=self.http_request_get_url, - http_method="GET" - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost"), - DataFeedMetric(name="revenue") - ], - dimensions=[ - DataFeedDimension(name="category"), - DataFeedDimension(name="city") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 10, 1), - ), - ) + name=name, + source=HttpRequestDataFeed( + url=self.http_request_get_url, + http_method="GET" + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost"), + DataFeedMetric(name="revenue") + ], + dimensions=[ + DataFeedDimension(name="category"), + DataFeedDimension(name="city") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 10, 1), + ), + ) self.assertIsNotNone(data_feed.id) @@ -389,30 +409,29 @@ def test_create_data_feed_with_http_request_post(self): name = self.create_random_name("httprequestfeedpost") try: data_feed = self.admin_client.create_data_feed( - DataFeed( - name=name, - source=HttpRequestDataFeed( - url=self.http_request_post_url, - http_method="POST", - payload="{'startTime': '@StartTime'}" - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost"), - DataFeedMetric(name="revenue") - ], - dimensions=[ - DataFeedDimension(name="category"), - DataFeedDimension(name="city") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 10, 1), - ), - ) + name=name, + source=HttpRequestDataFeed( + url=self.http_request_post_url, + http_method="POST", + payload="{'startTime': '@StartTime'}" + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost"), + DataFeedMetric(name="revenue") + ], + dimensions=[ + DataFeedDimension(name="category"), + DataFeedDimension(name="city") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 10, 1), + ), + ) self.assertIsNotNone(data_feed.id) @@ -433,31 +452,30 @@ def test_create_data_feed_with_application_insights(self): "duration_avg_ms = avg(duration), duration_95th_ms = percentile(duration, 95), " \ "duration_max_ms = max(duration) by resultCode" data_feed = self.admin_client.create_data_feed( - DataFeed( - name=name, - source=AzureApplicationInsightsDataFeed( - azure_cloud="Azure", - application_id="3706fe8b-98f1-47c7-bf69-b73b6e53274d", - api_key=self.application_insights_api_key, - query=query - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost"), - DataFeedMetric(name="revenue") - ], - dimensions=[ - DataFeedDimension(name="category"), - DataFeedDimension(name="city") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2020, 7, 1), - ), - ) + name=name, + source=AzureApplicationInsightsDataFeed( + azure_cloud="Azure", + application_id="3706fe8b-98f1-47c7-bf69-b73b6e53274d", + api_key=self.application_insights_api_key, + query=query + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost"), + DataFeedMetric(name="revenue") + ], + dimensions=[ + DataFeedDimension(name="category"), + DataFeedDimension(name="city") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2020, 7, 1), + ), + ) self.assertIsNotNone(data_feed.id) @@ -477,29 +495,28 @@ def test_create_data_feed_with_data_explorer(self): query = "let StartDateTime = datetime(@StartTime); let EndDateTime = StartDateTime + 1d; " \ "adsample | where Timestamp >= StartDateTime and Timestamp < EndDateTime" data_feed = self.admin_client.create_data_feed( - DataFeed( - name=name, - source=AzureDataExplorerDataFeed( - connection_string=self.azure_data_explorer_connection_string, - query=query - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost"), - DataFeedMetric(name="revenue") - ], - dimensions=[ - DataFeedDimension(name="category"), - DataFeedDimension(name="city") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 1, 1), - ), - ) + name=name, + source=AzureDataExplorerDataFeed( + connection_string=self.azure_data_explorer_connection_string, + query=query + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost"), + DataFeedMetric(name="revenue") + ], + dimensions=[ + DataFeedDimension(name="category"), + DataFeedDimension(name="city") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 1, 1), + ), + ) self.assertIsNotNone(data_feed.id) @@ -516,32 +533,31 @@ def test_create_data_feed_with_influxdb(self): name = self.create_random_name("influxdb") try: data_feed = self.admin_client.create_data_feed( - DataFeed( - name=name, - source=InfluxDBDataFeed( - connection_string=self.influxdb_connection_string, - database="adsample", - user_name="adreadonly", - password=self.influxdb_password, - query="'select * from adsample2 where Timestamp = @StartTime'" - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost"), - DataFeedMetric(name="revenue") - ], - dimensions=[ - DataFeedDimension(name="category"), - DataFeedDimension(name="city") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 1, 1), - ), - ) + name=name, + source=InfluxDBDataFeed( + connection_string=self.influxdb_connection_string, + database="adsample", + user_name="adreadonly", + password=self.influxdb_password, + query="'select * from adsample2 where Timestamp = @StartTime'" + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost"), + DataFeedMetric(name="revenue") + ], + dimensions=[ + DataFeedDimension(name="category"), + DataFeedDimension(name="city") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 1, 1), + ), + ) self.assertIsNotNone(data_feed.id) @@ -561,32 +577,31 @@ def test_create_data_feed_with_datalake(self): name = self.create_random_name("datalake") try: data_feed = self.admin_client.create_data_feed( - DataFeed( - name=name, - source=AzureDataLakeStorageGen2DataFeed( - account_name="adsampledatalakegen2", - account_key=self.azure_datalake_account_key, - file_system_name="adsample", - directory_template="%Y/%m/%d", - file_template="adsample.json" - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost", display_name="Cost"), - DataFeedMetric(name="revenue", display_name="Revenue") - ], - dimensions=[ - DataFeedDimension(name="category", display_name="Category"), - DataFeedDimension(name="city", display_name="City") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 1, 1), - ), - ) + name=name, + source=AzureDataLakeStorageGen2DataFeed( + account_name="adsampledatalakegen2", + account_key=self.azure_datalake_account_key, + file_system_name="adsample", + directory_template="%Y/%m/%d", + file_template="adsample.json" + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost", display_name="Cost"), + DataFeedMetric(name="revenue", display_name="Revenue") + ], + dimensions=[ + DataFeedDimension(name="category", display_name="Category"), + DataFeedDimension(name="city", display_name="City") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 1, 1), + ), + ) self.assertIsNotNone(data_feed.id) @@ -606,30 +621,29 @@ def test_create_data_feed_with_mongodb(self): name = self.create_random_name("mongodb") try: data_feed = self.admin_client.create_data_feed( - DataFeed( - name=name, - source=MongoDBDataFeed( - connection_string=self.mongodb_connection_string, - database="adsample", - command='{"find": "adsample", "filter": { Timestamp: { $eq: @StartTime }} "batchSize": 2000,}' - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost"), - DataFeedMetric(name="revenue") - ], - dimensions=[ - DataFeedDimension(name="category"), - DataFeedDimension(name="city") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 1, 1), - ), - ) + name=name, + source=MongoDBDataFeed( + connection_string=self.mongodb_connection_string, + database="adsample", + command='{"find": "adsample", "filter": { Timestamp: { $eq: @StartTime }} "batchSize": 2000,}' + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost"), + DataFeedMetric(name="revenue") + ], + dimensions=[ + DataFeedDimension(name="category"), + DataFeedDimension(name="city") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 1, 1), + ), + ) self.assertIsNotNone(data_feed.id) @@ -647,29 +661,28 @@ def test_create_data_feed_with_mysql(self): name = self.create_random_name("mysql") try: data_feed = self.admin_client.create_data_feed( - DataFeed( - name=name, - source=MySqlDataFeed( - connection_string=self.mysql_connection_string, - query="'select * from adsample2 where Timestamp = @StartTime'" - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost"), - DataFeedMetric(name="revenue") - ], - dimensions=[ - DataFeedDimension(name="category"), - DataFeedDimension(name="city") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 1, 1), - ), - ) + name=name, + source=MySqlDataFeed( + connection_string=self.mysql_connection_string, + query="'select * from adsample2 where Timestamp = @StartTime'" + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost"), + DataFeedMetric(name="revenue") + ], + dimensions=[ + DataFeedDimension(name="category"), + DataFeedDimension(name="city") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 1, 1), + ), + ) self.assertIsNotNone(data_feed.id) @@ -686,29 +699,28 @@ def test_create_data_feed_with_postgresql(self): name = self.create_random_name("postgresql") try: data_feed = self.admin_client.create_data_feed( - DataFeed( - name=name, - source=PostgreSqlDataFeed( - connection_string=self.postgresql_connection_string, - query="'select * from adsample2 where Timestamp = @StartTime'" - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost"), - DataFeedMetric(name="revenue") - ], - dimensions=[ - DataFeedDimension(name="category"), - DataFeedDimension(name="city") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 1, 1), - ), - ) + name=name, + source=PostgreSqlDataFeed( + connection_string=self.postgresql_connection_string, + query="'select * from adsample2 where Timestamp = @StartTime'" + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost"), + DataFeedMetric(name="revenue") + ], + dimensions=[ + DataFeedDimension(name="category"), + DataFeedDimension(name="city") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 1, 1), + ), + ) self.assertIsNotNone(data_feed.id) @@ -725,31 +737,30 @@ def test_create_data_feed_with_elasticsearch(self): name = self.create_random_name("elastic") try: data_feed = self.admin_client.create_data_feed( - DataFeed( - name=name, - source=ElasticsearchDataFeed( - host="ad-sample-es.westus2.cloudapp.azure.com", - port="9200", - auth_header=self.elasticsearch_auth_header, - query="'select * from adsample where timestamp = @StartTime'" - ), - granularity=DataFeedGranularity( - granularity_type="Daily", - ), - schema=DataFeedSchema( - metrics=[ - DataFeedMetric(name="cost", display_name="Cost"), - DataFeedMetric(name="revenue", display_name="Revenue") - ], - dimensions=[ - DataFeedDimension(name="category", display_name="Category"), - DataFeedDimension(name="city", display_name="City") - ], - ), - ingestion_settings=DataFeedIngestionSettings( - ingestion_begin_time=datetime.datetime(2019, 1, 1), - ), - ) + name=name, + source=ElasticsearchDataFeed( + host="ad-sample-es.westus2.cloudapp.azure.com", + port="9200", + auth_header=self.elasticsearch_auth_header, + query="'select * from adsample where timestamp = @StartTime'" + ), + granularity=DataFeedGranularity( + granularity_type="Daily", + ), + schema=DataFeedSchema( + metrics=[ + DataFeedMetric(name="cost", display_name="Cost"), + DataFeedMetric(name="revenue", display_name="Revenue") + ], + dimensions=[ + DataFeedDimension(name="category", display_name="Category"), + DataFeedDimension(name="city", display_name="City") + ], + ), + ingestion_settings=DataFeedIngestionSettings( + ingestion_begin_time=datetime.datetime(2019, 1, 1), + ), + ) self.assertIsNotNone(data_feed.id) diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/test_detection_config.py b/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/test_detection_config.py index 9299a5b02481..ef08873da31d 100644 --- a/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/test_detection_config.py +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/test_detection_config.py @@ -16,7 +16,6 @@ SuppressCondition, ChangeThresholdCondition, HardThresholdCondition, - AnomalyDetectionConfiguration ) from base_testcase import TestMetricsAdvisorAdministrationClientBase @@ -29,38 +28,36 @@ def test_create_ad_config_whole_series_detection(self): try: detection_config_name = self.create_random_name("testdetectionconfig") config = self.admin_client.create_detection_configuration( - AnomalyDetectionConfiguration( - name=detection_config_name, - metric_id=data_feed.metric_ids[0], - description="My test metric anomaly detection configuration", - whole_series_detection_condition=MetricDetectionCondition( - cross_conditions_operator="OR", - smart_detection_condition=SmartDetectionCondition( - sensitivity=50, - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=50, - min_ratio=50 - ) - ), - hard_threshold_condition=HardThresholdCondition( - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=5, - min_ratio=5 - ), - lower_bound=0, - upper_bound=100 + name=detection_config_name, + metric_id=data_feed.metric_ids[0], + description="My test metric anomaly detection configuration", + whole_series_detection_condition=MetricDetectionCondition( + cross_conditions_operator="OR", + smart_detection_condition=SmartDetectionCondition( + sensitivity=50, + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=50, + min_ratio=50 + ) + ), + hard_threshold_condition=HardThresholdCondition( + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=5, + min_ratio=5 ), - change_threshold_condition=ChangeThresholdCondition( - change_percentage=50, - shift_point=30, - within_range=True, - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=2, - min_ratio=2 - ) + lower_bound=0, + upper_bound=100 + ), + change_threshold_condition=ChangeThresholdCondition( + change_percentage=50, + shift_point=30, + within_range=True, + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=2, + min_ratio=2 ) ) ) @@ -109,63 +106,61 @@ def test_create_ad_config_with_series_and_group_conds(self): try: detection_config_name = self.create_random_name("testdetectionconfiget") detection_config = self.admin_client.create_detection_configuration( - AnomalyDetectionConfiguration( - name=detection_config_name, - metric_id=data_feed.metric_ids[0], - description="My test metric anomaly detection configuration", - whole_series_detection_condition=MetricDetectionCondition( - cross_conditions_operator="AND", - smart_detection_condition=SmartDetectionCondition( - sensitivity=50, - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=50, - min_ratio=50 - ) - ), - hard_threshold_condition=HardThresholdCondition( - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=5, - min_ratio=5 - ), - lower_bound=0, - upper_bound=100 - ), - change_threshold_condition=ChangeThresholdCondition( - change_percentage=50, - shift_point=30, - within_range=True, - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=2, - min_ratio=2 - ) + name=detection_config_name, + metric_id=data_feed.metric_ids[0], + description="My test metric anomaly detection configuration", + whole_series_detection_condition=MetricDetectionCondition( + cross_conditions_operator="AND", + smart_detection_condition=SmartDetectionCondition( + sensitivity=50, + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=50, + min_ratio=50 ) ), - series_detection_conditions=[MetricSingleSeriesDetectionCondition( - series_key={"city": "Shenzhen", "category": "Jewelry"}, - smart_detection_condition=SmartDetectionCondition( - anomaly_detector_direction="Both", - sensitivity=63, - suppress_condition=SuppressCondition( - min_number=1, - min_ratio=100 - ) + hard_threshold_condition=HardThresholdCondition( + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=5, + min_ratio=5 + ), + lower_bound=0, + upper_bound=100 + ), + change_threshold_condition=ChangeThresholdCondition( + change_percentage=50, + shift_point=30, + within_range=True, + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=2, + min_ratio=2 ) - )], - series_group_detection_conditions=[MetricSeriesGroupDetectionCondition( - series_group_key={"city": "Sao Paulo"}, - smart_detection_condition=SmartDetectionCondition( - anomaly_detector_direction="Both", - sensitivity=63, - suppress_condition=SuppressCondition( - min_number=1, - min_ratio=100 - ) + ) + ), + series_detection_conditions=[MetricSingleSeriesDetectionCondition( + series_key={"city": "Shenzhen", "category": "Jewelry"}, + smart_detection_condition=SmartDetectionCondition( + anomaly_detector_direction="Both", + sensitivity=63, + suppress_condition=SuppressCondition( + min_number=1, + min_ratio=100 ) - )] - ) + ) + )], + series_group_detection_conditions=[MetricSeriesGroupDetectionCondition( + series_group_key={"city": "Sao Paulo"}, + smart_detection_condition=SmartDetectionCondition( + anomaly_detector_direction="Both", + sensitivity=63, + suppress_condition=SuppressCondition( + min_number=1, + min_ratio=100 + ) + ) + )] ) self.assertIsNotNone(detection_config.id) @@ -226,18 +221,49 @@ def test_create_ad_config_multiple_series_and_group_conds(self): try: detection_config_name = self.create_random_name("multipledetectionconfigs") detection_config = self.admin_client.create_detection_configuration( - AnomalyDetectionConfiguration( - name=detection_config_name, - metric_id=data_feed.metric_ids[0], - description="My test metric anomaly detection configuration", - whole_series_detection_condition=MetricDetectionCondition( + name=detection_config_name, + metric_id=data_feed.metric_ids[0], + description="My test metric anomaly detection configuration", + whole_series_detection_condition=MetricDetectionCondition( + cross_conditions_operator="AND", + smart_detection_condition=SmartDetectionCondition( + sensitivity=50, + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=50, + min_ratio=50 + ) + ), + hard_threshold_condition=HardThresholdCondition( + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=5, + min_ratio=5 + ), + lower_bound=0, + upper_bound=100 + ), + change_threshold_condition=ChangeThresholdCondition( + change_percentage=50, + shift_point=30, + within_range=True, + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=2, + min_ratio=2 + ) + ) + ), + series_detection_conditions=[ + MetricSingleSeriesDetectionCondition( + series_key={"city": "Shenzhen", "category": "Jewelry"}, cross_conditions_operator="AND", smart_detection_condition=SmartDetectionCondition( - sensitivity=50, anomaly_detector_direction="Both", + sensitivity=63, suppress_condition=SuppressCondition( - min_number=50, - min_ratio=50 + min_number=1, + min_ratio=100 ) ), hard_threshold_condition=HardThresholdCondition( @@ -260,97 +286,64 @@ def test_create_ad_config_multiple_series_and_group_conds(self): ) ) ), - series_detection_conditions=[ - MetricSingleSeriesDetectionCondition( - series_key={"city": "Shenzhen", "category": "Jewelry"}, - cross_conditions_operator="AND", - smart_detection_condition=SmartDetectionCondition( - anomaly_detector_direction="Both", - sensitivity=63, - suppress_condition=SuppressCondition( - min_number=1, - min_ratio=100 - ) - ), - hard_threshold_condition=HardThresholdCondition( - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=5, - min_ratio=5 - ), - lower_bound=0, - upper_bound=100 - ), - change_threshold_condition=ChangeThresholdCondition( - change_percentage=50, - shift_point=30, - within_range=True, - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=2, - min_ratio=2 - ) - ) - ), - MetricSingleSeriesDetectionCondition( - series_key={"city": "Osaka", "category": "Cell Phones"}, - cross_conditions_operator="AND", - smart_detection_condition=SmartDetectionCondition( - anomaly_detector_direction="Both", - sensitivity=63, - suppress_condition=SuppressCondition( - min_number=1, - min_ratio=100 - ) + MetricSingleSeriesDetectionCondition( + series_key={"city": "Osaka", "category": "Cell Phones"}, + cross_conditions_operator="AND", + smart_detection_condition=SmartDetectionCondition( + anomaly_detector_direction="Both", + sensitivity=63, + suppress_condition=SuppressCondition( + min_number=1, + min_ratio=100 ) ) - ], - series_group_detection_conditions=[ - MetricSeriesGroupDetectionCondition( - series_group_key={"city": "Sao Paulo"}, - cross_conditions_operator="AND", - smart_detection_condition=SmartDetectionCondition( - anomaly_detector_direction="Both", - sensitivity=63, - suppress_condition=SuppressCondition( - min_number=1, - min_ratio=100 - ) - ), - hard_threshold_condition=HardThresholdCondition( - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=5, - min_ratio=5 - ), - lower_bound=0, - upper_bound=100 - ), - change_threshold_condition=ChangeThresholdCondition( - change_percentage=50, - shift_point=30, - within_range=True, - anomaly_detector_direction="Both", - suppress_condition=SuppressCondition( - min_number=2, - min_ratio=2 - ) + ) + ], + series_group_detection_conditions=[ + MetricSeriesGroupDetectionCondition( + series_group_key={"city": "Sao Paulo"}, + cross_conditions_operator="AND", + smart_detection_condition=SmartDetectionCondition( + anomaly_detector_direction="Both", + sensitivity=63, + suppress_condition=SuppressCondition( + min_number=1, + min_ratio=100 ) ), - MetricSeriesGroupDetectionCondition( - series_group_key={"city": "Seoul"}, - cross_conditions_operator="AND", - smart_detection_condition=SmartDetectionCondition( - anomaly_detector_direction="Both", - sensitivity=63, - suppress_condition=SuppressCondition( - min_number=1, - min_ratio=100 - ) + hard_threshold_condition=HardThresholdCondition( + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=5, + min_ratio=5 + ), + lower_bound=0, + upper_bound=100 + ), + change_threshold_condition=ChangeThresholdCondition( + change_percentage=50, + shift_point=30, + within_range=True, + anomaly_detector_direction="Both", + suppress_condition=SuppressCondition( + min_number=2, + min_ratio=2 ) ) - ] - ) + ), + MetricSeriesGroupDetectionCondition( + series_group_key={"city": "Seoul"}, + cross_conditions_operator="AND", + smart_detection_condition=SmartDetectionCondition( + anomaly_detector_direction="Both", + sensitivity=63, + suppress_condition=SuppressCondition( + min_number=1, + min_ratio=100 + ) + ) + ) + ] ) self.assertIsNotNone(detection_config.id) From b463b9d299da8f55c9183b14d7d68ea2c0e26aed Mon Sep 17 00:00:00 2001 From: Xiang Yan Date: Mon, 2 Nov 2020 11:13:54 -0800 Subject: [PATCH 2/4] update --- .../ai/metricsadvisor/_metrics_advisor_administration_client.py | 2 +- .../azure/ai/metricsadvisor/models/_models.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/_metrics_advisor_administration_client.py b/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/_metrics_advisor_administration_client.py index a204321d06e4..5617e66c0c55 100644 --- a/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/_metrics_advisor_administration_client.py +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/_metrics_advisor_administration_client.py @@ -9,6 +9,7 @@ from typing import ( Any, + List, Union, cast, TYPE_CHECKING @@ -67,7 +68,6 @@ AnomalyAlertConfiguration, AnomalyDetectionConfiguration, DataFeedIngestionProgress, - DataFeedIngestionProgress, AzureApplicationInsightsDataFeed, AzureBlobDataFeed, AzureCosmosDBDataFeed, diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/models/_models.py b/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/models/_models.py index 30ffb86eef1a..085de71bfd29 100644 --- a/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/models/_models.py +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/models/_models.py @@ -75,6 +75,7 @@ IncidentResult, RootCause, ) + from .._metrics_advisor_administration_client import DataFeedSourceUnion class MetricAnomalyAlertScopeType(str, Enum): From 1ccdcdd64bffa5cc02c9a99173e30b0d90b93816 Mon Sep 17 00:00:00 2001 From: Xiang Yan Date: Mon, 2 Nov 2020 11:27:33 -0800 Subject: [PATCH 3/4] update --- .../azure/ai/metricsadvisor/models/_models.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/models/_models.py b/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/models/_models.py index 085de71bfd29..16ea9a8ba209 100644 --- a/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/models/_models.py +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/azure/ai/metricsadvisor/models/_models.py @@ -59,6 +59,8 @@ ElasticsearchParameter as _ElasticsearchParameter, DimensionGroupIdentity as _DimensionGroupIdentity, SeriesIdentity as _SeriesIdentity, + AnomalyAlertingConfiguration as _AnomalyAlertingConfiguration, + AnomalyDetectionConfiguration as _AnomalyDetectionConfiguration, AnomalyAlertingConfigurationPatch as _AnomalyAlertingConfigurationPatch, AnomalyDetectionConfigurationPatch as _AnomalyDetectionConfigurationPatch ) From 03f5a9e6b687cf43cef75572587c3d2d304badac Mon Sep 17 00:00:00 2001 From: Xiang Yan Date: Mon, 2 Nov 2020 15:40:24 -0800 Subject: [PATCH 4/4] update --- .../azure-ai-metricsadvisor/tests/base_testcase.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/base_testcase.py b/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/base_testcase.py index bd0236ad5a06..ea34d8e0444f 100644 --- a/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/base_testcase.py +++ b/sdk/metricsadvisor/azure-ai-metricsadvisor/tests/base_testcase.py @@ -195,7 +195,7 @@ def _create_data_feed(self, name): def _create_data_feed_and_detection_config(self, name): data_feed = self._create_data_feed(name) - detection_config_name = self.create_random_name(name) + detection_config_name = create_random_name(name) detection_config = self.admin_client.create_detection_configuration( name=detection_config_name, metric_id=data_feed.metric_ids[0],