[M120 Migration][MM][CAPI] Fix the logic for media using capi player.
[platform/framework/web/chromium-efl.git] / media / mojo / services / cdm_service_unittest.cc
1 // Copyright 2018 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 "media/mojo/services/cdm_service.h"
6
7 #include <memory>
8 #include <tuple>
9
10 #include "base/files/file_path.h"
11 #include "base/functional/bind.h"
12 #include "base/memory/raw_ptr.h"
13 #include "base/run_loop.h"
14 #include "base/test/task_environment.h"
15 #include "base/unguessable_token.h"
16 #include "build/build_config.h"
17 #include "media/base/mock_filters.h"
18 #include "media/cdm/clear_key_cdm_common.h"
19 #include "media/cdm/default_cdm_factory.h"
20 #include "media/media_buildflags.h"
21 #include "mojo/public/cpp/bindings/pending_remote.h"
22 #include "mojo/public/cpp/bindings/remote.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 #include "url/gurl.h"
26
27 namespace media {
28
29 namespace {
30
31 using testing::_;
32 using testing::Invoke;
33 using testing::InvokeWithoutArgs;
34 using testing::NiceMock;
35 using testing::Return;
36
37 MATCHER_P(MatchesResult, success, "") {
38   return arg->success == success;
39 }
40
41 // MockCdmFactory treats any non-empty key system as valid and the empty key
42 // system as invalid.
43 const char kInvalidKeySystem[] = "";
44
45 // Needed since MockCdmServiceClient needs to return unique_ptr of CdmFactory.
46 class CdmFactoryWrapper : public CdmFactory {
47  public:
48   explicit CdmFactoryWrapper(CdmFactory* cdm_factory)
49       : cdm_factory_(cdm_factory) {}
50
51   // CdmFactory implementation.
52   void Create(const CdmConfig& cdm_config,
53               const SessionMessageCB& session_message_cb,
54               const SessionClosedCB& session_closed_cb,
55               const SessionKeysChangeCB& session_keys_change_cb,
56               const SessionExpirationUpdateCB& session_expiration_update_cb,
57               CdmCreatedCB cdm_created_cb) override {
58     cdm_factory_->Create(cdm_config, session_message_cb, session_closed_cb,
59                          session_keys_change_cb, session_expiration_update_cb,
60                          std::move(cdm_created_cb));
61   }
62
63  private:
64   const raw_ptr<CdmFactory> cdm_factory_;
65 };
66
67 class MockCdmServiceClient : public CdmService::Client {
68  public:
69   explicit MockCdmServiceClient(CdmFactory* cdm_factory)
70       : cdm_factory_(cdm_factory) {}
71   ~MockCdmServiceClient() override = default;
72
73   // CdmService::Client implementation.
74   MOCK_METHOD0(EnsureSandboxed, void());
75
76   std::unique_ptr<CdmFactory> CreateCdmFactory(
77       mojom::FrameInterfaceFactory* frame_interfaces) override {
78     return std::make_unique<CdmFactoryWrapper>(cdm_factory_);
79   }
80
81 #if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION)
82   void AddCdmHostFilePaths(std::vector<CdmHostFilePath>*) override {}
83 #endif  // BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION)
84
85  private:
86   const raw_ptr<CdmFactory> cdm_factory_;
87 };
88
89 class CdmServiceTest : public testing::Test {
90  public:
91   CdmServiceTest() = default;
92
93   CdmServiceTest(const CdmServiceTest&) = delete;
94   CdmServiceTest& operator=(const CdmServiceTest&) = delete;
95
96   ~CdmServiceTest() override = default;
97
98   MOCK_METHOD0(CdmServiceIdle, void());
99   MOCK_METHOD0(CdmFactoryConnectionClosed, void());
100   MOCK_METHOD0(CdmConnectionClosed, void());
101
102   void Initialize() {
103     EXPECT_CALL(*mock_cdm_, GetCdmContext())
104         .WillRepeatedly(Return(&cdm_context_));
105
106     auto mock_cdm_service_client =
107         std::make_unique<MockCdmServiceClient>(&mock_cdm_factory_);
108     mock_cdm_service_client_ = mock_cdm_service_client.get();
109
110     service_ = std::make_unique<CdmService>(
111         std::move(mock_cdm_service_client),
112         cdm_service_remote_.BindNewPipeAndPassReceiver());
113     cdm_service_remote_.set_idle_handler(
114         base::TimeDelta(), base::BindRepeating(&CdmServiceTest::CdmServiceIdle,
115                                                base::Unretained(this)));
116
117     mojo::PendingRemote<mojom::FrameInterfaceFactory> interfaces;
118     std::ignore = interfaces.InitWithNewPipeAndPassReceiver();
119
120     ASSERT_FALSE(cdm_factory_remote_);
121     cdm_service_remote_->CreateCdmFactory(
122         cdm_factory_remote_.BindNewPipeAndPassReceiver(),
123         std::move(interfaces));
124     cdm_service_remote_.FlushForTesting();
125     ASSERT_TRUE(cdm_factory_remote_);
126     cdm_factory_remote_.set_disconnect_handler(base::BindOnce(
127         &CdmServiceTest::CdmFactoryConnectionClosed, base::Unretained(this)));
128   }
129
130   void InitializeCdm(const std::string& key_system, bool expected_result) {
131     cdm_factory_remote_->CreateCdm(
132         {key_system, false, false, false},
133         base::BindOnce(&CdmServiceTest::OnCdmCreated, base::Unretained(this),
134                        expected_result));
135     cdm_factory_remote_.FlushForTesting();
136   }
137
138   void DestroyService() { service_.reset(); }
139
140   MockCdmServiceClient* mock_cdm_service_client() {
141     return mock_cdm_service_client_;
142   }
143
144   CdmService* cdm_service() { return service_.get(); }
145
146   base::test::TaskEnvironment task_environment_;
147   mojo::Remote<mojom::CdmService> cdm_service_remote_;
148   mojo::Remote<mojom::CdmFactory> cdm_factory_remote_;
149   mojo::Remote<mojom::ContentDecryptionModule> cdm_remote_;
150
151   // MojoCdmService will always create/use `mock_cdm_factory_` and `mock_cdm_`,
152   // so it's easier to set expectations on them.
153   scoped_refptr<MockCdm> mock_cdm_{new MockCdm()};
154   MockCdmFactory mock_cdm_factory_{mock_cdm_};
155   NiceMock<MockCdmContext> cdm_context_;
156
157  private:
158   void OnCdmCreated(bool expected_result,
159                     mojo::PendingRemote<mojom::ContentDecryptionModule> remote,
160                     mojom::CdmContextPtr cdm_context,
161                     const std::string& error_message) {
162     if (!expected_result) {
163       EXPECT_FALSE(remote);
164       EXPECT_FALSE(cdm_context);
165       EXPECT_TRUE(!error_message.empty());
166       return;
167     }
168     EXPECT_TRUE(remote);
169     EXPECT_TRUE(error_message.empty());
170     cdm_remote_.Bind(std::move(remote));
171     cdm_remote_.set_disconnect_handler(base::BindOnce(
172         &CdmServiceTest::CdmConnectionClosed, base::Unretained(this)));
173   }
174   std::unique_ptr<CdmService> service_;
175   raw_ptr<MockCdmServiceClient, AcrossTasksDanglingUntriaged>
176       mock_cdm_service_client_ = nullptr;
177 };
178
179 }  // namespace
180
181 TEST_F(CdmServiceTest, InitializeCdm_Success) {
182   Initialize();
183   InitializeCdm(kClearKeyKeySystem, true);
184 }
185
186 TEST_F(CdmServiceTest, InitializeCdm_InvalidKeySystem) {
187   Initialize();
188   InitializeCdm(kInvalidKeySystem, false);
189 }
190
191 TEST_F(CdmServiceTest, DestroyAndRecreateCdm) {
192   Initialize();
193   InitializeCdm(kClearKeyKeySystem, true);
194   cdm_remote_.reset();
195   InitializeCdm(kClearKeyKeySystem, true);
196 }
197
198 // CdmFactory disconnection will cause the service to idle.
199 TEST_F(CdmServiceTest, DestroyCdmFactory) {
200   Initialize();
201   auto* service = cdm_service();
202
203   InitializeCdm(kClearKeyKeySystem, true);
204   EXPECT_EQ(service->BoundCdmFactorySizeForTesting(), 1u);
205   EXPECT_EQ(service->UnboundCdmFactorySizeForTesting(), 0u);
206
207   cdm_factory_remote_.reset();
208   EXPECT_CALL(*this, CdmServiceIdle());
209   base::RunLoop().RunUntilIdle();
210   EXPECT_EQ(service->BoundCdmFactorySizeForTesting(), 0u);
211   EXPECT_EQ(service->UnboundCdmFactorySizeForTesting(), 1u);
212 }
213
214 // Destroy service will destroy the CdmFactory and all CDMs.
215 TEST_F(CdmServiceTest, DestroyCdmService_AfterCdmCreation) {
216   Initialize();
217   InitializeCdm(kClearKeyKeySystem, true);
218
219   base::RunLoop run_loop;
220   // Ideally we should not care about order, and should only quit the loop when
221   // both connections are closed.
222   EXPECT_CALL(*this, CdmFactoryConnectionClosed());
223   EXPECT_CALL(*this, CdmConnectionClosed())
224       .WillOnce(Invoke(&run_loop, &base::RunLoop::Quit));
225   DestroyService();
226   run_loop.Run();
227 }
228
229 // Before the CDM is fully created, CdmService has been destroyed. We should
230 // fail gracefully instead of a crash. See crbug.com/1190319.
231 TEST_F(CdmServiceTest, DestroyCdmService_DuringCdmCreation) {
232   base::RunLoop run_loop;
233   EXPECT_CALL(*this, CdmFactoryConnectionClosed())
234       .WillOnce(Invoke(&run_loop, &base::RunLoop::Quit));
235   mock_cdm_factory_.SetBeforeCreationCB(base::BindRepeating(
236       &CdmServiceTest::DestroyService, base::Unretained(this)));
237   Initialize();
238   InitializeCdm(kClearKeyKeySystem, true);
239   run_loop.Run();
240 }
241
242 }  // namespace media