-
-
Notifications
You must be signed in to change notification settings - Fork 256
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
Fix tests failing on WSL systems. #1511
base: main
Are you sure you want to change the base?
Conversation
tests/helper/test_helper.py
Outdated
if PLATFORM == "WSL": | ||
media_path = media_path.replace("/", "\\") | ||
|
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.
I'm not sure if I can import PLATFORM into tests, but this seemed like the only way to address the difference in file paths in WSL.
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.
To further clarify, based on a discussion on CZO, the issue stems from the normalized_path
function used in the download_media
method. The media_path
assertion doesn't account for the WSL-specific normalized path.
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.
For a conditional in a test, the cleaner way to handle this would normally be to parametrize the test (over PLATFORM), though note you'd want a third path for the expected_return_value
or similar output parameter, since it doesn't correspond to url
or media_path
in every case (though the latter may not be representative - see below re confirming).
The alternative to this conditional/parametrizing solution, which may also be clearer in the long term, is related to how (as we confirmed in the channel) the path returned is the path used for opening the temporary file, not the path used for saving it. So it would be clearer to refactor the code before fixing the tests, such that the normalized_file_path
occurs outside of this function, and this function would be platform-independent to test.
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.
Moved the normalized_file_path
to be called in process_media
👍
Clear explanation, thanks!
tests/helper/test_helper.py
Outdated
@pytest.mark.parametrize( | ||
"returncode, error", | ||
[ | ||
(0, []), | ||
(1 if PLATFORM == "WSL" else 0, []), | ||
( | ||
1, | ||
0 if PLATFORM == "WSL" else 1, | ||
[ | ||
" The tool ", | ||
("footer_contrast", "xdg-open"), | ||
" did not run successfully" ". Exited with ", | ||
("footer_contrast", "1"), | ||
("footer_contrast", "0" if PLATFORM == "WSL" else "1"), | ||
], | ||
), | ||
], |
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.
This test didn't consider the different return codes in WSL, as given in platform_code.py
line 92.
def successful_GUI_return_code() -> int: # noqa: N802 (allow upper case)
"""
Returns success return code for GUI commands, which are OS specific.
"""
# WSL uses GUI return code as 1. Refer below link to know more:
# https://stackoverflow.com/questions/52423031/
# why-does-opening-an-explorer-window-and-selecting-a-file-through-pythons-subpro/
# 52423798#52423798
if PLATFORM == "WSL":
return 1
return 0
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.
explorer.exe
seems to always return a non-zero exit code, regardless of whether the task is successful.
More information could be found on this issue.
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.
Your initial change may not be relevant now, so skip this paragraph to focus on possible solutions. However, note that (a) we should avoid repeating ourselves in this way, and (b) the way you have it written makes the test itself perform differently when run on WSL and elsewhere, which would be fragile - ie. suddenly break if not tested regularly (we don't test on WSL in CI). As long as the behavior and code can actually be run and tested from a different platform, we should prefer to mock PLATFORM
and ensure the outcome matches what we expect.
Based on the behavior you confirmed in the channel (and as per your comment above), it seems this is a bug, so it'd be worth not just fixing the test here.
One simple approach would be to revise the code to only output a message on running the tool, since that's the common factor we can actually determine across platforms.
However, to allow retaining some of the existing behavior, we can refactor the function you quoted, such that it returns some value, depending upon a passed-in return code. This would move the comparison, and hence these explicit error codes, into a platform-dependent location. In turn, the test you're aiming to fix could easily mock the new function, and would be independent of platform.
Depending upon the approach taken, we would lose the ability to test/show the exact error code in the output, but I'm not convinced this adds much to the experience, unless debugging.
To retain the existing behavior, different return values from that new function could signify eg. 'definitely opened', 'failed to open', 'trying to open', to cover the case across platforms.
Depending how far you wish to go with this refactor, a lot of the logic in open_media
could move into the new platform-dependent function, including possibly the tools-per-platform themselves. However, that could be a series of refactors after the first simplification.
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.
we can refactor the function you quoted, such that it returns some value, depending upon a passed-in return code. This would move the comparison, and hence these explicit error codes, into a platform-dependent location.
Implemented this approach, thanks for the suggestion! Also will look into refactoring some open_media
logic to a platform-specific location in another PR.
Nice work! Thanks for addressing those. |
@rsashank I started a review, but will leave that pending until I hear back to confirm the implementation details I noted in #zulip-terminal. |
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.
@rsashank Thanks for finding these problems and working on solutions - we don't have WSL in CI (GitHub PR tests), so some of these issues are not always obvious, and not everything can be tested in CI in any case.
Following the discussion in the channel, I've adjusted some comments, though the same general gist of my suggestions remains the same, ie. that refactoring slightly first would be preferable, and may allow further subsequent refactoring which would make everything a lot easier to read.
Due to limited resources for testing on each platform, in general its better if we can isolate as much into platform-code as we can, during times while people are available to test it manually. That applies to this code in helper
, as well as anywhere else we explicitly rely upon PLATFORM. That allows the platform-dependent code to be manually-tested well, and the interface between that and the application to be as clean as possible, as well as tests like these to be less fragile :)
tests/helper/test_helper.py
Outdated
@pytest.mark.parametrize( | ||
"returncode, error", | ||
[ | ||
(0, []), | ||
(1 if PLATFORM == "WSL" else 0, []), | ||
( | ||
1, | ||
0 if PLATFORM == "WSL" else 1, | ||
[ | ||
" The tool ", | ||
("footer_contrast", "xdg-open"), | ||
" did not run successfully" ". Exited with ", | ||
("footer_contrast", "1"), | ||
("footer_contrast", "0" if PLATFORM == "WSL" else "1"), | ||
], | ||
), | ||
], |
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.
Your initial change may not be relevant now, so skip this paragraph to focus on possible solutions. However, note that (a) we should avoid repeating ourselves in this way, and (b) the way you have it written makes the test itself perform differently when run on WSL and elsewhere, which would be fragile - ie. suddenly break if not tested regularly (we don't test on WSL in CI). As long as the behavior and code can actually be run and tested from a different platform, we should prefer to mock PLATFORM
and ensure the outcome matches what we expect.
Based on the behavior you confirmed in the channel (and as per your comment above), it seems this is a bug, so it'd be worth not just fixing the test here.
One simple approach would be to revise the code to only output a message on running the tool, since that's the common factor we can actually determine across platforms.
However, to allow retaining some of the existing behavior, we can refactor the function you quoted, such that it returns some value, depending upon a passed-in return code. This would move the comparison, and hence these explicit error codes, into a platform-dependent location. In turn, the test you're aiming to fix could easily mock the new function, and would be independent of platform.
Depending upon the approach taken, we would lose the ability to test/show the exact error code in the output, but I'm not convinced this adds much to the experience, unless debugging.
To retain the existing behavior, different return values from that new function could signify eg. 'definitely opened', 'failed to open', 'trying to open', to cover the case across platforms.
Depending how far you wish to go with this refactor, a lot of the logic in open_media
could move into the new platform-dependent function, including possibly the tools-per-platform themselves. However, that could be a series of refactors after the first simplification.
tests/helper/test_helper.py
Outdated
if PLATFORM == "WSL": | ||
media_path = media_path.replace("/", "\\") | ||
|
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.
For a conditional in a test, the cleaner way to handle this would normally be to parametrize the test (over PLATFORM), though note you'd want a third path for the expected_return_value
or similar output parameter, since it doesn't correspond to url
or media_path
in every case (though the latter may not be representative - see below re confirming).
The alternative to this conditional/parametrizing solution, which may also be clearer in the long term, is related to how (as we confirmed in the channel) the path returned is the path used for opening the temporary file, not the path used for saving it. So it would be clearer to refactor the code before fixing the tests, such that the normalized_file_path
occurs outside of this function, and this function would be platform-independent to test.
Hello @zulip/server-refactoring members, this pull request was labeled with the "area: refactoring" label, so you may want to check it out! |
5a821d0
to
424d8e8
Compare
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.
@rsashank I hoped to merge this fully but ended up leaving a few comments aimed primarily at the second commit - I've picked off the first commit and merged it already, after making the change I indicated in the comment re which item to patch.
Hopefully that first commit reduces the failing tests you're finding regularly, and the other commit will be quick to follow :)
tests/helper/test_helper.py
Outdated
mocker.patch(MODULE + ".PLATFORM", platform) | ||
mocker.patch("zulipterminal.platform_code.PLATFORM", platform) |
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.
Note that these two lines are patching
- the
PLATFORM
imported intohelper
- the
PLATFORM
in the original module
So, at the very least this is duplication. When patching, we want to adjust the name that's used, and if you only use the version you added (and remove the previous one), then it won't run the test - it doesn't patch properly.
=> The existing line is sufficient.
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.
While testing locally in my WSL environment, the platform detection incorrectly identifies the platform as WSL when either one of the patches is missing. This causes the tests to enter the if PLATFORM == 'WSL' condition and change the path.
So, I had to mock the PLATFORM value in both the platform_code and helper.
I'm not entirely sure why this is happening, but patching both seems to ensure the consistency for all platforms that are being tested.
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.
Thanks for this feedback! This seems likely since we still use PLATFORM in both locations for this :/
This appears to be the only outstanding change in this commit after a rebase, since I merged the first commit previously, so the commit text is currently inaccurate at that point. It'd also be useful to group and comment the two lines, if they appear to be necessary to pass the tests, as well as update the commit.
This is a 'test bugfix' commit, specific to WSL, essentially?
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.
Grouped them together and added a comment, also changed commit message.
Yes, it's a test bugfix specific to WSL.
zulipterminal/platform_code.py
Outdated
# NOTE: WSL always returns a non-zero exit code (1) for GUI commands. | ||
# This is a known issue. Therefore, we consider it a success if the exit code is 1. | ||
# For more information, see: https://github.com/microsoft/WSL/issues/6565 | ||
if PLATFORM == "WSL": | ||
return 1 | ||
return "success" if exit_status == 1 else "failure" |
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.
This claims to be able to return and handle failure
in the code, but the comment says it cannot. Then we don't test this code. If we're always going to return success, we should do that and then only test for it with WSL - or be able to return both success and failure, and test for both.
Is it only explorer.exe
under WSL that always succeeds?
If that's the case, this is quite fragile since this seems related to knowing that we're using it for explorer.exe only, but in another part of the code entirely. Having this change will be good for now, but we should ensure that we note this in each location that's affected.
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.
Thank you for pointing this out. I've removed the mention of "failure" handling.
The linked issue specifically refers to explorer.exe, and since validate_GUI_exit_status only deals with explorer.exe, I believe it should be fine to document here. What do you say?
tests/helper/test_helper.py
Outdated
media_path: str = "/tmp/zt-somerandomtext-image.png", | ||
) -> None: | ||
mocked_run = mocker.patch(MODULE + ".subprocess.run") | ||
mocker.patch("zulipterminal.platform_code.PLATFORM", platform) |
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.
See my comment on the other commit - you should be able to tell if this is working properly, by whether running the test shows the code sees the patched value properly. Something as simple as print(PLATFORM)
in the code will do the job - give it a try!
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.
Doesn't seem to work on my local WSL environment - trying to figure out why :)
I need to have both patched.
tests/helper/test_helper.py
Outdated
("footer_contrast", "1"), | ||
], | ||
), | ||
# NOTE: WSL always returns a non-zero exit code (1), so we do not test for it. |
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.
This is more re explorer.exe, right, rather than WSL?
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.
True, explorer.exe (WSL). Works?
("WSL", 1, "success"), | ||
("Linux", 1, "failure"), | ||
("MacOS", 1, "failure"), | ||
# NOTE: WSL always returns a non-zero exit code (1), so we do not test for it. |
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.
As per another comment, we should test for this, even if it results in the same response - we're testing the function, not the system behavior, in this test.
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.
I removed the failure handling entirely since it's considered an abnormality that might be addressed in the future. explorer.exe
seems to be intended to return 1 for failure and 0 for success, so returning 0 for a failure didn't make sense.
This could be updated if WSL fixes this, what do you think?
6853166
to
2f08b0b
Compare
Updated this PR, thanks for the feedback @neiljp! |
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.
@rsashank I'd like to get this merged to firm up the WSL behavior - while someone is testing it :)
Regards to the platform isolation, placing the remaining PLATFORM-dependent functionality in platform_code.py would be preferable and ease testing overall, and could be another refactor to explore in addition to the followup I mentioned in a comment.
tests/helper/test_helper.py
Outdated
mocker.patch(MODULE + ".PLATFORM", platform) | ||
mocker.patch("zulipterminal.platform_code.PLATFORM", platform) |
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.
Thanks for this feedback! This seems likely since we still use PLATFORM in both locations for this :/
This appears to be the only outstanding change in this commit after a rebase, since I merged the first commit previously, so the commit text is currently inaccurate at that point. It'd also be useful to group and comment the two lines, if they appear to be necessary to pass the tests, as well as update the commit.
This is a 'test bugfix' commit, specific to WSL, essentially?
" The tool ", | ||
("footer_contrast", "open"), | ||
" did not run successfully" ". Exited with ", | ||
("footer_contrast", "1"), |
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.
Reading this again, a reasonable PR after this would be to not output the error code, but provide more detailed output somewhere for followup later, a little like we do with the crash or threading errors. That, or try and diagnose further why the tool did not run properly.
We could also possibly provide a 'ran successfully' message in the footer for opening, but I've not looked at the code flow for that, and whether it would eg. overwrite other messages too rapidly?
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.
Understood 👍
Wouldn't diagnosing why the tool did not run properly be platform dependent though?
a237c02
to
9220bf9
Compare
Addressed issues with file path separators `\\` specific to WSL environments.
The process_media_tool function determines and returns the media tool used based on the OS.
efa23bb
to
532734c
Compare
@neiljp I've updated this PR—thank you! I added another commit to move the platform-based conditions in the helper function to platform_code.py. Can you elaborate on this a bit?
|
WSL always returns a non-zero exit code. The `successful_GUI_return_code()` function has been refactored to directly compare exit statuses and return "success" or "failure" accordingly. Fix open_media test to validate both the tool and the error code across various platforms. Refactor process_media to shift platform dependent code to platform_code.py.
532734c
to
fe589a5
Compare
What does this PR do, and why?
Addressed issues with file path separators
\\
and GUI return codes specific to WSL environments.Fixes the failing of these tests on WSL environments, these have been failing for a while now but I just got used to ignoring them, decided to look into them today and fix. 😓
Outstanding aspect(s)
External discussion & connections
How did you test this?
Self-review checklist for each commit
Visual changes