summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--extensions/BUILD.gn1
-rw-r--r--extensions/extensions.gyp1
-rw-r--r--extensions/renderer/api/serial/serial_api_unittest.cc2
-rw-r--r--extensions/renderer/api_test_base.cc4
-rw-r--r--extensions/renderer/api_test_base.h10
-rw-r--r--extensions/renderer/dispatcher.cc3
-rw-r--r--extensions/renderer/mojo/keep_alive_client_unittest.cc94
-rw-r--r--extensions/renderer/resources/binding.js7
-rw-r--r--extensions/renderer/resources/extensions_renderer_resources.grd2
-rw-r--r--extensions/renderer/resources/keep_alive.js41
-rw-r--r--extensions/test/data/keep_alive_client_unittest.js44
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);