File: single_client_extension_apps_sync_test.cc

package info (click to toggle)
chromium 138.0.7204.183-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 6,080,960 kB
  • sloc: cpp: 34,937,079; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,954; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,811; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (217 lines) | stat: -rw-r--r-- 8,050 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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <vector>

#include "build/build_config.h"
#include "chrome/browser/sync/test/integration/apps_helper.h"
#include "chrome/browser/sync/test/integration/fake_server_match_status_checker.h"
#include "chrome/browser/sync/test/integration/sync_test.h"
#include "chrome/browser/sync/test/integration/updated_progress_marker_checker.h"
#include "chrome/browser/web_applications/test/web_app_test_utils.h"
#include "components/app_constants/constants.h"
#include "components/sync/base/data_type.h"
#include "components/sync/base/features.h"
#include "components/sync/engine/loopback_server/persistent_unique_client_entity.h"
#include "components/sync/protocol/app_specifics.pb.h"
#include "components/sync/service/sync_service_impl.h"
#include "components/sync/test/fake_server.h"
#include "content/public/test/browser_test.h"
#include "extensions/common/constants.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

#if BUILDFLAG(IS_WIN)
#include "base/base_paths_win.h"
#include "base/test/scoped_path_override.h"
#endif  // BUILDFLAG(IS_WIN)

namespace {

using apps_helper::AllProfilesHaveSameApps;
using apps_helper::InstallHostedApp;
using apps_helper::InstallPlatformApp;
using testing::UnorderedElementsAre;

std::ostream& operator<<(std::ostream& os,
                         const base::flat_set<std::string>& set) {
  os << "{";
  for (const std::string& element : set) {
    os << element << ", ";
  }
  os << "}";
  return os;
}

class FakeServerAppChecker : public fake_server::FakeServerMatchStatusChecker {
 public:
  // Waits for the APPS entities in the server to be those with ids `app_ids`.
  // Depending on the platform some apps are auto-installed and synced, so they
  // are implicitly added to the expected set of ids.
  explicit FakeServerAppChecker(std::vector<std::string> expected_app_ids) {
    expected_app_ids.push_back(extensions::kWebStoreAppId);
#if BUILDFLAG(IS_CHROMEOS)
    expected_app_ids.push_back(app_constants::kChromeAppId);
#endif
    expected_app_ids_ = base::MakeFlatSet<std::string>(expected_app_ids);
  }

  FakeServerAppChecker(const FakeServerAppChecker&) = delete;
  FakeServerAppChecker& operator=(const FakeServerAppChecker&) = delete;

  ~FakeServerAppChecker() override = default;

  bool IsExitConditionSatisfied(std::ostream* os) override {
    std::vector<sync_pb::SyncEntity> app_entities =
        fake_server()->GetSyncEntitiesByDataType(syncer::APPS);
    base::flat_set<std::string> actual_app_ids = base::MakeFlatSet<std::string>(
        app_entities,
        /*comp=*/{}, /*proj=*/[](const sync_pb::SyncEntity& e) {
          return e.specifics().app().extension().id();
        });
    *os << "Expected app ids in fake server: " << expected_app_ids_
        << ". Actual app ids " << actual_app_ids << ".";
    return expected_app_ids_ == actual_app_ids;
  }

 private:
  base::flat_set<std::string> expected_app_ids_;
};

class SingleClientExtensionAppsSyncTest : public SyncTest {
 public:
  SingleClientExtensionAppsSyncTest() : SyncTest(SINGLE_CLIENT) {}
  ~SingleClientExtensionAppsSyncTest() override = default;

