| Index: chrome/browser/extensions/events_apitest.cc
 | 
| diff --git a/chrome/browser/extensions/events_apitest.cc b/chrome/browser/extensions/events_apitest.cc
 | 
| index 8787df1e60d083be72a850e2172ccf85857c39bf..143a82d733d684781eac5d82d07b4c60a7ddb6cb 100644
 | 
| --- a/chrome/browser/extensions/events_apitest.cc
 | 
| +++ b/chrome/browser/extensions/events_apitest.cc
 | 
| @@ -5,8 +5,12 @@
 | 
|  #include "base/files/file_path.h"
 | 
|  #include "base/files/file_util.h"
 | 
|  #include "chrome/browser/extensions/extension_apitest.h"
 | 
| +#include "chrome/browser/extensions/extension_service.h"
 | 
| +#include "chrome/test/base/ui_test_utils.h"
 | 
|  #include "extensions/browser/event_router.h"
 | 
|  #include "extensions/browser/extension_registry.h"
 | 
| +#include "extensions/browser/scoped_ignore_content_verifier_for_test.h"
 | 
| +#include "extensions/test/result_catcher.h"
 | 
|  
 | 
|  namespace extensions {
 | 
|  
 | 
| @@ -65,4 +69,146 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, EventsAreUnregistered) {
 | 
|        event_router->ExtensionHasEventListener(id, "webNavigation.onCompleted"));
 | 
|  }
 | 
|  
 | 
