merging the scheduler_export branch (2154:2179) back to the trunk;

this should have been done much earlier, but I forgot
This commit is contained in:
fgerlits 2006-08-07 18:45:50 +00:00
parent 5b27e430ed
commit 1dd37106d3
35 changed files with 1665 additions and 57 deletions

View file

@ -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 */

View file

@ -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);
}
}

View file

@ -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
);
}

View file

@ -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:

View file

@ -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
#-------------------------------------------------------------------------------

View file

@ -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 <version>", 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

View file

@ -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)

View file

@ -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<SessionId>::Ref sessionId,
Ptr<const Glib::ustring>::Ref path)
throw (XmlRpcException)
= 0;
/**
* A virtual destructor, as this class has virtual functions.
*/

View file

@ -241,7 +241,6 @@ SchedulerDaemonXmlRpcClient :: uploadPlaylist(
XmlRpcValue xmlRpcParams;
XmlRpcValue xmlRpcResult;
Ptr<const ptime>::Ref result;
XmlRpcClient xmlRpcClient(xmlRpcHost->c_str(),
xmlRpcPort,
@ -291,7 +290,6 @@ SchedulerDaemonXmlRpcClient :: displaySchedule(
XmlRpcValue xmlRpcParams;
XmlRpcValue xmlRpcResult;
Ptr<const ptime>::Ref result;
XmlRpcClient xmlRpcClient(xmlRpcHost->c_str(),
xmlRpcPort,
@ -338,7 +336,6 @@ SchedulerDaemonXmlRpcClient :: removeFromSchedule(
{
XmlRpcValue xmlRpcParams;
XmlRpcValue xmlRpcResult;
Ptr<const ptime>::Ref result;
XmlRpcClient xmlRpcClient(xmlRpcHost->c_str(),
xmlRpcPort,
@ -517,3 +514,43 @@ SchedulerDaemonXmlRpcClient :: createBackupClose(
xmlRpcClient.close();
}
/*------------------------------------------------------------------------------
* Restore a schedule backup.
*----------------------------------------------------------------------------*/
void
SchedulerDaemonXmlRpcClient :: restoreBackup(
Ptr<SessionId>::Ref sessionId,
Ptr<const Glib::ustring>::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();
}

View file

@ -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<SessionId>::Ref sessionId,
Ptr<const Glib::ustring>::Ref path)
throw (XmlRpcException);
};

View file

@ -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<SearchCriteria>::Ref criteria(new SearchCriteria);
Ptr<SearchCriteria>::Ref criteria(new SearchCriteria);
criteria->setLimit(10);
Ptr<ptime>::Ref from(new ptime(time_from_string("2004-07-23 10:00:00")));
Ptr<ptime>::Ref to(new ptime(time_from_string("2004-07-23 11:00:00")));
Ptr<Glib::ustring>::Ref token;
Ptr<const Glib::ustring>::Ref token;
CPPUNIT_ASSERT_NO_THROW(
token = schedulerClient->createBackupOpen(sessionId,
criteria,
@ -354,10 +364,10 @@ SchedulerDaemonXmlRpcClientTest :: createBackupTest(void)
);
CPPUNIT_ASSERT(token);
Ptr<const Glib::ustring>::Ref url;
Ptr<const Glib::ustring>::Ref path;
Ptr<const Glib::ustring>::Ref errorMessage;
AsyncState status;
Ptr<const Glib::ustring>::Ref url;
Ptr<const Glib::ustring>::Ref path;
Ptr<const Glib::ustring>::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<Glib::ustring>::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
}

View file

@ -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<SessionId>::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:

View file

@ -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

View file

@ -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<SessionId>::Ref sessionId,
Ptr<const Glib::ustring>::Ref path)
throw (XmlRpcException)
= 0;
/**
* A virtual destructor, as this class has virtual functions.
*/

View file

@ -32,6 +32,7 @@
#include <string>
#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",

View file

@ -93,8 +93,8 @@ using namespace LiveSupport::Core;
* <ul>
* <li>4101 - invalid argument format </li>
* <li>4102 - missing token argument </li>
* <li>4010 - error reported by the scheduler daemon </li>
* <li>4011 - syntax error in the values returned by
* <li>4110 - error reported by the scheduler daemon </li>
* <li>4111 - syntax error in the values returned by
* the scheduler daemon </li>
* </ul>
*

View file

@ -43,6 +43,7 @@
#include <string>
#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;
}

View file

@ -43,6 +43,7 @@
#include <string>
#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;
}

View file

@ -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<SessionId>::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<Document>::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<SessionId>::Ref sessionId,
Ptr<const Glib::ustring>::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<DomParser>::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);
}
}

View file

@ -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<SessionId>::Ref sessionId,
Ptr<const Glib::ustring>::Ref path)
throw (XmlRpcException);
};

View file

@ -41,7 +41,9 @@
#include <string>
#include <fstream>
#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<SearchCriteria>::Ref criteria(new SearchCriteria);
Ptr<SearchCriteria>::Ref criteria(new SearchCriteria);
criteria->setLimit(10);
Ptr<ptime>::Ref from(new ptime(time_from_string("2004-07-23 10:00:00")));
Ptr<ptime>::Ref to(new ptime(time_from_string("2004-07-23 11:00:00")));
Ptr<Glib::ustring>::Ref token;
Ptr<const Glib::ustring>::Ref token;
CPPUNIT_ASSERT_NO_THROW(
token = backup->createBackupOpen(sessionId, criteria, from, to);
);
CPPUNIT_ASSERT(token);
Ptr<const Glib::ustring>::Ref url;
Ptr<const Glib::ustring>::Ref path;
Ptr<const Glib::ustring>::Ref errorMessage;
AsyncState status;
Ptr<const Glib::ustring>::Ref url;
Ptr<const Glib::ustring>::Ref path;
Ptr<const Glib::ustring>::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<const Glib::ustring>::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
}

View file

@ -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<SessionId>::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:
/**

View file

@ -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) {

View file

@ -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);
/**

View file

@ -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<XmlRpc::XmlRpcServer>::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<SessionId>::Ref sessionId;
try{
sessionId = XmlRpcTools::extractSessionId(parameters);
} catch (std::invalid_argument &e) {
XmlRpcTools::markError(errorId+20,
"missing session ID argument",
returnValue);
return;
}
Ptr<Glib::ustring>::Ref path;
try{
path = XmlRpcTools::extractPath(parameters);
} catch (std::invalid_argument &e) {
XmlRpcTools::markError(errorId+2,
"missing path argument",
returnValue);
return;
}
Ptr<BackupFactory>::Ref bf = BackupFactory::getInstance();
Ptr<BackupInterface>::Ref backup = bf->getBackup();
try {
backup->restoreBackup(sessionId, path);
} catch (Core::XmlRpcException &e) {
XmlRpcTools::markError(errorId+10, e.what(), returnValue);
return;
}
}

View file

@ -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 <string>
#include <XmlRpcServerMethod.h>
#include <XmlRpcException.h>
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:
* <ul>
* <li>sessionId - string - the session ID obtained via the login()
* method of the authentication client; </li>
* <li>path - string - the local path and filename of the backup
* archive to be restored.</li>
* </ul>
*
* In case of an error, a standard XML-RPC fault response is generated,
* and a {&nbsp;faultCode, faultString&nbsp;} structure is returned. The
* possible errors are:
* <ul>
* <li>4501 - invalid argument format </li>
* <li>4502 - missing path argument </li>
* <li>4510 - error reported by the scheduler daemon </li>
* <li>4520 - missing session ID argument </li>
* </ul>
*
* @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<XmlRpc::XmlRpcServer>::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

View file

@ -30,11 +30,14 @@
/* ============================================================ include files */
#include <string>
#include <fstream>
#include <XmlRpcClient.h>
#include <XmlRpcValue.h>
#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<const Glib::ustring>::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
}

View file

@ -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<SessionId>::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:
/**

View file

@ -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 <string>
#include <XmlRpcClient.h>
#include <XmlRpcValue.h>
#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<SchedulerDaemon>::Ref daemon = SchedulerDaemon::getInstance();
if (!daemon->isConfigured()) {
try {
Ptr<xmlpp::DomParser>::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<SchedulerDaemon>::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<SchedulerDaemon>::Ref daemon = SchedulerDaemon::getInstance();
CPPUNIT_ASSERT(daemon);
Ptr<AudioPlayerInterface>::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<ptime>::Ref now = TimeConversion::now();
Ptr<ptime>::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();
}

View file

@ -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 <cppunit/extensions/HelperMacros.h>
#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<SessionId>::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

View file

@ -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;

View file

@ -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());
}

View file

@ -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<CreateBackupCloseMethod>::Ref createBackupCloseMethod;
/**
* The restoreBackupMethod the daemon is providing.
*/
Ptr<RestoreBackupMethod>::Ref restoreBackupMethod;
/**
* The stopCurrentlyPlayingMethod the daemon is providing.
*/
Ptr<StopCurrentlyPlayingMethod>::Ref stopCurrentlyPlayingMethod;
/**
* The login to the authentication system.
*/
@ -488,7 +499,6 @@ class SchedulerDaemon : public Installable,
*/
virtual void
update(void) throw (std::logic_error);
};

View file

@ -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 <time.h>
#else
#error need time.h
#endif
#include <string>
#include <stdexcept>
#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<XmlRpc::XmlRpcServer>::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<SessionId>::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<SchedulerDaemon>::Ref sd = SchedulerDaemon::getInstance();
Ptr<AudioPlayerInterface>::Ref audioPlayer = sd->getAudioPlayer();
try {
audioPlayer->stop();
audioPlayer->close();
} catch (std::logic_error &e) {
XmlRpcTools::markError(errorId+10, e.what(), returnValue);
return;
}
}

View file

@ -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 <string>
#include <XmlRpcServerMethod.h>
#include <XmlRpcValue.h>
#include <XmlRpcException.h>
#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:
* <ul>
* <li>sessionId - string - the session ID obtained via the login()
* method of the authentication client </li>
* </ul>
*
* In case of an error, a standard XML-RPC fault response is generated,
* and a {&nbsp;faultCode, faultString&nbsp;} structure is returned. The
* possible errors are:
* <ul>
* <li>5001 - invalid argument format </li>
* <li>5010 - error reported by the audio player component </li>
* <li>5020 - missing session ID argument </li>
* </ul>
*
* @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<XmlRpc::XmlRpcServer>::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