blob: 5a0242dbc8efeeeff7ba5bf28a5d341fa3e94021 [file] [log] [blame]
// Copyright (c) 2011 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.
// Illustrates how to use net::TestCompletionCallback.
#include "net/base/test_completion_callback.h"
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "net/base/completion_once_callback.h"
#include "net/test/test_with_scoped_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
namespace net {
namespace {
const int kMagicResult = 8888;
void CallClosureAfterCheckingResult(const base::Closure& closure,
bool* did_check_result,
int result) {
DCHECK_EQ(result, kMagicResult);
*did_check_result = true;
closure.Run();
}
// ExampleEmployer is a toy version of HostResolver
// TODO: restore damage done in extracting example from real code
// (e.g. bring back real destructor, bring back comments)
class ExampleEmployer {
public:
ExampleEmployer();
~ExampleEmployer();
// Posts to the current thread a task which itself posts |callback| to the
// current thread. Returns true on success
bool DoSomething(CompletionOnceCallback callback);
private:
class ExampleWorker;
friend class ExampleWorker;
scoped_refptr<ExampleWorker> request_;
DISALLOW_COPY_AND_ASSIGN(ExampleEmployer);
};
// Helper class; this is how ExampleEmployer schedules work.
class ExampleEmployer::ExampleWorker
: public base::RefCountedThreadSafe<ExampleWorker> {
public:
ExampleWorker(ExampleEmployer* employer, CompletionOnceCallback callback)
: employer_(employer), callback_(std::move(callback)) {}
void DoWork();
void DoCallback();
private:
friend class base::RefCountedThreadSafe<ExampleWorker>;
~ExampleWorker() = default;
// Only used on the origin thread (where DoSomething was called).
ExampleEmployer* employer_;
CompletionOnceCallback callback_;
// Used to post ourselves onto the origin thread.
const scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_ =
base::ThreadTaskRunnerHandle::Get();
};
void ExampleEmployer::ExampleWorker::DoWork() {
// In a real worker thread, some work would be done here.
// Pretend it is, and send the completion callback.
origin_task_runner_->PostTask(FROM_HERE,
base::Bind(&ExampleWorker::DoCallback, this));
}
void ExampleEmployer::ExampleWorker::DoCallback() {
// Running on the origin thread.
// Drop the employer_'s reference to us. Do this before running the
// callback since the callback might result in the employer being
// destroyed.
employer_->request_ = NULL;
std::move(callback_).Run(kMagicResult);
}
ExampleEmployer::ExampleEmployer() = default;
ExampleEmployer::~ExampleEmployer() = default;
bool ExampleEmployer::DoSomething(CompletionOnceCallback callback) {
DCHECK(!request_.get()) << "already in use";
request_ = new ExampleWorker(this, std::move(callback));
if (!base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&ExampleWorker::DoWork, request_))) {
NOTREACHED();
request_ = NULL;
return false;
}
return true;
}
} // namespace
class TestCompletionCallbackTest : public PlatformTest,
public WithScopedTaskEnvironment {};
TEST_F(TestCompletionCallbackTest, Simple) {
ExampleEmployer boss;
TestCompletionCallback callback;
bool queued = boss.DoSomething(callback.callback());
EXPECT_TRUE(queued);
int result = callback.WaitForResult();
EXPECT_EQ(result, kMagicResult);
}
TEST_F(TestCompletionCallbackTest, Closure) {
ExampleEmployer boss;
TestClosure closure;
bool did_check_result = false;
CompletionOnceCallback completion_callback =
base::BindOnce(&CallClosureAfterCheckingResult, closure.closure(),
base::Unretained(&did_check_result));
bool queued = boss.DoSomething(std::move(completion_callback));
EXPECT_TRUE(queued);
EXPECT_FALSE(did_check_result);
closure.WaitForResult();
EXPECT_TRUE(did_check_result);
}
// TODO: test deleting ExampleEmployer while work outstanding
} // namespace net