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#ifndef SYNC_TEST_ENGINE_SYNCER_COMMAND_TEST_H_
6#define SYNC_TEST_ENGINE_SYNCER_COMMAND_TEST_H_
7
8#include <algorithm>
9#include <string>
10#include <vector>
11
12#include "base/compiler_specific.h"
13#include "base/memory/ref_counted.h"
14#include "base/message_loop/message_loop.h"
15#include "sync/engine/model_changing_syncer_command.h"
16#include "sync/engine/traffic_recorder.h"
17#include "sync/internal_api/public/engine/model_safe_worker.h"
18#include "sync/sessions/debug_info_getter.h"
19#include "sync/sessions/sync_session.h"
20#include "sync/sessions/sync_session_context.h"
21#include "sync/syncable/directory.h"
22#include "sync/test/engine/fake_model_worker.h"
23#include "sync/test/engine/mock_connection_manager.h"
24#include "sync/test/engine/test_directory_setter_upper.h"
25#include "sync/util/extensions_activity.h"
26#include "testing/gmock/include/gmock/gmock.h"
27#include "testing/gtest/include/gtest/gtest.h"
28
29using ::testing::NiceMock;
30
31namespace syncer {
32
33class MockDebugInfoGetter : public sessions::DebugInfoGetter {
34 public:
35  MockDebugInfoGetter();
36  virtual ~MockDebugInfoGetter();
37  MOCK_METHOD1(GetAndClearDebugInfo, void(sync_pb::DebugInfo* debug_info));
38};
39
40// A test fixture that simplifies writing unit tests for individual
41// SyncerCommands, providing convenient access to a test directory
42// and a syncer session.
43class SyncerCommandTestBase : public testing::Test,
44                              public sessions::SyncSession::Delegate {
45 public:
46  // SyncSession::Delegate implementation.
47  virtual void OnThrottled(
48      const base::TimeDelta& throttle_duration) OVERRIDE {
49    FAIL() << "Should not get silenced.";
50  }
51  virtual void OnTypesThrottled(
52      ModelTypeSet types,
53      const base::TimeDelta& throttle_duration) OVERRIDE {
54    FAIL() << "Should not get silenced.";
55  }
56  virtual bool IsCurrentlyThrottled() OVERRIDE {
57    return false;
58  }
59  virtual void OnReceivedLongPollIntervalUpdate(
60      const base::TimeDelta& new_interval) OVERRIDE {
61    FAIL() << "Should not get poll interval update.";
62  }
63  virtual void OnReceivedShortPollIntervalUpdate(
64      const base::TimeDelta& new_interval) OVERRIDE {
65    FAIL() << "Should not get poll interval update.";
66  }
67  virtual void OnReceivedSessionsCommitDelay(
68      const base::TimeDelta& new_delay) OVERRIDE {
69    FAIL() << "Should not get sessions commit delay.";
70  }
71  virtual void OnReceivedClientInvalidationHintBufferSize(int size) OVERRIDE {
72    FAIL() << "Should not get hint buffer size.";
73  }
74  virtual void OnShouldStopSyncingPermanently() OVERRIDE {
75    FAIL() << "Shouldn't be called.";
76  }
77  virtual void OnSyncProtocolError(
78      const sessions::SyncSessionSnapshot& session) OVERRIDE {
79    return;
80  }
81
82  std::vector<ModelSafeWorker*> GetWorkers() {
83    std::vector<ModelSafeWorker*> workers;
84    std::vector<scoped_refptr<ModelSafeWorker> >::iterator it;
85    for (it = workers_.begin(); it != workers_.end(); ++it)
86      workers.push_back(it->get());
87    return workers;
88  }
89  void GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) {
90    ModelSafeRoutingInfo copy(routing_info_);
91    out->swap(copy);
92  }
93
94 protected:
95  SyncerCommandTestBase();
96
97  virtual ~SyncerCommandTestBase();
98  virtual void SetUp();
99  virtual void TearDown();
100
101  sessions::SyncSessionContext* context() const { return context_.get(); }
102  sessions::SyncSession::Delegate* delegate() { return this; }
103
104  // Lazily create a session requesting all datatypes with no state.
105  sessions::SyncSession* session() {
106    if (!session_.get())
107      session_.reset(sessions::SyncSession::Build(context(), delegate()));
108    return session_.get();
109  }
110
111  void ClearSession() {
112    session_.reset();
113  }
114
115  void ResetContext() {
116    context_.reset(new sessions::SyncSessionContext(
117            mock_server_.get(), directory(),
118            GetWorkers(), extensions_activity_.get(),
119            std::vector<SyncEngineEventListener*>(),
120            &mock_debug_info_getter_,
121            &traffic_recorder_,
122            true,  // enable keystore encryption
123            false,  // force enable pre-commit GU avoidance experiment
124            "fake_invalidator_client_id"));
125    context_->set_routing_info(routing_info_);
126    context_->set_account_name(directory()->name());
127    ClearSession();
128  }
129
130  // Install a MockServerConnection.  Resets the context.  By default,
131  // the context does not have a MockServerConnection attached.
132  void ConfigureMockServerConnection() {
133    mock_server_.reset(new MockConnectionManager(directory()));
134    ResetContext();
135  }
136
137  virtual syncable::Directory* directory() = 0;
138
139  std::vector<scoped_refptr<ModelSafeWorker> >* workers() {
140    return &workers_;
141  }
142
143  const ModelSafeRoutingInfo& routing_info() { return routing_info_; }
144  ModelSafeRoutingInfo* mutable_routing_info() { return &routing_info_; }
145
146  MockConnectionManager* mock_server() {
147    return mock_server_.get();
148  }
149
150  MockDebugInfoGetter* mock_debug_info_getter() {
151    return &mock_debug_info_getter_;
152  }
153
154  // Helper functions to check command.GetGroupsToChange().
155
156  void ExpectNoGroupsToChange(const ModelChangingSyncerCommand& command) {
157    EXPECT_TRUE(command.GetGroupsToChangeForTest(*session()).empty());
158  }
159
160  void ExpectGroupToChange(
161      const ModelChangingSyncerCommand& command, ModelSafeGroup group) {
162    std::set<ModelSafeGroup> expected_groups_to_change;
163    expected_groups_to_change.insert(group);
164    EXPECT_EQ(expected_groups_to_change,
165              command.GetGroupsToChangeForTest(*session()));
166  }
167
168  void ExpectGroupsToChange(
169      const ModelChangingSyncerCommand& command,
170      ModelSafeGroup group1, ModelSafeGroup group2) {
171    std::set<ModelSafeGroup> expected_groups_to_change;
172    expected_groups_to_change.insert(group1);
173    expected_groups_to_change.insert(group2);
174    EXPECT_EQ(expected_groups_to_change,
175              command.GetGroupsToChangeForTest(*session()));
176  }
177
178  void ExpectGroupsToChange(
179      const ModelChangingSyncerCommand& command,
180      ModelSafeGroup group1, ModelSafeGroup group2, ModelSafeGroup group3) {
181    std::set<ModelSafeGroup> expected_groups_to_change;
182    expected_groups_to_change.insert(group1);
183    expected_groups_to_change.insert(group2);
184    expected_groups_to_change.insert(group3);
185    EXPECT_EQ(expected_groups_to_change,
186              command.GetGroupsToChangeForTest(*session()));
187  }
188
189 private:
190  base::MessageLoop message_loop_;
191  scoped_ptr<sessions::SyncSessionContext> context_;
192  scoped_ptr<MockConnectionManager> mock_server_;
193  scoped_ptr<sessions::SyncSession> session_;
194  std::vector<scoped_refptr<ModelSafeWorker> > workers_;
195  ModelSafeRoutingInfo routing_info_;
196  NiceMock<MockDebugInfoGetter> mock_debug_info_getter_;
197  scoped_refptr<ExtensionsActivity> extensions_activity_;
198  TrafficRecorder traffic_recorder_;
199  DISALLOW_COPY_AND_ASSIGN(SyncerCommandTestBase);
200};
201
202class SyncerCommandTest : public SyncerCommandTestBase {
203 public:
204  virtual void SetUp() OVERRIDE;
205  virtual void TearDown() OVERRIDE;
206  virtual syncable::Directory* directory() OVERRIDE;
207
208 private:
209  TestDirectorySetterUpper dir_maker_;
210};
211
212}  // namespace syncer
213
214#endif  // SYNC_TEST_ENGINE_SYNCER_COMMAND_TEST_H_
215