Test Performance Issues: Fixed Delays and Inefficient Patterns
Analysis Date: 2025-11-12
Repository: eclipse.platform.ui
Scope: All test bundles under tests/ directory
Executive Summary
This analysis identified significant performance issues in the test suite related to fixed time delays and inefficient waiting patterns. These issues cause tests to run slower than necessary and reduce the reliability of the test suite.
Key Findings:
- 80+ instances of
Thread.sleep() with fixed delays ranging from 10ms to 2000ms
- 10+ instances of extremely long
DisplayHelper.sleep() calls (10+ seconds, some over 2 hours!)
- Multiple polling loops with fixed delay intervals instead of condition-based waiting
- Inefficient busy-wait patterns that waste CPU cycles
Categories of Issues
1. Fixed Thread.sleep() Delays
Issue Description
Tests use Thread.sleep() with fixed durations, causing tests to wait for a predetermined time regardless of whether the condition is already met. This makes tests slower and less reliable (too short = flaky, too long = slow).
Examples
High Impact (Long Delays):
-
KeyDispatcherTest.java:255 - 2 second sleep
tests/org.eclipse.e4.ui.bindings.tests/src/org/eclipse/e4/ui/bindings/tests/KeyDispatcherTest.java:255
Thread.sleep(2000L);
-
Bug78470Test.java:117 - 2 second sleep
tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/internal/Bug78470Test.java:117
Thread.sleep(2000);
-
ESelectionServiceTest.java:1014, 1019 - 1 second sleeps
tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/tests/application/ESelectionServiceTest.java:1014
tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/tests/application/ESelectionServiceTest.java:1019
Thread.sleep(1000);
-
Browser Tests - Multiple 2 second sleeps
tests/org.eclipse.ui.tests.browser/src/org/eclipse/ui/tests/browser/internal/ExternalBrowserTestCase.java:34, 42, 50
Thread.sleep(2000);
-
ResourceInitialSelectionTest.java:429 - 1 second retry delay
tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/dialogs/ResourceInitialSelectionTest.java:429
Thread.sleep(1000); // Wait 1 second before retry
Medium Impact (100-500ms delays):
-
ProgressViewTests.java:159 - 200ms throttled update wait
tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/progress/ProgressViewTests.java:159
Thread.sleep(200); // wait till throttled update ran.
-
FileDocumentProviderTest.java:239 - 100ms filesystem timestamp wait
tests/org.eclipse.ui.editors.tests/src/org/eclipse/ui/editors/tests/FileDocumentProviderTest.java:239
Thread.sleep(100);
-
MultiEditorTest.java:451 - 500ms delay
tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/multieditor/MultiEditorTest.java:451
Thread.sleep(500);
Low Impact but Cumulative (10-100ms delays):
Multiple test files with 10-100ms sleeps that add up across the test suite:
- ScreenshotTest.java:192 (100ms)
- ExpandableCompositeTest.java:142 (100ms)
- SizeCacheTest.java:96 (100ms)
- Multiple field assist tests (10ms each)
- Multiple DnD tests (10ms each)
- StickyScrollingHandlerTest.java:187, 189, 191 (10ms each)
2. Polling Loops with Fixed Delays
Issue Description
Tests use while loops that repeatedly check a condition with fixed Thread.sleep() delays between checks. This is inefficient and can lead to flaky tests.
Examples
-
FileDocumentProviderTest.java:240-244 - Busy loop with 10ms sleep
while (fsManager.fastIsSynchronized(file) && count < 1000) {
Files.setLastModifiedTime(file.getLocation().toFile().toPath(),
FileTime.fromMillis(System.currentTimeMillis()));
Thread.sleep(10); // Fixed delay in loop
count++;
}
Issue: Runs up to 1000 iterations with 10ms delays = up to 10 seconds worst case
-
TextFileDocumentProviderTest.java:228-231 - Similar pattern
while (fsManager.fastIsSynchronized(file) && count < 1000) {
Files.setLastModifiedTime(file.getLocation().toFile().toPath(),
FileTime.fromMillis(System.currentTimeMillis()));
Thread.sleep(10);
count++;
}
-
SorterTest.java:165-183 - Multiple polling loops with 100ms delays
while (!passed) {
items = _viewer.getTree().getItems();
// ... assertions ...
if (!childItems[0].getText().equals("f1") && count-- >= 0) {
DisplayHelper.sleep(100); // Fixed 100ms delay
continue;
}
passed = true;
}
Issue: Repeated pattern 3 times in same test, could wait up to several seconds
-
FindReplaceTestUtil.java:34-42 - Display pump with fixed delay
while (display.readAndDispatch()) {
// do nothing
}
Thread.sleep(50); // Fixed delay after event processing
3. Extremely Long DisplayHelper.sleep() Calls
Issue Description
Some tests contain DisplayHelper.sleep() calls with extremely long timeouts (10+ seconds, some over 2 hours). These appear to be debugging aids that were left in the code, often commented out but sometimes active.
Examples
CRITICAL - Active Long Sleeps:
- PR263695.java:87 - 2 second sleep (ACTIVE)
tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/dndtest/PR263695.java:87
Thread.sleep(2000);
CRITICAL - Commented but Dangerous:
-
M12Tests.java:122 - 10 million milliseconds (~2.8 hours!)
tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/M12Tests.java:122
DisplayHelper.sleep(10000000);
-
ActionProviderTest.java:85, 133 - 10 million milliseconds
tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/ActionProviderTest.java:85
tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/ActionProviderTest.java:133
DisplayHelper.sleep(10000000);
-
LabelProviderTest.java - Multiple 10 million millisecond sleeps
tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/LabelProviderTest.java:296, 317, 344, 370
DisplayHelper.sleep(10000000);
-
LinkHelperTest.java:72 - 100 million milliseconds (~27.8 hours!)
tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/LinkHelperTest.java:72
DisplayHelper.sleep(100000000);
-
PerformanceTest.java:92, 223 - 10 million milliseconds
tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/PerformanceTest.java:92
tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/PerformanceTest.java:223
DisplayHelper.sleep(Display.getCurrent(), 10000000);
-
NavigatorTestBase.java:238 - 1 million milliseconds (~16.7 minutes)
tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/NavigatorTestBase.java:238
DisplayHelper.sleep(1000000);
Note: Many of these are commented out or only conditionally executed, but they pose a risk if accidentally enabled.
4. Inefficient Wait Patterns in Test Utilities
Issue Description
Test utility classes sometimes use inefficient patterns that propagate throughout the test suite.
Examples
-
UITestUtil.java:177 - Fixed 20ms sleep in event processing
tests/org.eclipse.ui.tests.harness/src/org/eclipse/ui/tests/harness/util/UITestUtil.java:177
Thread.sleep(20);
-
EditorTestHelper.java:186 - Fixed interval sleep
tests/org.eclipse.ui.tests.harness/src/org/eclipse/ui/tests/harness/util/EditorTestHelper.java:186
Thread.sleep(intervalTime);
-
ViewerTestCase.java:137 - Generic sleep utility
tests/org.eclipse.jface.tests/src/org/eclipse/jface/tests/viewers/ViewerTestCase.java:137
Thread.sleep(millis);
5. Race Conditions and Timing Issues
Issue Description
Some tests show signs of race conditions where fixed delays are used to "hope" that asynchronous operations complete.
Examples
-
ProgressViewTests.java:159 - Comment indicates uncertainty
Thread.sleep(200); // wait till throttled update ran.
Issue: No guarantee that 200ms is enough
-
FileDocumentProviderTest.java:238-239 - File system timing race
// Give the file system a chance to have a *different* timestamp
Thread.sleep(100);
Issue: File system granularity varies by platform
-
WorkingSetTests.java:106, 129 - 250ms delays with no clear reason
tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/dynamicplugins/WorkingSetTests.java:106
tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/dynamicplugins/WorkingSetTests.java:129
Thread.sleep(250);
-
StickyScrollingHandlerTest.java:187-191 - Sequential 10ms sleeps
Thread.sleep(10);
// ... operation ...
Thread.sleep(10);
// ... operation ...
Thread.sleep(10);
Issue: Appears to be timing-sensitive operations that need proper synchronization
Recommended Solutions
1. Replace Fixed Delays with Condition-Based Waiting
Current Pattern:
doSomethingAsync();
Thread.sleep(1000); // Hope it's done
assertTrue(condition);
Recommended Pattern:
doSomethingAsync();
assertTrue(DisplayHelper.waitForCondition(display, 5000, () -> condition));
Benefits:
- Test completes as soon as condition is met (often much faster)
- More reliable (doesn't depend on arbitrary timeout)
- Clearer test intent
2. Use DisplayHelper.waitForCondition() Instead of Sleep
The codebase already has DisplayHelper.waitForCondition() which properly waits for conditions while processing the event loop. It should be used instead of fixed sleeps.
Example Conversion:
Before:
viewer.refresh();
Thread.sleep(100);
assertEquals(expected, actual);
After:
viewer.refresh();
DisplayHelper.waitForCondition(display, 1000, () -> expected.equals(actual));
3. Use Proper Synchronization for Async Operations
For tests that wait for asynchronous operations (jobs, UI updates, etc.), use appropriate synchronization mechanisms:
- For Jobs: Use
job.join() or Job.getJobManager().join()
- For UI Updates: Use
DisplayHelper.waitForCondition() with event loop processing
- For File System: Use workspace refresh notifications or listeners
- For Observable Values: Use proper listeners instead of polling
4. Remove or Fix Extremely Long Sleeps
Actions:
- Remove all
DisplayHelper.sleep() calls > 1 second
- Convert debug sleeps to conditional compilation or separate manual test classes
- Add assertions with timeouts instead of blind delays
5. Fix Polling Loops
Before:
int count = 0;
while (!condition && count < maxRetries) {
Thread.sleep(interval);
count++;
}
After:
assertTrue(DisplayHelper.waitForCondition(display, maxRetries * interval, () -> condition));
6. Platform-Specific File System Handling
For file system timestamp tests, use platform-aware approaches:
// Instead of fixed 100ms sleep
Thread.sleep(100);
// Use proper file system granularity detection
long granularity = getFileSystemTimeGranularity();
Thread.sleep(granularity + 10); // Add small buffer
Or better yet, use workspace synchronization events.
7. Add Test Timeout Configuration
For tests that genuinely need to wait for external events, use configurable timeouts:
// Allow override via system property for slow CI environments
long timeout = Long.getLong("test.timeout.ms", 5000);
DisplayHelper.waitForCondition(display, timeout, condition);
Priority Assessment
Critical Priority (Fix Immediately)
- All
DisplayHelper.sleep() calls > 5 seconds (risk of accidental activation)
- Polling loops with high iteration counts (FileDocumentProviderTest, TextFileDocumentProviderTest)
- Known flaky tests with timing issues
High Priority (Fix in Next Sprint)
- All
Thread.sleep() > 500ms (KeyDispatcherTest, Bug78470Test, ESelectionServiceTest, browser tests)
- Polling loops in viewer tests (SorterTest)
- Utility methods with fixed delays (UITestUtil, EditorTestHelper)
Medium Priority (Ongoing Improvement)
Thread.sleep() calls 100-500ms
- Race condition-prone patterns (ProgressViewTests, WorkingSetTests)
- Repeated patterns in similar tests
Low Priority (Opportunistic)
- Short sleeps (10-50ms) in stable tests
- Screenshot and manual test utilities
- Performance test infrastructure
Impact Analysis
Current State
- Estimated cumulative fixed delay time: 60+ seconds per full test suite run (conservative estimate)
- Many tests wait 5-10x longer than necessary
- Flaky test risk due to race conditions
- CI pipeline slower than necessary
Expected Improvements After Fixes
- 50-80% reduction in time spent in fixed delays
- More reliable tests (fewer false positives/negatives)
- Faster feedback for developers
- Clearer test intent (explicit conditions vs. mysterious delays)
Test Bundles Affected
Most Affected:
- org.eclipse.ui.tests.navigator - 40+ instances of DisplayHelper.sleep, including extremely long ones
- org.eclipse.ui.tests - 25+ instances of Thread.sleep
- org.eclipse.ui.editors.tests - 15+ instances with polling loops
- org.eclipse.jface.tests - 10+ instances in viewer tests
- org.eclipse.ui.genericeditor.tests - Multiple async content assist tests
Moderately Affected:
- org.eclipse.e4.ui.tests
- org.eclipse.ui.workbench.texteditor.tests
- org.eclipse.jface.text.tests
- org.eclipse.ui.tests.browser
- org.eclipse.ui.tests.forms
Less Affected but Still Need Review:
- org.eclipse.search.tests
- org.eclipse.ltk.core.refactoring.tests
- org.eclipse.core.filebuffers.tests
- org.eclipse.ui.monitoring.tests
Implementation Strategy
Phase 1: Remove Dangerous Code (1 day)
- Remove or properly disable all sleeps > 5 seconds
- Add code review rules to prevent reintroduction
Phase 2: Fix High-Impact Tests (1 week)
- Convert long Thread.sleep() calls to condition-based waits
- Fix polling loops in editor and viewer tests
- Improve test utility methods
Phase 3: Systematic Cleanup (2-3 weeks)
- Process each test bundle systematically
- Establish patterns and helper methods
- Document best practices
Phase 4: Infrastructure Improvements (ongoing)
- Add test performance monitoring
- Create guidelines for async test patterns
- Update developer documentation
Best Practices for Future Tests
DO:
✅ Use DisplayHelper.waitForCondition() for UI-dependent conditions
✅ Use job.join() for job completion
✅ Use explicit timeout values with clear meaning
✅ Write tests that fail fast if condition isn't met
✅ Add comments explaining why waits are necessary
DON'T:
❌ Use Thread.sleep() in tests (except for very specific timing tests)
❌ Use arbitrary timeout values (100, 500, 1000) without justification
❌ Create polling loops with fixed intervals
❌ Leave debug sleeps in committed code
❌ Assume operations complete within fixed time
Conclusion
The Eclipse Platform UI test suite has significant opportunities for performance improvement by replacing fixed delays with condition-based waiting. The existing DisplayHelper infrastructure provides good tools for this, but they need to be used more consistently throughout the codebase.
Estimated Overall Impact:
- Current test overhead from fixed delays: 60-120 seconds per full run
- Potential time savings: 40-90 seconds per full run (50-75% reduction)
- Additional benefits: More reliable tests, clearer test intent, better CI efficiency
Next Steps:
- Review and approve this analysis
- Create issues/tasks for each priority level
- Begin implementation starting with critical priority items
- Establish code review guidelines to prevent regression
Test Performance Issues: Fixed Delays and Inefficient Patterns
Analysis Date: 2025-11-12
Repository: eclipse.platform.ui
Scope: All test bundles under
tests/directoryExecutive Summary
This analysis identified significant performance issues in the test suite related to fixed time delays and inefficient waiting patterns. These issues cause tests to run slower than necessary and reduce the reliability of the test suite.
Key Findings:
Thread.sleep()with fixed delays ranging from 10ms to 2000msDisplayHelper.sleep()calls (10+ seconds, some over 2 hours!)Categories of Issues
1. Fixed Thread.sleep() Delays
Issue Description
Tests use
Thread.sleep()with fixed durations, causing tests to wait for a predetermined time regardless of whether the condition is already met. This makes tests slower and less reliable (too short = flaky, too long = slow).Examples
High Impact (Long Delays):
KeyDispatcherTest.java:255 - 2 second sleep
Bug78470Test.java:117 - 2 second sleep
ESelectionServiceTest.java:1014, 1019 - 1 second sleeps
Browser Tests - Multiple 2 second sleeps
ResourceInitialSelectionTest.java:429 - 1 second retry delay
Medium Impact (100-500ms delays):
ProgressViewTests.java:159 - 200ms throttled update wait
FileDocumentProviderTest.java:239 - 100ms filesystem timestamp wait
MultiEditorTest.java:451 - 500ms delay
Low Impact but Cumulative (10-100ms delays):
Multiple test files with 10-100ms sleeps that add up across the test suite:
2. Polling Loops with Fixed Delays
Issue Description
Tests use while loops that repeatedly check a condition with fixed
Thread.sleep()delays between checks. This is inefficient and can lead to flaky tests.Examples
FileDocumentProviderTest.java:240-244 - Busy loop with 10ms sleep
Issue: Runs up to 1000 iterations with 10ms delays = up to 10 seconds worst case
TextFileDocumentProviderTest.java:228-231 - Similar pattern
SorterTest.java:165-183 - Multiple polling loops with 100ms delays
Issue: Repeated pattern 3 times in same test, could wait up to several seconds
FindReplaceTestUtil.java:34-42 - Display pump with fixed delay
3. Extremely Long DisplayHelper.sleep() Calls
Issue Description
Some tests contain
DisplayHelper.sleep()calls with extremely long timeouts (10+ seconds, some over 2 hours). These appear to be debugging aids that were left in the code, often commented out but sometimes active.Examples
CRITICAL - Active Long Sleeps:
CRITICAL - Commented but Dangerous:
M12Tests.java:122 - 10 million milliseconds (~2.8 hours!)
ActionProviderTest.java:85, 133 - 10 million milliseconds
LabelProviderTest.java - Multiple 10 million millisecond sleeps
LinkHelperTest.java:72 - 100 million milliseconds (~27.8 hours!)
PerformanceTest.java:92, 223 - 10 million milliseconds
NavigatorTestBase.java:238 - 1 million milliseconds (~16.7 minutes)
Note: Many of these are commented out or only conditionally executed, but they pose a risk if accidentally enabled.
4. Inefficient Wait Patterns in Test Utilities
Issue Description
Test utility classes sometimes use inefficient patterns that propagate throughout the test suite.
Examples
UITestUtil.java:177 - Fixed 20ms sleep in event processing
EditorTestHelper.java:186 - Fixed interval sleep
ViewerTestCase.java:137 - Generic sleep utility
5. Race Conditions and Timing Issues
Issue Description
Some tests show signs of race conditions where fixed delays are used to "hope" that asynchronous operations complete.
Examples
ProgressViewTests.java:159 - Comment indicates uncertainty
Issue: No guarantee that 200ms is enough
FileDocumentProviderTest.java:238-239 - File system timing race
Issue: File system granularity varies by platform
WorkingSetTests.java:106, 129 - 250ms delays with no clear reason
StickyScrollingHandlerTest.java:187-191 - Sequential 10ms sleeps
Issue: Appears to be timing-sensitive operations that need proper synchronization
Recommended Solutions
1. Replace Fixed Delays with Condition-Based Waiting
Current Pattern:
Recommended Pattern:
Benefits:
2. Use DisplayHelper.waitForCondition() Instead of Sleep
The codebase already has
DisplayHelper.waitForCondition()which properly waits for conditions while processing the event loop. It should be used instead of fixed sleeps.Example Conversion:
Before:
After:
3. Use Proper Synchronization for Async Operations
For tests that wait for asynchronous operations (jobs, UI updates, etc.), use appropriate synchronization mechanisms:
job.join()orJob.getJobManager().join()DisplayHelper.waitForCondition()with event loop processing4. Remove or Fix Extremely Long Sleeps
Actions:
DisplayHelper.sleep()calls > 1 second5. Fix Polling Loops
Before:
After:
6. Platform-Specific File System Handling
For file system timestamp tests, use platform-aware approaches:
Or better yet, use workspace synchronization events.
7. Add Test Timeout Configuration
For tests that genuinely need to wait for external events, use configurable timeouts:
Priority Assessment
Critical Priority (Fix Immediately)
DisplayHelper.sleep()calls > 5 seconds (risk of accidental activation)High Priority (Fix in Next Sprint)
Thread.sleep()> 500ms (KeyDispatcherTest, Bug78470Test, ESelectionServiceTest, browser tests)Medium Priority (Ongoing Improvement)
Thread.sleep()calls 100-500msLow Priority (Opportunistic)
Impact Analysis
Current State
Expected Improvements After Fixes
Test Bundles Affected
Most Affected:
Moderately Affected:
Less Affected but Still Need Review:
Implementation Strategy
Phase 1: Remove Dangerous Code (1 day)
Phase 2: Fix High-Impact Tests (1 week)
Phase 3: Systematic Cleanup (2-3 weeks)
Phase 4: Infrastructure Improvements (ongoing)
Best Practices for Future Tests
DO:
✅ Use
DisplayHelper.waitForCondition()for UI-dependent conditions✅ Use
job.join()for job completion✅ Use explicit timeout values with clear meaning
✅ Write tests that fail fast if condition isn't met
✅ Add comments explaining why waits are necessary
DON'T:
❌ Use
Thread.sleep()in tests (except for very specific timing tests)❌ Use arbitrary timeout values (100, 500, 1000) without justification
❌ Create polling loops with fixed intervals
❌ Leave debug sleeps in committed code
❌ Assume operations complete within fixed time
Conclusion
The Eclipse Platform UI test suite has significant opportunities for performance improvement by replacing fixed delays with condition-based waiting. The existing
DisplayHelperinfrastructure provides good tools for this, but they need to be used more consistently throughout the codebase.Estimated Overall Impact:
Next Steps: