Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Twister: additional scripts #72808

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

majunkier
Copy link
Collaborator

@majunkier majunkier commented May 15, 2024

Add the execution of external scripts at precise moments. These scripts can be strategically deployed in three distinct phases: pre-script, post-flash-script and post-script. This functionality could help configuring the environment optimally before testing.
Script phases are already implemented solution, this PR serves as an extension to broaden their application and utility.

Usage is similar to quarantine file :

twister -p <BOARD> -T <TEST_SCENARIO> --scripting-list <PATH_TO_SCRIPTING_YAML>

An example of entries in a scripting list yaml:

    - scenarios:
    - sample.basic.helloworld
    platforms:
    - frdm_k64f
    pre_script:
        path: <PATH_TO_PRE_SCRIPT>
        timeout: <TIMEOUT TIME>
        override_script: <BOOLEAN>
    post_flash_script:
        path: <PATH_TO_PRE_SCRIPT>
        timeout: <TIMEOUT TIME>
        override_script: <BOOLEAN>
    post_script:
        path: <PATH_TO_PRE_SCRIPT>
        timeout: <TIMEOUT TIME>
        override_script: <BOOLEAN>
    comment:
        Testing extra scripts feature

Usage of all (pre_script, post_flash_script, post_script) is not mandatory, it could be only one parameter.

One of the primary benefits of this approach is the ability to execute scripts tailored to individual scenarios.

Comment on lines 1155 to 1358
pre_script:
<PATH_TO_PRE_SCRIPT>
post_flash_script:
<PATH_TO_POST_FLASH_SCRIPT>
post_script:
<PATH_TO_POST_SCRIPT>
comment:
Testing extra scripts
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we planning to use it for tests in Zephyr tree?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solution is designed with flexibility in mind, making it suitable for use in a variety of contexts, including the Zephyr tree.

@hakehuang
Copy link
Collaborator

why no just put to the map.yaml file? along with --device-testing?

@majunkier
Copy link
Collaborator Author

majunkier commented May 16, 2024

why no just put to the map.yaml file? along with --device-testing?

Currently, we have the capability to run scripts based on specified runner parameters; however, this approach limits us to the execution of pre scripts only. An alternative method would involve enhancing the map file to accommodate script execution, but this leads to redundancy when dealing with multiple identical boards, as we would need to replicate the script type, scenario, and path information for each entry.
By this approach its easy to execute scripts tailored to individual scenarios.

@hakehuang
Copy link
Collaborator

Currently, we have the capability to run scripts based on specified runner parameters; however, this approach limits us to the execution of pre scripts only. An alternative method would involve enhancing the map file to accommodate script execution, but this leads to redundancy when dealing with multiple identical boards, as we would need to replicate the script type, scenario, and path information for each entry.
By this approach its easy to execute scripts tailored to individual scenarios.

This could be easily out of control as no one knows what you do in the rep/post, why we need customer for each case? why not just use pytest framework to do so?

@majunkier
Copy link
Collaborator Author

majunkier commented May 16, 2024

This could be easily out of control as no one knows what you do in the rep/post, why we need customer for each case? why not just use pytest framework to do so?

I concur that allowing unrestricted modifications to scripts by everyone could pose risks. However, the proposed solution does not necessitate storing the scripts or the scripting-list.yaml file within the Zephyr repository, similar to how the quarantine-list file is managed. You will have the flexibility to manage scripts within your own environment. This file is not mandatory, it serves to enhance the functionality of Twister for use in personalized settings.

@hakehuang
Copy link
Collaborator

hakehuang commented May 16, 2024

You will have the flexibility to manage scripts within your own environment. This file is not mandatory, it serves to enhance the functionality of Twister for use in personalized settings.

this thing is if go this way, the twister will be diverged in its behavour, quaratine is to skip test cases. but adding pre/post staff will impact the way test runs. it is better in a controlable way. unless you have strong user case to supporting doing so.

@majunkier
Copy link
Collaborator Author

You will have the flexibility to manage scripts within your own environment. This file is not mandatory, it serves to enhance the functionality of Twister for use in personalized settings.

this thing is if go this way, the twister will be diverged in its behavour, quaratine is to skip test cases. but adding pre/post staff will impact the way test runs. it is better in a controlable way. unless you have strong user case to supporting doing so.

There are many ways of usage, i could take an example power management tests, where we can set up the necessary power conditions, calibrate or reset power measurement tools, perform initial checks to validate that the device is in the right state for power measurements and gather power usage data

