File: quiesce_status_change_checker.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (158 lines) | stat: -rw-r--r-- 6,080 bytes parent folder | download | duplicates (5)
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;
}