Skip to content
This repository was archived by the owner on Apr 7, 2022. It is now read-only.
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
13 changes: 11 additions & 2 deletions cfme/configure/configuration/system_schedules.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from cfme.utils.appliance.implementations.ui import navigator
from cfme.utils.pretty import Pretty
from cfme.utils.update import Updateable
from widgetastic_manageiq import AttributeValueForm
from widgetastic_manageiq import Calendar
from widgetastic_manageiq import Checkbox
from widgetastic_manageiq import Dropdown
Expand Down Expand Up @@ -59,6 +60,7 @@ class ScheduleAddEditEntities(View):
request = Input(name='object_request')
object_type = BootstrapSelect('target_class')
object_selection = BootstrapSelect('target_id')
attribute_value_pairs = AttributeValueForm("attribute_", "value_")


class ScheduleAllView(ConfigurationView):
Expand Down Expand Up @@ -196,6 +198,9 @@ class SystemSchedule(BaseEntity, Updateable, Pretty):
# Samba backup config
samba_username = attr.ib(default=None)
samba_password = attr.ib(default=None)
# Automation Task
request = attr.ib(default=None)
attribute_value_pairs = attr.ib(default=None)

def update(self, updates, reset=False, cancel=False):
""" Modify an existing schedule with informations from this instance.
Expand Down Expand Up @@ -309,7 +314,8 @@ class SystemSchedulesCollection(BaseCollection):
def create(self, name, description, active=True, action_type=None, run_type=None,
run_every=None, time_zone=None, start_date=None, start_hour=None, start_minute=None,
filter_level1=None, filter_level2=None, backup_type=None, depot_name=None, uri=None,
samba_username=None, samba_password=None, cancel=False):
samba_username=None, samba_password=None, cancel=False, request=None,
attribute_value_pairs=None):
""" Create a new schedule from the informations stored in the object.