hakehuang
hakehuang previously approved these changes May 30, 2024
@majunkier
Copy link
Collaborator Author

@evgeniy-paltsev could you take a look?

doc/develop/test/twister.rst Show resolved Hide resolved
doc/develop/test/twister.rst Show resolved Hide resolved
scripts/pylib/twister/twisterlib/testplan.py Outdated Show resolved Hide resolved
scripts/pylib/twister/twisterlib/environment.py Outdated Show resolved Hide resolved
scripts/pylib/twister/twisterlib/environment.py Outdated Show resolved Hide resolved
scripts/pylib/twister/twisterlib/testplan.py Outdated Show resolved Hide resolved
scripts/pylib/twister/twisterlib/testplan.py Outdated Show resolved Hide resolved
scripts/pylib/twister/twisterlib/testplan.py Outdated Show resolved Hide resolved
if script:
if Path(script).is_file():
logger.info(f"{script_name} {script} will be executed") # Validate if test exists
setattr(dut, script_name, script)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the the dut already have a script defined, then it will be overridden - this behavior should be documented.

imo, the new scripting schema should have an attribute like override (default = true ?) to resolve which configuration takes precedence.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is explained in twister.rst, you manage this which script will be executed so you don't need adding extra parameter

Copy link
Member

@golowanow golowanow Sep 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My concern is around the complexity introduced with this feature now with 3 configuration sources: command line, device map, and this new config (not mention its regexp selection rules).

Looks like a DUT can be selected several times matching different test case & platform pattens, so without explicit constrains its pre-/post- script constellation will, quite likely, composed in a funny way.

as @hakehuang also noted:

this thing is if go this way, the twister will be diverged in its behavour, quaratine is to skip test cases. but adding pre/post staff will impact the way test runs. it is better in a controlable way. unless you have strong user case to supporting doing so.

@golowanow
Copy link
Member

why no just put to the map.yaml file? along with --device-testing?

Currently, we have the capability to run scripts based on specified runner parameters; however, this approach limits us to the execution of pre scripts only. An alternative method would involve enhancing the map file to accommodate script execution, but this leads to redundancy when dealing with multiple identical boards, as we would need to replicate the script type, scenario, and path information for each entry. By this approach its easy to execute scripts tailored to individual scenarios.

@majunkier what about these alternative improvements then:

  1. extend test-config-schema with additional attributes instead of introducing the separate scripting-schema ?
  2. run twister several times with different command line options for a test scope, platforms and scripts (+ missed options) ?

Copy link

github-actions bot commented Aug 8, 2024

This pull request has been marked as stale because it has been open (more than) 60 days with no activity. Remove the stale label or add a comment saying that you would like to have the label removed otherwise this pull request will automatically be closed in 14 days. Note, that you can always re-open a closed pull request at any time.

@hakehuang
Copy link
Collaborator

@majunkier do you have time to follow up with @golowanow comments? besides that this PR looks ok.

@github-actions github-actions bot removed the Stale label Aug 20, 2024
@majunkier
Copy link
Collaborator Author

why no just put to the map.yaml file? along with --device-testing?

Currently, we have the capability to run scripts based on specified runner parameters; however, this approach limits us to the execution of pre scripts only. An alternative method would involve enhancing the map file to accommodate script execution, but this leads to redundancy when dealing with multiple identical boards, as we would need to replicate the script type, scenario, and path information for each entry. By this approach its easy to execute scripts tailored to individual scenarios.

@majunkier what about these alternative improvements then:

  1. extend test-config-schema with additional attributes instead of introducing the separate scripting-schema ?
  2. run twister several times with different command line options for a test scope, platforms and scripts (+ missed options) ?
  1. This works as quarantine list file - reduce complexity of test-config-schema, easier to manage, test-config-schema contains the structure and rules for how tests should be written and this is extra action without rules
  2. There are few tests that check functionality

@majunkier majunkier force-pushed the twister_additional_scripts branch 2 times, most recently from 8f057d8 to 62cd444 Compare August 26, 2024 08:54
Copy link
Member

@golowanow golowanow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@majunkier, sorry for so many comments, it took a while to review.

