diff options
| author | Yifan Hong <elsk@google.com> | 2020-05-05 14:34:38 -0700 |
|---|---|---|
| committer | Yifan Hong <elsk@google.com> | 2020-05-06 17:10:34 -0700 |
| commit | 8de84c3989e64d9b2bb6029b0b1589d8b51f974b (patch) | |
| tree | 542d8581a7e5984c749ce907ffe78f9e5edb9138 | |
| parent | 4e48f2b240062a19564e65ff24a9b86c306f762e (diff) | |
libsnapshot_fuzzer: Add tests
Add tests for the fuzzer itself. The test ensures that the
initial corpus is a good run on SnapshotManager (in the sense
that not only it doesn't crash, but also it executes as expected).
Also changed fuzz_utils so that impl functions return the
invocation result too, so that the test can check its values.
Test: run it
Bug: 154633114
Change-Id: I31ab7830f8c20a0575aaadabd038632d10f33962
| -rw-r--r-- | fs_mgr/TEST_MAPPING | 3 | ||||
| -rw-r--r-- | fs_mgr/libsnapshot/Android.bp | 20 | ||||
| -rw-r--r-- | fs_mgr/libsnapshot/fuzz_utils.h | 120 | ||||
| -rw-r--r-- | fs_mgr/libsnapshot/snapshot_fuzz.cpp | 189 |
4 files changed, 248 insertions, 84 deletions
diff --git a/fs_mgr/TEST_MAPPING b/fs_mgr/TEST_MAPPING index 676f446e72..6cd043013d 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 c1911022f1..2783e4de4c 100644 --- a/fs_mgr/libsnapshot/Android.bp +++ b/fs_mgr/libsnapshot/Android.bp @@ -246,8 +246,8 @@ cc_test { 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 @@ cc_fuzz { 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 @@ cc_fuzz { 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 4dc6cdc0b2..20b13b2fae 100644 --- a/fs_mgr/libsnapshot/fuzz_utils.h +++ b/fs_mgr/libsnapshot/fuzz_utils.h @@ -68,17 +68,25 @@ int CheckConsistency() { 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 @@ void ExecuteActionProto(typename Action::Class* module, 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 @@ FUZZ_DEFINE_PRIMITIVE_GETTER(float, GetFloat); // 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 @@ struct ActionPerfomer<FuzzFunction, void(const std::string&)> { // 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 @@ struct ActionPerfomer<FuzzFunction, void(const std::string&)> { // } // 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 @@ struct ActionPerfomer<FuzzFunction, void(const std::string&)> { // 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 1e90ace6f7..5b145c31f2 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::fuzz::CheckedCast; 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, RecoveryCreateSnapshotDevices); 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 @@ SNAPSHOT_FUZZ_FUNCTION(CreateLogicalAndSnapshotPartitions, } 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 @@ SNAPSHOT_FUZZ_FUNCTION(MapUpdateSnapshot, const CreateLogicalPartitionParamsProt 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 @@ void FatalOnlyLogger(LogId logid, LogSeverity severity, const char* tag, const c } // 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 @@ int StopLoggingAfterGlobalInit() { 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 @@ DEFINE_PROTO_FUZZER(const SnapshotFuzzData& snapshot_fuzz_data) { 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 |
