1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/sync/test/integration/quiesce_status_change_checker.h"
#include <stddef.h>
#include "base/format_macros.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/sync/test/integration/updated_progress_marker_checker.h"
#include "components/sync/engine/cycle/sync_cycle_snapshot.h"
#include "components/sync/protocol/data_type_progress_marker.pb.h"
#include "components/sync/service/sync_service_impl.h"
#include "components/sync/test/fake_server.h"
namespace {
// Compares two serialized progress markers for equivalence to determine client
// side progress. Some aspects of the progress markers like
// GarbageCollectionDirectives are irrelevant for this, as they can vary between
// requests -- for example a version_watermark could be based on request time.
bool AreProgressMarkersEquivalent(const std::string& serialized1,
const std::string& serialized2) {
sync_pb::DataTypeProgressMarker marker1;
sync_pb::DataTypeProgressMarker marker2;
CHECK(marker1.ParseFromString(serialized1));
CHECK(marker2.ParseFromString(serialized2));
DCHECK(marker1.data_type_id() == marker2.data_type_id());
DCHECK(!marker1.has_gc_directive());
DCHECK(!marker2.has_gc_directive());
if (syncer::GetDataTypeFromSpecificsFieldNumber(marker1.data_type_id()) ==
syncer::AUTOFILL_WALLET_DATA ||
syncer::GetDataTypeFromSpecificsFieldNumber(marker1.data_type_id()) ==
syncer::AUTOFILL_WALLET_OFFER ||
syncer::GetDataTypeFromSpecificsFieldNumber(marker1.data_type_id()) ==
syncer::AUTOFILL_VALUABLE) {
return fake_server::AreFullUpdateTypeDataProgressMarkersEquivalent(marker1,
marker2);
}
return marker1.SerializeAsString() == marker2.SerializeAsString();
}
// Returns true if these services have matching progress markers.
bool ProgressMarkersMatch(const syncer::SyncServiceImpl* service1,
const syncer::SyncServiceImpl* service2,
std::ostream* os) {
// GetActiveDataTypes() is always empty during configuration, so progress
// markers cannot be compared.
if (service1->GetTransportState() !=
syncer::SyncService::TransportState::ACTIVE ||
service2->GetTransportState() !=
syncer::SyncService::TransportState::ACTIVE) {
*os << "Transport state differs";
return false;
}
const syncer::DataTypeSet common_types = Intersection(
service1->GetActiveDataTypes(), service2->GetActiveDataTypes());
const syncer::SyncCycleSnapshot& snap1 =
service1->GetLastCycleSnapshotForDebugging();
const syncer::SyncCycleSnapshot& snap2 =
service2->GetLastCycleSnapshotForDebugging();
for (syncer::DataType type : common_types) {
if (!syncer::ProtocolTypes().Has(type)) {
continue;
}
// Look up the progress markers. Fail if either one is missing.
auto pm_it1 = snap1.download_progress_markers().find(type);
if (pm_it1 == snap1.download_progress_markers().end()) {
*os << "Progress marker missing in client 1 for "
<< syncer::DataTypeToDebugString(type);
return false;
}
auto pm_it2 = snap2.download_progress_markers().find(type);
if (pm_it2 == snap2.download_progress_markers().end()) {
*os << "Progress marker missing in client 2 for "
<< syncer::DataTypeToDebugString(type);
return false;
}
// Fail if any of them don't match.
if (!AreProgressMarkersEquivalent(pm_it1->second, pm_it2->second)) {
*os << "Progress markers don't match for "
<< syncer::DataTypeToDebugString(type);
return false;
}
}
return true;
}
} // namespace
// Variation of UpdateProgressMarkerChecker that intercepts calls to
// CheckExitCondition() and forwards them to a parent checker.
class QuiesceStatusChangeChecker::NestedUpdatedProgressMarkerChecker
: public UpdatedProgressMarkerChecker {
public:
NestedUpdatedProgressMarkerChecker(
syncer::SyncServiceImpl* service,
const base::RepeatingClosure& check_exit_condition_cb)
: UpdatedProgressMarkerChecker(service),
check_exit_condition_cb_(check_exit_condition_cb) {}
~NestedUpdatedProgressMarkerChecker() override = default;
protected:
void CheckExitCondition() override { check_exit_condition_cb_.Run(); }
private:
const base::RepeatingClosure check_exit_condition_cb_;
};
QuiesceStatusChangeChecker::QuiesceStatusChangeChecker(
std::vector<raw_ptr<syncer::SyncServiceImpl, VectorExperimental>> services)
: MultiClientStatusChangeChecker(services) {
DCHECK_LE(1U, services.size());
for (syncer::SyncServiceImpl* service : services) {
checkers_.push_back(std::make_unique<NestedUpdatedProgressMarkerChecker>(
service,
base::BindRepeating(&QuiesceStatusChangeChecker::CheckExitCondition,
base::Unretained(this))));
}
}
QuiesceStatusChangeChecker::~QuiesceStatusChangeChecker() = default;
bool QuiesceStatusChangeChecker::IsExitConditionSatisfied(std::ostream* os) {
// Check that all progress markers are up to date.
std::vector<syncer::SyncServiceImpl*> enabled_services;
for (const std::unique_ptr<NestedUpdatedProgressMarkerChecker>& checker :
checkers_) {
enabled_services.push_back(checker->service());
if (!checker->IsExitConditionSatisfied(os)) {
*os << "Not quiesced: Progress markers are old.";
return false;
}
}
for (size_t i = 1; i < enabled_services.size(); ++i) {
// Return false if there is a progress marker mismatch.
if (!ProgressMarkersMatch(enabled_services[i - 1], enabled_services[i],
os)) {
*os << "Not quiesced: Progress marker mismatch.";
return false;
}
}
return true;
}
|