Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/healthbot/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
Release History
===============

1.1.0
++++++
* Fix issue where new tiers were not being recognized.

1.0.0
++++++
* GA with additional tiers.
Expand Down
17 changes: 17 additions & 0 deletions src/healthbot/azext_healthbot/manual/_help.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------

from knack.help_files import helps


helps['healthbot update'] = """
type: command
short-summary: "Patch a HealthBot."
examples:
- name: BotUpdate
text: |-
az healthbot update --name "samplebotname" --sku "F0" --resource-group "healthbotClient"
"""
29 changes: 29 additions & 0 deletions src/healthbot/azext_healthbot/manual/_params.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
#
# Code generated by Microsoft (R) AutoRest Code Generator.
# Changes may cause incorrect behavior and will be lost if the code is
# regenerated.
# --------------------------------------------------------------------------
# pylint: disable=too-many-lines
# pylint: disable=too-many-statements

from azure.cli.core.commands.parameters import get_enum_type


def load_arguments(self, _):

# Only override the SKU argument where its behavior differs from the generated parameters.
with self.argument_context('healthbot create') as c:
c.argument('sku',
arg_type=get_enum_type(['F0', 'C0', 'C1', 'PES']),
help='The name of the HealthBot SKU',
arg_group='Sku')

with self.argument_context('healthbot update') as c:
c.argument('sku',
arg_type=get_enum_type(['F0', 'C0', 'C1', 'PES']),
help='The name of the HealthBot SKU',
arg_group='Sku')
19 changes: 19 additions & 0 deletions src/healthbot/azext_healthbot/manual/custom.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------


def healthbot_update(client,
resource_group_name,
bot_name,
tags=None,
sku=None):
parameters = {}
parameters['tags'] = tags
if sku is not None:
parameters['sku'] = {'name': sku}
return client.update(resource_group_name=resource_group_name,
bot_name=bot_name,
parameters=parameters)
109 changes: 0 additions & 109 deletions src/healthbot/azext_healthbot/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,116 +1,7 @@
# coding=utf-8
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
#
# Code generated by Microsoft (R) AutoRest Code Generator.
# Changes may cause incorrect behavior and will be lost if the code is
# regenerated.
# --------------------------------------------------------------------------
import inspect
import logging
import os
import sys
import traceback
import datetime as dt

from azure.core.exceptions import AzureError
from azure.cli.testsdk.exceptions import CliTestError, CliExecutionError, JMESPathCheckAssertionError


logger = logging.getLogger('azure.cli.testsdk')
logger.addHandler(logging.StreamHandler())
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
exceptions = []
test_map = dict()
SUCCESSED = "successed"
FAILED = "failed"


def try_manual(func):
def import_manual_function(origin_func):
from importlib import import_module
decorated_path = inspect.getfile(origin_func).lower()
module_path = __path__[0].lower()
if not decorated_path.startswith(module_path):
raise Exception("Decorator can only be used in submodules!")
manual_path = os.path.join(
decorated_path[module_path.rfind(os.path.sep) + 1:])
manual_file_path, manual_file_name = os.path.split(manual_path)
module_name, _ = os.path.splitext(manual_file_name)
manual_module = "..manual." + \
".".join(manual_file_path.split(os.path.sep) + [module_name, ])
return getattr(import_module(manual_module, package=__name__), origin_func.__name__)

def get_func_to_call():
func_to_call = func
try:
func_to_call = import_manual_function(func)
logger.info("Found manual override for %s(...)", func.__name__)
except (ImportError, AttributeError):
pass
return func_to_call

def wrapper(*args, **kwargs):
func_to_call = get_func_to_call()
logger.info("running %s()...", func.__name__)
try:
test_map[func.__name__] = dict()
test_map[func.__name__]["result"] = SUCCESSED
test_map[func.__name__]["error_message"] = ""
test_map[func.__name__]["error_stack"] = ""
test_map[func.__name__]["error_normalized"] = ""
test_map[func.__name__]["start_dt"] = dt.datetime.utcnow()
ret = func_to_call(*args, **kwargs)
except (AssertionError, AzureError, CliTestError, CliExecutionError, SystemExit,
JMESPathCheckAssertionError) as e:
use_exception_cache = os.getenv("TEST_EXCEPTION_CACHE")
if use_exception_cache is None or use_exception_cache.lower() != "true":
raise
test_map[func.__name__]["end_dt"] = dt.datetime.utcnow()
test_map[func.__name__]["result"] = FAILED
test_map[func.__name__]["error_message"] = str(e).replace("\r\n", " ").replace("\n", " ")[:500]
test_map[func.__name__]["error_stack"] = traceback.format_exc().replace(
"\r\n", " ").replace("\n", " ")[:500]
logger.info("--------------------------------------")
logger.info("step exception: %s", e)
logger.error("--------------------------------------")
logger.error("step exception in %s: %s", func.__name__, e)
logger.info(traceback.format_exc())
exceptions.append((func.__name__, sys.exc_info()))
else:
test_map[func.__name__]["end_dt"] = dt.datetime.utcnow()
return ret

if inspect.isclass(func):
return get_func_to_call()
return wrapper


