chromium/chrome/browser/sync/test/integration/single_client_arc_package_sync_test.cc

// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/constants/ash_features.h"
#include "chrome/browser/ash/app_list/arc/arc_package_syncable_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/test/integration/fake_server_match_status_checker.h"
#include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
#include "chrome/browser/sync/test/integration/sync_arc_package_helper.h"
#include "chrome/browser/sync/test/integration/sync_service_impl_harness.h"
#include "chrome/browser/sync/test/integration/sync_test.h"
#include "chrome/browser/sync/test/integration/updated_progress_marker_checker.h"
#include "components/sync/base/data_type.h"
#include "components/sync/protocol/arc_package_specifics.pb.h"
#include "components/sync/protocol/entity_specifics.pb.h"
#include "components/sync/service/sync_service.h"
#include "components/sync/test/fake_server.h"
#include "content/public/test/browser_test.h"
#include "testing/gmock/include/gmock/gmock.h"

namespace arc {

namespace {

using testing::IsEmpty;
using testing::SizeIs;

class ArcPackagesCountChecker : public SingleClientStatusChangeChecker {
 public:
  ArcPackagesCountChecker(Profile* profile,
                          syncer::SyncServiceImpl* service,
                          size_t expected_count)
      : SingleClientStatusChangeChecker(service),
        profile_(profile),
        expected_count_(expected_count) {}
  ~ArcPackagesCountChecker() override = default;

  bool IsExitConditionSatisfied(std::ostream* os) override {
    size_t current_count =
        ArcAppListPrefs::Get(profile_)->GetPackagesFromPrefs().size();
    *os << "Waiting for " << expected_count_ << " Arc packages, currently have "
        << current_count;
    return current_count == expected_count_;
  }

 private:
  const raw_ptr<Profile> profile_;
  const size_t expected_count_;
};

class FakeServerArcPackageMatchChecker
    : public fake_server::FakeServerMatchStatusChecker {
 public:
  explicit FakeServerArcPackageMatchChecker(
      const std::vector<sync_pb::EntitySpecifics>& expected_entities)
      : expected_entities_(expected_entities) {}
  ~FakeServerArcPackageMatchChecker() override = default;

  bool IsExitConditionSatisfied(std::ostream* os) override {
    *os << "Waiting for server-side Arc packages to match expected.";

    std::vector<sync_pb::SyncEntity> server_entities =
        fake_server()->GetSyncEntitiesByDataType(syncer::ARC_PACKAGE);
    if (server_entities.size() != expected_entities_.size()) {
      return false;
    }

    for (const auto& server_entity : server_entities) {
      const sync_pb::ArcPackageSpecifics& server_specifics =
          server_entity.specifics().arc_package();

      bool matched = false;
      for (const auto& expected_entity : expected_entities_) {
        const sync_pb::ArcPackageSpecifics& expected_specifics =
            expected_entity.arc_package();

        if (server_specifics.SerializeAsString() ==
            expected_specifics.SerializeAsString()) {
          matched = true;
          break;
        }
      }
      if (!matched) {
        return false;
      }
    }

    return true;
  }

 private:
  const std::vector<sync_pb::EntitySpecifics> expected_entities_;
};

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

IN_PROC_BROWSER_TEST_F(SingleClientArcPackageSyncTest, ArcPackageEmpty) {
  ASSERT_TRUE(SetupSync());

  EXPECT_THAT(ArcAppListPrefs::Get(GetProfile(0))->GetPackagesFromPrefs(),
              IsEmpty());
}

IN_PROC_BROWSER_TEST_F(SingleClientArcPackageSyncTest,
                       ArcPackageInstallSomePackages) {
  ASSERT_TRUE(SetupSync());

  constexpr size_t kNumPackages = 5;
  std::vector<sync_pb::EntitySpecifics> expected_specifics;
  for (size_t i = 0; i < kNumPackages; ++i) {
    sync_arc_helper()->InstallPackageWithIndex(GetProfile(0), i);
    expected_specifics.push_back(sync_arc_helper()->GetTestSpecifics(i));
  }

  ASSERT_THAT(ArcAppListPrefs::Get(GetProfile(0))->GetPackagesFromPrefs(),
              SizeIs(kNumPackages));
  EXPECT_TRUE(FakeServerArcPackageMatchChecker(expected_specifics).Wait());
}

// Regression test for crbug.com/978837.
IN_PROC_BROWSER_TEST_F(SingleClientArcPackageSyncTest, DisableAndReenable) {
  ASSERT_TRUE(SetupSync());

  const size_t kTestPackageId = 0;
  sync_pb::EntitySpecifics specifics =
      sync_arc_helper()->GetTestSpecifics(kTestPackageId);

  // Disable ARC++ to verify sync resumes correctly when it gets reenabled
  // later. Note that the sync datatype itself is not disabled.
  ASSERT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::ARC_PACKAGE));
  sync_arc_helper()->DisableArcService(GetProfile(0));
  ASSERT_FALSE(
      GetSyncService(0)->GetActiveDataTypes().Has(syncer::ARC_PACKAGE));

  // Fake new sync data being uploaded by another client while ARC++ is
  // disabled.
  fake_server_->InjectEntity(
      syncer::PersistentUniqueClientEntity::CreateFromSpecificsForTesting(
          /*non_unique_name=*/"",
          /*client_tag=*/specifics.arc_package().package_name(), specifics,
          /*creation_time=*/0, /*last_modified_time=*/0));

  // Reenable ARC++.
  sync_arc_helper()->EnableArcService(GetProfile(0));
  ASSERT_TRUE(GetClient(0)->AwaitSyncSetupCompletion());

  // The problematic scenario in the regression test involves the refresh
  // happening late, after sync has started.
  sync_arc_helper()->SendRefreshPackageList(GetProfile(0));

  EXPECT_TRUE(ArcPackagesCountChecker(GetProfile(0), GetSyncService(0),
                                      /*expected_count=*/1)
                  .Wait());
  EXPECT_TRUE(
      sync_arc_helper()->HasOnlyTestPackages(GetProfile(0), {kTestPackageId}));
}

}  // namespace
}  // namespace arc