Chromium Code Reviews

Side by Side Diff: chrome/browser/cocoa/cocoa_test_helper.mm

Issue 660213: [Mac] Make CocoaTest::TearDown() more scalable in the face of valgrind. (Closed)
Patch Set: get rid of last bit of royalty. the world is a dark and bitter place. Created 10 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
« no previous file with comments | « chrome/browser/cocoa/cocoa_test_helper.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import "chrome/browser/cocoa/cocoa_test_helper.h" 5 #import "chrome/browser/cocoa/cocoa_test_helper.h"
6 #import "chrome/browser/chrome_browser_application_mac.h" 6 #import "chrome/browser/chrome_browser_application_mac.h"
7 #import "base/logging.h" 7 #import "base/logging.h"
8 8
9 @implementation CocoaTestHelperWindow 9 @implementation CocoaTestHelperWindow
10 10
(...skipping 62 matching lines...)
73 } 73 }
74 74
75 void CocoaTest::TearDown() { 75 void CocoaTest::TearDown() {
76 called_tear_down_ = true; 76 called_tear_down_ = true;
77 // Call close on our test_window to clean it up if one was opened. 77 // Call close on our test_window to clean it up if one was opened.
78 [test_window_ close]; 78 [test_window_ close];
79 test_window_ = nil; 79 test_window_ = nil;
80 80
81 // Recycle the pool to clean up any stuff that was put on the 81 // Recycle the pool to clean up any stuff that was put on the
82 // autorelease pool due to window or windowcontroller closures. 82 // autorelease pool due to window or windowcontroller closures.
83 // Note that many controls (NSTextFields, NSComboboxes etc) may call
84 // performSelector:withDelay: to clean up drag handlers and other things.
85 // We must spin the event loop a bit to make sure that everything gets cleaned
86 // up correctly. We will wait up to one second for windows to clean themselves
87 // up (normally only takes one to two loops through the event loop).
88 // Radar 5851458 "Closing a window with a NSTextView in it should get rid of
89 // it immediately"
90 pool_.Recycle(); 83 pool_.Recycle();
91 NSDate *start_date = [NSDate date];
92 const std::vector<NSWindow*> windows_waiting(ApplicationWindows());
93 84
94 bool loop = windows_waiting.size() > 0; 85 // Some controls (NSTextFields, NSComboboxes etc) use
95 while (loop) { 86 // performSelector:withDelay: to clean up drag handlers and other
96 { 87 // things (Radar 5851458 "Closing a window with a NSTextView in it
97 // Need an autorelease pool to wrap our event loop. 88 // should get rid of it immediately"). The event loop must be spun
98 base::ScopedNSAutoreleasePool pool; 89 // to get everything cleaned up correctly. It normally only takes
99 NSEvent *next_event = [NSApp nextEventMatchingMask:NSAnyEventMask 90 // one to two spins through the event loop to see a change.
100 untilDate:nil 91
101 inMode:NSDefaultRunLoopMode 92 // NOTE(shess): Under valgrind, -nextEventMatchingMask:* in one test
102 dequeue:YES]; 93 // needed to run twice, once taking .2 seconds, the next time .6
103 [NSApp sendEvent:next_event]; 94 // seconds. The loop exit condition attempts to be scalable.
104 [NSApp updateWindows]; 95
96 // Get the set of windows which weren't present when the test
97 // started.
98 std::set<NSWindow*> windows_left(WindowsLeft());
99
100 while (windows_left.size() > 0) {
101 // Cover delayed actions by spinning the loop at least once after
102 // this timeout.
103 const NSTimeInterval kCloseTimeout = 1.0;
104
105 // Cover chains of delayed actions by spinning the loop at least
106 // this many times.
107 const int kCloseSpins = 2;
108
109 // Track the set of remaining windows so that everything can be
110 // reset if progress is made.
111 std::set<NSWindow*> still_left = windows_left;
112
113 NSDate* start_date = [NSDate date];
114 bool one_more_time = true;
115 int spins = 0;
116 while (still_left.size() == windows_left.size() &&
117 (spins < kCloseSpins || one_more_time)) {
118 // Check the timeout before pumping events, so that we'll spin
119 // the loop once after the timeout.
120 one_more_time = ([start_date timeIntervalSinceNow] > -kCloseTimeout);
121
122 // Autorelease anything thrown up by the event loop.
123 {
124 base::ScopedNSAutoreleasePool pool;
125 ++spins;
126 NSEvent *next_event = [NSApp nextEventMatchingMask:NSAnyEventMask
127 untilDate:nil
128 inMode:NSDefaultRunLoopMode
129 dequeue:YES];
130 [NSApp sendEvent:next_event];
131 [NSApp updateWindows];
132 }
133
134 // Refresh the outstanding windows.
135 still_left = WindowsLeft();
105 } 136 }
106 // Check the windows after we have released the event loop pool so that
107 // all retains are cleaned up.
108 const std::vector<NSWindow*> current_windows(ApplicationWindows());
109 std::vector<NSWindow*> windows_left;
110 std::set_difference(current_windows.begin(),
111 current_windows.end(),
112 initial_windows_.begin(),
113 initial_windows_.end(),
114 inserter(windows_left, windows_left.begin()));
115 137
116 if (windows_left.size() == 0) { 138 // If no progress is being made, log a failure and continue.
117 // All our windows are closed. 139 if (still_left.size() == windows_left.size()) {
118 break; 140 // NOTE(shess): Failing this expectation means that the test
119 } 141 // opened windows which have not been fully released. Either
120 if ([start_date timeIntervalSinceNow] < -1.0) { 142 // there is a leak, or perhaps one of |kCloseTimeout| or
121 // Took us over a second to shut down, and windows still exist. 143 // |kCloseSpins| needs adjustment.
122 // Log a failure and continue.
123 EXPECT_EQ(0U, windows_left.size()); 144 EXPECT_EQ(0U, windows_left.size());
124 for (size_t i = 0; i < windows_left.size(); ++i) { 145 for (std::set<NSWindow*>::iterator iter = windows_left.begin();
125 const char* desc = [[windows_left[i] description] UTF8String]; 146 iter != windows_left.end(); ++iter) {
147 const char* desc = [[*iter description] UTF8String];
126 LOG(WARNING) << "Didn't close window " << desc; 148 LOG(WARNING) << "Didn't close window " << desc;
127 } 149 }
128 break; 150 break;
129 } 151 }
152
153 windows_left = still_left;
130 } 154 }
131 PlatformTest::TearDown(); 155 PlatformTest::TearDown();
132 } 156 }
133 157
134 std::vector<NSWindow*> CocoaTest::ApplicationWindows() { 158 std::set<NSWindow*> CocoaTest::ApplicationWindows() {
135 // This must NOT retain the windows it is returning. 159 // This must NOT retain the windows it is returning.
136 std::vector<NSWindow*> windows; 160 std::set<NSWindow*> windows;
161
137 // Must create a pool here because [NSApp windows] has created an array 162 // Must create a pool here because [NSApp windows] has created an array
138 // with retains on all the windows in it. 163 // with retains on all the windows in it.
139 base::ScopedNSAutoreleasePool pool; 164 base::ScopedNSAutoreleasePool pool;
140 NSArray *appWindows = [NSApp windows]; 165 NSArray *appWindows = [NSApp windows];
141 for (NSWindow *window in appWindows) { 166 for (NSWindow *window in appWindows) {
142 windows.push_back(window); 167 windows.insert(window);
143 } 168 }
144 return windows; 169 return windows;
145 } 170 }
146 171
172 std::set<NSWindow*> CocoaTest::WindowsLeft() {
173 const std::set<NSWindow*> windows(ApplicationWindows());
174 std::set<NSWindow*> windows_left;
175 std::set_difference(windows.begin(), windows.end(),
176 initial_windows_.begin(), initial_windows_.end(),
177 std::inserter(windows_left, windows_left.begin()));
178 return windows_left;
179 }
180
147 CocoaTestHelperWindow* CocoaTest::test_window() { 181 CocoaTestHelperWindow* CocoaTest::test_window() {
148 if (!test_window_) { 182 if (!test_window_) {
149 test_window_ = [[CocoaTestHelperWindow alloc] init]; 183 test_window_ = [[CocoaTestHelperWindow alloc] init];
150 if (DebugUtil::BeingDebugged()) { 184 if (DebugUtil::BeingDebugged()) {
151 [test_window_ orderFront:nil]; 185 [test_window_ orderFront:nil];
152 } else { 186 } else {
153 [test_window_ orderBack:nil]; 187 [test_window_ orderBack:nil];
154 } 188 }
155 } 189 }
156 return test_window_; 190 return test_window_;
157 } 191 }
OLDNEW
« no previous file with comments | « chrome/browser/cocoa/cocoa_test_helper.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine