123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- # Copyright (c) 2017–2018 crocoite contributors
- #
- # Permission is hereby granted, free of charge, to any person obtaining a copy
- # of this software and associated documentation files (the "Software"), to deal
- # in the Software without restriction, including without limitation the rights
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- # copies of the Software, and to permit persons to whom the Software is
- # furnished to do so, subject to the following conditions:
- #
- # The above copyright notice and this permission notice shall be included in
- # all copies or substantial portions of the Software.
- #
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- # THE SOFTWARE.
- import asyncio
- from yarl import URL
- from aiohttp import web
- import pytest
- from .logger import Logger
- from .controller import ControllerSettings, SinglePageController, SetEntry, \
- IdleStateTracker
- from .browser import PageIdle
- from .devtools import Process
- from .test_browser import loader
- @pytest.mark.asyncio
- async def test_controller_timeout ():
- """ Make sure the controller terminates, even if the site keeps reloading/fetching stuff """
- async def f (req):
- return web.Response (body="""<html>
- <body>
- <p>hello</p>
- <script>
- window.setTimeout (function () { window.location = '/' }, 250);
- window.setInterval (function () { fetch('/').then (function (e) { console.log (e) }) }, 150);
- </script>
- </body>
- </html>""", status=200, content_type='text/html', charset='utf-8')
- url = URL.build (scheme='http', host='localhost', port=8080)
- app = web.Application ()
- app.router.add_route ('GET', '/', f)
- runner = web.AppRunner(app)
- await runner.setup()
- site = web.TCPSite(runner, url.host, url.port)
- await site.start()
- loop = asyncio.get_event_loop ()
- try:
- logger = Logger ()
- settings = ControllerSettings (idleTimeout=1, timeout=5)
- controller = SinglePageController (url=url, logger=logger,
- service=Process (), behavior=[], settings=settings)
- # give the controller a little more time to finish, since there are
- # hard-coded asyncio.sleep calls in there right now.
- # XXX fix this
- before = loop.time ()
- await asyncio.wait_for (controller.run (), timeout=settings.timeout*2)
- after = loop.time ()
- assert after-before >= settings.timeout, (settings.timeout*2, after-before)
- finally:
- # give the browser some time to close before interrupting the
- # connection by destroying the HTTP server
- await asyncio.sleep (1)
- await runner.cleanup ()
- @pytest.mark.asyncio
- async def test_controller_idle_timeout ():
- """ Make sure the controller terminates, even if the site keeps reloading/fetching stuff """
- async def f (req):
- return web.Response (body="""<html>
- <body>
- <p>hello</p>
- <script>
- window.setInterval (function () { fetch('/').then (function (e) { console.log (e) }) }, 2000);
- </script>
- </body>
- </html>""", status=200, content_type='text/html', charset='utf-8')
- url = URL.build (scheme='http', host='localhost', port=8080)
- app = web.Application ()
- app.router.add_route ('GET', '/', f)
- runner = web.AppRunner(app)
- await runner.setup()
- site = web.TCPSite(runner, url.host, url.port)
- await site.start()
- loop = asyncio.get_event_loop ()
- try:
- logger = Logger ()
- settings = ControllerSettings (idleTimeout=1, timeout=60)
- controller = SinglePageController (url=url, logger=logger,
- service=Process (), behavior=[], settings=settings)
- before = loop.time ()
- await asyncio.wait_for (controller.run (), settings.timeout*2)
- after = loop.time ()
- assert settings.idleTimeout <= after-before <= settings.idleTimeout*2+3
- finally:
- await runner.cleanup ()
- def test_set_entry ():
- a = SetEntry (1, a=2, b=3)
- assert a == a
- assert hash (a) == hash (a)
- b = SetEntry (1, a=2, b=4)
- assert a == b
- assert hash (a) == hash (b)
- c = SetEntry (2, a=2, b=3)
- assert a != c
- assert hash (a) != hash (c)
- @pytest.mark.asyncio
- async def test_idle_state_tracker ():
- # default is idle
- loop = asyncio.get_event_loop ()
- idle = IdleStateTracker (loop)
- assert idle._idle
- # idle change
- await idle.push (PageIdle (False))
- assert not idle._idle
- # nothing happens for other objects
- await idle.push ({})
- assert not idle._idle
- # no state change -> wait does not return
- with pytest.raises (asyncio.TimeoutError):
- await asyncio.wait_for (idle.wait (0.1), timeout=1)
- # wait at least timeout
- delta = 0.2
- timeout = 1
- await idle.push (PageIdle (True))
- assert idle._idle
- start = loop.time ()
- await idle.wait (timeout)
- end = loop.time ()
- assert (timeout-delta) < (end-start) < (timeout+delta)
- @pytest.fixture
- async def recordingServer ():
- """ Simple HTTP server that records raw requests """
- url = URL ('http://localhost:8080')
- reqs = []
- async def record (request):
- reqs.append (request)
- return web.Response(text='ok', content_type='text/plain')
- app = web.Application()
- app.add_routes([web.get(url.path, record)])
- runner = web.AppRunner(app)
- await runner.setup()
- site = web.TCPSite (runner, url.host, url.port)
- await site.start()
- yield url, reqs
- await runner.cleanup ()
- from .test_devtools import tab, browser
- from http.cookies import Morsel, SimpleCookie
- @pytest.mark.asyncio
- async def test_set_cookies (tab, recordingServer):
- """ Make sure cookies are set properly and only affect the domain they were
- set for """
- logger = Logger ()
- url, reqs = recordingServer
- cookies = []
- c = Morsel ()
- c.set ('foo', 'bar', '')
- c['domain'] = 'localhost'
- cookies.append (c)
- c = Morsel ()
- c.set ('buz', 'beef', '')
- c['domain'] = 'nonexistent.example'
- settings = ControllerSettings (idleTimeout=1, timeout=60, cookies=cookies)
- controller = SinglePageController (url=url, logger=logger,
- service=Process (), behavior=[], settings=settings)
- await asyncio.wait_for (controller.run (), settings.timeout*2)
-
- assert len (reqs) == 1
- req = reqs[0]
- reqCookies = SimpleCookie (req.headers['cookie'])
- assert len (reqCookies) == 1
- c = next (iter (reqCookies.values ()))
- assert c.key == cookies[0].key
- assert c.value == cookies[0].value
|