Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(87)

Side by Side Diff: chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views_unittest.cc

Issue 2700523002: arc: Fix crash on accessing app info for secondary user. (Closed)
Patch Set: clean up Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 #include "chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views.h" 5 #include "chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views.h"
6 6
7 #include <memory> 7 #include <memory>
8 #include <string> 8 #include <string>
9 9
10 #include "base/macros.h" 10 #include "base/macros.h"
11 #include "base/memory/ptr_util.h" 11 #include "base/memory/ptr_util.h"
12 #include "base/run_loop.h" 12 #include "base/run_loop.h"
13 #include "chrome/browser/extensions/extension_service.h" 13 #include "chrome/browser/extensions/extension_service.h"
14 #include "chrome/browser/extensions/test_extension_environment.h" 14 #include "chrome/browser/extensions/test_extension_environment.h"
15 #include "chrome/browser/ui/tabs/tab_strip_model.h" 15 #include "chrome/browser/ui/tabs/tab_strip_model.h"
16 #include "chrome/browser/ui/views/apps/app_info_dialog/app_info_header_panel.h" 16 #include "chrome/browser/ui/views/apps/app_info_dialog/app_info_header_panel.h"
17 #include "chrome/common/extensions/extension_constants.h"
17 #include "chrome/test/base/browser_with_test_window_test.h" 18 #include "chrome/test/base/browser_with_test_window_test.h"
18 #include "chrome/test/base/testing_profile.h" 19 #include "chrome/test/base/testing_profile.h"
19 #include "extensions/browser/extension_system.h" 20 #include "extensions/browser/extension_system.h"
20 #include "testing/gtest/include/gtest/gtest.h" 21 #include "testing/gtest/include/gtest/gtest.h"
21 #include "ui/views/controls/link.h" 22 #include "ui/views/controls/link.h"
22 #include "ui/views/test/scoped_views_test_helper.h" 23 #include "ui/views/test/scoped_views_test_helper.h"
23 #include "ui/views/widget/widget.h" 24 #include "ui/views/widget/widget.h"
24 #include "ui/views/widget/widget_observer.h" 25 #include "ui/views/widget/widget_observer.h"
25 #include "ui/views/window/dialog_delegate.h" 26 #include "ui/views/window/dialog_delegate.h"
26 27
27 #if defined(OS_CHROMEOS) 28 #if defined(OS_CHROMEOS)
28 #include "chrome/browser/chromeos/arc/arc_session_manager.h" 29 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
29 #include "components/arc/arc_session_runner.h" 30 #include "chrome/browser/ui/app_list/arc/arc_app_test.h"
30 #include "components/arc/test/fake_arc_session.h" 31 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
32 #endif
33
34 #if defined(OS_CHROMEOS)
35 namespace {
36
37 std::vector<arc::mojom::AppInfoPtr> GetArcSettingsAppMojoInfo() {
msw 2017/02/15 21:48:28 It's a little odd to return a vector for one item,
khmel 2017/02/16 15:47:52 Done.
38 std::vector<arc::mojom::AppInfoPtr> apps;
39 arc::mojom::AppInfoPtr app(arc::mojom::AppInfo::New());
40 app->name = "settings";
41 app->package_name = "com.android.settings";
42 app->activity = "com.android.settings.Settings";
43 app->sticky = false;
44 apps.push_back(std::move(app));
45 return apps;
46 }
47 } // namespace
msw 2017/02/15 21:48:28 nit: add a blank line above
khmel 2017/02/16 15:47:51 Done.
31 #endif 48 #endif
32 49
33 namespace test { 50 namespace test {
34 51
35 class AppInfoDialogTestApi { 52 class AppInfoDialogTestApi {
36 public: 53 public:
37 explicit AppInfoDialogTestApi(AppInfoDialog* dialog) : dialog_(dialog) {} 54 explicit AppInfoDialogTestApi(AppInfoDialog* dialog) : dialog_(dialog) {}
38 55
39 AppInfoHeaderPanel* header_panel() { 56 AppInfoHeaderPanel* header_panel() {
40 return static_cast<AppInfoHeaderPanel*>(dialog_->child_at(0)); 57 return static_cast<AppInfoHeaderPanel*>(dialog_->child_at(0));
(...skipping 21 matching lines...) Expand all
62 class AppInfoDialogViewsTest : public BrowserWithTestWindowTest, 79 class AppInfoDialogViewsTest : public BrowserWithTestWindowTest,
63 public views::WidgetObserver { 80 public views::WidgetObserver {
64 public: 81 public:
65 AppInfoDialogViewsTest() 82 AppInfoDialogViewsTest()
66 : extension_environment_(base::MessageLoopForUI::current()) {} 83 : extension_environment_(base::MessageLoopForUI::current()) {}
67 84
68 // Overridden from testing::Test: 85 // Overridden from testing::Test:
69 void SetUp() override { 86 void SetUp() override {
70 BrowserWithTestWindowTest::SetUp(); 87 BrowserWithTestWindowTest::SetUp();
71 #if defined(OS_CHROMEOS) 88 #if defined(OS_CHROMEOS)
72 arc::ArcSessionManager::DisableUIForTesting(); 89 arc_test_.SetUp(extension_environment_.profile());
khmel 2017/02/15 16:38:45 This actually does not start ARC (we need extra pr
msw 2017/02/15 21:48:28 Acknowledged.
73 arc_session_manager_ = base::MakeUnique<arc::ArcSessionManager>(
74 base::MakeUnique<arc::ArcSessionRunner>(
75 base::Bind(arc::FakeArcSession::Create)));
76 arc_session_manager_->OnPrimaryUserProfilePrepared(
77 extension_environment_.profile());
78 #endif 90 #endif
79 widget_ = views::DialogDelegate::CreateDialogWidget(
80 new views::DialogDelegateView(), GetContext(), nullptr);
81 widget_->AddObserver(this);
82 extension_ = extension_environment_.MakePackagedApp(kTestExtensionId, true); 91 extension_ = extension_environment_.MakePackagedApp(kTestExtensionId, true);
83 dialog_ = new AppInfoDialog(widget_->GetNativeWindow(), 92 chrome_app_ = extension_environment_.MakePackagedApp(
khmel 2017/02/15 16:38:45 Move creation and closing to separate methods Show
msw 2017/02/15 21:48:28 Acknowledged.
84 extension_environment_.profile(), 93 extension_misc::kChromeAppId, true);
85 extension_.get());
86
87 widget_->GetContentsView()->AddChildView(dialog_);
88 widget_->Show();
89 } 94 }
90 95
91 void TearDown() override { 96 void TearDown() override {
92 if (!widget_destroyed_) 97 CloseAppInfo();
93 widget_->CloseNow();
94 EXPECT_TRUE(widget_destroyed_);
95 extension_ = nullptr; 98 extension_ = nullptr;
99 chrome_app_ = nullptr;
96 #if defined(OS_CHROMEOS) 100 #if defined(OS_CHROMEOS)
97 if (arc_session_manager_) { 101 arc_test_.TearDown();
98 arc_session_manager_->Shutdown();
99 arc_session_manager_ = nullptr;
100 }
101 #endif 102 #endif
102 BrowserWithTestWindowTest::TearDown(); 103 BrowserWithTestWindowTest::TearDown();
103 } 104 }
104 105
105 // BrowserWithTestWindowTest: 106 // BrowserWithTestWindowTest:
106 TestingProfile* CreateProfile() override { 107 TestingProfile* CreateProfile() override {
107 return extension_environment_.profile(); 108 return extension_environment_.profile();
108 } 109 }
109 110
110 void DestroyProfile(TestingProfile* profile) override { 111 void DestroyProfile(TestingProfile* profile) override {
111 #if defined(OS_CHROMEOS) 112 #if defined(OS_CHROMEOS)
112 if (arc_session_manager_) { 113 arc_test_.TearDown();
113 arc_session_manager_->Shutdown();
114 arc_session_manager_ = nullptr;
115 }
116 #endif 114 #endif
117 } 115 }
118 116
119 protected: 117 protected:
118 void ShowAppInfo(const std::string& app_id) {
119 ShowAppInfoForProfile(app_id, extension_environment_.profile());
120 }
121
122 void ShowAppInfoForProfile(const std::string& app_id, Profile* profile) {
123 const extensions::Extension* extension =
124 extensions::ExtensionSystem::Get(profile)
125 ->extension_service()
126 ->GetExtensionById(app_id, true);
127 DCHECK(extension);
128
129 DCHECK(!widget_);
130 widget_destroyed_ = false;
131 widget_ = views::DialogDelegate::CreateDialogWidget(
132 new views::DialogDelegateView(), GetContext(), nullptr);
133 widget_->AddObserver(this);
134 dialog_ = new AppInfoDialog(widget_->GetNativeWindow(), profile, extension);
135
136 widget_->GetContentsView()->AddChildView(dialog_);
137 widget_->Show();
138 }
139
140 void CloseAppInfo() {
141 if (!widget_destroyed_) {
142 DCHECK(widget_);
143 widget_->CloseNow();
144 }
145 base::RunLoop().RunUntilIdle();
146 EXPECT_TRUE(widget_destroyed_);
147 DCHECK(!widget_);
148 }
149
120 // Overridden from views::WidgetObserver: 150 // Overridden from views::WidgetObserver:
121 void OnWidgetDestroyed(views::Widget* widget) override { 151 void OnWidgetDestroyed(views::Widget* widget) override {
122 widget_destroyed_ = true; 152 widget_destroyed_ = true;
123 widget_->RemoveObserver(this); 153 widget_->RemoveObserver(this);
124 widget_ = NULL; 154 widget_ = NULL;
125 } 155 }
126 156
127 void UninstallApp(const std::string& app_id) { 157 void UninstallApp(const std::string& app_id) {
128 extensions::ExtensionSystem::Get(extension_environment_.profile()) 158 extensions::ExtensionSystem::Get(extension_environment_.profile())
129 ->extension_service() 159 ->extension_service()
130 ->UninstallExtension( 160 ->UninstallExtension(
131 app_id, extensions::UninstallReason::UNINSTALL_REASON_FOR_TESTING, 161 app_id, extensions::UninstallReason::UNINSTALL_REASON_FOR_TESTING,
132 base::Closure(), NULL); 162 base::Closure(), NULL);
133 } 163 }
134 164
135 protected: 165 protected:
136 views::Widget* widget_ = nullptr; 166 views::Widget* widget_ = nullptr;
137 bool widget_destroyed_ = false; 167 bool widget_destroyed_ = true;
msw 2017/02/15 21:48:28 optional nit: invert this member as |widget_exists
khmel 2017/02/16 15:47:52 Good catch. removed.
138 AppInfoDialog* dialog_ = nullptr; // Owned by |widget_|'s views hierarchy. 168 AppInfoDialog* dialog_ = nullptr; // Owned by |widget_|'s views hierarchy.
139 scoped_refptr<extensions::Extension> extension_; 169 scoped_refptr<extensions::Extension> extension_;
170 scoped_refptr<extensions::Extension> chrome_app_;
140 extensions::TestExtensionEnvironment extension_environment_; 171 extensions::TestExtensionEnvironment extension_environment_;
141 #if defined(OS_CHROMEOS) 172 #if defined(OS_CHROMEOS)
142 std::unique_ptr<arc::ArcSessionManager> arc_session_manager_; 173 ArcAppTest arc_test_;
143 #endif 174 #endif
144 175
145 private: 176 private:
146 DISALLOW_COPY_AND_ASSIGN(AppInfoDialogViewsTest); 177 DISALLOW_COPY_AND_ASSIGN(AppInfoDialogViewsTest);
147 }; 178 };
148 179
149 // Tests that the dialog closes when the current app is uninstalled. 180 // Tests that the dialog closes when the current app is uninstalled.
150 TEST_F(AppInfoDialogViewsTest, UninstallingAppClosesDialog) { 181 TEST_F(AppInfoDialogViewsTest, UninstallingAppClosesDialog) {
182 ShowAppInfo(kTestExtensionId);
151 EXPECT_FALSE(widget_->IsClosed()); 183 EXPECT_FALSE(widget_->IsClosed());
152 EXPECT_FALSE(widget_destroyed_); 184 EXPECT_FALSE(widget_destroyed_);
153 UninstallApp(kTestExtensionId); 185 UninstallApp(kTestExtensionId);
154 base::RunLoop().RunUntilIdle(); 186 base::RunLoop().RunUntilIdle();
155 EXPECT_TRUE(widget_destroyed_); 187 EXPECT_TRUE(widget_destroyed_);
156 } 188 }
157 189
158 // Tests that the dialog does not close when a different app is uninstalled. 190 // Tests that the dialog does not close when a different app is uninstalled.
159 TEST_F(AppInfoDialogViewsTest, UninstallingOtherAppDoesNotCloseDialog) { 191 TEST_F(AppInfoDialogViewsTest, UninstallingOtherAppDoesNotCloseDialog) {
192 ShowAppInfo(kTestExtensionId);
160 extension_environment_.MakePackagedApp(kTestOtherExtensionId, true); 193 extension_environment_.MakePackagedApp(kTestOtherExtensionId, true);
161 194
162 EXPECT_FALSE(widget_->IsClosed()); 195 EXPECT_FALSE(widget_->IsClosed());
163 EXPECT_FALSE(widget_destroyed_); 196 EXPECT_FALSE(widget_destroyed_);
164 UninstallApp(kTestOtherExtensionId); 197 UninstallApp(kTestOtherExtensionId);
165 base::RunLoop().RunUntilIdle(); 198 base::RunLoop().RunUntilIdle();
166 EXPECT_FALSE(widget_destroyed_); 199 EXPECT_FALSE(widget_destroyed_);
167 } 200 }
168 201
169 // Tests that the dialog closes when the current profile is destroyed. 202 // Tests that the dialog closes when the current profile is destroyed.
170 TEST_F(AppInfoDialogViewsTest, DestroyedProfileClosesDialog) { 203 TEST_F(AppInfoDialogViewsTest, DestroyedProfileClosesDialog) {
204 ShowAppInfo(kTestExtensionId);
171 // First delete the test browser window. This ensures the test harness isn't 205 // First delete the test browser window. This ensures the test harness isn't
172 // surprised by it being closed in response to the profile deletion below. 206 // surprised by it being closed in response to the profile deletion below.
173 // Note the base class doesn't own the profile, so that part is skipped. 207 // Note the base class doesn't own the profile, so that part is skipped.
174 DestroyBrowserAndProfile(); 208 DestroyBrowserAndProfile();
175 209
176 // The following does nothing: it just ensures the Widget close is being 210 // The following does nothing: it just ensures the Widget close is being
177 // triggered by the DeleteProfile() call rather than the line above. 211 // triggered by the DeleteProfile() call rather than the line above.
178 base::RunLoop().RunUntilIdle(); 212 base::RunLoop().RunUntilIdle();
179 213
180 EXPECT_FALSE(widget_->IsClosed()); 214 EXPECT_FALSE(widget_->IsClosed());
181 EXPECT_FALSE(widget_destroyed_); 215 EXPECT_FALSE(widget_destroyed_);
182 extension_environment_.DeleteProfile(); 216 extension_environment_.DeleteProfile();
183 217
184 base::RunLoop().RunUntilIdle(); 218 base::RunLoop().RunUntilIdle();
185 EXPECT_TRUE(widget_destroyed_); 219 EXPECT_TRUE(widget_destroyed_);
186 } 220 }
187 221
188 // Tests that the dialog does not close when a different profile is destroyed. 222 // Tests that the dialog does not close when a different profile is destroyed.
189 TEST_F(AppInfoDialogViewsTest, DestroyedOtherProfileDoesNotCloseDialog) { 223 TEST_F(AppInfoDialogViewsTest, DestroyedOtherProfileDoesNotCloseDialog) {
224 ShowAppInfo(kTestExtensionId);
190 std::unique_ptr<TestingProfile> other_profile(new TestingProfile); 225 std::unique_ptr<TestingProfile> other_profile(new TestingProfile);
191 extension_environment_.CreateExtensionServiceForProfile(other_profile.get()); 226 extension_environment_.CreateExtensionServiceForProfile(other_profile.get());
192 227
193 scoped_refptr<const extensions::Extension> other_app = 228 scoped_refptr<const extensions::Extension> other_app =
194 extension_environment_.MakePackagedApp(kTestOtherExtensionId, false); 229 extension_environment_.MakePackagedApp(kTestOtherExtensionId, false);
195 extensions::ExtensionSystem::Get(other_profile.get()) 230 extensions::ExtensionSystem::Get(other_profile.get())
196 ->extension_service() 231 ->extension_service()
197 ->AddExtension(other_app.get()); 232 ->AddExtension(other_app.get());
198 233
199 EXPECT_FALSE(widget_->IsClosed()); 234 EXPECT_FALSE(widget_->IsClosed());
200 EXPECT_FALSE(widget_destroyed_); 235 EXPECT_FALSE(widget_destroyed_);
201 other_profile.reset(); 236 other_profile.reset();
202 base::RunLoop().RunUntilIdle(); 237 base::RunLoop().RunUntilIdle();
203 EXPECT_FALSE(widget_destroyed_); 238 EXPECT_FALSE(widget_destroyed_);
204 } 239 }
205 240
206 // Tests that clicking the View in Store link opens a browser tab and closes the 241 // Tests that clicking the View in Store link opens a browser tab and closes the
207 // dialog cleanly. 242 // dialog cleanly.
208 TEST_F(AppInfoDialogViewsTest, ViewInStore) { 243 TEST_F(AppInfoDialogViewsTest, ViewInStore) {
244 ShowAppInfo(kTestExtensionId);
209 EXPECT_TRUE(extension_->from_webstore()); // Otherwise there is no link. 245 EXPECT_TRUE(extension_->from_webstore()); // Otherwise there is no link.
210 views::Link* link = test::AppInfoDialogTestApi(dialog_).view_in_store_link(); 246 views::Link* link = test::AppInfoDialogTestApi(dialog_).view_in_store_link();
211 EXPECT_TRUE(link); 247 EXPECT_TRUE(link);
212 248
213 TabStripModel* tabs = browser()->tab_strip_model(); 249 TabStripModel* tabs = browser()->tab_strip_model();
214 EXPECT_EQ(0, tabs->count()); 250 EXPECT_EQ(0, tabs->count());
215 251
216 EXPECT_FALSE(widget_->IsClosed()); 252 EXPECT_FALSE(widget_->IsClosed());
217 EXPECT_FALSE(widget_destroyed_); 253 EXPECT_FALSE(widget_destroyed_);
218 link->OnKeyPressed(ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_SPACE, 0)); 254 link->OnKeyPressed(ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_SPACE, 0));
219 255
220 EXPECT_TRUE(widget_->IsClosed()); 256 EXPECT_TRUE(widget_->IsClosed());
221 EXPECT_FALSE(widget_destroyed_); 257 EXPECT_FALSE(widget_destroyed_);
222 258
223 EXPECT_EQ(1, tabs->count()); 259 EXPECT_EQ(1, tabs->count());
224 content::WebContents* web_contents = tabs->GetWebContentsAt(0); 260 content::WebContents* web_contents = tabs->GetWebContentsAt(0);
225 261
226 std::string url = "https://chrome.google.com/webstore/detail/"; 262 std::string url = "https://chrome.google.com/webstore/detail/";
227 url += kTestExtensionId; 263 url += kTestExtensionId;
228 url += "?utm_source=chrome-app-launcher-info-dialog"; 264 url += "?utm_source=chrome-app-launcher-info-dialog";
229 EXPECT_EQ(GURL(url), web_contents->GetURL()); 265 EXPECT_EQ(GURL(url), web_contents->GetURL());
230 266
231 base::RunLoop().RunUntilIdle(); 267 base::RunLoop().RunUntilIdle();
232 EXPECT_TRUE(widget_destroyed_); 268 EXPECT_TRUE(widget_destroyed_);
233 } 269 }
270
271 #if defined(OS_CHROMEOS)
272 TEST_F(AppInfoDialogViewsTest, ArcAppInfoLinks) {
273 ShowAppInfo(extension_misc::kChromeAppId);
274 EXPECT_FALSE(widget_->IsClosed());
275 // App Info should not have ARC App info links section because ARC Settings
276 // app is not available yet.
277 EXPECT_FALSE(dialog_->arc_app_info_links_);
278
279 // Re-show App Info but with ARC Settings app enabled.
280 CloseAppInfo();
281 ArcAppListPrefs* arc_prefs =
282 ArcAppListPrefs::Get(extension_environment_.profile());
283 ASSERT_TRUE(arc_prefs);
284 arc::mojom::AppHost* app_host = arc_prefs;
285 app_host->OnAppListRefreshed(GetArcSettingsAppMojoInfo());
286 EXPECT_TRUE(arc_prefs->IsRegistered(arc::kSettingsAppId));
287 ShowAppInfo(extension_misc::kChromeAppId);
288 EXPECT_FALSE(widget_->IsClosed());
289 EXPECT_TRUE(dialog_->arc_app_info_links_);
290
291 // Re-show App Info but for non-primary profie.
msw 2017/02/15 21:48:28 nit: 'profile'
khmel 2017/02/16 15:47:52 Done.
292 CloseAppInfo();
293 std::unique_ptr<TestingProfile> other_profile(new TestingProfile);
msw 2017/02/15 21:48:28 nit: base::MakeUnique
khmel 2017/02/16 15:47:51 Done.
294 extension_environment_.CreateExtensionServiceForProfile(other_profile.get());
295 scoped_refptr<const extensions::Extension> other_app =
296 extension_environment_.MakePackagedApp(extension_misc::kChromeAppId,
297 true);
298 extensions::ExtensionSystem::Get(other_profile.get())
299 ->extension_service()
300 ->AddExtension(other_app.get());
301 ShowAppInfoForProfile(extension_misc::kChromeAppId, other_profile.get());
302 EXPECT_FALSE(widget_->IsClosed());
303 EXPECT_FALSE(dialog_->arc_app_info_links_);
msw 2017/02/15 21:48:28 nit: add some explanation as to why the links aren
khmel 2017/02/16 15:47:52 Thanks for ready-to-use proposal :)
304 }
305 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698