2010-03-06 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

Added changeUri XML-RPC method.  This method removes/adds URIs
	dynamically.
	* doc/aria2c.1.txt
	* src/AbstractCommand.cc
	* src/DownloadContext.cc
	* src/DownloadContext.h
	* src/FileEntry.cc
	* src/FileEntry.h
	* src/Request.cc
	* src/Request.h
	* src/RequestGroup.cc
	* src/RequestGroupMan.cc
	* src/XmlRpcMethodFactory.cc
	* src/XmlRpcMethodImpl.cc
	* src/XmlRpcMethodImpl.h
	* test/FileEntryTest.cc
	* test/XmlRpcMethodTest.cc
pull/1/head
Tatsuhiro Tsujikawa 2010-03-06 14:21:43 +00:00
parent 61b2b88c29
commit b1713e6373
18 changed files with 461 additions and 12 deletions

View File

@ -1,3 +1,23 @@
2010-03-06 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Added changeUri XML-RPC method. This method removes/adds URIs
dynamically.
* doc/aria2c.1.txt
* src/AbstractCommand.cc
* src/DownloadContext.cc
* src/DownloadContext.h
* src/FileEntry.cc
* src/FileEntry.h
* src/Request.cc
* src/Request.h
* src/RequestGroup.cc
* src/RequestGroupMan.cc
* src/XmlRpcMethodFactory.cc
* src/XmlRpcMethodImpl.cc
* src/XmlRpcMethodImpl.h
* test/FileEntryTest.cc
* test/XmlRpcMethodTest.cc
2010-03-06 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Rewritten copy ctor of RequestSlot to use initialization list.

View File

@ -2,12 +2,12 @@
.\" Title: aria2c
.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
.\" Date: 02/25/2010
.\" Date: 03/06/2010
.\" Manual: Aria2 Manual
.\" Source: Aria2 1.9.0a
.\" Language: English
.\"
.TH "ARIA2C" "1" "02/25/2010" "Aria2 1\&.9\&.0a" "Aria2 Manual"
.TH "ARIA2C" "1" "03/06/2010" "Aria2 1\&.9\&.0a" "Aria2 Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@ -2467,6 +2467,10 @@ This method changes the position of the download denoted by \fIgid\fR\&. \fIpos\
.sp
For example, if GID#1 is placed in position 3, aria2\&.changePosition(1, \-1, POS_CUR) will change its position to 2\&. Additional aria2\&.changePosition(1, 0, POS_SET) will change its position to 0(the beginning of the queue)\&.
.sp
\fBaria2\&.changeUri\fR \fIgid, fileIndex, delUris, addUris[, position]\fR
.sp
This method removes URIs in \fIdelUris\fR from and appends URIs in \fIaddUris\fR to download denoted by \fIgid\fR\&. \fIdelUris\fR and \fIaddUris\fR are list of string\&. A download can contain multiple files and URIs are attached to each file\&. \fIfileIndex\fR is used to select which file to remove/attach given URIs\&. \fIposition\fR is used to specify where URIs are inserted in the existing waiting URI list\&. \fIposition\fR is 0\-based\&. When \fIposition\fR is omitted, URIs are appended to the back of the list\&. This method first execute removal and then addition\&. \fIposition\fR is the position after URIs are removed, not the position when this method is called\&. When removing URI, if same URIs exist in download, only one of them is removed for each URI in \fIdelUris\fR\&. In other words, there are three URIs "http://example\&.org/aria2" and you want remove them all, you have to specify (at least) 3 "http://example\&.org/aria2" in \fIdelUris\fR\&. This method returns a list which contains 2 integers\&. The first integer is the number of URIs deleted\&. The second integer is the number of URIs added\&.
.sp
\fBaria2\&.getOption\fR \fIgid\fR
.sp
This method returns options of the download denoted by \fIgid\fR\&. The response is of type struct\&. Its key is the name of option\&. The value type is string\&.

View File

