Merge lp:~robru/python-dbusmock/querycalls into lp:~pitti/python-dbusmock/old-bzr-trunk

Proposed by Robert Bruce Park
Status: Merged
Merged at revision: 100
Proposed branch: lp:~robru/python-dbusmock/querycalls
Merge into: lp:~pitti/python-dbusmock/old-bzr-trunk
Diff against target: 105 lines (+70/-0)
2 files modified
dbusmock/mockobject.py (+23/-0)
tests/test_api.py (+47/-0)
To merge this branch: bzr merge lp:~robru/python-dbusmock/querycalls
Reviewer Review Type Date Requested Status
Martin Pitt Approve
Robert Bruce Park (community) Approve
Review via email: mp+143153@code.launchpad.net

Description of the change

This change makes it possible to query for the called method signatures over dbus, and also makes it possible to clear this log, such that each individual test can start with a fresh state (so no worries about one test checking the log and finding method invocations logged from the previous test).

Let me know how you feel about the implementation, I would be happy to alter it to fit your standards.

To post a comment you must log in.
lp:~robru/python-dbusmock/querycalls updated
101. By Robert Bruce Park

Use str.index instead of str.find.

The reason for this is that str.index will raise an exception if the
substring is not found, which will cause the test to fail; str.find
will return -1 if the substring is not found, which technically
evaluates to true, and thus doesn't cause the test to fail at all if
the string is not found.

Revision history for this message
Martin Pitt (pitti) wrote :

I think this is a great idea, thanks for working on this!

If a program uses the D-BUS queries for the logs, and it wants to suppress stdout, you can already use "-l /dev/null", so I don't think we need another command line argument for this. Do you agree?

My main nitpick with this is QueryCalls() returning a single string, which the caller then has to pick apart again. In some cases you just want to know "has this function being called", but in other cases you actually want to verify the arguments of a particular call. So how about:

 - ClearLog() sounds good to me.

 - GetLog() ("Query.." is unusual in D-BUS interfaces) has a return signature a(tsav), returning a list of (timestamp, method, args) tuples.

 - GetMethodCalls(method) has a return signature a(tav), returning a list of (timestamp, args) tuples; by merely checking the returned list length against 0, a caller can conveniently check whether a method was called.

> self.assertTrue(self.dbus_mock.QueryCalls().index(' Wop "foo"'))

Please don't use this test form, it looks confusing as index() can return 0 if the string is right at the start, and 0 counts as False. Please use

  self.assertTrue('search' in QueryCalls() ...)

(Won't be relevant after above API changes, of course).

+ def test_new_logging(self):

Please name this "test_dbus_logging".

Thanks!

review: Needs Fixing
Revision history for this message
Martin Pitt (pitti) wrote :

> - GetLog()

Perhaps we should call this GetCalls() for consistency? As "Log" might also indicate information about the mock process itself, which we are not interested in here.

Revision history for this message
Robert Bruce Park (robru) wrote :

Sounds good, Martin. I am just running around moving into my new apartment, but I will find time this evening to work on this. So you'll be able to merge it tomorrow ;-)

Martin Pitt <email address hidden> wrote:

>> - GetLog()
>
>Perhaps we should call this GetCalls() for consistency? As "Log" might also indicate information about the mock process itself, which we are not interested in here.
>--
>https://code.launchpad.net/~robru/python-dbusmock/querycalls/+merge/143153
>You are the owner of lp:~robru/python-dbusmock/querycalls.

lp:~robru/python-dbusmock/querycalls updated
102. By Robert Bruce Park

Cleanup API as per Martin Pitt's requests.

Revision history for this message
Robert Bruce Park (robru) wrote :

Ok pitti, I think you should find this to your liking now. I even expanded the test coverage a little ;-)

review: Approve
Revision history for this message
Martin Pitt (pitti) wrote :

