Determine the necessary changes to use db with test code,

I made necessary edits

.travis.yml
  necessary to depend on wx mod indirectly when running test code

eos\config.py
  copy from development branch, This change was necessary when using data base in test code.

service\settings.py
  copy from development branch.
  and modified SettingsProvider.getSettings and Settings.save.
  After that, we made the same as master branch except for necessary code.
  This change was necessary when using data base in test code.

and other improvement.
This commit is contained in:
jeffy-g
2017-04-10 14:15:24 +09:00
parent fc7ca56f8b
commit c07bcf6a29
9 changed files with 134 additions and 486 deletions

View File

@@ -1,4 +1,5 @@
language: python
cache: pip
python:
- '2.7'
env:
@@ -6,20 +7,33 @@ env:
addons:
apt:
packages:
# for wxPython:
- python-wxgtk2.8
- python-wxtools
- wx2.8-doc
- wx2.8-examples
- wx2.8-headers
- wx2.8-i18n
before_install:
- pip install -U tox
- sudo apt-get update && sudo apt-get --reinstall install -qq language-pack-en language-pack-ru language-pack-he language-pack-zh-hans
- pip install tox
# We're not actually installing Tox, but have to run it before we install wxPython via Conda. This is fugly but vOv
- tox
# get Conda
- if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then
wget https://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh;
else
wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh;
fi
- bash miniconda.sh -b -p $HOME/miniconda
- export PATH="$HOME/miniconda/bin:$PATH"
- hash -r
- conda config --set always_yes yes --set changeps1 no
- conda update -q conda
# Useful for debugging any issues with conda
- conda info -a
install:
# install wxPython 3.0.0.0
- conda install -c https://conda.anaconda.org/travis wxpython
before_script:
- pip install -r requirements.txt
- pip install -r requirements_test.txt
script:
- tox
- py.test --cov=./
after_success:
- bash <(curl -s https://codecov.io/bash)
before_deploy:
- pip install -r requirements_build_linux.txt

View File

@@ -1,143 +0,0 @@
# noinspection PyPackageRequirements
import pytest
import os
import sys
import threading
from sqlalchemy import MetaData, create_engine
from sqlalchemy.orm import sessionmaker
script_dir = os.path.dirname(os.path.abspath(__file__))
# Add root folder to python paths
sys.path.append(os.path.realpath(os.path.join(script_dir, '..', '..')))
sys._called_from_test = True
# noinspection PyUnresolvedReferences,PyUnusedLocal
@pytest.fixture
def DBInMemory_test():
def rollback():
with sd_lock:
saveddata_session.rollback()
print("Creating database in memory")
from os.path import realpath, join, dirname, abspath
debug = False
gamedataCache = True
saveddataCache = True
gamedata_version = ""
gamedata_connectionstring = 'sqlite:///' + realpath(join(dirname(abspath(unicode(__file__))), "..", "eve.db"))
saveddata_connectionstring = 'sqlite:///:memory:'
class ReadOnlyException(Exception):
pass
if callable(gamedata_connectionstring):
gamedata_engine = create_engine("sqlite://", creator=gamedata_connectionstring, echo=debug)
else:
gamedata_engine = create_engine(gamedata_connectionstring, echo=debug)
gamedata_meta = MetaData()
gamedata_meta.bind = gamedata_engine
gamedata_session = sessionmaker(bind=gamedata_engine, autoflush=False, expire_on_commit=False)()
# This should be moved elsewhere, maybe as an actual query. Current, without try-except, it breaks when making a new
# game db because we haven't reached gamedata_meta.create_all()
try:
gamedata_version = gamedata_session.execute(
"SELECT `field_value` FROM `metadata` WHERE `field_name` LIKE 'client_build'"
).fetchone()[0]
except Exception as e:
print("Missing gamedata version.")
gamedata_version = None
if saveddata_connectionstring is not None:
if callable(saveddata_connectionstring):
saveddata_engine = create_engine(creator=saveddata_connectionstring, echo=debug)
else:
saveddata_engine = create_engine(saveddata_connectionstring, echo=debug)
saveddata_meta = MetaData()
saveddata_meta.bind = saveddata_engine
saveddata_session = sessionmaker(bind=saveddata_engine, autoflush=False, expire_on_commit=False)()
else:
saveddata_meta = None
# Lock controlling any changes introduced to session
sd_lock = threading.Lock()
# Import all the definitions for all our database stuff
# noinspection PyPep8
#from eos.db.gamedata import alphaClones, attribute, category, effect, group, icon, item, marketGroup, metaData, metaGroup, queries, traits, unit
# noinspection PyPep8
#from eos.db.saveddata import booster, cargo, character, crest, damagePattern, databaseRepair, drone, fighter, fit, implant, implantSet, loadDefaultDatabaseValues, miscData, module, override, price, queries, skill, targetResists, user
# If using in memory saveddata, you'll want to reflect it so the data structure is good.
if saveddata_connectionstring == "sqlite:///:memory:":
saveddata_meta.create_all()
# Output debug info to help us troubleshoot Travis
print(saveddata_engine)
print(gamedata_engine)
helper = {
#'config': eos.config,
'gamedata_session' : gamedata_session,
'saveddata_session' : saveddata_session,
}
return helper
# noinspection PyUnresolvedReferences,PyUnusedLocal
@pytest.fixture
def DBInMemory():
print("Creating database in memory")
import eos.config
import eos
import eos.db
# Output debug info to help us troubleshoot Travis
print(eos.db.saveddata_engine)
print(eos.db.gamedata_engine)
helper = {
'config': eos.config,
'db' : eos.db,
'gamedata_session' : eos.db.gamedata_session,
'saveddata_session' : eos.db.saveddata_session,
}
return helper
@pytest.fixture
def Gamedata():
print("Building Gamedata")
from eos.gamedata import Item
helper = {
'Item': Item,
}
return helper
@pytest.fixture
def Saveddata():
print("Building Saveddata")
from eos.saveddata.ship import Ship
from eos.saveddata.fit import Fit
from eos.saveddata.character import Character
from eos.saveddata.module import Module, State
from eos.saveddata.citadel import Citadel
helper = {
'Structure': Citadel,
'Ship' : Ship,
'Fit' : Fit,
'Character': Character,
'Module' : Module,
'State' : State,
}
return helper

View File

@@ -1,66 +0,0 @@
import pytest
# noinspection PyPackageRequirements
from _development.helpers import DBInMemory as DB, Gamedata, Saveddata
# noinspection PyShadowingNames
@pytest.fixture
def RifterFit(DB, Gamedata, Saveddata):
print("Creating Rifter")
item = DB['gamedata_session'].query(Gamedata['Item']).filter(Gamedata['Item'].name == "Rifter").first()
ship = Saveddata['Ship'](item)
# setup fit
fit = Saveddata['Fit'](ship, "My Rifter Fit")
return fit
# noinspection PyShadowingNames
@pytest.fixture
def KeepstarFit(DB, Gamedata, Saveddata):
print("Creating Keepstar")
item = DB['gamedata_session'].query(Gamedata['Item']).filter(Gamedata['Item'].name == "Keepstar").first()
ship = Saveddata['Structure'](item)
# setup fit
fit = Saveddata['Fit'](ship, "Keepstar Fit")
return fit
# noinspection PyShadowingNames
@pytest.fixture
def CurseFit(DB, Gamedata, Saveddata):
print("Creating Curse - With Neuts")
item = DB['gamedata_session'].query(Gamedata['Item']).filter(Gamedata['Item'].name == "Curse").first()
ship = Saveddata['Ship'](item)
# setup fit
fit = Saveddata['Fit'](ship, "Curse - With Neuts")
mod = Saveddata['Module'](DB['db'].getItem("Medium Energy Neutralizer II"))
mod.state = Saveddata['State'].ONLINE
# Add 5 neuts
for _ in xrange(5):
fit.modules.append(mod)
return fit
# noinspection PyShadowingNames
@pytest.fixture
def HeronFit(DB, Gamedata, Saveddata):
print("Creating Heron - RemoteSebo")
item = DB['gamedata_session'].query(Gamedata['Item']).filter(Gamedata['Item'].name == "Heron").first()
ship = Saveddata['Ship'](item)
# setup fit
fit = Saveddata['Fit'](ship, "Heron - RemoteSebo")
mod = Saveddata['Module'](DB['db'].getItem("Remote Sensor Booster II"))
mod.state = Saveddata['State'].ONLINE
# Add 5 neuts
for _ in xrange(4):
fit.modules.append(mod)
return fit

View File

@@ -1,17 +1,29 @@
import sys
from os.path import realpath, join, dirname, abspath
from logbook import Logger
import os
istravis = os.environ.get('TRAVIS') == 'true'
pyfalog = Logger(__name__)
debug = False
gamedataCache = True
saveddataCache = True
gamedata_version = ""
gamedata_connectionstring = 'sqlite:///' + unicode(realpath(join(dirname(abspath(__file__)), "..", "eve.db")),
sys.getfilesystemencoding())
saveddata_connectionstring = 'sqlite:///' + unicode(
realpath(join(dirname(abspath(__file__)), "..", "saveddata", "saveddata.db")), sys.getfilesystemencoding())
gamedata_connectionstring = 'sqlite:///' + unicode(realpath(join(dirname(abspath(__file__)), "..", "eve.db")), sys.getfilesystemencoding())
pyfalog.debug("Gamedata connection string: {0}", gamedata_connectionstring)
if istravis is True or hasattr(sys, '_called_from_test'):
# Running in Travis. Run saveddata database in memory.
saveddata_connectionstring = 'sqlite:///:memory:'
else:
saveddata_connectionstring = 'sqlite:///' + unicode(realpath(join(dirname(abspath(__file__)), "..", "saveddata", "saveddata.db")), sys.getfilesystemencoding())
pyfalog.debug("Saveddata connection string: {0}", saveddata_connectionstring)
settings = {
"setting1": True
"useStaticAdaptiveArmorHardener": False
}
# Autodetect path, only change if the autodetection bugs out.

View File

@@ -199,6 +199,10 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
if self.owner:
return self.owner.modules.index(self)
@property
def isCapitalSize(self):
return self.getModifiedItemAttr("volume", 0) >= 4000
@property
def hpBeforeReload(self):
"""
@@ -418,6 +422,11 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
if isinstance(fit.ship, Citadel) and len(fitsOnGroup) == 0 and len(fitsOnType) == 0:
return False
# EVE doesn't let capital modules be fit onto subcapital hulls. Confirmed by CCP Larrikin that this is dictated
# by the modules volume. See GH issue #1096
if (fit.ship.getModifiedItemAttr("isCapitalSize", 0) != 1 and self.isCapitalSize):
return False
# If the mod is a subsystem, don't let two subs in the same slot fit
if self.slot == Slot.SUBSYSTEM:
subSlot = self.getModifiedItemAttr("subSystemSlot")

View File

@@ -46,36 +46,61 @@ class SettingsProvider(object):
if not os.path.exists(self.BASE_PATH):
os.mkdir(self.BASE_PATH)
# def getSettings(self, area, defaults=None):
# # type: (basestring, dict) -> service.Settings
# # NOTE: needed to change for tests
# settings_obj = self.settings.get(area)
#
# if settings_obj is None and hasattr(self, 'BASE_PATH'):
# canonical_path = os.path.join(self.BASE_PATH, area)
#
# if not os.path.exists(canonical_path):
# info = {}
# if defaults:
# for item in defaults:
# info[item] = defaults[item]
#
# else:
# try:
# f = open(canonical_path, "rb")
# info = cPickle.load(f)
# for item in defaults:
# if item not in info:
# info[item] = defaults[item]
#
# except:
# info = {}
# if defaults:
# for item in defaults:
# info[item] = defaults[item]
#
# self.settings[area] = settings_obj = Settings(canonical_path, info)
#
# return settings_obj
def getSettings(self, area, defaults=None):
s = self.settings.get(area)
if s is None and hasattr(self, 'BASE_PATH'):
p = os.path.join(self.BASE_PATH, area)
if not os.path.exists(p):
# type: (basestring, dict) -> service.Settings
# NOTE: needed to change for tests
# TODO: Write to memory with mmap -> https://docs.python.org/2/library/mmap.html
settings_obj = self.settings.get(area)
if settings_obj is None: # and hasattr(self, 'BASE_PATH'):
canonical_path = os.path.join(self.BASE_PATH, area) if hasattr(self, 'BASE_PATH') else ""
if not os.path.exists(canonical_path): # path string or empty string.
info = {}
if defaults:
for item in defaults:
info[item] = defaults[item]
info.update(defaults)
else:
try:
f = open(p, "rb")
info = cPickle.load(f)
with open(canonical_path, "rb") as f:
info = cPickle.load(f)
for item in defaults:
if item not in info:
info[item] = defaults[item]
except:
info = {}
if defaults:
for item in defaults:
info[item] = defaults[item]
info.update(defaults)
self.settings[area] = s = Settings(p, info)
return s
self.settings[area] = settings_obj = Settings(canonical_path, info)
return settings_obj
def saveAll(self):
for settings in self.settings.itervalues():
@@ -84,12 +109,22 @@ class SettingsProvider(object):
class Settings(object):
def __init__(self, location, info):
# type: (basestring, dict) -> None
# path string or empty string.
self.location = location
self.info = info
# def save(self):
# f = open(self.location, "wb")
# cPickle.dump(self.info, f, cPickle.HIGHEST_PROTOCOL)
def save(self):
f = open(self.location, "wb")
cPickle.dump(self.info, f, cPickle.HIGHEST_PROTOCOL)
# NOTE: needed to change for tests
if self.location is None or not self.location:
return
# NOTE: with + open -> file handle auto close
with open(self.location, "wb") as f:
cPickle.dump(self.info, f, cPickle.HIGHEST_PROTOCOL)
def __getitem__(self, k):
try:

View File

@@ -1,232 +0,0 @@
# Add root folder to python paths
# This must be done on every test in order to pass in Travis
import os
import sys
from time import time
script_dir = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.realpath(os.path.join(script_dir, '..')))
#
# noinspection PyPackageRequirements
from _development.helpers import DBInMemory as DB, Gamedata, Saveddata
# noinspection PyPackageRequirements
from _development.helpers_fits import RifterFit, KeepstarFit, HeronFit, CurseFit
from service.fit import Fit
#
# # Fake import wx
# # todo: fix this
# # from types import ModuleType
# # wx = ModuleType("fake_module")
# # sys.modules[wx.__name__] = wx
#
# def test_getAllFits(DB, RifterFit, KeepstarFit):
# assert len(Fit.getAllFits()) == 0
# DB['db'].save(RifterFit)
# assert len(Fit.getAllFits()) == 1
# DB['db'].save(KeepstarFit)
# assert len(Fit.getAllFits()) == 2
#
# # Cleanup after ourselves
# DB['db'].remove(RifterFit)
# DB['db'].remove(KeepstarFit)
#
#
# def test_getFitsWithShip_RifterFit(DB, RifterFit):
# DB['db'].save(RifterFit)
#
# assert Fit.getFitsWithShip(587)[0][1] == 'My Rifter Fit'
#
# DB['db'].remove(RifterFit)
def test_RifterSingleNew(DB, RifterFit, KeepstarFit, HeronFit, CurseFit):
DB['db'].save(RifterFit)
DB['db'].save(KeepstarFit)
DB['db'].save(HeronFit)
DB['db'].save(CurseFit)
sFit = Fit.getInstance()
sFit.serviceFittingOptions = {
"useGlobalCharacter" : False,
"useGlobalDamagePattern": False,
"useGlobalForceReload" : False,
"colorFitBySlot" : False,
"rackSlots" : True,
"rackLabels" : True,
"compactSkills" : True,
"showTooltip" : True,
"showMarketShortcuts" : False,
"enableGaugeAnimation" : True,
"exportCharges" : True,
"openFitInNew" : False,
"priceSystem" : "Jita",
"showShipBrowserTooltip": True,
}
cached_fits = []
fit = DB["db"].getFit(1)
cached_fits.append(fit)
fit = None
time_start = time()
for _ in xrange(1000000):
fit = next((x for x in cached_fits if x.ID == 1), None)
fit = None
print("1000000 of the Rifter fit (new): " + str(time()-time_start))
# fit = DB["db"].getFit(1)
# Cleanup after ourselves
DB['db'].remove(RifterFit)
DB['db'].remove(KeepstarFit)
DB['db'].remove(HeronFit)
DB['db'].remove(CurseFit)
def test_RifterSingleOld(DB, RifterFit, KeepstarFit, HeronFit, CurseFit):
DB['db'].save(RifterFit)
DB['db'].save(KeepstarFit)
DB['db'].save(HeronFit)
DB['db'].save(CurseFit)
sFit = Fit.getInstance()
sFit.serviceFittingOptions = {
"useGlobalCharacter" : False,
"useGlobalDamagePattern": False,
"useGlobalForceReload" : False,
"colorFitBySlot" : False,
"rackSlots" : True,
"rackLabels" : True,
"compactSkills" : True,
"showTooltip" : True,
"showMarketShortcuts" : False,
"enableGaugeAnimation" : True,
"exportCharges" : True,
"openFitInNew" : False,
"priceSystem" : "Jita",
"showShipBrowserTooltip": True,
}
cached_fits = []
fit = DB["db"].getFit(1)
cached_fits.append(fit)
fit = None
time_start = time()
for _ in xrange(1000000):
fit = DB["db"].getFit(1)
fit = None
print("1000000 of the Rifter fit (old): " + str(time()-time_start))
# Cleanup after ourselves
DB['db'].remove(RifterFit)
DB['db'].remove(KeepstarFit)
DB['db'].remove(HeronFit)
DB['db'].remove(CurseFit)
def test_FourNew(DB, RifterFit, KeepstarFit, HeronFit, CurseFit):
DB['db'].save(RifterFit)
DB['db'].save(KeepstarFit)
DB['db'].save(HeronFit)
DB['db'].save(CurseFit)
sFit = Fit.getInstance()
sFit.serviceFittingOptions = {
"useGlobalCharacter" : False,
"useGlobalDamagePattern": False,
"useGlobalForceReload" : False,
"colorFitBySlot" : False,
"rackSlots" : True,
"rackLabels" : True,
"compactSkills" : True,
"showTooltip" : True,
"showMarketShortcuts" : False,
"enableGaugeAnimation" : True,
"exportCharges" : True,
"openFitInNew" : False,
"priceSystem" : "Jita",
"showShipBrowserTooltip": True,
}
cached_fits = []
fit = DB["db"].getFit(1)
cached_fits.append(fit)
fit = None
time_start = time()
for _ in xrange(250000):
fit = next((x for x in cached_fits if x.ID == 1), None)
fit = None
fit = next((x for x in cached_fits if x.ID == 2), None)
fit = None
fit = next((x for x in cached_fits if x.ID == 3), None)
fit = None
fit = next((x for x in cached_fits if x.ID == 4), None)
fit = None
print("1000000 of the four fits (new): " + str(time()-time_start))
# fit = DB["db"].getFit(1)
# Cleanup after ourselves
DB['db'].remove(RifterFit)
DB['db'].remove(KeepstarFit)
DB['db'].remove(HeronFit)
DB['db'].remove(CurseFit)
def test_FourOld(DB, RifterFit, KeepstarFit, HeronFit, CurseFit):
DB['db'].save(RifterFit)
DB['db'].save(KeepstarFit)
DB['db'].save(HeronFit)
DB['db'].save(CurseFit)
sFit = Fit.getInstance()
sFit.serviceFittingOptions = {
"useGlobalCharacter" : False,
"useGlobalDamagePattern": False,
"useGlobalForceReload" : False,
"colorFitBySlot" : False,
"rackSlots" : True,
"rackLabels" : True,
"compactSkills" : True,
"showTooltip" : True,
"showMarketShortcuts" : False,
"enableGaugeAnimation" : True,
"exportCharges" : True,
"openFitInNew" : False,
"priceSystem" : "Jita",
"showShipBrowserTooltip": True,
}
cached_fits = []
fit = DB["db"].getFit(1)
cached_fits.append(fit)
fit = None
time_start = time()
for _ in xrange(250000):
fit = DB["db"].getFit(1)
fit = None
fit = DB["db"].getFit(2)
fit = None
fit = DB["db"].getFit(3)
fit = None
fit = DB["db"].getFit(4)
fit = None
print("1000000 of the four fits (old): " + str(time()-time_start))
# Cleanup after ourselves
DB['db'].remove(RifterFit)
DB['db'].remove(KeepstarFit)
DB['db'].remove(HeronFit)
DB['db'].remove(CurseFit)

View File

@@ -1,23 +1,26 @@
"""
2017/04/05: unread description tests module.
"""
# noinspection PyPackageRequirements
import pytest
# Add root folder to python paths
# This must be done on every test in order to pass in Travis
import os
import sys
script_dir = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.realpath(os.path.join(script_dir, '..')))
# nopep8
import re
#
# noinspection PyPackageRequirements
from _development.helpers import DBInMemory as DB, Gamedata, Saveddata
# noinspection PyPep8
from service.port import Port, IPortUser
# from utils.strfunctions import sequential_rep, replace_ltgt
from utils.stopwatch import Stopwatch
script_dir = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.realpath(os.path.join(script_dir, '..')))
sys._called_from_test = True # need db open for tests. (see eos/config.py#17
# noinspection PyPep8
from service.port import Port, IPortUser
#
# noinspection PyPackageRequirements
# from _development.helpers import DBInMemory as DB
"""
NOTE:
description character length is restricted 4hundred by EVE client.
@@ -41,6 +44,9 @@ NOTE of @decorator:
o Function to receive arguments of function to be decorated
o A function that accepts the decorate target function itself as an argument
o A function that accepts arguments of the decorator itself
for local coverage:
py.test --cov=./ --cov-report=html
"""
class PortUser(IPortUser):
@@ -52,11 +58,24 @@ class PortUser(IPortUser):
stpw = Stopwatch('test measurementer')
def test_import_xml():
@pytest.fixture()
def print_db_info():
# Output debug info
import eos
print
print "------------ data base connection info ------------"
print(eos.db.saveddata_engine)
print(eos.db.gamedata_engine)
print
# noinspection PyUnusedLocal
def test_import_xml(print_db_info):
usr = PortUser()
# for path in XML_FILES:
xml_file = "jeffy_ja-en[99].xml"
fit_count = int(re.search(r"\[(\d+)\]", xml_file).group(1))
fits = None
with open(os.path.join(script_dir, xml_file), "r") as file_:
srcString = file_.read()
srcString = unicode(srcString, "utf-8")