Skip to content

Commit

Permalink
Merge branch 'main' into bugfix/ordering-file-groups-with-suite-comma…
Browse files Browse the repository at this point in the history
…nd-line-args
  • Loading branch information
mkorpela authored Nov 30, 2024
2 parents a7044a6 + f6a6af8 commit 1d9d5df
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 19 deletions.
13 changes: 7 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: CI

on: [ push ]
on: [ push, pull_request ]

jobs:
build:
Expand All @@ -9,11 +9,12 @@ jobs:
matrix:
python: [ "3.8", "3.10", "3.12" ]
robotframework:
- "4.1.0"
- "5.0.0"
- "6.0.0"
- "6.1.0"
- "7.0.0"
- "4.1.3"
- "5.0.1"
- "6.0.2"
- "6.1.1"
- "7.0.1"
- "7.1.1"

steps:
- uses: actions/checkout@v4
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# Pabot

[Русская версия](README_ru.md)
[中文版](README_zh.md)

[![Version](https://img.shields.io/pypi/v/robotframework-pabot.svg)](https://pypi.python.org/pypi/robotframework-pabot)
Expand Down
7 changes: 6 additions & 1 deletion src/pabot/SharedLibrary.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import absolute_import

from robot import __version__ as ROBOT_VERSION
from robot.api import logger
from robot.libraries.BuiltIn import BuiltIn
from robot.libraries.Remote import Remote
Expand All @@ -24,7 +25,11 @@ def __init__(self, name, args=None):
logger.debug(
"Not currently running pabot. Importing library for this process."
)
self._lib = RemoteLibraryFactory(TestLibrary(name, args=args).get_instance())
self._lib = RemoteLibraryFactory(
TestLibrary.from_name(name, args=args, variables=None, create_keywords=True).instance
if ROBOT_VERSION >= "7.0"
else TestLibrary(name, args=args).get_instance()
)
return
uri = BuiltIn().get_variable_value("${PABOTLIBURI}")
logger.debug("PabotLib URI %r" % uri)
Expand Down
2 changes: 1 addition & 1 deletion src/pabot/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from __future__ import absolute_import

from .pabotlib import PabotLib
__version__ = "2.18.0"
__version__ = "3.0.1"
13 changes: 8 additions & 5 deletions src/pabot/pabot.py
Original file line number Diff line number Diff line change
Expand Up @@ -1505,7 +1505,10 @@ def invalid_xml_callback():
files, options, tests_root_name, copied_artifacts, invalid_xml_callback
)
_update_stats(resu, stats)
resu.save(output_path)
if ROBOT_VERSION >= "7.0" and options.get("legacyoutput"):
resu.save(output_path, legacy_output=True)
else:
resu.save(output_path)
return output_path


Expand Down Expand Up @@ -1772,7 +1775,7 @@ def _create_execution_items_for_dry_run(
chunk_size = (
round(len(items) / processes_count)
if len(items) > processes_count
else len(items)
else 1
)
chunked_items = list(_chunk_items(items, chunk_size))
_NUMBER_OF_ITEMS_TO_BE_EXECUTED += len(chunked_items)
Expand Down Expand Up @@ -1973,10 +1976,10 @@ def main_program(args):
def _group_suites(outs_dir, datasources, options, pabot_args):
suite_names = solve_suite_names(outs_dir, datasources, options, pabot_args)
_verify_depends(suite_names)
shard_suites = solve_shard_suites(suite_names, pabot_args)
ordered_suites = _preserve_order(shard_suites, pabot_args.get("ordering"))
ordered_suites = _preserve_order(suite_names, pabot_args.get("ordering"))
shard_suites = solve_shard_suites(ordered_suites, pabot_args)
grouped_suites = (
_chunked_suite_names(ordered_suites, pabot_args["processes"])
_chunked_suite_names(shard_suites, pabot_args["processes"])
if pabot_args["chunk"]
else _group_by_wait(_group_by_groups(ordered_suites))
)
Expand Down
4 changes: 2 additions & 2 deletions tests/mylib.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
class mylib(object):
ROBOT_LIBRARY_SCOPE = "TEST"

def __init__(self):
self.round = 0
def __init__(self, round=0):
self.round = round

def mykeyword(self):
self.round += 1
Expand Down
103 changes: 103 additions & 0 deletions tests/test_pabot.py
Original file line number Diff line number Diff line change
Expand Up @@ -1226,6 +1226,109 @@ def test_copy_output_artifacts_include_subfolders(self):
file_path = os.path.join(_opts["outputdir"], f)
self.assertTrue(os.path.isfile(file_path), "file not copied: {}".format(f))
os.remove(file_path) # clean up

def test_merge_one_run_with_and_without_legacyoutput(self):
dtemp = tempfile.mkdtemp()
# Create the same directory structure as pabot
test_outputs = os.path.join(dtemp, 'outputs')
os.makedirs(test_outputs)
test_output = os.path.join(test_outputs, 'output.xml')
# Create a minimal but valid output.xml
with open(test_output, 'w') as f:
f.write("""<?xml version="1.0" encoding="UTF-8"?>
<robot generator="Rebot 7.1.1 (Python 3.11.7 on darwin)" generated="20241130 11:19:45.235" rpa="false" schemaversion="4">
<suite id="s1" name="Suites">
<suite id="s1-s1" name="Test" source="/Users/mkorpela/workspace/pabot/test.robot">
<test id="s1-s1-t1" name="Testing" line="5">
<kw name="Log" library="BuiltIn">
<msg timestamp="20241130 11:19:44.911" level="INFO">hello</msg>
<arg>hello</arg>
<doc>Logs the given message with the given level.</doc>
<status status="PASS" starttime="20241130 11:19:44.911" endtime="20241130 11:19:44.911"/>
</kw>
<status status="PASS" starttime="20241130 11:19:44.910" endtime="20241130 11:19:44.911"/>
</test>
<status status="PASS" starttime="20241130 11:19:44.909" endtime="20241130 11:19:44.914"/>
</suite>
<suite id="s1-s2" name="Test" source="/Users/mkorpela/workspace/pabot/test.robot">
<test id="s1-s2-t1" name="Testing" line="5">
<kw name="Log" library="BuiltIn">
<msg timestamp="20241130 11:19:44.913" level="INFO">hello</msg>
<arg>hello</arg>
<doc>Logs the given message with the given level.</doc>
<status status="PASS" starttime="20241130 11:19:44.913" endtime="20241130 11:19:44.913"/>
</kw>
<status status="PASS" starttime="20241130 11:19:44.913" endtime="20241130 11:19:44.913"/>
</test>
<status status="PASS" starttime="20241130 11:19:44.912" endtime="20241130 11:19:44.914"/>
</suite>
<doc>[https://pabot.org/?ref=log|Pabot] result from 1 executions.</doc>
<status status="PASS" starttime="20241130 11:19:44.893" endtime="20241130 11:19:44.914"/>
</suite>
<statistics>
<total>
<stat pass="2" fail="0" skip="0">All Tests</stat>
</total>
<tag>
</tag>
<suite>
<stat pass="2" fail="0" skip="0" id="s1" name="Suites">Suites</stat>
<stat pass="1" fail="0" skip="0" id="s1-s1" name="Test">Suites.Test</stat>
<stat pass="1" fail="0" skip="0" id="s1-s2" name="Test">Suites.Test</stat>
</suite>
</statistics>
<errors>
<msg timestamp="20241130 11:19:44.910" level="ERROR">Error in file '/Users/mkorpela/workspace/pabot/test.robot' on line 2: Library 'Easter' expected 0 arguments, got 1.</msg>
<msg timestamp="20241130 11:19:44.913" level="ERROR">Error in file '/Users/mkorpela/workspace/pabot/test.robot' on line 2: Library 'Easter' expected 0 arguments, got 1.</msg>
</errors>
</robot>""")

self._options['outputdir'] = dtemp
if ROBOT_VERSION >= "7.0":
self._options['legacyoutput'] = True
try:
output = pabot._merge_one_run(
outs_dir=dtemp,
options=self._options,
tests_root_name='Test', # Should match suite name in XML
stats={
"total": 0,
"passed": 0,
"failed": 0,
"skipped": 0,
},
copied_artifacts=[],
outputfile='merged_output.xml') # Use different name to avoid confusion
self.assertTrue(output, "merge_one_run returned empty string") # Verify we got output path
with open(output, 'r') as f:
content = f.read()
if ROBOT_VERSION >= "6.1":
self.assertIn('schemaversion="4"', content)
elif ROBOT_VERSION >= "5.0":
self.assertIn('schemaversion="3"', content)
elif ROBOT_VERSION >= "4.0":
self.assertIn('schemaversion="2"', content)
if ROBOT_VERSION >= "7.0":
del self._options['legacyoutput']
output = pabot._merge_one_run(
outs_dir=dtemp,
options=self._options,
tests_root_name='Test', # Should match suite name in XML
stats={
"total": 0,
"passed": 0,
"failed": 0,
"skipped": 0,
},
copied_artifacts=[],
outputfile='merged_2_output.xml') # Use different name to avoid confusion
self.assertTrue(output, "merge_one_run returned empty string") # Verify we got output path
with open(output, 'r') as f:
content = f.read()
self.assertIn('schemaversion="5"', content)
self.assertNotIn('schemaversion="4"', content)
finally:
shutil.rmtree(dtemp)


if __name__ == "__main__":
Expand Down
23 changes: 20 additions & 3 deletions tests/test_pabotlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
from robot.errors import RobotError

from pabot import pabotlib
from pabot.SharedLibrary import SharedLibrary
from robot.running.context import EXECUTION_CONTEXTS
from robot.running.namespace import Namespace
from robot.running.model import TestSuite
from robot.variables import Variables
from robot import __version__ as ROBOT_VERSION


class PabotLibTests(unittest.TestCase):
Expand All @@ -23,6 +25,16 @@ def runned(*args):
pabotlib.BuiltIn = lambda: builtinmock
self.builtinmock = builtinmock

def test_shared_library_with_args(self):
try:
self._create_ctx() # Set up Robot Framework context
lib = SharedLibrary("mylib", ["2"])
self.assertIsNotNone(lib)
lib._remote = None
lib._lib.run_keyword("mykeyword", ["arg"], {})
except Exception as e:
self.fail(f"SharedLibrary initialization failed: {str(e)}")

def test_pabotlib_listener_path(self):
lib = pabotlib.PabotLib()
lib._start_suite("Suite", {"longname": "Suite"})
Expand Down Expand Up @@ -289,9 +301,14 @@ def _create_ctx(self):
suite = TestSuite()
variables = Variables()
EXECUTION_CONTEXTS._contexts = []
EXECUTION_CONTEXTS.start_suite(
suite, Namespace(variables, suite, suite.resource), self._output()
)
if ROBOT_VERSION >= "6.0":
EXECUTION_CONTEXTS.start_suite(
suite, Namespace(variables, suite, suite.resource, []), self._output()
)
else:
EXECUTION_CONTEXTS.start_suite(
suite, Namespace(variables, suite, suite.resource), self._output()
)


if __name__ == "__main__":
Expand Down

0 comments on commit 1d9d5df

Please sign in to comment.