This looks good, thanks! I cleaned up the test cases a bit, and added some documentation/docstrings:

  http://bazaar.launchpad.net/~pitti/python-dbusmock/trunk/revision/100

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'dbusmock/mockobject.py'
2--- dbusmock/mockobject.py 2012-12-19 14:54:18 +0000
3+++ dbusmock/mockobject.py 2013-01-16 02:34:20 +0000
4@@ -69,6 +69,7 @@
5 self.logfile = open(logfile, 'w')
6 else:
7 self.logfile = None
8+ self.call_log = []
9
10 def __del__(self):
11 if self.logfile:
12@@ -344,6 +345,27 @@
13
14 dbus_fn(self, *args)
15
16+ @dbus.service.method(MOCK_IFACE,
17+ in_signature='',
18+ out_signature='a(tsav)')
19+ def GetCalls(self):
20+ '''List all the logged calls since the last call to ClearCalls.'''
21+ return self.call_log
22+
23+ @dbus.service.method(MOCK_IFACE,
24+ in_signature='s',
25+ out_signature='a(tav)')
26+ def GetMethodCalls(self, method):
27+ '''List all the logged calls of a particular method.'''
28+ return [(row[0], row[2]) for row in self.call_log if row[1] == method]
29+
30+ @dbus.service.method(MOCK_IFACE,
31+ in_signature='',
32+ out_signature='')
33+ def ClearCalls(self):
34+ '''Empty the log of mock call signatures'''
35+ self.call_log = []
36+
37 def mock_method(self, interface, dbus_method, in_signature, *args, **kwargs):
38 '''Master mock method.
39
40@@ -362,6 +384,7 @@
41 args = m.get_args_list()
42
43 self.log(dbus_method + self.format_args(args))
44+ self.call_log.append((int(time.time()), str(dbus_method), args))
45
46 code = self.methods[interface][dbus_method][2]
47 if code:
48
49=== modified file 'tests/test_api.py'
50--- tests/test_api.py 2012-12-19 11:44:13 +0000
51+++ tests/test_api.py 2013-01-16 02:34:20 +0000
52@@ -414,6 +414,53 @@
53 check('i', ['hello'], 'TypeError: an integer is required')
54 check('s', [1], 'TypeError: Expected a string')
55
56+ def test_dbus_get_log(self):
57+ '''Ensure that the logs can be queried over DBus.'''
58+
59+ self.dbus_mock.AddMethod('', 'Do', '', '', '')
60+ self.assertEqual(self.dbus_test.Do(), None)
61+ mock_log = self.dbus_mock.GetCalls()
62+ self.assertEqual(len(mock_log), 1)
63+ self.assertTrue('Do' in mock_log[0])
64+ self.assertEqual(self.dbus_mock.ClearCalls(), None)
65+ self.assertEqual(self.dbus_mock.GetCalls(), dbus.Array([]))
66+
67+ self.dbus_mock.AddMethod('', 'Wop', 's', 's', 'ret="hello"')
68+ self.assertEqual(self.dbus_test.Wop('foo'), 'hello')
69+ self.assertEqual(self.dbus_test.Wop('bar'), 'hello')
70+ mock_log = self.dbus_mock.GetCalls()
71+ self.assertEqual(len(mock_log), 2)
72+ self.assertTrue('Wop' in mock_log[0])
73+ self.assertTrue('foo' in mock_log[0][2])
74+ self.assertTrue('Wop' in mock_log[1])
75+ self.assertTrue('bar' in mock_log[1][2])
76+ self.assertEqual(self.dbus_mock.ClearCalls(), None)
77+ self.assertEqual(self.dbus_mock.GetCalls(), dbus.Array([]))
78+
79+ def test_dbus_get_method_calls(self):
80+ '''Ensure that the logs can be queried over DBus.'''
81+
82+ self.dbus_mock.AddMethod('', 'Do', '', '', '')
83+ self.assertEqual(self.dbus_test.Do(), None)
84+ self.assertEqual(self.dbus_test.Do(), None)
85+ mock_calls = self.dbus_mock.GetMethodCalls('Do')
86+ self.assertEqual(len(mock_calls), 2)
87+ self.assertEqual(mock_calls[0][1], [])
88+ self.assertEqual(mock_calls[1][1], [])
89+ self.assertEqual(self.dbus_mock.ClearCalls(), None)
90+ self.assertEqual(self.dbus_mock.GetMethodCalls('Do'), dbus.Array([]))
91+
92+ self.dbus_mock.AddMethod('', 'Wop', 's', 's', 'ret="hello"')
93+ self.assertEqual(self.dbus_test.Do(), None)
94+ self.assertEqual(self.dbus_test.Wop('foo'), 'hello')
95+ self.assertEqual(self.dbus_test.Wop('bar'), 'hello')
96+ mock_calls = self.dbus_mock.GetMethodCalls('Wop')
97+ self.assertEqual(len(mock_calls), 2)
98+ self.assertEqual(mock_calls[0][1], ['foo'])
99+ self.assertEqual(mock_calls[1][1], ['bar'])
100+ self.assertEqual(self.dbus_mock.ClearCalls(), None)
101+ self.assertEqual(self.dbus_mock.GetMethodCalls('Wop'), [])
102+
103 if __name__ == '__main__':
104 # avoid writing to stderr
105 unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2))

Subscribers

People subscribed via source and target branches

to all changes: