40 Commits

Author SHA1 Message Date
49e55b22f4 Remove U-H command 2016-03-21 18:01:07 +00:00
9da66831fa Updated types from YC118-3 2016-03-21 17:52:58 +00:00
19c2ccdfde Remove custom deploy, revert back to basic Heroku 2015-10-21 19:31:10 +01:00
Rob Haswell
b4495d346a Merge pull request #26 from nikdoof/vanguard-update
Vanguard update
2015-10-20 17:35:04 +01:00
Rob Haswell
4d16f31209 New Vanguard items. 2015-10-20 17:00:08 +01:00
Rob Haswell
84794533d8 Executable. 2015-10-20 16:59:59 +01:00
Rob Haswell
cdfefdcffd Updates to the .gitignore file. 2015-10-20 16:59:30 +01:00
Rob Haswell
c3ffc2af0a This isn't necessary, and causes spuriour errors. Unexpected new files should be staged manually by the developer. 2015-10-20 16:56:58 +01:00
Rob Haswell
f65ff4c6aa Force-overwrite the sde. 2015-10-20 16:56:17 +01:00
7b88760d0a Quote commands to run on the remote system. 2015-08-22 19:25:17 +01:00
56f2e40d4d Fix requirements.txt reference. 2015-08-22 19:23:48 +01:00
8e3996054d Fix target user for virtualenv setup. 2015-08-22 19:16:39 +01:00
8b6c3bf1eb Fix validation for Wercker YML 2015-08-22 19:09:17 +01:00
f2685a05d2 Fix YML indentation 2015-08-22 19:04:11 +01:00
6545a8fad3 Update wrecker config for SSH deployments 2015-08-22 19:03:03 +01:00
5d296b1aab SDE update script
A script to assist with SDE updates, resolves #20
2015-08-13 10:25:36 +01:00
971abfa714 Add test for "Hek" command 2015-08-13 09:59:23 +01:00
63e42d6df5 Merge pull request #25 from Cubox-/patch-1
Add Hek as a default trade hub.
2015-08-11 21:51:36 +01:00
Andy Pilate
b026a6e37c Added Hek as a default trading hub 2015-08-11 15:08:39 +02:00
Rob Haswell
af8c1b474d Merge pull request #21 from nikdoof/fozziesov-update
Fozziesov update
2015-07-28 17:42:52 +01:00
Rob
a3c90d2487 Streamline the update instructions. 2015-07-28 17:41:14 +01:00
Rob
90a04ee857 Aegis update. 2015-07-28 17:40:24 +01:00
Rob Haswell
bf9f879b32 Merge pull request #19 from nikdoof/carnyx-item-test
Carnyx item test
2015-06-04 13:50:24 +01:00
Rob
39eb3b9b0e Probably don' want to include pdb in the live code huh. 2015-06-04 10:46:04 +01:00
Rob
034fb3a2dd Fix up looking for plex. 2015-06-04 10:45:12 +01:00
Rob
35da7264c7 Add a test to look for Carnyx items. 2015-06-04 10:26:48 +01:00
Rob Haswell
0d563c479b Merge pull request #17 from nikdoof/carnyx
Carnyx
2015-06-03 17:49:05 +01:00
Rob
c7a5377740 Five new wormhole systems were added. 2015-06-03 17:46:54 +01:00
Rob
3d18e3d127 Carnyx data, and some minor hints in the README. 2015-06-03 17:40:20 +01:00
Rob
4b24b95904 Use CCP's name for the SQLite db. 2015-06-03 11:56:16 +01:00
Rob
5c6030cd74 Add the copy step to the SDE update instructions. 2015-06-03 11:55:26 +01:00
fd5b08227f Add basic jump fatigue calculator into the map class. 2015-04-02 12:07:10 +01:00
feb70dccf2 Pass a workable message (not a mock). Add mute tests. 2015-04-02 12:06:57 +01:00
7d3d933189 Add decimal minutes to hms conversion function and tests. 2015-04-02 12:06:41 +01:00
de32857247 Test the bot commands. 2015-04-02 12:06:11 +01:00
8b642165c5 PEP8 tidy-up. 2015-03-29 23:55:11 +01:00
ab8857aea6 Stop using reserved names in the A* implementation. 2015-03-29 23:46:26 +01:00
58cdc22acb Remove debugging print statement. 2015-03-29 23:44:59 +01:00
5fd225aa55 More tests for calculating jump ranges. 2015-03-29 23:43:53 +01:00
41f71e2086 Switch Market Systems to a config item. 2015-03-29 23:16:17 +01:00
13 changed files with 470 additions and 52 deletions

7
.gitignore vendored
View File

