| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 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 "blimp/helium/update_scheduler.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/memory/ptr_util.h" | |
| 9 #include "blimp/common/proto/helium.pb.h" | |
| 10 #include "blimp/helium/helium_test.h" | |
| 11 #include "blimp/helium/mock_objects.h" | |
| 12 #include "blimp/helium/object_sync_state.h" | |
| 13 #include "testing/gmock/include/gmock/gmock.h" | |
| 14 #include "testing/gtest/include/gtest/gtest.h" | |
| 15 | |
| 16 using testing::_; | |
| 17 using testing::Expectation; | |
| 18 using testing::Return; | |
| 19 using testing::ReturnPointee; | |
| 20 using testing::SaveArg; | |
| 21 | |
| 22 namespace blimp { | |
| 23 namespace helium { | |
| 24 namespace { | |
| 25 | |
| 26 using MessagePreparedCallback = UpdateScheduler::MessagePreparedCallback; | |
| 27 | |
| 28 constexpr HeliumObjectId kFirstObjectId = 24; | |
| 29 constexpr HeliumObjectId kSecondObjectId = 42; | |
| 30 constexpr Revision kFirstRevision = 1; | |
| 31 constexpr Revision kSecondRevision = 2; | |
| 32 | |
| 33 // Dummy values and corresponding changesets for those values. | |
| 34 constexpr int32_t kFirstChangesetValue = 5; | |
| 35 const char kFirstChangeset[] = "\x5"; | |
| 36 constexpr int32_t kSecondChangesetValue = 6; | |
| 37 const char kSecondChangeset[] = "\x6"; | |
| 38 | |
| 39 class UpdateSchedulerTest : public HeliumTest { | |
| 40 public: | |
| 41 UpdateSchedulerTest() : scheduler_(UpdateScheduler::Create()) { | |
| 42 SetupObjectSyncStates(); | |
| 43 ConnectAndAcknowledgeObjects(); | |
| 44 SetupTestChangesets(); | |
| 45 } | |
| 46 ~UpdateSchedulerTest() override = default; | |
| 47 | |
| 48 MOCK_METHOD1(MessagePrepared, void(proto::HeliumMessage)); | |
| 49 | |
| 50 protected: | |
| 51 MessagePreparedCallback CreateTestMessagePreparedCallback() { | |
| 52 return base::Bind(&UpdateSchedulerTest::MessagePrepared, | |
| 53 base::Unretained(this)); | |
| 54 } | |
| 55 | |
| 56 // Helium objects used across tests. | |
| 57 std::unique_ptr<UpdateScheduler> scheduler_; | |
| 58 MockStreamPump pump_; | |
| 59 MockSyncable syncable1_; | |
| 60 MockSyncable syncable2_; | |
| 61 std::unique_ptr<ObjectSyncState> state1_; | |
| 62 std::unique_ptr<ObjectSyncState> state2_; | |
| 63 std::unique_ptr<TestSyncableChangeset> changeset1_; | |
| 64 std::unique_ptr<TestSyncableChangeset> changeset2_; | |
| 65 | |
| 66 // Holds the local update callback that |state1_| gives to |syncable1_|. | |
| 67 base::Closure local_update_callback1_; | |
| 68 // Holds the local update callback that |state2_| gives to |syncable2_|. | |
| 69 base::Closure local_update_callback2_; | |
| 70 // Holds the HeliumMessage sent to |pump_|. | |
| 71 proto::HeliumMessage sent_message_; | |
| 72 | |
| 73 private: | |
| 74 void SetupObjectSyncStates() { | |
| 75 // Create ObjectSyncStates for each object and store the local update | |
| 76 // callbacks. | |
| 77 EXPECT_CALL(syncable1_, SetLocalUpdateCallback(_)) | |
| 78 .WillOnce(SaveArg<0>(&local_update_callback1_)); | |
| 79 state1_ = ObjectSyncState::CreateForObject(kFirstObjectId, &syncable1_); | |
| 80 | |
| 81 EXPECT_CALL(syncable2_, SetLocalUpdateCallback(_)) | |
| 82 .WillOnce(SaveArg<0>(&local_update_callback2_)); | |
| 83 state2_ = ObjectSyncState::CreateForObject(kSecondObjectId, &syncable2_); | |
| 84 } | |
| 85 | |
| 86 void ConnectAndAcknowledgeObjects() { | |
| 87 // Add the objects to |scheduler_|. | |
| 88 scheduler_->AddObject(kFirstObjectId, state1_.get()); | |
| 89 scheduler_->AddObject(kSecondObjectId, state2_.get()); | |
| 90 | |
| 91 // Connect the |pump_|. | |
| 92 scheduler_->OnStreamConnected(&pump_); | |
| 93 | |
| 94 // |pump_| asks |scheduler_| for acknowlegement messages for each object. We | |
| 95 // are able to call PrepareMessage() twice in a row because we know that | |
| 96 // these are acknowledgement messages and therefore will be made | |
| 97 // synchronously. | |
| 98 scheduler_->PrepareMessage(CreateTestMessagePreparedCallback()); | |
| 99 scheduler_->PrepareMessage(CreateTestMessagePreparedCallback()); | |
| 100 } | |
| 101 | |
| 102 void SetupTestChangesets() { | |
| 103 changeset1_ = base::MakeUnique<TestSyncableChangeset>(); | |
| 104 changeset2_ = base::MakeUnique<TestSyncableChangeset>(); | |
| 105 changeset1_->value.Set(kFirstChangesetValue); | |
| 106 changeset2_->value.Set(kSecondChangesetValue); | |
| 107 } | |
| 108 | |
| 109 DISALLOW_COPY_AND_ASSIGN(UpdateSchedulerTest); | |
| 110 }; | |
| 111 | |
| 112 TEST_F(UpdateSchedulerTest, BasicLocalUpdateFlow) { | |
| 113 base::Closure prepared_for_changeset_callback; | |
| 114 | |
| 115 EXPECT_CALL(pump_, OnMessageAvailable()); | |
| 116 EXPECT_CALL(syncable1_, GetRevision()).WillRepeatedly(Return(kFirstRevision)); | |
| 117 Expectation prepare_to_create_changeset = | |
| 118 EXPECT_CALL(syncable1_, PrepareToCreateChangeset(_, _)) | |
| 119 .WillOnce(SaveArg<1>(&prepared_for_changeset_callback)); | |
| 120 EXPECT_CALL(syncable1_, CreateChangesetMock(_)) | |
| 121 .After(prepare_to_create_changeset) | |
| 122 .WillOnce(Return(changeset1_.release())); | |
| 123 EXPECT_CALL(*this, MessagePrepared(_)).WillOnce(SaveArg<0>(&sent_message_)); | |
| 124 | |
| 125 // |syncable1_| is locally updated. | |
| 126 local_update_callback1_.Run(); | |
| 127 | |
| 128 // Verify that |scheduler_| is ready to send a message with the update. | |
| 129 EXPECT_TRUE(scheduler_->HasMessageReady()); | |
| 130 | |
| 131 // |pump_| asks |scheduler_| for a HeliumMessage. | |
| 132 scheduler_->PrepareMessage(CreateTestMessagePreparedCallback()); | |
| 133 | |
| 134 // |syncable1_| lets |state1_| know it's ready to create a Changeset. | |
| 135 prepared_for_changeset_callback.Run(); | |
| 136 | |
| 137 // Verify that |pump_| receives the correct HeliumMessage. | |
| 138 EXPECT_EQ(kFirstObjectId, sent_message_.object_id()); | |
| 139 EXPECT_EQ(kFirstRevision, sent_message_.end_revision()); | |
| 140 EXPECT_EQ(kFirstChangeset, sent_message_.changeset()); | |
| 141 | |
| 142 // Verify that |scheduler_| is no longer ready to send a message. | |
| 143 EXPECT_FALSE(scheduler_->HasMessageReady()); | |
| 144 } | |
| 145 | |
| 146 TEST_F(UpdateSchedulerTest, LocalUpdateTwice) { | |
| 147 base::Closure prepared_for_changeset_callback; | |
| 148 Revision current_revision = kFirstRevision; | |
| 149 | |
| 150 EXPECT_CALL(pump_, OnMessageAvailable()).Times(2); | |
| 151 EXPECT_CALL(syncable1_, GetRevision()) | |
| 152 .WillRepeatedly(ReturnPointee(¤t_revision)); | |
| 153 EXPECT_CALL(syncable1_, PrepareToCreateChangeset(_, _)) | |
| 154 .Times(2) | |
| 155 .WillRepeatedly(SaveArg<1>(&prepared_for_changeset_callback)); | |
| 156 EXPECT_CALL(syncable1_, CreateChangesetMock(_)) | |
| 157 .Times(2) | |
| 158 .WillOnce(Return(changeset1_.release())) | |
| 159 .WillOnce(Return(changeset2_.release())); | |
| 160 EXPECT_CALL(*this, MessagePrepared(_)) | |
| 161 .Times(2) | |
| 162 .WillRepeatedly(SaveArg<0>(&sent_message_)); | |
| 163 | |
| 164 // |syncable1_| is locally updated. | |
| 165 local_update_callback1_.Run(); | |
| 166 | |
| 167 // Verify that |scheduler_| is ready to send a message with the update. | |
| 168 EXPECT_TRUE(scheduler_->HasMessageReady()); | |
| 169 | |
| 170 // |pump_| asks |scheduler_| for a HeliumMessage. | |
| 171 scheduler_->PrepareMessage(CreateTestMessagePreparedCallback()); | |
| 172 | |
| 173 // |syncable1_| lets |state1_| know it's ready to create a Changeset. | |
| 174 prepared_for_changeset_callback.Run(); | |
| 175 | |
| 176 // Verify that |pump_| receives the correct HeliumMessage. | |
| 177 EXPECT_EQ(kFirstObjectId, sent_message_.object_id()); | |
| 178 EXPECT_EQ(kFirstRevision, sent_message_.end_revision()); | |
| 179 EXPECT_EQ(kFirstChangeset, sent_message_.changeset()); | |
| 180 | |
| 181 // Verify that |scheduler_| no longer has any updates to send. | |
| 182 EXPECT_FALSE(scheduler_->HasMessageReady()); | |
| 183 | |
| 184 // |syncable1_| has another local update. | |
| 185 local_update_callback1_.Run(); | |
| 186 | |
| 187 // Verify that |scheduler_| is ready to send the next update. | |
| 188 EXPECT_TRUE(scheduler_->HasMessageReady()); | |
| 189 | |
| 190 // |pump_| asks |scheduler_| for the next HeliumMessage. | |
| 191 scheduler_->PrepareMessage(CreateTestMessagePreparedCallback()); | |
| 192 | |
| 193 // |syncable1_| updates internally to prepare to create the Changeset. | |
| 194 current_revision = kSecondRevision; | |
| 195 | |
| 196 // |syncable1_| lets |state1_| know it's ready to create the next Changeset. | |
| 197 prepared_for_changeset_callback.Run(); | |
| 198 | |
| 199 // Verify that |pump_| receives the correct HeliumMessage. | |
| 200 EXPECT_EQ(kFirstObjectId, sent_message_.object_id()); | |
| 201 EXPECT_EQ(kSecondRevision, sent_message_.end_revision()); | |
| 202 EXPECT_EQ(kSecondChangeset, sent_message_.changeset()); | |
| 203 } | |
| 204 | |
| 205 TEST_F(UpdateSchedulerTest, LocalUpdateMultipleObjects) { | |
| 206 base::Closure prepared_for_changeset_callback1; | |
| 207 base::Closure prepared_for_changeset_callback2; | |
| 208 | |
| 209 EXPECT_CALL(pump_, OnMessageAvailable()).Times(2); | |
| 210 EXPECT_CALL(syncable1_, GetRevision()).WillRepeatedly(Return(kFirstRevision)); | |
| 211 Expectation prepare_to_create_changeset1 = | |
| 212 EXPECT_CALL(syncable1_, PrepareToCreateChangeset(_, _)) | |
| 213 .WillOnce(SaveArg<1>(&prepared_for_changeset_callback1)); | |
| 214 EXPECT_CALL(syncable1_, CreateChangesetMock(_)) | |
| 215 .After(prepare_to_create_changeset1) | |
| 216 .WillOnce(Return(changeset1_.release())); | |
| 217 EXPECT_CALL(syncable2_, GetRevision()) | |
| 218 .WillRepeatedly(Return(kSecondRevision)); | |
| 219 Expectation prepare_to_create_changeset2 = | |
| 220 EXPECT_CALL(syncable2_, PrepareToCreateChangeset(_, _)) | |
| 221 .WillOnce(SaveArg<1>(&prepared_for_changeset_callback2)); | |
| 222 EXPECT_CALL(syncable2_, CreateChangesetMock(_)) | |
| 223 .After(prepare_to_create_changeset2) | |
| 224 .WillOnce(Return(changeset2_.release())); | |
| 225 EXPECT_CALL(*this, MessagePrepared(_)) | |
| 226 .Times(2) | |
| 227 .WillRepeatedly(SaveArg<0>(&sent_message_)); | |
| 228 | |
| 229 // |syncable1_| and |syncable2_| are locally updated. | |
| 230 local_update_callback1_.Run(); | |
| 231 local_update_callback2_.Run(); | |
| 232 | |
| 233 // Verify that |scheduler_| is ready to send a message with the update. | |
| 234 EXPECT_TRUE(scheduler_->HasMessageReady()); | |
| 235 | |
| 236 // |pump_| asks |scheduler_| for a HeliumMessage. | |
| 237 scheduler_->PrepareMessage(CreateTestMessagePreparedCallback()); | |
| 238 | |
| 239 // |syncable1_| lets |state1_| know it's ready to create a Changeset. | |
| 240 prepared_for_changeset_callback1.Run(); | |
| 241 | |
| 242 // Verify that |pump_| receives the correct HeliumMessage. | |
| 243 EXPECT_EQ(kFirstObjectId, sent_message_.object_id()); | |
| 244 EXPECT_EQ(kFirstRevision, sent_message_.end_revision()); | |
| 245 EXPECT_EQ(kFirstChangeset, sent_message_.changeset()); | |
| 246 | |
| 247 // Verify that |scheduler_| is ready to send the next update. | |
| 248 EXPECT_TRUE(scheduler_->HasMessageReady()); | |
| 249 | |
| 250 // |pump_| asks |scheduler_| for the next HeliumMessage. | |
| 251 scheduler_->PrepareMessage(CreateTestMessagePreparedCallback()); | |
| 252 | |
| 253 // |syncable2_| lets |state2_| know it's ready to create a Changeset. | |
| 254 prepared_for_changeset_callback2.Run(); | |
| 255 | |
| 256 // Verify that |pump_| receives the correct HeliumMessage. | |
| 257 EXPECT_EQ(kSecondObjectId, sent_message_.object_id()); | |
| 258 EXPECT_EQ(kSecondRevision, sent_message_.end_revision()); | |
| 259 EXPECT_EQ(kSecondChangeset, sent_message_.changeset()); | |
| 260 | |
| 261 // Verify that |scheduler_| is no longer ready to send a message. | |
| 262 EXPECT_FALSE(scheduler_->HasMessageReady()); | |
| 263 } | |
| 264 | |
| 265 TEST_F(UpdateSchedulerTest, LocalUpdateDuringChangesetPreparation) { | |
| 266 base::Closure prepared_for_changeset_callback; | |
| 267 Revision current_revision = kFirstRevision; | |
| 268 | |
| 269 EXPECT_CALL(pump_, OnMessageAvailable()).Times(2); | |
| 270 EXPECT_CALL(syncable1_, GetRevision()) | |
| 271 .WillRepeatedly(ReturnPointee(¤t_revision)); | |
| 272 EXPECT_CALL(syncable1_, PrepareToCreateChangeset(_, _)) | |
| 273 .Times(2) | |
| 274 .WillRepeatedly(SaveArg<1>(&prepared_for_changeset_callback)); | |
| 275 EXPECT_CALL(syncable1_, CreateChangesetMock(_)) | |
| 276 .Times(2) | |
| 277 .WillOnce(Return(changeset1_.release())) | |
| 278 .WillOnce(Return(changeset2_.release())); | |
| 279 EXPECT_CALL(*this, MessagePrepared(_)) | |
| 280 .Times(2) | |
| 281 .WillRepeatedly(SaveArg<0>(&sent_message_)); | |
| 282 | |
| 283 // |syncable1_| is locally updated. | |
| 284 local_update_callback1_.Run(); | |
| 285 | |
| 286 // Verify that |scheduler_| is ready to send a message with the update. | |
| 287 EXPECT_TRUE(scheduler_->HasMessageReady()); | |
| 288 | |
| 289 // |pump_| asks |scheduler_| for a HeliumMessage. | |
| 290 scheduler_->PrepareMessage(CreateTestMessagePreparedCallback()); | |
| 291 | |
| 292 // |syncable1_| has another local update during preparation. | |
| 293 local_update_callback1_.Run(); | |
| 294 | |
| 295 // |syncable1_| lets |state1_| know it's ready to create a Changeset. | |
| 296 prepared_for_changeset_callback.Run(); | |
| 297 | |
| 298 // Verify that |pump_| receives the correct HeliumMessage. | |
| 299 EXPECT_EQ(kFirstObjectId, sent_message_.object_id()); | |
| 300 EXPECT_EQ(kFirstRevision, sent_message_.end_revision()); | |
| 301 EXPECT_EQ(kFirstChangeset, sent_message_.changeset()); | |
| 302 | |
| 303 // Verify that |scheduler_| is ready to send the next update. | |
| 304 EXPECT_TRUE(scheduler_->HasMessageReady()); | |
| 305 | |
| 306 // |pump_| asks |scheduler_| for the next HeliumMessage. | |
| 307 scheduler_->PrepareMessage(CreateTestMessagePreparedCallback()); | |
| 308 | |
| 309 // |syncable1_| updates internally to prepare to create the Changeset. | |
| 310 current_revision = kSecondRevision; | |
| 311 | |
| 312 // |syncable1_| lets |state1_| know it's ready to create the next Changeset. | |
| 313 prepared_for_changeset_callback.Run(); | |
| 314 | |
| 315 // Verify that |pump_| receives the correct HeliumMessage. | |
| 316 EXPECT_EQ(kFirstObjectId, sent_message_.object_id()); | |
| 317 EXPECT_EQ(kSecondRevision, sent_message_.end_revision()); | |
| 318 EXPECT_EQ(kSecondChangeset, sent_message_.changeset()); | |
| 319 } | |
| 320 | |
| 321 TEST_F(UpdateSchedulerTest, BasicRemoteUpdateFlow) { | |
| 322 TestSyncableChangeset validated_changeset; | |
| 323 TestSyncableChangeset applied_changeset; | |
| 324 | |
| 325 Expectation changeset_validation = | |
| 326 EXPECT_CALL(syncable1_, ValidateChangeset(_)) | |
| 327 .WillOnce(DoAll(SaveArg<0>(&validated_changeset), Return(true))); | |
| 328 EXPECT_CALL(syncable1_, ApplyChangeset(_)) | |
| 329 .After(changeset_validation) | |
| 330 .WillOnce(SaveArg<0>(&applied_changeset)); | |
| 331 EXPECT_CALL(pump_, OnMessageAvailable()); | |
| 332 EXPECT_CALL(*this, MessagePrepared(_)).WillOnce(SaveArg<0>(&sent_message_)); | |
| 333 | |
| 334 // |state1_| receives a Changeset from the SyncManager. | |
| 335 state1_->OnChangesetReceived(kFirstRevision, kFirstChangeset); | |
| 336 | |
| 337 // Verify that |syncable1_| validates and applies the given Changeset. | |
| 338 EXPECT_EQ(kFirstChangesetValue, validated_changeset.value()); | |
| 339 EXPECT_EQ(kFirstChangesetValue, applied_changeset.value()); | |
| 340 | |
| 341 // Verify that |scheduler_| is ready to send a message to acknowledge the | |
| 342 // Changeset. | |
| 343 EXPECT_TRUE(scheduler_->HasMessageReady()); | |
| 344 | |
| 345 // |pump_| asks |scheduler_| for a HeliumMessage. | |
| 346 scheduler_->PrepareMessage(CreateTestMessagePreparedCallback()); | |
| 347 | |
| 348 // Verify that |pump_| receives the correct HeliumMessage. | |
| 349 EXPECT_EQ(kFirstObjectId, sent_message_.object_id()); | |
| 350 EXPECT_EQ(kFirstRevision, sent_message_.ack_revision()); | |
| 351 } | |
| 352 | |
| 353 TEST_F(UpdateSchedulerTest, LocalUpdateAndAcknowledgementOneMessage) { | |
| 354 base::Closure prepared_for_changeset_callback; | |
| 355 TestSyncableChangeset validated_changeset; | |
| 356 TestSyncableChangeset applied_changeset; | |
| 357 | |
| 358 Expectation changeset_validation = | |
| 359 EXPECT_CALL(syncable1_, ValidateChangeset(_)) | |
| 360 .WillOnce(DoAll(SaveArg<0>(&validated_changeset), Return(true))); | |
| 361 EXPECT_CALL(syncable1_, ApplyChangeset(_)) | |
| 362 .After(changeset_validation) | |
| 363 .WillOnce(SaveArg<0>(&applied_changeset)); | |
| 364 EXPECT_CALL(pump_, OnMessageAvailable()).Times(2); | |
| 365 EXPECT_CALL(syncable1_, GetRevision()) | |
| 366 .WillRepeatedly(Return(kSecondRevision)); | |
| 367 Expectation prepare_to_create_changeset = | |
| 368 EXPECT_CALL(syncable1_, PrepareToCreateChangeset(_, _)) | |
| 369 .WillOnce(SaveArg<1>(&prepared_for_changeset_callback)); | |
| 370 EXPECT_CALL(syncable1_, CreateChangesetMock(_)) | |
| 371 .After(prepare_to_create_changeset) | |
| 372 .WillOnce(Return(changeset1_.release())); | |
| 373 EXPECT_CALL(*this, MessagePrepared(_)).WillOnce(SaveArg<0>(&sent_message_)); | |
| 374 | |
| 375 // |state1_| receives a Changeset from the SyncManager. | |
| 376 state1_->OnChangesetReceived(kFirstRevision, kFirstChangeset); | |
| 377 | |
| 378 // Verify that |syncable1_| validates and applies the given Changeset. | |
| 379 EXPECT_EQ(kFirstChangesetValue, validated_changeset.value()); | |
| 380 EXPECT_EQ(kFirstChangesetValue, applied_changeset.value()); | |
| 381 | |
| 382 // |syncable1_| is locally updated. | |
| 383 local_update_callback1_.Run(); | |
| 384 | |
| 385 // Verify that |scheduler_| is ready to send a message with the update. | |
| 386 EXPECT_TRUE(scheduler_->HasMessageReady()); | |
| 387 | |
| 388 // |pump_| asks |scheduler_| for a HeliumMessage. | |
| 389 scheduler_->PrepareMessage(CreateTestMessagePreparedCallback()); | |
| 390 | |
| 391 // |syncable1_| lets |state1_| know it's ready to create a Changeset. | |
| 392 prepared_for_changeset_callback.Run(); | |
| 393 | |
| 394 // Verify that |pump_| receives the correct HeliumMessage, with both the local | |
| 395 // update and the acknowledgement of the received Changeset. | |
| 396 EXPECT_EQ(kFirstObjectId, sent_message_.object_id()); | |
| 397 EXPECT_EQ(kSecondRevision, sent_message_.end_revision()); | |
| 398 EXPECT_EQ(kFirstChangeset, sent_message_.changeset()); | |
| 399 EXPECT_EQ(kFirstRevision, sent_message_.ack_revision()); | |
| 400 | |
| 401 // Verify that |scheduler_| is no longer ready to send a message. | |
| 402 EXPECT_FALSE(scheduler_->HasMessageReady()); | |
| 403 } | |
| 404 | |
| 405 } // namespace | |
| 406 } // namespace helium | |
| 407 } // namespace blimp | |
| OLD | NEW |