Skip to content

Commit 6548f0f

Browse files
[az][load] bug fixes on kvrefid splitcsv & terminal state (#8297)
* [az][load] bug fixes on kvrefid splitcsv & terminal state * [az][load] bug fixes on kvrefid splitcsv & terminal state * refactor for pylint R0912, version bump * update HISTORY text * add terminal state for aio
1 parent 50d0e1c commit 6548f0f

File tree

15 files changed

+8280
-81
lines changed

15 files changed

+8280
-81
lines changed

src/load/HISTORY.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22
33
Release History
44
===============
5+
1.3.1
6+
++++++
7+
* Bug fix for `splitAllCSVs` not being honoured from config file due to CLI argument being set as false by default leading to configuration not being selected from the config file.
8+
* Bug fix for `keyVaultReferenceIdentity` not being honoured from config file as the key being looked up while YAML parsing was incorrect.
9+
* Change 'VALIDATION_FAILED' to 'VALIDATION_FAILURE' as a terminal status for File Validation.
10+
* Add 'NOT_VALIDATED' as a terminal status for File Validation in Async IO.
11+
512
1.3.0
613
++++++
714
* Add support for autostop criteria. Autostop error rate and time window in seconds can be set using `--autostop-error-rate` and `--autostop-time-window` arguments in 'az load test create' and 'az load test update' commands. Autostop can be disabled by using `--autostop disable` in 'az load test create' and 'az load test update' commands. Autostop criteria set in YAML config file will now also be honoured.

src/load/azext_load/data_plane/load_test/custom.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,6 @@ def create_test(
6060
raise InvalidArgumentValueError(msg)
6161
body = {}
6262
yaml, yaml_test_body = None, None
63-
if split_csv is None:
64-
split_csv = False
6563
autostop_criteria = create_autostop_criteria_from_args(
6664
autostop=autostop, error_rate=autostop_error_rate, time_window=autostop_error_rate_time_window)
6765
if load_test_config_file is None:

src/load/azext_load/data_plane/utils/utils.py

Lines changed: 7 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@
44
# --------------------------------------------------------------------------------------------
55

66
import os
7-
import uuid
87
from enum import EnumMeta
98

109
import requests
1110
import yaml
12-
from azext_load.data_plane.utils import validators
11+
from azext_load.data_plane.utils import validators, utils_yaml_config
1312
from azext_load.vendored_sdks.loadtesting_mgmt import LoadTestMgmtClient
1413
from azure.cli.core.azclierror import (
1514
FileOperationError,
@@ -296,8 +295,8 @@ def convert_yaml_to_test(data):
296295
if "description" in data:
297296
new_body["description"] = data["description"]
298297
new_body["keyvaultReferenceIdentityType"] = IdentityType.SystemAssigned
299-
if "keyvaultReferenceIdentityId" in data:
300-
new_body["keyvaultReferenceIdentityId"] = data["keyvaultReferenceIdentityId"]
298+
if "keyVaultReferenceIdentity" in data:
299+
new_body["keyvaultReferenceIdentityId"] = data["keyVaultReferenceIdentity"]
301300
new_body["keyvaultReferenceIdentityType"] = IdentityType.UserAssigned
302301

303302
if "subnetId" in data:
@@ -322,62 +321,11 @@ def convert_yaml_to_test(data):
322321
"Quick start test is not supported currently in CLI. Please use portal to run quick start test"
323322
)
324323
if data.get("splitAllCSVs") is not None:
325-
new_body["loadTestConfiguration"]["splitAllCSVs"] = data.get("splitAllCSVs")
326-
324+
new_body["loadTestConfiguration"]["splitAllCSVs"] = utils_yaml_config.yaml_parse_splitcsv(data=data)
327325
if data.get("failureCriteria"):
328-
new_body["passFailCriteria"] = {}
329-
new_body["passFailCriteria"]["passFailMetrics"] = {}
330-
for items in data["failureCriteria"]:
331-
metric_id = get_random_uuid()
332-
# check if item is string or dict. if string then no name is provided
333-
name = None
334-
components = items
335-
if isinstance(items, dict):
336-
name = list(items.keys())[0]
337-
components = list(items.values())[0]
338-
# validate failure criteria
339-
try:
340-
validate_failure_criteria(components)
341-
except InvalidArgumentValueError as e:
342-
logger.error("Invalid failure criteria: %s", str(e))
343-
new_body["passFailCriteria"]["passFailMetrics"][metric_id] = {}
344-
new_body["passFailCriteria"]["passFailMetrics"][metric_id]["aggregate"] = (
345-
components.split("(")[0].strip()
346-
)
347-
new_body["passFailCriteria"]["passFailMetrics"][metric_id][
348-
"clientMetric"
349-
] = (components.split("(")[1].split(")")[0].strip())
350-
new_body["passFailCriteria"]["passFailMetrics"][metric_id]["condition"] = (
351-
components.split(")")[1].strip()[0]
352-
)
353-
new_body["passFailCriteria"]["passFailMetrics"][metric_id]["value"] = (
354-
components.split(
355-
new_body["passFailCriteria"]["passFailMetrics"][metric_id]["condition"]
356-
)[1].strip()
357-
)
358-
if name is not None:
359-
new_body["passFailCriteria"]["passFailMetrics"][metric_id][
360-
"requestName"
361-
] = name
326+
new_body["passFailCriteria"] = utils_yaml_config.yaml_parse_failure_criteria(data=data)
362327
if data.get("autoStop") is not None:
363-
if (isinstance(data["autoStop"], str)):
364-
# pylint: disable-next=protected-access
365-
validators._validate_autostop_disable_configfile(data["autoStop"])
366-
new_body["autoStopCriteria"] = {
367-
"autoStopDisabled": True,
368-
}
369-
else:
370-
error_rate = data["autoStop"].get("errorPercentage")
371-
time_window = data["autoStop"].get("timeWindow")
372-
# pylint: disable-next=protected-access
373-
validators._validate_autostop_criteria_configfile(error_rate, time_window)
374-
new_body["autoStopCriteria"] = {
375-
"autoStopDisabled": False,
376-
}
377-
if error_rate is not None:
378-
new_body["autoStopCriteria"]["errorRate"] = error_rate
379-
if time_window is not None:
380-
new_body["autoStopCriteria"]["errorRateTimeWindowInSeconds"] = time_window
328+
new_body["autoStopCriteria"] = utils_yaml_config.yaml_parse_autostop_criteria(data=data)
381329
logger.debug("Converted yaml to test body: %s", new_body)
382330
return new_body
383331

@@ -421,7 +369,7 @@ def create_or_update_test_with_config(
421369
new_body["keyvaultReferenceIdentityType"] = IdentityType.UserAssigned
422370
elif yaml_test_body.get("keyvaultReferenceIdentityId") is not None:
423371
new_body["keyvaultReferenceIdentityId"] = yaml_test_body.get(
424-
"keyVaultReferenceIdentity"
372+
"keyvaultReferenceIdentityId"
425373
)
426374
new_body["keyvaultReferenceIdentityType"] = IdentityType.UserAssigned
427375
else:
@@ -802,20 +750,3 @@ def upload_files_helper(
802750
client=client,
803751
test_id=test_id, yaml_data=yaml_data, test_plan=test_plan,
804752
load_test_config_file=load_test_config_file, existing_test_files=files, wait=wait)
805-
806-
807-
def validate_failure_criteria(failure_criteria):
808-
parts = failure_criteria.split("(")
809-
if len(parts) != 2:
810-
raise ValueError(f"Invalid failure criteria: {failure_criteria}")
811-
_, condition_value = parts
812-
if (
813-
")" not in condition_value
814-
or len(condition_value.split(")")) != 2
815-
or condition_value.endswith(")")
816-
):
817-
raise ValueError(f"Invalid failure criteria: {failure_criteria}")
818-
819-
820-
def get_random_uuid():
821-
return str(uuid.uuid4())
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# --------------------------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for license information.
4+
# --------------------------------------------------------------------------------------------
5+
6+
import uuid
7+
8+
from azext_load.data_plane.utils import validators
9+
from azure.cli.core.azclierror import (
10+
InvalidArgumentValueError,
11+
)
12+
13+
from knack.log import get_logger
14+
15+
logger = get_logger(__name__)
16+
17+
18+
def yaml_parse_autostop_criteria(data):
19+
if (isinstance(data["autoStop"], str)):
20+
# pylint: disable-next=protected-access
21+
validators._validate_autostop_disable_configfile(data["autoStop"])
22+
return {
23+
"autoStopDisabled": True,
24+
}
25+
error_rate = data["autoStop"].get("errorPercentage")
26+
time_window = data["autoStop"].get("timeWindow")
27+
# pylint: disable-next=protected-access
28+
validators._validate_autostop_criteria_configfile(error_rate, time_window)
29+
autostop_criteria = {
30+
"autoStopDisabled": False,
31+
}
32+
if error_rate is not None:
33+
autostop_criteria["errorRate"] = error_rate
34+
if time_window is not None:
35+
autostop_criteria["errorRateTimeWindowInSeconds"] = time_window
36+
return autostop_criteria
37+
38+
39+
def yaml_parse_splitcsv(data):
40+
if not isinstance(data.get("splitAllCSVs"), bool):
41+
raise InvalidArgumentValueError(
42+
"Invalid value for splitAllCSVs. Allowed values are boolean true or false"
43+
)
44+
return data.get("splitAllCSVs")
45+
46+
47+
def validate_failure_criteria(failure_criteria):
48+
parts = failure_criteria.split("(")
49+
if len(parts) != 2:
50+
raise ValueError(f"Invalid failure criteria: {failure_criteria}")
51+
_, condition_value = parts
52+
if (
53+
")" not in condition_value
54+
or len(condition_value.split(")")) != 2
55+
or condition_value.endswith(")")
56+
):
57+
raise ValueError(f"Invalid failure criteria: {failure_criteria}")
58+
59+
60+
def get_random_uuid():
61+
return str(uuid.uuid4())
62+
63+
64+
def yaml_parse_failure_criteria(data):
65+
passfail_criteria = {}
66+
passfail_criteria["passFailMetrics"] = {}
67+
for items in data["failureCriteria"]:
68+
metric_id = get_random_uuid()
69+
# check if item is string or dict. if string then no name is provided
70+
name = None
71+
components = items
72+
if isinstance(items, dict):
73+
name = list(items.keys())[0]
74+
components = list(items.values())[0]
75+
# validate failure criteria
76+
try:
77+
validate_failure_criteria(components)
78+
except InvalidArgumentValueError as e:
79+
logger.error("Invalid failure criteria: %s", str(e))
80+
passfail_criteria["passFailMetrics"][metric_id] = {}
81+
passfail_criteria["passFailMetrics"][metric_id]["aggregate"] = (
82+
components.split("(")[0].strip()
83+
)
84+
passfail_criteria["passFailMetrics"][metric_id][
85+
"clientMetric"
86+
] = (components.split("(")[1].split(")")[0].strip())
87+
passfail_criteria["passFailMetrics"][metric_id]["condition"] = (
88+
components.split(")")[1].strip()[0]
89+
)
90+
passfail_criteria["passFailMetrics"][metric_id]["value"] = (
91+
components.split(
92+
passfail_criteria["passFailMetrics"][metric_id]["condition"]
93+
)[1].strip()
94+
)
95+
if name is not None:
96+
passfail_criteria["passFailMetrics"][metric_id][
97+
"requestName"
98+
] = name
99+
return passfail_criteria

src/load/azext_load/tests/latest/constants.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ class LoadConstants:
1919
INVALID_ZIP_ARTIFACT_LOAD_TEST_CONFIG_FILE = os.path.join(
2020
TEST_RESOURCES_DIR, r"invalid-config-with-zip-artifacts.yaml"
2121
)
22+
LOAD_TEST_CONFIG_FILE_KVREFID = os.path.join(TEST_RESOURCES_DIR, r"config-kvrefid.yaml")
23+
LOAD_TEST_CONFIG_FILE_INVALID_KVREFID = os.path.join(TEST_RESOURCES_DIR, r"config-invalid-kvrefid.yaml")
24+
LOAD_TEST_CONFIG_FILE_SPLITCSV_FALSE = os.path.join(TEST_RESOURCES_DIR, r"config-splitcsv-false.yaml")
25+
LOAD_TEST_CONFIG_FILE_INVALID_SPLITCSV = os.path.join(TEST_RESOURCES_DIR, r"config-invalid-splitcsv.yaml")
2226
TEST_PLAN = os.path.join(TEST_RESOURCES_DIR, r"sample-JMX-file.jmx")
2327
ADDITIONAL_FILE = os.path.join(TEST_RESOURCES_DIR, r"additional-data.csv")
2428
FILE_NAME = "sample-JMX-file.jmx"
@@ -98,6 +102,8 @@ class LoadTestConstants(LoadConstants):
98102
APP_COMPONENT_TEST_ID = "app-component-test-case"
99103
SERVER_METRIC_TEST_ID = "server-metric-test-case"
100104
FILE_TEST_ID = "file-test-case"
105+
LOAD_TEST_KVREF_ID = "loadtest-kvrefid-case"
106+
LOAD_TEST_SPLITCSV_ID = "loadtest-splitcsv-case"
101107

102108
INVALID_UPDATE_TEST_ID = "invalid-update-test-case"
103109
INVALID_PF_TEST_ID = "invalid-pf-test-case"

0 commit comments

Comments
 (0)