Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2013 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/test/fake_server.h" | |
| 6 | |
| 7 #include <limits> | |
| 8 #include <string> | |
| 9 #include <vector> | |
| 10 | |
| 11 #include "base/basictypes.h" | |
| 12 #include "base/logging.h" | |
| 13 #include "base/strings/string_number_conversions.h" | |
| 14 #include "sync/internal_api/public/base/model_type.h" | |
| 15 #include "sync/protocol/sync.pb.h" | |
| 16 | |
| 17 using std::string; | |
| 18 | |
| 19 // The PermanentItemSpec parent_tag for a root node. | |
| 20 static const std::string kRootParentTag = "0"; | |
|
rlarocque
2013/12/18 20:22:01
I'm not 100% sure about this, but I think this lin
pval...(no longer on Chromium)
2014/01/03 23:25:31
I'm fine with leaving it here if there are no awfu
rlarocque
2014/01/04 00:06:24
The namespace doesn't matter too much. Because it
| |
| 21 | |
| 22 namespace syncer { | |
| 23 | |
| 24 FakeServer::UpdateSieve::UpdateSieve( | |
| 25 const sync_pb::GetUpdatesMessage& get_updates_message) | |
| 26 : get_updates_message_(get_updates_message) { | |
| 27 DCHECK_GT(get_updates_message.from_progress_marker_size(), 0); | |
| 28 | |
| 29 int64 min_version = std::numeric_limits<int64>::max(); | |
| 30 for (int i = 0; i < get_updates_message_.from_progress_marker_size(); i++) { | |
| 31 sync_pb::DataTypeProgressMarker marker = | |
| 32 get_updates_message_.from_progress_marker(i); | |
| 33 | |
| 34 int64 version; | |
| 35 if (!base::StringToInt64(marker.token(), &version)) { | |
| 36 version = 0; | |
| 37 } | |
| 38 | |
| 39 state_[marker.data_type_id()] = version; | |
| 40 | |
| 41 if (version < min_version) | |
| 42 min_version = version; | |
| 43 } | |
| 44 | |
| 45 min_version_ = min_version; | |
| 46 state_[ModelTypeFromInt(TOP_LEVEL_FOLDER)] = min_version_; | |
|
rlarocque
2013/12/18 20:22:01
This looks sketchy to me.
TOP_LEVEL_FOLDER is eno
pval...(no longer on Chromium)
2014/01/03 23:25:31
I've removed handling of TOP_LEVEL_FOLDER since it
| |
| 47 } | |
| 48 | |
| 49 FakeServer::UpdateSieve::~UpdateSieve() { } | |
| 50 | |
| 51 void FakeServer::UpdateSieve::UpdateProgressMarkers( | |
| 52 int64 new_version, | |
| 53 sync_pb::GetUpdatesResponse* get_updates_response) { | |
| 54 for (TypeIdToVersionMap::iterator it = state_.begin(); it != state_.end(); | |
| 55 ++it) { | |
| 56 if (it->first == TOP_LEVEL_FOLDER) | |
| 57 continue; | |
| 58 | |
| 59 sync_pb::DataTypeProgressMarker* new_marker = | |
| 60 get_updates_response->add_new_progress_marker(); | |
| 61 new_marker->set_data_type_id(it->first); | |
| 62 | |
| 63 int64 version = new_version > state_[new_marker->data_type_id()] ? | |
| 64 new_version : state_[new_marker->data_type_id()]; | |
| 65 new_marker->set_token(base::Int64ToString(version)); | |
| 66 } | |
| 67 } | |
| 68 | |
| 69 bool FakeServer::UpdateSieve::ClientWantsItem( | |
| 70 const sync_pb::SyncEntity& entity) { | |
| 71 ModelType model_type = GetModelType(entity); | |
| 72 int data_type_id = GetSpecificsFieldNumberFromModelType(model_type); | |
| 73 return state_[data_type_id] < entity.version(); | |
| 74 } | |
| 75 | |
| 76 int64 FakeServer::UpdateSieve::GetMinVersion() { | |
| 77 return min_version_; | |
| 78 } | |
| 79 | |
| 80 std::vector<int> FakeServer::UpdateSieve::GetFirstTimeTypes() { | |
| 81 std::vector<int> types; | |
| 82 | |
| 83 for (TypeIdToVersionMap::iterator it = state_.begin(); it != state_.end(); | |
| 84 ++it) { | |
| 85 if (state_[it->first] == 0) | |
|
rlarocque
2013/12/18 20:22:01
Could TOP_LEVEL_FOLDER wind up in this list of typ
pval...(no longer on Chromium)
2014/01/03 23:25:31
Not anymore (see comment above about removing it e
| |
| 86 types.push_back(it->first); | |
| 87 } | |
| 88 | |
| 89 return types; | |
| 90 } | |
| 91 | |
| 92 FakeServer::FakeServer() : initialized_(false), version_(0) { } | |
| 93 | |
| 94 FakeServer::~FakeServer() { } | |
| 95 | |
| 96 bool FakeServer::Init() { | |
| 97 // Use dummy values for these fields. | |
| 98 keystore_keys_.push_back("1111111111111111"); | |
| 99 birthday_ = "1234567890"; | |
| 100 | |
| 101 initialized_ = PopulatePermanentItemSpecs(); | |
| 102 return initialized_; | |
| 103 } | |
| 104 | |
| 105 bool FakeServer::PopulatePermanentItemSpecs() { | |
| 106 ModelTypeSet protocol_types = ProtocolTypes(); | |
| 107 for (ModelTypeSet::Iterator it = protocol_types.First(); it.Good(); | |
| 108 it.Inc()) { | |
| 109 ModelType model_type = it.Get(); | |
| 110 | |
| 111 PermanentItemSpec spec; | |
| 112 spec.tag = ModelTypeToRootTag(model_type); | |
| 113 spec.name = ModelTypeToString(model_type); | |
| 114 spec.parent_tag = kRootParentTag; | |
|
rlarocque
2013/12/18 20:22:01
It seems you're using tags as IDs?
The root node'
pval...(no longer on Chromium)
2014/01/03 23:25:31
Is it only "r" on the client side?
It appears tha
rlarocque
2014/01/04 00:06:24
Looks like you're right. The server refers to is
| |
| 115 spec.sync_type = model_type; | |
| 116 spec.create_by_default = true; | |
| 117 permanent_item_specs_.push_back(spec); | |
| 118 } | |
| 119 | |
| 120 PermanentItemSpec bookmark_bar_spec; | |
| 121 bookmark_bar_spec.tag = "bookmark_bar"; | |
| 122 bookmark_bar_spec.name = "Bookmark Bar"; | |
| 123 bookmark_bar_spec.parent_tag = "google_chrome_bookmarks"; | |
| 124 bookmark_bar_spec.sync_type = BOOKMARKS; | |
| 125 bookmark_bar_spec.create_by_default = true; | |
| 126 permanent_item_specs_.push_back(bookmark_bar_spec); | |
| 127 | |
| 128 PermanentItemSpec other_bookmarks_spec; | |
| 129 other_bookmarks_spec.tag = "other_bookmarks"; | |
| 130 other_bookmarks_spec.name = "Other Bookmarks"; | |
| 131 other_bookmarks_spec.parent_tag = "google_chrome_bookmarks"; | |
| 132 other_bookmarks_spec.sync_type = BOOKMARKS; | |
| 133 other_bookmarks_spec.create_by_default = true; | |
| 134 permanent_item_specs_.push_back(other_bookmarks_spec); | |
| 135 | |
|
rlarocque
2013/12/18 20:22:01
In certain situations, you should create the mobil
albertb
2013/12/18 20:45:30
Specifically, the situation when you need to creat
pval...(no longer on Chromium)
2014/01/03 23:25:31
Thanks; I added a TODO for this.
| |
| 136 return true; | |
| 137 } | |
| 138 | |
| 139 void FakeServer::CreateDefaultPermanentItems( | |
| 140 const std::vector<int>& first_time_type_ids) { | |
| 141 for (size_t i = 0; i < permanent_item_specs_.size(); i++) { | |
|
rlarocque
2013/12/18 20:22:01
Why is the creation of permanent items a two-step
pval...(no longer on Chromium)
2014/01/03 23:25:31
This was a result of following the Python server's
| |
| 142 PermanentItemSpec spec = permanent_item_specs_[i]; | |
| 143 | |
| 144 int spec_id = GetSpecificsFieldNumberFromModelType(spec.sync_type); | |
| 145 bool first_time = std::find(first_time_type_ids.begin(), | |
| 146 first_time_type_ids.end(), spec_id) != first_time_type_ids.end(); | |
| 147 | |
| 148 if (first_time && spec.create_by_default) { | |
| 149 CreatePermanentItem(spec); | |
| 150 } | |
| 151 } | |
| 152 } | |
| 153 | |
| 154 void FakeServer::CreatePermanentItem(const PermanentItemSpec& spec) { | |
| 155 sync_pb::SyncEntity entity; | |
| 156 entity.set_id_string(spec.tag); | |
| 157 entity.set_non_unique_name(spec.name); | |
| 158 entity.set_name(spec.name); | |
| 159 entity.set_server_defined_unique_tag(spec.tag); | |
| 160 entity.set_folder(true); | |
| 161 entity.set_deleted(false); | |
| 162 | |
| 163 if (spec.parent_tag == kRootParentTag) { | |
| 164 entity.set_parent_id_string(kRootParentTag); | |
| 165 } else { | |
| 166 for (size_t i = 0; i < permanent_item_specs_.size(); i++) { | |
|
rlarocque
2013/12/18 20:22:01
nit: You should prefer to use STL iterators rather
pval...(no longer on Chromium)
2014/01/03 23:25:31
Done.
| |
| 167 if (spec.parent_tag == permanent_item_specs_[i].tag) { | |
| 168 entity.set_parent_id_string(permanent_item_specs_[i].tag); | |
|
rlarocque
2013/12/18 20:22:01
This looks like it's redundant. Can't you just ca
pval...(no longer on Chromium)
2014/01/03 23:25:31
Yes. I've made this change in the new version.
| |
| 169 // Use a dummy value here. | |
| 170 entity.set_position_in_parent(1337); | |
|
rlarocque
2013/12/18 20:22:01
I think this should be unset on all items that are
pval...(no longer on Chromium)
2014/01/03 23:25:31
Done.
| |
| 171 } | |
| 172 } | |
| 173 | |
| 174 if (entity.parent_id_string().empty()) { | |
| 175 NOTREACHED() << "The permanent item's parent node was not found."; | |
| 176 } | |
| 177 } | |
| 178 | |
| 179 sync_pb::EntitySpecifics* specifics = entity.mutable_specifics(); | |
| 180 AddDefaultFieldValue(spec.sync_type, specifics); | |
| 181 | |
| 182 SaveEntity(entity); | |
| 183 } | |
| 184 | |
| 185 void FakeServer::SaveEntity(sync_pb::SyncEntity entity) { | |
| 186 version_++; | |
| 187 entity.set_version(version_); | |
| 188 entity.set_sync_timestamp(version_); | |
| 189 | |
| 190 sync_pb::SyncEntity original_entity = entities_[entity.id_string()]; | |
| 191 entity.set_originator_cache_guid(original_entity.originator_cache_guid()); | |
|
albertb
2013/12/18 20:45:30
The client should be setting originator_cache_guid
rlarocque
2013/12/18 21:26:49
Are you sure? I'm pretty sure we're not setting i
albertb
2013/12/18 21:47:30
Ah, I was slightly confused. Looking at the code:
pval...(no longer on Chromium)
2014/01/03 23:25:31
Thanks for the explanation.
I will follow this co
albertb
2014/01/06 17:25:16
That does look correct. The server should preserve
| |
| 192 entity.set_originator_client_item_id( | |
|
albertb
2013/12/18 20:45:30
Same comment about originator_client_item_id.
| |
| 193 original_entity.originator_client_item_id()); | |
| 194 | |
| 195 entities_[entity.id_string()] = entity; | |
| 196 } | |
| 197 | |
| 198 string FakeServer::HandleCommand(string request, int* error_code, | |
| 199 int* response_code) { | |
| 200 DCHECK(initialized_); | |
| 201 sync_pb::ClientToServerMessage message; | |
| 202 DCHECK(message.ParseFromString(request)); | |
| 203 | |
| 204 switch (message.message_contents()) { | |
| 205 case sync_pb::ClientToServerMessage::GET_UPDATES: | |
| 206 *error_code = 0; | |
| 207 *response_code = 200; | |
| 208 return HandleGetUpdatesRequest(message).SerializeAsString(); | |
| 209 case sync_pb::ClientToServerMessage::COMMIT: | |
| 210 *error_code = 0; | |
| 211 *response_code = 200; | |
| 212 return HandleCommitRequest(message).SerializeAsString(); | |
| 213 default: | |
| 214 *error_code = -1; | |
| 215 *response_code = 400; | |
| 216 return ""; | |
| 217 } | |
| 218 } | |
| 219 | |
| 220 bool SyncEntityVersionComparator(const sync_pb::SyncEntity& first, | |
| 221 const sync_pb::SyncEntity& second) { | |
| 222 return first.version() < second.version(); | |
| 223 } | |
| 224 | |
| 225 sync_pb::ClientToServerResponse FakeServer::HandleGetUpdatesRequest( | |
| 226 const sync_pb::ClientToServerMessage& message) { | |
| 227 sync_pb::ClientToServerResponse response; | |
| 228 response.set_error_code(sync_pb::SyncEnums::SUCCESS); | |
| 229 response.set_store_birthday(birthday_); | |
| 230 | |
| 231 sync_pb::GetUpdatesResponse* get_updates_response = | |
| 232 response.mutable_get_updates(); | |
| 233 get_updates_response->set_changes_remaining(0); | |
|
albertb
2013/12/18 20:45:30
Will all SyncEntities always fit in a single respo
pval...(no longer on Chromium)
2014/01/03 23:25:31
I've added a TODO for this.
| |
| 234 | |
| 235 UpdateSieve sieve(message.get_updates()); | |
| 236 CreateDefaultPermanentItems(sieve.GetFirstTimeTypes()); | |
| 237 | |
| 238 int64 min_version = sieve.GetMinVersion(); | |
| 239 | |
| 240 // use std::transform instead? | |
| 241 std::vector<sync_pb::SyncEntity> filtered_entities; | |
| 242 for (EntityMap::iterator it = entities_.begin(); it != entities_.end(); | |
| 243 ++it) { | |
| 244 sync_pb::SyncEntity entity = it->second; | |
| 245 if (entity.version() > min_version) { | |
| 246 filtered_entities.push_back(entity); | |
| 247 } | |
| 248 } | |
| 249 | |
| 250 std::sort(filtered_entities.begin(), filtered_entities.end(), | |
| 251 SyncEntityVersionComparator); | |
| 252 | |
| 253 bool sending_nigori = false; | |
| 254 for (size_t i = 0; i < filtered_entities.size(); i++) { | |
| 255 if (sieve.ClientWantsItem(filtered_entities[i])) { | |
| 256 sync_pb::SyncEntity* entity = get_updates_response->add_entries(); | |
| 257 entity->CopyFrom(filtered_entities[i]); | |
| 258 | |
| 259 if (entity->name() == "Nigori") | |
| 260 sending_nigori = true; | |
| 261 } | |
| 262 } | |
| 263 | |
| 264 if (sending_nigori || message.get_updates().need_encryption_key()) { | |
|
albertb
2013/12/18 20:45:30
Note that sending_nigori does not necessarily impl
pval...(no longer on Chromium)
2014/01/03 23:25:31
Thanks, I added some logic here for this.
| |
| 265 for (size_t i = 0; i < keystore_keys_.size(); i++) { | |
| 266 get_updates_response->add_encryption_keys(keystore_keys_[i]); | |
| 267 } | |
| 268 } | |
| 269 | |
| 270 int new_version = filtered_entities.empty() ? | |
| 271 0 : filtered_entities.back().version(); | |
| 272 | |
| 273 sieve.UpdateProgressMarkers(new_version, get_updates_response); | |
| 274 | |
| 275 return response; | |
| 276 } | |
| 277 | |
| 278 sync_pb::SyncEntity FakeServer::CommitEntity(sync_pb::SyncEntity entity, | |
| 279 string guid) { | |
| 280 // TODO(pvalenzuela): Implement this. Right now this method cheats and | |
| 281 // doesn't actually commit. | |
| 282 return entity; | |
| 283 } | |
| 284 | |
| 285 sync_pb::ClientToServerResponse FakeServer::HandleCommitRequest( | |
| 286 const sync_pb::ClientToServerMessage& message) { | |
| 287 sync_pb::ClientToServerResponse response; | |
| 288 response.set_error_code(sync_pb::SyncEnums::SUCCESS); | |
| 289 response.set_store_birthday(birthday_); | |
| 290 | |
| 291 sync_pb::CommitMessage commit = message.commit(); | |
| 292 string guid = commit.cache_guid(); | |
| 293 | |
| 294 sync_pb::CommitResponse* commit_response = response.mutable_commit(); | |
| 295 | |
| 296 ::google::protobuf::RepeatedPtrField<sync_pb::SyncEntity>::const_iterator it; | |
| 297 for (it = commit.entries().begin(); it != commit.entries().end(); ++it) { | |
| 298 sync_pb::CommitResponse_EntryResponse* entry_response = | |
| 299 commit_response->add_entryresponse(); | |
| 300 | |
| 301 sync_pb::SyncEntity server_entity = CommitEntity(*it, guid); | |
| 302 | |
| 303 entry_response->set_id_string(server_entity.id_string()); | |
| 304 entry_response->set_response_type(sync_pb::CommitResponse::SUCCESS); | |
| 305 entry_response->set_version(it->version() + 1); | |
| 306 } | |
| 307 | |
| 308 return response; | |
| 309 } | |
| 310 | |
| 311 } // namespace syncer | |
| OLD | NEW |