Updated the tests so that they can be used with a remote server.

master v0.6
Pacman Ghost 5 years ago
parent 7d9ceac239
commit e6c37c49f9
  1. 1
      .pylintrc
  2. 65
      conftest.py
  3. 3
      vasl_templates/webapp/__init__.py
  4. 41
      vasl_templates/webapp/testing.py
  5. 168
      vasl_templates/webapp/tests/remote.py
  6. 13
      vasl_templates/webapp/tests/test_capabilities.py
  7. 62
      vasl_templates/webapp/tests/test_counters.py
  8. 12
      vasl_templates/webapp/tests/test_default_scenario.py
  9. 8
      vasl_templates/webapp/tests/test_snippets.py
  10. 11
      vasl_templates/webapp/tests/test_template_packs.py
  11. 15
      vasl_templates/webapp/tests/test_user_settings.py
  12. 89
      vasl_templates/webapp/tests/test_vassal.py
  13. 53
      vasl_templates/webapp/tests/test_vehicles_ordnance.py
  14. 39
      vasl_templates/webapp/tests/utils.py
  15. 2
      vasl_templates/webapp/vassal.py

@ -141,6 +141,7 @@ disable=print-statement,
global-statement,
too-few-public-methods,
duplicate-code, # can't get it to shut up about @pytest.mark.skipif's :-/
no-else-return
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option