scripts/schemas/twister/scripting-schema.yaml Show resolved Hide resolved
scripts/schemas/twister/scripting-schema.yaml Show resolved Hide resolved
scripts/schemas/twister/scripting-schema.yaml Show resolved Hide resolved
scripts/pylib/twister/twisterlib/testplan.py Outdated Show resolved Hide resolved
scripts/pylib/twister/twisterlib/testplan.py Outdated Show resolved Hide resolved
scripts/pylib/twister/twisterlib/scripting.py Outdated Show resolved Hide resolved
scripts/pylib/twister/twisterlib/scripting.py Outdated Show resolved Hide resolved
return any(board in platform_scope for board in platform_from_yaml)

# Define the types of scripts we are interested in
script_types = {'pre_script': 'pre_script','post_flash_script': 'post_flash_script', 'post_script': 'post_script' }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why it needs a dictionary with keys == values, not just a list ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated, now added timeout which will use dict.
Before it was part of old code with you pointed

if script:
if Path(script).is_file():
logger.info(f"{script_name} {script} will be executed") # Validate if test exists
setattr(dut, script_name, script)
Copy link
Member

@golowanow golowanow Sep 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My concern is around the complexity introduced with this feature now with 3 configuration sources: command line, device map, and this new config (not mention its regexp selection rules).

Looks like a DUT can be selected several times matching different test case & platform pattens, so without explicit constrains its pre-/post- script constellation will, quite likely, composed in a funny way.

as @hakehuang also noted:

this thing is if go this way, the twister will be diverged in its behavour, quaratine is to skip test cases. but adding pre/post staff will impact the way test runs. it is better in a controlable way. unless you have strong user case to supporting doing so.

scripts/pylib/twister/twisterlib/testplan.py Outdated Show resolved Hide resolved
@PerMac
Copy link
Member

PerMac commented Sep 16, 2024

I saw @hakehuang asking about it, but haven't seen an answer: isn't using pytest for such scripting already a more general solution with the ease of expandability with fixtures?

@majunkier
Copy link
Collaborator Author

I saw @hakehuang asking about it, but haven't seen an answer: isn't using pytest for such scripting already a more general solution with the ease of expandability with fixtures?

Indeed, there are numerous methods to attain the same or comparable solutions. However, this solution emphasizes enhancing the core functionality of Twister, making it more apt for testing within the Zephyr ecosystem.

@hakehuang
Copy link
Collaborator

Indeed, there are numerous methods to attain the same or comparable solutions. However, this solution emphasizes enhancing the core functionality of Twister, making it more apt for testing within the Zephyr ecosystem.

I do support to add such case by case control method, however, as @PerMac and @golowanow suggested, maybe we need consider to use pytest instead of on the fly shell scripts, as those scripts are not likely be maintained in tree, this diverge may introduce inconsistency to test result. so for your case, would you try use pytest to organize your logic and which will be in-tree and benefit for all other developers. or you find it is impossible to do in pytest?

@majunkier
Copy link
Collaborator Author

Indeed, there are numerous methods to attain the same or comparable solutions. However, this solution emphasizes enhancing the core functionality of Twister, making it more apt for testing within the Zephyr ecosystem.

I do support to add such case by case control method, however, as @PerMac and @golowanow suggested, maybe we need consider to use pytest instead of on the fly shell scripts, as those scripts are not likely be maintained in tree, this diverge may introduce inconsistency to test result. so for your case, would you try use pytest to organize your logic and which will be in-tree and benefit for all other developers. or you find it is impossible to do in pytest?

This change does not affect pytest as a plugin, it is an extension to the basic twister implementation. The functionality already exists, this changes are adding an additional extension for the currently working solution.

@majunkier majunkier force-pushed the twister_additional_scripts branch 2 times, most recently from ac28429 to 9c50aac Compare September 23, 2024 07:16
@majunkier
Copy link
Collaborator Author

Apart from review changes I have implemented additional parameters to the scripting schema:
'timeout': parameter to specify the duration for script execution. @hakehuang based on your changes
'override_script': a parameter that requires confirmation before proceeding to override and execute the existing script.

hakehuang
hakehuang previously approved these changes Sep 23, 2024
scripts/schemas/twister/scripting-schema.yaml Show resolved Hide resolved
scripts/pylib/twister/twisterlib/scripting.py Outdated Show resolved Hide resolved
scripts/pylib/twister/twisterlib/scripting.py Outdated Show resolved Hide resolved
scripts/pylib/twister/twisterlib/scripting.py Outdated Show resolved Hide resolved
continue
if element.platforms and not _matches_element(platform, element.re_platforms):
continue
return element
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To deal with several matching entries situation I'd suggest to look over all elements and return a list with all matched scripting elements.

scripts/pylib/twister/twisterlib/testplan.py Outdated Show resolved Hide resolved
# Iterate over all DUTs to set the appropriate scripts if they match the platform and are supported
for dut in self.env.hwm.duts:
# Check if the platform matches and if the platform is supported by the matched scripting
if dut.platform == plat.name and validate_boards(plat.name, matched_scripting.platforms):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handle several matched entries case here to check either a single match, or only one override element is present which becomes the resulting entry. All other cases will be configuration error.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, matched_scripting = self.scripting.get_matched_scripting(instance.testsuite.id, plat.name) is designed to return either None or a single ScriptingElement. Without modifying thefind_matching_scriptingmethod to return a list as you proposed, we will not encounter multiple matches in this context.

scripts/pylib/twister/twisterlib/testplan.py Outdated Show resolved Hide resolved
scripts/pylib/twister/twisterlib/testplan.py Outdated Show resolved Hide resolved
Copy link
Member

@golowanow golowanow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the multiple match problem using the override_script attribute seems not addressed yet

Comment on lines 255 to 273
if self.scripting:
# Check if at least one provided script met the conditions.
# Summarize logs for all calls.
was_script_matched = False
for instance in self.instances.values():
was_script_matched = was_script_matched or self.handle_additional_scripts(instance.platform.name, instance.testsuite.id)

if not was_script_matched:
logger.info("Scripting list was provided, none of the specified conditions were met")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if self.scripting:
# Check if at least one provided script met the conditions.
# Summarize logs for all calls.
was_script_matched = False
for instance in self.instances.values():
was_script_matched = was_script_matched or self.handle_additional_scripts(instance.platform.name, instance.testsuite.id)
if not was_script_matched:
logger.info("Scripting list was provided, none of the specified conditions were met")
if self.scripting and not any([self.handle_additional_scripts(inst_) for inst_ in self.instances.values()]):
logger.warning("Scripting list was provided, none of the specified conditions were met")

Comment on lines 1116 to 1197
def handle_additional_scripts(self, platform_name: Platform, testsuide: TestInstance):
matched_scripting = self.scripting.get_matched_scripting(testsuide, platform_name)
if matched_scripting:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def handle_additional_scripts(self, platform_name: Platform, testsuide: TestInstance):
matched_scripting = self.scripting.get_matched_scripting(testsuide, platform_name)
if matched_scripting:
def handle_additional_scripts(self, platform_name: Platform, testsuide: TestInstance):
matched_scripting = self.scripting.get_matched_scripting(testsuide, platform_name)
if matched_scripting:
Suggested change
def handle_additional_scripts(self, platform_name: Platform, testsuide: TestInstance):
matched_scripting = self.scripting.get_matched_scripting(testsuide, platform_name)
if matched_scripting:
def handle_additional_scripts(self, platform_name: Platform, test_instance: TestInstance):
platform_name = test_instance.platform.name
matched_scripting = self.scripting.get_matched_scripting(test_instance.testsuite.id, platform_name)
if not matched_scripting:
return False

Comment on lines +1148 to +1230
return True
return False
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return True
return False
return True

continue
if element.platforms and not _matches_element(platform, element.re_platforms):
continue
return element
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it still looks for only one first matching pattern combination - see all my previous comments on this problem, eg. #72808 (comment)

# If a script object is provided, check if the script path is a valid file
if script_obj and script_obj.get('path'):
# Check if there's an existing script and if override is not allowed
if not script_obj.get('override_script'):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm puzzled - it seems the override_script must be always present in the config otherwise the script will never considered irregardless of match duplications.
This attribute should be taken into account at get_matched_scripting() as the better and the only one choice among others.
https://github.com/zephyrproject-rtos/zephyr/pull/72808/files#diff-cf21072267d967b317067e8df4b6946aada828f0dec1e7705505100e36b4d43fR1271-R1274

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

your suggestions was implemented. Now entry must have override_script set to true to be executed and if there are duplicates job will be stopped

@hakehuang
Copy link
Collaborator

@majunkier would update this PR, I think there are only some code snippet changes by now. Thanks. Am I right? @golowanow

Add the execution of external scripts at precise moments.
These scripts can be strategically deployed in three distinct
phases: pre-script, post-flash-script and post-script.
This functionality could help configuring the environment optimally
before testing.

Signed-off-by: Mateusz Junkier <[email protected]>
Add unit tests designed for testing additional scripting
feature.

Signed-off-by: Mateusz Junkier <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants