1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "sync/internal_api/public/attachments/task_queue.h" 6 7 #include <vector> 8 9 #include "base/bind.h" 10 #include "base/memory/weak_ptr.h" 11 #include "base/message_loop/message_loop.h" 12 #include "base/run_loop.h" 13 #include "base/timer/mock_timer.h" 14 #include "testing/gtest/include/gtest/gtest.h" 15 16 using base::TimeDelta; 17 18 namespace syncer { 19 20 namespace { 21 22 const TimeDelta kZero; 23 24 } // namespace 25 26 class TaskQueueTest : public testing::Test { 27 protected: 28 TaskQueueTest() : weak_ptr_factory_(this) { 29 queue_.reset(new TaskQueue<int>( 30 base::Bind(&TaskQueueTest::Process, weak_ptr_factory_.GetWeakPtr()), 31 TimeDelta::FromMinutes(1), 32 TimeDelta::FromMinutes(8))); 33 } 34 35 void RunLoop() { 36 base::RunLoop run_loop; 37 run_loop.RunUntilIdle(); 38 } 39 40 void Process(const int& task) { dispatched_.push_back(task); } 41 42 base::MessageLoop message_loop_; 43 scoped_ptr<TaskQueue<int> > queue_; 44 std::vector<int> dispatched_; 45 base::WeakPtrFactory<TaskQueueTest> weak_ptr_factory_; 46 }; 47 48 // See that at most one task is dispatched at a time. 49 TEST_F(TaskQueueTest, AddToQueue_NoConcurrentTasks) { 50 queue_->AddToQueue(1); 51 queue_->AddToQueue(2); 52 RunLoop(); 53 54 // Only one has been dispatched. 55 ASSERT_EQ(1U, dispatched_.size()); 56 EXPECT_EQ(1, dispatched_.front()); 57 RunLoop(); 58 59 // Still only one. 60 ASSERT_EQ(1U, dispatched_.size()); 61 EXPECT_EQ(1, dispatched_.front()); 62 dispatched_.clear(); 63 queue_->MarkAsSucceeded(1); 64 RunLoop(); 65 66 ASSERT_EQ(1U, dispatched_.size()); 67 EXPECT_EQ(2, dispatched_.front()); 68 dispatched_.clear(); 69 queue_->MarkAsSucceeded(2); 70 RunLoop(); 71 72 ASSERT_TRUE(dispatched_.empty()); 73 } 74 75 // See that that the queue ignores duplicate adds. 76 TEST_F(TaskQueueTest, AddToQueue_NoDuplicates) { 77 queue_->AddToQueue(1); 78 queue_->AddToQueue(1); 79 queue_->AddToQueue(2); 80 queue_->AddToQueue(1); 81 ASSERT_TRUE(dispatched_.empty()); 82 RunLoop(); 83 84 ASSERT_EQ(1U, dispatched_.size()); 85 EXPECT_EQ(1, dispatched_.front()); 86 dispatched_.clear(); 87 queue_->MarkAsSucceeded(1); 88 RunLoop(); 89 90 ASSERT_EQ(1U, dispatched_.size()); 91 EXPECT_EQ(2, dispatched_.front()); 92 dispatched_.clear(); 93 queue_->MarkAsSucceeded(2); 94 RunLoop(); 95 96 ASSERT_TRUE(dispatched_.empty()); 97 } 98 99 // See that Retry works as expected. 100 TEST_F(TaskQueueTest, Retry) { 101 scoped_ptr<base::MockTimer> timer_to_pass(new base::MockTimer(false, false)); 102 base::MockTimer* mock_timer = timer_to_pass.get(); 103 queue_->SetTimerForTest(timer_to_pass.PassAs<base::Timer>()); 104 105 // 1st attempt. 106 queue_->AddToQueue(1); 107 ASSERT_TRUE(mock_timer->IsRunning()); 108 ASSERT_EQ(kZero, mock_timer->GetCurrentDelay()); 109 TimeDelta last_delay = mock_timer->GetCurrentDelay(); 110 mock_timer->Fire(); 111 RunLoop(); 112 113 // 2nd attempt. 114 ASSERT_FALSE(mock_timer->IsRunning()); 115 ASSERT_EQ(1U, dispatched_.size()); 116 EXPECT_EQ(1, dispatched_.front()); 117 dispatched_.clear(); 118 queue_->MarkAsFailed(1); 119 queue_->AddToQueue(1); 120 ASSERT_TRUE(mock_timer->IsRunning()); 121 EXPECT_GT(mock_timer->GetCurrentDelay(), last_delay); 122 EXPECT_LE(mock_timer->GetCurrentDelay(), TimeDelta::FromMinutes(1)); 123 last_delay = mock_timer->GetCurrentDelay(); 124 mock_timer->Fire(); 125 RunLoop(); 126 127 // 3rd attempt. 128 ASSERT_FALSE(mock_timer->IsRunning()); 129 ASSERT_EQ(1U, dispatched_.size()); 130 EXPECT_EQ(1, dispatched_.front()); 131 dispatched_.clear(); 132 queue_->MarkAsFailed(1); 133 queue_->AddToQueue(1); 134 ASSERT_TRUE(mock_timer->IsRunning()); 135 EXPECT_GT(mock_timer->GetCurrentDelay(), last_delay); 136 last_delay = mock_timer->GetCurrentDelay(); 137 mock_timer->Fire(); 138 RunLoop(); 139 140 // Give up. 141 ASSERT_FALSE(mock_timer->IsRunning()); 142 ASSERT_EQ(1U, dispatched_.size()); 143 EXPECT_EQ(1, dispatched_.front()); 144 dispatched_.clear(); 145 queue_->Cancel(1); 146 ASSERT_FALSE(mock_timer->IsRunning()); 147 148 // Try a different task. See the timer remains unchanged because the previous 149 // task was cancelled. 150 ASSERT_TRUE(dispatched_.empty()); 151 queue_->AddToQueue(2); 152 ASSERT_TRUE(mock_timer->IsRunning()); 153 EXPECT_GE(last_delay, mock_timer->GetCurrentDelay()); 154 last_delay = mock_timer->GetCurrentDelay(); 155 mock_timer->Fire(); 156 RunLoop(); 157 158 // Mark this one as succeeding, which will clear the backoff delay. 159 ASSERT_FALSE(mock_timer->IsRunning()); 160 ASSERT_EQ(1U, dispatched_.size()); 161 EXPECT_EQ(2, dispatched_.front()); 162 dispatched_.clear(); 163 queue_->MarkAsSucceeded(2); 164 ASSERT_FALSE(mock_timer->IsRunning()); 165 166 // Add one last task and see that it's dispatched without delay because the 167 // previous one succeeded. 168 ASSERT_TRUE(dispatched_.empty()); 169 queue_->AddToQueue(3); 170 ASSERT_TRUE(mock_timer->IsRunning()); 171 EXPECT_LT(mock_timer->GetCurrentDelay(), last_delay); 172 last_delay = mock_timer->GetCurrentDelay(); 173 mock_timer->Fire(); 174 RunLoop(); 175 176 // Clean up. 177 ASSERT_EQ(1U, dispatched_.size()); 178 EXPECT_EQ(3, dispatched_.front()); 179 dispatched_.clear(); 180 queue_->MarkAsSucceeded(3); 181 ASSERT_FALSE(mock_timer->IsRunning()); 182 } 183 184 TEST_F(TaskQueueTest, Cancel) { 185 queue_->AddToQueue(1); 186 RunLoop(); 187 188 ASSERT_EQ(1U, dispatched_.size()); 189 EXPECT_EQ(1, dispatched_.front()); 190 dispatched_.clear(); 191 queue_->Cancel(1); 192 RunLoop(); 193 194 ASSERT_TRUE(dispatched_.empty()); 195 } 196 197 // See that ResetBackoff resets the backoff delay. 198 TEST_F(TaskQueueTest, ResetBackoff) { 199 scoped_ptr<base::MockTimer> timer_to_pass(new base::MockTimer(false, false)); 200 base::MockTimer* mock_timer = timer_to_pass.get(); 201 queue_->SetTimerForTest(timer_to_pass.PassAs<base::Timer>()); 202 203 // Add an item, mark it as failed, re-add it and see that we now have a 204 // backoff delay. 205 queue_->AddToQueue(1); 206 ASSERT_TRUE(mock_timer->IsRunning()); 207 ASSERT_EQ(kZero, mock_timer->GetCurrentDelay()); 208 mock_timer->Fire(); 209 RunLoop(); 210 ASSERT_FALSE(mock_timer->IsRunning()); 211 ASSERT_EQ(1U, dispatched_.size()); 212 EXPECT_EQ(1, dispatched_.front()); 213 dispatched_.clear(); 214 queue_->MarkAsFailed(1); 215 queue_->AddToQueue(1); 216 ASSERT_TRUE(mock_timer->IsRunning()); 217 EXPECT_GT(mock_timer->GetCurrentDelay(), kZero); 218 EXPECT_LE(mock_timer->GetCurrentDelay(), TimeDelta::FromMinutes(1)); 219 220 // Call ResetBackoff and see that there is no longer a delay. 221 queue_->ResetBackoff(); 222 ASSERT_TRUE(mock_timer->IsRunning()); 223 ASSERT_EQ(kZero, mock_timer->GetCurrentDelay()); 224 mock_timer->Fire(); 225 RunLoop(); 226 ASSERT_FALSE(mock_timer->IsRunning()); 227 ASSERT_EQ(1U, dispatched_.size()); 228 EXPECT_EQ(1, dispatched_.front()); 229 dispatched_.clear(); 230 queue_->MarkAsSucceeded(1); 231 } 232 233 } // namespace syncer 234