@ -3176,6 +3176,24 @@ destination position.</p></div>
-1, POS_CUR) will change its position to 2. Additional
aria2.changePosition(1, 0, POS_SET) will change its position to 0(the
beginning of the queue).</p></div>
<div class="paragraph"><p><strong>aria2.changeUri</strong> <em>gid, fileIndex, delUris, addUris[, position]</em></p></div>
<div class="paragraph"><p>This method removes URIs in <em>delUris</em> from and appends URIs in
<em>addUris</em> to download denoted by <em>gid</em>. <em>delUris</em> and <em>addUris</em> are
list of string. A download can contain multiple files and URIs are
attached to each file. <em>fileIndex</em> is used to select which file to
remove/attach given URIs. <em>position</em> is used to specify where URIs
are inserted in the existing waiting URI list. <em>position</em> is
0-based. When <em>position</em> is omitted, URIs are appended to the back of
the list. This method first execute removal and then
addition. <em>position</em> is the position after URIs are removed, not the
position when this method is called. When removing URI, if same URIs
exist in download, only one of them is removed for each URI in
<em>delUris</em>. In other words, there are three URIs
"http://example.org/aria2" and you want remove them all, you have to
specify (at least) 3 "http://example.org/aria2" in <em>delUris</em>. This
method returns a list which contains 2 integers. The first integer is
the number of URIs deleted. The second integer is the number of URIs
added.</p></div>
<div class="paragraph"><p><strong>aria2.getOption</strong> <em>gid</em></p></div>
<div class="paragraph"><p>This method returns options of the download denoted by <em>gid</em>. The
response is of type struct. Its key is the name of option. The value type
@ -3722,7 +3740,7 @@ files in the program, then also delete it here.</p></div>
<div id="footnotes"><hr /></div>
<div id="footer">
<div id="footer-text">
Last updated 2010-02-23 23:01:01 JST
Last updated 2010-03-06 23:18:27 JST
</div>
</div>
</body>

View File

@ -1465,6 +1465,26 @@ For example, if GID#1 is placed in position 3, aria2.changePosition(1,
aria2.changePosition(1, 0, POS_SET) will change its position to 0(the
beginning of the queue).
*aria2.changeUri* 'gid, fileIndex, delUris, addUris[, position]'
This method removes URIs in 'delUris' from and appends URIs in
'addUris' to download denoted by 'gid'. 'delUris' and 'addUris' are
list of string. A download can contain multiple files and URIs are
attached to each file. 'fileIndex' is used to select which file to
remove/attach given URIs. 'position' is used to specify where URIs
are inserted in the existing waiting URI list. 'position' is
0-based. When 'position' is omitted, URIs are appended to the back of
the list. This method first execute removal and then
addition. 'position' is the position after URIs are removed, not the
position when this method is called. When removing URI, if same URIs
exist in download, only one of them is removed for each URI in
'delUris'. In other words, there are three URIs
"http://example.org/aria2" and you want remove them all, you have to
specify (at least) 3 "http://example.org/aria2" in 'delUris'. This
method returns a list which contains 2 integers. The first integer is
the number of URIs deleted. The second integer is the number of URIs
added.
*aria2.getOption* 'gid'
This method returns options of the download denoted by 'gid'. The

View File

