1 /*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "m3u8_unit_test.h"
16 #include "http_server_demo.h"
17
18 #include <new>
19 #define LOCAL true
20
21 using namespace OHOS;
22 using namespace OHOS::Media;
23 namespace OHOS::Media::Plugins::HttpPlugin {
24 using namespace testing::ext;
25 using namespace std;
26 constexpr uint32_t MAX_LOOP = 16;
27 std::unique_ptr<MediaAVCodec::HttpServerDemo> g_server = nullptr;
SetUpTestCase(void)28 void M3u8UnitTest::SetUpTestCase(void) {}
29
TearDownTestCase(void)30 void M3u8UnitTest::TearDownTestCase(void) {}
31
SetUp(void)32 void M3u8UnitTest::SetUp(void)
33 {
34 g_server = std::make_unique<MediaAVCodec::HttpServerDemo>();
35 g_server->StartServer();
36 }
37
TearDown(void)38 void M3u8UnitTest::TearDown(void)
39 {
40 g_server->StopServer();
41 g_server = nullptr;
42 }
43
44 HWTEST_F(M3u8UnitTest, Init_Tag_Updaters_Map_001, TestSize.Level1)
45 {
46 double duration = testM3u8->GetDuration();
47 bool isLive = testM3u8->IsLive();
48 EXPECT_GE(duration, 0.0);
49 EXPECT_EQ(isLive, false);
50 }
51
52 HWTEST_F(M3u8UnitTest, is_live_001, TestSize.Level1)
53 {
54 EXPECT_EQ(testM3u8->GetDuration(), 0.0);
55 }
56
57 HWTEST_F(M3u8UnitTest, ConstructorTest, TestSize.Level1)
58 {
59 M3U8 m3u8(testUri, testName);
60 // 检查 URI 和名称是否正确设置
61 ASSERT_EQ(m3u8.uri_, testUri);
62 ASSERT_EQ(m3u8.name_, testName);
63 // 这里可以添加更多的断言来检查初始化的状态
64 }
65
66 // 测试 Update 方法
67 HWTEST_F(M3u8UnitTest, UpdateTest, TestSize.Level1)
68 {
69 M3U8 m3u8("http://example.com/test.m3u8", "TestPlaylist");
70 std::string testPlaylist = "#EXTM3U\n#EXT-X-TARGETDURATION:10\n...";
71
72 // 测试有效的播放列表更新
73 EXPECT_TRUE(m3u8.Update(testPlaylist, true));
74
75 // 测试当播放列表不变时的更新
76 EXPECT_TRUE(m3u8.Update(testPlaylist, true));
77
78 // 测试无效的播放列表更新
79 EXPECT_FALSE(m3u8.Update("Invalid Playlist", true));
80 }
81
82 HWTEST_F(M3u8UnitTest, UPDATE_FROM_TAGS_TEST, TestSize.Level1)
83 {
84 M3U8 m3u8("http://example.com/test.m3u8", "TestPlaylist");
85 //
86 std::list<std::shared_ptr<Tag>> tags;
87 m3u8.UpdateFromTags(tags);
88 EXPECT_TRUE(m3u8.bLive_);
89 m3u8.isDecryptAble_ = true;
90 m3u8.UpdateFromTags(tags);
91 //
92 EXPECT_TRUE(m3u8.bLive_);
93 EXPECT_EQ(m3u8.files_.size(), 0);
94 m3u8.isDecryptAble_ = false;
95 m3u8.UpdateFromTags(tags);
96
97 //
98 EXPECT_TRUE(m3u8.bLive_);
99 EXPECT_EQ(m3u8.files_.size(), 0);
100 }
101
102 HWTEST_F(M3u8UnitTest, TEST_CONSTRUCTOR_WITH_NULL_KEY_AND_IV, TestSize.Level1)
103 {
104 M3U8Fragment m3u8("http://example.com", 10.0, 1, false);
105 M3U8Fragment fragment(m3u8, nullptr, nullptr);
106 EXPECT_EQ(fragment.duration_, 10.0);
107 EXPECT_EQ(fragment.sequence_, 1);
108 EXPECT_EQ(fragment.discont_, false);
109 //
110
111 for (int i = 0; i < static_cast<int>(MAX_LOOP); i++) {
112 EXPECT_NE(fragment.iv_[i], -1);
113 EXPECT_NE(fragment.key_[i], -1);
114 }
115 }
116
117 HWTEST_F(M3u8UnitTest, TEST_CONSTRUCTOR_WITH_VALID_KEY_AND_IV, TestSize.Level1)
118 {
119 M3U8Fragment m3u8("http://example.com", 10.0, 1, false);
120 uint8_t key[MAX_LOOP] = {1, 2, 3, 4, 5};
121 uint8_t iv[MAX_LOOP] = {6, 7, 8, 9, 10};
122 M3U8Fragment fragment(m3u8, key, iv);
123 EXPECT_EQ(fragment.uri_, "http://example.com");
124 EXPECT_EQ(fragment.duration_, 10.0);
125 EXPECT_EQ(fragment.sequence_, 1);
126 EXPECT_EQ(fragment.discont_, false);
127 //
128 for (int i = 0; i < 5; i++) {
129 EXPECT_EQ(fragment.iv_[i], iv[i]);
130 }
131 }
132
133 HWTEST_F(M3u8UnitTest, TEST_CONSTRUCTOR, TestSize.Level1)
134 {
135 M3U8 m3u8("http://example.com/test.m3u8", "Test M3U8");
136
137 // check url
138 EXPECT_EQ(m3u8.uri_, "http://example.com/test.m3u8");
139
140 //check name
141 EXPECT_EQ(m3u8.name_, "Test M3U8");
142
143 //check updaters map
144 EXPECT_FALSE(m3u8.tagUpdatersMap_.empty());
145 }
146
147 HWTEST_F(M3u8UnitTest, TEST_EMPTY_URI, TestSize.Level1)
148 {
149 M3U8 m3u8("", "Test M3U8");
150
151 // check url
152 EXPECT_EQ(m3u8.uri_, "");
153
154 //check name
155 EXPECT_EQ(m3u8.name_, "Test M3U8");
156
157 //check updaters map
158 EXPECT_FALSE(m3u8.tagUpdatersMap_.empty());
159 }
160
161 HWTEST_F(M3u8UnitTest, TEST_EMPTY_NAME, TestSize.Level1)
162 {
163 M3U8 m3u8("http://example.com/test.m3u8", "");
164
165 // check url
166 EXPECT_EQ(m3u8.uri_, "http://example.com/test.m3u8");
167
168 //check name
169 EXPECT_EQ(m3u8.name_, "");
170
171 //check updaters map
172 EXPECT_FALSE(m3u8.tagUpdatersMap_.empty());
173 }
174
175 // test get ext
176 HWTEST_F(M3u8UnitTest, GET_EXT_INF_TEST, TestSize.Level1)
177 {
178 M3U8 m3u8("http://example.com/test.m3u8", "");
179 auto tag = std::make_shared<AttributesTag>(HlsTag::EXTXDISCONTINUITY, "123");
180 auto attr1 = std::make_shared<Attribute>("DURATION", "3.5");
181 tag->AddAttribute(attr1);
182 double duration;
183 m3u8.GetExtInf(tag, duration);
184 //check name
185 EXPECT_DOUBLE_EQ(3.5, duration);
186 }
187
188 HWTEST_F(M3u8UnitTest, PARSE_KEY_METHOD_ATTRIBUTE, TestSize.Level1)
189 {
190 M3U8 m3u8("http://example.com/test.m3u8", "");
191 auto tag = std::make_shared<AttributesTag>(HlsTag::EXTXDISCONTINUITY, "123");
192 auto attr1 = std::make_shared<Attribute>("METHOD", "AES-128");
193 tag->AddAttribute(attr1);
194 m3u8.ParseKey(tag);
195 EXPECT_EQ(*m3u8.method_, "AES-128");
196 }
197
198 HWTEST_F(M3u8UnitTest, PARSE_KEY_URI_ATTRIBUTE, TestSize.Level1)
199 {
200 M3U8 m3u8("http://example.com/test.m3u8", "");
201 auto tag = std::make_shared<AttributesTag>(HlsTag::EXTXDISCONTINUITY, "123");
202 auto attr1 = std::make_shared<Attribute>("URI", "http://example.com/key.bin");
203 tag->AddAttribute(attr1);
204 m3u8.ParseKey(tag);
205 EXPECT_EQ(*m3u8.keyUri_, "http://example.com/key.bin");
206 }
207
208 HWTEST_F(M3u8UnitTest, PARSE_KEY_IV_ATTRIBUTE, TestSize.Level1)
209 {
210 M3U8 m3u8("http://example.com/test.m3u8", "");
211 auto tag = std::make_shared<AttributesTag>(HlsTag::EXTXDISCONTINUITY, "123");
212 auto attr1 = std::make_shared<Attribute>("IV", "0x12345678");
213 tag->AddAttribute(attr1);
214 m3u8.ParseKey(tag);
215 uint8_t vec[4] {0x12, 0x34, 0x56, 0x78};
216 EXPECT_NE(m3u8.iv_, vec);
217 }
218
219 HWTEST_F(M3u8UnitTest, PARSE_KEY_NO_ATTRIBUTE, TestSize.Level1)
220 {
221 M3U8 m3u8("http://example.com/test.m3u8", "");
222 auto tag = std::make_shared<AttributesTag>(HlsTag::EXTXDISCONTINUITY, "123");
223 m3u8.ParseKey(tag);
224 EXPECT_EQ(m3u8.method_, nullptr);
225 EXPECT_EQ(m3u8.keyUri_, nullptr);
226 uint8_t vec[4] {0, 0, 0, 0};
227 EXPECT_NE(m3u8.iv_, vec);
228 }
229
230 HWTEST_F(M3u8UnitTest, SAVE_DATA_VALID_DATA, TestSize.Level1)
231 {
232 M3U8 m3u8("http://example.com/test.m3u8", "");
233 uint8_t data[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
234 uint32_t len = 10;
235
236 bool result = m3u8.SaveData(data, len);
237
238 EXPECT_TRUE(result);
239 EXPECT_EQ(m3u8.keyLen_, len);
240 EXPECT_TRUE(m3u8.isDecryptKeyReady_);
241 }
242
243 HWTEST_F(M3u8UnitTest, SAVE_DATA_INVALID_DATA, TestSize.Level1)
244 {
245 M3U8 m3u8("http://example.com/test.m3u8", "");
246 uint8_t data[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
247 uint32_t len = 10;
248
249 bool result = m3u8.SaveData(data, len);
250
251 EXPECT_TRUE(result);
252 EXPECT_EQ(m3u8.keyLen_, len);
253 EXPECT_TRUE(m3u8.isDecryptKeyReady_);
254 }
255
256 HWTEST_F(M3u8UnitTest, SAVE_DATA_EXVEEDS_MAX_LOOP, TestSize.Level1)
257 {
258 M3U8 m3u8("http://example.com/test.m3u8", "");
259 uint8_t data[MAX_LOOP + 1];
260 uint32_t len = MAX_LOOP + 1;
261
262 bool result = m3u8.SaveData(data, len);
263
264 EXPECT_FALSE(result);
265 EXPECT_EQ(m3u8.keyLen_, 0);
266 EXPECT_FALSE(m3u8.isDecryptKeyReady_);
267 }
268
269 HWTEST_F(M3u8UnitTest, SET_DRM_INFO_NULL_KEY_URI, TestSize.Level1)
270 {
271 M3U8 m3u8("http://example.com/test.m3u8", "");
272 std::multimap<std::string, std::vector<uint8_t>> drmInfo;
273 EXPECT_FALSE(m3u8.SetDrmInfo(drmInfo));
274 }
275
276 HWTEST_F(M3u8UnitTest, SET_DRM_INFO_INVALID_KEY_URI, TestSize.Level1)
277 {
278 M3U8 m3u8("http://example.com/test.m3u8", "");
279 m3u8.keyUri_ = std::make_shared<std::string>("invalid");
280 std::multimap<std::string, std::vector<uint8_t>> drmInfo;
281 EXPECT_FALSE(m3u8.SetDrmInfo(drmInfo));
282 }
283
284 HWTEST_F(M3u8UnitTest, SET_DRM_INFO_VALID_KEY_URI, TestSize.Level1)
285 {
286 M3U8 m3u8("http://example.com/test.m3u8", "");
287 m3u8.keyUri_ = std::make_shared<std::string>("base64,valid");
288 std::multimap<std::string, std::vector<uint8_t>> drmInfo;
289 EXPECT_FALSE(m3u8.SetDrmInfo(drmInfo));
290 }
291
292 HWTEST_F(M3u8UnitTest, SET_DRM_INFO_PSSH_SIZE_SMALL, TestSize.Level1)
293 {
294 M3U8 m3u8("http://example.com/test.m3u8", "");
295 m3u8.keyUri_ = std::make_shared<std::string>("base64,valid");
296 std::multimap<std::string, std::vector<uint8_t>> drmInfo;
297 EXPECT_FALSE(m3u8.SetDrmInfo(drmInfo));
298 }
299
300 HWTEST_F(M3u8UnitTest, SET_DRM_INFO_PSSH_SIZE_VALID, TestSize.Level1)
301 {
302 M3U8 m3u8("http://example.com/test.m3u8", "");
303 m3u8.keyUri_ = std::make_shared<std::string>("base64,valid");
304 std::multimap<std::string, std::vector<uint8_t>> drmInfo;
305 EXPECT_FALSE(m3u8.SetDrmInfo(drmInfo));
306 }
307
308 HWTEST_F(M3u8UnitTest, SET_DRM_INFOS, TestSize.Level1)
309 {
310 M3U8 m3u8("http://example.com/test.m3u8", "");
311 std::multimap<std::string, std::vector<uint8_t>> drmInfo;
312
313 // test no DRM info
314 m3u8.StoreDrmInfos(drmInfo);
315 EXPECT_TRUE(m3u8.localDrmInfos_.empty());
316
317 // test new drm info
318 std::vector<uint8_t> pssh = {1, 2, 3, 4, 5};
319 drmInfo.insert(std::make_pair("uuid1", pssh));
320 m3u8.StoreDrmInfos(drmInfo);
321 EXPECT_EQ(1, m3u8.localDrmInfos_.size());
322 EXPECT_EQ(pssh, m3u8.localDrmInfos_.begin()->second);
323
324 // test existed drm info
325 drmInfo.insert(std::make_pair("uuid1", pssh));
326 m3u8.StoreDrmInfos(drmInfo);
327 EXPECT_EQ(1, m3u8.localDrmInfos_.size());
328 EXPECT_EQ(pssh, m3u8.localDrmInfos_.begin()->second);
329
330 // test diff drm info
331 std::vector<uint8_t> pssh2 = {6, 7, 8, 9, 10};
332 drmInfo.insert(std::make_pair("uuid1", pssh2));
333 m3u8.StoreDrmInfos(drmInfo);
334 EXPECT_EQ(2, m3u8.localDrmInfos_.size());
335 EXPECT_EQ(pssh2, (++m3u8.localDrmInfos_.begin())->second);
336 }
337
338 HWTEST_F(M3u8UnitTest, TestPlaylistStartWithEXTM3U, TestSize.Level1)
339 {
340 M3U8MasterPlaylist playlist("#EXTM3U", "uri");
341 EXPECT_EQ(playlist.playList_, "#EXTM3U");
342 }
343
344 HWTEST_F(M3u8UnitTest, TestPlaylistNotStartWithEXTM3U, TestSize.Level1)
345 {
346 M3U8MasterPlaylist playlist("playlist", "uri");
347 EXPECT_EQ(playlist.playList_, "playlist");
348 }
349
350 HWTEST_F(M3u8UnitTest, TestPlaylistContainsEXTINF, TestSize.Level1)
351 {
352 M3U8MasterPlaylist playlist("\n#EXTM3U:", "uri");
353 EXPECT_EQ(playlist.playList_, "\n#EXTM3U:");
354 }
355
356 HWTEST_F(M3u8UnitTest, TestPlaylistNotContainsEXTINF, TestSize.Level1)
357 {
358 M3U8MasterPlaylist playlist("playlist", "uri");
359 EXPECT_EQ(playlist.playList_, "playlist");
360 }
361
362 HWTEST_F(M3u8UnitTest, UpdateMediaPlaylistTest, TestSize.Level1)
363 {
364 M3U8MasterPlaylist playlist("playlist", "uri");
365 playlist.UpdateMediaPlaylist();
366
367 // test variants contains new stream
368 EXPECT_EQ(1, playlist.variants_.size());
369
370 // test defaultVariant_ point new stream
371 EXPECT_EQ(playlist.variants_.front(), playlist.defaultVariant_);
372
373 // test duration updated
374 EXPECT_EQ(0, playlist.duration_);
375
376 // test bLive_ updated
377 EXPECT_FALSE(playlist.bLive_);
378
379 // isSimple updated
380 EXPECT_TRUE(playlist.isSimple_);
381 }
382
383 HWTEST_F(M3u8UnitTest, UpdateMasterPlaylist_default, TestSize.Level1)
384 {
385 M3U8MasterPlaylist playlist("test", "http://test.com/test");
386 playlist.UpdateMediaPlaylist();
387 EXPECT_EQ(playlist.defaultVariant_, playlist.variants_.front());
388 }
389 // 测试 IsLive 方法
390 HWTEST_F(M3u8UnitTest, IS_LIVE_TEST, TestSize.Level1)
391 {
392 M3U8 m3u8(testUri, "LivePlaylist");
393 EXPECT_FALSE(m3u8.IsLive());
394 }
395
396 // 测试 M3U8Fragment 构造函数
397 HWTEST_F(M3u8UnitTest, M3U8FragmentConstructorTest, TestSize.Level1)
398 {
399 double testDuration = 10.0;
400 int testSequence = 1;
401 bool testDiscont = false;
402 M3U8Fragment fragment(testUri, testDuration, testSequence, testDiscont);
403 ASSERT_EQ(fragment.uri_, testUri);
404 ASSERT_DOUBLE_EQ(fragment.duration_, testDuration);
405 ASSERT_EQ(fragment.sequence_, testSequence);
406 ASSERT_EQ(fragment.discont_, testDiscont);
407 }
408
409 HWTEST_F(M3u8UnitTest, ParseKeyTest, TestSize.Level1)
410 {
411 auto attributesTag = std::make_shared<AttributesTag>(HlsTag::EXTINF, "1234");
412 auto uriAttr = std::make_shared<Attribute>("METHOD", "\"SAMPLE-AES\"");
413 attributesTag->AddAttribute(uriAttr);
414 auto uriAttr1 = std::make_shared<Attribute>("URI", "\"https://example.com/key\"");
415 attributesTag->AddAttribute(uriAttr1);
416 auto uriAttr2 = std::make_shared<Attribute>("IV", "\"0123456789ABCDEF\"");
417 attributesTag->AddAttribute(uriAttr2);
418
419 testM3u8->ParseKey(attributesTag);
420
421 // 验证 method_, keyUri_ 和 iv_ 是否正确设置
422 auto testStr = std::make_shared<std::string>("SAMPLE-AES");
423 ASSERT_EQ(*(testM3u8->method_), *testStr);
424 auto testStr1 = std::make_shared<std::string>("https://example.com/key");
425 ASSERT_EQ(*(testM3u8->keyUri_), *testStr1);
426 }
427
428 HWTEST_F(M3u8UnitTest, SaveDataTest, TestSize.Level1)
429 {
430 uint8_t data[] = {0x01, 0x02, 0x03, 0x04};
431 bool result = testM3u8->SaveData(data, sizeof(data));
432 ASSERT_TRUE(result);
433
434 // 验证 key_ 成员变量中的数据是否与传入的数据一致
435 for (size_t i = 0; i < sizeof(data); ++i) {
436 ASSERT_EQ(testM3u8->key_[i], data[i]);
437 }
438
439 // 验证 keyLen_ 是否被正确设置
440 ASSERT_EQ(testM3u8->keyLen_, sizeof(data));
441 }
442
443 HWTEST_F(M3u8UnitTest, SetDrmInfoTest, TestSize.Level1)
444 {
445 std::multimap<std::string, std::vector<uint8_t>> drmInfo;
446 // 设置 keyUri_ 为有效的 base64 编码字符串
447 testM3u8->keyUri_ = std::make_shared<std::string>("base64,VALID_BASE64_ENCODED_STRING");
448
449 bool result = testM3u8->SetDrmInfo(drmInfo);
450 ASSERT_FALSE(result);
451 ASSERT_TRUE(drmInfo.empty());
452 // 验证 drmInfo 是否包含预期的 UUID 和解码后的数据
453 }
454
455 HWTEST_F(M3u8UnitTest, StoreDrmInfosTest, TestSize.Level1)
456 {
457 std::multimap<std::string, std::vector<uint8_t>> drmInfo = { { "uuid1", { 1, 2, 3 } }, { "uuid2", { 4, 5, 6 } } };
458 testM3u8->StoreDrmInfos(drmInfo);
459 // 验证 localDrmInfos_ 是否正确包含了 drmInfo 的内容
460 for (const auto &item : drmInfo) {
461 auto range = testM3u8->localDrmInfos_.equal_range(item.first);
462 ASSERT_NE(range.first, testM3u8->localDrmInfos_.end());
463 ASSERT_EQ(range.first->second, item.second);
464 }
465 }
466
467 HWTEST_F(M3u8UnitTest, ProcessDrmInfosTest, TestSize.Level1)
468 {
469 testM3u8->keyUri_ = std::make_shared<std::string>("base64,VALID_BASE64_ENCODED_STRING");
470 testM3u8->ProcessDrmInfos();
471 // 验证 isDecryptAble_ 是否根据 DRM 信息的处理结果正确设置
472 ASSERT_EQ(testM3u8->isDecryptAble_, testM3u8->localDrmInfos_.empty());
473 }
474
475 }