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

toEventually in Xcode 15 somtimes results in "main run loop was unresponsive" #1095

Open
obrhoff opened this issue Nov 1, 2023 · 6 comments

Comments

@obrhoff
Copy link

obrhoff commented Nov 1, 2023

What did you do?

We upgraded our Azure DevOps Pipeline from Xcode 14 to 15.

What did you expect to happen?

Tests that use toEventually() should succeed like before.

What actually happened instead?

Some Tests are now randomly failing with main run loop was unresponsive when they use toEventually()

The tests are really simple.

func testConsentOnAppear() {
	// when
	sut.handle(.appear)

	// then
	expect(self.userConsentProvider.calls)
		.toEventually(
			equal([.presentInitialConsent]
			)
		)
}

Environment

List the software versions you're using:

  • Nimble: 13.0.0
  • Xcode Version: 15.0.1 (15A507)
  • Swift Version: 5.9

Please also mention which package manager you used and its version. Delete the
other package managers in this list:

  • Swift Package Manager *5.8.
@obrhoff
Copy link
Author

obrhoff commented Nov 2, 2023

After digging more into this topic, I suspect that this is related to the issue: https://discuss.circleci.com/t/severe-performance-problems-with-xcode-15/49205

@tahirmt
Copy link

tahirmt commented Jul 15, 2024

@obrhoff were you able to find any solution for this? I have many of these issues with toEventually and waitUntil tests. They work if the test is run individually but as a full suite I get this error a lot.

@obrhoff
Copy link
Author

obrhoff commented Jul 15, 2024

Unfortunately not. It still happened randomly, and I left the project to keep track of what happened in the meantime.

@tahirmt
Copy link

tahirmt commented Jul 15, 2024

@younata do you have any ideas about this? Not sure how common this issue is but in our projects this happens 100% of the time when running the full suite.

@younata
Copy link
Member

younata commented Jul 18, 2024

Hey @tahirmt

The "main run loop was unresponsive" error happens when the the main thread gets blocked while canceling the polling.

The way that polling expectations work is that they run 2 tasks at the same time. The first task runs on the main thread and does the work of continuously polling the matcher until the conditions of the assertion pass. The second task runs on a background thread, where it waits until the timeout period has passed, and if the second task hasn't been canceled yet, then it cancels the first task and reports a failure.

This second task failing to cancel the first task in time is what causes the "main run loop was unresponsive" error to happen. It's a minor race condition where if the main thread is blocked long enough for the DispatchSemaphore.wait(timeout:) to not return .success, then Nimble reports that error. With large codebases that make liberal use of polling expectations, the chances of this error happening increases dramatically, as you've discovered.

Fixing this race condition is on my radar, but this is rather complex code and I'm always a bit hesitant to mess with it.

@aleksanderlorenc-lw
Copy link

Has anyone found a resilient workaround for this? Every once in a while we seem to be affected by this issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants