blob: 91a9782c6b670a565db1607bece54024c7e362e6 [file] [log] [blame]
// Copyright 2020 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.
#include "chrome/browser/updater/browser_updater_client_mac.h"
#import <Foundation/Foundation.h>
#include <string>
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/mac/foundation_util.h"
#include "base/mac/scoped_nsobject.h"
#include "base/run_loop.h"
#include "base/strings/sys_string_conversions.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "chrome/browser/ui/webui/help/version_updater.h"
#include "chrome/browser/updater/browser_updater_client_util.h"
#import "chrome/updater/app/server/mac/service_protocol.h"
#import "chrome/updater/app/server/mac/update_service_wrappers.h"
#include "chrome/updater/update_service.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
constexpr char kUnittestAppId[] = "cr-unknown";
constexpr char kUnittestVersion[] = "0.0.0.0";
constexpr char kFakeAppId[] = "fakebundleid";
base::FilePath GetPerUserUpdaterPath() {
return base::mac::GetUserLibraryPath().Append(GetUpdaterFolderName());
}
} // namespace
@interface TestCRUUpdateClientOnDemandImpl : CRUUpdateClientOnDemandImpl {
bool _useStateChange;
updater::UpdateService::UpdateState::State _statusValue;
}
- (instancetype)initWithStatusValue:
(updater::UpdateService::UpdateState::State)statusValue
useStateUpdate:(bool)useStateChange;
@end
@implementation TestCRUUpdateClientOnDemandImpl
- (instancetype)initWithStatusValue:
(updater::UpdateService::UpdateState::State)statusValue
useStateUpdate:(bool)useStateChange {
if (self = [super init]) {
_statusValue = statusValue;
_useStateChange = useStateChange;
}
return self;
}
- (void)getUpdaterVersionWithReply:(void (^_Nonnull)(NSString* version))reply {
NOTIMPLEMENTED();
}
- (void)registerForUpdatesWithAppId:(NSString* _Nullable)appId
brandCode:(NSString* _Nullable)brandCode
tag:(NSString* _Nullable)tag
version:(NSString* _Nullable)version
existenceCheckerPath:(NSString* _Nullable)existenceCheckerPath
reply:(void (^_Nonnull)(int rc))reply {
reply(static_cast<int>(_statusValue));
}
// Checks for updates and returns the result in the reply block.
- (void)checkForUpdatesWithUpdateState:
(CRUUpdateStateObserver* _Nonnull)updateState
reply:(void (^_Nonnull)(int rc))reply {
NOTIMPLEMENTED();
}
// Checks for update of a given app, with specified priority. Sends repeated
// updates of progress and returns the result in the reply block.
- (void)checkForUpdateWithAppID:(NSString* _Nonnull)appID
priority:(CRUPriorityWrapper* _Nonnull)priority
updateState:(CRUUpdateStateObserver* _Nonnull)updateState
reply:(void (^_Nonnull)(int rc))reply {
if (_useStateChange) {
base::scoped_nsobject<CRUUpdateStateStateWrapper> stateWrapper(
[[CRUUpdateStateStateWrapper alloc]
initWithUpdateStateState:_statusValue]);
base::scoped_nsobject<CRUErrorCategoryWrapper> errorCategoryWrapper(
[[CRUErrorCategoryWrapper alloc]
initWithErrorCategory:updater::UpdateService::ErrorCategory::
kNone]);
base::scoped_nsobject<CRUUpdateStateWrapper> wrapper(
[[CRUUpdateStateWrapper alloc]
initWithAppId:base::SysUTF8ToNSString(kUnittestAppId)
state:stateWrapper
version:base::SysUTF8ToNSString(kUnittestVersion)
downloadedBytes:0
totalBytes:100 // use a fake total bytes to curb FPE_INTDIV
installProgress:0
errorCategory:errorCategoryWrapper
errorCode:5
extraCode:12]);
[updateState observeUpdateState:wrapper];
} else {
reply(static_cast<int>(_statusValue));
}
}
- (void)haltForUpdateToVersion:(NSString* _Nonnull)version
reply:(void (^_Nonnull)(BOOL shouldUpdate))reply {
NOTIMPLEMENTED();
}
@end
class UpdateClientMacTest : public ::testing::Test {
public:
scoped_refptr<BrowserUpdaterClientMac> update_client() const {
return update_client_;
}
void set_update_client(scoped_refptr<BrowserUpdaterClientMac> client) {
update_client_ = client;
}
protected:
void SetUp() override {
base::mac::SetBaseBundleID(kFakeAppId);
if (!base::PathExists(GetPerUserUpdaterPath()))
ASSERT_TRUE(base::CreateDirectory(GetPerUserUpdaterPath()));
}
void TearDown() override {
if (base::PathExists(GetPerUserUpdaterPath()))
ASSERT_TRUE(base::DeletePathRecursively(GetPerUserUpdaterPath()));
}
private:
base::test::TaskEnvironment task_environment_;
scoped_refptr<BrowserUpdaterClientMac> update_client_;
};
TEST_F(UpdateClientMacTest, SuccessfullyUpdatedStatus) {
base::RunLoop run_loop;
updater::UpdateService::UpdateState::State expected_status =
updater::UpdateService::UpdateState::State::kUpdated;
set_update_client(base::MakeRefCounted<BrowserUpdaterClientMac>(
base::scoped_nsobject<CRUUpdateClientOnDemandImpl>(
[[TestCRUUpdateClientOnDemandImpl alloc]
initWithStatusValue:expected_status
useStateUpdate:true])));
update_client()->CheckForUpdate(
base::BindRepeating(base::BindLambdaForTesting(
[&](updater::UpdateService::UpdateState update_state) {
// Ignore checking for updates - this is the initial status from
// running CheckForUpdates.
if (update_state.state ==
updater::UpdateService::UpdateState::State::kCheckingForUpdates)
return;
EXPECT_EQ(expected_status, update_state.state);
run_loop.Quit();
})));
run_loop.Run();
}
TEST_F(UpdateClientMacTest, UpdateDownloadingStatus) {
base::RunLoop run_loop;
updater::UpdateService::UpdateState::State expected_status =
updater::UpdateService::UpdateState::State::kDownloading;
set_update_client(base::MakeRefCounted<BrowserUpdaterClientMac>(
base::scoped_nsobject<CRUUpdateClientOnDemandImpl>(
[[TestCRUUpdateClientOnDemandImpl alloc]
initWithStatusValue:expected_status
useStateUpdate:true])));
update_client()->CheckForUpdate(
base::BindRepeating(base::BindLambdaForTesting(
[&](updater::UpdateService::UpdateState update_state) {
// Ignore checking for updates - this is the initial status from
// running CheckForUpdates.
if (update_state.state ==
updater::UpdateService::UpdateState::State::kCheckingForUpdates)
return;
EXPECT_EQ(expected_status, update_state.state);
run_loop.Quit();
})));
run_loop.Run();
}
TEST_F(UpdateClientMacTest, NoUpdateStatus) {
base::RunLoop run_loop;
updater::UpdateService::UpdateState::State expected_status =
updater::UpdateService::UpdateState::State::kNoUpdate;
set_update_client(base::MakeRefCounted<BrowserUpdaterClientMac>(
base::scoped_nsobject<CRUUpdateClientOnDemandImpl>(
[[TestCRUUpdateClientOnDemandImpl alloc]
initWithStatusValue:expected_status
useStateUpdate:true])));
update_client()->CheckForUpdate(
base::BindRepeating(base::BindLambdaForTesting(
[&](updater::UpdateService::UpdateState update_state) {
// Ignore checking for updates - this is the initial status from
// running CheckForUpdates.
if (update_state.state ==
updater::UpdateService::UpdateState::State::kCheckingForUpdates)
return;
EXPECT_EQ(expected_status, update_state.state);
run_loop.Quit();
})));
run_loop.Run();
}
TEST_F(UpdateClientMacTest, ErrorStatus) {
base::RunLoop run_loop;
updater::UpdateService::UpdateState::State expected_status =
updater::UpdateService::UpdateState::State::kUpdateError;
set_update_client(base::MakeRefCounted<BrowserUpdaterClientMac>(
base::scoped_nsobject<CRUUpdateClientOnDemandImpl>(
[[TestCRUUpdateClientOnDemandImpl alloc]
initWithStatusValue:expected_status
useStateUpdate:true])));
update_client()->CheckForUpdate(
base::BindRepeating(base::BindLambdaForTesting(
[&](updater::UpdateService::UpdateState update_state) {
// Ignore checking for updates - this is the initial status from
// running CheckForUpdates.
if (update_state.state ==
updater::UpdateService::UpdateState::State::kCheckingForUpdates)
return;
EXPECT_EQ(expected_status, update_state.state);
run_loop.Quit();
})));
run_loop.Run();
}