diff options
-rw-r--r-- | extensions/BUILD.gn | 1 | ||||
-rw-r--r-- | extensions/extensions.gyp | 1 | ||||
-rw-r--r-- | extensions/renderer/api/serial/serial_api_unittest.cc | 2 | ||||
-rw-r--r-- | extensions/renderer/api_test_base.cc | 4 | ||||
-rw-r--r-- | extensions/renderer/api_test_base.h | 10 | ||||
-rw-r--r-- | extensions/renderer/dispatcher.cc | 3 | ||||
-rw-r--r-- | extensions/renderer/mojo/keep_alive_client_unittest.cc | 94 | ||||
-rw-r--r-- | extensions/renderer/resources/binding.js | 7 | ||||
-rw-r--r-- | extensions/renderer/resources/extensions_renderer_resources.grd | 2 | ||||
-rw-r--r-- | extensions/renderer/resources/keep_alive.js | 41 | ||||
-rw-r--r-- | extensions/test/data/keep_alive_client_unittest.js | 44 |
11 files changed, 209 insertions, 0 deletions
diff --git a/extensions/BUILD.gn b/extensions/BUILD.gn index 51da392..4600161 100644 --- a/extensions/BUILD.gn +++ b/extensions/BUILD.gn @@ -238,6 +238,7 @@ test("extensions_unittests") { "renderer/module_system_test.cc", "renderer/module_system_test.h", "renderer/module_system_unittest.cc", + "renderer/mojo/keep_alive_client_unittest.cc", "renderer/safe_builtins_unittest.cc", "renderer/script_context_set_unittest.cc", "renderer/utils_unittest.cc", diff --git a/extensions/extensions.gyp b/extensions/extensions.gyp index 5ca8ca8..969847d 100644 --- a/extensions/extensions.gyp +++ b/extensions/extensions.gyp @@ -1212,6 +1212,7 @@ 'renderer/api_test_base_unittest.cc', 'renderer/event_unittest.cc', 'renderer/json_schema_unittest.cc', + 'renderer/mojo/keep_alive_client_unittest.cc', 'renderer/messaging_utils_unittest.cc', 'renderer/module_system_test.cc', 'renderer/module_system_test.h', diff --git a/extensions/renderer/api/serial/serial_api_unittest.cc b/extensions/renderer/api/serial/serial_api_unittest.cc index 31362eb..a01c69f 100644 --- a/extensions/renderer/api/serial/serial_api_unittest.cc +++ b/extensions/renderer/api/serial/serial_api_unittest.cc @@ -5,6 +5,7 @@ #include "device/serial/serial_device_enumerator.h" #include "device/serial/serial_service_impl.h" #include "device/serial/test_serial_io_handler.h" +#include "extensions/common/mojo/keep_alive.mojom.h" #include "extensions/renderer/api_test_base.h" #include "grit/extensions_renderer_resources.h" @@ -410,6 +411,7 @@ class SerialApiTest : public ApiTestBase { IDR_SERIAL_SERIALIZATION_MOJOM_JS); service_provider()->AddService<device::serial::SerialService>(base::Bind( &SerialApiTest::CreateSerialService, base::Unretained(this))); + service_provider()->IgnoreServiceRequests<KeepAlive>(); } scoped_refptr<TestIoHandlerBase> io_handler_; diff --git a/extensions/renderer/api_test_base.cc b/extensions/renderer/api_test_base.cc index 7e3dd7b..17e09c2 100644 --- a/extensions/renderer/api_test_base.cc +++ b/extensions/renderer/api_test_base.cc @@ -96,6 +96,10 @@ mojo::Handle TestServiceProvider::ConnectToService( TestServiceProvider::TestServiceProvider() { } +// static +void TestServiceProvider::IgnoreHandle(mojo::ScopedMessagePipeHandle handle) { +} + ApiTestBase::ApiTestBase() { } ApiTestBase::~ApiTestBase() { diff --git a/extensions/renderer/api_test_base.h b/extensions/renderer/api_test_base.h index cc12e73..3684080 100644 --- a/extensions/renderer/api_test_base.h +++ b/extensions/renderer/api_test_base.h @@ -43,6 +43,13 @@ class TestServiceProvider : public gin::Wrappable<TestServiceProvider> { base::Bind(ForwardToServiceFactory<Interface>, service_factory))); } + // Ignore requests for the Interface service. + template <typename Interface> + void IgnoreServiceRequests() { + service_factories_.insert(std::make_pair( + Interface::Name_, base::Bind(&TestServiceProvider::IgnoreHandle))); + } + static gin::WrapperInfo kWrapperInfo; private: @@ -57,6 +64,9 @@ class TestServiceProvider : public gin::Wrappable<TestServiceProvider> { mojo::ScopedMessagePipeHandle handle) { service_factory.Run(mojo::MakeRequest<Interface>(handle.Pass())); } + + static void IgnoreHandle(mojo::ScopedMessagePipeHandle handle); + std::map<std::string, base::Callback<void(mojo::ScopedMessagePipeHandle)> > service_factories_; }; diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc index 2e42d71..6522034 100644 --- a/extensions/renderer/dispatcher.cc +++ b/extensions/renderer/dispatcher.cc @@ -574,6 +574,9 @@ std::vector<std::pair<std::string, int> > Dispatcher::GetJsResources() { std::make_pair(mojo::kUnicodeModuleName, IDR_MOJO_UNICODE_JS)); resources.push_back( std::make_pair(mojo::kValidatorModuleName, IDR_MOJO_VALIDATOR_JS)); + resources.push_back(std::make_pair("keep_alive", IDR_KEEP_ALIVE_JS)); + resources.push_back(std::make_pair("extensions/common/mojo/keep_alive.mojom", + IDR_KEEP_ALIVE_MOJOM_JS)); // Custom bindings. resources.push_back( diff --git a/extensions/renderer/mojo/keep_alive_client_unittest.cc b/extensions/renderer/mojo/keep_alive_client_unittest.cc new file mode 100644 index 0000000..2e76dd3 --- /dev/null +++ b/extensions/renderer/mojo/keep_alive_client_unittest.cc @@ -0,0 +1,94 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/common/mojo/keep_alive.mojom.h" +#include "extensions/renderer/api_test_base.h" +#include "grit/extensions_renderer_resources.h" +#include "mojo/public/cpp/bindings/interface_impl.h" + +// A test launcher for tests for the stash client defined in +// extensions/test/data/keep_alive_client_unittest.js. + +namespace extensions { +namespace { + +// A KeepAlive implementation that calls provided callbacks on creation and +// destruction. +class TestKeepAlive : public mojo::InterfaceImpl<KeepAlive> { + public: + explicit TestKeepAlive(const base::Closure& on_destruction) + : on_destruction_(on_destruction) {} + + ~TestKeepAlive() override { on_destruction_.Run(); } + + static void Create(const base::Closure& on_creation, + const base::Closure& on_destruction, + mojo::InterfaceRequest<KeepAlive> keep_alive) { + mojo::BindToRequest(new TestKeepAlive(on_destruction), &keep_alive); + on_creation.Run(); + } + + private: + const base::Closure on_destruction_; +}; + +} // namespace + +class KeepAliveClientTest : public ApiTestBase { + public: + KeepAliveClientTest() {} + + void SetUp() override { + ApiTestBase::SetUp(); + service_provider()->AddService( + base::Bind(&TestKeepAlive::Create, + base::Bind(&KeepAliveClientTest::KeepAliveCreated, + base::Unretained(this)), + base::Bind(&KeepAliveClientTest::KeepAliveDestroyed, + base::Unretained(this)))); + created_keep_alive_ = false; + destroyed_keep_alive_ = false; + } + + void WaitForKeepAlive() { + // Wait for a keep-alive to be created and destroyed. + while (!created_keep_alive_ || !destroyed_keep_alive_) { + base::RunLoop run_loop; + stop_run_loop_ = run_loop.QuitClosure(); + run_loop.Run(); + } + EXPECT_TRUE(created_keep_alive_); + EXPECT_TRUE(destroyed_keep_alive_); + } + + private: + void KeepAliveCreated() { + created_keep_alive_ = true; + if (!stop_run_loop_.is_null()) + stop_run_loop_.Run(); + } + void KeepAliveDestroyed() { + destroyed_keep_alive_ = true; + if (!stop_run_loop_.is_null()) + stop_run_loop_.Run(); + } + + bool created_keep_alive_; + bool destroyed_keep_alive_; + base::Closure stop_run_loop_; + + DISALLOW_COPY_AND_ASSIGN(KeepAliveClientTest); +}; + +TEST_F(KeepAliveClientTest, KeepAliveWithSuccessfulCall) { + RunTest("keep_alive_client_unittest.js", "testKeepAliveWithSuccessfulCall"); + WaitForKeepAlive(); +} + +TEST_F(KeepAliveClientTest, KeepAliveWithError) { + RunTest("keep_alive_client_unittest.js", "testKeepAliveWithError"); + WaitForKeepAlive(); +} + +} // namespace extensions diff --git a/extensions/renderer/resources/binding.js b/extensions/renderer/resources/binding.js index d36f1ed..9804b61 100644 --- a/extensions/renderer/resources/binding.js +++ b/extensions/renderer/resources/binding.js @@ -73,12 +73,19 @@ APIFunctions.prototype.setHandleRequestWithPromise = var stack = exceptionHandler.getExtensionStackTrace(); var callback = arguments[arguments.length - 1]; var args = $Array.slice(arguments, 0, arguments.length - 1); + var keepAlivePromise = requireAsync('keep_alive').then(function(module) { + return module.createKeepAlive(); + }); $Function.apply(customizedFunction, this, args).then(function(result) { sendRequestHandler.safeCallbackApply( name, {'stack': stack}, callback, [result]); }).catch(function(error) { var message = exceptionHandler.safeErrorToString(error, true); lastError.run(name, message, stack, callback); + }).then(function() { + keepAlivePromise.then(function(keepAlive) { + keepAlive.close(); + }); }); }); }; diff --git a/extensions/renderer/resources/extensions_renderer_resources.grd b/extensions/renderer/resources/extensions_renderer_resources.grd index 2913fdf..84f67875 100644 --- a/extensions/renderer/resources/extensions_renderer_resources.grd +++ b/extensions/renderer/resources/extensions_renderer_resources.grd @@ -20,6 +20,8 @@ <include name="IDR_EVENT_BINDINGS_JS" file="event.js" type="BINDATA" /> <include name="IDR_IMAGE_UTIL_JS" file="image_util.js" type="BINDATA" /> <include name="IDR_JSON_SCHEMA_JS" file="json_schema.js" type="BINDATA" /> + <include name="IDR_KEEP_ALIVE_JS" file="keep_alive.js" type="BINDATA" /> + <include name="IDR_KEEP_ALIVE_MOJOM_JS" file="${mojom_root}\extensions\common\mojo\keep_alive.mojom.js" use_base_dir="false" type="BINDATA" /> <include name="IDR_LAST_ERROR_JS" file="last_error.js" type="BINDATA" /> <include name="IDR_MESSAGING_JS" file="messaging.js" type="BINDATA" /> <include name="IDR_MESSAGING_UTILS_JS" file="messaging_utils.js" type="BINDATA" /> diff --git a/extensions/renderer/resources/keep_alive.js b/extensions/renderer/resources/keep_alive.js new file mode 100644 index 0000000..281e851 --- /dev/null +++ b/extensions/renderer/resources/keep_alive.js @@ -0,0 +1,41 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +define('keep_alive', [ + 'content/public/renderer/service_provider', + 'extensions/common/mojo/keep_alive.mojom', + 'mojo/public/js/bindings/core', +], function(serviceProvider, mojom, core) { + + /** + * An object that keeps the background page alive until closed. + * @constructor + * @alias module:keep_alive~KeepAlive + */ + function KeepAlive() { + /** + * The handle to the keep-alive object in the browser. + * @type {!MojoHandle} + * @private + */ + this.handle_ = serviceProvider.connectToService(mojom.KeepAlive.name); + } + + /** + * Removes this keep-alive. + */ + KeepAlive.prototype.close = function() { + core.close(this.handle_); + }; + + var exports = {}; + + return { + /** + * Creates a keep-alive. + * @return {!module:keep_alive~KeepAlive} A new keep-alive. + */ + createKeepAlive: function() { return new KeepAlive(); } + }; +}); diff --git a/extensions/test/data/keep_alive_client_unittest.js b/extensions/test/data/keep_alive_client_unittest.js new file mode 100644 index 0000000..7b88fb0 --- /dev/null +++ b/extensions/test/data/keep_alive_client_unittest.js @@ -0,0 +1,44 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * Unit tests for the keep-alive client. + * + * They are launched by extensions/renderer/mojo/keep_alive_client_unittest.cc. + */ + +var test = require('test').binding; +var unittestBindings = require('test_environment_specific_bindings'); +var utils = require('utils'); + +var shouldSucceed; + +// We need to set custom bindings for a real API and serial.getDevices has a +// simple signature. +var binding = require('binding').Binding.create('serial'); +binding.registerCustomHook(function(bindingsAPI) { + bindingsAPI.apiFunctions.setHandleRequestWithPromise('getDevices', + function() { + if (shouldSucceed) + return Promise.resolve([]); + else + return Promise.reject(); + }); +}); +var apiFunction = binding.generate().getDevices; + +unittestBindings.exportTests([ + // Test that a keep alive is created and destroyed for a successful API call. + function testKeepAliveWithSuccessfulCall() { + shouldSucceed = true; + utils.promise(apiFunction).then(test.succeed, test.fail); + }, + + // Test that a keep alive is created and destroyed for an unsuccessful API + // call. + function testKeepAliveWithError() { + shouldSucceed = false; + utils.promise(apiFunction).then(test.fail, test.succeed); + }, +], test.runTests, exports); |