@ -14,7 +14,7 @@ from vasl_templates.webapp import app
app.testing = True
from vasl_templates.webapp.tests import utils
FLASK_WEBAPP_PORT = 5001
FLASK_WEBAPP_PORT = 5011
# ---------------------------------------------------------------------
@ -24,6 +24,10 @@ def pytest_addoption( parser ):
# NOTE: This file needs to be in the project root for this to work :-/
# add test options
parser.addoption(
"--server-url", action="store", dest="server_url", default=None,
help="Webapp server to test against."
)
# NOTE: Chrome seems to be ~15% faster than Firefox, headless ~5% faster than headful.
parser.addoption(
"--webdriver", action="store", dest="webdriver", default="chrome",
@ -73,6 +77,10 @@ def pytest_addoption( parser ):
def webapp():
"""Launch the webapp."""
# initialize
server_url = pytest.config.option.server_url #pylint: disable=no-member
logging.disable( logging.CRITICAL )
# initialize
# WTF?! https://github.com/pallets/flask/issues/824
def make_webapp_url( endpoint, **kwargs ):
@ -94,39 +102,40 @@ def webapp():
# to avoid problems if something else uses the clipboard while the tests are running.
kwargs["store_clipboard"] = 1
url = url_for( endpoint, _external=True, **kwargs )
return url.replace( "localhost/", "localhost:{}/".format(FLASK_WEBAPP_PORT) )
if server_url:
url = url.replace( "http://localhost", server_url )
else:
url = url.replace( "localhost/", "localhost:{}/".format(FLASK_WEBAPP_PORT) )
return url
app.url_for = make_webapp_url
# configure the webapp to use our test data
# NOTE: Can't seem to change constants.DATA_DIR (probably some pytest funkiness :-/)
app.config["DATA_DIR"] = os.path.join( os.path.split(__file__)[0], "vasl_templates/webapp/tests/fixtures/data" )
# start the webapp server (in a background thread)
logging.disable( logging.CRITICAL )
thread = threading.Thread(
target = lambda: app.run( host="0.0.0.0", port=FLASK_WEBAPP_PORT, use_reloader=False )
)
thread.start()
# wait for the server to start up
def is_ready():
"""Try to connect to the webapp server."""
try:
resp = urllib.request.urlopen( app.url_for("ping") ).read()
assert resp == b"pong"
return True
except URLError:
return False
except Exception as ex: #pylint: disable=broad-except
assert False, "Unexpected exception: {}".format(ex)
utils.wait_for( 5, is_ready )
# check if we need to start a local webapp server
if not server_url:
# yup - make it so
thread = threading.Thread(
target = lambda: app.run( host="0.0.0.0", port=FLASK_WEBAPP_PORT, use_reloader=False )
)
thread.start()
# wait for the server to start up
def is_ready():
"""Try to connect to the webapp server."""
try:
resp = urllib.request.urlopen( app.url_for("ping") ).read()
assert resp == b"pong"
return True
except URLError:
return False
except Exception as ex: #pylint: disable=broad-except
assert False, "Unexpected exception: {}".format(ex)
utils.wait_for( 5, is_ready )
# return the server to the caller
yield app
# shutdown the webapp server
urllib.request.urlopen( app.url_for("shutdown") ).read()
thread.join()
# shutdown the local webapp server
if not server_url:
urllib.request.urlopen( app.url_for("shutdown") ).read()
thread.join()
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

@ -60,6 +60,9 @@ import vasl_templates.webapp.vo #pylint: disable=cyclic-import
import vasl_templates.webapp.snippets #pylint: disable=cyclic-import
import vasl_templates.webapp.files #pylint: disable=cyclic-import
import vasl_templates.webapp.vassal #pylint: disable=cyclic-import
if app.config.get( "ENABLE_REMOTE_TEST_CONTROL" ):
print( "*** WARNING: Remote test control enabled! ***" )
import vasl_templates.webapp.testing #pylint: disable=cyclic-import
# ---------------------------------------------------------------------

@ -0,0 +1,41 @@
"""Webapp handlers for testing porpoises."""
import inspect
from flask import request, jsonify, abort
from vasl_templates.webapp import app
from vasl_templates.webapp.tests.remote import ControlTests
# ---------------------------------------------------------------------
@app.route( "/control-tests/<action>" )
def control_tests( action ):
"""Accept commands from a remote test suite."""
# check if this functionality has been enabled
if not app.config.get( "ENABLE_REMOTE_TEST_CONTROL" ):
abort( 404 )
# figure out what we're being asked to do
controller = ControlTests( app )
func = getattr( controller, action )
if not func:
abort( 404 )
# get any parameters
sig = inspect.signature( func )
kwargs = {}
for param in sig.parameters.values():
if param.name in ("vengine","vmod","gpids","ddtype","fname","dname"):
kwargs[ param.name ] = request.args.get( param.name, param.default )
# execute the command
resp = func( **kwargs )
# return any response
if isinstance( resp, (str,list,dict) ):
return jsonify( resp )
else:
assert resp == controller, "Methods should return self if there is no response data."
return "ok"

@ -0,0 +1,168 @@
"""Allow a remote server to be controlled during tests.
We sometimes make changes to the webapp server during tests, and while we used to do that using pytest's monkeypatch,
that will not work if we are talking to a remote (i.e. in another process) server. This module defines the things
that can be changed during the course of tests, and a simple RPC mechanism that lets them be executed remotely.
It needs to be enabled in the server via the ENABLE_REMOTE_TEST_CONTROL debug switch.
"""
import os
import urllib.request
import json
import glob
import logging
import random
import pytest
from vasl_templates.webapp import app
from vasl_templates.webapp.config.constants import DATA_DIR
from vasl_templates.webapp import main as webapp_main
from vasl_templates.webapp import snippets as webapp_snippets
from vasl_templates.webapp import files as webapp_files
from vasl_templates.webapp.file_server import utils as webapp_file_server_utils
from vasl_templates.webapp.file_server.vasl_mod import VaslMod
_logger = logging.getLogger( "control_tests" )
# ---------------------------------------------------------------------
class ControlTests:
"""Control a remote server during tests."""
def __init__( self, webapp ):
self.webapp = webapp
try:
self.server_url = pytest.config.option.server_url #pylint: disable=no-member
except AttributeError:
self.server_url = None
def __getattr__( self, name ):
"""Generic entry point for handling control requests."""
if name.startswith( ("get_","set_") ):
# check if we are talking to a local or remote server
if self.server_url:
# remote: return a function that will invoke the handler function on the remote server
def call_remote( **kwargs ): #pylint: disable=missing-docstring
return self._remote_test_control( name, **kwargs )
return call_remote
else:
# local: return the actual handler function
return getattr( self, "_"+name )
raise AttributeError( name )
def _remote_test_control( self, action, **kwargs ):
"""Invoke a handler function on the remote server."""
resp = urllib.request.urlopen(
self.webapp.url_for( "control_tests", action=action, **kwargs )
).read()
if resp == b"ok":
return self
else:
return json.loads( resp.decode( "utf-8" ) )
def _set_data_dir( self, ddtype=None ):
"""Set the webapp's data directory."""
if ddtype == "real":
dname = DATA_DIR
elif ddtype == "test":
dname = os.path.join( os.path.split(__file__)[0], "fixtures/data" )
else:
raise RuntimeError( "Unknown data dir type: {}".format( ddtype ) )
_logger.info( "Setting data dir: %s", dname )
self.webapp.config[ "DATA_DIR" ] = dname
return self
def _set_default_scenario( self, fname=None ):
"""Set the default scenario."""
if fname:
dname = os.path.join( os.path.split(__file__)[0], "fixtures" )
fname = os.path.join( dname, fname )
_logger.info( "Setting default scenario: %s", fname )
webapp_main.default_scenario = fname
return self
def _set_default_template_pack( self, dname=None ):
"""Set the default template pack."""
if dname:
dname2 = os.path.join( os.path.split(__file__)[0], "fixtures" )
dname = os.path.join( dname2, dname )
_logger.info( "Setting default template pack: %s", dname )
webapp_snippets.default_template_pack = dname
return self
def _set_gpid_remappings( self, gpids=None ): #pylint: disable=no-self-use
"""Configure the GPID remappings."""
if isinstance( gpids, str ):
gpids = json.loads( gpids.replace( "'", '"' ) )
gpids = { int(k): v for k,v in gpids.items() }
_logger.info( "Setting GPID remappings: %s", gpids )
prev_gpid_mappings = webapp_file_server_utils.GPID_REMAPPINGS
webapp_file_server_utils.GPID_REMAPPINGS = gpids
return prev_gpid_mappings
def _get_vasl_mods( self ):
"""Return the available VASL modules."""
fnames = self._do_get_vasl_mods()
_logger.debug( "Returning VASL modules:\n%s",
"\n".join( "- {}".format( f ) for f in fnames )
)
return fnames
def _do_get_vasl_mods( self ): #pylint: disable=no-self-use
"""Return the available VASL modules."""
try:
dname = pytest.config.option.vasl_mods #pylint: disable=no-member
except AttributeError:
dname = app.config["TEST_VASL_MODS"]
fspec = os.path.join( dname, "*.vmod" )
return glob.glob( fspec )
def _set_vasl_mod( self, vmod=None ):
"""Install a VASL module."""
if vmod is None:
_logger.info( "Installing VASL module: %s", vmod )
webapp_files.vasl_mod = None
else:
fnames = self._do_get_vasl_mods()
if vmod == "random":
# NOTE: Some tests require a VASL module to be loaded, and since they should all
# should behave in the same way, it doesn't matter which one we load.
fname = random.choice( fnames )
else:
assert vmod in fnames
fname = vmod
_logger.info( "Installing VASL module: %s", fname )
webapp_files.vasl_mod = VaslMod( fname, DATA_DIR )
return self
def _get_vassal_engines( self ):
"""Get the available VASSAL engines."""
vassal_engines = self._do_get_vassal_engines()
_logger.debug( "Returning VASSAL engines:\n%s",
"\n".join( "- {}".format( ve ) for ve in vassal_engines )
)
return vassal_engines
def _do_get_vassal_engines( self ): #pylint: disable=no-self-use
"""Get the available VASSAL engines."""
try:
dname = pytest.config.option.vassal #pylint: disable=no-member
except AttributeError:
dname = app.config[ "TEST_VASSAL_ENGINES"]
vassal_engines = []
for root,_,fnames in os.walk( dname ):
for fname in fnames:
if fname == "Vengine.jar":
if root.endswith( "/lib" ):
root = root[:-4]
vassal_engines.append( root )
return vassal_engines
def _set_vassal_engine( self, vengine=None ):
"""Install a VASSAL engine."""
if vengine:
assert vengine in self._do_get_vassal_engines()
_logger.info( "Installing VASSAL engine: %s", vengine )
app.config["VASSAL_DIR"] = vengine
return self

@ -8,12 +8,11 @@ from selenium.webdriver.common.keys import Keys
from vasl_templates.webapp.tests.utils import \
init_webapp, select_menu_option, select_tab, click_dialog_button, \
load_vasl_mod, find_child, find_children, wait_for_clipboard, \
find_child, find_children, wait_for_clipboard, \
set_scenario_date
from vasl_templates.webapp.tests.test_vo_reports import get_vo_report
from vasl_templates.webapp.tests.test_vehicles_ordnance import add_vo
from vasl_templates.webapp.tests.test_scenario_persistence import save_scenario, load_scenario
from vasl_templates.webapp.config.constants import DATA_DIR as REAL_DATA_DIR
# ---------------------------------------------------------------------
@ -555,13 +554,15 @@ def test_custom_capabilities( webapp, webdriver ): #pylint: disable=too-many-sta
not pytest.config.option.vasl_mods, #pylint: disable=no-member
reason = "--vasl-mods not specified"
) #pylint: disable=too-many-statements
def test_capability_updates_in_ui( webapp, webdriver, monkeypatch ):
def test_capability_updates_in_ui( webapp, webdriver ):
"""Ensure that capabilities are updated in the UI correctly."""
# initialize
monkeypatch.setitem( webapp.config, "DATA_DIR", REAL_DATA_DIR )
load_vasl_mod( REAL_DATA_DIR, monkeypatch )
init_webapp( webapp, webdriver, scenario_persistence=1 )
init_webapp( webapp, webdriver, scenario_persistence=1,
reset = lambda ct:
ct.set_data_dir( ddtype="real" ) \
.set_vasl_mod( vmod="random" )
)
# load the scenario
scenario_data = {

@ -2,7 +2,6 @@
import os
import io
import glob
import json
import re
import urllib.request
@ -10,11 +9,12 @@ import urllib.request
import pytest
import tabulate
from vasl_templates.webapp.file_server.vasl_mod import VaslMod
from vasl_templates.webapp.file_server.utils import get_vo_gpids
from vasl_templates.webapp.file_server import utils as webapp_file_server_utils
from vasl_templates.webapp.config.constants import DATA_DIR as REAL_DATA_DIR
from vasl_templates.webapp.tests.utils import init_webapp, load_vasl_mod, select_tab, find_child, find_children
from vasl_templates.webapp.config.constants import DATA_DIR
from vasl_templates.webapp.tests.utils import init_webapp, select_tab, find_child, find_children
from vasl_templates.webapp.tests.test_scenario_persistence import load_scenario
from vasl_templates.webapp.tests.remote import ControlTests
# ---------------------------------------------------------------------
@ -26,13 +26,13 @@ from vasl_templates.webapp.tests.test_scenario_persistence import load_scenario
pytest.config.option.short_tests, #pylint: disable=no-member
reason = "--short-tests specified"
) #pylint: disable=too-many-statements
def test_counter_images( webapp, monkeypatch ):
def test_counter_images( webapp ):
"""Test that counter images are served correctly."""
# NOTE: This is ridiculously slow on Windows :-/
# figure out which pieces we're interested in
gpids = get_vo_gpids( REAL_DATA_DIR )
gpids = get_vo_gpids( DATA_DIR )
def check_images( check_front, check_back ): #pylint: disable=unused-argument
"""Check getting the front and back images for each counter."""
@ -49,7 +49,8 @@ def test_counter_images( webapp, monkeypatch ):
assert locals()["check_"+side]( resp_code, resp_data )
# test counter images when no VASL module has been configured
load_vasl_mod( None, monkeypatch )
control_tests = ControlTests( webapp )
control_tests.set_vasl_mod( vmod=None )
fname = os.path.join( os.path.split(__file__)[0], "../static/images/missing-image.png" )
missing_image_data = open( fname, "rb" ).read()
check_images(
@ -60,13 +61,20 @@ def test_counter_images( webapp, monkeypatch ):
# test each VASL module file in the specified directory
fname = os.path.join( os.path.split(__file__)[0], "fixtures/vasl-pieces.txt" )
expected_vasl_pieces = open( fname, "r" ).read()
fspec = os.path.join( pytest.config.option.vasl_mods, "*.vmod" ) #pylint: disable=no-member
for fname in glob.glob( fspec ):
vasl_mods = control_tests.get_vasl_mods()
for vasl_mod in vasl_mods:
# install the VASL module file
vasl_mod = load_vasl_mod( REAL_DATA_DIR, monkeypatch, fname=os.path.split(fname)[1] )
control_tests.set_vasl_mod( vmod=vasl_mod )
# NOTE: We assume we have access to the same VASL modules as the server, but the path on the webserver
# might be different to what it is locally, so we translate it here.
fname = os.path.split( vasl_mod )[1]
vasl_mods_dir = pytest.config.option.vasl_mods #pylint: disable=no-member
fname = os.path.join( vasl_mods_dir, fname )
# check the pieces loaded
vasl_mod = VaslMod( fname, DATA_DIR )
buf = io.StringIO()
_dump_pieces( vasl_mod, buf )
assert buf.getvalue() == expected_vasl_pieces
@ -96,11 +104,11 @@ def _dump_pieces( vasl_mod, out ):
not pytest.config.option.vasl_mods, #pylint: disable=no-member
reason = "--vasl-mods not specified"
)
def test_gpid_remapping( webapp, webdriver, monkeypatch ):
def test_gpid_remapping( webapp, webdriver ):
"""Test GPID remapping."""
# initialize
monkeypatch.setitem( webapp.config, "DATA_DIR", REAL_DATA_DIR )
control_tests = init_webapp( webapp, webdriver )
def check_gpid_image( gpid ):
"""Check if we can get the image for the specified GPID."""
@ -127,8 +135,11 @@ def test_gpid_remapping( webapp, webdriver, monkeypatch ):
def do_test( vasl_mod, valid_images ):
"""Do the test."""
# initialize (using the specified VASL vmod)
load_vasl_mod( REAL_DATA_DIR, monkeypatch, vasl_mod )
init_webapp( webapp, webdriver, scenario_persistence=1 )
init_webapp( webapp, webdriver, scenario_persistence=1,
reset = lambda ct:
ct.set_data_dir( ddtype="real" ) \
.set_vasl_mod( vmod=vasl_mod )
)
load_scenario( scenario_data )
# check that the German vehicles loaded correctly
select_tab( "ob1" )
@ -142,11 +153,24 @@ def test_gpid_remapping( webapp, webdriver, monkeypatch ):
fname = os.path.join( os.path.split(__file__)[0], "fixtures/gpid-remapping.json" )
scenario_data = json.load( open( fname, "r" ) )
# locate the VASL modules
vasl_mods = control_tests.get_vasl_mods()
def find_vasl_mod( version ):
"""Find the VASL module for the specified version."""
matches = [ vmod for vmod in vasl_mods if "vasl-{}.vmod".format(version) in vmod ]
assert len(matches) == 1
return matches[0]
# run the tests using VASL 6.4.2 and 6.4.3
do_test( "vasl-6.4.2.vmod", True )
do_test( "vasl-6.4.3.vmod", True )
do_test( find_vasl_mod("6.4.2"), True )
do_test( find_vasl_mod("6.4.3"), True )
# disable GPID remapping and try again
monkeypatch.setattr( webapp_file_server_utils, "GPID_REMAPPINGS", {} )
do_test( "vasl-6.4.2.vmod", True )
do_test( "vasl-6.4.3.vmod", False )
prev_gpid_mappings = control_tests.set_gpid_remappings( gpids={} )
try:
do_test( find_vasl_mod("6.4.2"), True )
do_test( find_vasl_mod("6.4.3"), False )
finally:
# NOTE: This won't get done if Python exits unexpectedly in the try block,
# which will leave the server in the wrong state if it's remote.
control_tests.set_gpid_remappings( gpids=prev_gpid_mappings )

