| Index: extensions/browser/renderer_startup_helper_unittest.cc | 
| diff --git a/extensions/browser/renderer_startup_helper_unittest.cc b/extensions/browser/renderer_startup_helper_unittest.cc | 
| index 613ed8443787c6e86c662e3b9705cd688a058915..2e922343a3ac4ef05a708d97fe2b18c2443bcf0b 100644 | 
| --- a/extensions/browser/renderer_startup_helper_unittest.cc | 
| +++ b/extensions/browser/renderer_startup_helper_unittest.cc | 
| @@ -6,12 +6,16 @@ | 
|  | 
| #include "base/memory/ptr_util.h" | 
| #include "base/stl_util.h" | 
| +#include "components/crx_file/id_util.h" | 
| #include "content/public/browser/notification_service.h" | 
| #include "content/public/browser/notification_types.h" | 
| #include "content/public/test/mock_render_process_host.h" | 
| +#include "extensions/browser/extension_prefs.h" | 
| #include "extensions/browser/extension_registry.h" | 
| #include "extensions/browser/extension_registry_factory.h" | 
| +#include "extensions/browser/extension_util.h" | 
| #include "extensions/browser/extensions_test.h" | 
| +#include "extensions/browser/test_extensions_browser_client.h" | 
| #include "extensions/common/extension_builder.h" | 
| #include "extensions/common/extension_messages.h" | 
|  | 
| @@ -29,11 +33,14 @@ class RendererStartupHelperTest : public ExtensionsTest { | 
| ExtensionRegistryFactory::GetForBrowserContext(browser_context()); | 
| render_process_host_ = | 
| base::MakeUnique<content::MockRenderProcessHost>(browser_context()); | 
| +    incognito_render_process_host_ = | 
| +        base::MakeUnique<content::MockRenderProcessHost>(incognito_context()); | 
| extension_ = CreateExtension("ext_1"); | 
| } | 
|  | 
| void TearDown() override { | 
| render_process_host_.reset(); | 
| +    incognito_render_process_host_.reset(); | 
| helper_.reset(); | 
| ExtensionsTest::TearDown(); | 
| } | 
| @@ -53,7 +60,7 @@ class RendererStartupHelperTest : public ExtensionsTest { | 
| content::NotificationService::NoDetails()); | 
| } | 
|  | 
| -  scoped_refptr<Extension> CreateExtension(const std::string& extension_id) { | 
| +  scoped_refptr<Extension> CreateExtension(const std::string& id_input) { | 
| std::unique_ptr<base::DictionaryValue> manifest = | 
| DictionaryBuilder() | 
| .Set("name", "extension") | 
| @@ -61,13 +68,10 @@ class RendererStartupHelperTest : public ExtensionsTest { | 
| .Set("manifest_version", 2) | 
| .Set("version", "0.1") | 
| .Build(); | 
| -    return ExtensionBuilder() | 
| -        .SetManifest(std::move(manifest)) | 
| -        .SetID(extension_id) | 
| -        .Build(); | 
| +    return CreateExtension(id_input, std::move(manifest)); | 
| } | 
|  | 
| -  scoped_refptr<Extension> CreateTheme(const std::string& extension_id) { | 
| +  scoped_refptr<Extension> CreateTheme(const std::string& id_input) { | 
| std::unique_ptr<base::DictionaryValue> manifest = | 
| DictionaryBuilder() | 
| .Set("name", "theme") | 
| @@ -76,10 +80,25 @@ class RendererStartupHelperTest : public ExtensionsTest { | 
| .Set("manifest_version", 2) | 
| .Set("version", "0.1") | 
| .Build(); | 
| -    return ExtensionBuilder() | 
| -        .SetManifest(std::move(manifest)) | 
| -        .SetID(extension_id) | 
| -        .Build(); | 
| +    return CreateExtension(id_input, std::move(manifest)); | 
| +  } | 
| + | 
| +  scoped_refptr<Extension> CreatePlatformApp(const std::string& id_input) { | 
| +    std::unique_ptr<base::Value> background = | 
| +        DictionaryBuilder() | 
| +            .Set("scripts", ListBuilder().Append("background.js").Build()) | 
| +            .Build(); | 
| +    std::unique_ptr<base::DictionaryValue> manifest = | 
| +        DictionaryBuilder() | 
| +            .Set("name", "platform_app") | 
| +            .Set("description", "a platform app") | 
| +            .Set("app", DictionaryBuilder() | 
| +                            .Set("background", std::move(background)) | 
| +                            .Build()) | 
| +            .Set("manifest_version", 2) | 
| +            .Set("version", "0.1") | 
| +            .Build(); | 
| +    return CreateExtension(id_input, std::move(manifest)); | 
| } | 
|  | 
| void AddExtensionToRegistry(scoped_refptr<Extension> extension) { | 
| @@ -115,9 +134,20 @@ class RendererStartupHelperTest : public ExtensionsTest { | 
| std::unique_ptr<RendererStartupHelper> helper_; | 
| ExtensionRegistry* registry_;  // Weak. | 
| std::unique_ptr<content::MockRenderProcessHost> render_process_host_; | 
| +  std::unique_ptr<content::MockRenderProcessHost> | 
| +      incognito_render_process_host_; | 
| scoped_refptr<Extension> extension_; | 
|  | 
| private: | 
| +  scoped_refptr<Extension> CreateExtension( | 
| +      const std::string& id_input, | 
| +      std::unique_ptr<base::DictionaryValue> manifest) { | 
| +    return ExtensionBuilder() | 
| +        .SetManifest(std::move(manifest)) | 
| +        .SetID(crx_file::id_util::GenerateId(id_input)) | 
| +        .Build(); | 
| +  } | 
| + | 
| DISALLOW_COPY_AND_ASSIGN(RendererStartupHelperTest); | 
| }; | 
|  | 
| @@ -243,4 +273,94 @@ TEST_F(RendererStartupHelperTest, LoadTheme) { | 
| EXPECT_FALSE(IsExtensionLoaded(*extension)); | 
| } | 
|  | 
| +// Tests that only incognito-enabled extensions are loaded in an incognito | 
| +// context. | 
| +TEST_F(RendererStartupHelperTest, ExtensionInIncognitoRenderer) { | 
| +  // Initialize the incognito renderer. | 
| +  EXPECT_FALSE(IsProcessInitialized(incognito_render_process_host_.get())); | 
| +  SimulateRenderProcessCreated(incognito_render_process_host_.get()); | 
| +  EXPECT_TRUE(IsProcessInitialized(incognito_render_process_host_.get())); | 
| + | 
| +  IPC::TestSink& sink = render_process_host_->sink(); | 
| +  IPC::TestSink& incognito_sink = incognito_render_process_host_->sink(); | 
| + | 
| +  // Enable the extension. It should not be loaded in the initialized incognito | 
| +  // renderer. | 
| +  sink.ClearMessages(); | 
| +  incognito_sink.ClearMessages(); | 
| +  EXPECT_FALSE(util::IsIncognitoEnabled(extension_->id(), browser_context())); | 
| +  EXPECT_FALSE(IsExtensionLoaded(*extension_)); | 
| +  AddExtensionToRegistry(extension_); | 
| +  helper_->OnExtensionLoaded(*extension_); | 
| +  EXPECT_EQ(0u, sink.message_count()); | 
| +  EXPECT_EQ(0u, incognito_sink.message_count()); | 
| +  EXPECT_TRUE(IsExtensionLoaded(*extension_)); | 
| +  EXPECT_FALSE(IsExtensionLoadedInProcess( | 
| +      *extension_, incognito_render_process_host_.get())); | 
| +  EXPECT_FALSE( | 
| +      IsExtensionLoadedInProcess(*extension_, render_process_host_.get())); | 
| + | 
| +  // Initialize the normal renderer. The extension should get loaded in it. | 
| +  sink.ClearMessages(); | 
| +  incognito_sink.ClearMessages(); | 
| +  EXPECT_FALSE(IsProcessInitialized(render_process_host_.get())); | 
| +  SimulateRenderProcessCreated(render_process_host_.get()); | 
| +  EXPECT_TRUE(IsProcessInitialized(render_process_host_.get())); | 
| +  EXPECT_TRUE( | 
| +      IsExtensionLoadedInProcess(*extension_, render_process_host_.get())); | 
| +  EXPECT_FALSE(IsExtensionLoadedInProcess( | 
| +      *extension_, incognito_render_process_host_.get())); | 
| +  // Multiple initialization messages including the extension load message | 
| +  // should be dispatched to the non-incognito renderer. | 
| +  EXPECT_LE(1u, sink.message_count()); | 
| +  EXPECT_EQ(0u, incognito_sink.message_count()); | 
| + | 
| +  // Enable the extension in incognito mode. This will reload the extension. | 
| +  sink.ClearMessages(); | 
| +  incognito_sink.ClearMessages(); | 
| +  ExtensionPrefs::Get(browser_context()) | 
| +      ->SetIsIncognitoEnabled(extension_->id(), true); | 
| +  helper_->OnExtensionUnloaded(*extension_); | 
| +  helper_->OnExtensionLoaded(*extension_); | 
| +  EXPECT_TRUE(IsExtensionLoadedInProcess(*extension_, | 
| +                                         incognito_render_process_host_.get())); | 
| +  EXPECT_TRUE( | 
| +      IsExtensionLoadedInProcess(*extension_, render_process_host_.get())); | 
| +  // The extension would not have been unloaded from the incognito renderer | 
| +  // since it wasn't loaded. | 
| +  ASSERT_EQ(1u, incognito_sink.message_count()); | 
| +  EXPECT_EQ(ExtensionMsg_Loaded::ID, incognito_sink.GetMessageAt(0)->type()); | 
| +  // The extension would be first unloaded and then loaded from the normal | 
| +  // renderer. | 
| +  ASSERT_EQ(2u, sink.message_count()); | 
| +  EXPECT_EQ(ExtensionMsg_Unloaded::ID, sink.GetMessageAt(0)->type()); | 
| +  EXPECT_EQ(ExtensionMsg_Loaded::ID, sink.GetMessageAt(1)->type()); | 
| +} | 
| + | 
| +// Tests that platform apps are always loaded in an incognito renderer. | 
| +TEST_F(RendererStartupHelperTest, PlatformAppInIncognitoRenderer) { | 
| +  // Initialize the incognito renderer. | 
| +  EXPECT_FALSE(IsProcessInitialized(incognito_render_process_host_.get())); | 
| +  SimulateRenderProcessCreated(incognito_render_process_host_.get()); | 
| +  EXPECT_TRUE(IsProcessInitialized(incognito_render_process_host_.get())); | 
| + | 
| +  IPC::TestSink& incognito_sink = incognito_render_process_host_->sink(); | 
| + | 
| +  scoped_refptr<Extension> platform_app(CreatePlatformApp("platform_app")); | 
| +  ASSERT_TRUE(platform_app->is_platform_app()); | 
| +  EXPECT_FALSE(util::IsIncognitoEnabled(platform_app->id(), browser_context())); | 
| +  EXPECT_FALSE(util::CanBeIncognitoEnabled(platform_app.get())); | 
| + | 
| +  // Enable the app. It should get loaded in the incognito renderer even though | 
| +  // IsIncognitoEnabled returns false for it, since it can't be enabled for | 
| +  // incognito. | 
| +  incognito_sink.ClearMessages(); | 
| +  AddExtensionToRegistry(platform_app); | 
| +  helper_->OnExtensionLoaded(*platform_app); | 
| +  EXPECT_TRUE(IsExtensionLoadedInProcess(*platform_app, | 
| +                                         incognito_render_process_host_.get())); | 
| +  ASSERT_EQ(1u, incognito_sink.message_count()); | 
| +  EXPECT_EQ(ExtensionMsg_Loaded::ID, incognito_sink.GetMessageAt(0)->type()); | 
| +} | 
| + | 
| }  // namespace extensions | 
|  |