blob: acc3082a7a9d5825f6f25a6a2e654f517be407a7 [file] [log] [blame]
hkuang26587cb2020-01-16 10:36:08 -08001/*
2 * Copyright (C) 2020 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// Unit Test for TranscodingClientManager
18
19// #define LOG_NDEBUG 0
20#define LOG_TAG "TranscodingClientManagerTest"
21
Chong Zhang6d58e4b2020-03-31 09:41:10 -070022#include <aidl/android/media/BnTranscodingClientCallback.h>
hkuang26587cb2020-01-16 10:36:08 -080023#include <aidl/android/media/IMediaTranscodingService.h>
hkuang26587cb2020-01-16 10:36:08 -080024#include <android-base/logging.h>
25#include <android/binder_manager.h>
26#include <android/binder_process.h>
27#include <gtest/gtest.h>
Chong Zhang6d58e4b2020-03-31 09:41:10 -070028#include <media/SchedulerClientInterface.h>
hkuang26587cb2020-01-16 10:36:08 -080029#include <media/TranscodingClientManager.h>
Chong Zhang6d58e4b2020-03-31 09:41:10 -070030#include <media/TranscodingRequest.h>
hkuang26587cb2020-01-16 10:36:08 -080031#include <utils/Log.h>
32
Chong Zhang6d58e4b2020-03-31 09:41:10 -070033#include <list>
34
hkuang26587cb2020-01-16 10:36:08 -080035namespace android {
36
37using Status = ::ndk::ScopedAStatus;
Chong Zhang6d58e4b2020-03-31 09:41:10 -070038using ::aidl::android::media::BnTranscodingClientCallback;
39using ::aidl::android::media::IMediaTranscodingService;
40using ::aidl::android::media::TranscodingErrorCode;
41using ::aidl::android::media::TranscodingJobParcel;
42using ::aidl::android::media::TranscodingRequestParcel;
43using ::aidl::android::media::TranscodingResultParcel;
hkuang26587cb2020-01-16 10:36:08 -080044
Chong Zhang6d58e4b2020-03-31 09:41:10 -070045constexpr pid_t kInvalidClientPid = -1;
Chong Zhang8e062632020-03-31 10:56:37 -070046constexpr const char* kInvalidClientName = "";
47constexpr const char* kInvalidClientPackage = "";
hkuang26587cb2020-01-16 10:36:08 -080048
Chong Zhang6d58e4b2020-03-31 09:41:10 -070049constexpr pid_t kClientPid = 2;
50constexpr uid_t kClientUid = 3;
Chong Zhang8e062632020-03-31 10:56:37 -070051constexpr const char* kClientName = "TestClientName";
52constexpr const char* kClientPackage = "TestClientPackage";
hkuang26587cb2020-01-16 10:36:08 -080053
Chong Zhang6d58e4b2020-03-31 09:41:10 -070054struct TestClientCallback : public BnTranscodingClientCallback {
55 TestClientCallback() { ALOGI("TestClientCallback Created"); }
hkuang26587cb2020-01-16 10:36:08 -080056
Chong Zhang6d58e4b2020-03-31 09:41:10 -070057 virtual ~TestClientCallback() { ALOGI("TestClientCallback destroyed"); };
58
59 Status onTranscodingFinished(int32_t in_jobId,
60 const TranscodingResultParcel& in_result) override {
61 EXPECT_EQ(in_jobId, in_result.jobId);
62 mEventQueue.push_back(Finished(in_jobId));
hkuang26587cb2020-01-16 10:36:08 -080063 return Status::ok();
64 }
65
Chong Zhang6d58e4b2020-03-31 09:41:10 -070066 Status onTranscodingFailed(int32_t in_jobId, TranscodingErrorCode /*in_errorCode */) override {
67 mEventQueue.push_back(Failed(in_jobId));
hkuang26587cb2020-01-16 10:36:08 -080068 return Status::ok();
69 }
70
71 Status onAwaitNumberOfJobsChanged(int32_t /* in_jobId */, int32_t /* in_oldAwaitNumber */,
72 int32_t /* in_newAwaitNumber */) override {
73 return Status::ok();
74 }
75
76 Status onProgressUpdate(int32_t /* in_jobId */, int32_t /* in_progress */) override {
77 return Status::ok();
78 }
79
Chong Zhang6d58e4b2020-03-31 09:41:10 -070080 struct Event {
81 enum {
82 NoEvent,
83 Finished,
84 Failed,
85 } type;
86 int32_t jobId;
87 };
88
89 static constexpr Event NoEvent = {Event::NoEvent, 0};
90#define DECLARE_EVENT(action) \
91 static Event action(int32_t jobId) { return {Event::action, jobId}; }
92
93 DECLARE_EVENT(Finished);
94 DECLARE_EVENT(Failed);
95
96 const Event& popEvent() {
97 if (mEventQueue.empty()) {
98 mPoppedEvent = NoEvent;
99 } else {
100 mPoppedEvent = *mEventQueue.begin();
101 mEventQueue.pop_front();
102 }
103 return mPoppedEvent;
104 }
hkuang26587cb2020-01-16 10:36:08 -0800105
Chong Zhang8e062632020-03-31 10:56:37 -0700106private:
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700107 Event mPoppedEvent;
108 std::list<Event> mEventQueue;
109
110 TestClientCallback(const TestClientCallback&) = delete;
111 TestClientCallback& operator=(const TestClientCallback&) = delete;
112};
113
114bool operator==(const TestClientCallback::Event& lhs, const TestClientCallback::Event& rhs) {
115 return lhs.type == rhs.type && lhs.jobId == rhs.jobId;
116}
117
118struct TestScheduler : public SchedulerClientInterface {
119 TestScheduler() { ALOGI("TestScheduler Created"); }
120
121 virtual ~TestScheduler() { ALOGI("TestScheduler Destroyed"); }
122
123 bool submit(int64_t clientId, int32_t jobId, pid_t /*pid*/,
124 const TranscodingRequestParcel& request,
125 const std::weak_ptr<ITranscodingClientCallback>& clientCallback) override {
126 JobKeyType jobKey = std::make_pair(clientId, jobId);
127 if (mJobs.count(jobKey) > 0) {
128 return false;
129 }
130
131 // This is the secret name we'll check, to test error propagation from
132 // the scheduler back to client.
133 if (request.fileName == "bad_file") {
134 return false;
135 }
136
137 mJobs[jobKey].request = request;
138 mJobs[jobKey].callback = clientCallback;
139
140 mLastJob = jobKey;
141 return true;
142 }
143
144 bool cancel(int64_t clientId, int32_t jobId) override {
145 JobKeyType jobKey = std::make_pair(clientId, jobId);
146
147 if (mJobs.count(jobKey) == 0) {
148 return false;
149 }
150 mJobs.erase(jobKey);
151 return true;
152 }
153
154 bool getJob(int64_t clientId, int32_t jobId, TranscodingRequestParcel* request) override {
155 JobKeyType jobKey = std::make_pair(clientId, jobId);
156 if (mJobs.count(jobKey) == 0) {
157 return false;
158 }
159
160 *(TranscodingRequest*)request = mJobs[jobKey].request;
161 return true;
162 }
163
164 void finishLastJob() {
165 auto it = mJobs.find(mLastJob);
166 if (it == mJobs.end()) {
167 return;
168 }
169 {
170 auto clientCallback = it->second.callback.lock();
171 if (clientCallback != nullptr) {
172 clientCallback->onTranscodingFinished(
173 mLastJob.second, TranscodingResultParcel({mLastJob.second, 0}));
174 }
175 }
176 mJobs.erase(it);
177 }
178
179 void abortLastJob() {
180 auto it = mJobs.find(mLastJob);
181 if (it == mJobs.end()) {
182 return;
183 }
184 {
185 auto clientCallback = it->second.callback.lock();
186 if (clientCallback != nullptr) {
hkuang08b38d02020-04-17 14:29:33 -0700187 clientCallback->onTranscodingFailed(mLastJob.second,
188 TranscodingErrorCode::kUnknown);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700189 }
190 }
191 mJobs.erase(it);
192 }
193
194 struct Job {
195 TranscodingRequest request;
196 std::weak_ptr<ITranscodingClientCallback> callback;
197 };
198
199 typedef std::pair<int64_t, int32_t> JobKeyType;
200 std::map<JobKeyType, Job> mJobs;
201 JobKeyType mLastJob;
hkuang26587cb2020-01-16 10:36:08 -0800202};
203
204class TranscodingClientManagerTest : public ::testing::Test {
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700205public:
206 TranscodingClientManagerTest()
207 : mScheduler(new TestScheduler()),
208 mClientManager(new TranscodingClientManager(mScheduler)) {
hkuang5172cab2020-01-31 12:40:28 -0800209 ALOGD("TranscodingClientManagerTest created");
210 }
hkuang26587cb2020-01-16 10:36:08 -0800211
212 void SetUp() override {
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700213 mClientCallback1 = ::ndk::SharedRefBase::make<TestClientCallback>();
214 mClientCallback2 = ::ndk::SharedRefBase::make<TestClientCallback>();
215 mClientCallback3 = ::ndk::SharedRefBase::make<TestClientCallback>();
hkuang26587cb2020-01-16 10:36:08 -0800216 }
217
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700218 void TearDown() override { ALOGI("TranscodingClientManagerTest tear down"); }
hkuang26587cb2020-01-16 10:36:08 -0800219
220 ~TranscodingClientManagerTest() { ALOGD("TranscodingClientManagerTest destroyed"); }
221
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700222 void addMultipleClients() {
223 EXPECT_EQ(mClientManager->addClient(mClientCallback1, kClientPid, kClientUid, kClientName,
224 kClientPackage, &mClient1),
225 OK);
226 EXPECT_NE(mClient1, nullptr);
227
228 EXPECT_EQ(mClientManager->addClient(mClientCallback2, kClientPid, kClientUid, kClientName,
229 kClientPackage, &mClient2),
230 OK);
231 EXPECT_NE(mClient2, nullptr);
232
233 EXPECT_EQ(mClientManager->addClient(mClientCallback3, kClientPid, kClientUid, kClientName,
234 kClientPackage, &mClient3),
235 OK);
236 EXPECT_NE(mClient3, nullptr);
237
238 EXPECT_EQ(mClientManager->getNumOfClients(), 3);
239 }
240
241 void unregisterMultipleClients() {
242 EXPECT_TRUE(mClient1->unregister().isOk());
243 EXPECT_TRUE(mClient2->unregister().isOk());
244 EXPECT_TRUE(mClient3->unregister().isOk());
245 EXPECT_EQ(mClientManager->getNumOfClients(), 0);
246 }
247
248 std::shared_ptr<TestScheduler> mScheduler;
249 std::shared_ptr<TranscodingClientManager> mClientManager;
250 std::shared_ptr<ITranscodingClient> mClient1;
251 std::shared_ptr<ITranscodingClient> mClient2;
252 std::shared_ptr<ITranscodingClient> mClient3;
253 std::shared_ptr<TestClientCallback> mClientCallback1;
254 std::shared_ptr<TestClientCallback> mClientCallback2;
255 std::shared_ptr<TestClientCallback> mClientCallback3;
hkuang26587cb2020-01-16 10:36:08 -0800256};
257
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700258TEST_F(TranscodingClientManagerTest, TestAddingWithInvalidClientCallback) {
259 // Add a client with null callback and expect failure.
Chong Zhang8e062632020-03-31 10:56:37 -0700260 std::shared_ptr<ITranscodingClient> client;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700261 status_t err = mClientManager->addClient(nullptr, kClientPid, kClientUid, kClientName,
262 kClientPackage, &client);
Chong Zhang8e062632020-03-31 10:56:37 -0700263 EXPECT_EQ(err, BAD_VALUE);
hkuang26587cb2020-01-16 10:36:08 -0800264}
265
266TEST_F(TranscodingClientManagerTest, TestAddingWithInvalidClientPid) {
Chong Zhang8e062632020-03-31 10:56:37 -0700267 // Add a client with invalid Pid and expect failure.
268 std::shared_ptr<ITranscodingClient> client;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700269 status_t err = mClientManager->addClient(mClientCallback1, kInvalidClientPid, kClientUid,
270 kClientName, kClientPackage, &client);
Chong Zhang8e062632020-03-31 10:56:37 -0700271 EXPECT_EQ(err, BAD_VALUE);
272}
hkuang26587cb2020-01-16 10:36:08 -0800273
Chong Zhang8e062632020-03-31 10:56:37 -0700274TEST_F(TranscodingClientManagerTest, TestAddingWithInvalidClientName) {
275 // Add a client with invalid name and expect failure.
276 std::shared_ptr<ITranscodingClient> client;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700277 status_t err = mClientManager->addClient(mClientCallback1, kClientPid, kClientUid,
278 kInvalidClientName, kClientPackage, &client);
Chong Zhang8e062632020-03-31 10:56:37 -0700279 EXPECT_EQ(err, BAD_VALUE);
hkuang26587cb2020-01-16 10:36:08 -0800280}
281
282TEST_F(TranscodingClientManagerTest, TestAddingWithInvalidClientPackageName) {
Chong Zhang8e062632020-03-31 10:56:37 -0700283 // Add a client with invalid packagename and expect failure.
284 std::shared_ptr<ITranscodingClient> client;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700285 status_t err = mClientManager->addClient(mClientCallback1, kClientPid, kClientUid, kClientName,
286 kInvalidClientPackage, &client);
Chong Zhang8e062632020-03-31 10:56:37 -0700287 EXPECT_EQ(err, BAD_VALUE);
hkuang26587cb2020-01-16 10:36:08 -0800288}
289
290TEST_F(TranscodingClientManagerTest, TestAddingValidClient) {
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700291 // Add a valid client, should succeed.
Chong Zhang8e062632020-03-31 10:56:37 -0700292 std::shared_ptr<ITranscodingClient> client;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700293 status_t err = mClientManager->addClient(mClientCallback1, kClientPid, kClientUid, kClientName,
294 kClientPackage, &client);
Chong Zhang8e062632020-03-31 10:56:37 -0700295 EXPECT_EQ(err, OK);
296 EXPECT_NE(client.get(), nullptr);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700297 EXPECT_EQ(mClientManager->getNumOfClients(), 1);
hkuang26587cb2020-01-16 10:36:08 -0800298
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700299 // Unregister client, should succeed.
Chong Zhang8e062632020-03-31 10:56:37 -0700300 Status status = client->unregister();
301 EXPECT_TRUE(status.isOk());
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700302 EXPECT_EQ(mClientManager->getNumOfClients(), 0);
hkuang26587cb2020-01-16 10:36:08 -0800303}
304
305TEST_F(TranscodingClientManagerTest, TestAddingDupliacteClient) {
Chong Zhang8e062632020-03-31 10:56:37 -0700306 std::shared_ptr<ITranscodingClient> client;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700307 status_t err = mClientManager->addClient(mClientCallback1, kClientPid, kClientUid, kClientName,
308 kClientPackage, &client);
Chong Zhang8e062632020-03-31 10:56:37 -0700309 EXPECT_EQ(err, OK);
310 EXPECT_NE(client.get(), nullptr);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700311 EXPECT_EQ(mClientManager->getNumOfClients(), 1);
hkuang26587cb2020-01-16 10:36:08 -0800312
Chong Zhang8e062632020-03-31 10:56:37 -0700313 std::shared_ptr<ITranscodingClient> dupClient;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700314 err = mClientManager->addClient(mClientCallback1, kClientPid, kClientUid, "dupClient",
315 "dupPackage", &dupClient);
Chong Zhang8e062632020-03-31 10:56:37 -0700316 EXPECT_EQ(err, ALREADY_EXISTS);
317 EXPECT_EQ(dupClient.get(), nullptr);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700318 EXPECT_EQ(mClientManager->getNumOfClients(), 1);
hkuang26587cb2020-01-16 10:36:08 -0800319
Chong Zhang8e062632020-03-31 10:56:37 -0700320 Status status = client->unregister();
321 EXPECT_TRUE(status.isOk());
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700322 EXPECT_EQ(mClientManager->getNumOfClients(), 0);
hkuang26587cb2020-01-16 10:36:08 -0800323
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700324 err = mClientManager->addClient(mClientCallback1, kClientPid, kClientUid, "dupClient",
325 "dupPackage", &dupClient);
Chong Zhang8e062632020-03-31 10:56:37 -0700326 EXPECT_EQ(err, OK);
327 EXPECT_NE(dupClient.get(), nullptr);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700328 EXPECT_EQ(mClientManager->getNumOfClients(), 1);
hkuang26587cb2020-01-16 10:36:08 -0800329
Chong Zhang8e062632020-03-31 10:56:37 -0700330 status = dupClient->unregister();
331 EXPECT_TRUE(status.isOk());
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700332 EXPECT_EQ(mClientManager->getNumOfClients(), 0);
hkuang26587cb2020-01-16 10:36:08 -0800333}
334
335TEST_F(TranscodingClientManagerTest, TestAddingMultipleClient) {
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700336 addMultipleClients();
337 unregisterMultipleClients();
338}
hkuang26587cb2020-01-16 10:36:08 -0800339
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700340TEST_F(TranscodingClientManagerTest, TestSubmitCancelGetJobs) {
341 addMultipleClients();
hkuang26587cb2020-01-16 10:36:08 -0800342
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700343 // Test jobId assignment.
344 TranscodingRequestParcel request;
345 request.fileName = "test_file_0";
346 TranscodingJobParcel job;
347 bool result;
348 EXPECT_TRUE(mClient1->submitRequest(request, &job, &result).isOk());
349 EXPECT_TRUE(result);
350 EXPECT_EQ(job.jobId, 0);
hkuang26587cb2020-01-16 10:36:08 -0800351
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700352 request.fileName = "test_file_1";
353 EXPECT_TRUE(mClient1->submitRequest(request, &job, &result).isOk());
354 EXPECT_TRUE(result);
355 EXPECT_EQ(job.jobId, 1);
hkuang26587cb2020-01-16 10:36:08 -0800356
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700357 request.fileName = "test_file_2";
358 EXPECT_TRUE(mClient1->submitRequest(request, &job, &result).isOk());
359 EXPECT_TRUE(result);
360 EXPECT_EQ(job.jobId, 2);
361
362 // Test submit bad request (no valid fileName) fails.
363 TranscodingRequestParcel badRequest;
364 badRequest.fileName = "bad_file";
365 EXPECT_TRUE(mClient1->submitRequest(badRequest, &job, &result).isOk());
366 EXPECT_FALSE(result);
367
368 // Test get jobs by id.
369 EXPECT_TRUE(mClient1->getJobWithId(2, &job, &result).isOk());
370 EXPECT_EQ(job.jobId, 2);
371 EXPECT_EQ(job.request.fileName, "test_file_2");
372 EXPECT_TRUE(result);
373
374 // Test get jobs by invalid id fails.
375 EXPECT_TRUE(mClient1->getJobWithId(100, &job, &result).isOk());
376 EXPECT_FALSE(result);
377
378 // Test cancel non-existent job fail.
379 EXPECT_TRUE(mClient2->cancelJob(100, &result).isOk());
380 EXPECT_FALSE(result);
381
382 // Test cancel valid jobId in arbitrary order.
383 EXPECT_TRUE(mClient1->cancelJob(2, &result).isOk());
384 EXPECT_TRUE(result);
385
386 EXPECT_TRUE(mClient1->cancelJob(0, &result).isOk());
387 EXPECT_TRUE(result);
388
389 EXPECT_TRUE(mClient1->cancelJob(1, &result).isOk());
390 EXPECT_TRUE(result);
391
392 // Test cancel job again fails.
393 EXPECT_TRUE(mClient1->cancelJob(1, &result).isOk());
394 EXPECT_FALSE(result);
395
396 // Test get job after cancel fails.
397 EXPECT_TRUE(mClient1->getJobWithId(2, &job, &result).isOk());
398 EXPECT_FALSE(result);
399
400 // Test jobId independence for each client.
401 EXPECT_TRUE(mClient2->submitRequest(request, &job, &result).isOk());
402 EXPECT_TRUE(result);
403 EXPECT_EQ(job.jobId, 0);
404
405 EXPECT_TRUE(mClient2->submitRequest(request, &job, &result).isOk());
406 EXPECT_TRUE(result);
407 EXPECT_EQ(job.jobId, 1);
408
409 unregisterMultipleClients();
410}
411
412TEST_F(TranscodingClientManagerTest, TestClientCallback) {
413 addMultipleClients();
414
415 TranscodingRequestParcel request;
416 request.fileName = "test_file_name";
417 TranscodingJobParcel job;
418 bool result;
419 EXPECT_TRUE(mClient1->submitRequest(request, &job, &result).isOk());
420 EXPECT_TRUE(result);
421 EXPECT_EQ(job.jobId, 0);
422
423 mScheduler->finishLastJob();
424 EXPECT_EQ(mClientCallback1->popEvent(), TestClientCallback::Finished(job.jobId));
425
426 EXPECT_TRUE(mClient1->submitRequest(request, &job, &result).isOk());
427 EXPECT_TRUE(result);
428 EXPECT_EQ(job.jobId, 1);
429
430 mScheduler->abortLastJob();
431 EXPECT_EQ(mClientCallback1->popEvent(), TestClientCallback::Failed(job.jobId));
432
433 EXPECT_TRUE(mClient1->submitRequest(request, &job, &result).isOk());
434 EXPECT_TRUE(result);
435 EXPECT_EQ(job.jobId, 2);
436
437 EXPECT_TRUE(mClient2->submitRequest(request, &job, &result).isOk());
438 EXPECT_TRUE(result);
439 EXPECT_EQ(job.jobId, 0);
440
441 mScheduler->finishLastJob();
442 EXPECT_EQ(mClientCallback2->popEvent(), TestClientCallback::Finished(job.jobId));
443
444 unregisterMultipleClients();
hkuang26587cb2020-01-16 10:36:08 -0800445}
446
Chong Zhang8e062632020-03-31 10:56:37 -0700447} // namespace android