Skip to content

Commit

Permalink
Initial #SLEEP Keyword implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
joonaskuisma committed Feb 13, 2025
1 parent a0b35eb commit 2997fc5
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 3 deletions.
3 changes: 3 additions & 0 deletions src/pabot/arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
SuiteItem,
TestItem,
WaitItem,
SleepItem,
)

ARGSMATCHER = re.compile(r"--argumentfile(\d+)")
Expand Down Expand Up @@ -219,6 +220,8 @@ def parse_execution_item_line(text): # type: (str) -> ExecutionItem
if text.startswith("DYNAMICTEST"):
suite, test = text[12:].split(" :: ")
return DynamicTestItem(test, suite)
if text.startswith("#SLEEP "):
return SleepItem(text[7:])
if text == "#WAIT":
return WaitItem()
if text == "{":
Expand Down
29 changes: 29 additions & 0 deletions src/pabot/execution_items.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class ExecutionItem(object):
isWait = False
type = None # type: str
name = None # type: str
sleep = 0 # type: int

def top_name(self):
# type: () -> str
Expand All @@ -29,6 +30,14 @@ def line(self):
# type: () -> str
return ""

def set_sleep(self, sleep_time):
# type: (int) -> None
self.sleep = sleep_time

def get_sleep(self):
# type: () -> int
return self.sleep

def modify_options_for_executor(self, options):
options[self.type] = self.name

Expand Down Expand Up @@ -82,6 +91,8 @@ def add(self, item):
)
if len(self._items) > 0:
self.name += "_"
if self.get_sleep() < item.get_sleep(): # TODO: check!
self.set_sleep(item.get_sleep())
self.name += item.name
self._element_type = item.type
self._items.append(item)
Expand Down Expand Up @@ -274,6 +285,24 @@ def line(self):
return self.name


class SleepItem(ExecutionItem):
type = "sleep"

def __init__(self, time):
try:
3600 >= int(time) >= 0 # 1h max.
except ValueError:
raise ValueError("#SLEEP value %s is not integer or in between 0 and 3600" % self.name)
self.name = time

def line(self):
return "#SLEEP " + self.name

def get_time_from_sleep_item(self):
# type: () -> int
return int(self.name) # This is already check as integer when parsing


class GroupStartItem(ExecutionItem):
type = "group"

Expand Down
47 changes: 44 additions & 3 deletions src/pabot/pabot.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import time
import traceback
import uuid
import copy
from collections import namedtuple
from contextlib import closing
from glob import glob
Expand Down Expand Up @@ -78,6 +79,7 @@
SuiteItems,
TestItem,
RunnableItem,
SleepItem,
)
from .result_merger import merge

Expand Down Expand Up @@ -262,6 +264,7 @@ def execute_and_wait_with(item):
item.index,
item.execution_item.type != "test",
process_timeout=item.timeout,
sleep_before_start=item.sleep_before_start
)
outputxml_preprocessing(
item.options, outs_dir, name, item.verbose, _make_id(), caller_id
Expand Down Expand Up @@ -320,8 +323,9 @@ def _try_execute_and_wait(
my_index=-1,
show_stdout_on_failure=False,
process_timeout=None,
sleep_before_start=0
):
# type: (List[str], str, str, bool, int, str, int, bool, Optional[int]) -> None
# type: (List[str], str, str, bool, int, str, int, bool, Optional[int], int) -> None
plib = None
is_ignored = False
if _pabotlib_in_use():
Expand All @@ -339,6 +343,7 @@ def _try_execute_and_wait(
my_index,
outs_dir,
process_timeout,
sleep_before_start
)
except:
_write(traceback.format_exc())
Expand Down Expand Up @@ -521,8 +526,16 @@ def _run(
item_index,
outs_dir,
process_timeout,
sleep_before_start,
):
# type: (List[str], IO[Any], IO[Any], str, bool, int, int, str, Optional[int]) -> Tuple[Union[subprocess.Popen[bytes], subprocess.Popen], Tuple[int, float]]
# type: (List[str], IO[Any], IO[Any], str, bool, int, int, str, Optional[int], int) -> Tuple[Union[subprocess.Popen[bytes], subprocess.Popen], Tuple[int, float]]
timestamp = datetime.datetime.now()
if sleep_before_start > 0:
_write(
"%s [%s] [ID:%s] SLEEPING %s second before starting %s"
% (timestamp, pool_id, item_index, sleep_before_start, item_name),
)
time.sleep(sleep_before_start)
timestamp = datetime.datetime.now()
cmd = " ".join(command)
if PY2:
Expand Down Expand Up @@ -757,6 +770,7 @@ def _group_by_groups(tokens):
"Ordering: Group can not contain a group. Encoutered '{'"
)
group = GroupItem()
group.set_sleep(token.get_sleep())
result.append(group)
continue
if isinstance(token, GroupEndItem):
Expand Down Expand Up @@ -1742,6 +1756,7 @@ def __init__(
self.hive = hive
self.processes = processes
self.timeout = timeout
self.sleep_before_start = execution_item.get_sleep()

@property
def index(self):
Expand Down Expand Up @@ -2058,6 +2073,8 @@ def _parse_ordering(filename): # type: (str) -> List[ExecutionItem]
]
except FileNotFoundError:
raise DataError("Error: File '%s' not found." % filename)
except ValueError as e:
raise DataError("Error in ordering file: %s: %s" % (filename, e))
except:
raise DataError("Error parsing ordering file '%s'" % filename)

Expand All @@ -2066,7 +2083,8 @@ def _group_suites(outs_dir, datasources, options, pabot_args):
suite_names = solve_suite_names(outs_dir, datasources, options, pabot_args)
_verify_depends(suite_names)
ordering_arg = _parse_ordering(pabot_args.get("ordering")) if (pabot_args.get("ordering")) is not None else None
ordered_suites = _preserve_order(suite_names, ordering_arg)
ordering_arg_with_sleep = _set_sleep_times(ordering_arg)
ordered_suites = _preserve_order(suite_names, ordering_arg_with_sleep)
shard_suites = solve_shard_suites(ordered_suites, pabot_args)
grouped_suites = (
_chunked_suite_names(shard_suites, pabot_args["processes"])
Expand All @@ -2077,6 +2095,29 @@ def _group_suites(outs_dir, datasources, options, pabot_args):
return grouped_by_depend


def _set_sleep_times(ordering_arg):
# type: (List[ExecutionItem]) -> List[ExecutionItem]
set_sleep_value = 0
in_group = False
output = copy.deepcopy(ordering_arg)
if output is not None:
if len(output) > 2:
for i in range(len(output) - 1):
if isinstance(output[i], SleepItem):
set_sleep_value = output[i].get_time_from_sleep_item()
else:
set_sleep_value = 0
if isinstance(output[i], GroupStartItem):
in_group = True
if isinstance(output[i], GroupEndItem):
in_group = False
if isinstance(output[i + 1], GroupStartItem) and set_sleep_value > 0:
output[i + 1].set_sleep(set_sleep_value)
if isinstance(output[i + 1], RunnableItem) and set_sleep_value > 0 and not in_group:
output[i + 1].set_sleep(set_sleep_value)
return output


def _chunked_suite_names(suite_names, processes):
q, r = divmod(len(suite_names), processes)
result = []
Expand Down

0 comments on commit 2997fc5

Please sign in to comment.