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

Side by Side Diff: chrome/browser/renderer_host/site_instance_unittest.cc

Issue 155071: Do some refactoring of renderer_host.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 5 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2006-2008 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/string16.h"
6 #include "chrome/browser/child_process_security_policy.h"
7 #include "chrome/browser/renderer_host/browser_render_process_host.h"
8 #include "chrome/browser/renderer_host/render_view_host.h"
9 #include "chrome/browser/renderer_host/test_render_view_host.h"
10 #include "chrome/browser/tab_contents/navigation_entry.h"
11 #include "chrome/browser/tab_contents/tab_contents.h"
12 #include "chrome/common/chrome_constants.h"
13 #include "chrome/common/render_messages.h"
14 #include "chrome/test/testing_profile.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 class SiteInstanceTest : public testing::Test {
18 private:
19 MessageLoopForUI message_loop_;
20 };
21
22 namespace {
23
24 class TestBrowsingInstance : public BrowsingInstance {
25 public:
26 TestBrowsingInstance(Profile* profile, int* deleteCounter)
27 : BrowsingInstance(profile),
28 use_process_per_site(false),
29 deleteCounter_(deleteCounter) {
30 }
31
32 ~TestBrowsingInstance() {
33 (*deleteCounter_)++;
34 }
35
36 // Overrides BrowsingInstance::ShouldUseProcessPerSite so that we can test
37 // both alternatives without using command-line switches.
38 bool ShouldUseProcessPerSite(const GURL& url) {
39 return use_process_per_site;
40 }
41
42 // Set by individual tests.
43 bool use_process_per_site;
44
45 private:
46 int* deleteCounter_;
47 };
48
49
50 class TestSiteInstance : public SiteInstance {
51 public:
52 static TestSiteInstance* CreateTestSiteInstance(Profile* profile,
53 int* siteDeleteCounter,
54 int* browsingDeleteCounter) {
55 TestBrowsingInstance* browsing_instance =
56 new TestBrowsingInstance(profile, browsingDeleteCounter);
57 return new TestSiteInstance(browsing_instance, siteDeleteCounter);
58 }
59
60 private:
61 TestSiteInstance(BrowsingInstance* browsing_instance, int* deleteCounter)
62 : SiteInstance(browsing_instance), deleteCounter_(deleteCounter) {}
63 ~TestSiteInstance() {
64 (*deleteCounter_)++;
65 }
66
67 int* deleteCounter_;
68 };
69
70 } // namespace
71
72 // Test to ensure no memory leaks for SiteInstance objects.
73 TEST_F(SiteInstanceTest, SiteInstanceDestructor) {
74 // The existance of these factories will cause TabContents to create our test
75 // one instead of the real one.
76 MockRenderProcessHostFactory rph_factory;
77 TestRenderViewHostFactory rvh_factory(&rph_factory);
78 int siteDeleteCounter = 0;
79 int browsingDeleteCounter = 0;
80 const GURL url("test:foo");
81
82 // Ensure that instances are deleted when their NavigationEntries are gone.
83 TestSiteInstance* instance =
84 TestSiteInstance::CreateTestSiteInstance(NULL, &siteDeleteCounter,
85 &browsingDeleteCounter);
86 EXPECT_EQ(0, siteDeleteCounter);
87
88 NavigationEntry* e1 = new NavigationEntry(instance, 0, url, GURL(),
89 string16(),
90 PageTransition::LINK);
91
92 // Redundantly setting e1's SiteInstance shouldn't affect the ref count.
93 e1->set_site_instance(instance);
94 EXPECT_EQ(0, siteDeleteCounter);
95
96 // Add a second reference
97 NavigationEntry* e2 = new NavigationEntry(instance, 0, url,
98 GURL(), string16(),
99 PageTransition::LINK);
100
101 // Now delete both entries and be sure the SiteInstance goes away.
102 delete e1;
103 EXPECT_EQ(0, siteDeleteCounter);
104 EXPECT_EQ(0, browsingDeleteCounter);
105 delete e2;
106 EXPECT_EQ(1, siteDeleteCounter);
107 // instance is now deleted
108 EXPECT_EQ(1, browsingDeleteCounter);
109 // browsing_instance is now deleted
110
111 // Ensure that instances are deleted when their RenderViewHosts are gone.
112 scoped_ptr<TestingProfile> profile(new TestingProfile());
113 instance =
114 TestSiteInstance::CreateTestSiteInstance(profile.get(),
115 &siteDeleteCounter,
116 &browsingDeleteCounter);
117 {
118 TabContents contents(profile.get(), instance, MSG_ROUTING_NONE, NULL);
119 EXPECT_EQ(1, siteDeleteCounter);
120 EXPECT_EQ(1, browsingDeleteCounter);
121 }
122
123 // Make sure that we flush any messages related to the above TabContents
124 // destruction.
125 MessageLoop::current()->RunAllPending();
126
127 EXPECT_EQ(2, siteDeleteCounter);
128 EXPECT_EQ(2, browsingDeleteCounter);
129 // contents is now deleted, along with instance and browsing_instance
130 }
131
132 // Test that NavigationEntries with SiteInstances can be cloned, but that their
133 // SiteInstances can be changed afterwards. Also tests that the ref counts are
134 // updated properly after the change.
135 TEST_F(SiteInstanceTest, CloneNavigationEntry) {
136 int siteDeleteCounter1 = 0;
137 int siteDeleteCounter2 = 0;
138 int browsingDeleteCounter = 0;
139 const GURL url("test:foo");
140
141 SiteInstance* instance1 =
142 TestSiteInstance::CreateTestSiteInstance(NULL, &siteDeleteCounter1,
143 &browsingDeleteCounter);
144 SiteInstance* instance2 =
145 TestSiteInstance::CreateTestSiteInstance(NULL, &siteDeleteCounter2,
146 &browsingDeleteCounter);
147
148 NavigationEntry* e1 = new NavigationEntry(instance1, 0, url, GURL(),
149 string16(),
150 PageTransition::LINK);
151 // Clone the entry
152 NavigationEntry* e2 = new NavigationEntry(*e1);
153
154 // Should be able to change the SiteInstance of the cloned entry.
155 e2->set_site_instance(instance2);
156
157 // The first SiteInstance should go away after deleting e1, since e2 should
158 // no longer be referencing it.
159 delete e1;
160 EXPECT_EQ(1, siteDeleteCounter1);
161 EXPECT_EQ(0, siteDeleteCounter2);
162
163 // The second SiteInstance should go away after deleting e2.
164 delete e2;
165 EXPECT_EQ(1, siteDeleteCounter1);
166 EXPECT_EQ(1, siteDeleteCounter2);
167
168 // Both BrowsingInstances are also now deleted
169 EXPECT_EQ(2, browsingDeleteCounter);
170 }
171
172 // Test to ensure UpdateMaxPageID is working properly.
173 TEST_F(SiteInstanceTest, UpdateMaxPageID) {
174 scoped_refptr<SiteInstance> instance(SiteInstance::CreateSiteInstance(NULL));
175 EXPECT_EQ(-1, instance->max_page_id());
176
177 // Make sure max_page_id_ is monotonically increasing.
178 instance->UpdateMaxPageID(3);
179 instance->UpdateMaxPageID(1);
180 EXPECT_EQ(3, instance->max_page_id());
181 }
182
183 // Test to ensure GetProcess returns and creates processes correctly.
184 TEST_F(SiteInstanceTest, GetProcess) {
185 // Ensure that GetProcess returns a process.
186 scoped_ptr<TestingProfile> profile(new TestingProfile());
187 scoped_ptr<RenderProcessHost> host1;
188 scoped_refptr<SiteInstance> instance(
189 SiteInstance::CreateSiteInstance(profile.get()));
190 host1.reset(instance->GetProcess());
191 EXPECT_TRUE(host1.get() != NULL);
192
193 // Ensure that GetProcess creates a new process.
194 scoped_refptr<SiteInstance> instance2(
195 SiteInstance::CreateSiteInstance(profile.get()));
196 scoped_ptr<RenderProcessHost> host2(instance2->GetProcess());
197 EXPECT_TRUE(host2.get() != NULL);
198 EXPECT_NE(host1.get(), host2.get());
199 }
200
201 // Test to ensure SetSite and site() work properly.
202 TEST_F(SiteInstanceTest, SetSite) {
203 scoped_refptr<SiteInstance> instance(SiteInstance::CreateSiteInstance(NULL));
204 EXPECT_FALSE(instance->has_site());
205 EXPECT_TRUE(instance->site().is_empty());
206
207 instance->SetSite(GURL("http://www.google.com/index.html"));
208 EXPECT_EQ(GURL("http://google.com"), instance->site());
209
210 EXPECT_TRUE(instance->has_site());
211 }
212
213 // Test to ensure GetSiteForURL properly returns sites for URLs.
214 TEST_F(SiteInstanceTest, GetSiteForURL) {
215 // Pages are irrelevant.
216 GURL test_url = GURL("http://www.google.com/index.html");
217 EXPECT_EQ(GURL("http://google.com"), SiteInstance::GetSiteForURL(test_url));
218
219 // Ports are irrlevant.
220 test_url = GURL("https://www.google.com:8080");
221 EXPECT_EQ(GURL("https://google.com"), SiteInstance::GetSiteForURL(test_url));
222
223 // Javascript URLs have no site.
224 test_url = GURL("javascript:foo();");
225 EXPECT_EQ(GURL::EmptyGURL(), SiteInstance::GetSiteForURL(test_url));
226
227 test_url = GURL("http://foo/a.html");
228 EXPECT_EQ(GURL("http://foo"), SiteInstance::GetSiteForURL(test_url));
229
230 test_url = GURL("file:///C:/Downloads/");
231 EXPECT_EQ(GURL::EmptyGURL(), SiteInstance::GetSiteForURL(test_url));
232
233 // TODO(creis): Do we want to special case file URLs to ensure they have
234 // either no site or a special "file://" site? We currently return
235 // "file://home/" as the site, which seems broken.
236 // test_url = GURL("file://home/");
237 // EXPECT_EQ(GURL::EmptyGURL(), SiteInstance::GetSiteForURL(test_url));
238 }
239
240 // Test of distinguishing URLs from different sites. Most of this logic is
241 // tested in RegistryControlledDomainTest. This test focuses on URLs with
242 // different schemes or ports.
243 TEST_F(SiteInstanceTest, IsSameWebSite) {
244 GURL url_foo = GURL("http://foo/a.html");
245 GURL url_foo2 = GURL("http://foo/b.html");
246 GURL url_foo_https = GURL("https://foo/a.html");
247 GURL url_foo_port = GURL("http://foo:8080/a.html");
248 GURL url_javascript = GURL("javascript:alert(1);");
249 GURL url_crash = GURL("about:crash");
250 GURL url_hang = GURL("about:hang");
251 GURL url_shorthang = GURL("about:shorthang");
252
253 // Same scheme and port -> same site.
254 EXPECT_TRUE(SiteInstance::IsSameWebSite(url_foo, url_foo2));
255
256 // Different scheme -> different site.
257 EXPECT_FALSE(SiteInstance::IsSameWebSite(url_foo, url_foo_https));
258
259 // Different port -> same site.
260 // (Changes to document.domain make renderer ignore the port.)
261 EXPECT_TRUE(SiteInstance::IsSameWebSite(url_foo, url_foo_port));
262
263 // JavaScript links should be considered same site for anything.
264 EXPECT_TRUE(SiteInstance::IsSameWebSite(url_javascript, url_foo));
265 EXPECT_TRUE(SiteInstance::IsSameWebSite(url_javascript, url_foo_https));
266 EXPECT_TRUE(SiteInstance::IsSameWebSite(url_javascript, url_foo_port));
267
268 // The crash/hang URLs should also be treated as same site. (Bug 1143809.)
269 EXPECT_TRUE(SiteInstance::IsSameWebSite(url_crash, url_foo));
270 EXPECT_TRUE(SiteInstance::IsSameWebSite(url_hang, url_foo));
271 EXPECT_TRUE(SiteInstance::IsSameWebSite(url_shorthang, url_foo));
272 }
273
274 // Test to ensure that there is only one SiteInstance per site in a given
275 // BrowsingInstance, when process-per-site is not in use.
276 TEST_F(SiteInstanceTest, OneSiteInstancePerSite) {
277 int deleteCounter = 0;
278 TestBrowsingInstance* browsing_instance =
279 new TestBrowsingInstance(NULL, &deleteCounter);
280 browsing_instance->use_process_per_site = false;
281
282 const GURL url_a1("http://www.google.com/1.html");
283 scoped_refptr<SiteInstance> site_instance_a1(
284 browsing_instance->GetSiteInstanceForURL(url_a1));
285 EXPECT_TRUE(site_instance_a1.get() != NULL);
286
287 // A separate site should create a separate SiteInstance.
288 const GURL url_b1("http://www.yahoo.com/");
289 scoped_refptr<SiteInstance> site_instance_b1(
290 browsing_instance->GetSiteInstanceForURL(url_b1));
291 EXPECT_NE(site_instance_a1.get(), site_instance_b1.get());
292
293 // Getting the new SiteInstance from the BrowsingInstance and from another
294 // SiteInstance in the BrowsingInstance should give the same result.
295 EXPECT_EQ(site_instance_b1.get(),
296 site_instance_a1->GetRelatedSiteInstance(url_b1));
297
298 // A second visit to the original site should return the same SiteInstance.
299 const GURL url_a2("http://www.google.com/2.html");
300 EXPECT_EQ(site_instance_a1.get(),
301 browsing_instance->GetSiteInstanceForURL(url_a2));
302 EXPECT_EQ(site_instance_a1.get(),
303 site_instance_a1->GetRelatedSiteInstance(url_a2));
304
305 // A visit to the original site in a new BrowsingInstance (same or different
306 // profile) should return a different SiteInstance.
307 TestBrowsingInstance* browsing_instance2 =
308 new TestBrowsingInstance(NULL, &deleteCounter);
309 browsing_instance2->use_process_per_site = false;
310 // Ensure the new SiteInstance is ref counted so that it gets deleted.
311 scoped_refptr<SiteInstance> site_instance_a2_2(
312 browsing_instance2->GetSiteInstanceForURL(url_a2));
313 EXPECT_NE(site_instance_a1.get(), site_instance_a2_2.get());
314
315 // Should be able to see that we do have SiteInstances.
316 EXPECT_TRUE(browsing_instance->HasSiteInstance(
317 GURL("http://mail.google.com")));
318 EXPECT_TRUE(browsing_instance2->HasSiteInstance(
319 GURL("http://mail.google.com")));
320 EXPECT_TRUE(browsing_instance->HasSiteInstance(
321 GURL("http://mail.yahoo.com")));
322
323 // Should be able to see that we don't have SiteInstances.
324 EXPECT_FALSE(browsing_instance->HasSiteInstance(
325 GURL("https://www.google.com")));
326 EXPECT_FALSE(browsing_instance2->HasSiteInstance(
327 GURL("http://www.yahoo.com")));
328
329 // browsing_instances will be deleted when their SiteInstances are deleted
330 }
331
332 // Test to ensure that there is only one SiteInstance per site for an entire
333 // Profile, if process-per-site is in use.
334 TEST_F(SiteInstanceTest, OneSiteInstancePerSiteInProfile) {
335 int deleteCounter = 0;
336 TestBrowsingInstance* browsing_instance =
337 new TestBrowsingInstance(NULL, &deleteCounter);
338 browsing_instance->use_process_per_site = true;
339
340 const GURL url_a1("http://www.google.com/1.html");
341 scoped_refptr<SiteInstance> site_instance_a1(
342 browsing_instance->GetSiteInstanceForURL(url_a1));
343 EXPECT_TRUE(site_instance_a1.get() != NULL);
344
345 // A separate site should create a separate SiteInstance.
346 const GURL url_b1("http://www.yahoo.com/");
347 scoped_refptr<SiteInstance> site_instance_b1(
348 browsing_instance->GetSiteInstanceForURL(url_b1));
349 EXPECT_NE(site_instance_a1.get(), site_instance_b1.get());
350
351 // Getting the new SiteInstance from the BrowsingInstance and from another
352 // SiteInstance in the BrowsingInstance should give the same result.
353 EXPECT_EQ(site_instance_b1.get(),
354 site_instance_a1->GetRelatedSiteInstance(url_b1));
355
356 // A second visit to the original site should return the same SiteInstance.
357 const GURL url_a2("http://www.google.com/2.html");
358 EXPECT_EQ(site_instance_a1.get(),
359 browsing_instance->GetSiteInstanceForURL(url_a2));
360 EXPECT_EQ(site_instance_a1.get(),
361 site_instance_a1->GetRelatedSiteInstance(url_a2));
362
363 // A visit to the original site in a new BrowsingInstance (same profile)
364 // should also return the same SiteInstance.
365 // This BrowsingInstance doesn't get its own SiteInstance within the test, so
366 // it won't be deleted by its children. Thus, we'll keep a ref count to it
367 // to make sure it gets deleted.
368 scoped_refptr<TestBrowsingInstance> browsing_instance2(
369 new TestBrowsingInstance(NULL, &deleteCounter));
370 browsing_instance2->use_process_per_site = true;
371 EXPECT_EQ(site_instance_a1.get(),
372 browsing_instance2->GetSiteInstanceForURL(url_a2));
373
374 // A visit to the original site in a new BrowsingInstance (different profile)
375 // should return a different SiteInstance.
376 scoped_ptr<TestingProfile> profile(new TestingProfile());
377 TestBrowsingInstance* browsing_instance3 =
378 new TestBrowsingInstance(profile.get(), &deleteCounter);
379 browsing_instance3->use_process_per_site = true;
380 // Ensure the new SiteInstance is ref counted so that it gets deleted.
381 scoped_refptr<SiteInstance> site_instance_a2_3(
382 browsing_instance3->GetSiteInstanceForURL(url_a2));
383 EXPECT_NE(site_instance_a1.get(), site_instance_a2_3.get());
384
385 // Should be able to see that we do have SiteInstances.
386 EXPECT_TRUE(browsing_instance->HasSiteInstance(
387 GURL("http://mail.google.com"))); // visited before
388 EXPECT_TRUE(browsing_instance2->HasSiteInstance(
389 GURL("http://mail.google.com"))); // visited before
390 EXPECT_TRUE(browsing_instance->HasSiteInstance(
391 GURL("http://mail.yahoo.com"))); // visited before
392 EXPECT_TRUE(browsing_instance2->HasSiteInstance(
393 GURL("http://www.yahoo.com"))); // different BI, but same profile
394
395 // Should be able to see that we don't have SiteInstances.
396 EXPECT_FALSE(browsing_instance->HasSiteInstance(
397 GURL("https://www.google.com"))); // not visited before
398 EXPECT_FALSE(browsing_instance3->HasSiteInstance(
399 GURL("http://www.yahoo.com"))); // different BI, different profile
400
401 // browsing_instances will be deleted when their SiteInstances are deleted
402 }
403
404 static SiteInstance* CreateSiteInstance(RenderProcessHostFactory* factory,
405 const GURL& url) {
406 SiteInstance* instance = SiteInstance::CreateSiteInstanceForURL(NULL, url);
407 instance->set_render_process_host_factory(factory);
408 return instance;
409 }
410
411 // Test to ensure that pages that require certain privileges are grouped
412 // in processes with similar pages.
413 TEST_F(SiteInstanceTest, ProcessSharingByType) {
414 MockRenderProcessHostFactory rph_factory;
415 ChildProcessSecurityPolicy* policy =
416 ChildProcessSecurityPolicy::GetInstance();
417
418 // Make a bunch of mock renderers so that we hit the limit.
419 std::vector<MockRenderProcessHost*> hosts;
420 for (size_t i = 0; i < chrome::kMaxRendererProcessCount; ++i)
421 hosts.push_back(new MockRenderProcessHost(NULL));
422
423 // Create some extension instances and make sure they share a process.
424 scoped_refptr<SiteInstance> extension1_instance(
425 CreateSiteInstance(&rph_factory, GURL("chrome-extension://foo/bar")));
426 policy->Add(extension1_instance->GetProcess()->pid());
427 policy->GrantExtensionBindings(extension1_instance->GetProcess()->pid());
428
429 scoped_refptr<SiteInstance> extension2_instance(
430 CreateSiteInstance(&rph_factory, GURL("chrome-extension://baz/bar")));
431
432 scoped_ptr<RenderProcessHost> extension_host(
433 extension1_instance->GetProcess());
434 EXPECT_EQ(extension1_instance->GetProcess(),
435 extension2_instance->GetProcess());
436
437 // Create some DOMUI instances and make sure they share a process.
438 scoped_refptr<SiteInstance> dom1_instance(
439 CreateSiteInstance(&rph_factory, GURL("chrome://newtab")));
440 policy->Add(dom1_instance->GetProcess()->pid());
441 policy->GrantDOMUIBindings(dom1_instance->GetProcess()->pid());
442
443 scoped_refptr<SiteInstance> dom2_instance(
444 CreateSiteInstance(&rph_factory, GURL("chrome://history")));
445
446 scoped_ptr<RenderProcessHost> dom_host(dom1_instance->GetProcess());
447 EXPECT_EQ(dom1_instance->GetProcess(), dom2_instance->GetProcess());
448
449 // Make sure none of differing privilege processes are mixed.
450 EXPECT_NE(extension1_instance->GetProcess(), dom1_instance->GetProcess());
451
452 for (size_t i = 0; i < chrome::kMaxRendererProcessCount; ++i) {
453 EXPECT_NE(extension1_instance->GetProcess(), hosts[i]);
454 EXPECT_NE(dom1_instance->GetProcess(), hosts[i]);
455 }
456
457 STLDeleteContainerPointers(hosts.begin(), hosts.end());
458 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698