@ -1,24 +1,20 @@
"""Test the loading of the default scenario."""
import os
from selenium.webdriver.support.ui import Select
from selenium.webdriver.common.keys import Keys
from vasl_templates.webapp import main
from vasl_templates.webapp.tests.utils import select_tab, find_child, get_sortable_entry_text, \
wait_for, init_webapp
# ---------------------------------------------------------------------
def test_default_scenario( webapp, webdriver, monkeypatch ):
def test_default_scenario( webapp, webdriver ):
"""Test loading the default scenario."""
# configure a new default scenario
fname = os.path.join( os.path.split(__file__)[0], "fixtures/new-default-scenario.json" )
monkeypatch.setattr( main, "default_scenario", fname )
# initialize
init_webapp( webapp, webdriver )
init_webapp( webapp, webdriver,
reset = lambda ct: ct.set_default_scenario( fname="new-default-scenario.json" )
)
# wait for the scenario to load
elem = find_child( "input[name='SCENARIO_NAME']" )

@ -2,7 +2,6 @@
from selenium.webdriver.common.keys import Keys
from vasl_templates.webapp.config.constants import DATA_DIR as REAL_DATA_DIR
from vasl_templates.webapp.tests.utils import \
init_webapp, select_tab, select_tab_for_elem, set_template_params, wait_for_clipboard, \
get_stored_msg, set_stored_msg_marker, find_child, find_children, adjust_html, \
@ -13,12 +12,13 @@ from vasl_templates.webapp.tests.test_scenario_persistence import load_scenario,
# ---------------------------------------------------------------------
def test_snippet_ids( webapp, webdriver, monkeypatch ):
def test_snippet_ids( webapp, webdriver ):
"""Check that snippet ID's are generated correctly."""
# initialize
monkeypatch.setitem( webapp.config, "DATA_DIR", REAL_DATA_DIR )
init_webapp( webapp, webdriver, scenario_persistence=1 )
init_webapp( webapp, webdriver, scenario_persistence=1,
reset = lambda ct: ct.set_data_dir( ddtype="real" )
)
# load a scenario (so that we get some sortable's)
scenario_data = {

@ -7,7 +7,6 @@ import base64
from selenium.webdriver.support.ui import Select
from vasl_templates.webapp import snippets
from vasl_templates.webapp.tests.utils import \
select_tab, select_menu_option, wait_for_clipboard, get_stored_msg, set_stored_msg, set_stored_msg_marker,\
add_simple_note, for_each_template, find_child, find_children, wait_for, \
@ -72,15 +71,13 @@ def test_zip_files( webapp, webdriver ):
# ---------------------------------------------------------------------
def test_new_default_template_pack( webapp, webdriver, monkeypatch ):
def test_new_default_template_pack( webapp, webdriver ):
"""Test changing the default template pack."""
# configure a new default template pack
dname = os.path.join( os.path.split(__file__)[0], "fixtures/template-packs/new-default/" )
monkeypatch.setattr( snippets, "default_template_pack", dname )
# initialize
init_webapp( webapp, webdriver )
init_webapp( webapp, webdriver,
reset = lambda ct: ct.set_default_template_pack( dname="template-packs/new-default/" )
)
# check that the new templates are being used
_check_snippets( lambda tid: "New default {}.".format( tid.upper() ) )

@ -11,16 +11,16 @@ from vasl_templates.webapp.tests.utils import \
from vasl_templates.webapp.tests.test_vehicles_ordnance import add_vo
from vasl_templates.webapp.tests.test_scenario_persistence import save_scenario, load_scenario
from vasl_templates.webapp.tests.test_template_packs import upload_template_pack_file
from vasl_templates.webapp.config.constants import DATA_DIR as REAL_DATA_DIR
# ---------------------------------------------------------------------
def test_include_vasl_images_in_snippets( webapp, webdriver, monkeypatch ):
def test_include_vasl_images_in_snippets( webapp, webdriver ):
"""Test including VASL counter images in snippets."""
# initialize
monkeypatch.setitem( webapp.config, "DATA_DIR", REAL_DATA_DIR )
init_webapp( webapp, webdriver )
init_webapp( webapp, webdriver,
reset = lambda ct: ct.set_data_dir( ddtype="real" )
)
# add a vehicle
add_vo( webdriver, "vehicles", 1, "PzKpfw IB (Tt)" )
@ -52,12 +52,13 @@ def test_include_vasl_images_in_snippets( webapp, webdriver, monkeypatch ):
# ---------------------------------------------------------------------
def test_include_flags_in_snippets( webapp, webdriver, monkeypatch ):
def test_include_flags_in_snippets( webapp, webdriver ):
"""Test including flags in snippets."""
# initialize
monkeypatch.setitem( webapp.config, "DATA_DIR", REAL_DATA_DIR )
init_webapp( webapp, webdriver )
init_webapp( webapp, webdriver,
reset = lambda ct: ct.set_data_dir( ddtype="real" )
)
# prepare the scenario
select_tab( "ob1" )

@ -1,7 +1,6 @@
""" Test VASSAL integration. """
import os
import glob
import re
import json
import base64
@ -10,7 +9,6 @@ import typing.re #pylint: disable=import-error
import pytest
from vasl_templates.webapp.config.constants import DATA_DIR as REAL_DATA_DIR
from vasl_templates.webapp.vassal import VassalShim
from vasl_templates.webapp.utils import TempFile, change_extn
from vasl_templates.webapp.tests.utils import \
@ -23,15 +21,13 @@ from vasl_templates.webapp.tests.test_scenario_persistence import load_scenario,
@pytest.mark.skipif( not pytest.config.option.vasl_mods, reason="--vasl-mods not specified" ) #pylint: disable=no-member
@pytest.mark.skipif( not pytest.config.option.vassal, reason="--vassal not specified" ) #pylint: disable=no-member
@pytest.mark.skipif( pytest.config.option.short_tests, reason="--short-tests specified" ) #pylint: disable=no-member
def test_full_update( webapp, webdriver, monkeypatch ):
def test_full_update( webapp, webdriver ):
"""Test updating a scenario that contains the full set of snippets."""
# initialize
monkeypatch.setitem( webapp.config, "DATA_DIR", REAL_DATA_DIR )
init_webapp( webapp, webdriver, vsav_persistence=1 )
# NOTE: We disable this for speed, since we don't care about label positioning.
monkeypatch.setitem( webapp.config, "DISABLE_UPDATE_VSAV_SCREENSHOTS", True )
control_tests = init_webapp( webapp, webdriver, vsav_persistence=1,
reset = lambda ct: ct.set_data_dir( ddtype="real" )
)
# load the scenario fields
SCENARIO_PARAMS = {
@ -144,22 +140,20 @@ def test_full_update( webapp, webdriver, monkeypatch ):
assert updated_vsav_data == b"No changes."
# run the test against all versions of VASSAL+VASL
_run_tests( webapp, monkeypatch, do_test, True )
_run_tests( control_tests, do_test, True )
# ---------------------------------------------------------------------
@pytest.mark.skipif( not pytest.config.option.vasl_mods, reason="--vasl-mods not specified" ) #pylint: disable=no-member
@pytest.mark.skipif( not pytest.config.option.vassal, reason="--vassal not specified" ) #pylint: disable=no-member
@pytest.mark.skipif( pytest.config.option.short_tests, reason="--short-tests specified" ) #pylint: disable=no-member
def test_latw_autocreate( webapp, webdriver, monkeypatch ):
def test_latw_autocreate( webapp, webdriver ):
"""Test auto-creation of LATW labels."""
# initialize
monkeypatch.setitem( webapp.config, "DATA_DIR", REAL_DATA_DIR )
init_webapp( webapp, webdriver, vsav_persistence=1 )
# NOTE: We disable this for speed, since we don't care about label positioning.
monkeypatch.setitem( webapp.config, "DISABLE_UPDATE_VSAV_SCREENSHOTS", True )
control_tests = init_webapp( webapp, webdriver, vsav_persistence=1,
reset = lambda ct: ct.set_data_dir( ddtype="real" )
)
# NOTE: We're only interested in what happens with the LATW labels, we ignore everything else.
ignore_labels = [ "scenario", "players", "victory_conditions" ]
@ -217,22 +211,20 @@ def test_latw_autocreate( webapp, webdriver, monkeypatch ):
# NOTE: We're testing the logic in the front/back-ends that determine whether LATW labels
# get created/updated/deleted, not the interaction with VASSAL, so we don't need to test
# against every VASSAL+VASL combination (although we can, if we want, but it'll be slow!)
_run_tests( webapp, monkeypatch, do_test, False )
_run_tests( control_tests, do_test, False )
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@pytest.mark.skipif( not pytest.config.option.vasl_mods, reason="--vasl-mods not specified" ) #pylint: disable=no-member
@pytest.mark.skipif( not pytest.config.option.vassal, reason="--vassal not specified" ) #pylint: disable=no-member
@pytest.mark.skipif( pytest.config.option.short_tests, reason="--short-tests specified" ) #pylint: disable=no-member
def test_latw_update( webapp, webdriver, monkeypatch ):
def test_latw_update( webapp, webdriver ):
"""Test updating of LATW labels."""
# initialize
monkeypatch.setitem( webapp.config, "DATA_DIR", REAL_DATA_DIR )
init_webapp( webapp, webdriver, vsav_persistence=1 )
# NOTE: We disable this for speed, since we don't care about label positioning.
monkeypatch.setitem( webapp.config, "DISABLE_UPDATE_VSAV_SCREENSHOTS", True )
control_tests = init_webapp( webapp, webdriver, vsav_persistence=1,
reset = lambda ct: ct.set_data_dir( ddtype="real" )
)
# NOTE: We're only interested in what happens with the LATW labels, we ignore everything else.
ignore_labels = [ "scenario", "players", "victory_conditions" ]
@ -274,18 +266,18 @@ def test_latw_update( webapp, webdriver, monkeypatch ):
# NOTE: We're testing the logic in the front/back-ends that determine whether LATW labels
# get created/updated/deleted, not the interaction with VASSAL, so we don't need to test
# against every VASSAL+VASL combination (although we can, if we want, but it'll be slow!)
_run_tests( webapp, monkeypatch, do_test, False )
_run_tests( control_tests, do_test, False )
# ---------------------------------------------------------------------
@pytest.mark.skipif( not pytest.config.option.vasl_mods, reason="--vasl-mods not specified" ) #pylint: disable=no-member
@pytest.mark.skipif( not pytest.config.option.vassal, reason="--vassal not specified" ) #pylint: disable=no-member
@pytest.mark.skipif( pytest.config.option.short_tests, reason="--short-tests specified" ) #pylint: disable=no-member
def test_dump_vsav( webapp, webdriver, monkeypatch ):
def test_dump_vsav( webapp, webdriver ):
"""Test dumping a scenario."""
# initialize
init_webapp( webapp, webdriver )
control_tests = init_webapp( webapp, webdriver )
def do_test(): #pylint: disable=missing-docstring
@ -300,22 +292,20 @@ def test_dump_vsav( webapp, webdriver, monkeypatch ):
assert vsav_dump == expected
# run the test against all versions of VASSAL+VASL
_run_tests( webapp, monkeypatch, do_test, True )
_run_tests( control_tests, do_test, True )
# ---------------------------------------------------------------------
@pytest.mark.skipif( not pytest.config.option.vasl_mods, reason="--vasl-mods not specified" ) #pylint: disable=no-member
@pytest.mark.skipif( not pytest.config.option.vassal, reason="--vassal not specified" ) #pylint: disable=no-member
@pytest.mark.skipif( pytest.config.option.short_tests, reason="--short-tests specified" ) #pylint: disable=no-member
def test_legacy_labels( webapp, webdriver, monkeypatch ):
def test_legacy_labels( webapp, webdriver ):
"""Test detection and updating of legacy labels."""
# initialize
monkeypatch.setitem( webapp.config, "DATA_DIR", REAL_DATA_DIR )
init_webapp( webapp, webdriver, vsav_persistence=1, scenario_persistence=1 )
# NOTE: We disable this for speed, since we don't care about label positioning.
monkeypatch.setitem( webapp.config, "DISABLE_UPDATE_VSAV_SCREENSHOTS", True )
control_tests = init_webapp( webapp, webdriver, vsav_persistence=1, scenario_persistence=1,
reset = lambda ct: ct.set_data_dir( ddtype="real" )
)
def do_test(): #pylint: disable=missing-docstring
@ -361,22 +351,20 @@ def test_legacy_labels( webapp, webdriver, monkeypatch ):
} )
# run the test
_run_tests( webapp, monkeypatch, do_test, False )
_run_tests( control_tests, do_test, False )
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@pytest.mark.skipif( not pytest.config.option.vasl_mods, reason="--vasl-mods not specified" ) #pylint: disable=no-member
@pytest.mark.skipif( not pytest.config.option.vassal, reason="--vassal not specified" ) #pylint: disable=no-member
@pytest.mark.skipif( pytest.config.option.short_tests, reason="--short-tests specified" ) #pylint: disable=no-member
def test_legacy_latw_labels( webapp, webdriver, monkeypatch ):
def test_legacy_latw_labels( webapp, webdriver ):
"""Test detection and updating of legacy LATW labels."""
# initialize
monkeypatch.setitem( webapp.config, "DATA_DIR", REAL_DATA_DIR )
init_webapp( webapp, webdriver, vsav_persistence=1, scenario_persistence=1 )
# NOTE: We disable this for speed, since we don't care about label positioning.
monkeypatch.setitem( webapp.config, "DISABLE_UPDATE_VSAV_SCREENSHOTS", True )
control_tests = init_webapp( webapp, webdriver, vsav_persistence=1, scenario_persistence=1,
reset = lambda ct: ct.set_data_dir( ddtype="real" )
)
def do_test(): #pylint: disable=missing-docstring
@ -441,29 +429,20 @@ def test_legacy_latw_labels( webapp, webdriver, monkeypatch ):
assert len( [ lbl for lbl in labels if "vasl-templates:id" not in lbl ] ) == 6
# run the test
_run_tests( webapp, monkeypatch, do_test, False )
_run_tests( control_tests, do_test, False )
# ---------------------------------------------------------------------
def _run_tests( webapp, monkeypatch, func, test_all ):
def _run_tests( control_tests, func, test_all ):
"""Run the test function for each combination of VASSAL + VASL.
This is, of course, going to be insanely slow, since we need to spin up a JVM
and initialize VASSAL/VASL each time :-/
"""
# locate all VASL modules
vasl_mods_dir = pytest.config.option.vasl_mods #pylint: disable=no-member
fspec = os.path.join( vasl_mods_dir, "*.vmod" )
vasl_mods = glob.glob( fspec )
# locate all VASSAL engines
vassal_engines = []
vassal_dir = pytest.config.option.vassal #pylint: disable=no-member
for root,_,fnames in os.walk( vassal_dir ):
for fname in fnames:
if fname == "Vengine.jar":
vassal_engines.append( root )
# locate all VASL modules and VASSAL engines
vasl_mods = control_tests.get_vasl_mods()
vassal_engines = control_tests.get_vassal_engines()
# check if we want to test all VASSAL+VASL combinations (nb: if not, we test against only one combination,
# and since they all should give the same results, it doesn't matter which one.
@ -473,9 +452,9 @@ def _run_tests( webapp, monkeypatch, func, test_all ):
# run the test for each VASSAL+VASL
for vassal_engine in vassal_engines:
monkeypatch.setitem( webapp.config, "VASSAL_DIR", vassal_engine )
control_tests.set_vassal_engine( vengine=vassal_engine )
for vasl_mod in vasl_mods:
monkeypatch.setitem( webapp.config, "VASL_MOD", vasl_mod )
control_tests.set_vasl_mod( vmod=vasl_mod )
func()
# ---------------------------------------------------------------------

