python-pycurl/0000-pycurl-7.19.7-9b8f4e38.patch
2013-04-09 15:48:57 +02:00

9417 lines
282 KiB
Diff

From 15a1c96494611dafd6444655bce0b13c64a6172f Mon Sep 17 00:00:00 2001
From: Kjetil Jacobsen <kjetilja@gmail.com>
Date: Tue, 9 Sep 2008 18:49:59 +0000
Subject: [PATCH 001/112] whitespace
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
ChangeLog | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 0fb7f8c..3d68424 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,7 @@
Version 7.19.0 [requires libcurl-7.19.0 or better]
--------------
- * Added CURLFILE, ADDRESS_SCOPE and ISSUERCERT options,
+ * Added CURLFILE, ADDRESS_SCOPE and ISSUERCERT options,
as well as the APPCONNECT_TIME info.
* Added PRIMARY_IP info (patch by
--
1.7.1
From f79d0ea41bad7ea25cf949ca5398ed61b87de722 Mon Sep 17 00:00:00 2001
From: Kjetil Jacobsen <kjetilja@gmail.com>
Date: Mon, 29 Sep 2008 10:56:57 +0000
Subject: [PATCH 002/112] No longer keep copies of string options since this is managed by libcurl
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
ChangeLog | 10 +++++++++-
src/pycurl.c | 58 +---------------------------------------------------------
2 files changed, 10 insertions(+), 58 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 3d68424..618654d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,12 @@
-Version 7.19.0 [requires libcurl-7.19.0 or better]
+Version 7.19.1 [requires libcurl-7.19.0 or better]
+--------------
+
+ * No longer keep string options copies in the
+ Curl Python objects, since string options are
+ now managed by libcurl.
+
+
+Version 7.19.0
--------------
* Added CURLFILE, ADDRESS_SCOPE and ISSUERCERT options,
diff --git a/src/pycurl.c b/src/pycurl.c
index 50ec9ce..189f5d6 100644
--- a/src/pycurl.c
+++ b/src/pycurl.c
@@ -97,12 +97,6 @@ static void pycurl_ssl_cleanup(void);
/* Calculate the number of OBJECTPOINT options we need to store */
#define OPTIONS_SIZE ((int)CURLOPT_LASTENTRY % 10000)
#define MOPTIONS_SIZE ((int)CURLMOPT_LASTENTRY % 10000)
-static int OPT_INDEX(int o)
-{
- assert(o >= CURLOPTTYPE_OBJECTPOINT);
- assert(o < CURLOPTTYPE_OBJECTPOINT + OPTIONS_SIZE);
- return o - CURLOPTTYPE_OBJECTPOINT;
-}
/* Type objects */
static PyObject *ErrorObject = NULL;
@@ -161,7 +155,6 @@ typedef struct {
PyObject *writedata_fp;
PyObject *writeheader_fp;
/* misc */
- void *options[OPTIONS_SIZE]; /* for OBJECTPOINT options */
char error[CURL_ERROR_SIZE+1];
} CurlObject;
@@ -741,7 +734,6 @@ util_curl_new(void)
self->writeheader_fp = NULL;
/* Zero string pointer memory buffer used by setopt */
- memset(self->options, 0, sizeof(self->options));
memset(self->error, 0, sizeof(self->error));
return self;
@@ -804,7 +796,6 @@ do_curl_new(PyObject *dummy)
free(s);
goto error;
}
- self->options[ OPT_INDEX(CURLOPT_USERAGENT) ] = s; s = NULL;
/* Success - return new object */
return self;
@@ -872,7 +863,6 @@ static void
util_curl_close(CurlObject *self)
{
CURL *handle;
- int i;
/* Zero handle and thread-state to disallow any operations to be run
* from now on */
@@ -916,16 +906,6 @@ util_curl_close(CurlObject *self)
SFREE(self->postquote);
SFREE(self->prequote);
#undef SFREE
-
- /* Last, free the options. This must be done after the curl handle
- * is closed since libcurl assumes that some options are valid when
- * invoking curl_easy_cleanup(). */
- for (i = 0; i < OPTIONS_SIZE; i++) {
- if (self->options[i] != NULL) {
- free(self->options[i]);
- self->options[i] = NULL;
- }
- }
}
@@ -1424,8 +1404,6 @@ verbose_error:
static PyObject*
do_curl_reset(CurlObject *self)
{
- unsigned int i;
-
curl_easy_reset(self->handle);
/* Decref callbacks and file handles */
@@ -1443,15 +1421,6 @@ do_curl_reset(CurlObject *self)
SFREE(self->postquote);
SFREE(self->prequote);
#undef SFREE
-
- /* Last, free the options */
- for (i = 0; i < OPTIONS_SIZE; i++) {
- if (self->options[i] != NULL) {
- free(self->options[i]);
- self->options[i] = NULL;
- }
- }
-
return Py_None;
}
@@ -1461,7 +1430,6 @@ static PyObject *
util_curl_unsetopt(CurlObject *self, int option)
{
int res;
- int opt_index = -1;
#define SETOPT2(o,x) \
if ((res = curl_easy_setopt(self->handle, (o), (x))) != CURLE_OK) goto error
@@ -1502,7 +1470,6 @@ util_curl_unsetopt(CurlObject *self, int option)
case CURLOPT_SSL_CIPHER_LIST:
case CURLOPT_USERPWD:
SETOPT((char *) 0);
- opt_index = OPT_INDEX(option);
break;
/* info: we explicitly list unsupported options here */
@@ -1512,11 +1479,6 @@ util_curl_unsetopt(CurlObject *self, int option)
return NULL;
}
- if (opt_index >= 0 && self->options[opt_index] != NULL) {
- free(self->options[opt_index]);
- self->options[opt_index] = NULL;
- }
-
Py_INCREF(Py_None);
return Py_None;
@@ -1587,8 +1549,6 @@ do_curl_setopt(CurlObject *self, PyObject *args)
if (PyString_Check(obj)) {
char *str = NULL;
Py_ssize_t len = -1;
- char *buf;
- int opt_index;
/* Check that the option specified a string as well as the input */
switch (option) {
@@ -1651,28 +1611,12 @@ do_curl_setopt(CurlObject *self, PyObject *args)
}
/* Allocate memory to hold the string */
assert(str != NULL);
- if (len <= 0)
- buf = strdup(str);
- else {
- buf = (char *) malloc(len);
- if (buf) memcpy(buf, str, len);
- }
- if (buf == NULL)
- return PyErr_NoMemory();
/* Call setopt */
- res = curl_easy_setopt(self->handle, (CURLoption)option, buf);
+ res = curl_easy_setopt(self->handle, (CURLoption)option, str);
/* Check for errors */
if (res != CURLE_OK) {
- free(buf);
CURLERROR_RETVAL();
}
- /* Save allocated option buffer */
- opt_index = OPT_INDEX(option);
- if (self->options[opt_index] != NULL) {
- free(self->options[opt_index]);
- self->options[opt_index] = NULL;
- }
- self->options[opt_index] = buf;
Py_INCREF(Py_None);
return Py_None;
}
--
1.7.1
From 5267a6278f4b3993811a5eacf068942e01416d29 Mon Sep 17 00:00:00 2001
From: Christopher Warner <cwarner@kernelcode.com>
Date: Fri, 23 Apr 2010 16:06:41 +0000
Subject: [PATCH 003/112] Fixes https://sourceforge.net/tracker/?func=detail&aid=2812016&group_id=28236&atid=392777 with applied patch from sourceforge user dbprice1.
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
setup.py | 21 +++++++++++++++++----
1 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/setup.py b/setup.py
index 1c3831b..632399d 100644
--- a/setup.py
+++ b/setup.py
@@ -9,7 +9,7 @@ PACKAGE = "pycurl"
PY_PACKAGE = "curl"
VERSION = "7.19.0"
-import glob, os, re, sys, string
+import glob, os, re, sys, string, subprocess
import distutils
from distutils.core import setup
from distutils.extension import Extension
@@ -96,9 +96,22 @@ else:
include_dirs.append(e[2:])
else:
extra_compile_args.append(e)
- libs = split_quoted(
- os.popen("'%s' --libs" % CURL_CONFIG).read()+\
- os.popen("'%s' --static-libs" % CURL_CONFIG).read())
+
+ # Run curl-config --libs and --static-libs. Some platforms may not
+ # support one or the other of these curl-config options, so gracefully
+ # tolerate failure of either, but not both.
+ optbuf = ""
+ for option in ["--libs", "--static-libs"]:
+ p = subprocess.Popen("'%s' %s" % (CURL_CONFIG, option), shell=True,
+ stdout=subprocess.PIPE)
+ (stdout, stderr) = p.communicate()
+ if p.wait() == 0:
+ optbuf += stdout
+ if optbuf == "":
+ raise Exception, ("Neither of curl-config --libs or --static-libs" +
+ "produced output")
+ libs = split_quoted(optbuf)
+
for e in libs:
if e[:2] == "-l":
libraries.append(e[2:])
--
1.7.1
From efeb6581db4c6fd8980bb4007d14afce96ce4642 Mon Sep 17 00:00:00 2001
From: Christopher Warner <cwarner@kernelcode.com>
Date: Wed, 28 Apr 2010 16:02:41 +0000
Subject: [PATCH 004/112] Fixes refcount bug and provides better organization of PyCurl object. Submitted by dbprice1.
https://sourceforge.net/tracker/?func=detail&aid=2893665&group_id=28236&atid=392777
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
src/pycurl.c | 87 ++++++++++++++++++++++++++++++++++++++--------------------
1 files changed, 57 insertions(+), 30 deletions(-)
diff --git a/src/pycurl.c b/src/pycurl.c
index 189f5d6..47de850 100644
--- a/src/pycurl.c
+++ b/src/pycurl.c
@@ -739,64 +739,80 @@ util_curl_new(void)
return self;
}
-
-/* constructor - this is a module-level function returning a new instance */
-static CurlObject *
-do_curl_new(PyObject *dummy)
+/* initializer - used to intialize curl easy handles for use with pycurl */
+static int
+util_curl_init(CurlObject *self)
{
- CurlObject *self = NULL;
int res;
char *s = NULL;
- UNUSED(dummy);
-
- /* Allocate python curl object */
- self = util_curl_new();
- if (self == NULL)
- return NULL;
-
- /* Initialize curl handle */
- self->handle = curl_easy_init();
- if (self->handle == NULL)
- goto error;
-
/* Set curl error buffer and zero it */
res = curl_easy_setopt(self->handle, CURLOPT_ERRORBUFFER, self->error);
- if (res != CURLE_OK)
- goto error;
+ if (res != CURLE_OK) {
+ return (-1);
+ }
memset(self->error, 0, sizeof(self->error));
/* Set backreference */
res = curl_easy_setopt(self->handle, CURLOPT_PRIVATE, (char *) self);
- if (res != CURLE_OK)
- goto error;
+ if (res != CURLE_OK) {
+ return (-1);
+ }
/* Enable NOPROGRESS by default, i.e. no progress output */
res = curl_easy_setopt(self->handle, CURLOPT_NOPROGRESS, (long)1);
- if (res != CURLE_OK)
- goto error;
+ if (res != CURLE_OK) {
+ return (-1);
+ }
/* Disable VERBOSE by default, i.e. no verbose output */
res = curl_easy_setopt(self->handle, CURLOPT_VERBOSE, (long)0);
- if (res != CURLE_OK)
- goto error;
+ if (res != CURLE_OK) {
+ return (-1);
+ }
/* Set FTP_ACCOUNT to NULL by default */
res = curl_easy_setopt(self->handle, CURLOPT_FTP_ACCOUNT, NULL);
- if (res != CURLE_OK)
- goto error;
+ if (res != CURLE_OK) {
+ return (-1);
+ }
/* Set default USERAGENT */
s = (char *) malloc(7 + strlen(LIBCURL_VERSION) + 1);
- if (s == NULL)
- goto error;
+ if (s == NULL) {
+ return (-1);
+ }
strcpy(s, "PycURL/"); strcpy(s+7, LIBCURL_VERSION);
res = curl_easy_setopt(self->handle, CURLOPT_USERAGENT, (char *) s);
if (res != CURLE_OK) {
free(s);
- goto error;
+ return (-1);
}
+ return (0);
+}
+
+/* constructor - this is a module-level function returning a new instance */
+static CurlObject *
+do_curl_new(PyObject *dummy)
+{
+ CurlObject *self = NULL;
+ int res;
+
+ UNUSED(dummy);
+
+ /* Allocate python curl object */
+ self = util_curl_new();
+ if (self == NULL)
+ return NULL;
+
+ /* Initialize curl handle */
+ self->handle = curl_easy_init();
+ if (self->handle == NULL)
+ goto error;
+ res = util_curl_init(self);
+ if (res < 0)
+ goto error;
/* Success - return new object */
return self;
@@ -1404,6 +1420,8 @@ verbose_error:
static PyObject*
do_curl_reset(CurlObject *self)
{
+ int res;
+
curl_easy_reset(self->handle);
/* Decref callbacks and file handles */
@@ -1421,10 +1439,19 @@ do_curl_reset(CurlObject *self)
SFREE(self->postquote);
SFREE(self->prequote);
#undef SFREE
+ res = util_curl_init(self);
+ if (res < 0) {
+ Py_DECREF(self); /* this also closes self->handle */
+ PyErr_SetString(ErrorObject, "resetting curl failed");
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
return Py_None;
}
/* --------------- unsetopt/setopt/getinfo --------------- */
+ int res;
static PyObject *
util_curl_unsetopt(CurlObject *self, int option)
--
1.7.1
From 6c8f676e53cf3a54836134ddc11d7a707793414d Mon Sep 17 00:00:00 2001
From: Christopher Warner <cwarner@kernelcode.com>
Date: Wed, 28 Apr 2010 16:03:40 +0000
Subject: [PATCH 005/112] Test for reset fixes refcount bug
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/test_reset.py | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 75 insertions(+), 0 deletions(-)
create mode 100644 tests/test_reset.py
diff --git a/tests/test_reset.py b/tests/test_reset.py
new file mode 100644
index 0000000..1addcfe
--- /dev/null
+++ b/tests/test_reset.py
@@ -0,0 +1,75 @@
+#!/usr/bin/python
+
+import sys
+import pycurl
+
+saw_error = 1
+
+def main():
+ global saw_error
+
+ pycurl.global_init(pycurl.GLOBAL_DEFAULT)
+
+ outf = file("/dev/null", "rb+")
+ cm = pycurl.CurlMulti()
+
+ # Set multi handle's options
+ cm.setopt(pycurl.M_PIPELINING, 1)
+
+ eh = pycurl.Curl()
+
+ for x in range(1, 20):
+
+ eh.setopt(pycurl.WRITEDATA, outf)
+ eh.setopt(pycurl.URL, sys.argv[1])
+ cm.add_handle(eh)
+
+ while 1:
+ ret, active_handles = cm.perform()
+ if ret != pycurl.E_CALL_MULTI_PERFORM:
+ break
+
+ while active_handles:
+ ret = cm.select(1.0)
+ if ret == -1:
+ continue
+ while 1:
+ ret, active_handles = cm.perform()
+ if ret != pycurl.E_CALL_MULTI_PERFORM:
+ break
+
+ count, good, bad = cm.info_read()
+
+ for h, en, em in bad:
+ print "Transfer to %s failed with %d, %s\n" % \
+ (h.getinfo(pycurl.EFFECTIVE_URL), en, em)
+ raise RuntimeError
+
+ for h in good:
+ httpcode = h.getinfo(pycurl.RESPONSE_CODE)
+ if httpcode != 200:
+ print "Transfer to %s failed with code %d\n" %\
+ (h.getinfo(pycurl.EFFECTIVE_URL), httpcode)
+ raise RuntimeError
+
+ else:
+ print "Recd %d bytes from %s" % \
+ (h.getinfo(pycurl.SIZE_DOWNLOAD),
+ h.getinfo(pycurl.EFFECTIVE_URL))
+
+ cm.remove_handle(eh)
+ eh.reset()
+
+ eh.close()
+ cm.close()
+ outf.close()
+
+ pycurl.global_cleanup()
+
+
+if __name__ == '__main__':
+ if len(sys.argv) != 2:
+ print "Usage: %s <url>" % sys.argv[0]
+ sys.exit(2)
+ main()
+
--
1.7.1
From 5c2023a7a9373d7ca816c2546fd2db63432bba0c Mon Sep 17 00:00:00 2001
From: Christopher Warner <cwarner@kernelcode.com>
Date: Wed, 28 Apr 2010 16:06:35 +0000
Subject: [PATCH 006/112] Added myself to the list of maintainers
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
setup.py | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/setup.py b/setup.py
index 632399d..33704ef 100644
--- a/setup.py
+++ b/setup.py
@@ -197,8 +197,8 @@ setup_args = get_kw(
description="PycURL -- cURL library module for Python",
author="Kjetil Jacobsen, Markus F.X.J. Oberhumer",
author_email="kjetilja at gmail.com, markus at oberhumer.com",
- maintainer="Kjetil Jacobsen, Markus F.X.J. Oberhumer",
- maintainer_email="kjetilja at gmail.com, markus at oberhumer.com",
+ maintainer="Kjetil Jacobsen, Markus F.X.J. Oberhumer, Christopher Warner",
+ maintainer_email="kjetilja at gmail.com, markus at oberhumer.com, cwarner at kernelcode.com",
url="http://pycurl.sourceforge.net/",
license="LGPL/MIT",
data_files=get_data_files(),
--
1.7.1
From 86777baedfac6c10ec0edd4e1e68519be83740e1 Mon Sep 17 00:00:00 2001
From: Christopher Warner <cwarner@kernelcode.com>
Date: Tue, 4 May 2010 18:47:08 +0000
Subject: [PATCH 007/112] Updating ChangeLog with relevant changes
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
ChangeLog | 11 +++++++++++
1 files changed, 11 insertions(+), 0 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 618654d..885c8b0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+Version 7.19.2
+--------------
+
+ * Cleaned up website
+
+ * Fix pycurl.reset() (patch by <johansen at sun.com>).
+
+ * Fix install routine in setup.py where
+ certain platforms (Solaris, Mac OSX, etc)
+ would search for a static copy of libcurl (dbp)
+
Version 7.19.1 [requires libcurl-7.19.0 or better]
--------------
--
1.7.1
From f42d34b86ce7c4d93bde71d7d1c56486bd98afa3 Mon Sep 17 00:00:00 2001
From: Christopher Warner <cwarner@kernelcode.com>
Date: Wed, 13 Oct 2010 15:53:40 +0000
Subject: [PATCH 008/112] Added CURLOPT_SEEKFUNCTION, CURLOPT_SEEKDATA
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
src/pycurl.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 88 insertions(+), 1 deletions(-)
diff --git a/src/pycurl.c b/src/pycurl.c
index 47de850..ac448b0 100644
--- a/src/pycurl.c
+++ b/src/pycurl.c
@@ -150,6 +150,7 @@ typedef struct {
PyObject *debug_cb;
PyObject *ioctl_cb;
PyObject *opensocket_cb;
+ PyObject *seek_cb;
/* file objects */
PyObject *readdata_fp;
PyObject *writedata_fp;
@@ -727,6 +728,7 @@ util_curl_new(void)
self->debug_cb = NULL;
self->ioctl_cb = NULL;
self->opensocket_cb = NULL;
+ self->seek_cb = NULL;
/* Set file object pointers to NULL by default */
self->readdata_fp = NULL;
@@ -1181,6 +1183,82 @@ verbose_error:
goto silent_error;
}
+static int
+seek_callback(void *stream, curl_off_t offset, int origin)
+{
+ CurlObject *self;
+ PyThreadState *tmp_state;
+ PyObject *arglist;
+ PyObject *result = NULL;
+ int ret = 2; /* assume error 2 (can't seek, libcurl free to work around). */
+ PyObject *cb;
+ int source = 0; /* assume beginning */
+
+ /* acquire thread */
+ self = (CurlObject *)stream;
+ tmp_state = get_thread_state(self);
+ if (tmp_state == NULL)
+ return ret;
+ PyEval_AcquireThread(tmp_state);
+
+ /* check arguments */
+ switch (origin)
+ {
+ case SEEK_SET:
+ source = 0;
+ break;
+ case SEEK_CUR:
+ source = 1;
+ break;
+ case SEEK_END:
+ source = 2;
+ break;
+ default:
+ source = origin;
+ break;
+ }
+
+ /* run callback */
+ cb = self->seek_cb;
+ if (cb == NULL)
+ goto silent_error;
+ arglist = Py_BuildValue("(i,i)", offset, source);
+ if (arglist == NULL)
+ goto verbose_error;
+ result = PyEval_CallObject(cb, arglist);
+ Py_DECREF(arglist);
+ if (result == NULL)
+ goto verbose_error;
+
+ /* handle result */
+ if (result == Py_None) {
+ ret = 0; /* None means success */
+ }
+ else if (PyInt_Check(result)) {
+ int ret_code = PyInt_AsLong(result);
+ if (ret_code < 0 || ret_code > 2) {
+ PyErr_Format(ErrorObject, "invalid return value for seek callback %d not in (0, 1, 2)", ret_code);
+ goto verbose_error;
+ }
+ ret = ret_code; /* pass the return code from the callback */
+ }
+ else {
+ PyErr_SetString(ErrorObject, "seek callback must return 0 (CURL_SEEKFUNC_OK), 1 (CURL_SEEKFUNC_FAIL), 2 (CURL_SEEKFUNC_CANTSEEK) or None");
+ goto verbose_error;
+ }
+
+silent_error:
+ Py_XDECREF(result);
+ PyEval_ReleaseThread(tmp_state);
+ return ret;
+verbose_error:
+ PyErr_Print();
+ goto silent_error;
+}
+
+
+
+
static size_t
read_callback(char *ptr, size_t size, size_t nmemb, void *stream)
{
@@ -1988,7 +2066,8 @@ do_curl_setopt(CurlObject *self, PyObject *args)
const curl_progress_callback pro_cb = progress_callback;
const curl_debug_callback debug_cb = debug_callback;
const curl_ioctl_callback ioctl_cb = ioctl_callback;
- const curl_opensocket_callback opensocket_cb = opensocket_callback;
+ const curl_opensocket_callback opensocket_cb = opensocket_callback;
+ const curl_seek_callback seek_cb = seek_callback;
switch(option) {
case CURLOPT_WRITEFUNCTION:
@@ -2046,6 +2125,13 @@ do_curl_setopt(CurlObject *self, PyObject *args)
curl_easy_setopt(self->handle, CURLOPT_OPENSOCKETFUNCTION, opensocket_cb);
curl_easy_setopt(self->handle, CURLOPT_OPENSOCKETDATA, self);
break;
+ case CURLOPT_SEEKFUNCTION:
+ Py_INCREF(obj);
+ ZAP(self->seek_cb);
+ self->seek_cb = obj;
+ curl_easy_setopt(self->handle, CURLOPT_SEEKFUNCTION, seek_cb);
+ curl_easy_setopt(self->handle, CURLOPT_SEEKDATA, self);
+ break;
default:
/* None of the function options were recognized, throw exception */
@@ -3616,6 +3702,7 @@ initpycurl(void)
insint_c(d, "PREQUOTE", CURLOPT_PREQUOTE);
insint_c(d, "WRITEHEADER", CURLOPT_WRITEHEADER);
insint_c(d, "HEADERFUNCTION", CURLOPT_HEADERFUNCTION);
+ insint_c(d, "SEEKFUNCTION", CURLOPT_SEEKFUNCTION);
insint_c(d, "COOKIEFILE", CURLOPT_COOKIEFILE);
insint_c(d, "SSLVERSION", CURLOPT_SSLVERSION);
insint_c(d, "TIMECONDITION", CURLOPT_TIMECONDITION);
--
1.7.1
From cd16f58fd7e2a089408ad0275bdcac6d6e5e1b7e Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@redhat.com>
Date: Tue, 26 Feb 2013 09:13:24 +0100
Subject: [PATCH 009/112] pycurl.c: remove a left-over global variable introduced in r150
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
src/pycurl.c | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
diff --git a/src/pycurl.c b/src/pycurl.c
index ac448b0..094bc60 100644
--- a/src/pycurl.c
+++ b/src/pycurl.c
@@ -1529,7 +1529,6 @@ do_curl_reset(CurlObject *self)
}
/* --------------- unsetopt/setopt/getinfo --------------- */
- int res;
static PyObject *
util_curl_unsetopt(CurlObject *self, int option)
--
1.7.1
From 802240d937867454026b6d8baaded841f6f32057 Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@redhat.com>
Date: Mon, 25 Feb 2013 19:50:18 +0100
Subject: [PATCH 010/112] test_internals.py: add a test for ref-counting in reset()
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/test_internals.py | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/tests/test_internals.py b/tests/test_internals.py
index a1a6533..3f5eefd 100644
--- a/tests/test_internals.py
+++ b/tests/test_internals.py
@@ -245,6 +245,11 @@ if 1 and gc:
if opts.verbose >= 1:
print "Tracked objects:", len(gc.get_objects())
+if 1:
+ # Ensure that the refcounting error in "reset" is fixed:
+ for i in xrange(100000):
+ c = Curl()
+ c.reset()
# /***********************************************************************
# // done
--
1.7.1
From 2baf0fab555c9f0f292e400222c79b01f9211abf Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 01:15:00 -0500
Subject: [PATCH 011/112] Add gitignore
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
.gitignore | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 .gitignore
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/build
--
1.7.1
From 53a2bfa7c8f381a4d4465d204fc3e4f7133a2db6 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Fri, 1 Mar 2013 00:11:47 -0500
Subject: [PATCH 012/112] A much simpler request test, in unittest format
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/request_test.py | 31 +++++++++++++++++++++++++++++++
1 files changed, 31 insertions(+), 0 deletions(-)
create mode 100644 tests/request_test.py
diff --git a/tests/request_test.py b/tests/request_test.py
new file mode 100644
index 0000000..0761d6c
--- /dev/null
+++ b/tests/request_test.py
@@ -0,0 +1,31 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+
+import pycurl
+import unittest
+try:
+ from cStringIO import StringIO
+except ImportError:
+ try:
+ from StringIO import StringIO
+ except ImportError:
+ from io import StringIO
+
+class RequestTest(unittest.TestCase):
+ def setUp(self):
+ self.curl = pycurl.Curl()
+
+ def tearDown(self):
+ self.curl.close()
+
+ def test_perform_get(self):
+ self.curl.setopt(pycurl.URL, 'http://localhost')
+ self.curl.perform()
+
+ def test_perform_get_with_write_function(self):
+ self.curl.setopt(pycurl.URL, 'http://localhost')
+ sio = StringIO()
+ self.curl.setopt(pycurl.WRITEFUNCTION, sio.write)
+ self.curl.perform()
+ print(sio.getvalue())
--
1.7.1
From 127442bead3a274cc5239e6389682d239c1fcbca Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Fri, 1 Mar 2013 13:35:59 -0500
Subject: [PATCH 013/112] init.py for test package
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
0 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 tests/__init__.py
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--
1.7.1
From 97ac029a9e925bd4903bd7a41e69110e158ec897 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Fri, 1 Mar 2013 13:36:08 -0500
Subject: [PATCH 014/112] wsgi application runner
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/runwsgi.py | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 82 insertions(+), 0 deletions(-)
create mode 100644 tests/runwsgi.py
diff --git a/tests/runwsgi.py b/tests/runwsgi.py
new file mode 100644
index 0000000..d658614
--- /dev/null
+++ b/tests/runwsgi.py
@@ -0,0 +1,82 @@
+# Run a WSGI application in a daemon thread
+
+import bottle
+import threading
+import socket
+import time as _time
+
+class Server(bottle.WSGIRefServer):
+ def run(self, handler): # pragma: no cover
+ from wsgiref.simple_server import make_server, WSGIRequestHandler
+ if self.quiet:
+ base = self.options.get('handler_class', WSGIRequestHandler)
+ class QuietHandler(base):
+ def log_request(*args, **kw): pass
+ self.options['handler_class'] = QuietHandler
+ self.srv = make_server(self.host, self.port, handler, **self.options)
+ self.srv.serve_forever(poll_interval=0.1)
+
+def start_bottle_server(app, port, **kwargs):
+ server_thread = ServerThread(app, port, kwargs)
+ server_thread.daemon = True
+ server_thread.start()
+
+ ok = False
+ for i in range(10):
+ try:
+ conn = socket.create_connection(('127.0.0.1', port), 0.1)
+ except socket.error as e:
+ _time.sleep(0.1)
+ else:
+ conn.close()
+ ok = True
+ break
+ if not ok:
+ import warnings
+ warnings.warn('Server did not start after 1 second')
+
+ return server_thread.server
+
+class ServerThread(threading.Thread):
+ def __init__(self, app, port, server_kwargs):
+ threading.Thread.__init__(self)
+ self.app = app
+ self.port = port
+ self.server_kwargs = server_kwargs
+ self.server = Server(host='localhost', port=self.port, **self.server_kwargs)
+
+ def run(self):
+ bottle.run(self.app, server=self.server, quiet=True)
+
+def app_runner_setup(*specs):
+ '''Returns setup and teardown methods for running a list of WSGI
+ applications in a daemon thread.
+
+ Each argument is an (app, port) pair.
+
+ Return value is a (setup, teardown) function pair.
+
+ The setup and teardown functions expect to be called with an argument
+ on which server state will be stored.
+
+ Example usage with nose:
+
+ >>> setup_module, teardown_module = \
+ runwsgi.app_runner_setup((app_module.app, 8050))
+ '''
+
+ def setup(self):
+ self.servers = []
+ for spec in specs:
+ if len(spec) == 2:
+ app, port = spec
+ kwargs = {}
+ else:
+ app, port, kwargs = spec
+ self.servers.append(start_bottle_server(app, port, **kwargs))
+
+ def teardown(self):
+ for server in self.servers:
+ server.srv.shutdown()
+
+ return [setup, teardown]
--
1.7.1
From 766e9a77708953c56b33d087561eddab853a08da Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Fri, 1 Mar 2013 14:06:42 -0500
Subject: [PATCH 015/112] Test application to be on the server side
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/app.py | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)
create mode 100644 tests/app.py
diff --git a/tests/app.py b/tests/app.py
new file mode 100644
index 0000000..b173fd6
--- /dev/null
+++ b/tests/app.py
@@ -0,0 +1,7 @@
+import bottle
+
+app = bottle.Bottle()
+
+@app.route('/success')
+def ok():
+ return 'success'
--
1.7.1
From a1449f4986686920904d7f781327e3ca520e4933 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Fri, 1 Mar 2013 14:07:04 -0500
Subject: [PATCH 016/112] Use the test application in request test
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/request_test.py | 59 ++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 56 insertions(+), 3 deletions(-)
diff --git a/tests/request_test.py b/tests/request_test.py
index 0761d6c..127fbeb 100644
--- a/tests/request_test.py
+++ b/tests/request_test.py
@@ -2,8 +2,12 @@
# -*- coding: iso-8859-1 -*-
# vi:ts=4:et
+import os
+import sys
+import tempfile
import pycurl
import unittest
+import io
try:
from cStringIO import StringIO
except ImportError:
@@ -12,6 +16,11 @@ except ImportError:
except ImportError:
from io import StringIO
+from . import app
+from . import runwsgi
+
+setup_module, teardown_module = runwsgi.app_runner_setup((app.app, 8380))
+
class RequestTest(unittest.TestCase):
def setUp(self):
self.curl = pycurl.Curl()
@@ -20,12 +29,56 @@ class RequestTest(unittest.TestCase):
self.curl.close()
def test_perform_get(self):
- self.curl.setopt(pycurl.URL, 'http://localhost')
+ # This test performs a GET request without doing anything else.
+ # Unfortunately, the default curl behavior is to print response
+ # body to standard output, which spams test output.
+ # As a result this test is commented out. Uncomment for debugging.
+ # test_perform_get_with_default_write_function is the test
+ # which exercises default curl write handler.
+ return
+
+ self.curl.setopt(pycurl.URL, 'http://localhost:8380/success')
self.curl.perform()
def test_perform_get_with_write_function(self):
- self.curl.setopt(pycurl.URL, 'http://localhost')
+ self.curl.setopt(pycurl.URL, 'http://localhost:8380/success')
sio = StringIO()
self.curl.setopt(pycurl.WRITEFUNCTION, sio.write)
self.curl.perform()
- print(sio.getvalue())
+ self.assertEqual('success', sio.getvalue())
+
+ def test_perform_get_with_default_write_function(self):
+ self.curl.setopt(pycurl.URL, 'http://localhost:8380/success')
+ #with tempfile.NamedTemporaryFile() as f:
+ with open('w', 'w+') as f:
+ # nose output capture plugin replaces sys.stdout with a StringIO
+ # instance. We want to redirect the underlying file descriptor
+ # anyway because underlying C code uses it.
+ # But keep track of whether we replace sys.stdout.
+ perform_dup = False
+ if hasattr(sys.stdout, 'fileno'):
+ try:
+ sys.stdout.fileno()
+ perform_dup = True
+ except io.UnsupportedOperation:
+ # stdout is a StringIO
+ pass
+ if perform_dup:
+ saved_stdout_fd = os.dup(sys.stdout.fileno())
+ os.dup2(f.fileno(), sys.stdout.fileno())
+ else:
+ saved_stdout = sys.stdout
+ sys.stdout = f
+ try:
+ self.curl.perform()
+ finally:
+ sys.stdout.flush()
+ if perform_dup:
+ os.fsync(sys.stdout.fileno())
+ os.dup2(saved_stdout_fd, sys.stdout.fileno())
+ os.close(saved_stdout_fd)
+ else:
+ sys.stdout = saved_stdout
+ f.seek(0)
+ body = f.read()
+ self.assertEqual('success', body)
--
1.7.1
From b332c2265bd3958a964bd2e69f9eeda96bafc814 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Sat, 2 Mar 2013 02:23:27 -0500
Subject: [PATCH 017/112] Put stringio import into util
This way all tests can simply import stringio from util in one line.
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/util.py | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/tests/util.py b/tests/util.py
index a1a9978..891da44 100644
--- a/tests/util.py
+++ b/tests/util.py
@@ -4,6 +4,14 @@
import os, sys
+try:
+ from cStringIO import StringIO
+except ImportError:
+ try:
+ from StringIO import StringIO
+ except ImportError:
+ from io import StringIO
+
#
# prepare sys.path in case we are still in the build directory
# see also: distutils/command/build.py (build_platlib)
--
1.7.1
From c912395f00df7a91f3d9c0fcc16821c7cc25bf63 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Sat, 2 Mar 2013 02:24:11 -0500
Subject: [PATCH 018/112] Debug test, ported from the old debug test
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/debug_test.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 46 insertions(+), 0 deletions(-)
create mode 100644 tests/debug_test.py
diff --git a/tests/debug_test.py b/tests/debug_test.py
new file mode 100644
index 0000000..dd00719
--- /dev/null
+++ b/tests/debug_test.py
@@ -0,0 +1,46 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+
+import pycurl
+import unittest
+
+from . import app
+from . import runwsgi
+
+setup_module, teardown_module = runwsgi.app_runner_setup((app.app, 8380))
+
+class DebugTest(unittest.TestCase):
+ def setUp(self):
+ self.curl = pycurl.Curl()
+ self.debug_entries = []
+
+ def tearDown(self):
+ self.curl.close()
+
+ def debug_function(self, t, b):
+ self.debug_entries.append((t, b))
+
+ def test_perform_get_with_debug_function(self):
+ self.curl.setopt(pycurl.VERBOSE, 1)
+ self.curl.setopt(pycurl.DEBUGFUNCTION, self.debug_function)
+ self.curl.setopt(pycurl.URL, 'http://localhost:8380/success')
+ self.curl.perform()
+
+ # Some checks with no particular intent
+ self.check(0, 'About to connect')
+ self.check(0, 'Connected to localhost')
+ self.check(0, 'port 8380')
+ # request
+ self.check(2, 'GET /success HTTP/1.1')
+ # response
+ self.check(1, 'HTTP/1.0 200 OK')
+ self.check(1, 'Content-Length: 7')
+ # result
+ self.check(3, 'success')
+
+ def check(self, wanted_t, wanted_b):
+ for t, b in self.debug_entries:
+ if t == wanted_t and wanted_b in b:
+ return
+ assert False, "%d: %s not found in debug entries" % (wanted_t, wanted_b)
--
1.7.1
From d3133de193791e731867c0ab02c49cd3f88422c0 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Sat, 2 Mar 2013 02:43:57 -0500
Subject: [PATCH 019/112] Write output to a stringio to avoid stdout spam
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/debug_test.py | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/tests/debug_test.py b/tests/debug_test.py
index dd00719..8005239 100644
--- a/tests/debug_test.py
+++ b/tests/debug_test.py
@@ -7,6 +7,7 @@ import unittest
from . import app
from . import runwsgi
+from . import util
setup_module, teardown_module = runwsgi.app_runner_setup((app.app, 8380))
@@ -25,6 +26,8 @@ class DebugTest(unittest.TestCase):
self.curl.setopt(pycurl.VERBOSE, 1)
self.curl.setopt(pycurl.DEBUGFUNCTION, self.debug_function)
self.curl.setopt(pycurl.URL, 'http://localhost:8380/success')
+ sio = util.StringIO()
+ self.curl.setopt(pycurl.WRITEFUNCTION, sio.write)
self.curl.perform()
# Some checks with no particular intent
--
1.7.1
From ff2df7b5ef851c29328dfb1ff501ff610690c63b Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Sat, 2 Mar 2013 02:44:24 -0500
Subject: [PATCH 020/112] Use stringio from util in request test
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/request_test.py | 10 ++--------
1 files changed, 2 insertions(+), 8 deletions(-)
diff --git a/tests/request_test.py b/tests/request_test.py
index 127fbeb..afd8566 100644
--- a/tests/request_test.py
+++ b/tests/request_test.py
@@ -8,16 +8,10 @@ import tempfile
import pycurl
import unittest
import io
-try:
- from cStringIO import StringIO
-except ImportError:
- try:
- from StringIO import StringIO
- except ImportError:
- from io import StringIO
from . import app
from . import runwsgi
+from . import util
setup_module, teardown_module = runwsgi.app_runner_setup((app.app, 8380))
@@ -42,7 +36,7 @@ class RequestTest(unittest.TestCase):
def test_perform_get_with_write_function(self):
self.curl.setopt(pycurl.URL, 'http://localhost:8380/success')
- sio = StringIO()
+ sio = util.StringIO()
self.curl.setopt(pycurl.WRITEFUNCTION, sio.write)
self.curl.perform()
self.assertEqual('success', sio.getvalue())
--
1.7.1
From 8121df921a0615d1f5c6793ad86e17dc20e00902 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Sat, 2 Mar 2013 04:06:00 -0500
Subject: [PATCH 021/112] Add a test that writes response to a file
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/request_test.py | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/tests/request_test.py b/tests/request_test.py
index afd8566..7386a51 100644
--- a/tests/request_test.py
+++ b/tests/request_test.py
@@ -41,6 +41,15 @@ class RequestTest(unittest.TestCase):
self.curl.perform()
self.assertEqual('success', sio.getvalue())
+ def test_write_to_file(self):
+ self.curl.setopt(pycurl.URL, 'http://localhost:8380/success')
+ with tempfile.NamedTemporaryFile() as f:
+ self.curl.setopt(pycurl.WRITEFUNCTION, f.write)
+ self.curl.perform()
+ f.seek(0)
+ body = f.read()
+ self.assertEqual('success', body)
+
def test_perform_get_with_default_write_function(self):
self.curl.setopt(pycurl.URL, 'http://localhost:8380/success')
#with tempfile.NamedTemporaryFile() as f:
--
1.7.1
From 5c59850b231cc0e9d38c7d56e67d55500e024577 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Sun, 3 Mar 2013 00:14:26 -0500
Subject: [PATCH 022/112] Account for the case of nose running no tests
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/runwsgi.py | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/tests/runwsgi.py b/tests/runwsgi.py
index d658614..7b39358 100644
--- a/tests/runwsgi.py
+++ b/tests/runwsgi.py
@@ -77,6 +77,8 @@ def app_runner_setup(*specs):
def teardown(self):
for server in self.servers:
- server.srv.shutdown()
+ # if no tests from module were run, there is no server to shut down
+ if hasattr(server, 'srv'):
+ server.srv.shutdown()
return [setup, teardown]
--
1.7.1
From 48ac39062e8cd19ee4ddf590278aa6e35477a8d3 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Sun, 3 Mar 2013 00:14:41 -0500
Subject: [PATCH 023/112] Split request test
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/default_write_function_test.py | 70 +++++++++++++++++++++++++++
tests/request_test.py | 87 ----------------------------------
tests/write_to_file_test.py | 29 +++++++++++
tests/write_to_stringio_test.py | 30 ++++++++++++
4 files changed, 129 insertions(+), 87 deletions(-)
create mode 100644 tests/default_write_function_test.py
delete mode 100644 tests/request_test.py
create mode 100644 tests/write_to_file_test.py
create mode 100644 tests/write_to_stringio_test.py
diff --git a/tests/default_write_function_test.py b/tests/default_write_function_test.py
new file mode 100644
index 0000000..2efc579
--- /dev/null
+++ b/tests/default_write_function_test.py
@@ -0,0 +1,70 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+
+import unittest
+import pycurl
+import sys
+import tempfile
+import io
+import os
+
+from . import app
+from . import runwsgi
+from . import util
+
+setup_module, teardown_module = runwsgi.app_runner_setup((app.app, 8380))
+
+class RequestTest(unittest.TestCase):
+ def setUp(self):
+ self.curl = pycurl.Curl()
+
+ def tearDown(self):
+ self.curl.close()
+
+ def test_perform_get(self):
+ # This test performs a GET request without doing anything else.
+ # Unfortunately, the default curl behavior is to print response
+ # body to standard output, which spams test output.
+ # As a result this test is commented out. Uncomment for debugging.
+ # test_perform_get_with_default_write_function is the test
+ # which exercises default curl write handler.
+
+ self.curl.setopt(pycurl.URL, 'http://localhost:8380/success')
+ self.curl.perform()
+
+ def test_perform_get_with_default_write_function(self):
+ self.curl.setopt(pycurl.URL, 'http://localhost:8380/success')
+ #with tempfile.NamedTemporaryFile() as f:
+ with open('w', 'w+') as f:
+ # nose output capture plugin replaces sys.stdout with a StringIO
+ # instance. We want to redirect the underlying file descriptor
+ # anyway because underlying C code uses it.
+ # But keep track of whether we replace sys.stdout.
+ perform_dup = False
+ if hasattr(sys.stdout, 'fileno'):
+ try:
+ sys.stdout.fileno()
+ perform_dup = True
+ except io.UnsupportedOperation:
+ # stdout is a StringIO
+ pass
+ if perform_dup:
+ saved_stdout_fd = os.dup(sys.stdout.fileno())
+ os.dup2(f.fileno(), sys.stdout.fileno())
+ else:
+ saved_stdout = sys.stdout
+ sys.stdout = f
+ try:
+ self.curl.perform()
+ finally:
+ sys.stdout.flush()
+ if perform_dup:
+ os.fsync(sys.stdout.fileno())
+ os.dup2(saved_stdout_fd, sys.stdout.fileno())
+ os.close(saved_stdout_fd)
+ else:
+ sys.stdout = saved_stdout
+ f.seek(0)
+ body = f.read()
+ self.assertEqual('success', body)
diff --git a/tests/request_test.py b/tests/request_test.py
deleted file mode 100644
index 7386a51..0000000
--- a/tests/request_test.py
+++ /dev/null
@@ -1,87 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-
-import os
-import sys
-import tempfile
-import pycurl
-import unittest
-import io
-
-from . import app
-from . import runwsgi
-from . import util
-
-setup_module, teardown_module = runwsgi.app_runner_setup((app.app, 8380))
-
-class RequestTest(unittest.TestCase):
- def setUp(self):
- self.curl = pycurl.Curl()
-
- def tearDown(self):
- self.curl.close()
-
- def test_perform_get(self):
- # This test performs a GET request without doing anything else.
- # Unfortunately, the default curl behavior is to print response
- # body to standard output, which spams test output.
- # As a result this test is commented out. Uncomment for debugging.
- # test_perform_get_with_default_write_function is the test
- # which exercises default curl write handler.
- return
-
- self.curl.setopt(pycurl.URL, 'http://localhost:8380/success')
- self.curl.perform()
-
- def test_perform_get_with_write_function(self):
- self.curl.setopt(pycurl.URL, 'http://localhost:8380/success')
- sio = util.StringIO()
- self.curl.setopt(pycurl.WRITEFUNCTION, sio.write)
- self.curl.perform()
- self.assertEqual('success', sio.getvalue())
-
- def test_write_to_file(self):
- self.curl.setopt(pycurl.URL, 'http://localhost:8380/success')
- with tempfile.NamedTemporaryFile() as f:
- self.curl.setopt(pycurl.WRITEFUNCTION, f.write)
- self.curl.perform()
- f.seek(0)
- body = f.read()
- self.assertEqual('success', body)
-
- def test_perform_get_with_default_write_function(self):
- self.curl.setopt(pycurl.URL, 'http://localhost:8380/success')
- #with tempfile.NamedTemporaryFile() as f:
- with open('w', 'w+') as f:
- # nose output capture plugin replaces sys.stdout with a StringIO
- # instance. We want to redirect the underlying file descriptor
- # anyway because underlying C code uses it.
- # But keep track of whether we replace sys.stdout.
- perform_dup = False
- if hasattr(sys.stdout, 'fileno'):
- try:
- sys.stdout.fileno()
- perform_dup = True
- except io.UnsupportedOperation:
- # stdout is a StringIO
- pass
- if perform_dup:
- saved_stdout_fd = os.dup(sys.stdout.fileno())
- os.dup2(f.fileno(), sys.stdout.fileno())
- else:
- saved_stdout = sys.stdout
- sys.stdout = f
- try:
- self.curl.perform()
- finally:
- sys.stdout.flush()
- if perform_dup:
- os.fsync(sys.stdout.fileno())
- os.dup2(saved_stdout_fd, sys.stdout.fileno())
- os.close(saved_stdout_fd)
- else:
- sys.stdout = saved_stdout
- f.seek(0)
- body = f.read()
- self.assertEqual('success', body)
diff --git a/tests/write_to_file_test.py b/tests/write_to_file_test.py
new file mode 100644
index 0000000..6528f81
--- /dev/null
+++ b/tests/write_to_file_test.py
@@ -0,0 +1,29 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+
+import unittest
+import pycurl
+import tempfile
+
+from . import app
+from . import runwsgi
+from . import util
+
+setup_module, teardown_module = runwsgi.app_runner_setup((app.app, 8380))
+
+class RequestTest(unittest.TestCase):
+ def setUp(self):
+ self.curl = pycurl.Curl()
+
+ def tearDown(self):
+ self.curl.close()
+
+ def test_get_to_file(self):
+ self.curl.setopt(pycurl.URL, 'http://localhost:8380/success')
+ with tempfile.NamedTemporaryFile() as f:
+ self.curl.setopt(pycurl.WRITEFUNCTION, f.write)
+ self.curl.perform()
+ f.seek(0)
+ body = f.read()
+ self.assertEqual('success', body)
diff --git a/tests/write_to_stringio_test.py b/tests/write_to_stringio_test.py
new file mode 100644
index 0000000..fd1c28d
--- /dev/null
+++ b/tests/write_to_stringio_test.py
@@ -0,0 +1,30 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+
+import os
+import sys
+import tempfile
+import pycurl
+import unittest
+import io
+
+from . import app
+from . import runwsgi
+from . import util
+
+setup_module, teardown_module = runwsgi.app_runner_setup((app.app, 8380))
+
+class WriteToStringioTest(unittest.TestCase):
+ def setUp(self):
+ self.curl = pycurl.Curl()
+
+ def tearDown(self):
+ self.curl.close()
+
+ def test_get(self):
+ self.curl.setopt(pycurl.URL, 'http://localhost:8380/success')
+ sio = util.StringIO()
+ self.curl.setopt(pycurl.WRITEFUNCTION, sio.write)
+ self.curl.perform()
+ self.assertEqual('success', sio.getvalue())
--
1.7.1
From 3f765182563497ed5dc0348474e8e9f30618576e Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Sun, 3 Mar 2013 00:22:05 -0500
Subject: [PATCH 024/112] Need to flush when using default write function
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/default_write_function_test.py | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/tests/default_write_function_test.py b/tests/default_write_function_test.py
index 2efc579..afbba33 100644
--- a/tests/default_write_function_test.py
+++ b/tests/default_write_function_test.py
@@ -32,6 +32,9 @@ class RequestTest(unittest.TestCase):
self.curl.setopt(pycurl.URL, 'http://localhost:8380/success')
self.curl.perform()
+ # If this flush is not done, stdout output bleeds into the next test
+ # that is executed
+ sys.stdout.flush()
def test_perform_get_with_default_write_function(self):
self.curl.setopt(pycurl.URL, 'http://localhost:8380/success')
@@ -57,8 +60,8 @@ class RequestTest(unittest.TestCase):
sys.stdout = f
try:
self.curl.perform()
- finally:
sys.stdout.flush()
+ finally:
if perform_dup:
os.fsync(sys.stdout.fileno())
os.dup2(saved_stdout_fd, sys.stdout.fileno())
--
1.7.1
From 8515cd10d9ead70ce306fcf2de96b0d34a402d88 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Sun, 3 Mar 2013 00:34:39 -0500
Subject: [PATCH 025/112] Trying to get the default write function test to work with nose output capture, but no luck so far
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/default_write_function_test.py | 52 +++++++++++++++++----------------
1 files changed, 27 insertions(+), 25 deletions(-)
diff --git a/tests/default_write_function_test.py b/tests/default_write_function_test.py
index afbba33..853992b 100644
--- a/tests/default_write_function_test.py
+++ b/tests/default_write_function_test.py
@@ -15,6 +15,8 @@ from . import util
setup_module, teardown_module = runwsgi.app_runner_setup((app.app, 8380))
+STDOUT_FD_NUM = 1
+
class RequestTest(unittest.TestCase):
def setUp(self):
self.curl = pycurl.Curl()
@@ -33,41 +35,41 @@ class RequestTest(unittest.TestCase):
self.curl.setopt(pycurl.URL, 'http://localhost:8380/success')
self.curl.perform()
# If this flush is not done, stdout output bleeds into the next test
- # that is executed
+ # that is executed (without nose output capture)
sys.stdout.flush()
+ os.fsync(STDOUT_FD_NUM)
- def test_perform_get_with_default_write_function(self):
+ # I have a really hard time getting this to work with nose output capture
+ def skip_test_perform_get_with_default_write_function(self):
self.curl.setopt(pycurl.URL, 'http://localhost:8380/success')
- #with tempfile.NamedTemporaryFile() as f:
- with open('w', 'w+') as f:
+ with tempfile.NamedTemporaryFile() as f:
+ #with open('w', 'w+') as f:
# nose output capture plugin replaces sys.stdout with a StringIO
# instance. We want to redirect the underlying file descriptor
# anyway because underlying C code uses it.
- # But keep track of whether we replace sys.stdout.
- perform_dup = False
- if hasattr(sys.stdout, 'fileno'):
- try:
- sys.stdout.fileno()
- perform_dup = True
- except io.UnsupportedOperation:
- # stdout is a StringIO
- pass
- if perform_dup:
- saved_stdout_fd = os.dup(sys.stdout.fileno())
- os.dup2(f.fileno(), sys.stdout.fileno())
- else:
- saved_stdout = sys.stdout
- sys.stdout = f
+ # Therefore:
+ # 1. Use file descriptor 1 rather than sys.stdout.fileno() to
+ # reference the standard output file descriptor.
+ # 2. We do not touch sys.stdout. This means anything written to
+ # sys.stdout will be captured by nose, and not make it to our code.
+ # But the output we care about happens at libcurl level, below
+ # nose, therefore this is fine.
+ saved_stdout_fd = os.dup(STDOUT_FD_NUM)
+ os.dup2(f.fileno(), STDOUT_FD_NUM)
+ #os.dup2(1, 100)
+ #os.dup2(2, 1)
+ # We also need to flush the output that libcurl wrote to stdout.
+ # Since sys.stdout might be nose's StringIO instance, open the
+ # stdout file descriptor manually.
+
try:
self.curl.perform()
sys.stdout.flush()
finally:
- if perform_dup:
- os.fsync(sys.stdout.fileno())
- os.dup2(saved_stdout_fd, sys.stdout.fileno())
- os.close(saved_stdout_fd)
- else:
- sys.stdout = saved_stdout
+ os.fsync(STDOUT_FD_NUM)
+ os.dup2(saved_stdout_fd, STDOUT_FD_NUM)
+ os.close(saved_stdout_fd)
+ #os.dup2(100, 1)
f.seek(0)
body = f.read()
self.assertEqual('success', body)
--
1.7.1
From a43c72743b7a191622da9b1a933600c92b892529 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Sun, 3 Mar 2013 00:35:25 -0500
Subject: [PATCH 026/112] Fix test class names
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/default_write_function_test.py | 2 +-
tests/write_to_file_test.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/tests/default_write_function_test.py b/tests/default_write_function_test.py
index 853992b..a0de66e 100644
--- a/tests/default_write_function_test.py
+++ b/tests/default_write_function_test.py
@@ -17,7 +17,7 @@ setup_module, teardown_module = runwsgi.app_runner_setup((app.app, 8380))
STDOUT_FD_NUM = 1
-class RequestTest(unittest.TestCase):
+class DefaultWriteFunctionTest(unittest.TestCase):
def setUp(self):
self.curl = pycurl.Curl()
diff --git a/tests/write_to_file_test.py b/tests/write_to_file_test.py
index 6528f81..67c9c63 100644
--- a/tests/write_to_file_test.py
+++ b/tests/write_to_file_test.py
@@ -12,7 +12,7 @@ from . import util
setup_module, teardown_module = runwsgi.app_runner_setup((app.app, 8380))
-class RequestTest(unittest.TestCase):
+class WriteToFileTest(unittest.TestCase):
def setUp(self):
self.curl = pycurl.Curl()
--
1.7.1
From 748ffdb26baef8fa43e8da7e086325e5a77dafee Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Sun, 3 Mar 2013 00:36:34 -0500
Subject: [PATCH 027/112] Delete unused imports
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/write_to_stringio_test.py | 3 ---
1 files changed, 0 insertions(+), 3 deletions(-)
diff --git a/tests/write_to_stringio_test.py b/tests/write_to_stringio_test.py
index fd1c28d..018800d 100644
--- a/tests/write_to_stringio_test.py
+++ b/tests/write_to_stringio_test.py
@@ -2,9 +2,6 @@
# -*- coding: iso-8859-1 -*-
# vi:ts=4:et
-import os
-import sys
-import tempfile
import pycurl
import unittest
import io
--
1.7.1
From da193274e430029a18b1f9b28729d9e165196f29 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Sun, 3 Mar 2013 00:41:35 -0500
Subject: [PATCH 028/112] Test for header function
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/header_function_test.py | 50 +++++++++++++++++++++++++++++++++++++++++
1 files changed, 50 insertions(+), 0 deletions(-)
create mode 100644 tests/header_function_test.py
diff --git a/tests/header_function_test.py b/tests/header_function_test.py
new file mode 100644
index 0000000..bfe7173
--- /dev/null
+++ b/tests/header_function_test.py
@@ -0,0 +1,50 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+
+import pycurl
+import unittest
+import io
+import time as _time
+
+from . import app
+from . import runwsgi
+from . import util
+
+setup_module, teardown_module = runwsgi.app_runner_setup((app.app, 8380))
+
+class HeaderFunctionTest(unittest.TestCase):
+ def setUp(self):
+ self.curl = pycurl.Curl()
+ self.header_lines = []
+
+ def tearDown(self):
+ self.curl.close()
+
+ def header_function(self, line):
+ self.header_lines.append(line)
+
+ def test_get(self):
+ self.curl.setopt(pycurl.URL, 'http://localhost:8380/success')
+ sio = util.StringIO()
+ self.curl.setopt(pycurl.WRITEFUNCTION, sio.write)
+ self.curl.setopt(pycurl.HEADERFUNCTION, self.header_function)
+ self.curl.perform()
+ self.assertEqual('success', sio.getvalue())
+
+ assert len(self.header_lines) > 0
+ self.assertEqual("HTTP/1.0 200 OK\r\n", self.header_lines[0])
+ # day of week
+ todays_day = _time.strftime('%a')
+ # Date: Sun, 03 Mar 2013 05:38:12 GMT\r\n
+ self.check('Date: %s' % todays_day)
+ # Server: WSGIServer/0.1 Python/2.7.3\r\n
+ self.check('Server: WSGIServer')
+ self.check('Content-Length: 7')
+ self.check('Content-Type: text/html')
+
+ def check(self, wanted_text):
+ for line in self.header_lines:
+ if wanted_text in line:
+ return
+ assert False, "%s not found in header lines" % wanted_text
--
1.7.1
From 040b13d56a0eb2a9c8e5ee7e35142c4e240d48db Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Sun, 3 Mar 2013 01:35:21 -0500
Subject: [PATCH 029/112] FTP test
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/ftp_test.py | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 48 insertions(+), 0 deletions(-)
create mode 100644 tests/ftp_test.py
diff --git a/tests/ftp_test.py b/tests/ftp_test.py
new file mode 100644
index 0000000..d215b6e
--- /dev/null
+++ b/tests/ftp_test.py
@@ -0,0 +1,48 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+
+import pycurl
+import unittest
+
+from . import util
+
+class FtpTest(unittest.TestCase):
+ def setUp(self):
+ self.curl = pycurl.Curl()
+
+ def tearDown(self):
+ self.curl.close()
+
+ def test_get_ftp(self):
+ self.curl.setopt(pycurl.URL, 'ftp://localhost:8921')
+ sio = util.StringIO()
+ self.curl.setopt(pycurl.WRITEFUNCTION, sio.write)
+ self.curl.perform()
+
+ result = sio.getvalue()
+ assert 'README' in result
+ assert 'bin -> usr/bin' in result
+
+ # XXX this test needs to be fixed
+ def test_quote(self):
+ self.curl.setopt(pycurl.URL, 'ftp://localhost:8921')
+ sio = util.StringIO()
+ self.curl.setopt(pycurl.WRITEFUNCTION, sio.write)
+ self.curl.setopt(pycurl.QUOTE, ['CWD pub'])
+ self.curl.perform()
+
+ result = sio.getvalue()
+ assert 'README' in result
+ assert 'bin -> usr/bin' in result
+
+ def test_epsv(self):
+ self.curl.setopt(pycurl.URL, 'ftp://localhost:8921')
+ sio = util.StringIO()
+ self.curl.setopt(pycurl.WRITEFUNCTION, sio.write)
+ self.curl.setopt(pycurl.FTP_USE_EPSV, 1)
+ self.curl.perform()
+
+ result = sio.getvalue()
+ assert 'README' in result
+ assert 'bin -> usr/bin' in result
--
1.7.1
From eb36d56c850ed14a52d0a1f3afb62165444f9b84 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Sun, 3 Mar 2013 01:44:22 -0500
Subject: [PATCH 030/112] Getinfo test
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/getinfo_test.py | 43 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 43 insertions(+), 0 deletions(-)
create mode 100644 tests/getinfo_test.py
diff --git a/tests/getinfo_test.py b/tests/getinfo_test.py
new file mode 100644
index 0000000..39dff2f
--- /dev/null
+++ b/tests/getinfo_test.py
@@ -0,0 +1,43 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+
+import pycurl
+import unittest
+
+from . import app
+from . import runwsgi
+from . import util
+
+setup_module, teardown_module = runwsgi.app_runner_setup((app.app, 8380))
+
+class GetinfoTest(unittest.TestCase):
+ def setUp(self):
+ self.curl = pycurl.Curl()
+
+ def tearDown(self):
+ self.curl.close()
+
+ def test_getinfo(self):
+ self.curl.setopt(pycurl.URL, 'http://localhost:8380/success')
+ sio = util.StringIO()
+ self.curl.setopt(pycurl.WRITEFUNCTION, sio.write)
+ self.curl.perform()
+ self.assertEqual('success', sio.getvalue())
+
+ self.assertEqual(200, self.curl.getinfo(pycurl.HTTP_CODE))
+ assert type(self.curl.getinfo(pycurl.TOTAL_TIME)) is float
+ assert self.curl.getinfo(pycurl.TOTAL_TIME) > 0
+ assert self.curl.getinfo(pycurl.TOTAL_TIME) < 1
+ assert type(self.curl.getinfo(pycurl.SPEED_DOWNLOAD)) is float
+ assert self.curl.getinfo(pycurl.SPEED_DOWNLOAD) > 0
+ self.assertEqual(7, self.curl.getinfo(pycurl.SIZE_DOWNLOAD))
+ self.assertEqual('http://localhost:8380/success', self.curl.getinfo(pycurl.EFFECTIVE_URL))
+ self.assertEqual('text/html; charset=utf-8', self.curl.getinfo(pycurl.CONTENT_TYPE).lower())
+ assert type(self.curl.getinfo(pycurl.NAMELOOKUP_TIME)) is float
+ assert self.curl.getinfo(pycurl.NAMELOOKUP_TIME) > 0
+ assert self.curl.getinfo(pycurl.NAMELOOKUP_TIME) < 1
+ self.assertEqual(0, self.curl.getinfo(pycurl.REDIRECT_TIME))
+ self.assertEqual(0, self.curl.getinfo(pycurl.REDIRECT_COUNT))
+ # time not requested
+ self.assertEqual(-1, self.curl.getinfo(pycurl.INFO_FILETIME))
--
1.7.1
From ca2118da041f15f5bbb2bf6a0e12b7bd57d16332 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Sun, 3 Mar 2013 02:05:30 -0500
Subject: [PATCH 031/112] Ported internals test
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/internals_test.py | 224 +++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 224 insertions(+), 0 deletions(-)
create mode 100644 tests/internals_test.py
diff --git a/tests/internals_test.py b/tests/internals_test.py
new file mode 100644
index 0000000..34d4eb8
--- /dev/null
+++ b/tests/internals_test.py
@@ -0,0 +1,224 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+
+import pycurl
+import unittest
+from .util import StringIO
+try:
+ import cPickle
+except ImportError:
+ cPickle = None
+import pickle
+import gc
+import copy
+
+class InternalsTest(unittest.TestCase):
+ def setUp(self):
+ self.curl = pycurl.Curl()
+
+ def tearDown(self):
+ self.curl.close()
+ del self.curl
+
+ # /***********************************************************************
+ # // test misc
+ # ************************************************************************/
+
+ def test_constant_aliasing(self):
+ assert self.curl.URL is pycurl.URL
+
+ # /***********************************************************************
+ # // test handles
+ # ************************************************************************/
+
+ def test_remove_invalid_handle(self):
+ m = pycurl.CurlMulti()
+ try:
+ m.remove_handle(self.curl)
+ except pycurl.error:
+ pass
+ else:
+ assert False, "No exception when trying to remove a handle that is not in CurlMulti"
+ del m
+
+ def test_remove_invalid_closed_handle(self):
+ m = pycurl.CurlMulti()
+ c = pycurl.Curl()
+ c.close()
+ m.remove_handle(c)
+ del m, c
+
+ def test_add_closed_handle(self):
+ m = pycurl.CurlMulti()
+ c = pycurl.Curl()
+ c.close()
+ try:
+ m.add_handle(c)
+ except pycurl.error:
+ pass
+ else:
+ assert 0, "No exception when trying to add a close handle to CurlMulti"
+ m.close()
+ del m, c
+
+ def test_add_handle_twice(self):
+ m = pycurl.CurlMulti()
+ m.add_handle(self.curl)
+ try:
+ m.add_handle(self.curl)
+ except pycurl.error:
+ pass
+ else:
+ assert 0, "No exception when trying to add the same handle twice"
+ del m
+
+ def test_add_handle_on_multiple_stacks(self):
+ m1 = pycurl.CurlMulti()
+ m2 = pycurl.CurlMulti()
+ m1.add_handle(self.curl)
+ try:
+ m2.add_handle(self.curl)
+ except pycurl.error:
+ pass
+ else:
+ assert 0, "No exception when trying to add the same handle on multiple stacks"
+ del m1, m2
+
+ def test_move_handle(self):
+ m1 = pycurl.CurlMulti()
+ m2 = pycurl.CurlMulti()
+ m1.add_handle(self.curl)
+ m1.remove_handle(self.curl)
+ m2.add_handle(self.curl)
+ del m1, m2
+
+ # /***********************************************************************
+ # // test copying and pickling - copying and pickling of
+ # // instances of Curl and CurlMulti is not allowed
+ # ************************************************************************/
+
+ def test_copy_curl(self):
+ try:
+ copy.copy(self.curl)
+ # python 2 raises copy.Error, python 3 raises TypeError
+ except (copy.Error, TypeError):
+ pass
+ else:
+ assert False, "No exception when trying to copy a Curl handle"
+
+ def test_copy_multi(self):
+ m = pycurl.CurlMulti()
+ try:
+ copy.copy(m)
+ except (copy.Error, TypeError):
+ pass
+ else:
+ assert False, "No exception when trying to copy a CurlMulti handle"
+
+ def test_pickle_curl(self):
+ fp = StringIO()
+ p = pickle.Pickler(fp, 1)
+ try:
+ p.dump(self.curl)
+ # python 2 raises pickle.PicklingError, python 3 raises TypeError
+ except (pickle.PicklingError, TypeError):
+ pass
+ else:
+ assert 0, "No exception when trying to pickle a Curl handle"
+ del fp, p
+
+ def test_pickle_multi(self):
+ m = pycurl.CurlMulti()
+ fp = StringIO()
+ p = pickle.Pickler(fp, 1)
+ try:
+ p.dump(m)
+ except (pickle.PicklingError, TypeError):
+ pass
+ else:
+ assert 0, "No exception when trying to pickle a CurlMulti handle"
+ del m, fp, p
+
+ if cPickle is not None:
+ def test_cpickle_curl(self):
+ fp = StringIO()
+ p = cPickle.Pickler(fp, 1)
+ try:
+ p.dump(self.curl)
+ except cPickle.PicklingError:
+ pass
+ else:
+ assert 0, "No exception when trying to pickle a Curl handle via cPickle"
+ del fp, p
+
+ def test_cpickle_multi(self):
+ m = pycurl.CurlMulti()
+ fp = StringIO()
+ p = cPickle.Pickler(fp, 1)
+ try:
+ p.dump(m)
+ except cPickle.PicklingError:
+ pass
+ else:
+ assert 0, "No exception when trying to pickle a CurlMulti handle via cPickle"
+ del m, fp, p
+
+ # /***********************************************************************
+ # // test refcounts
+ # ************************************************************************/
+
+ # basic check of reference counting (use a memory checker like valgrind)
+ def test_reference_counting(self):
+ c = pycurl.Curl()
+ m = pycurl.CurlMulti()
+ m.add_handle(c)
+ del m
+ m = pycurl.CurlMulti()
+ c.close()
+ del m, c
+
+ def test_cyclic_gc(self):
+ gc.collect()
+ c = pycurl.Curl()
+ c.m = pycurl.CurlMulti()
+ c.m.add_handle(c)
+ # create some nasty cyclic references
+ c.c = c
+ c.c.c1 = c
+ c.c.c2 = c
+ c.c.c3 = c.c
+ c.c.c4 = c.m
+ c.m.c = c
+ c.m.m = c.m
+ c.m.c = c
+ # delete
+ gc.collect()
+ flags = gc.DEBUG_COLLECTABLE | gc.DEBUG_UNCOLLECTABLE
+ # python 3 has no DEBUG_OBJECTS
+ #if hasattr(gc, 'DEBUG_OBJECTS'):
+ #flags |= gc.DEBUG_OBJECTS
+ #if opts.verbose >= 1:
+ #flags = flags | gc.DEBUG_STATS
+ gc.set_debug(flags)
+ gc.collect()
+ ##print gc.get_referrers(c)
+ ##print gc.get_objects()
+ #if opts.verbose >= 1:
+ #print("Tracked objects:", len(gc.get_objects()))
+ # The `del' below should delete these 4 objects:
+ # Curl + internal dict, CurlMulti + internal dict
+ del c
+ gc.collect()
+ #if opts.verbose >= 1:
+ #print("Tracked objects:", len(gc.get_objects()))
+
+ def test_refcounting_bug_in_reset(self):
+ try:
+ range_generator = xrange
+ except NameError:
+ range_generator = range
+ # Ensure that the refcounting error in "reset" is fixed:
+ for i in range_generator(100000):
+ c = pycurl.Curl()
+ c.reset()
--
1.7.1
From 5400bd486457b34d8c49ca3ad1f74f03143172bd Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Sun, 3 Mar 2013 02:16:10 -0500
Subject: [PATCH 032/112] Make cyclic gc test actually check that cycles are collected
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/internals_test.py | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/tests/internals_test.py b/tests/internals_test.py
index 34d4eb8..fb451df 100644
--- a/tests/internals_test.py
+++ b/tests/internals_test.py
@@ -12,6 +12,7 @@ except ImportError:
import pickle
import gc
import copy
+import re
class InternalsTest(unittest.TestCase):
def setUp(self):
@@ -179,6 +180,7 @@ class InternalsTest(unittest.TestCase):
del m, c
def test_cyclic_gc(self):
+ regexp = re.compile(r'at (0x\d+)')
gc.collect()
c = pycurl.Curl()
c.m = pycurl.CurlMulti()
@@ -206,10 +208,17 @@ class InternalsTest(unittest.TestCase):
##print gc.get_objects()
#if opts.verbose >= 1:
#print("Tracked objects:", len(gc.get_objects()))
+ match = regexp.search(repr(c))
+ assert match is not None
+ address = match.group(1)
# The `del' below should delete these 4 objects:
# Curl + internal dict, CurlMulti + internal dict
del c
gc.collect()
+ objects = gc.get_objects()
+ search = 'at %s' % address
+ for object in objects:
+ assert search not in repr(object)
#if opts.verbose >= 1:
#print("Tracked objects:", len(gc.get_objects()))
--
1.7.1
From b0c490027c63d5f8eb5dfc81c646e5edfb79635c Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Sun, 3 Mar 2013 03:00:20 -0500
Subject: [PATCH 033/112] Ported memleak test
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/memleak_test.py | 59 +++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 59 insertions(+), 0 deletions(-)
create mode 100644 tests/memleak_test.py
diff --git a/tests/memleak_test.py b/tests/memleak_test.py
new file mode 100644
index 0000000..6e9f76c
--- /dev/null
+++ b/tests/memleak_test.py
@@ -0,0 +1,59 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+
+import pycurl
+import unittest
+import gc
+import re
+
+class MemleakTest(unittest.TestCase):
+ def test_collection(self):
+ regexp = re.compile(r'at (0x\d+)')
+
+ gc.collect()
+ flags = gc.DEBUG_COLLECTABLE | gc.DEBUG_UNCOLLECTABLE
+ # python 3 has no DEBUG_OBJECTS
+ #if hasattr(gc, 'DEBUG_OBJECTS'):
+ #flags |= gc.DEBUG_OBJECTS
+ #if 1:
+ #flags = flags | gc.DEBUG_STATS
+ #gc.set_debug(flags)
+ gc.collect()
+
+ #print("Tracked objects:", len(gc.get_objects()))
+
+ multi = pycurl.CurlMulti()
+ t = []
+ searches = []
+ for a in range(100):
+ curl = pycurl.Curl()
+ multi.add_handle(curl)
+ t.append(curl)
+
+ match = regexp.search(repr(curl))
+ assert match is not None
+ searches.append(match.group(1))
+ match = regexp.search(repr(multi))
+ assert match
+ searches.append(match.group(1))
+
+ #print("Tracked objects:", len(gc.get_objects()))
+
+ for curl in t:
+ curl.close()
+ multi.remove_handle(curl)
+
+ #print("Tracked objects:", len(gc.get_objects()))
+
+ del curl
+ del t
+ del multi
+
+ #print("Tracked objects:", len(gc.get_objects()))
+ gc.collect()
+ #print("Tracked objects:", len(gc.get_objects()))
+
+ objects = gc.get_objects()
+ for search in searches:
+ assert 'at %s' % search not in repr(object)
--
1.7.1
From dd5650bb58e60c27fa32c27b5d39dbf5ad13c132 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Sun, 3 Mar 2013 03:06:26 -0500
Subject: [PATCH 034/112] Ported the first multi test
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/multi_test.py | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 56 insertions(+), 0 deletions(-)
create mode 100644 tests/multi_test.py
diff --git a/tests/multi_test.py b/tests/multi_test.py
new file mode 100644
index 0000000..4c0bdaf
--- /dev/null
+++ b/tests/multi_test.py
@@ -0,0 +1,56 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+
+import pycurl
+import unittest
+
+from . import app
+from . import runwsgi
+from . import util
+
+setup_module_1, teardown_module_1 = runwsgi.app_runner_setup((app.app, 8380))
+setup_module_2, teardown_module_2 = runwsgi.app_runner_setup((app.app, 8381))
+
+def setup_module(mod):
+ setup_module_1(mod)
+ setup_module_2(mod)
+
+def teardown_module(mod):
+ teardown_module_2(mod)
+ teardown_module_1(mod)
+
+class MultiTest(unittest.TestCase):
+ def test_multi(self):
+ io1 = util.StringIO()
+ io2 = util.StringIO()
+ m = pycurl.CurlMulti()
+ m.handles = []
+ c1 = pycurl.Curl()
+ c2 = pycurl.Curl()
+ c1.setopt(c1.URL, 'http://localhost:8380/success')
+ c1.setopt(c1.WRITEFUNCTION, io1.write)
+ c2.setopt(c2.URL, 'http://localhost:8381/success')
+ c2.setopt(c1.WRITEFUNCTION, io2.write)
+ m.add_handle(c1)
+ m.add_handle(c2)
+ m.handles.append(c1)
+ m.handles.append(c2)
+
+ num_handles = len(m.handles)
+ while num_handles:
+ while 1:
+ ret, num_handles = m.perform()
+ if ret != pycurl.E_CALL_MULTI_PERFORM:
+ break
+ m.select(1.0)
+
+ m.remove_handle(c2)
+ m.remove_handle(c1)
+ del m.handles
+ m.close()
+ c1.close()
+ c2.close()
+
+ self.assertEqual('success', io1.getvalue())
+ self.assertEqual('success', io2.getvalue())
--
1.7.1
From c651e8ab37cc21ab790b293ad00ad43a8a5e608f Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Sun, 3 Mar 2013 12:55:42 -0500
Subject: [PATCH 035/112] Port multi2 test
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/app.py | 8 +++++++
tests/multi_test.py | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 62 insertions(+), 0 deletions(-)
diff --git a/tests/app.py b/tests/app.py
index b173fd6..3b9303b 100644
--- a/tests/app.py
+++ b/tests/app.py
@@ -5,3 +5,11 @@ app = bottle.Bottle()
@app.route('/success')
def ok():
return 'success'
+
+@app.route('/status/403')
+def forbidden():
+ bottle.abort(403, 'forbidden')
+
+@app.route('/status/404')
+def not_found():
+ bottle.abort(404, 'not found')
diff --git a/tests/multi_test.py b/tests/multi_test.py
index 4c0bdaf..fd96e51 100644
--- a/tests/multi_test.py
+++ b/tests/multi_test.py
@@ -11,12 +11,15 @@ from . import util
setup_module_1, teardown_module_1 = runwsgi.app_runner_setup((app.app, 8380))
setup_module_2, teardown_module_2 = runwsgi.app_runner_setup((app.app, 8381))
+setup_module_3, teardown_module_3 = runwsgi.app_runner_setup((app.app, 8382))
def setup_module(mod):
setup_module_1(mod)
setup_module_2(mod)
+ setup_module_3(mod)
def teardown_module(mod):
+ teardown_module_3(mod)
teardown_module_2(mod)
teardown_module_1(mod)
@@ -54,3 +57,54 @@ class MultiTest(unittest.TestCase):
self.assertEqual('success', io1.getvalue())
self.assertEqual('success', io2.getvalue())
+
+ def test_multi_status_codes(self):
+ # init
+ m = pycurl.CurlMulti()
+ m.handles = []
+ urls = [
+ 'http://localhost:8380/success',
+ 'http://localhost:8381/status/403',
+ 'http://localhost:8382/status/404',
+ ]
+ for url in urls:
+ c = pycurl.Curl()
+ # save info in standard Python attributes
+ c.url = url.rstrip()
+ c.body = util.StringIO()
+ c.http_code = -1
+ m.handles.append(c)
+ # pycurl API calls
+ c.setopt(c.URL, c.url)
+ c.setopt(c.WRITEFUNCTION, c.body.write)
+ m.add_handle(c)
+
+ # get data
+ num_handles = len(m.handles)
+ while num_handles:
+ while 1:
+ ret, num_handles = m.perform()
+ if ret != pycurl.E_CALL_MULTI_PERFORM:
+ break
+ # currently no more I/O is pending, could do something in the meantime
+ # (display a progress bar, etc.)
+ m.select(0.1)
+
+ # close handles
+ for c in m.handles:
+ # save info in standard Python attributes
+ c.http_code = c.getinfo(c.HTTP_CODE)
+ # pycurl API calls
+ m.remove_handle(c)
+ c.close()
+ m.close()
+
+ # check result
+ self.assertEqual('success', m.handles[0].body.getvalue())
+ self.assertEqual(200, m.handles[0].http_code)
+ # bottle generated response body
+ assert 'Error 403: Forbidden' in m.handles[1].body.getvalue()
+ self.assertEqual(403, m.handles[1].http_code)
+ # bottle generated response body
+ assert 'Error 404: Not Found' in m.handles[2].body.getvalue()
+ self.assertEqual(404, m.handles[2].http_code)
--
1.7.1
From 18212fb2181a57e67988e7a336ac4b9c90e17d1a Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Sun, 3 Mar 2013 14:05:49 -0500
Subject: [PATCH 036/112] Porting multi3 test
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/multi_test.py | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 71 insertions(+), 0 deletions(-)
diff --git a/tests/multi_test.py b/tests/multi_test.py
index fd96e51..1c13f70 100644
--- a/tests/multi_test.py
+++ b/tests/multi_test.py
@@ -108,3 +108,74 @@ class MultiTest(unittest.TestCase):
# bottle generated response body
assert 'Error 404: Not Found' in m.handles[2].body.getvalue()
self.assertEqual(404, m.handles[2].http_code)
+
+ def test_adding_closed_handle(self):
+ # init
+ m = pycurl.CurlMulti()
+ m.handles = []
+ urls = [
+ 'http://localhost:8380/success',
+ 'http://localhost:8381/status/403',
+ 'http://localhost:8382/status/404',
+ ]
+ for url in urls:
+ c = pycurl.Curl()
+ # save info in standard Python attributes
+ c.url = url
+ c.body = util.StringIO()
+ c.http_code = -1
+ c.debug = 0
+ m.handles.append(c)
+ # pycurl API calls
+ c.setopt(c.URL, c.url)
+ c.setopt(c.WRITEFUNCTION, c.body.write)
+ m.add_handle(c)
+
+ # debug - close a handle
+ c = m.handles[2]
+ c.debug = 1
+ c.close()
+
+ # get data
+ num_handles = len(m.handles)
+ while num_handles:
+ while 1:
+ ret, num_handles = m.perform()
+ if ret != pycurl.E_CALL_MULTI_PERFORM:
+ break
+ # currently no more I/O is pending, could do something in the meantime
+ # (display a progress bar, etc.)
+ m.select(0.1)
+
+ # close handles
+ for c in m.handles:
+ # save info in standard Python attributes
+ try:
+ c.http_code = c.getinfo(c.HTTP_CODE)
+ except pycurl.error:
+ # handle already closed - see debug above
+ assert c.debug
+ c.http_code = -1
+ # pycurl API calls
+ if 0:
+ m.remove_handle(c)
+ c.close()
+ elif 0:
+ # in the C API this is the wrong calling order, but pycurl
+ # handles this automatically
+ c.close()
+ m.remove_handle(c)
+ else:
+ # actually, remove_handle is called automatically on close
+ c.close()
+ m.close()
+
+ # check result
+ self.assertEqual('success', m.handles[0].body.getvalue())
+ self.assertEqual(200, m.handles[0].http_code)
+ # bottle generated response body
+ assert 'Error 403: Forbidden' in m.handles[1].body.getvalue()
+ self.assertEqual(403, m.handles[1].http_code)
+ # bottle generated response body
+ self.assertEqual('', m.handles[2].body.getvalue())
+ self.assertEqual(-1, m.handles[2].http_code)
--
1.7.1
From 55b38bfbba56f6179633dc90f7cf3e72c3433b9f Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Sun, 3 Mar 2013 14:15:13 -0500
Subject: [PATCH 037/112] Exercise all 3 possibilites in ported multi3 test
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/multi_test.py | 37 +++++++++++++++++++++++++------------
1 files changed, 25 insertions(+), 12 deletions(-)
diff --git a/tests/multi_test.py b/tests/multi_test.py
index 1c13f70..e1fec05 100644
--- a/tests/multi_test.py
+++ b/tests/multi_test.py
@@ -109,7 +109,7 @@ class MultiTest(unittest.TestCase):
assert 'Error 404: Not Found' in m.handles[2].body.getvalue()
self.assertEqual(404, m.handles[2].http_code)
- def test_adding_closed_handle(self):
+ def check_adding_closed_handle(self, close_fn):
# init
m = pycurl.CurlMulti()
m.handles = []
@@ -157,17 +157,7 @@ class MultiTest(unittest.TestCase):
assert c.debug
c.http_code = -1
# pycurl API calls
- if 0:
- m.remove_handle(c)
- c.close()
- elif 0:
- # in the C API this is the wrong calling order, but pycurl
- # handles this automatically
- c.close()
- m.remove_handle(c)
- else:
- # actually, remove_handle is called automatically on close
- c.close()
+ close_fn(m, c)
m.close()
# check result
@@ -179,3 +169,26 @@ class MultiTest(unittest.TestCase):
# bottle generated response body
self.assertEqual('', m.handles[2].body.getvalue())
self.assertEqual(-1, m.handles[2].http_code)
+
+ def _remove_then_close(self, m, c):
+ m.remove_handle(c)
+ c.close()
+
+ def _close_then_remove(self, m, c):
+ # in the C API this is the wrong calling order, but pycurl
+ # handles this automatically
+ c.close()
+ m.remove_handle(c)
+
+ def _close_without_removing(self, m, c):
+ # actually, remove_handle is called automatically on close
+ c.close
+
+ def test_adding_closed_handle_remove_then_close(self):
+ self.check_adding_closed_handle(self._remove_then_close)
+
+ def test_adding_closed_handle_close_then_remove(self):
+ self.check_adding_closed_handle(self._close_then_remove)
+
+ def test_adding_closed_handle_close_without_removing(self):
+ self.check_adding_closed_handle(self._close_without_removing)
--
1.7.1
From 6ec826f66a9a86a2c1701e60a094d1f0004f9dff Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Sun, 3 Mar 2013 14:21:33 -0500
Subject: [PATCH 038/112] Port mulit4 test
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/multi_test.py | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 50 insertions(+), 0 deletions(-)
diff --git a/tests/multi_test.py b/tests/multi_test.py
index e1fec05..a508809 100644
--- a/tests/multi_test.py
+++ b/tests/multi_test.py
@@ -4,6 +4,7 @@
import pycurl
import unittest
+import select
from . import app
from . import runwsgi
@@ -58,6 +59,55 @@ class MultiTest(unittest.TestCase):
self.assertEqual('success', io1.getvalue())
self.assertEqual('success', io2.getvalue())
+ def test_multi_select_fdset(self):
+ c1 = pycurl.Curl()
+ c2 = pycurl.Curl()
+ c3 = pycurl.Curl()
+ c1.setopt(c1.URL, "http://localhost:8380/success")
+ c2.setopt(c2.URL, "http://localhost:8381/success")
+ c3.setopt(c3.URL, "http://localhost:8382/success")
+ c1.body = util.StringIO()
+ c2.body = util.StringIO()
+ c3.body = util.StringIO()
+ c1.setopt(c1.WRITEFUNCTION, c1.body.write)
+ c2.setopt(c2.WRITEFUNCTION, c2.body.write)
+ c3.setopt(c3.WRITEFUNCTION, c3.body.write)
+
+ m = pycurl.CurlMulti()
+ m.add_handle(c1)
+ m.add_handle(c2)
+ m.add_handle(c3)
+
+ # Number of seconds to wait for a timeout to happen
+ SELECT_TIMEOUT = 0.1
+
+ # Stir the state machine into action
+ while 1:
+ ret, num_handles = m.perform()
+ if ret != pycurl.E_CALL_MULTI_PERFORM:
+ break
+
+ # Keep going until all the connections have terminated
+ while num_handles:
+ select.select(*m.fdset() + (SELECT_TIMEOUT,))
+ while 1:
+ ret, num_handles = m.perform()
+ if ret != pycurl.E_CALL_MULTI_PERFORM:
+ break
+
+ # Cleanup
+ m.remove_handle(c3)
+ m.remove_handle(c2)
+ m.remove_handle(c1)
+ m.close()
+ c1.close()
+ c2.close()
+ c3.close()
+
+ self.assertEqual('success', c1.body.getvalue())
+ self.assertEqual('success', c2.body.getvalue())
+ self.assertEqual('success', c3.body.getvalue())
+
def test_multi_status_codes(self):
# init
m = pycurl.CurlMulti()
--
1.7.1
From b29ff271843da14e9b008e8853a3b84b06ed6ecc Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Tue, 5 Mar 2013 00:24:44 -0500
Subject: [PATCH 039/112] Port multit6 test
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/multi_test.py | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 55 insertions(+), 0 deletions(-)
diff --git a/tests/multi_test.py b/tests/multi_test.py
index a508809..e83ce48 100644
--- a/tests/multi_test.py
+++ b/tests/multi_test.py
@@ -242,3 +242,58 @@ class MultiTest(unittest.TestCase):
def test_adding_closed_handle_close_without_removing(self):
self.check_adding_closed_handle(self._close_without_removing)
+
+ def test_multi_info_read(self):
+ c1 = pycurl.Curl()
+ c2 = pycurl.Curl()
+ c3 = pycurl.Curl()
+ c1.setopt(c1.URL, "http://localhost:8380/success")
+ c2.setopt(c2.URL, "http://localhost:8381/success")
+ c3.setopt(c3.URL, "http://localhost:8382/success")
+ c1.body = util.StringIO()
+ c2.body = util.StringIO()
+ c3.body = util.StringIO()
+ c1.setopt(c1.WRITEFUNCTION, c1.body.write)
+ c2.setopt(c2.WRITEFUNCTION, c2.body.write)
+ c3.setopt(c3.WRITEFUNCTION, c3.body.write)
+
+ m = pycurl.CurlMulti()
+ m.add_handle(c1)
+ m.add_handle(c2)
+ m.add_handle(c3)
+
+ # Number of seconds to wait for a timeout to happen
+ SELECT_TIMEOUT = 1.0
+
+ # Stir the state machine into action
+ while 1:
+ ret, num_handles = m.perform()
+ if ret != pycurl.E_CALL_MULTI_PERFORM:
+ break
+
+ # Keep going until all the connections have terminated
+ while num_handles:
+ # The select method uses fdset internally to determine which file descriptors
+ # to check.
+ m.select(SELECT_TIMEOUT)
+ while 1:
+ ret, num_handles = m.perform()
+ # Print the message, if any
+ while True:
+ info = m.info_read()
+ print info
+ if ret != pycurl.E_CALL_MULTI_PERFORM:
+ break
+
+ # Cleanup
+ m.remove_handle(c3)
+ m.remove_handle(c2)
+ m.remove_handle(c1)
+ m.close()
+ c1.close()
+ c2.close()
+ c3.close()
+
+ self.assertEqual('success', c1.body.getvalue())
+ self.assertEqual('success', c2.body.getvalue())
+ self.assertEqual('success', c3.body.getvalue())
--
1.7.1
From a14adcb02e78aa26e1f6b326815a7a0ae824fc4d Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Tue, 5 Mar 2013 00:38:59 -0500
Subject: [PATCH 040/112] Improve info_read test to test info_read
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/multi_test.py | 19 +++++++++++++++----
1 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/tests/multi_test.py b/tests/multi_test.py
index e83ce48..10af44c 100644
--- a/tests/multi_test.py
+++ b/tests/multi_test.py
@@ -271,6 +271,7 @@ class MultiTest(unittest.TestCase):
if ret != pycurl.E_CALL_MULTI_PERFORM:
break
+ infos = []
# Keep going until all the connections have terminated
while num_handles:
# The select method uses fdset internally to determine which file descriptors
@@ -278,13 +279,23 @@ class MultiTest(unittest.TestCase):
m.select(SELECT_TIMEOUT)
while 1:
ret, num_handles = m.perform()
- # Print the message, if any
- while True:
- info = m.info_read()
- print info
+ info = m.info_read()
+ infos.append(info)
if ret != pycurl.E_CALL_MULTI_PERFORM:
break
+ all_handles = []
+ for info in infos:
+ handles = info[1]
+ # last info is an empty array
+ if handles:
+ all_handles.extend(handles)
+
+ self.assertEqual(3, len(all_handles))
+ assert c1 in all_handles
+ assert c2 in all_handles
+ assert c3 in all_handles
+
# Cleanup
m.remove_handle(c3)
m.remove_handle(c2)
--
1.7.1
From ef1510a4b5426b2fb0458ae244be17a578407fc7 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Tue, 5 Mar 2013 00:40:25 -0500
Subject: [PATCH 041/112] Port multi5 test
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/multi_test.py | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 51 insertions(+), 0 deletions(-)
diff --git a/tests/multi_test.py b/tests/multi_test.py
index 10af44c..d9c6174 100644
--- a/tests/multi_test.py
+++ b/tests/multi_test.py
@@ -243,6 +243,57 @@ class MultiTest(unittest.TestCase):
def test_adding_closed_handle_close_without_removing(self):
self.check_adding_closed_handle(self._close_without_removing)
+ def test_multi_select(self):
+ c1 = pycurl.Curl()
+ c2 = pycurl.Curl()
+ c3 = pycurl.Curl()
+ c1.setopt(c1.URL, "http://localhost:8380/success")
+ c2.setopt(c2.URL, "http://localhost:8381/success")
+ c3.setopt(c3.URL, "http://localhost:8382/success")
+ c1.body = util.StringIO()
+ c2.body = util.StringIO()
+ c3.body = util.StringIO()
+ c1.setopt(c1.WRITEFUNCTION, c1.body.write)
+ c2.setopt(c2.WRITEFUNCTION, c2.body.write)
+ c3.setopt(c3.WRITEFUNCTION, c3.body.write)
+
+ m = pycurl.CurlMulti()
+ m.add_handle(c1)
+ m.add_handle(c2)
+ m.add_handle(c3)
+
+ # Number of seconds to wait for a timeout to happen
+ SELECT_TIMEOUT = 1.0
+
+ # Stir the state machine into action
+ while 1:
+ ret, num_handles = m.perform()
+ if ret != pycurl.E_CALL_MULTI_PERFORM:
+ break
+
+ # Keep going until all the connections have terminated
+ while num_handles:
+ # The select method uses fdset internally to determine which file descriptors
+ # to check.
+ m.select(SELECT_TIMEOUT)
+ while 1:
+ ret, num_handles = m.perform()
+ if ret != pycurl.E_CALL_MULTI_PERFORM:
+ break
+
+ # Cleanup
+ m.remove_handle(c3)
+ m.remove_handle(c2)
+ m.remove_handle(c1)
+ m.close()
+ c1.close()
+ c2.close()
+ c3.close()
+
+ self.assertEqual('success', c1.body.getvalue())
+ self.assertEqual('success', c2.body.getvalue())
+ self.assertEqual('success', c3.body.getvalue())
+
def test_multi_info_read(self):
c1 = pycurl.Curl()
c2 = pycurl.Curl()
--
1.7.1
From 2a6f3d5ff191f6709fddfac3a2e0a6794a66f75d Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Tue, 5 Mar 2013 22:05:34 -0500
Subject: [PATCH 042/112] Ported test_multi_socket.py
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/multi_socket_test.py | 110 ++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 110 insertions(+), 0 deletions(-)
create mode 100644 tests/multi_socket_test.py
diff --git a/tests/multi_socket_test.py b/tests/multi_socket_test.py
new file mode 100644
index 0000000..2586569
--- /dev/null
+++ b/tests/multi_socket_test.py
@@ -0,0 +1,110 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+
+import pycurl
+import unittest
+import select
+
+from . import app
+from . import runwsgi
+from . import util
+
+setup_module_1, teardown_module_1 = runwsgi.app_runner_setup((app.app, 8380))
+setup_module_2, teardown_module_2 = runwsgi.app_runner_setup((app.app, 8381))
+setup_module_3, teardown_module_3 = runwsgi.app_runner_setup((app.app, 8382))
+
+def setup_module(mod):
+ setup_module_1(mod)
+ setup_module_2(mod)
+ setup_module_3(mod)
+
+def teardown_module(mod):
+ teardown_module_3(mod)
+ teardown_module_2(mod)
+ teardown_module_1(mod)
+
+class MultiSocketTest(unittest.TestCase):
+ def test_multi_socket(self):
+ urls = [
+ 'http://localhost:8380/success',
+ 'http://localhost:8381/success',
+ 'http://localhost:8382/success',
+ ]
+
+ timers = []
+
+ # timer callback
+ def timer(msecs):
+ #print('Timer callback msecs:', msecs)
+ timers.append(msecs)
+
+ socket_events = []
+
+ # socket callback
+ def socket(event, socket, multi, data):
+ #print(event, socket, multi, data)
+ # multi.assign(socket, timer)
+ socket_events.append((event, multi))
+
+ # init
+ m = pycurl.CurlMulti()
+ m.setopt(pycurl.M_PIPELINING, 1)
+ m.setopt(pycurl.M_TIMERFUNCTION, timer)
+ m.setopt(pycurl.M_SOCKETFUNCTION, socket)
+ m.handles = []
+ for url in urls:
+ c = pycurl.Curl()
+ # save info in standard Python attributes
+ c.url = url
+ c.body = util.StringIO()
+ c.http_code = -1
+ m.handles.append(c)
+ # pycurl API calls
+ c.setopt(c.URL, c.url)
+ c.setopt(c.WRITEFUNCTION, c.body.write)
+ m.add_handle(c)
+
+ # get data
+ num_handles = len(m.handles)
+ while num_handles:
+ while 1:
+ ret, num_handles = m.socket_all()
+ if ret != pycurl.E_CALL_MULTI_PERFORM:
+ break
+ # currently no more I/O is pending, could do something in the meantime
+ # (display a progress bar, etc.)
+ m.select(0.1)
+
+ for c in m.handles:
+ # save info in standard Python attributes
+ c.http_code = c.getinfo(c.HTTP_CODE)
+
+ # at least in and remove events per socket
+ assert len(socket_events) >= 6
+
+ # print result
+ for c in m.handles:
+ self.assertEqual('success', c.body.getvalue())
+ self.assertEqual(200, c.http_code)
+
+ # multi, not curl handle
+ self.check(pycurl.POLL_IN, m, socket_events)
+ self.check(pycurl.POLL_REMOVE, m, socket_events)
+
+ assert len(timers) > 0
+ assert timers[0] > 0
+ self.assertEqual(-1, timers[-1])
+
+ # close handles
+ for c in m.handles:
+ # pycurl API calls
+ m.remove_handle(c)
+ c.close()
+ m.close()
+
+ def check(self, event, multi, socket_events):
+ for event_, multi_ in socket_events:
+ if event == event_ and multi == multi_:
+ return
+ assert False, '%d %s not found in socket events' % (event, multi)
--
1.7.1
From 408772865075a389e89441afc44ae402bf87cae7 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Tue, 5 Mar 2013 22:29:45 -0500
Subject: [PATCH 043/112] Ported test_multi_socket_select.py
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/multi_socket_select_test.py | 130 +++++++++++++++++++++++++++++++++++++
1 files changed, 130 insertions(+), 0 deletions(-)
create mode 100644 tests/multi_socket_select_test.py
diff --git a/tests/multi_socket_select_test.py b/tests/multi_socket_select_test.py
new file mode 100644
index 0000000..b9ba950
--- /dev/null
+++ b/tests/multi_socket_select_test.py
@@ -0,0 +1,130 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+
+import pycurl
+import unittest
+import select
+
+from . import app
+from . import runwsgi
+from . import util
+
+setup_module_1, teardown_module_1 = runwsgi.app_runner_setup((app.app, 8380))
+setup_module_2, teardown_module_2 = runwsgi.app_runner_setup((app.app, 8381))
+setup_module_3, teardown_module_3 = runwsgi.app_runner_setup((app.app, 8382))
+
+def setup_module(mod):
+ setup_module_1(mod)
+ setup_module_2(mod)
+ setup_module_3(mod)
+
+def teardown_module(mod):
+ teardown_module_3(mod)
+ teardown_module_2(mod)
+ teardown_module_1(mod)
+
+class MultiSocketSelectTest(unittest.TestCase):
+ def test_multi_socket_select(self):
+ sockets = set()
+ timeout = 0
+
+ urls = [
+ 'http://localhost:8380/success',
+ 'http://localhost:8381/success',
+ 'http://localhost:8382/success',
+ ]
+
+ timers = []
+
+ # timer callback
+ def timer(msecs):
+ #print('Timer callback msecs:', msecs)
+ timers.append(msecs)
+
+ socket_events = []
+
+ # socket callback
+ def socket(event, socket, multi, data):
+ if event == pycurl.POLL_REMOVE:
+ #print("Remove Socket %d"%socket)
+ sockets.remove(socket)
+ else:
+ if socket not in sockets:
+ #print("Add socket %d"%socket)
+ sockets.add(socket)
+ socket_events.append((event, multi))
+
+ # init
+ m = pycurl.CurlMulti()
+ m.setopt(pycurl.M_PIPELINING, 1)
+ m.setopt(pycurl.M_TIMERFUNCTION, timer)
+ m.setopt(pycurl.M_SOCKETFUNCTION, socket)
+ m.handles = []
+ for url in urls:
+ c = pycurl.Curl()
+ # save info in standard Python attributes
+ c.url = url
+ c.body = util.StringIO()
+ c.http_code = -1
+ m.handles.append(c)
+ # pycurl API calls
+ c.setopt(c.URL, c.url)
+ c.setopt(c.WRITEFUNCTION, c.body.write)
+ m.add_handle(c)
+
+ # get data
+ num_handles = len(m.handles)
+
+ while (pycurl.E_CALL_MULTI_PERFORM==m.socket_all()[0]):
+ pass
+
+ timeout = m.timeout()
+
+
+ while True:
+ (rr, wr, er) = select.select(sockets,sockets,sockets,timeout/1000.0)
+ socketSet = set(rr+wr+er)
+ if socketSet:
+ for s in socketSet:
+ while True:
+ (ret,running) = m.socket_action(s,0)
+ if ret!=pycurl.E_CALL_MULTI_PERFORM:
+ break
+ else:
+ (ret,running) = m.socket_action(pycurl.SOCKET_TIMEOUT,0)
+ if running==0:
+ break
+
+ for c in m.handles:
+ # save info in standard Python attributes
+ c.http_code = c.getinfo(c.HTTP_CODE)
+
+ # at least in and remove events per socket
+ assert len(socket_events) >= 6
+
+ # print result
+ for c in m.handles:
+ self.assertEqual('success', c.body.getvalue())
+ self.assertEqual(200, c.http_code)
+
+ # multi, not curl handle
+ self.check(pycurl.POLL_IN, m, socket_events)
+ self.check(pycurl.POLL_REMOVE, m, socket_events)
+
+ assert len(timers) > 0
+ assert timers[0] > 0
+ self.assertEqual(-1, timers[-1])
+
+ # close handles
+ for c in m.handles:
+ # pycurl API calls
+ m.remove_handle(c)
+ c.close()
+ m.close()
+
+ def check(self, event, multi, socket_events):
+ for event_, multi_ in socket_events:
+ if event == event_ and multi == multi_:
+ return
+ assert False, '%d %s not found in socket events' % (event, multi)
--
1.7.1
From b9fc3bbb01affc790d94801556275e853d03c2c0 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Tue, 5 Mar 2013 23:15:47 -0500
Subject: [PATCH 044/112] Ported test_multi_timer.py
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/multi_timer_test.py | 88 +++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 88 insertions(+), 0 deletions(-)
create mode 100644 tests/multi_timer_test.py
diff --git a/tests/multi_timer_test.py b/tests/multi_timer_test.py
new file mode 100644
index 0000000..e961780
--- /dev/null
+++ b/tests/multi_timer_test.py
@@ -0,0 +1,88 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+
+import pycurl
+import unittest
+import select
+
+from . import app
+from . import runwsgi
+from . import util
+
+setup_module_1, teardown_module_1 = runwsgi.app_runner_setup((app.app, 8380))
+setup_module_2, teardown_module_2 = runwsgi.app_runner_setup((app.app, 8381))
+setup_module_3, teardown_module_3 = runwsgi.app_runner_setup((app.app, 8382))
+
+def setup_module(mod):
+ setup_module_1(mod)
+ setup_module_2(mod)
+ setup_module_3(mod)
+
+def teardown_module(mod):
+ teardown_module_3(mod)
+ teardown_module_2(mod)
+ teardown_module_1(mod)
+
+class MultiSocketTest(unittest.TestCase):
+ def test_multi_timer(self):
+ urls = [
+ 'http://localhost:8380/success',
+ 'http://localhost:8381/success',
+ 'http://localhost:8382/success',
+ ]
+
+ timers = []
+
+ # timer callback
+ def timer(msecs):
+ #print('Timer callback msecs:', msecs)
+ timers.append(msecs)
+
+ # init
+ m = pycurl.CurlMulti()
+ m.setopt(pycurl.M_PIPELINING, 1)
+ m.setopt(pycurl.M_TIMERFUNCTION, timer)
+ m.handles = []
+ for url in urls:
+ c = pycurl.Curl()
+ # save info in standard Python attributes
+ c.url = url
+ c.body = util.StringIO()
+ c.http_code = -1
+ m.handles.append(c)
+ # pycurl API calls
+ c.setopt(c.URL, c.url)
+ c.setopt(c.WRITEFUNCTION, c.body.write)
+ m.add_handle(c)
+
+ # get data
+ num_handles = len(m.handles)
+ while num_handles:
+ while 1:
+ ret, num_handles = m.perform()
+ if ret != pycurl.E_CALL_MULTI_PERFORM:
+ break
+ # currently no more I/O is pending, could do something in the meantime
+ # (display a progress bar, etc.)
+ m.select(1.0)
+
+ for c in m.handles:
+ # save info in standard Python attributes
+ c.http_code = c.getinfo(c.HTTP_CODE)
+
+ # print result
+ for c in m.handles:
+ self.assertEqual('success', c.body.getvalue())
+ self.assertEqual(200, c.http_code)
+
+ assert len(timers) > 0
+ assert timers[0] > 0
+ self.assertEqual(-1, timers[-1])
+
+ # close handles
+ for c in m.handles:
+ # pycurl API calls
+ m.remove_handle(c)
+ c.close()
+ m.close()
--
1.7.1
From 1411a22bd02d30b7a0dc884ad406fdb4169e1307 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Tue, 5 Mar 2013 23:17:14 -0500
Subject: [PATCH 045/112] Timers are tested in multi_timer test, delete them from other multi tests
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/multi_socket_select_test.py | 12 ------------
tests/multi_socket_test.py | 13 -------------
2 files changed, 0 insertions(+), 25 deletions(-)
diff --git a/tests/multi_socket_select_test.py b/tests/multi_socket_select_test.py
index b9ba950..0c472cf 100644
--- a/tests/multi_socket_select_test.py
+++ b/tests/multi_socket_select_test.py
@@ -35,13 +35,6 @@ class MultiSocketSelectTest(unittest.TestCase):
'http://localhost:8382/success',
]
- timers = []
-
- # timer callback
- def timer(msecs):
- #print('Timer callback msecs:', msecs)
- timers.append(msecs)
-
socket_events = []
# socket callback
@@ -58,7 +51,6 @@ class MultiSocketSelectTest(unittest.TestCase):
# init
m = pycurl.CurlMulti()
m.setopt(pycurl.M_PIPELINING, 1)
- m.setopt(pycurl.M_TIMERFUNCTION, timer)
m.setopt(pycurl.M_SOCKETFUNCTION, socket)
m.handles = []
for url in urls:
@@ -112,10 +104,6 @@ class MultiSocketSelectTest(unittest.TestCase):
self.check(pycurl.POLL_IN, m, socket_events)
self.check(pycurl.POLL_REMOVE, m, socket_events)
- assert len(timers) > 0
- assert timers[0] > 0
- self.assertEqual(-1, timers[-1])
-
# close handles
for c in m.handles:
# pycurl API calls
diff --git a/tests/multi_socket_test.py b/tests/multi_socket_test.py
index 2586569..2cce7ae 100644
--- a/tests/multi_socket_test.py
+++ b/tests/multi_socket_test.py
@@ -32,25 +32,16 @@ class MultiSocketTest(unittest.TestCase):
'http://localhost:8382/success',
]
- timers = []
-
- # timer callback
- def timer(msecs):
- #print('Timer callback msecs:', msecs)
- timers.append(msecs)
-
socket_events = []
# socket callback
def socket(event, socket, multi, data):
#print(event, socket, multi, data)
- # multi.assign(socket, timer)
socket_events.append((event, multi))
# init
m = pycurl.CurlMulti()
m.setopt(pycurl.M_PIPELINING, 1)
- m.setopt(pycurl.M_TIMERFUNCTION, timer)
m.setopt(pycurl.M_SOCKETFUNCTION, socket)
m.handles = []
for url in urls:
@@ -92,10 +83,6 @@ class MultiSocketTest(unittest.TestCase):
self.check(pycurl.POLL_IN, m, socket_events)
self.check(pycurl.POLL_REMOVE, m, socket_events)
- assert len(timers) > 0
- assert timers[0] > 0
- self.assertEqual(-1, timers[-1])
-
# close handles
for c in m.handles:
# pycurl API calls
--
1.7.1
From dae1d75a3c083cc5c37cefff47d185ed0bf16af6 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Tue, 5 Mar 2013 23:30:48 -0500
Subject: [PATCH 046/112] Ported post test
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/app.py | 5 +++++
tests/post_test.py | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 54 insertions(+), 0 deletions(-)
create mode 100644 tests/post_test.py
diff --git a/tests/app.py b/tests/app.py
index 3b9303b..1fa09a6 100644
--- a/tests/app.py
+++ b/tests/app.py
@@ -1,4 +1,5 @@
import bottle
+import json
app = bottle.Bottle()
@@ -13,3 +14,7 @@ def forbidden():
@app.route('/status/404')
def not_found():
bottle.abort(404, 'not found')
+
+@app.route('/postfields', method='post')
+def postfields():
+ return json.dumps(dict(bottle.request.forms))
diff --git a/tests/post_test.py b/tests/post_test.py
new file mode 100644
index 0000000..183c4c9
--- /dev/null
+++ b/tests/post_test.py
@@ -0,0 +1,49 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+
+import pycurl
+import unittest
+import io
+import json
+try:
+ import urllib.parse as urllib_parse
+except ImportError:
+ import urllib as urllib_parse
+
+from . import app
+from . import runwsgi
+from . import util
+
+setup_module, teardown_module = runwsgi.app_runner_setup((app.app, 8380))
+
+class PostTest(unittest.TestCase):
+ def setUp(self):
+ self.curl = pycurl.Curl()
+
+ def tearDown(self):
+ self.curl.close()
+
+ def test_post_single_field(self):
+ pf = {'field1': 'value1'}
+ self.check(pf)
+
+ def test_post_multiple_fields(self):
+ pf = {'field1':'value1', 'field2':'value2 with blanks', 'field3':'value3'}
+ self.check(pf)
+
+ def test_post_fields_with_ampersand(self):
+ pf = {'field1':'value1', 'field2':'value2 with blanks and & chars',
+ 'field3':'value3'}
+ self.check(pf)
+
+ def check(self, pf):
+ self.curl.setopt(pycurl.URL, 'http://localhost:8380/postfields')
+ self.curl.setopt(pycurl.POSTFIELDS, urllib_parse.urlencode(pf))
+ #self.curl.setopt(pycurl.VERBOSE, 1)
+ sio = util.StringIO()
+ self.curl.setopt(pycurl.WRITEFUNCTION, sio.write)
+ self.curl.perform()
+ body = sio.getvalue()
+ returned_fields = json.loads(body)
+ self.assertEqual(pf, returned_fields)
--
1.7.1
From 453c605a6a0ab5b04d5d1e2cf70cd99a4fd9db18 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Tue, 5 Mar 2013 23:35:02 -0500
Subject: [PATCH 047/112] Port test_post2.py null byte test
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/post_test.py | 28 ++++++++++++++++++++++++----
1 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/tests/post_test.py b/tests/post_test.py
index 183c4c9..6f9cf80 100644
--- a/tests/post_test.py
+++ b/tests/post_test.py
@@ -26,18 +26,18 @@ class PostTest(unittest.TestCase):
def test_post_single_field(self):
pf = {'field1': 'value1'}
- self.check(pf)
+ self.urlencode_and_check(pf)
def test_post_multiple_fields(self):
pf = {'field1':'value1', 'field2':'value2 with blanks', 'field3':'value3'}
- self.check(pf)
+ self.urlencode_and_check(pf)
def test_post_fields_with_ampersand(self):
pf = {'field1':'value1', 'field2':'value2 with blanks and & chars',
'field3':'value3'}
- self.check(pf)
+ self.urlencode_and_check(pf)
- def check(self, pf):
+ def urlencode_and_check(self, pf):
self.curl.setopt(pycurl.URL, 'http://localhost:8380/postfields')
self.curl.setopt(pycurl.POSTFIELDS, urllib_parse.urlencode(pf))
#self.curl.setopt(pycurl.VERBOSE, 1)
@@ -47,3 +47,23 @@ class PostTest(unittest.TestCase):
body = sio.getvalue()
returned_fields = json.loads(body)
self.assertEqual(pf, returned_fields)
+
+ def test_post_with_null_byte(self):
+ send = [
+ ('field3', (pycurl.FORM_CONTENTS, 'this is wei\000rd, but null-bytes are okay'))
+ ]
+ expect = {
+ 'field3': 'this is wei\000rd, but null-bytes are okay',
+ }
+ self.check_post(send, expect)
+
+ def check_post(self, send, expect):
+ self.curl.setopt(pycurl.URL, 'http://localhost:8380/postfields')
+ self.curl.setopt(pycurl.HTTPPOST, send)
+ #self.curl.setopt(pycurl.VERBOSE, 1)
+ sio = util.StringIO()
+ self.curl.setopt(pycurl.WRITEFUNCTION, sio.write)
+ self.curl.perform()
+ body = sio.getvalue()
+ returned_fields = json.loads(body)
+ self.assertEqual(expect, returned_fields)
--
1.7.1
From 7b1e54bf72d209964ba47f5bfa8f8b192b697632 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Tue, 5 Mar 2013 23:50:51 -0500
Subject: [PATCH 048/112] Port test_post2.py file upload test
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/app.py | 24 ++++++++++++++++++++++++
tests/post_test.py | 22 +++++++++++++++++++---
2 files changed, 43 insertions(+), 3 deletions(-)
diff --git a/tests/app.py b/tests/app.py
index 1fa09a6..a83e628 100644
--- a/tests/app.py
+++ b/tests/app.py
@@ -18,3 +18,27 @@ def not_found():
@app.route('/postfields', method='post')
def postfields():
return json.dumps(dict(bottle.request.forms))
+
+# XXX file is not a bottle FileUpload instance, but FieldStorage?
+def convert_file(key, file):
+ return {
+ 'key': key,
+ 'name': file.name,
+ 'raw_filename': file.raw_filename,
+ 'headers': file.headers,
+ 'content_type': file.content_type,
+ 'content_length': file.content_length,
+ 'data': file.read(),
+ }
+
+def convert_file(key, file):
+ return {
+ 'name': file.name,
+ 'filename': file.filename,
+ 'data': file.file.read(),
+ }
+
+@app.route('/files', method='post')
+def files():
+ files = [convert_file(key, bottle.request.files[key]) for key in bottle.request.files]
+ return json.dumps(files)
diff --git a/tests/post_test.py b/tests/post_test.py
index 6f9cf80..7df0f3b 100644
--- a/tests/post_test.py
+++ b/tests/post_test.py
@@ -2,6 +2,7 @@
# -*- coding: iso-8859-1 -*-
# vi:ts=4:et
+import os.path
import pycurl
import unittest
import io
@@ -55,10 +56,25 @@ class PostTest(unittest.TestCase):
expect = {
'field3': 'this is wei\000rd, but null-bytes are okay',
}
- self.check_post(send, expect)
+ self.check_post(send, expect, 'http://localhost:8380/postfields')
- def check_post(self, send, expect):
- self.curl.setopt(pycurl.URL, 'http://localhost:8380/postfields')
+ def test_post_file(self):
+ path = os.path.join(os.path.dirname(__file__), '..', 'README')
+ with open(path) as f:
+ contents = f.read()
+ send = [
+ #('field2', (pycurl.FORM_FILE, 'test_post.py', pycurl.FORM_FILE, 'test_post2.py')),
+ ('field2', (pycurl.FORM_FILE, path)),
+ ]
+ expect = [{
+ 'name': 'field2',
+ 'filename': 'README',
+ 'data': contents,
+ }]
+ self.check_post(send, expect, 'http://localhost:8380/files')
+
+ def check_post(self, send, expect, endpoint):
+ self.curl.setopt(pycurl.URL, endpoint)
self.curl.setopt(pycurl.HTTPPOST, send)
#self.curl.setopt(pycurl.VERBOSE, 1)
sio = util.StringIO()
--
1.7.1
From f48bdb27952ad5e38f8c259711a514e146ff454c Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Tue, 5 Mar 2013 23:51:45 -0500
Subject: [PATCH 049/112] Add a note that this test takes forever to run
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/post_test.py | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/tests/post_test.py b/tests/post_test.py
index 7df0f3b..564d043 100644
--- a/tests/post_test.py
+++ b/tests/post_test.py
@@ -73,6 +73,7 @@ class PostTest(unittest.TestCase):
}]
self.check_post(send, expect, 'http://localhost:8380/files')
+ # XXX this test takes about a second to run, check keep-alives?
def check_post(self, send, expect, endpoint):
self.curl.setopt(pycurl.URL, endpoint)
self.curl.setopt(pycurl.HTTPPOST, send)
--
1.7.1
From e276465088c1bfa8141417c1d8375de2c5a969a2 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Tue, 5 Mar 2013 23:59:04 -0500
Subject: [PATCH 050/112] Ported test_post3.py
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/post_with_read_callback_test.py | 60 +++++++++++++++++++++++++++++++++
1 files changed, 60 insertions(+), 0 deletions(-)
create mode 100644 tests/post_with_read_callback_test.py
diff --git a/tests/post_with_read_callback_test.py b/tests/post_with_read_callback_test.py
new file mode 100644
index 0000000..a09e83a
--- /dev/null
+++ b/tests/post_with_read_callback_test.py
@@ -0,0 +1,60 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+
+import os.path
+import pycurl
+import unittest
+import io
+import json
+try:
+ import urllib.parse as urllib_parse
+except ImportError:
+ import urllib as urllib_parse
+
+from . import app
+from . import runwsgi
+from . import util
+
+setup_module, teardown_module = runwsgi.app_runner_setup((app.app, 8380))
+
+POSTFIELDS = {
+ 'field1':'value1',
+ 'field2':'value2 with blanks',
+ 'field3':'value3',
+}
+POSTSTRING = urllib_parse.urlencode(POSTFIELDS)
+
+class DataProvider(object):
+ def __init__(self):
+ self.finished = False
+
+ def read_cb(self, size):
+ assert len(POSTSTRING) <= size
+ if not self.finished:
+ self.finished = True
+ return POSTSTRING
+ else:
+ # Nothing more to read
+ return ""
+
+class PostWithReadCallbackTest(unittest.TestCase):
+ def setUp(self):
+ self.curl = pycurl.Curl()
+
+ def tearDown(self):
+ self.curl.close()
+
+ def test_post_with_read_callback(self):
+ d = DataProvider()
+ self.curl.setopt(self.curl.URL, 'http://localhost:8380/postfields')
+ self.curl.setopt(self.curl.POST, 1)
+ self.curl.setopt(self.curl.POSTFIELDSIZE, len(POSTSTRING))
+ self.curl.setopt(self.curl.READFUNCTION, d.read_cb)
+ #self.curl.setopt(self.curl.VERBOSE, 1)
+ sio = util.StringIO()
+ self.curl.setopt(pycurl.WRITEFUNCTION, sio.write)
+ self.curl.perform()
+
+ actual = json.loads(sio.getvalue())
+ self.assertEqual(POSTFIELDS, actual)
--
1.7.1
From bff1fa53c2c59ee0a31e3bb73d20eb56cf0305d4 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 00:10:41 -0500
Subject: [PATCH 051/112] Ported test_socketopen.py
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/socket_open_test.py | 45 +++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 45 insertions(+), 0 deletions(-)
create mode 100644 tests/socket_open_test.py
diff --git a/tests/socket_open_test.py b/tests/socket_open_test.py
new file mode 100644
index 0000000..dff3f65
--- /dev/null
+++ b/tests/socket_open_test.py
@@ -0,0 +1,45 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+
+import socket
+import pycurl
+import unittest
+try:
+ import urllib.parse as urllib_parse
+except ImportError:
+ import urllib as urllib_parse
+
+from . import app
+from . import runwsgi
+from . import util
+
+setup_module, teardown_module = runwsgi.app_runner_setup((app.app, 8380))
+
+socket_open_called = False
+
+def socket_open(family, socktype, protocol):
+ global socket_open_called
+ socket_open_called = True
+
+ #print(family, socktype, protocol)
+ s = socket.socket(family, socktype, protocol)
+ s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
+ return s
+
+class SocketOpenTest(unittest.TestCase):
+ def setUp(self):
+ self.curl = pycurl.Curl()
+
+ def tearDown(self):
+ self.curl.close()
+
+ def test_socket_open(self):
+ self.curl.setopt(pycurl.OPENSOCKETFUNCTION, socket_open)
+ self.curl.setopt(self.curl.URL, 'http://localhost:8380/success')
+ sio = util.StringIO()
+ self.curl.setopt(pycurl.WRITEFUNCTION, sio.write)
+ self.curl.perform()
+
+ assert socket_open_called
+ self.assertEqual('success', sio.getvalue())
--
1.7.1
From 3336fa0310f6f030f8a9e27009c42e1b560d3a43 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 00:13:46 -0500
Subject: [PATCH 052/112] Ported test_share.py
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/share_test.py | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 51 insertions(+), 0 deletions(-)
create mode 100644 tests/share_test.py
diff --git a/tests/share_test.py b/tests/share_test.py
new file mode 100644
index 0000000..7b5da77
--- /dev/null
+++ b/tests/share_test.py
@@ -0,0 +1,51 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+
+import threading
+import pycurl
+import unittest
+try:
+ import urllib.parse as urllib_parse
+except ImportError:
+ import urllib as urllib_parse
+
+from . import app
+from . import runwsgi
+from . import util
+
+setup_module, teardown_module = runwsgi.app_runner_setup((app.app, 8380))
+
+class WorkerThread(threading.Thread):
+
+ def __init__(self, share):
+ threading.Thread.__init__(self)
+ self.curl = pycurl.Curl()
+ self.curl.setopt(pycurl.URL, 'http://localhost:8380/success')
+ self.curl.setopt(pycurl.SHARE, share)
+ self.sio = util.StringIO()
+ self.curl.setopt(pycurl.WRITEFUNCTION, self.sio.write)
+
+ def run(self):
+ self.curl.perform()
+ self.curl.close()
+
+class ShareTest(unittest.TestCase):
+ def test_share(self):
+ s = pycurl.CurlShare()
+ s.setopt(pycurl.SH_SHARE, pycurl.LOCK_DATA_COOKIE)
+ s.setopt(pycurl.SH_SHARE, pycurl.LOCK_DATA_DNS)
+
+ t1 = WorkerThread(s)
+ t2 = WorkerThread(s)
+
+ t1.start()
+ t2.start()
+
+ t1.join()
+ t2.join()
+
+ del s
+
+ self.assertEqual('success', t1.sio.getvalue())
+ self.assertEqual('success', t2.sio.getvalue())
--
1.7.1
From 1a601a915a969434e1c707e3d17e302b1c7421a5 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 00:26:45 -0500
Subject: [PATCH 053/112] Port test_reset.py, which appears to be broken; skip the ported version for now
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/reset_test.py | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 76 insertions(+), 0 deletions(-)
create mode 100644 tests/reset_test.py
diff --git a/tests/reset_test.py b/tests/reset_test.py
new file mode 100644
index 0000000..66b7108
--- /dev/null
+++ b/tests/reset_test.py
@@ -0,0 +1,76 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+
+import sys
+import pycurl
+import unittest
+try:
+ import urllib.parse as urllib_parse
+except ImportError:
+ import urllib as urllib_parse
+
+from . import app
+from . import runwsgi
+from . import util
+
+setup_module, teardown_module = runwsgi.app_runner_setup((app.app, 8380))
+
+class ResetTest(unittest.TestCase):
+ # XXX this test was broken when it was test_reset.py
+ def skip_test_reset(self):
+ outf = util.StringIO()
+ cm = pycurl.CurlMulti()
+
+ # Set multi handle's options
+ cm.setopt(pycurl.M_PIPELINING, 1)
+
+ eh = pycurl.Curl()
+
+ for x in range(1, 20):
+
+ eh.setopt(pycurl.WRITEFUNCTION, outf.write)
+ eh.setopt(pycurl.URL, 'http://localhost:8380/success')
+ cm.add_handle(eh)
+
+ while 1:
+ ret, active_handles = cm.perform()
+ if ret != pycurl.E_CALL_MULTI_PERFORM:
+ break
+
+ while active_handles:
+ ret = cm.select(1.0)
+ if ret == -1:
+ continue
+ while 1:
+ ret, active_handles = cm.perform()
+ if ret != pycurl.E_CALL_MULTI_PERFORM:
+ break
+
+ count, good, bad = cm.info_read()
+
+ for h, en, em in bad:
+ print("Transfer to %s failed with %d, %s\n" % \
+ (h.getinfo(pycurl.EFFECTIVE_URL), en, em))
+ raise RuntimeError
+
+ for h in good:
+ httpcode = h.getinfo(pycurl.RESPONSE_CODE)
+ if httpcode != 200:
+ print("Transfer to %s failed with code %d\n" %\
+ (h.getinfo(pycurl.EFFECTIVE_URL), httpcode))
+ raise RuntimeError
+
+ else:
+ print("Recd %d bytes from %s" % \
+ (h.getinfo(pycurl.SIZE_DOWNLOAD),
+ h.getinfo(pycurl.EFFECTIVE_URL)))
+
+ cm.remove_handle(eh)
+ eh.reset()
+
+ eh.close()
+ cm.close()
+ outf.close()
+
+ pycurl.global_cleanup()
--
1.7.1
From 4c6a41a2156ef35f9f06f604101bc12422806eed Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 00:55:41 -0500
Subject: [PATCH 054/112] Start a server on each port once, different servers should go on different ports
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/runwsgi.py | 9 ++++++++-
1 files changed, 8 insertions(+), 1 deletions(-)
diff --git a/tests/runwsgi.py b/tests/runwsgi.py
index 7b39358..6d3b69f 100644
--- a/tests/runwsgi.py
+++ b/tests/runwsgi.py
@@ -48,6 +48,8 @@ class ServerThread(threading.Thread):
def run(self):
bottle.run(self.app, server=self.server, quiet=True)
+started_servers = {}
+
def app_runner_setup(*specs):
'''Returns setup and teardown methods for running a list of WSGI
applications in a daemon thread.
@@ -73,9 +75,14 @@ def app_runner_setup(*specs):
kwargs = {}
else:
app, port, kwargs = spec
- self.servers.append(start_bottle_server(app, port, **kwargs))
+ if port in started_servers:
+ assert started_servers[port] == (app, kwargs)
+ else:
+ self.servers.append(start_bottle_server(app, port, **kwargs))
+ started_servers[port] = (app, kwargs)
def teardown(self):
+ return
for server in self.servers:
# if no tests from module were run, there is no server to shut down
if hasattr(server, 'srv'):
--
1.7.1
From 5e561de2fcf5cab18d29063b778ea24d61ce8b0e Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 00:56:44 -0500
Subject: [PATCH 055/112] Need to skip more aggressively it would seem
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/default_write_function_test.py | 2 +-
tests/reset_test.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/tests/default_write_function_test.py b/tests/default_write_function_test.py
index a0de66e..c0d256b 100644
--- a/tests/default_write_function_test.py
+++ b/tests/default_write_function_test.py
@@ -40,7 +40,7 @@ class DefaultWriteFunctionTest(unittest.TestCase):
os.fsync(STDOUT_FD_NUM)
# I have a really hard time getting this to work with nose output capture
- def skip_test_perform_get_with_default_write_function(self):
+ def skip_perform_get_with_default_write_function(self):
self.curl.setopt(pycurl.URL, 'http://localhost:8380/success')
with tempfile.NamedTemporaryFile() as f:
#with open('w', 'w+') as f:
diff --git a/tests/reset_test.py b/tests/reset_test.py
index 66b7108..cc55f86 100644
--- a/tests/reset_test.py
+++ b/tests/reset_test.py
@@ -18,7 +18,7 @@ setup_module, teardown_module = runwsgi.app_runner_setup((app.app, 8380))
class ResetTest(unittest.TestCase):
# XXX this test was broken when it was test_reset.py
- def skip_test_reset(self):
+ def skip_reset(self):
outf = util.StringIO()
cm = pycurl.CurlMulti()
--
1.7.1
From 136485fea353fb6b2c63bf8ea313187835852d11 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 01:29:59 -0500
Subject: [PATCH 056/112] Store urlencode result in a local variable, otherwise things break in a highly weird way
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/post_test.py | 24 +++++++++++++++++++++++-
1 files changed, 23 insertions(+), 1 deletions(-)
diff --git a/tests/post_test.py b/tests/post_test.py
index 564d043..e8b0675 100644
--- a/tests/post_test.py
+++ b/tests/post_test.py
@@ -40,11 +40,33 @@ class PostTest(unittest.TestCase):
def urlencode_and_check(self, pf):
self.curl.setopt(pycurl.URL, 'http://localhost:8380/postfields')
- self.curl.setopt(pycurl.POSTFIELDS, urllib_parse.urlencode(pf))
+ postfields = urllib_parse.urlencode(pf)
+ self.curl.setopt(pycurl.POSTFIELDS, postfields)
+
+ # But directly passing urlencode result into setopt call:
+ #self.curl.setopt(pycurl.POSTFIELDS, urllib_parse.urlencode(pf))
+ # produces:
+ # {'\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00': ''}
+ # Traceback (most recent call last):
+ # File "/usr/local/bin/bottle.py", line 744, in _handle
+ # return route.call(**args)
+ # File "/usr/local/bin/bottle.py", line 1479, in wrapper
+ # rv = callback(*a, **ka)
+ # File "/home/pie/apps/pycurl/tests/app.py", line 21, in postfields
+ # return json.dumps(dict(bottle.request.forms))
+ # File "/usr/local/lib/python2.7/json/__init__.py", line 231, in dumps
+ # return _default_encoder.encode(obj)
+ # File "/usr/local/lib/python2.7/json/encoder.py", line 201, in encode
+ # chunks = self.iterencode(o, _one_shot=True)
+ # File "/usr/local/lib/python2.7/json/encoder.py", line 264, in iterencode
+ # return _iterencode(o, 0)
+ # UnicodeDecodeError: 'utf8' codec can't decode byte 0x80 in position 4: invalid start byte
+
#self.curl.setopt(pycurl.VERBOSE, 1)
sio = util.StringIO()
self.curl.setopt(pycurl.WRITEFUNCTION, sio.write)
self.curl.perform()
+ self.assertEqual(200, self.curl.getinfo(pycurl.HTTP_CODE))
body = sio.getvalue()
returned_fields = json.loads(body)
self.assertEqual(pf, returned_fields)
--
1.7.1
From f456a8e787078a333c2465a1bb4b4bae2a76be9f Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 01:32:33 -0500
Subject: [PATCH 057/112] Fix regular expression to allow all hex chars like it should
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/internals_test.py | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/tests/internals_test.py b/tests/internals_test.py
index fb451df..f628ab2 100644
--- a/tests/internals_test.py
+++ b/tests/internals_test.py
@@ -180,7 +180,7 @@ class InternalsTest(unittest.TestCase):
del m, c
def test_cyclic_gc(self):
- regexp = re.compile(r'at (0x\d+)')
+ regexp = re.compile(r'at (0x[\da-f]+)')
gc.collect()
c = pycurl.Curl()
c.m = pycurl.CurlMulti()
--
1.7.1
From c321100736f098850b3b6c2b75fbf7355ae635ce Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 01:36:48 -0500
Subject: [PATCH 058/112] Rewrite cyclic gc test to use id()
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/internals_test.py | 9 ++-------
1 files changed, 2 insertions(+), 7 deletions(-)
diff --git a/tests/internals_test.py b/tests/internals_test.py
index f628ab2..0133da0 100644
--- a/tests/internals_test.py
+++ b/tests/internals_test.py
@@ -12,7 +12,6 @@ except ImportError:
import pickle
import gc
import copy
-import re
class InternalsTest(unittest.TestCase):
def setUp(self):
@@ -180,7 +179,6 @@ class InternalsTest(unittest.TestCase):
del m, c
def test_cyclic_gc(self):
- regexp = re.compile(r'at (0x[\da-f]+)')
gc.collect()
c = pycurl.Curl()
c.m = pycurl.CurlMulti()
@@ -208,17 +206,14 @@ class InternalsTest(unittest.TestCase):
##print gc.get_objects()
#if opts.verbose >= 1:
#print("Tracked objects:", len(gc.get_objects()))
- match = regexp.search(repr(c))
- assert match is not None
- address = match.group(1)
+ c_id = id(c)
# The `del' below should delete these 4 objects:
# Curl + internal dict, CurlMulti + internal dict
del c
gc.collect()
objects = gc.get_objects()
- search = 'at %s' % address
for object in objects:
- assert search not in repr(object)
+ assert id(object) != c_id
#if opts.verbose >= 1:
#print("Tracked objects:", len(gc.get_objects()))
--
1.7.1
From 5b644f3685a8af09b39a0b94b718a2fc7c33b22e Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 03:25:34 -0500
Subject: [PATCH 059/112] Adjust ftp test to work with vsftpd started from project root
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/ftp_test.py | 18 ++++++++++--------
1 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/tests/ftp_test.py b/tests/ftp_test.py
index d215b6e..1d382ed 100644
--- a/tests/ftp_test.py
+++ b/tests/ftp_test.py
@@ -2,6 +2,8 @@
# -*- coding: iso-8859-1 -*-
# vi:ts=4:et
+# Note: this test is meant to be run from pycurl project root.
+
import pycurl
import unittest
@@ -15,29 +17,29 @@ class FtpTest(unittest.TestCase):
self.curl.close()
def test_get_ftp(self):
- self.curl.setopt(pycurl.URL, 'ftp://localhost:8921')
+ self.curl.setopt(pycurl.URL, 'ftp://localhost:8321')
sio = util.StringIO()
self.curl.setopt(pycurl.WRITEFUNCTION, sio.write)
self.curl.perform()
result = sio.getvalue()
assert 'README' in result
- assert 'bin -> usr/bin' in result
+ assert 'INSTALL' in result
# XXX this test needs to be fixed
def test_quote(self):
- self.curl.setopt(pycurl.URL, 'ftp://localhost:8921')
+ self.curl.setopt(pycurl.URL, 'ftp://localhost:8321')
sio = util.StringIO()
self.curl.setopt(pycurl.WRITEFUNCTION, sio.write)
- self.curl.setopt(pycurl.QUOTE, ['CWD pub'])
+ self.curl.setopt(pycurl.QUOTE, ['CWD tests'])
self.curl.perform()
result = sio.getvalue()
- assert 'README' in result
- assert 'bin -> usr/bin' in result
+ assert 'README' not in result
+ assert 'ftp_test.py' in result
def test_epsv(self):
- self.curl.setopt(pycurl.URL, 'ftp://localhost:8921')
+ self.curl.setopt(pycurl.URL, 'ftp://localhost:8321')
sio = util.StringIO()
self.curl.setopt(pycurl.WRITEFUNCTION, sio.write)
self.curl.setopt(pycurl.FTP_USE_EPSV, 1)
@@ -45,4 +47,4 @@ class FtpTest(unittest.TestCase):
result = sio.getvalue()
assert 'README' in result
- assert 'bin -> usr/bin' in result
+ assert 'INSTALL' in result
--
1.7.1
From 758ab367deff461fdd9c631ee4128bd7a4a0b1b3 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 04:01:13 -0500
Subject: [PATCH 060/112] Execute vsftpd as test ftp server
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/ftp_test.py | 3 ++
tests/procmgr.py | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++
tests/runwsgi.py | 20 ++++++++------
tests/vsftpd.conf | 10 +++++++
4 files changed, 98 insertions(+), 8 deletions(-)
create mode 100644 tests/procmgr.py
create mode 100644 tests/vsftpd.conf
diff --git a/tests/ftp_test.py b/tests/ftp_test.py
index 1d382ed..fa2ef79 100644
--- a/tests/ftp_test.py
+++ b/tests/ftp_test.py
@@ -8,6 +8,9 @@ import pycurl
import unittest
from . import util
+from . import procmgr
+
+setup_module, teardown_module = procmgr.vsftpd_setup()
class FtpTest(unittest.TestCase):
def setUp(self):
diff --git a/tests/procmgr.py b/tests/procmgr.py
new file mode 100644
index 0000000..8d5c0cc
--- /dev/null
+++ b/tests/procmgr.py
@@ -0,0 +1,73 @@
+import threading
+import subprocess
+import os
+import signal
+
+from . import runwsgi
+
+class ProcessManager(object):
+ def __init__(self, cmd):
+ self.cmd = cmd
+
+ def start(self):
+ self.process = subprocess.Popen(self.cmd)
+
+ self.thread = threading.Thread(target=self.run)
+ self.thread.daemon = True
+ self.thread.start()
+
+ def run(self):
+ self.process.communicate()
+
+managers = {}
+
+def start(cmd):
+ if str(cmd) in managers:
+ # already started
+ return
+
+ manager = ProcessManager(cmd)
+ managers[str(cmd)] = manager
+ manager.start()
+
+def start_setup(cmd):
+ def do_start():
+ start(cmd)
+ return do_start
+
+# Example on FreeBSD:
+# PYCURL_VSFTPD_PATH=/usr/local/libexec/vsftpd nosetests
+
+if 'PYCURL_VSFTPD_PATH' in os.environ:
+ vsftpd_path = os.environ['PYCURL_VSFTPD_PATH']
+else:
+ vsftpd_path = 'vsftpd'
+
+def vsftpd_setup():
+ config_file_path = os.path.join(os.path.dirname(__file__), 'vsftpd.conf')
+ root_path = os.path.join(os.path.dirname(__file__), '..')
+ cmd = [
+ vsftpd_path,
+ config_file_path,
+ '-oanon_root=%s' % root_path,
+ ]
+ setup_module = start_setup(cmd)
+ def do_setup_module():
+ setup_module()
+ ok = runwsgi.wait_for_network_service(('127.0.0.1', 8321), 0.1, 10)
+ if not ok:
+ import warnings
+ warnings.warn('vsftpd did not start after 1 second')
+
+ def teardown_module():
+ try:
+ manager = managers[str(cmd)]
+ except KeyError:
+ pass
+ else:
+ try:
+ os.kill(manager.process.pid, signal.SIGTERM)
+ except OSError:
+ pass
+
+ return do_setup_module, teardown_module
diff --git a/tests/runwsgi.py b/tests/runwsgi.py
index 6d3b69f..5217a3f 100644
--- a/tests/runwsgi.py
+++ b/tests/runwsgi.py
@@ -16,21 +16,25 @@ class Server(bottle.WSGIRefServer):
self.srv = make_server(self.host, self.port, handler, **self.options)
self.srv.serve_forever(poll_interval=0.1)
-def start_bottle_server(app, port, **kwargs):
- server_thread = ServerThread(app, port, kwargs)
- server_thread.daemon = True
- server_thread.start()
-
+def wait_for_network_service(netloc, check_interval, num_attempts):
ok = False
- for i in range(10):
+ for i in range(num_attempts):
try:
- conn = socket.create_connection(('127.0.0.1', port), 0.1)
+ conn = socket.create_connection(netloc, check_interval)
except socket.error as e:
- _time.sleep(0.1)
+ _time.sleep(check_interval)
else:
conn.close()
ok = True
break
+ return ok
+
+def start_bottle_server(app, port, **kwargs):
+ server_thread = ServerThread(app, port, kwargs)
+ server_thread.daemon = True
+ server_thread.start()
+
+ ok = wait_for_network_service(('127.0.0.1', port), 0.1, 10)
if not ok:
import warnings
warnings.warn('Server did not start after 1 second')
diff --git a/tests/vsftpd.conf b/tests/vsftpd.conf
new file mode 100644
index 0000000..0abb39f
--- /dev/null
+++ b/tests/vsftpd.conf
@@ -0,0 +1,10 @@
+anon_world_readable_only=yes
+anonymous_enable=yes
+# currently we only list files
+download_enable=no
+listen=yes
+run_as_launching_user=yes
+write_enable=no
+listen_port=8321
+# should be supplied on command line
+anon_root=/var/empty
--
1.7.1
From 67495d01da3e8875a9b5882ecdca50c96ee47b15 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 00:37:19 -0500
Subject: [PATCH 061/112] Move gtk and xmlrpc tests to examples as they do not test anything not already tested by the test suite
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
examples/tests/test_gtk.py | 98 +++++++++++++++++++++++++++++++++++++++++
examples/tests/test_xmlrpc.py | 29 ++++++++++++
tests/test_gtk.py | 98 -----------------------------------------
tests/test_xmlrpc.py | 29 ------------
4 files changed, 127 insertions(+), 127 deletions(-)
create mode 100644 examples/tests/test_gtk.py
create mode 100644 examples/tests/test_xmlrpc.py
delete mode 100644 tests/test_gtk.py
delete mode 100644 tests/test_xmlrpc.py
diff --git a/examples/tests/test_gtk.py b/examples/tests/test_gtk.py
new file mode 100644
index 0000000..7104439
--- /dev/null
+++ b/examples/tests/test_gtk.py
@@ -0,0 +1,98 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+# $Id$
+
+import sys, threading
+import pycurl
+import pygtk
+pygtk.require('2.0')
+import gtk
+
+# We should ignore SIGPIPE when using pycurl.NOSIGNAL - see
+# the libcurl tutorial for more info.
+try:
+ import signal
+ from signal import SIGPIPE, SIG_IGN
+ signal.signal(signal.SIGPIPE, signal.SIG_IGN)
+except ImportError:
+ pass
+
+
+class ProgressBar:
+ def __init__(self, uri):
+ self.round = 0.0
+ win = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ win.set_title("PycURL progress")
+ win.show()
+ vbox = gtk.VBox(spacing=5)
+ vbox.set_border_width(10)
+ win.add(vbox)
+ win.set_default_size(200, 20)
+ vbox.show()
+ label = gtk.Label("Downloading %s" % uri)
+ label.set_alignment(0, 0.5)
+ vbox.pack_start(label)
+ label.show()
+ pbar = gtk.ProgressBar()
+ pbar.show()
+ self.pbar = pbar
+ vbox.pack_start(pbar)
+ win.connect("destroy", self.close_app)
+
+ def progress(self, download_t, download_d, upload_t, upload_d):
+ if download_t == 0:
+ self.round = self.round + 0.1
+ if self.round >= 1.0: self.round = 0.0
+ else:
+ self.round = float(download_d) / float(download_t)
+ gtk.threads_enter()
+ self.pbar.set_fraction(self.round)
+ gtk.threads_leave()
+
+ def mainloop(self):
+ gtk.threads_enter()
+ gtk.main()
+ gtk.threads_leave()
+
+ def close_app(self, *args):
+ args[0].destroy()
+ gtk.main_quit()
+
+
+class Test(threading.Thread):
+ def __init__(self, url, target_file, progress):
+ threading.Thread.__init__(self)
+ self.target_file = target_file
+ self.progress = progress
+ self.curl = pycurl.Curl()
+ self.curl.setopt(pycurl.URL, url)
+ self.curl.setopt(pycurl.WRITEDATA, self.target_file)
+ self.curl.setopt(pycurl.FOLLOWLOCATION, 1)
+ self.curl.setopt(pycurl.NOPROGRESS, 0)
+ self.curl.setopt(pycurl.PROGRESSFUNCTION, self.progress)
+ self.curl.setopt(pycurl.MAXREDIRS, 5)
+ self.curl.setopt(pycurl.NOSIGNAL, 1)
+
+ def run(self):
+ self.curl.perform()
+ self.curl.close()
+ self.target_file.close()
+ self.progress(1.0, 1.0, 0, 0)
+
+
+# Check command line args
+if len(sys.argv) < 3:
+ print "Usage: %s <URL> <filename>" % sys.argv[0]
+ raise SystemExit
+
+# Make a progress bar window
+p = ProgressBar(sys.argv[1])
+# Start thread for fetching url
+Test(sys.argv[1], open(sys.argv[2], 'wb'), p.progress).start()
+# Enter the GTK mainloop
+gtk.threads_init()
+try:
+ p.mainloop()
+except KeyboardInterrupt:
+ pass
diff --git a/examples/tests/test_xmlrpc.py b/examples/tests/test_xmlrpc.py
new file mode 100644
index 0000000..bc5953e
--- /dev/null
+++ b/examples/tests/test_xmlrpc.py
@@ -0,0 +1,29 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+# $Id$
+
+## XML-RPC lib included in python2.2
+import xmlrpclib
+import pycurl
+
+# Header fields passed in request
+xmlrpc_header = [
+ "User-Agent: PycURL XML-RPC Test", "Content-Type: text/xml"
+ ]
+
+# XML-RPC request template
+xmlrpc_template = """
+<?xml version='1.0'?><methodCall><methodName>%s</methodName>%s</methodCall>
+"""
+
+# Engage
+c = pycurl.Curl()
+c.setopt(c.URL, 'http://betty.userland.com/RPC2')
+c.setopt(c.POST, 1)
+c.setopt(c.HTTPHEADER, xmlrpc_header)
+c.setopt(c.POSTFIELDS, xmlrpc_template % ("examples.getStateName", xmlrpclib.dumps((5,))))
+
+print 'Response from http://betty.userland.com/'
+c.perform()
+c.close()
diff --git a/tests/test_gtk.py b/tests/test_gtk.py
deleted file mode 100644
index 7104439..0000000
--- a/tests/test_gtk.py
+++ /dev/null
@@ -1,98 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-# $Id$
-
-import sys, threading
-import pycurl
-import pygtk
-pygtk.require('2.0')
-import gtk
-
-# We should ignore SIGPIPE when using pycurl.NOSIGNAL - see
-# the libcurl tutorial for more info.
-try:
- import signal
- from signal import SIGPIPE, SIG_IGN
- signal.signal(signal.SIGPIPE, signal.SIG_IGN)
-except ImportError:
- pass
-
-
-class ProgressBar:
- def __init__(self, uri):
- self.round = 0.0
- win = gtk.Window(gtk.WINDOW_TOPLEVEL)
- win.set_title("PycURL progress")
- win.show()
- vbox = gtk.VBox(spacing=5)
- vbox.set_border_width(10)
- win.add(vbox)
- win.set_default_size(200, 20)
- vbox.show()
- label = gtk.Label("Downloading %s" % uri)
- label.set_alignment(0, 0.5)
- vbox.pack_start(label)
- label.show()
- pbar = gtk.ProgressBar()
- pbar.show()
- self.pbar = pbar
- vbox.pack_start(pbar)
- win.connect("destroy", self.close_app)
-
- def progress(self, download_t, download_d, upload_t, upload_d):
- if download_t == 0:
- self.round = self.round + 0.1
- if self.round >= 1.0: self.round = 0.0
- else:
- self.round = float(download_d) / float(download_t)
- gtk.threads_enter()
- self.pbar.set_fraction(self.round)
- gtk.threads_leave()
-
- def mainloop(self):
- gtk.threads_enter()
- gtk.main()
- gtk.threads_leave()
-
- def close_app(self, *args):
- args[0].destroy()
- gtk.main_quit()
-
-
-class Test(threading.Thread):
- def __init__(self, url, target_file, progress):
- threading.Thread.__init__(self)
- self.target_file = target_file
- self.progress = progress
- self.curl = pycurl.Curl()
- self.curl.setopt(pycurl.URL, url)
- self.curl.setopt(pycurl.WRITEDATA, self.target_file)
- self.curl.setopt(pycurl.FOLLOWLOCATION, 1)
- self.curl.setopt(pycurl.NOPROGRESS, 0)
- self.curl.setopt(pycurl.PROGRESSFUNCTION, self.progress)
- self.curl.setopt(pycurl.MAXREDIRS, 5)
- self.curl.setopt(pycurl.NOSIGNAL, 1)
-
- def run(self):
- self.curl.perform()
- self.curl.close()
- self.target_file.close()
- self.progress(1.0, 1.0, 0, 0)
-
-
-# Check command line args
-if len(sys.argv) < 3:
- print "Usage: %s <URL> <filename>" % sys.argv[0]
- raise SystemExit
-
-# Make a progress bar window
-p = ProgressBar(sys.argv[1])
-# Start thread for fetching url
-Test(sys.argv[1], open(sys.argv[2], 'wb'), p.progress).start()
-# Enter the GTK mainloop
-gtk.threads_init()
-try:
- p.mainloop()
-except KeyboardInterrupt:
- pass
diff --git a/tests/test_xmlrpc.py b/tests/test_xmlrpc.py
deleted file mode 100644
index bc5953e..0000000
--- a/tests/test_xmlrpc.py
+++ /dev/null
@@ -1,29 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-# $Id$
-
-## XML-RPC lib included in python2.2
-import xmlrpclib
-import pycurl
-
-# Header fields passed in request
-xmlrpc_header = [
- "User-Agent: PycURL XML-RPC Test", "Content-Type: text/xml"
- ]
-
-# XML-RPC request template
-xmlrpc_template = """
-<?xml version='1.0'?><methodCall><methodName>%s</methodName>%s</methodCall>
-"""
-
-# Engage
-c = pycurl.Curl()
-c.setopt(c.URL, 'http://betty.userland.com/RPC2')
-c.setopt(c.POST, 1)
-c.setopt(c.HTTPHEADER, xmlrpc_header)
-c.setopt(c.POSTFIELDS, xmlrpc_template % ("examples.getStateName", xmlrpclib.dumps((5,))))
-
-print 'Response from http://betty.userland.com/'
-c.perform()
-c.close()
--
1.7.1
From 8519dd18dd06138ed48eebfef966e3740e7737ef Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 00:37:41 -0500
Subject: [PATCH 062/112] Delete old tests
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/test.py | 74 -----------
tests/test_cb.py | 28 ----
tests/test_debug.py | 16 ---
tests/test_ftp.py | 13 --
tests/test_getinfo.py | 49 -------
tests/test_internals.py | 258 ------------------------------------
tests/test_memleak.py | 53 --------
tests/test_multi.py | 33 -----
tests/test_multi2.py | 72 ----------
tests/test_multi3.py | 87 ------------
tests/test_multi4.py | 57 --------
tests/test_multi5.py | 60 ---------
tests/test_multi6.py | 62 ---------
tests/test_multi_socket.py | 82 ------------
tests/test_multi_socket_select.py | 105 ---------------
tests/test_multi_timer.py | 76 -----------
tests/test_multi_vs_thread.py | 262 -------------------------------------
tests/test_post.py | 24 ----
tests/test_post2.py | 18 ---
tests/test_post3.py | 32 -----
tests/test_reset.py | 75 -----------
tests/test_share.py | 34 -----
tests/test_socketopen.py | 17 ---
tests/test_stringio.py | 25 ----
24 files changed, 0 insertions(+), 1612 deletions(-)
delete mode 100644 tests/test.py
delete mode 100644 tests/test_cb.py
delete mode 100644 tests/test_debug.py
delete mode 100644 tests/test_ftp.py
delete mode 100644 tests/test_getinfo.py
delete mode 100644 tests/test_internals.py
delete mode 100644 tests/test_memleak.py
delete mode 100644 tests/test_multi.py
delete mode 100644 tests/test_multi2.py
delete mode 100644 tests/test_multi3.py
delete mode 100644 tests/test_multi4.py
delete mode 100644 tests/test_multi5.py
delete mode 100644 tests/test_multi6.py
delete mode 100644 tests/test_multi_socket.py
delete mode 100644 tests/test_multi_socket_select.py
delete mode 100644 tests/test_multi_timer.py
delete mode 100644 tests/test_multi_vs_thread.py
delete mode 100644 tests/test_post.py
delete mode 100644 tests/test_post2.py
delete mode 100644 tests/test_post3.py
delete mode 100644 tests/test_reset.py
delete mode 100644 tests/test_share.py
delete mode 100644 tests/test_socketopen.py
delete mode 100644 tests/test_stringio.py
diff --git a/tests/test.py b/tests/test.py
deleted file mode 100644
index 5cd9740..0000000
--- a/tests/test.py
+++ /dev/null
@@ -1,74 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-# $Id$
-
-import sys, threading, time
-import pycurl
-
-# We should ignore SIGPIPE when using pycurl.NOSIGNAL - see
-# the libcurl tutorial for more info.
-try:
- import signal
- from signal import SIGPIPE, SIG_IGN
- signal.signal(signal.SIGPIPE, signal.SIG_IGN)
-except ImportError:
- pass
-
-
-class Test(threading.Thread):
- def __init__(self, url, ofile):
- threading.Thread.__init__(self)
- self.curl = pycurl.Curl()
- self.curl.setopt(pycurl.URL, url)
- self.curl.setopt(pycurl.WRITEDATA, ofile)
- self.curl.setopt(pycurl.FOLLOWLOCATION, 1)
- self.curl.setopt(pycurl.MAXREDIRS, 5)
- self.curl.setopt(pycurl.NOSIGNAL, 1)
-
- def run(self):
- self.curl.perform()
- self.curl.close()
- sys.stdout.write(".")
- sys.stdout.flush()
-
-
-# Read list of URIs from file specified on commandline
-try:
- urls = open(sys.argv[1]).readlines()
-except IndexError:
- # No file was specified, show usage string
- print "Usage: %s <file with uris to fetch>" % sys.argv[0]
- raise SystemExit
-
-# Initialize thread array and the file number
-threads = []
-fileno = 0
-
-# Start one thread per URI in parallel
-t1 = time.time()
-for url in urls:
- f = open(str(fileno), "wb")
- t = Test(url.rstrip(), f)
- t.start()
- threads.append((t, f))
- fileno = fileno + 1
-# Wait for all threads to finish
-for thread, file in threads:
- thread.join()
- file.close()
-t2 = time.time()
-print "\n** Multithreading, %d seconds elapsed for %d uris" % (int(t2-t1), len(urls))
-
-# Start one thread per URI in sequence
-fileno = 0
-t1 = time.time()
-for url in urls:
- f = open(str(fileno), "wb")
- t = Test(url.rstrip(), f)
- t.start()
- fileno = fileno + 1
- t.join()
- f.close()
-t2 = time.time()
-print "\n** Singlethreading, %d seconds elapsed for %d uris" % (int(t2-t1), len(urls))
diff --git a/tests/test_cb.py b/tests/test_cb.py
deleted file mode 100644
index 1be305c..0000000
--- a/tests/test_cb.py
+++ /dev/null
@@ -1,28 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-# $Id$
-
-import sys
-import pycurl
-
-## Callback function invoked when body data is ready
-def body(buf):
- # Print body data to stdout
- sys.stdout.write(buf)
-
-## Callback function invoked when header data is ready
-def header(buf):
- # Print header data to stderr
- sys.stderr.write(buf)
-
-c = pycurl.Curl()
-c.setopt(pycurl.URL, 'http://www.python.org/')
-c.setopt(pycurl.WRITEFUNCTION, body)
-c.setopt(pycurl.HEADERFUNCTION, header)
-c.setopt(pycurl.FOLLOWLOCATION, 1)
-c.setopt(pycurl.MAXREDIRS, 5)
-c.perform()
-c.setopt(pycurl.URL, 'http://curl.haxx.se/')
-c.perform()
-c.close()
diff --git a/tests/test_debug.py b/tests/test_debug.py
deleted file mode 100644
index d439b16..0000000
--- a/tests/test_debug.py
+++ /dev/null
@@ -1,16 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-# $Id$
-
-import pycurl
-
-def test(t, b):
- print "debug(%d): %s" % (t, b)
-
-c = pycurl.Curl()
-c.setopt(pycurl.URL, 'http://curl.haxx.se/')
-c.setopt(pycurl.VERBOSE, 1)
-c.setopt(pycurl.DEBUGFUNCTION, test)
-c.perform()
-c.close()
diff --git a/tests/test_ftp.py b/tests/test_ftp.py
deleted file mode 100644
index 2d4d358..0000000
--- a/tests/test_ftp.py
+++ /dev/null
@@ -1,13 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-# $Id$
-
-import pycurl
-
-c = pycurl.Curl()
-c.setopt(c.URL, 'ftp://ftp.sunet.se/')
-c.setopt(c.FTP_USE_EPSV, 1)
-c.setopt(c.QUOTE, ['cwd pub', 'type i'])
-c.perform()
-c.close()
diff --git a/tests/test_getinfo.py b/tests/test_getinfo.py
deleted file mode 100644
index ed64594..0000000
--- a/tests/test_getinfo.py
+++ /dev/null
@@ -1,49 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-# $Id$
-
-import time
-import pycurl
-
-
-## Callback function invoked when progress information is updated
-def progress(download_t, download_d, upload_t, upload_d):
- print "Total to download %d bytes, have %d bytes so far" % \
- (download_t, download_d)
-
-url = "http://www.cnn.com"
-
-print "Starting downloading", url
-print
-f = open("body", "wb")
-h = open("header", "wb")
-c = pycurl.Curl()
-c.setopt(c.URL, url)
-c.setopt(c.WRITEDATA, f)
-c.setopt(c.NOPROGRESS, 0)
-c.setopt(c.PROGRESSFUNCTION, progress)
-c.setopt(c.FOLLOWLOCATION, 1)
-c.setopt(c.MAXREDIRS, 5)
-c.setopt(c.WRITEHEADER, h)
-c.setopt(c.OPT_FILETIME, 1)
-c.perform()
-
-print
-print "HTTP-code:", c.getinfo(c.HTTP_CODE)
-print "Total-time:", c.getinfo(c.TOTAL_TIME)
-print "Download speed: %.2f bytes/second" % c.getinfo(c.SPEED_DOWNLOAD)
-print "Document size: %d bytes" % c.getinfo(c.SIZE_DOWNLOAD)
-print "Effective URL:", c.getinfo(c.EFFECTIVE_URL)
-print "Content-type:", c.getinfo(c.CONTENT_TYPE)
-print "Namelookup-time:", c.getinfo(c.NAMELOOKUP_TIME)
-print "Redirect-time:", c.getinfo(c.REDIRECT_TIME)
-print "Redirect-count:", c.getinfo(c.REDIRECT_COUNT)
-epoch = c.getinfo(c.INFO_FILETIME)
-print "Filetime: %d (%s)" % (epoch, time.ctime(epoch))
-print
-print "Header is in file 'header', body is in file 'body'"
-
-c.close()
-f.close()
-h.close()
diff --git a/tests/test_internals.py b/tests/test_internals.py
deleted file mode 100644
index 3f5eefd..0000000
--- a/tests/test_internals.py
+++ /dev/null
@@ -1,258 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-# $Id$
-
-#
-# a simple self-test
-#
-
-try:
- # need Python 2.2 or better for garbage collection
- from gc import get_objects
- import gc
- del get_objects
- gc.enable()
-except ImportError:
- gc = None
-import copy, os, sys
-from StringIO import StringIO
-try:
- import cPickle
-except ImportError:
- cPickle = None
-try:
- import pickle
-except ImportError:
- pickle = None
-
-# update sys.path when running in the build directory
-from util import get_sys_path
-sys.path = get_sys_path()
-
-import pycurl
-from pycurl import Curl, CurlMulti
-
-
-class opts:
- verbose = 1
-
-if "-q" in sys.argv:
- opts.verbose = opts.verbose - 1
-
-
-print "Python", sys.version
-print "PycURL %s (compiled against 0x%x)" % (pycurl.version, pycurl.COMPILE_LIBCURL_VERSION_NUM)
-print "PycURL version info", pycurl.version_info()
-print " %s, compiled %s" % (pycurl.__file__, pycurl.COMPILE_DATE)
-
-
-# /***********************************************************************
-# // test misc
-# ************************************************************************/
-
-if 1:
- c = Curl()
- assert c.URL is pycurl.URL
- del c
-
-
-# /***********************************************************************
-# // test handles
-# ************************************************************************/
-
-# remove an invalid handle: this should fail
-if 1:
- m = CurlMulti()
- c = Curl()
- try:
- m.remove_handle(c)
- except pycurl.error:
- pass
- else:
- assert 0, "internal error"
- del m, c
-
-
-# remove an invalid but closed handle
-if 1:
- m = CurlMulti()
- c = Curl()
- c.close()
- m.remove_handle(c)
- del m, c
-
-
-# add a closed handle: this should fail
-if 1:
- m = CurlMulti()
- c = Curl()
- c.close()
- try:
- m.add_handle(c)
- except pycurl.error:
- pass
- else:
- assert 0, "internal error"
- m.close()
- del m, c
-
-
-# add a handle twice: this should fail
-if 1:
- m = CurlMulti()
- c = Curl()
- m.add_handle(c)
- try:
- m.add_handle(c)
- except pycurl.error:
- pass
- else:
- assert 0, "internal error"
- del m, c
-
-
-# add a handle on multiple stacks: this should fail
-if 1:
- m1 = CurlMulti()
- m2 = CurlMulti()
- c = Curl()
- m1.add_handle(c)
- try:
- m2.add_handle(c)
- except pycurl.error:
- pass
- else:
- assert 0, "internal error"
- del m1, m2, c
-
-
-# move a handle
-if 1:
- m1 = CurlMulti()
- m2 = CurlMulti()
- c = Curl()
- m1.add_handle(c)
- m1.remove_handle(c)
- m2.add_handle(c)
- del m1, m2, c
-
-
-# /***********************************************************************
-# // test copying and pickling - copying and pickling of
-# // instances of Curl and CurlMulti is not allowed
-# ************************************************************************/
-
-if 1 and copy:
- c = Curl()
- m = CurlMulti()
- try:
- copy.copy(c)
- except copy.Error:
- pass
- else:
- assert 0, "internal error - copying should fail"
- try:
- copy.copy(m)
- except copy.Error:
- pass
- else:
- assert 0, "internal error - copying should fail"
-
-if 1 and pickle:
- c = Curl()
- m = CurlMulti()
- fp = StringIO()
- p = pickle.Pickler(fp, 1)
- try:
- p.dump(c)
- except pickle.PicklingError:
- pass
- else:
- assert 0, "internal error - pickling should fail"
- try:
- p.dump(m)
- except pickle.PicklingError:
- pass
- else:
- assert 0, "internal error - pickling should fail"
- del c, m, fp, p
-
-if 1 and cPickle:
- c = Curl()
- m = CurlMulti()
- fp = StringIO()
- p = cPickle.Pickler(fp, 1)
- try:
- p.dump(c)
- except cPickle.PicklingError:
- pass
- else:
- assert 0, "internal error - pickling should fail"
- try:
- p.dump(m)
- except cPickle.PicklingError:
- pass
- else:
- assert 0, "internal error - pickling should fail"
- del c, m, fp, p
-
-
-# /***********************************************************************
-# // test refcounts
-# ************************************************************************/
-
-# basic check of reference counting (use a memory checker like valgrind)
-if 1:
- c = Curl()
- m = CurlMulti()
- m.add_handle(c)
- del m
- m = CurlMulti()
- c.close()
- del m, c
-
-# basic check of cyclic garbage collection
-if 1 and gc:
- gc.collect()
- c = Curl()
- c.m = CurlMulti()
- c.m.add_handle(c)
- # create some nasty cyclic references
- c.c = c
- c.c.c1 = c
- c.c.c2 = c
- c.c.c3 = c.c
- c.c.c4 = c.m
- c.m.c = c
- c.m.m = c.m
- c.m.c = c
- # delete
- gc.collect()
- flags = gc.DEBUG_COLLECTABLE | gc.DEBUG_UNCOLLECTABLE | gc.DEBUG_OBJECTS
- if opts.verbose >= 1:
- flags = flags | gc.DEBUG_STATS
- gc.set_debug(flags)
- gc.collect()
- ##print gc.get_referrers(c)
- ##print gc.get_objects()
- if opts.verbose >= 1:
- print "Tracked objects:", len(gc.get_objects())
- # The `del' below should delete these 4 objects:
- # Curl + internal dict, CurlMulti + internal dict
- del c
- gc.collect()
- if opts.verbose >= 1:
- print "Tracked objects:", len(gc.get_objects())
-
-if 1:
- # Ensure that the refcounting error in "reset" is fixed:
- for i in xrange(100000):
- c = Curl()
- c.reset()
-
-# /***********************************************************************
-# // done
-# ************************************************************************/
-
-print "All tests passed."
diff --git a/tests/test_memleak.py b/tests/test_memleak.py
deleted file mode 100644
index 8577b97..0000000
--- a/tests/test_memleak.py
+++ /dev/null
@@ -1,53 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-# $Id$
-
-#
-# just a simple self-test
-# need Python 2.2 or better for garbage collection
-#
-
-import gc, pycurl, sys
-gc.enable()
-
-
-print "Python", sys.version
-print "PycURL %s (compiled against 0x%x)" % (pycurl.version, pycurl.COMPILE_LIBCURL_VERSION_NUM)
-##print "PycURL version info", pycurl.version_info()
-print " %s, compiled %s" % (pycurl.__file__, pycurl.COMPILE_DATE)
-
-
-gc.collect()
-flags = gc.DEBUG_COLLECTABLE | gc.DEBUG_UNCOLLECTABLE | gc.DEBUG_OBJECTS
-if 1:
- flags = flags | gc.DEBUG_STATS
-gc.set_debug(flags)
-gc.collect()
-
-print "Tracked objects:", len(gc.get_objects())
-
-multi = pycurl.CurlMulti()
-t = []
-for a in range(100):
- curl = pycurl.Curl()
- multi.add_handle(curl)
- t.append(curl)
-
-print "Tracked objects:", len(gc.get_objects())
-
-for curl in t:
- curl.close()
- multi.remove_handle(curl)
-
-print "Tracked objects:", len(gc.get_objects())
-
-del curl
-del t
-del multi
-
-print "Tracked objects:", len(gc.get_objects())
-gc.collect()
-print "Tracked objects:", len(gc.get_objects())
-
-
diff --git a/tests/test_multi.py b/tests/test_multi.py
deleted file mode 100644
index 9193986..0000000
--- a/tests/test_multi.py
+++ /dev/null
@@ -1,33 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-# $Id$
-
-import pycurl
-
-m = pycurl.CurlMulti()
-m.handles = []
-c1 = pycurl.Curl()
-c2 = pycurl.Curl()
-c1.setopt(c1.URL, 'http://curl.haxx.se')
-c2.setopt(c2.URL, 'http://cnn.com')
-c2.setopt(c2.FOLLOWLOCATION, 1)
-m.add_handle(c1)
-m.add_handle(c2)
-m.handles.append(c1)
-m.handles.append(c2)
-
-num_handles = len(m.handles)
-while num_handles:
- while 1:
- ret, num_handles = m.perform()
- if ret != pycurl.E_CALL_MULTI_PERFORM:
- break
- m.select(1.0)
-
-m.remove_handle(c2)
-m.remove_handle(c1)
-del m.handles
-m.close()
-c1.close()
-c2.close()
diff --git a/tests/test_multi2.py b/tests/test_multi2.py
deleted file mode 100644
index 4b96789..0000000
--- a/tests/test_multi2.py
+++ /dev/null
@@ -1,72 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-# $Id$
-
-import os, sys
-try:
- from cStringIO import StringIO
-except ImportError:
- from StringIO import StringIO
-import pycurl
-
-
-urls = (
- "http://curl.haxx.se",
- "http://www.python.org",
- "http://pycurl.sourceforge.net",
- "http://pycurl.sourceforge.net/tests/403_FORBIDDEN", # that actually exists ;-)
- "http://pycurl.sourceforge.net/tests/404_NOT_FOUND",
-)
-
-# Read list of URIs from file specified on commandline
-try:
- urls = open(sys.argv[1], "rb").readlines()
-except IndexError:
- # No file was specified
- pass
-
-# init
-m = pycurl.CurlMulti()
-m.handles = []
-for url in urls:
- c = pycurl.Curl()
- # save info in standard Python attributes
- c.url = url.rstrip()
- c.body = StringIO()
- c.http_code = -1
- m.handles.append(c)
- # pycurl API calls
- c.setopt(c.URL, c.url)
- c.setopt(c.WRITEFUNCTION, c.body.write)
- m.add_handle(c)
-
-# get data
-num_handles = len(m.handles)
-while num_handles:
- while 1:
- ret, num_handles = m.perform()
- if ret != pycurl.E_CALL_MULTI_PERFORM:
- break
- # currently no more I/O is pending, could do something in the meantime
- # (display a progress bar, etc.)
- m.select(1.0)
-
-# close handles
-for c in m.handles:
- # save info in standard Python attributes
- c.http_code = c.getinfo(c.HTTP_CODE)
- # pycurl API calls
- m.remove_handle(c)
- c.close()
-m.close()
-
-# print result
-for c in m.handles:
- data = c.body.getvalue()
- if 0:
- print "**********", c.url, "**********"
- print data
- else:
- print "%-53s http_code %3d, %6d bytes" % (c.url, c.http_code, len(data))
-
diff --git a/tests/test_multi3.py b/tests/test_multi3.py
deleted file mode 100644
index 5b7ea6e..0000000
--- a/tests/test_multi3.py
+++ /dev/null
@@ -1,87 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-# $Id$
-
-# same as test_multi2.py, but enforce some debugging and strange API-calls
-
-import os, sys
-try:
- from cStringIO import StringIO
-except ImportError:
- from StringIO import StringIO
-import pycurl
-
-
-urls = (
- "http://curl.haxx.se",
- "http://www.python.org",
- "http://pycurl.sourceforge.net",
- "http://pycurl.sourceforge.net/THIS_HANDLE_IS_CLOSED",
-)
-
-# init
-m = pycurl.CurlMulti()
-m.handles = []
-for url in urls:
- c = pycurl.Curl()
- # save info in standard Python attributes
- c.url = url
- c.body = StringIO()
- c.http_code = -1
- c.debug = 0
- m.handles.append(c)
- # pycurl API calls
- c.setopt(c.URL, c.url)
- c.setopt(c.WRITEFUNCTION, c.body.write)
- m.add_handle(c)
-
-# debug - close a handle
-if 1:
- c = m.handles[3]
- c.debug = 1
- c.close()
-
-# get data
-num_handles = len(m.handles)
-while num_handles:
- while 1:
- ret, num_handles = m.perform()
- if ret != pycurl.E_CALL_MULTI_PERFORM:
- break
- # currently no more I/O is pending, could do something in the meantime
- # (display a progress bar, etc.)
- m.select(1.0)
-
-# close handles
-for c in m.handles:
- # save info in standard Python attributes
- try:
- c.http_code = c.getinfo(c.HTTP_CODE)
- except pycurl.error:
- # handle already closed - see debug above
- assert c.debug
- c.http_code = -1
- # pycurl API calls
- if 0:
- m.remove_handle(c)
- c.close()
- elif 0:
- # in the C API this is the wrong calling order, but pycurl
- # handles this automatically
- c.close()
- m.remove_handle(c)
- else:
- # actually, remove_handle is called automatically on close
- c.close()
-m.close()
-
-# print result
-for c in m.handles:
- data = c.body.getvalue()
- if 0:
- print "**********", c.url, "**********"
- print data
- else:
- print "%-53s http_code %3d, %6d bytes" % (c.url, c.http_code, len(data))
-
diff --git a/tests/test_multi4.py b/tests/test_multi4.py
deleted file mode 100644
index f37ea26..0000000
--- a/tests/test_multi4.py
+++ /dev/null
@@ -1,57 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-# $Id$
-
-import sys, select, time
-import pycurl
-
-c1 = pycurl.Curl()
-c2 = pycurl.Curl()
-c3 = pycurl.Curl()
-c1.setopt(c1.URL, "http://www.python.org")
-c2.setopt(c2.URL, "http://curl.haxx.se")
-c3.setopt(c3.URL, "http://slashdot.org")
-c1.body = open("doc1", "wb")
-c2.body = open("doc2", "wb")
-c3.body = open("doc3", "wb")
-c1.setopt(c1.WRITEFUNCTION, c1.body.write)
-c2.setopt(c2.WRITEFUNCTION, c2.body.write)
-c3.setopt(c3.WRITEFUNCTION, c3.body.write)
-
-m = pycurl.CurlMulti()
-m.add_handle(c1)
-m.add_handle(c2)
-m.add_handle(c3)
-
-# Number of seconds to wait for a timeout to happen
-SELECT_TIMEOUT = 1.0
-
-# Stir the state machine into action
-while 1:
- ret, num_handles = m.perform()
- if ret != pycurl.E_CALL_MULTI_PERFORM:
- break
-
-# Keep going until all the connections have terminated
-while num_handles:
- apply(select.select, m.fdset() + (SELECT_TIMEOUT,))
- while 1:
- ret, num_handles = m.perform()
- if ret != pycurl.E_CALL_MULTI_PERFORM:
- break
-
-# Cleanup
-m.remove_handle(c3)
-m.remove_handle(c2)
-m.remove_handle(c1)
-m.close()
-c1.body.close()
-c2.body.close()
-c3.body.close()
-c1.close()
-c2.close()
-c3.close()
-print "http://www.python.org is in file doc1"
-print "http://curl.haxx.se is in file doc2"
-print "http://slashdot.org is in file doc3"
diff --git a/tests/test_multi5.py b/tests/test_multi5.py
deleted file mode 100644
index 3f0c8df..0000000
--- a/tests/test_multi5.py
+++ /dev/null
@@ -1,60 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-# $Id$
-
-import sys, select, time
-import pycurl
-
-c1 = pycurl.Curl()
-c2 = pycurl.Curl()
-c3 = pycurl.Curl()
-c1.setopt(c1.URL, "http://www.python.org")
-c2.setopt(c2.URL, "http://curl.haxx.se")
-c3.setopt(c3.URL, "http://slashdot.org")
-c1.body = open("doc1", "wb")
-c2.body = open("doc2", "wb")
-c3.body = open("doc3", "wb")
-c1.setopt(c1.WRITEFUNCTION, c1.body.write)
-c2.setopt(c2.WRITEFUNCTION, c2.body.write)
-c3.setopt(c3.WRITEFUNCTION, c3.body.write)
-
-m = pycurl.CurlMulti()
-m.add_handle(c1)
-m.add_handle(c2)
-m.add_handle(c3)
-
-# Number of seconds to wait for a timeout to happen
-SELECT_TIMEOUT = 1.0
-
-# Stir the state machine into action
-while 1:
- ret, num_handles = m.perform()
- if ret != pycurl.E_CALL_MULTI_PERFORM:
- break
-
-# Keep going until all the connections have terminated
-while num_handles:
- # The select method uses fdset internally to determine which file descriptors
- # to check.
- m.select(SELECT_TIMEOUT)
- while 1:
- ret, num_handles = m.perform()
- if ret != pycurl.E_CALL_MULTI_PERFORM:
- break
-
-# Cleanup
-m.remove_handle(c3)
-m.remove_handle(c2)
-m.remove_handle(c1)
-m.close()
-c1.body.close()
-c2.body.close()
-c3.body.close()
-c1.close()
-c2.close()
-c3.close()
-print "http://www.python.org is in file doc1"
-print "http://curl.haxx.se is in file doc2"
-print "http://slashdot.org is in file doc3"
-
diff --git a/tests/test_multi6.py b/tests/test_multi6.py
deleted file mode 100644
index 35a284f..0000000
--- a/tests/test_multi6.py
+++ /dev/null
@@ -1,62 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-# $Id$
-
-import sys, select, time
-import pycurl
-
-c1 = pycurl.Curl()
-c2 = pycurl.Curl()
-c3 = pycurl.Curl()
-c1.setopt(c1.URL, "http://www.python.org")
-c2.setopt(c2.URL, "http://curl.haxx.se")
-c3.setopt(c3.URL, "http://slashdot.org")
-c1.body = open("doc1", "wb")
-c2.body = open("doc2", "wb")
-c3.body = open("doc3", "wb")
-c1.setopt(c1.WRITEFUNCTION, c1.body.write)
-c2.setopt(c2.WRITEFUNCTION, c2.body.write)
-c3.setopt(c3.WRITEFUNCTION, c3.body.write)
-
-m = pycurl.CurlMulti()
-m.add_handle(c1)
-m.add_handle(c2)
-m.add_handle(c3)
-
-# Number of seconds to wait for a timeout to happen
-SELECT_TIMEOUT = 1.0
-
-# Stir the state machine into action
-while 1:
- ret, num_handles = m.perform()
- if ret != pycurl.E_CALL_MULTI_PERFORM:
- break
-
-# Keep going until all the connections have terminated
-while num_handles:
- # The select method uses fdset internally to determine which file descriptors
- # to check.
- m.select(SELECT_TIMEOUT)
- while 1:
- ret, num_handles = m.perform()
- # Print the message, if any
- print m.info_read(1)
- if ret != pycurl.E_CALL_MULTI_PERFORM:
- break
-
-# Cleanup
-m.remove_handle(c3)
-m.remove_handle(c2)
-m.remove_handle(c1)
-m.close()
-c1.body.close()
-c2.body.close()
-c3.body.close()
-c1.close()
-c2.close()
-c3.close()
-print "http://www.python.org is in file doc1"
-print "http://curl.haxx.se is in file doc2"
-print "http://slashdot.org is in file doc3"
-
diff --git a/tests/test_multi_socket.py b/tests/test_multi_socket.py
deleted file mode 100644
index 6768061..0000000
--- a/tests/test_multi_socket.py
+++ /dev/null
@@ -1,82 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-# $Id$
-
-import os, sys
-try:
- from cStringIO import StringIO
-except ImportError:
- from StringIO import StringIO
-import pycurl
-
-
-urls = (
- "http://curl.haxx.se",
- "http://www.python.org",
- "http://pycurl.sourceforge.net",
-)
-
-# Read list of URIs from file specified on commandline
-try:
- urls = open(sys.argv[1], "rb").readlines()
-except IndexError:
- # No file was specified
- pass
-
-# timer callback
-def timer(msecs):
- print 'Timer callback msecs:', msecs
-
-# socket callback
-def socket(event, socket, multi, data):
- print event, socket, multi, data
-# multi.assign(socket, timer)
-
-# init
-m = pycurl.CurlMulti()
-m.setopt(pycurl.M_PIPELINING, 1)
-m.setopt(pycurl.M_TIMERFUNCTION, timer)
-m.setopt(pycurl.M_SOCKETFUNCTION, socket)
-m.handles = []
-for url in urls:
- c = pycurl.Curl()
- # save info in standard Python attributes
- c.url = url
- c.body = StringIO()
- c.http_code = -1
- m.handles.append(c)
- # pycurl API calls
- c.setopt(c.URL, c.url)
- c.setopt(c.WRITEFUNCTION, c.body.write)
- m.add_handle(c)
-
-# get data
-num_handles = len(m.handles)
-while num_handles:
- while 1:
- ret, num_handles = m.socket_all()
- if ret != pycurl.E_CALL_MULTI_PERFORM:
- break
- # currently no more I/O is pending, could do something in the meantime
- # (display a progress bar, etc.)
- m.select(1.0)
-
-# close handles
-for c in m.handles:
- # save info in standard Python attributes
- c.http_code = c.getinfo(c.HTTP_CODE)
- # pycurl API calls
- m.remove_handle(c)
- c.close()
-m.close()
-
-# print result
-for c in m.handles:
- data = c.body.getvalue()
- if 0:
- print "**********", c.url, "**********"
- print data
- else:
- print "%-53s http_code %3d, %6d bytes" % (c.url, c.http_code, len(data))
-
diff --git a/tests/test_multi_socket_select.py b/tests/test_multi_socket_select.py
deleted file mode 100644
index 1f56d1d..0000000
--- a/tests/test_multi_socket_select.py
+++ /dev/null
@@ -1,105 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-# $Id$
-
-import os, sys
-try:
- from cStringIO import StringIO
-except ImportError:
- from StringIO import StringIO
-import pycurl
-import select
-
-sockets = set()
-timeout = 0
-
-urls = (
- "http://curl.haxx.se",
- "http://www.python.org",
- "http://pycurl.sourceforge.net",
-)
-
-# Read list of URIs from file specified on commandline
-try:
- urls = open(sys.argv[1], "rb").readlines()
-except IndexError:
- # No file was specified
- pass
-
-# timer callback
-def timer(msecs):
- global timeout
- timeout = msecs
- print 'Timer callback msecs:', msecs
-
-# socket callback
-def socket(event, socket, multi, data):
- if event == pycurl.POLL_REMOVE:
- print "Remove Socket %d"%socket
- sockets.remove(socket)
- else:
- if socket not in sockets:
- print "Add socket %d"%socket
- sockets.add(socket)
- print event, socket, multi, data
-
-# init
-m = pycurl.CurlMulti()
-m.setopt(pycurl.M_PIPELINING, 1)
-m.setopt(pycurl.M_TIMERFUNCTION, timer)
-m.setopt(pycurl.M_SOCKETFUNCTION, socket)
-m.handles = []
-for url in urls:
- c = pycurl.Curl()
- # save info in standard Python attributes
- c.url = url
- c.body = StringIO()
- c.http_code = -1
- m.handles.append(c)
- # pycurl API calls
- c.setopt(c.URL, c.url)
- c.setopt(c.WRITEFUNCTION, c.body.write)
- m.add_handle(c)
-
-# get data
-num_handles = len(m.handles)
-
-while (pycurl.E_CALL_MULTI_PERFORM==m.socket_all()[0]):
- pass
-
-timeout = m.timeout()
-
-
-while True:
- (rr, wr, er) = select.select(sockets,sockets,sockets,timeout/1000.0)
- socketSet = set(rr+wr+er)
- if socketSet:
- for s in socketSet:
- while True:
- (ret,running) = m.socket_action(s,0)
- if ret!=pycurl.E_CALL_MULTI_PERFORM:
- break
- else:
- (ret,running) = m.socket_action(pycurl.SOCKET_TIMEOUT,0)
- if running==0:
- break
-
-# close handles
-for c in m.handles:
- # save info in standard Python attributes
- c.http_code = c.getinfo(c.HTTP_CODE)
- # pycurl API calls
- m.remove_handle(c)
- c.close()
-m.close()
-
-# print result
-for c in m.handles:
- data = c.body.getvalue()
- if 0:
- print "**********", c.url, "**********"
- print data
- else:
- print "%-53s http_code %3d, %6d bytes" % (c.url, c.http_code, len(data))
-
diff --git a/tests/test_multi_timer.py b/tests/test_multi_timer.py
deleted file mode 100644
index 17371d3..0000000
--- a/tests/test_multi_timer.py
+++ /dev/null
@@ -1,76 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-# $Id$
-
-import os, sys
-try:
- from cStringIO import StringIO
-except ImportError:
- from StringIO import StringIO
-import pycurl
-
-
-urls = (
- "http://curl.haxx.se",
- "http://www.python.org",
- "http://pycurl.sourceforge.net",
-)
-
-# Read list of URIs from file specified on commandline
-try:
- urls = open(sys.argv[1], "rb").readlines()
-except IndexError:
- # No file was specified
- pass
-
-# timer callback
-def timer(msecs):
- print 'Timer callback msecs:', msecs
-
-# init
-m = pycurl.CurlMulti()
-m.setopt(pycurl.M_PIPELINING, 1)
-m.setopt(pycurl.M_TIMERFUNCTION, timer)
-m.handles = []
-for url in urls:
- c = pycurl.Curl()
- # save info in standard Python attributes
- c.url = url
- c.body = StringIO()
- c.http_code = -1
- m.handles.append(c)
- # pycurl API calls
- c.setopt(c.URL, c.url)
- c.setopt(c.WRITEFUNCTION, c.body.write)
- m.add_handle(c)
-
-# get data
-num_handles = len(m.handles)
-while num_handles:
- while 1:
- ret, num_handles = m.perform()
- if ret != pycurl.E_CALL_MULTI_PERFORM:
- break
- # currently no more I/O is pending, could do something in the meantime
- # (display a progress bar, etc.)
- m.select(1.0)
-
-# close handles
-for c in m.handles:
- # save info in standard Python attributes
- c.http_code = c.getinfo(c.HTTP_CODE)
- # pycurl API calls
- m.remove_handle(c)
- c.close()
-m.close()
-
-# print result
-for c in m.handles:
- data = c.body.getvalue()
- if 0:
- print "**********", c.url, "**********"
- print data
- else:
- print "%-53s http_code %3d, %6d bytes" % (c.url, c.http_code, len(data))
-
diff --git a/tests/test_multi_vs_thread.py b/tests/test_multi_vs_thread.py
deleted file mode 100644
index 0caed60..0000000
--- a/tests/test_multi_vs_thread.py
+++ /dev/null
@@ -1,262 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-# $Id$
-
-import os, sys, time
-from threading import Thread, RLock
-try:
- from cStringIO import StringIO
-except ImportError:
- from StringIO import StringIO
-import pycurl
-
-# We should ignore SIGPIPE when using pycurl.NOSIGNAL - see
-# the libcurl tutorial for more info.
-try:
- import signal
- from signal import SIGPIPE, SIG_IGN
- signal.signal(signal.SIGPIPE, signal.SIG_IGN)
-except ImportError:
- pass
-
-# The conclusion is: the multi interface is fastest!
-
-NUM_PAGES = 30
-NUM_THREADS = 10
-assert NUM_PAGES % NUM_THREADS == 0
-
-##URL = "http://pycurl.sourceforge.net/tests/testgetvars.php?%d"
-URL = "http://pycurl.sourceforge.net/tests/teststaticpage.html?%d"
-
-
-#
-# util
-#
-
-class Curl:
- def __init__(self, url):
- self.url = url
- self.body = StringIO()
- self.http_code = -1
- # pycurl API calls
- self._curl = pycurl.Curl()
- self._curl.setopt(pycurl.URL, self.url)
- self._curl.setopt(pycurl.WRITEFUNCTION, self.body.write)
- self._curl.setopt(pycurl.NOSIGNAL, 1)
-
- def perform(self):
- self._curl.perform()
-
- def close(self):
- self.http_code = self._curl.getinfo(pycurl.HTTP_CODE)
- self._curl.close()
-
-
-def print_result(items):
- return # DO NOTHING
- #
- for c in items:
- data = c.body.getvalue()
- if 0:
- print "**********", c.url, "**********"
- print data
- elif 1:
- print "%-60s %3d %6d" % (c.url, c.http_code, len(data))
-
-
-###
-### 1) multi
-###
-
-def test_multi():
- clock1 = time.time()
-
- # init
- handles = []
- m = pycurl.CurlMulti()
- for i in range(NUM_PAGES):
- c = Curl(URL %i)
- m.add_handle(c._curl)
- handles.append(c)
-
- clock2 = time.time()
-
- # stir state machine into action
- while 1:
- ret, num_handles = m.perform()
- if ret != pycurl.E_CALL_MULTI_PERFORM:
- break
-
- # get data
- while num_handles:
- m.select(1.0)
- while 1:
- ret, num_handles = m.perform()
- if ret != pycurl.E_CALL_MULTI_PERFORM:
- break
-
- clock3 = time.time()
-
- # close handles
- for c in handles:
- c.close()
- m.close()
-
- clock4 = time.time()
- print "multi interface: %d pages: perform %5.2f secs, total %5.2f secs" % (NUM_PAGES, clock3 - clock2, clock4 - clock1)
-
- # print result
- print_result(handles)
-
-
-
-###
-### 2) thread
-###
-
-class Test(Thread):
- def __init__(self, lock=None):
- Thread.__init__(self)
- self.lock = lock
- self.items = []
-
- def run(self):
- if self.lock:
- self.lock.acquire()
- self.lock.release()
- for c in self.items:
- c.perform()
-
-
-def test_threads(lock=None):
- clock1 = time.time()
-
- # create and start threads, but block them
- if lock:
- lock.acquire()
-
- # init (FIXME - this is ugly)
- threads = []
- handles = []
- t = None
- for i in range(NUM_PAGES):
- if i % (NUM_PAGES / NUM_THREADS) == 0:
- t = Test(lock)
- if lock:
- t.start()
- threads.append(t)
- c = Curl(URL % i)
- t.items.append(c)
- handles.append(c)
- assert len(handles) == NUM_PAGES
- assert len(threads) == NUM_THREADS
-
- clock2 = time.time()
-
- #
- if lock:
- # release lock to let the blocked threads run
- lock.release()
- else:
- # start threads
- for t in threads:
- t.start()
- # wait for threads to finish
- for t in threads:
- t.join()
-
- clock3 = time.time()
-
- # close handles
- for c in handles:
- c.close()
-
- clock4 = time.time()
- if lock:
- print "thread interface [lock]: %d pages: perform %5.2f secs, total %5.2f secs" % (NUM_PAGES, clock3 - clock2, clock4 - clock1)
- else:
- print "thread interface: %d pages: perform %5.2f secs, total %5.2f secs" % (NUM_PAGES, clock3 - clock2, clock4 - clock1)
-
- # print result
- print_result(handles)
-
-
-
-###
-### 3) thread - threads grab curl objects on demand from a shared pool
-###
-
-class TestPool(Thread):
- def __init__(self, lock, pool):
- Thread.__init__(self)
- self.lock = lock
- self.pool = pool
-
- def run(self):
- while 1:
- self.lock.acquire()
- c = None
- if self.pool:
- c = self.pool.pop()
- self.lock.release()
- if c is None:
- break
- c.perform()
-
-
-def test_thread_pool(lock):
- clock1 = time.time()
-
- # init
- handles = []
- for i in range(NUM_PAGES):
- c = Curl(URL %i)
- handles.append(c)
-
- # create and start threads, but block them
- lock.acquire()
- threads = []
- pool = handles[:] # shallow copy of the list, shared for pop()
- for i in range(NUM_THREADS):
- t = TestPool(lock, pool)
- t.start()
- threads.append(t)
- assert len(pool) == NUM_PAGES
- assert len(threads) == NUM_THREADS
-
- clock2 = time.time()
-
- # release lock to let the blocked threads run
- lock.release()
-
- # wait for threads to finish
- for t in threads:
- t.join()
-
- clock3 = time.time()
-
- # close handles
- for c in handles:
- c.close()
-
- clock4 = time.time()
- print "thread interface [pool]: %d pages: perform %5.2f secs, total %5.2f secs" % (NUM_PAGES, clock3 - clock2, clock4 - clock1)
-
- # print result
- print_result(handles)
-
-
-
-lock = RLock()
-if 1:
- test_multi()
- test_threads()
- test_threads(lock)
- test_thread_pool(lock)
-else:
- test_thread_pool(lock)
- test_threads(lock)
- test_threads()
- test_multi()
-
diff --git a/tests/test_post.py b/tests/test_post.py
deleted file mode 100644
index f0a8ad0..0000000
--- a/tests/test_post.py
+++ /dev/null
@@ -1,24 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-# $Id$
-
-import urllib
-import pycurl
-
-# simple
-pf = {'field1': 'value1'}
-
-# multiple fields
-pf = {'field1':'value1', 'field2':'value2 with blanks', 'field3':'value3'}
-
-# multiple fields with & in field
-pf = {'field1':'value1', 'field2':'value2 with blanks and & chars',
- 'field3':'value3'}
-
-c = pycurl.Curl()
-c.setopt(c.URL, 'http://pycurl.sourceforge.net/tests/testpostvars.php')
-c.setopt(c.POSTFIELDS, urllib.urlencode(pf))
-c.setopt(c.VERBOSE, 1)
-c.perform()
-c.close()
diff --git a/tests/test_post2.py b/tests/test_post2.py
deleted file mode 100644
index 74a6eca..0000000
--- a/tests/test_post2.py
+++ /dev/null
@@ -1,18 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-# $Id$
-
-import pycurl
-
-pf = [('field1', 'this is a test using httppost & stuff'),
- ('field2', (pycurl.FORM_FILE, 'test_post.py', pycurl.FORM_FILE, 'test_post2.py')),
- ('field3', (pycurl.FORM_CONTENTS, 'this is wei\000rd, but null-bytes are okay'))
- ]
-
-c = pycurl.Curl()
-c.setopt(c.URL, 'http://www.contactor.se/~dast/postit.cgi')
-c.setopt(c.HTTPPOST, pf)
-c.setopt(c.VERBOSE, 1)
-c.perform()
-c.close()
diff --git a/tests/test_post3.py b/tests/test_post3.py
deleted file mode 100644
index 617eba2..0000000
--- a/tests/test_post3.py
+++ /dev/null
@@ -1,32 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-# $Id$
-
-import urllib
-POSTSTRING = urllib.urlencode({'field1':'value1', 'field2':'value2 with blanks', 'field3':'value3'})
-
-class test:
-
- def __init__(self):
- self.finished = False
-
- def read_cb(self, size):
- assert len(POSTSTRING) <= size
- if not self.finished:
- self.finished = True
- return POSTSTRING
- else:
- # Nothing more to read
- return ""
-
-import pycurl
-c = pycurl.Curl()
-t = test()
-c.setopt(c.URL, 'http://pycurl.sourceforge.net/tests/testpostvars.php')
-c.setopt(c.POST, 1)
-c.setopt(c.POSTFIELDSIZE, len(POSTSTRING))
-c.setopt(c.READFUNCTION, t.read_cb)
-c.setopt(c.VERBOSE, 1)
-c.perform()
-c.close()
diff --git a/tests/test_reset.py b/tests/test_reset.py
deleted file mode 100644
index 1addcfe..0000000
--- a/tests/test_reset.py
+++ /dev/null
@@ -1,75 +0,0 @@
-#!/usr/bin/python
-
-import sys
-import pycurl
-
-saw_error = 1
-
-def main():
- global saw_error
-
- pycurl.global_init(pycurl.GLOBAL_DEFAULT)
-
- outf = file("/dev/null", "rb+")
- cm = pycurl.CurlMulti()
-
- # Set multi handle's options
- cm.setopt(pycurl.M_PIPELINING, 1)
-
- eh = pycurl.Curl()
-
- for x in range(1, 20):
-
- eh.setopt(pycurl.WRITEDATA, outf)
- eh.setopt(pycurl.URL, sys.argv[1])
- cm.add_handle(eh)
-
- while 1:
- ret, active_handles = cm.perform()
- if ret != pycurl.E_CALL_MULTI_PERFORM:
- break
-
- while active_handles:
- ret = cm.select(1.0)
- if ret == -1:
- continue
- while 1:
- ret, active_handles = cm.perform()
- if ret != pycurl.E_CALL_MULTI_PERFORM:
- break
-
- count, good, bad = cm.info_read()
-
- for h, en, em in bad:
- print "Transfer to %s failed with %d, %s\n" % \
- (h.getinfo(pycurl.EFFECTIVE_URL), en, em)
- raise RuntimeError
-
- for h in good:
- httpcode = h.getinfo(pycurl.RESPONSE_CODE)
- if httpcode != 200:
- print "Transfer to %s failed with code %d\n" %\
- (h.getinfo(pycurl.EFFECTIVE_URL), httpcode)
- raise RuntimeError
-
- else:
- print "Recd %d bytes from %s" % \
- (h.getinfo(pycurl.SIZE_DOWNLOAD),
- h.getinfo(pycurl.EFFECTIVE_URL))
-
- cm.remove_handle(eh)
- eh.reset()
-
- eh.close()
- cm.close()
- outf.close()
-
- pycurl.global_cleanup()
-
-
-if __name__ == '__main__':
- if len(sys.argv) != 2:
- print "Usage: %s <url>" % sys.argv[0]
- sys.exit(2)
- main()
-
diff --git a/tests/test_share.py b/tests/test_share.py
deleted file mode 100644
index 3332cda..0000000
--- a/tests/test_share.py
+++ /dev/null
@@ -1,34 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-# $Id$
-
-import sys
-import pycurl
-import threading
-
-print >>sys.stderr, 'Testing', pycurl.version
-
-
-class Test(threading.Thread):
-
- def __init__(self, share):
- threading.Thread.__init__(self)
- self.curl = pycurl.Curl()
- self.curl.setopt(pycurl.URL, 'http://curl.haxx.se')
- self.curl.setopt(pycurl.SHARE, share)
-
- def run(self):
- self.curl.perform()
- self.curl.close()
-
-s = pycurl.CurlShare()
-s.setopt(pycurl.SH_SHARE, pycurl.LOCK_DATA_COOKIE)
-s.setopt(pycurl.SH_SHARE, pycurl.LOCK_DATA_DNS)
-
-t1 = Test(s)
-t2 = Test(s)
-
-t1.start()
-t2.start()
-del s
diff --git a/tests/test_socketopen.py b/tests/test_socketopen.py
deleted file mode 100644
index d3f0a62..0000000
--- a/tests/test_socketopen.py
+++ /dev/null
@@ -1,17 +0,0 @@
-import pycurl
-import StringIO
-import socket
-
-def socketopen(family, socktype, protocol):
- print family, socktype, protocol
- s = socket.socket(family, socktype, protocol)
- s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
- return s
-
-sio = StringIO.StringIO()
-
-c = pycurl.Curl()
-c.setopt(pycurl.OPENSOCKETFUNCTION, socketopen)
-c.setopt(pycurl.URL, 'http://camvine.com')
-c.setopt(pycurl.WRITEFUNCTION, sio.write)
-c.perform()
diff --git a/tests/test_stringio.py b/tests/test_stringio.py
deleted file mode 100644
index 25e639b..0000000
--- a/tests/test_stringio.py
+++ /dev/null
@@ -1,25 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# vi:ts=4:et
-# $Id$
-
-import sys
-try:
- from cStringIO import StringIO
-except ImportError:
- from StringIO import StringIO
-import pycurl
-
-url = "http://curl.haxx.se/dev/"
-
-print "Testing", pycurl.version
-
-body = StringIO()
-c = pycurl.Curl()
-c.setopt(c.URL, url)
-c.setopt(c.WRITEFUNCTION, body.write)
-c.perform()
-c.close()
-
-contents = body.getvalue()
-print contents
--
1.7.1
From 217287f1378ef018fae789f748470a170515a3ea Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 13:36:38 -0500
Subject: [PATCH 063/112] Fix make test to run nosetests (closes #5)
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
Makefile | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/Makefile b/Makefile
index 9b2369d..9475250 100644
--- a/Makefile
+++ b/Makefile
@@ -7,6 +7,7 @@ SHELL = /bin/sh
PYTHON = python2.3
PYTHON = python
+NOSETESTS = nosetests
all build:
$(PYTHON) setup.py build
@@ -15,7 +16,8 @@ build-7.10.8:
$(PYTHON) setup.py build --curl-config=/home/hosts/localhost/packages/curl-7.10.8/bin/curl-config
test: build
- $(PYTHON) tests/test_internals.py -q
+ PYTHONPATH=$$(ls -d build/lib.*):$$PYTHONPATH \
+ $(NOSETESTS)
# (needs GNU binutils)
strip: build
--
1.7.1
From dd6cb3db28d4960e5a5902731bd989b918a018ce Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 04:25:47 -0500
Subject: [PATCH 064/112] First stab at travis configuration
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
.travis.yml | 11 +++++++++++
requirements-dev.txt | 1 +
2 files changed, 12 insertions(+), 0 deletions(-)
create mode 100644 .travis.yml
create mode 100644 requirements-dev.txt
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..2350dfb
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,11 @@
+language: python
+python:
+ - "2.5"
+ - "2.6"
+ - "2.7"
+install: >
+ pip install -r requirements-dev.txt --use-mirrors &&
+ sudo apt-get install vsftpd
+script: >
+ export PYCURL_VSFTPD_PATH=/usr/sbin/vsftpd &&
+ nosetests
diff --git a/requirements-dev.txt b/requirements-dev.txt
new file mode 100644
index 0000000..f3c7e8e
--- /dev/null
+++ b/requirements-dev.txt
@@ -0,0 +1 @@
+nose
--
1.7.1
From 6d4f146d910400dfcfe9ea758024fbf0a118242f Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 04:37:47 -0500
Subject: [PATCH 065/112] Building the C module will help
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
.travis.yml | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 2350dfb..ae17929 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,5 +7,7 @@ install: >
pip install -r requirements-dev.txt --use-mirrors &&
sudo apt-get install vsftpd
script: >
+ make &&
+ export PYTHONPATH=build/lib.* &&
export PYCURL_VSFTPD_PATH=/usr/sbin/vsftpd &&
nosetests
--
1.7.1
From 08975482a2e8f09128e261c352866049b1b3b928 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 04:45:46 -0500
Subject: [PATCH 066/112] Go through more hoops (/bin/dash in play?)
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
.travis.yml | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index ae17929..4afdff9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,6 +8,6 @@ install: >
sudo apt-get install vsftpd
script: >
make &&
- export PYTHONPATH=build/lib.* &&
+ export PYTHONPATH=$(ls -d build/lib.*) &&
export PYCURL_VSFTPD_PATH=/usr/sbin/vsftpd &&
nosetests
--
1.7.1
From b55b5ace06a87a7bd1464b3be888a9d71b204a58 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 04:50:21 -0500
Subject: [PATCH 067/112] Forgot about bottle
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
requirements-dev.txt | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/requirements-dev.txt b/requirements-dev.txt
index f3c7e8e..36b0b24 100644
--- a/requirements-dev.txt
+++ b/requirements-dev.txt
@@ -1 +1,2 @@
+bottle
nose
--
1.7.1
From cbf6fd82722d6db1a6bf8c20b2a95bc04373a31d Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 06:20:25 -0500
Subject: [PATCH 068/112] Python 2.5 needs simplejson
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
.travis.yml | 6 +++++-
requirements-dev-2.5.txt | 2 ++
2 files changed, 7 insertions(+), 1 deletions(-)
create mode 100644 requirements-dev-2.5.txt
diff --git a/.travis.yml b/.travis.yml
index 4afdff9..4268895 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,7 +4,11 @@ python:
- "2.6"
- "2.7"
install: >
- pip install -r requirements-dev.txt --use-mirrors &&
+ if test -e requirements-dev-$TRAVIS_PYTHON_VERSION.txt; then
+ pip install -r requirements-dev-$TRAVIS_PYTHON_VERSION.txt --use-mirrors
+ else
+ pip install -r requirements-dev.txt --use-mirrors
+ fi &&
sudo apt-get install vsftpd
script: >
make &&
diff --git a/requirements-dev-2.5.txt b/requirements-dev-2.5.txt
new file mode 100644
index 0000000..52e3460
--- /dev/null
+++ b/requirements-dev-2.5.txt
@@ -0,0 +1,2 @@
+-r requirements-dev.txt
+simplejson
--
1.7.1
From c90d60edd47a2a3ef20b3a09f2c2c3dc59938746 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Thu, 7 Mar 2013 04:23:52 -0500
Subject: [PATCH 069/112] Expand readme (mostly borrowed from @Lispython's fork)
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
README | 13 --------
README.rst | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 93 insertions(+), 13 deletions(-)
delete mode 100644 README
create mode 100644 README.rst
diff --git a/README b/README
deleted file mode 100644
index 6b3e1d4..0000000
--- a/README
+++ /dev/null
@@ -1,13 +0,0 @@
-License
--------
-
-Copyright (C) 2001-2008 by Kjetil Jacobsen <kjetilja at gmail.com>
-Copyright (C) 2001-2008 by Markus F.X.J. Oberhumer <markus at oberhumer.com>
-
-All rights reserved.
-
-PycURL is dual licensed under the LGPL and an MIT/X derivative license
-based on the cURL license. A full copy of the LGPL license is included
-in the file COPYING. A full copy of the MIT/X derivative license is
-included in the file COPYING2. You can redistribute and/or modify PycURL
-according to the terms of either license.
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..3518d9d
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,93 @@
+PycURL: Python interface to libcurl
+====================================
+
+PycURL is a Python interface to `libcurl`_. PycURL can be used to fetch objects
+identified by a URL from a Python program, similar to the `urllib`_ Python module.
+PycURL is mature, very fast, and supports a lot of features.
+
+Overview
+--------
+
+- libcurl is a free and easy-to-use client-side URL transfer library, supporting
+ FTP, FTPS, HTTP, HTTPS, SCP, SFTP, TFTP, TELNET, DICT, LDAP, LDAPS, FILE, IMAP,
+ SMTP, POP3 and RTSP. libcurl supports SSL certificates, HTTP POST, HTTP PUT,
+ FTP uploading, HTTP form based upload, proxies, cookies, user+password
+ authentication (Basic, Digest, NTLM, Negotiate, Kerberos4), file transfer
+ resume, http proxy tunneling and more!
+
+- libcurl is highly portable, it builds and works identically on numerous
+ platforms, including Solaris, NetBSD, FreeBSD, OpenBSD, Darwin, HPUX, IRIX,
+ AIX, Tru64, Linux, UnixWare, HURD, Windows, Amiga, OS/2, BeOs, Mac OS X,
+ Ultrix, QNX, OpenVMS, RISC OS, Novell NetWare, DOS and more...
+
+- libcurl is `free`_, `thread-safe`_, `IPv6 compatible`_, `feature rich`_,
+ `well supported`_, `fast`_, `thoroughly documented`_ and is already used by
+ many known, big and successful `companies`_ and numerous `applications`_.
+
+.. _free: http://curl.haxx.se/docs/copyright.html
+.. _thread-safe: http://curl.haxx.se/libcurl/features.html#thread
+.. _`IPv6 compatible`: http://curl.haxx.se/libcurl/features.html#ipv6
+.. _`feature rich`: http://curl.haxx.se/libcurl/features.html#features
+.. _`well supported`: http://curl.haxx.se/libcurl/features.html#support
+.. _`fast`: http://curl.haxx.se/libcurl/features.html#fast
+.. _`thoroughly documented`: http://curl.haxx.se/libcurl/features.html#docs
+.. _companies: http://curl.haxx.se/docs/companies.html
+.. _applications: http://curl.haxx.se/libcurl/using/apps.html
+
+Installation
+------------
+
+You can install the most recent PycURL version using `easy_install`_::
+
+ easy_install pycurl
+
+or `pip`_::
+
+ pip install pycurl
+
+
+.. _easy_install: http://peak.telecommunity.com/DevCenter/EasyInstall
+.. _pip: http://pypi.python.org/pypi/pip
+
+Contribute
+----------
+
+For smaller changes:
+
+#. Fork `the repository`_ on Github.
+#. Create a branch off **master**.
+#. Make your changes.
+#. Write a test which shows that the bug was fixed or that the feature
+ works as expected.
+#. Send a pull request.
+
+For larger changes:
+
+#. Join the `mailing list`_.
+#. Discuss your proposal on the mailing list.
+#. When consensus is reached, implement it as described above.
+
+.. image:: https://api.travis-ci.org/p/pycurl.png
+ :target: https://travis-ci.org/p/pycurl
+
+License
+-------
+
+::
+
+ Copyright (C) 2001-2008 by Kjetil Jacobsen <kjetilja at gmail.com>
+ Copyright (C) 2001-2008 by Markus F.X.J. Oberhumer <markus at oberhumer.com>
+
+ All rights reserved.
+
+ PycURL is dual licensed under the LGPL and an MIT/X derivative license
+ based on the cURL license. A full copy of the LGPL license is included
+ in the file COPYING. A full copy of the MIT/X derivative license is
+ included in the file COPYING2. You can redistribute and/or modify PycURL
+ according to the terms of either license.
+
+.. _PycURL: http://pycurl.sourceforge.net/
+.. _libcurl: http://curl.haxx.se/libcurl/
+.. _urllib: http://docs.python.org/library/urllib.html
+.. _`the repository`: https://github.com/p/pycurl
+.. _`mailing list`: http://cool.haxx.se/mailman/listinfo/curl-and-python
--
1.7.1
From 27c1817d13b1773558d5a7b6b327c14c5b4ffdf9 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Thu, 7 Mar 2013 04:30:23 -0500
Subject: [PATCH 070/112] Readme -> readme.rst elsewhere
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
MANIFEST.in | 2 +-
setup.py | 2 +-
tests/ftp_test.py | 6 +++---
tests/post_test.py | 4 ++--
4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/MANIFEST.in b/MANIFEST.in
index 7d5aaf5..11ce1fe 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -8,7 +8,7 @@ include COPYING
include COPYING2
include INSTALL
include Makefile
-include README
+include README.rst
include TODO
include MANIFEST.in
include src/Makefile
diff --git a/setup.py b/setup.py
index 33704ef..235e4c9 100644
--- a/setup.py
+++ b/setup.py
@@ -166,7 +166,7 @@ def get_data_files():
else:
datadir = os.path.join("share", "doc", PACKAGE)
#
- files = ["ChangeLog", "COPYING", "COPYING2", "INSTALL", "README", "TODO",]
+ files = ["ChangeLog", "COPYING", "COPYING2", "INSTALL", "README.rst", "TODO",]
if files:
data_files.append((os.path.join(datadir), files))
files = glob.glob(os.path.join("doc", "*.html"))
diff --git a/tests/ftp_test.py b/tests/ftp_test.py
index fa2ef79..5ee380c 100644
--- a/tests/ftp_test.py
+++ b/tests/ftp_test.py
@@ -26,7 +26,7 @@ class FtpTest(unittest.TestCase):
self.curl.perform()
result = sio.getvalue()
- assert 'README' in result
+ assert 'README.rst' in result
assert 'INSTALL' in result
# XXX this test needs to be fixed
@@ -38,7 +38,7 @@ class FtpTest(unittest.TestCase):
self.curl.perform()
result = sio.getvalue()
- assert 'README' not in result
+ assert 'README.rst' not in result
assert 'ftp_test.py' in result
def test_epsv(self):
@@ -49,5 +49,5 @@ class FtpTest(unittest.TestCase):
self.curl.perform()
result = sio.getvalue()
- assert 'README' in result
+ assert 'README.rst' in result
assert 'INSTALL' in result
diff --git a/tests/post_test.py b/tests/post_test.py
index e8b0675..6f9d8d4 100644
--- a/tests/post_test.py
+++ b/tests/post_test.py
@@ -81,7 +81,7 @@ class PostTest(unittest.TestCase):
self.check_post(send, expect, 'http://localhost:8380/postfields')
def test_post_file(self):
- path = os.path.join(os.path.dirname(__file__), '..', 'README')
+ path = os.path.join(os.path.dirname(__file__), '..', 'README.rst')
with open(path) as f:
contents = f.read()
send = [
@@ -90,7 +90,7 @@ class PostTest(unittest.TestCase):
]
expect = [{
'name': 'field2',
- 'filename': 'README',
+ 'filename': 'README.rst',
'data': contents,
}]
self.check_post(send, expect, 'http://localhost:8380/files')
--
1.7.1
From b3a7a67683458b9b5f7d8a68df533319b6bfbcd6 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 04:50:34 -0500
Subject: [PATCH 071/112] Python 2.5 compatibility: with statement
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/default_write_function_test.py | 2 ++
tests/post_test.py | 2 ++
tests/write_to_file_test.py | 2 ++
3 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/tests/default_write_function_test.py b/tests/default_write_function_test.py
index c0d256b..1d31e97 100644
--- a/tests/default_write_function_test.py
+++ b/tests/default_write_function_test.py
@@ -2,6 +2,8 @@
# -*- coding: iso-8859-1 -*-
# vi:ts=4:et
+from __future__ import with_statement
+
import unittest
import pycurl
import sys
diff --git a/tests/post_test.py b/tests/post_test.py
index 6f9d8d4..804104e 100644
--- a/tests/post_test.py
+++ b/tests/post_test.py
@@ -2,6 +2,8 @@
# -*- coding: iso-8859-1 -*-
# vi:ts=4:et
+from __future__ import with_statement
+
import os.path
import pycurl
import unittest
diff --git a/tests/write_to_file_test.py b/tests/write_to_file_test.py
index 67c9c63..c3c8822 100644
--- a/tests/write_to_file_test.py
+++ b/tests/write_to_file_test.py
@@ -2,6 +2,8 @@
# -*- coding: iso-8859-1 -*-
# vi:ts=4:et
+from __future__ import with_statement
+
import unittest
import pycurl
import tempfile
--
1.7.1
From 370806caa376039f9ba97b9e79e7565b54a4b6f0 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 06:10:22 -0500
Subject: [PATCH 072/112] Python 2.5 compatibility: json/simplejson
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/app.py | 5 ++++-
tests/post_test.py | 5 ++++-
tests/post_with_read_callback_test.py | 5 ++++-
3 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/tests/app.py b/tests/app.py
index a83e628..eb10668 100644
--- a/tests/app.py
+++ b/tests/app.py
@@ -1,5 +1,8 @@
import bottle
-import json
+try:
+ import json
+except ImportError:
+ import simplejson as json
app = bottle.Bottle()
diff --git a/tests/post_test.py b/tests/post_test.py
index 804104e..a36a677 100644
--- a/tests/post_test.py
+++ b/tests/post_test.py
@@ -8,7 +8,10 @@ import os.path
import pycurl
import unittest
import io
-import json
+try:
+ import json
+except ImportError:
+ import simplejson as json
try:
import urllib.parse as urllib_parse
except ImportError:
diff --git a/tests/post_with_read_callback_test.py b/tests/post_with_read_callback_test.py
index a09e83a..4d8f261 100644
--- a/tests/post_with_read_callback_test.py
+++ b/tests/post_with_read_callback_test.py
@@ -6,7 +6,10 @@ import os.path
import pycurl
import unittest
import io
-import json
+try:
+ import json
+except ImportError:
+ import simplejson as json
try:
import urllib.parse as urllib_parse
except ImportError:
--
1.7.1
From d1128e970d6427e16f9eb4909531427a0c799d2e Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 06:18:02 -0500
Subject: [PATCH 073/112] Python 2.5 compatibility: except as
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/runwsgi.py | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/tests/runwsgi.py b/tests/runwsgi.py
index 5217a3f..8a978ec 100644
--- a/tests/runwsgi.py
+++ b/tests/runwsgi.py
@@ -1,5 +1,6 @@
# Run a WSGI application in a daemon thread
+import sys
import bottle
import threading
import socket
@@ -21,7 +22,8 @@ def wait_for_network_service(netloc, check_interval, num_attempts):
for i in range(num_attempts):
try:
conn = socket.create_connection(netloc, check_interval)
- except socket.error as e:
+ except socket.error:
+ e = sys.exc_info()[1]
_time.sleep(check_interval)
else:
conn.close()
--
1.7.1
From 64a832f50f7063cce2df5507b69ac2f216e22f59 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 06:23:08 -0500
Subject: [PATCH 074/112] Delete unused io imports
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/default_write_function_test.py | 1 -
tests/header_function_test.py | 1 -
tests/post_test.py | 1 -
tests/post_with_read_callback_test.py | 1 -
tests/write_to_stringio_test.py | 1 -
5 files changed, 0 insertions(+), 5 deletions(-)
diff --git a/tests/default_write_function_test.py b/tests/default_write_function_test.py
index 1d31e97..27a3d04 100644
--- a/tests/default_write_function_test.py
+++ b/tests/default_write_function_test.py
@@ -8,7 +8,6 @@ import unittest
import pycurl
import sys
import tempfile
-import io
import os
from . import app
diff --git a/tests/header_function_test.py b/tests/header_function_test.py
index bfe7173..00080ba 100644
--- a/tests/header_function_test.py
+++ b/tests/header_function_test.py
@@ -4,7 +4,6 @@
import pycurl
import unittest
-import io
import time as _time
from . import app
diff --git a/tests/post_test.py b/tests/post_test.py
index a36a677..c11c3c8 100644
--- a/tests/post_test.py
+++ b/tests/post_test.py
@@ -7,7 +7,6 @@ from __future__ import with_statement
import os.path
import pycurl
import unittest
-import io
try:
import json
except ImportError:
diff --git a/tests/post_with_read_callback_test.py b/tests/post_with_read_callback_test.py
index 4d8f261..f0776ea 100644
--- a/tests/post_with_read_callback_test.py
+++ b/tests/post_with_read_callback_test.py
@@ -5,7 +5,6 @@
import os.path
import pycurl
import unittest
-import io
try:
import json
except ImportError:
diff --git a/tests/write_to_stringio_test.py b/tests/write_to_stringio_test.py
index 018800d..e9ab0c7 100644
--- a/tests/write_to_stringio_test.py
+++ b/tests/write_to_stringio_test.py
@@ -4,7 +4,6 @@
import pycurl
import unittest
-import io
from . import app
from . import runwsgi
--
1.7.1
From 6c9103dd1769a91967dc9f5d2d0ac3a48fa9528f Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 04:54:35 -0500
Subject: [PATCH 075/112] Ignore fsync of stdout failures on travis
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/default_write_function_test.py | 13 +++++++++++--
1 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/tests/default_write_function_test.py b/tests/default_write_function_test.py
index 27a3d04..1c8ec16 100644
--- a/tests/default_write_function_test.py
+++ b/tests/default_write_function_test.py
@@ -18,6 +18,15 @@ setup_module, teardown_module = runwsgi.app_runner_setup((app.app, 8380))
STDOUT_FD_NUM = 1
+def try_fsync(fd):
+ try:
+ os.fsync(fd)
+ except OSError:
+ # On travis:
+ # OSError: [Errno 22] Invalid argument
+ # ignore
+ pass
+
class DefaultWriteFunctionTest(unittest.TestCase):
def setUp(self):
self.curl = pycurl.Curl()
@@ -38,7 +47,7 @@ class DefaultWriteFunctionTest(unittest.TestCase):
# If this flush is not done, stdout output bleeds into the next test
# that is executed (without nose output capture)
sys.stdout.flush()
- os.fsync(STDOUT_FD_NUM)
+ try_fsync(STDOUT_FD_NUM)
# I have a really hard time getting this to work with nose output capture
def skip_perform_get_with_default_write_function(self):
@@ -67,7 +76,7 @@ class DefaultWriteFunctionTest(unittest.TestCase):
self.curl.perform()
sys.stdout.flush()
finally:
- os.fsync(STDOUT_FD_NUM)
+ try_fsync(STDOUT_FD_NUM)
os.dup2(saved_stdout_fd, STDOUT_FD_NUM)
os.close(saved_stdout_fd)
#os.dup2(100, 1)
--
1.7.1
From 560621974748957f45da26461184ace7bbf05919 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 04:58:42 -0500
Subject: [PATCH 076/112] My vps says timeout might be -1 there
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/multi_socket_select_test.py | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/tests/multi_socket_select_test.py b/tests/multi_socket_select_test.py
index 0c472cf..6db8b44 100644
--- a/tests/multi_socket_select_test.py
+++ b/tests/multi_socket_select_test.py
@@ -73,8 +73,9 @@ class MultiSocketSelectTest(unittest.TestCase):
timeout = m.timeout()
-
- while True:
+ # timeout might be -1, indicating that all work is done
+ # XXX make sure there is always work to be done here?
+ while timeout >= 0:
(rr, wr, er) = select.select(sockets,sockets,sockets,timeout/1000.0)
socketSet = set(rr+wr+er)
if socketSet:
--
1.7.1
From 9de0de72ea5134d0e3976b0044936ed42e422fc4 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 06:14:57 -0500
Subject: [PATCH 077/112] Show pycurl versions in package setup
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/__init__.py | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/tests/__init__.py b/tests/__init__.py
index e69de29..c1ff976 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -0,0 +1,4 @@
+import pycurl
+
+def setup_package():
+ print('Testing %s' % pycurl.version)
--
1.7.1
From 37b493365811d2809927163de3809ac80d1bfc9a Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 06:07:19 -0500
Subject: [PATCH 078/112] Show what the entries are if assertion fails
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/debug_test.py | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/tests/debug_test.py b/tests/debug_test.py
index 8005239..d74bed9 100644
--- a/tests/debug_test.py
+++ b/tests/debug_test.py
@@ -46,4 +46,5 @@ class DebugTest(unittest.TestCase):
for t, b in self.debug_entries:
if t == wanted_t and wanted_b in b:
return
- assert False, "%d: %s not found in debug entries" % (wanted_t, wanted_b)
+ assert False, "%d: %s not found in debug entries\nEntries are:\n%s" % \
+ (wanted_t, wanted_b, repr(self.debug_entries))
--
1.7.1
From 54c08110d132bcc1f79d0484154854f7fedbe6d1 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 06:09:22 -0500
Subject: [PATCH 079/112] More informative failure message
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/multi_test.py | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/tests/multi_test.py b/tests/multi_test.py
index d9c6174..8701649 100644
--- a/tests/multi_test.py
+++ b/tests/multi_test.py
@@ -214,7 +214,10 @@ class MultiTest(unittest.TestCase):
self.assertEqual('success', m.handles[0].body.getvalue())
self.assertEqual(200, m.handles[0].http_code)
# bottle generated response body
- assert 'Error 403: Forbidden' in m.handles[1].body.getvalue()
+ body = m.handles[1].body.getvalue()
+ search = 'Error 403: Forbidden'
+ if search not in body:
+ assert False, "'%s' not found in body:\n%s" % (search, body)
self.assertEqual(403, m.handles[1].http_code)
# bottle generated response body
self.assertEqual('', m.handles[2].body.getvalue())
--
1.7.1
From 8870f4272ba3bb0042168e597a32e3c22b80dc6f Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 06:34:39 -0500
Subject: [PATCH 080/112] Return complete response bodies for 403 and 404 responses as it looks like exact wording varies between bottle versions
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/app.py | 4 ++--
tests/multi_test.py | 9 +++------
2 files changed, 5 insertions(+), 8 deletions(-)
diff --git a/tests/app.py b/tests/app.py
index eb10668..9b56ace 100644
--- a/tests/app.py
+++ b/tests/app.py
@@ -12,11 +12,11 @@ def ok():
@app.route('/status/403')
def forbidden():
- bottle.abort(403, 'forbidden')
+ return bottle.HTTPResponse('forbidden', 403)
@app.route('/status/404')
def not_found():
- bottle.abort(404, 'not found')
+ return bottle.HTTPResponse('not found', 404)
@app.route('/postfields', method='post')
def postfields():
diff --git a/tests/multi_test.py b/tests/multi_test.py
index 8701649..d540413 100644
--- a/tests/multi_test.py
+++ b/tests/multi_test.py
@@ -153,10 +153,10 @@ class MultiTest(unittest.TestCase):
self.assertEqual('success', m.handles[0].body.getvalue())
self.assertEqual(200, m.handles[0].http_code)
# bottle generated response body
- assert 'Error 403: Forbidden' in m.handles[1].body.getvalue()
+ self.assertEqual('forbidden', m.handles[1].body.getvalue())
self.assertEqual(403, m.handles[1].http_code)
# bottle generated response body
- assert 'Error 404: Not Found' in m.handles[2].body.getvalue()
+ self.assertEqual('not found', m.handles[2].body.getvalue())
self.assertEqual(404, m.handles[2].http_code)
def check_adding_closed_handle(self, close_fn):
@@ -214,10 +214,7 @@ class MultiTest(unittest.TestCase):
self.assertEqual('success', m.handles[0].body.getvalue())
self.assertEqual(200, m.handles[0].http_code)
# bottle generated response body
- body = m.handles[1].body.getvalue()
- search = 'Error 403: Forbidden'
- if search not in body:
- assert False, "'%s' not found in body:\n%s" % (search, body)
+ self.assertEqual('forbidden', m.handles[1].body.getvalue())
self.assertEqual(403, m.handles[1].http_code)
# bottle generated response body
self.assertEqual('', m.handles[2].body.getvalue())
--
1.7.1
From 567ab2309e67aecda5ba7e46069b1cb85b9bea73 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 22:15:47 -0500
Subject: [PATCH 081/112] Debug messages originated by curl 7.22 are different
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/debug_test.py | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/tests/debug_test.py b/tests/debug_test.py
index d74bed9..70e121c 100644
--- a/tests/debug_test.py
+++ b/tests/debug_test.py
@@ -32,7 +32,11 @@ class DebugTest(unittest.TestCase):
# Some checks with no particular intent
self.check(0, 'About to connect')
- self.check(0, 'Connected to localhost')
+ version = map(int, pycurl.version_info()[1].split('.'))
+ if version[0] < 7 or version[0] == 7 and version[1] <= 22:
+ self.check(0, 'connected')
+ else:
+ self.check(0, 'Connected to localhost')
self.check(0, 'port 8380')
# request
self.check(2, 'GET /success HTTP/1.1')
--
1.7.1
From d3e6168efb78f643677693afc607abd9e635dd07 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 22:17:48 -0500
Subject: [PATCH 082/112] Times in http headers are in UTC
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/header_function_test.py | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/tests/header_function_test.py b/tests/header_function_test.py
index 00080ba..7ca564d 100644
--- a/tests/header_function_test.py
+++ b/tests/header_function_test.py
@@ -34,7 +34,8 @@ class HeaderFunctionTest(unittest.TestCase):
assert len(self.header_lines) > 0
self.assertEqual("HTTP/1.0 200 OK\r\n", self.header_lines[0])
# day of week
- todays_day = _time.strftime('%a')
+ # important: must be in utc
+ todays_day = _time.strftime('%a', _time.gmtime())
# Date: Sun, 03 Mar 2013 05:38:12 GMT\r\n
self.check('Date: %s' % todays_day)
# Server: WSGIServer/0.1 Python/2.7.3\r\n
--
1.7.1
From c223f392fde2b40bb5d88763bcfd9e6883de36c0 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 22:26:19 -0500
Subject: [PATCH 083/112] Create a generalized function for curl version comparisons
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/util.py | 15 +++++++++++++++
tests/version_comparison_test.py | 15 +++++++++++++++
2 files changed, 30 insertions(+), 0 deletions(-)
create mode 100644 tests/version_comparison_test.py
diff --git a/tests/util.py b/tests/util.py
index 891da44..46ac59f 100644
--- a/tests/util.py
+++ b/tests/util.py
@@ -3,6 +3,7 @@
# $Id$
import os, sys
+import pycurl
try:
from cStringIO import StringIO
@@ -12,6 +13,20 @@ except ImportError:
except ImportError:
from io import StringIO
+def version_less_than_spec(version_tuple, spec_tuple):
+ # spec_tuple may have 2 elements, expect version_tuple to have 3 elements
+ assert len(version_tuple) >= len(spec_tuple)
+ for i in range(len(spec_tuple)):
+ if version_tuple[i] < spec_tuple[i]:
+ return True
+ if version_tuple[i] > spec_tuple[i]:
+ return False
+ return False
+
+def pycurl_version_less_than(spec_tuple):
+ version = map(int, pycurl.version_info()[1].split('.'))
+ return version_less_than_spec(version, spec_tuple)
+
#
# prepare sys.path in case we are still in the build directory
# see also: distutils/command/build.py (build_platlib)
diff --git a/tests/version_comparison_test.py b/tests/version_comparison_test.py
new file mode 100644
index 0000000..80e780c
--- /dev/null
+++ b/tests/version_comparison_test.py
@@ -0,0 +1,15 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+
+import unittest
+
+from . import util
+
+class VersionComparisonTest(unittest.TestCase):
+ def test_comparison(self):
+ assert util.version_less_than_spec((7, 22, 0), (7, 23, 0))
+ assert util.version_less_than_spec((7, 22, 0), (7, 23))
+ assert util.version_less_than_spec((7, 22, 0), (7, 22, 1))
+ assert not util.version_less_than_spec((7, 22, 0), (7, 22, 0))
+ assert not util.version_less_than_spec((7, 22, 0), (7, 22))
--
1.7.1
From e7e7a0f047d88409d9355dab3fab2316b809e5ae Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 22:27:25 -0500
Subject: [PATCH 084/112] Use version comparison helper in debug test
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/debug_test.py | 3 +--
tests/util.py | 4 ++--
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/tests/debug_test.py b/tests/debug_test.py
index 70e121c..e81d653 100644
--- a/tests/debug_test.py
+++ b/tests/debug_test.py
@@ -32,8 +32,7 @@ class DebugTest(unittest.TestCase):
# Some checks with no particular intent
self.check(0, 'About to connect')
- version = map(int, pycurl.version_info()[1].split('.'))
- if version[0] < 7 or version[0] == 7 and version[1] <= 22:
+ if util.pycurl_version_less_than(7, 24):
self.check(0, 'connected')
else:
self.check(0, 'Connected to localhost')
diff --git a/tests/util.py b/tests/util.py
index 46ac59f..b8e22ec 100644
--- a/tests/util.py
+++ b/tests/util.py
@@ -23,9 +23,9 @@ def version_less_than_spec(version_tuple, spec_tuple):
return False
return False
-def pycurl_version_less_than(spec_tuple):
+def pycurl_version_less_than(*spec):
version = map(int, pycurl.version_info()[1].split('.'))
- return version_less_than_spec(version, spec_tuple)
+ return version_less_than_spec(version, spec)
#
# prepare sys.path in case we are still in the build directory
--
1.7.1
From ee31a65de12bea5d00f0720eb8b5ec5be796c322 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 6 Mar 2013 22:30:44 -0500
Subject: [PATCH 085/112] libcurl 7.23.0 produces different results
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/multi_timer_test.py | 7 +++++--
1 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/tests/multi_timer_test.py b/tests/multi_timer_test.py
index e961780..c4b3df4 100644
--- a/tests/multi_timer_test.py
+++ b/tests/multi_timer_test.py
@@ -77,8 +77,11 @@ class MultiSocketTest(unittest.TestCase):
self.assertEqual(200, c.http_code)
assert len(timers) > 0
- assert timers[0] > 0
- self.assertEqual(-1, timers[-1])
+ # libcurl 7.23.0 produces a 0 timer
+ assert timers[0] >= 0
+ # this assertion does not appear to hold on older libcurls
+ if not util.pycurl_version_less_than(7, 24):
+ self.assertEqual(-1, timers[-1])
# close handles
for c in m.handles:
--
1.7.1
From f510b505c4e497904e3591696c7d8985baea409b Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Thu, 7 Mar 2013 00:16:21 -0500
Subject: [PATCH 086/112] Change memleak test to use id() rather than regexp match of addresses (closes #12)
This commit also fixes the test to check objects that GC tracks
rather than the object type repeatedly.
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/memleak_test.py | 16 ++++++----------
1 files changed, 6 insertions(+), 10 deletions(-)
diff --git a/tests/memleak_test.py b/tests/memleak_test.py
index 6e9f76c..1b1bbd5 100644
--- a/tests/memleak_test.py
+++ b/tests/memleak_test.py
@@ -5,12 +5,9 @@
import pycurl
import unittest
import gc
-import re
class MemleakTest(unittest.TestCase):
def test_collection(self):
- regexp = re.compile(r'at (0x\d+)')
-
gc.collect()
flags = gc.DEBUG_COLLECTABLE | gc.DEBUG_UNCOLLECTABLE
# python 3 has no DEBUG_OBJECTS
@@ -31,12 +28,10 @@ class MemleakTest(unittest.TestCase):
multi.add_handle(curl)
t.append(curl)
- match = regexp.search(repr(curl))
- assert match is not None
- searches.append(match.group(1))
- match = regexp.search(repr(multi))
- assert match
- searches.append(match.group(1))
+ c_id = id(curl)
+ searches.append(c_id)
+ m_id = id(multi)
+ searches.append(m_id)
#print("Tracked objects:", len(gc.get_objects()))
@@ -56,4 +51,5 @@ class MemleakTest(unittest.TestCase):
objects = gc.get_objects()
for search in searches:
- assert 'at %s' % search not in repr(object)
+ for object in objects:
+ assert search != id(object)
--
1.7.1
From 70206193e5219fac1da3e3d27167ed070fdff7b9 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Mon, 11 Mar 2013 22:19:14 -0400
Subject: [PATCH 087/112] More informative exception message when vsftpd is missing or not in PATH (closes #6)
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/procmgr.py | 12 +++++++++++-
1 files changed, 11 insertions(+), 1 deletions(-)
diff --git a/tests/procmgr.py b/tests/procmgr.py
index 8d5c0cc..ce08da9 100644
--- a/tests/procmgr.py
+++ b/tests/procmgr.py
@@ -1,6 +1,7 @@
import threading
import subprocess
import os
+import sys
import signal
from . import runwsgi
@@ -53,7 +54,16 @@ def vsftpd_setup():
]
setup_module = start_setup(cmd)
def do_setup_module():
- setup_module()
+ try:
+ setup_module()
+ except OSError:
+ import errno
+ e = sys.exc_info()[1]
+ if e.errno == errno.ENOENT:
+ msg = "Tried to execute `%s`\nTry specifying path to vsftpd via PYCURL_VSFTPD_PATH environment variable\n" % vsftpd_path
+ raise OSError(e.errno, e.strerror + "\n" + msg)
+ else:
+ raise
ok = runwsgi.wait_for_network_service(('127.0.0.1', 8321), 0.1, 10)
if not ok:
import warnings
--
1.7.1
From c42d5555e33105b8ea2317e63ac4b80b0c152be9 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Mon, 11 Mar 2013 22:22:02 -0400
Subject: [PATCH 088/112] Delete -1 timer assertion from multi timer test (closes #19)
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/multi_timer_test.py | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/tests/multi_timer_test.py b/tests/multi_timer_test.py
index c4b3df4..ff856d7 100644
--- a/tests/multi_timer_test.py
+++ b/tests/multi_timer_test.py
@@ -80,8 +80,10 @@ class MultiSocketTest(unittest.TestCase):
# libcurl 7.23.0 produces a 0 timer
assert timers[0] >= 0
# this assertion does not appear to hold on older libcurls
- if not util.pycurl_version_less_than(7, 24):
- self.assertEqual(-1, timers[-1])
+ # or apparently on any linuxes, see
+ # https://github.com/p/pycurl/issues/19
+ #if not util.pycurl_version_less_than(7, 24):
+ # self.assertEqual(-1, timers[-1])
# close handles
for c in m.handles:
--
1.7.1
From ccc7c66b76cef1ad3a00448d08f4aec7e21eaf69 Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@redhat.com>
Date: Mon, 11 Mar 2013 14:00:04 +0100
Subject: [PATCH 089/112] remove .cvsignore files, add *.pyc and *.pyo to .gitignore
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
.gitignore | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
index 796b96d..899daba 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,3 @@
+*.pyc
+*.pyo
/build
--
1.7.1
From bed41e852cb37b23b2cfc4513b701f3463a97c86 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Mon, 11 Mar 2013 22:40:12 -0400
Subject: [PATCH 090/112] Readd cvsignore contents and empty directories
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
.gitignore | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
index 899daba..c873e32 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,9 @@
*.pyc
*.pyo
+/MANIFEST
/build
+/dist
+/www/htdocs/download/*.bz2
+/www/htdocs/download/*.exe
+/www/htdocs/download/*.gz
+/www/upload/*
--
1.7.1
From 49e560395f55efa3bb9ec09f44b5c893f0571404 Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@redhat.com>
Date: Mon, 11 Mar 2013 14:03:06 +0100
Subject: [PATCH 091/112] vsftpd.conf: add background=no to allow for proper shutdown
When the "background" directive in the vsftpd.conf configuration file is
set to "YES", the vsftpd startup script forks, creating a child process
(the vsftpd daemon) which immediately sends the SIGUSR1 signal to its
parent process, which exits upon receiving it. The teardown routine in
procmgr.py would then send the SIGTERM signal to a process that does not
exist anymore.
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/vsftpd.conf | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/tests/vsftpd.conf b/tests/vsftpd.conf
index 0abb39f..b4e4972 100644
--- a/tests/vsftpd.conf
+++ b/tests/vsftpd.conf
@@ -1,5 +1,6 @@
anon_world_readable_only=yes
anonymous_enable=yes
+background=no
# currently we only list files
download_enable=no
listen=yes
--
1.7.1
From 2d1e91297f6d56286b9172090e6c16d9e509de0a Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@redhat.com>
Date: Tue, 26 Feb 2013 14:49:47 +0100
Subject: [PATCH 092/112] pycurl.c: eliminate duplicated code in util_write_callback()
Suggested by Zdenek Pavlas <https://bugzilla.redhat.com/857875#c8>.
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
src/pycurl.c | 10 +---------
1 files changed, 1 insertions(+), 9 deletions(-)
diff --git a/src/pycurl.c b/src/pycurl.c
index 094bc60..f701543 100644
--- a/src/pycurl.c
+++ b/src/pycurl.c
@@ -1082,15 +1082,7 @@ util_write_callback(int flags, char *ptr, size_t size, size_t nmemb, void *strea
if (result == Py_None) {
ret = total_size; /* None means success */
}
- else if (PyInt_Check(result)) {
- long obj_size = PyInt_AsLong(result);
- if (obj_size < 0 || obj_size > total_size) {
- PyErr_Format(ErrorObject, "invalid return value for write callback %ld %ld", (long)obj_size, (long)total_size);
- goto verbose_error;
- }
- ret = (size_t) obj_size; /* success */
- }
- else if (PyLong_Check(result)) {
+ else if (PyInt_Check(result) || PyLong_Check(result)) {
long obj_size = PyLong_AsLong(result);
if (obj_size < 0 || obj_size > total_size) {
PyErr_Format(ErrorObject, "invalid return value for write callback %ld %ld", (long)obj_size, (long)total_size);
--
1.7.1
From a3ab87495c91bf9b88ed5b8e8b4369d7adab96c2 Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@redhat.com>
Date: Tue, 26 Feb 2013 16:58:55 +0100
Subject: [PATCH 093/112] pycurl.c: allow to return -1 from write callback
... to abort the transfer and WRITEFUNC_PAUSE to pause the transfer
Reported By: Zdenek Pavlas
Bug: https://bugzilla.redhat.com/857875
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
src/pycurl.c | 11 +++++------
1 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/src/pycurl.c b/src/pycurl.c
index f701543..a30c339 100644
--- a/src/pycurl.c
+++ b/src/pycurl.c
@@ -1083,12 +1083,8 @@ util_write_callback(int flags, char *ptr, size_t size, size_t nmemb, void *strea
ret = total_size; /* None means success */
}
else if (PyInt_Check(result) || PyLong_Check(result)) {
- long obj_size = PyLong_AsLong(result);
- if (obj_size < 0 || obj_size > total_size) {
- PyErr_Format(ErrorObject, "invalid return value for write callback %ld %ld", (long)obj_size, (long)total_size);
- goto verbose_error;
- }
- ret = (size_t) obj_size; /* success */
+ /* if the cast to long fails, PyLong_AsLong() returns -1L */
+ ret = (size_t) PyLong_AsLong(result);
}
else {
PyErr_SetString(ErrorObject, "write callback must return int or None");
@@ -3509,6 +3505,9 @@ initpycurl(void)
/* Abort curl_read_callback(). */
insint_c(d, "READFUNC_ABORT", CURL_READFUNC_ABORT);
+ /* Pause curl_write_callback(). */
+ insint_c(d, "WRITEFUNC_PAUSE", CURL_WRITEFUNC_PAUSE);
+
/* constants for ioctl callback return values */
insint_c(d, "IOE_OK", CURLIOE_OK);
insint_c(d, "IOE_UNKNOWNCMD", CURLIOE_UNKNOWNCMD);
--
1.7.1
From 1ca0c365f45526d625fe79475c74b92818e9889d Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@redhat.com>
Date: Wed, 6 Mar 2013 14:38:01 +0100
Subject: [PATCH 094/112] write_abort_test.py: test returning -1 from write callback
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/write_abort_test.py | 35 +++++++++++++++++++++++++++++++++++
1 files changed, 35 insertions(+), 0 deletions(-)
create mode 100755 tests/write_abort_test.py
diff --git a/tests/write_abort_test.py b/tests/write_abort_test.py
new file mode 100755
index 0000000..73e8245
--- /dev/null
+++ b/tests/write_abort_test.py
@@ -0,0 +1,35 @@
+#!/usr/bin/python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+
+import os.path
+import pycurl
+import sys
+import unittest
+
+class WriteAbortTest(unittest.TestCase):
+ def setUp(self):
+ pycurl.global_init(pycurl.GLOBAL_DEFAULT)
+
+ def tearDown(self):
+ pycurl.global_cleanup()
+
+ def test_write_abort(self):
+ def write_cb(_):
+ # this should cause pycurl.WRITEFUNCTION (without any range errors)
+ return -1
+
+ # download the script itself through the file:// protocol into write_cb
+ c = pycurl.Curl()
+ c.setopt(pycurl.URL, 'file://' + os.path.abspath(sys.argv[0]))
+ c.setopt(pycurl.WRITEFUNCTION, write_cb)
+ try:
+ c.perform()
+ except pycurl.error, (err, msg):
+ # we expect pycurl.E_WRITE_ERROR as the response
+ assert pycurl.E_WRITE_ERROR == err
+
+ # no additional errors should be reported
+ assert not hasattr(sys, 'last_value')
+
+ c.close()
--
1.7.1
From 671bb961f3c16821684ac92f1ae6de9138b92d0f Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Mon, 11 Mar 2013 23:48:10 -0400
Subject: [PATCH 095/112] setup/teardown consistent with other tests
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/write_abort_test.py | 13 +++++--------
1 files changed, 5 insertions(+), 8 deletions(-)
diff --git a/tests/write_abort_test.py b/tests/write_abort_test.py
index 73e8245..f720882 100755
--- a/tests/write_abort_test.py
+++ b/tests/write_abort_test.py
@@ -9,10 +9,10 @@ import unittest
class WriteAbortTest(unittest.TestCase):
def setUp(self):
- pycurl.global_init(pycurl.GLOBAL_DEFAULT)
+ self.curl = pycurl.Curl()
def tearDown(self):
- pycurl.global_cleanup()
+ self.curl.close()
def test_write_abort(self):
def write_cb(_):
@@ -20,16 +20,13 @@ class WriteAbortTest(unittest.TestCase):
return -1
# download the script itself through the file:// protocol into write_cb
- c = pycurl.Curl()
- c.setopt(pycurl.URL, 'file://' + os.path.abspath(sys.argv[0]))
- c.setopt(pycurl.WRITEFUNCTION, write_cb)
+ self.curl.setopt(pycurl.URL, 'file://' + os.path.abspath(sys.argv[0]))
+ self.curl.setopt(pycurl.WRITEFUNCTION, write_cb)
try:
- c.perform()
+ self.curl.perform()
except pycurl.error, (err, msg):
# we expect pycurl.E_WRITE_ERROR as the response
assert pycurl.E_WRITE_ERROR == err
# no additional errors should be reported
assert not hasattr(sys, 'last_value')
-
- c.close()
--
1.7.1
From 0ddb01d99c34fa5ae7581697edeb2de49decc442 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Mon, 11 Mar 2013 23:48:41 -0400
Subject: [PATCH 096/112] Correct shebang
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/write_abort_test.py | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/tests/write_abort_test.py b/tests/write_abort_test.py
index f720882..3272961 100755
--- a/tests/write_abort_test.py
+++ b/tests/write_abort_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#! /usr/bin/env python
# -*- coding: iso-8859-1 -*-
# vi:ts=4:et
--
1.7.1
From 165d6e5e332a20ceca178b105aa165aa6873b662 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Mon, 11 Mar 2013 23:56:36 -0400
Subject: [PATCH 097/112] Check that bogus return values from write callback are correctly handled (still)
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/write_cb_bogus_test.py | 44 ++++++++++++++++++++++++++++++++++++++++++
1 files changed, 44 insertions(+), 0 deletions(-)
create mode 100644 tests/write_cb_bogus_test.py
diff --git a/tests/write_cb_bogus_test.py b/tests/write_cb_bogus_test.py
new file mode 100644
index 0000000..4bec2ad
--- /dev/null
+++ b/tests/write_cb_bogus_test.py
@@ -0,0 +1,44 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+
+import os.path
+import pycurl
+import sys
+import unittest
+
+class WriteAbortTest(unittest.TestCase):
+ def setUp(self):
+ self.curl = pycurl.Curl()
+
+ def tearDown(self):
+ self.curl.close()
+
+ def write_cb_returning_string(self, data):
+ return 'foo'
+
+ def write_cb_returning_float(self, data):
+ return 0.5
+
+ def test_write_cb_returning_string(self):
+ self.check(self.write_cb_returning_string)
+
+ def test_write_cb_returning_float(self):
+ self.check(self.write_cb_returning_float)
+
+ def check(self, write_cb):
+ # download the script itself through the file:// protocol into write_cb
+ c = pycurl.Curl()
+ self.curl.setopt(pycurl.URL, 'file://' + os.path.abspath(sys.argv[0]))
+ self.curl.setopt(pycurl.WRITEFUNCTION, write_cb)
+ try:
+ self.curl.perform()
+ except pycurl.error, (err, msg):
+ # we expect pycurl.E_WRITE_ERROR as the response
+ assert pycurl.E_WRITE_ERROR == err
+
+ # actual error
+ assert hasattr(sys, 'last_type')
+ self.assertEqual(pycurl.error, sys.last_type)
+ assert hasattr(sys, 'last_value')
+ self.assertEqual('write callback must return int or None', str(sys.last_value))
--
1.7.1
From cafe4e74ebd12a2c571319e0cfeb6d64f48abe08 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Tue, 12 Mar 2013 00:00:40 -0400
Subject: [PATCH 098/112] Fix mode on write abort test
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
0 files changed, 0 insertions(+), 0 deletions(-)
mode change 100755 => 100644 tests/write_abort_test.py
diff --git a/tests/write_abort_test.py b/tests/write_abort_test.py
old mode 100755
new mode 100644
--
1.7.1
From c84e139df96307aff908f69949cbe123fc40a14f Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Tue, 12 Mar 2013 00:02:56 -0400
Subject: [PATCH 099/112] This test fails intermittently, add diagnostics
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/multi_socket_select_test.py | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/tests/multi_socket_select_test.py b/tests/multi_socket_select_test.py
index 6db8b44..9546169 100644
--- a/tests/multi_socket_select_test.py
+++ b/tests/multi_socket_select_test.py
@@ -94,7 +94,7 @@ class MultiSocketSelectTest(unittest.TestCase):
c.http_code = c.getinfo(c.HTTP_CODE)
# at least in and remove events per socket
- assert len(socket_events) >= 6
+ assert len(socket_events) >= 6, 'Less than 6 socket events: %s' % repr(socket_events)
# print result
for c in m.handles:
--
1.7.1
From 47db8853813888148a4bc91754de8a83de4e8c0b Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Tue, 12 Mar 2013 22:43:47 -0400
Subject: [PATCH 100/112] Python 2.5 compatibility: socket.create_connection
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/runwsgi.py | 14 +++++++++++++-
1 files changed, 13 insertions(+), 1 deletions(-)
diff --git a/tests/runwsgi.py b/tests/runwsgi.py
index 8a978ec..be05dfa 100644
--- a/tests/runwsgi.py
+++ b/tests/runwsgi.py
@@ -6,6 +6,18 @@ import threading
import socket
import time as _time
+try:
+ create_connection = socket.create_connection
+except AttributeError:
+ # python 2.5
+ def create_connection(netloc, timeout=None):
+ # XXX ipv4 only
+ s = socket.socket()
+ if timeout is not None:
+ s.settimeout(timeout)
+ s.connect(netloc)
+ return s
+
class Server(bottle.WSGIRefServer):
def run(self, handler): # pragma: no cover
from wsgiref.simple_server import make_server, WSGIRequestHandler
@@ -21,7 +33,7 @@ def wait_for_network_service(netloc, check_interval, num_attempts):
ok = False
for i in range(num_attempts):
try:
- conn = socket.create_connection(netloc, check_interval)
+ conn = create_connection(netloc, check_interval)
except socket.error:
e = sys.exc_info()[1]
_time.sleep(check_interval)
--
1.7.1
From 94f689b61e1675f3ab9b4cc74ad53ae960d0a1b0 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Tue, 12 Mar 2013 22:55:08 -0400
Subject: [PATCH 101/112] Python 2.5 compatibility: poll_interval in SocketServer
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/runwsgi.py | 17 +++++++++++++++--
1 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/tests/runwsgi.py b/tests/runwsgi.py
index be05dfa..114ce42 100644
--- a/tests/runwsgi.py
+++ b/tests/runwsgi.py
@@ -18,6 +18,8 @@ except AttributeError:
s.connect(netloc)
return s
+global_stop = False
+
class Server(bottle.WSGIRefServer):
def run(self, handler): # pragma: no cover
from wsgiref.simple_server import make_server, WSGIRequestHandler
@@ -27,7 +29,13 @@ class Server(bottle.WSGIRefServer):
def log_request(*args, **kw): pass
self.options['handler_class'] = QuietHandler
self.srv = make_server(self.host, self.port, handler, **self.options)
- self.srv.serve_forever(poll_interval=0.1)
+ if sys.version_info[0] == 2 and sys.version_info[1] < 6:
+ # python 2.5 has no poll_interval
+ # and thus no way to stop the server
+ while not global_stop:
+ self.srv.handle_request()
+ else:
+ self.srv.serve_forever(poll_interval=0.1)
def wait_for_network_service(netloc, check_interval, num_attempts):
ok = False
@@ -104,6 +112,11 @@ def app_runner_setup(*specs):
for server in self.servers:
# if no tests from module were run, there is no server to shut down
if hasattr(server, 'srv'):
- server.srv.shutdown()
+ if hasattr(server.srv, 'shutdown'):
+ server.srv.shutdown()
+ else:
+ # python 2.5
+ global global_stop
+ global_stop = True
return [setup, teardown]
--
1.7.1
From d8dda1c31521d338b9119dd679c25257232a8656 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Fri, 15 Mar 2013 12:28:11 -0400
Subject: [PATCH 102/112] Tests do not call global cleanup for now
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/reset_test.py | 2 --
1 files changed, 0 insertions(+), 2 deletions(-)
diff --git a/tests/reset_test.py b/tests/reset_test.py
index cc55f86..61a692a 100644
--- a/tests/reset_test.py
+++ b/tests/reset_test.py
@@ -72,5 +72,3 @@ class ResetTest(unittest.TestCase):
eh.close()
cm.close()
outf.close()
-
- pycurl.global_cleanup()
--
1.7.1
From 8e307f81488c66a02516204cb7566f159b065371 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Fri, 15 Mar 2013 17:01:35 -0400
Subject: [PATCH 103/112] Python 3 compatibility: except syntax
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/write_abort_test.py | 3 ++-
tests/write_cb_bogus_test.py | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/tests/write_abort_test.py b/tests/write_abort_test.py
index 3272961..957fe78 100644
--- a/tests/write_abort_test.py
+++ b/tests/write_abort_test.py
@@ -24,7 +24,8 @@ class WriteAbortTest(unittest.TestCase):
self.curl.setopt(pycurl.WRITEFUNCTION, write_cb)
try:
self.curl.perform()
- except pycurl.error, (err, msg):
+ except pycurl.error:
+ err, msg = sys.exc_info()[1]
# we expect pycurl.E_WRITE_ERROR as the response
assert pycurl.E_WRITE_ERROR == err
diff --git a/tests/write_cb_bogus_test.py b/tests/write_cb_bogus_test.py
index 4bec2ad..ef709db 100644
--- a/tests/write_cb_bogus_test.py
+++ b/tests/write_cb_bogus_test.py
@@ -33,7 +33,8 @@ class WriteAbortTest(unittest.TestCase):
self.curl.setopt(pycurl.WRITEFUNCTION, write_cb)
try:
self.curl.perform()
- except pycurl.error, (err, msg):
+ except pycurl.error:
+ err, msg = sys.exc_info()[1]
# we expect pycurl.E_WRITE_ERROR as the response
assert pycurl.E_WRITE_ERROR == err
--
1.7.1
From f1674b26ef4094d20c46dbfc0cb7ae3026fce525 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Fri, 15 Mar 2013 21:21:50 -0400
Subject: [PATCH 104/112] Python 3 compatibility: map
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
tests/util.py | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/tests/util.py b/tests/util.py
index b8e22ec..1e9f406 100644
--- a/tests/util.py
+++ b/tests/util.py
@@ -24,7 +24,7 @@ def version_less_than_spec(version_tuple, spec_tuple):
return False
def pycurl_version_less_than(*spec):
- version = map(int, pycurl.version_info()[1].split('.'))
+ version = [int(part) for part in pycurl.version_info()[1].split('.')]
return version_less_than_spec(version, spec)
#
--
1.7.1
From 5797557b27a19c247967f8fc3cf8b1068139fecf Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Fri, 15 Mar 2013 21:27:58 -0400
Subject: [PATCH 105/112] Python 3 compatibility: apply no longer exists
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
python/curl/__init__.py | 4 ++--
setup.py | 3 +--
setup_win32_ssl.py | 2 +-
3 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/python/curl/__init__.py b/python/curl/__init__.py
index b002618..5b6b549 100644
--- a/python/curl/__init__.py
+++ b/python/curl/__init__.py
@@ -63,7 +63,7 @@ class Curl:
def set_option(self, *args):
"Set an option on the retrieval."
- apply(self.handle.setopt, args)
+ self.handle.setopt(*args)
def set_verbosity(self, level):
"Set verbosity to 1 to see transactions."
@@ -103,7 +103,7 @@ class Curl:
def get_info(self, *args):
"Get information about retrieval."
- return apply(self.handle.getinfo, args)
+ return self.handle.getinfo(*args)
def info(self):
"Return a dictionary with all info on the last response."
diff --git a/setup.py b/setup.py
index 235e4c9..013bd11 100644
--- a/setup.py
+++ b/setup.py
@@ -221,5 +221,4 @@ if LooseVersion(distutils.__version__) < LooseVersion("1.0.3"):
if __name__ == "__main__":
for o in ext.extra_objects:
assert os.path.isfile(o), o
- # We can live with the deprecationwarning for a while
- apply(setup, (), setup_args)
+ setup(**setup_args)
diff --git a/setup_win32_ssl.py b/setup_win32_ssl.py
index 332c04c..0ecc399 100644
--- a/setup_win32_ssl.py
+++ b/setup_win32_ssl.py
@@ -32,5 +32,5 @@ ext.extra_objects.append(r"c:\src\pool\libidn-0.5.15" + pool + "idn.lib")
if __name__ == "__main__":
for o in ext.extra_objects:
assert os.path.isfile(o), o
- apply(setup, (), setup_args)
+ setup(**setup_args)
--
1.7.1
From 94c63e7fe049d893a455b944c0deebe0f0c3ed37 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Tue, 26 Feb 2013 16:40:28 -0500
Subject: [PATCH 106/112] Python 3 compatibility: exception raising syntax
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
setup.py | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/setup.py b/setup.py
index 013bd11..725007c 100644
--- a/setup.py
+++ b/setup.py
@@ -108,7 +108,7 @@ else:
if p.wait() == 0:
optbuf += stdout
if optbuf == "":
- raise Exception, ("Neither of curl-config --libs or --static-libs" +
+ raise Exception("Neither of curl-config --libs or --static-libs" +
"produced output")
libs = split_quoted(optbuf)
--
1.7.1
From 530d280486742612cdbf7b306ce20e0200195adc Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 27 Feb 2013 20:23:28 -0500
Subject: [PATCH 107/112] Python 3 compatibility: print syntax (src)
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
python/curl/__init__.py | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/python/curl/__init__.py b/python/curl/__init__.py
index 5b6b549..5617262 100644
--- a/python/curl/__init__.py
+++ b/python/curl/__init__.py
@@ -164,10 +164,10 @@ if __name__ == "__main__":
url = sys.argv[1]
c = Curl()
c.get(url)
- print c.body()
- print '='*74 + '\n'
+ print(c.body())
+ print('='*74 + '\n')
import pprint
pprint.pprint(c.info())
- print c.get_info(pycurl.OS_ERRNO)
- print c.info()['os-errno']
+ print(c.get_info(pycurl.OS_ERRNO))
+ print(c.info()['os-errno'])
c.close()
--
1.7.1
From 8f47e45b2814f03400f5f42aa67527147981b67f Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Tue, 26 Feb 2013 16:49:09 -0500
Subject: [PATCH 108/112] Python 3 compatibility: print syntax (former tests)
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
examples/tests/test_gtk.py | 2 +-
examples/tests/test_xmlrpc.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/examples/tests/test_gtk.py b/examples/tests/test_gtk.py
index 7104439..da8c22a 100644
--- a/examples/tests/test_gtk.py
+++ b/examples/tests/test_gtk.py
@@ -83,7 +83,7 @@ class Test(threading.Thread):
# Check command line args
if len(sys.argv) < 3:
- print "Usage: %s <URL> <filename>" % sys.argv[0]
+ print("Usage: %s <URL> <filename>" % sys.argv[0])
raise SystemExit
# Make a progress bar window
diff --git a/examples/tests/test_xmlrpc.py b/examples/tests/test_xmlrpc.py
index bc5953e..3a5469a 100644
--- a/examples/tests/test_xmlrpc.py
+++ b/examples/tests/test_xmlrpc.py
@@ -24,6 +24,6 @@ c.setopt(c.POST, 1)
c.setopt(c.HTTPHEADER, xmlrpc_header)
c.setopt(c.POSTFIELDS, xmlrpc_template % ("examples.getStateName", xmlrpclib.dumps((5,))))
-print 'Response from http://betty.userland.com/'
+print('Response from http://betty.userland.com/')
c.perform()
c.close()
--
1.7.1
From a69c0133c05d1a8b059514b58c369f69db53faa9 Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Wed, 27 Feb 2013 20:23:39 -0500
Subject: [PATCH 109/112] Python 3 compatibility: print syntax (examples)
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
examples/basicfirst.py | 4 +-
examples/file_upload.py | 6 +-
examples/linksys.py | 182 +++++++++++++++++++++---------------------
examples/retriever-multi.py | 10 +-
examples/retriever.py | 6 +-
examples/sfquery.py | 2 +-
examples/xmlrpc_curl.py | 6 +-
7 files changed, 108 insertions(+), 108 deletions(-)
diff --git a/examples/basicfirst.py b/examples/basicfirst.py
index af59405..44060af 100644
--- a/examples/basicfirst.py
+++ b/examples/basicfirst.py
@@ -13,7 +13,7 @@ class Test:
def body_callback(self, buf):
self.contents = self.contents + buf
-print >>sys.stderr, 'Testing', pycurl.version
+sys.stderr.write("Testing %s\n" % pycurl.version)
t = Test()
c = pycurl.Curl()
@@ -22,4 +22,4 @@ c.setopt(c.WRITEFUNCTION, t.body_callback)
c.perform()
c.close()
-print t.contents
+print(t.contents)
diff --git a/examples/file_upload.py b/examples/file_upload.py
index a514c1c..7750865 100644
--- a/examples/file_upload.py
+++ b/examples/file_upload.py
@@ -15,13 +15,13 @@ class FileReader:
# Check commandline arguments
if len(sys.argv) < 3:
- print "Usage: %s <url> <file to upload>" % sys.argv[0]
+ print("Usage: %s <url> <file to upload>" % sys.argv[0])
raise SystemExit
url = sys.argv[1]
filename = sys.argv[2]
if not os.path.exists(filename):
- print "Error: the file '%s' does not exist" % filename
+ print("Error: the file '%s' does not exist" % filename)
raise SystemExit
# Initialize pycurl
@@ -41,6 +41,6 @@ filesize = os.path.getsize(filename)
c.setopt(pycurl.INFILESIZE, filesize)
# Start transfer
-print 'Uploading file %s to url %s' % (filename, url)
+print('Uploading file %s to url %s' % (filename, url))
c.perform()
c.close()
diff --git a/examples/linksys.py b/examples/linksys.py
index 5304886..24cb2a9 100755
--- a/examples/linksys.py
+++ b/examples/linksys.py
@@ -224,11 +224,11 @@ if __name__ == "__main__":
self.session = LinksysSession()
if os.isatty(0):
import readline
- print "Type ? or `help' for help."
+ print("Type ? or `help' for help.")
self.prompt = self.session.host + ": "
else:
self.prompt = ""
- print "Bar1"
+ print("Bar1")
def flag_command(self, func, line):
if line.strip() in ("on", "enable", "yes"):
@@ -246,96 +246,96 @@ if __name__ == "__main__":
self.session.cache_flush()
self.prompt = self.session.host + ": "
else:
- print self.session.host
+ print(self.session.host)
return 0
def help_connect(self):
- print "Usage: connect [<hostname-or-IP>]"
- print "Connect to a Linksys by name or IP address."
- print "If no argument is given, print the current host."
+ print("Usage: connect [<hostname-or-IP>]")
+ print("Connect to a Linksys by name or IP address.")
+ print("If no argument is given, print the current host.")
def do_status(self, line):
self.session.cache_load("")
if "" in self.session.pagecache:
- print "Firmware:", self.session.get_firmware_version()
- print "LAN MAC:", self.session.get_LAN_MAC()
- print "Wireless MAC:", self.session.get_Wireless_MAC()
- print "WAN MAC:", self.session.get_WAN_MAC()
- print "."
+ print("Firmware:", self.session.get_firmware_version())
+ print("LAN MAC:", self.session.get_LAN_MAC())
+ print("Wireless MAC:", self.session.get_Wireless_MAC())
+ print("WAN MAC:", self.session.get_WAN_MAC())
+ print(".")
return 0
def help_status(self):
- print "Usage: status"
- print "The status command shows the status of the Linksys."
- print "It is mainly useful as a sanity check to make sure"
- print "the box is responding correctly."
+ print("Usage: status")
+ print("The status command shows the status of the Linksys.")
+ print("It is mainly useful as a sanity check to make sure")
+ print("the box is responding correctly.")
def do_verbose(self, line):
self.flag_command(self.session.set_verbosity, line)
def help_verbose(self):
- print "Usage: verbose {on|off|enable|disable|yes|no}"
- print "Enables display of HTTP requests."
+ print("Usage: verbose {on|off|enable|disable|yes|no}")
+ print("Enables display of HTTP requests.")
def do_host(self, line):
self.session.set_host_name(line)
return 0
def help_host(self):
- print "Usage: host <hostname>"
- print "Sets the Host field to be queried by the ISP."
+ print("Usage: host <hostname>")
+ print("Sets the Host field to be queried by the ISP.")
def do_domain(self, line):
- print "Usage: host <domainname>"
+ print("Usage: host <domainname>")
self.session.set_domain_name(line)
return 0
def help_domain(self):
- print "Sets the Domain field to be queried by the ISP."
+ print("Sets the Domain field to be queried by the ISP.")
def do_lan_address(self, line):
self.session.set_LAN_IP(line)
return 0
def help_lan_address(self):
- print "Usage: lan_address <ip-address>"
- print "Sets the LAN IP address."
+ print("Usage: lan_address <ip-address>")
+ print("Sets the LAN IP address.")
def do_lan_netmask(self, line):
self.session.set_LAN_netmask(line)
return 0
def help_lan_netmask(self):
- print "Usage: lan_netmask <ip-mask>"
- print "Sets the LAN subnetwork mask."
+ print("Usage: lan_netmask <ip-mask>")
+ print("Sets the LAN subnetwork mask.")
def do_wireless(self, line):
self.flag_command(self.session.set_wireless, line)
return 0
def help_wireless(self):
- print "Usage: wireless {on|off|enable|disable|yes|no}"
- print "Switch to enable or disable wireless features."
+ print("Usage: wireless {on|off|enable|disable|yes|no}")
+ print("Switch to enable or disable wireless features.")
def do_ssid(self, line):
self.session.set_SSID(line)
return 0
def help_ssid(self):
- print "Usage: ssid <string>"
- print "Sets the SSID used to control wireless access."
+ print("Usage: ssid <string>")
+ print("Sets the SSID used to control wireless access.")
def do_ssid_broadcast(self, line):
self.flag_command(self.session.set_SSID_broadcast, line)
return 0
def help_ssid_broadcast(self):
- print "Usage: ssid_broadcast {on|off|enable|disable|yes|no}"
- print "Switch to enable or disable SSID broadcast."
+ print("Usage: ssid_broadcast {on|off|enable|disable|yes|no}")
+ print("Switch to enable or disable SSID broadcast.")
def do_channel(self, line):
self.session.set_channel(line)
return 0
def help_channel(self):
- print "Usage: channel <number>"
- print "Sets the wireless channel."
+ print("Usage: channel <number>")
+ print("Sets the wireless channel.")
def do_wep(self, line):
self.flag_command(self.session.set_WEP, line)
return 0
def help_wep(self):
- print "Usage: wep {on|off|enable|disable|yes|no}"
- print "Switch to enable or disable WEP security."
+ print("Usage: wep {on|off|enable|disable|yes|no}")
+ print("Switch to enable or disable WEP security.")
def do_wan_type(self, line):
try:
@@ -345,29 +345,29 @@ if __name__ == "__main__":
print >>sys.stderr, "linksys: unknown connection type."
return 0
def help_wan_type(self):
- print "Usage: wan_type {auto|static|ppoe|ras|pptp|heartbeat}"
- print "Set the WAN connection type."
+ print("Usage: wan_type {auto|static|ppoe|ras|pptp|heartbeat}")
+ print("Set the WAN connection type.")
def do_wan_address(self, line):
self.session.set_WAN_IP(line)
return 0
def help_wan_address(self):
- print "Usage: wan_address <ip-address>"
- print "Sets the WAN IP address."
+ print("Usage: wan_address <ip-address>")
+ print("Sets the WAN IP address.")
def do_wan_netmask(self, line):
self.session.set_WAN_netmask(line)
return 0
def help_wan_netmask(self):
- print "Usage: wan_netmask <ip-mask>"
- print "Sets the WAN subnetwork mask."
+ print("Usage: wan_netmask <ip-mask>")
+ print("Sets the WAN subnetwork mask.")
def do_wan_gateway(self, line):
self.session.set_WAN_gateway(line)
return 0
def help_wan_gateway(self):
- print "Usage: wan_gateway <ip-address>"
- print "Sets the LAN subnetwork mask."
+ print("Usage: wan_gateway <ip-address>")
+ print("Sets the LAN subnetwork mask.")
def do_dns(self, line):
(index, address) = line.split()
@@ -377,52 +377,52 @@ if __name__ == "__main__":
print >>sys.stderr, "linksys: server index out of bounds."
return 0
def help_dns(self):
- print "Usage: dns {1|2|3} <ip-mask>"
- print "Sets a primary, secondary, or tertiary DNS server address."
+ print("Usage: dns {1|2|3} <ip-mask>")
+ print("Sets a primary, secondary, or tertiary DNS server address.")
def do_password(self, line):
self.session.set_password(line)
return 0
def help_password(self):
- print "Usage: password <string>"
- print "Sets the router password."
+ print("Usage: password <string>")
+ print("Sets the router password.")
def do_upnp(self, line):
self.flag_command(self.session.set_UPnP, line)
return 0
def help_upnp(self):
- print "Usage: upnp {on|off|enable|disable|yes|no}"
- print "Switch to enable or disable Universal Plug and Play."
+ print("Usage: upnp {on|off|enable|disable|yes|no}")
+ print("Switch to enable or disable Universal Plug and Play.")
def do_reset(self, line):
self.session.reset()
def help_reset(self):
- print "Usage: reset"
- print "Reset Linksys settings to factory defaults."
+ print("Usage: reset")
+ print("Reset Linksys settings to factory defaults.")
def do_dhcp(self, line):
self.flag_command(self.session.set_DHCP, line)
def help_dhcp(self):
- print "Usage: dhcp {on|off|enable|disable|yes|no}"
- print "Switch to enable or disable DHCP features."
+ print("Usage: dhcp {on|off|enable|disable|yes|no}")
+ print("Switch to enable or disable DHCP features.")
def do_dhcp_start(self, line):
self.session.set_DHCP_starting_IP(line)
def help_dhcp_start(self):
- print "Usage: dhcp_start <number>"
- print "Set the start address of the DHCP pool."
+ print("Usage: dhcp_start <number>")
+ print("Set the start address of the DHCP pool.")
def do_dhcp_users(self, line):
self.session.set_DHCP_users(line)
def help_dhcp_users(self):
- print "Usage: dhcp_users <number>"
- print "Set number of address slots to allocate in the DHCP pool."
+ print("Usage: dhcp_users <number>")
+ print("Set number of address slots to allocate in the DHCP pool.")
def do_dhcp_lease(self, line):
self.session.set_DHCP_lease(line)
def help_dhcp_lease(self):
- print "Usage: dhcp_lease <number>"
- print "Set number of address slots to allocate in the DHCP pool."
+ print("Usage: dhcp_lease <number>")
+ print("Set number of address slots to allocate in the DHCP pool.")
def do_dhcp_dns(self, line):
(index, address) = line.split()
@@ -432,46 +432,46 @@ if __name__ == "__main__":
print >>sys.stderr, "linksys: server index out of bounds."
return 0
def help_dhcp_dns(self):
- print "Usage: dhcp_dns {1|2|3} <ip-mask>"
- print "Sets primary, secondary, or tertiary DNS server address."
+ print("Usage: dhcp_dns {1|2|3} <ip-mask>")
+ print("Sets primary, secondary, or tertiary DNS server address.")
def do_logging(self, line):
self.flag_command(self.session.set_logging, line)
def help_logging(self):
- print "Usage: logging {on|off|enable|disable|yes|no}"
- print "Switch to enable or disable session logging."
+ print("Usage: logging {on|off|enable|disable|yes|no}")
+ print("Switch to enable or disable session logging.")
def do_log_address(self, line):
self.session.set_Log_address(line)
def help_log_address(self):
- print "Usage: log_address <number>"
- print "Set the last quad of the address to which to log."
+ print("Usage: log_address <number>")
+ print("Set the last quad of the address to which to log.")
def do_configure(self, line):
self.session.configure()
return 0
def help_configure(self):
- print "Usage: configure"
- print "Writes the configuration to the Linksys."
+ print("Usage: configure")
+ print("Writes the configuration to the Linksys.")
def do_cache(self, line):
- print self.session.pagecache
+ print(self.session.pagecache)
def help_cache(self):
- print "Usage: cache"
- print "Display the page cache."
+ print("Usage: cache")
+ print("Display the page cache.")
def do_quit(self, line):
return 1
def help_quit(self, line):
- print "The quit command ends your linksys session without"
- print "writing configuration changes to the Linksys."
+ print("The quit command ends your linksys session without")
+ print("writing configuration changes to the Linksys.")
def do_EOF(self, line):
- print ""
+ print("")
self.session.configure()
return 1
def help_EOF(self):
- print "The EOF command writes the configuration to the linksys"
- print "and ends your session."
+ print("The EOF command writes the configuration to the linksys")
+ print("and ends your session.")
def default(self, line):
"""Pass the command through to be executed by the shell."""
@@ -479,11 +479,11 @@ if __name__ == "__main__":
return 0
def help_help(self):
- print "On-line help is available through this command."
- print "? is a convenience alias for help."
+ print("On-line help is available through this command.")
+ print("? is a convenience alias for help.")
def help_introduction(self):
- print """\
+ print("""\
This program supports changing the settings on Linksys blue-box routers. This
capability may come in handy when they freeze up and have to be reset. Though
@@ -506,16 +506,16 @@ will be shipped to the Linksys at the end of session (e.g. when the program
running in batch mode encounters end-of-file or you type a control-D). If you
end the session with `quit', pending changes will be discarded.
-For more help, read the topics 'wan', 'lan', and 'wireless'."""
+For more help, read the topics 'wan', 'lan', and 'wireless'.""")
def help_lan(self):
- print """\
+ print("""\
The `lan_address' and `lan_netmask' commands let you set the IP location of
the Linksys on your LAN, or inside. Normally you'll want to leave these
-untouched."""
+untouched.""")
def help_wan(self):
- print """\
+ print("""\
The WAN commands become significant if you are using the BEFSR41 or any of
the other Linksys boxes designed as DSL or cable-modem gateways. You will
need to use `wan_type' to declare how you expect to get your address.
@@ -527,22 +527,22 @@ need to use the `dns' command to declare which remote servers your DNS
requests should be forwarded to.
Some ISPs may require you to set host and domain for use with dynamic-address
-allocation."""
+allocation.""")
def help_wireless(self):
- print """\
+ print("""\
The channel, ssid, ssid_broadcast, wep, and wireless commands control
-wireless routing."""
+wireless routing.""")
def help_switches(self):
- print "Switches may be turned on with 'on', 'enable', or 'yes'."
- print "Switches may be turned off with 'off', 'disable', or 'no'."
- print "Switch commands include: wireless, ssid_broadcast."
+ print("Switches may be turned on with 'on', 'enable', or 'yes'.")
+ print("Switches may be turned off with 'off', 'disable', or 'no'.")
+ print("Switch commands include: wireless, ssid_broadcast.")
def help_addresses(self):
- print "An address argument must be a valid IP address;"
- print "four decimal numbers separated by dots, each "
- print "between 0 and 255."
+ print("An address argument must be a valid IP address;")
+ print("four decimal numbers separated by dots, each ")
+ print("between 0 and 255.")
def emptyline(self):
pass
diff --git a/examples/retriever-multi.py b/examples/retriever-multi.py
index 1a941be..ad4cebd 100644
--- a/examples/retriever-multi.py
+++ b/examples/retriever-multi.py
@@ -31,7 +31,7 @@ try:
if len(sys.argv) >= 3:
num_conn = int(sys.argv[2])
except:
- print "Usage: %s <file with URLs to fetch> [<# of concurrent connections>]" % sys.argv[0]
+ print("Usage: %s <file with URLs to fetch> [<# of concurrent connections>]" % sys.argv[0])
raise SystemExit
@@ -50,8 +50,8 @@ assert queue, "no URLs given"
num_urls = len(queue)
num_conn = min(num_conn, num_urls)
assert 1 <= num_conn <= 10000, "invalid number of concurrent connections"
-print "PycURL %s (compiled against 0x%x)" % (pycurl.version, pycurl.COMPILE_LIBCURL_VERSION_NUM)
-print "----- Getting", num_urls, "URLs using", num_conn, "connections -----"
+print("PycURL %s (compiled against 0x%x)" % (pycurl.version, pycurl.COMPILE_LIBCURL_VERSION_NUM))
+print("----- Getting", num_urls, "URLs using", num_conn, "connections -----")
# Pre-allocate a list of curl objects
@@ -95,13 +95,13 @@ while num_processed < num_urls:
c.fp.close()
c.fp = None
m.remove_handle(c)
- print "Success:", c.filename, c.url, c.getinfo(pycurl.EFFECTIVE_URL)
+ print("Success:", c.filename, c.url, c.getinfo(pycurl.EFFECTIVE_URL))
freelist.append(c)
for c, errno, errmsg in err_list:
c.fp.close()
c.fp = None
m.remove_handle(c)
- print "Failed: ", c.filename, c.url, errno, errmsg
+ print("Failed: ", c.filename, c.url, errno, errmsg)
freelist.append(c)
num_processed = num_processed + len(ok_list) + len(err_list)
if num_q == 0:
diff --git a/examples/retriever.py b/examples/retriever.py
index 2c91d07..be1b6ea 100644
--- a/examples/retriever.py
+++ b/examples/retriever.py
@@ -31,7 +31,7 @@ try:
if len(sys.argv) >= 3:
num_conn = int(sys.argv[2])
except:
- print "Usage: %s <file with URLs to fetch> [<# of concurrent connections>]" % sys.argv[0]
+ print("Usage: %s <file with URLs to fetch> [<# of concurrent connections>]" % sys.argv[0])
raise SystemExit
@@ -50,8 +50,8 @@ assert queue.queue, "no URLs given"
num_urls = len(queue.queue)
num_conn = min(num_conn, num_urls)
assert 1 <= num_conn <= 10000, "invalid number of concurrent connections"
-print "PycURL %s (compiled against 0x%x)" % (pycurl.version, pycurl.COMPILE_LIBCURL_VERSION_NUM)
-print "----- Getting", num_urls, "URLs using", num_conn, "connections -----"
+print("PycURL %s (compiled against 0x%x)" % (pycurl.version, pycurl.COMPILE_LIBCURL_VERSION_NUM))
+print("----- Getting", num_urls, "URLs using", num_conn, "connections -----")
class WorkerThread(threading.Thread):
diff --git a/examples/sfquery.py b/examples/sfquery.py
index 741feb0..16aa9d4 100644
--- a/examples/sfquery.py
+++ b/examples/sfquery.py
@@ -40,7 +40,7 @@ if __name__ == "__main__":
name, account, password = auth
except:
if len(sys.argv) < 4:
- print "Usage: %s <project id> <username> <password>" % sys.argv[0]
+ print("Usage: %s <project id> <username> <password>" % sys.argv[0])
raise SystemExit
name = sys.argv[2]
password = sys.argv[3]
diff --git a/examples/xmlrpc_curl.py b/examples/xmlrpc_curl.py
index ec0df50..a9a7d9e 100644
--- a/examples/xmlrpc_curl.py
+++ b/examples/xmlrpc_curl.py
@@ -55,8 +55,8 @@ if __name__ == "__main__":
## Test
server = xmlrpclib.ServerProxy("http://betty.userland.com",
transport=CURLTransport())
- print server
+ print(server)
try:
- print server.examples.getStateName(41)
+ print(server.examples.getStateName(41))
except xmlrpclib.Error, v:
- print "ERROR", v
+ print("ERROR", v)
--
1.7.1
From 41478f926b683d2141732936cad1855a7632552a Mon Sep 17 00:00:00 2001
From: Oleg Pudeyev <oleg@bsdpower.com>
Date: Thu, 28 Feb 2013 00:30:00 -0500
Subject: [PATCH 110/112] Python 3 compatibility: printing to stderr (linksys example)
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
examples/linksys.py | 14 +++++++++-----
1 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/examples/linksys.py b/examples/linksys.py
index 24cb2a9..f66ff0d 100755
--- a/examples/linksys.py
+++ b/examples/linksys.py
@@ -34,6 +34,10 @@
import sys, re, copy, curl, exceptions
+def print_stderr(arg):
+ sys.stderr.write(arg)
+ sys.stderr.write("\n")
+
class LinksysError(exceptions.Exception):
def __init__(self, *args):
self.args = args
@@ -202,7 +206,7 @@ class LinksysSession:
for (page, field, value) in self.actions:
self.cache_load(page)
if self.pagecache[page].find(field) == -1:
- print >>sys.stderr, "linksys: field %s not found where expected in page %s!" % (field, os.path.join(self.host, page))
+ print_stderr("linksys: field %s not found where expected in page %s!" % (field, os.path.join(self.host, page)))
continue
else:
fields.append((field, value))
@@ -236,7 +240,7 @@ if __name__ == "__main__":
elif line.strip() in ("off", "disable", "no"):
func(False)
else:
- print >>sys.stderr, "linksys: unknown switch value"
+ print_stderr("linksys: unknown switch value")
return 0
def do_connect(self, line):
@@ -342,7 +346,7 @@ if __name__ == "__main__":
type=eval("LinksysSession.WAN_CONNECT_"+line.strip().upper())
self.session.set_connection_type(type)
except ValueError:
- print >>sys.stderr, "linksys: unknown connection type."
+ print_stderr("linksys: unknown connection type.")
return 0
def help_wan_type(self):
print("Usage: wan_type {auto|static|ppoe|ras|pptp|heartbeat}")
@@ -374,7 +378,7 @@ if __name__ == "__main__":
if index in ("1", "2", "3"):
self.session.set_DNS_server(eval(index), address)
else:
- print >>sys.stderr, "linksys: server index out of bounds."
+ print_stderr("linksys: server index out of bounds.")
return 0
def help_dns(self):
print("Usage: dns {1|2|3} <ip-mask>")
@@ -429,7 +433,7 @@ if __name__ == "__main__":
if index in ("1", "2", "3"):
self.session.set_DHCP_DNS_server(eval(index), address)
else:
- print >>sys.stderr, "linksys: server index out of bounds."
+ print_stderr("linksys: server index out of bounds.")
return 0
def help_dhcp_dns(self):
print("Usage: dhcp_dns {1|2|3} <ip-mask>")
--
1.7.1
From a20b726b10b5e1bc27ba95808ef11154973b6403 Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@redhat.com>
Date: Mon, 8 Apr 2013 14:25:26 +0200
Subject: [PATCH 111/112] allow to unset a previously set RANGE value
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
... and add the unset_range_test.py unit test exercising it
Reported by: Zdeněk Pavlas
Bug: https://bugzilla.redhat.com/928370
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
src/pycurl.c | 1 +
tests/unset_range_test.py | 39 +++++++++++++++++++++++++++++++++++++++
2 files changed, 40 insertions(+), 0 deletions(-)
create mode 100644 tests/unset_range_test.py
diff --git a/src/pycurl.c b/src/pycurl.c
index a30c339..bd28b81 100644
--- a/src/pycurl.c
+++ b/src/pycurl.c
@@ -1561,6 +1561,7 @@ util_curl_unsetopt(CurlObject *self, int option)
case CURLOPT_RANDOM_FILE:
case CURLOPT_SSL_CIPHER_LIST:
case CURLOPT_USERPWD:
+ case CURLOPT_RANGE:
SETOPT((char *) 0);
break;
diff --git a/tests/unset_range_test.py b/tests/unset_range_test.py
new file mode 100644
index 0000000..4400851
--- /dev/null
+++ b/tests/unset_range_test.py
@@ -0,0 +1,39 @@
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+# vi:ts=4:et
+
+import os.path
+import pycurl
+import sys
+import unittest
+
+class UnsetRangeTest(unittest.TestCase):
+ def setUp(self):
+ self.curl = pycurl.Curl()
+
+ def tearDown(self):
+ self.curl.close()
+
+ def test_unset_range(self):
+ def write_cb(data):
+ self.read += len(data)
+ return None
+
+ # download bytes 0-9 of the script itself through the file:// protocol
+ self.read = 0
+ self.curl.setopt(pycurl.URL, 'file://' + os.path.abspath(sys.argv[0]))
+ self.curl.setopt(pycurl.WRITEFUNCTION, write_cb)
+ self.curl.setopt(pycurl.RANGE, '0-9')
+ self.curl.perform()
+ assert 10 == self.read
+
+ # the RANGE setting should be preserved from the previous transfer
+ self.read = 0
+ self.curl.perform()
+ assert 10 == self.read
+
+ # drop the RANGE setting using unsetopt() and download entire script
+ self.read = 0
+ self.curl.unsetopt(pycurl.RANGE)
+ self.curl.perform()
+ assert 10 < self.read
--
1.7.1
From 6d43dc15185016b0e2dd993e18bd124f87554445 Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@redhat.com>
Date: Mon, 8 Apr 2013 14:31:30 +0200
Subject: [PATCH 112/112] allow to use setopt(..., None) as unsetopt()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
... and extend the unset_range_test.py unit test to exercise it
Reported by: Zdeněk Pavlas
Bug: https://bugzilla.redhat.com/928370
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
src/pycurl.c | 4 +---
tests/unset_range_test.py | 12 ++++++++++++
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/src/pycurl.c b/src/pycurl.c
index bd28b81..619ca20 100644
--- a/src/pycurl.c
+++ b/src/pycurl.c
@@ -1631,12 +1631,10 @@ do_curl_setopt(CurlObject *self, PyObject *args)
if (option % 10000 >= OPTIONS_SIZE)
goto error;
-#if 0 /* XXX - should we ??? */
- /* Handle the case of None */
+ /* Handle the case of None as the call of unsetopt() */
if (obj == Py_None) {
return util_curl_unsetopt(self, option);
}
-#endif
/* Handle the case of string arguments */
if (PyString_Check(obj)) {
diff --git a/tests/unset_range_test.py b/tests/unset_range_test.py
index 4400851..10ee801 100644
--- a/tests/unset_range_test.py
+++ b/tests/unset_range_test.py
@@ -37,3 +37,15 @@ class UnsetRangeTest(unittest.TestCase):
self.curl.unsetopt(pycurl.RANGE)
self.curl.perform()
assert 10 < self.read
+
+ # now set the RANGE again and check that pycurl takes it into account
+ self.read = 0
+ self.curl.setopt(pycurl.RANGE, '0-9')
+ self.curl.perform()
+ assert 10 == self.read
+
+ # now drop the RANGE setting using setopt(..., None)
+ self.read = 0
+ self.curl.setopt(pycurl.RANGE, None)
+ self.curl.perform()
+ assert 10 < self.read
--
1.7.1