Merge lp:~jameinel/u1db/client_delete_doc into lp:u1db

Proposed by John A Meinel
Status: Merged
Approved by: Samuele Pedroni
Approved revision: 135
Merged at revision: 134
Proposed branch: lp:~jameinel/u1db/client_delete_doc
Merge into: lp:u1db
Diff against target: 172 lines (+101/-1)
2 files modified
u1db/commandline/client.py (+21/-0)
u1db/tests/commandline/test_client.py (+80/-1)
To merge this branch: bzr merge lp:~jameinel/u1db/client_delete_doc
Reviewer Review Type Date Requested Status
Samuele Pedroni Approve
Review via email: mp+83940@code.launchpad.net

Description of the change

Exposes "u1db-client delete db doc-id doc-rev"

To post a comment you must log in.
lp:~jameinel/u1db/client_delete_doc updated
133. By John A Meinel

Add some focused tests on the error conditions.

134. By John A Meinel

Merge trunk to get u1db.open()

135. By John A Meinel

Change CmdDelete to use u1db_open.

Revision history for this message
Samuele Pedroni (pedronis) wrote :

+1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'u1db/commandline/client.py'
2--- u1db/commandline/client.py 2011-11-30 13:09:38 +0000
3+++ u1db/commandline/client.py 2011-11-30 14:25:32 +0000
4@@ -56,6 +56,27 @@
5 client_commands.register(CmdCreate)
6
7
8+class CmdDelete(command.Command):
9+ """Delete a document from the database"""
10+
11+ name = 'delete'
12+
13+ @classmethod
14+ def _populate_subparser(cls, parser):
15+ parser.add_argument('database', help='The database to update')
16+ parser.add_argument('doc_id', help='The document id to retrieve')
17+ parser.add_argument('doc_rev',
18+ help='The revision of the document (which is being superseded.)')
19+
20+ def run(self, database, doc_id, doc_rev):
21+ db = u1db_open(database, create=False)
22+ doc = Document(doc_id, doc_rev, None)
23+ db.delete_doc(doc)
24+ self.stderr.write('rev: %s\n' % (doc.rev,))
25+
26+client_commands.register(CmdDelete)
27+
28+
29 class CmdGet(command.Command):
30 """Extract a document from the database"""
31
32
33=== modified file 'u1db/tests/commandline/test_client.py'
34--- u1db/tests/commandline/test_client.py 2011-11-23 12:39:27 +0000
35+++ u1db/tests/commandline/test_client.py 2011-11-30 14:25:32 +0000
36@@ -19,6 +19,7 @@
37
38 from u1db import (
39 __version__ as _u1db_version,
40+ errors,
41 tests,
42 )
43 from u1db.backends import (
44@@ -30,6 +31,11 @@
45
46
47 class TestArgs(tests.TestCase):
48+ """These tests are meant to test just the argument parsing.
49+
50+ Each Command should have at least one test, possibly more if it allows
51+ optional arguments, etc.
52+ """
53
54 def setUp(self):
55 super(TestArgs, self).setUp()
56@@ -58,6 +64,13 @@
57 self.assertEqual('xyz', args.doc_id)
58 self.assertEqual(None, args.infile)
59
60+ def test_delete(self):
61+ args = self.parse_args(['delete', 'test.db', 'doc-id', 'doc-rev'])
62+ self.assertEqual(client.CmdDelete, args.subcommand)
63+ self.assertEqual('test.db', args.database)
64+ self.assertEqual('doc-id', args.doc_id)
65+ self.assertEqual('doc-rev', args.doc_rev)
66+
67 def test_get(self):
68 args = self.parse_args(['get', 'test.db', 'doc-id'])
69 self.assertEqual(client.CmdGet, args.subcommand)
70@@ -94,6 +107,12 @@
71
72
73 class TestCaseWithDB(tests.TestCase):
74+ """These next tests are meant to have one class per Command.
75+
76+ It is meant to test the inner workings of each command. The detailed
77+ testing should happen in these classes. Stuff like how it handles errors,
78+ etc. should be done here.
79+ """
80
81 def setUp(self):
82 super(TestCaseWithDB, self).setUp()
83@@ -124,6 +143,48 @@
84 cmd.stderr.getvalue())
85
86
87+class TestCmdDelete(TestCaseWithDB):
88+
89+ def test_delete(self):
90+ doc = self.db.create_doc(tests.simple_doc)
91+ cmd = self.make_command(client.CmdDelete)
92+ cmd.run(self.db_path, doc.doc_id, doc.rev)
93+ doc2 = self.db.get_doc(doc.doc_id)
94+ self.assertEqual(doc.doc_id, doc2.doc_id)
95+ self.assertNotEqual(doc.rev, doc2.rev)
96+ self.assertIs(None, doc2.content)
97+ self.assertEqual('', cmd.stdout.getvalue())
98+ self.assertEqual('rev: %s\n' % (doc2.rev,), cmd.stderr.getvalue())
99+
100+ def test_delete_fails_if_nonexistent(self):
101+ doc = self.db.create_doc(tests.simple_doc)
102+ db2_path = self.db_path + '.typo'
103+ cmd = self.make_command(client.CmdDelete)
104+ # TODO: We should really not be showing a traceback here. But we need
105+ # to teach the commandline infrastructure how to handle
106+ # exceptions.
107+ # However, we *do* want to test that the db doesn't get created
108+ # by accident.
109+ self.assertRaises(errors.DatabaseDoesNotExist,
110+ cmd.run, db2_path, doc.doc_id, doc.rev)
111+ self.assertFalse(os.path.exists(db2_path))
112+
113+ def test_delete_no_such_doc(self):
114+ cmd = self.make_command(client.CmdDelete)
115+ # TODO: We should really not be showing a traceback here. But we need
116+ # to teach the commandline infrastructure how to handle
117+ # exceptions.
118+ self.assertRaises(errors.DocumentDoesNotExist,
119+ cmd.run, self.db_path, 'no-doc-id', 'no-rev')
120+
121+ def test_delete_bad_rev(self):
122+ doc = self.db.create_doc(tests.simple_doc)
123+ cmd = self.make_command(client.CmdDelete)
124+ self.assertRaises(errors.RevisionConflict,
125+ cmd.run, self.db_path, doc.doc_id, 'not-the-actual-doc-rev:1')
126+ # TODO: Test that we get a pretty output.
127+
128+
129 class TestCmdGet(TestCaseWithDB):
130
131 def setUp(self):
132@@ -215,6 +276,12 @@
133
134
135 class TestCommandLine(TestCaseWithDB):
136+ """These are meant to test that the infrastructure is fully connected.
137+
138+ Each command is likely to only have one test here. Something that ensures
139+ 'main()' knows about and can run the command correctly. Most logic-level
140+ testing of the Command should go into its own test class above.
141+ """
142
143 def _get_u1db_client_path(self):
144 from u1db import __path__ as u1db_path
145@@ -236,7 +303,10 @@
146 stderr = cStringIO.StringIO()
147 self.patch(sys, 'stdout', stdout)
148 self.patch(sys, 'stderr', stderr)
149- ret = client.main(args)
150+ try:
151+ ret = client.main(args)
152+ except SystemExit, e:
153+ self.fail("Intercepted SystemExit: %s" % (e,))
154 if ret is None:
155 ret = 0
156 return ret, stdout.getvalue(), stderr.getvalue()
157@@ -259,6 +329,15 @@
158 self.assertEqual(tests.simple_doc, stdout)
159 self.assertEqual('rev: %s\n' % (doc.rev,), stderr)
160
161+ def test_delete(self):
162+ doc = self.db.create_doc(tests.simple_doc, doc_id='test-id')
163+ ret, stdout, stderr = self.run_main(
164+ ['delete', self.db_path, 'test-id', doc.rev])
165+ doc = self.db.get_doc('test-id')
166+ self.assertEqual(0, ret)
167+ self.assertEqual('', stdout)
168+ self.assertEqual('rev: %s\n' % (doc.rev,), stderr)
169+
170 def test_init_db(self):
171 path = self.working_dir + '/test2.db'
172 ret, stdout, stderr = self.run_main(['init-db', path, 'uid'])

Subscribers

People subscribed via source and target branches