avs-device-sdk/PlaylistParser/test/PlaylistParser/MockContentFetcher.h

313 lines
14 KiB
C++

/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0/
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
#ifndef ALEXA_CLIENT_SDK_PLAYLISTPARSER_TEST_PLAYLISTPARSER_MOCKCONTENTFETCHER_H_
#define ALEXA_CLIENT_SDK_PLAYLISTPARSER_TEST_PLAYLISTPARSER_MOCKCONTENTFETCHER_H_
#include <string>
#include <vector>
#include <unordered_map>
#include <AVSCommon/SDKInterfaces/HTTPContentFetcherInterface.h>
namespace alexaClientSDK {
namespace playlistParser {
namespace test {
using namespace avsCommon::sdkInterfaces;
/// Short time out for when callbacks are expected not to occur.
static const auto SHORT_TIMEOUT = std::chrono::milliseconds(100);
/// Test M3U url.
static const std::string TEST_M3U_PLAYLIST_URL{"http://sanjayisthecoolest.com/sample.m3u"};
static const std::string TEST_M3U_PLAYLIST_CONTENT =
"http://stream.radiotime.com/sample.mp3\n"
"http://live-mp3-128.kexp.org\n";
static const size_t TEST_M3U_PLAYLIST_URL_EXPECTED_PARSES = 2;
static const std::vector<std::chrono::milliseconds> TEST_M3U_DURATIONS = {std::chrono::milliseconds{-1},
std::chrono::milliseconds{-1}};
static const std::vector<std::string> TEST_M3U_PLAYLIST_URLS = {"http://stream.radiotime.com/sample.mp3",
"http://live-mp3-128.kexp.org"};
/// Test M3U url with relative urls within.
static const std::string TEST_M3U_RELATIVE_PLAYLIST_URL{"http://sanjayisthecoolest.com/sampleRelativeUrls.m3u"};
static const std::string TEST_M3U_RELATIVE_PLAYLIST_CONTENT =
"../test.mp3\n"
"test2.aac\n";
static const size_t TEST_M3U_RELATIVE_PLAYLIST_URL_EXPECTED_PARSES = 2;
static const std::vector<std::string> TEST_M3U_RELATIVE_PLAYLIST_URLS = {"http://sanjayisthecoolest.com/../test.mp3",
"http://sanjayisthecoolest.com/test2.aac"};
/// A test playlist in HLS format.
static const std::string TEST_HLS_PLAYLIST_URL{"http://sanjayisthecoolest.com/sample.m3u8"};
static const std::string TEST_HLS_PLAYLIST_CONTENT =
"#EXTM3U\n"
"#EXT-X-TARGETDURATION:10\n"
"#EXT-X-MEDIA-SEQUENCE:9684358\n"
"#EXTINF:10,RADIO\n"
"http://76.74.255.139/bismarck/live/bismarck.mov_9684358.aac\n"
"#EXTINF:10.0,RADIO\n"
"http://76.74.255.139/bismarck/live/bismarck.mov_9684359.aac\n"
"#EXTINF:10,RADIO\n"
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac\n"
"#EXTINF:10.34,RADIO\n"
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac\n"
"#EXTINF:10.344,RADIO\n"
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac\n"
"#EXTINF:10.3444,RADIO\n"
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac\n"
"#EXTINF:10.002,RADIO\n"
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac\n"
"#EXTINF:10.0022,RADIO\n"
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac\n"
"#EXTINF : 10.0022,RADIO\n"
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac\n"
"#EXTINF : -1,RADIO\n"
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac\n"
"#EXTINF:123ms,RADIO\n"
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac\n"
"#EXTINF:123 ms,RADIO\n"
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac\n"
"#EXTINF:123.0ms,RADIO\n"
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac\n"
"#EXTINF:123ms,\n"
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac\n"
"#EXTINF:123 ,hi\n"
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac\n"
"#EXT-X-ENDLIST\n";
static const size_t TEST_HLS_PLAYLIST_URL_EXPECTED_PARSES = 15;
static const std::vector<std::string> TEST_HLS_PLAYLIST_URLS = {
"http://76.74.255.139/bismarck/live/bismarck.mov_9684358.aac",
"http://76.74.255.139/bismarck/live/bismarck.mov_9684359.aac",
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac",
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac",
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac",
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac",
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac",
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac",
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac",
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac",
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac",
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac",
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac",
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac",
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac"};
static const std::vector<std::chrono::milliseconds> TEST_HLS_DURATIONS = {std::chrono::milliseconds{10000},
std::chrono::milliseconds{10000},
std::chrono::milliseconds{10000},
std::chrono::milliseconds{10340},
std::chrono::milliseconds{10344},
std::chrono::milliseconds{10344},
std::chrono::milliseconds{10002},
std::chrono::milliseconds{10002},
std::chrono::milliseconds{10002},
std::chrono::milliseconds{-1},
std::chrono::milliseconds{-1},
std::chrono::milliseconds{-1},
std::chrono::milliseconds{-1},
std::chrono::milliseconds{-1},
std::chrono::milliseconds{123000}};
/// A test playlist in PLS format.
static const std::string TEST_PLS_PLAYLIST_URL{"http://sanjayisthecoolest.com/sample3.pls"};
static const std::string TEST_PLS_CONTENT =
"[playlist]\n"
"NumberOfEntries=2\n"
"File1=http://stream.radiotime.com/sample.mp3\n"
"Length1=-1\n"
"File2=http://live-mp3-128.kexp.org\n"
"Length2=-1\n";
static const size_t TEST_PLS_PLAYLIST_URL_EXPECTED_PARSES = 2;
static const std::vector<std::string> TEST_PLS_PLAYLIST_URLS = {"http://stream.radiotime.com/sample.mp3",
"http://live-mp3-128.kexp.org"};
/// A test playlist in HLS format.
static const std::string TEST_HLS_LIVE_STREAM_PLAYLIST_URL{"http://sanjayisthecoolest.com/liveStream.m3u8"};
static const std::string TEST_HLS_LIVE_STREAM_PLAYLIST_CONTENT_1 =
"#EXTM3U\n"
"#EXT-X-TARGETDURATION:10\n"
"#EXT-X-MEDIA-SEQUENCE:9684358\n"
"#EXTINF:10,RADIO\n"
"http://76.74.255.139/bismarck/live/bismarck.mov_9684358.aac\n"
"#EXTINF:10.0,RADIO\n"
"http://76.74.255.139/bismarck/live/bismarck.mov_9684359.aac\n"
"#EXTINF:10,RADIO\n"
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac\n";
static const std::string TEST_HLS_LIVE_STREAM_PLAYLIST_CONTENT_2 =
"#EXTM3U\n"
"#EXT-X-TARGETDURATION:10\n"
"#EXT-X-MEDIA-SEQUENCE:9684360\n"
"#EXTINF:10,RADIO\n"
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac\n"
"#EXTINF:10,RADIO\n"
"http://sanjay.com/chunk.mp3\n"
"#EXTINF:10,RADIO\n"
"http://sanjay.com/anotherChunk.mp3\n"
"#EXT-X-ENDLIST\n";
static const size_t TEST_HLS_LIVE_STREAM_PLAYLIST_EXPECTED_PARSES = 5;
static const std::vector<std::string> TEST_HLS_LIVE_STREAM_PLAYLIST_URLS = {
"http://76.74.255.139/bismarck/live/bismarck.mov_9684358.aac",
"http://76.74.255.139/bismarck/live/bismarck.mov_9684359.aac",
"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac",
"http://sanjay.com/chunk.mp3",
"http://sanjay.com/anotherChunk.mp3"};
static const std::vector<std::chrono::milliseconds> TEST_HLS_LIVE_STREAM_DURATIONS = {std::chrono::milliseconds{10000},
std::chrono::milliseconds{10000},
std::chrono::milliseconds{10000},
std::chrono::milliseconds{10000},
std::chrono::milliseconds{10000}};
static const size_t NUM_PARSES_EXPECTED_WHEN_NO_PARSING = 1;
static const std::string TEST_MEDIA_URL = "https://sanjay.com/some_media.mp3";
static const std::unordered_map<std::string, std::string> urlsToContentTypes{
// Valid playlist content types
{TEST_M3U_PLAYLIST_URL, "audio/mpegurl"},
{TEST_M3U_RELATIVE_PLAYLIST_URL, "audio/mpegurl"},
{TEST_HLS_PLAYLIST_URL, "application/vnd.apple.mpegurl"},
{TEST_PLS_PLAYLIST_URL, "audio/x-scpls"},
{TEST_HLS_LIVE_STREAM_PLAYLIST_URL, "audio/mpegurl"},
// Not playlist content types
{TEST_MEDIA_URL, "audio/mpeg"},
{"http://stream.radiotime.com/sample.mp3", "audio/mpeg"},
{"http://live-mp3-128.kexp.org", "audio/mpeg"},
{"http://76.74.255.139/bismarck/live/bismarck.mov_9684358.aac", "audio/mpeg"},
{"http://76.74.255.139/bismarck/live/bismarck.mov_9684359.aac", "audio/mpeg"},
{"http://76.74.255.139/bismarck/live/bismarck.mov_9684360.aac", "audio/mpeg"},
{"http://stream.radiotime.com/sample.mp3", "audio/mpeg"},
{"http://live-mp3-128.kexp.org", "audio/mpeg"},
{"http://sanjayisthecoolest.com/../test.mp3", "audio/mpeg"},
{"http://sanjayisthecoolest.com/test2.aac", "audio/mpeg"},
{"http://sanjay.com/chunk.mp3", "audio/mpeg"},
{"http://sanjay.com/anotherChunk.mp3", "audio/mpeg"}};
static std::unordered_map<std::string, std::string> urlsToContent{
{TEST_M3U_PLAYLIST_URL, TEST_M3U_PLAYLIST_CONTENT},
{TEST_M3U_RELATIVE_PLAYLIST_URL, TEST_M3U_RELATIVE_PLAYLIST_CONTENT},
{TEST_HLS_PLAYLIST_URL, TEST_HLS_PLAYLIST_CONTENT},
{TEST_PLS_PLAYLIST_URL, TEST_PLS_CONTENT},
{TEST_HLS_LIVE_STREAM_PLAYLIST_URL, TEST_HLS_LIVE_STREAM_PLAYLIST_CONTENT_1}};
/// A mock content fetcher
class MockContentFetcher : public HTTPContentFetcherInterface {
public:
MockContentFetcher(const std::string& url) : m_url{url}, m_state{HTTPContentFetcherInterface::State::INITIALIZED} {
}
std::string getUrl() const override {
return m_url;
}
HTTPContentFetcherInterface::Header getHeader(std::atomic<bool>* shouldShutdown) override {
HTTPContentFetcherInterface::Header header;
auto it1 = urlsToContentTypes.find(m_url);
if (it1 == urlsToContentTypes.end()) {
header.successful = false;
} else {
header.successful = true;
header.responseCode = avsCommon::utils::http::HTTPResponseCode::SUCCESS_OK;
header.contentType = it1->second;
m_state = HTTPContentFetcherInterface::State::HEADER_DONE;
}
return header;
}
HTTPContentFetcherInterface::State getState() override {
return m_state;
}
bool getBody(std::shared_ptr<avsCommon::avs::attachment::AttachmentWriter> writer) override {
auto it2 = urlsToContent.find(m_url);
if (it2 == urlsToContent.end()) {
return false;
} else {
static bool liveStreamPlaylistRequested = false;
if (m_url == TEST_HLS_LIVE_STREAM_PLAYLIST_URL) {
if (!liveStreamPlaylistRequested) {
it2->second = TEST_HLS_LIVE_STREAM_PLAYLIST_CONTENT_1;
liveStreamPlaylistRequested = true;
} else {
it2->second = TEST_HLS_LIVE_STREAM_PLAYLIST_CONTENT_2;
}
}
auto attachment = writeStringIntoAttachment(it2->second, std::move(writer));
if (!attachment) {
return false;
}
m_state = HTTPContentFetcherInterface::State::BODY_DONE;
}
return true;
}
void shutdown() override {
}
std::unique_ptr<avsCommon::utils::HTTPContent> getContent(
FetchOptions fetchOption,
std::unique_ptr<avsCommon::avs::attachment::AttachmentWriter> writer,
const std::vector<std::string>& customHeaders = std::vector<std::string>()) override {
return nullptr;
}
private:
std::shared_ptr<avsCommon::avs::attachment::InProcessAttachment> writeStringIntoAttachment(
const std::string& string,
std::shared_ptr<avsCommon::avs::attachment::AttachmentWriter> writer) {
static int id = 0;
std::shared_ptr<avsCommon::avs::attachment::InProcessAttachment> stream =
std::make_shared<avsCommon::avs::attachment::InProcessAttachment>(std::to_string(id++));
if (!stream) {
return nullptr;
}
if (!writer) {
writer = stream->createWriter();
}
avsCommon::avs::attachment::AttachmentWriter::WriteStatus writeStatus;
writer->write(string.data(), string.size(), &writeStatus);
return stream;
};
std::string m_url;
HTTPContentFetcherInterface::State m_state;
};
} // namespace test
} // namespace playlistParser
} // namespace alexaClientSDK
#endif // ALEXA_CLIENT_SDK_PLAYLISTPARSER_TEST_PLAYLISTPARSER_MOCKCONTENTFETCHER_H_