Repository navigation
implemented retry_type checks used in the TestClass #267
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,4 +29,5 @@ venv37 | |
| .vscode/settings.json | ||
| docs/_build/ | ||
| .DS_Store | ||
| .env | ||
| .env | ||
| *.lock | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -277,7 +277,9 @@ def run_once(self): | |
| if self.run_test(): | ||
| top.index += 1 | ||
| else: | ||
| if not self.retry_prompt(): | ||
| if not self.retry_prompt( | ||
| retry_type=top.current().retry_type | ||
| ): | ||
| # mark the test as failed and continue. else will loop and try again | ||
| self.tests_failed += 1 | ||
| top.index += 1 | ||
|
|
@@ -371,7 +373,7 @@ def run_test(self): | |
| ) | ||
| attempts = 0 | ||
| active_test_status = "ERROR" | ||
| if not self.retry_prompt(): | ||
| if not self.retry_prompt(retry_type=active_test.retry_type): | ||
| self.tests_errored += 1 | ||
| break | ||
| # Retry logic for exceptions | ||
|
|
@@ -395,15 +397,32 @@ def run_test(self): | |
| ) | ||
| return active_test_status == "PASS" | ||
|
|
||
| def retry_prompt(self): | ||
| def retry_prompt(self, *, retry_type: TestClass.RetryMode): | ||
| """Prompt the user when something goes wrong. | ||
|
|
||
| For retry return True, to fail return False and to abort raise and abort exception. Respect the | ||
| non_interactive flag, which can be set by the command line option --non-interactive | ||
| """ | ||
| if not isinstance(retry_type, TestClass.RetryMode): | ||
| raise TypeError( | ||
| f"Invalid retry_type:{retry_type} retry_type must be valid{type(retry_type).__name__}" | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This error message is not really all that helpful. I think something like the below will be clearer. raise TypeError(
f"Invalid retry_type type: {type(retry_type).__name__}. retry_type must be a valid {TestClass.RetryMode.__name__} member"
) |
||
| ) | ||
|
|
||
| if self.non_interactive: | ||
| return False | ||
| if retry_type == TestClass.RetryMode.RT_PROMPT: | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These 2 cases are currently identical. If attempts in the test class is > 1, the test will be attempted I think we have 2 options.
My personal vote is for option 2. @daniel-montanari thoughts?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the logic should be moved out a level. Then outside of this function implement the logic for the other RT types and switch off either the prompt or non-interactive RT type
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah having another look at this the whole loop is broken. I don't understand why abort_exceptions allows retries. self.ABORT inside of run_test also doesn't seem to get used as it only gets set after the test has exited. I think the attempts and retry logic should be moved out of run_test so the only place to deal with it is in run_once. Also those names seem backwards to me. |
||
| # RT_PROMPT is the default behaviour and will prompt the user below. | ||
| pass | ||
| if retry_type == TestClass.RetryMode.RT_RETRY: | ||
| # RT_RETRY behaviour is determined by active_test.attempt, | ||
| # By default it is set to 1. For example if the value is set to 3 it will | ||
| # retry the test 3 times if all fails then it prompts the user. | ||
| pass | ||
| if retry_type == TestClass.RetryMode.RT_FAIL: | ||
| return False | ||
| if retry_type == TestClass.RetryMode.RT_ABORT: | ||
| raise SequenceAbort("Sequence Aborted By The Test") | ||
|
|
||
| resp = user_retry_abort_fail(msg="") | ||
| if resp == "ABORT": | ||
| raise SequenceAbort("Sequence Aborted By User") | ||
|
|
||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You get bonus points for writing tests without being prompted to. But these are manual tests, so should be in the |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,175 @@ | ||
| """ | ||
| Testing the RetryMode implementation. | ||
| """ | ||
|
|
||
| from fixate.core.checks import chk_true | ||
| from fixate.core.common import TestClass, TestList | ||
| from fixate.core.ui import user_info, user_ok | ||
|
|
||
|
|
||
| class SimpleTestToPass(TestClass): | ||
| """Simple test case that always passes""" | ||
|
|
||
| test_desc = __qualname__ | ||
|
|
||
| def set_up(self): | ||
| user_info("Setting up to pass") | ||
|
|
||
| def test(self): | ||
| user_info("Testing to Pass the test") | ||
| chk_true(True, "Passed the test") | ||
|
|
||
| def tear_down(self): | ||
| user_info("Well done, you wouldn't fail anyway!") | ||
|
|
||
|
|
||
| class SimpleTestToFail(TestClass): | ||
| """Simple test case that always fails""" | ||
|
|
||
| test_desc = __qualname__ | ||
| attempts = 2 | ||
| retry_type = TestClass.RetryMode.RT_PROMPT | ||
|
|
||
| def set_up(self): | ||
| user_info("Setting up to fail") | ||
|
|
||
| def test(self): | ||
| user_info("Testing to Fail the test") | ||
| chk_true(False, "Failed the test") | ||
|
|
||
| def tear_down(self): | ||
| user_info("Well, you wouldn't pass anyway!") | ||
|
|
||
|
|
||
| class RetryTestPass(TestClass): | ||
| """Simple test case that always passes but setup to retry if fails to test passing cases.""" | ||
|
|
||
| test_desc = __qualname__ | ||
| retry_type = TestClass.RetryMode.RT_RETRY | ||
| attempts = 3 | ||
|
|
||
| def set_up(self): | ||
| user_info("Setting up to pass") | ||
|
|
||
| def test(self): | ||
| user_info("Testing to Pass the test") | ||
| chk_true(True, "Passed the test") | ||
|
|
||
| def tear_down(self): | ||
| user_info("Well done, you wouldn't fail anyway!") | ||
|
|
||
|
|
||
| class RetryTestFail(TestClass): | ||
| """Simple test case that always fails and retries for the number of | ||
| attempts and prompts the user after all the attempts have failed.. | ||
| """ | ||
|
|
||
| test_desc = __qualname__ | ||
|
|
||
| retry_type = TestClass.RetryMode.RT_RETRY | ||
| attempts = 3 | ||
|
|
||
| def set_up(self): | ||
| user_info("Setting up to fail") | ||
|
|
||
| def test(self): | ||
| user_info("Testing to Fail the test") | ||
| chk_true(False, "Failed the test") | ||
|
|
||
| def tear_down(self): | ||
| user_info("Well, you wouldn't pass anyway!") | ||
|
|
||
|
|
||
| # RT_FAIL = 4 # Automatically fail and move on | ||
| class RetryTestPassRTFAIL(TestClass): | ||
| """Simple test case that always passes but setup to retry if fails to test passing cases.""" | ||
|
|
||
| test_desc = __qualname__ | ||
|
|
||
| retry_type = TestClass.RetryMode.RT_FAIL | ||
| attempts = 3 | ||
|
|
||
| def set_up(self): | ||
| user_info("Setting up to pass") | ||
|
|
||
| def test(self): | ||
| user_info("Testing to Pass the test") | ||
| chk_true(True, "Passed the test") | ||
|
|
||
| def tear_down(self): | ||
| user_info("Well done, you wouldn't fail anyway!") | ||
|
|
||
|
|
||
| class RetryTestFailRTFAIL(TestClass): | ||
| """Simple test case that always fails and retries for the number of | ||
| attempts. Then automatically failes the test and moves onto the next one.""" | ||
|
|
||
| test_desc = __qualname__ | ||
|
|
||
| retry_type = TestClass.RetryMode.RT_FAIL | ||
| attempts = 3 | ||
|
|
||
| def set_up(self): | ||
| user_info("Setting up to fail") | ||
|
|
||
| def test(self): | ||
| user_info("Testing to Fail the test") | ||
| chk_true(False, "Failed the test") | ||
|
|
||
| def tear_down(self): | ||
| user_info("Well, you wouldn't pass anyway!") | ||
|
|
||
|
|
||
| class TestListRTFAIL(TestList): | ||
| """Test list to test the RT_FAIL within the test list""" | ||
|
|
||
| def enter(self): | ||
| user_info("Entering the test list") | ||
|
|
||
| def exit(self): | ||
| user_info("Leaving the test list") | ||
|
|
||
|
|
||
| # RT_ABORT = 1 # Abort the whole test sequence | ||
| class RetryTestFailRTABORT(TestClass): | ||
| """Simple test case that always fails and retries the number of attempts when final attempt has failed | ||
| It aborts the all the test. It may be useful if there is critical test that may damage Device Under Test if fails. | ||
| """ | ||
|
|
||
| test_desc = __qualname__ | ||
|
|
||
| retry_type = TestClass.RetryMode.RT_ABORT | ||
| attempts = 3 | ||
|
|
||
| def set_up(self): | ||
| user_ok("Setting up to abort, Press Enter to proceed") | ||
|
|
||
| def test(self): | ||
| user_info("Testing to Fail the test") | ||
| chk_true(False, "Failed the test") | ||
|
|
||
| def tear_down(self): | ||
| user_info("ABORTING!") | ||
|
|
||
|
|
||
| TEST_SEQUENCE = [ | ||
| SimpleTestToPass(), | ||
| SimpleTestToFail(), | ||
| RetryTestPass(), | ||
| RetryTestFail(), | ||
| RetryTestPassRTFAIL(), | ||
| RetryTestFailRTFAIL(), | ||
| TestListRTFAIL( | ||
| [ | ||
| RetryTestPassRTFAIL(), | ||
| RetryTestFailRTFAIL(), | ||
| ] | ||
| ), | ||
| RetryTestFailRTABORT(), | ||
| ] | ||
|
|
||
| if __name__ == "__main__": | ||
| import fixate | ||
|
|
||
| argv = ["-p", __file__, "--serial_number", "1234567890"] | ||
| fixate.run(__file__, argv) |

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you move these comments into the doc string? That way instead of
We get
