1
0
mirror of https://github.com/wting/autojump synced 2024-10-27 20:34:07 +00:00

Fix #123, new installations were not initializing database properly.

Also added unit test coverage to check database initialization, saving, and
loading.  Unit tests also revealed that migration code was not working properly
(starts database from scratch instead of copying existing entries over).
This commit is contained in:
William Ting 2012-05-28 09:21:31 -10:00
parent b3c3253e89
commit b00e0e85e1
2 changed files with 98 additions and 22 deletions

View File

@ -81,6 +81,7 @@ class Database:
else: else:
import math import math
self.data[path] = math.sqrt((self.data[path]**2)+(increment**2)) self.data[path] = math.sqrt((self.data[path]**2)+(increment**2))
self.save()
def decay(self): def decay(self):
""" """
@ -102,34 +103,34 @@ class Database:
""" """
Try to open the database file, recovering from backup if needed. Try to open the database file, recovering from backup if needed.
""" """
try: if os.path.exists(self.filename):
with open(self.filename, 'r') as aj_file: with open(self.filename, 'r') as f:
for line in aj_file.readlines(): for line in f.readlines():
weight, path = line[:-1].split("\t", 1) weight, path = line[:-1].split("\t", 1)
path = decode(path, 'utf-8') path = decode(path, 'utf-8')
self.data[path] = float(weight) self.data[path] = float(weight)
except (IOError, EOFError): elif os.path.exists(self.filename + '.bak'):
if not error_recovery and os.path.exists(self.filename + ".bak"): if not error_recovery:
print('Problem with autojump database,\ print('Problem with autojump database,\
trying to recover from backup...', file=sys.stderr) trying to recover from backup...', file=sys.stderr)
shutil.copy(self.filename + '.bak', self.filename) shutil.copy(self.filename + '.bak', self.filename)
return self.load(True) return self.load(True)
else: else:
# TODO: migration code, will be removed in v22+ # migration code, autojump_py last used in v17
# autojump_py last used in v17
self.filename = get_db_file('autojump_py') self.filename = get_db_file('autojump_py')
if os.path.exists(self.filename): if os.path.exists(self.filename):
try: # fix to get optimised pickle in python < 3 try: # fix to get optimised pickle in python < 3
import cPickle as pickle import cPickle as pickle
except ImportError: except ImportError:
import pickle import pickle
try: try:
with open(self.filename, 'rb') as aj_file: with open(self.filename, 'rb') as f:
# encoding is only specified for Python 2 compatibility # encoding is only specified for Python 2 compatibility
if sys.version_info[0] > 2: if sys.version_info[0] > 2:
self.data = pickle.load(aj_file, encoding="utf-8") self.data = pickle.load(f, encoding="utf-8")
else: else:
self.data = pickle.load(aj_file) self.data = pickle.load(f)
unicode_dict = {} unicode_dict = {}
for k, v in self.data.items(): for k, v in self.data.items():
print(k) print(k)
@ -163,7 +164,8 @@ class Database:
def save(self): def save(self):
""" """
Save database atomically and preserve backup. Save database atomically and preserve backup, creating new database if
needed.
""" """
# check file existence and permissions # check file existence and permissions
if ((not os.path.exists(self.filename)) or if ((not os.path.exists(self.filename)) or
@ -247,7 +249,6 @@ def options():
if(ARGS.add != os.path.expanduser("~")): if(ARGS.add != os.path.expanduser("~")):
db = Database(DB_FILE) db = Database(DB_FILE)
db.add(decode(ARGS.add)) db.add(decode(ARGS.add))
db.save()
return True return True
if (ARGS.purge): if (ARGS.purge):

View File

@ -6,10 +6,23 @@
from __future__ import division from __future__ import division
import autojump import autojump
import contextlib
import random
import os import os
import shutil
import sys
import tempfile import tempfile
import unittest import unittest
@contextlib.contextmanager
def no_stderr():
savestderr = sys.stderr
class DevNull(object):
def write(self, _): pass
sys.stderr = DevNull()
yield
sys.stderr = savestderr
# test suite # test suite
class TestAutojump(unittest.TestCase): class TestAutojump(unittest.TestCase):
@ -18,6 +31,8 @@ class TestAutojump(unittest.TestCase):
self.fd, self.fname = tempfile.mkstemp() self.fd, self.fname = tempfile.mkstemp()
self.db = autojump.Database(self.fname) self.db = autojump.Database(self.fname)
random.seed()
def tearDown(self): def tearDown(self):
os.remove(self.fname) os.remove(self.fname)
if os.path.isfile(self.fname + ".bak"): if os.path.isfile(self.fname + ".bak"):
@ -42,26 +57,86 @@ class TestAutojump(unittest.TestCase):
self.db.decay() self.db.decay()
self.assertTrue(self.db.get_weight('/1') < 10) self.assertTrue(self.db.get_weight('/1') < 10)
def test_db_load_empty(self):
pass
def test_db_load_backup(self):
pass
def test_db_load_migrate(self):
pass
def test_db_load_existing(self): def test_db_load_existing(self):
self.db = autojump.Database('tests/database.txt') self.db = autojump.Database('tests/database.txt')
self.assertTrue(len(self.db) > 0) self.assertTrue(len(self.db) > 0)
def test_db_load_empty(self):
# setup
_, fname = tempfile.mkstemp()
db = autojump.Database(fname)
try:
# test
self.assertEquals(len(self.db), 0)
finally:
# teardown
os.remove(fname)
def test_db_load_backup(self):
# setup
fname = '/tmp/autojump_test_db_load_backup_' + str(random.randint(0,32678))
db = autojump.Database(fname)
db.add('/1')
os.rename(fname, fname + '.bak')
try:
# test
with no_stderr():
db = autojump.Database(fname)
self.assertTrue(len(db.data) > 0)
self.assertTrue(os.path.isfile(fname))
finally:
# teardown
os.remove(fname)
os.remove(fname + '.bak')
def test_db_load_migrate(self):
ORIG_CONFIG_DIR = autojump.CONFIG_DIR
try:
# setup
CONFIG_DIR = '/tmp/autojump_test_db_load_migrate_' + str(random.randint(0,32678))
os.mkdir(CONFIG_DIR)
autojump.CONFIG_DIR = CONFIG_DIR
fname = CONFIG_DIR + '/autojump_py'
db = autojump.Database(fname)
db.add('/1')
shutil.copy(fname, fname + '.bak')
db.add('/2')
# test
missing_fname = '/tmp/autojump_test_db_load_missing_' + str(random.randint(0,32678)) + '.txt'
db = autojump.Database(missing_fname)
db.add('/3')
self.assertEquals(len(db.data), 3)
finally:
# teardown
shutil.rmtree(CONFIG_DIR)
os.remove(missing_fname)
os.remove(missing_fname + '.bak')
autojump.CONFIG_DIR = ORIG_CONFIG_DIR
def test_db_purge(self): def test_db_purge(self):
self.db.add('/1') self.db.add('/1')
self.db.purge() self.db.purge()
self.assertEquals(len(self.db), 0) self.assertEquals(len(self.db), 0)
def test_db_save(self): def test_db_save(self):
pass # setup
fname = '/tmp/autojump_test_db_save_' + str(random.randint(0,32678)) + '.txt'
db = autojump.Database(fname)
try:
# test
db.save()
self.assertTrue(os.path.isfile(fname))
finally:
# teardown
os.remove(fname)
os.remove(fname + '.bak')
def test_db_trim(self): def test_db_trim(self):
self.db.add('/1') self.db.add('/1')