robotframework-pabot 4.1.1__tar.gz → 4.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {robotframework_pabot-4.1.1/src/robotframework_pabot.egg-info → robotframework_pabot-4.2.0}/PKG-INFO +60 -9
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/README.md +57 -7
- robotframework_pabot-4.2.0/pyproject.toml +3 -0
- robotframework_pabot-4.2.0/setup.py +14 -0
- robotframework_pabot-4.2.0/src/pabot/__init__.py +10 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/src/pabot/arguments.py +5 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/src/pabot/execution_items.py +28 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/src/pabot/pabot.py +59 -3
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0/src/robotframework_pabot.egg-info}/PKG-INFO +60 -9
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/src/robotframework_pabot.egg-info/SOURCES.txt +1 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/tests/test_ordering.py +70 -0
- robotframework_pabot-4.2.0/tests/test_suite_structure.py +232 -0
- robotframework_pabot-4.1.1/pyproject.toml +0 -3
- robotframework_pabot-4.1.1/setup.py +0 -5
- robotframework_pabot-4.1.1/src/pabot/__init__.py +0 -5
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/LICENSE.txt +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/MANIFEST.in +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/setup.cfg +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/src/pabot/SharedLibrary.py +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/src/pabot/clientwrapper.py +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/src/pabot/coordinatorwrapper.py +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/src/pabot/pabotlib.py +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/src/pabot/py3/__init__.py +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/src/pabot/py3/client.py +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/src/pabot/py3/coordinator.py +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/src/pabot/py3/messages.py +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/src/pabot/py3/worker.py +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/src/pabot/result_merger.py +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/src/pabot/robotremoteserver.py +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/src/pabot/workerwrapper.py +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/src/robotframework_pabot.egg-info/dependency_links.txt +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/src/robotframework_pabot.egg-info/entry_points.txt +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/src/robotframework_pabot.egg-info/requires.txt +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/src/robotframework_pabot.egg-info/top_level.txt +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/tests/test_arguments_output.py +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/tests/test_basic_arguments.py +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/tests/test_depends.py +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/tests/test_functional.py +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/tests/test_pabot.py +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/tests/test_pabotlib.py +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/tests/test_pabotprerunmodifier.py +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/tests/test_pabotsuitenames_io.py +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/tests/test_prerunmodifier.py +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/tests/test_resultmerger.py +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/tests/test_stacktrace.py +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/tests/test_testlevelsplit_include.py +0 -0
- {robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/tests/test_testlevelsplit_output_task_order.py +0 -0
{robotframework_pabot-4.1.1/src/robotframework_pabot.egg-info → robotframework_pabot-4.2.0}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: robotframework-pabot
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.2.0
|
|
4
4
|
Summary: Parallel test runner for Robot Framework
|
|
5
5
|
Home-page: https://pabot.org
|
|
6
6
|
Download-URL: https://pypi.python.org/pypi/robotframework-pabot
|
|
@@ -22,6 +22,7 @@ Requires-Dist: robotframework>=3.2
|
|
|
22
22
|
Requires-Dist: robotframework-stacktrace>=0.4.1
|
|
23
23
|
Requires-Dist: natsort>=8.2.0
|
|
24
24
|
Dynamic: download-url
|
|
25
|
+
Dynamic: license-file
|
|
25
26
|
|
|
26
27
|
# Pabot
|
|
27
28
|
|
|
@@ -88,9 +89,10 @@ pabot [--verbose|--testlevelsplit|--command .. --end-command|
|
|
|
88
89
|
--processtimeout num|
|
|
89
90
|
--shard i/n|
|
|
90
91
|
--artifacts extensions|--artifactsinsubfolders|
|
|
91
|
-
--resourcefile file|--argumentfile[num] file|--suitesfrom file|--ordering file
|
|
92
|
-
--chunk
|
|
93
|
-
--pabotprerunmodifier modifier
|
|
92
|
+
--resourcefile file|--argumentfile[num] file|--suitesfrom file|--ordering file|
|
|
93
|
+
--chunk|
|
|
94
|
+
--pabotprerunmodifier modifier|
|
|
95
|
+
--no-rebot|
|
|
94
96
|
--help|--version]
|
|
95
97
|
[robot options] [path ...]
|
|
96
98
|
|
|
@@ -178,11 +180,16 @@ Supports all [Robot Framework command line options](https://robotframework.org/r
|
|
|
178
180
|
pabot subprocesses. Depending on the intended use, this may be desirable as well as more efficient. Can be used, for
|
|
179
181
|
example, to modify the list of tests to be performed.
|
|
180
182
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
+
--no-rebot
|
|
184
|
+
If specified, the tests will execute as usual, but Rebot will not be called to merge the logs. This option is designed
|
|
185
|
+
for scenarios where Rebot should be run later due to large log files, ensuring better memory and resource availability.
|
|
186
|
+
Subprocess results are stored in the pabot_results folder.
|
|
187
|
+
|
|
188
|
+
--help
|
|
189
|
+
Print usage instructions.
|
|
183
190
|
|
|
184
|
-
|
|
185
|
-
|
|
191
|
+
--version
|
|
192
|
+
Print version information.
|
|
186
193
|
|
|
187
194
|
Example usages:
|
|
188
195
|
|
|
@@ -284,6 +291,50 @@ There different possibilities to influence the execution:
|
|
|
284
291
|
--test robotTest.1 Scalar.Test With Arguments and Return Values
|
|
285
292
|
--test robotTest.3 Dictionary.Test with Dictionaries as Arguments
|
|
286
293
|
--test robotTest.3 Dictionary.Test with FOR loops and Dictionaries #DEPENDS robotTest.1 Scalar.Test Case with Return Values
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
* By using the command `#SLEEP X`, where `X` is an integer in the range [0-3600] (in seconds), you can
|
|
297
|
+
define a startup delay for each subprocess. `#SLEEP` affects the next line unless the next line starts a
|
|
298
|
+
group with `{`, in which case the delay applies to the entire group. If the next line begins with `--test`
|
|
299
|
+
or `--suite`, the delay is applied to that specific item. Any other occurrences of `#SLEEP` are ignored.
|
|
300
|
+
|
|
301
|
+
The following example clarifies the behavior:
|
|
302
|
+
|
|
303
|
+
```sh
|
|
304
|
+
pabot --process 2 --ordering order.txt data_1
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
where order.txt is:
|
|
308
|
+
|
|
309
|
+
```
|
|
310
|
+
#SLEEP 1
|
|
311
|
+
{
|
|
312
|
+
#SLEEP 2
|
|
313
|
+
--suite Data 1.suite A
|
|
314
|
+
#SLEEP 3
|
|
315
|
+
--suite Data 1.suite B
|
|
316
|
+
#SLEEP 4
|
|
317
|
+
}
|
|
318
|
+
#SLEEP 5
|
|
319
|
+
#SLEEP 6
|
|
320
|
+
--suite Data 1.suite C
|
|
321
|
+
#SLEEP 7
|
|
322
|
+
--suite Data 1.suite D
|
|
323
|
+
#SLEEP 8
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
prints something like this:
|
|
327
|
+
|
|
328
|
+
```
|
|
329
|
+
2025-02-15 19:15:00.408321 [0] [ID:1] SLEEPING 6 SECONDS BEFORE STARTING Data 1.suite C
|
|
330
|
+
2025-02-15 19:15:00.408321 [1] [ID:0] SLEEPING 1 SECONDS BEFORE STARTING Group_Data 1.suite A_Data 1.suite B
|
|
331
|
+
2025-02-15 19:15:01.409389 [PID:52008] [1] [ID:0] EXECUTING Group_Data 1.suite A_Data 1.suite B
|
|
332
|
+
2025-02-15 19:15:06.409024 [PID:1528] [0] [ID:1] EXECUTING Data 1.suite C
|
|
333
|
+
2025-02-15 19:15:09.257564 [PID:52008] [1] [ID:0] PASSED Group_Data 1.suite A_Data 1.suite B in 7.8 seconds
|
|
334
|
+
2025-02-15 19:15:09.259067 [1] [ID:2] SLEEPING 7 SECONDS BEFORE STARTING Data 1.suite D
|
|
335
|
+
2025-02-15 19:15:09.647342 [PID:1528] [0] [ID:1] PASSED Data 1.suite C in 3.2 seconds
|
|
336
|
+
2025-02-15 19:15:16.260432 [PID:48156] [1] [ID:2] EXECUTING Data 1.suite D
|
|
337
|
+
2025-02-15 19:15:18.696420 [PID:48156] [1] [ID:2] PASSED Data 1.suite D in 2.4 seconds
|
|
287
338
|
```
|
|
288
339
|
|
|
289
340
|
### Programmatic use
|
|
@@ -63,9 +63,10 @@ pabot [--verbose|--testlevelsplit|--command .. --end-command|
|
|
|
63
63
|
--processtimeout num|
|
|
64
64
|
--shard i/n|
|
|
65
65
|
--artifacts extensions|--artifactsinsubfolders|
|
|
66
|
-
--resourcefile file|--argumentfile[num] file|--suitesfrom file|--ordering file
|
|
67
|
-
--chunk
|
|
68
|
-
--pabotprerunmodifier modifier
|
|
66
|
+
--resourcefile file|--argumentfile[num] file|--suitesfrom file|--ordering file|
|
|
67
|
+
--chunk|
|
|
68
|
+
--pabotprerunmodifier modifier|
|
|
69
|
+
--no-rebot|
|
|
69
70
|
--help|--version]
|
|
70
71
|
[robot options] [path ...]
|
|
71
72
|
|
|
@@ -153,11 +154,16 @@ Supports all [Robot Framework command line options](https://robotframework.org/r
|
|
|
153
154
|
pabot subprocesses. Depending on the intended use, this may be desirable as well as more efficient. Can be used, for
|
|
154
155
|
example, to modify the list of tests to be performed.
|
|
155
156
|
|
|
156
|
-
|
|
157
|
-
|
|
157
|
+
--no-rebot
|
|
158
|
+
If specified, the tests will execute as usual, but Rebot will not be called to merge the logs. This option is designed
|
|
159
|
+
for scenarios where Rebot should be run later due to large log files, ensuring better memory and resource availability.
|
|
160
|
+
Subprocess results are stored in the pabot_results folder.
|
|
161
|
+
|
|
162
|
+
--help
|
|
163
|
+
Print usage instructions.
|
|
158
164
|
|
|
159
|
-
|
|
160
|
-
|
|
165
|
+
--version
|
|
166
|
+
Print version information.
|
|
161
167
|
|
|
162
168
|
Example usages:
|
|
163
169
|
|
|
@@ -259,6 +265,50 @@ There different possibilities to influence the execution:
|
|
|
259
265
|
--test robotTest.1 Scalar.Test With Arguments and Return Values
|
|
260
266
|
--test robotTest.3 Dictionary.Test with Dictionaries as Arguments
|
|
261
267
|
--test robotTest.3 Dictionary.Test with FOR loops and Dictionaries #DEPENDS robotTest.1 Scalar.Test Case with Return Values
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
* By using the command `#SLEEP X`, where `X` is an integer in the range [0-3600] (in seconds), you can
|
|
271
|
+
define a startup delay for each subprocess. `#SLEEP` affects the next line unless the next line starts a
|
|
272
|
+
group with `{`, in which case the delay applies to the entire group. If the next line begins with `--test`
|
|
273
|
+
or `--suite`, the delay is applied to that specific item. Any other occurrences of `#SLEEP` are ignored.
|
|
274
|
+
|
|
275
|
+
The following example clarifies the behavior:
|
|
276
|
+
|
|
277
|
+
```sh
|
|
278
|
+
pabot --process 2 --ordering order.txt data_1
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
where order.txt is:
|
|
282
|
+
|
|
283
|
+
```
|
|
284
|
+
#SLEEP 1
|
|
285
|
+
{
|
|
286
|
+
#SLEEP 2
|
|
287
|
+
--suite Data 1.suite A
|
|
288
|
+
#SLEEP 3
|
|
289
|
+
--suite Data 1.suite B
|
|
290
|
+
#SLEEP 4
|
|
291
|
+
}
|
|
292
|
+
#SLEEP 5
|
|
293
|
+
#SLEEP 6
|
|
294
|
+
--suite Data 1.suite C
|
|
295
|
+
#SLEEP 7
|
|
296
|
+
--suite Data 1.suite D
|
|
297
|
+
#SLEEP 8
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
prints something like this:
|
|
301
|
+
|
|
302
|
+
```
|
|
303
|
+
2025-02-15 19:15:00.408321 [0] [ID:1] SLEEPING 6 SECONDS BEFORE STARTING Data 1.suite C
|
|
304
|
+
2025-02-15 19:15:00.408321 [1] [ID:0] SLEEPING 1 SECONDS BEFORE STARTING Group_Data 1.suite A_Data 1.suite B
|
|
305
|
+
2025-02-15 19:15:01.409389 [PID:52008] [1] [ID:0] EXECUTING Group_Data 1.suite A_Data 1.suite B
|
|
306
|
+
2025-02-15 19:15:06.409024 [PID:1528] [0] [ID:1] EXECUTING Data 1.suite C
|
|
307
|
+
2025-02-15 19:15:09.257564 [PID:52008] [1] [ID:0] PASSED Group_Data 1.suite A_Data 1.suite B in 7.8 seconds
|
|
308
|
+
2025-02-15 19:15:09.259067 [1] [ID:2] SLEEPING 7 SECONDS BEFORE STARTING Data 1.suite D
|
|
309
|
+
2025-02-15 19:15:09.647342 [PID:1528] [0] [ID:1] PASSED Data 1.suite C in 3.2 seconds
|
|
310
|
+
2025-02-15 19:15:16.260432 [PID:48156] [1] [ID:2] EXECUTING Data 1.suite D
|
|
311
|
+
2025-02-15 19:15:18.696420 [PID:48156] [1] [ID:2] PASSED Data 1.suite D in 2.4 seconds
|
|
262
312
|
```
|
|
263
313
|
|
|
264
314
|
### Programmatic use
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
|
|
3
|
+
from setuptools import setup
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
# Add src to path so that version can be imported
|
|
8
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))
|
|
9
|
+
from pabot import __version__
|
|
10
|
+
|
|
11
|
+
setup(
|
|
12
|
+
name="robotframework-pabot",
|
|
13
|
+
version=__version__,
|
|
14
|
+
)
|
|
@@ -16,6 +16,7 @@ from .execution_items import (
|
|
|
16
16
|
SuiteItem,
|
|
17
17
|
TestItem,
|
|
18
18
|
WaitItem,
|
|
19
|
+
SleepItem,
|
|
19
20
|
)
|
|
20
21
|
|
|
21
22
|
ARGSMATCHER = re.compile(r"--argumentfile(\d+)")
|
|
@@ -91,6 +92,7 @@ def _parse_pabot_args(args): # type: (List[str]) -> Tuple[List[str], Dict[str,
|
|
|
91
92
|
"shardindex": 0,
|
|
92
93
|
"shardcount": 1,
|
|
93
94
|
"chunk": False,
|
|
95
|
+
"no-rebot": False,
|
|
94
96
|
}
|
|
95
97
|
# Explicitly define argument types for validation
|
|
96
98
|
flag_args = {
|
|
@@ -100,6 +102,7 @@ def _parse_pabot_args(args): # type: (List[str]) -> Tuple[List[str], Dict[str,
|
|
|
100
102
|
"pabotlib",
|
|
101
103
|
"artifactsinsubfolders",
|
|
102
104
|
"chunk",
|
|
105
|
+
"no-rebot"
|
|
103
106
|
}
|
|
104
107
|
value_args = {
|
|
105
108
|
"hive": str,
|
|
@@ -217,6 +220,8 @@ def parse_execution_item_line(text): # type: (str) -> ExecutionItem
|
|
|
217
220
|
if text.startswith("DYNAMICTEST"):
|
|
218
221
|
suite, test = text[12:].split(" :: ")
|
|
219
222
|
return DynamicTestItem(test, suite)
|
|
223
|
+
if text.startswith("#SLEEP "):
|
|
224
|
+
return SleepItem(text[7:])
|
|
220
225
|
if text == "#WAIT":
|
|
221
226
|
return WaitItem()
|
|
222
227
|
if text == "{":
|
|
@@ -12,6 +12,7 @@ class ExecutionItem(object):
|
|
|
12
12
|
isWait = False
|
|
13
13
|
type = None # type: str
|
|
14
14
|
name = None # type: str
|
|
15
|
+
sleep = 0 # type: int
|
|
15
16
|
|
|
16
17
|
def top_name(self):
|
|
17
18
|
# type: () -> str
|
|
@@ -29,6 +30,14 @@ class ExecutionItem(object):
|
|
|
29
30
|
# type: () -> str
|
|
30
31
|
return ""
|
|
31
32
|
|
|
33
|
+
def set_sleep(self, sleep_time):
|
|
34
|
+
# type: (int) -> None
|
|
35
|
+
self.sleep = sleep_time
|
|
36
|
+
|
|
37
|
+
def get_sleep(self):
|
|
38
|
+
# type: () -> int
|
|
39
|
+
return self.sleep
|
|
40
|
+
|
|
32
41
|
def modify_options_for_executor(self, options):
|
|
33
42
|
options[self.type] = self.name
|
|
34
43
|
|
|
@@ -82,6 +91,8 @@ class GroupItem(ExecutionItem):
|
|
|
82
91
|
)
|
|
83
92
|
if len(self._items) > 0:
|
|
84
93
|
self.name += "_"
|
|
94
|
+
if self.get_sleep() < item.get_sleep(): # TODO: check!
|
|
95
|
+
self.set_sleep(item.get_sleep())
|
|
85
96
|
self.name += item.name
|
|
86
97
|
self._element_type = item.type
|
|
87
98
|
self._items.append(item)
|
|
@@ -274,6 +285,23 @@ class WaitItem(ExecutionItem):
|
|
|
274
285
|
return self.name
|
|
275
286
|
|
|
276
287
|
|
|
288
|
+
class SleepItem(ExecutionItem):
|
|
289
|
+
type = "sleep"
|
|
290
|
+
|
|
291
|
+
def __init__(self, time):
|
|
292
|
+
try:
|
|
293
|
+
assert 3600 >= int(time) >= 0 # 1 h max.
|
|
294
|
+
self.name = time
|
|
295
|
+
self.sleep = int(time)
|
|
296
|
+
except ValueError:
|
|
297
|
+
raise ValueError("#SLEEP value %s is not integer" % time)
|
|
298
|
+
except AssertionError:
|
|
299
|
+
raise ValueError("#SLEEP value %s is not in between 0 and 3600" % time)
|
|
300
|
+
|
|
301
|
+
def line(self):
|
|
302
|
+
return "#SLEEP " + self.name
|
|
303
|
+
|
|
304
|
+
|
|
277
305
|
class GroupStartItem(ExecutionItem):
|
|
278
306
|
type = "group"
|
|
279
307
|
|
|
@@ -41,6 +41,7 @@ import threading
|
|
|
41
41
|
import time
|
|
42
42
|
import traceback
|
|
43
43
|
import uuid
|
|
44
|
+
import copy
|
|
44
45
|
from collections import namedtuple
|
|
45
46
|
from contextlib import closing
|
|
46
47
|
from glob import glob
|
|
@@ -78,6 +79,7 @@ from .execution_items import (
|
|
|
78
79
|
SuiteItems,
|
|
79
80
|
TestItem,
|
|
80
81
|
RunnableItem,
|
|
82
|
+
SleepItem,
|
|
81
83
|
)
|
|
82
84
|
from .result_merger import merge
|
|
83
85
|
|
|
@@ -262,6 +264,7 @@ def execute_and_wait_with(item):
|
|
|
262
264
|
item.index,
|
|
263
265
|
item.execution_item.type != "test",
|
|
264
266
|
process_timeout=item.timeout,
|
|
267
|
+
sleep_before_start=item.sleep_before_start
|
|
265
268
|
)
|
|
266
269
|
outputxml_preprocessing(
|
|
267
270
|
item.options, outs_dir, name, item.verbose, _make_id(), caller_id
|
|
@@ -320,8 +323,9 @@ def _try_execute_and_wait(
|
|
|
320
323
|
my_index=-1,
|
|
321
324
|
show_stdout_on_failure=False,
|
|
322
325
|
process_timeout=None,
|
|
326
|
+
sleep_before_start=0
|
|
323
327
|
):
|
|
324
|
-
# type: (List[str], str, str, bool, int, str, int, bool, Optional[int]) -> None
|
|
328
|
+
# type: (List[str], str, str, bool, int, str, int, bool, Optional[int], int) -> None
|
|
325
329
|
plib = None
|
|
326
330
|
is_ignored = False
|
|
327
331
|
if _pabotlib_in_use():
|
|
@@ -339,6 +343,7 @@ def _try_execute_and_wait(
|
|
|
339
343
|
my_index,
|
|
340
344
|
outs_dir,
|
|
341
345
|
process_timeout,
|
|
346
|
+
sleep_before_start
|
|
342
347
|
)
|
|
343
348
|
except:
|
|
344
349
|
_write(traceback.format_exc())
|
|
@@ -521,8 +526,16 @@ def _run(
|
|
|
521
526
|
item_index,
|
|
522
527
|
outs_dir,
|
|
523
528
|
process_timeout,
|
|
529
|
+
sleep_before_start,
|
|
524
530
|
):
|
|
525
|
-
# type: (List[str], IO[Any], IO[Any], str, bool, int, int, str, Optional[int]) -> Tuple[Union[subprocess.Popen[bytes], subprocess.Popen], Tuple[int, float]]
|
|
531
|
+
# 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]]
|
|
532
|
+
timestamp = datetime.datetime.now()
|
|
533
|
+
if sleep_before_start > 0:
|
|
534
|
+
_write(
|
|
535
|
+
"%s [%s] [ID:%s] SLEEPING %s SECONDS BEFORE STARTING %s"
|
|
536
|
+
% (timestamp, pool_id, item_index, sleep_before_start, item_name),
|
|
537
|
+
)
|
|
538
|
+
time.sleep(sleep_before_start)
|
|
526
539
|
timestamp = datetime.datetime.now()
|
|
527
540
|
cmd = " ".join(command)
|
|
528
541
|
if PY2:
|
|
@@ -757,6 +770,7 @@ def _group_by_groups(tokens):
|
|
|
757
770
|
"Ordering: Group can not contain a group. Encoutered '{'"
|
|
758
771
|
)
|
|
759
772
|
group = GroupItem()
|
|
773
|
+
group.set_sleep(token.get_sleep())
|
|
760
774
|
result.append(group)
|
|
761
775
|
continue
|
|
762
776
|
if isinstance(token, GroupEndItem):
|
|
@@ -935,6 +949,13 @@ def solve_suite_names(outs_dir, datasources, options, pabot_args):
|
|
|
935
949
|
)
|
|
936
950
|
execution_item_lines = [parse_execution_item_line(l) for l in lines[4:]]
|
|
937
951
|
if corrupted or h != file_h or file_hash != hash_of_file or pabot_args.get("pabotprerunmodifier"):
|
|
952
|
+
if file_h[0] != h[0] and file_h[2] == h[2]:
|
|
953
|
+
suite_names = _levelsplit(
|
|
954
|
+
generate_suite_names_with_builder(outs_dir, datasources, options),
|
|
955
|
+
pabot_args,
|
|
956
|
+
)
|
|
957
|
+
store_suite_names(h, suite_names)
|
|
958
|
+
return suite_names
|
|
938
959
|
return _regenerate(
|
|
939
960
|
file_h,
|
|
940
961
|
h,
|
|
@@ -1735,6 +1756,7 @@ class QueueItem(object):
|
|
|
1735
1756
|
self.hive = hive
|
|
1736
1757
|
self.processes = processes
|
|
1737
1758
|
self.timeout = timeout
|
|
1759
|
+
self.sleep_before_start = execution_item.get_sleep()
|
|
1738
1760
|
|
|
1739
1761
|
@property
|
|
1740
1762
|
def index(self):
|
|
@@ -2002,6 +2024,14 @@ def main_program(args):
|
|
|
2002
2024
|
opts_for_run,
|
|
2003
2025
|
pabot_args,
|
|
2004
2026
|
)
|
|
2027
|
+
if pabot_args["no-rebot"]:
|
|
2028
|
+
_write((
|
|
2029
|
+
"All tests were executed, but the --no-rebot argument was given, "
|
|
2030
|
+
"so the results were not compiled, and no summary was generated. "
|
|
2031
|
+
f"All results have been saved in the {os.path.join(os.path.curdir, 'pabot_results')} folder."
|
|
2032
|
+
))
|
|
2033
|
+
_write("===================================================")
|
|
2034
|
+
return 0 if not _ABNORMAL_EXIT_HAPPENED else 252
|
|
2005
2035
|
result_code = _report_results(
|
|
2006
2036
|
outs_dir,
|
|
2007
2037
|
pabot_args,
|
|
@@ -2043,6 +2073,8 @@ def _parse_ordering(filename): # type: (str) -> List[ExecutionItem]
|
|
|
2043
2073
|
]
|
|
2044
2074
|
except FileNotFoundError:
|
|
2045
2075
|
raise DataError("Error: File '%s' not found." % filename)
|
|
2076
|
+
except ValueError as e:
|
|
2077
|
+
raise DataError("Error in ordering file: %s: %s" % (filename, e))
|
|
2046
2078
|
except:
|
|
2047
2079
|
raise DataError("Error parsing ordering file '%s'" % filename)
|
|
2048
2080
|
|
|
@@ -2051,7 +2083,8 @@ def _group_suites(outs_dir, datasources, options, pabot_args):
|
|
|
2051
2083
|
suite_names = solve_suite_names(outs_dir, datasources, options, pabot_args)
|
|
2052
2084
|
_verify_depends(suite_names)
|
|
2053
2085
|
ordering_arg = _parse_ordering(pabot_args.get("ordering")) if (pabot_args.get("ordering")) is not None else None
|
|
2054
|
-
|
|
2086
|
+
ordering_arg_with_sleep = _set_sleep_times(ordering_arg)
|
|
2087
|
+
ordered_suites = _preserve_order(suite_names, ordering_arg_with_sleep)
|
|
2055
2088
|
shard_suites = solve_shard_suites(ordered_suites, pabot_args)
|
|
2056
2089
|
grouped_suites = (
|
|
2057
2090
|
_chunked_suite_names(shard_suites, pabot_args["processes"])
|
|
@@ -2062,6 +2095,29 @@ def _group_suites(outs_dir, datasources, options, pabot_args):
|
|
|
2062
2095
|
return grouped_by_depend
|
|
2063
2096
|
|
|
2064
2097
|
|
|
2098
|
+
def _set_sleep_times(ordering_arg):
|
|
2099
|
+
# type: (List[ExecutionItem]) -> List[ExecutionItem]
|
|
2100
|
+
set_sleep_value = 0
|
|
2101
|
+
in_group = False
|
|
2102
|
+
output = copy.deepcopy(ordering_arg)
|
|
2103
|
+
if output is not None:
|
|
2104
|
+
if len(output) >= 2:
|
|
2105
|
+
for i in range(len(output) - 1):
|
|
2106
|
+
if isinstance(output[i], SleepItem):
|
|
2107
|
+
set_sleep_value = output[i].get_sleep()
|
|
2108
|
+
else:
|
|
2109
|
+
set_sleep_value = 0
|
|
2110
|
+
if isinstance(output[i], GroupStartItem):
|
|
2111
|
+
in_group = True
|
|
2112
|
+
if isinstance(output[i], GroupEndItem):
|
|
2113
|
+
in_group = False
|
|
2114
|
+
if isinstance(output[i + 1], GroupStartItem) and set_sleep_value > 0:
|
|
2115
|
+
output[i + 1].set_sleep(set_sleep_value)
|
|
2116
|
+
if isinstance(output[i + 1], RunnableItem) and set_sleep_value > 0 and not in_group:
|
|
2117
|
+
output[i + 1].set_sleep(set_sleep_value)
|
|
2118
|
+
return output
|
|
2119
|
+
|
|
2120
|
+
|
|
2065
2121
|
def _chunked_suite_names(suite_names, processes):
|
|
2066
2122
|
q, r = divmod(len(suite_names), processes)
|
|
2067
2123
|
result = []
|
{robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0/src/robotframework_pabot.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: robotframework-pabot
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.2.0
|
|
4
4
|
Summary: Parallel test runner for Robot Framework
|
|
5
5
|
Home-page: https://pabot.org
|
|
6
6
|
Download-URL: https://pypi.python.org/pypi/robotframework-pabot
|
|
@@ -22,6 +22,7 @@ Requires-Dist: robotframework>=3.2
|
|
|
22
22
|
Requires-Dist: robotframework-stacktrace>=0.4.1
|
|
23
23
|
Requires-Dist: natsort>=8.2.0
|
|
24
24
|
Dynamic: download-url
|
|
25
|
+
Dynamic: license-file
|
|
25
26
|
|
|
26
27
|
# Pabot
|
|
27
28
|
|
|
@@ -88,9 +89,10 @@ pabot [--verbose|--testlevelsplit|--command .. --end-command|
|
|
|
88
89
|
--processtimeout num|
|
|
89
90
|
--shard i/n|
|
|
90
91
|
--artifacts extensions|--artifactsinsubfolders|
|
|
91
|
-
--resourcefile file|--argumentfile[num] file|--suitesfrom file|--ordering file
|
|
92
|
-
--chunk
|
|
93
|
-
--pabotprerunmodifier modifier
|
|
92
|
+
--resourcefile file|--argumentfile[num] file|--suitesfrom file|--ordering file|
|
|
93
|
+
--chunk|
|
|
94
|
+
--pabotprerunmodifier modifier|
|
|
95
|
+
--no-rebot|
|
|
94
96
|
--help|--version]
|
|
95
97
|
[robot options] [path ...]
|
|
96
98
|
|
|
@@ -178,11 +180,16 @@ Supports all [Robot Framework command line options](https://robotframework.org/r
|
|
|
178
180
|
pabot subprocesses. Depending on the intended use, this may be desirable as well as more efficient. Can be used, for
|
|
179
181
|
example, to modify the list of tests to be performed.
|
|
180
182
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
+
--no-rebot
|
|
184
|
+
If specified, the tests will execute as usual, but Rebot will not be called to merge the logs. This option is designed
|
|
185
|
+
for scenarios where Rebot should be run later due to large log files, ensuring better memory and resource availability.
|
|
186
|
+
Subprocess results are stored in the pabot_results folder.
|
|
187
|
+
|
|
188
|
+
--help
|
|
189
|
+
Print usage instructions.
|
|
183
190
|
|
|
184
|
-
|
|
185
|
-
|
|
191
|
+
--version
|
|
192
|
+
Print version information.
|
|
186
193
|
|
|
187
194
|
Example usages:
|
|
188
195
|
|
|
@@ -284,6 +291,50 @@ There different possibilities to influence the execution:
|
|
|
284
291
|
--test robotTest.1 Scalar.Test With Arguments and Return Values
|
|
285
292
|
--test robotTest.3 Dictionary.Test with Dictionaries as Arguments
|
|
286
293
|
--test robotTest.3 Dictionary.Test with FOR loops and Dictionaries #DEPENDS robotTest.1 Scalar.Test Case with Return Values
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
* By using the command `#SLEEP X`, where `X` is an integer in the range [0-3600] (in seconds), you can
|
|
297
|
+
define a startup delay for each subprocess. `#SLEEP` affects the next line unless the next line starts a
|
|
298
|
+
group with `{`, in which case the delay applies to the entire group. If the next line begins with `--test`
|
|
299
|
+
or `--suite`, the delay is applied to that specific item. Any other occurrences of `#SLEEP` are ignored.
|
|
300
|
+
|
|
301
|
+
The following example clarifies the behavior:
|
|
302
|
+
|
|
303
|
+
```sh
|
|
304
|
+
pabot --process 2 --ordering order.txt data_1
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
where order.txt is:
|
|
308
|
+
|
|
309
|
+
```
|
|
310
|
+
#SLEEP 1
|
|
311
|
+
{
|
|
312
|
+
#SLEEP 2
|
|
313
|
+
--suite Data 1.suite A
|
|
314
|
+
#SLEEP 3
|
|
315
|
+
--suite Data 1.suite B
|
|
316
|
+
#SLEEP 4
|
|
317
|
+
}
|
|
318
|
+
#SLEEP 5
|
|
319
|
+
#SLEEP 6
|
|
320
|
+
--suite Data 1.suite C
|
|
321
|
+
#SLEEP 7
|
|
322
|
+
--suite Data 1.suite D
|
|
323
|
+
#SLEEP 8
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
prints something like this:
|
|
327
|
+
|
|
328
|
+
```
|
|
329
|
+
2025-02-15 19:15:00.408321 [0] [ID:1] SLEEPING 6 SECONDS BEFORE STARTING Data 1.suite C
|
|
330
|
+
2025-02-15 19:15:00.408321 [1] [ID:0] SLEEPING 1 SECONDS BEFORE STARTING Group_Data 1.suite A_Data 1.suite B
|
|
331
|
+
2025-02-15 19:15:01.409389 [PID:52008] [1] [ID:0] EXECUTING Group_Data 1.suite A_Data 1.suite B
|
|
332
|
+
2025-02-15 19:15:06.409024 [PID:1528] [0] [ID:1] EXECUTING Data 1.suite C
|
|
333
|
+
2025-02-15 19:15:09.257564 [PID:52008] [1] [ID:0] PASSED Group_Data 1.suite A_Data 1.suite B in 7.8 seconds
|
|
334
|
+
2025-02-15 19:15:09.259067 [1] [ID:2] SLEEPING 7 SECONDS BEFORE STARTING Data 1.suite D
|
|
335
|
+
2025-02-15 19:15:09.647342 [PID:1528] [0] [ID:1] PASSED Data 1.suite C in 3.2 seconds
|
|
336
|
+
2025-02-15 19:15:16.260432 [PID:48156] [1] [ID:2] EXECUTING Data 1.suite D
|
|
337
|
+
2025-02-15 19:15:18.696420 [PID:48156] [1] [ID:2] PASSED Data 1.suite D in 2.4 seconds
|
|
287
338
|
```
|
|
288
339
|
|
|
289
340
|
### Programmatic use
|
|
@@ -192,3 +192,73 @@ class PabotOrderingGroupTest(unittest.TestCase):
|
|
|
192
192
|
self.assertIn(b"PASSED", stdout, stderr)
|
|
193
193
|
self.assertNotIn(b"FAILED", stdout, stderr)
|
|
194
194
|
self.assertEqual(stdout.count(b"PASSED"), 2)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class PabotOrderingSleepTest(unittest.TestCase):
|
|
198
|
+
def setUp(self):
|
|
199
|
+
self.tmpdir = tempfile.mkdtemp()
|
|
200
|
+
|
|
201
|
+
def tearDown(self):
|
|
202
|
+
shutil.rmtree(self.tmpdir)
|
|
203
|
+
|
|
204
|
+
def _run_tests_with(self, testfile, orderfile):
|
|
205
|
+
robot_file = open("{}/test.robot".format(self.tmpdir), "w")
|
|
206
|
+
robot_file.write(textwrap.dedent(testfile))
|
|
207
|
+
robot_file.close()
|
|
208
|
+
with open("{}/order.dat".format(self.tmpdir), "w") as f:
|
|
209
|
+
f.write(textwrap.dedent(orderfile))
|
|
210
|
+
process = subprocess.Popen(
|
|
211
|
+
[
|
|
212
|
+
sys.executable,
|
|
213
|
+
"-m" "pabot.pabot",
|
|
214
|
+
"--testlevelsplit",
|
|
215
|
+
"--ordering",
|
|
216
|
+
"{}/order.dat".format(self.tmpdir),
|
|
217
|
+
"{}/test.robot".format(self.tmpdir),
|
|
218
|
+
],
|
|
219
|
+
cwd=self.tmpdir,
|
|
220
|
+
stdout=subprocess.PIPE,
|
|
221
|
+
stderr=subprocess.PIPE,
|
|
222
|
+
)
|
|
223
|
+
return process.communicate()
|
|
224
|
+
|
|
225
|
+
def test_sleep_test_cases_and_group(self):
|
|
226
|
+
stdout, stderr = self._run_tests_with(
|
|
227
|
+
"""
|
|
228
|
+
*** Test Cases ***
|
|
229
|
+
Test Case A
|
|
230
|
+
Log Hello!
|
|
231
|
+
|
|
232
|
+
Test Case B
|
|
233
|
+
Log Hello!
|
|
234
|
+
|
|
235
|
+
Test Case C
|
|
236
|
+
Log Hello!
|
|
237
|
+
|
|
238
|
+
Test Case D
|
|
239
|
+
Log Hello!
|
|
240
|
+
""",
|
|
241
|
+
"""
|
|
242
|
+
#SLEEP 1
|
|
243
|
+
{
|
|
244
|
+
#SLEEP 4
|
|
245
|
+
--test Test.Test Case A
|
|
246
|
+
#SLEEP 4
|
|
247
|
+
--test Test.Test Case B
|
|
248
|
+
#SLEEP 4
|
|
249
|
+
}
|
|
250
|
+
#SLEEP 4
|
|
251
|
+
#SLEEP 3
|
|
252
|
+
--test Test.Test Case C
|
|
253
|
+
#SLEEP 2
|
|
254
|
+
--test Test.Test Case D
|
|
255
|
+
#SLEEP 4
|
|
256
|
+
""",
|
|
257
|
+
)
|
|
258
|
+
self.assertIn(b"PASSED", stdout, stderr)
|
|
259
|
+
self.assertNotIn(b"FAILED", stdout, stderr)
|
|
260
|
+
self.assertEqual(stdout.count(b"PASSED"), 3)
|
|
261
|
+
self.assertIn(b"SLEEPING 1 SECONDS BEFORE STARTING Group_Test.Test Case A_Test.Test Case B", stdout, stderr)
|
|
262
|
+
self.assertIn(b"SLEEPING 3 SECONDS BEFORE STARTING Test.Test Case C", stdout, stderr)
|
|
263
|
+
self.assertIn(b"SLEEPING 2 SECONDS BEFORE STARTING Test.Test Case D", stdout, stderr)
|
|
264
|
+
self.assertNotIn(b"SLEEPING 4", stdout, stderr)
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import tempfile
|
|
3
|
+
import textwrap
|
|
4
|
+
import shutil
|
|
5
|
+
import subprocess
|
|
6
|
+
import sys
|
|
7
|
+
import os
|
|
8
|
+
from test_pabotprerunmodifier import get_tmpdir_name
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class SuiteStructureTests(unittest.TestCase):
|
|
12
|
+
@classmethod
|
|
13
|
+
def setUpClass(cls):
|
|
14
|
+
cls.tmpdir = tempfile.mkdtemp()
|
|
15
|
+
cls.tmpdir_name = get_tmpdir_name(os.path.basename(cls.tmpdir))
|
|
16
|
+
|
|
17
|
+
# robot case files
|
|
18
|
+
cls.robot_file_path_1 = f'{cls.tmpdir}/dir_1/suite_1.robot'
|
|
19
|
+
cls.robot_file_path_2 = f'{cls.tmpdir}/dir_1/dir_2/suite_2.robot'
|
|
20
|
+
cls.robot_file_path_3 = f'{cls.tmpdir}/dir_1/dir_2/dir_3/suite_3.robot'
|
|
21
|
+
cls.robot_file_path_4 = f'{cls.tmpdir}/dir_1/dir_2/dir_3/dir_4/suite_4.robot'
|
|
22
|
+
|
|
23
|
+
cls.robot_dir_1 = os.path.dirname(cls.robot_file_path_1)
|
|
24
|
+
cls.robot_dir_2 = os.path.dirname(cls.robot_file_path_2)
|
|
25
|
+
cls.robot_dir_3 = os.path.dirname(cls.robot_file_path_3)
|
|
26
|
+
cls.robot_dir_4 = os.path.dirname(cls.robot_file_path_4)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
os.makedirs(os.path.dirname(cls.robot_file_path_4), exist_ok=True)
|
|
30
|
+
with open(cls.robot_file_path_1, 'w') as robot_file:
|
|
31
|
+
robot_file.write(
|
|
32
|
+
textwrap.dedent("""
|
|
33
|
+
*** Test Cases ***
|
|
34
|
+
Testing 1 1
|
|
35
|
+
Log hello
|
|
36
|
+
"""))
|
|
37
|
+
|
|
38
|
+
with open(cls.robot_file_path_2, 'w') as robot_file:
|
|
39
|
+
robot_file.write(
|
|
40
|
+
textwrap.dedent("""
|
|
41
|
+
*** Test Cases ***
|
|
42
|
+
Testing 2 1
|
|
43
|
+
Log hello
|
|
44
|
+
"""))
|
|
45
|
+
|
|
46
|
+
with open(cls.robot_file_path_3, 'w') as robot_file:
|
|
47
|
+
robot_file.write(
|
|
48
|
+
textwrap.dedent("""
|
|
49
|
+
*** Test Cases ***
|
|
50
|
+
Testing 3 1
|
|
51
|
+
Log hello
|
|
52
|
+
"""))
|
|
53
|
+
|
|
54
|
+
with open(cls.robot_file_path_4, 'w') as robot_file:
|
|
55
|
+
robot_file.write(
|
|
56
|
+
textwrap.dedent("""
|
|
57
|
+
*** Test Cases ***
|
|
58
|
+
Testing 4 1
|
|
59
|
+
[Tags] tag
|
|
60
|
+
Log hello
|
|
61
|
+
"""))
|
|
62
|
+
|
|
63
|
+
@classmethod
|
|
64
|
+
def tearDownClass(cls):
|
|
65
|
+
shutil.rmtree(cls.tmpdir)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def tearDown(self):
|
|
69
|
+
""" Deletes .pabotsuitenames ja output.xml files between tests. """
|
|
70
|
+
for filename in [".pabotsuitenames", "output.xml"]:
|
|
71
|
+
file_path = os.path.join(self.tmpdir, filename)
|
|
72
|
+
if os.path.exists(file_path):
|
|
73
|
+
os.remove(file_path)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def test_run_root_then_suite_4_then_dir_1_then_dir_4(self):
|
|
77
|
+
process_root_1 = subprocess.Popen(
|
|
78
|
+
[
|
|
79
|
+
sys.executable,
|
|
80
|
+
"-m", "pabot.pabot",
|
|
81
|
+
self.tmpdir
|
|
82
|
+
],
|
|
83
|
+
cwd=self.tmpdir,
|
|
84
|
+
stdout=subprocess.PIPE,
|
|
85
|
+
stderr=subprocess.PIPE
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
stdout, stderr = process_root_1.communicate()
|
|
89
|
+
self.assertIn(b'4 tests, 4 passed, 0 failed, 0 skipped.', stdout)
|
|
90
|
+
self.assertEqual(b"", stderr)
|
|
91
|
+
self.assertIn(f'PASSED {self.tmpdir_name}.Dir 1.Suite 1'.encode('utf-8'), stdout)
|
|
92
|
+
self.assertIn(f'PASSED {self.tmpdir_name}.Dir 1.Dir 2.Suite 2'.encode('utf-8'), stdout)
|
|
93
|
+
self.assertIn(f'PASSED {self.tmpdir_name}.Dir 1.Dir 2.Dir 3.Suite 3'.encode('utf-8'), stdout)
|
|
94
|
+
self.assertIn(f'PASSED {self.tmpdir_name}.Dir 1.Dir 2.Dir 3.Dir 4.Suite 4'.encode('utf-8'), stdout)
|
|
95
|
+
|
|
96
|
+
process_suite_4 = subprocess.Popen(
|
|
97
|
+
[
|
|
98
|
+
sys.executable,
|
|
99
|
+
"-m", "pabot.pabot",
|
|
100
|
+
self.robot_file_path_4
|
|
101
|
+
],
|
|
102
|
+
cwd=self.tmpdir,
|
|
103
|
+
stdout=subprocess.PIPE,
|
|
104
|
+
stderr=subprocess.PIPE
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
stdout, stderr = process_suite_4.communicate()
|
|
108
|
+
self.assertIn(b'1 tests, 1 passed, 0 failed, 0 skipped.', stdout)
|
|
109
|
+
self.assertEqual(b"", stderr)
|
|
110
|
+
self.assertNotIn(f'Suite 1'.encode('utf-8'), stdout)
|
|
111
|
+
self.assertNotIn(f'Suite 2'.encode('utf-8'), stdout)
|
|
112
|
+
self.assertNotIn(f'Suite 3'.encode('utf-8'), stdout)
|
|
113
|
+
self.assertIn(f'PASSED Suite 4'.encode('utf-8'), stdout)
|
|
114
|
+
|
|
115
|
+
process_dir_1 = subprocess.Popen(
|
|
116
|
+
[
|
|
117
|
+
sys.executable,
|
|
118
|
+
"-m", "pabot.pabot",
|
|
119
|
+
self.robot_dir_1
|
|
120
|
+
],
|
|
121
|
+
cwd=self.tmpdir,
|
|
122
|
+
stdout=subprocess.PIPE,
|
|
123
|
+
stderr=subprocess.PIPE
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
stdout, stderr = process_dir_1.communicate()
|
|
127
|
+
self.assertIn(b'4 tests, 4 passed, 0 failed, 0 skipped.', stdout)
|
|
128
|
+
self.assertEqual(b"", stderr)
|
|
129
|
+
self.assertIn(f'PASSED Dir 1.Suite 1'.encode('utf-8'), stdout)
|
|
130
|
+
self.assertIn(f'PASSED Dir 1.Dir 2.Suite 2'.encode('utf-8'), stdout)
|
|
131
|
+
self.assertIn(f'PASSED Dir 1.Dir 2.Dir 3.Suite 3'.encode('utf-8'), stdout)
|
|
132
|
+
self.assertIn(f'PASSED Dir 1.Dir 2.Dir 3.Dir 4.Suite 4'.encode('utf-8'), stdout)
|
|
133
|
+
|
|
134
|
+
process_dir_4 = subprocess.Popen(
|
|
135
|
+
[
|
|
136
|
+
sys.executable,
|
|
137
|
+
"-m", "pabot.pabot",
|
|
138
|
+
self.robot_dir_4
|
|
139
|
+
],
|
|
140
|
+
cwd=self.tmpdir,
|
|
141
|
+
stdout=subprocess.PIPE,
|
|
142
|
+
stderr=subprocess.PIPE
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
stdout, stderr = process_dir_4.communicate()
|
|
146
|
+
self.assertIn(b'1 tests, 1 passed, 0 failed, 0 skipped.', stdout)
|
|
147
|
+
self.assertEqual(b"", stderr)
|
|
148
|
+
self.assertNotIn(f'Suite 1'.encode('utf-8'), stdout)
|
|
149
|
+
self.assertNotIn(f'Suite 2'.encode('utf-8'), stdout)
|
|
150
|
+
self.assertNotIn(f'Suite 3'.encode('utf-8'), stdout)
|
|
151
|
+
self.assertIn(f'PASSED Dir 4.Suite 4'.encode('utf-8'), stdout)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def test_run_dir_2_then_dir_3(self):
|
|
156
|
+
process_dir_2 = subprocess.Popen(
|
|
157
|
+
[
|
|
158
|
+
sys.executable,
|
|
159
|
+
"-m", "pabot.pabot",
|
|
160
|
+
self.robot_dir_2
|
|
161
|
+
],
|
|
162
|
+
cwd=self.tmpdir,
|
|
163
|
+
stdout=subprocess.PIPE,
|
|
164
|
+
stderr=subprocess.PIPE
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
stdout, stderr = process_dir_2.communicate()
|
|
168
|
+
self.assertIn(b'3 tests, 3 passed, 0 failed, 0 skipped.', stdout)
|
|
169
|
+
self.assertEqual(b"", stderr)
|
|
170
|
+
self.assertNotIn(f'Suite 1'.encode('utf-8'), stdout)
|
|
171
|
+
self.assertIn(f'PASSED Dir 2.Suite 2'.encode('utf-8'), stdout)
|
|
172
|
+
self.assertIn(f'PASSED Dir 2.Dir 3.Suite 3'.encode('utf-8'), stdout)
|
|
173
|
+
self.assertIn(f'PASSED Dir 2.Dir 3.Dir 4.Suite 4'.encode('utf-8'), stdout)
|
|
174
|
+
|
|
175
|
+
process_dir_3 = subprocess.Popen(
|
|
176
|
+
[
|
|
177
|
+
sys.executable,
|
|
178
|
+
"-m", "pabot.pabot",
|
|
179
|
+
self.robot_dir_3
|
|
180
|
+
],
|
|
181
|
+
cwd=self.tmpdir,
|
|
182
|
+
stdout=subprocess.PIPE,
|
|
183
|
+
stderr=subprocess.PIPE
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
stdout, stderr = process_dir_3.communicate()
|
|
187
|
+
self.assertIn(b'2 tests, 2 passed, 0 failed, 0 skipped.', stdout)
|
|
188
|
+
self.assertEqual(b"", stderr)
|
|
189
|
+
self.assertNotIn(f'Suite 1'.encode('utf-8'), stdout)
|
|
190
|
+
self.assertNotIn(f'Suite 2'.encode('utf-8'), stdout)
|
|
191
|
+
self.assertIn(f'PASSED Dir 3.Suite 3'.encode('utf-8'), stdout)
|
|
192
|
+
self.assertIn(f'PASSED Dir 3.Dir 4.Suite 4'.encode('utf-8'), stdout)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def test_run_dir_3_then_dir_2(self):
|
|
196
|
+
process_dir_3 = subprocess.Popen(
|
|
197
|
+
[
|
|
198
|
+
sys.executable,
|
|
199
|
+
"-m", "pabot.pabot",
|
|
200
|
+
self.robot_dir_3
|
|
201
|
+
],
|
|
202
|
+
cwd=self.tmpdir,
|
|
203
|
+
stdout=subprocess.PIPE,
|
|
204
|
+
stderr=subprocess.PIPE
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
stdout, stderr = process_dir_3.communicate()
|
|
208
|
+
self.assertIn(b'2 tests, 2 passed, 0 failed, 0 skipped.', stdout)
|
|
209
|
+
self.assertEqual(b"", stderr)
|
|
210
|
+
self.assertNotIn(f'Suite 1'.encode('utf-8'), stdout)
|
|
211
|
+
self.assertNotIn(f'Suite 2'.encode('utf-8'), stdout)
|
|
212
|
+
self.assertIn(f'PASSED Dir 3.Suite 3'.encode('utf-8'), stdout)
|
|
213
|
+
self.assertIn(f'PASSED Dir 3.Dir 4.Suite 4'.encode('utf-8'), stdout)
|
|
214
|
+
|
|
215
|
+
process_dir_2 = subprocess.Popen(
|
|
216
|
+
[
|
|
217
|
+
sys.executable,
|
|
218
|
+
"-m", "pabot.pabot",
|
|
219
|
+
self.robot_dir_2
|
|
220
|
+
],
|
|
221
|
+
cwd=self.tmpdir,
|
|
222
|
+
stdout=subprocess.PIPE,
|
|
223
|
+
stderr=subprocess.PIPE
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
stdout, stderr = process_dir_2.communicate()
|
|
227
|
+
self.assertIn(b'3 tests, 3 passed, 0 failed, 0 skipped.', stdout)
|
|
228
|
+
self.assertEqual(b"", stderr)
|
|
229
|
+
self.assertNotIn(f'Suite 1'.encode('utf-8'), stdout)
|
|
230
|
+
self.assertIn(f'PASSED Dir 2.Suite 2'.encode('utf-8'), stdout)
|
|
231
|
+
self.assertIn(f'PASSED Dir 2.Dir 3.Suite 3'.encode('utf-8'), stdout)
|
|
232
|
+
self.assertIn(f'PASSED Dir 2.Dir 3.Dir 4.Suite 4'.encode('utf-8'), stdout)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{robotframework_pabot-4.1.1 → robotframework_pabot-4.2.0}/tests/test_testlevelsplit_include.py
RENAMED
|
File without changes
|
|
File without changes
|