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