Merge lp:~chipaca/ubuntu-push/simple-bus-interface into lp:ubuntu-push

Proposed by John Lenton
Status: Merged
Approved by: John Lenton
Approved revision: 14
Merged at revision: 10
Proposed branch: lp:~chipaca/ubuntu-push/simple-bus-interface
Merge into: lp:ubuntu-push
Diff against target: 837 lines (+744/-4)
12 files modified
.bzrignore (+1/-0)
Makefile (+5/-4)
bus/bus.go (+87/-0)
bus/bus_test.go (+67/-0)
bus/endpoint.go (+121/-0)
bus/endpoint_test.go (+32/-0)
bus/testing/testing_bus.go (+63/-0)
bus/testing/testing_endpoint.go (+76/-0)
bus/testing/testing_endpoint_test.go (+73/-0)
dependencies.tsv (+1/-0)
testing/condition/condition.go (+142/-0)
testing/condition/condition_test.go (+76/-0)
To merge this branch: bzr merge lp:~chipaca/ubuntu-push/simple-bus-interface
Reviewer Review Type Date Requested Status
Samuele Pedroni Approve
Review via email: mp+202241@code.launchpad.net

Commit message

A simplified (and more testable) dbus api

Description of the change

A very simple interface to dbus, probably not usable outside of what
we need to do. Aiming at being easier to test things that use it.

To post a comment you must log in.
Revision history for this message
Samuele Pedroni (pedronis) wrote :

