1 //
2 // Copyright (C) 2021 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include <algorithm>
18
19 #include <brillo/message_loops/fake_message_loop.h>
20 #include <gtest/gtest.h>
21 #include <libsnapshot/snapshot.h>
22 #include <libsnapshot/mock_snapshot.h>
23 #include <libsnapshot/mock_snapshot_merge_stats.h>
24
25 #include "update_engine/aosp/cleanup_previous_update_action.h"
26 #include "update_engine/common/mock_boot_control.h"
27 #include "update_engine/common/mock_dynamic_partition_control.h"
28 #include "update_engine/common/mock_prefs.h"
29
30 namespace chromeos_update_engine {
31
32 using android::snapshot::AutoDevice;
33 using android::snapshot::MockSnapshotManager;
34 using android::snapshot::MockSnapshotMergeStats;
35 using android::snapshot::UpdateState;
36 using testing::_;
37 using testing::AtLeast;
38 using testing::Return;
39
40 class MockCleanupPreviousUpdateActionDelegate final
41 : public CleanupPreviousUpdateActionDelegateInterface {
42 MOCK_METHOD(void, OnCleanupProgressUpdate, (double), (override));
43 };
44
45 class MockActionProcessor : public ActionProcessor {
46 public:
47 MOCK_METHOD(void, ActionComplete, (AbstractAction*, ErrorCode), (override));
48 };
49
50 class MockAutoDevice : public AutoDevice {
51 public:
MockAutoDevice(std::string name)52 explicit MockAutoDevice(std::string name) : AutoDevice(name) {}
53 ~MockAutoDevice() = default;
54 };
55
56 class CleanupPreviousUpdateActionTest : public ::testing::Test {
57 public:
SetUp()58 void SetUp() override {
59 ON_CALL(boot_control_, GetDynamicPartitionControl())
60 .WillByDefault(Return(&dynamic_control_));
61 ON_CALL(boot_control_, GetCurrentSlot()).WillByDefault(Return(0));
62 ON_CALL(mock_snapshot_, GetSnapshotMergeStatsInstance())
63 .WillByDefault(Return(&mock_stats_));
64 action_.SetProcessor(&mock_processor_);
65 loop_.SetAsCurrent();
66 }
67
68 constexpr static FeatureFlag LAUNCH{FeatureFlag::Value::LAUNCH};
69 constexpr static FeatureFlag NONE{FeatureFlag::Value::NONE};
70 MockSnapshotManager mock_snapshot_;
71 MockPrefs mock_prefs_;
72 MockBootControl boot_control_;
73 MockDynamicPartitionControl dynamic_control_{};
74 MockCleanupPreviousUpdateActionDelegate mock_delegate_;
75 MockSnapshotMergeStats mock_stats_;
76 MockActionProcessor mock_processor_;
77 brillo::FakeMessageLoop loop_{nullptr};
78 CleanupPreviousUpdateAction action_{
79 &mock_prefs_, &boot_control_, &mock_snapshot_, &mock_delegate_};
80 };
81
TEST_F(CleanupPreviousUpdateActionTest,NonVabTest)82 TEST_F(CleanupPreviousUpdateActionTest, NonVabTest) {
83 // Since VAB isn't even enabled, |GetSnapshotMergeStatsInstance| shouldn't be
84 // called at all
85 EXPECT_CALL(mock_snapshot_, GetSnapshotMergeStatsInstance()).Times(0);
86 EXPECT_CALL(dynamic_control_, GetVirtualAbFeatureFlag())
87 .Times(AtLeast(1))
88 .WillRepeatedly(Return(NONE));
89 action_.PerformAction();
90 }
91
TEST_F(CleanupPreviousUpdateActionTest,VABSlotSuccessful)92 TEST_F(CleanupPreviousUpdateActionTest, VABSlotSuccessful) {
93 // Expectaion: if VABC is enabled, Clenup action should call
94 // |SnapshotMergeStats::Start()| to start merge, and wait for it to finish
95 EXPECT_CALL(mock_snapshot_, GetSnapshotMergeStatsInstance())
96 .Times(AtLeast(1));
97 EXPECT_CALL(mock_snapshot_, EnsureMetadataMounted())
98 .Times(AtLeast(1))
99 .WillRepeatedly(
100 []() { return std::make_unique<MockAutoDevice>("mock_device"); });
101 EXPECT_CALL(dynamic_control_, GetVirtualAbFeatureFlag())
102 .Times(AtLeast(1))
103 .WillRepeatedly(Return(LAUNCH));
104 // CleanupPreviousUpdateAction should use whatever slot returned by
105 // |GetCurrentSlot()|
106 EXPECT_CALL(boot_control_, GetCurrentSlot())
107 .Times(AtLeast(1))
108 .WillRepeatedly(Return(1));
109 EXPECT_CALL(boot_control_, IsSlotMarkedSuccessful(1))
110 .Times(AtLeast(1))
111 .WillRepeatedly(Return(true));
112 EXPECT_CALL(mock_snapshot_, ProcessUpdateState(_, _))
113 .Times(AtLeast(2))
114 .WillOnce(Return(UpdateState::Merging))
115 .WillRepeatedly(Return(UpdateState::MergeCompleted));
116 EXPECT_CALL(mock_stats_, Start())
117 .Times(AtLeast(1))
118 .WillRepeatedly(Return(true));
119 EXPECT_CALL(mock_processor_, ActionComplete(&action_, ErrorCode::kSuccess))
120 .Times(1);
121 action_.PerformAction();
122 while (loop_.PendingTasks()) {
123 ASSERT_TRUE(loop_.RunOnce(true));
124 }
125 }
126
TEST_F(CleanupPreviousUpdateActionTest,VabSlotNotReady)127 TEST_F(CleanupPreviousUpdateActionTest, VabSlotNotReady) {
128 // Cleanup action should repeatly query boot control until the slot is marked
129 // successful.
130 static constexpr auto MAX_TIMEPOINT =
131 std::chrono::steady_clock::time_point::max();
132 EXPECT_CALL(mock_snapshot_, GetSnapshotMergeStatsInstance())
133 .Times(AtLeast(1));
134 EXPECT_CALL(mock_snapshot_, EnsureMetadataMounted())
135 .Times(AtLeast(1))
136 .WillRepeatedly(
137 []() { return std::make_unique<MockAutoDevice>("mock_device"); });
138 EXPECT_CALL(dynamic_control_, GetVirtualAbFeatureFlag())
139 .Times(AtLeast(1))
140 .WillRepeatedly(Return(LAUNCH));
141 auto slot_success_time = MAX_TIMEPOINT;
142 auto merge_start_time = MAX_TIMEPOINT;
143 EXPECT_CALL(boot_control_, IsSlotMarkedSuccessful(_))
144 .Times(AtLeast(3))
145 .WillOnce(Return(false))
146 .WillOnce(Return(false))
147 .WillOnce([&slot_success_time]() {
148 slot_success_time =
149 std::min(slot_success_time, std::chrono::steady_clock::now());
150 return true;
151 });
152
153 EXPECT_CALL(mock_stats_, Start())
154 .Times(1)
155 .WillRepeatedly([&merge_start_time]() {
156 merge_start_time =
157 std::min(merge_start_time, std::chrono::steady_clock::now());
158 return true;
159 });
160
161 EXPECT_CALL(mock_snapshot_, ProcessUpdateState(_, _))
162 .Times(AtLeast(1))
163 .WillRepeatedly(Return(UpdateState::MergeCompleted));
164 EXPECT_CALL(mock_processor_, ActionComplete(&action_, ErrorCode::kSuccess))
165 .Times(1);
166 action_.PerformAction();
167 while (loop_.PendingTasks()) {
168 ASSERT_TRUE(loop_.RunOnce(true));
169 }
170 ASSERT_LT(slot_success_time, merge_start_time)
171 << "Merge should not be started until slot is marked successful";
172 }
173
174 } // namespace chromeos_update_engine
175