Args:
Expand Down Expand Up @@ -343,6 +349,8 @@ def create(self, name, description, active=True, action_type=None, run_type=None
'samba_password': samba_password,
'samba_password_verify': samba_password
})
elif action_type == "Automation Tasks":
details.update({"request": request, "attribute_value_pairs": attribute_value_pairs})
else:
details.update({
'items_analysis': {
Expand All @@ -364,7 +372,8 @@ def create(self, name, description, active=True, action_type=None, run_type=None
start_minute=start_minute, filter_level1=filter_level1,
filter_level2=filter_level2, backup_type=backup_type,
depot_name=depot_name, uri=uri, samba_username=samba_username,
samba_password=samba_password)
samba_password=samba_password, request=request,
attribute_value_pairs=attribute_value_pairs)
return schedule


Expand Down
19 changes: 19 additions & 0 deletions cfme/fixtures/automate.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import fauxfactory
import pytest
import pytz
from dateutil import parser

from cfme.utils.conf import cfme_data
from cfme.utils.ftp import FTPClientWrapper
Expand Down Expand Up @@ -108,3 +110,20 @@ def test_foo(import_datastore, import_data):
domain.enabled = True
yield domain
domain.delete_if_exists()


@pytest.fixture
def current_server_time(appliance):
current_time = parser.parse(appliance.ssh_client.run_command('date').output)
tz_list = appliance.ssh_client.run_command("timedatectl | grep 'Time zone'") \
.output.strip().split(' ')

tz_name = tz_list[2]
tz_num = tz_list[-1][:-1]
date = current_time.replace(tzinfo=pytz.timezone(tz_name))
return date, tz_num


def round_min(value, base=5):
round_value = int(base * round(float(value) / base))
return 0 if round_value == 60 else round_value
36 changes: 0 additions & 36 deletions cfme/tests/automate/test_automate_manual.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,42 +287,6 @@ def test_git_refresh_with_rapid_updates():
pass


@pytest.mark.tier(2)
@pytest.mark.meta(coverage=[1713072, 1745197])
def test_automate_task_schedule():
"""
Polarion:
assignee: dgaikwad
initialEstimate: 1/8h
caseposneg: positive
casecomponent: Automate
setup:
1. Create domain, namespace, class and instance
2. Also create automate method with below ruby code:
>> $evm.log(:info, "Hello World")
testSteps:
1. Go to Configuration > Settings > Zones > Schedules
2. Create schedule with required fields:
>> Action - Automation Tasks
>> Object Details(Request) - Call_Instance
>> Attribute/Value Pairs
>> domain - domain_name
>> namespace - namespace_name
>> class - class_name
>> instance - instance_name
>> Timer Options
3. Check automation logs
expectedResults:
1.
2.
3. Automate method should be executed on scheduled time.

Bugzilla:
1713072
"""
pass


@pytest.mark.tier(2)
@pytest.mark.meta(coverage=[1743227])
def test_queue_up_schedule_run_now():
Expand Down
117 changes: 117 additions & 0 deletions cfme/tests/automate/test_method.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

import fauxfactory
import pytest
from dateutil import relativedelta

from . import tag_delete_from_category
from cfme import test_requirements
from cfme.automate.explorer.klass import ClassDetailsView
from cfme.automate.simulation import simulate
from cfme.fixtures.automate import round_min
from cfme.rest.gen_data import users as _users
from cfme.services.service_catalogs import ServiceCatalogs
from cfme.utils.appliance.implementations.rest import ViaREST
Expand All @@ -21,6 +23,34 @@
pytestmark = [test_requirements.automate, pytest.mark.tier(2)]


@pytest.fixture
def custom_automate_setup(domain, namespace):
auto_class = namespace.classes.create(
name=fauxfactory.gen_alphanumeric(15, start="class_"),
display_name=fauxfactory.gen_alpha(),
description=fauxfactory.gen_alpha(),
)

method = auto_class.methods.create(
name=fauxfactory.gen_alphanumeric(15, start="method_"),
location="inline",
script='$evm.log(:info, "Hello World")',
)
schema_field = {
"name": fauxfactory.gen_alphanumeric(15, start="schema_"),
"type": "Method",
"data_type": "String",
}
auto_class.schema.add_fields(schema_field)

instance = auto_class.instances.create(
name=fauxfactory.gen_alphanumeric(15, start="instance_"),
fields={schema_field["name"]: {"value": method.name}},
)
yield domain, namespace, auto_class, instance
auto_class.delete()


@pytest.fixture(scope='function')
def original_class(domain):
# Take the 'Request' class and copy it for own purpose.
Expand Down Expand Up @@ -797,3 +827,90 @@ def test_delete_tag_from_category(custom_instance):
"instance": instance.name,
},
)


@pytest.mark.customer_scenario
@pytest.mark.meta(automate=[1713072, 1745197])
def test_automate_task_schedule(appliance, custom_automate_setup, current_server_time, request):
"""
Polarion:
assignee: dgaikwad
initialEstimate: 1/8h
caseposneg: positive
casecomponent: Automate
setup:
1. Create domain, namespace, class and instance
2. Also create automate method with below ruby code:
>> $evm.log(:info, "Hello World")
testSteps:
1. Go to Configuration > Settings > Zones > Schedules
2. Create schedule with required fields:
>> Action - Automation Tasks
>> Object Details(Request) - Call_Instance
>> Attribute/Value Pairs
>> domain - domain_name
>> namespace - namespace_name
>> class - class_name
>> instance - instance_name
>> Timer Options
3. Check automation logs more than 1 times
expectedResults:
1.
2.
3. Automate method should be executed on scheduled time.

Bugzilla:
1713072
"""
domain, namespace, auto_class, instance = custom_automate_setup
current_time, tz_num = current_server_time
start_date = current_time + relativedelta.relativedelta(minutes=5)
view = navigate_to(appliance.collections.system_schedules, 'Add')
available_list = view.form.time_zone.all_options
tz_select = next(tz.text for tz in available_list if f'{tz_num[0:3]}:00'in tz.text)
if round_min(start_date.minute) == 0:
start_date = start_date + relativedelta.relativedelta(minutes=60 - start_date.minute)
start_date_minute = str(start_date.minute)
else:
start_date_minute = str(round_min(start_date.minute))

