""" Test serving files. """ import os import re import urllib.request import pytest import werkzeug.exceptions from vasl_templates.webapp.files import FileServer from vasl_templates.webapp.tests.utils import init_webapp, find_child, wait_for_clipboard # --------------------------------------------------------------------- def test_local_file_server( webapp ): """Test serving files from the local file system.""" # initialize base_dir = os.path.normpath( os.path.join( os.path.split(__file__)[0], "fixtures/file-server" ) ) file_server = FileServer( base_dir ) # do the tests with webapp.test_request_context(): assert _get_response_data( file_server.serve_file( "1.txt" ) ).strip() == b"file 1" with pytest.raises( werkzeug.exceptions.NotFound ): _get_response_data( file_server.serve_file( "/1.txt" ) ) with pytest.raises( werkzeug.exceptions.NotFound ): _get_response_data( file_server.serve_file( "unknown.txt" ) ) assert _get_response_data( file_server.serve_file( "subdir/2.txt" ) ).strip() == b"file 2" with pytest.raises( werkzeug.exceptions.NotFound ): _get_response_data( file_server.serve_file( "/subdir/2.txt" ) ) # try to get a file outside the configured directory fname = "../new-default-scenario.json" assert os.path.isfile( os.path.join( base_dir, fname ) ) with pytest.raises( werkzeug.exceptions.NotFound ): _get_response_data( file_server.serve_file( fname) ) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def test_remote_file_server( webapp ): """Test serving files from a remote file system.""" # initialize base_url = "{}/static/images".format( _get_base_url( webapp ) ) file_server = FileServer( base_url ) base_dir = os.path.join( os.path.split(__file__)[0], "../static/images" ) def do_test( fname ): """Get the specified user file from the remote server and check the response.""" buf = _get_response_data( file_server.serve_file( fname ) ) with open( os.path.join( base_dir, fname ), "rb" ) as fp: assert buf == fp.read() # do the tests with webapp.test_request_context(): do_test( "hint.png" ) do_test( "flags/german.png" ) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def _get_base_url( webapp ): """Get the webapp base URL.""" url = webapp.url_for( "get_user_file", path="unused" ) mo = re.search( r"^http://.+?:\d+", url ) return mo.group() def _get_response_data( resp ): """Get the data from a Flask response.""" resp.direct_passthrough = False return resp.get_data() # --------------------------------------------------------------------- def test_local_user_files( webapp, webdriver ): """Test serving user files from the local file system.""" def do_test( enable_user_files ): #pylint: disable=missing-docstring # initialize webapp.control_tests.set_user_files_dir( "user-files/" if enable_user_files else None ) init_webapp( webapp, webdriver ) # try getting a user file try: url = webapp.url_for( "get_user_file", path="hello.txt" ) with urllib.request.urlopen( url ) as resp: assert enable_user_files # nb: we should only get here if user files are enabled assert resp.code == 200 assert resp.read().strip() == b"Yo, wassup!" assert resp.headers[ "Content-Type" ].startswith( "text/plain" ) except urllib.error.HTTPError as ex: assert not enable_user_files # nb: we should only get here if user files are disabled assert ex.code == 404 # try getting a non-existent file (nb: should always fail, whether user files are enabled/disabled) with pytest.raises( urllib.error.HTTPError ) as exc_info: url = webapp.url_for( "get_user_file", path="unknown" ) with urllib.request.urlopen( url ): pass assert exc_info.value.code == 404 # try getting a file in a sub-directory try: url = webapp.url_for( "get_user_file", path="subdir/placeholder.png" ) with urllib.request.urlopen( url ) as resp: assert enable_user_files # nb: we should only get here if user files are enabled assert resp.code == 200 assert resp.read().startswith( b"\x89PNG\r\n" ) assert resp.headers[ "Content-Type" ] == "image/png" except urllib.error.HTTPError as ex: assert not enable_user_files # nb: we should only get here if user files are disabled assert ex.code == 404 # try getting a file outside the configured directory (nb: should always fail) fname = os.path.join( os.path.split(__file__)[0], "fixtures/new-default-scenario.json" ) assert os.path.isfile( fname ) with pytest.raises( urllib.error.HTTPError ) as exc_info: url = webapp.url_for( "get_user_file", path="../new-default-scenario.json" ) with urllib.request.urlopen( url ): pass assert exc_info.value.code == 404 # try getting a file with special characters in its name try: url = webapp.url_for( "get_user_file", path="amp=& ; plus=+.txt" ) with urllib.request.urlopen( url ) as resp: assert enable_user_files # nb: we should only get here if user files are enabled assert resp.code == 200 assert resp.read().strip() == b"special chars" assert resp.headers[ "Content-Type" ].startswith( "text/plain" ) except urllib.error.HTTPError as ex: assert not enable_user_files # nb: we should only get here if user files are disabled assert ex.code == 404 # do the tests with user files enabled/disabled do_test( True ) do_test( False ) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def test_remote_user_files( webapp, webdriver ): """Test serving user files from a remote server.""" # initialize init_webapp( webapp, webdriver ) remote_app_config = webapp.control_tests.get_app_config() def do_test( enable_user_files ): #pylint: disable=missing-docstring # initialize base_url = "{}/static/images".format( _get_base_url( webapp ) ) if remote_app_config.get( "IS_CONTAINER" ): # FUDGE! We test getting a file from a remote server by requesting a file from the webapp (since we know # it will be available). However, if it's running in a container, the port it needs to use to talk # to itself is not necessarily the same as the port an outside client (e.g. us) uses to talk with it, # so we need to adjust the user files base URL to reflect that. remote_base_url = "http://localhost:{}".format( remote_app_config["FLASK_PORT_NO"] ) base_url = re.sub( r"http://.+?:\d+", remote_base_url, base_url ) webapp.control_tests.set_user_files_dir( base_url if enable_user_files else None ) init_webapp( webapp, webdriver ) # try getting a user file try: url = webapp.url_for( "get_user_file", path="menu.png" ) with urllib.request.urlopen( url ) as resp: assert enable_user_files # nb: we should only get here if user files are enabled assert resp.code == 200 assert resp.read().startswith( b"\x89PNG\r\n" ) assert resp.headers[ "Content-Type" ] == "image/png" except urllib.error.HTTPError as ex: assert not enable_user_files # nb: we should only get here if user files are disabled assert ex.code == 404 # do the tests with user files enabled/disabled do_test( True ) do_test( False ) # --------------------------------------------------------------------- def test_user_file_snippets( webapp, webdriver ): """Test user files in snippets.""" def do_test( enable_user_files ): #pylint: disable=missing-docstring # initialize webapp.control_tests.set_user_files_dir( "user-files/" if enable_user_files else None ) init_webapp( webapp, webdriver ) # set the victory conditions elem = find_child( "textarea[name='VICTORY_CONDITIONS']" ) elem.send_keys( "my image: {{USER_FILES}}/subdir/placeholder.png" ) btn = find_child( "button.generate[data-id='victory_conditions']" ) btn.click() def get_user_file_url( clipboard ): #pylint: disable=missing-docstring # nb: the test template wraps {{VICTORY_CONDITIONS}} in square brackets :-/ mo = re.search( r"http://.+?/([^]]+)", clipboard ) return "/" + mo.group(1) wait_for_clipboard( 2, "/user/subdir/placeholder.png", transform=get_user_file_url ) # do the tests with user files enabled/disabled # NOTE: The user file URL will be inserted into the snippet even if user files are disabled, # but the URL will 404 when somebody tries to resolve it. do_test( True ) do_test( False )