/* * Copyright (C) 2015-2020 Team Kodi * This file is part of Kodi - https://kodi.tv * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSES/README.md for more information. */ #include "FileItem.h" #include "URL.h" #include "filesystem/CurlFile.h" #include "filesystem/HTTPDirectory.h" #include "network/WebServer.h" #include "network/httprequesthandler/HTTPVfsHandler.h" #include "settings/MediaSourceSettings.h" #include "test/TestUtils.h" #include "utils/StringUtils.h" #include "utils/URIUtils.h" #include "utils/XTimeUtils.h" #include #include #include using namespace XFILE; #define WEBSERVER_HOST "localhost" #define SOURCE_PATH "xbmc/filesystem/test/data/httpdirectory/" #define TEST_FILE_APACHE_DEFAULT "apache-default.html" #define TEST_FILE_APACHE_FANCY "apache-fancy.html" #define TEST_FILE_APACHE_HTML "apache-html.html" #define TEST_FILE_BASIC "basic.html" #define TEST_FILE_BASIC_MULTILINE "basic-multiline.html" #define TEST_FILE_LIGHTTP_DEFAULT "lighttp-default.html" #define TEST_FILE_NGINX_DEFAULT "nginx-default.html" #define TEST_FILE_NGINX_FANCYINDEX "nginx-fancyindex.html" #define SAMPLE_ITEM_COUNT 6 #define SAMPLE_ITEM_1_LABEL "folder1" #define SAMPLE_ITEM_2_LABEL "folder2" #define SAMPLE_ITEM_3_LABEL "sample3: the sampling.mpg" #define SAMPLE_ITEM_4_LABEL "sample & samplability 4.mpg" #define SAMPLE_ITEM_5_LABEL "sample5.mpg" #define SAMPLE_ITEM_6_LABEL "sample6.mpg" #define SAMPLE_ITEM_1_SIZE 0 #define SAMPLE_ITEM_2_SIZE 0 #define SAMPLE_ITEM_3_SIZE 123 #define SAMPLE_ITEM_4_SIZE 125952 // 123K #define SAMPLE_ITEM_5_SIZE 128974848 // 123M #define SAMPLE_ITEM_6_SIZE 132070244352 // 123G // HTTPDirectory ignores the seconds component of parsed date/times #define SAMPLE_ITEM_1_DATETIME "2019-01-01 01:01:00" #define SAMPLE_ITEM_2_DATETIME "2019-02-02 02:02:00" #define SAMPLE_ITEM_3_DATETIME "2019-03-03 03:03:00" #define SAMPLE_ITEM_4_DATETIME "2019-04-04 04:04:00" #define SAMPLE_ITEM_5_DATETIME "2019-05-05 05:05:00" #define SAMPLE_ITEM_6_DATETIME "2019-06-06 06:06:00" class TestHTTPDirectory : public testing::Test { protected: TestHTTPDirectory() : m_sourcePath(XBMC_REF_FILE_PATH(SOURCE_PATH)) { std::random_device rd; std::mt19937 mt(rd()); std::uniform_int_distribution dist(49152, 65535); m_webServerPort = dist(mt); m_baseUrl = StringUtils::Format("http://" WEBSERVER_HOST ":{}", m_webServerPort); } ~TestHTTPDirectory() override = default; protected: void SetUp() override { SetupMediaSources(); m_webServer.Start(m_webServerPort, "", ""); m_webServer.RegisterRequestHandler(&m_vfsHandler); } void TearDown() override { if (m_webServer.IsStarted()) m_webServer.Stop(); m_webServer.UnregisterRequestHandler(&m_vfsHandler); TearDownMediaSources(); } void SetupMediaSources() { CMediaSource source; source.strName = "WebServer Share"; source.strPath = m_sourcePath; source.vecPaths.push_back(m_sourcePath); source.m_allowSharing = true; source.m_iDriveType = CMediaSource::SOURCE_TYPE_LOCAL; source.m_iLockMode = LOCK_MODE_EVERYONE; source.m_ignore = true; CMediaSourceSettings::GetInstance().AddShare("videos", source); } void TearDownMediaSources() { CMediaSourceSettings::GetInstance().Clear(); } std::string GetUrl(const std::string& path) { if (path.empty()) return m_baseUrl; return URIUtils::AddFileToFolder(m_baseUrl, path); } std::string GetUrlOfTestFile(const std::string& testFile) { if (testFile.empty()) return ""; std::string path = URIUtils::AddFileToFolder(m_sourcePath, testFile); path = CURL::Encode(path); path = URIUtils::AddFileToFolder("vfs", path); return GetUrl(path); } void CheckFileItemTypes(CFileItemList const& items) { ASSERT_EQ(items.GetObjectCount(), SAMPLE_ITEM_COUNT); // folders ASSERT_TRUE(items[0]->m_bIsFolder); ASSERT_TRUE(items[1]->m_bIsFolder); // files ASSERT_FALSE(items[2]->m_bIsFolder); ASSERT_FALSE(items[3]->m_bIsFolder); ASSERT_FALSE(items[4]->m_bIsFolder); ASSERT_FALSE(items[5]->m_bIsFolder); } void CheckFileItemLabels(CFileItemList const& items) { ASSERT_EQ(items.GetObjectCount(), SAMPLE_ITEM_COUNT); ASSERT_STREQ(items[0]->GetLabel().c_str(), SAMPLE_ITEM_1_LABEL); ASSERT_STREQ(items[1]->GetLabel().c_str(), SAMPLE_ITEM_2_LABEL); ASSERT_STREQ(items[2]->GetLabel().c_str(), SAMPLE_ITEM_3_LABEL); ASSERT_STREQ(items[3]->GetLabel().c_str(), SAMPLE_ITEM_4_LABEL); ASSERT_STREQ(items[4]->GetLabel().c_str(), SAMPLE_ITEM_5_LABEL); ASSERT_STREQ(items[5]->GetLabel().c_str(), SAMPLE_ITEM_6_LABEL); } void CheckFileItemDateTimes(CFileItemList const& items) { ASSERT_EQ(items.GetObjectCount(), SAMPLE_ITEM_COUNT); ASSERT_STREQ(items[0]->m_dateTime.GetAsDBDateTime().c_str(), SAMPLE_ITEM_1_DATETIME); ASSERT_STREQ(items[1]->m_dateTime.GetAsDBDateTime().c_str(), SAMPLE_ITEM_2_DATETIME); ASSERT_STREQ(items[2]->m_dateTime.GetAsDBDateTime().c_str(), SAMPLE_ITEM_3_DATETIME); ASSERT_STREQ(items[3]->m_dateTime.GetAsDBDateTime().c_str(), SAMPLE_ITEM_4_DATETIME); ASSERT_STREQ(items[4]->m_dateTime.GetAsDBDateTime().c_str(), SAMPLE_ITEM_5_DATETIME); ASSERT_STREQ(items[5]->m_dateTime.GetAsDBDateTime().c_str(), SAMPLE_ITEM_6_DATETIME); } void CheckFileItemSizes(CFileItemList const& items) { ASSERT_EQ(items.GetObjectCount(), SAMPLE_ITEM_COUNT); // folders ASSERT_EQ(items[0]->m_dwSize, SAMPLE_ITEM_1_SIZE); ASSERT_EQ(items[1]->m_dwSize, SAMPLE_ITEM_2_SIZE); // files - due to K/M/G conversions provided by some formats, allow for // non-zero values that are less than or equal to the expected file size ASSERT_NE(items[2]->m_dwSize, 0); ASSERT_LE(items[2]->m_dwSize, SAMPLE_ITEM_3_SIZE); ASSERT_NE(items[3]->m_dwSize, 0); ASSERT_LE(items[3]->m_dwSize, SAMPLE_ITEM_4_SIZE); ASSERT_NE(items[4]->m_dwSize, 0); ASSERT_LE(items[4]->m_dwSize, SAMPLE_ITEM_5_SIZE); ASSERT_NE(items[5]->m_dwSize, 0); ASSERT_LE(items[5]->m_dwSize, SAMPLE_ITEM_6_SIZE); } void CheckFileItems(CFileItemList const& items) { CheckFileItemTypes(items); CheckFileItemLabels(items); } void CheckFileItemsAndMetadata(CFileItemList const& items) { CheckFileItems(items); CheckFileItemDateTimes(items); CheckFileItemSizes(items); } CWebServer m_webServer; uint16_t m_webServerPort; std::string m_baseUrl; std::string const m_sourcePath; CHTTPVfsHandler m_vfsHandler; CHTTPDirectory m_httpDirectory; }; TEST_F(TestHTTPDirectory, IsStarted) { ASSERT_TRUE(m_webServer.IsStarted()); } TEST_F(TestHTTPDirectory, ApacheDefaultIndex) { CFileItemList items; ASSERT_TRUE(m_httpDirectory.Exists(CURL(GetUrlOfTestFile(TEST_FILE_APACHE_DEFAULT)))); ASSERT_TRUE( m_httpDirectory.GetDirectory(CURL(GetUrlOfTestFile(TEST_FILE_APACHE_DEFAULT)), items)); CheckFileItems(items); } TEST_F(TestHTTPDirectory, ApacheFancyIndex) { CFileItemList items; ASSERT_TRUE(m_httpDirectory.Exists(CURL(GetUrlOfTestFile(TEST_FILE_APACHE_FANCY)))); ASSERT_TRUE(m_httpDirectory.GetDirectory(CURL(GetUrlOfTestFile(TEST_FILE_APACHE_FANCY)), items)); CheckFileItemsAndMetadata(items); } TEST_F(TestHTTPDirectory, ApacheHtmlIndex) { CFileItemList items; ASSERT_TRUE(m_httpDirectory.Exists(CURL(GetUrlOfTestFile(TEST_FILE_APACHE_HTML)))); ASSERT_TRUE(m_httpDirectory.GetDirectory(CURL(GetUrlOfTestFile(TEST_FILE_APACHE_HTML)), items)); CheckFileItemsAndMetadata(items); } TEST_F(TestHTTPDirectory, BasicIndex) { CFileItemList items; ASSERT_TRUE(m_httpDirectory.Exists(CURL(GetUrlOfTestFile(TEST_FILE_BASIC)))); ASSERT_TRUE(m_httpDirectory.GetDirectory(CURL(GetUrlOfTestFile(TEST_FILE_BASIC)), items)); CheckFileItems(items); } TEST_F(TestHTTPDirectory, BasicMultilineIndex) { CFileItemList items; ASSERT_TRUE(m_httpDirectory.Exists(CURL(GetUrlOfTestFile(TEST_FILE_BASIC_MULTILINE)))); ASSERT_TRUE( m_httpDirectory.GetDirectory(CURL(GetUrlOfTestFile(TEST_FILE_BASIC_MULTILINE)), items)); CheckFileItems(items); } TEST_F(TestHTTPDirectory, LighttpDefaultIndex) { CFileItemList items; ASSERT_TRUE(m_httpDirectory.Exists(CURL(GetUrlOfTestFile(TEST_FILE_LIGHTTP_DEFAULT)))); ASSERT_TRUE( m_httpDirectory.GetDirectory(CURL(GetUrlOfTestFile(TEST_FILE_LIGHTTP_DEFAULT)), items)); CheckFileItemsAndMetadata(items); } TEST_F(TestHTTPDirectory, NginxDefaultIndex) { CFileItemList items; ASSERT_TRUE(m_httpDirectory.Exists(CURL(GetUrlOfTestFile(TEST_FILE_NGINX_DEFAULT)))); ASSERT_TRUE(m_httpDirectory.GetDirectory(CURL(GetUrlOfTestFile(TEST_FILE_NGINX_DEFAULT)), items)); CheckFileItemsAndMetadata(items); } TEST_F(TestHTTPDirectory, NginxFancyIndex) { CFileItemList items; ASSERT_TRUE(m_httpDirectory.Exists(CURL(GetUrlOfTestFile(TEST_FILE_NGINX_FANCYINDEX)))); ASSERT_TRUE(m_httpDirectory.GetDirectory(CURL(GetUrlOfTestFile(TEST_FILE_NGINX_FANCYINDEX)), items)); CheckFileItemsAndMetadata(items); }