summaryrefslogtreecommitdiff
path: root/aosp/cleanup_previous_update_action_unittest.cc
diff options
context:
space:
mode:
authorKelvin Zhang <zhangkelvin@google.com>2021-04-05 15:56:26 -0400
committerKelvin Zhang <zhangkelvin@google.com>2021-04-06 15:26:59 -0400
commitb4b95c28346c919bd4f4f04859bb5b7484dd2c27 (patch)
tree2e861c0f2144a49d7fdb5972a1ce9cc21f5b568e /aosp/cleanup_previous_update_action_unittest.cc
parent65e8b6c19582f196dfab67d12cc3af78bb8d138c (diff)
Add unittest for CleanupPreviousUpdateAction
We had a severe bug in CleanupPreviousUpdateAction, undetected for a while. Added unittest to cover the bug so we don't regress. Bug: 169436297 Bug: 178637306 Test: th Change-Id: I40fc97a5c771ec001896ecd8f6d46b551cc7724c
Diffstat (limited to 'aosp/cleanup_previous_update_action_unittest.cc')
-rw-r--r--aosp/cleanup_previous_update_action_unittest.cc174
1 files changed, 174 insertions, 0 deletions
diff --git a/aosp/cleanup_previous_update_action_unittest.cc b/aosp/cleanup_previous_update_action_unittest.cc
new file mode 100644
index 00000000..0d2b4e6a
--- /dev/null
+++ b/aosp/cleanup_previous_update_action_unittest.cc
@@ -0,0 +1,174 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <algorithm>
+
+#include <brillo/message_loops/fake_message_loop.h>
+#include <gtest/gtest.h>
+#include <libsnapshot/snapshot.h>
+#include <libsnapshot/mock_snapshot.h>
+#include <libsnapshot/mock_snapshot_merge_stats.h>
+
+#include "update_engine/aosp/cleanup_previous_update_action.h"
+#include "update_engine/common/mock_boot_control.h"
+#include "update_engine/common/mock_dynamic_partition_control.h"
+#include "update_engine/common/mock_prefs.h"
+
+namespace chromeos_update_engine {
+
+using android::snapshot::AutoDevice;
+using android::snapshot::MockSnapshotManager;
+using android::snapshot::MockSnapshotMergeStats;
+using android::snapshot::UpdateState;
+using testing::_;
+using testing::AtLeast;
+using testing::Return;
+
+class MockCleanupPreviousUpdateActionDelegate final
+ : public CleanupPreviousUpdateActionDelegateInterface {
+ MOCK_METHOD(void, OnCleanupProgressUpdate, (double), (override));
+};
+
+class MockActionProcessor : public ActionProcessor {
+ public:
+ MOCK_METHOD(void, ActionComplete, (AbstractAction*, ErrorCode), (override));
+};
+
+class MockAutoDevice : public AutoDevice {
+ public:
+ explicit MockAutoDevice(std::string name) : AutoDevice(name) {}
+ ~MockAutoDevice() = default;
+};
+
+class CleanupPreviousUpdateActionTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ ON_CALL(boot_control_, GetDynamicPartitionControl())
+ .WillByDefault(Return(&dynamic_control_));
+ ON_CALL(boot_control_, GetCurrentSlot()).WillByDefault(Return(0));
+ ON_CALL(mock_snapshot_, GetSnapshotMergeStatsInstance())
+ .WillByDefault(Return(&mock_stats_));
+ action_.SetProcessor(&mock_processor_);
+ loop_.SetAsCurrent();
+ }
+
+ constexpr static FeatureFlag LAUNCH{FeatureFlag::Value::LAUNCH};
+ constexpr static FeatureFlag NONE{FeatureFlag::Value::NONE};
+ MockSnapshotManager mock_snapshot_;
+ MockPrefs mock_prefs_;
+ MockBootControl boot_control_;
+ MockDynamicPartitionControl dynamic_control_{};
+ MockCleanupPreviousUpdateActionDelegate mock_delegate_;
+ MockSnapshotMergeStats mock_stats_;
+ MockActionProcessor mock_processor_;
+ brillo::FakeMessageLoop loop_{nullptr};
+ CleanupPreviousUpdateAction action_{
+ &mock_prefs_, &boot_control_, &mock_snapshot_, &mock_delegate_};
+};
+
+TEST_F(CleanupPreviousUpdateActionTest, NonVabTest) {
+ // Since VAB isn't even enabled, |GetSnapshotMergeStatsInstance| shouldn't be
+ // called at all
+ EXPECT_CALL(mock_snapshot_, GetSnapshotMergeStatsInstance()).Times(0);
+ EXPECT_CALL(dynamic_control_, GetVirtualAbFeatureFlag())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(NONE));
+ action_.PerformAction();
+}
+
+TEST_F(CleanupPreviousUpdateActionTest, VABSlotSuccessful) {
+ // Expectaion: if VABC is enabled, Clenup action should call
+ // |SnapshotMergeStats::Start()| to start merge, and wait for it to finish
+ EXPECT_CALL(mock_snapshot_, GetSnapshotMergeStatsInstance())
+ .Times(AtLeast(1));
+ EXPECT_CALL(mock_snapshot_, EnsureMetadataMounted())
+ .Times(AtLeast(1))
+ .WillRepeatedly(
+ []() { return std::make_unique<MockAutoDevice>("mock_device"); });
+ EXPECT_CALL(dynamic_control_, GetVirtualAbFeatureFlag())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(LAUNCH));
+ // CleanupPreviousUpdateAction should use whatever slot returned by
+ // |GetCurrentSlot()|
+ EXPECT_CALL(boot_control_, GetCurrentSlot())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(1));
+ EXPECT_CALL(boot_control_, IsSlotMarkedSuccessful(1))
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(mock_snapshot_, ProcessUpdateState(_, _))
+ .Times(AtLeast(2))
+ .WillOnce(Return(UpdateState::Merging))
+ .WillRepeatedly(Return(UpdateState::MergeCompleted));
+ EXPECT_CALL(mock_stats_, Start())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(mock_processor_, ActionComplete(&action_, ErrorCode::kSuccess))
+ .Times(1);
+ action_.PerformAction();
+ while (loop_.PendingTasks()) {
+ ASSERT_TRUE(loop_.RunOnce(true));
+ }
+}
+
+TEST_F(CleanupPreviousUpdateActionTest, VabSlotNotReady) {
+ // Cleanup action should repeatly query boot control until the slot is marked
+ // successful.
+ static constexpr auto MAX_TIMEPOINT =
+ std::chrono::steady_clock::time_point::max();
+ EXPECT_CALL(mock_snapshot_, GetSnapshotMergeStatsInstance())
+ .Times(AtLeast(1));
+ EXPECT_CALL(mock_snapshot_, EnsureMetadataMounted())
+ .Times(AtLeast(1))
+ .WillRepeatedly(
+ []() { return std::make_unique<MockAutoDevice>("mock_device"); });
+ EXPECT_CALL(dynamic_control_, GetVirtualAbFeatureFlag())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(LAUNCH));
+ auto slot_success_time = MAX_TIMEPOINT;
+ auto merge_start_time = MAX_TIMEPOINT;
+ EXPECT_CALL(boot_control_, IsSlotMarkedSuccessful(_))
+ .Times(AtLeast(3))
+ .WillOnce(Return(false))
+ .WillOnce(Return(false))
+ .WillOnce([&slot_success_time]() {
+ slot_success_time =
+ std::min(slot_success_time, std::chrono::steady_clock::now());
+ return true;
+ });
+
+ EXPECT_CALL(mock_stats_, Start())
+ .Times(1)
+ .WillRepeatedly([&merge_start_time]() {
+ merge_start_time =
+ std::min(merge_start_time, std::chrono::steady_clock::now());
+ return true;
+ });
+
+ EXPECT_CALL(mock_snapshot_, ProcessUpdateState(_, _))
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(UpdateState::MergeCompleted));
+ EXPECT_CALL(mock_processor_, ActionComplete(&action_, ErrorCode::kSuccess))
+ .Times(1);
+ action_.PerformAction();
+ while (loop_.PendingTasks()) {
+ ASSERT_TRUE(loop_.RunOnce(true));
+ }
+ ASSERT_LT(slot_success_time, merge_start_time)
+ << "Merge should not be started until slot is marked successful";
+}
+
+} // namespace chromeos_update_engine