@@ -13,6 +13,7 @@ env/
build/
develop-eggs/
dist/
.eggs/
eggs/
lib/
lib64/
@@ -40,6 +41,7 @@ htmlcov/
.cache
nosetests.xml
coverage.xml
_trial_temp/
# Translations
*.mo
@@ -62,3 +64,8 @@ eve.db
# Vagrant
.vagrant/
# Cruft
*.json
sde.sqlite
sde.sqlite.bz2

View File

@@ -39,6 +39,7 @@ The configuration is passed by using environment variables.
* ```DROPBOT_REDIS_URL``` - 12 factor style URL of the Redis server to use (defaults to redis://localhost:6379/0)
* ```DROPBOT_CMD_PREFIX``` - Prefix of MUC channel commands (defaults to !)
* ```DROPBOT_KOS_URL``` - URL of the CVA KOS API service (defaults to http://kos.cva-eve.org/api/)
* ```DROPBOT_MARKET_SYSTEMS``` - A comma seperated list of systems to be used for the best price checker (defaults to Jita, Amarr, Rens, Dodixie, Hek)
* ```DROPBOT_KILL_CORPS``` - List of Corp IDs to track for kills
* ```DROPBOT_KILLS_DISABLED``` - Disables the streaming of zKillboard kills to the channels (default to 0)
* ```DROPBOT_OFFICE_API_KEYID``` - API KeyID to use for the nearest office finder.
@@ -49,12 +50,15 @@ Updating the SDE data
To update the SDE data in the bot, use the ```gen_reference_data.py``` with a copy of the Sqlite conversion of the SDE, this will produce three json files that need to be copied to the data directory witthin the ```dropbot``` package.
$ python gen_reference_data.py eve.db
The SDE conversion is usually available here: https://www.fuzzwork.co.uk/dump/
$ wget https://www.fuzzwork.co.uk/dump/sqlite-latest.sqlite.bz2
$ python gen_reference_data.py sqlite-latest.sqlite.bz2
Importing Types...
Importing Stations...
Importing Map...
$ ls -1
$ ls *.json
map.json
stations.json
types.json
$ cp -i map.json stations.json types.json dropbot/data/

View File

@@ -20,14 +20,6 @@ from dropbot.stomp_listener import ZKillboardStompListener
urlparse.uses_netloc.append("redis")
market_systems = [
('Jita', 30000142),
('Amarr', 30002187),
('Rens', 30002510),
('Dodixie', 30002659),
('U-HVIX', 30000575),
]
zkillboard_regex = re.compile(r'http(s|):\/\/(?P<host>.*)\/kill\/(?P<killID>\d+)\/')
@@ -48,7 +40,8 @@ class DropBot(ClientXMPP):
self.kills_muted = False
self.office_api_key_keyid = kwargs.pop('office_api_keyid', None)
self.office_api_key_vcode = kwargs.pop('office_api_vcode', None)
self.market_systems = kwargs.pop('market_systems', ['Jita', 'Amarr', 'Rens', 'Dodixie', 'Hek'])
if 'redis_url' in kwargs:
self.redis_pool = ConnectionPool.from_url(kwargs.pop('redis_url', 'redis://localhost:6379/0'))
self.redis = Redis(connection_pool=self.redis_pool)
@@ -181,7 +174,7 @@ class DropBot(ClientXMPP):
if item.strip() == '':
return 'Usage: !price <item>'
if item.lower() == 'plex':
item = '30 Day'
return (u"29668", u"30 Day Pilot's License Extension (PLEX)")
types = dict([(i, v) for i, v in self.types.iteritems() if item.lower() in v.lower()])
if len(types) == 0:
return "No items named {} found".format(item)
@@ -289,7 +282,6 @@ class DropBot(ClientXMPP):
else:
return 'Unknown command'
def cmd_bestprice(self, args, msg):
"""Returns the best price for an item out of the current known market hub systems"""
item = ' '.join(args)
@@ -303,7 +295,10 @@ class DropBot(ClientXMPP):
sell_sys = None
buy_sys = None
for name, sys_id in market_systems:
for name in self.market_systems:
sys_id = self.map.get_system_id(name)
if not sys_id:
continue
sell, buy = self._get_evecentral_price(type_id, sys_id)
if (sell < min_sell or min_sell == 0) and sell > 0:
min_sell = sell
@@ -350,12 +345,12 @@ class DropBot(ClientXMPP):
return self.cmd_price(['Rens'] + args, msg)
def cmd_dodixie(self, args, msg):
"""Returns the price of a item in Dodixie"""
"""Returns the price of a item in Dodixie"""
return self.cmd_price(['Dodixie'] + args, msg)
def cmd_uh(self, args, msg):
"""Returns the price of a item in U-HVIX"""
return self.cmd_price(['U-HVIX'] + args, msg)
def cmd_hek(self, args, msg):
"""Returns the price of a item in Hek"""
return self.cmd_price(['Hek'] + args, msg)
def cmd_r(self, args, msg):
return self.cmd_redditimg(args, msg)
@@ -702,7 +697,6 @@ class DropBot(ClientXMPP):
self.schedule('unmute', 30 * 60, unmute, [self])
return 'Killmails muted, posting will resume automatically in 30 minutes'
def cmd_nearestoffice(self, args, msg):
if len(args) != 1:
return '!nearestoffice <system>'

View File

@@ -33,7 +33,7 @@ def main():
# Parse the environment for config
config = dict([(k[8:].lower(), v) for k, v in os.environ.items() if 'DROPBOT_' in k])
# Split out array type configs
for key in ['rooms', 'admins', 'kill_corps']:
for key in ['rooms', 'admins', 'kill_corps', 'market_systems']:
if key in config:
config[key] = [x.strip() for x in config[key].split(',')]
elif opts.config.lower().startswith('http'):
@@ -65,4 +65,4 @@ def main():
if __name__ == '__main__':
main()
main()

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -52,21 +52,35 @@ isotope_usage = {
'blackops': 450,
}
fatiuge_bonus = {
'blackops': (.5, .5),
'covertops': (0, .5),
'forcerecon': (0, .5),
'blockaderunner': (.9, .95),
'industrial': (.9, 0),
'freighter': (.9, 0),
'jumpfreighter': (.9, 0),
'deepspacetransport': (.9, 0),
}
EVE_LY = 9460000000000000 # EVE's definition of a ly in KM
JDC_BONUS = 0.20
def calc_distance(sys1, sys2):
"""Calculate the distance in light years between two sets of 3d coordinates"""
return math.sqrt(sum((a - b)**2 for a, b in zip(sys1, sys2))) / EVE_LY
def hull_to_range(hull, jdc_skill):
"""Returns the jump range of a provided ship hull and Jump Drive Calibration skill"""
if hull.lower() not in hull_classes:
raise ValueError('Unknown hull class {}'.format(hull))
return ship_class_to_range(hull_classes[hull.lower()], jdc_skill)
def ship_class_to_range(ship_class, jdc_skill):
"""Returns the jump range of a provided ship class and Jump Drive Calibration skill"""
if ship_class.lower() not in base_range:
@@ -84,9 +98,10 @@ class Map(networkx.Graph):
def from_sde(self, db_conn):
"""Load map data from a EVE SDE Sqlite DB"""
for id, name, region_name, x, y, z, security in db_conn.execute("""
SELECT solarSystemID, solarSystemName, regionName, mapSolarSystems.x, mapSolarSystems.y, mapSolarSystems.z, mapSolarSystems.security
FROM mapSolarSystems
INNER JOIN mapRegions ON mapSolarSystems.regionID = mapRegions.regionID"""):
SELECT solarSystemID, solarSystemName, regionName, mapSolarSystems.x, mapSolarSystems.y, mapSolarSystems.z, mapSolarSystems.security
FROM mapSolarSystems
INNER JOIN mapRegions ON mapSolarSystems.regionID = mapRegions.regionID
"""):
self.add_node(id, system_id=id, name=name, region=region_name, coords=(x, y, z), security=security)
for from_id, to_id in db_conn.execute("SELECT fromSolarSystemID, toSolarSystemID FROM mapSolarSystemJumps"):
self.add_edge(from_id, to_id, weight=1, link_type='gate')
@@ -135,18 +150,15 @@ class Map(networkx.Graph):
def route_gate(self, source, destination, filter=None):
"""Route between two systems using gates (fastest)"""
# TODO: add EVE routing options (highsec/lowsec/fastest)
g = networkx.Graph(data=[(u, v) for u, v, d in self.edges_iter(data=True) if d['link_type'] == 'gate' or d['link_type'] == 'bridge'])
return networkx.astar_path(self, source, destination)
def _route_jump_fast(self, source, destination, range=None, hull=None, ship_class=None, station_only=False, avoid_systems=[]):
"""A fast but error prone route calculation between two systems using jumps"""
print source, destination
route = [source]
current_system = source
while not destination in route:
while destination not in route:
next_distance = None
next_system = None
# Iterate through jump neighbour systems to find the best candidate
@@ -160,7 +172,6 @@ class Map(networkx.Graph):
if system['system_id'] == destination:
route.append(destination)
return route
# Use heuristics to identify the best candidate (one that gets us closest to the target)
distance_to_target = self.system_distance(system['system_id'], destination)
if distance_to_target < next_distance or not next_distance:
@@ -171,14 +182,14 @@ class Map(networkx.Graph):
def route_jump(self, source, destination, range=None, hull=None, ship_class=None, station_only=False, avoid_systems=[]):
"""Calculate a jump route between two systems"""
closed = set()
open = set([source])
closed_set = set()
open_set = set([source])
route = {}
g_score = {source: 0}
f_score = {source: g_score[source] + self.system_distance(source, destination)}
while len(open):
current = min([x for x in f_score.items() if x[0] in open], key=lambda x: x[1])[0]
while len(open_set):
current = min([x for x in f_score.items() if x[0] in open_set], key=lambda x: x[1])[0]
if current == destination:
def build_path(route, current):
@@ -186,26 +197,26 @@ class Map(networkx.Graph):
p = build_path(route, route[current])
p.append(current)
return p
return [current]
return [current]
return build_path(route, destination)
open.remove(current)
closed.add(current)
open_set.remove(current)
closed_set.add(current)
for neighbor, distance in self.neighbors_jump(current, range, hull, ship_class):
neighbor_id = neighbor['system_id']
if neighbor_id in closed or \
if neighbor_id in closed_set or \
neighbor['security'] >= 0.45 or \
(station_only and not neighbor['station']) or \
neighbor_id in avoid_systems:
continue
score = g_score[current] + self.system_distance(current, neighbor_id)
if neighbor_id not in open or score < g_score[neighbor_id]:
if neighbor_id not in open_set or score < g_score[neighbor_id]:
route[neighbor_id] = current
g_score[neighbor_id] = score
f_score[neighbor_id] = score + self.system_distance(neighbor_id, destination)
if neighbor_id not in open:
open.add(neighbor_id)
if neighbor_id not in open_set:
open_set.add(neighbor_id)
def route_jump_distance(self, route):
"""Calculate the total ly distance of a route"""
@@ -230,10 +241,38 @@ class Map(networkx.Graph):
multi = 1 - (.1 * jfc_skill)
if ship_class == 'jumpfreighter':
multi = multi * (1 - (.1 * jf_skill))
base = isotope_usage[ship_class] * multi
ly = self.route_jump_distance(route)
base = isotope_usage[ship_class] * multi
ly = self.route_jump_distance(route)
return round(ly * base, 0)
def jump_fatigue(self, fatigue, source, destination, bonus=0, ship_class=None, jump_type='standard'):
"""Calculate the jump fatigue gained by jumping between two systems"""
if bonus == 0 and ship_class:
standard = covert = 0
if ship_class and ship_class in fatiuge_bonus:
standard, covert = fatiuge_bonus[ship_class]
if jump_type == 'standard':
bonus = standard
else:
bonus = covert
distance = self.system_distance(source, destination)
cooldown = max(fatigue / 10, 1 + (distance * (1-bonus)))
new_fatigue = min(60 * 24 * 30, max(fatigue, 10) * (1 + (distance * (1 - bonus))))
return round(cooldown, 2), round(new_fatigue, 2)
def route_jump_fatigue(self, route, fatigue, bonus=0, ship_class=None, jump_type='standard'):
"""Calculate the jump fatigue for the specified route"""
results = []
source = route.pop(0)
for target in route:
cooldown, new_fatigue = self.jump_fatigue(fatigue, source, target, bonus, ship_class, jump_type)
results.append({
'source': source, 'target': target, 'cooldown': cooldown, 'fatigue': new_fatigue,
})
source = target
fatigue = new_fatigue
return results
def neighbors_gate(self, system_id):
"""List systems that are connected to a system by gates"""
return self.neighbors(system_id)
@@ -260,9 +299,8 @@ class Map(networkx.Graph):
if destination_data['coords'][0] > range_x[0] or destination_data['coords'][0] < range_x[1] or \
destination_data['coords'][1] > range_y[0] or destination_data['coords'][1] < range_y[1] or \
destination_data['coords'][2] > range_z[0] or destination_data['coords'][2] < range_z[1]:
continue
continue
distance = calc_distance(source['coords'], destination_data['coords'])
if distance <= range and destination_id != system_id:
destinations.append((destination_data, distance))
return destinations

View File

@@ -5,6 +5,7 @@ import logging
urlparse.uses_netloc.append('tcp')
class ZKillboardStompListener(stomp.listener.ConnectionListener):
def __init__(self, bot):
@@ -53,4 +54,4 @@ class ZKillboardStompListener(stomp.listener.ConnectionListener):
self.conn.set_listener('', self)
self.conn.start()
self.conn.connect('guest', 'guest')
self.conn.subscribe('/topic/kills', id='dropbot')
self.conn.subscribe('/topic/kills', id='dropbot')

View File

@@ -2,6 +2,36 @@ from hashlib import sha1
import zlib
import redis
import logging
import math
def decimal_minutes_to_hms(minutes):
"""Converts a value of decimal minutes into a hms format"""
if not isinstance(minutes, (int, float, long)):
if isinstance(minutes, basestring):
try:
minutes = float(minutes)
except ValueError:
raise ValueError('minutes is not a valid number')
else:
raise ValueError('minutes is not a valid number')
# If we have a negative number, invert
if minutes < 0:
minutes = -1 * minutes
out_secs = round(60 * (minutes % 1))
out_minutes = math.floor(minutes) % 60
out_hours = math.floor(math.floor(minutes) / 60)
output = ''
if out_hours > 0:
output += '{}h '.format(int(out_hours))
if out_minutes > 0:
output += '{}m '.format(int(out_minutes))
if out_secs > 0:
output += '{}s '.format(int(out_secs))
return output.strip()
class EVEAPIRedisCache(object):

24
sde_update.sh Executable file
View File

@@ -0,0 +1,24 @@
#!/bin/bash
SDE_URL="https://www.fuzzwork.co.uk/dump/sqlite-latest.sqlite.bz2"
echo "Downloading SDE from ${SDE_URL}"
curl -o sde.sqlite.bz2 "${SDE_URL}" && bunzip2 -f sde.sqlite.bz2
if [ -e sde.sqlite ]; then
echo "Generating reference data"
/usr/bin/env python gen_reference_data.py sde.sqlite
cp *.json dropbot/data/
echo "Running unit tests"
/usr/bin/env python setup.py test > /dev/null 2>&1
if [ $? -eq 0 ]; then
git status
echo "SDE data updated successfully"
else
echo "Unit tests failed, please investigate"
fi
else
echo "Error downloading SDE"
exit 1
fi

View File

@@ -1,3 +1,6 @@
import os
import unittest
import mock
from unittest import TestCase
from dropbot.bot import DropBot
@@ -7,6 +10,11 @@ class DropBotTestCase(TestCase):
def setUp(self):
self.bot = DropBot('test@test.com', 'testpassword')
def call_command(self, command, args=[]):
"""Fakes a call to a bot command"""
msg = {'type': 'groupchat'}
return self.bot.call_command(command, args, msg)
def test_simple_bot(self):
self.assertIsNotNone(self.bot)
@@ -18,6 +26,141 @@ class DropBotTestCase(TestCase):
self.assertEqual(self.bot._system_picker('GE-'), 'Did you mean: GE-94X, GE-8JV?')
self.assertEqual(self.bot._system_picker('asdasd'), 'No systems found matching asdasd')
@unittest.skipIf(os.environ.get('NO_NETWORK', '0') == '1', 'No networking, skipping test')
def test_get_evecentral_price(self):
self.assertIs(self.bot._get_evecentral_price(1,1), None)
self.assertIs(type(self.bot._get_evecentral_price(22430, 30000142)), tuple)
self.assertIs(type(self.bot._get_evecentral_price(22430, 30000142)), tuple)
def test_cmd_help(self):
res = self.call_command('help')
self.assertIsInstance(res, tuple)
self.assertIsInstance(res[0], basestring)
@unittest.skipIf(os.environ.get('NO_NETWORK', '0') == '1', 'No networking, skipping test')
def test_cmd_bestprice(self):
res = self.call_command('bestprice', ['rifter'])
self.assertIsInstance(res, tuple)
self.assertIsInstance(res[0], basestring)
@unittest.skipIf(os.environ.get('NO_NETWORK', '0') == '1', 'No networking, skipping test')
def test_cmd_price(self):
res = self.call_command('price', args=['jita', 'rifter'])
self.assertIsInstance(res, tuple)
self.assertIsInstance(res[0], basestring)
@unittest.skipIf(os.environ.get('NO_NETWORK', '0') == '1', 'No networking, skipping test')
def test_cmd_jita(self):
res = self.call_command('jita', ['rifter'])
self.assertIsInstance(res, tuple)
self.assertIsInstance(res[0], basestring)
@unittest.skipIf(os.environ.get('NO_NETWORK', '0') == '1', 'No networking, skipping test')
def test_cmd_amarr(self):
res = self.call_command('amarr', ['rifter'])
self.assertIsInstance(res, tuple)
self.assertIsInstance(res[0], basestring)
@unittest.skipIf(os.environ.get('NO_NETWORK', '0') == '1', 'No networking, skipping test')
def test_cmd_rens(self):
res = self.call_command('rens', ['rifter'])
self.assertIsInstance(res, tuple)
self.assertIsInstance(res[0], basestring)
@unittest.skipIf(os.environ.get('NO_NETWORK', '0') == '1', 'No networking, skipping test')
def test_cmd_dodixie(self):
res = self.call_command('dodixie', ['rifter'])
self.assertIsInstance(res, tuple)
self.assertIsInstance(res[0], basestring)
@unittest.skipIf(os.environ.get('NO_NETWORK', '0') == '1', 'No networking, skipping test')
def test_cmd_uh(self):
res = self.call_command('uh', ['rifter'])
self.assertIsInstance(res, tuple)
self.assertIsInstance(res[0], basestring)
@unittest.skipIf(os.environ.get('NO_NETWORK', '0') == '1', 'No networking, skipping test')
def test_cmd_hek(self):
res = self.call_command('hek', ['rifter'])
self.assertIsInstance(res, tuple)
self.assertIsInstance(res[0], basestring)
def test_cmd_r(self):
pass
def test_cmd_redditimg(self):
pass
@unittest.skipIf(os.environ.get('NO_NETWORK', '0') == '1', 'No networking, skipping test')
def test_cmd_kos(self):
res = self.call_command('kos', ['Palkark'])
self.assertIsInstance(res, tuple)
self.assertIsInstance(res[0], basestring)
def test_cmd_range(self):
res = self.call_command('range', ['U-HVIX'])
self.assertIsInstance(res, tuple)
self.assertIsInstance(res[0], basestring)
def test_cmd_route(self):
res = self.call_command('route', ['Jita', 'Amarr'])
self.assertIsInstance(res, tuple)
self.assertIsInstance(res[0], basestring)
def test_cmd_addjb(self):
res = self.call_command('addjb', ['Jita', 'Amarr'])
self.assertIsInstance(res, tuple)
self.assertIsInstance(res[0], basestring)
self.assertEqual(res[0], 'Done')
def test_cmd_listjbs(self):
res = self.call_command('listjbs')
self.assertIsInstance(res, tuple)
self.assertIsNone(res[0], None)
self.call_command('addjb', ['Jita', 'Amarr'])
res = self.call_command('listjbs')
self.assertIsInstance(res, tuple)
self.assertIsInstance(res[0], basestring)
def test_cmd_mapstats(self):
res = self.call_command('mapstats')
self.assertIsInstance(res, tuple)
self.assertIsInstance(res[0], basestring)
def test_cmd_hit(self):
pass
def test_cmd_jump(self):
pass
@unittest.skipIf(os.environ.get('NO_NETWORK', '0') == '1', 'No networking, skipping test')
def test_cmd_id(self):
pass
@unittest.skipIf(os.environ.get('NO_NETWORK', '0') == '1', 'No networking, skipping test')
def test_cmd_kill(self):
pass
def test_cmd_mute(self):
self.assertEqual(self.bot.kills_muted, False)
res = self.call_command('mute')
self.assertIsInstance(res, tuple)
self.assertIsInstance(res[0], basestring)
self.assertEqual(res[0], 'Killmails muted, posting will resume automatically in 30 minutes')
self.assertEqual(self.bot.kills_muted, True)
@unittest.skipIf(os.environ.get('NO_NETWORK', '0') == '1', 'No networking, skipping test')
def test_cmd_nearestoffice(self):
pass
def test_cmd_rageping(self):
pass
def test_jackdaw(self):
"""
The items in the Carnyx release can be found.
"""
self.assertEqual(self.bot._item_picker("Jackdaw"), (u'34828', u'Jackdaw'))
def test_carnyx_plex(self):
self.assertEqual(self.bot._item_picker("plex"), (u"29668", "30 Day Pilot's License Extension (PLEX)"))

View File

@@ -8,33 +8,39 @@ class MapTestCase(TestCase):
self.map = Map.from_json(pkgutil.get_data('dropbot', 'data/map.json'))
def test_load_from_package_data(self):
"""Check the package data can be correctly loaded into the map"""
m = Map.from_json(pkgutil.get_data('dropbot', 'data/map.json'))
self.assertIsNotNone(m)
def test_get_system_name(self):
"""Test looking up system names from IDs"""
self.assertEquals(self.map.get_system_name(123), None)
self.assertEqual(self.map.get_system_name(30000142), 'Jita')
def test_get_system_id(self):
"""Test looking up system ID by name"""
self.assertEqual(self.map.get_system_id('Llamatron'), None)
self.assertEqual(self.map.get_system_id('Jita'), 30000142)
def test_get_systems(self):
"""Check partial matching of system names works correctly"""
self.assertEquals(len(self.map.get_systems('Jita')), 1)
self.assertEquals(len(self.map.get_systems('Ji')), 7)
self.assertEquals(len(self.map.get_systems('J')), 2760)
self.assertEquals(len(self.map.get_systems('J')), 2765)
self.assertEquals(len(self.map.get_systems('123435345345')), 0)
self.assertEquals(len(self.map.get_systems('jita')), 1)
self.assertEquals(len(self.map.get_systems('JITA')), 1)
self.assertEquals(len(self.map.get_systems('JiTa')), 1)
def test_system_distance(self):
"""Test the distance calculator"""
self.assertEqual(self.map.system_distance(30000142, 30000144), 2.10268108033618)
self.assertEqual(self.map.system_distance(30000142, 30000222), 9.334275248404591)
self.assertEqual(self.map.system_distance(30000142, 30000536), 39.15289747780095)
self.assertRaises(Exception, self.map.system_distance, (1, 2))
def test_route_gate(self):
"""Test the gate routing system"""
r = self.map.route_gate(30001161, 30001198)
self.assertEqual(len(r), 9)
self.assertListEqual(r, [30001161, 30001158, 30001160, 30001154, 30001157, 30001155, 30001156, 30001162, 30001198])
@@ -48,6 +54,63 @@ class MapTestCase(TestCase):
def test_route_jump_isotopes(self):
pass
def test_jump_fatigue_standard(self):
"""Test jump fatigue calculator, 4.119ly jump, no bonus"""
sys1 = self.map.get_system_id('U-HVIX')
sys2 = self.map.get_system_id('V-IUEL')
cooldown, new_fatigue = self.map.jump_fatigue(0, sys1, sys2)
self.assertEqual(cooldown, 5.12)
self.assertEqual(new_fatigue, 51.19)
def test_jump_fatigue_covertops(self):
"""Test jump fatigue calculator, 4.119ly jump, covertops being bridged by titan"""
sys1 = self.map.get_system_id('U-HVIX')
sys2 = self.map.get_system_id('V-IUEL')
cooldown, new_fatigue = self.map.jump_fatigue(0, sys1, sys2, ship_class='covertops')
self.assertEqual(cooldown, 5.12)
self.assertEqual(new_fatigue, 51.19)
def test_jump_fatigue_covertops_covertcyno(self):
"""Test jump fatigue calculator, 4.119ly jump, covertops being bridged by blops"""
sys1 = self.map.get_system_id('U-HVIX')
sys2 = self.map.get_system_id('V-IUEL')
cooldown, new_fatigue = self.map.jump_fatigue(0, sys1, sys2, ship_class='covertops', jump_type='covert')
self.assertEqual(cooldown, 3.06)
self.assertEqual(new_fatigue, 30.59)
def test_route_jump_fatigue_covertops_covertcyno(self):
"""Test jump fatigue calculator, 4.119ly jump, covertops being bridged by blops"""
sys1 = self.map.get_system_id('U-HVIX')
sys2 = self.map.get_system_id('V-IUEL')
res = self.map.route_jump_fatigue([sys1, sys2], 0, ship_class='covertops', jump_type='covert')
self.assertListEqual(res, [
{'source': sys1, 'target': sys2, 'cooldown': 3.06, 'fatigue': 30.59,}
])
def test_route_jump_fatigue_covertops_covertcyno_two_jumps(self):
"""Test route jump fatigue calculator, covertops being bridged by blops for two jumps"""
sys1 = self.map.get_system_id('U-HVIX')
sys2 = self.map.get_system_id('RMOC-W')
sys3 = self.map.get_system_id('Podion')
res = self.map.route_jump_fatigue([sys1, sys2, sys3], 0, ship_class='covertops', jump_type='covert')
self.assertListEqual(res, [
{'source': sys1, 'target': sys2, 'cooldown': 4.77, 'fatigue': 47.72, },
{'source': sys2, 'target': sys3, 'cooldown': 4.77, 'fatigue': 222.91, },
])
def test_route_jump_fatigue_covertops_covertcyno_three_jumps(self):
"""Test route jump fatigue calculator, covertops being bridged by blops for three jumps"""
sys1 = self.map.get_system_id('U-HVIX')
sys2 = self.map.get_system_id('RMOC-W')
sys3 = self.map.get_system_id('Podion')
sys4 = self.map.get_system_id('Hothomouh')
res = self.map.route_jump_fatigue([sys1, sys2, sys3, sys4], 0, ship_class='covertops', jump_type='covert')
self.assertListEqual(res, [
{'source': sys1, 'target': sys2, 'cooldown': 4.77, 'fatigue': 47.72, },
{'source': sys2, 'target': sys3, 'cooldown': 4.77, 'fatigue': 222.91, },
{'source': sys3, 'target': sys4, 'cooldown': 22.29, 'fatigue': 786.39, },
])
def test_neighbors_gate(self):
pass
@@ -55,7 +118,7 @@ class MapTestCase(TestCase):
pass
def test_jump_bridge_addition(self):
# HED-GP to GE-8
"""Test addition of a jump bridge"""
self.assertGreater(len(self.map.route_gate(30001161, 30001198)), 2)
self.map.add_jumpbridge(30001161, 30001198)
r = self.map.route_gate(30001161, 30001198)
@@ -106,3 +169,57 @@ class MapTestCase(TestCase):
The maximum jump range of a bloops is 8LY.
"""
self.assertEquals(ship_class_to_range('blackops', 5), 8)
def test_jump_distance_skills_titan(self):
"""
Test the correct range for titans for each JDC skill level
"""
ship_ranges = [2.5, 3.0, 3.5, 4.0, 4.5, 5.0]
for skill in range(0, 6):
jump_range = ship_ranges[skill]
self.assertEquals(ship_class_to_range('titan', skill), jump_range)
def test_jump_distance_skills_supercarrier(self):
"""
Test the correct range for titans for each JDC skill level
"""
ship_ranges = [2.5, 3.0, 3.5, 4.0, 4.5, 5.0]
for skill in range(0, 6):
jump_range = ship_ranges[skill]
self.assertEquals(ship_class_to_range('supercarrier', skill), jump_range)
def test_jump_distance_skills_carrier(self):
"""
Test the correct range for supercarriers for each JDC skill level
"""
ship_ranges = [2.5, 3.0, 3.5, 4.0, 4.5, 5.0]
for skill in range(0, 6):
jump_range = ship_ranges[skill]
self.assertEquals(ship_class_to_range('carrier', skill), jump_range)
def test_jump_distance_skills_dreadnought(self):
"""
Test the correct range for dreadnoughts for each JDC skill level
"""
ship_ranges = [2.5, 3.0, 3.5, 4.0, 4.5, 5.0]
for skill in range(0, 6):
jump_range = ship_ranges[skill]
self.assertEquals(ship_class_to_range('dreadnought', skill), jump_range)
def test_jump_distance_skills_industrial(self):
"""
Test the correct range for industrials for each JDC skill level
"""
ship_ranges = [2.5, 3.0, 3.5, 4.0, 4.5, 5.0]
for skill in range(0, 6):
jump_range = ship_ranges[skill]
self.assertEquals(ship_class_to_range('industrial', skill), jump_range)
def test_jump_distance_skills_jumpfreighter(self):
"""
Test the correct range for jump freighters for each JDC skill level
"""
ship_ranges = [5.0, 6.0, 7.0, 8.0, 9.0, 10.0]
for skill in range(0, 6):
jump_range = ship_ranges[skill]
self.assertEquals(ship_class_to_range('jumpfreighter', skill), jump_range)

60
tests/test_utils.py Normal file
View File

@@ -0,0 +1,60 @@
import mock
from unittest import TestCase
from dropbot.utils import decimal_minutes_to_hms
class DecimalToHMSTest(TestCase):
"""
Tests the decimal_minutes_to_hms function
"""
def test_seconds_only(self):
"""Check seconds are calculated correctly"""
self.assertEqual(decimal_minutes_to_hms(0.5), '30s')
self.assertEqual(decimal_minutes_to_hms(0.75), '45s')
self.assertEqual(decimal_minutes_to_hms(0.25), '15s')
self.assertEqual(decimal_minutes_to_hms(0.56), '34s')
self.assertEqual(decimal_minutes_to_hms(0.57), '34s')
self.assertEqual(decimal_minutes_to_hms(0.58), '35s')
def test_full_minutes(self):
"""Check minutes are correclty output"""
self.assertEqual(decimal_minutes_to_hms(1), '1m')
self.assertEqual(decimal_minutes_to_hms(10), '10m')
self.assertEqual(decimal_minutes_to_hms(30), '30m')
def test_minutes_and_seconds(self):
"""Check minutes and seconds are correctly output"""
self.assertEqual(decimal_minutes_to_hms(1.5), '1m 30s')
self.assertEqual(decimal_minutes_to_hms(59.5), '59m 30s')
self.assertEqual(decimal_minutes_to_hms(5.25), '5m 15s')
def test_full_hours(self):
"""Check hours are correctly output"""
self.assertEqual(decimal_minutes_to_hms(60), '1h')
self.assertEqual(decimal_minutes_to_hms(120), '2h')
self.assertEqual(decimal_minutes_to_hms(1440), '24h')
def test_hour_minutes_and_seconds(self):
"""Check HMS are correctly output in the correct situations"""
self.assertEqual(decimal_minutes_to_hms(61.5), '1h 1m 30s')
def test_partial_seconds(self):
"""Check that partial seconds are rounded to the nearest second"""
self.assertEqual(decimal_minutes_to_hms(4.56), '4m 34s')
self.assertEqual(decimal_minutes_to_hms(4.57), '4m 34s')
self.assertEqual(decimal_minutes_to_hms(4.58), '4m 35s')
def test_large_numbers(self):
self.assertEqual(decimal_minutes_to_hms(300000000000000), '5000000000000h')
self.assertEqual(decimal_minutes_to_hms(3000023423234.4), '50000390387h 14m 24s')
def test_negative_numbers(self):
self.assertEqual(decimal_minutes_to_hms(-1), '1m')
self.assertEqual(decimal_minutes_to_hms(-1.2), '1m 12s')
def test_invalid_input(self):
with self.assertRaises(ValueError):
decimal_minutes_to_hms('dsd')
with self.assertRaises(ValueError):
decimal_minutes_to_hms(mock.Mock())