diff --git a/test/meson.build b/test/meson.build index 7264f5613ac80ce7bb92979c46a1b04190a5b779..185002854b9ff5b29d876e3e63d87f48a0bc53e9 100644 --- a/test/meson.build +++ b/test/meson.build @@ -10,4 +10,5 @@ else subdir('sqlite_load') subdir('fast_teardown') subdir('fast_discover_cancel') + subdir('subscriptions_importer') endif diff --git a/test/subscriptions_importer/main.cpp b/test/subscriptions_importer/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..78802bb87ab8c11daa6d614051748cfb5bd059dd --- /dev/null +++ b/test/subscriptions_importer/main.cpp @@ -0,0 +1,168 @@ +/***************************************************************************** + * Media Library + ***************************************************************************** + * Copyright (C) 2022 Hugo Beauzée-Luyssen, Videolabs, VideoLAN + * + * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include "medialibrary/IMediaLibrary.h" +#include "test/common/NoopCallback.h" +#include "test/common/util.h" + +#include "compat/ConditionVariable.h" +#include "compat/Mutex.h" + +#include <iostream> +#include <unistd.h> +#include <cassert> + +class TestCb : public mock::NoopCallback +{ +public: + TestCb() + : m_isParsingCompleted( false ) + { + } + + bool waitForCompletion() + { + std::unique_lock<compat::Mutex> lock( m_mutex ); + m_cond.wait( lock, [this](){ + return m_isParsingCompleted == true; + }); + return true; + } + + void prepareWaitForCache() + { + std::lock_guard<compat::Mutex> lock{ m_mutex }; + m_cacheUpdated = false; + m_cacheWorkerIdle = false; + } + + void waitForCacheUpdated() + { + std::unique_lock<compat::Mutex> lock{ m_mutex }; + m_cond.wait( lock, [this]() { + return m_cacheWorkerIdle == true && m_cacheUpdated == true; + }); + } + +private: + virtual void onParsingStatsUpdated( uint32_t done, uint32_t scheduled ) override + { + { + std::lock_guard<compat::Mutex> lock( m_mutex ); + m_isParsingCompleted = (done == scheduled); + } + m_cond.notify_all(); + } + + virtual void onCacheIdleChanged( bool idle ) override + { + std::lock_guard<compat::Mutex> lock( m_mutex ); + m_cacheWorkerIdle = idle; + m_cond.notify_all(); + } + + virtual void onSubscriptionCacheUpdated( int64_t ) override + { + std::lock_guard<compat::Mutex> lock( m_mutex ); + assert( m_cacheWorkerIdle == false ); + m_cacheUpdated = true; + } + +private: + compat::ConditionVariable m_cond; + compat::Mutex m_mutex; + bool m_isParsingCompleted; + bool m_cacheUpdated; + bool m_cacheWorkerIdle; +}; + +static void usage( const char* const* argv ) +{ + std::cerr << "usage: " << argv[0] << "[-q] [-c] <RSS_MRL>\n" + "-q: Use Error log level. Default is Debug\n" + "-c: Automatically cache this subscription\n" + << std::endl; +} + +int main( int argc, char** argv ) +{ + if ( argc < 2 ) + { + usage(argv); + exit(1); + } + + auto quiet = false; + auto cache = false; + int opt; + while ( ( opt = getopt( argc, argv, "qc" ) ) != -1 ) + { + switch ( opt ) + { + case 'q': + quiet = true; + break; + case 'c': + cache = true; + break; + default: + usage( argv ); + exit( 1 ); + } + } + if ( optind >= argc ) + { + std::cerr << "Missing subscription RSS MRL" << std::endl; + usage(argv); + exit(2); + } + auto subMrl = argv[optind]; + + auto mlDir = getTempPath( "subscriptions_importer" ); + auto dbPath = mlDir + "/test.db"; + unlink( dbPath.c_str() ); + + auto testCb = std::make_unique<TestCb>(); + std::unique_ptr<medialibrary::IMediaLibrary> ml{ + NewMediaLibrary( dbPath.c_str(), mlDir.c_str(), false, nullptr ) + }; + + ml->setVerbosity( quiet == true ? medialibrary::LogLevel::Error : + medialibrary::LogLevel::Debug ); + auto initRes = ml->initialize( testCb.get() ); + assert( initRes == InitializeResult::Success ); + ml->setDiscoverNetworkEnabled( true ); + + ml->addSubscription( Service::Podcast, subMrl ); + + testCb->waitForCompletion(); + if ( cache == true ) + { + testCb->prepareWaitForCache(); + ml->cacheNewSubscriptionMedia(); + testCb->waitForCacheUpdated(); + } +} diff --git a/test/subscriptions_importer/meson.build b/test/subscriptions_importer/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..8d8f9df3d9dc2dbbaa6bc696972b5e1fffe201f6 --- /dev/null +++ b/test/subscriptions_importer/meson.build @@ -0,0 +1,6 @@ +executable('subscriptions_importer', 'main.cpp', + link_with: [medialib], + include_directories: [includes, test_include_dir], + dependencies: [sqlite_dep], + build_by_default: true +)