| // 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. |
| |
| #include "net/dns/watching_file_reader.h" |
| |
| #include "base/message_loop.h" |
| #include "base/synchronization/lock.h" |
| #include "base/synchronization/waitable_event.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace net { |
| |
| namespace { |
| |
| class WatchingFileReaderTest : public testing::Test { |
| public: |
| |
| // Mocks |
| |
| class MockWorker : public SerialWorker { |
| public: |
| explicit MockWorker(WatchingFileReaderTest* t) : test_(t) {} |
| virtual void WorkNow() OVERRIDE { |
| test_->OnWork(); |
| } |
| virtual void DoWork() OVERRIDE {} |
| virtual void OnWorkFinished() OVERRIDE {} |
| private: |
| virtual ~MockWorker() {} |
| WatchingFileReaderTest* test_; |
| }; |
| |
| class MockFilePathWatcherShim |
| : public FilePathWatcherShim { |
| public: |
| typedef base::files::FilePathWatcher::Delegate Delegate; |
| |
| explicit MockFilePathWatcherShim(WatchingFileReaderTest* t) : test_(t) {} |
| virtual ~MockFilePathWatcherShim() { |
| test_->OnShimDestroyed(this); |
| } |
| |
| // Enforce one-Watch-per-lifetime as the original FilePathWatcher |
| virtual bool Watch(const FilePath& path, |
| Delegate* delegate) OVERRIDE { |
| EXPECT_TRUE(path_.empty()) << "Only one-Watch-per-lifetime allowed."; |
| EXPECT_TRUE(!delegate_.get()); |
| path_ = path; |
| delegate_ = delegate; |
| return test_->OnWatch(); |
| } |
| |
| void PathChanged() { |
| delegate_->OnFilePathChanged(path_); |
| } |
| |
| void PathError() { |
| delegate_->OnFilePathError(path_); |
| } |
| |
| private: |
| FilePath path_; |
| scoped_refptr<Delegate> delegate_; |
| WatchingFileReaderTest* test_; |
| }; |
| |
| class MockFilePathWatcherFactory |
| : public FilePathWatcherFactory { |
| public: |
| explicit MockFilePathWatcherFactory(WatchingFileReaderTest* t) |
| : test(t) {} |
| virtual FilePathWatcherShim* |
| CreateFilePathWatcher() OVERRIDE { |
| return test->CreateFilePathWatcher(); |
| } |
| WatchingFileReaderTest* test; |
| }; |
| |
| // Helpers for mocks. |
| |
| FilePathWatcherShim* CreateFilePathWatcher() { |
| watcher_shim_ = new MockFilePathWatcherShim(this); |
| return watcher_shim_; |
| } |
| |
| void OnShimDestroyed(MockFilePathWatcherShim* destroyed_shim) { |
| // Precaution to avoid segfault. |
| if (watcher_shim_ == destroyed_shim) |
| watcher_shim_ = NULL; |
| } |
| |
| // On each event, post QuitTask to allow use of MessageLoop::Run() to |
| // synchronize the threads. |
| |
| bool OnWatch() { |
| EXPECT_TRUE(message_loop_ == MessageLoop::current()); |
| BreakNow("OnWatch"); |
| return !fail_on_watch_; |
| } |
| |
| void OnWork() { |
| EXPECT_TRUE(message_loop_ == MessageLoop::current()); |
| BreakNow("OnWork"); |
| } |
| |
| protected: |
| friend class BreakTask; |
| class BreakTask : public Task { |
| public: |
| BreakTask(WatchingFileReaderTest* test, std::string breakpoint) |
| : test_(test), breakpoint_(breakpoint) {} |
| virtual ~BreakTask() {} |
| virtual void Run() OVERRIDE { |
| test_->breakpoint_ = breakpoint_; |
| MessageLoop::current()->QuitNow(); |
| } |
| private: |
| WatchingFileReaderTest* test_; |
| std::string breakpoint_; |
| }; |
| |
| void BreakNow(std::string b) { |
| message_loop_->PostTask(FROM_HERE, new BreakTask(this, b)); |
| } |
| |
| void RunUntilBreak(std::string b) { |
| message_loop_->Run(); |
| ASSERT_EQ(breakpoint_, b); |
| } |
| |
| WatchingFileReaderTest() |
| : watcher_shim_(NULL), |
| fail_on_watch_(false), |
| message_loop_(MessageLoop::current()), |
| watcher_(new WatchingFileReader()) { |
| watcher_->set_watcher_factory(new MockFilePathWatcherFactory(this)); |
| } |
| |
| MockFilePathWatcherShim* watcher_shim_; |
| bool fail_on_watch_; |
| MessageLoop* message_loop_; |
| scoped_ptr<WatchingFileReader> watcher_; |
| |
| std::string breakpoint_; |
| }; |
| |
| TEST_F(WatchingFileReaderTest, FilePathWatcherFailures) { |
| fail_on_watch_ = true; |
| watcher_->StartWatch(FilePath(FILE_PATH_LITERAL("some_file_name")), |
| new MockWorker(this)); |
| RunUntilBreak("OnWatch"); |
| |
| fail_on_watch_ = false; |
| RunUntilBreak("OnWatch"); // Due to backoff this will take 100ms. |
| RunUntilBreak("OnWork"); |
| |
| ASSERT_TRUE(watcher_shim_); |
| watcher_shim_->PathError(); |
| RunUntilBreak("OnWatch"); |
| RunUntilBreak("OnWork"); |
| |
| message_loop_->AssertIdle(); |
| |
| ASSERT_TRUE(watcher_shim_); |
| watcher_shim_->PathChanged(); |
| RunUntilBreak("OnWork"); |
| |
| message_loop_->AssertIdle(); |
| } |
| |
| } // namespace |
| |
| } // namespace net |
| |