1 // Copyright (c) 2012 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 // Mock ServerConnectionManager class for use in client unit tests. 6 7 #ifndef SYNC_TEST_ENGINE_MOCK_CONNECTION_MANAGER_H_ 8 #define SYNC_TEST_ENGINE_MOCK_CONNECTION_MANAGER_H_ 9 10 #include <bitset> 11 #include <list> 12 #include <string> 13 #include <vector> 14 15 #include "base/callback.h" 16 #include "base/compiler_specific.h" 17 #include "base/memory/scoped_vector.h" 18 #include "base/synchronization/lock.h" 19 #include "sync/engine/net/server_connection_manager.h" 20 #include "sync/internal_api/public/base/model_type.h" 21 #include "sync/internal_api/public/base/unique_position.h" 22 #include "sync/protocol/sync.pb.h" 23 24 namespace syncer { 25 26 class MockConnectionManager : public ServerConnectionManager { 27 public: 28 class MidCommitObserver { 29 public: 30 virtual void Observe() = 0; 31 32 protected: ~MidCommitObserver()33 virtual ~MidCommitObserver() {} 34 }; 35 36 MockConnectionManager(syncable::Directory*, 37 CancelationSignal* signal); 38 virtual ~MockConnectionManager(); 39 40 // Overridden ServerConnectionManager functions. 41 virtual bool PostBufferToPath( 42 PostBufferParams*, 43 const std::string& path, 44 const std::string& auth_token, 45 ScopedServerStatusWatcher* watcher) OVERRIDE; 46 47 // Control of commit response. 48 // NOTE: Commit callback is invoked only once then reset. 49 void SetMidCommitCallback(const base::Closure& callback); 50 void SetMidCommitObserver(MidCommitObserver* observer); 51 52 // Set this if you want commit to perform commit time rename. Will request 53 // that the client renames all commited entries, prepending this string. 54 void SetCommitTimeRename(std::string prepend); 55 56 // Generic versions of AddUpdate functions. Tests using these function should 57 // compile for both the int64 and string id based versions of the server. 58 // The SyncEntity returned is only valid until the Sync is completed 59 // (e.g. with SyncShare.) It allows to add further entity properties before 60 // sync, using SetLastXXX() methods and/or GetMutableLastUpdate(). 61 sync_pb::SyncEntity* AddUpdateDirectory( 62 syncable::Id id, 63 syncable::Id parent_id, 64 std::string name, 65 int64 version, 66 int64 sync_ts, 67 std::string originator_cache_guid, 68 std::string originator_client_item_id); 69 sync_pb::SyncEntity* AddUpdateBookmark(syncable::Id id, 70 syncable::Id parent_id, 71 std::string name, 72 int64 version, 73 int64 sync_ts, 74 std::string originator_cache_guid, 75 std::string originator_client_item_id); 76 // Versions of the AddUpdate functions that accept integer IDs. 77 sync_pb::SyncEntity* AddUpdateDirectory( 78 int id, 79 int parent_id, 80 std::string name, 81 int64 version, 82 int64 sync_ts, 83 std::string originator_cache_guid, 84 std::string originator_client_item_id); 85 sync_pb::SyncEntity* AddUpdateBookmark(int id, 86 int parent_id, 87 std::string name, 88 int64 version, 89 int64 sync_ts, 90 std::string originator_cache_guid, 91 std::string originator_client_item_id); 92 // New protocol versions of the AddUpdate functions. 93 sync_pb::SyncEntity* AddUpdateDirectory( 94 std::string id, 95 std::string parent_id, 96 std::string name, 97 int64 version, 98 int64 sync_ts, 99 std::string originator_cache_guid, 100 std::string originator_client_item_id); 101 sync_pb::SyncEntity* AddUpdateBookmark(std::string id, 102 std::string parent_id, 103 std::string name, 104 int64 version, 105 int64 sync_ts, 106 std::string originator_cache_guid, 107 std::string originator_client_item_id); 108 // Versions of the AddUpdate function that accept specifics. 109 sync_pb::SyncEntity* AddUpdateSpecifics( 110 int id, 111 int parent_id, 112 std::string name, 113 int64 version, 114 int64 sync_ts, 115 bool is_dir, 116 int64 position, 117 const sync_pb::EntitySpecifics& specifics); 118 sync_pb::SyncEntity* AddUpdateSpecifics( 119 int id, 120 int parent_id, 121 std::string name, 122 int64 version, 123 int64 sync_ts, 124 bool is_dir, 125 int64 position, 126 const sync_pb::EntitySpecifics& specifics, 127 std::string originator_cache_guid, 128 std::string originator_client_item_id); 129 sync_pb::SyncEntity* SetNigori( 130 int id, 131 int64 version, 132 int64 sync_ts, 133 const sync_pb::EntitySpecifics& specifics); 134 // Unique client tag variant for adding items. 135 sync_pb::SyncEntity* AddUpdatePref(std::string id, 136 std::string parent_id, 137 std::string client_tag, 138 int64 version, 139 int64 sync_ts); 140 141 // Find the last commit sent by the client, and replay it for the next get 142 // updates command. This can be used to simulate the GetUpdates that happens 143 // immediately after a successful commit. 144 sync_pb::SyncEntity* AddUpdateFromLastCommit(); 145 146 // Add a deleted item. Deletion records typically contain no 147 // additional information beyond the deletion, and no specifics. 148 // The server may send the originator fields. 149 void AddUpdateTombstone(const syncable::Id& id); 150 151 void SetLastUpdateDeleted(); 152 void SetLastUpdateServerTag(const std::string& tag); 153 void SetLastUpdateClientTag(const std::string& tag); 154 void SetLastUpdateOriginatorFields(const std::string& client_id, 155 const std::string& entry_id); 156 void SetLastUpdatePosition(int64 position_in_parent); 157 void SetNewTimestamp(int ts); 158 void SetChangesRemaining(int64 count); 159 160 // Add a new batch of updates after the current one. Allows multiple 161 // GetUpdates responses to be buffered up, since the syncer may 162 // issue multiple requests during a sync cycle. 163 void NextUpdateBatch(); 164 FailNextPostBufferToPathCall()165 void FailNextPostBufferToPathCall() { countdown_to_postbuffer_fail_ = 1; } FailNthPostBufferToPathCall(int n)166 void FailNthPostBufferToPathCall(int n) { countdown_to_postbuffer_fail_ = n; } 167 168 void SetKeystoreKey(const std::string& key); 169 FailNonPeriodicGetUpdates()170 void FailNonPeriodicGetUpdates() { fail_non_periodic_get_updates_ = true; } 171 172 // Simple inspectors. client_stuck()173 bool client_stuck() const { return client_stuck_; } 174 175 // warning: These take ownership of their input. 176 void SetGUClientCommand(sync_pb::ClientCommand* command); 177 void SetCommitClientCommand(sync_pb::ClientCommand* command); 178 179 void SetTransientErrorId(syncable::Id); 180 committed_ids()181 const std::vector<syncable::Id>& committed_ids() const { 182 return committed_ids_; 183 } commit_messages()184 const std::vector<sync_pb::CommitMessage*>& commit_messages() const { 185 return commit_messages_.get(); 186 } commit_responses()187 const std::vector<sync_pb::CommitResponse*>& commit_responses() const { 188 return commit_responses_.get(); 189 } 190 // Retrieve the last sent commit message. 191 const sync_pb::CommitMessage& last_sent_commit() const; 192 193 // Retrieve the last returned commit response. 194 const sync_pb::CommitResponse& last_commit_response() const; 195 196 // Retrieve the last request submitted to the server (regardless of type). 197 const sync_pb::ClientToServerMessage& last_request() const; 198 199 // Retrieve the cumulative collection of all requests sent by clients. 200 const std::vector<sync_pb::ClientToServerMessage>& requests() const; 201 set_conflict_all_commits(bool value)202 void set_conflict_all_commits(bool value) { 203 conflict_all_commits_ = value; 204 } set_next_new_id(int value)205 void set_next_new_id(int value) { 206 next_new_id_ = value; 207 } set_conflict_n_commits(int value)208 void set_conflict_n_commits(int value) { 209 conflict_n_commits_ = value; 210 } 211 set_use_legacy_bookmarks_protocol(bool value)212 void set_use_legacy_bookmarks_protocol(bool value) { 213 use_legacy_bookmarks_protocol_ = value; 214 } 215 set_store_birthday(std::string new_birthday)216 void set_store_birthday(std::string new_birthday) { 217 // Multiple threads can set store_birthday_ in our tests, need to lock it to 218 // ensure atomic read/writes and avoid race conditions. 219 base::AutoLock lock(store_birthday_lock_); 220 store_birthday_ = new_birthday; 221 } 222 223 // Retrieve the number of GetUpdates requests that the mock server has 224 // seen since the last time this function was called. Can be used to 225 // verify that a GetUpdates actually did or did not happen after running 226 // the syncer. GetAndClearNumGetUpdatesRequests()227 int GetAndClearNumGetUpdatesRequests() { 228 int result = num_get_updates_requests_; 229 num_get_updates_requests_ = 0; 230 return result; 231 } 232 233 // Expect that GetUpdates will request exactly the types indicated in 234 // the bitset. ExpectGetUpdatesRequestTypes(ModelTypeSet expected_filter)235 void ExpectGetUpdatesRequestTypes(ModelTypeSet expected_filter) { 236 expected_filter_ = expected_filter; 237 } 238 239 void SetServerReachable(); 240 241 void SetServerNotReachable(); 242 243 // Updates our internal state as if we had attempted a connection. Does not 244 // send notifications as a real connection attempt would. This is useful in 245 // cases where we're mocking out most of the code that performs network 246 // requests. 247 void UpdateConnectionStatus(); 248 249 void SetServerStatus(HttpResponse::ServerConnectionCode server_status); 250 251 // Return by copy to be thread-safe. store_birthday()252 const std::string store_birthday() { 253 base::AutoLock lock(store_birthday_lock_); 254 return store_birthday_; 255 } 256 257 // Explicitly indicate that we will not be fetching some updates. ClearUpdatesQueue()258 void ClearUpdatesQueue() { 259 update_queue_.clear(); 260 } 261 262 // Locate the most recent update message for purpose of alteration. 263 sync_pb::SyncEntity* GetMutableLastUpdate(); 264 265 private: 266 sync_pb::SyncEntity* AddUpdateFull(syncable::Id id, syncable::Id parentid, 267 std::string name, int64 version, 268 int64 sync_ts, 269 bool is_dir); 270 sync_pb::SyncEntity* AddUpdateFull(std::string id, 271 std::string parentid, std::string name, 272 int64 version, int64 sync_ts, 273 bool is_dir); 274 sync_pb::SyncEntity* AddUpdateMeta(std::string id, std::string parentid, 275 std::string name, int64 version, 276 int64 sync_ts); 277 278 // Functions to handle the various types of server request. 279 void ProcessGetUpdates(sync_pb::ClientToServerMessage* csm, 280 sync_pb::ClientToServerResponse* response); 281 void ProcessCommit(sync_pb::ClientToServerMessage* csm, 282 sync_pb::ClientToServerResponse* response_buffer); 283 void ProcessClearData(sync_pb::ClientToServerMessage* csm, 284 sync_pb::ClientToServerResponse* response); 285 void AddDefaultBookmarkData(sync_pb::SyncEntity* entity, bool is_folder); 286 287 // Determine if one entry in a commit should be rejected with a conflict. 288 bool ShouldConflictThisCommit(); 289 290 // Determine if the given item's commit request should be refused with 291 // a TRANSIENT_ERROR response. 292 bool ShouldTransientErrorThisId(syncable::Id id); 293 294 // Generate a numeric position_in_parent value. We use a global counter 295 // that only decreases; this simulates new objects always being added to the 296 // front of the ordering. GeneratePositionInParent()297 int64 GeneratePositionInParent() { 298 return next_position_in_parent_--; 299 } 300 301 // Get a mutable update response which will eventually be returned to the 302 // client. 303 sync_pb::GetUpdatesResponse* GetUpdateResponse(); 304 void ApplyToken(); 305 306 // Determine whether an progress marker array (like that sent in 307 // GetUpdates.from_progress_marker) indicates that a particular ModelType 308 // should be included. 309 bool IsModelTypePresentInSpecifics( 310 const google::protobuf::RepeatedPtrField< 311 sync_pb::DataTypeProgressMarker>& filter, 312 ModelType value); 313 314 sync_pb::DataTypeProgressMarker const* GetProgressMarkerForType( 315 const google::protobuf::RepeatedPtrField< 316 sync_pb::DataTypeProgressMarker>& filter, 317 ModelType value); 318 319 // When false, we pretend to have network connectivity issues. 320 bool server_reachable_; 321 322 // All IDs that have been committed. 323 std::vector<syncable::Id> committed_ids_; 324 325 // List of IDs which should return a transient error. 326 std::vector<syncable::Id> transient_error_ids_; 327 328 // Control of when/if we return conflicts. 329 bool conflict_all_commits_; 330 int conflict_n_commits_; 331 332 // Commit messages we've sent, and responses we've returned. 333 ScopedVector<sync_pb::CommitMessage> commit_messages_; 334 ScopedVector<sync_pb::CommitResponse> commit_responses_; 335 336 // The next id the mock will return to a commit. 337 int next_new_id_; 338 339 // The store birthday we send to the client. 340 std::string store_birthday_; 341 base::Lock store_birthday_lock_; 342 bool store_birthday_sent_; 343 bool client_stuck_; 344 std::string commit_time_rename_prepended_string_; 345 346 // On each PostBufferToPath() call, we decrement this counter. The call fails 347 // iff we hit zero at that call. 348 int countdown_to_postbuffer_fail_; 349 350 // Our directory. Used only to ensure that we are not holding the transaction 351 // lock when performing network I/O. Can be NULL if the test author is 352 // confident this can't happen. 353 syncable::Directory* directory_; 354 355 // The updates we'll return to the next request. 356 std::list<sync_pb::GetUpdatesResponse> update_queue_; 357 base::Closure mid_commit_callback_; 358 MidCommitObserver* mid_commit_observer_; 359 360 // The keystore key we return for a GetUpdates with need_encryption_key set. 361 std::string keystore_key_; 362 363 // The AUTHENTICATE response we'll return for auth requests. 364 sync_pb::AuthenticateResponse auth_response_; 365 // What we use to determine if we should return SUCCESS or BAD_AUTH_TOKEN. 366 std::string valid_auth_token_; 367 368 // Whether we are faking a server mandating clients to throttle requests. 369 // Protected by |response_code_override_lock_|. 370 bool throttling_; 371 372 // Whether we are failing all requests by returning 373 // ClientToServerResponse::AUTH_INVALID. 374 // Protected by |response_code_override_lock_|. 375 bool fail_with_auth_invalid_; 376 377 base::Lock response_code_override_lock_; 378 379 // True if we are only accepting GetUpdatesCallerInfo::PERIODIC requests. 380 bool fail_non_periodic_get_updates_; 381 382 scoped_ptr<sync_pb::ClientCommand> gu_client_command_; 383 scoped_ptr<sync_pb::ClientCommand> commit_client_command_; 384 385 // The next value to use for the position_in_parent property. 386 int64 next_position_in_parent_; 387 388 // The default is to use the newer sync_pb::BookmarkSpecifics-style protocol. 389 // If this option is set to true, then the MockConnectionManager will 390 // use the older sync_pb::SyncEntity_BookmarkData-style protocol. 391 bool use_legacy_bookmarks_protocol_; 392 393 ModelTypeSet expected_filter_; 394 395 int num_get_updates_requests_; 396 397 std::string next_token_; 398 399 std::vector<sync_pb::ClientToServerMessage> requests_; 400 401 DISALLOW_COPY_AND_ASSIGN(MockConnectionManager); 402 }; 403 404 } // namespace syncer 405 406 #endif // SYNC_TEST_ENGINE_MOCK_CONNECTION_MANAGER_H_ 407