From 1dd37106d351d81f56cab49f78e716900456f2d8 Mon Sep 17 00:00:00 2001 From: fgerlits Date: Mon, 7 Aug 2006 18:45:50 +0000 Subject: [PATCH] merging the scheduler_export branch (2154:2179) back to the trunk; this should have been done much earlier, but I forgot --- .../core/include/LiveSupport/Core/FileTools.h | 18 +- .../src/modules/core/src/FileTools.cxx | 55 ++++ .../src/modules/core/src/FileToolsTest.cxx | 50 +++- .../src/modules/core/src/FileToolsTest.h | 11 +- .../modules/schedulerClient/etc/Makefile.in | 8 +- .../modules/schedulerClient/etc/acinclude.m4 | 56 ++++ .../modules/schedulerClient/etc/configure.ac | 7 + .../SchedulerClientInterface.h | 20 ++ .../src/SchedulerDaemonXmlRpcClient.cxx | 43 +++- .../src/SchedulerDaemonXmlRpcClient.h | 17 ++ .../src/SchedulerDaemonXmlRpcClientTest.cxx | 107 +++++++- .../src/SchedulerDaemonXmlRpcClientTest.h | 15 ++ .../src/products/scheduler/etc/Makefile.in | 8 +- .../products/scheduler/src/BackupInterface.h | 26 ++ .../scheduler/src/CreateBackupCheckMethod.cxx | 5 +- .../scheduler/src/CreateBackupCheckMethod.h | 4 +- .../scheduler/src/CreateBackupCloseMethod.cxx | 3 +- .../scheduler/src/CreateBackupOpenMethod.cxx | 3 +- .../scheduler/src/PostgresqlBackup.cxx | 57 ++++- .../products/scheduler/src/PostgresqlBackup.h | 22 +- .../scheduler/src/PostgresqlBackupTest.cxx | 101 +++++++- .../scheduler/src/PostgresqlBackupTest.h | 15 ++ .../scheduler/src/PostgresqlSchedule.cxx | 4 +- .../scheduler/src/PostgresqlSchedule.h | 2 +- .../scheduler/src/RestoreBackupMethod.cxx | 123 +++++++++ .../scheduler/src/RestoreBackupMethod.h | 141 ++++++++++ .../products/scheduler/src/RpcBackupTest.cxx | 111 +++++++- .../products/scheduler/src/RpcBackupTest.h | 17 ++ .../src/RpcStopCurrentlyPlayingTest.cxx | 240 ++++++++++++++++++ .../src/RpcStopCurrentlyPlayingTest.h | 138 ++++++++++ .../scheduler/src/ScheduleInterface.h | 2 +- .../scheduler/src/SchedulerDaemon.cxx | 4 + .../products/scheduler/src/SchedulerDaemon.h | 14 +- .../src/StopCurrentlyPlayingMethod.cxx | 129 ++++++++++ .../src/StopCurrentlyPlayingMethod.h | 146 +++++++++++ 35 files changed, 1665 insertions(+), 57 deletions(-) create mode 100644 livesupport/src/products/scheduler/src/RestoreBackupMethod.cxx create mode 100644 livesupport/src/products/scheduler/src/RestoreBackupMethod.h create mode 100644 livesupport/src/products/scheduler/src/RpcStopCurrentlyPlayingTest.cxx create mode 100644 livesupport/src/products/scheduler/src/RpcStopCurrentlyPlayingTest.h create mode 100644 livesupport/src/products/scheduler/src/StopCurrentlyPlayingMethod.cxx create mode 100644 livesupport/src/products/scheduler/src/StopCurrentlyPlayingMethod.h diff --git a/livesupport/src/modules/core/include/LiveSupport/Core/FileTools.h b/livesupport/src/modules/core/include/LiveSupport/Core/FileTools.h index 174504ab1..e4b2669a6 100644 --- a/livesupport/src/modules/core/include/LiveSupport/Core/FileTools.h +++ b/livesupport/src/modules/core/include/LiveSupport/Core/FileTools.h @@ -106,7 +106,7 @@ class FileTools * @param tarFileName the name of the existing tar file * @param newFileRealName the name of the new file to append * @param newFileInTarball the name of the new file in the tarball - * @throws std::runtime_error on file / tarball handling issues. + * @exception std::runtime_error on file / tarball handling issues. */ static void appendFileToTarball(const std::string & tarFileName, @@ -121,13 +121,27 @@ class FileTools * @param fileName the name of the file to check in the traball. * @return true if a file named fileName exists in the tarball, * false otherwise. - * @throws std::runtime_error on file / tarball handling issues. + * @exception std::runtime_error on file / tarball handling issues. */ static bool existsInTarball(const std::string & tarFileName, const std::string & fileName) throw (std::runtime_error); + /** + * Extract a file from a tarball. + * + * @param tarFileName the name of the existing tar file. + * @param fileInTarball the name of the file to be extracted + * in the tarball. + * @param fileExtracted the name of the new file to create. + * @exception std::runtime_error on file / tarball handling issues. + */ + static void + extractFileFromTarball(const std::string & tarFileName, + const std::string & fileInTarball, + const std::string & fileExtracted) + throw (std::runtime_error); }; /* ================================================= external data structures */ diff --git a/livesupport/src/modules/core/src/FileTools.cxx b/livesupport/src/modules/core/src/FileTools.cxx index 7a44eedcc..50c53f915 100644 --- a/livesupport/src/modules/core/src/FileTools.cxx +++ b/livesupport/src/modules/core/src/FileTools.cxx @@ -275,3 +275,58 @@ FileTools :: existsInTarball(const std::string & tarFileName, return result; } + +/*------------------------------------------------------------------------------ + * Extract a file from a tarball. + *----------------------------------------------------------------------------*/ +void +FileTools :: extractFileFromTarball(const std::string & tarFileName, + const std::string & fileInTarball, + const std::string & fileExtracted) + throw (std::runtime_error) +{ + TAR * tar; + bool found = false; + + if (tar_open(&tar, + (char*) tarFileName.c_str(), + NULL, + O_RDONLY, + 0, + 0) == -1) { + throw std::runtime_error("can't open tarball"); + } + + while (th_read(tar) == 0) { + if (TH_ISREG(tar)) { + char * path = th_get_pathname(tar); + + if (fileInTarball == path) { + found = true; + if (tar_extract_file(tar, + (char *) fileExtracted.c_str()) != 0) { + std::string errorMsg = "can't extract file "; + errorMsg += fileInTarball; + errorMsg += " from tarball "; + errorMsg += tarFileName; + throw std::runtime_error(errorMsg); + } + break; + } + + tar_skip_regfile(tar); + } + } + + // at this point, tarFileEnd is position where EOT block begins + tar_close(tar); // close for reading + + if (!found) { + std::string errorMsg = "could not find file "; + errorMsg += fileInTarball; + errorMsg += " in the tarball "; + errorMsg += tarFileName; + throw std::runtime_error(errorMsg); + } +} + diff --git a/livesupport/src/modules/core/src/FileToolsTest.cxx b/livesupport/src/modules/core/src/FileToolsTest.cxx index 626a3df59..377e47234 100644 --- a/livesupport/src/modules/core/src/FileToolsTest.cxx +++ b/livesupport/src/modules/core/src/FileToolsTest.cxx @@ -58,16 +58,24 @@ using namespace LiveSupport::Core; CPPUNIT_TEST_SUITE_REGISTRATION(FileToolsTest); +namespace { + /** * The name of the test tar file */ -static const std::string tarFileName = "var/hello.tar"; +const std::string tarFileName = "var/hello.tar"; /** * The name of the test file in the tar file */ -static const std::string fileInTarName = "hello"; +const std::string fileInTarName = "hello"; +/** + * The name of the test file after extraction + */ +const std::string fileExtracted = "tmp/hello.txt"; + +} /* =============================================== local function prototypes */ @@ -93,7 +101,7 @@ FileToolsTest :: tearDown(void) throw () /*------------------------------------------------------------------------------ - * Test to see if the singleton Hello object is accessible + * Test to see if the sample hello tarfile is accessible *----------------------------------------------------------------------------*/ void FileToolsTest :: existsInTarTest(void) @@ -103,3 +111,39 @@ FileToolsTest :: existsInTarTest(void) CPPUNIT_ASSERT(!FileTools::existsInTarball(tarFileName, "foobar")); } + +/*------------------------------------------------------------------------------ + * Test to see if the sample hello tarfile is accessible + *----------------------------------------------------------------------------*/ +void +FileToolsTest :: extractFileFromTarballTest(void) + throw (CPPUNIT_NS::Exception) +{ + FILE * file; + + remove(fileExtracted.c_str()); + file = fopen(fileExtracted.c_str(), "r"); + CPPUNIT_ASSERT(file == 0); + + CPPUNIT_ASSERT_NO_THROW( + FileTools::extractFileFromTarball(tarFileName, + fileInTarName, + fileExtracted) + ); + + file = fopen(fileExtracted.c_str(), "r"); + CPPUNIT_ASSERT(file != 0); + CPPUNIT_ASSERT(fclose(file) == 0); + + CPPUNIT_ASSERT(remove(fileExtracted.c_str()) == 0); + file = fopen(fileExtracted.c_str(), "r"); + CPPUNIT_ASSERT(file == 0); + + CPPUNIT_ASSERT_THROW( + FileTools::extractFileFromTarball(tarFileName, + "foobar", + fileExtracted), + std::runtime_error + ); +} + diff --git a/livesupport/src/modules/core/src/FileToolsTest.h b/livesupport/src/modules/core/src/FileToolsTest.h index 6c3e54fad..067a0a234 100644 --- a/livesupport/src/modules/core/src/FileToolsTest.h +++ b/livesupport/src/modules/core/src/FileToolsTest.h @@ -66,6 +66,7 @@ class FileToolsTest : public CPPUNIT_NS::TestFixture { CPPUNIT_TEST_SUITE(FileToolsTest); CPPUNIT_TEST(existsInTarTest); + CPPUNIT_TEST(extractFileFromTarballTest); CPPUNIT_TEST_SUITE_END(); private: @@ -73,13 +74,21 @@ class FileToolsTest : public CPPUNIT_NS::TestFixture protected: /** - * A simple test. + * Test the existsInTarball() function. * * @exception CPPUNIT_NS::Exception on test failures. */ void existsInTarTest(void) throw (CPPUNIT_NS::Exception); + /** + * Test the extractFileFromTarball() function. + * + * @exception CPPUNIT_NS::Exception on test failures. + */ + void + extractFileFromTarballTest(void) throw (CPPUNIT_NS::Exception); + public: diff --git a/livesupport/src/modules/schedulerClient/etc/Makefile.in b/livesupport/src/modules/schedulerClient/etc/Makefile.in index 0da1469a1..d2c106151 100644 --- a/livesupport/src/modules/schedulerClient/etc/Makefile.in +++ b/livesupport/src/modules/schedulerClient/etc/Makefile.in @@ -84,6 +84,9 @@ BOOST_DATE_TIME_LIB=@BOOST_DATE_TIME_LIB@ LIBXMLPP_CFLAGS=@LIBXMLPP_CFLAGS@ LIBXMLPP_LIBS=@LIBXMLPP_LIBS@ +CURL_CFLAGS=@CURL_CFLAGS@ +CURL_LIBS=@CURL_LIBS@ + ICU_CFLAGS=@ICU_CFLAGS@ ICU_CXXFLAGS=@ICU_CXXFLAGS@ ICU_LIBS=@ICU_LIBS@ @@ -111,6 +114,7 @@ CPPFLAGS = @CPPFLAGS@ CXXFLAGS = @CXXFLAGS@ @DEFS@ @COVERAGE_CXXFLAGS@ -pthread \ -pedantic -Wall -Wno-long-long \ ${LIBXMLPP_CFLAGS} \ + ${LIBTAR_CFLAGS} \ -I${USR_INCLUDE_DIR} \ -I${BOOST_INCLUDE_DIR} \ -I${CORE_INCLUDE_DIR} \ @@ -118,8 +122,10 @@ CXXFLAGS = @CXXFLAGS@ @DEFS@ @COVERAGE_CXXFLAGS@ -pthread \ -I${INCLUDE_DIR} -I${TMP_DIR} LDFLAGS = @LDFLAGS@ -pthread \ ${LIBXMLPP_LIBS} \ + ${CURL_LIBS} \ ${ICU_LIBS} \ ${TAGLIB_LIBS} \ + ${LIBTAR_LIBS} \ -L${USR_LIB_DIR} \ -L${CORE_LIB_DIR} \ -L${AUTHENTICATION_LIB_DIR} \ @@ -140,7 +146,7 @@ TEST_RUNNER_LIBS = -l${SCHEDULER_CLIENT_LIB} \ -l${CORE_LIB} \ -l${AUTHENTICATION_LIB} \ -l${BOOST_DATE_TIME_LIB} \ - -lcppunit -ldl -lxmlrpc++ -lssl + -lcppunit -ldl -lxmlrpc++ -lssl -ltar #------------------------------------------------------------------------------- diff --git a/livesupport/src/modules/schedulerClient/etc/acinclude.m4 b/livesupport/src/modules/schedulerClient/etc/acinclude.m4 index 5a39bd119..9725e771d 100644 --- a/livesupport/src/modules/schedulerClient/etc/acinclude.m4 +++ b/livesupport/src/modules/schedulerClient/etc/acinclude.m4 @@ -206,6 +206,62 @@ AC_DEFUN([AC_CHECK_ICU], [ +dnl----------------------------------------------------------------------------- +dnl Macro to check for curl of sufficient version by looking at curl-config +dnl +dnl usage: +dnl AC_CHECK_CURL(version, action-if, action-not) +dnl +dnl defines CURL_LIBS, CURL_CFLAGS, see curl-config man page +dnl----------------------------------------------------------------------------- +AC_DEFUN([AC_CHECK_CURL], [ + succeeded=no + + if test -z "$CURL_CONFIG"; then + AC_PATH_PROG(CURL_CONFIG, curl-config, no) + fi + + if test "$CURL_CONFIG" = "no" ; then + echo "*** The curl-config script could not be found. Make sure it is" + echo "*** in your path, and that curl is properly installed." + echo "*** Or see http://curl.haxx.se/" + else + dnl curl-config --version returns "libcurl ", thus cut the number + CURL_VERSION=`$CURL_CONFIG --version | cut -d" " -f2` + AC_MSG_CHECKING(for curl >= $1) + VERSION_CHECK=`expr $CURL_VERSION \>\= $1` + if test "$VERSION_CHECK" = "1" ; then + AC_MSG_RESULT(yes) + succeeded=yes + + AC_MSG_CHECKING(CURL_CFLAGS) + CURL_CFLAGS=`$CURL_CONFIG --cflags` + AC_MSG_RESULT($CURL_CFLAGS) + + AC_MSG_CHECKING(CURL_LIBS) + CURL_LIBS=`$CURL_CONFIG --libs` + AC_MSG_RESULT($CURL_LIBS) + else + CURL_CFLAGS="" + CURL_LIBS="" + ## If we have a custom action on failure, don't print errors, but + ## do set a variable so people can do so. + ifelse([$3], ,echo "can't find curl >= $1",) + fi + + AC_SUBST(CURL_CFLAGS) + AC_SUBST(CURL_LIBS) + fi + + if test $succeeded = yes; then + ifelse([$2], , :, [$2]) + else + ifelse([$3], , AC_MSG_ERROR([Library requirements (curl) not met.]), [$3]) + fi +]) + + + dnl----------------------------------------------------------------------------- dnl Macro to check for C++ namespaces dnl for more information on this macro, see diff --git a/livesupport/src/modules/schedulerClient/etc/configure.ac b/livesupport/src/modules/schedulerClient/etc/configure.ac index 61470e057..7104ba05d 100644 --- a/livesupport/src/modules/schedulerClient/etc/configure.ac +++ b/livesupport/src/modules/schedulerClient/etc/configure.ac @@ -44,6 +44,9 @@ AC_PROG_CXX() AC_CHECK_HEADERS(getopt.h sys/time.h) +AC_CHECK_HEADERS(libtar.h) + + dnl----------------------------------------------------------------------------- dnl specify the pkg-config path dnl----------------------------------------------------------------------------- @@ -71,6 +74,10 @@ PKG_CHECK_MODULES(LIBXMLPP,[libxml++-2.6 >= 2.8.1]) AC_SUBST(LIBXMLPP_CFLAGS) AC_SUBST(LIBXMLPP_LIBS) +AC_CHECK_CURL(7.12.3) +AC_SUBST(CURL_CFLAGS) +AC_SUBST(CURL_LIBS) + AC_CHECK_TAGLIB(1.3.1) AC_SUBST(TAGLIB_CFLAGS) AC_SUBST(TAGLIB_LIBS) diff --git a/livesupport/src/modules/schedulerClient/include/LiveSupport/SchedulerClient/SchedulerClientInterface.h b/livesupport/src/modules/schedulerClient/include/LiveSupport/SchedulerClient/SchedulerClientInterface.h index 383f1c9ba..90912b5f2 100644 --- a/livesupport/src/modules/schedulerClient/include/LiveSupport/SchedulerClient/SchedulerClientInterface.h +++ b/livesupport/src/modules/schedulerClient/include/LiveSupport/SchedulerClient/SchedulerClientInterface.h @@ -52,6 +52,8 @@ #include "LiveSupport/Core/Playlist.h" #include "LiveSupport/Core/SearchCriteria.h" #include "LiveSupport/Core/AsyncState.h" +#include "LiveSupport/Core/SearchCriteria.h" +#include "LiveSupport/Core/AsyncState.h" namespace LiveSupport { namespace SchedulerClient { @@ -232,6 +234,24 @@ class SchedulerClientInterface throw (XmlRpcException) = 0; + /** + * Restore a schedule backup. + * + * All playlist IDs contained in the backup should already be in the + * storage. If this is a combined backup, with both storage and + * schedule components, then restore this backup to the storage + * first, and then call this function. + * + * @param sessionId a valid session ID to identify the user. + * @param path the location of the archive to upload. + * @exception XmlRpcException if there is an error. + */ + virtual void + restoreBackup(Ptr::Ref sessionId, + Ptr::Ref path) + throw (XmlRpcException) + = 0; + /** * A virtual destructor, as this class has virtual functions. */ diff --git a/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClient.cxx b/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClient.cxx index 9e369c9d6..fb13d18ed 100644 --- a/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClient.cxx +++ b/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClient.cxx @@ -241,7 +241,6 @@ SchedulerDaemonXmlRpcClient :: uploadPlaylist( XmlRpcValue xmlRpcParams; XmlRpcValue xmlRpcResult; - Ptr::Ref result; XmlRpcClient xmlRpcClient(xmlRpcHost->c_str(), xmlRpcPort, @@ -291,7 +290,6 @@ SchedulerDaemonXmlRpcClient :: displaySchedule( XmlRpcValue xmlRpcParams; XmlRpcValue xmlRpcResult; - Ptr::Ref result; XmlRpcClient xmlRpcClient(xmlRpcHost->c_str(), xmlRpcPort, @@ -338,7 +336,6 @@ SchedulerDaemonXmlRpcClient :: removeFromSchedule( { XmlRpcValue xmlRpcParams; XmlRpcValue xmlRpcResult; - Ptr::Ref result; XmlRpcClient xmlRpcClient(xmlRpcHost->c_str(), xmlRpcPort, @@ -517,3 +514,43 @@ SchedulerDaemonXmlRpcClient :: createBackupClose( xmlRpcClient.close(); } + + +/*------------------------------------------------------------------------------ + * Restore a schedule backup. + *----------------------------------------------------------------------------*/ +void +SchedulerDaemonXmlRpcClient :: restoreBackup( + Ptr::Ref sessionId, + Ptr::Ref path) + throw (Core::XmlRpcException) +{ + XmlRpcValue xmlRpcParams; + XmlRpcValue xmlRpcResult; + + XmlRpcClient xmlRpcClient(xmlRpcHost->c_str(), + xmlRpcPort, + xmlRpcUri->c_str(), + false); + + XmlRpcTools::sessionIdToXmlRpcValue(sessionId, xmlRpcParams); + XmlRpcTools::pathToXmlRpcValue(path, xmlRpcParams); + + xmlRpcResult.clear(); + if (!xmlRpcClient.execute("restoreBackup", + xmlRpcParams, + xmlRpcResult)) { + throw Core::XmlRpcCommunicationException( + "cannot execute XML-RPC method 'restoreBackup'"); + } + + if (xmlRpcClient.isFault()) { + std::stringstream eMsg; + eMsg << "XML-RPC method 'restoreBackup' returned error message:\n" + << xmlRpcResult; + throw Core::XmlRpcMethodFaultException(eMsg.str()); + } + + xmlRpcClient.close(); +} + diff --git a/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClient.h b/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClient.h index 3d3b09c6c..1f4a76dc8 100644 --- a/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClient.h +++ b/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClient.h @@ -313,6 +313,23 @@ class SchedulerDaemonXmlRpcClient : virtual void createBackupClose(const Glib::ustring & token) const throw (XmlRpcException); + + /** + * Restore a schedule backup. + * + * All playlist IDs contained in the backup should already be in the + * storage. If this is a combined backup, with both storage and + * schedule components, then restore this backup to the storage + * first, and then call this function. + * + * @param sessionId a valid session ID to identify the user. + * @param path the location of the archive to upload. + * @exception XmlRpcException if there is an error. + */ + virtual void + restoreBackup(Ptr::Ref sessionId, + Ptr::Ref path) + throw (XmlRpcException); }; diff --git a/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClientTest.cxx b/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClientTest.cxx index 551ecf4a5..fced2fa8b 100644 --- a/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClientTest.cxx +++ b/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClientTest.cxx @@ -48,6 +48,7 @@ #include "LiveSupport/Core/TimeConversion.h" #include "LiveSupport/Core/XmlRpcMethodFaultException.h" +#include "LiveSupport/Core/FileTools.h" #include "LiveSupport/Authentication/AuthenticationClientFactory.h" #include "SchedulerDaemonXmlRpcClientTest.h" @@ -65,10 +66,19 @@ using namespace LiveSupport::SchedulerClient; CPPUNIT_TEST_SUITE_REGISTRATION(SchedulerDaemonXmlRpcClientTest); +namespace { + /** * The name of the configuration file for the scheduler client. */ -static const std::string configFileName = "schedulerDaemonXmlRpcClient.xml"; +const std::string configFileName = "schedulerDaemonXmlRpcClient.xml"; + +/** + * The location of the temporary backup file + */ +const std::string tempBackupTarFileName = "tmp/scheduleBackup.tar"; + +} /* =============================================== local function prototypes */ @@ -334,18 +344,18 @@ SchedulerDaemonXmlRpcClientTest :: xmlRpcErrorTest(void) /*------------------------------------------------------------------------------ - * Test the create backup functions. + * Create the backup. *----------------------------------------------------------------------------*/ void -SchedulerDaemonXmlRpcClientTest :: createBackupTest(void) +SchedulerDaemonXmlRpcClientTest :: createBackup(void) throw (CPPUNIT_NS::Exception) { - Ptr::Ref criteria(new SearchCriteria); + Ptr::Ref criteria(new SearchCriteria); criteria->setLimit(10); Ptr::Ref from(new ptime(time_from_string("2004-07-23 10:00:00"))); Ptr::Ref to(new ptime(time_from_string("2004-07-23 11:00:00"))); - Ptr::Ref token; + Ptr::Ref token; CPPUNIT_ASSERT_NO_THROW( token = schedulerClient->createBackupOpen(sessionId, criteria, @@ -354,10 +364,10 @@ SchedulerDaemonXmlRpcClientTest :: createBackupTest(void) ); CPPUNIT_ASSERT(token); - Ptr::Ref url; - Ptr::Ref path; - Ptr::Ref errorMessage; - AsyncState status; + Ptr::Ref url; + Ptr::Ref path; + Ptr::Ref errorMessage; + AsyncState status; int iterations = 20; do { std::cerr << "-/|\\"[iterations%4] << '\b'; @@ -374,11 +384,86 @@ SchedulerDaemonXmlRpcClientTest :: createBackupTest(void) } while (--iterations && status == AsyncState::pendingState); CPPUNIT_ASSERT_EQUAL(AsyncState::finishedState, status); - // TODO: test accessibility of the URL? + CPPUNIT_ASSERT(url); + CPPUNIT_ASSERT(path); + + // copy the backup file + CPPUNIT_ASSERT_NO_THROW( + remove(tempBackupTarFileName.c_str()); + std::ifstream ifs(path->c_str(), std::ios::binary); + std::ofstream ofs(tempBackupTarFileName.c_str(), std::ios::binary); + ofs << ifs.rdbuf(); + ); CPPUNIT_ASSERT_NO_THROW( schedulerClient->createBackupClose(*token); ); - // TODO: test existence of schedule backup in tarball +} + + +/*------------------------------------------------------------------------------ + * Test the backup functions. + *----------------------------------------------------------------------------*/ +void +SchedulerDaemonXmlRpcClientTest :: createBackupTest(void) + throw (CPPUNIT_NS::Exception) +{ + CPPUNIT_ASSERT_NO_THROW( + createBackup() + ); + + bool exists; + std::string schedulerBackupInTarball = "meta-inf/scheduler.xml"; + CPPUNIT_ASSERT_NO_THROW( + exists = FileTools::existsInTarball(tempBackupTarFileName, + schedulerBackupInTarball) + ); + CPPUNIT_ASSERT(exists); + + std::string extractedTempFileName = "tmp/scheduler.tmp.xml"; + FILE * file; + + remove(extractedTempFileName.c_str()); + file = fopen(extractedTempFileName.c_str(), "r"); + CPPUNIT_ASSERT(file == 0); + + CPPUNIT_ASSERT_NO_THROW( + FileTools::extractFileFromTarball(tempBackupTarFileName, + schedulerBackupInTarball, + extractedTempFileName) + ); + + file = fopen(extractedTempFileName.c_str(), "r"); + CPPUNIT_ASSERT(file != 0); + CPPUNIT_ASSERT(fclose(file) == 0); + + CPPUNIT_ASSERT(remove(extractedTempFileName.c_str()) == 0); + file = fopen(extractedTempFileName.c_str(), "r"); + CPPUNIT_ASSERT(file == 0); +} + + +/*------------------------------------------------------------------------------ + * Test to see if we can restore backups. + *----------------------------------------------------------------------------*/ +void +SchedulerDaemonXmlRpcClientTest :: restoreBackupTest(void) + throw (CPPUNIT_NS::Exception) +{ + CPPUNIT_ASSERT_NO_THROW( + createBackup() + ); + + Ptr::Ref backupFile(new Glib::ustring()); + char * currentDirName = get_current_dir_name(); + backupFile->append(currentDirName); + backupFile->append("/"); + backupFile->append(tempBackupTarFileName); + free(currentDirName); + + CPPUNIT_ASSERT_NO_THROW( + schedulerClient->restoreBackup(sessionId, backupFile) + ); + // TODO: try this with a non-empty backup file, too } diff --git a/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClientTest.h b/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClientTest.h index 9613d5fbb..1680814de 100644 --- a/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClientTest.h +++ b/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClientTest.h @@ -76,6 +76,7 @@ class SchedulerDaemonXmlRpcClientTest : public BaseTestMethod CPPUNIT_TEST(playlistMgmtTest); CPPUNIT_TEST(xmlRpcErrorTest); CPPUNIT_TEST(createBackupTest); + CPPUNIT_TEST(restoreBackupTest); CPPUNIT_TEST_SUITE_END(); private: @@ -89,6 +90,12 @@ class SchedulerDaemonXmlRpcClientTest : public BaseTestMethod */ Ptr::Ref sessionId; + /** + * Auxiliary method: create the backup file. Used by both backup tests. + */ + void + createBackup(void) throw (CPPUNIT_NS::Exception); + protected: @@ -141,6 +148,14 @@ class SchedulerDaemonXmlRpcClientTest : public BaseTestMethod void createBackupTest(void) throw (CPPUNIT_NS::Exception); + /** + * Test the restore backup function. + * + * @exception CPPUNIT_NS::Exception on test failures. + */ + void + restoreBackupTest(void) throw (CPPUNIT_NS::Exception); + public: diff --git a/livesupport/src/products/scheduler/etc/Makefile.in b/livesupport/src/products/scheduler/etc/Makefile.in index 592c07dfe..67a48cc4e 100644 --- a/livesupport/src/products/scheduler/etc/Makefile.in +++ b/livesupport/src/products/scheduler/etc/Makefile.in @@ -253,7 +253,9 @@ SCHEDULER_OBJS = ${TMP_DIR}/SignalDispatcher.o \ ${TMP_DIR}/PostgresqlBackup.o \ ${TMP_DIR}/CreateBackupOpenMethod.o \ ${TMP_DIR}/CreateBackupCheckMethod.o \ - ${TMP_DIR}/CreateBackupCloseMethod.o + ${TMP_DIR}/CreateBackupCloseMethod.o \ + ${TMP_DIR}/RestoreBackupMethod.o \ + ${TMP_DIR}/StopCurrentlyPlayingMethod.o SCHEDULER_EXE_OBJS = ${SCHEDULER_OBJS} \ @@ -290,7 +292,9 @@ TEST_RUNNER_OBJS = ${SCHEDULER_OBJS} \ ${TMP_DIR}/PlaylistEventContainerTest.o \ ${TMP_DIR}/PlaylistEventTest.o \ ${TMP_DIR}/PostgresqlBackupTest.o \ - ${TMP_DIR}/RpcBackupTest.o + ${TMP_DIR}/RpcBackupTest.o \ + ${TMP_DIR}/RpcStopCurrentlyPlayingTest.o + TEST_RUNNER_LIBS = ${SCHEDULER_EXE_LIBS} -lcppunit -ldl diff --git a/livesupport/src/products/scheduler/src/BackupInterface.h b/livesupport/src/products/scheduler/src/BackupInterface.h index 72954e53a..ac09e2765 100644 --- a/livesupport/src/products/scheduler/src/BackupInterface.h +++ b/livesupport/src/products/scheduler/src/BackupInterface.h @@ -67,6 +67,14 @@ using namespace LiveSupport::StorageClient; /** * The generic interface for creating and restoring schedule backups. * + * There is a singleton instance of this type, which is manufactured by the + * BackupFactory class. + * + * There are separate xxxxMethod classes which perform these + * functions via XML-RPC, by delegating them to this singleton object. + * The xxxxMethod classes are registered in the SchedulerDaemon + * object, which calls them when an XML-RPC request is received. + * * @author $Author$ * @version $Revision$ */ @@ -143,6 +151,24 @@ class BackupInterface : virtual public Installable throw (XmlRpcException) = 0; + /** + * Restore a schedule backup. + * + * All playlist IDs contained in the backup should already be in the + * storage. If this is a combined backup, with both storage and + * schedule components, then restore this backup to the storage + * first, and then call this function. + * + * @param sessionId a valid session ID to identify the user. + * @param path the location of the archive to upload. + * @exception XmlRpcException if there is an error. + */ + virtual void + restoreBackup(Ptr::Ref sessionId, + Ptr::Ref path) + throw (XmlRpcException) + = 0; + /** * A virtual destructor, as this class has virtual functions. */ diff --git a/livesupport/src/products/scheduler/src/CreateBackupCheckMethod.cxx b/livesupport/src/products/scheduler/src/CreateBackupCheckMethod.cxx index 68726ec0f..4e667c2ce 100644 --- a/livesupport/src/products/scheduler/src/CreateBackupCheckMethod.cxx +++ b/livesupport/src/products/scheduler/src/CreateBackupCheckMethod.cxx @@ -32,6 +32,7 @@ #include #include "LiveSupport/Core/XmlRpcTools.h" +#include "LiveSupport/Core/XmlRpcException.h" #include "BackupFactory.h" #include "CreateBackupCheckMethod.h" @@ -111,7 +112,7 @@ CreateBackupCheckMethod :: execute(XmlRpc::XmlRpcValue & rootParameter, try { state = backup->createBackupCheck(*token, url, path, errorMessage); - } catch (std::invalid_argument &e) { + } catch (Core::XmlRpcException &e) { XmlRpcTools::markError(errorId+10, e.what(), returnValue); return; } @@ -121,7 +122,7 @@ CreateBackupCheckMethod :: execute(XmlRpc::XmlRpcValue & rootParameter, if (state == AsyncState::finishedState) { if (url && path) { XmlRpcTools::urlToXmlRpcValue(url, returnValue); - XmlRpcTools::pathToXmlRpcValue(url, returnValue); + XmlRpcTools::pathToXmlRpcValue(path, returnValue); } else { XmlRpcTools::markError(errorId+11, "missing url or path return value", diff --git a/livesupport/src/products/scheduler/src/CreateBackupCheckMethod.h b/livesupport/src/products/scheduler/src/CreateBackupCheckMethod.h index a41cca083..e4b8105d2 100644 --- a/livesupport/src/products/scheduler/src/CreateBackupCheckMethod.h +++ b/livesupport/src/products/scheduler/src/CreateBackupCheckMethod.h @@ -93,8 +93,8 @@ using namespace LiveSupport::Core; *
    *
  • 4101 - invalid argument format
  • *
  • 4102 - missing token argument
  • - *
  • 4010 - error reported by the scheduler daemon
  • - *
  • 4011 - syntax error in the values returned by + *
  • 4110 - error reported by the scheduler daemon
  • + *
  • 4111 - syntax error in the values returned by * the scheduler daemon
  • *
* diff --git a/livesupport/src/products/scheduler/src/CreateBackupCloseMethod.cxx b/livesupport/src/products/scheduler/src/CreateBackupCloseMethod.cxx index 6ae80732c..af69e8b59 100644 --- a/livesupport/src/products/scheduler/src/CreateBackupCloseMethod.cxx +++ b/livesupport/src/products/scheduler/src/CreateBackupCloseMethod.cxx @@ -43,6 +43,7 @@ #include #include "LiveSupport/Core/XmlRpcTools.h" +#include "LiveSupport/Core/XmlRpcException.h" #include "BackupFactory.h" #include "CreateBackupCloseMethod.h" @@ -118,7 +119,7 @@ CreateBackupCloseMethod :: execute(XmlRpc::XmlRpcValue & rootParameter, try { backup->createBackupClose(*token); - } catch (std::invalid_argument &e) { + } catch (Core::XmlRpcException &e) { XmlRpcTools::markError(errorId+10, e.what(), returnValue); return; } diff --git a/livesupport/src/products/scheduler/src/CreateBackupOpenMethod.cxx b/livesupport/src/products/scheduler/src/CreateBackupOpenMethod.cxx index e5704bd9e..3196ade8d 100644 --- a/livesupport/src/products/scheduler/src/CreateBackupOpenMethod.cxx +++ b/livesupport/src/products/scheduler/src/CreateBackupOpenMethod.cxx @@ -43,6 +43,7 @@ #include #include "LiveSupport/Core/XmlRpcTools.h" +#include "LiveSupport/Core/XmlRpcException.h" #include "BackupFactory.h" #include "CreateBackupOpenMethod.h" @@ -147,7 +148,7 @@ CreateBackupOpenMethod :: execute(XmlRpc::XmlRpcValue & rootParameter, criteria, fromTime, toTime); - } catch (std::invalid_argument &e) { + } catch (Core::XmlRpcException &e) { XmlRpcTools::markError(errorId+5, e.what(), returnValue); return; } diff --git a/livesupport/src/products/scheduler/src/PostgresqlBackup.cxx b/livesupport/src/products/scheduler/src/PostgresqlBackup.cxx index 801a630e5..0b0abaabf 100644 --- a/livesupport/src/products/scheduler/src/PostgresqlBackup.cxx +++ b/livesupport/src/products/scheduler/src/PostgresqlBackup.cxx @@ -36,6 +36,9 @@ #include "LiveSupport/Core/TimeConversion.h" #include "LiveSupport/Core/FileTools.h" +#include "LiveSupport/Core/XmlRpcInvalidArgumentException.h" +#include "LiveSupport/Core/XmlRpcMethodFaultException.h" +#include "LiveSupport/Core/XmlRpcIOException.h" #include "LiveSupport/Db/Conversion.h" #include "PostgresqlBackup.h" @@ -320,11 +323,11 @@ PostgresqlBackup ::createBackupOpen(Ptr::Ref sessionId, if (conn) { connectionManager->returnConnection(conn); } - throw std::invalid_argument(e.what()); + throw XmlRpcMethodFaultException(e.what()); } if (!result) { - throw std::invalid_argument("couldn't insert into database"); + throw XmlRpcMethodFaultException("couldn't insert into database"); } return token; @@ -402,11 +405,11 @@ PostgresqlBackup ::createBackupCheck( if (conn) { connectionManager->returnConnection(conn); } - throw std::invalid_argument(e.what()); + throw XmlRpcMethodFaultException(e.what()); } if (!result) { - throw std::invalid_argument("couldn't insert into database"); + throw XmlRpcMethodFaultException("couldn't insert into database"); } return status; @@ -424,7 +427,7 @@ PostgresqlBackup ::putScheduleExportIntoTar( throw (std::runtime_error) { Ptr::Ref document(new Document()); - Element * root = document->create_root_node("scheduler"); + Element * root = document->create_root_node("scheduler"); std::string tmpFileName = FileTools::tempnam(); // create the export, and write it to a temporary file @@ -471,11 +474,11 @@ PostgresqlBackup ::createBackupClose(const Glib::ustring & token) if (conn) { connectionManager->returnConnection(conn); } - throw std::invalid_argument(e.what()); + throw XmlRpcInvalidArgumentException(e.what()); } if (!result) { - throw std::invalid_argument("couldn't insert into database"); + throw XmlRpcMethodFaultException("couldn't insert into database"); } } @@ -501,3 +504,43 @@ PostgresqlBackup ::asyncStateToString(AsyncState status) return *status.toBackupString(); } + +/*------------------------------------------------------------------------------ + * Restore a schedule backup. + *----------------------------------------------------------------------------*/ +void +PostgresqlBackup :: restoreBackup(Ptr::Ref sessionId, + Ptr::Ref path) + throw (XmlRpcException) +{ + //TODO: check the session ID + + std::string tmpFileName = FileTools::tempnam(); + try { + FileTools::extractFileFromTarball(*path, + scheduleExportFileName, + tmpFileName); + } catch (std::runtime_error &e) { + remove(tmpFileName.c_str()); + std::string errorMsg = "error opening the schedule backup file:\n"; + errorMsg += e.what(); + throw XmlRpcIOException(errorMsg); + } + + Ptr::Ref parser(new DomParser(tmpFileName, + false /* do not expect a DTD */)); + const Document * document = parser->get_document(); + const Element * xmlSchedule = document->get_root_node(); + const Node::NodeList children = xmlSchedule->get_children( + "scheduleExport"); + const Element * xmlScheduleExport + = (const Element *) children.front(); + try { + schedule->importScheduleEntries(xmlScheduleExport); + } catch (std::invalid_argument &e) { + std::string errorMsg = "error restoring the schedule backup:\n"; + errorMsg += e.what(); + throw XmlRpcMethodFaultException(errorMsg); + } +} + diff --git a/livesupport/src/products/scheduler/src/PostgresqlBackup.h b/livesupport/src/products/scheduler/src/PostgresqlBackup.h index 715f9a654..6dd22cdf8 100644 --- a/livesupport/src/products/scheduler/src/PostgresqlBackup.h +++ b/livesupport/src/products/scheduler/src/PostgresqlBackup.h @@ -65,7 +65,10 @@ using namespace LiveSupport::StorageClient; /* =============================================================== data types */ /** - * An object containing the schedule of events in a PostreSQL database. + * An object for creating and restoring combined schedule and storage backups. + * + * This an implementation of the BackupInterface type. It stores the token + * used for the createBackupXxxx() functions in a PostgreSQL database. * * This object has to be configured with a simple empty element, as * the following: @@ -308,6 +311,23 @@ class PostgresqlBackup : public Configurable, virtual void createBackupClose(const Glib::ustring & token) throw (XmlRpcException); + + /** + * Restore a schedule backup. + * + * All playlist IDs contained in the backup should already be in the + * storage. If this is a combined backup, with both storage and + * schedule components, then restore this backup to the storage + * first, and then call this function. + * + * @param sessionId a valid session ID to identify the user. + * @param path the location of the archive to upload. + * @exception XmlRpcException if there is an error. + */ + virtual void + restoreBackup(Ptr::Ref sessionId, + Ptr::Ref path) + throw (XmlRpcException); }; diff --git a/livesupport/src/products/scheduler/src/PostgresqlBackupTest.cxx b/livesupport/src/products/scheduler/src/PostgresqlBackupTest.cxx index 660826171..2e4ccd7e4 100644 --- a/livesupport/src/products/scheduler/src/PostgresqlBackupTest.cxx +++ b/livesupport/src/products/scheduler/src/PostgresqlBackupTest.cxx @@ -41,7 +41,9 @@ #include +#include +#include "LiveSupport/Core/FileTools.h" #include "SchedulerDaemon.h" #include "PostgresqlBackup.h" #include "PostgresqlBackupTest.h" @@ -56,6 +58,14 @@ using namespace LiveSupport::Scheduler; CPPUNIT_TEST_SUITE_REGISTRATION(PostgresqlBackupTest); +namespace { + +/** + * The location of the temporary backup file + */ +const std::string tempBackupTarFileName = "tmp/scheduleBackup.tar"; + +} /* =============================================== local function prototypes */ @@ -111,31 +121,33 @@ PostgresqlBackupTest :: tearDown(void) throw (CPPUNIT_NS::Exception) CPPUNIT_ASSERT_NO_THROW( backup->uninstall(); ); + + remove(tempBackupTarFileName.c_str()); } /*------------------------------------------------------------------------------ - * Test to see if we can create backups + * Create the backup. *----------------------------------------------------------------------------*/ void -PostgresqlBackupTest :: createBackupTest(void) +PostgresqlBackupTest :: createBackup(void) throw (CPPUNIT_NS::Exception) { - Ptr::Ref criteria(new SearchCriteria); + Ptr::Ref criteria(new SearchCriteria); criteria->setLimit(10); Ptr::Ref from(new ptime(time_from_string("2004-07-23 10:00:00"))); Ptr::Ref to(new ptime(time_from_string("2004-07-23 11:00:00"))); - Ptr::Ref token; + Ptr::Ref token; CPPUNIT_ASSERT_NO_THROW( token = backup->createBackupOpen(sessionId, criteria, from, to); ); CPPUNIT_ASSERT(token); - Ptr::Ref url; - Ptr::Ref path; - Ptr::Ref errorMessage; - AsyncState status; + Ptr::Ref url; + Ptr::Ref path; + Ptr::Ref errorMessage; + AsyncState status; int iterations = 20; do { std::cerr << "-/|\\"[iterations%4] << '\b'; @@ -149,12 +161,81 @@ PostgresqlBackupTest :: createBackupTest(void) } while (--iterations && status == AsyncState::pendingState); CPPUNIT_ASSERT_EQUAL(AsyncState::finishedState, status); - // TODO: test accessibility of the URL? + CPPUNIT_ASSERT(url); + CPPUNIT_ASSERT(path); + + // copy the backup file + CPPUNIT_ASSERT_NO_THROW( + remove(tempBackupTarFileName.c_str()); + std::ifstream ifs(path->c_str(), std::ios::binary); + std::ofstream ofs(tempBackupTarFileName.c_str(), std::ios::binary); + ofs << ifs.rdbuf(); + ); CPPUNIT_ASSERT_NO_THROW( backup->createBackupClose(*token); ); - // TODO: test existence of schedule backup in tarball } +/*------------------------------------------------------------------------------ + * Test to see if we can create backups. + *----------------------------------------------------------------------------*/ +void +PostgresqlBackupTest :: createBackupTest(void) + throw (CPPUNIT_NS::Exception) +{ + CPPUNIT_ASSERT_NO_THROW( + createBackup() + ); + + bool exists; + std::string schedulerBackupInTarball = "meta-inf/scheduler.xml"; + CPPUNIT_ASSERT_NO_THROW( + exists = FileTools::existsInTarball(tempBackupTarFileName, + schedulerBackupInTarball) + ); + CPPUNIT_ASSERT(exists); + + std::string extractedTempFileName = "tmp/scheduler.tmp.xml"; + FILE * file; + + remove(extractedTempFileName.c_str()); + file = fopen(extractedTempFileName.c_str(), "r"); + CPPUNIT_ASSERT(file == 0); + + CPPUNIT_ASSERT_NO_THROW( + FileTools::extractFileFromTarball(tempBackupTarFileName, + schedulerBackupInTarball, + extractedTempFileName) + ); + + file = fopen(extractedTempFileName.c_str(), "r"); + CPPUNIT_ASSERT(file != 0); + CPPUNIT_ASSERT(fclose(file) == 0); + + CPPUNIT_ASSERT(remove(extractedTempFileName.c_str()) == 0); + file = fopen(extractedTempFileName.c_str(), "r"); + CPPUNIT_ASSERT(file == 0); +} + + +/*------------------------------------------------------------------------------ + * Test to see if we can restore backups. + *----------------------------------------------------------------------------*/ +void +PostgresqlBackupTest :: restoreBackupTest(void) + throw (CPPUNIT_NS::Exception) +{ + CPPUNIT_ASSERT_NO_THROW( + createBackup() + ); + + Ptr::Ref backupFile(new const Glib::ustring( + tempBackupTarFileName)); + CPPUNIT_ASSERT_NO_THROW( + backup->restoreBackup(sessionId, backupFile) + ); + // TODO: try this with a non-empty backup file, too +} + diff --git a/livesupport/src/products/scheduler/src/PostgresqlBackupTest.h b/livesupport/src/products/scheduler/src/PostgresqlBackupTest.h index 8e6784832..ee1efa6f0 100644 --- a/livesupport/src/products/scheduler/src/PostgresqlBackupTest.h +++ b/livesupport/src/products/scheduler/src/PostgresqlBackupTest.h @@ -70,6 +70,7 @@ class PostgresqlBackupTest : public CPPUNIT_NS::TestFixture { CPPUNIT_TEST_SUITE(PostgresqlBackupTest); CPPUNIT_TEST(createBackupTest); + CPPUNIT_TEST(restoreBackupTest); CPPUNIT_TEST_SUITE_END(); private: @@ -88,6 +89,12 @@ class PostgresqlBackupTest : public CPPUNIT_NS::TestFixture * A session ID from the authentication client login() method. */ Ptr::Ref sessionId; + + /** + * Auxiliary method: create the backup file. Used by both tests. + */ + void + createBackup(void) throw (CPPUNIT_NS::Exception); protected: @@ -100,6 +107,14 @@ class PostgresqlBackupTest : public CPPUNIT_NS::TestFixture void createBackupTest(void) throw (CPPUNIT_NS::Exception); + /** + * Test to see if the backup works as expected + * + * @exception CPPUNIT_NS::Exception on test failures. + */ + void + restoreBackupTest(void) throw (CPPUNIT_NS::Exception); + public: /** diff --git a/livesupport/src/products/scheduler/src/PostgresqlSchedule.cxx b/livesupport/src/products/scheduler/src/PostgresqlSchedule.cxx index 46fac04d5..8853d1f6b 100644 --- a/livesupport/src/products/scheduler/src/PostgresqlSchedule.cxx +++ b/livesupport/src/products/scheduler/src/PostgresqlSchedule.cxx @@ -523,10 +523,10 @@ PostgresqlSchedule :: exportScheduleEntries( /*------------------------------------------------------------------------------ - * Import schedule entries to an XML file. + * Import schedule entries from an XML file. *----------------------------------------------------------------------------*/ void -PostgresqlSchedule :: importScheduleEntries(xmlpp::Element * element) +PostgresqlSchedule :: importScheduleEntries(const xmlpp::Element * element) throw (std::invalid_argument) { if (element->get_name() != scheduleExportElementName) { diff --git a/livesupport/src/products/scheduler/src/PostgresqlSchedule.h b/livesupport/src/products/scheduler/src/PostgresqlSchedule.h index fe42982d2..fb754de83 100644 --- a/livesupport/src/products/scheduler/src/PostgresqlSchedule.h +++ b/livesupport/src/products/scheduler/src/PostgresqlSchedule.h @@ -336,7 +336,7 @@ class PostgresqlSchedule : public Configurable, * @see #exportScheduleEntries */ virtual void - importScheduleEntries(xmlpp::Element * element) + importScheduleEntries(const xmlpp::Element * element) throw (std::invalid_argument); /** diff --git a/livesupport/src/products/scheduler/src/RestoreBackupMethod.cxx b/livesupport/src/products/scheduler/src/RestoreBackupMethod.cxx new file mode 100644 index 000000000..2ae208278 --- /dev/null +++ b/livesupport/src/products/scheduler/src/RestoreBackupMethod.cxx @@ -0,0 +1,123 @@ +/*------------------------------------------------------------------------------ + + Copyright (c) 2004 Media Development Loan Fund + + This file is part of the LiveSupport project. + http://livesupport.campware.org/ + To report bugs, send an e-mail to bugs@campware.org + + LiveSupport is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + LiveSupport 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LiveSupport; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + Author : $Author: fgerlits $ + Version : $Revision$ + Location : $URL: svn+ssh://fgerlits@code.campware.org/home/svn/repo/livesupport/branches/scheduler_export/livesupport/src/products/scheduler/src/RestoreBackupMethod.cxx $ + +------------------------------------------------------------------------------*/ + +/* ============================================================ include files */ + +#include "LiveSupport/Core/XmlRpcTools.h" +#include "LiveSupport/Core/XmlRpcException.h" +#include "BackupFactory.h" + +#include "RestoreBackupMethod.h" + + +using namespace LiveSupport; +using namespace LiveSupport::Core; + +using namespace LiveSupport::Scheduler; + +/* =================================================== local data structures */ + + +/* ================================================ local constants & macros */ + +/*------------------------------------------------------------------------------ + * The name of this XML-RPC method. + *----------------------------------------------------------------------------*/ +const std::string RestoreBackupMethod::methodName = "restoreBackup"; + +/*------------------------------------------------------------------------------ + * The ID of this method for error reporting purposes. + *----------------------------------------------------------------------------*/ +const int RestoreBackupMethod::errorId = 4500; + + +/* =============================================== local function prototypes */ + + +/* ============================================================= module code */ + +/*------------------------------------------------------------------------------ + * Construct the method and register it right away. + *----------------------------------------------------------------------------*/ +RestoreBackupMethod :: RestoreBackupMethod ( + Ptr::Ref xmlRpcServer) + throw() + : XmlRpc::XmlRpcServerMethod(methodName, xmlRpcServer.get()) +{ +} + + +/*------------------------------------------------------------------------------ + * Execute the upload playlist method XML-RPC function call. + *----------------------------------------------------------------------------*/ +void +RestoreBackupMethod :: execute(XmlRpc::XmlRpcValue & rootParameter, + XmlRpc::XmlRpcValue & returnValue) + throw (XmlRpc::XmlRpcException) +{ + if (!rootParameter.valid() || rootParameter.size() != 1 + || !rootParameter[0].valid()) { + XmlRpcTools::markError(errorId+1, "invalid argument format", + returnValue); + return; + } + XmlRpc::XmlRpcValue parameters = rootParameter[0]; + + Ptr::Ref sessionId; + try{ + sessionId = XmlRpcTools::extractSessionId(parameters); + } catch (std::invalid_argument &e) { + XmlRpcTools::markError(errorId+20, + "missing session ID argument", + returnValue); + return; + } + + Ptr::Ref path; + try{ + path = XmlRpcTools::extractPath(parameters); + + } catch (std::invalid_argument &e) { + XmlRpcTools::markError(errorId+2, + "missing path argument", + returnValue); + return; + } + + Ptr::Ref bf = BackupFactory::getInstance(); + Ptr::Ref backup = bf->getBackup(); + try { + backup->restoreBackup(sessionId, path); + + } catch (Core::XmlRpcException &e) { + XmlRpcTools::markError(errorId+10, e.what(), returnValue); + return; + } +} + diff --git a/livesupport/src/products/scheduler/src/RestoreBackupMethod.h b/livesupport/src/products/scheduler/src/RestoreBackupMethod.h new file mode 100644 index 000000000..251fa7d63 --- /dev/null +++ b/livesupport/src/products/scheduler/src/RestoreBackupMethod.h @@ -0,0 +1,141 @@ +/*------------------------------------------------------------------------------ + + Copyright (c) 2004 Media Development Loan Fund + + This file is part of the LiveSupport project. + http://livesupport.campware.org/ + To report bugs, send an e-mail to bugs@campware.org + + LiveSupport is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + LiveSupport 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LiveSupport; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + Author : $Author: fgerlits $ + Version : $Revision$ + Location : $URL: svn+ssh://fgerlits@code.campware.org/home/svn/repo/livesupport/branches/scheduler_export/livesupport/src/products/scheduler/src/RestoreBackupMethod.h $ + +------------------------------------------------------------------------------*/ +#ifndef RestoreBackupMethod_h +#define RestoreBackupMethod_h + +#ifndef __cplusplus +#error This is a C++ include file +#endif + + +/* ============================================================ include files */ + +#ifdef HAVE_CONFIG_H +#include "configure.h" +#endif + +#include +#include +#include + + +namespace LiveSupport { +namespace Scheduler { + +/* ================================================================ constants */ + + +/* =================================================================== macros */ + + +/* =============================================================== data types */ + +/** + * An XML-RPC method object to restore a schedule backup. + * + * The name of the method when called through XML-RPC is "restoreBackup". + * + * The expected parameter is an XML-RPC structure with these members: + *
    + *
  • sessionId - string - the session ID obtained via the login() + * method of the authentication client;
  • + *
  • path - string - the local path and filename of the backup + * archive to be restored.
  • + *
+ * + * In case of an error, a standard XML-RPC fault response is generated, + * and a { faultCode, faultString } structure is returned. The + * possible errors are: + *
    + *
  • 4501 - invalid argument format
  • + *
  • 4502 - missing path argument
  • + *
  • 4510 - error reported by the scheduler daemon
  • + *
  • 4520 - missing session ID argument
  • + *
+ * + * @author $Author: fgerlits $ + * @version $Revision$ + */ +class RestoreBackupMethod : public XmlRpc::XmlRpcServerMethod +{ + private: + /** + * The name of this method, as it will be registered into the + * XML-RPC server. + */ + static const std::string methodName; + + /** + * The ID of this method for error reporting purposes. + */ + static const int errorId; + + + public: + /** + * A default constructor, for testing purposes. + */ + RestoreBackupMethod(void) throw () + : XmlRpc::XmlRpcServerMethod(methodName) + { + } + + /** + * Constuctor that registers the method with the server right away. + * + * @param xmlRpcServer the XML-RPC server to register with. + */ + RestoreBackupMethod( + Ptr::Ref xmlRpcServer) + throw (); + + /** + * Execute the createBackupOpen command on the Scheduler daemon. + * + * @param parameters XML-RPC function call parameters + * @param returnValue the return value of the call (out parameter) + */ + void + execute(XmlRpc::XmlRpcValue & parameters, + XmlRpc::XmlRpcValue & returnValue) + throw (XmlRpc::XmlRpcException); +}; + + +/* ================================================= external data structures */ + + +/* ====================================================== function prototypes */ + + +} // namespace Scheduler +} // namespace LiveSupport + +#endif // RestoreBackupMethod_h + diff --git a/livesupport/src/products/scheduler/src/RpcBackupTest.cxx b/livesupport/src/products/scheduler/src/RpcBackupTest.cxx index 20090459f..25c017233 100644 --- a/livesupport/src/products/scheduler/src/RpcBackupTest.cxx +++ b/livesupport/src/products/scheduler/src/RpcBackupTest.cxx @@ -30,11 +30,14 @@ /* ============================================================ include files */ #include +#include + #include #include #include "LiveSupport/Core/UniqueId.h" #include "LiveSupport/Core/XmlRpcTools.h" +#include "LiveSupport/Core/FileTools.h" #include "SchedulerDaemon.h" #include "PlayLogFactory.h" @@ -51,11 +54,19 @@ using namespace LiveSupport::Scheduler; CPPUNIT_TEST_SUITE_REGISTRATION(RpcBackupTest); +namespace { + /** * The name of the configuration file for the scheduler daemon */ -static const std::string configFileName = "etc/scheduler.xml"; +const std::string configFileName = "etc/scheduler.xml"; +/** + * The location of the temporary backup file + */ +const std::string tempBackupTarFileName = "tmp/scheduleBackup.tar"; + +} /* =============================================== local function prototypes */ @@ -135,14 +146,16 @@ RpcBackupTest :: tearDown(void) throw (CPPUNIT_NS::Exception) CPPUNIT_ASSERT(!xmlRpcClient.isFault()); xmlRpcClient.close(); + + remove(tempBackupTarFileName.c_str()); } /*------------------------------------------------------------------------------ - * Test the createBackupXxxx methods. + * Create the backup. *----------------------------------------------------------------------------*/ void -RpcBackupTest :: createBackupTest(void) +RpcBackupTest :: createBackup(void) throw (CPPUNIT_NS::Exception) { CPPUNIT_ASSERT(sessionId); @@ -210,6 +223,14 @@ RpcBackupTest :: createBackupTest(void) path = XmlRpcTools::extractPath(result); ); + // copy the backup file + CPPUNIT_ASSERT_NO_THROW( + remove(tempBackupTarFileName.c_str()); + std::ifstream ifs(path->c_str(), std::ios::binary); + std::ofstream ofs(tempBackupTarFileName.c_str(), std::ios::binary); + ofs << ifs.rdbuf(); + ); + parameters.clear(); XmlRpcTools::tokenToXmlRpcValue(token, parameters); result.clear(); @@ -217,6 +238,88 @@ RpcBackupTest :: createBackupTest(void) parameters, result)); CPPUNIT_ASSERT(!xmlRpcClient.isFault()); - // TODO: test existence of schedule backup in tarball + + xmlRpcClient.close(); +} + + +/*------------------------------------------------------------------------------ + * Test the createBackupXxxx methods. + *----------------------------------------------------------------------------*/ +void +RpcBackupTest :: createBackupTest(void) + throw (CPPUNIT_NS::Exception) +{ + // Create the backup. + CPPUNIT_ASSERT_NO_THROW( + createBackup() + ); + + // Check the backup file. + bool exists; + std::string schedulerBackupInTarball = "meta-inf/scheduler.xml"; + CPPUNIT_ASSERT_NO_THROW( + exists = FileTools::existsInTarball(tempBackupTarFileName, + schedulerBackupInTarball) + ); + CPPUNIT_ASSERT(exists); + + std::string extractedTempFileName = "tmp/scheduler.tmp.xml"; + FILE * file; + + remove(extractedTempFileName.c_str()); + file = fopen(extractedTempFileName.c_str(), "r"); + CPPUNIT_ASSERT(file == 0); + + CPPUNIT_ASSERT_NO_THROW( + FileTools::extractFileFromTarball(tempBackupTarFileName, + schedulerBackupInTarball, + extractedTempFileName) + ); + + file = fopen(extractedTempFileName.c_str(), "r"); + CPPUNIT_ASSERT(file != 0); + CPPUNIT_ASSERT(fclose(file) == 0); + + CPPUNIT_ASSERT(remove(extractedTempFileName.c_str()) == 0); + file = fopen(extractedTempFileName.c_str(), "r"); + CPPUNIT_ASSERT(file == 0); +} + + +/*------------------------------------------------------------------------------ + * Test the restoreBackup method. + *----------------------------------------------------------------------------*/ +void +RpcBackupTest :: restoreBackupTest(void) + throw (CPPUNIT_NS::Exception) +{ + // Create the backup. + CPPUNIT_ASSERT_NO_THROW( + createBackup() + ); + + XmlRpc::XmlRpcValue parameters; + XmlRpc::XmlRpcValue result; + + XmlRpc::XmlRpcClient xmlRpcClient(getXmlRpcHost().c_str(), + getXmlRpcPort(), + "/RPC2", + false); + + CPPUNIT_ASSERT(sessionId); + Ptr::Ref path(new const Glib::ustring( + tempBackupTarFileName)); + + XmlRpcTools::sessionIdToXmlRpcValue(sessionId, parameters); + XmlRpcTools::pathToXmlRpcValue(path, parameters); + + CPPUNIT_ASSERT(xmlRpcClient.execute("restoreBackup", + parameters, + result)); + CPPUNIT_ASSERT(!xmlRpcClient.isFault()); + + xmlRpcClient.close(); + // TODO: try this with a non-empty backup file, too } diff --git a/livesupport/src/products/scheduler/src/RpcBackupTest.h b/livesupport/src/products/scheduler/src/RpcBackupTest.h index 9171551ca..8e58235a9 100644 --- a/livesupport/src/products/scheduler/src/RpcBackupTest.h +++ b/livesupport/src/products/scheduler/src/RpcBackupTest.h @@ -71,6 +71,7 @@ class RpcBackupTest : public BaseTestMethod { CPPUNIT_TEST_SUITE(RpcBackupTest); CPPUNIT_TEST(createBackupTest); + CPPUNIT_TEST(restoreBackupTest); CPPUNIT_TEST_SUITE_END(); private: @@ -80,6 +81,13 @@ class RpcBackupTest : public BaseTestMethod */ Ptr::Ref sessionId; + /** + * Auxiliary method: create the backup file. Used by both tests. + */ + void + createBackup(void) throw (CPPUNIT_NS::Exception); + + protected: /** @@ -90,6 +98,15 @@ class RpcBackupTest : public BaseTestMethod void createBackupTest(void) throw (CPPUNIT_NS::Exception); + /** + * Test the restoreBackup method. + * + * @exception CPPUNIT_NS::Exception on test failures. + */ + void + restoreBackupTest(void) throw (CPPUNIT_NS::Exception); + + public: /** diff --git a/livesupport/src/products/scheduler/src/RpcStopCurrentlyPlayingTest.cxx b/livesupport/src/products/scheduler/src/RpcStopCurrentlyPlayingTest.cxx new file mode 100644 index 000000000..a8ee12d19 --- /dev/null +++ b/livesupport/src/products/scheduler/src/RpcStopCurrentlyPlayingTest.cxx @@ -0,0 +1,240 @@ +/*------------------------------------------------------------------------------ + + Copyright (c) 2004 Media Development Loan Fund + + This file is part of the LiveSupport project. + http://livesupport.campware.org/ + To report bugs, send an e-mail to bugs@campware.org + + LiveSupport is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + LiveSupport 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LiveSupport; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + Author : $Author: fgerlits $ + Version : $Revision$ + Location : $URL: svn+ssh://fgerlits@code.campware.org/home/svn/repo/livesupport/branches/scheduler_export/livesupport/src/products/scheduler/src/RpcStopCurrentlyPlayingTest.cxx $ + +------------------------------------------------------------------------------*/ + +/* ============================================================ include files */ + +#include +#include +#include + +#include "SchedulerDaemon.h" +#include "LiveSupport/Core/TimeConversion.h" + +#include "RpcStopCurrentlyPlayingTest.h" + + +using namespace LiveSupport::Core; +using namespace LiveSupport::Scheduler; + +/* =================================================== local data structures */ + + +/* ================================================ local constants & macros */ + +CPPUNIT_TEST_SUITE_REGISTRATION(RpcStopCurrentlyPlayingTest); + +/** + * The name of the configuration file for the scheduler daemon. + */ +static const std::string configFileName = "etc/scheduler.xml"; + + +/* =============================================== local function prototypes */ + + +/* ============================================================= module code */ + +/*------------------------------------------------------------------------------ + * Set up the test environment + *----------------------------------------------------------------------------*/ +void +RpcStopCurrentlyPlayingTest :: setUp(void) throw (CPPUNIT_NS::Exception) +{ + Ptr::Ref daemon = SchedulerDaemon::getInstance(); + + if (!daemon->isConfigured()) { + try { + Ptr::Ref parser(new xmlpp::DomParser( + configFileName, true)); + const xmlpp::Document * document = parser->get_document(); + const xmlpp::Element * root = document->get_root_node(); + daemon->configure(*root); + } catch (std::invalid_argument &e) { + std::cerr << e.what() << std::endl; + CPPUNIT_FAIL("semantic error in configuration file"); + } catch (xmlpp::exception &e) { + std::cerr << e.what() << std::endl; + CPPUNIT_FAIL("error parsing configuration file"); + } + } + + daemon->install(); + + XmlRpc::XmlRpcValue parameters; + XmlRpc::XmlRpcValue result; + + XmlRpc::XmlRpcClient xmlRpcClient(getXmlRpcHost().c_str(), + getXmlRpcPort(), + "/RPC2", + false); + + CPPUNIT_ASSERT(xmlRpcClient.execute("resetStorage", parameters, result)); + CPPUNIT_ASSERT(!xmlRpcClient.isFault()); + + parameters["login"] = "root"; + parameters["password"] = "q"; + CPPUNIT_ASSERT(xmlRpcClient.execute("login", parameters, result)); + CPPUNIT_ASSERT(!xmlRpcClient.isFault()); + CPPUNIT_ASSERT(result.hasMember("sessionId")); + + xmlRpcClient.close(); + + sessionId.reset(new SessionId(std::string(result["sessionId"]))); +} + + +/*------------------------------------------------------------------------------ + * Clean up the test environment + *----------------------------------------------------------------------------*/ +void +RpcStopCurrentlyPlayingTest :: tearDown(void) throw (CPPUNIT_NS::Exception) +{ + Ptr::Ref daemon = SchedulerDaemon::getInstance(); + daemon->uninstall(); + + CPPUNIT_ASSERT(sessionId); + + XmlRpc::XmlRpcValue parameters; + XmlRpc::XmlRpcValue result; + + XmlRpc::XmlRpcClient xmlRpcClient(getXmlRpcHost().c_str(), + getXmlRpcPort(), + "/RPC2", + false); + + parameters["sessionId"] = sessionId->getId(); + CPPUNIT_ASSERT(xmlRpcClient.execute("logout", parameters, result)); + CPPUNIT_ASSERT(!xmlRpcClient.isFault()); + + xmlRpcClient.close(); +} + + +/*------------------------------------------------------------------------------ + * A simple smoke test. + *----------------------------------------------------------------------------*/ +void +RpcStopCurrentlyPlayingTest :: simpleTest(void) + throw (CPPUNIT_NS::Exception) +{ + schedulePlaylistToPlayNow(); + + Ptr::Ref daemon = SchedulerDaemon::getInstance(); + CPPUNIT_ASSERT(daemon); + Ptr::Ref audioPlayer = daemon->getAudioPlayer(); + CPPUNIT_ASSERT(audioPlayer); + + sleep(10); + CPPUNIT_ASSERT(audioPlayer->isOpen()); + CPPUNIT_ASSERT(audioPlayer->isPlaying()); + + XmlRpc::XmlRpcValue parameters; + XmlRpc::XmlRpcValue result; + + XmlRpc::XmlRpcClient xmlRpcClient(getXmlRpcHost().c_str(), + getXmlRpcPort(), + "/RPC2", + false); + + // first schedule a playlist, so that there is something to reschedule + CPPUNIT_ASSERT(sessionId); + parameters["sessionId"] = sessionId->getId(); + + result.clear(); + xmlRpcClient.execute("stopCurrentlyPlaying", parameters, result); + CPPUNIT_ASSERT(!xmlRpcClient.isFault()); + + xmlRpcClient.close(); + + CPPUNIT_ASSERT(!audioPlayer->isPlaying()); + CPPUNIT_ASSERT(!audioPlayer->isOpen()); +} + + +/*------------------------------------------------------------------------------ + * A simple negative test. + *----------------------------------------------------------------------------*/ +void +RpcStopCurrentlyPlayingTest :: negativeTest(void) + throw (CPPUNIT_NS::Exception) +{ + CPPUNIT_ASSERT(sessionId); + + XmlRpc::XmlRpcValue parameters; + XmlRpc::XmlRpcValue result; + + XmlRpc::XmlRpcClient xmlRpcClient(getXmlRpcHost().c_str(), + getXmlRpcPort(), + "/RPC2", + false); + + CPPUNIT_ASSERT(sessionId); + parameters["sessionId"] = sessionId->getId(); + + result.clear(); + xmlRpcClient.execute("stopCurrentlyPlaying", parameters, result); + CPPUNIT_ASSERT(xmlRpcClient.isFault()); + + xmlRpcClient.close(); +} + + +/*------------------------------------------------------------------------------ + * Schedule a playlist to play now. + *----------------------------------------------------------------------------*/ +void +RpcStopCurrentlyPlayingTest :: schedulePlaylistToPlayNow(void) + throw (CPPUNIT_NS::Exception) +{ + XmlRpc::XmlRpcValue parameters; + XmlRpc::XmlRpcValue result; + struct tm time; + + XmlRpc::XmlRpcClient xmlRpcClient(getXmlRpcHost().c_str(), + getXmlRpcPort(), + "/RPC2", + false); + + // try to schedule playlist #1 for the time in 5 seconds + parameters.clear(); + CPPUNIT_ASSERT(sessionId); + parameters["sessionId"] = sessionId->getId(); + parameters["playlistId"] = "0000000000000001"; + Ptr::Ref now = TimeConversion::now(); + Ptr::Ref startTime(new ptime(*now + seconds(10))); + TimeConversion::ptimeToTm(startTime, time); + parameters["playtime"] = &time; + + result.clear(); + xmlRpcClient.execute("uploadPlaylist", parameters, result); + CPPUNIT_ASSERT(!xmlRpcClient.isFault()); + + xmlRpcClient.close(); +} + diff --git a/livesupport/src/products/scheduler/src/RpcStopCurrentlyPlayingTest.h b/livesupport/src/products/scheduler/src/RpcStopCurrentlyPlayingTest.h new file mode 100644 index 000000000..342133527 --- /dev/null +++ b/livesupport/src/products/scheduler/src/RpcStopCurrentlyPlayingTest.h @@ -0,0 +1,138 @@ +/*------------------------------------------------------------------------------ + + Copyright (c) 2004 Media Development Loan Fund + + This file is part of the LiveSupport project. + http://livesupport.campware.org/ + To report bugs, send an e-mail to bugs@campware.org + + LiveSupport is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + LiveSupport 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LiveSupport; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + Author : $Author: fgerlits $ + Version : $Revision$ + Location : $URL: svn+ssh://fgerlits@code.campware.org/home/svn/repo/livesupport/branches/scheduler_export/livesupport/src/products/scheduler/src/RpcStopCurrentlyPlayingTest.h $ + +------------------------------------------------------------------------------*/ +#ifndef RpcStopCurrentlyPlayingTest_h +#define RpcStopCurrentlyPlayingTest_h + +#ifndef __cplusplus +#error This is a C++ include file +#endif + + +/* ============================================================ include files */ + +#ifdef HAVE_CONFIG_H +#include "configure.h" +#endif + +#include + +#include "LiveSupport/Core/Ptr.h" +#include "LiveSupport/Core/SessionId.h" + +#include "BaseTestMethod.h" + +namespace LiveSupport { +namespace Scheduler { + +using namespace LiveSupport::Core; + +/* ================================================================ constants */ + + +/* =================================================================== macros */ + + +/* =============================================================== data types */ + +/** + * Unit test to test the removeFromSchedule XML-RPC call. + * + * @author $Author: fgerlits $ + * @version $Revision$ + * @see SchedulerDaemon + */ +class RpcStopCurrentlyPlayingTest : public BaseTestMethod +{ + CPPUNIT_TEST_SUITE(RpcStopCurrentlyPlayingTest); + CPPUNIT_TEST(simpleTest); + CPPUNIT_TEST(negativeTest); + CPPUNIT_TEST_SUITE_END(); + + private: + + /** + * A session ID from the authentication client login() method. + */ + Ptr::Ref sessionId; + + /** + * Schedule a playlist, so we can stop it. + * + * @exception CPPUNIT_NS::Exception on test failures. + */ + void + schedulePlaylistToPlayNow(void) throw (CPPUNIT_NS::Exception); + + + protected: + + /** + * Simple smoke test. + * + * @exception CPPUNIT_NS::Exception on test failures. + */ + void + simpleTest(void) throw (CPPUNIT_NS::Exception); + + /** + * Simple negative test. + * + * @exception CPPUNIT_NS::Exception on test failures. + */ + void + negativeTest(void) throw (CPPUNIT_NS::Exception); + + + public: + + /** + * Set up the environment for the test case. + */ + void + setUp(void) throw (CPPUNIT_NS::Exception); + + /** + * Clean up the environment after the test case. + */ + void + tearDown(void) throw (CPPUNIT_NS::Exception); +}; + + +/* ================================================= external data structures */ + + +/* ====================================================== function prototypes */ + + +} // namespace Scheduler +} // namespace LiveSupport + +#endif // RpcStopCurrentlyPlayingTest_h + diff --git a/livesupport/src/products/scheduler/src/ScheduleInterface.h b/livesupport/src/products/scheduler/src/ScheduleInterface.h index 4e868ebfd..2defe1724 100644 --- a/livesupport/src/products/scheduler/src/ScheduleInterface.h +++ b/livesupport/src/products/scheduler/src/ScheduleInterface.h @@ -152,7 +152,7 @@ class ScheduleInterface : virtual public Installable * @see #exportScheduleEntries */ virtual void - importScheduleEntries(xmlpp::Element * domTree) + importScheduleEntries(const xmlpp::Element * domTree) throw (std::invalid_argument) = 0; diff --git a/livesupport/src/products/scheduler/src/SchedulerDaemon.cxx b/livesupport/src/products/scheduler/src/SchedulerDaemon.cxx index 8a3eafea6..13d55ccb0 100644 --- a/livesupport/src/products/scheduler/src/SchedulerDaemon.cxx +++ b/livesupport/src/products/scheduler/src/SchedulerDaemon.cxx @@ -135,6 +135,8 @@ SchedulerDaemon :: SchedulerDaemon (void) throw () createBackupOpenMethod.reset(new CreateBackupOpenMethod()); createBackupCheckMethod.reset(new CreateBackupCheckMethod()); createBackupCloseMethod.reset(new CreateBackupCloseMethod()); + restoreBackupMethod.reset(new RestoreBackupMethod()); + stopCurrentlyPlayingMethod.reset(new StopCurrentlyPlayingMethod()); } @@ -295,6 +297,8 @@ SchedulerDaemon :: registerXmlRpcFunctions( xmlRpcServer->addMethod(createBackupOpenMethod.get()); xmlRpcServer->addMethod(createBackupCheckMethod.get()); xmlRpcServer->addMethod(createBackupCloseMethod.get()); + xmlRpcServer->addMethod(restoreBackupMethod.get()); + xmlRpcServer->addMethod(stopCurrentlyPlayingMethod.get()); } diff --git a/livesupport/src/products/scheduler/src/SchedulerDaemon.h b/livesupport/src/products/scheduler/src/SchedulerDaemon.h index 7e4133edd..56cc8fc31 100644 --- a/livesupport/src/products/scheduler/src/SchedulerDaemon.h +++ b/livesupport/src/products/scheduler/src/SchedulerDaemon.h @@ -83,7 +83,8 @@ #include "CreateBackupOpenMethod.h" #include "CreateBackupCheckMethod.h" #include "CreateBackupCloseMethod.h" - +#include "RestoreBackupMethod.h" +#include "StopCurrentlyPlayingMethod.h" namespace LiveSupport { namespace Scheduler { @@ -302,6 +303,16 @@ class SchedulerDaemon : public Installable, */ Ptr::Ref createBackupCloseMethod; + /** + * The restoreBackupMethod the daemon is providing. + */ + Ptr::Ref restoreBackupMethod; + + /** + * The stopCurrentlyPlayingMethod the daemon is providing. + */ + Ptr::Ref stopCurrentlyPlayingMethod; + /** * The login to the authentication system. */ @@ -488,7 +499,6 @@ class SchedulerDaemon : public Installable, */ virtual void update(void) throw (std::logic_error); - }; diff --git a/livesupport/src/products/scheduler/src/StopCurrentlyPlayingMethod.cxx b/livesupport/src/products/scheduler/src/StopCurrentlyPlayingMethod.cxx new file mode 100644 index 000000000..9dcd3ac54 --- /dev/null +++ b/livesupport/src/products/scheduler/src/StopCurrentlyPlayingMethod.cxx @@ -0,0 +1,129 @@ +/*------------------------------------------------------------------------------ + + Copyright (c) 2004 Media Development Loan Fund + + This file is part of the LiveSupport project. + http://livesupport.campware.org/ + To report bugs, send an e-mail to bugs@campware.org + + LiveSupport is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + LiveSupport 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LiveSupport; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + Author : $Author: fgerlits $ + Version : $Revision$ + Location : $URL: svn+ssh://fgerlits@code.campware.org/home/svn/repo/livesupport/trunk/livesupport/src/products/scheduler/src/StopCurrentlyPlayingMethod.cxx $ + +------------------------------------------------------------------------------*/ + +/* ============================================================ include files */ + +#ifdef HAVE_CONFIG_H +#include "configure.h" +#endif + +#ifdef HAVE_TIME_H +#include +#else +#error need time.h +#endif + + +#include +#include + +#include "LiveSupport/PlaylistExecutor/AudioPlayerInterface.h" +#include "LiveSupport/Core/XmlRpcTools.h" +#include "SchedulerDaemon.h" + +#include "StopCurrentlyPlayingMethod.h" + + +using namespace LiveSupport; +using namespace LiveSupport::Core; +using namespace LiveSupport::Scheduler; + +/* =================================================== local data structures */ + + +/* ================================================ local constants & macros */ + +/*------------------------------------------------------------------------------ + * The name of this XML-RPC method. + *----------------------------------------------------------------------------*/ +const std::string StopCurrentlyPlayingMethod::methodName + = "stopCurrentlyPlaying"; + +/*------------------------------------------------------------------------------ + * The ID of this method for error reporting purposes. + *----------------------------------------------------------------------------*/ +const int StopCurrentlyPlayingMethod::errorId = 5000; + + +/* =============================================== local function prototypes */ + + +/* ============================================================= module code */ + +/*------------------------------------------------------------------------------ + * Construct the method and register it right away. + *----------------------------------------------------------------------------*/ +StopCurrentlyPlayingMethod :: StopCurrentlyPlayingMethod ( + Ptr::Ref xmlRpcServer) throw() + : XmlRpc::XmlRpcServerMethod(methodName, xmlRpcServer.get()) +{ +} + + +/*------------------------------------------------------------------------------ + * Execute the remove from schedule XML-RPC function call. + *----------------------------------------------------------------------------*/ +void +StopCurrentlyPlayingMethod :: execute(XmlRpc::XmlRpcValue & rootParameter, + XmlRpc::XmlRpcValue & returnValue) + throw (XmlRpc::XmlRpcException) +{ + if (!rootParameter.valid() || rootParameter.size() != 1 + || !rootParameter[0].valid()) { + XmlRpcTools::markError(errorId+1, + "invalid argument format", + returnValue); + return; + } + XmlRpc::XmlRpcValue parameters = rootParameter[0]; + + Ptr::Ref sessionId; + try{ + sessionId = XmlRpcTools::extractSessionId(parameters); + } catch (std::invalid_argument &e) { + XmlRpcTools::markError(errorId+20, + "missing session ID argument", + returnValue); + return; + } + // TODO: check the session ID + + Ptr::Ref sd = SchedulerDaemon::getInstance(); + Ptr::Ref audioPlayer = sd->getAudioPlayer(); + + try { + audioPlayer->stop(); + audioPlayer->close(); + + } catch (std::logic_error &e) { + XmlRpcTools::markError(errorId+10, e.what(), returnValue); + return; + } +} + diff --git a/livesupport/src/products/scheduler/src/StopCurrentlyPlayingMethod.h b/livesupport/src/products/scheduler/src/StopCurrentlyPlayingMethod.h new file mode 100644 index 000000000..d59912fe4 --- /dev/null +++ b/livesupport/src/products/scheduler/src/StopCurrentlyPlayingMethod.h @@ -0,0 +1,146 @@ +/*------------------------------------------------------------------------------ + + Copyright (c) 2004 Media Development Loan Fund + + This file is part of the LiveSupport project. + http://livesupport.campware.org/ + To report bugs, send an e-mail to bugs@campware.org + + LiveSupport is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + LiveSupport 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LiveSupport; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + Author : $Author: fgerlits $ + Version : $Revision$ + Location : $URL: svn+ssh://fgerlits@code.campware.org/home/svn/repo/livesupport/trunk/livesupport/src/products/scheduler/src/StopCurrentlyPlayingMethod.h $ + +------------------------------------------------------------------------------*/ +#ifndef StopCurrentlyPlayingMethod_h +#define StopCurrentlyPlayingMethod_h + +#ifndef __cplusplus +#error This is a C++ include file +#endif + + +/* ============================================================ include files */ + +#ifdef HAVE_CONFIG_H +#include "configure.h" +#endif + +#include +#include +#include +#include + +#include "LiveSupport/Core/Ptr.h" +#include "LiveSupport/Core/UniqueId.h" + + +namespace LiveSupport { +namespace Scheduler { + +using namespace LiveSupport; +using namespace LiveSupport::Core; + +/* ================================================================ constants */ + + +/* =================================================================== macros */ + + +/* =============================================================== data types */ + +/** + * An XML-RPC method object to stop the scheduler's audio player. + * + * The name of the method when called through XML-RPC is "stopCurrenlyPlaying". + * + * The expected parameter is an XML-RPC structure, with the following + * member: + *
    + *
  • sessionId - string - the session ID obtained via the login() + * method of the authentication client
  • + *
+ * + * In case of an error, a standard XML-RPC fault response is generated, + * and a { faultCode, faultString } structure is returned. The + * possible errors are: + *
    + *
  • 5001 - invalid argument format
  • + *
  • 5010 - error reported by the audio player component
  • + *
  • 5020 - missing session ID argument
  • + *
+ * + * @author $Author: fgerlits $ + * @version $Revision$ + */ +class StopCurrentlyPlayingMethod : public XmlRpc::XmlRpcServerMethod +{ + private: + /** + * The name of this method, as it will be registered into the + * XML-RPC server. + */ + static const std::string methodName; + + /** + * The ID of this method for error reporting purposes. + */ + static const int errorId; + + + public: + /** + * A default constructor, for testing purposes. + */ + StopCurrentlyPlayingMethod(void) throw () + : XmlRpc::XmlRpcServerMethod(methodName) + { + } + + /** + * Constuctor that registers the method with the server right away. + * + * @param xmlRpcServer the XML-RPC server to register with. + */ + StopCurrentlyPlayingMethod( + Ptr::Ref xmlRpcServer) + throw (); + + /** + * Execute the remove from schedule command on the Scheduler daemon. + * + * @param parameters XML-RPC function call parameters + * @param returnValue the return value of the call (out parameter) + */ + void + execute(XmlRpc::XmlRpcValue & parameters, + XmlRpc::XmlRpcValue & returnValue) + throw (XmlRpc::XmlRpcException); +}; + + +/* ================================================= external data structures */ + + +/* ====================================================== function prototypes */ + + +} // namespace Scheduler +} // namespace LiveSupport + +#endif // StopCurrentlyPlayingMethod_h +