[go: nahoru, domu]

blob: 336ce309d62248eec64a9e59e537dd53bfc6e938 [file] [log] [blame]
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/file_system_provider/queue.h"
#include <stddef.h>
#include <vector>
#include "base/files/file.h"
#include "base/functional/bind.h"
#include "base/run_loop.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace ash::file_system_provider {
namespace {
void OnAbort(int* abort_counter) {
++(*abort_counter);
}
AbortCallback OnRun(int* run_counter, int* abort_counter) {
++(*run_counter);
return base::BindOnce(&OnAbort, abort_counter);
}
#if !defined(NDEBUG) && defined(GTEST_HAS_DEATH_TEST)
AbortCallback OnRunNonAbortable(int* run_counter, int* abort_counter) {
++(*run_counter);
return AbortCallback();
}
#endif
} // namespace
class FileSystemProviderQueueTest : public testing::Test {
protected:
FileSystemProviderQueueTest() = default;
~FileSystemProviderQueueTest() override = default;
content::BrowserTaskEnvironment task_environment_;
};
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::BindOnce(&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::BindOnce(&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 from the queue should run the second task.
queue.Complete(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::BindOnce(&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.
queue.Abort(second_token);
queue.Complete(second_token);
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);
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::BindOnce(&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::BindOnce(&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::BindOnce(&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);
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::BindOnce(&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::BindOnce(&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::BindOnce(&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), "");
}
TEST_F(FileSystemProviderQueueTest,
InvalidUsage_CompleteAfterAbortingNonExecutedTask) {
Queue queue(1);
const size_t first_token = queue.NewToken();
int first_counter = 0;
int first_abort_counter = 0;
queue.Enqueue(first_token,
base::BindOnce(&OnRun, &first_counter, &first_abort_counter));
std::vector<base::File::Error> first_abort_callback_log;
queue.Abort(first_token);
EXPECT_DEATH(queue.Complete(first_token), "");
}
TEST_F(FileSystemProviderQueueTest, InvalidUsage_AbortAfterCompleting) {
Queue queue(1);
const size_t first_token = queue.NewToken();
int first_counter = 0;
int first_abort_counter = 0;
queue.Enqueue(first_token,
base::BindOnce(&OnRun, &first_counter, &first_abort_counter));
base::RunLoop().RunUntilIdle();
queue.Complete(first_token);
EXPECT_DEATH(queue.Abort(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;
queue.Enqueue(first_token,
base::BindOnce(&OnRun, &first_counter, &first_abort_counter));
base::RunLoop().RunUntilIdle();
queue.Complete(first_token);
EXPECT_DEATH(queue.Complete(first_token), "");
}
TEST_F(FileSystemProviderQueueTest, InvalidUsage_AbortTwice) {
Queue queue(1);
const size_t first_token = queue.NewToken();
int first_counter = 0;
int first_abort_counter = 0;
queue.Enqueue(first_token,
base::BindOnce(&OnRun, &first_counter, &first_abort_counter));
base::RunLoop().RunUntilIdle();
queue.Abort(first_token);
EXPECT_DEATH(queue.Abort(first_token), "");
}
TEST_F(FileSystemProviderQueueTest, InvalidUsage_AbortNonAbortable) {
Queue queue(1);
const size_t first_token = queue.NewToken();
int first_counter = 0;
int first_abort_counter = 0;
queue.Enqueue(first_token, base::BindOnce(&OnRunNonAbortable, &first_counter,
&first_abort_counter));
base::RunLoop().RunUntilIdle();
EXPECT_DEATH(queue.Abort(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;
queue.Enqueue(first_token,
base::BindOnce(&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::BindOnce(&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.
queue.Abort(first_token);
queue.Complete(first_token);
// Abort the second task, before it's started.
EXPECT_EQ(0, second_counter);
queue.Abort(second_token);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, first_counter);
EXPECT_EQ(1, first_abort_counter);
EXPECT_EQ(0, second_counter);
EXPECT_EQ(0, second_abort_counter);
}
} // namespace ash::file_system_provider