this is needed (godeps doesn't grab things just fixes revnos):

 -GODEPS = launchpad.net/gocheck
+GODEPS = launchpad.net/gocheck launchpad.net/go-dbus/v1

wondering if

type Bus dbs.StandardBus

wouldn't be a more natural encapsulation?

TestConnect needs to defer .Close

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

+ conn.log.Errorf("Got not-OK from %s watch", member)

is this really a error situation? or just expected and then should be a Debugf

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

does connection need to be its own package? calling Interface interface is a bit atypical, compare with stdlib net for example, in general wondering when the concrete type should have the less nice name and the interface should have the name of the concrete type

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

I would have at least one more

0 + // c.Check(cond.OK(), gocheck.Equals, true)

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

you don't need the _ in _iter

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

go doesn't care too much about order, readers a bit more,

I think typical declaration order is

type,

new function(s),

methods,

here sometimes I see

new function(s)

type

this confused me a couple of times, especially when type is something like work

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

test suites are wrongly named sometimes, like I see

NMTSuite

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

I see:

bus/connection/testing/testing_test.go:type NMTSuite struct{}

bus/connection/connection_test.go:type BusSuite struct {

Revision history for this message
John Lenton (chipaca) wrote :

☑ GODEPS.
☑ bus type encapsulation (nice suggestion, switching to that)
☑ Deferred the close.
☐ I believe that that error is a sign of something Really Bad happening outside of this service, so I wanted to log it as early as possible and as loudly as possible.
☐ connection does not need its own package; if you can suggest a naming scheme that works for the callee, I'll switch (have tried several things already---but I do suck at naming remember) will discuss more on IRC.
☐ the _ in _iter is to signal to the reader that it is a minor detail (in a more dynamic language it wouldn't even be there). I could probably move it out into its own little file to make it invisible (like I did with networkmanager's state).
☑ I was wondering about the order. Thanks.
☑ Good catch about NMTSuite. Signs of bits I missed during refactoring (there are probably more of these).

Revision history for this message
Samuele Pedroni (pedronis) :
review: Approve
Revision history for this message
Ubuntu One Auto Pilot (otto-pilot) wrote :

The attempt to merge lp:~chipaca/ubuntu-push/simple-bus-interface into lp:ubuntu-push failed. Below is the output from the failed tests.

mkdir -p /mnt/tarmac/cache/ubuntu-push/go-ws/bin
mkdir -p /mnt/tarmac/cache/ubuntu-push/go-ws/pkg
go get -u launchpad.net/godeps
go get -d -u launchpad.net/gocheck launchpad.net/go-dbus/v1
/mnt/tarmac/cache/ubuntu-push/go-ws/bin/godeps -u dependencies.tsv
go install launchpad.net/gocheck launchpad.net/go-dbus/v1
go test launchpad.net/ubuntu-push/...
ok launchpad.net/ubuntu-push/bus 0.014s
ok launchpad.net/ubuntu-push/bus/testing 0.024s
ok launchpad.net/ubuntu-push/config 0.007s
ok launchpad.net/ubuntu-push/logger 0.007s
ok launchpad.net/ubuntu-push/protocol 0.010s
ok launchpad.net/ubuntu-push/server/acceptance 0.011s
? launchpad.net/ubuntu-push/server/acceptance/cmd [no test files]
ok launchpad.net/ubuntu-push/server/api 0.014s
ok launchpad.net/ubuntu-push/server/broker 0.013s
ok launchpad.net/ubuntu-push/server/dev 0.015s
ok launchpad.net/ubuntu-push/server/listener 0.400s
ok launchpad.net/ubuntu-push/server/session 0.086s
ok launchpad.net/ubuntu-push/server/store 0.006s
? launchpad.net/ubuntu-push/testing [no test files]
ok launchpad.net/ubuntu-push/testing/condition 0.005s
ok launchpad.net/ubuntu-push/whoopsie/identifier 0.017s
ok launchpad.net/ubuntu-push/whoopsie/identifier/testing 0.010s
scripts/check_fmt launchpad.net/ubuntu-push
pkg launchpad.net/ubuntu-push/bus has some gofmt non-compliant files:
bus.go
endpoint.go
endpoint_test.go

pkg launchpad.net/ubuntu-push/bus/testing has some gofmt non-compliant files:
testing_bus.go
testing_endpoint.go

make: *** [check-format] Error 1

14. By John Lenton

make format

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2014-01-14 15:35:20 +0000
3+++ .bzrignore 2014-01-20 13:45:30 +0000
4@@ -1,3 +1,4 @@
5 acceptanceclient
6 testserver
7 coverhtml
8+coverage.out
9
10=== modified file 'Makefile'
11--- Makefile 2014-01-16 19:37:57 +0000
12+++ Makefile 2014-01-20 13:45:30 +0000
13@@ -8,6 +8,7 @@
14 endif
15
16 GODEPS = launchpad.net/gocheck
17+GODEPS += launchpad.net/go-dbus/v1
18
19 bootstrap:
20 mkdir -p $(GOPATH)/bin
21@@ -18,20 +19,20 @@
22 go install $(GODEPS)
23
24 check:
25- go test $(PROJECT)/...
26+ go test $(TESTFLAGS) $(PROJECT)/...
27
28 check-race:
29- go test -race $(PROJECT)/...
30+ go test $(TESTFLAGS) -race $(PROJECT)/...
31
32 coverage-summary:
33- go test -a -cover $(PROJECT)/...
34+ go test $(TESTFLAGS) -a -cover $(PROJECT)/...
35
36 coverage-html:
37 mkdir -p coverhtml
38 for pkg in $$(go list $(PROJECT)/...|grep -v acceptance ); do \
39 relname="$${pkg#$(PROJECT)/}" ; \
40 mkdir -p coverhtml/$$(dirname $${relname}) ; \
41- go test -a -coverprofile=coverhtml/$${relname}.out $$pkg ; \
42+ go test $(TESTFLAGS) -a -coverprofile=coverhtml/$${relname}.out $$pkg ; \
43 if [ -f coverhtml/$${relname}.out ] ; then \
44 go tool cover -html=coverhtml/$${relname}.out -o coverhtml/$${relname}.html ; \
45 go tool cover -func=coverhtml/$${relname}.out -o coverhtml/$${relname}.txt ; \
46
47=== added directory 'bus'
48=== added file 'bus/bus.go'
49--- bus/bus.go 1970-01-01 00:00:00 +0000
50+++ bus/bus.go 2014-01-20 13:45:30 +0000
51@@ -0,0 +1,87 @@
52+/*
53+ Copyright 2013-2014 Canonical Ltd.
54+
55+ This program is free software: you can redistribute it and/or modify it
56+ under the terms of the GNU General Public License version 3, as published
57+ by the Free Software Foundation.
58+
59+ This program is distributed in the hope that it will be useful, but
60+ WITHOUT ANY WARRANTY; without even the implied warranties of
61+ MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
62+ PURPOSE. See the GNU General Public License for more details.
63+
64+ You should have received a copy of the GNU General Public License along
65+ with this program. If not, see <http://www.gnu.org/licenses/>.
66+*/
67+
68+// Package bus provides a simplified (and more testable?) interface to DBus.
69+package bus
70+
71+// Here we define the Bus itself
72+
73+import (
74+ "launchpad.net/go-dbus/v1"
75+ "launchpad.net/ubuntu-push/logger"
76+)
77+
78+/*****************************************************************
79+ * Bus (and its implementation)
80+ */
81+
82+// This is the Bus itself.
83+type Bus interface {
84+ String() string
85+ Connect(Address, logger.Logger) (Endpoint, error)
86+}
87+
88+type concreteBus dbus.StandardBus
89+
90+// ensure concreteBus implements Bus
91+var _ Bus = new(concreteBus)
92+
93+// no bus.Bus constructor, just two standard, constant, busses
94+var (
95+ SessionBus Bus = concreteBus(dbus.SessionBus)
96+ SystemBus Bus = concreteBus(dbus.SystemBus)
97+)
98+
99+/*
100+ public methods
101+*/
102+
103+func (bus concreteBus) String() string {
104+ if bus == concreteBus(dbus.SystemBus) {
105+ return "SystemBus"
106+ } else {
107+ return "SessionBus"
108+ }
109+}
110+
111+// Connect() connects to the bus, and returns the bus endpoint (and/or error).
112+func (bus concreteBus) Connect(addr Address, log logger.Logger) (Endpoint, error) {
113+ conn, err := dbus.Connect(bus.dbusType())
114+ if err != nil {
115+ return nil, err
116+ } else {
117+ return &endpoint{conn, addr.Name, addr.Path, addr.Interface, log}, nil
118+ }
119+}
120+
121+/*
122+ private methods
123+*/
124+
125+func (bus concreteBus) dbusType() dbus.StandardBus {
126+ return dbus.StandardBus(bus)
127+}
128+
129+/*****************************************************************
130+ * Address
131+ */
132+
133+// bus.Address is just a bag of configuration
134+type Address struct {
135+ Name string
136+ Path string
137+ Interface string
138+}
139
140=== added file 'bus/bus_test.go'
141--- bus/bus_test.go 1970-01-01 00:00:00 +0000
142+++ bus/bus_test.go 2014-01-20 13:45:30 +0000
143@@ -0,0 +1,67 @@
144+/*
145+ Copyright 2013-2014 Canonical Ltd.
146+
147+ This program is free software: you can redistribute it and/or modify it
148+ under the terms of the GNU General Public License version 3, as published
149+ by the Free Software Foundation.
150+
151+ This program is distributed in the hope that it will be useful, but
152+ WITHOUT ANY WARRANTY; without even the implied warranties of
153+ MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
154+ PURPOSE. See the GNU General Public License for more details.
155+
156+ You should have received a copy of the GNU General Public License along
157+ with this program. If not, see <http://www.gnu.org/licenses/>.
158+*/
159+
160+package bus
161+
162+import (
163+ "fmt"
164+ "io/ioutil"
165+ "launchpad.net/go-dbus/v1"
166+ . "launchpad.net/gocheck"
167+ "launchpad.net/ubuntu-push/logger"
168+ "os"
169+ "testing"
170+)
171+
172+// hook up gocheck
173+func Test(t *testing.T) { TestingT(t) }
174+
175+type BusSuite struct{}
176+
177+var nullog = logger.NewSimpleLogger(ioutil.Discard, "error")
178+var _ = Suite(&BusSuite{})
179+
180+// Test we stringify sanely
181+func (s *BusSuite) TestBusType(c *C) {
182+ c.Check(fmt.Sprintf("%s", SystemBus), Equals, "SystemBus")
183+ c.Check(fmt.Sprintf("%s", SessionBus), Equals, "SessionBus")
184+}
185+
186+// Test we get the right DBus bus
187+func (s *BusSuite) TestDBusType(c *C) {
188+ c.Check(SystemBus.(concreteBus).dbusType(), DeepEquals, dbus.SystemBus)
189+ c.Check(SessionBus.(concreteBus).dbusType(), DeepEquals, dbus.SessionBus)
190+}
191+
192+// Tests that we can connect to the *actual* system bus.
193+// XXX maybe connect to a mock/fake/etc bus?
194+func (s *BusSuite) TestConnect(c *C) {
195+ b, err := SystemBus.Connect(Address{"", "", ""}, nullog)
196+ c.Assert(err, IsNil)
197+ defer b.Close()
198+}
199+
200+// Test that if we try to connect to the session bus when no session
201+// bus is available, we get a reasonable result (i.e., an error).
202+func (s *BusSuite) TestConnectCanFail(c *C) {
203+ db := "DBUS_SESSION_BUS_ADDRESS"
204+ odb := os.Getenv(db)
205+ defer os.Setenv(db, odb)
206+ os.Setenv(db, "")
207+
208+ _, err := SessionBus.Connect(Address{"", "", ""}, nullog)
209+ c.Check(err, NotNil)
210+}
211
212=== added file 'bus/endpoint.go'
213--- bus/endpoint.go 1970-01-01 00:00:00 +0000
214+++ bus/endpoint.go 2014-01-20 13:45:30 +0000
215@@ -0,0 +1,121 @@
216+/*
217+ Copyright 2013-2014 Canonical Ltd.
218+
219+ This program is free software: you can redistribute it and/or modify it
220+ under the terms of the GNU General Public License version 3, as published
221+ by the Free Software Foundation.
222+
223+ This program is distributed in the hope that it will be useful, but
224+ WITHOUT ANY WARRANTY; without even the implied warranties of
225+ MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
226+ PURPOSE. See the GNU General Public License for more details.
227+
228+ You should have received a copy of the GNU General Public License along
229+ with this program. If not, see <http://www.gnu.org/licenses/>.
230+*/
231+
232+package bus
233+
234+// Here we define the Endpoint, which represents the DBus connection itself.
235+
236+import (
237+ "launchpad.net/go-dbus/v1"
238+ "launchpad.net/ubuntu-push/logger"
239+)
240+
241+/*****************************************************************
242+ * Endpoint (and its implementation)
243+ */
244+
245+// bus.Endpoint represents the DBus connection itself.
246+type Endpoint interface {
247+ WatchSignal(member string, f func(interface{}), d func()) error
248+ Call(member string, args ...interface{}) (interface{}, error)
249+ Close()
250+}
251+
252+type endpoint struct {
253+ bus *dbus.Connection
254+ name string
255+ path string
256+ iface string
257+ log logger.Logger
258+}
259+
260+// ensure endpoint implements Endpoint
261+var _ Endpoint = endpoint{}
262+
263+/*
264+ public methods
265+*/
266+
267+// WatchSignal() takes a member name and sets up a watch for it (on the name,
268+// path and interface provided when creating the endpoint), and then calls f()
269+// with the unpacked value. If it's unable to set up the watch it'll return an
270+// error. If the watch fails once established, d() is called. Typically f()
271+// sends the values over a channel, and d() would close the channel.
272+func (endp endpoint) WatchSignal(member string, f func(interface{}), d func()) error {
273+ watch, err := endp.bus.WatchSignal(&dbus.MatchRule{
274+ Type: dbus.TypeSignal,
275+ Sender: endp.name,
276+ Path: dbus.ObjectPath(endp.path),
277+ Interface: endp.iface,
278+ Member: member,
279+ })
280+ if err != nil {
281+ endp.log.Debugf("Failed to set up the watch: %s", err)
282+ return err
283+ }
284+
285+ go endp.unpackMessages(watch, f, d, member)
286+
287+ return nil
288+}
289+
290+// Call() invokes the provided member method (on the name, path and interface
291+// provided when creating the endpoint). The return value is unpacked before
292+// being returned.
293+func (endp endpoint) Call(member string, args ...interface{}) (interface{}, error) {
294+ proxy := endp.bus.Object(endp.name, dbus.ObjectPath(endp.path))
295+ if msg, err := proxy.Call(endp.iface, member, args...); err == nil {
296+ return endp.unpackOneMsg(msg, member)
297+ } else {
298+ return 0, err
299+ }
300+}
301+
302+// Close the connection to dbus.
303+func (endp endpoint) Close() {
304+ endp.bus.Close()
305+}
306+
307+/*
308+ private methods
309+*/
310+
311+// unpackOneMsg unpacks the value from the response msg
312+func (endp endpoint) unpackOneMsg(msg *dbus.Message, member string) (interface{}, error) {
313+ var v interface{}
314+ if err := msg.Args(&v); err != nil {
315+ endp.log.Errorf("Decoding %s: %s", member, err)
316+ return 0, err
317+ } else {
318+ return v, nil
319+ }
320+}
321+
322+// unpackMessages unpacks the value from the watch
323+func (endp endpoint) unpackMessages(watch *dbus.SignalWatch, f func(interface{}), d func(), member string) {
324+ for {
325+ msg, ok := <-watch.C
326+ if !ok {
327+ break
328+ }
329+ if val, err := endp.unpackOneMsg(msg, member); err == nil {
330+ // errors are ignored at this level
331+ f(val)
332+ }
333+ }
334+ endp.log.Errorf("Got not-OK from %s watch", member)
335+ d()
336+}
337
338=== added file 'bus/endpoint_test.go'
339--- bus/endpoint_test.go 1970-01-01 00:00:00 +0000
340+++ bus/endpoint_test.go 2014-01-20 13:45:30 +0000
341@@ -0,0 +1,32 @@
342+/*
343+ Copyright 2013-2014 Canonical Ltd.
344+
345+ This program is free software: you can redistribute it and/or modify it
346+ under the terms of the GNU General Public License version 3, as published
347+ by the Free Software Foundation.
348+
349+ This program is distributed in the hope that it will be useful, but
350+ WITHOUT ANY WARRANTY; without even the implied warranties of
351+ MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
352+ PURPOSE. See the GNU General Public License for more details.
353+
354+ You should have received a copy of the GNU General Public License along
355+ with this program. If not, see <http://www.gnu.org/licenses/>.
356+*/
357+
358+package bus
359+
360+import (
361+ . "launchpad.net/gocheck"
362+ "testing"
363+)
364+
365+// hook up gocheck
366+func EndpointTest(t *testing.T) { TestingT(t) }
367+
368+type EndpointSuite struct{}
369+
370+var _ = Suite(&EndpointSuite{})
371+
372+// TODO: this is going to remain empty until go-dbus grows some
373+// testing amenities (already talked about it with jamesh)
374
375=== added directory 'bus/testing'
376=== added file 'bus/testing/testing_bus.go'
377--- bus/testing/testing_bus.go 1970-01-01 00:00:00 +0000
378+++ bus/testing/testing_bus.go 2014-01-20 13:45:30 +0000
379@@ -0,0 +1,63 @@
380+/*
381+ Copyright 2013-2014 Canonical Ltd.
382+
383+ This program is free software: you can redistribute it and/or modify it
384+ under the terms of the GNU General Public License version 3, as published
385+ by the Free Software Foundation.
386+
387+ This program is distributed in the hope that it will be useful, but
388+ WITHOUT ANY WARRANTY; without even the implied warranties of
389+ MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
390+ PURPOSE. See the GNU General Public License for more details.
391+
392+ You should have received a copy of the GNU General Public License along
393+ with this program. If not, see <http://www.gnu.org/licenses/>.
394+*/
395+
396+// Package bus/testing provides an implementation of bus.Bus and bus.Endpoint
397+// suitable for testing.
398+package testing
399+
400+// Here, the bus.Bus implementation.
401+
402+import (
403+ "errors"
404+ "launchpad.net/ubuntu-push/bus"
405+ "launchpad.net/ubuntu-push/logger"
406+ "launchpad.net/ubuntu-push/testing/condition"
407+)
408+
409+/*****************************************************************
410+ * TestingBus
411+ */
412+
413+type testingBus struct {
414+ TestCond condition.Interface
415+ TestEndp *testingEndpoint
416+}
417+
418+// Build a bus.Bus that takes a condition to determine whether it should work,
419+// as well as a condition and series of return values for the testing
420+// bus.Endpoint it builds.
421+func NewTestingBus(clientTC condition.Interface, busTC condition.Interface, retvals ...interface{}) *testingBus {
422+ return &testingBus{clientTC, NewTestingEndpoint(busTC, retvals...)}
423+}
424+
425+// ensure testingBus implements bus.Interface
426+var _ bus.Bus = &testingBus{}
427+
428+/*
429+ public methods
430+*/
431+
432+func (tb *testingBus) Connect(info bus.Address, log logger.Logger) (bus.Endpoint, error) {
433+ if tb.TestCond.OK() {
434+ return tb.TestEndp, nil
435+ } else {
436+ return nil, errors.New(tb.TestCond.String())
437+ }
438+}
439+
440+func (tb *testingBus) String() string {
441+ return "<TestingBus>"
442+}
443
444=== added file 'bus/testing/testing_endpoint.go'
445--- bus/testing/testing_endpoint.go 1970-01-01 00:00:00 +0000
446+++ bus/testing/testing_endpoint.go 2014-01-20 13:45:30 +0000
447@@ -0,0 +1,76 @@
448+/*
449+ Copyright 2013-2014 Canonical Ltd.
450+
451+ This program is free software: you can redistribute it and/or modify it
452+ under the terms of the GNU General Public License version 3, as published
453+ by the Free Software Foundation.
454+
455+ This program is distributed in the hope that it will be useful, but
456+ WITHOUT ANY WARRANTY; without even the implied warranties of
457+ MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
458+ PURPOSE. See the GNU General Public License for more details.
459+
460+ You should have received a copy of the GNU General Public License along
461+ with this program. If not, see <http://www.gnu.org/licenses/>.
462+*/
463+
464+package testing
465+
466+// Here, the bus.Endpoint implementation.
467+
468+import (
469+ "errors"
470+ "launchpad.net/ubuntu-push/bus"
471+ "launchpad.net/ubuntu-push/testing/condition"
472+ "time"
473+)
474+
475+type testingEndpoint struct {
476+ cond condition.Interface
477+ retvals []interface{}
478+}
479+
480+// Build a bus.Endpoint that calls OK() on its condition before returning
481+// the provided return values.
482+//
483+// NOTE: Call() always returns the first return value; Watch() will provide
484+// each of them intern, irrespective of whether Call has been called.
485+func NewTestingEndpoint(cond condition.Interface, retvals ...interface{}) *testingEndpoint {
486+ return &testingEndpoint{cond, retvals}
487+}
488+
489+// See Endpoint's WatchSignal. This WatchSignal will check its condition to
490+// decide whether to return an error, or provide each of its return values
491+func (tc *testingEndpoint) WatchSignal(member string, f func(interface{}), d func()) error {
492+ if tc.cond.OK() {
493+ go func() {
494+ for _, v := range tc.retvals {
495+ f(v)
496+ time.Sleep(10 * time.Millisecond)
497+ }
498+ d()
499+ }()
500+ return nil
501+ } else {
502+ return errors.New("no way")
503+ }
504+}
505+
506+// See Endpoint's Call. This Call will check its condition to decide whether
507+// to return an error, or the first of its return values
508+func (tc *testingEndpoint) Call(member string, args ...interface{}) (interface{}, error) {
509+ if tc.cond.OK() {
510+ if len(tc.retvals) == 0 {
511+ panic("No return values provided!")
512+ }
513+ return tc.retvals[0], nil
514+ } else {
515+ return 0, errors.New("no way")
516+ }
517+}
518+
519+// see Endpoint's Close. This one does nothing.
520+func (tc *testingEndpoint) Close() {}
521+
522+// ensure testingEndpoint implements bus.Endpoint
523+var _ bus.Endpoint = &testingEndpoint{}
524
525=== added file 'bus/testing/testing_endpoint_test.go'
526--- bus/testing/testing_endpoint_test.go 1970-01-01 00:00:00 +0000
527+++ bus/testing/testing_endpoint_test.go 2014-01-20 13:45:30 +0000
528@@ -0,0 +1,73 @@
529+/*
530+ Copyright 2013-2014 Canonical Ltd.
531+
532+ This program is free software: you can redistribute it and/or modify it
533+ under the terms of the GNU General Public License version 3, as published
534+ by the Free Software Foundation.
535+
536+ This program is distributed in the hope that it will be useful, but
537+ WITHOUT ANY WARRANTY; without even the implied warranties of
538+ MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
539+ PURPOSE. See the GNU General Public License for more details.
540+
541+ You should have received a copy of the GNU General Public License along
542+ with this program. If not, see <http://www.gnu.org/licenses/>.
543+*/
544+
545+package testing
546+
547+import (
548+ . "launchpad.net/gocheck"
549+ "launchpad.net/ubuntu-push/testing/condition"
550+ "testing"
551+)
552+
553+// hook up gocheck
554+func Test(t *testing.T) { TestingT(t) }
555+
556+type TestingEndpointSuite struct{}
557+
558+var _ = Suite(&TestingEndpointSuite{})
559+
560+// Test that Call() with a positive condition returns the first return value
561+// provided, as advertised.
562+func (s *TestingEndpointSuite) TestCallReturnsFirstRetval(c *C) {
563+ var m, n uint32 = 42, 17
564+ endp := NewTestingEndpoint(condition.Work(true), m, n)
565+ v, e := endp.Call("what")
566+ c.Check(e, IsNil)
567+ c.Check(v, Equals, m)
568+}
569+
570+// Test that Call() with a negative condition returns an error.
571+func (s *TestingEndpointSuite) TestCallFails(c *C) {
572+ endp := NewTestingEndpoint(condition.Work(false))
573+ _, e := endp.Call("what")
574+ c.Check(e, NotNil)
575+}
576+
577+// Test that Call() with a positive condition and no return values panics with
578+// a helpful message.
579+func (s *TestingEndpointSuite) TestCallPanicsWithNiceMessage(c *C) {
580+ endp := NewTestingEndpoint(condition.Work(true))
581+ c.Check(func() { endp.Call("") }, PanicMatches, "No return values provided!")
582+}
583+
584+// Test that WatchSignal() with a positive condition sends the provided return
585+// values over the channel.
586+func (s *TestingEndpointSuite) TestWatch(c *C) {
587+ var m, n uint32 = 42, 17
588+ endp := NewTestingEndpoint(condition.Work(true), m, n)
589+ ch := make(chan uint32)
590+ e := endp.WatchSignal("what", func(u interface{}) { ch <- u.(uint32) }, func() { close(ch) })
591+ c.Check(e, IsNil)
592+ c.Check(<-ch, Equals, m)
593+ c.Check(<-ch, Equals, n)
594+}
595+
596+// Test that WatchSignal() with a negative condition returns an error.
597+func (s *TestingEndpointSuite) TestWatchFails(c *C) {
598+ endp := NewTestingEndpoint(condition.Work(false))
599+ e := endp.WatchSignal("what", func(u interface{}) {}, func() {})
600+ c.Check(e, NotNil)
601+}
602
603=== modified file 'dependencies.tsv'
604--- dependencies.tsv 2014-01-14 15:35:20 +0000
605+++ dependencies.tsv 2014-01-20 13:45:30 +0000
606@@ -1,1 +1,2 @@
607+launchpad.net/go-dbus/v1 bzr james@jamesh.id.au-20140117100040-mmhdtiz5w9pxqtcr 124
608 launchpad.net/gocheck bzr gustavo@niemeyer.net-20130302024745-6ikofwq2c03h7giu 85
609
610=== added directory 'testing/condition'
611=== added file 'testing/condition/condition.go'
612--- testing/condition/condition.go 1970-01-01 00:00:00 +0000
613+++ testing/condition/condition.go 2014-01-20 13:45:30 +0000
614@@ -0,0 +1,142 @@
615+/*
616+ Copyright 2013-2014 Canonical Ltd.
617+
618+ This program is free software: you can redistribute it and/or modify it
619+ under the terms of the GNU General Public License version 3, as published
620+ by the Free Software Foundation.
621+
622+ This program is distributed in the hope that it will be useful, but
623+ WITHOUT ANY WARRANTY; without even the implied warranties of
624+ MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
625+ PURPOSE. See the GNU General Public License for more details.
626+
627+ You should have received a copy of the GNU General Public License along
628+ with this program. If not, see <http://www.gnu.org/licenses/>.
629+*/
630+
631+// Package testing/condition implements a strategy family for use in testing.
632+package condition
633+
634+import (
635+ "fmt"
636+ "strings"
637+)
638+
639+type Interface interface {
640+ OK() bool
641+ String() string
642+}
643+
644+// Work is a simple boolean condition; either it works all the time
645+// (when true), or it fails all the time (when false).
646+func Work(wk bool) work {
647+ return work(wk)
648+}
649+
650+type work bool
651+
652+func (c work) OK() bool {
653+ if c {
654+ return true
655+ } else {
656+ return false
657+ }
658+}
659+func (c work) String() string {
660+ if c {
661+ return "Always Working."
662+ } else {
663+ return "Never Working."
664+ }
665+}
666+
667+var _ Interface = work(false)
668+
669+// Fail2Work fails for the first n times its OK() method is checked,
670+// and then mysteriously starts working.
671+func Fail2Work(left int32) *fail2Work {
672+ c := new(fail2Work)
673+ c.Left = left
674+ return c
675+}
676+
677+type fail2Work struct {
678+ Left int32
679+}
680+
681+func (c *fail2Work) OK() bool {
682+ if c.Left > 0 {
683+ c.Left--
684+ return false
685+ } else {
686+ return true
687+ }
688+}
689+
690+func (c *fail2Work) String() string {
691+ if c.Left > 0 {
692+ return fmt.Sprintf("Still Broken, %d to go.", c.Left)
693+ } else {
694+ return "Working."
695+ }
696+}
697+
698+var _ Interface = &fail2Work{}
699+
700+// Not builds a condition that negates the one passed in.
701+func Not(sub Interface) *not {
702+ return &not{sub}
703+}
704+
705+type not struct{ sub Interface }
706+
707+func (c *not) OK() bool { return !c.sub.OK() }
708+func (c *not) String() string { return fmt.Sprintf("Not %s", c.sub) }
709+
710+var _ Interface = &not{}
711+
712+type _iter struct {
713+ cond Interface
714+ remaining int
715+}
716+
717+func (i _iter) String() string { return fmt.Sprintf("%d of %s", i.remaining, i.cond) }
718+
719+type chain struct {
720+ subs []*_iter
721+}
722+
723+func (c *chain) OK() bool {
724+ var sub *_iter
725+ for _, sub = range c.subs {
726+ if sub.remaining > 0 {
727+ sub.remaining--
728+ return sub.cond.OK()
729+ }
730+ }
731+ return sub.cond.OK()
732+}
733+
734+func (c *chain) String() string {
735+ ss := make([]string, len(c.subs))
736+ for i, sub := range c.subs {
737+ ss[i] = sub.String()
738+ }
739+ return strings.Join(ss, " Then: ")
740+}
741+
742+var _ Interface = new(chain)
743+
744+// Chain(n1, cond1, n2, cond2, ...) returns cond1.OK() the first n1
745+// times OK() is called, cond2.OK() the following n2 times, etc.
746+func Chain(args ...interface{}) *chain {
747+ iters := make([]*_iter, 0, len(args)/2)
748+ for len(args) > 1 {
749+ rem := args[0].(int)
750+ sub := args[1].(Interface)
751+ iters = append(iters, &_iter{sub, rem})
752+ args = args[2:]
753+ }
754+
755+ return &chain{iters}
756+}
757
758=== added file 'testing/condition/condition_test.go'
759--- testing/condition/condition_test.go 1970-01-01 00:00:00 +0000
760+++ testing/condition/condition_test.go 2014-01-20 13:45:30 +0000
761@@ -0,0 +1,76 @@
762+/*
763+ Copyright 2013-2014 Canonical Ltd.
764+
765+ This program is free software: you can redistribute it and/or modify it
766+ under the terms of the GNU General Public License version 3, as published
767+ by the Free Software Foundation.
768+
769+ This program is distributed in the hope that it will be useful, but
770+ WITHOUT ANY WARRANTY; without even the implied warranties of
771+ MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
772+ PURPOSE. See the GNU General Public License for more details.
773+
774+ You should have received a copy of the GNU General Public License along
775+ with this program. If not, see <http://www.gnu.org/licenses/>.
776+*/
777+
778+package condition
779+
780+import (
781+ "launchpad.net/gocheck" // not into . because we have our own Not
782+ "testing"
783+)
784+
785+// hook up gocheck
786+func Test(t *testing.T) { gocheck.TestingT(t) }
787+
788+type CondSuite struct{}
789+
790+var _ = gocheck.Suite(&CondSuite{})
791+
792+func (s *CondSuite) TestConditionWorkTrue(c *gocheck.C) {
793+ cond := Work(true)
794+ c.Check(cond.OK(), gocheck.Equals, true)
795+ c.Check(cond.String(), gocheck.Equals, "Always Working.")
796+}
797+
798+func (s *CondSuite) TestConditionWorkFalse(c *gocheck.C) {
799+ cond := Work(false)
800+ c.Check(cond.OK(), gocheck.Equals, false)
801+ c.Check(cond.String(), gocheck.Equals, "Never Working.")
802+}
803+
804+func (s *CondSuite) TestConditionFail2Work(c *gocheck.C) {
805+ cond := Fail2Work(2)
806+ c.Check(cond.String(), gocheck.Equals, "Still Broken, 2 to go.")
807+ c.Check(cond.OK(), gocheck.Equals, false)
808+ c.Check(cond.String(), gocheck.Equals, "Still Broken, 1 to go.")
809+ c.Check(cond.OK(), gocheck.Equals, false)
810+ c.Check(cond.String(), gocheck.Equals, "Working.")
811+ c.Check(cond.OK(), gocheck.Equals, true)
812+ c.Check(cond.String(), gocheck.Equals, "Working.")
813+ c.Check(cond.OK(), gocheck.Equals, true)
814+ c.Check(cond.String(), gocheck.Equals, "Working.")
815+}
816+
817+func (s *CondSuite) TestConditionNot(c *gocheck.C) {
818+ cond := Not(Fail2Work(1))
819+ c.Check(cond.String(), gocheck.Equals, "Not Still Broken, 1 to go.")
820+ c.Check(cond.OK(), gocheck.Equals, true)
821+ c.Check(cond.String(), gocheck.Equals, "Not Working.")
822+ c.Check(cond.OK(), gocheck.Equals, false)
823+}
824+
825+func (s *CondSuite) TestConditionChain(c *gocheck.C) {
826+ cond := Chain(2, Work(true), 3, Work(false), 0, Work(true))
827+ c.Check(cond.String(), gocheck.Equals, "2 of Always Working. Then: 3 of Never Working. Then: 0 of Always Working.")
828+ c.Check(cond.OK(), gocheck.Equals, true)
829+ c.Check(cond.OK(), gocheck.Equals, true)
830+ c.Check(cond.OK(), gocheck.Equals, false)
831+ c.Check(cond.OK(), gocheck.Equals, false)
832+ c.Check(cond.OK(), gocheck.Equals, false)
833+ c.Check(cond.OK(), gocheck.Equals, true)
834+ // c.Check(cond.OK(), gocheck.Equals, true)
835+ // c.Check(cond.OK(), gocheck.Equals, true)
836+ // c.Check(cond.OK(), gocheck.Equals, true)
837+}

Subscribers

People subscribed via source and target branches