blob: da2941d8e89458ce35fe29ee57b492697930bf86 [file] [log] [blame]
// 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 <string>
#include "base/bind.h"
#include "base/callback.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "chrome/browser/chromeos/file_system_provider/request_manager.h"
#include "chrome/browser/chromeos/file_system_provider/request_value.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
namespace file_system_provider {
namespace {
// Logs calls of the success and error callbacks on requests.
class EventLogger {
public:
class ExecuteEvent {
public:
explicit ExecuteEvent(int request_id) : request_id_(request_id) {}
virtual ~ExecuteEvent() {}
int request_id() { return request_id_; }
private:
int request_id_;
};
class SuccessEvent {
public:
SuccessEvent(int request_id, scoped_ptr<RequestValue> result, bool has_next)
: request_id_(request_id),
result_(result.Pass()),
has_next_(has_next) {}
virtual ~SuccessEvent() {}
int request_id() { return request_id_; }
RequestValue* result() { return result_.get(); }
bool has_next() { return has_next_; }
private:
int request_id_;
scoped_ptr<RequestValue> result_;
bool has_next_;
};
class ErrorEvent {
public:
ErrorEvent(int request_id, base::File::Error error)
: request_id_(request_id), error_(error) {}
virtual ~ErrorEvent() {}
int request_id() { return request_id_; }
base::File::Error error() { return error_; }
private:
int request_id_;
base::File::Error error_;
};
EventLogger() : weak_ptr_factory_(this) {}
virtual ~EventLogger() {}
void OnExecute(int request_id) {
execute_events_.push_back(new ExecuteEvent(request_id));
}
void OnSuccess(int request_id,
scoped_ptr<RequestValue> result,
bool has_next) {
success_events_.push_back(
new SuccessEvent(request_id, result.Pass(), has_next));
}
void OnError(int request_id, base::File::Error error) {
error_events_.push_back(new ErrorEvent(request_id, error));
}
ScopedVector<ExecuteEvent>& execute_events() { return execute_events_; }
ScopedVector<SuccessEvent>& success_events() { return success_events_; }
ScopedVector<ErrorEvent>& error_events() { return error_events_; }
base::WeakPtr<EventLogger> GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
private:
ScopedVector<ExecuteEvent> execute_events_;
ScopedVector<SuccessEvent> success_events_;
ScopedVector<ErrorEvent> error_events_;
base::WeakPtrFactory<EventLogger> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(EventLogger);
};
// Fake handler, which forwards callbacks to the logger. The handler is owned
// by a request manager, however the logger is owned by tests.
class FakeHandler : public RequestManager::HandlerInterface {
public:
// The handler can outlive the passed logger, so using a weak pointer. The
// |execute_reply| value will be returned for the Execute() call.
FakeHandler(base::WeakPtr<EventLogger> logger, bool execute_reply)
: logger_(logger), execute_reply_(execute_reply) {}
// RequestManager::Handler overrides.
virtual bool Execute(int request_id) OVERRIDE {
if (logger_.get())
logger_->OnExecute(request_id);
return execute_reply_;
}
// RequestManager::Handler overrides.
virtual void OnSuccess(int request_id,
scoped_ptr<RequestValue> result,
bool has_next) OVERRIDE {
if (logger_.get())
logger_->OnSuccess(request_id, result.Pass(), has_next);
}
// RequestManager::Handler overrides.
virtual void OnError(int request_id, base::File::Error error) OVERRIDE {
if (logger_.get())
logger_->OnError(request_id, error);
}
virtual ~FakeHandler() {}
private:
base::WeakPtr<EventLogger> logger_;
bool execute_reply_;
DISALLOW_COPY_AND_ASSIGN(FakeHandler);
};
} // namespace
class FileSystemProviderRequestManagerTest : public testing::Test {
protected:
FileSystemProviderRequestManagerTest() {}
virtual ~FileSystemProviderRequestManagerTest() {}
virtual void SetUp() OVERRIDE {
request_manager_.reset(new RequestManager());
}
content::TestBrowserThreadBundle thread_bundle_;
scoped_ptr<RequestManager> request_manager_;
};
TEST_F(FileSystemProviderRequestManagerTest, CreateAndFulFill) {
EventLogger logger;
const int request_id = request_manager_->CreateRequest(
make_scoped_ptr<RequestManager::HandlerInterface>(
new FakeHandler(logger.GetWeakPtr(), true /* execute_reply */)));
EXPECT_EQ(1, request_id);
EXPECT_EQ(0u, logger.success_events().size());
EXPECT_EQ(0u, logger.error_events().size());
scoped_ptr<RequestValue> response(
RequestValue::CreateForTesting("i-like-vanilla"));
const bool has_next = false;
bool result =
request_manager_->FulfillRequest(request_id, response.Pass(), has_next);
EXPECT_TRUE(result);
// Validate if the callback has correct arguments.
ASSERT_EQ(1u, logger.success_events().size());
EXPECT_EQ(0u, logger.error_events().size());
EventLogger::SuccessEvent* event = logger.success_events()[0];
ASSERT_TRUE(event->result());
const std::string* response_test_string = event->result()->testing_params();
ASSERT_TRUE(response_test_string);
EXPECT_EQ("i-like-vanilla", *response_test_string);
EXPECT_FALSE(event->has_next());
// Confirm, that the request is removed. Basically, fulfilling again for the
// same request, should fail.
{
scoped_ptr<RequestValue> response;
bool retry =
request_manager_->FulfillRequest(request_id, response.Pass(), has_next);
EXPECT_FALSE(retry);
}
// Rejecting should also fail.
{
bool retry = request_manager_->RejectRequest(request_id,
base::File::FILE_ERROR_FAILED);
EXPECT_FALSE(retry);
}
}
TEST_F(FileSystemProviderRequestManagerTest, CreateAndFulFill_WithHasNext) {
EventLogger logger;
const int request_id = request_manager_->CreateRequest(
make_scoped_ptr<RequestManager::HandlerInterface>(
new FakeHandler(logger.GetWeakPtr(), true /* execute_reply */)));
EXPECT_EQ(1, request_id);
EXPECT_EQ(0u, logger.success_events().size());
EXPECT_EQ(0u, logger.error_events().size());
scoped_ptr<RequestValue> response;
const bool has_next = true;
bool result =
request_manager_->FulfillRequest(request_id, response.Pass(), has_next);
EXPECT_TRUE(result);
// Validate if the callback has correct arguments.
ASSERT_EQ(1u, logger.success_events().size());
EXPECT_EQ(0u, logger.error_events().size());
EventLogger::SuccessEvent* event = logger.success_events()[0];
EXPECT_FALSE(event->result());
EXPECT_TRUE(event->has_next());
// Confirm, that the request is not removed (since it has has_next == true).
// Basically, fulfilling again for the same request, should not fail.
{
bool new_has_next = false;
bool retry = request_manager_->FulfillRequest(
request_id, response.Pass(), new_has_next);
EXPECT_TRUE(retry);
}
// Since |new_has_next| is false, then the request should be removed. To check
// it, try to fulfill again, what should fail.
{
bool new_has_next = false;
bool retry = request_manager_->FulfillRequest(
request_id, response.Pass(), new_has_next);
EXPECT_FALSE(retry);
}
}
TEST_F(FileSystemProviderRequestManagerTest, CreateAndReject) {
EventLogger logger;
const int request_id = request_manager_->CreateRequest(
make_scoped_ptr<RequestManager::HandlerInterface>(
new FakeHandler(logger.GetWeakPtr(), true /* execute_reply */)));
EXPECT_EQ(1, request_id);
EXPECT_EQ(0u, logger.success_events().size());
EXPECT_EQ(0u, logger.error_events().size());
base::File::Error error = base::File::FILE_ERROR_NO_MEMORY;
bool result = request_manager_->RejectRequest(request_id, error);
EXPECT_TRUE(result);
// Validate if the callback has correct arguments.
ASSERT_EQ(1u, logger.error_events().size());
EXPECT_EQ(0u, logger.success_events().size());
EventLogger::ErrorEvent* event = logger.error_events()[0];
EXPECT_EQ(error, event->error());
// Confirm, that the request is removed. Basically, fulfilling again for the
// same request, should fail.
{
scoped_ptr<RequestValue> response;
bool has_next = false;
bool retry =
request_manager_->FulfillRequest(request_id, response.Pass(), has_next);
EXPECT_FALSE(retry);
}
// Rejecting should also fail.
{
bool retry = request_manager_->RejectRequest(request_id, error);
EXPECT_FALSE(retry);
}
}
TEST_F(FileSystemProviderRequestManagerTest,
CreateAndFulfillWithWrongRequestId) {
EventLogger logger;
const int request_id = request_manager_->CreateRequest(
make_scoped_ptr<RequestManager::HandlerInterface>(
new FakeHandler(logger.GetWeakPtr(), true /* execute_reply */)));
EXPECT_EQ(1, request_id);
EXPECT_EQ(0u, logger.success_events().size());
EXPECT_EQ(0u, logger.error_events().size());
base::File::Error error = base::File::FILE_ERROR_NO_MEMORY;
bool result = request_manager_->RejectRequest(request_id + 1, error);
EXPECT_FALSE(result);
// Callbacks should not be called.
EXPECT_EQ(0u, logger.error_events().size());
EXPECT_EQ(0u, logger.success_events().size());
// Confirm, that the request hasn't been removed, by rejecting it correctly.
{
bool retry = request_manager_->RejectRequest(request_id, error);
EXPECT_TRUE(retry);
}
}
TEST_F(FileSystemProviderRequestManagerTest,
CreateAndRejectWithWrongRequestId) {
EventLogger logger;
const int request_id = request_manager_->CreateRequest(
make_scoped_ptr<RequestManager::HandlerInterface>(
new FakeHandler(logger.GetWeakPtr(), true /* execute_reply */)));
EXPECT_EQ(1, request_id);
EXPECT_EQ(0u, logger.success_events().size());
EXPECT_EQ(0u, logger.error_events().size());
base::File::Error error = base::File::FILE_ERROR_NO_MEMORY;
bool result = request_manager_->RejectRequest(request_id + 1, error);
EXPECT_FALSE(result);
// Callbacks should not be called.
EXPECT_EQ(0u, logger.error_events().size());
EXPECT_EQ(0u, logger.success_events().size());
// Confirm, that the request hasn't been removed, by rejecting it correctly.
{
bool retry = request_manager_->RejectRequest(request_id, error);
EXPECT_TRUE(retry);
}
}
TEST_F(FileSystemProviderRequestManagerTest, UniqueIds) {
EventLogger logger;
const int first_request_id = request_manager_->CreateRequest(
make_scoped_ptr<RequestManager::HandlerInterface>(
new FakeHandler(logger.GetWeakPtr(), true /* execute_reply */)));
const int second_request_id = request_manager_->CreateRequest(
make_scoped_ptr<RequestManager::HandlerInterface>(
new FakeHandler(logger.GetWeakPtr(), true /* execute_reply */)));
EXPECT_EQ(1, first_request_id);
EXPECT_EQ(2, second_request_id);
}
TEST_F(FileSystemProviderRequestManagerTest, AbortOnDestroy) {
EventLogger logger;
{
RequestManager request_manager;
const int request_id = request_manager.CreateRequest(
make_scoped_ptr<RequestManager::HandlerInterface>(
new FakeHandler(logger.GetWeakPtr(), true /* execute_reply */)));
EXPECT_EQ(1, request_id);
EXPECT_EQ(0u, logger.success_events().size());
EXPECT_EQ(0u, logger.error_events().size());
}
// All active requests should be aborted in the destructor of RequestManager.
ASSERT_EQ(1u, logger.error_events().size());
EventLogger::ErrorEvent* event = logger.error_events()[0];
EXPECT_EQ(base::File::FILE_ERROR_ABORT, event->error());
EXPECT_EQ(0u, logger.success_events().size());
}
TEST_F(FileSystemProviderRequestManagerTest, AbortOnTimeout) {
EventLogger logger;
base::RunLoop run_loop;
request_manager_->SetTimeoutForTests(base::TimeDelta::FromSeconds(0));
const int request_id = request_manager_->CreateRequest(
make_scoped_ptr<RequestManager::HandlerInterface>(
new FakeHandler(logger.GetWeakPtr(), true /* execute_reply */)));
EXPECT_LT(0, request_id);
// Wait until the request is timeouted.
run_loop.RunUntilIdle();
ASSERT_EQ(1u, logger.error_events().size());
EventLogger::ErrorEvent* event = logger.error_events()[0];
EXPECT_EQ(base::File::FILE_ERROR_ABORT, event->error());
}
} // namespace file_system_provider
} // namespace chromeos