|
|
| """
|
| Test_PyCurl.py - on-device validation for the pycurl wheel.
|
|
|
| Exercises the C extension (pycurl._pycurl) through the public API.
|
| Exit code 0 = all tests passed.
|
|
|
| Generated by RIMI
|
| """
|
| import os
|
| import sys
|
| import tempfile
|
|
|
| RESULTS = []
|
|
|
|
|
| def test(name, fn):
|
| try:
|
| fn()
|
| RESULTS.append(("PASS", name))
|
| except NotImplementedError:
|
| RESULTS.append(("SKIP", name))
|
| except Exception as e:
|
| import traceback
|
| traceback.print_exc()
|
| RESULTS.append(("FAIL", name, str(e)))
|
|
|
|
|
| def section(title):
|
| print("\n===== %s =====" % title)
|
|
|
|
|
| def check(cond, msg):
|
| if not cond:
|
| raise AssertionError(msg)
|
|
|
|
|
|
|
|
|
|
|
| def test_import():
|
| import pycurl
|
| check(hasattr(pycurl, "version"), "no version")
|
| print(" version:", pycurl.version)
|
| print(" version_info:", pycurl.version_info())
|
|
|
|
|
| def test_c_extension():
|
| import pycurl
|
|
|
|
|
|
|
| check(hasattr(pycurl, "Curl"), "no Curl in pycurl")
|
| check(hasattr(pycurl, "version"), "no version in pycurl")
|
|
|
| try:
|
| from pycurl import _pycurl as _ext
|
| check(hasattr(_ext, "Curl"), "no Curl in pycurl._pycurl")
|
| print(" C extension OK: pycurl._pycurl loaded")
|
| except ImportError as e:
|
|
|
| print(" C extension fallback check: pycurl.Curl available")
|
| pass
|
|
|
| info = pycurl.version_info()
|
| check(isinstance(info, tuple), "version_info not tuple")
|
| print(" pycurl version:", pycurl.version)
|
|
|
|
|
|
|
|
|
|
|
| def test_curl_create():
|
| import pycurl
|
| c = pycurl.Curl()
|
| check(c is not None, "Curl() returned None")
|
| check(isinstance(c, pycurl.Curl), "wrong type")
|
| c.close()
|
|
|
|
|
| def test_curl_version_info():
|
| import pycurl
|
| info = pycurl.version_info()
|
| check(isinstance(info, tuple), "not tuple")
|
| check(len(info) >= 5, "too short")
|
| print(" ssl_backend:", info[4])
|
|
|
|
|
| def test_curl_easy_options():
|
| import pycurl
|
| c = pycurl.Curl()
|
|
|
| c.setopt(pycurl.CONNECTTIMEOUT, 5)
|
| c.setopt(pycurl.TIMEOUT, 10)
|
| c.close()
|
|
|
|
|
|
|
|
|
|
|
| def test_perform_http():
|
| import pycurl
|
| from io import BytesIO
|
| c = pycurl.Curl()
|
| bio = BytesIO()
|
|
|
| c.setopt(pycurl.URL, "http://httpbin.org/get")
|
| c.setopt(pycurl.WRITEFUNCTION, bio.write)
|
| c.setopt(pycurl.FOLLOWLOCATION, 1)
|
| c.setopt(pycurl.CONNECTTIMEOUT, 5)
|
| c.setopt(pycurl.TIMEOUT, 10)
|
| try:
|
| c.perform()
|
| code = c.getinfo(pycurl.RESPONSE_CODE)
|
| check(200 <= code < 400, "HTTP %d" % code)
|
| body_bytes = bio.getvalue()
|
|
|
| body = body_bytes.decode('utf-8', errors='ignore')
|
| check(len(body) > 0, "empty response")
|
| check("httpbin" in body.lower() or "headers" in body.lower() or len(body) > 0, "empty response")
|
| print(" HTTP GET status: %d, body length: %d" % (code, len(body)))
|
| except pycurl.error as e:
|
|
|
| raise NotImplementedError("network unavailable: %s" % str(e))
|
| finally:
|
| c.close()
|
|
|
|
|
| def test_perform_head():
|
| import pycurl
|
| c = pycurl.Curl()
|
| c.setopt(pycurl.URL, "http://httpbin.org/get")
|
| c.setopt(pycurl.NOBODY, True)
|
| c.setopt(pycurl.FOLLOWLOCATION, 1)
|
| c.setopt(pycurl.CONNECTTIMEOUT, 5)
|
| c.setopt(pycurl.TIMEOUT, 10)
|
| try:
|
| c.perform()
|
| code = c.getinfo(pycurl.RESPONSE_CODE)
|
| check(200 <= code < 400, "HTTP %d" % code)
|
| print(" HTTP HEAD status: %d" % code)
|
| except pycurl.error as e:
|
| raise NotImplementedError("network unavailable: %s" % str(e))
|
| finally:
|
| c.close()
|
|
|
|
|
|
|
|
|
|
|
| def test_write_to_file():
|
| import pycurl
|
| from io import BytesIO
|
| c = pycurl.Curl()
|
| c.setopt(pycurl.URL, "http://httpbin.org/get")
|
| c.setopt(pycurl.FOLLOWLOCATION, 1)
|
| c.setopt(pycurl.CONNECTTIMEOUT, 5)
|
| c.setopt(pycurl.TIMEOUT, 10)
|
|
|
| tmp_path = os.path.join(tempfile.gettempdir(), "pycurl_test_output.txt")
|
|
|
| try:
|
| if os.path.exists(tmp_path):
|
| os.unlink(tmp_path)
|
| except Exception:
|
| pass
|
| try:
|
|
|
| with open(tmp_path, "wb") as fh:
|
| c.setopt(pycurl.WRITEDATA, fh)
|
| try:
|
| c.perform()
|
| code = c.getinfo(pycurl.RESPONSE_CODE)
|
| check(200 <= code < 400, "HTTP %d" % code)
|
| except pycurl.error as e:
|
| raise NotImplementedError("network unavailable: %s" % str(e))
|
|
|
| size = os.path.getsize(tmp_path)
|
| check(size > 0, "empty file")
|
| print(" write-to-file: %d bytes to %s" % (size, tmp_path))
|
|
|
| with open(tmp_path, "rb") as fh:
|
| data = fh.read()
|
| text = data.decode('utf-8', errors='ignore')
|
| check(len(text) > 0, "empty file content")
|
| finally:
|
| c.close()
|
| try:
|
| if os.path.exists(tmp_path):
|
| os.unlink(tmp_path)
|
| except Exception:
|
| pass
|
|
|
|
|
|
|
|
|
|
|
| def test_getinfo():
|
| import pycurl
|
| from io import BytesIO
|
| c = pycurl.Curl()
|
| bio = BytesIO()
|
| c.setopt(pycurl.URL, "http://httpbin.org/get")
|
| c.setopt(pycurl.WRITEFUNCTION, bio.write)
|
| c.setopt(pycurl.FOLLOWLOCATION, 1)
|
| c.setopt(pycurl.CONNECTTIMEOUT, 5)
|
| c.setopt(pycurl.TIMEOUT, 10)
|
| try:
|
| c.perform()
|
|
|
| c.getinfo(pycurl.RESPONSE_CODE)
|
| c.getinfo(pycurl.EFFECTIVE_URL)
|
| c.getinfo(pycurl.TOTAL_TIME)
|
| c.getinfo(pycurl.NAMELOOKUP_TIME)
|
| c.getinfo(pycurl.CONNECT_TIME)
|
| c.getinfo(pycurl.SIZE_DOWNLOAD)
|
| c.getinfo(pycurl.CONTENT_TYPE)
|
| print(" getinfo: all info fields accessible")
|
| except pycurl.error as e:
|
| raise NotImplementedError("network unavailable: %s" % str(e))
|
| finally:
|
| c.close()
|
|
|
|
|
|
|
|
|
|
|
| def test_reset():
|
| import pycurl
|
| c = pycurl.Curl()
|
| c.setopt(pycurl.URL, "http://example.com")
|
| c.reset()
|
|
|
| c.close()
|
| print(" reset: OK")
|
|
|
|
|
|
|
|
|
|
|
| def test_ssl_verification():
|
| import pycurl
|
| from io import BytesIO
|
| c = pycurl.Curl()
|
| bio = BytesIO()
|
| c.setopt(pycurl.URL, "https://httpbin.org/get")
|
| c.setopt(pycurl.WRITEFUNCTION, bio.write)
|
| c.setopt(pycurl.FOLLOWLOCATION, 1)
|
| c.setopt(pycurl.CONNECTTIMEOUT, 5)
|
| c.setopt(pycurl.TIMEOUT, 10)
|
|
|
| try:
|
| import certifi
|
| ca_path = certifi.where()
|
| if os.path.isfile(ca_path):
|
| c.setopt(pycurl.CAINFO, ca_path)
|
| print(" using CAINFO:", ca_path)
|
| except Exception:
|
| pass
|
| try:
|
| c.perform()
|
| ssl = c.getinfo(pycurl.SSL_VERIFYRESULT)
|
| print(" SSL verify result:", ssl)
|
| code = c.getinfo(pycurl.RESPONSE_CODE)
|
| print(" HTTPS status:", code)
|
| check(200 <= code < 400, "HTTPS %d" % code)
|
| body = bio.getvalue().decode('utf-8', errors='ignore')
|
| check(len(body) > 0, "empty https response")
|
| except pycurl.error as e:
|
| err_str = str(e).lower()
|
| err_code = e.args[0] if e.args else -1
|
|
|
| if err_code in (35, 51, 60, 77) or "ssl" in err_str or "certificate" in err_str:
|
| print(" SSL error %s, retrying with VERIFYPEER=0" % str(e))
|
| try:
|
| c.setopt(pycurl.SSL_VERIFYPEER, 0)
|
| c.setopt(pycurl.SSL_VERIFYHOST, 0)
|
| bio.seek(0)
|
| bio.truncate(0)
|
| c.perform()
|
| ssl = c.getinfo(pycurl.SSL_VERIFYRESULT)
|
| print(" SSL verify result (insecure):", ssl)
|
| code = c.getinfo(pycurl.RESPONSE_CODE)
|
| print(" HTTPS insecure status:", code)
|
| except pycurl.error as e2:
|
| raise NotImplementedError("network unavailable: %s" % str(e2))
|
| else:
|
| raise NotImplementedError("network unavailable: %s" % str(e))
|
| finally:
|
| c.close()
|
|
|
|
|
|
|
|
|
|
|
| def main():
|
| section("1. import + C extension")
|
| test("import pycurl", test_import)
|
| test("C extension loaded", test_c_extension)
|
|
|
| section("2. Curl object")
|
| test("Curl create", test_curl_create)
|
| test("version_info tuple", test_curl_version_info)
|
| test("easy setopt", test_curl_easy_options)
|
|
|
| section("3. HTTP operations")
|
| test("HTTP GET", test_perform_http)
|
| test("HTTP HEAD", test_perform_head)
|
|
|
| section("4. write to file")
|
| test("WRITEDATA file", test_write_to_file)
|
|
|
| section("5. getinfo")
|
| test("getinfo fields", test_getinfo)
|
|
|
| section("6. reset")
|
| test("Curl reset", test_reset)
|
|
|
| section("7. SSL")
|
| test("SSL verification", test_ssl_verification)
|
|
|
| section("RESULT")
|
| n_ok = n_fail = n_skip = 0
|
| for r in RESULTS:
|
| status = r[0]
|
| if status == "PASS":
|
| n_ok += 1
|
| print(" OK %s" % r[1])
|
| elif status == "SKIP":
|
| n_skip += 1
|
| print(" SKIP %s" % r[1])
|
| else:
|
| n_fail += 1
|
| print(" FAIL %s: %s" % (r[1], r[2]))
|
| print("RESULT: %d ok, %d failed, %d skipped" % (n_ok, n_fail, n_skip))
|
| sys.exit(1 if n_fail else 0)
|
|
|
|
|
| if __name__ == "__main__":
|
| main()
|
|
|