diff options
Diffstat (limited to 'mojo')
-rw-r--r-- | mojo/shell/public/cpp/connection.h | 5 | ||||
-rw-r--r-- | mojo/shell/public/cpp/lib/connection_impl.cc | 15 | ||||
-rw-r--r-- | mojo/shell/public/cpp/lib/connection_impl.h | 6 | ||||
-rw-r--r-- | mojo/shell/public/cpp/lib/connector_impl.cc | 6 | ||||
-rw-r--r-- | mojo/shell/public/cpp/lib/shell_connection.cc | 2 | ||||
-rw-r--r-- | mojo/shell/shell.cc | 46 | ||||
-rw-r--r-- | mojo/shell/tests/connect/BUILD.gn | 21 | ||||
-rw-r--r-- | mojo/shell/tests/connect/connect_test.mojom | 17 | ||||
-rw-r--r-- | mojo/shell/tests/connect/connect_test_app.cc | 33 | ||||
-rw-r--r-- | mojo/shell/tests/connect/connect_test_app_manifest.json | 6 | ||||
-rw-r--r-- | mojo/shell/tests/connect/connect_test_class_app.cc | 101 | ||||
-rw-r--r-- | mojo/shell/tests/connect/connect_test_class_app_manifest.json | 10 | ||||
-rw-r--r-- | mojo/shell/tests/connect/connect_unittest.cc | 48 |
13 files changed, 275 insertions, 41 deletions
diff --git a/mojo/shell/public/cpp/connection.h b/mojo/shell/public/cpp/connection.h index d3b3b8a..edb4073 100644 --- a/mojo/shell/public/cpp/connection.h +++ b/mojo/shell/public/cpp/connection.h @@ -82,6 +82,11 @@ class Connection { mojo::GetInterface(GetRemoteInterfaces(), ptr); } + // Returns true if the remote application has the specified capability class + // specified in its manifest. Only valid for inbound connections. Will return + // false for outbound connections. + virtual bool HasCapabilityClass(const std::string& class_name) const = 0; + // Returns the name that was used by the source application to establish a // connection to the destination application. // diff --git a/mojo/shell/public/cpp/lib/connection_impl.cc b/mojo/shell/public/cpp/lib/connection_impl.cc index d3585e7..5cfed52 100644 --- a/mojo/shell/public/cpp/lib/connection_impl.cc +++ b/mojo/shell/public/cpp/lib/connection_impl.cc @@ -25,7 +25,7 @@ ConnectionImpl::ConnectionImpl( uint32_t remote_id, shell::mojom::InterfaceProviderPtr remote_interfaces, shell::mojom::InterfaceProviderRequest local_interfaces, - const std::set<std::string>& allowed_interfaces, + const CapabilityRequest& capability_request, State initial_state) : connection_name_(connection_name), remote_(remote), @@ -33,9 +33,9 @@ ConnectionImpl::ConnectionImpl( state_(initial_state), local_registry_(std::move(local_interfaces), this), remote_interfaces_(std::move(remote_interfaces)), - allowed_interfaces_(allowed_interfaces), - allow_all_interfaces_(allowed_interfaces_.size() == 1 && - allowed_interfaces_.count("*") == 1), + capability_request_(capability_request), + allow_all_interfaces_(capability_request.interfaces.size() == 1 && + capability_request.interfaces.count("*") == 1), weak_factory_(this) {} ConnectionImpl::ConnectionImpl() @@ -53,6 +53,10 @@ shell::mojom::Connector::ConnectCallback ConnectionImpl::GetConnectCallback() { //////////////////////////////////////////////////////////////////////////////// // ConnectionImpl, Connection implementation: +bool ConnectionImpl::HasCapabilityClass(const std::string& class_name) const { + return capability_request_.classes.count(class_name) > 0; +} + const std::string& ConnectionImpl::GetConnectionName() { return connection_name_; } @@ -85,7 +89,8 @@ void ConnectionImpl::AddConnectionCompletedClosure(const Closure& callback) { } bool ConnectionImpl::AllowsInterface(const std::string& interface_name) const { - return allow_all_interfaces_ || allowed_interfaces_.count(interface_name); + return allow_all_interfaces_ || + capability_request_.interfaces.count(interface_name); } shell::mojom::InterfaceProvider* ConnectionImpl::GetRemoteInterfaces() { diff --git a/mojo/shell/public/cpp/lib/connection_impl.h b/mojo/shell/public/cpp/lib/connection_impl.h index 3247a5a..2c58d86 100644 --- a/mojo/shell/public/cpp/lib/connection_impl.h +++ b/mojo/shell/public/cpp/lib/connection_impl.h @@ -11,6 +11,7 @@ #include <string> #include "mojo/public/cpp/bindings/binding.h" +#include "mojo/shell/public/cpp/capabilities.h" #include "mojo/shell/public/cpp/connection.h" #include "mojo/shell/public/cpp/identity.h" #include "mojo/shell/public/interfaces/connector.mojom.h" @@ -33,7 +34,7 @@ class ConnectionImpl : public Connection { uint32_t remote_id, shell::mojom::InterfaceProviderPtr remote_interfaces, shell::mojom::InterfaceProviderRequest local_interfaces, - const std::set<std::string>& allowed_interfaces, + const CapabilityRequest& capability_request, State initial_state); ~ConnectionImpl() override; @@ -41,6 +42,7 @@ class ConnectionImpl : public Connection { private: // Connection: + bool HasCapabilityClass(const std::string& class_name) const override; const std::string& GetConnectionName() override; const Identity& GetRemoteIdentity() const override; void SetConnectionLostClosure(const Closure& handler) override; @@ -68,7 +70,7 @@ class ConnectionImpl : public Connection { InterfaceRegistry local_registry_; shell::mojom::InterfaceProviderPtr remote_interfaces_; - const std::set<std::string> allowed_interfaces_; + const CapabilityRequest capability_request_; const bool allow_all_interfaces_; base::WeakPtrFactory<ConnectionImpl> weak_factory_; diff --git a/mojo/shell/public/cpp/lib/connector_impl.cc b/mojo/shell/public/cpp/lib/connector_impl.cc index 74edbe4..98a7ae5 100644 --- a/mojo/shell/public/cpp/lib/connector_impl.cc +++ b/mojo/shell/public/cpp/lib/connector_impl.cc @@ -49,8 +49,8 @@ scoped_ptr<Connection> ConnectorImpl::Connect(ConnectParams* params) { // TODO(beng): We should filter outgoing interfaces also. The shell must pass // the manifest CapabilityFilter to the ShellConnection via // Initialize(), it can be used here. - std::set<std::string> allowed; - allowed.insert("*"); + CapabilityRequest request; + request.interfaces.insert("*"); shell::mojom::InterfaceProviderPtr local_interfaces; shell::mojom::InterfaceProviderRequest local_request = GetProxy(&local_interfaces); @@ -60,7 +60,7 @@ scoped_ptr<Connection> ConnectorImpl::Connect(ConnectParams* params) { scoped_ptr<internal::ConnectionImpl> registry(new internal::ConnectionImpl( params->target().name(), params->target(), shell::mojom::kInvalidInstanceID, std::move(remote_interfaces), - std::move(local_request), allowed, Connection::State::PENDING)); + std::move(local_request), request, Connection::State::PENDING)); shell::mojom::ShellClientFactoryPtr shell_client_factory; shell::mojom::PIDReceiverRequest pid_receiver_request; diff --git a/mojo/shell/public/cpp/lib/shell_connection.cc b/mojo/shell/public/cpp/lib/shell_connection.cc index 2e2a7ec..b169895 100644 --- a/mojo/shell/public/cpp/lib/shell_connection.cc +++ b/mojo/shell/public/cpp/lib/shell_connection.cc @@ -55,7 +55,7 @@ void ShellConnection::AcceptConnection( scoped_ptr<Connection> registry(new internal::ConnectionImpl( name, source.To<Identity>(), source_id, std::move(remote_interfaces), std::move(local_interfaces), - allowed_capabilities->interfaces.To<std::set<std::string>>(), + allowed_capabilities.To<CapabilityRequest>(), Connection::State::CONNECTED)); if (!client_->AcceptConnection(registry.get())) return; diff --git a/mojo/shell/shell.cc b/mojo/shell/shell.cc index 1daa93a..e5c46b3 100644 --- a/mojo/shell/shell.cc +++ b/mojo/shell/shell.cc @@ -55,22 +55,39 @@ CapabilitySpec GetPermissiveCapabilities() { return capabilities; } -CapabilityRequest GetCapabilityRequest(const CapabilitySpec& spec, - const Identity& identity) { +CapabilityRequest GetCapabilityRequest(const CapabilitySpec& source_spec, + const Identity& target) { // Start by looking for specs specific to the supplied identity. - auto it = spec.required.find(identity.name()); - if (it != spec.required.end()) + auto it = source_spec.required.find(target.name()); + if (it != source_spec.required.end()) return it->second; // Fall back to looking for a wildcard rule. - it = spec.required.find("*"); - if (spec.required.size() == 1 && it != spec.required.end()) + it = source_spec.required.find("*"); + if (source_spec.required.size() == 1 && it != source_spec.required.end()) return it->second; // Finally, nothing is allowed. return CapabilityRequest(); } +CapabilityRequest GenerateCapabilityRequestForConnection( + const CapabilitySpec& source_spec, + const Identity& target, + const CapabilitySpec& target_spec) { + CapabilityRequest request = GetCapabilityRequest(source_spec, target); + // Flatten all interfaces from classes requested by the source into the + // allowed interface set in the request. + for (const auto& class_name : request.classes) { + auto it = target_spec.provided.find(class_name); + if (it != target_spec.provided.end()) { + for (const auto& interface_name : it->second) + request.interfaces.insert(interface_name); + } + } + return request; +} + // Encapsulates a connection to an instance of an application, tracked by the // shell's Shell. class Shell::Instance : public mojom::Connector, @@ -82,13 +99,13 @@ class Shell::Instance : public mojom::Connector, Instance(mojom::ShellClientPtr shell_client, mojo::shell::Shell* shell, const Identity& identity, - const CapabilitySpec& capabilities) + const CapabilitySpec& capability_spec) : shell_(shell), id_(GenerateUniqueID()), identity_(identity), - capabilities_(capabilities), - allow_any_application_(capabilities.required.size() == 1 && - capabilities.required.count("*") == 1), + capability_spec_(capability_spec), + allow_any_application_(capability_spec.required.size() == 1 && + capability_spec.required.count("*") == 1), shell_client_(std::move(shell_client)), pid_receiver_binding_(this), weak_factory_(this) { @@ -117,7 +134,8 @@ class Shell::Instance : public mojom::Connector, spec.interfaces.insert("*"); Instance* source = shell_->GetExistingInstance(params->source()); if (source) { - spec = GetCapabilityRequest(source->capabilities_, identity_); + spec = GenerateCapabilityRequestForConnection( + source->capability_spec_, identity_, capability_spec_); source_id = source->id(); } shell_client_->AcceptConnection( @@ -267,8 +285,8 @@ class Shell::Instance : public mojom::Connector, bool ValidateCapabilities(const Identity& target, const ConnectCallback& callback) { if (allow_any_application_ || - capabilities_.required.find(target.name()) != - capabilities_.required.end()) { + capability_spec_.required.find(target.name()) != + capability_spec_.required.end()) { return true; } LOG(ERROR) << "Capabilities prevented connection from: " << @@ -296,7 +314,7 @@ class Shell::Instance : public mojom::Connector, // process is launched. const uint32_t id_; const Identity identity_; - const CapabilitySpec capabilities_; + const CapabilitySpec capability_spec_; const bool allow_any_application_; mojom::ShellClientPtr shell_client_; Binding<mojom::PIDReceiver> pid_receiver_binding_; diff --git a/mojo/shell/tests/connect/BUILD.gn b/mojo/shell/tests/connect/BUILD.gn index d2818b2..f55c225 100644 --- a/mojo/shell/tests/connect/BUILD.gn +++ b/mojo/shell/tests/connect/BUILD.gn @@ -23,6 +23,7 @@ source_set("connect") { data_deps = [ ":connect_test_app", + ":connect_test_class_app", ":connect_test_package", ":manifest", ] @@ -96,3 +97,23 @@ mojo_application_manifest("connect_test_app_manifest") { application_name = "connect_test_app" source = "connect_test_app_manifest.json" } + +mojo_native_application("connect_test_class_app") { + testonly = true + sources = [ + "connect_test_class_app.cc", + ] + deps = [ + ":connect_test_class_app_manifest", + ":interfaces", + "//base", + "//mojo/common:common_base", + "//mojo/shell/public/cpp:sources", + "//mojo/shell/public/interfaces", + ] +} + +mojo_application_manifest("connect_test_class_app_manifest") { + application_name = "connect_test_class_app" + source = "connect_test_class_app_manifest.json" +} diff --git a/mojo/shell/tests/connect/connect_test.mojom b/mojo/shell/tests/connect/connect_test.mojom index ba29865..2598f3e 100644 --- a/mojo/shell/tests/connect/connect_test.mojom +++ b/mojo/shell/tests/connect/connect_test.mojom @@ -9,12 +9,25 @@ interface ConnectTestService { GetInstance() => (string instance); }; -// Interface implemented by a standalone (non-package) app. +interface ClassInterface { + Ping() => (string response); +}; + +// Interface implemented by a standalone (non-package) app, +// mojo:connect_test_app. interface StandaloneApp { // Attempts to connect to an application whose name is explicitly allowed by - // the standalone app's CapabilityFilter, but whose enclosing package is not. + // the standalone app's CapabilitySpec, but whose enclosing package is not. // The connection should be blocked and title should be "uninitialized". ConnectToAllowedAppInBlockedPackage() => (string title); + + // Connects to mojo:connect_test_class_app & requests ClassInterface from it. + // This should be permitted because mojo:connect_test_app requests class + // "class" from mojo:connect_test_class_app, which mojo:connect_test_class_app + // defines as including ClassInterface. + // The response contains the response from ClassInterface::Ping() and + // ConnectTestService::GetTitle(). + ConnectToClassInterface() => (string class_interface_response, string title); }; struct ConnectionState { diff --git a/mojo/shell/tests/connect/connect_test_app.cc b/mojo/shell/tests/connect/connect_test_app.cc index 86ae235..abf51dc 100644 --- a/mojo/shell/tests/connect/connect_test_app.cc +++ b/mojo/shell/tests/connect/connect_test_app.cc @@ -17,6 +17,13 @@ namespace mojo { namespace shell { +namespace { +void ReceiveString(std::string* string, base::RunLoop* loop, + const std::string& response) { + *string = response; + loop->Quit(); +} +} using GetTitleCallback = test::mojom::ConnectTestService::GetTitleCallback; @@ -119,6 +126,32 @@ class ConnectTestApp : public ShellClient, run_loop.Run(); } } + void ConnectToClassInterface( + const ConnectToClassInterfaceCallback& callback) override { + scoped_ptr<Connection> connection = + connector_->Connect("mojo:connect_test_class_app"); + test::mojom::ClassInterfacePtr class_interface; + connection->GetInterface(&class_interface); + std::string ping_response; + { + base::RunLoop loop; + class_interface->Ping(base::Bind(&ReceiveString, &ping_response, &loop)); + base::MessageLoop::ScopedNestableTaskAllower allow( + base::MessageLoop::current()); + loop.Run(); + } + test::mojom::ConnectTestServicePtr service; + connection->GetInterface(&service); + std::string title_response; + { + base::RunLoop loop; + service->GetTitle(base::Bind(&ReceiveString, &title_response, &loop)); + base::MessageLoop::ScopedNestableTaskAllower allow( + base::MessageLoop::current()); + loop.Run(); + } + callback.Run(ping_response, title_response); + } // test::mojom::BlockedInterface: void GetTitleBlocked(const GetTitleBlockedCallback& callback) override { diff --git a/mojo/shell/tests/connect/connect_test_app_manifest.json b/mojo/shell/tests/connect/connect_test_app_manifest.json index ae25a53..8b636b9 100644 --- a/mojo/shell/tests/connect/connect_test_app_manifest.json +++ b/mojo/shell/tests/connect/connect_test_app_manifest.json @@ -4,7 +4,11 @@ "display_name": "Connect Test App", "capabilities": { "required": { - "mojo:connect_test_a": { "interfaces": ["*"] } + "mojo:connect_test_a": { "interfaces": ["*"] }, + "mojo:connect_test_class_app": { + "classes": ["class"], + "interfaces": ["mojo.shell.test.mojom.ConnectTestService"] + } } } } diff --git a/mojo/shell/tests/connect/connect_test_class_app.cc b/mojo/shell/tests/connect/connect_test_class_app.cc new file mode 100644 index 0000000..5b22dbc --- /dev/null +++ b/mojo/shell/tests/connect/connect_test_class_app.cc @@ -0,0 +1,101 @@ +// Copyright 2016 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 "base/bind.h" +#include "base/macros.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "mojo/public/c/system/main.h" +#include "mojo/public/cpp/bindings/binding_set.h" +#include "mojo/shell/public/cpp/application_runner.h" +#include "mojo/shell/public/cpp/connector.h" +#include "mojo/shell/public/cpp/interface_factory.h" +#include "mojo/shell/public/cpp/shell_client.h" +#include "mojo/shell/public/interfaces/connector.mojom.h" +#include "mojo/shell/tests/connect/connect_test.mojom.h" + +namespace mojo { +namespace shell { + +using GetTitleCallback = test::mojom::ConnectTestService::GetTitleCallback; + +class ConnectTestClassApp + : public ShellClient, + public InterfaceFactory<test::mojom::ConnectTestService>, + public InterfaceFactory<test::mojom::ClassInterface>, + public test::mojom::ConnectTestService, + public test::mojom::ClassInterface { + public: + ConnectTestClassApp() {} + ~ConnectTestClassApp() override {} + + private: + // mojo::ShellClient: + void Initialize(Connector* connector, const Identity& identity, + uint32_t id) override { + connector_ = connector; + identity_ = identity; + } + bool AcceptConnection(Connection* connection) override { + CHECK(connection->HasCapabilityClass("class")); + connection->AddInterface<test::mojom::ConnectTestService>(this); + connection->AddInterface<test::mojom::ClassInterface>(this); + inbound_connections_.insert(connection); + connection->SetConnectionLostClosure( + base::Bind(&ConnectTestClassApp::OnConnectionError, + base::Unretained(this), connection)); + return true; + } + + // InterfaceFactory<test::mojom::ConnectTestService>: + void Create(Connection* connection, + test::mojom::ConnectTestServiceRequest request) override { + bindings_.AddBinding(this, std::move(request)); + } + + // InterfaceFactory<test::mojom::ClassInterface>: + void Create(Connection* connection, + test::mojom::ClassInterfaceRequest request) override { + class_interface_bindings_.AddBinding(this, std::move(request)); + } + + // test::mojom::ConnectTestService: + void GetTitle(const GetTitleCallback& callback) override { + callback.Run("CLASS APP"); + } + void GetInstance(const GetInstanceCallback& callback) override { + callback.Run(identity_.instance()); + } + + // test::mojom::ClassInterface: + void Ping(const PingCallback& callback) override { + callback.Run("PONG"); + } + + void OnConnectionError(Connection* connection) { + auto it = inbound_connections_.find(connection); + DCHECK(it != inbound_connections_.end()); + inbound_connections_.erase(it); + if (inbound_connections_.empty()) + base::MessageLoop::current()->QuitWhenIdle(); + } + + Connector* connector_ = nullptr; + Identity identity_; + std::set<Connection*> inbound_connections_; + BindingSet<test::mojom::ConnectTestService> bindings_; + BindingSet<test::mojom::ClassInterface> class_interface_bindings_; + + DISALLOW_COPY_AND_ASSIGN(ConnectTestClassApp); +}; + +} // namespace shell +} // namespace mojo + + +MojoResult MojoMain(MojoHandle shell_handle) { + MojoResult rv = mojo::ApplicationRunner( + new mojo::shell::ConnectTestClassApp).Run(shell_handle); + return rv; +} diff --git a/mojo/shell/tests/connect/connect_test_class_app_manifest.json b/mojo/shell/tests/connect/connect_test_class_app_manifest.json new file mode 100644 index 0000000..492f679 --- /dev/null +++ b/mojo/shell/tests/connect/connect_test_class_app_manifest.json @@ -0,0 +1,10 @@ +{ + "manifest_version": 1, + "name": "mojo:connect_test_class_app", + "display_name": "Connect Test Class App", + "capabilities": { + "provided": { + "class": ["mojo.shell.test.mojom.ClassInterface"] + } + } +} diff --git a/mojo/shell/tests/connect/connect_unittest.cc b/mojo/shell/tests/connect/connect_unittest.cc index 38aee7a..0c65d9d 100644 --- a/mojo/shell/tests/connect/connect_unittest.cc +++ b/mojo/shell/tests/connect/connect_unittest.cc @@ -29,10 +29,18 @@ const char kTestAppName[] = "mojo:connect_test_app"; const char kTestAppAName[] = "mojo:connect_test_a"; const char kTestAppBName[] = "mojo:connect_test_b"; -void ReceiveTitle(std::string* out_name, - base::RunLoop* loop, - const String& name) { - *out_name = name; +void ReceiveOneString(std::string* out_string, + base::RunLoop* loop, + const String& in_string) { + *out_string = in_string; + loop->Quit(); +} + +void ReceiveTwoStrings(std::string* out_string_1, std::string* out_string_2, + base::RunLoop* loop, + const String& in_string_1, const String& in_string_2) { + *out_string_1 = in_string_1; + *out_string_2 = in_string_2; loop->Quit(); } @@ -93,7 +101,8 @@ class ConnectTest : public mojo::test::ShellTest, connection->GetInterface(&root_service); base::RunLoop run_loop; std::string root_name; - root_service->GetTitle(base::Bind(&ReceiveTitle, &root_name, &run_loop)); + root_service->GetTitle( + base::Bind(&ReceiveOneString, &root_name, &run_loop)); run_loop.Run(); } @@ -123,7 +132,7 @@ TEST_F(ConnectTest, Connect) { connection->GetInterface(&service); base::RunLoop run_loop; std::string title; - service->GetTitle(base::Bind(&ReceiveTitle, &title, &run_loop)); + service->GetTitle(base::Bind(&ReceiveOneString, &title, &run_loop)); run_loop.Run(); EXPECT_EQ("APP", title); EXPECT_FALSE(connection->IsPending()); @@ -141,14 +150,14 @@ TEST_F(ConnectTest, Instances) { { connection_a1->GetInterface(&service_a1); base::RunLoop loop; - service_a1->GetInstance(base::Bind(&ReceiveTitle, &instance_a1, &loop)); + service_a1->GetInstance(base::Bind(&ReceiveOneString, &instance_a1, &loop)); loop.Run(); } test::mojom::ConnectTestServicePtr service_a2; { connection_a2->GetInterface(&service_a2); base::RunLoop loop; - service_a2->GetInstance(base::Bind(&ReceiveTitle, &instance_a2, &loop)); + service_a2->GetInstance(base::Bind(&ReceiveOneString, &instance_a2, &loop)); loop.Run(); } EXPECT_EQ(instance_a1, instance_a2); @@ -161,7 +170,7 @@ TEST_F(ConnectTest, Instances) { { connection_b->GetInterface(&service_b); base::RunLoop loop; - service_b->GetInstance(base::Bind(&ReceiveTitle, &instance_b, &loop)); + service_b->GetInstance(base::Bind(&ReceiveOneString, &instance_b, &loop)); loop.Run(); } @@ -188,7 +197,7 @@ TEST_F(ConnectTest, PreferUnresolvedDefaultInstanceName) { test::mojom::ConnectTestServicePtr service; connection->GetInterface(&service); base::RunLoop loop; - service->GetInstance(base::Bind(&ReceiveTitle, &instance, &loop)); + service->GetInstance(base::Bind(&ReceiveOneString, &instance, &loop)); loop.Run(); } EXPECT_EQ(GetNamePath(kTestAppName), instance); @@ -203,7 +212,7 @@ TEST_F(ConnectTest, BlockedInterface) { connection->GetInterface(&blocked); blocked.set_connection_error_handler(base::Bind(&QuitLoop, &run_loop)); std::string title = "unchanged"; - blocked->GetTitleBlocked(base::Bind(&ReceiveTitle, &title, &run_loop)); + blocked->GetTitleBlocked(base::Bind(&ReceiveOneString, &title, &run_loop)); run_loop.Run(); EXPECT_EQ("unchanged", title); } @@ -215,7 +224,7 @@ TEST_F(ConnectTest, PackagedApp) { connection->GetInterface(&service_a); base::RunLoop run_loop; std::string a_name; - service_a->GetTitle(base::Bind(&ReceiveTitle, &a_name, &run_loop)); + service_a->GetTitle(base::Bind(&ReceiveOneString, &a_name, &run_loop)); run_loop.Run(); EXPECT_EQ("A", a_name); EXPECT_FALSE(connection->IsPending()); @@ -234,7 +243,7 @@ TEST_F(ConnectTest, BlockedPackage) { base::RunLoop run_loop; std::string title; standalone_app->ConnectToAllowedAppInBlockedPackage( - base::Bind(&ReceiveTitle, &title, &run_loop)); + base::Bind(&ReceiveOneString, &title, &run_loop)); run_loop.Run(); EXPECT_EQ("uninitialized", title); } @@ -264,6 +273,19 @@ TEST_F(ConnectTest, BlockedPackagedApplication) { EXPECT_EQ(mojom::kInvalidInstanceID, connection->GetRemoteInstanceID()); } +TEST_F(ConnectTest, CapabilityClasses) { + scoped_ptr<Connection> connection = connector()->Connect(kTestAppName); + test::mojom::StandaloneAppPtr standalone_app; + connection->GetInterface(&standalone_app); + std::string string1, string2; + base::RunLoop loop; + standalone_app->ConnectToClassInterface( + base::Bind(&ReceiveTwoStrings, &string1, &string2, &loop)); + loop.Run(); + EXPECT_EQ("PONG", string1); + EXPECT_EQ("CLASS APP", string2); +} + // Tests that we can expose an interface to targets on outbound connections. // TODO(beng): Currently all interfaces on outbound connections are exposed. // See ConnectorImpl::Connect(). |