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

[trainer] sanitize test case name and test identifier consistently when looking up test failures #21565

Conversation

TheMetalCode
Copy link
Contributor

@TheMetalCode TheMetalCode commented Oct 9, 2023

Checklist

  • I've run bundle exec rspec from the root directory to see all new and existing tests pass
  • I've followed the fastlane code style and run bundle exec rubocop -a to ensure the code style is valid
  • I see several green ci/circleci builds in the "All checks have passed" section of my PR (connect CircleCI to GitHub if not)
  • I've read the Contribution Guidelines
  • I've updated the documentation if necessary.
  • I've added or updated relevant unit tests.

Motivation and Context

I recently had an issue in CI builds where failing tests were not being reported as failures once trainer converted the xcresult to junit xml. After digging in and debugging, I found that the existing logic in Trainer::XCResult::ActionTestMetadata#find_failure was expecting the test identifier to have a particular format that didn't end up matching. This led me to the insight that instead of having this expectation of the identifier, we could sanitize both it and the test case name consistently, then compare them for a potential match.

Using xcresult artifacts from the failing CI runs, this fix was effective. Unfortunately, since those xcresult artifacts contain proprietary data, I've yet to figure out how to unit test this safely. 🙈

Description

Testing Steps

.tr("-", "")
.tr("[", "")
.tr("]", "")
.tr(" ", "/")
Copy link
Contributor Author

Choose a reason for hiding this comment

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

In my case, this ended up being the unmet expectation - not all spaces were replaced by / in the identifier. So the comparison ended up being [somewhat redacted due to proprietary info]:

[1] pry(#<Trainer::XCResult::ActionTestMetadata>)> self.identifier
=> "MyPrivateSpec/my test condition, should return an error()"
[2] pry(#<Trainer::XCResult::ActionTestMetadata>)> sanitized_test_case_name
=> "MyPrivateSpec/my/test/condition,/should/return/an/error()"

Anyways, the bet I'm making with this PR is: rather than have any expectation of how self.identifier is formatted, sanitize both it and failure.test_case_name in the same fashion then compare.

Copy link
Member

@rogerluan rogerluan left a comment

Choose a reason for hiding this comment

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

Hi @TheMetalCode 👋

Thanks for this PR! Your rationale makes sense to me, and I think this is a good solution moving forward.

Do you mind adding unit tests to this PR, hopefully with real-life strings for both test case name and identifiers? Ideally we should cover the happy path (scenarios where the previous implementation used to work) as well as the edge case you were seeing (so that it fails, when run using the previous comparison algorithm, but succeeds now using the new algorithm). That would be super!

Let me know if you need any support adding these tests 🤗 thanks again for your hard work! 🙏

PS: If you could also add steps to reproduce this issue locally so we can verify your results, that would be great. The simpler these steps are, the better (extra points if you can provide a demo project where the issue is reproducible) 🙇

@rogerluan rogerluan changed the title [trainer] Sanitize Test Case Name and Test Identifier Consistently when Finding Test Failures [trainer] sanitize test case name and test identifier consistently when looking up test failures Dec 19, 2023
@rogerluan
Copy link
Member

Heads up: no need to implement the unit tests in this PR. I decided to merge part of this PR's solution into the PR #21432 where we already have unit tests and a sample project, so once we merge that PR, this one can be closed 🙇

Thanks for the contribution in this PR! 🙌

@TheMetalCode
Copy link
Contributor Author

Heads up: no need to implement the unit tests in this PR. I decided to merge part of this PR's solution into the PR #21432 where we already have unit tests and a sample project, so once we merge that PR, this one can be closed 🙇

Thanks for the contribution in this PR! 🙌

That's great, thank you!

My struggle with unit tests on this one is that I had them locally but they were relying on sample xcresult bundles from a private project and I didn't know of a way to edit xcresult files to make them non-proprietary. This private project is using Quick/Nimble though, didn't realize that in and of itself would create the error condition.

Anyways, happy to have influenced #21432, looking forward to the fix!

@TheMetalCode TheMetalCode force-pushed the jjh/trainer-sanitize-test-case-and-identifier-consistently branch from 13ed3d4 to ce58be5 Compare January 2, 2024 19:54
jaysoffian added a commit to jaysoffian/fastlane that referenced this pull request Apr 24, 2024
When trainer is parsing an xcresult bundle which contains test
failures, it has an `ActionTestMetadata` object that is identified one
way (by "identifier") and it's trying to find the corresponding
`TestFailureIssueSummary` object that's identified another way (by
`testCaseName`). These values are not the same, so in order to locate
the correct `TestFailureIssueSummary` object it needs to transform the
`testCaseName` in the same way that Xcode does when generating the
`ActionTestMetadata` identifier. Exactly how to do this is
undocumented, so folks have attempted to figure it out empirically.

Most recently, dda4007 ([trainer] fix issues where number of
failures would always be zero (fastlane#21432), 2024-01-10) changed this
transformation code in a way that fixed test names that contain spaces,
but broke Objective-C test names.

This commit fixes the regression caused by dda4007 with ObjC tests
as follows:

1) It reverts the transformation behavior to how the code worked
previously. Instead of "sanitizing" both the identifier and the test
case name, it now keeps the identifier as is and "normalizes" the test
case name. The test case name normalization has been moved into its own
method which passes unit tests for ObjC, Swift, and tests with spaces.

2) It adds an ObjC xcresult bundle and unit test to prevent regressing
parsing ObjC test names.

3) It refactors summaries_to_data so that if the corresponding test
failure message cannot be located (but hopefully that won't happen
anymore), we at least properly report that the test failed, but use the
generic "unknown failure message" as the failure message.

See discussion on:

- fastlane#21565
- fastlane#21432
jaysoffian added a commit to jaysoffian/fastlane that referenced this pull request Apr 25, 2024
When trainer is parsing an xcresult bundle which contains test
failures, it has an `ActionTestMetadata` object that is identified one
way (by "identifier") and it's trying to find the corresponding
`TestFailureIssueSummary` object that's identified another way (by
`testCaseName`). These values are not the same, so in order to locate
the correct `TestFailureIssueSummary` object it needs to transform the
`testCaseName` in the same way that Xcode does when generating the
`ActionTestMetadata` identifier. Exactly how to do this is
undocumented, so folks have attempted to figure it out empirically.

Most recently, dda4007 ([trainer] fix issues where number of
failures would always be zero (fastlane#21432), 2024-01-10) changed this
transformation code in a way that fixed test names that contain spaces,
but broke Objective-C test names.

This commit fixes the regression caused by dda4007 with ObjC tests
as follows:

1) It reverts the transformation behavior to how the code worked
previously. Instead of "sanitizing" both the identifier and the test
case name, it now keeps the identifier as is and "normalizes" the test
case name. The test case name normalization has been moved into its own
method which passes unit tests for ObjC, Swift, and tests with spaces.

2) It adds an ObjC xcresult bundle and unit test to prevent regressing
parsing ObjC test names.

3) It refactors summaries_to_data so that if the corresponding test
failure message cannot be located (but hopefully that won't happen
anymore), we at least properly report that the test failed, but use the
generic "unknown failure message" as the failure message.

See discussion on:

- fastlane#21565
- fastlane#21432
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.

None yet

2 participants