1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/basictypes.h" 6 #include "base/command_line.h" 7 #include "base/file_util.h" 8 #include "base/files/file_path.h" 9 #include "base/path_service.h" 10 #include "base/strings/string_util.h" 11 #include "base/threading/platform_thread.h" 12 #include "base/threading/thread_restrictions.h" 13 #include "chrome/common/chrome_constants.h" 14 #include "chrome/common/chrome_paths.h" 15 #include "chrome/common/chrome_switches.h" 16 #include "chrome/common/net/url_fixer_upper.h" 17 #include "chrome/test/automation/automation_proxy.h" 18 #include "chrome/test/automation/browser_proxy.h" 19 #include "chrome/test/automation/tab_proxy.h" 20 #include "chrome/test/automation/window_proxy.h" 21 #include "chrome/test/base/chrome_process_util.h" 22 #include "chrome/test/perf/perf_test.h" 23 #include "chrome/test/ui/ui_perf_test.h" 24 #include "gpu/command_buffer/service/gpu_switches.h" 25 #include "net/base/net_util.h" 26 #include "testing/gtest/include/gtest/gtest.h" 27 #include "url/gurl.h" 28 29 namespace { 30 31 static const base::FilePath::CharType kTempDirName[] = 32 FILE_PATH_LITERAL("memory_test_profile"); 33 34 class MemoryTest : public UIPerfTest { 35 public: 36 MemoryTest() : cleanup_temp_dir_on_exit_(false) {} 37 38 virtual ~MemoryTest() { 39 // Cleanup our temporary directory. 40 if (cleanup_temp_dir_on_exit_) 41 base::DeleteFile(temp_dir_, true); 42 } 43 44 // Called from SetUp() to determine the user data dir to copy. 45 virtual base::FilePath GetUserDataDirSource() const = 0; 46 47 // Called from RunTest() to determine the set of URLs to retrieve. 48 // Returns the length of the list. 49 virtual size_t GetUrlList(std::string** list) = 0; 50 51 virtual void SetUp() { 52 show_window_ = true; 53 54 // For now, turn off plugins because they crash like crazy. 55 // TODO(mbelshe): Fix Chrome to not crash with plugins. 56 launch_arguments_.AppendSwitch(switches::kDisablePlugins); 57 58 launch_arguments_.AppendSwitch(switches::kEnableLogging); 59 60 #if defined (OS_MACOSX) 61 // On Mac the OpenGL driver will leave around active pages for GPU 62 // memory, resulting in a massive reported memory regression. Limit 63 // the impact of this by minimizing the amount of GPU memory used. 64 // http://crbug.com/178531 65 launch_arguments_.AppendSwitchASCII(switches::kForceGpuMemAvailableMb, 66 "1"); 67 #endif 68 69 // In order to record a dataset to cache for future playback, 70 // set the |playback| to false and run the test. The source user data dir 71 // will be populated with an appropriate cache set. If any of source 72 // urls are particularly slow, setting |kMaxWaitTime| higher while record 73 // may be useful. 74 bool playback = true; 75 if (playback) { 76 // Use the playback cache, but don't use playback events. 77 launch_arguments_.AppendSwitch(switches::kPlaybackMode); 78 launch_arguments_.AppendSwitch(switches::kNoEvents); 79 launch_arguments_.AppendSwitch(switches::kDisableGpuShaderDiskCache); 80 81 // Get the specified user data dir (optional) 82 base::FilePath profile_dir = 83 CommandLine::ForCurrentProcess()->GetSwitchValuePath( 84 switches::kUserDataDir); 85 86 if (profile_dir.empty()) { 87 if (!SetupTempDirectory(GetUserDataDirSource())) { 88 // There isn't really a way to fail gracefully here. 89 // Neither this constructor nor the SetUp() method return 90 // status to the caller. So, just fall through using the 91 // default profile and log this. The failure will be 92 // obvious. 93 LOG(ERROR) << "Error preparing temp directory for test"; 94 } 95 } 96 } else { // Record session. 97 launch_arguments_.AppendSwitch(switches::kRecordMode); 98 launch_arguments_.AppendSwitch(switches::kNoEvents); 99 100 user_data_dir_ = GetUserDataDirSource(); 101 } 102 103 launch_arguments_.AppendSwitchPath(switches::kUserDataDir, user_data_dir_); 104 UITest::SetUp(); 105 } 106 107 // This memory test loads a set of URLs across a set of tabs, maintaining the 108 // number of concurrent open tabs at num_target_tabs. 109 // <NEWTAB> is a special URL which informs the loop when we should create a 110 // new tab. 111 // <PAUSE> is a special URL that informs the loop to pause before proceeding 112 // to the next URL. 113 void RunTest(const char* test_name, int num_target_tabs) { 114 std::string* urls; 115 size_t urls_length = GetUrlList(&urls); 116 117 // Record the initial CommitCharge. This is a system-wide measurement, 118 // so if other applications are running, they can create variance in this 119 // test. 120 size_t start_size = base::GetSystemCommitCharge(); 121 122 // Cycle through the URLs. 123 scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0)); 124 ASSERT_TRUE(window.get()); 125 int active_window = 0; // The index of the window we are currently using. 126 scoped_refptr<TabProxy> tab(window->GetActiveTab()); 127 ASSERT_TRUE(tab.get()); 128 int expected_tab_count = 1; 129 for (unsigned counter = 0; counter < urls_length; ++counter) { 130 std::string url = urls[counter]; 131 132 SCOPED_TRACE(url); 133 134 if (url == "<PAUSE>") { // Special command to delay on this page 135 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2)); 136 continue; 137 } 138 139 if (url == "<NEWTAB>") { // Special command to create a new tab 140 if (++counter >= urls_length) 141 continue; // Newtab was specified at end of list. ignore. 142 143 url = urls[counter]; 144 if (GetTabCount() < num_target_tabs) { 145 EXPECT_TRUE(window->AppendTab(GURL(url))); 146 expected_tab_count++; 147 WaitUntilTabCount(expected_tab_count); 148 tab = window->GetActiveTab(); 149 ASSERT_TRUE(tab.get()); 150 continue; 151 } 152 153 int tab_index = counter % num_target_tabs; // A pseudo-random tab. 154 tab = window->GetTab(tab_index); 155 ASSERT_TRUE(tab.get()); 156 } 157 158 if (url == "<NEXTTAB>") { // Special command to select the next tab. 159 int tab_index, tab_count; 160 EXPECT_TRUE(window->GetActiveTabIndex(&tab_index)); 161 EXPECT_TRUE(window->GetTabCount(&tab_count)); 162 tab_index = (tab_index + 1) % tab_count; 163 tab = window->GetTab(tab_index); 164 ASSERT_TRUE(tab.get()); 165 continue; 166 } 167 168 if (url == "<NEWWINDOW>") { // Special command to create a new window. 169 if (counter + 1 >= urls_length) 170 continue; // Newwindows was specified at end of list. ignore. 171 172 int window_count; 173 EXPECT_TRUE(automation()->GetBrowserWindowCount(&window_count)); 174 EXPECT_TRUE(automation()->OpenNewBrowserWindow(Browser::TYPE_TABBED, 175 show_window_)); 176 int expected_window_count = window_count + 1; 177 EXPECT_TRUE(automation()->WaitForWindowCountToBecome( 178 expected_window_count)); 179 EXPECT_TRUE(automation()->GetBrowserWindowCount(&window_count)); 180 EXPECT_EQ(expected_window_count, window_count); 181 182 // A new window will not load a url if requested too soon. The window 183 // stays on the new tab page instead. 184 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(200)); 185 186 active_window = window_count - 1; 187 window = automation()->GetBrowserWindow(active_window); 188 ASSERT_TRUE(window.get()); 189 tab = window->GetActiveTab(); 190 ASSERT_TRUE(tab.get()); 191 continue; 192 } 193 194 if (url == "<NEXTWINDOW>") { // Select the next window. 195 int window_count; 196 EXPECT_TRUE(automation()->GetBrowserWindowCount(&window_count)); 197 active_window = (active_window + 1) % window_count; 198 window = automation()->GetBrowserWindow(active_window); 199 ASSERT_TRUE(window.get()); 200 tab = window->GetActiveTab(); 201 ASSERT_TRUE(tab.get()); 202 continue; 203 } 204 205 EXPECT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, 206 tab->NavigateToURL(GURL(urls[counter]))); 207 208 // TODO(mbelshe): Bug 2953 209 // The automation crashes periodically if we cycle too quickly. 210 // To make these tests more reliable, slowing them down a bit. 211 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); 212 } 213 214 size_t stop_size = base::GetSystemCommitCharge(); 215 PrintIOPerfInfo(test_name); 216 PrintMemoryUsageInfo(test_name); 217 perf_test::PrintSystemCommitCharge(test_name, stop_size - start_size, 218 true /* important */); 219 } 220 221 private: 222 // Setup a temporary directory to store the profile to use 223 // with these tests. 224 // Input: 225 // src_dir is set to the source directory 226 // Output: 227 // On success, modifies user_data_dir_ to be a new profile directory 228 // sets temp_dir_ to the containing temporary directory, 229 // and sets cleanup_temp_dir_on_exit_ to true. 230 bool SetupTempDirectory(const base::FilePath& src_dir) { 231 VLOG(1) << "Setting up temp directory in " << src_dir.value(); 232 // We create a copy of the test dir and use it so that each 233 // run of this test starts with the same data. Running this 234 // test has the side effect that it will change the profile. 235 if (!file_util::CreateNewTempDirectory(kTempDirName, &temp_dir_)) { 236 LOG(ERROR) << "Could not create temp directory:" << kTempDirName; 237 return false; 238 } 239 240 if (!base::CopyDirectory(src_dir, temp_dir_, true)) { 241 LOG(ERROR) << "Could not copy temp directory"; 242 return false; 243 } 244 245 // The profile directory was copied in to the containing temp 246 // directory as its base name, so point user_data_dir_ there. 247 user_data_dir_ = temp_dir_.Append(src_dir.BaseName()); 248 cleanup_temp_dir_on_exit_ = true; 249 VLOG(1) << "Finished temp directory setup."; 250 return true; 251 } 252 253 bool cleanup_temp_dir_on_exit_; 254 base::FilePath temp_dir_; 255 base::FilePath user_data_dir_; 256 base::ThreadRestrictions::ScopedAllowIO allow_io_; 257 }; 258 259 class GeneralMixMemoryTest : public MemoryTest { 260 public: 261 virtual base::FilePath GetUserDataDirSource() const OVERRIDE { 262 base::FilePath profile_dir; 263 PathService::Get(base::DIR_SOURCE_ROOT, &profile_dir); 264 profile_dir = profile_dir.AppendASCII("data"); 265 profile_dir = profile_dir.AppendASCII("memory_test"); 266 profile_dir = profile_dir.AppendASCII("general_mix"); 267 return profile_dir; 268 } 269 270 virtual size_t GetUrlList(std::string** list) OVERRIDE { 271 *list = urls_; 272 return urls_length_; 273 } 274 275 private: 276 static std::string urls_[]; 277 static size_t urls_length_; 278 }; 279 280 // TODO(mbelshe): Separate this data to an external file. 281 std::string GeneralMixMemoryTest::urls_[] = { 282 "http://www.yahoo.com/", 283 "http://hotjobs.yahoo.com/career-articles-the_biggest_resume_mistake_you_can_make-436", 284 "http://news.yahoo.com/s/ap/20080804/ap_on_re_mi_ea/odd_israel_home_alone", 285 "http://news.yahoo.com/s/nm/20080729/od_nm/subway_dc", 286 "http://search.yahoo.com/search?p=new+york+subway&ygmasrchbtn=web+search&fr=ush-news", 287 "<NEWTAB>", 288 "http://www.cnn.com/", 289 "http://www.cnn.com/2008/SHOWBIZ/TV/08/03/applegate.cancer.ap/index.html", 290 "http://www.cnn.com/2008/HEALTH/conditions/07/29/black.aids.report/index.html", 291 "http://www.cnn.com/POLITICS/", 292 "http://search.cnn.com/search.jsp?query=obama&type=web&sortBy=date&intl=false", 293 "<NEWTAB>", 294 "http://mail.google.com/", 295 "http://mail.google.com/mail/?shva=1", 296 "http://mail.google.com/mail/?shva=1#search/ipsec", 297 "http://mail.google.com/mail/?shva=1#search/ipsec/ee29ae66165d417", 298 "http://mail.google.com/mail/?shva=1#compose", 299 "<NEWTAB>", 300 "http://docs.google.com/", 301 "<NEWTAB>", 302 "http://calendar.google.com/", 303 "<NEWTAB>", 304 "http://maps.google.com/", 305 "http://maps.google.com/maps/mpl?moduleurl=http://earthquake.usgs.gov/eqcenter/mapplets/earthquakes.xml&ie=UTF8&ll=20,170&spn=140.625336,73.828125&t=k&z=2", 306 "http://maps.google.com/maps?f=q&hl=en&geocode=&q=1600+amphitheater+parkway,+mountain+view,+ca&ie=UTF8&z=13", 307 "<NEWTAB>", 308 "http://www.google.com/", 309 "http://www.google.com/search?hl=en&q=food&btnG=Google+Search", 310 "http://books.google.com/books?hl=en&q=food&um=1&ie=UTF-8&sa=N&tab=wp", 311 "http://images.google.com/images?hl=en&q=food&um=1&ie=UTF-8&sa=N&tab=pi", 312 "http://news.google.com/news?hl=en&q=food&um=1&ie=UTF-8&sa=N&tab=in", 313 "http://www.google.com/products?sa=N&tab=nf&q=food", 314 "<NEWTAB>", 315 "http://www.scoundrelspoint.com/polyhedra/shuttle/index.html", 316 "<PAUSE>", 317 "<NEWTAB>", 318 "http://ctho.ath.cx/toys/3d.html", 319 "<PAUSE>", 320 "<NEWTAB>", 321 "http://www.youtube.com/", 322 "http://www.youtube.com/results?search_query=funny&search_type=&aq=f", 323 "http://www.youtube.com/watch?v=GuMMfgWhm3g", 324 "<NEWTAB>", 325 "http://www.craigslist.com/", 326 "http://sfbay.craigslist.org/", 327 "http://sfbay.craigslist.org/apa/", 328 "http://sfbay.craigslist.org/sfc/apa/782398209.html", 329 "http://sfbay.craigslist.org/sfc/apa/782347795.html", 330 "http://sfbay.craigslist.org/sby/apa/782342791.html", 331 "http://sfbay.craigslist.org/sfc/apa/782344396.html", 332 "<NEWTAB>", 333 "http://www.whitehouse.gov/", 334 "http://www.whitehouse.gov/news/releases/2008/07/20080729.html", 335 "http://www.whitehouse.gov/infocus/afghanistan/", 336 "http://www.whitehouse.gov/infocus/africa/", 337 "<NEWTAB>", 338 "http://www.msn.com/", 339 "http://msn.foxsports.com/horseracing/story/8409670/Big-Brown-rebounds-in-Haskell-Invitational?MSNHPHMA", 340 "http://articles.moneycentral.msn.com/Investing/StockInvestingTrading/TheBiggestRiskToYourRetirement_SeriesHome.aspx", 341 "http://articles.moneycentral.msn.com/Investing/StockInvestingTrading/TheSmartWayToGetRich.aspx", 342 "http://articles.moneycentral.msn.com/Investing/ContrarianChronicles/TheFictionOfCorporateTransparency.aspx", 343 "<NEWTAB>", 344 "http://flickr.com/", 345 "http://flickr.com/explore/interesting/2008/03/18/", 346 "http://flickr.com/photos/chavals/2344906748/", 347 "http://flickr.com/photos/rosemary/2343058024/", 348 "http://flickr.com/photos/arbaa/2343235019/", 349 "<NEWTAB>", 350 "http://zh.wikipedia.org/wiki/%E6%B1%B6%E5%B7%9D%E5%A4%A7%E5%9C%B0%E9%9C%87", 351 "http://zh.wikipedia.org/wiki/5%E6%9C%8812%E6%97%A5", 352 "http://zh.wikipedia.org/wiki/5%E6%9C%8820%E6%97%A5", 353 "http://zh.wikipedia.org/wiki/%E9%A6%96%E9%A1%B5", 354 "<NEWTAB>", 355 "http://www.nytimes.com/pages/technology/index.html", 356 "http://pogue.blogs.nytimes.com/2008/07/17/a-candy-store-for-the-iphone/", 357 "http://www.nytimes.com/2008/07/21/technology/21pc.html?_r=1&ref=technology&oref=slogin", 358 "http://bits.blogs.nytimes.com/2008/07/19/a-wikipedian-challenge-convincing-arabic-speakers-to-write-in-arabic/", 359 "<NEWTAB>", 360 "http://www.amazon.com/exec/obidos/tg/browse/-/502394/ref=topnav_storetab_p", 361 "http://www.amazon.com/Panasonic-DMC-TZ5K-Digital-Optical-Stabilized/dp/B0011Z8CCG/ref=pd_ts_p_17?ie=UTF8&s=photo", 362 "http://www.amazon.com/Nikon-Coolpix-Digital-Vibration-Reduction/dp/B0012OI6HW/ref=pd_ts_p_24?ie=UTF8&s=photo", 363 "http://www.amazon.com/Digital-SLRs-Cameras-Photo/b/ref=sv_p_2?ie=UTF8&node=3017941", 364 "<NEWTAB>", 365 "http://www.boston.com/bigpicture/2008/07/californias_continuing_fires.html", 366 "http://www.boston.com/business/", 367 "http://www.boston.com/business/articles/2008/07/29/staples_has_a_games_plan/", 368 "http://www.boston.com/business/personalfinance/articles/2008/08/04/a_grim_forecast_for_heating_costs/", 369 "<NEWTAB>", 370 "http://arstechnica.com/", 371 "http://arstechnica.com/news.ars/post/20080721-this-years-e3-substance-over-styleand-far-from-dead.html", 372 "http://arstechnica.com/news.ars/post/20080729-ifpi-italian-police-take-down-italian-bittorrent-tracker.html", 373 "http://arstechnica.com/news.ars/post/20080804-congress-wants-privacy-answers-from-google-ms-aol.html", 374 "<NEWTAB>", 375 "http://finance.google.com/finance?q=NASDAQ:AAPL", 376 "http://finance.google.com/finance?q=GOOG&hl=en", 377 "<NEWTAB>", 378 "http://blog.wired.com/underwire/2008/07/futurama-gets-m.html", 379 "http://blog.wired.com/cars/2008/07/gas-prices-hit.html", 380 "<NEWTAB>", 381 "http://del.icio.us/popular/programming", 382 "http://del.icio.us/popular/", 383 "http://del.icio.us/tag/", 384 "<NEWTAB>", 385 "http://gadgets.boingboing.net/2008/07/21/boom-computing.html", 386 "http://3533.spreadshirt.com/us/US/Shop/", 387 "<NEWTAB>", 388 "http://www.autoblog.com/", 389 "http://www.autoblog.com/2008/07/21/audi-introduces-the-next-mmi/", 390 "http://www.autoblog.com/categories/auto-types/", 391 "http://www.autoblog.com/category/sports/", 392 "<NEWTAB>", 393 "http://www.wikipedia.org/", 394 "http://en.wikipedia.org/wiki/Main_Page", 395 "http://fr.wikipedia.org/wiki/Accueil", 396 "http://de.wikipedia.org/wiki/Hauptseite", 397 "http://ja.wikipedia.org/wiki/%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8", 398 "http://it.wikipedia.org/wiki/Pagina_principale", 399 "http://nl.wikipedia.org/wiki/Hoofdpagina", 400 "http://pt.wikipedia.org/wiki/P%C3%A1gina_principal", 401 "http://es.wikipedia.org/wiki/Portada", 402 "http://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0", 403 "<NEWTAB>", 404 "http://www.google.com/translate_t?hl=en&text=This%20Is%20A%20Test%20Of%20missspellingsdfdf&sl=en&tl=ja" 405 }; 406 407 size_t GeneralMixMemoryTest::urls_length_ = 408 arraysize(GeneralMixMemoryTest::urls_); 409 410 class GeneralMixReferenceMemoryTest : public GeneralMixMemoryTest { 411 public: 412 virtual void SetUp() { 413 UseReferenceBuild(); 414 GeneralMixMemoryTest::SetUp(); 415 } 416 }; 417 418 class MembusterMemoryTest : public MemoryTest { 419 public: 420 MembusterMemoryTest() : test_urls_(NULL) {} 421 422 virtual ~MembusterMemoryTest() { 423 delete[] test_urls_; 424 } 425 426 virtual base::FilePath GetUserDataDirSource() const OVERRIDE { 427 base::FilePath profile_dir; 428 PathService::Get(base::DIR_SOURCE_ROOT, &profile_dir); 429 profile_dir = profile_dir.AppendASCII("data"); 430 profile_dir = profile_dir.AppendASCII("memory_test"); 431 profile_dir = profile_dir.AppendASCII("membuster"); 432 return profile_dir; 433 } 434 435 virtual size_t GetUrlList(std::string** list) OVERRIDE { 436 size_t total_url_entries = urls_length_ * kIterations_ * 2 - 1; 437 if (!test_urls_) { 438 test_urls_ = new std::string[total_url_entries]; 439 440 // Open url_length_ + 1 windows as we access urls. We start with one 441 // open window. 442 test_urls_[0] = source_urls_[0]; 443 size_t fill_position = 1; 444 size_t source_url_index = 1; 445 for (; fill_position <= urls_length_ * 2; fill_position += 2) { 446 test_urls_[fill_position] = "<NEWWINDOW>"; 447 test_urls_[fill_position + 1] = source_urls_[source_url_index]; 448 source_url_index = (source_url_index + 1) % urls_length_; 449 } 450 451 // Then cycle through all the urls to fill out the list. 452 for (; fill_position < total_url_entries; fill_position += 2) { 453 test_urls_[fill_position] = "<NEXTWINDOW>"; 454 test_urls_[fill_position + 1] = source_urls_[source_url_index]; 455 source_url_index = (source_url_index + 1) % urls_length_; 456 } 457 } 458 *list = test_urls_; 459 return total_url_entries; 460 } 461 462 private: 463 static const int kIterations_ = 11; 464 465 static std::string source_urls_[]; 466 static size_t urls_length_; 467 468 std::string* test_urls_; 469 }; 470 471 // membuster traverses the list in reverse order. We just list them that way. 472 std::string MembusterMemoryTest::source_urls_[] = { 473 "http://joi.ito.com/archives/email/", 474 "http://joi.ito.com/jp/", 475 "http://forums.studentdoctor.net/showthread.php?t=469342", 476 "http://forums.studentdoctor.net/forumdisplay.php?s=718b9d0e8692d7c3f4cc7c64faffd17b&f=10", 477 "http://de.wikipedia.org/wiki/Hauptseite", 478 "http://zh.wikipedia.org/wiki/", 479 "http://ru.wikipedia.org/wiki/", 480 "http://ja.wikipedia.org/wiki/", 481 "http://en.wikipedia.org/wiki/Main_Page", 482 "http://wikitravel.org/ru/", 483 "http://wikitravel.org/hi/", 484 "http://wikitravel.org/he/", 485 "http://wikitravel.org/ja/", 486 "http://wikitravel.org/en/Main_Page", 487 "http://wikitravel.org/en/China", 488 "http://www.vodcars.com/", 489 "http://en.wikinews.org/wiki/Main_Page", 490 "http://creativecommons.org/", 491 "http://pushingdaisies.wikia.com/wiki/Pushing_Daisies", 492 "http://www.wowwiki.com/Main_Page", 493 "http://spademanns.wikia.com/wiki/Forside", 494 "http://ja.uncyclopedia.info/wiki/", 495 "http://uncyclopedia.org/wiki/Babel:Vi", 496 "http://uncyclopedia.org/wiki/Main_Page", 497 "http://en.marveldatabase.com/Main_Page", 498 "http://bioshock.wikia.com/wiki/Main_Page", 499 "http://www.armchairgm.com/Special:ImageRating", 500 "http://www.armchairgm.com/Anderson_Continues_to_Thrive_for_Cleveland", 501 "http://www.armchairgm.com/Main_Page" 502 }; 503 504 size_t MembusterMemoryTest::urls_length_ = 505 arraysize(MembusterMemoryTest::source_urls_); 506 507 #define QUOTE(x) #x 508 #define GENERAL_MIX_MEMORY_TESTS(name, tabs) \ 509 TEST_F(GeneralMixMemoryTest, name) { \ 510 RunTest(QUOTE(_##tabs##t), tabs); \ 511 } \ 512 TEST_F(GeneralMixReferenceMemoryTest, name) { \ 513 RunTest(QUOTE(_##tabs##t_ref), tabs); \ 514 } 515 516 GENERAL_MIX_MEMORY_TESTS(SingleTabTest, 1); 517 GENERAL_MIX_MEMORY_TESTS(FiveTabTest, 5); 518 GENERAL_MIX_MEMORY_TESTS(TwelveTabTest, 12); 519 520 // Commented out until the recorded cache data is added. 521 //TEST_F(MembusterMemoryTest, Windows) { 522 // RunTest("membuster", 0); 523 //} 524 525 } // namespace 526