@ -107,6 +107,14 @@ bool AbstractCommand::execute() {
//logger->debug("CUID#%d - finished.", cuid);
return true;
}
if(!req.isNull() && req->removalRequested()) {
if(logger->debug()) {
logger->debug
("CUID#%d - Discard original URI=%s because it is requested.",
cuid, req->getUrl().c_str());
}
return prepareForRetry(0);
}
// TODO it is not needed to check other PeerStats every time.
// Find faster Request when no segment is available.
if(!req.isNull() && _fileEntry->countPooledRequest() > 0 &&

View File

@ -39,6 +39,7 @@
#include "FileEntry.h"
#include "StringFormat.h"
#include "util.h"
#include "wallclock.h"
namespace aria2 {
@ -58,7 +59,7 @@ DownloadContext::DownloadContext(size_t pieceLength,
_knowsTotalLength(true),
_ownerRequestGroup(0),
_downloadStartTime(0),
_downloadStopTime(_downloadStartTime)
_downloadStopTime(0)
{
SharedHandle<FileEntry> fileEntry
(new FileEntry(util::escapePath(path), totalLength, 0));
@ -67,12 +68,12 @@ DownloadContext::DownloadContext(size_t pieceLength,
void DownloadContext::resetDownloadStartTime()
{
_downloadStartTime.reset();
_downloadStartTime = global::wallclock;
}
void DownloadContext::resetDownloadStopTime()
{
_downloadStopTime.reset();
_downloadStopTime = global::wallclock;
}
int64_t DownloadContext::calculateSessionTime() const

View File

@ -233,6 +233,11 @@ public:
void resetDownloadStopTime();
const Time& getDownloadStopTime() const
{
return _downloadStopTime;
}
int64_t calculateSessionTime() const;
// Returns FileEntry at given offset. SharedHandle<FileEntry>() is

View File

@ -218,7 +218,9 @@ void FileEntry::storePool(const SharedHandle<Request>& request)
void FileEntry::poolRequest(const SharedHandle<Request>& request)
{
removeRequest(request);
storePool(request);
if(!request->removalRequested()) {
storePool(request);
}
}
bool FileEntry::removeRequest(const SharedHandle<Request>& request)
@ -330,4 +332,49 @@ void FileEntry::releaseRuntimeResource()
_uriResults.clear();
}
template<typename InputIterator, typename T>
static InputIterator findRequestByUri
(InputIterator first, InputIterator last, const T& uri)
{
for(; first != last; ++first) {
if(!(*first)->removalRequested() && (*first)->getUrl() == uri) {
return first;
}
}
return last;
}
bool FileEntry::removeUri(const std::string& uri)
{
std::deque<std::string>::iterator itr =
std::find(_spentUris.begin(), _spentUris.end(), uri);
if(itr == _spentUris.end()) {
itr = std::find(_uris.begin(), _uris.end(), uri);
if(itr == _uris.end()) {
return false;
} else {
_uris.erase(itr);
return true;
}
} else {
_spentUris.erase(itr);
SharedHandle<Request> req;
std::deque<SharedHandle<Request> >::iterator riter =
findRequestByUri(_inFlightRequests.begin(), _inFlightRequests.end(), uri);
if(riter == _inFlightRequests.end()) {
riter = findRequestByUri(_requestPool.begin(), _requestPool.end(), uri);
if(riter == _requestPool.end()) {
return true;
} else {
req = *riter;
_requestPool.erase(riter);
}
} else {
req = *riter;
}
req->requestRemoval();
return true;
}
}
} // namespace aria2

View File

@ -129,15 +129,43 @@ public:
return _spentUris;
}
void setUris(const std::vector<std::string>& uris)
size_t setUris(const std::vector<std::string>& uris)
{
_uris = std::deque<std::string>(uris.begin(), uris.end());
_uris.clear();
return addUris(uris.begin(), uris.end());
}
template<typename InputIterator>
void addUris(InputIterator first, InputIterator last)
size_t addUris(InputIterator first, InputIterator last)
{
_uris.insert(_uris.end(), first, last);
size_t count = 0;
for(; first != last; ++first) {
if(addUri(*first)) {
++count;
}
}
return count;
}
bool addUri(const std::string& uri)
{
if(Request().setUrl(uri)) {
_uris.push_back(uri);
return true;
} else {
return false;
}
}
bool insertUri(const std::string& uri, size_t pos)
{
if(Request().setUrl(uri)) {
pos = std::min(pos, _uris.size());
_uris.insert(_uris.begin()+pos, uri);
return true;
} else {
return false;
}
}
// Inserts _uris and _spentUris into uris.
@ -234,6 +262,8 @@ public:
{
return _originalName;
}
bool removeUri(const std::string& uri);
};
// Returns the first FileEntry which isRequested() method returns

View File

@ -63,7 +63,8 @@ Request::Request():
_maxPipelinedRequest(1),
_method(METHOD_GET),
_hasPassword(false),
_ipv6LiteralAddress(false)
_ipv6LiteralAddress(false),
_removalRequested(false)
{}
static std::string removeFragment(const std::string& url)

View File

@ -88,6 +88,8 @@ private:
SharedHandle<PeerStat> _peerStat;
bool _removalRequested;
bool parseUrl(const std::string& url);
public:
Request();
@ -204,6 +206,16 @@ public:
const SharedHandle<PeerStat>& initPeerStat();
void requestRemoval()
{
_removalRequested = true;
}
bool removalRequested() const
{
return _removalRequested;
}
static const std::string METHOD_GET;
static const std::string METHOD_HEAD;

View File

@ -991,6 +991,9 @@ bool RequestGroup::needsFileAllocation() const
DownloadResultHandle RequestGroup::createDownloadResult() const
{
if(_logger->debug()) {
_logger->debug("GID#%d - Creating DownloadResult.", _gid);
}
uint64_t sessionDownloadLength = 0;
#ifdef ENABLE_BITTORRENT

View File

@ -336,6 +336,16 @@ public:
void operator()(const SharedHandle<RequestGroup>& group)
{
if(group->getNumCommand() == 0) {
SharedHandle<DownloadContext> dctx = group->getDownloadContext();
// DownloadContext::resetDownloadStopTime() is only called when
// download completed. If
// DownloadContext::getDownloadStopTime().isZero() is true, then
// there is a possibility that the download is error or
// in-progress and resetDownloadStopTime() is not called. So
// call it here.
if(dctx->getDownloadStopTime().isZero()) {
dctx->resetDownloadStopTime();
}
try {
group->closeFile();
if(group->downloadFinished()) {

View File

@ -79,6 +79,8 @@ XmlRpcMethodFactory::create(const std::string& methodName)
return SharedHandle<XmlRpcMethod>(new TellStoppedXmlRpcMethod());
} else if(methodName == GetOptionXmlRpcMethod::getMethodName()) {
return SharedHandle<XmlRpcMethod>(new GetOptionXmlRpcMethod());
} else if(methodName == ChangeUriXmlRpcMethod::getMethodName()) {
return SharedHandle<XmlRpcMethod>(new ChangeUriXmlRpcMethod());
} else if(methodName == ChangeOptionXmlRpcMethod::getMethodName()) {
return SharedHandle<XmlRpcMethod>(new ChangeOptionXmlRpcMethod());
} else if(methodName == GetGlobalOptionXmlRpcMethod::getMethodName()) {

View File

@ -851,6 +851,67 @@ BDE GetSessionInfoXmlRpcMethod::process
return result;
}
BDE ChangeUriXmlRpcMethod::process
(const XmlRpcRequest& req, DownloadEngine* e)
{
const BDE& params = req._params;
assert(params.isList());
if(params.size() < 4 ||
!params[0].isString() || !params[1].isInteger() ||
!params[2].isList() || !params[3].isList() ||
params[1].i() < 0) {
throw DL_ABORT_EX("Bad request");
}
size_t pos = 0;
bool posGiven = false;
getPosParam(params, 4, posGiven, pos);
int32_t gid = util::parseInt(params[0].s());
size_t index = params[1].i();
const BDE& deluris = params[2];
const BDE& adduris = params[3];
SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
if(group.isNull()) {
throw DL_ABORT_EX
(StringFormat("Cannot remove URIs from GID#%d", gid).str());
}
SharedHandle<DownloadContext> dctx = group->getDownloadContext();
const std::vector<SharedHandle<FileEntry> >& files = dctx->getFileEntries();
if(files.size() <= index) {
throw DL_ABORT_EX(StringFormat("fileIndex is out of range").str());
}
SharedHandle<FileEntry> s = files[index];
size_t delcount = 0;
for(BDE::List::const_iterator i = deluris.listBegin(),
eoi = deluris.listEnd(); i != eoi; ++i) {
if(s->removeUri((*i).s())) {
++delcount;
}
}
size_t addcount = 0;
if(posGiven) {
for(BDE::List::const_iterator i = adduris.listBegin(),
eoi = adduris.listEnd(); i != eoi; ++i) {
if(s->insertUri((*i).s(), pos)) {
++addcount;
++pos;
}
}
} else {
for(BDE::List::const_iterator i = adduris.listBegin(),
eoi = adduris.listEnd(); i != eoi; ++i) {
if(s->addUri((*i).s())) {
++addcount;
}
}
}
BDE res = BDE::list();
res << delcount;
res << addcount;
return res;
}
BDE SystemMulticallXmlRpcMethod::process
(const XmlRpcRequest& req, DownloadEngine* e)
{

View File

@ -341,6 +341,17 @@ public:
}
};
class ChangeUriXmlRpcMethod:public XmlRpcMethod {
protected:
virtual BDE process(const XmlRpcRequest& req, DownloadEngine* e);
public:
static const std::string& getMethodName()
{
static std::string methodName = "aria2.changeUri";
return methodName;
}
};
class GetSessionInfoXmlRpcMethod:public XmlRpcMethod {
protected:
virtual BDE process(const XmlRpcRequest& req, DownloadEngine* e);

View File

@ -15,6 +15,10 @@ class FileEntryTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testGetRequest);
CPPUNIT_TEST(testGetRequest_disableSingleHostMultiConnection);
CPPUNIT_TEST(testReuseUri);
CPPUNIT_TEST(testAddUri);
CPPUNIT_TEST(testAddUris);
CPPUNIT_TEST(testInsertUri);
CPPUNIT_TEST(testRemoveUri);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() {}
@ -25,6 +29,10 @@ public:
void testGetRequest();
void testGetRequest_disableSingleHostMultiConnection();
void testReuseUri();
void testAddUri();
void testAddUris();
void testInsertUri();
void testRemoveUri();
};
@ -149,4 +157,63 @@ void FileEntryTest::testReuseUri()
CPPUNIT_ASSERT_EQUAL(std::string("ftp://localhost/aria2.zip"), uris[2]);
}
void FileEntryTest::testAddUri()
{
FileEntry file;
CPPUNIT_ASSERT(file.addUri("http://good"));
CPPUNIT_ASSERT(!file.addUri("bad"));
}
void FileEntryTest::testAddUris()
{
FileEntry file;
std::string uris[] = {"bad", "http://good"};
CPPUNIT_ASSERT_EQUAL((size_t)1, file.addUris(&uris[0], &uris[2]));
}
void FileEntryTest::testInsertUri()
{
FileEntry file;
CPPUNIT_ASSERT(file.insertUri("http://example.org/1", 0));
CPPUNIT_ASSERT(file.insertUri("http://example.org/2", 0));
CPPUNIT_ASSERT(file.insertUri("http://example.org/3", 1));
CPPUNIT_ASSERT(file.insertUri("http://example.org/4", 5));
std::deque<std::string> uris = file.getRemainingUris();
CPPUNIT_ASSERT_EQUAL(std::string("http://example.org/2"), uris[0]);
CPPUNIT_ASSERT_EQUAL(std::string("http://example.org/3"), uris[1]);
CPPUNIT_ASSERT_EQUAL(std::string("http://example.org/1"), uris[2]);
CPPUNIT_ASSERT_EQUAL(std::string("http://example.org/4"), uris[3]);
}
void FileEntryTest::testRemoveUri()
{
SharedHandle<InOrderURISelector> selector(new InOrderURISelector());
FileEntry file;
file.addUri("http://example.org/");
CPPUNIT_ASSERT(file.removeUri("http://example.org/"));
CPPUNIT_ASSERT(file.getRemainingUris().empty());
CPPUNIT_ASSERT(!file.removeUri("http://example.org/"));
file.addUri("http://example.org/");
SharedHandle<Request> exampleOrgReq = file.getRequest(selector);
CPPUNIT_ASSERT(!exampleOrgReq->removalRequested());
CPPUNIT_ASSERT_EQUAL((size_t)1, file.getSpentUris().size());
CPPUNIT_ASSERT(file.removeUri("http://example.org/"));
CPPUNIT_ASSERT(file.getSpentUris().empty());
CPPUNIT_ASSERT(exampleOrgReq->removalRequested());
file.poolRequest(exampleOrgReq);
CPPUNIT_ASSERT_EQUAL((size_t)0, file.countPooledRequest());
file.addUri("http://example.org/");
exampleOrgReq = file.getRequest(selector);
file.poolRequest(exampleOrgReq);
CPPUNIT_ASSERT_EQUAL((size_t)1, file.countPooledRequest());
CPPUNIT_ASSERT(file.removeUri("http://example.org/"));
CPPUNIT_ASSERT_EQUAL((size_t)0, file.countPooledRequest());
CPPUNIT_ASSERT(file.getSpentUris().empty());
file.addUri("http://example.org/");
CPPUNIT_ASSERT(!file.removeUri("http://example.net"));
}
} // namespace aria2

View File

@ -75,6 +75,8 @@ class XmlRpcMethodTest:public CppUnit::TestFixture {
CPPUNIT_TEST(testChangePosition);
CPPUNIT_TEST(testChangePosition_fail);
CPPUNIT_TEST(testGetSessionInfo);
CPPUNIT_TEST(testChangeUri);
CPPUNIT_TEST(testChangeUri_fail);
CPPUNIT_TEST(testSystemMulticall);
CPPUNIT_TEST(testSystemMulticall_fail);
CPPUNIT_TEST_SUITE_END();
@ -135,6 +137,8 @@ public:
void testChangePosition();
void testChangePosition_fail();
void testGetSessionInfo();
void testChangeUri();
void testChangeUri_fail();
void testSystemMulticall();
void testSystemMulticall_fail();
};
@ -779,6 +783,131 @@ void XmlRpcMethodTest::testChangePosition_fail()
CPPUNIT_ASSERT_EQUAL(1, res._code);
}
void XmlRpcMethodTest::testChangeUri()
{
SharedHandle<FileEntry> files[3];
for(int i = 0; i < 3; ++i) {
files[i].reset(new FileEntry());
}
files[1]->addUri("http://example.org/aria2.tar.bz2");
files[1]->addUri("http://example.org/mustremove1");
files[1]->addUri("http://example.org/mustremove2");
SharedHandle<DownloadContext> dctx(new DownloadContext());
dctx->setFileEntries(&files[0], &files[3]);
SharedHandle<RequestGroup> group(new RequestGroup(_option));
group->setDownloadContext(dctx);
_e->_requestGroupMan->addReservedGroup(group);
ChangeUriXmlRpcMethod m;
XmlRpcRequest req(ChangeUriXmlRpcMethod::getMethodName(), BDE::list());
req._params << std::string("1"); // GID
req._params << 1; // index of FileEntry
BDE removeuris = BDE::list();
removeuris << std::string("http://example.org/mustremove1");
removeuris << std::string("http://example.org/mustremove2");
removeuris << std::string("http://example.org/notexist");
req._params << removeuris;
BDE adduris = BDE::list();
adduris << std::string("http://example.org/added1");
adduris << std::string("http://example.org/added2");
adduris << std::string("baduri");
adduris << std::string("http://example.org/added3");
req._params << adduris;
XmlRpcResponse res = m.execute(req, _e.get());
CPPUNIT_ASSERT_EQUAL(0, res._code);
CPPUNIT_ASSERT_EQUAL((int64_t)2, res._param[0].i());
CPPUNIT_ASSERT_EQUAL((int64_t)3, res._param[1].i());
CPPUNIT_ASSERT_EQUAL((size_t)0, files[0]->getRemainingUris().size());
CPPUNIT_ASSERT_EQUAL((size_t)0, files[2]->getRemainingUris().size());
std::deque<std::string> uris = files[1]->getRemainingUris();
CPPUNIT_ASSERT_EQUAL((size_t)4, uris.size());
CPPUNIT_ASSERT_EQUAL(std::string("http://example.org/aria2.tar.bz2"),uris[0]);
CPPUNIT_ASSERT_EQUAL(std::string("http://example.org/added1"), uris[1]);
CPPUNIT_ASSERT_EQUAL(std::string("http://example.org/added2"), uris[2]);
CPPUNIT_ASSERT_EQUAL(std::string("http://example.org/added3"), uris[3]);
// Change adduris
adduris = BDE::list();
adduris << std::string("http://example.org/added1-1");
adduris << std::string("http://example.org/added1-2");
req._params[3] = adduris;
// Set position parameter
req._params << 2;
res = m.execute(req, _e.get());
CPPUNIT_ASSERT_EQUAL(0, res._code);
CPPUNIT_ASSERT_EQUAL((int64_t)0, res._param[0].i());
CPPUNIT_ASSERT_EQUAL((int64_t)2, res._param[1].i());
uris = files[1]->getRemainingUris();
CPPUNIT_ASSERT_EQUAL((size_t)6, uris.size());
CPPUNIT_ASSERT_EQUAL(std::string("http://example.org/added1-1"), uris[2]);
CPPUNIT_ASSERT_EQUAL(std::string("http://example.org/added1-2"), uris[3]);
// Change index of FileEntry
req._params[1] = 0;
// Set position far beyond the size of uris in FileEntry.
req._params[4] = 1000;
res = m.execute(req, _e.get());
CPPUNIT_ASSERT_EQUAL(0, res._code);
CPPUNIT_ASSERT_EQUAL((int64_t)0, res._param[0].i());
CPPUNIT_ASSERT_EQUAL((int64_t)2, res._param[1].i());
uris = files[0]->getRemainingUris();
CPPUNIT_ASSERT_EQUAL((size_t)2, uris.size());
CPPUNIT_ASSERT_EQUAL(std::string("http://example.org/added1-1"), uris[0]);
CPPUNIT_ASSERT_EQUAL(std::string("http://example.org/added1-2"), uris[1]);
}
void XmlRpcMethodTest::testChangeUri_fail()
{
SharedHandle<FileEntry> files[3];
for(int i = 0; i < 3; ++i) {
files[i].reset(new FileEntry());
}
SharedHandle<DownloadContext> dctx(new DownloadContext());
dctx->setFileEntries(&files[0], &files[3]);
SharedHandle<RequestGroup> group(new RequestGroup(_option));
group->setDownloadContext(dctx);
_e->_requestGroupMan->addReservedGroup(group);
ChangeUriXmlRpcMethod m;
XmlRpcRequest req(ChangeUriXmlRpcMethod::getMethodName(), BDE::list());
req._params << std::string("1"); // GID
req._params << 0; // index of FileEntry
BDE removeuris = BDE::list();
req._params << removeuris;
BDE adduris = BDE::list();
req._params << adduris;
XmlRpcResponse res = m.execute(req, _e.get());
CPPUNIT_ASSERT_EQUAL(0, res._code);
req._params[0] = std::string("2");
res = m.execute(req, _e.get());
// RPC request fails because GID#2 does not exist.
CPPUNIT_ASSERT_EQUAL(1, res._code);
req._params[0] = std::string("1");
req._params[1] = 3;
res = m.execute(req, _e.get());
// RPC request fails because FileEntry#3 does not exist.
CPPUNIT_ASSERT_EQUAL(1, res._code);
req._params[1] = std::string("0");
res = m.execute(req, _e.get());
// RPC request fails because index of FileEntry is string.
CPPUNIT_ASSERT_EQUAL(1, res._code);
req._params[1] = 0;
req._params[2] = std::string("http://url");
res = m.execute(req, _e.get());
// RPC request fails because 3rd param is not list.
CPPUNIT_ASSERT_EQUAL(1, res._code);
req._params[2] = BDE::list();
req._params[3] = std::string("http://url");
res = m.execute(req, _e.get());
// RPC request fails because 4th param is not list.
CPPUNIT_ASSERT_EQUAL(1, res._code);
}
void XmlRpcMethodTest::testGetSessionInfo()
{
GetSessionInfoXmlRpcMethod m;