text: // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  //
  // Mock ServerConnectionManager class for use in client unit tests.
  
  #ifndef SYNC_TEST_ENGINE_MOCK_CONNECTION_MANAGER_H_
  #define SYNC_TEST_ENGINE_MOCK_CONNECTION_MANAGER_H_
  #pragma once
  
  #include <bitset>
  #include <list>
  #include <string>
  #include <vector>
  
  #include "base/callback.h"
  #include "base/compiler_specific.h"
  #include "base/memory/scoped_vector.h"
  #include "sync/engine/net/server_connection_manager.h"
  #include "sync/syncable/model_type.h"
  #include "sync/syncable/model_type_payload_map.h"
  #include "sync/protocol/sync.pb.h"
  
  class MockConnectionManager : public browser_sync::ServerConnectionManager {
   public:
    class MidCommitObserver {
     public:
      virtual void Observe() = 0;
  
     protected:
      virtual ~MidCommitObserver() {}
    };
  
    explicit MockConnectionManager(syncable::Directory*);
    virtual ~MockConnectionManager();
  
    // Overridden ServerConnectionManager functions.
    virtual bool PostBufferToPath(
        PostBufferParams*,
        const std::string& path,
        const std::string& auth_token,
        browser_sync::ScopedServerStatusWatcher* watcher) OVERRIDE;
  
    // Control of commit response.
    // NOTE: Commit callback is invoked only once then reset.
    void SetMidCommitCallback(const base::Closure& callback);
    void SetMidCommitObserver(MidCommitObserver* observer);
  
    // Set this if you want commit to perform commit time rename. Will request
    // that the client renames all commited entries, prepending this string.
    void SetCommitTimeRename(std::string prepend);
  
    // Generic versions of AddUpdate functions. Tests using these function should
    // compile for both the int64 and string id based versions of the server.
    // The SyncEntity returned is only valid until the Sync is completed
    // (e.g. with SyncShare.) It allows to add further entity properties before
    // sync, using SetLastXXX() methods and/or GetMutableLastUpdate().
    sync_pb::SyncEntity* AddUpdateDirectory(syncable::Id id,
                                            syncable::Id parent_id,
                                            std::string name,
                                            int64 version,
                                            int64 sync_ts);
    sync_pb::SyncEntity* AddUpdateBookmark(syncable::Id id,
                                           syncable::Id parent_id,
                                           std::string name,
                                           int64 version,
                                           int64 sync_ts);
    // Versions of the AddUpdate functions that accept integer IDs.
    sync_pb::SyncEntity* AddUpdateDirectory(int id,
                                            int parent_id,
                                            std::string name,
                                            int64 version,
                                            int64 sync_ts);
    sync_pb::SyncEntity* AddUpdateBookmark(int id,
                                           int parent_id,
                                           std::string name,
                                           int64 version,
                                           int64 sync_ts);
    // New protocol versions of the AddUpdate functions.
    sync_pb::SyncEntity* AddUpdateDirectory(std::string id,
                                            std::string parent_id,
                                            std::string name,
                                            int64 version,
                                            int64 sync_ts);
    sync_pb::SyncEntity* AddUpdateBookmark(std::string id,
                                           std::string parent_id,
                                           std::string name,
                                           int64 version,
                                           int64 sync_ts);
    // Versions of the AddUpdate function that accept specifics.
    sync_pb::SyncEntity* AddUpdateSpecifics(int id, int parent_id,
        std::string name,int64 version, int64 sync_ts, bool is_dir,
        int64 position, const sync_pb::EntitySpecifics& specifics);
    sync_pb::SyncEntity* SetNigori(int id, int64 version, int64 sync_ts,
        const sync_pb::EntitySpecifics& specifics);
  
    // Find the last commit sent by the client, and replay it for the next get
    // updates command.  This can be used to simulate the GetUpdates that happens
    // immediately after a successful commit.
    sync_pb::SyncEntity* AddUpdateFromLastCommit();
  
    // Add a deleted item.  Deletion records typically contain no
    // additional information beyond the deletion, and no specifics.
    // The server may send the originator fields.
    void AddUpdateTombstone(const syncable::Id& id);
  
    void SetLastUpdateDeleted();
    void SetLastUpdateServerTag(const std::string& tag);
    void SetLastUpdateClientTag(const std::string& tag);
    void SetLastUpdateOriginatorFields(const std::string& client_id,
                                       const std::string& entry_id);
    void SetLastUpdatePosition(int64 position_in_parent);
    void SetNewTimestamp(int ts);
    void SetChangesRemaining(int64 count);
  
    // Add a new batch of updates after the current one.  Allows multiple
    // GetUpdates responses to be buffered up, since the syncer may
    // issue multiple requests during a sync cycle.
    void NextUpdateBatch();
  
    void FailNextPostBufferToPathCall() { countdown_to_postbuffer_fail_ = 1; }
    void FailNthPostBufferToPathCall(int n) { countdown_to_postbuffer_fail_ = n; }
  
    void SetClearUserDataResponseStatus(sync_pb::SyncEnums::ErrorType errortype);
  
    void FailNonPeriodicGetUpdates() { fail_non_periodic_get_updates_ = true; }
  
    // Simple inspectors.
    bool client_stuck() const { return client_stuck_; }
  
    sync_pb::ClientCommand* GetNextClientCommand();
  
    const std::vector<syncable::Id>& committed_ids() const {
      return committed_ids_;
    }
    const std::vector<sync_pb::CommitMessage*>& commit_messages() const {
      return commit_messages_.get();
    }
    const std::vector<sync_pb::CommitResponse*>& commit_responses() const {
      return commit_responses_.get();
    }
    // Retrieve the last sent commit message.
    const sync_pb::CommitMessage& last_sent_commit() const;
  
    // Retrieve the last returned commit response.
    const sync_pb::CommitResponse& last_commit_response() const;
  
    // Retrieve the last request submitted to the server (regardless of type).
    const sync_pb::ClientToServerMessage& last_request() const {
      return last_request_;
    }
  
    void set_conflict_all_commits(bool value) {
      conflict_all_commits_ = value;
    }
    void set_next_new_id(int value) {
      next_new_id_ = value;
    }
    void set_conflict_n_commits(int value) {
      conflict_n_commits_ = value;
    }
  
    void set_use_legacy_bookmarks_protocol(bool value) {
      use_legacy_bookmarks_protocol_ = value;
    }
  
    void set_store_birthday(std::string new_birthday) {
      // Multiple threads can set store_birthday_ in our tests, need to lock it to
      // ensure atomic read/writes and avoid race conditions.
      base::AutoLock lock(store_birthday_lock_);
      store_birthday_ = new_birthday;
    }
  
    // Retrieve the number of GetUpdates requests that the mock server has
    // seen since the last time this function was called.  Can be used to
    // verify that a GetUpdates actually did or did not happen after running
    // the syncer.
    int GetAndClearNumGetUpdatesRequests() {
      int result = num_get_updates_requests_;
      num_get_updates_requests_ = 0;
      return result;
    }
  
    // Expect that GetUpdates will request exactly the types indicated in
    // the bitset.
    void ExpectGetUpdatesRequestTypes(
        syncable::ModelTypeSet expected_filter) {
      expected_filter_ = expected_filter;
    }
  
    void ExpectGetUpdatesRequestPayloads(
        const syncable::ModelTypePayloadMap& payloads) {
      expected_payloads_ = payloads;
    }
  
    void SetServerReachable();
  
    void SetServerNotReachable();
  
    // Updates our internal state as if we had attempted a connection.  Does not
    // send notifications as a real connection attempt would.  This is useful in
    // cases where we're mocking out most of the code that performs network
    // requests.
    void UpdateConnectionStatus();
  
    // Return by copy to be thread-safe.
    const std::string store_birthday() {
      base::AutoLock lock(store_birthday_lock_);
      return store_birthday_;
    }
  
    // Explicitly indicate that we will not be fetching some updates.
    void ClearUpdatesQueue() {
      update_queue_.clear();
    }
  
    // Locate the most recent update message for purpose of alteration.
    sync_pb::SyncEntity* GetMutableLastUpdate();
  
   private:
    sync_pb::SyncEntity* AddUpdateFull(syncable::Id id, syncable::Id parentid,
                                       std::string name, int64 version,
                                       int64 sync_ts,
                                       bool is_dir);
    sync_pb::SyncEntity* AddUpdateFull(std::string id,
                                       std::string parentid, std::string name,
                                       int64 version, int64 sync_ts,
                                       bool is_dir);
    sync_pb::SyncEntity* AddUpdateMeta(std::string id, std::string parentid,
                                      std::string name, int64 version,
                                      int64 sync_ts);
  
    // Functions to handle the various types of server request.
    void ProcessGetUpdates(sync_pb::ClientToServerMessage* csm,
                           sync_pb::ClientToServerResponse* response);
    void ProcessCommit(sync_pb::ClientToServerMessage* csm,
                       sync_pb::ClientToServerResponse* response_buffer);
    void ProcessClearData(sync_pb::ClientToServerMessage* csm,
                          sync_pb::ClientToServerResponse* response);
    void AddDefaultBookmarkData(sync_pb::SyncEntity* entity, bool is_folder);
  
    // Determine if one entry in a commit should be rejected with a conflict.
    bool ShouldConflictThisCommit();
  
    // Generate a numeric position_in_parent value.  We use a global counter
    // that only decreases; this simulates new objects always being added to the
    // front of the ordering.
    int64 GeneratePositionInParent() {
      return next_position_in_parent_--;
    }
  
    // Get a mutable update response which will eventually be returned to the
    // client.
    sync_pb::GetUpdatesResponse* GetUpdateResponse();
    void ApplyToken();
  
    // Determine whether an progress marker array (like that sent in
    // GetUpdates.from_progress_marker) indicates that a particular ModelType
    // should be included.
    bool IsModelTypePresentInSpecifics(
        const google::protobuf::RepeatedPtrField<
            sync_pb::DataTypeProgressMarker>& filter,
        syncable::ModelType value);
  
    sync_pb::DataTypeProgressMarker const* GetProgressMarkerForType(
        const google::protobuf::RepeatedPtrField<
            sync_pb::DataTypeProgressMarker>& filter,
        syncable::ModelType value);
  
    // When false, we pretend to have network connectivity issues.
    bool server_reachable_;
  
    // All IDs that have been committed.
    std::vector<syncable::Id> committed_ids_;
  
    // Control of when/if we return conflicts.
    bool conflict_all_commits_;
    int conflict_n_commits_;
  
    // Commit messages we've sent, and responses we've returned.
    ScopedVector<sync_pb::CommitMessage> commit_messages_;
    ScopedVector<sync_pb::CommitResponse> commit_responses_;
  
    // The next id the mock will return to a commit.
    int next_new_id_;
  
    // The store birthday we send to the client.
    std::string store_birthday_;
    base::Lock store_birthday_lock_;
    bool store_birthday_sent_;
    bool client_stuck_;
    std::string commit_time_rename_prepended_string_;
  
    // On each PostBufferToPath() call, we decrement this counter.  The call fails
    // iff we hit zero at that call.
    int countdown_to_postbuffer_fail_;
  
    // Our directory.  Used only to ensure that we are not holding the transaction
    // lock when performing network I/O.  Can be NULL if the test author is
    // confident this can't happen.
    syncable::Directory* directory_;
  
    // The updates we'll return to the next request.
    std::list<sync_pb::GetUpdatesResponse> update_queue_;
    base::Closure mid_commit_callback_;
    MidCommitObserver* mid_commit_observer_;
  
    // The clear data response we'll return in the next response
    sync_pb::SyncEnums::ErrorType clear_user_data_response_errortype_;
  
    // The AUTHENTICATE response we'll return for auth requests.
    sync_pb::AuthenticateResponse auth_response_;
    // What we use to determine if we should return SUCCESS or BAD_AUTH_TOKEN.
    std::string valid_auth_token_;
  
    // Whether we are faking a server mandating clients to throttle requests.
    // Protected by |response_code_override_lock_|.
    bool throttling_;
  
    // Whether we are failing all requests by returning
    // ClientToServerResponse::AUTH_INVALID.
    // Protected by |response_code_override_lock_|.
    bool fail_with_auth_invalid_;
  
    base::Lock response_code_override_lock_;
  
    // True if we are only accepting GetUpdatesCallerInfo::PERIODIC requests.
    bool fail_non_periodic_get_updates_;
  
    scoped_ptr<sync_pb::ClientCommand> client_command_;
  
    // The next value to use for the position_in_parent property.
    int64 next_position_in_parent_;
  
    // The default is to use the newer sync_pb::BookmarkSpecifics-style protocol.
    // If this option is set to true, then the MockConnectionManager will
    // use the older sync_pb::SyncEntity_BookmarkData-style protocol.
    bool use_legacy_bookmarks_protocol_;
  
    syncable::ModelTypeSet expected_filter_;
  
    syncable::ModelTypePayloadMap expected_payloads_;
  
    int num_get_updates_requests_;
  
    std::string next_token_;
  
    sync_pb::ClientToServerMessage last_request_;
  
    DISALLOW_COPY_AND_ASSIGN(MockConnectionManager);
  };
  
  #endif  // SYNC_TEST_ENGINE_MOCK_CONNECTION_MANAGER_H_
  