@ -12,10 +12,10 @@ from selenium.common.exceptions import WebDriverException
from vasl_templates.webapp.tests.test_scenario_persistence import load_scenario, save_scenario
from vasl_templates.webapp.tests.utils import \
init_webapp, load_vasl_mod, get_nationalities, select_tab, set_template_params, find_child, find_children, \
init_webapp, get_nationalities, select_tab, set_template_params, find_child, find_children, \
wait_for_clipboard, click_dialog_button, select_menu_option, select_droplist_val, \
set_stored_msg_marker, get_stored_msg, get_sortable_vo_names
from vasl_templates.webapp.config.constants import DATA_DIR as REAL_DATA_DIR
from vasl_templates.webapp.config.constants import DATA_DIR
# ---------------------------------------------------------------------
@ -229,13 +229,15 @@ def test_variable_capabilities( webapp, webdriver ):
not pytest.config.option.vasl_mods, #pylint: disable=no-member
reason = "--vasl-mods not specified"
)
def test_html_names( webapp, webdriver, monkeypatch ):
def test_html_names( webapp, webdriver ):
"""Test handling of vehicles/ordnance that have HTML in their name."""
# initialize
monkeypatch.setitem( webapp.config, "DATA_DIR", REAL_DATA_DIR )
load_vasl_mod( REAL_DATA_DIR, monkeypatch )
init_webapp( webapp, webdriver )
init_webapp( webapp, webdriver,
reset = lambda ct:
ct.set_data_dir( ddtype="real" ) \
.set_vasl_mod( vmod="random" )
)
def get_available_ivfs():
"""Get the PzKw IVF's available for selection."""
@ -289,12 +291,13 @@ def test_html_names( webapp, webdriver, monkeypatch ):
pytest.config.option.short_tests, #pylint: disable=no-member
reason = "--short-tests specified"
) #pylint: disable=too-many-locals,too-many-branches
def test_common_vo( webapp, webdriver, monkeypatch ):
def test_common_vo( webapp, webdriver ):
"""Test loading of common vehicles/ordnance and landing craft."""
# initialize
monkeypatch.setitem( webapp.config, "DATA_DIR", REAL_DATA_DIR )
init_webapp( webapp, webdriver )
init_webapp( webapp, webdriver,
reset = lambda ct: ct.set_data_dir( ddtype="real" )
)
# initialize
ALLIED_MINOR = [ "belgian", "danish", "dutch", "greek", "polish", "yugoslavian" ]
@ -303,7 +306,7 @@ def test_common_vo( webapp, webdriver, monkeypatch ):
# get the common vehicles/ordnance
def get_common_vo( fname ):
"""Get the vehicle/ordnance information from the specified file."""
fname = os.path.join( REAL_DATA_DIR, fname )
fname = os.path.join( DATA_DIR, fname )
data = json.load( open( fname, "r" ) )
def get_gpid( val ): #pylint: disable=missing-docstring
if isinstance( val, list ):
@ -412,13 +415,15 @@ def test_common_vo( webapp, webdriver, monkeypatch ):
not pytest.config.option.vasl_mods, #pylint: disable=no-member
reason = "--vasl-mods not specified"
) #pylint: disable=too-many-statements
def test_vo_images( webapp, webdriver, monkeypatch ): #pylint: disable=too-many-statements
def test_vo_images( webapp, webdriver ): #pylint: disable=too-many-statements
"""Test handling of vehicles/ordnance that have multiple images."""
# initialize
monkeypatch.setitem( webapp.config, "DATA_DIR", REAL_DATA_DIR )
load_vasl_mod( REAL_DATA_DIR, monkeypatch )
init_webapp( webapp, webdriver, scenario_persistence=1 )
init_webapp( webapp, webdriver, scenario_persistence=1,
reset = lambda ct:
ct.set_data_dir( ddtype="real" ) \
.set_vasl_mod( vmod="random" )
)
def check_sortable2_entries( player_no, expected ):
"""Check the settings on the player's vehicles."""
@ -587,13 +592,15 @@ def test_vo_images( webapp, webdriver, monkeypatch ): #pylint: disable=too-many-
not pytest.config.option.vasl_mods, #pylint: disable=no-member
reason = "--vasl-mods not specified"
) #pylint: disable=too-many-statements
def test_change_vo_image( webapp, webdriver, monkeypatch ):
def test_change_vo_image( webapp, webdriver ):
"""Test changing a V/O image."""
# initialize
monkeypatch.setitem( webapp.config, "DATA_DIR", REAL_DATA_DIR )
load_vasl_mod( REAL_DATA_DIR, monkeypatch )
init_webapp( webapp, webdriver, scenario_persistence=1 )
init_webapp( webapp, webdriver, scenario_persistence=1,
reset = lambda ct:
ct.set_data_dir( ddtype="real" ) \
.set_vasl_mod( vmod="random" )
)
# add an ISU-152
add_vo( webdriver, "vehicles", 2, "ISU-152 (AG)" )
@ -659,13 +666,15 @@ def test_change_vo_image( webapp, webdriver, monkeypatch ):
not pytest.config.option.vasl_mods, #pylint: disable=no-member
reason = "--vasl-mods not specified"
)
def test_change_vo_image2( webapp, webdriver, monkeypatch ):
def test_change_vo_image2( webapp, webdriver ):
"""Test changing the image for a V/O that has no alternative images."""
# initialize
monkeypatch.setitem( webapp.config, "DATA_DIR", REAL_DATA_DIR )
load_vasl_mod( REAL_DATA_DIR, monkeypatch )
init_webapp( webapp, webdriver, scenario_persistence=1 )
init_webapp( webapp, webdriver, scenario_persistence=1,
reset = lambda ct:
ct.set_data_dir( ddtype="real" ) \
.set_vasl_mod( vmod="random" )
)
# add an 107mm GVPM
add_vo( webdriver, "ordnance", 2, "107mm GVPM obr. 38 (MTR)" )

