1// Copyright 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 "ios/chrome/browser/test/perf_test_with_bvc_ios.h"
6
7#import <UIKit/UIKit.h>
8
9#include "base/files/file_path.h"
10#include "base/strings/sys_string_conversions.h"
11#include "components/bookmarks/test/bookmark_test_helpers.h"
12#include "ios/chrome/browser/autocomplete/autocomplete_classifier_factory.h"
13#include "ios/chrome/browser/bookmarks/bookmark_model_factory.h"
14#include "ios/chrome/browser/browser_state/test_chrome_browser_state_manager.h"
15#import "ios/chrome/browser/main/test_browser.h"
16#include "ios/chrome/browser/search_engines/template_url_service_factory.h"
17#import "ios/chrome/browser/sessions/session_ios.h"
18#include "ios/chrome/browser/sessions/session_restoration_browser_agent.h"
19#import "ios/chrome/browser/sessions/session_service_ios.h"
20#import "ios/chrome/browser/sessions/session_window_ios.h"
21#import "ios/chrome/browser/ui/browser_container/browser_container_view_controller.h"
22#import "ios/chrome/browser/ui/browser_view/browser_view_controller+private.h"
23#import "ios/chrome/browser/ui/browser_view/browser_view_controller.h"
24#import "ios/chrome/browser/ui/browser_view/browser_view_controller_dependency_factory.h"
25#import "ios/chrome/browser/ui/commands/command_dispatcher.h"
26#import "ios/chrome/browser/web/chrome_web_client.h"
27#include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
28
29#if !defined(__has_feature) || !__has_feature(objc_arc)
30#error "This file requires ARC support."
31#endif
32
33// Subclass of PrerenderController so it isn't actually used. Using a mock for
34// this makes cleanup on shutdown simpler, by minimizing the number of profile
35// observers registered with the profiles.  The profile observers have to be
36// deallocated before the profiles themselves, but in practice it is very hard
37// to ensure that happens.  Also, for performance testing, not having the
38// PrerenderController makes the test far simpler to analyze.
39namespace {
40static GURL emptyGurl_ = GURL("foo", 3, url::Parsed(), false);
41}
42
43PerfTestWithBVC::PerfTestWithBVC(std::string testGroup)
44    : PerfTest(testGroup),
45      slow_teardown_(false),
46      web_client_(std::make_unique<ChromeWebClient>()),
47      provider_(ios::CreateChromeBrowserProvider()),
48      browser_state_manager_(
49          std::make_unique<TestChromeBrowserStateManager>(base::FilePath())),
50      web_state_list_(&web_state_list_delegate_),
51      otr_web_state_list_(&web_state_list_delegate_) {}
52
53PerfTestWithBVC::PerfTestWithBVC(std::string testGroup,
54                                 std::string firstLabel,
55                                 std::string averageLabel,
56                                 bool isWaterfall,
57                                 bool verbose,
58                                 bool slowTeardown,
59                                 int repeat)
60    : PerfTest(testGroup,
61               firstLabel,
62               averageLabel,
63               isWaterfall,
64               verbose,
65               repeat),
66      slow_teardown_(slowTeardown),
67      web_client_(std::make_unique<ChromeWebClient>()),
68      provider_(ios::CreateChromeBrowserProvider()),
69      browser_state_manager_(
70          std::make_unique<TestChromeBrowserStateManager>(base::FilePath())),
71      web_state_list_(&web_state_list_delegate_),
72      otr_web_state_list_(&web_state_list_delegate_) {}
73
74PerfTestWithBVC::~PerfTestWithBVC() {}
75
76void PerfTestWithBVC::SetUp() {
77  PerfTest::SetUp();
78
79  // Set up the ChromeBrowserState instances.
80  TestChromeBrowserState::Builder test_cbs_builder;
81  test_cbs_builder.AddTestingFactory(
82      ios::TemplateURLServiceFactory::GetInstance(),
83      ios::TemplateURLServiceFactory::GetDefaultFactory());
84  test_cbs_builder.AddTestingFactory(
85      ios::AutocompleteClassifierFactory::GetInstance(),
86      ios::AutocompleteClassifierFactory::GetDefaultFactory());
87  chrome_browser_state_ = test_cbs_builder.Build();
88  chrome_browser_state_->CreateBookmarkModel(false);
89  bookmarks::test::WaitForBookmarkModelToLoad(
90      ios::BookmarkModelFactory::GetForBrowserState(
91          chrome_browser_state_.get()));
92  ASSERT_TRUE(chrome_browser_state_->CreateHistoryService());
93
94  // Force creation of AutocompleteClassifier instance.
95  ios::AutocompleteClassifierFactory::GetForBrowserState(
96      chrome_browser_state_.get());
97
98  // Use the session to create a window which will contain the tabs.
99  NSString* state_path = base::SysUTF8ToNSString(
100      chrome_browser_state_->GetStatePath().AsUTF8Unsafe());
101  SessionIOS* session =
102      [[SessionServiceIOS sharedService] loadSessionFromDirectory:state_path];
103  DCHECK_EQ(session.sessionWindows.count, 1u);
104
105  browser_ = std::make_unique<TestBrowser>(chrome_browser_state_.get(),
106                                           &web_state_list_);
107  otr_browser_ = std::make_unique<TestBrowser>(
108      chrome_browser_state_->GetOffTheRecordChromeBrowserState(),
109      &otr_web_state_list_);
110  SessionRestorationBrowserAgent::CreateForBrowser(
111      browser_.get(), [SessionServiceIOS sharedService]);
112  SessionRestorationBrowserAgent::CreateForBrowser(
113      otr_browser_.get(), [SessionServiceIOS sharedService]);
114  SessionRestorationBrowserAgent::FromBrowser(browser_.get())
115      ->RestoreSessionWindow(session.sessionWindows[0]);
116  SessionRestorationBrowserAgent::FromBrowser(otr_browser_.get())
117      ->RestoreSessionWindow(session.sessionWindows[0]);
118
119  // Create the browser view controller with its testing factory.
120  bvc_factory_ = [[BrowserViewControllerDependencyFactory alloc]
121      initWithBrowser:browser_.get()];
122  bvc_ = [[BrowserViewController alloc]
123                     initWithBrowser:browser_.get()
124                   dependencyFactory:bvc_factory_
125      browserContainerViewController:[[BrowserContainerViewController alloc]
126                                         init]
127                          dispatcher:browser_->GetCommandDispatcher()];
128  [bvc_ setActive:YES];
129
130  // Create a real window to give to the browser view controller.
131  window_ = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
132  [window_ makeKeyAndVisible];
133  [window_ addSubview:[bvc_ view]];
134  [[bvc_ view] setFrame:[[UIScreen mainScreen] bounds]];
135}
136
137void PerfTestWithBVC::TearDown() {
138  browser_.get()->GetWebStateList()->CloseAllWebStates(
139      WebStateList::CLOSE_NO_FLAGS);
140  [[bvc_ view] removeFromSuperview];
141
142  // Documented example of how to clear out the browser view controller
143  // and its associated data.
144  window_ = nil;
145  [bvc_ shutdown];
146  bvc_ = nil;
147  bvc_factory_ = nil;
148
149  // The base class |TearDown| method calls the run loop so the
150  // NSAutoreleasePool can drain. This needs to be done before
151  // |chrome_browser_state_| can be cleared. For tests that allocate more
152  // objects, more runloop time may be required.
153  if (slow_teardown_)
154    SpinRunLoop(.5);
155  PerfTest::TearDown();
156
157  // Before destroying chrome_browser_state_ we need to make sure that no tasks
158  // are left on the ThreadPool since they might depend on it.
159  task_environment_.RunUntilIdle();
160
161  // The profiles can be deallocated only after the BVC has been deallocated.
162  chrome_browser_state_.reset();
163}
164