diff options
author | sammc <sammc@chromium.org> | 2014-10-23 18:46:40 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-10-24 01:47:03 +0000 |
commit | 680be408457f4272b468e72468eb22e1c0f0b67a (patch) | |
tree | 9b0581a0cdd4faf690443e1e28030cd64d99e864 /extensions/browser/mojo | |
parent | 51307ca7a09f7be8da0572a7eff2b8e47bdb8d78 (diff) | |
download | chromium_src-680be408457f4272b468e72468eb22e1c0f0b67a.zip chromium_src-680be408457f4272b468e72468eb22e1c0f0b67a.tar.gz chromium_src-680be408457f4272b468e72468eb22e1c0f0b67a.tar.bz2 |
Move stash_backend into extensions/browser/mojo.
Review URL: https://codereview.chromium.org/638273004
Cr-Commit-Position: refs/heads/master@{#301024}
Diffstat (limited to 'extensions/browser/mojo')
-rw-r--r-- | extensions/browser/mojo/stash_backend.cc | 73 | ||||
-rw-r--r-- | extensions/browser/mojo/stash_backend.h | 45 | ||||
-rw-r--r-- | extensions/browser/mojo/stash_backend_unittest.cc | 174 |
3 files changed, 292 insertions, 0 deletions
diff --git a/extensions/browser/mojo/stash_backend.cc b/extensions/browser/mojo/stash_backend.cc new file mode 100644 index 0000000..da4842d --- /dev/null +++ b/extensions/browser/mojo/stash_backend.cc @@ -0,0 +1,73 @@ +// 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/browser/mojo/stash_backend.h" + +namespace extensions { + +// An implementation of StashService that forwards calls to a StashBackend. +class StashServiceImpl : public mojo::InterfaceImpl<StashService> { + public: + explicit StashServiceImpl(base::WeakPtr<StashBackend> backend); + ~StashServiceImpl() override; + + // mojo::InterfaceImpl<StashService> overrides. + void AddToStash(mojo::Array<StashedObjectPtr> stash) override; + void RetrieveStash( + const mojo::Callback<void(mojo::Array<StashedObjectPtr> stash)>& callback) + override; + + private: + base::WeakPtr<StashBackend> backend_; + + DISALLOW_COPY_AND_ASSIGN(StashServiceImpl); +}; + +StashBackend::StashBackend() : weak_factory_(this) { +} + +StashBackend::~StashBackend() { +} + +void StashBackend::AddToStash(mojo::Array<StashedObjectPtr> stashed_objects) { + for (size_t i = 0; i < stashed_objects.size(); i++) { + stashed_objects_.push_back(stashed_objects[i].Pass()); + } +} + +mojo::Array<StashedObjectPtr> StashBackend::RetrieveStash() { + if (stashed_objects_.is_null()) + stashed_objects_.resize(0); + return stashed_objects_.Pass(); +} + +void StashBackend::BindToRequest(mojo::InterfaceRequest<StashService> request) { + mojo::BindToRequest(new StashServiceImpl(weak_factory_.GetWeakPtr()), + &request); +} + +StashServiceImpl::StashServiceImpl(base::WeakPtr<StashBackend> backend) + : backend_(backend) { +} + +StashServiceImpl::~StashServiceImpl() { +} + +void StashServiceImpl::AddToStash( + mojo::Array<StashedObjectPtr> stashed_objects) { + if (!backend_) + return; + backend_->AddToStash(stashed_objects.Pass()); +} + +void StashServiceImpl::RetrieveStash( + const mojo::Callback<void(mojo::Array<StashedObjectPtr>)>& callback) { + if (!backend_) { + callback.Run(mojo::Array<StashedObjectPtr>(0)); + return; + } + callback.Run(backend_->RetrieveStash()); +} + +} // namespace extensions diff --git a/extensions/browser/mojo/stash_backend.h b/extensions/browser/mojo/stash_backend.h new file mode 100644 index 0000000..b90e43d --- /dev/null +++ b/extensions/browser/mojo/stash_backend.h @@ -0,0 +1,45 @@ +// 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. + +#ifndef EXTENSIONS_BROWSER_MOJO_STASH_BACKEND_H_ +#define EXTENSIONS_BROWSER_MOJO_STASH_BACKEND_H_ + +#include <vector> + +#include "base/memory/linked_ptr.h" +#include "base/memory/weak_ptr.h" +#include "extensions/common/mojo/stash.mojom.h" +#include "mojo/public/cpp/bindings/interface_request.h" + +namespace extensions { + +// A backend that provides access to StashService for a single extension. +class StashBackend { + public: + StashBackend(); + ~StashBackend(); + + // Creates a StashService that forwards calls to this StashBackend and bind it + // to |request|. + void BindToRequest(mojo::InterfaceRequest<StashService> request); + + // Adds the StashedObjects contained within |stash| to the stash. + void AddToStash(mojo::Array<StashedObjectPtr> stash); + + // Returns all StashedObjects added to the stash since the last call to + // RetrieveStash. + mojo::Array<StashedObjectPtr> RetrieveStash(); + + private: + // The objects that have been stashed. + mojo::Array<StashedObjectPtr> stashed_objects_; + + base::WeakPtrFactory<StashBackend> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(StashBackend); +}; + +} // namespace extensions + +#endif // EXTENSIONS_BROWSER_MOJO_STASH_BACKEND_H_ diff --git a/extensions/browser/mojo/stash_backend_unittest.cc b/extensions/browser/mojo/stash_backend_unittest.cc new file mode 100644 index 0000000..0a0244b --- /dev/null +++ b/extensions/browser/mojo/stash_backend_unittest.cc @@ -0,0 +1,174 @@ +// 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 "base/bind.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "extensions/browser/mojo/stash_backend.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace extensions { + +class StashServiceTest : public testing::Test, public mojo::ErrorHandler { + public: + enum Event { + EVENT_NONE, + EVENT_STASH_RETRIEVED, + }; + + StashServiceTest() {} + + virtual void SetUp() override { + expecting_error_ = false; + expected_event_ = EVENT_NONE; + stash_backend_.reset(new StashBackend); + stash_backend_->BindToRequest(mojo::GetProxy(&stash_service_)); + stash_service_.set_error_handler(this); + } + + void OnConnectionError() override { FAIL() << "Unexpected connection error"; } + + mojo::Array<StashedObjectPtr> RetrieveStash() { + mojo::Array<StashedObjectPtr> stash; + stash_service_->RetrieveStash(base::Bind( + &StashServiceTest::StashRetrieved, base::Unretained(this), &stash)); + WaitForEvent(EVENT_STASH_RETRIEVED); + return stash.Pass(); + } + + void StashRetrieved(mojo::Array<StashedObjectPtr>* output, + mojo::Array<StashedObjectPtr> stash) { + *output = stash.Pass(); + EventReceived(EVENT_STASH_RETRIEVED); + } + + void WaitForEvent(Event event) { + expected_event_ = event; + base::RunLoop run_loop; + stop_run_loop_ = run_loop.QuitClosure(); + run_loop.Run(); + } + + void EventReceived(Event event) { + if (event == expected_event_ && !stop_run_loop_.is_null()) + stop_run_loop_.Run(); + } + + protected: + base::MessageLoop message_loop_; + base::Closure stop_run_loop_; + scoped_ptr<StashBackend> stash_backend_; + Event expected_event_; + bool expecting_error_; + mojo::InterfacePtr<StashService> stash_service_; + + private: + DISALLOW_COPY_AND_ASSIGN(StashServiceTest); +}; + +// Test that adding stashed objects in multiple calls can all be retrieved by a +// Retrieve call. +TEST_F(StashServiceTest, AddTwiceAndRetrieve) { + mojo::Array<StashedObjectPtr> stashed_objects; + StashedObjectPtr stashed_object(StashedObject::New()); + stashed_object->id = "test type"; + stashed_object->data.push_back(1); + stashed_object->stashed_handles = mojo::Array<mojo::ScopedHandle>(0); + stashed_objects.push_back(stashed_object.Pass()); + stash_service_->AddToStash(stashed_objects.Pass()); + stashed_object = StashedObject::New(); + stashed_object->id = "test type2"; + stashed_object->data.push_back(2); + stashed_object->data.push_back(3); + stashed_object->stashed_handles = mojo::Array<mojo::ScopedHandle>(0); + stashed_objects.push_back(stashed_object.Pass()); + stash_service_->AddToStash(stashed_objects.Pass()); + stashed_objects = RetrieveStash(); + ASSERT_EQ(2u, stashed_objects.size()); + EXPECT_EQ("test type", stashed_objects[0]->id); + EXPECT_EQ(0u, stashed_objects[0]->stashed_handles.size()); + EXPECT_EQ(1u, stashed_objects[0]->data.size()); + EXPECT_EQ(1, stashed_objects[0]->data[0]); + EXPECT_EQ("test type2", stashed_objects[1]->id); + EXPECT_EQ(0u, stashed_objects[1]->stashed_handles.size()); + EXPECT_EQ(2u, stashed_objects[1]->data.size()); + EXPECT_EQ(2, stashed_objects[1]->data[0]); + EXPECT_EQ(3, stashed_objects[1]->data[1]); +} + +// Test that handles survive a round-trip through the stash. +TEST_F(StashServiceTest, StashAndRetrieveHandles) { + mojo::Array<StashedObjectPtr> stashed_objects; + StashedObjectPtr stashed_object(StashedObject::New()); + stashed_object->id = "test type"; + stashed_object->data.push_back(1); + + mojo::ScopedDataPipeConsumerHandle consumer; + mojo::ScopedDataPipeProducerHandle producer; + MojoCreateDataPipeOptions options = { + sizeof(options), MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, 1, 1, + }; + mojo::CreateDataPipe(&options, &producer, &consumer); + uint32_t num_bytes = 1; + MojoResult result = mojo::WriteDataRaw( + producer.get(), "1", &num_bytes, MOJO_WRITE_DATA_FLAG_ALL_OR_NONE); + ASSERT_EQ(MOJO_RESULT_OK, result); + ASSERT_EQ(1u, num_bytes); + + stashed_object->stashed_handles.push_back( + mojo::ScopedHandle::From(producer.Pass())); + stashed_object->stashed_handles.push_back( + mojo::ScopedHandle::From(consumer.Pass())); + stashed_objects.push_back(stashed_object.Pass()); + stash_service_->AddToStash(stashed_objects.Pass()); + stashed_objects = RetrieveStash(); + ASSERT_EQ(1u, stashed_objects.size()); + EXPECT_EQ("test type", stashed_objects[0]->id); + ASSERT_EQ(2u, stashed_objects[0]->stashed_handles.size()); + + consumer = mojo::ScopedDataPipeConsumerHandle::From( + stashed_objects[0]->stashed_handles[1].Pass()); + result = mojo::Wait( + consumer.get(), MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE); + ASSERT_EQ(MOJO_RESULT_OK, result); + char data = '\0'; + result = mojo::ReadDataRaw( + consumer.get(), &data, &num_bytes, MOJO_READ_DATA_FLAG_ALL_OR_NONE); + ASSERT_EQ(MOJO_RESULT_OK, result); + ASSERT_EQ(1u, num_bytes); + EXPECT_EQ('1', data); +} + +TEST_F(StashServiceTest, RetrieveWithoutStashing) { + mojo::Array<StashedObjectPtr> stashed_objects = RetrieveStash(); + ASSERT_TRUE(!stashed_objects.is_null()); + EXPECT_EQ(0u, stashed_objects.size()); +} + +// Test that a stash service discards stashed objects when the backend no longer +// exists. +TEST_F(StashServiceTest, ServiceWithDeletedBackend) { + stash_backend_.reset(); + stash_service_.set_error_handler(this); + + mojo::Array<StashedObjectPtr> stashed_objects; + StashedObjectPtr stashed_object(StashedObject::New()); + stashed_object->id = "test type"; + stashed_object->data.push_back(1); + mojo::MessagePipe message_pipe; + stashed_object->stashed_handles.push_back( + mojo::ScopedHandle::From(message_pipe.handle0.Pass())); + stashed_objects.push_back(stashed_object.Pass()); + stash_service_->AddToStash(stashed_objects.Pass()); + stashed_objects = RetrieveStash(); + ASSERT_EQ(0u, stashed_objects.size()); + // Check that the stashed handle has been closed. + MojoResult result = + mojo::Wait(message_pipe.handle1.get(), + MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); +} + +} // namespace extensions |