db_tests.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. from pwman.util.callback import Callback
  2. from pwman.util.generator import leetlist
  3. from pwman.data.drivers.sqlite import DatabaseException
  4. import os
  5. import os.path
  6. import sys
  7. class DummyCallback(Callback):
  8. def getsecret(self, question):
  9. return u'12345'
  10. def getnewsecret(self, question):
  11. return u'12345'
  12. class DummyCallback2(Callback):
  13. def getinput(self, question):
  14. return u'newsecret'
  15. def getsecret(self, question):
  16. return u'wrong'
  17. def getnewsecret(self, question):
  18. return u'newsecret'
  19. class DummyCallback3(Callback):
  20. def getinput(self, question):
  21. return u'newsecret'
  22. def getsecret(self, question):
  23. return u'12345'
  24. def getnewsecret(self, question):
  25. return u'newsecret'
  26. class DummyCallback4(Callback):
  27. def getinput(self, question):
  28. return u'newsecret'
  29. def getsecret(self, question):
  30. return u'newsecret'
  31. def getnewsecret(self, question):
  32. return u'newsecret'
  33. if 'darwin' in sys.platform: # pragma: no cover
  34. from pwman.ui.mac import PwmanCliMacNew as PwmanCliNew
  35. OSX = True
  36. elif 'win' in sys.platform: # pragma: no cover
  37. from pwman.ui.win import PwmanCliWinNew as PwmanCliNew
  38. OSX = False
  39. else:
  40. from pwman.ui.cli import PwmanCliNew
  41. OSX = False
  42. import pwman.util.config as config
  43. import pwman.data.factory
  44. from pwman.data.nodes import NewNode
  45. from pwman.data.tags import TagNew
  46. from pwman.util.crypto import CryptoEngine, CryptoBadKeyException
  47. from pwman import which, default_config
  48. from pwman.ui.base import get_pass_conf
  49. from pwman.ui.tools import CMDLoop, CliMenuItem
  50. import unittest
  51. from pwman.data import factory
  52. _saveconfig = False
  53. default_config['Database'] = {'type': 'SQLite',
  54. 'filename':
  55. os.path.join(os.path.dirname(__file__),
  56. "test.pwman.db")
  57. }
  58. class SetupTester(object):
  59. def __init__(self):
  60. config.set_defaults(default_config)
  61. if not OSX:
  62. self.xselpath = which("xsel")
  63. config.set_value("Global", "xsel", self.xselpath)
  64. else:
  65. self.xselpath = "xsel"
  66. def clean(self):
  67. if os.path.exists(config.get_value('Database', 'filename')):
  68. os.remove(config.get_value('Database', 'filename'))
  69. if os.path.exists(os.path.join(os.path.dirname(__file__),
  70. 'testing_config')):
  71. os.remove(os.path.join(os.path.dirname(__file__),
  72. 'testing_config'))
  73. def create(self):
  74. dbver = 0.4
  75. dbtype = config.get_value("Database", "type")
  76. db = pwman.data.factory.create(dbtype, dbver)
  77. self.cli = PwmanCliNew(db, self.xselpath, DummyCallback)
  78. class DBTests(unittest.TestCase):
  79. """test everything related to db"""
  80. def setUp(self):
  81. "test that the right db instance was created"
  82. dbver = 0.4
  83. self.dbtype = config.get_value("Database", "type")
  84. self.db = pwman.data.factory.create(self.dbtype, dbver)
  85. self.tester = SetupTester()
  86. self.tester.create()
  87. def test_db_created(self):
  88. "test that the right db instance was created"
  89. # self.db = pwman.data.factory.create(dbtype, dbver)
  90. self.assertIn(self.dbtype, self.db.__class__.__name__)
  91. def test_db_opened(self):
  92. "db was successfuly opened"
  93. # it will have a file name associated
  94. self.assertTrue(hasattr(self.db, '_filename'))
  95. def test_create_node(self):
  96. "test that a node can be successfuly created"
  97. # this method does not test do_new
  98. # which is a UI method, rather we test
  99. # _db.addnodes
  100. username = 'tester'
  101. password = 'Password'
  102. url = 'example.org'
  103. notes = 'some notes'
  104. #node = NewNode(username, password, url, notes)
  105. node = NewNode()
  106. node.username = username
  107. node.password = password
  108. node.url = url
  109. node.notes = notes
  110. #node = NewNode(username, password, url, notes)
  111. tags = [TagNew(tn) for tn in ['testing1', 'testing2']]
  112. node.tags = tags
  113. self.db.open()
  114. self.db.addnodes([node])
  115. idx_created = node._id
  116. new_node = self.db.getnodes([idx_created])[0]
  117. for key, attr in {'password': password, 'username': username,
  118. 'url': url, 'notes': notes}.iteritems():
  119. self.assertEquals(attr, getattr(new_node, key))
  120. self.db.close()
  121. def test_tags(self):
  122. enc = CryptoEngine.get()
  123. got_tags = self.tester.cli._tags(enc)
  124. self.assertEqual(2, len(got_tags))
  125. def test_change_pass(self):
  126. enc = CryptoEngine.get()
  127. enc._callback = DummyCallback2()
  128. self.assertRaises(CryptoBadKeyException,
  129. self.tester.cli._db.changepassword)
  130. def test_db_change_pass(self):
  131. "fuck yeah, we change the password and the new dummy works"
  132. enc = CryptoEngine.get()
  133. enc._callback = DummyCallback3()
  134. self.tester.cli._db.changepassword()
  135. self.tester.cli.do_forget('')
  136. enc._callback = DummyCallback4()
  137. self.tester.cli.do_ls('')
  138. def test_db_list_tags(self):
  139. # tags are return as ecrypted strings
  140. tags = self.tester.cli._db.listtags()
  141. self.assertEqual(2, len(tags))
  142. self.tester.cli.do_filter('testing1')
  143. tags = self.tester.cli._db.listtags()
  144. self.assertEqual(1, len(tags))
  145. self.tester.cli.do_ls('')
  146. def test_db_remove_node(self):
  147. node = self.tester.cli._db.getnodes([1])
  148. self.tester.cli._db.removenodes(node)
  149. # create the removed node again
  150. node = NewNode()
  151. node.username = 'tester'
  152. node.password = 'Password'
  153. node.url = 'example.org'
  154. node.notes = 'some notes'
  155. tags = [TagNew(tn) for tn in ['testing1', 'testing2']]
  156. node.tags = tags
  157. self.db.open()
  158. self.db.addnodes([node])
  159. class TestDBFalseConfig(unittest.TestCase):
  160. def setUp(self):
  161. #filename = default_config['Database'].pop('filename')
  162. self.fname1 = default_config['Database'].pop('filename')
  163. self.fname = config._conf['Database'].pop('filename')
  164. def test_db_missing_conf_parameter(self):
  165. self.assertRaises(DatabaseException, pwman.data.factory.create,
  166. 'SQLite', 0.4)
  167. def tearDown(self):
  168. config.set_value('Database', 'filename', self.fname)
  169. default_config['Database']['filename'] = self.fname1
  170. config._conf['Database']['filename'] = self.fname
  171. class CLITests(unittest.TestCase):
  172. """
  173. test command line functionallity
  174. """
  175. def setUp(self):
  176. "test that the right db instance was created"
  177. dbver = 0.4
  178. self.dbtype = config.get_value("Database", "type")
  179. self.db = pwman.data.factory.create(self.dbtype, dbver)
  180. self.tester = SetupTester()
  181. self.tester.create()
  182. def test_input(self):
  183. name = self.tester.cli.get_username(reader=lambda: u'alice')
  184. self.assertEqual(name, u'alice')
  185. def test_password(self):
  186. password = self.tester.cli.get_password(None,
  187. reader=lambda x: u'hatman')
  188. self.assertEqual(password, u'hatman')
  189. def test_random_password(self):
  190. password = self.tester.cli.get_password(None, length=7)
  191. self.assertEqual(len(password), 7)
  192. def test_random_leet_password(self):
  193. password = self.tester.cli.get_password(None, leetify=True, length=7)
  194. l_num = 0
  195. for v in leetlist.values():
  196. if v in password:
  197. l_num += 1
  198. # sometime despite all efforts, randomness dictates that no
  199. # leetifying happens ...
  200. self.assertTrue(l_num >= 0)
  201. def test_leet_password(self):
  202. password = self.tester.cli.get_password(None, leetify=True,
  203. reader=lambda x: u'HAtman')
  204. self.assertRegexpMatches(password, ("(H|h)?(A|a|4)?(T|t|\+)?(m|M|\|"
  205. "\/\|)?(A|a|4)?(N|n|\|\\|)?"))
  206. def test_get_url(self):
  207. url = self.tester.cli.get_url(reader=lambda: u'example.com')
  208. self.assertEqual(url, u'example.com')
  209. def test_get_notes(self):
  210. notes = self.tester.cli.get_notes(reader=lambda:
  211. u'test 123\n test 456')
  212. self.assertEqual(notes, u'test 123\n test 456')
  213. def test_get_tags(self):
  214. tags = self.tester.cli.get_tags(reader=lambda: u'looking glass')
  215. for t in tags:
  216. self.assertIsInstance(t, TagNew)
  217. for t, n in zip(tags, 'looking glass'.split()):
  218. self.assertEqual(t.name.strip(), n)
  219. # creating all the components of the node does
  220. # the node is still not added !
  221. def test_add_new_entry(self):
  222. #node = NewNode('alice', 'dough!', 'example.com',
  223. # 'lorem impsum')
  224. node = NewNode()
  225. node.username = 'alice'
  226. node.password = 'dough!'
  227. node.url = 'example.com'
  228. node.notes = 'somenotes'
  229. node.tags = 'lorem ipsum'
  230. tags = self.tester.cli.get_tags(reader=lambda: u'looking glass')
  231. node.tags = tags
  232. self.tester.cli._db.addnodes([node])
  233. self.tester.cli._db._cur.execute(
  234. "SELECT ID FROM NODES ORDER BY ID ASC", [])
  235. rows = self.tester.cli._db._cur.fetchall()
  236. # by now the db should have 2 new nodes
  237. # the first one was added by test_create_node in DBTests
  238. # the second was added just now.
  239. # This will pass only when running all the tests then ...
  240. self.assertEqual(len(rows), 2)
  241. def test_get_ids(self):
  242. #used by do_cp or do_open,
  243. # this spits many time could not understand your input
  244. self.assertEqual([1], self.tester.cli.get_ids('1'))
  245. self.assertListEqual([1, 2, 3, 4, 5], self.tester.cli.get_ids('1-5'))
  246. self.assertListEqual([], self.tester.cli.get_ids('5-1'))
  247. self.assertListEqual([], self.tester.cli.get_ids('5x-1'))
  248. self.assertListEqual([], self.tester.cli.get_ids('5x'))
  249. self.assertListEqual([], self.tester.cli.get_ids('5\\'))
  250. def test_edit(self):
  251. node = self.tester.cli._db.getnodes([2])[0]
  252. menu = CMDLoop()
  253. menu.add(CliMenuItem("Username", self.tester.cli.get_username,
  254. node.username,
  255. node.username))
  256. menu.add(CliMenuItem("Password", self.tester.cli.get_password,
  257. node.password,
  258. node.password))
  259. menu.add(CliMenuItem("Url", self.tester.cli.get_url,
  260. node.url,
  261. node.url))
  262. menunotes = CliMenuItem("Notes",
  263. self.tester.cli.get_notes(reader=lambda:
  264. u'bla bla'),
  265. node.notes,
  266. node.notes)
  267. menu.add(menunotes)
  268. menu.add(CliMenuItem("Tags", self.tester.cli.get_tags,
  269. node.tags,
  270. node.tags))
  271. import StringIO
  272. dummy_stdin = StringIO.StringIO('4\n\nX')
  273. self.assertTrue(len(dummy_stdin.readlines()))
  274. dummy_stdin.seek(0)
  275. sys.stdin = dummy_stdin
  276. menu.run(node)
  277. self.tester.cli._db.editnode(2, node)
  278. sys.stdin = sys.__stdin__
  279. def test_get_pass_conf(self):
  280. numerics, leet, s_chars = get_pass_conf()
  281. self.assertFalse(numerics)
  282. self.assertFalse(leet)
  283. self.assertFalse(s_chars)
  284. def test_do_tags(self):
  285. self.tester.cli.do_filter('bank')
  286. def test_do_clear(self):
  287. self.tester.cli.do_clear('')
  288. def test_do_exit(self):
  289. self.assertTrue(self.tester.cli.do_exit(''))
  290. class FactoryTest(unittest.TestCase):
  291. def test_factory_check_db_ver(self):
  292. self.assertEquals(factory.check_db_version('SQLite'), u"'0.4'")
  293. class ConfigTest(unittest.TestCase):
  294. def setUp(self):
  295. "test that the right db instance was created"
  296. dbver = 0.4
  297. self.dbtype = config.get_value("Database", "type")
  298. self.db = pwman.data.factory.create(self.dbtype, dbver)
  299. self.tester = SetupTester()
  300. self.tester.create()
  301. def test_config_write(self):
  302. _filename = os.path.join(os.path.dirname(__file__),
  303. 'testing_config')
  304. config._file = _filename
  305. config.save(_filename)
  306. self.assertTrue(_filename)
  307. os.remove(_filename)
  308. def test_config_write_with_none(self):
  309. _filename = os.path.join(os.path.dirname(__file__),
  310. 'testing_config')
  311. config._file = _filename
  312. config.save()
  313. self.assertTrue(os.path.exists(_filename))
  314. os.remove(_filename)
  315. def test_write_no_permission(self):
  316. # this test will pass if you run as root ...
  317. # assuming you are not doing something like that
  318. self.assertRaises(config.ConfigException, config.save,
  319. '/root/test_config')
  320. def test_add_default(self):
  321. config.add_defaults({'Section1': {'name': 'value'}})
  322. self.assertIn('Section1', config._defaults)
  323. def test_get_conf(self):
  324. cnf = config.get_conf()
  325. cnf_keys = cnf.keys()
  326. self.assertTrue('Encryption' in cnf_keys)
  327. self.assertTrue('Readline' in cnf_keys)
  328. self.assertTrue('Global' in cnf_keys)
  329. self.assertTrue('Database' in cnf_keys)
  330. def test_load_conf(self):
  331. self.assertRaises(config.ConfigException, config.load, 'NoSuchFile')
  332. # Everything should be ok
  333. config.save('TestConfig.ini')
  334. config.load('TestConfig.ini')
  335. # let's corrupt the file
  336. cfg = open('TestConfig.ini', 'w')
  337. cfg.write('Corruption')
  338. cfg.close()
  339. self.assertRaises(config.ConfigException, config.load,
  340. 'TestConfig.ini')
  341. os.remove('TestConfig.ini')