Skip to content
This repository has been archived by the owner on Apr 14, 2022. It is now read-only.

Run Windows tests on GitHub Actions #153

Merged
merged 10 commits into from
Nov 26, 2019
38 changes: 38 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: CI

on: [push, pull_request]

jobs:
Windows:

runs-on: windows-latest
strategy:
fail-fast: false
matrix:
python-version: [2.7, 3.5, 3.6, 3.7, 3.8]

steps:
- uses: actions/checkout@v1
- name: Set up Python 3.7 to run nox
uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Set up Python ${{ matrix.python-version }}
if: matrix.python_version != '3.7'
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
# Work around https://github.com/theacodes/nox/issues/250
Remove-Item C:\ProgramData\Chocolatey\bin\python2.7.exe
py -3.7 -m pip install nox
- name: Test
run: |
nox -s test-${{ matrix.python-version }}
- name: Coverage upload
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
run: |
python.exe -m pip install codecov
python.exe -m codecov
53 changes: 0 additions & 53 deletions appveyor.yml

This file was deleted.

12 changes: 0 additions & 12 deletions cleancov.py

This file was deleted.

2 changes: 1 addition & 1 deletion dev-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pytest-random-order==1.0.4;python_version>="3.6"
pytest-timeout==1.3.3
pytest-cov==2.7.1
h11==0.8.0
cryptography==2.6.1
cryptography==2.8
flaky==3.6.1

# https://github.com/GoogleCloudPlatform/python-repo-tools/issues/23
Expand Down
14 changes: 13 additions & 1 deletion noxfile.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
from xml.etree import ElementTree as ET
import os
import re
import shutil
import sys

import nox


def _clean_coverage(coverage_path):
input_xml = ET.ElementTree(file=coverage_path)
for class_ in input_xml.findall(".//class"):
filename = class_.get("filename")
filename = re.sub("_sync", "_async", filename)
class_.set("filename", filename)
input_xml.write(coverage_path, xml_declaration=True)


def tests_impl(session, extras="socks,secure,brotli"):
# Install deps and the package itself.
session.install("-r", "dev-requirements.txt")
Expand All @@ -28,7 +40,7 @@ def tests_impl(session, extras="socks,secure,brotli"):
env={"PYTHONWARNINGS": "always::DeprecationWarning"}
)
session.run("coverage", "xml")
session.run("python", "cleancov.py", "coverage.xml")
_clean_coverage("coverage.xml")


@nox.session(python=["2.7", "3.5", "3.6", "3.7", "3.8", "pypy"])
Expand Down
2 changes: 1 addition & 1 deletion test/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
# 3. To test our timeout logic by using two different values, eg. by using different
# values at the pool level and at the request level.
SHORT_TIMEOUT = 0.001
LONG_TIMEOUT = 0.5 if os.environ.get("CI") else 0.01
LONG_TIMEOUT = 0.5 if os.environ.get("CI") or os.environ.get("GITHUB_ACTIONS") else 0.01


def clear_warnings(cls=HTTPWarning):
Expand Down
11 changes: 11 additions & 0 deletions test/conftest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
import platform
import sys

import pytest

# We support Python 3.6+ for async code
if sys.version_info[:2] < (3, 6):
collect_ignore_glob = ["async/*.py", "with_dummyserver/async/*.py"]

# The Python 3.8+ default loop on Windows breaks Tornado
@pytest.fixture(scope="session", autouse=True)
def configure_windows_event_loop():
if sys.version_info >= (3, 8) and platform.system() == "Windows":
import asyncio

asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is going to be a problem at some point – hip itself will need to support, and be tested on, the default event loop :-/. (Not something for this PR to worry about of course.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, opened #154 so that we don't forget about it

43 changes: 8 additions & 35 deletions test/with_dummyserver/test_connectionpool.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,20 +78,13 @@ def test_conn_closed(self):
def test_timeout(self):
# Requests should time out when expected
block_event = Event()
ready_event = self.start_basic_handler(block_send=block_event, num=6)
ready_event = self.start_basic_handler(block_send=block_event, num=3)

# Pool-global timeout
timeout = Timeout(read=SHORT_TIMEOUT)
short_timeout = Timeout(read=SHORT_TIMEOUT)
with HTTPConnectionPool(
self.host, self.port, timeout=timeout, retries=False
self.host, self.port, timeout=short_timeout, retries=False
) as pool:
wait_for_socket(ready_event)
conn = pool._get_conn()
with pytest.raises(ReadTimeoutError):
pool._make_request(conn, "GET", "/")
pool._put_conn(conn)
block_event.set() # Release request

wait_for_socket(ready_event)
block_event.clear()
with pytest.raises(ReadTimeoutError):
Expand All @@ -100,44 +93,24 @@ def test_timeout(self):

# Request-specific timeouts should raise errors
with HTTPConnectionPool(
self.host, self.port, timeout=LONG_TIMEOUT, retries=False
self.host, self.port, timeout=short_timeout, retries=False
) as pool:
conn = pool._get_conn()
wait_for_socket(ready_event)
now = time.time()
with pytest.raises(ReadTimeoutError):
pool._make_request(conn, "GET", "/", timeout=timeout)
delta = time.time() - now
block_event.set() # Release request

message = "timeout was pool-level LONG_TIMEOUT rather than request-level SHORT_TIMEOUT"
assert delta < LONG_TIMEOUT, message
pool._put_conn(conn)

wait_for_socket(ready_event)
now = time.time()
with pytest.raises(ReadTimeoutError):
pool.request("GET", "/", timeout=timeout)
pool.request("GET", "/", timeout=LONG_TIMEOUT)
delta = time.time() - now

message = "timeout was pool-level LONG_TIMEOUT rather than request-level SHORT_TIMEOUT"
assert delta < LONG_TIMEOUT, message
message = "timeout was pool-level SHORT_TIMEOUT rather than request-level LONG_TIMEOUT"
assert delta >= LONG_TIMEOUT, message
block_event.set() # Release request

# Timeout int/float passed directly to request and _make_request should
# raise a request timeout
# Timeout passed directly to request should raise a request timeout
wait_for_socket(ready_event)
with pytest.raises(ReadTimeoutError):
pool.request("GET", "/", timeout=SHORT_TIMEOUT)
block_event.set() # Release request

wait_for_socket(ready_event)
conn = pool._new_conn()
# FIXME: This assert flakes sometimes. Not sure why.
with pytest.raises(ReadTimeoutError):
pool._make_request(conn, "GET", "/", timeout=SHORT_TIMEOUT)
block_event.set() # Release request

def test_connect_timeout(self):
url = "/"
host, port = TARPIT_HOST, 80
Expand Down
4 changes: 0 additions & 4 deletions test/with_dummyserver/test_proxy_poolmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,15 +131,13 @@ def test_cross_host_redirect(self):
"GET",
"%s/redirect" % self.http_url,
fields={"target": cross_host_location},
timeout=LONG_TIMEOUT,
retries=0,
)

r = http.request(
"GET",
"%s/redirect" % self.http_url,
fields={"target": "%s/echo?a=b" % self.http_url_alt},
timeout=LONG_TIMEOUT,
retries=1,
)
assert r._pool.host != self.http_host_alt
Expand All @@ -152,15 +150,13 @@ def test_cross_protocol_redirect(self):
"GET",
"%s/redirect" % self.http_url,
fields={"target": cross_protocol_location},
timeout=LONG_TIMEOUT,
retries=0,
)

r = http.request(
"GET",
"%s/redirect" % self.http_url,
fields={"target": "%s/echo?a=b" % self.https_url},
timeout=LONG_TIMEOUT,
retries=1,
)
assert r._pool.host == self.https_host
Expand Down