attribute_value_pairs = {
"domain": domain.name,
"namespace": namespace.name,
"class": auto_class.name,
"instance": instance.name,
}

schedule = appliance.collections.system_schedules.create(
name=fauxfactory.gen_alphanumeric(),
description=fauxfactory.gen_alphanumeric(),
action_type="Automation Tasks",
request="Call_Instance",
attribute_value_pairs=attribute_value_pairs,
run_type="Hourly",
time_zone=tz_select,
start_hour=str(start_date.hour),
start_minute=start_date_minute,
)

@request.addfinalizer
def _finalize():
try:
schedule.delete_if_exists()
except TypeError:
# Delete failing only on PRT with type error
pass

matched_pattern = ".*INFO.* : Q-task_id.* Hello World"

def _check_automation_log():
log = LogValidator("/var/www/miq/vmdb/log/automation.log",
matched_patterns=[matched_pattern]
)
log.start_monitoring()
log.validate(wait="15m")

_check_automation_log()
next_run_date = start_date + relativedelta.relativedelta(minutes=-5, hours=1)
appliance.ssh_client.run_command(f"date {next_run_date.strftime('%m%d%H%M%Y')}")
_check_automation_log()
19 changes: 1 addition & 18 deletions cfme/tests/configure/test_schedule_operations.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import fauxfactory
import pytest
import pytz
from dateutil import parser
from dateutil import relativedelta

from cfme import test_requirements
from cfme.base.ui import BaseLoggedInPage
from cfme.fixtures.automate import round_min
from cfme.infrastructure.provider.virtualcenter import VMwareProvider
from cfme.markers.env_markers.provider import ONE
from cfme.utils.appliance.implementations.ui import navigate_to
Expand Down Expand Up @@ -37,23 +37,6 @@ def host_with_credentials(appliance, provider):
host.remove_credentials_rest()


@pytest.fixture
def current_server_time(appliance):
current_time = parser.parse(appliance.ssh_client.run_command('date').output)
tz_list = appliance.ssh_client.run_command("timedatectl | grep 'Time zone'") \
.output.strip().split(' ')

tz_name = tz_list[2]
tz_num = tz_list[-1][:-1]
date = current_time.replace(tzinfo=pytz.timezone(tz_name))
return date, tz_num


def round_min(value, base=5):
return (0 if int(base * round(float(value) / base)) == 60
else int(base * round(float(value) / base)))


def test_schedule_crud(appliance, current_server_time):
"""
Polarion:
Expand Down
14 changes: 11 additions & 3 deletions widgetastic_manageiq/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3155,10 +3155,16 @@ class fields(ParametrizedView): # noqa
PARAMETERS = ("id",)

attribute = Input(
locator=ParametrizedLocator(".//input[@id=concat({@attr_prefix|quote}, {id|quote})]")
locator=ParametrizedLocator(
"(.//input[@id=concat({@attr_prefix|quote}, {id|quote})])|"
"(.//div[./label[contains((.),{id|quote})]]//input[contains(@ng-model,'0')])"
)
)
value = Input(
locator=ParametrizedLocator(".//input[@id=concat({@val_prefix|quote}, {id|quote})]")
locator=ParametrizedLocator(
"(.//input[@id=concat({@val_prefix|quote}, {id|quote})])|"
"(.//div[./label[contains((.),{id|quote})]]//input[contains(@ng-model,'1')])"
)
)

@property
Expand All @@ -3172,7 +3178,9 @@ def val_prefix(self):
# TODO: Figure out how to smuggle some extra data to the all classmethod
# TODO: since it is now impossible to pass the attr_prefix to it.

ATTRIBUTES = ParametrizedLocator(".//input[starts-with(@id, {@attr_prefix|quote})]")
ATTRIBUTES = ParametrizedLocator(
"(.//input[starts-with(@id, {@attr_prefix|quote})])|(.//input[contains(@ng-model, '0')])"
)

def __init__(self, parent, attr_prefix, val_prefix, start=1, end=5, logger=None):
View.__init__(self, parent, logger=logger)
Expand Down