@ -6,8 +6,6 @@ import json
import time
import re
import uuid
import glob
import random
import pytest
from PyQt5.QtWidgets import QApplication
@ -16,8 +14,7 @@ from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
from selenium.common.exceptions import NoSuchElementException, StaleElementReferenceException
from vasl_templates.webapp.file_server.vasl_mod import VaslMod
from vasl_templates.webapp import files as webapp_files
from vasl_templates.webapp.tests.remote import ControlTests
# standard templates
_STD_TEMPLATES = {
@ -44,29 +41,23 @@ def init_webapp( webapp, webdriver, **options ):
global _webapp, _webdriver
_webapp = webapp
_webdriver = webdriver
# reset the server
# NOTE: We have to do this manually, since we can't use pytest's monkeypatch'ing,
# since we could be talking to a remote server (see ControlTests for more details).
control_tests = ControlTests( webapp )
control_tests \
.set_data_dir( ddtype="test" ) \
.set_default_scenario( fname=None ) \
.set_default_template_pack( dname=None ) \
.set_vasl_mod( vmod=None ) \
.set_vassal_engine( vengine=None )
if "reset" in options:
options.pop( "reset" )( control_tests )
webdriver.get( webapp.url_for( "main", **options ) )
wait_for( 5, lambda: find_child("#_page-loaded_") is not None )
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
def load_vasl_mod( data_dir, monkeypatch, fname=None ):
"""Load a VASL module."""
if data_dir:
vasl_mods_dir = pytest.config.option.vasl_mods #pylint: disable=no-member
if fname:
fname = os.path.join( vasl_mods_dir, fname )
else:
# NOTE: Some tests require a VASL module to be loaded, and since they should all
# should behave in the same way, it doesn't matter which one we load.
fspec = os.path.join( vasl_mods_dir, "*.vmod" )
fname = random.choice( glob.glob( fspec ) )
vasl_mod = VaslMod( fname, data_dir )
else:
vasl_mod = None
monkeypatch.setattr( webapp_files, "vasl_mod", vasl_mod )
return vasl_mod
return control_tests
# ---------------------------------------------------------------------

@ -216,7 +216,7 @@ def _parse_label_report( fname ):
class VassalShim:
"""Provide access to VASSAL via the Java shim."""
def __init__( self ):
def __init__( self ): #pylint: disable=too-many-branches
# locate the VASSAL engine
vassal_dir = app.config.get( "VASSAL_DIR" )

Loading…
Cancel
Save