def calc_coverage(filename):
filename = filename.split(".")[0]
coverage_name = filename + "_coverage.md"
with open(coverage_name, "w") as f:
f.write("|Scenario|Result|ErrorMessage|ErrorStack|ErrorNormalized|StartDt|EndDt|\n")
total = len(test_map)
covered = 0
for k, v in test_map.items():
if not k.startswith("step_"):
total -= 1
continue
if v["result"] == SUCCESSED:
covered += 1
f.write("|{step_name}|{result}|{error_message}|{error_stack}|{error_normalized}|{start_dt}|"
"{end_dt}|\n".format(step_name=k, **v))
f.write("Coverage: {}/{}\n".format(covered, total))
print("Create coverage\n", file=sys.stderr)


def raise_if():
if exceptions:
if len(exceptions) <= 1:
raise exceptions[0][1][1]
message = "{}\nFollowed with exceptions in other steps:\n".format(str(exceptions[0][1][1]))
message += "\n".join(["{}: {}".format(h[0], h[1][1]) for h in exceptions[1:]])
raise exceptions[0][1][0](message).with_traceback(exceptions[0][1][2])
118 changes: 90 additions & 28 deletions src/healthbot/azext_healthbot/tests/latest/example_steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,23 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
#
# Code generated by Microsoft (R) AutoRest Code Generator.
# Changes may cause incorrect behavior and will be lost if the code is
# regenerated.
# --------------------------------------------------------------------------


from .. import try_manual


# EXAMPLE: /Bots/put/BotCreate
@try_manual
def step_create(test, rg, rg_2, checks=None):
def step_create_with_sku(test, rg, sku, checks=None):
if checks is None:
checks = []
test.cmd('az healthbot create '
'--name "{myBot}" '
'--location "eastus" '
'--sku "F0" '
'--resource-group "{rg}"',
test.cmd(f'az healthbot create '
f'--name "{{myBot}}" '
f'--location "eastus" '
f'--sku "{sku}" '
f'--resource-group "{{rg}}"',
checks=checks)


# EXAMPLE: /Bots/get/List Bots by Resource Group
@try_manual
def step_list(test, rg, rg_2, checks=None):
def step_list(test, rg, checks=None):
if checks is None:
checks = []
test.cmd('az healthbot list '
Expand All @@ -36,18 +27,15 @@ def step_list(test, rg, rg_2, checks=None):


# EXAMPLE: /Bots/get/List Bots by Subscription
@try_manual
def step_list2(test, rg, rg_2, checks=None):
def step_list2(test, rg, checks=None):
if checks is None:
checks = []
test.cmd('az healthbot list '
'-g ""',
test.cmd('az healthbot list',
checks=checks)


# EXAMPLE: /Bots/get/ResourceInfoGet
@try_manual
def step_show(test, rg, rg_2, checks=None):
def step_show(test, rg, checks=None):
if checks is None:
checks = []
test.cmd('az healthbot show '
Expand All @@ -57,23 +45,97 @@ def step_show(test, rg, rg_2, checks=None):


# EXAMPLE: /Bots/patch/BotUpdate
@try_manual
def step_update(test, rg, rg_2, checks=None):
def step_update_with_sku(test, rg, sku, checks=None):
if checks is None:
checks = []
test.cmd(f'az healthbot update '
f'--name "{{myBot}}" '
f'--sku "{sku}" '
f'--resource-group "{{rg}}"',
checks=checks)


# EXAMPLE: /Bots/delete/BotDelete
def step_delete(test, rg, checks=None):
if checks is None:
checks = []
test.cmd('az healthbot delete -y '
'--name "{myBot}" '
'--resource-group "{rg}"',
checks=checks)


# Boundary value: update with tags only, no --sku (sku=None)
def step_update_tags_only(test, rg, checks=None):
if checks is None:
checks = []
test.cmd('az healthbot update '
'--name "{myBot}" '
'--tags testkey=testvalue '
'--resource-group "{rg}"',
checks=checks)


# Boundary value: update with empty tags (tags='')
def step_update_empty_tags(test, rg, checks=None):
if checks is None:
checks = []
test.cmd('az healthbot update '
'--name "{myBot}" '
'--tags '
'--resource-group "{rg}"',
checks=checks)


# Boundary value: create with empty bot name (bot_name='')
def step_create_empty_name(test, rg, checks=None):
if checks is None:
checks = []
test.cmd('az healthbot create '
'--name "" '
'--location "eastus" '
'--sku "F0" '
'--resource-group "{rg}"',
checks=checks,
expect_failure=True)


# Boundary value: create with tags
def step_create_with_tags(test, rg, sku, checks=None):
if checks is None:
checks = []
test.cmd(f'az healthbot create '
f'--name "{{myBot}}" '
f'--location "eastus" '
f'--sku "{sku}" '
f'--tags env=test '
f'--resource-group "{{rg}}"',
checks=checks)


# EXAMPLE: /Bots/delete/BotDelete
@try_manual
def step_delete(test, rg, rg_2, checks=None):
# Boundary value: list with empty resource group (boundary: empty string)
def step_list_empty_rg(test, rg, checks=None):
if checks is None:
checks = []
test.cmd('az healthbot list '
'-g ""',
checks=checks)


# Wait for provisioning to complete
def step_wait_for_provisioned(test, rg):
test.cmd('az healthbot wait '
'--name "{myBot}" '
'--resource-group "{rg}" '
'--updated')


# Boundary value: delete with --no-wait (no_wait=True)
def step_delete_no_wait(test, rg, checks=None):
if checks is None:
checks = []
test.cmd('az healthbot delete -y '
'--name "{myBot}" '
'--resource-group "{rg}"',
'--resource-group "{rg}" '
'--no-wait',
checks=checks)
Loading
Loading