| +class EventsApiTest : public ExtensionApiTest {
 | 
| + public:
 | 
| +  EventsApiTest() {}
 | 
| +
 | 
| + protected:
 | 
| +  void SetUpOnMainThread() override {
 | 
| +    ExtensionApiTest::SetUpOnMainThread();
 | 
| +    EXPECT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
 | 
| +  }
 | 
| +
 | 
| +  struct ExtensionCRXData {
 | 
| +    std::string unpacked_relative_path;
 | 
| +    base::FilePath crx_path;
 | 
| +    explicit ExtensionCRXData(const std::string& unpacked_relative_path)
 | 
| +        : unpacked_relative_path(unpacked_relative_path) {}
 | 
| +  };
 | 
| +
 | 
| +  void SetUpCRX(const std::string& root_dir,
 | 
| +                const std::string& pem_filename,
 | 
| +                std::vector<ExtensionCRXData>* crx_data_list) {
 | 
| +    const base::FilePath test_dir = test_data_dir_.AppendASCII(root_dir);
 | 
| +    const base::FilePath pem_path = test_dir.AppendASCII(pem_filename);
 | 
| +    for (ExtensionCRXData& crx_data : *crx_data_list) {
 | 
| +      crx_data.crx_path = PackExtensionWithOptions(
 | 
| +          test_dir.AppendASCII(crx_data.unpacked_relative_path),
 | 
| +          scoped_temp_dir_.GetPath().AppendASCII(
 | 
| +              crx_data.unpacked_relative_path + ".crx"),
 | 
| +          pem_path, base::FilePath());
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  base::ScopedTempDir scoped_temp_dir_;
 | 
| +  ScopedIgnoreContentVerifierForTest ignore_content_verification_;
 | 
| +
 | 
| +  DISALLOW_COPY_AND_ASSIGN(EventsApiTest);
 | 
| +};
 | 
| +
 | 
| +// Tests that updating an extension sends runtime.onInstalled event to the
 | 
| +// updated extension.
 | 
| +IN_PROC_BROWSER_TEST_F(EventsApiTest, ExtensionUpdateSendsOnInstalledEvent) {
 | 
| +  std::vector<ExtensionCRXData> data;
 | 
| +  data.emplace_back("v1");
 | 
| +  data.emplace_back("v2");
 | 
| +  SetUpCRX("lazy_events/on_installed", "pem.pem", &data);
 | 
| +
 | 
| +  ExtensionId extension_id;
 | 
| +  {
 | 
| +    // Install version 1 of the extension and expect runtime.onInstalled.
 | 
| +    ResultCatcher catcher;
 | 
| +    const int expected_change = 1;
 | 
| +    const Extension* extension_v1 =
 | 
| +        InstallExtension(data[0].crx_path, expected_change);
 | 
| +    extension_id = extension_v1->id();
 | 
| +    ASSERT_TRUE(extension_v1);
 | 
| +    EXPECT_TRUE(catcher.GetNextResult());
 | 
| +  }
 | 
| +  {
 | 
| +    // Update to version 2, also expect runtime.onInstalled.
 | 
| +    ResultCatcher catcher;
 | 
| +    const int expected_change = 0;
 | 
| +    const Extension* extension_v2 =
 | 
| +        UpdateExtension(extension_id, data[1].crx_path, expected_change);
 | 
| +    ASSERT_TRUE(extension_v2);
 | 
| +    EXPECT_TRUE(catcher.GetNextResult());
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +// Tests that if updating an extension makes the extension disabled (due to
 | 
| +// permissions increase), then enabling the extension fires runtime.onInstalled
 | 
| +// correctly to the updated extension.
 | 
| +IN_PROC_BROWSER_TEST_F(EventsApiTest,
 | 
| +                       UpdateDispatchesOnInstalledAfterEnablement) {
 | 
| +  std::vector<ExtensionCRXData> data;
 | 
| +  data.emplace_back("v1");
 | 
| +  data.emplace_back("v2");
 | 
| +  SetUpCRX("lazy_events/on_installed_permissions_increase", "pem.pem", &data);
 | 
| +
 | 
| +  ExtensionRegistry* registry = ExtensionRegistry::Get(profile());
 | 
| +  ExtensionId extension_id;
 | 
| +  {
 | 
| +    // Install version 1 of the extension and expect runtime.onInstalled.
 | 
| +    ResultCatcher catcher;
 | 
| +    const int expected_change = 1;
 | 
| +    const Extension* extension_v1 =
 | 
| +        InstallExtension(data[0].crx_path, expected_change);
 | 
| +    extension_id = extension_v1->id();
 | 
| +    ASSERT_TRUE(extension_v1);
 | 
| +    EXPECT_TRUE(catcher.GetNextResult());
 | 
| +  }
 | 
| +  {
 | 
| +    // Update to version 2, which will be disabled due to permissions increase.
 | 
| +    ResultCatcher catcher;
 | 
| +    const int expected_change = -1;  // Expect extension to be disabled.
 | 
| +    ASSERT_FALSE(
 | 
| +        UpdateExtension(extension_id, data[1].crx_path, expected_change));
 | 
| +
 | 
| +    const Extension* extension_v2 =
 | 
| +        registry->disabled_extensions().GetByID(extension_id);
 | 
| +    ASSERT_TRUE(extension_v2);
 | 
| +    // Enable the extension.
 | 
| +    extension_service()->GrantPermissionsAndEnableExtension(extension_v2);
 | 
| +    EXPECT_TRUE(catcher.GetNextResult());
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +// Tests that if an extension's updated version has a new lazy listener, it
 | 
| +// fires properly after the update.
 | 
| +IN_PROC_BROWSER_TEST_F(EventsApiTest, NewlyIntroducedListener) {
 | 
| +  std::vector<ExtensionCRXData> data;
 | 
| +  data.emplace_back("v1");
 | 
| +  data.emplace_back("v2");
 | 
| +  SetUpCRX("lazy_events/new_event_in_new_version", "pem.pem", &data);
 | 
| +
 | 
| +  ExtensionId extension_id;
 | 
| +  {
 | 
| +    // Install version 1 of the extension.
 | 
| +    ResultCatcher catcher;
 | 
| +    const int expected_change = 1;
 | 
| +    const Extension* extension_v1 =
 | 
| +        InstallExtension(data[0].crx_path, expected_change);
 | 
| +    EXPECT_TRUE(extension_v1);
 | 
| +    extension_id = extension_v1->id();
 | 
| +    ASSERT_TRUE(extension_v1);
 | 
| +    EXPECT_TRUE(catcher.GetNextResult());
 | 
| +  }
 | 
| +  {
 | 
| +    // Update to version 2, that has tabs.onCreated event listener.
 | 
| +    ResultCatcher catcher;
 | 
| +    const int expected_change = 0;
 | 
| +    const Extension* extension_v2 =
 | 
| +        UpdateExtension(extension_id, data[1].crx_path, expected_change);
 | 
| +    ASSERT_TRUE(extension_v2);
 | 
| +    ui_test_utils::NavigateToURLWithDisposition(
 | 
| +        browser(), GURL(url::kAboutBlankURL),
 | 
| +        WindowOpenDisposition::NEW_BACKGROUND_TAB,
 | 
| +        ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
 | 
| +    // Expect tabs.onCreated to fire.
 | 
| +    EXPECT_TRUE(catcher.GetNextResult());
 | 
| +  }
 | 
| +}
 | 
| +
 | 
|  }  // namespace extensions
 | 
| 
 |