blob: fbfa52744b8c3c075e8e1feb26471f865a579131 [file] [log] [blame]
// Copyright 2015 The Android Open Source Project
//
// This software is licensed under the terms of the GNU General Public
// License version 2, as published by the Free Software Foundation, and
// may be copied, distributed, and modified under those terms.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
#include "android/update-check/UpdateChecker.h"
#include "android/update-check/VersionExtractor.h"
#include "android/base/Optional.h"
#include "android/base/testing/TestSystem.h"
#include "android/base/Version.h"
#include <gtest/gtest.h>
#include <string>
namespace android {
namespace update_check {
using android::base::Version;
using android::studio::UpdateChannel;
class MockVersionExtractor : public IVersionExtractor {
public:
virtual Versions extractVersions(
android::base::StringView data) const override {
++mExtractVersionCallCount;
EXPECT_EQ(mExtractVersionDataParam, data);
return mExtractVersionResult ? Versions{{UpdateChannel::Canary,
*mExtractVersionResult}}
: Versions{};
}
virtual Version getCurrentVersion() const {
++mGetCurrentVersionCallCount;
return mGetCurrentVersionResult;
}
std::string mExtractVersionDataParam;
android::base::Optional<Version> mExtractVersionResult = {{0, 0, 0}};
mutable int mExtractVersionCallCount = 0;
Version mGetCurrentVersionResult = {0, 0, 0};
mutable int mGetCurrentVersionCallCount = 0;
};
class MockDataLoader : public IDataLoader {
public:
virtual std::string load() override {
++mLoadCallCount;
return mLoadResult;
}
virtual std::string getUniqueDataKey() override {
++mGetUniqueDataKeyCallCount;
return mUniqueDataKey;
}
std::string mLoadResult;
int mLoadCallCount = 0;
std::string mUniqueDataKey;
int mGetUniqueDataKeyCallCount = 0;
};
class MockTimeStorage : public ITimeStorage {
public:
virtual bool lock() override {
++mLockCallCount;
return mLockResult;
}
virtual time_t getTime(const std::string& key) override {
EXPECT_STREQ(mKeyParam.c_str(), key.c_str());
++mGetTimeCallCount;
return mGetTimeResult;
}
virtual void setTime(const std::string& key, time_t time) override {
EXPECT_STREQ(mKeyParam.c_str(), key.c_str());
++mSetTimeCallCount;
EXPECT_EQ(mSetTimeParam, time);
}
int mLockCallCount = 0;
int mGetTimeCallCount = 0;
int mSetTimeCallCount = 0;
bool mLockResult = false;
time_t mGetTimeResult = 0;
time_t mSetTimeParam = 0;
std::string mKeyParam;
};
class MockNewerVersionReporter : public INewerVersionReporter {
public:
virtual void reportNewerVersion(const Version& existing,
const Version& newer) {
EXPECT_EQ(mReportNewerVersionExistingParam, existing);
EXPECT_EQ(mReportNewerVersionNewerParam, newer);
++mReportNewerVersionCallCount;
}
Version mReportNewerVersionExistingParam = {0, 0, 0};
Version mReportNewerVersionNewerParam = {0, 0, 0};
int mReportNewerVersionCallCount = 0;
};
class TestUpdateChecker : public UpdateChecker {
public:
TestUpdateChecker(IVersionExtractor* extractor,
IDataLoader* loader,
ITimeStorage* storage,
INewerVersionReporter* reporter)
: UpdateChecker(extractor, loader, storage, reporter) {}
// make it public for testing
using UpdateChecker::asyncWorker;
};
class TestData {
public:
TestData() : mSystem("", 32) {
mSystem.getTempRoot();
mDataLoader = new MockDataLoader();
mReporter = new MockNewerVersionReporter();
mTimeStorage = new MockTimeStorage();
mVersionExtractor = new MockVersionExtractor();
mUC.reset(new TestUpdateChecker(mVersionExtractor, mDataLoader,
mTimeStorage, mReporter));
}
std::unique_ptr<TestUpdateChecker> mUC;
MockDataLoader* mDataLoader;
MockNewerVersionReporter* mReporter;
MockTimeStorage* mTimeStorage;
MockVersionExtractor* mVersionExtractor;
android::base::TestSystem mSystem;
};
TEST(UpdateChecker, init) {
TestData test;
test.mTimeStorage->mLockResult = false;
EXPECT_FALSE(test.mUC->init());
EXPECT_EQ(1, test.mTimeStorage->mLockCallCount);
/////////////////////////////////////////////////////////////////////
test.mTimeStorage->mLockResult = true;
EXPECT_TRUE(test.mUC->init());
EXPECT_EQ(2, test.mTimeStorage->mLockCallCount);
}
TEST(UpdateChecker, needsCheck) {
TestData test;
// set last check time and current time to be close enough -
// no new check is needed
test.mTimeStorage->mKeyParam = test.mDataLoader->mUniqueDataKey = "key";
test.mTimeStorage->mGetTimeResult = time_t(1);
test.mSystem.setUnixTime(time_t(2));
EXPECT_FALSE(test.mUC->needsCheck());
EXPECT_EQ(1, test.mDataLoader->mGetUniqueDataKeyCallCount);
EXPECT_EQ(1, test.mTimeStorage->mGetTimeCallCount);
/////////////////////////////////////////////////////////////////////
// now set the current time to require the check (+one year from the epoch)
test.mSystem.setUnixTime(time_t(365 * 24 * 60 * 60));
EXPECT_TRUE(test.mUC->needsCheck());
EXPECT_EQ(2, test.mTimeStorage->mGetTimeCallCount);
}
TEST(UpdateChecker, getVersion) {
TestData test;
test.mDataLoader->mLoadResult =
test.mVersionExtractor->mExtractVersionDataParam = "test";
test.mVersionExtractor->mExtractVersionResult = Version(1, 0, 0);
auto returnedVersion = test.mUC->getLatestVersion();
EXPECT_TRUE(returnedVersion);
EXPECT_EQ(Version(1, 0, 0), returnedVersion->first);
EXPECT_EQ(UpdateChannel::Canary, returnedVersion->second);
}
TEST(UpdateChecker, asyncWorker) {
TestData test;
// first set version to be the newest
test.mDataLoader->mLoadResult =
test.mVersionExtractor->mExtractVersionDataParam = "test";
test.mVersionExtractor->mExtractVersionResult = Version(1, 0, 0);
test.mVersionExtractor->mGetCurrentVersionResult = Version(1, 0, 0);
test.mSystem.setUnixTime(time_t(1));
test.mTimeStorage->mKeyParam = test.mDataLoader->mUniqueDataKey = "key";
test.mTimeStorage->mSetTimeParam = time_t(1);
test.mUC->asyncWorker();
EXPECT_EQ(1, test.mDataLoader->mLoadCallCount);
EXPECT_EQ(1, test.mVersionExtractor->mExtractVersionCallCount);
EXPECT_EQ(1, test.mVersionExtractor->mGetCurrentVersionCallCount);
EXPECT_EQ(1, test.mTimeStorage->mSetTimeCallCount);
// didn't report the newer version
EXPECT_EQ(0, test.mReporter->mReportNewerVersionCallCount);
/////////////////////////////////////////////////////////////////////
// now there's a newer version available
test.mVersionExtractor->mExtractVersionResult = Version(2, 0, 0);
test.mReporter->mReportNewerVersionExistingParam = Version(1, 0, 0);
test.mReporter->mReportNewerVersionNewerParam = Version(2, 0, 0);
test.mUC->asyncWorker();
EXPECT_EQ(2, test.mDataLoader->mLoadCallCount);
EXPECT_EQ(2, test.mVersionExtractor->mExtractVersionCallCount);
EXPECT_EQ(2, test.mVersionExtractor->mGetCurrentVersionCallCount);
EXPECT_EQ(2, test.mTimeStorage->mSetTimeCallCount);
// reported the newer version
EXPECT_EQ(1, test.mReporter->mReportNewerVersionCallCount);
/////////////////////////////////////////////////////////////////////
// failed to get the last version
test.mVersionExtractor->mExtractVersionResult = {};
test.mUC->asyncWorker();
EXPECT_EQ(3, test.mDataLoader->mLoadCallCount);
EXPECT_EQ(3, test.mVersionExtractor->mExtractVersionCallCount);
EXPECT_EQ(3, test.mVersionExtractor->mGetCurrentVersionCallCount);
// didn't store the last check time
EXPECT_EQ(2, test.mTimeStorage->mSetTimeCallCount);
// didn't report the newer version
EXPECT_EQ(1, test.mReporter->mReportNewerVersionCallCount);
}
} // namespace update_check
} // namespace android