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/test/engine/mock_model_type_sync_proxy.h"
6
7#include "base/bind.h"
8
9namespace syncer {
10
11MockModelTypeSyncProxy::MockModelTypeSyncProxy() : is_synchronous_(true) {
12}
13
14MockModelTypeSyncProxy::~MockModelTypeSyncProxy() {
15}
16
17void MockModelTypeSyncProxy::OnCommitCompleted(
18    const DataTypeState& type_state,
19    const CommitResponseDataList& response_list) {
20  base::Closure task =
21      base::Bind(&MockModelTypeSyncProxy::OnCommitCompletedImpl,
22                 base::Unretained(this),
23                 type_state,
24                 response_list);
25  pending_tasks_.push_back(task);
26  if (is_synchronous_)
27    RunQueuedTasks();
28}
29
30void MockModelTypeSyncProxy::OnUpdateReceived(
31    const DataTypeState& type_state,
32    const UpdateResponseDataList& response_list,
33    const UpdateResponseDataList& pending_updates) {
34  base::Closure task = base::Bind(&MockModelTypeSyncProxy::OnUpdateReceivedImpl,
35                                  base::Unretained(this),
36                                  type_state,
37                                  response_list,
38                                  pending_updates);
39  pending_tasks_.push_back(task);
40  if (is_synchronous_)
41    RunQueuedTasks();
42}
43
44void MockModelTypeSyncProxy::SetSynchronousExecution(bool is_synchronous) {
45  is_synchronous_ = is_synchronous;
46}
47
48void MockModelTypeSyncProxy::RunQueuedTasks() {
49  for (std::vector<base::Closure>::iterator it = pending_tasks_.begin();
50       it != pending_tasks_.end();
51       ++it) {
52    it->Run();
53  }
54  pending_tasks_.clear();
55}
56
57CommitRequestData MockModelTypeSyncProxy::CommitRequest(
58    const std::string& tag_hash,
59    const sync_pb::EntitySpecifics& specifics) {
60  const int64 base_version = GetBaseVersion(tag_hash);
61
62  CommitRequestData data;
63
64  if (HasServerAssignedId(tag_hash)) {
65    data.id = GetServerAssignedId(tag_hash);
66  }
67
68  data.client_tag_hash = tag_hash;
69  data.sequence_number = GetNextSequenceNumber(tag_hash);
70  data.deleted = false;
71  data.specifics = specifics;
72  data.base_version = base_version;
73
74  // These fields are not really used for much, but we set them anyway
75  // to make this item look more realistic.
76  data.ctime = base::Time::UnixEpoch() + base::TimeDelta::FromDays(1);
77  data.mtime = data.ctime + base::TimeDelta::FromSeconds(base_version);
78  data.non_unique_name = "Name: " + tag_hash;
79
80  return data;
81}
82
83CommitRequestData MockModelTypeSyncProxy::DeleteRequest(
84    const std::string& tag_hash) {
85  const int64 base_version = GetBaseVersion(tag_hash);
86  CommitRequestData data;
87
88  if (HasServerAssignedId(tag_hash)) {
89    data.id = GetServerAssignedId(tag_hash);
90  }
91
92  data.client_tag_hash = tag_hash;
93  data.sequence_number = GetNextSequenceNumber(tag_hash);
94  data.base_version = base_version;
95  data.mtime = data.ctime + base::TimeDelta::FromSeconds(base_version);
96  data.deleted = true;
97
98  // These fields have little or no effect on behavior.  We set them anyway to
99  // make the test more realistic.
100  data.ctime = base::Time::UnixEpoch() + base::TimeDelta::FromDays(1);
101  data.non_unique_name = "Name deleted";
102
103  return data;
104}
105
106size_t MockModelTypeSyncProxy::GetNumUpdateResponses() const {
107  return received_update_responses_.size();
108}
109
110UpdateResponseDataList MockModelTypeSyncProxy::GetNthUpdateResponse(
111    size_t n) const {
112  DCHECK_LT(n, GetNumUpdateResponses());
113  return received_update_responses_[n];
114}
115
116UpdateResponseDataList MockModelTypeSyncProxy::GetNthPendingUpdates(
117    size_t n) const {
118  DCHECK_LT(n, GetNumUpdateResponses());
119  return received_pending_updates_[n];
120}
121
122DataTypeState MockModelTypeSyncProxy::GetNthTypeStateReceivedInUpdateResponse(
123    size_t n) const {
124  DCHECK_LT(n, GetNumUpdateResponses());
125  return type_states_received_on_update_[n];
126}
127
128size_t MockModelTypeSyncProxy::GetNumCommitResponses() const {
129  return received_commit_responses_.size();
130}
131
132CommitResponseDataList MockModelTypeSyncProxy::GetNthCommitResponse(
133    size_t n) const {
134  DCHECK_LT(n, GetNumCommitResponses());
135  return received_commit_responses_[n];
136}
137
138DataTypeState MockModelTypeSyncProxy::GetNthTypeStateReceivedInCommitResponse(
139    size_t n) const {
140  DCHECK_LT(n, GetNumCommitResponses());
141  return type_states_received_on_commit_[n];
142}
143
144bool MockModelTypeSyncProxy::HasUpdateResponse(
145    const std::string& tag_hash) const {
146  std::map<const std::string, UpdateResponseData>::const_iterator it =
147      update_response_items_.find(tag_hash);
148  return it != update_response_items_.end();
149}
150
151UpdateResponseData MockModelTypeSyncProxy::GetUpdateResponse(
152    const std::string& tag_hash) const {
153  DCHECK(HasUpdateResponse(tag_hash));
154  std::map<const std::string, UpdateResponseData>::const_iterator it =
155      update_response_items_.find(tag_hash);
156  return it->second;
157}
158
159bool MockModelTypeSyncProxy::HasCommitResponse(
160    const std::string& tag_hash) const {
161  std::map<const std::string, CommitResponseData>::const_iterator it =
162      commit_response_items_.find(tag_hash);
163  return it != commit_response_items_.end();
164}
165
166CommitResponseData MockModelTypeSyncProxy::GetCommitResponse(
167    const std::string& tag_hash) const {
168  DCHECK(HasCommitResponse(tag_hash));
169  std::map<const std::string, CommitResponseData>::const_iterator it =
170      commit_response_items_.find(tag_hash);
171  return it->second;
172}
173
174void MockModelTypeSyncProxy::OnCommitCompletedImpl(
175    const DataTypeState& type_state,
176    const CommitResponseDataList& response_list) {
177  received_commit_responses_.push_back(response_list);
178  type_states_received_on_commit_.push_back(type_state);
179  for (CommitResponseDataList::const_iterator it = response_list.begin();
180       it != response_list.end();
181       ++it) {
182    commit_response_items_.insert(std::make_pair(it->client_tag_hash, *it));
183
184    // Server wins.  Set the model's base version.
185    SetBaseVersion(it->client_tag_hash, it->response_version);
186    SetServerAssignedId(it->client_tag_hash, it->id);
187  }
188}
189
190void MockModelTypeSyncProxy::OnUpdateReceivedImpl(
191    const DataTypeState& type_state,
192    const UpdateResponseDataList& response_list,
193    const UpdateResponseDataList& pending_updates) {
194  received_update_responses_.push_back(response_list);
195  received_pending_updates_.push_back(pending_updates);
196  type_states_received_on_update_.push_back(type_state);
197  for (UpdateResponseDataList::const_iterator it = response_list.begin();
198       it != response_list.end();
199       ++it) {
200    update_response_items_.insert(std::make_pair(it->client_tag_hash, *it));
201
202    // Server wins.  Set the model's base version.
203    SetBaseVersion(it->client_tag_hash, it->response_version);
204    SetServerAssignedId(it->client_tag_hash, it->id);
205  }
206}
207
208// Fetches the sequence number as of the most recent update request.
209int64 MockModelTypeSyncProxy::GetCurrentSequenceNumber(
210    const std::string& tag_hash) const {
211  std::map<const std::string, int64>::const_iterator it =
212      sequence_numbers_.find(tag_hash);
213  if (it == sequence_numbers_.end()) {
214    return 0;
215  } else {
216    return it->second;
217  }
218}
219
220// The model thread should be sending us items with strictly increasing
221// sequence numbers.  Here's where we emulate that behavior.
222int64 MockModelTypeSyncProxy::GetNextSequenceNumber(
223    const std::string& tag_hash) {
224  int64 sequence_number = GetCurrentSequenceNumber(tag_hash);
225  sequence_number++;
226  sequence_numbers_[tag_hash] = sequence_number;
227  return sequence_number;
228}
229
230int64 MockModelTypeSyncProxy::GetBaseVersion(
231    const std::string& tag_hash) const {
232  std::map<const std::string, int64>::const_iterator it =
233      base_versions_.find(tag_hash);
234  if (it == base_versions_.end()) {
235    return kUncommittedVersion;
236  } else {
237    return it->second;
238  }
239}
240
241void MockModelTypeSyncProxy::SetBaseVersion(const std::string& tag_hash,
242                                            int64 version) {
243  base_versions_[tag_hash] = version;
244}
245
246bool MockModelTypeSyncProxy::HasServerAssignedId(
247    const std::string& tag_hash) const {
248  return assigned_ids_.find(tag_hash) != assigned_ids_.end();
249}
250
251const std::string& MockModelTypeSyncProxy::GetServerAssignedId(
252    const std::string& tag_hash) const {
253  DCHECK(HasServerAssignedId(tag_hash));
254  return assigned_ids_.find(tag_hash)->second;
255}
256
257void MockModelTypeSyncProxy::SetServerAssignedId(const std::string& tag_hash,
258                                                 const std::string& id) {
259  assigned_ids_[tag_hash] = id;
260}
261
262}  // namespace syncer
263