 private:
#if BUILDFLAG(IS_WIN)
  // This stops extension installation from creating a shortcut in the real
  // desktop startup dir. This prevents Chrome launching with the extension
  // on startup on trybots and developer machines.
  base::ScopedPathOverride override_start_menu_dir_{base::DIR_START_MENU};
#endif  // BUILDFLAG(IS_WIN)
};

IN_PROC_BROWSER_TEST_F(SingleClientExtensionAppsSyncTest, StartWithNoApps) {
  ASSERT_TRUE(SetupSync());
  ASSERT_TRUE(FakeServerAppChecker({}).Wait());
}

IN_PROC_BROWSER_TEST_F(SingleClientExtensionAppsSyncTest,
                       StartWithSomeLegacyApps) {
  ASSERT_TRUE(SetupClients());

  const std::string id0 = InstallHostedApp(GetProfile(0), 0);
  const std::string id1 = InstallHostedApp(GetProfile(0), 1);

  ASSERT_TRUE(SetupSync());
  ASSERT_TRUE(FakeServerAppChecker({id0, id1}).Wait());
}

IN_PROC_BROWSER_TEST_F(SingleClientExtensionAppsSyncTest,
                       StartWithSomePlatformApps) {
  ASSERT_TRUE(SetupClients());

  const std::string id0 = InstallPlatformApp(GetProfile(0), 0);
  const std::string id1 = InstallPlatformApp(GetProfile(0), 1);

  ASSERT_TRUE(SetupSync());
  ASSERT_TRUE(FakeServerAppChecker({id0, id1}).Wait());
}

IN_PROC_BROWSER_TEST_F(SingleClientExtensionAppsSyncTest,
                       InstallSomeLegacyApps) {
  ASSERT_TRUE(SetupSync());

  const std::string id0 = InstallHostedApp(GetProfile(0), 0);
  const std::string id1 = InstallHostedApp(GetProfile(0), 1);

  ASSERT_TRUE(FakeServerAppChecker({id0, id1}).Wait());
}

IN_PROC_BROWSER_TEST_F(SingleClientExtensionAppsSyncTest,
                       InstallSomePlatformApps) {
  ASSERT_TRUE(SetupSync());

  const std::string id0 = InstallPlatformApp(GetProfile(0), 0);
  const std::string id1 = InstallPlatformApp(GetProfile(0), 1);

  ASSERT_TRUE(FakeServerAppChecker({id0, id1}).Wait());
}

IN_PROC_BROWSER_TEST_F(SingleClientExtensionAppsSyncTest, InstallSomeApps) {
  ASSERT_TRUE(SetupSync());

  const std::string id0 = InstallHostedApp(GetProfile(0), 0);
  const std::string id1 = InstallPlatformApp(GetProfile(0), 1);

  ASSERT_TRUE(FakeServerAppChecker({id0, id1}).Wait());
}

std::vector<sync_pb::SyncEntity> FilterForBookmarkApps(
    const std::vector<sync_pb::SyncEntity>& entities) {
  std::vector<sync_pb::SyncEntity> bookmark_apps;
  for (const sync_pb::SyncEntity& entity : entities) {
    if (!entity.specifics().has_app() ||
        !entity.specifics().app().has_bookmark_app_url()) {
      continue;
    }
    bookmark_apps.push_back(entity);
  }
  return bookmark_apps;
}

class NoBookmarkAppServerChecker
    : public fake_server::FakeServerMatchStatusChecker {
 public:
  NoBookmarkAppServerChecker() = default;
  ~NoBookmarkAppServerChecker() override = default;
  // StatusChangeChecker implementation.
  bool IsExitConditionSatisfied(std::ostream* os) override {
    std::vector<sync_pb::SyncEntity> bookmark_entities = FilterForBookmarkApps(
        fake_server()->GetSyncEntitiesByDataType(syncer::APPS));
    testing::StringMatchResultListener result_listener;
    const bool matches = testing::ExplainMatchResult(
        testing::IsEmpty(), bookmark_entities, &result_listener);
    *os << result_listener.str();
    return matches;
  }
};

IN_PROC_BROWSER_TEST_F(SingleClientExtensionAppsSyncTest, NoBookmarkApps) {
  const int64_t kDefaultTime = 1234L;

  std::vector<sync_pb::SyncEntity> server_apps =
      GetFakeServer()->GetSyncEntitiesByDataType(syncer::APPS);
  ASSERT_EQ(0ul, server_apps.size());

  // This creates a "google photos" bookmark app specifics.
  sync_pb::EntitySpecifics specifics;
  sync_pb::AppSpecifics* app_specifics = specifics.mutable_app();
  sync_pb::ExtensionSpecifics* extension_specifics =
      app_specifics->mutable_extension();
  extension_specifics->set_id("ncmjhecbjeaamljdfahankockkkdmedg");
  extension_specifics->set_version("0");
  extension_specifics->set_enabled(true);
  extension_specifics->set_update_url("");
  extension_specifics->set_remote_install(false);
  extension_specifics->set_incognito_enabled(false);
  extension_specifics->set_disable_reasons(0);
  app_specifics->set_bookmark_app_url("https://photos.google.com/?lfhs=2");

  GetFakeServer()->InjectEntity(
      syncer::PersistentUniqueClientEntity::CreateFromSpecificsForTesting(
          /*non_unique_name=*/"", "ncmjhecbjeaamljdfahankockkkdmedg", specifics,
          kDefaultTime, kDefaultTime));
  server_apps = FilterForBookmarkApps(
      GetFakeServer()->GetSyncEntitiesByDataType(syncer::APPS));
  ASSERT_EQ(1u, server_apps.size());

  ASSERT_TRUE(SetupSync());
  // Since bookmark apps are deprecated (https://crbug.com/877898), the client
  // should have deleted it from the server.
  EXPECT_TRUE(NoBookmarkAppServerChecker().Wait());
}

}  // namespace