Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Broken tests on 32-bit platforms: test_set_cookie and test_expires_on_set_cookie #2032

Closed
kraptor opened this issue Feb 11, 2023 · 6 comments

Comments

@kraptor
Copy link
Contributor

kraptor commented Feb 11, 2023

The following test will never success in 32-bit platforms, as the date goes beyond the maximum value that time_t can hold, causing an overflow exception. I suggest to add a skip on these platforms for these tests or rework them to not to break.

Broken tests:

We are skipping these tests in openSUSE as we build for i586 and armv7l archs, but it would be nice to take them into account.

Here is an excerpt of one of the errors:


[   40s] ___________________ test_expires_on_set_cookie[asyncio-int] ____________________
[   40s] 
[   40s] test_client_factory = functools.partial(<class 'starlette.testclient.TestClient'>, backend='asyncio', backend_options={})
[   40s] monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0xf38e7988>
[   40s] expires = 10
[   40s] 
[   40s]     @pytest.mark.parametrize(
[   40s]         "expires",
[   40s]         [
[   40s]             pytest.param(
[   40s]                 dt.datetime(2100, 1, 22, 12, 0, 10, tzinfo=dt.timezone.utc), id="datetime"
[   40s]             ),
[   40s]             pytest.param("Fri, 22 Jan 2100 12:00:10 GMT", id="str"),
[   40s]             pytest.param(10, id="int"),
[   40s]         ],
[   40s]     )
[   40s]     def test_expires_on_set_cookie(test_client_factory, monkeypatch, expires):
[   40s]         # Mock time used as a reference for `Expires` by stdlib `SimpleCookie`.
[   40s]         mocked_now = dt.datetime(2100, 1, 22, 12, 0, 0, tzinfo=dt.timezone.utc)
[   40s]         monkeypatch.setattr(time, "time", lambda: mocked_now.timestamp())
[   40s]     
[   40s]         async def app(scope, receive, send):
[   40s]             response = Response("Hello, world!", media_type="text/plain")
[   40s]             response.set_cookie("mycookie", "myvalue", expires=expires)
[   40s]             await response(scope, receive, send)
[   40s]     
[   40s]         client = test_client_factory(app)
[   40s] >       response = client.get("/")
[   40s] 
[   40s] tests/test_responses.py:345: 
[   40s] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
[   40s] starlette/testclient.py:492: in get
[   40s]     return super().get(
[   40s] /usr/lib/python3.8/site-packages/httpx/_client.py:1045: in get
[   40s]     return self.request(
[   40s] starlette/testclient.py:458: in request
[   40s]     return super().request(
[   40s] /usr/lib/python3.8/site-packages/httpx/_client.py:821: in request
[   40s]     return self.send(request, auth=auth, follow_redirects=follow_redirects)
[   40s] /usr/lib/python3.8/site-packages/httpx/_client.py:908: in send
[   40s]     response = self._send_handling_auth(
[   40s] /usr/lib/python3.8/site-packages/httpx/_client.py:936: in _send_handling_auth
[   40s]     response = self._send_handling_redirects(
[   40s] /usr/lib/python3.8/site-packages/httpx/_client.py:973: in _send_handling_redirects
[   40s]     response = self._send_single_request(request)
[   40s] /usr/lib/python3.8/site-packages/httpx/_client.py:1009: in _send_single_request
[   40s]     response = transport.handle_request(request)
[   40s] starlette/testclient.py:337: in handle_request
[   40s]     raise exc
[   40s] starlette/testclient.py:334: in handle_request
[   40s]     portal.call(self.app, scope, receive, send)
[   40s] /usr/lib/python3.8/site-packages/anyio/from_thread.py:283: in call
[   40s]     return cast(T_Retval, self.start_task_soon(func, *args).result())
[   40s] /usr/lib/python3.8/concurrent/futures/_base.py:437: in result
[   40s]     return self.__get_result()
[   40s] /usr/lib/python3.8/concurrent/futures/_base.py:389: in __get_result
[   40s]     raise self._exception
[   40s] /usr/lib/python3.8/site-packages/anyio/from_thread.py:219: in _call_func
[   40s]     retval = await retval
[   40s] tests/test_responses.py:341: in app
[   40s]     response.set_cookie("mycookie", "myvalue", expires=expires)
[   40s] starlette/responses.py:140: in set_cookie
[   40s]     cookie_val = cookie.output(header="").strip()
[   40s] /usr/lib/python3.8/http/cookies.py:502: in output
[   40s]     result.append(value.output(attrs, header))
[   40s] /usr/lib/python3.8/http/cookies.py:372: in output
[   40s]     return "%s %s" % (header, self.OutputString(attrs))
[   40s] /usr/lib/python3.8/http/cookies.py:408: in OutputString
[   40s]     append("%s=%s" % (self._reserved[key], _getdate(value)))
[   40s] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
[   40s] 
[   40s] future = 10, weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', ...]
[   40s] monthname = [None, 'Jan', 'Feb', 'Mar', 'Apr', 'May', ...]
[   40s] 
[   40s]     def _getdate(future=0, weekdayname=_weekdayname, monthname=_monthname):
[   40s]         from time import gmtime, time
[   40s]         now = time()
[   40s] >       year, month, day, hh, mm, ss, wd, y, z = gmtime(now + future)
[   40s] E       OverflowError: timestamp out of range for platform time_t
@Kludex
Copy link
Sponsor Member

Kludex commented Feb 11, 2023

We just need to change the year?

@kraptor
Copy link
Contributor Author

kraptor commented Feb 11, 2023

We just need to change the year?

Yeah, that will do it.

@Kludex
Copy link
Sponsor Member

Kludex commented Feb 11, 2023

Would you like to open a PR? Since you can verify the date it will work on those OSs.

@kraptor
Copy link
Contributor Author

kraptor commented Feb 11, 2023

Sure, let me do it.

@Kludex
Copy link
Sponsor Member

Kludex commented Feb 11, 2023

Closed by #2033

@Kludex Kludex closed this as completed Feb 11, 2023
@cglacet
Copy link

cglacet commented Feb 21, 2023

Isn't the test wrong anyway? Shouldn't set-cookie be automatically propagated to subsequent requests made by the TestClient?

I had to work around this limitation in my tests using something like this:

from requests.models import Response
from starlette.testclient import TestClient


def collect_set_cookies(response: Response):
    cookies = SimpleCookie()
    cookies.load(response.headers["set-cookie"])
    return {name: cookie.value for name, cookie in cookies.items()}


def test_set_cookies(client: TestClient):
    response_A = client.post("/apiA")
    jsonA = response.json()
    cookies = collect_set_cookies(response)
    responseB = client.post("/apiB", json=jsonA, cookies=cookies)
    assert True

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants