Reland "libsnapshot_fuzzer: Add tests"
This reverts commit 254b9046f70b324cca75857b7bddd12908ade81b.
Reason for revert: test fixed
Bug: 156689792
Test: run it then reboot
Change-Id: I33603e87b8f6b06fed2d18066ee5f00cdf45a52e
diff --git a/fs_mgr/TEST_MAPPING b/fs_mgr/TEST_MAPPING
index 676f446..6cd0430 100644
--- a/fs_mgr/TEST_MAPPING
+++ b/fs_mgr/TEST_MAPPING
@@ -14,6 +14,9 @@
},
{
"name": "vts_libsnapshot_test"
+ },
+ {
+ "name": "libsnapshot_fuzzer_test"
}
]
}
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index c191102..2783e4d 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -246,8 +246,8 @@
gtest: false,
}
-cc_fuzz {
- name: "libsnapshot_fuzzer",
+cc_defaults {
+ name: "libsnapshot_fuzzer_defaults",
// TODO(b/154633114): make host supported.
// host_supported: true,
@@ -289,6 +289,11 @@
canonical_path_from_root: false,
local_include_dirs: ["."],
},
+}
+
+cc_fuzz {
+ name: "libsnapshot_fuzzer",
+ defaults: ["libsnapshot_fuzzer_defaults"],
corpus: ["corpus/*"],
fuzz_config: {
cc: ["android-virtual-ab+bugs@google.com"],
@@ -298,3 +303,14 @@
fuzz_on_haiku_device: true,
},
}
+
+cc_test {
+ name: "libsnapshot_fuzzer_test",
+ defaults: ["libsnapshot_fuzzer_defaults"],
+ data: ["corpus/*"],
+ test_suites: [
+ "device-tests",
+ ],
+ auto_gen_config: true,
+ require_root: true,
+}
diff --git a/fs_mgr/libsnapshot/fuzz_utils.h b/fs_mgr/libsnapshot/fuzz_utils.h
index 4dc6cdc..20b13b2 100644
--- a/fs_mgr/libsnapshot/fuzz_utils.h
+++ b/fs_mgr/libsnapshot/fuzz_utils.h
@@ -68,17 +68,25 @@
return 0;
}
+// Get the field descriptor for the oneof field in the action message. If no oneof field is set,
+// return nullptr.
template <typename Action>
-void ExecuteActionProto(typename Action::Class* module,
- const typename Action::Proto& action_proto) {
+const google::protobuf::FieldDescriptor* GetValueFieldDescriptor(
+ const typename Action::Proto& action_proto) {
static auto* action_value_desc = GetProtoValueDescriptor(Action::Proto::GetDescriptor());
auto* action_refl = Action::Proto::GetReflection();
if (!action_refl->HasOneof(action_proto, action_value_desc)) {
- return;
+ return nullptr;
}
+ return action_refl->GetOneofFieldDescriptor(action_proto, action_value_desc);
+}
- const auto* field_desc = action_refl->GetOneofFieldDescriptor(action_proto, action_value_desc);
+template <typename Action>
+void ExecuteActionProto(typename Action::ClassType* module,
+ const typename Action::Proto& action_proto) {
+ const auto* field_desc = GetValueFieldDescriptor<Action>(action_proto);
+ if (field_desc == nullptr) return;
auto number = field_desc->number();
const auto& map = *Action::GetFunctionMap();
auto it = map.find(number);
@@ -89,7 +97,7 @@
template <typename Action>
void ExecuteAllActionProtos(
- typename Action::Class* module,
+ typename Action::ClassType* module,
const google::protobuf::RepeatedPtrField<typename Action::Proto>& action_protos) {
for (const auto& proto : action_protos) {
ExecuteActionProto<Action>(module, proto);
@@ -134,53 +142,57 @@
// ActionPerformer extracts arguments from the protobuf message, and then call FuzzFunction
// with these arguments.
template <typename FuzzFunction, typename Signature, typename Enabled = void>
-struct ActionPerfomer; // undefined
+struct ActionPerformerImpl; // undefined
template <typename FuzzFunction, typename MessageProto>
-struct ActionPerfomer<
+struct ActionPerformerImpl<
FuzzFunction, void(const MessageProto&),
typename std::enable_if_t<std::is_base_of_v<google::protobuf::Message, MessageProto>>> {
- static void Invoke(typename FuzzFunction::Class* module,
- const google::protobuf::Message& action_proto,
- const google::protobuf::FieldDescriptor* field_desc) {
+ static typename FuzzFunction::ReturnType Invoke(
+ typename FuzzFunction::ClassType* module, const google::protobuf::Message& action_proto,
+ const google::protobuf::FieldDescriptor* field_desc) {
const MessageProto& arg = CheckedCast<std::remove_reference_t<MessageProto>>(
action_proto.GetReflection()->GetMessage(action_proto, field_desc));
- FuzzFunction::ImplBody(module, arg);
+ return FuzzFunction::ImplBody(module, arg);
}
};
template <typename FuzzFunction, typename Primitive>
-struct ActionPerfomer<FuzzFunction, void(Primitive),
- typename std::enable_if_t<std::is_arithmetic_v<Primitive>>> {
- static void Invoke(typename FuzzFunction::Class* module,
- const google::protobuf::Message& action_proto,
- const google::protobuf::FieldDescriptor* field_desc) {
+struct ActionPerformerImpl<FuzzFunction, void(Primitive),
+ typename std::enable_if_t<std::is_arithmetic_v<Primitive>>> {
+ static typename FuzzFunction::ReturnType Invoke(
+ typename FuzzFunction::ClassType* module, const google::protobuf::Message& action_proto,
+ const google::protobuf::FieldDescriptor* field_desc) {
Primitive arg = std::invoke(PrimitiveGetter<Primitive>::fp, action_proto.GetReflection(),
action_proto, field_desc);
- FuzzFunction::ImplBody(module, arg);
+ return FuzzFunction::ImplBody(module, arg);
}
};
template <typename FuzzFunction>
-struct ActionPerfomer<FuzzFunction, void()> {
- static void Invoke(typename FuzzFunction::Class* module, const google::protobuf::Message&,
- const google::protobuf::FieldDescriptor*) {
- FuzzFunction::ImplBody(module);
+struct ActionPerformerImpl<FuzzFunction, void()> {
+ static typename FuzzFunction::ReturnType Invoke(typename FuzzFunction::ClassType* module,
+ const google::protobuf::Message&,
+ const google::protobuf::FieldDescriptor*) {
+ return FuzzFunction::ImplBody(module);
}
};
template <typename FuzzFunction>
-struct ActionPerfomer<FuzzFunction, void(const std::string&)> {
- static void Invoke(typename FuzzFunction::Class* module,
- const google::protobuf::Message& action_proto,
- const google::protobuf::FieldDescriptor* field_desc) {
+struct ActionPerformerImpl<FuzzFunction, void(const std::string&)> {
+ static typename FuzzFunction::ReturnType Invoke(
+ typename FuzzFunction::ClassType* module, const google::protobuf::Message& action_proto,
+ const google::protobuf::FieldDescriptor* field_desc) {
std::string scratch;
const std::string& arg = action_proto.GetReflection()->GetStringReference(
action_proto, field_desc, &scratch);
- FuzzFunction::ImplBody(module, arg);
+ return FuzzFunction::ImplBody(module, arg);
}
};
+template <typename FuzzFunction>
+struct ActionPerformer : ActionPerformerImpl<FuzzFunction, typename FuzzFunction::Signature> {};
+
} // namespace android::fuzz
// Fuzz existing C++ class, ClassType, with a collection of functions under the name Action.
@@ -197,11 +209,11 @@
// FUZZ_CLASS(Foo, FooAction)
// After linking functions of Foo to FooAction, execute all actions by:
// FooAction::ExecuteAll(foo_object, action_protos)
-#define FUZZ_CLASS(ClassType, Action) \
+#define FUZZ_CLASS(Class, Action) \
class Action { \
public: \
using Proto = Action##Proto; \
- using Class = ClassType; \
+ using ClassType = Class; \
using FunctionMap = android::fuzz::FunctionMap<Class>; \
static FunctionMap* GetFunctionMap() { \
static Action::FunctionMap map; \
@@ -225,29 +237,33 @@
// }
// class Foo { public: void DoAwesomeFoo(bool arg); };
// FUZZ_OBJECT(FooAction, Foo);
-// FUZZ_FUNCTION(FooAction, DoFoo, module, bool arg) {
+// FUZZ_FUNCTION(FooAction, DoFoo, void, IFoo* module, bool arg) {
// module->DoAwesomeFoo(arg);
// }
// The name DoFoo is the camel case name of the action in protobuf definition of FooActionProto.
-#define FUZZ_FUNCTION(Action, FunctionName, module, ...) \
- class FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName) { \
- public: \
- using Class = Action::Class; \
- static void ImplBody(Action::Class*, ##__VA_ARGS__); \
- \
- private: \
- static bool registered_; \
- }; \
- auto FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName)::registered_ = ([] { \
- auto tag = Action::Proto::ValueCase::FUZZ_FUNCTION_TAG_NAME(FunctionName); \
- auto func = \
- &::android::fuzz::ActionPerfomer<FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName), \
- void(__VA_ARGS__)>::Invoke; \
- Action::GetFunctionMap()->CheckEmplace(tag, func); \
- return true; \
- })(); \
- void FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName)::ImplBody(Action::Class* module, \
- ##__VA_ARGS__)
+#define FUZZ_FUNCTION(Action, FunctionName, Return, ModuleArg, ...) \
+ class FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName) { \
+ public: \
+ using ActionType = Action; \
+ using ClassType = Action::ClassType; \
+ using ReturnType = Return; \
+ using Signature = void(__VA_ARGS__); \
+ static constexpr const char name[] = #FunctionName; \
+ static constexpr const auto tag = \
+ Action::Proto::ValueCase::FUZZ_FUNCTION_TAG_NAME(FunctionName); \
+ static ReturnType ImplBody(ModuleArg, ##__VA_ARGS__); \
+ \
+ private: \
+ static bool registered_; \
+ }; \
+ auto FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName)::registered_ = ([] { \
+ auto tag = FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName)::tag; \
+ auto func = &::android::fuzz::ActionPerformer<FUZZ_FUNCTION_CLASS_NAME( \
+ Action, FunctionName)>::Invoke; \
+ Action::GetFunctionMap()->CheckEmplace(tag, func); \
+ return true; \
+ })(); \
+ Return FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName)::ImplBody(ModuleArg, ##__VA_ARGS__)
// Implement a simple action by linking it to the function with the same name. Example:
// message FooActionProto {
@@ -261,5 +277,9 @@
// FUZZ_FUNCTION(FooAction, DoBar);
// The name DoBar is the camel case name of the action in protobuf definition of FooActionProto, and
// also the name of the function of Foo.
-#define FUZZ_SIMPLE_FUNCTION(Action, FunctionName) \
- FUZZ_FUNCTION(Action, FunctionName, module) { (void)module->FunctionName(); }
+#define FUZZ_SIMPLE_FUNCTION(Action, FunctionName) \
+ FUZZ_FUNCTION(Action, FunctionName, \
+ decltype(std::declval<Action::ClassType>().FunctionName()), \
+ Action::ClassType* module) { \
+ return module->FunctionName(); \
+ }
diff --git a/fs_mgr/libsnapshot/snapshot_fuzz.cpp b/fs_mgr/libsnapshot/snapshot_fuzz.cpp
index 1e90ace..5b145c3 100644
--- a/fs_mgr/libsnapshot/snapshot_fuzz.cpp
+++ b/fs_mgr/libsnapshot/snapshot_fuzz.cpp
@@ -21,14 +21,21 @@
#include <tuple>
#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/result.h>
+#include <gtest/gtest.h>
#include <src/libfuzzer/libfuzzer_macro.h>
#include <storage_literals/storage_literals.h>
#include "fuzz_utils.h"
#include "snapshot_fuzz_utils.h"
+using android::base::Error;
+using android::base::GetBoolProperty;
using android::base::LogId;
using android::base::LogSeverity;
+using android::base::ReadFileToString;
+using android::base::Result;
using android::base::SetLogger;
using android::base::StderrLogger;
using android::base::StdioLogger;
@@ -37,6 +44,8 @@
using android::snapshot::SnapshotFuzzData;
using android::snapshot::SnapshotFuzzEnv;
using chromeos_update_engine::DeltaArchiveManifest;
+using google::protobuf::FieldDescriptor;
+using google::protobuf::Message;
using google::protobuf::RepeatedPtrField;
// Avoid linking to libgsi since it needs disk I/O.
@@ -74,48 +83,49 @@
FUZZ_SIMPLE_FUNCTION(SnapshotManagerAction, EnsureMetadataMounted);
FUZZ_SIMPLE_FUNCTION(SnapshotManagerAction, GetSnapshotMergeStatsInstance);
-#define SNAPSHOT_FUZZ_FUNCTION(FunctionName, ...) \
- FUZZ_FUNCTION(SnapshotManagerAction, FunctionName, snapshot, ##__VA_ARGS__)
+#define SNAPSHOT_FUZZ_FUNCTION(FunctionName, ReturnType, ...) \
+ FUZZ_FUNCTION(SnapshotManagerAction, FunctionName, ReturnType, ISnapshotManager* snapshot, \
+ ##__VA_ARGS__)
-SNAPSHOT_FUZZ_FUNCTION(FinishedSnapshotWrites, bool wipe) {
- (void)snapshot->FinishedSnapshotWrites(wipe);
+SNAPSHOT_FUZZ_FUNCTION(FinishedSnapshotWrites, bool, bool wipe) {
+ return snapshot->FinishedSnapshotWrites(wipe);
}
-SNAPSHOT_FUZZ_FUNCTION(ProcessUpdateState, const ProcessUpdateStateArgs& args) {
+SNAPSHOT_FUZZ_FUNCTION(ProcessUpdateState, bool, const ProcessUpdateStateArgs& args) {
std::function<bool()> before_cancel;
if (args.has_before_cancel()) {
before_cancel = [&]() { return args.fail_before_cancel(); };
}
- (void)snapshot->ProcessUpdateState({}, before_cancel);
+ return snapshot->ProcessUpdateState({}, before_cancel);
}
-SNAPSHOT_FUZZ_FUNCTION(GetUpdateState, bool has_progress_arg) {
+SNAPSHOT_FUZZ_FUNCTION(GetUpdateState, UpdateState, bool has_progress_arg) {
double progress;
- (void)snapshot->GetUpdateState(has_progress_arg ? &progress : nullptr);
+ return snapshot->GetUpdateState(has_progress_arg ? &progress : nullptr);
}
-SNAPSHOT_FUZZ_FUNCTION(HandleImminentDataWipe, bool has_callback) {
+SNAPSHOT_FUZZ_FUNCTION(HandleImminentDataWipe, bool, bool has_callback) {
std::function<void()> callback;
if (has_callback) {
callback = []() {};
}
- (void)snapshot->HandleImminentDataWipe(callback);
+ return snapshot->HandleImminentDataWipe(callback);
}
-SNAPSHOT_FUZZ_FUNCTION(Dump) {
+SNAPSHOT_FUZZ_FUNCTION(Dump, bool) {
std::stringstream ss;
- (void)snapshot->Dump(ss);
+ return snapshot->Dump(ss);
}
-SNAPSHOT_FUZZ_FUNCTION(CreateUpdateSnapshots, const DeltaArchiveManifest& manifest) {
- (void)snapshot->CreateUpdateSnapshots(manifest);
+SNAPSHOT_FUZZ_FUNCTION(CreateUpdateSnapshots, bool, const DeltaArchiveManifest& manifest) {
+ return snapshot->CreateUpdateSnapshots(manifest);
}
-SNAPSHOT_FUZZ_FUNCTION(UnmapUpdateSnapshot, const std::string& name) {
- (void)snapshot->UnmapUpdateSnapshot(name);
+SNAPSHOT_FUZZ_FUNCTION(UnmapUpdateSnapshot, bool, const std::string& name) {
+ return snapshot->UnmapUpdateSnapshot(name);
}
-SNAPSHOT_FUZZ_FUNCTION(CreateLogicalAndSnapshotPartitions,
+SNAPSHOT_FUZZ_FUNCTION(CreateLogicalAndSnapshotPartitions, bool,
const CreateLogicalAndSnapshotPartitionsArgs& args) {
const std::string* super;
if (args.use_correct_super()) {
@@ -123,20 +133,21 @@
} else {
super = &args.super();
}
- (void)snapshot->CreateLogicalAndSnapshotPartitions(
+ return snapshot->CreateLogicalAndSnapshotPartitions(
*super, std::chrono::milliseconds(args.timeout_millis()));
}
-SNAPSHOT_FUZZ_FUNCTION(RecoveryCreateSnapshotDevicesWithMetadata,
+SNAPSHOT_FUZZ_FUNCTION(RecoveryCreateSnapshotDevicesWithMetadata, CreateResult,
const RecoveryCreateSnapshotDevicesArgs& args) {
std::unique_ptr<AutoDevice> device;
if (args.has_metadata_device_object()) {
device = std::make_unique<DummyAutoDevice>(args.metadata_mounted());
}
- (void)snapshot->RecoveryCreateSnapshotDevices(device);
+ return snapshot->RecoveryCreateSnapshotDevices(device);
}
-SNAPSHOT_FUZZ_FUNCTION(MapUpdateSnapshot, const CreateLogicalPartitionParamsProto& params_proto) {
+SNAPSHOT_FUZZ_FUNCTION(MapUpdateSnapshot, bool,
+ const CreateLogicalPartitionParamsProto& params_proto) {
auto partition_opener = std::make_unique<TestPartitionOpener>(GetSnapshotFuzzEnv()->super());
CreateLogicalPartitionParams params;
if (params_proto.use_correct_super()) {
@@ -153,10 +164,10 @@
params.device_name = params_proto.device_name();
params.partition_opener = partition_opener.get();
std::string path;
- (void)snapshot->MapUpdateSnapshot(params, &path);
+ return snapshot->MapUpdateSnapshot(params, &path);
}
-SNAPSHOT_FUZZ_FUNCTION(SwitchSlot) {
+SNAPSHOT_FUZZ_FUNCTION(SwitchSlot, void) {
(void)snapshot;
CHECK(current_module != nullptr);
CHECK(current_module->device_info != nullptr);
@@ -194,7 +205,8 @@
}
// Stop logging (except fatal messages) after global initialization. This is only done once.
int StopLoggingAfterGlobalInit() {
- [[maybe_unused]] static protobuf_mutator::protobuf::LogSilencer log_silincer;
+ (void)GetSnapshotFuzzEnv();
+ [[maybe_unused]] static protobuf_mutator::protobuf::LogSilencer log_silencer;
SetLogger(&FatalOnlyLogger);
return 0;
}
@@ -202,15 +214,10 @@
SnapshotFuzzEnv* GetSnapshotFuzzEnv() {
[[maybe_unused]] static auto allow_logging = AllowLoggingDuringGlobalInit();
static SnapshotFuzzEnv env;
- [[maybe_unused]] static auto stop_logging = StopLoggingAfterGlobalInit();
return &env;
}
-} // namespace android::snapshot
-
-DEFINE_PROTO_FUZZER(const SnapshotFuzzData& snapshot_fuzz_data) {
- using namespace android::snapshot;
-
+SnapshotTestModule SetUpTest(const SnapshotFuzzData& snapshot_fuzz_data) {
current_data = &snapshot_fuzz_data;
auto env = GetSnapshotFuzzEnv();
@@ -219,9 +226,127 @@
auto test_module = env->CheckCreateSnapshotManager(snapshot_fuzz_data);
current_module = &test_module;
CHECK(test_module.snapshot);
+ return test_module;
+}
- SnapshotManagerAction::ExecuteAll(test_module.snapshot.get(), snapshot_fuzz_data.actions());
-
+void TearDownTest() {
current_module = nullptr;
current_data = nullptr;
}
+
+} // namespace android::snapshot
+
+DEFINE_PROTO_FUZZER(const SnapshotFuzzData& snapshot_fuzz_data) {
+ using namespace android::snapshot;
+
+ [[maybe_unused]] static auto stop_logging = StopLoggingAfterGlobalInit();
+ auto test_module = SetUpTest(snapshot_fuzz_data);
+ SnapshotManagerAction::ExecuteAll(test_module.snapshot.get(), snapshot_fuzz_data.actions());
+ TearDownTest();
+}
+
+namespace android::snapshot {
+
+// Work-around to cast a 'void' value to Result<void>.
+template <typename T>
+struct GoodResult {
+ template <typename F>
+ static Result<T> Cast(F&& f) {
+ return f();
+ }
+};
+
+template <>
+struct GoodResult<void> {
+ template <typename F>
+ static Result<void> Cast(F&& f) {
+ f();
+ return {};
+ }
+};
+
+class LibsnapshotFuzzerTest : public ::testing::Test {
+ protected:
+ static void SetUpTestCase() {
+ // Do initialization once.
+ (void)GetSnapshotFuzzEnv();
+ }
+ void SetUp() override {
+ bool is_virtual_ab = GetBoolProperty("ro.virtual_ab.enabled", false);
+ if (!is_virtual_ab) GTEST_SKIP() << "Test only runs on Virtual A/B devices.";
+ }
+ void SetUpFuzzData(const std::string& fn) {
+ auto path = android::base::GetExecutableDirectory() + "/corpus/"s + fn;
+ std::string proto_text;
+ ASSERT_TRUE(ReadFileToString(path, &proto_text));
+ snapshot_fuzz_data_ = std::make_unique<SnapshotFuzzData>();
+ ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(proto_text,
+ snapshot_fuzz_data_.get()));
+ test_module_ = android::snapshot::SetUpTest(*snapshot_fuzz_data_);
+ }
+ void TearDown() override { android::snapshot::TearDownTest(); }
+ template <typename FuzzFunction>
+ Result<typename FuzzFunction::ReturnType> Execute(int action_index) {
+ if (action_index >= snapshot_fuzz_data_->actions_size()) {
+ return Error() << "Index " << action_index << " is out of bounds ("
+ << snapshot_fuzz_data_->actions_size() << " actions in corpus";
+ }
+ const auto& action_proto = snapshot_fuzz_data_->actions(action_index);
+ const auto* field_desc =
+ android::fuzz::GetValueFieldDescriptor<typename FuzzFunction::ActionType>(
+ action_proto);
+ if (field_desc == nullptr) {
+ return Error() << "Action at index " << action_index << " has no value defined.";
+ }
+ if (FuzzFunction::tag != field_desc->number()) {
+ return Error() << "Action at index " << action_index << " is expected to be "
+ << FuzzFunction::name << ", but it is " << field_desc->name()
+ << " in corpus.";
+ }
+ return GoodResult<typename FuzzFunction::ReturnType>::Cast([&]() {
+ return android::fuzz::ActionPerformer<FuzzFunction>::Invoke(test_module_.snapshot.get(),
+ action_proto, field_desc);
+ });
+ }
+
+ std::unique_ptr<SnapshotFuzzData> snapshot_fuzz_data_;
+ SnapshotTestModule test_module_;
+};
+
+#define SNAPSHOT_FUZZ_FN_NAME(name) FUZZ_FUNCTION_CLASS_NAME(SnapshotManagerAction, name)
+
+MATCHER_P(ResultIs, expected, "") {
+ if (!arg.ok()) {
+ *result_listener << arg.error();
+ return false;
+ }
+ *result_listener << "expected: " << expected;
+ return arg.value() == expected;
+}
+
+#define ASSERT_RESULT_TRUE(actual) ASSERT_THAT(actual, ResultIs(true))
+
+// Check that launch_device.txt is executed correctly.
+TEST_F(LibsnapshotFuzzerTest, LaunchDevice) {
+ SetUpFuzzData("launch_device.txt");
+
+ int i = 0;
+ ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(BeginUpdate)>(i++));
+ ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(CreateUpdateSnapshots)>(i++));
+ ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(MapUpdateSnapshot)>(i++)) << "sys_b";
+ ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(MapUpdateSnapshot)>(i++)) << "vnd_b";
+ ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(MapUpdateSnapshot)>(i++)) << "prd_b";
+ ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(FinishedSnapshotWrites)>(i++));
+ ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(UnmapUpdateSnapshot)>(i++)) << "sys_b";
+ ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(UnmapUpdateSnapshot)>(i++)) << "vnd_b";
+ ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(UnmapUpdateSnapshot)>(i++)) << "prd_b";
+ ASSERT_RESULT_OK(Execute<SNAPSHOT_FUZZ_FN_NAME(SwitchSlot)>(i++));
+ ASSERT_EQ("_b", test_module_.device_info->GetSlotSuffix());
+ ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(NeedSnapshotsInFirstStageMount)>(i++));
+ ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(CreateLogicalAndSnapshotPartitions)>(i++));
+ ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(InitiateMerge)>(i++));
+ ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(ProcessUpdateState)>(i++));
+ ASSERT_EQ(i, snapshot_fuzz_data_->actions_size()) << "Not all actions are executed.";
+}
+
+} // namespace android::snapshot