[M120 Migration][MM][CAPI] Fix the logic for media using capi player.
[platform/framework/web/chromium-efl.git] / media / mojo / services / webrtc_video_perf_mojolpm_fuzzer.cc
1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <stdint.h>
6 #include <utility>
7
8 #include "base/command_line.h"
9 #include "base/logging.h"
10 #include "base/notreached.h"
11 #include "base/task/single_thread_task_runner.h"
12 #include "base/test/task_environment.h"
13 #include "base/test/test_timeouts.h"
14 #include "components/leveldb_proto/testing/fake_db.h"
15 #include "media/capabilities/webrtc_video_stats.pb.h"
16 #include "media/capabilities/webrtc_video_stats_db_impl.h"
17 #include "media/mojo/mojom/webrtc_video_perf.mojom-mojolpm.h"
18 #include "media/mojo/services/webrtc_video_perf_history.h"
19 #include "media/mojo/services/webrtc_video_perf_mojolpm_fuzzer.pb.h"
20 #include "media/mojo/services/webrtc_video_perf_recorder.h"
21 #include "third_party/libprotobuf-mutator/src/src/libfuzzer/libfuzzer_macro.h"
22
23 namespace media {
24
25 // Helper class to call private constructor of friend class.
26 class WebrtcVideoPerfLPMFuzzerHelper {
27  public:
28   static std::unique_ptr<WebrtcVideoStatsDBImpl> CreateWebrtcVideoStatsDbImpl(
29       std::unique_ptr<leveldb_proto::ProtoDatabase<WebrtcVideoStatsEntryProto>>
30           proto_db) {
31     return base::WrapUnique(new WebrtcVideoStatsDBImpl(std::move(proto_db)));
32   }
33 };
34
35 namespace {
36
37 struct InitGlobals {
38   InitGlobals() {
39     // The call to CommandLine::Init is needed so that TestTimeouts::Initialize
40     // does not fail.
41     bool success = base::CommandLine::Init(0, nullptr);
42     DCHECK(success);
43     // TaskEnvironment requires TestTimeouts initialization to watch for
44     // problematic long-running tasks.
45     TestTimeouts::Initialize();
46
47     // Mark this thread as an IO_THREAD with MOCK_TIME, and ensure that Now()
48     // is driven from the same mock clock.
49     task_environment = std::make_unique<base::test::TaskEnvironment>(
50         base::test::TaskEnvironment::MainThreadType::IO,
51         base::test::TaskEnvironment::TimeSource::MOCK_TIME);
52   }
53
54   // This allows us to mock time for all threads.
55   std::unique_ptr<base::test::TaskEnvironment> task_environment;
56 };
57
58 InitGlobals* init_globals = new InitGlobals();
59
60 base::test::TaskEnvironment& GetEnvironment() {
61   return *init_globals->task_environment;
62 }
63
64 scoped_refptr<base::SingleThreadTaskRunner> GetFuzzerTaskRunner() {
65   return GetEnvironment().GetMainThreadTaskRunner();
66 }
67
68 // This in-memory database uses the FakeDB proto implementation as the
69 // underlying storage. The underlying FakeDB class requires that all callbacks
70 // are triggered manually. This class is used as a convenience class triggering
71 // the callbacks with success=true.
72 class InMemoryWebrtcVideoPerfDb
73     : public leveldb_proto::test::FakeDB<WebrtcVideoStatsEntryProto> {
74  public:
75   explicit InMemoryWebrtcVideoPerfDb(EntryMap* db) : FakeDB(db) {}
76
77   // Partial ProtoDatabase implementation.
78   void Init(leveldb_proto::Callbacks::InitStatusCallback callback) override {
79     FakeDB::Init(std::move(callback));
80     InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
81   }
82
83   void GetEntry(
84       const std::string& key,
85       typename leveldb_proto::Callbacks::Internal<
86           WebrtcVideoStatsEntryProto>::GetCallback callback) override {
87     FakeDB::GetEntry(key, std::move(callback));
88     // Run callback.
89     GetCallback(true);
90   }
91
92   void LoadKeysAndEntriesWhile(
93       const std::string& start,
94       const leveldb_proto::KeyIteratorController& controller,
95       typename leveldb_proto::Callbacks::Internal<WebrtcVideoStatsEntryProto>::
96           LoadKeysAndEntriesCallback callback) override {
97     FakeDB::LoadKeysAndEntriesWhile(start, controller, std::move(callback));
98     // Run callback.
99     LoadCallback(true);
100   }
101
102   void UpdateEntries(
103       std::unique_ptr<typename ProtoDatabase<
104           WebrtcVideoStatsEntryProto>::KeyEntryVector> entries_to_save,
105       std::unique_ptr<std::vector<std::string>> keys_to_remove,
106       leveldb_proto::Callbacks::UpdateCallback callback) override {
107     FakeDB::UpdateEntries(std::move(entries_to_save), std::move(keys_to_remove),
108                           std::move(callback));
109     // Run callback.
110     UpdateCallback(true);
111   }
112
113   void UpdateEntriesWithRemoveFilter(
114       std::unique_ptr<typename leveldb_proto::Util::Internal<
115           WebrtcVideoStatsEntryProto>::KeyEntryVector> entries_to_save,
116       const leveldb_proto::KeyFilter& filter,
117       leveldb_proto::Callbacks::UpdateCallback callback) override {
118     FakeDB::UpdateEntriesWithRemoveFilter(std::move(entries_to_save), filter,
119                                           std::move(callback));
120     // Run callback.
121     UpdateCallback(true);
122   }
123 };
124
125 class WebrtcVideoPerfLPMFuzzer {
126  public:
127   WebrtcVideoPerfLPMFuzzer(
128       const fuzzing::webrtc_video_perf::proto::Testcase& testcase)
129       : testcase_(testcase) {
130     // Create all objects that are needed and connect everything.
131     in_memory_db_ = new InMemoryWebrtcVideoPerfDb(&in_memory_db_map_);
132     std::unique_ptr<WebrtcVideoStatsDBImpl> stats_db =
133         WebrtcVideoPerfLPMFuzzerHelper::CreateWebrtcVideoStatsDbImpl(
134             std::unique_ptr<InMemoryWebrtcVideoPerfDb>(in_memory_db_));
135     perf_history_ =
136         std::make_unique<WebrtcVideoPerfHistory>(std::move(stats_db));
137     perf_recorder_ = std::make_unique<WebrtcVideoPerfRecorder>(
138         perf_history_->GetSaveCallback());
139   }
140
141   void NextAction() {
142     const auto& action = testcase_->actions(action_index_);
143     switch (action.action_case()) {
144       case fuzzing::webrtc_video_perf::proto::Action::kUpdateRecord: {
145         const auto& update_record = action.update_record();
146         auto features_ptr = media::mojom::WebrtcPredictionFeatures::New();
147         auto video_stats_ptr = media::mojom::WebrtcVideoStats::New();
148         mojolpm::FromProto(update_record.features(), features_ptr);
149         mojolpm::FromProto(update_record.video_stats(), video_stats_ptr);
150         perf_recorder_->UpdateRecord(std::move(features_ptr),
151                                      std::move(video_stats_ptr));
152         break;
153       }
154       case fuzzing::webrtc_video_perf::proto::Action::kGetPerfInfo: {
155         const auto& get_perf_info = action.get_perf_info();
156         auto features_ptr = media::mojom::WebrtcPredictionFeatures::New();
157         mojolpm::FromProto(get_perf_info.features(), features_ptr);
158         perf_history_->GetPerfInfo(std::move(features_ptr),
159                                    get_perf_info.frames_per_second(),
160                                    base::DoNothing());
161         break;
162       }
163       default: {
164         // Do nothing.
165       }
166     }
167     ++action_index_;
168   }
169
170   bool IsFinished() { return action_index_ >= testcase_->actions_size(); }
171
172  private:
173   const raw_ref<const fuzzing::webrtc_video_perf::proto::Testcase> testcase_;
174   int action_index_ = 0;
175
176   // Database storage.
177   InMemoryWebrtcVideoPerfDb::EntryMap in_memory_db_map_;
178   // Proto buffer database implementation that uses `in_memory_db_map_` as
179   // storage.
180   raw_ptr<InMemoryWebrtcVideoPerfDb> in_memory_db_;
181   std::unique_ptr<WebrtcVideoPerfHistory> perf_history_;
182   std::unique_ptr<WebrtcVideoPerfRecorder> perf_recorder_;
183 };
184
185 void NextAction(WebrtcVideoPerfLPMFuzzer* testcase,
186                 base::OnceClosure fuzzer_run_loop) {
187   if (!testcase->IsFinished()) {
188     testcase->NextAction();
189     GetFuzzerTaskRunner()->PostTask(
190         FROM_HERE, base::BindOnce(NextAction, base::Unretained(testcase),
191                                   std::move(fuzzer_run_loop)));
192   } else {
193     std::move(fuzzer_run_loop).Run();
194   }
195 }
196
197 void RunTestcase(WebrtcVideoPerfLPMFuzzer* testcase) {
198   base::RunLoop fuzzer_run_loop;
199   GetFuzzerTaskRunner()->PostTask(
200       FROM_HERE, base::BindOnce(NextAction, base::Unretained(testcase),
201                                 fuzzer_run_loop.QuitClosure()));
202   // Make sure that all callbacks have completed.
203   constexpr base::TimeDelta kTimeout = base::Seconds(5);
204   GetEnvironment().FastForwardBy(kTimeout);
205   fuzzer_run_loop.Run();
206 }
207
208 }  // namespace
209
210 DEFINE_BINARY_PROTO_FUZZER(
211     const fuzzing::webrtc_video_perf::proto::Testcase& testcase) {
212   if (!testcase.actions_size()) {
213     return;
214   }
215
216   WebrtcVideoPerfLPMFuzzer webtc_video_perf_fuzzer_instance(testcase);
217   base::RunLoop main_run_loop;
218
219   GetFuzzerTaskRunner()->PostTaskAndReply(
220       FROM_HERE,
221       base::BindOnce(RunTestcase,
222                      base::Unretained(&webtc_video_perf_fuzzer_instance)),
223       main_run_loop.QuitClosure());
224   main_run_loop.Run();
225 }
226
227 }  // namespace media