Merge lp:~chipaca/ubuntu-push/client-v0-p9 into lp:ubuntu-push

Proposed by John Lenton
Status: Merged
Approved by: John Lenton
Approved revision: 57
Merged at revision: 50
Proposed branch: lp:~chipaca/ubuntu-push/client-v0-p9
Merge into: lp:ubuntu-push
Prerequisite: lp:~chipaca/ubuntu-push/client-v0-p5
Diff against target: 351 lines (+173/-42)
4 files modified
bus/testing/testing_endpoint.go (+14/-2)
bus/testing/testing_endpoint_test.go (+9/-0)
client/client.go (+83/-32)
client/client_test.go (+67/-8)
To merge this branch: bzr merge lp:~chipaca/ubuntu-push/client-v0-p9
Reviewer Review Type Date Requested Status
Samuele Pedroni Approve
Review via email: mp+204691@code.launchpad.net

Commit message

Several things:
* features:
  * bus/testing/'s Endpoint now tracks Calls; call bus/testing.GetCallCargs(endp) to get the list.
  * Client.handleErr, Client.handleNotification and Client.handleClick (and tests)
* cleanups:
  * renamed client's Client's connState to hasConnectivity
  * split out code from handleConnState into initSession/connectSession/disconnectSession

Description of the change

Several things:
* features:
  * bus/testing/'s Endpoint now tracks Calls; call bus/testing.GetCallCargs(endp) to get the list.
  * Client.handleErr, Client.handleNotification and Client.handleClick (and tests)
* cleanups:
  * renamed client's Client's connState to hasConnectivity
  * split out code from handleConnState into initSession/connectSession/disconnectSession

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

