Index: chrome/browser/chromeos/file_system_provider/queue_unittest.cc |
diff --git a/chrome/browser/chromeos/file_system_provider/queue_unittest.cc b/chrome/browser/chromeos/file_system_provider/queue_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9cda477697b7d5a40e3330c94664d0e4ee15dd27 |
--- /dev/null |
+++ b/chrome/browser/chromeos/file_system_provider/queue_unittest.cc |
@@ -0,0 +1,324 @@ |
+// Copyright 2015 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 "chrome/browser/chromeos/file_system_provider/queue.h" |
+ |
+#include <vector> |
+ |
+#include "base/files/file.h" |
+#include "base/run_loop.h" |
+#include "content/public/test/test_browser_thread_bundle.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace chromeos { |
+namespace file_system_provider { |
+namespace { |
+ |
+void OnAbort(int* abort_counter, |
+ const storage::AsyncFileUtil::StatusCallback& callback) { |
+ (*abort_counter)++; |
+ callback.Run(base::File::FILE_ERROR_FAILED); |
+} |
+ |
+AbortCallback OnRun(int* run_counter, int* abort_counter) { |
+ (*run_counter)++; |
+ return base::Bind(&OnAbort, abort_counter); |
+} |
+ |
+void OnAbortCallback(std::vector<base::File::Error>* log, |
+ base::File::Error result) { |
+ log->push_back(result); |
+} |
+ |
+} // namespace |
+ |
+class FileSystemProviderQueueTest : public testing::Test { |
+ protected: |
+ FileSystemProviderQueueTest() {} |
+ virtual ~FileSystemProviderQueueTest() {} |
+ |
+ content::TestBrowserThreadBundle thread_bundle_; |
+}; |
+ |
+TEST_F(FileSystemProviderQueueTest, NewToken) { |
+ Queue queue(1); |
+ EXPECT_EQ(1u, queue.NewToken()); |
+ EXPECT_EQ(2u, queue.NewToken()); |
+ EXPECT_EQ(3u, queue.NewToken()); |
+} |
+ |
+TEST_F(FileSystemProviderQueueTest, Enqueue_OneAtOnce) { |
+ Queue queue(1); |
+ const size_t first_token = queue.NewToken(); |
+ int first_counter = 0; |
+ int first_abort_counter = 0; |
+ queue.Enqueue(first_token, |
+ base::Bind(&OnRun, &first_counter, &first_abort_counter)); |
+ |
+ const size_t second_token = queue.NewToken(); |
+ int second_counter = 0; |
+ int second_abort_counter = 0; |
+ const AbortCallback abort_callback = queue.Enqueue( |
+ second_token, base::Bind(&OnRun, &second_counter, &second_abort_counter)); |
+ |
+ base::RunLoop().RunUntilIdle(); |
+ EXPECT_EQ(1, first_counter); |
+ EXPECT_EQ(0, first_abort_counter); |
+ EXPECT_EQ(0, second_counter); |
+ EXPECT_EQ(0, second_abort_counter); |
+ |
+ // Complete the first task, which should not run the second one, yet. |
+ queue.Complete(first_token); |
+ base::RunLoop().RunUntilIdle(); |
+ EXPECT_EQ(1, first_counter); |
+ EXPECT_EQ(0, first_abort_counter); |
+ EXPECT_EQ(0, second_counter); |
+ EXPECT_EQ(0, second_abort_counter); |
+ |
+ // Removing the first task from the queue should run the second task. |
+ queue.Remove(first_token); |
+ base::RunLoop().RunUntilIdle(); |
+ EXPECT_EQ(1, first_counter); |
+ EXPECT_EQ(0, first_abort_counter); |
+ EXPECT_EQ(1, second_counter); |
+ EXPECT_EQ(0, second_abort_counter); |
+ |
+ const size_t third_token = queue.NewToken(); |
+ int third_counter = 0; |
+ int third_abort_counter = 0; |
+ queue.Enqueue(third_token, |
+ base::Bind(&OnRun, &third_counter, &third_abort_counter)); |
+ |
+ // The second task is still running, so the third one is blocked. |
+ base::RunLoop().RunUntilIdle(); |
+ EXPECT_EQ(1, first_counter); |
+ EXPECT_EQ(0, first_abort_counter); |
+ EXPECT_EQ(1, second_counter); |
+ EXPECT_EQ(0, second_abort_counter); |
+ EXPECT_EQ(0, third_counter); |
+ EXPECT_EQ(0, third_abort_counter); |
+ |
+ // After aborting the second task, the third should run. |
+ std::vector<base::File::Error> abort_callback_log; |
+ abort_callback.Run(base::Bind(&OnAbortCallback, &abort_callback_log)); |
+ base::RunLoop().RunUntilIdle(); |
+ EXPECT_EQ(1, first_counter); |
+ EXPECT_EQ(0, first_abort_counter); |
+ EXPECT_EQ(1, second_counter); |
+ EXPECT_EQ(1, second_abort_counter); |
+ ASSERT_EQ(1u, abort_callback_log.size()); |
+ EXPECT_EQ(base::File::FILE_ERROR_FAILED, abort_callback_log[0]); |
+ EXPECT_EQ(1, third_counter); |
+ EXPECT_EQ(0, third_abort_counter); |
+} |
+ |
+TEST_F(FileSystemProviderQueueTest, Enqueue_MultipleAtOnce) { |
+ Queue queue(2); |
+ const size_t first_token = queue.NewToken(); |
+ int first_counter = 0; |
+ int first_abort_counter = 0; |
+ queue.Enqueue(first_token, |
+ base::Bind(&OnRun, &first_counter, &first_abort_counter)); |
+ |
+ const size_t second_token = queue.NewToken(); |
+ int second_counter = 0; |
+ int second_abort_counter = 0; |
+ queue.Enqueue(second_token, |
+ base::Bind(&OnRun, &second_counter, &second_abort_counter)); |
+ |
+ const size_t third_token = queue.NewToken(); |
+ int third_counter = 0; |
+ int third_abort_counter = 0; |
+ queue.Enqueue(third_token, |
+ base::Bind(&OnRun, &third_counter, &third_abort_counter)); |
+ |
+ base::RunLoop().RunUntilIdle(); |
+ EXPECT_EQ(1, first_counter); |
+ EXPECT_EQ(0, first_abort_counter); |
+ EXPECT_EQ(1, second_counter); |
+ EXPECT_EQ(0, second_abort_counter); |
+ EXPECT_EQ(0, third_counter); |
+ EXPECT_EQ(0, third_abort_counter); |
+ |
+ // Completing and removing the second task, should start the last one. |
+ queue.Complete(second_token); |
+ queue.Remove(second_token); |
+ base::RunLoop().RunUntilIdle(); |
+ EXPECT_EQ(1, first_counter); |
+ EXPECT_EQ(0, first_abort_counter); |
+ EXPECT_EQ(1, second_counter); |
+ EXPECT_EQ(0, second_abort_counter); |
+ EXPECT_EQ(1, third_counter); |
+ EXPECT_EQ(0, third_abort_counter); |
+} |
+ |
+#if !defined(NDEBUG) && defined(GTEST_HAS_DEATH_TEST) |
+ |
+TEST_F(FileSystemProviderQueueTest, InvalidUsage_DuplicatedTokens) { |
+ Queue queue(1); |
+ const size_t first_token = queue.NewToken(); |
+ int first_counter = 0; |
+ int first_abort_counter = 0; |
+ queue.Enqueue(first_token, |
+ base::Bind(&OnRun, &first_counter, &first_abort_counter)); |
+ |
+ // Use the first token on purpose. |
+ int second_counter = 0; |
+ int second_abort_counter = 0; |
+ EXPECT_DEATH(queue.Enqueue(first_token, base::Bind(&OnRun, &second_counter, |
+ &second_abort_counter)), |
+ ""); |
+} |
+ |
+TEST_F(FileSystemProviderQueueTest, InvalidUsage_CompleteNotStarted) { |
+ Queue queue(1); |
+ const size_t first_token = queue.NewToken(); |
+ int first_counter = 0; |
+ int first_abort_counter = 0; |
+ queue.Enqueue(first_token, |
+ base::Bind(&OnRun, &first_counter, &first_abort_counter)); |
+ |
+ // Completing and removing the first task, which however hasn't started. |
+ // That should not invoke the second task. |
+ EXPECT_DEATH(queue.Complete(first_token), ""); |
+ EXPECT_DEATH(queue.Remove(first_token), ""); |
+} |
+ |
+TEST_F(FileSystemProviderQueueTest, InvalidUsage_RemoveNotCompleted) { |
+ Queue queue(1); |
+ const size_t first_token = queue.NewToken(); |
+ int first_counter = 0; |
+ int first_abort_counter = 0; |
+ queue.Enqueue(first_token, |
+ base::Bind(&OnRun, &first_counter, &first_abort_counter)); |
+ |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ // Remove before completing. |
+ EXPECT_DEATH(queue.Remove(first_token), ""); |
+} |
+ |
+TEST_F(FileSystemProviderQueueTest, InvalidUsage_CompleteAfterAborting) { |
+ Queue queue(1); |
+ const size_t first_token = queue.NewToken(); |
+ int first_counter = 0; |
+ int first_abort_counter = 0; |
+ AbortCallback first_abort_callback = queue.Enqueue( |
+ first_token, base::Bind(&OnRun, &first_counter, &first_abort_counter)); |
+ |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ // Run, then abort. |
+ std::vector<base::File::Error> first_abort_callback_log; |
+ first_abort_callback.Run( |
+ base::Bind(&OnAbortCallback, &first_abort_callback_log)); |
+ |
+ EXPECT_DEATH(queue.Complete(first_token), ""); |
+} |
+ |
+TEST_F(FileSystemProviderQueueTest, InvalidUsage_RemoveAfterAborting) { |
+ Queue queue(1); |
+ const size_t first_token = queue.NewToken(); |
+ int first_counter = 0; |
+ int first_abort_counter = 0; |
+ AbortCallback first_abort_callback = queue.Enqueue( |
+ first_token, base::Bind(&OnRun, &first_counter, &first_abort_counter)); |
+ |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ // Abort after executing. |
+ std::vector<base::File::Error> first_abort_callback_log; |
+ first_abort_callback.Run( |
+ base::Bind(&OnAbortCallback, &first_abort_callback_log)); |
+ |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ // Remove before completing. |
+ EXPECT_DEATH(queue.Remove(first_token), ""); |
+} |
+ |
+TEST_F(FileSystemProviderQueueTest, InvalidUsage_CompleteTwice) { |
+ Queue queue(1); |
+ const size_t first_token = queue.NewToken(); |
+ int first_counter = 0; |
+ int first_abort_counter = 0; |
+ AbortCallback first_abort_callback = queue.Enqueue( |
+ first_token, base::Bind(&OnRun, &first_counter, &first_abort_counter)); |
+ |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ queue.Complete(first_token); |
+ EXPECT_DEATH(queue.Complete(first_token), ""); |
+} |
+ |
+TEST_F(FileSystemProviderQueueTest, InvalidUsage_RemoveTwice) { |
+ Queue queue(1); |
+ const size_t first_token = queue.NewToken(); |
+ int first_counter = 0; |
+ int first_abort_counter = 0; |
+ AbortCallback first_abort_callback = queue.Enqueue( |
+ first_token, base::Bind(&OnRun, &first_counter, &first_abort_counter)); |
+ |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ queue.Complete(first_token); |
+ queue.Remove(first_token); |
+ EXPECT_DEATH(queue.Complete(first_token), ""); |
+} |
+ |
+#endif |
+ |
+TEST_F(FileSystemProviderQueueTest, Enqueue_Abort) { |
+ Queue queue(1); |
+ const size_t first_token = queue.NewToken(); |
+ int first_counter = 0; |
+ int first_abort_counter = 0; |
+ const AbortCallback first_abort_callback = queue.Enqueue( |
+ first_token, base::Bind(&OnRun, &first_counter, &first_abort_counter)); |
+ |
+ const size_t second_token = queue.NewToken(); |
+ int second_counter = 0; |
+ int second_abort_counter = 0; |
+ const AbortCallback second_abort_callback = queue.Enqueue( |
+ second_token, base::Bind(&OnRun, &second_counter, &second_abort_counter)); |
+ |
+ base::RunLoop().RunUntilIdle(); |
+ EXPECT_EQ(1, first_counter); |
+ EXPECT_EQ(0, first_abort_counter); |
+ EXPECT_EQ(0, second_counter); |
+ EXPECT_EQ(0, second_abort_counter); |
+ |
+ // Abort the first task while it's being executed. |
+ std::vector<base::File::Error> first_abort_callback_log; |
+ first_abort_callback.Run( |
+ base::Bind(&OnAbortCallback, &first_abort_callback_log)); |
+ |
+ // Abort the second task, before it's started. |
+ EXPECT_EQ(0, second_counter); |
+ std::vector<base::File::Error> second_abort_callback_log; |
+ second_abort_callback.Run( |
+ base::Bind(&OnAbortCallback, &second_abort_callback_log)); |
+ |
+ base::RunLoop().RunUntilIdle(); |
+ EXPECT_EQ(1, first_counter); |
+ EXPECT_EQ(1, first_abort_counter); |
+ ASSERT_EQ(1u, first_abort_callback_log.size()); |
+ EXPECT_EQ(base::File::FILE_ERROR_FAILED, first_abort_callback_log[0]); |
+ EXPECT_EQ(0, second_counter); |
+ EXPECT_EQ(0, second_abort_counter); |
+ ASSERT_EQ(1u, second_abort_callback_log.size()); |
+ EXPECT_EQ(base::File::FILE_OK, second_abort_callback_log[0]); |
+ |
+ // Aborting again, should result in the FILE_ERROR_INVALID_MODIFICATION error |
+ // code. |
+ second_abort_callback.Run( |
+ base::Bind(&OnAbortCallback, &second_abort_callback_log)); |
+ |
+ ASSERT_EQ(2u, second_abort_callback_log.size()); |
+ EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION, |
+ second_abort_callback_log[1]); |
+} |
+ |
+} // namespace file_system_provider |
+} // namespace chromeos |