ok, but see bug lp:1276199 and as discussed

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bus/testing/testing_endpoint.go'
2--- bus/testing/testing_endpoint.go 2014-01-31 13:46:31 +0000
3+++ bus/testing/testing_endpoint.go 2014-02-04 14:21:43 +0000
4@@ -26,11 +26,17 @@
5 "time"
6 )
7
8+type callArgs struct {
9+ Member string
10+ Args []interface{}
11+}
12+
13 type testingEndpoint struct {
14 dialCond condition.Interface
15 callCond condition.Interface
16 retvals [][]interface{}
17 watchTicker chan bool
18+ callArgs []callArgs
19 }
20
21 // Build a bus.Endpoint that calls OK() on its condition before returning
22@@ -39,7 +45,7 @@
23 // NOTE: Call() always returns the first return value; Watch() will provide
24 // each of them in turn, irrespective of whether Call has been called.
25 func NewMultiValuedTestingEndpoint(dialCond condition.Interface, callCond condition.Interface, retvalses ...[]interface{}) bus.Endpoint {
26- return &testingEndpoint{dialCond, callCond, retvalses, nil}
27+ return &testingEndpoint{dialCond, callCond, retvalses, nil, nil}
28 }
29
30 func NewTestingEndpoint(dialCond condition.Interface, callCond condition.Interface, retvals ...interface{}) bus.Endpoint {
31@@ -47,7 +53,7 @@
32 for i, x := range retvals {
33 retvalses[i] = []interface{}{x}
34 }
35- return &testingEndpoint{dialCond, callCond, retvalses, nil}
36+ return &testingEndpoint{dialCond, callCond, retvalses, nil, nil}
37 }
38
39 // If SetWatchTicker is called with a non-nil watchTicker, it is used
40@@ -57,6 +63,11 @@
41 tc.(*testingEndpoint).watchTicker = watchTicker
42 }
43
44+// GetCallArgs returns a list of the arguments for each Call() invocation.
45+func GetCallArgs(tc bus.Endpoint) []callArgs {
46+ return tc.(*testingEndpoint).callArgs
47+}
48+
49 // See Endpoint's WatchSignal. This WatchSignal will check its condition to
50 // decide whether to return an error, or provide each of its return values
51 func (tc *testingEndpoint) WatchSignal(member string, f func(...interface{}), d func()) error {
52@@ -81,6 +92,7 @@
53 // See Endpoint's Call. This Call will check its condition to decide whether
54 // to return an error, or the first of its return values
55 func (tc *testingEndpoint) Call(member string, args ...interface{}) ([]interface{}, error) {
56+ tc.callArgs = append(tc.callArgs, callArgs{member, args})
57 if tc.callCond.OK() {
58 if len(tc.retvals) == 0 {
59 panic("No return values provided!")
60
61=== modified file 'bus/testing/testing_endpoint_test.go'
62--- bus/testing/testing_endpoint_test.go 2014-01-31 13:31:09 +0000
63+++ bus/testing/testing_endpoint_test.go 2014-02-04 14:21:43 +0000
64@@ -65,6 +65,15 @@
65 c.Check(func() { endp.Call("") }, PanicMatches, "No return values provided.*")
66 }
67
68+// Test that Call() updates callArgs
69+func (s *TestingEndpointSuite) TestCallArgs(c *C) {
70+ endp := NewTestingEndpoint(nil, condition.Work(true), 0)
71+ _, err := endp.Call("what", "is", "this", "thing")
72+ c.Assert(err, IsNil)
73+ c.Check(GetCallArgs(endp), DeepEquals,
74+ []callArgs{{"what", []interface{}{"is", "this", "thing"}}})
75+}
76+
77 // Test that WatchSignal() with a positive condition sends the provided return
78 // values over the channel.
79 func (s *TestingEndpointSuite) TestWatch(c *C) {
80
81=== modified file 'client/client.go'
82--- client/client.go 2014-02-04 14:21:43 +0000
83+++ client/client.go 2014-02-04 14:21:43 +0000
84@@ -22,6 +22,7 @@
85 "encoding/pem"
86 "fmt"
87 "io/ioutil"
88+ "launchpad.net/go-dbus/v1"
89 "launchpad.net/ubuntu-push/bus"
90 "launchpad.net/ubuntu-push/bus/connectivity"
91 "launchpad.net/ubuntu-push/bus/networkmanager"
92@@ -57,7 +58,7 @@
93 urlDispatcherEndp bus.Endpoint
94 connectivityEndp bus.Endpoint
95 connCh chan bool
96- connState bool
97+ hasConnectivity bool
98 actionsCh <-chan notifications.RawActionReply
99 session *session.ClientSession
100 sessionRetrierStopper chan bool
101@@ -124,40 +125,90 @@
102 return err
103 }
104
105+// initSession creates the session object
106+func (client *Client) initSession() {
107+ sess, err := session.NewSession(string(client.config.Addr), client.pem,
108+ client.config.ExchangeTimeout.Duration, client.deviceId, client.log)
109+ if err != nil {
110+ panic("Don't know how to handle session creation failure.")
111+ }
112+ client.session = sess
113+}
114+
115+// connectSession kicks off the session connection dance
116+func (client *Client) connectSession() {
117+ if client.sessionRetrierStopper != nil {
118+ client.sessionRetrierStopper <- true
119+ client.sessionRetrierStopper = nil
120+ }
121+ ar := &util.AutoRetrier{
122+ make(chan bool, 1),
123+ client.session.Dial,
124+ util.Jitter}
125+ client.sessionRetrierStopper = ar.Stop
126+ go ar.Retry()
127+}
128+
129+// disconnectSession disconnects the session
130+func (client *Client) disconnectSession() {
131+ if client.sessionRetrierStopper != nil {
132+ client.sessionRetrierStopper <- true
133+ client.sessionRetrierStopper = nil
134+ } else {
135+ client.session.Close()
136+ }
137+}
138+
139 // handleConnState deals with connectivity events
140-func (client *Client) handleConnState(connState bool) {
141- if client.connState == connState {
142+func (client *Client) handleConnState(hasConnectivity bool) {
143+ if client.hasConnectivity == hasConnectivity {
144 // nothing to do!
145 return
146 }
147- client.connState = connState
148- if client.session == nil {
149- sess, err := session.NewSession(string(client.config.Addr), client.pem,
150- client.config.ExchangeTimeout.Duration, client.deviceId, client.log)
151- if err != nil {
152- panic("Don't know how to handle session creation failure.")
153- }
154- client.session = sess
155- }
156- if connState {
157- // connected
158- if client.sessionRetrierStopper != nil {
159- client.sessionRetrierStopper <- true
160- client.sessionRetrierStopper = nil
161- }
162- ar := &util.AutoRetrier{
163- make(chan bool, 1),
164- client.session.Dial,
165- util.Jitter}
166- client.sessionRetrierStopper = ar.Stop
167- go ar.Retry()
168+ client.hasConnectivity = hasConnectivity
169+ if hasConnectivity {
170+ client.connectSession()
171 } else {
172- // disconnected
173- if client.sessionRetrierStopper != nil {
174- client.sessionRetrierStopper <- true
175- client.sessionRetrierStopper = nil
176- } else {
177- client.session.Close()
178- }
179- }
180+ client.disconnectSession()
181+ }
182+}
183+
184+// handleErr deals with the session erroring out of its loop
185+func (client *Client) handleErr(err error) {
186+ // if we're not connected, we don't really care
187+ client.log.Errorf("session exited: %s", err)
188+ if client.hasConnectivity {
189+ client.connectSession()
190+ }
191+}
192+
193+// handleNotification deals with receiving a notification
194+func (client *Client) handleNotification() error {
195+ action_id := "dummy_id"
196+ a := []string{action_id, "Go get it!"} // action value not visible on the phone
197+ h := map[string]*dbus.Variant{"x-canonical-switch-to-application": &dbus.Variant{true}}
198+ nots := notifications.Raw(client.notificationsEndp, client.log)
199+ not_id, err := nots.Notify(
200+ "ubuntu-push-client", // app name
201+ uint32(0), // id
202+ "update_manager_icon", // icon
203+ "There's an updated system image!", // summary
204+ "You've got to get it! Now! Run!", // body
205+ a, // actions
206+ h, // hints
207+ int32(10*1000), // timeout (ms)
208+ )
209+ if err != nil {
210+ client.log.Errorf("showing notification: %s", err)
211+ return err
212+ }
213+ client.log.Debugf("got notification id %d", not_id)
214+ return nil
215+}
216+
217+// handleClick deals with the user clicking a notification
218+func (client *Client) handleClick() error {
219+ // it doesn't get much simpler...
220+ urld := urldispatcher.New(client.urlDispatcherEndp, client.log)
221+ return urld.DispatchURL("settings:///system/system-update")
222 }
223
224=== modified file 'client/client_test.go'
225--- client/client_test.go 2014-02-04 14:21:43 +0000
226+++ client/client_test.go 2014-02-04 14:21:43 +0000
227@@ -17,6 +17,7 @@
228 package client
229
230 import (
231+ "bytes"
232 "fmt"
233 "io/ioutil"
234 . "launchpad.net/gocheck"
235@@ -280,32 +281,47 @@
236 }
237
238 /*****************************************************************
239+ handleErr tests
240+******************************************************************/
241+
242+func (cs *clientSuite) TestHandleErr(c *C) {
243+ cli := new(Client)
244+ cli.log = noisylog
245+ cli.initSession()
246+ cli.hasConnectivity = true
247+ cli.handleErr(nil)
248+ c.Assert(cli.session, NotNil)
249+ // let the session connection fail
250+ time.Sleep(100 * time.Millisecond)
251+ c.Check(cli.session.State(), Equals, session.Error)
252+}
253+
254+/*****************************************************************
255 handleConnState tests
256 ******************************************************************/
257
258 func (cs *clientSuite) TestHandleConnStateD2C(c *C) {
259 cli := new(Client)
260-
261+ cli.initSession()
262 // let's pretend the client had a previous attempt at connecting still pending
263 // (hard to trigger in real life, but possible)
264 cli.sessionRetrierStopper = make(chan bool, 1)
265
266- c.Assert(cli.connState, Equals, false)
267+ c.Assert(cli.hasConnectivity, Equals, false)
268 cli.handleConnState(true)
269- c.Check(cli.connState, Equals, true)
270+ c.Check(cli.hasConnectivity, Equals, true)
271 c.Assert(cli.session, NotNil)
272- c.Check(cli.session.State(), Equals, session.Disconnected)
273 }
274
275 func (cs *clientSuite) TestHandleConnStateSame(c *C) {
276 cli := new(Client)
277 // here we want to check that we don't do anything
278 c.Assert(cli.session, IsNil)
279- c.Assert(cli.connState, Equals, false)
280+ c.Assert(cli.hasConnectivity, Equals, false)
281 cli.handleConnState(false)
282 c.Check(cli.session, IsNil)
283
284- cli.connState = true
285+ cli.hasConnectivity = true
286 cli.handleConnState(true)
287 c.Check(cli.session, IsNil)
288 }
289@@ -314,7 +330,7 @@
290 cli := new(Client)
291 cli.session, _ = session.NewSession(string(cli.config.Addr), cli.pem, cli.config.ExchangeTimeout.Duration, cli.deviceId, noisylog)
292 cli.session.Dial()
293- cli.connState = true
294+ cli.hasConnectivity = true
295
296 // cli.session.State() will be "Error" here, for now at least
297 c.Check(cli.session.State(), Not(Equals), session.Disconnected)
298@@ -326,9 +342,52 @@
299 cli := new(Client)
300 cli.session, _ = session.NewSession(string(cli.config.Addr), cli.pem, cli.config.ExchangeTimeout.Duration, cli.deviceId, noisylog)
301 cli.sessionRetrierStopper = make(chan bool, 1)
302- cli.connState = true
303+ cli.hasConnectivity = true
304
305 cli.handleConnState(false)
306 c.Check(cli.session.State(), Equals, session.Disconnected)
307 c.Check(cli.sessionRetrierStopper, IsNil)
308 }
309+
310+/*****************************************************************
311+ handleNotification tests
312+******************************************************************/
313+
314+func (cs *clientSuite) TestHandleNotification(c *C) {
315+ buf := &bytes.Buffer{}
316+ cli := new(Client)
317+ endp := testibus.NewTestingEndpoint(nil, condition.Work(true), uint32(1))
318+ cli.notificationsEndp = endp
319+ cli.log = logger.NewSimpleLogger(buf, "debug")
320+ c.Check(cli.handleNotification(), IsNil)
321+ // check we sent the notification
322+ args := testibus.GetCallArgs(endp)
323+ c.Assert(args, HasLen, 1)
324+ c.Check(args[0].Member, Equals, "Notify")
325+ c.Check(buf.String(), Matches, `.* got notification id \d+\s*`)
326+}
327+
328+func (cs *clientSuite) TestHandleNotificationFail(c *C) {
329+ cli := new(Client)
330+ endp := testibus.NewTestingEndpoint(nil, condition.Work(false))
331+ cli.notificationsEndp = endp
332+ cli.log = noisylog
333+ c.Check(cli.handleNotification(), NotNil)
334+}
335+
336+/*****************************************************************
337+ handleClick tests
338+******************************************************************/
339+
340+func (cs *clientSuite) TestHandleClick(c *C) {
341+ cli := new(Client)
342+ endp := testibus.NewTestingEndpoint(nil, condition.Work(true), nil)
343+ cli.urlDispatcherEndp = endp
344+ cli.log = noisylog
345+ c.Check(cli.handleClick(), IsNil)
346+ // check we sent the notification
347+ args := testibus.GetCallArgs(endp)
348+ c.Assert(args, HasLen, 1)
349+ c.Check(args[0].Member, Equals, "DispatchURL")
350+ c.Check(args[0].Args, DeepEquals, []interface{}{"settings:///system/system-update"})
351+}

Subscribers

People subscribed via source and target branches