Merge lp:~chipaca/ubuntu-push/release-0.67 into lp:ubuntu-push

Proposed by John Lenton
Status: Merged
Approved by: John Lenton
Approved revision: 140
Merged at revision: 140
Proposed branch: lp:~chipaca/ubuntu-push/release-0.67
Merge into: lp:ubuntu-push
Diff against target: 1442 lines (+374/-124)
46 files modified
bus/connectivity/connectivity.go (+23/-12)
bus/connectivity/connectivity_test.go (+10/-11)
bus/connectivity/webchecker.go (+8/-5)
bus/connectivity/webchecker_test.go (+3/-2)
bus/endpoint.go (+7/-7)
bus/networkmanager/networkmanager.go (+6/-6)
bus/notifications/raw.go (+1/-1)
bus/systemimage/systemimage.go (+1/-1)
bus/testing/testing_endpoint.go (+5/-1)
click/cclick/cclick.go (+1/-0)
client/client.go (+3/-3)
client/client_test.go (+18/-2)
client/service/postal.go (+0/-1)
client/service/service.go (+3/-3)
client/session/seenstate/seenstate.go (+6/-1)
client/session/seenstate/sqlseenstate.go (+5/-0)
client/session/seenstate/sqlseenstate_test.go (+9/-0)
client/session/session.go (+38/-2)
client/session/session_test.go (+1/-0)
debian/changelog (+40/-0)
dependencies.tsv (+1/-1)
docs/example-client/main.qml (+13/-1)
docs/example-client/manifest.json (+2/-2)
identifier/identifier.go (+1/-1)
identifier/identifier_test.go (+1/-1)
launch_helper/helper_finder/helper_finder.go (+1/-1)
launch_helper/helper_finder/helper_finder_test.go (+1/-1)
launch_helper/kindpool.go (+1/-1)
launch_helper/legacy/legacy.go (+1/-1)
launch_helper/legacy/legacy_test.go (+1/-1)
logger/logger.go (+12/-7)
logger/logger_test.go (+12/-0)
messaging/messaging.go (+1/-1)
poller/poller.go (+1/-1)
server/acceptance/acceptanceclient.go (+2/-0)
server/acceptance/kit/api.go (+14/-3)
server/acceptance/suites/helpers.go (+1/-1)
server/acceptance/suites/suite.go (+11/-3)
testing/helpers.go (+1/-1)
ubuntu-push-client.go (+18/-0)
urldispatcher/curldispatcher/curldispatcher.go (+1/-1)
urldispatcher/urldispatcher.go (+2/-2)
urldispatcher/urldispatcher_test.go (+2/-2)
util/redialer.go (+69/-26)
util/redialer_states.gv (+9/-0)
util/redialer_test.go (+7/-7)
To merge this branch: bzr merge lp:~chipaca/ubuntu-push/release-0.67
Reviewer Review Type Date Requested Status
John Lenton (community) Approve
Review via email: mp+249049@code.launchpad.net

Commit message

  * Updated precommit script. [dev]

  * Include code examples in docs (instead of repeating). [docs]

  * Make tests more robust in the face of go 1.3 [client, server]

  * Introduce StartClientAuthFlex for acceptance tests: Start a client
    with auth, take a devId regexp, don't check any client event; support
    connbroken in acceptanceclient. [server]

  * Cleanup and improve logging, and make log messages more
    consistent. [client]

  * Partially work around bug lp:1390663 in a minimally intrusive way
    (real fix will have to wait). [client]

  * Add SIGQUIT handler to spit out stack dumps; more logging
    tweaks. [client, server]

  * Adds a couple of buttons to exercise more APIs, version bump to
    0.44. [sample app]

  * Add APIError to server/acceptance/kit that includes the body for
    debugging. [server]

  * Add DisableKeepAlives and MaxIdleConnsPerHost to the APIClient
    SetupClient method. [server]

  * Clean up goroutines in tests. [client]

  * Add an explicit check and log message for nil error on webcheck's CopyN. [client]

  * Log line nums, enabled when logLevel = debug. [client server]

  * Workaround gc issue with 1.3 and 32 bits. Fixes FTBFS. [client]

Description of the change

Merging from automatic.

  * Updated precommit script. [dev]

  * Include code examples in docs (instead of repeating). [docs]

  * Make tests more robust in the face of go 1.3 [client, server]

  * Introduce StartClientAuthFlex for acceptance tests: Start a client
    with auth, take a devId regexp, don't check any client event; support
    connbroken in acceptanceclient. [server]

  * Cleanup and improve logging, and make log messages more
    consistent. [client]

  * Partially work around bug lp:1390663 in a minimally intrusive way
    (real fix will have to wait). [client]

  * Add SIGQUIT handler to spit out stack dumps; more logging
    tweaks. [client, server]

  * Adds a couple of buttons to exercise more APIs, version bump to
    0.44. [sample app]

  * Add APIError to server/acceptance/kit that includes the body for
    debugging. [server]

  * Add DisableKeepAlives and MaxIdleConnsPerHost to the APIClient
    SetupClient method. [server]

  * Clean up goroutines in tests. [client]

  * Add an explicit check and log message for nil error on webcheck's CopyN. [client]

  * Log line nums, enabled when logLevel = debug. [client server]

  * Workaround gc issue with 1.3 and 32 bits. Fixes FTBFS. [client]

To post a comment you must log in.
lp:~chipaca/ubuntu-push/release-0.67 updated
141. By John Lenton

changelog polish.

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

Individual branches have been approved sepparately.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'bus/connectivity/connectivity.go'
--- bus/connectivity/connectivity.go 2014-07-04 19:12:38 +0000
+++ bus/connectivity/connectivity.go 2015-02-09 10:47:29 +0000
@@ -82,7 +82,7 @@
82 // Get the current state.82 // Get the current state.
83 initial = nm.GetState()83 initial = nm.GetState()
84 if initial == networkmanager.Unknown {84 if initial == networkmanager.Unknown {
85 cs.log.Debugf("Failed to get state.")85 cs.log.Debugf("failed to get state.")
86 goto Continue86 goto Continue
87 }87 }
88 cs.log.Debugf("got initial state of %s", initial)88 cs.log.Debugf("got initial state of %s", initial)
@@ -120,40 +120,51 @@
120 case <-cs.networkConCh:120 case <-cs.networkConCh:
121 cs.webgetCh = nil121 cs.webgetCh = nil
122 cs.timer.Reset(stabilizingTimeout)122 cs.timer.Reset(stabilizingTimeout)
123 log.Debugf("PrimaryConnection changed. Assuming disconnect.")
124 if cs.lastSent == true {123 if cs.lastSent == true {
124 log.Debugf("connectivity: PrimaryConnection changed. lastSent: %v, sending 'disconnected'.", cs.lastSent)
125 cs.lastSent = false125 cs.lastSent = false
126 break Loop126 break Loop
127 } else {
128 log.Debugf("connectivity: PrimaryConnection changed. lastSent: %v, Ignoring.", cs.lastSent)
127 }129 }
128130
129 case v, ok := <-cs.networkStateCh:131 case v, ok := <-cs.networkStateCh:
132 // Handle only disconnecting here, connecting handled under the timer below
130 if !ok {133 if !ok {
131 // tear it all down and start over134 // tear it all down and start over
132 return false, errors.New("got not-OK from StateChanged watch")135 return false, errors.New("got not-OK from StateChanged watch")
133 }136 }
134 cs.webgetCh = nil137 cs.webgetCh = nil
138 lastState := cs.currentState
135 cs.currentState = v139 cs.currentState = v
136 cs.timer.Reset(stabilizingTimeout)140 // ignore Connecting (followed immediately by "Connected Global") and repeats
137 log.Debugf("State changed to %s. Assuming disconnect.", v)141 if v != networkmanager.Connecting && lastState != v {
138 if cs.lastSent == true {142 cs.timer.Reset(stabilizingTimeout)
139 log.Infof("Sending 'disconnected'.")143 log.Debugf("state changed to %s. Assuming disconnect.", v)
140 cs.lastSent = false144 if cs.lastSent == true {
141 break Loop145 log.Debugf("connectivity: %s -> %s. lastSent: %v, sending 'disconnected'", lastState, v, cs.lastSent)
146 cs.lastSent = false
147 break Loop
148 } else {
149 log.Debugf("connectivity: %s -> %s. lastSent: %v, Ignoring.", lastState, v, cs.lastSent)
150 }
151 } else {
152 log.Debugf("connectivity: %s -> %s. lastSent: %v, Ignoring.", lastState, v, cs.lastSent)
142 }153 }
143154
144 case <-cs.timer.C:155 case <-cs.timer.C:
145 if cs.currentState == networkmanager.ConnectedGlobal {156 if cs.currentState == networkmanager.ConnectedGlobal {
146 log.Debugf("May be connected; checking...")157 log.Debugf("connectivity: timer signal, state: ConnectedGlobal, checking...")
147 cs.webgetCh = make(chan bool)158 cs.webgetCh = make(chan bool)
148 go cs.webget(cs.webgetCh)159 go cs.webget(cs.webgetCh)
149 }160 }
150161
151 case connected := <-cs.webgetCh:162 case connected := <-cs.webgetCh:
152 cs.timer.Reset(recheckTimeout)163 cs.timer.Reset(recheckTimeout)
153 log.Debugf("Connection check says: %t", connected)164 log.Debugf("connectivity: connection check says: %t", connected)
154 cs.webgetCh = nil165 cs.webgetCh = nil
155 if connected && cs.lastSent == false {166 if connected && cs.lastSent == false {
156 log.Infof("Sending 'connected'.")167 log.Debugf("connectivity: connection check ok, lastSent: %v, sending 'connected'.", cs.lastSent)
157 cs.lastSent = true168 cs.lastSent = true
158 break Loop169 break Loop
159 }170 }
@@ -178,7 +189,7 @@
178 }189 }
179190
180Start:191Start:
181 log.Infof("Sending initial 'disconnected'.")192 log.Debugf("sending initial 'disconnected'.")
182 out <- false193 out <- false
183 cs.lastSent = false194 cs.lastSent = false
184 cs.currentState = cs.start()195 cs.currentState = cs.start()
185196
=== modified file 'bus/connectivity/connectivity_test.go'
--- bus/connectivity/connectivity_test.go 2014-07-04 23:00:42 +0000
+++ bus/connectivity/connectivity_test.go 2015-02-09 10:47:29 +0000
@@ -217,20 +217,22 @@
217 f, e := cs.connectedStateStep()217 f, e := cs.connectedStateStep()
218 c.Check(e, IsNil)218 c.Check(e, IsNil)
219 c.Check(f, Equals, true)219 c.Check(f, Equals, true)
220 ch <- networkmanager.ConnectedGlobal // a ConnectedGlobal when connected signals trouble220 ch <- networkmanager.Disconnected
221 f, e = cs.connectedStateStep()221 ch <- networkmanager.ConnectedGlobal
222 c.Check(e, IsNil)222 f, e = cs.connectedStateStep()
223 c.Check(f, Equals, false) // so we assume a disconnect happened223 c.Check(e, IsNil)
224 f, e = cs.connectedStateStep()224 c.Check(f, Equals, false)
225 c.Check(e, IsNil)225 f, e = cs.connectedStateStep()
226 c.Check(f, Equals, true) // and if the web check works, go back to connected226 c.Check(e, IsNil)
227 c.Check(f, Equals, true)
227228
228 // same scenario, but with failing web check229 // same scenario, but with failing web check
229 webget_p = condition.Fail2Work(1)230 webget_p = condition.Fail2Work(1)
231 ch <- networkmanager.Disconnected
230 ch <- networkmanager.ConnectedGlobal232 ch <- networkmanager.ConnectedGlobal
231 f, e = cs.connectedStateStep()233 f, e = cs.connectedStateStep()
232 c.Check(e, IsNil)234 c.Check(e, IsNil)
233 c.Check(f, Equals, false) // first false is from assuming a Connected signals trouble235 c.Check(f, Equals, false) // first false is from the Disconnected
234236
235 // the next call to Step will time out237 // the next call to Step will time out
236 _ch := make(chan bool, 1)238 _ch := make(chan bool, 1)
@@ -284,7 +286,6 @@
284286
285 endp := testingbus.NewTestingEndpoint(condition.Work(true), condition.Work(true),287 endp := testingbus.NewTestingEndpoint(condition.Work(true), condition.Work(true),
286 uint32(networkmanager.ConnectedGlobal),288 uint32(networkmanager.ConnectedGlobal),
287 uint32(networkmanager.ConnectedGlobal),
288 uint32(networkmanager.Disconnected),289 uint32(networkmanager.Disconnected),
289 )290 )
290291
@@ -303,8 +304,6 @@
303 }{304 }{
304 {false, "first state is always false", 0},305 {false, "first state is always false", 0},
305 {true, "then it should be true as per ConnectedGlobal above", 0},306 {true, "then it should be true as per ConnectedGlobal above", 0},
306 {false, "then, false (upon receiving the next ConnectedGlobal)", 2},
307 {true, "then it should be true (webcheck passed)", 0},
308 {false, "then it should be false (Disconnected)", 2},307 {false, "then it should be false (Disconnected)", 2},
309 {false, "then it should be false again because it's restarted", 2},308 {false, "then it should be false again because it's restarted", 2},
310 }309 }
311310
=== modified file 'bus/connectivity/webchecker.go'
--- bus/connectivity/webchecker.go 2014-03-20 12:24:33 +0000
+++ bus/connectivity/webchecker.go 2015-02-09 10:47:29 +0000
@@ -64,7 +64,7 @@
64func (wb *webchecker) Webcheck(ch chan<- bool) {64func (wb *webchecker) Webcheck(ch chan<- bool) {
65 response, err := wb.cli.Get(wb.url)65 response, err := wb.cli.Get(wb.url)
66 if err != nil {66 if err != nil {
67 wb.log.Errorf("While GETting %s: %v", wb.url, err)67 wb.log.Errorf("while GETting %s: %v", wb.url, err)
68 ch <- false68 ch <- false
69 return69 return
70 }70 }
@@ -72,17 +72,20 @@
72 hash := md5.New()72 hash := md5.New()
73 _, err = io.CopyN(hash, response.Body, 1024)73 _, err = io.CopyN(hash, response.Body, 1024)
74 if err != io.EOF {74 if err != io.EOF {
75 wb.log.Errorf("Reading %s, expecting EOF, got: %v",75 if err == nil {
76 wb.url, err)76 wb.log.Errorf("reading %s, but response body is larger than 1k.", wb.url)
77 } else {
78 wb.log.Errorf("reading %s, expecting EOF, got: %v", wb.url, err)
79 }
77 ch <- false80 ch <- false
78 return81 return
79 }82 }
80 sum := fmt.Sprintf("%x", hash.Sum(nil))83 sum := fmt.Sprintf("%x", hash.Sum(nil))
81 if sum == wb.target {84 if sum == wb.target {
82 wb.log.Infof("Connectivity check passed.")85 wb.log.Infof("connectivity check passed.")
83 ch <- true86 ch <- true
84 } else {87 } else {
85 wb.log.Infof("Connectivity check failed: content mismatch.")88 wb.log.Infof("connectivity check failed: content mismatch.")
86 ch <- false89 ch <- false
87 }90 }
88}91}
8992
=== modified file 'bus/connectivity/webchecker_test.go'
--- bus/connectivity/webchecker_test.go 2014-03-20 12:24:33 +0000
+++ bus/connectivity/webchecker_test.go 2015-02-09 10:47:29 +0000
@@ -18,7 +18,6 @@
1818
19import (19import (
20 . "launchpad.net/gocheck"20 . "launchpad.net/gocheck"
21 "launchpad.net/ubuntu-push/logger"
22 helpers "launchpad.net/ubuntu-push/testing"21 helpers "launchpad.net/ubuntu-push/testing"
23 "launchpad.net/ubuntu-push/util"22 "launchpad.net/ubuntu-push/util"
24 "net/http"23 "net/http"
@@ -28,7 +27,7 @@
2827
29type WebcheckerSuite struct {28type WebcheckerSuite struct {
30 timeouts []time.Duration29 timeouts []time.Duration
31 log logger.Logger30 log *helpers.TestLogger
32}31}
3332
34var _ = Suite(&WebcheckerSuite{})33var _ = Suite(&WebcheckerSuite{})
@@ -104,6 +103,7 @@
104 ch := make(chan bool, 1)103 ch := make(chan bool, 1)
105 ck.Webcheck(ch)104 ck.Webcheck(ch)
106 c.Check(<-ch, Equals, false)105 c.Check(<-ch, Equals, false)
106 c.Check(s.log.Captured(), Matches, "(?ism).*content mismatch.*")
107}107}
108108
109// Webchecker sends false if the download is too big109// Webchecker sends false if the download is too big
@@ -115,6 +115,7 @@
115 ch := make(chan bool, 1)115 ch := make(chan bool, 1)
116 ck.Webcheck(ch)116 ck.Webcheck(ch)
117 c.Check(<-ch, Equals, false)117 c.Check(<-ch, Equals, false)
118 c.Check(s.log.Captured(), Matches, "(?ism).*larger than 1k.*")
118}119}
119120
120// Webchecker sends false if the request timeouts121// Webchecker sends false if the request timeouts
121122
=== modified file 'bus/endpoint.go'
--- bus/endpoint.go 2014-09-08 15:48:00 +0000
+++ bus/endpoint.go 2015-02-09 10:47:29 +0000
@@ -84,7 +84,7 @@
84 name := endp.addr.Name84 name := endp.addr.Name
85 hasOwner, err := d.NameHasOwner(name)85 hasOwner, err := d.NameHasOwner(name)
86 if err != nil {86 if err != nil {
87 endp.log.Debugf("Unable to determine ownership of %#v: %v", name, err)87 endp.log.Debugf("unable to determine ownership of %#v: %v", name, err)
88 bus.Close()88 bus.Close()
89 return err89 return err
90 }90 }
@@ -110,7 +110,7 @@
110 return errors.New(msg)110 return errors.New(msg)
111 }111 }
112 }112 }
113 endp.log.Infof("%#v dialed in.", name)113 endp.log.Debugf("%#v dialed in.", name)
114 endp.bus = bus114 endp.bus = bus
115 endp.proxy = bus.Object(name, dbus.ObjectPath(endp.addr.Path))115 endp.proxy = bus.Object(name, dbus.ObjectPath(endp.addr.Path))
116 return nil116 return nil
@@ -126,7 +126,7 @@
126func (endp *endpoint) WatchSignal(member string, f func(...interface{}), d func()) error {126func (endp *endpoint) WatchSignal(member string, f func(...interface{}), d func()) error {
127 watch, err := endp.proxy.WatchSignal(endp.addr.Interface, member)127 watch, err := endp.proxy.WatchSignal(endp.addr.Interface, member)
128 if err != nil {128 if err != nil {
129 endp.log.Debugf("Failed to set up the watch: %s", err)129 endp.log.Debugf("failed to set up the watch: %s", err)
130 return err130 return err
131 }131 }
132132
@@ -167,15 +167,15 @@
167 variantvs := endp.unpackOneMsg(msg, property)167 variantvs := endp.unpackOneMsg(msg, property)
168 switch len(variantvs) {168 switch len(variantvs) {
169 default:169 default:
170 return nil, fmt.Errorf("Too many values in Properties.Get response: %d", len(variantvs))170 return nil, fmt.Errorf("too many values in Properties.Get response: %d", len(variantvs))
171 case 0:171 case 0:
172 return nil, fmt.Errorf("Not enough values in Properties.Get response: %d", len(variantvs))172 return nil, fmt.Errorf("not enough values in Properties.Get response: %d", len(variantvs))
173 case 1:173 case 1:
174 // carry on174 // carry on
175 }175 }
176 variant, ok := variantvs[0].(*dbus.Variant)176 variant, ok := variantvs[0].(*dbus.Variant)
177 if !ok {177 if !ok {
178 return nil, fmt.Errorf("Response from Properties.Get wasn't a *dbus.Variant")178 return nil, fmt.Errorf("response from Properties.Get wasn't a *dbus.Variant")
179 }179 }
180 return variant.Value, nil180 return variant.Value, nil
181}181}
@@ -324,6 +324,6 @@
324 }324 }
325 f(endp.unpackOneMsg(msg, member)...)325 f(endp.unpackOneMsg(msg, member)...)
326 }326 }
327 endp.log.Errorf("Got not-OK from %s watch", member)327 endp.log.Errorf("got not-OK from %s watch", member)
328 d()328 d()
329}329}
330330
=== modified file 'bus/networkmanager/networkmanager.go'
--- bus/networkmanager/networkmanager.go 2014-04-04 12:01:42 +0000
+++ bus/networkmanager/networkmanager.go 2015-02-09 10:47:29 +0000
@@ -71,14 +71,14 @@
71func (nm *networkManager) GetState() State {71func (nm *networkManager) GetState() State {
72 s, err := nm.bus.GetProperty("state")72 s, err := nm.bus.GetProperty("state")
73 if err != nil {73 if err != nil {
74 nm.log.Errorf("Failed gettting current state: %s", err)74 nm.log.Errorf("failed gettting current state: %s", err)
75 nm.log.Debugf("Defaulting state to Unknown")75 nm.log.Debugf("defaulting state to Unknown")
76 return Unknown76 return Unknown
77 }77 }
7878
79 v, ok := s.(uint32)79 v, ok := s.(uint32)
80 if !ok {80 if !ok {
81 nm.log.Errorf("Got weird state: %#v", s)81 nm.log.Errorf("got weird state: %#v", s)
82 return Unknown82 return Unknown
83 }83 }
8484
@@ -110,8 +110,8 @@
110func (nm *networkManager) GetPrimaryConnection() string {110func (nm *networkManager) GetPrimaryConnection() string {
111 s, err := nm.bus.GetProperty("PrimaryConnection")111 s, err := nm.bus.GetProperty("PrimaryConnection")
112 if err != nil {112 if err != nil {
113 nm.log.Errorf("Failed gettting current primary connection: %s", err)113 nm.log.Errorf("failed gettting current primary connection: %s", err)
114 nm.log.Debugf("Defaulting primary connection to empty")114 nm.log.Debugf("defaulting primary connection to empty")
115 return ""115 return ""
116 }116 }
117117
@@ -146,7 +146,7 @@
146 ch <- string(con)146 ch <- string(con)
147 }, func() { close(ch) })147 }, func() { close(ch) })
148 if err != nil {148 if err != nil {
149 nm.log.Debugf("Failed to set up the watch: %s", err)149 nm.log.Debugf("failed to set up the watch: %s", err)
150 return nil, err150 return nil, err
151 }151 }
152152
153153
=== modified file 'bus/notifications/raw.go'
--- bus/notifications/raw.go 2014-08-15 10:33:04 +0000
+++ bus/notifications/raw.go 2015-02-09 10:47:29 +0000
@@ -119,7 +119,7 @@
119 ch <- action119 ch <- action
120 }, func() { close(ch) })120 }, func() { close(ch) })
121 if err != nil {121 if err != nil {
122 raw.log.Debugf("Failed to set up the watch: %s", err)122 raw.log.Debugf("failed to set up the watch: %s", err)
123 return nil, err123 return nil, err
124 }124 }
125 return ch, nil125 return ch, nil
126126
=== modified file 'bus/systemimage/systemimage.go'
--- bus/systemimage/systemimage.go 2014-04-02 08:46:48 +0000
+++ bus/systemimage/systemimage.go 2015-02-09 10:47:29 +0000
@@ -57,7 +57,7 @@
57var _ SystemImage = &systemImage{} // ensures it conforms57var _ SystemImage = &systemImage{} // ensures it conforms
5858
59func (si *systemImage) Info() (*InfoResult, error) {59func (si *systemImage) Info() (*InfoResult, error) {
60 si.log.Debugf("Invoking Info")60 si.log.Debugf("invoking Info")
61 res := &InfoResult{}61 res := &InfoResult{}
62 err := si.endp.Call("Info", bus.Args(), &res.BuildNumber, &res.Device, &res.Channel, &res.LastUpdate, &res.VersionDetail)62 err := si.endp.Call("Info", bus.Args(), &res.BuildNumber, &res.Device, &res.Channel, &res.LastUpdate, &res.VersionDetail)
63 if err != nil {63 if err != nil {
6464
=== modified file 'bus/testing/testing_endpoint.go'
--- bus/testing/testing_endpoint.go 2014-07-04 23:00:42 +0000
+++ bus/testing/testing_endpoint.go 2015-02-09 10:47:29 +0000
@@ -89,7 +89,11 @@
89 ticker := tc.watchTicker89 ticker := tc.watchTicker
90 tc.watchLck.RUnlock()90 tc.watchLck.RUnlock()
91 if ticker != nil {91 if ticker != nil {
92 <-ticker92 _, ok := <-ticker
93 if !ok {
94 // bail out
95 return
96 }
93 } else {97 } else {
94 time.Sleep(10 * time.Millisecond)98 time.Sleep(10 * time.Millisecond)
95 }99 }
96100
=== modified file 'click/cclick/cclick.go'
--- click/cclick/cclick.go 2014-07-07 22:04:30 +0000
+++ click/cclick/cclick.go 2015-02-09 10:47:29 +0000
@@ -51,6 +51,7 @@
51 }51 }
52 ccu.cref = cref52 ccu.cref = cref
53 runtime.SetFinalizer(holder, func(interface{}) {53 runtime.SetFinalizer(holder, func(interface{}) {
54 ccu.cref = nil // 1.3 gc gets confused otherwise
54 C.g_object_unref((C.gpointer)(cref))55 C.g_object_unref((C.gpointer)(cref))
55 })56 })
56 return nil57 return nil
5758
=== modified file 'client/client.go'
--- client/client.go 2014-11-03 13:36:00 +0000
+++ client/client.go 2015-02-09 10:47:29 +0000
@@ -376,15 +376,15 @@
376376
377// handleConnState deals with connectivity events377// handleConnState deals with connectivity events
378func (client *PushClient) handleConnState(hasConnectivity bool) {378func (client *PushClient) handleConnState(hasConnectivity bool) {
379 client.log.Debugf("handleConnState: %v", hasConnectivity)
379 if client.hasConnectivity == hasConnectivity {380 if client.hasConnectivity == hasConnectivity {
380 // nothing to do!381 // nothing to do!
381 return382 return
382 }383 }
383 client.hasConnectivity = hasConnectivity384 client.hasConnectivity = hasConnectivity
385 client.session.Close()
384 if hasConnectivity {386 if hasConnectivity {
385 client.session.AutoRedial(client.sessionConnectedCh)387 client.session.AutoRedial(client.sessionConnectedCh)
386 } else {
387 client.session.Close()
388 }388 }
389}389}
390390
@@ -490,7 +490,7 @@
490 case err := <-client.session.ErrCh:490 case err := <-client.session.ErrCh:
491 errhandler(err)491 errhandler(err)
492 case count := <-client.sessionConnectedCh:492 case count := <-client.sessionConnectedCh:
493 client.log.Debugf("Session connected after %d attempts", count)493 client.log.Debugf("session connected after %d attempts", count)
494 case app := <-client.unregisterCh:494 case app := <-client.unregisterCh:
495 unregisterhandler(app)495 unregisterhandler(app)
496 }496 }
497497
=== modified file 'client/client_test.go'
--- client/client_test.go 2014-09-05 10:47:29 +0000
+++ client/client_test.go 2015-02-09 10:47:29 +0000
@@ -27,6 +27,7 @@
27 "os"27 "os"
28 "path/filepath"28 "path/filepath"
29 "reflect"29 "reflect"
30 //"runtime"
30 "testing"31 "testing"
31 "time"32 "time"
3233
@@ -203,6 +204,15 @@
203 cs.writeTestConfig(nil)204 cs.writeTestConfig(nil)
204}205}
205206
207func (cs *clientSuite) TearDownTest(c *C) {
208 //fmt.Println("GOROUTINE# ", runtime.NumGoroutine())
209 /*
210 var x [16*1024]byte
211 sz := runtime.Stack(x[:], true)
212 fmt.Println(string(x[:sz]))
213 */
214}
215
206type sqlientSuite struct{ clientSuite }216type sqlientSuite struct{ clientSuite }
207217
208func (s *sqlientSuite) SetUpSuite(c *C) {218func (s *sqlientSuite) SetUpSuite(c *C) {
@@ -651,7 +661,9 @@
651 )661 )
652 siCond := condition.Fail2Work(2)662 siCond := condition.Fail2Work(2)
653 siEndp := testibus.NewMultiValuedTestingEndpoint(siCond, condition.Work(true), []interface{}{int32(101), "mako", "daily", "Unknown", map[string]string{}})663 siEndp := testibus.NewMultiValuedTestingEndpoint(siCond, condition.Work(true), []interface{}{int32(101), "mako", "daily", "Unknown", map[string]string{}})
654 testibus.SetWatchTicker(cEndp, make(chan bool))664 tickerCh := make(chan bool)
665 testibus.SetWatchTicker(cEndp, tickerCh)
666 defer close(tickerCh)
655 // ok, create the thing667 // ok, create the thing
656 cli := NewPushClient(cs.configPath, cs.leveldbPath)668 cli := NewPushClient(cs.configPath, cs.leveldbPath)
657 cli.log = cs.log669 cli.log = cs.log
@@ -700,6 +712,7 @@
700 c.Assert(cli.initSessionAndPoller(), IsNil)712 c.Assert(cli.initSessionAndPoller(), IsNil)
701 cs.log.ResetCapture()713 cs.log.ResetCapture()
702 cli.hasConnectivity = true714 cli.hasConnectivity = true
715 defer cli.session.Close()
703 cli.handleErr(errors.New("bananas"))716 cli.handleErr(errors.New("bananas"))
704 c.Check(cs.log.Captured(), Matches, ".*session exited.*bananas\n")717 c.Check(cs.log.Captured(), Matches, ".*session exited.*bananas\n")
705}718}
@@ -712,6 +725,7 @@
712 cli := NewPushClient(cs.configPath, "")725 cli := NewPushClient(cs.configPath, "")
713 ln, err := cli.seenStateFactory()726 ln, err := cli.seenStateFactory()
714 c.Assert(err, IsNil)727 c.Assert(err, IsNil)
728 defer ln.Close()
715 c.Check(fmt.Sprintf("%T", ln), Equals, "*seenstate.memSeenState")729 c.Check(fmt.Sprintf("%T", ln), Equals, "*seenstate.memSeenState")
716}730}
717731
@@ -719,6 +733,7 @@
719 cli := NewPushClient(cs.configPath, ":memory:")733 cli := NewPushClient(cs.configPath, ":memory:")
720 ln, err := cli.seenStateFactory()734 ln, err := cli.seenStateFactory()
721 c.Assert(err, IsNil)735 c.Assert(err, IsNil)
736 defer ln.Close()
722 c.Check(fmt.Sprintf("%T", ln), Equals, "*seenstate.sqliteSeenState")737 c.Check(fmt.Sprintf("%T", ln), Equals, "*seenstate.sqliteSeenState")
723}738}
724739
@@ -733,6 +748,7 @@
733 c.Assert(cli.initSessionAndPoller(), IsNil)748 c.Assert(cli.initSessionAndPoller(), IsNil)
734749
735 c.Assert(cli.hasConnectivity, Equals, false)750 c.Assert(cli.hasConnectivity, Equals, false)
751 defer cli.session.Close()
736 cli.handleConnState(true)752 cli.handleConnState(true)
737 c.Check(cli.hasConnectivity, Equals, true)753 c.Check(cli.hasConnectivity, Equals, true)
738 c.Assert(cli.session, NotNil)754 c.Assert(cli.session, NotNil)
@@ -1135,7 +1151,7 @@
1135 // sessionConnectedCh to nothing in particular, but it'll help sync this test1151 // sessionConnectedCh to nothing in particular, but it'll help sync this test
1136 cli.sessionConnectedCh <- 421152 cli.sessionConnectedCh <- 42
1137 tick()1153 tick()
1138 c.Check(cs.log.Captured(), Matches, "(?ms).*Session connected after 42 attempts$")1154 c.Check(cs.log.Captured(), Matches, "(?msi).*Session connected after 42 attempts$")
11391155
1140 // loop() should have connected:1156 // loop() should have connected:
1141 // * connCh to the connectivity checker1157 // * connCh to the connectivity checker
11421158
=== modified file 'client/service/postal.go'
--- client/service/postal.go 2014-11-03 13:36:00 +0000
+++ client/service/postal.go 2015-02-09 10:47:29 +0000
@@ -244,7 +244,6 @@
244 for _, endp := range endps {244 for _, endp := range endps {
245 go func(name string, endp bus.Endpoint) {245 go func(name string, endp bus.Endpoint) {
246 util.NewAutoRedialer(endp).Redial()246 util.NewAutoRedialer(endp).Redial()
247 svc.Log.Debugf("%s dialed in", name)
248 wg.Done()247 wg.Done()
249 }(endp.name, endp.endp)248 }(endp.name, endp.endp)
250 }249 }
251250
=== modified file 'client/service/service.go'
--- client/service/service.go 2014-11-19 13:58:12 +0000
+++ client/service/service.go 2015-02-09 10:47:29 +0000
@@ -149,14 +149,14 @@
149 // errors below here Can't Happen (tm).149 // errors below here Can't Happen (tm).
150 body, err := ioutil.ReadAll(resp.Body)150 body, err := ioutil.ReadAll(resp.Body)
151 if err != nil {151 if err != nil {
152 svc.Log.Errorf("Reading response body: %v", err)152 svc.Log.Errorf("during ReadAll() of response body: %v", err)
153 return nil, err153 return nil, err
154 }154 }
155155
156 var reply registrationReply156 var reply registrationReply
157 err = json.Unmarshal(body, &reply)157 err = json.Unmarshal(body, &reply)
158 if err != nil {158 if err != nil {
159 svc.Log.Errorf("Unmarshalling response body: %v", err)159 svc.Log.Errorf("during Unmarshal of response body: %v", err)
160 return nil, fmt.Errorf("unable to unmarshal register response: %v", err)160 return nil, fmt.Errorf("unable to unmarshal register response: %v", err)
161 }161 }
162162
@@ -181,7 +181,7 @@
181 }181 }
182182
183 if !reply.Ok || reply.Token == "" {183 if !reply.Ok || reply.Token == "" {
184 svc.Log.Errorf("Unexpected response: %#v", reply)184 svc.Log.Errorf("unexpected response: %#v", reply)
185 return nil, ErrBadToken185 return nil, ErrBadToken
186 }186 }
187187
188188
=== modified file 'client/session/seenstate/seenstate.go'
--- client/session/seenstate/seenstate.go 2014-05-14 17:42:24 +0000
+++ client/session/seenstate/seenstate.go 2015-02-09 10:47:29 +0000
@@ -28,8 +28,10 @@
28 // GetAll() returns a "simple" map of the current levels.28 // GetAll() returns a "simple" map of the current levels.
29 GetAllLevels() (map[string]int64, error)29 GetAllLevels() (map[string]int64, error)
30 // FilterBySeen filters notifications already seen, keep track30 // FilterBySeen filters notifications already seen, keep track
31 // of them as well31 // of them as well.
32 FilterBySeen([]protocol.Notification) ([]protocol.Notification, error)32 FilterBySeen([]protocol.Notification) ([]protocol.Notification, error)
33 // Close closes state.
34 Close()
33}35}
3436
35type memSeenState struct {37type memSeenState struct {
@@ -58,6 +60,9 @@
58 return acc, nil60 return acc, nil
59}61}
6062
63func (m *memSeenState) Close() {
64}
65
61var _ SeenState = (*memSeenState)(nil)66var _ SeenState = (*memSeenState)(nil)
6267
63// NewSeenState returns an implementation of SeenState that is memory-based and68// NewSeenState returns an implementation of SeenState that is memory-based and
6469
=== modified file 'client/session/seenstate/sqlseenstate.go'
--- client/session/seenstate/sqlseenstate.go 2014-05-14 17:42:24 +0000
+++ client/session/seenstate/sqlseenstate.go 2015-02-09 10:47:29 +0000
@@ -48,6 +48,11 @@
48 return &sqliteSeenState{db}, nil48 return &sqliteSeenState{db}, nil
49}49}
5050
51// Closes closes the underlying db.
52func (ps *sqliteSeenState) Close() {
53 ps.db.Close()
54}
55
51func (ps *sqliteSeenState) SetLevel(level string, top int64) error {56func (ps *sqliteSeenState) SetLevel(level string, top int64) error {
52 _, err := ps.db.Exec("REPLACE INTO level_map (level, top) VALUES (?, ?)", level, top)57 _, err := ps.db.Exec("REPLACE INTO level_map (level, top) VALUES (?, ?)", level, top)
53 if err != nil {58 if err != nil {
5459
=== modified file 'client/session/seenstate/sqlseenstate_test.go'
--- client/session/seenstate/sqlseenstate_test.go 2014-05-14 17:42:24 +0000
+++ client/session/seenstate/sqlseenstate_test.go 2015-02-09 10:47:29 +0000
@@ -112,6 +112,15 @@
112 c.Check(err, ErrorMatches, "cannot insert .*")112 c.Check(err, ErrorMatches, "cannot insert .*")
113}113}
114114
115func (s *sqlsSuite) TestClose(c *C) {
116 dir := c.MkDir()
117 filename := dir + "test.db"
118 sqls, err := NewSqliteSeenState(filename)
119 c.Check(err, IsNil)
120 c.Assert(sqls, NotNil)
121 sqls.Close()
122}
123
115func (s *sqlsSuite) TestDropPrevThan(c *C) {124func (s *sqlsSuite) TestDropPrevThan(c *C) {
116 dir := c.MkDir()125 dir := c.MkDir()
117 filename := dir + "test.db"126 filename := dir + "test.db"
118127
=== modified file 'client/session/session.go'
--- client/session/session.go 2014-11-19 13:58:12 +0000
+++ client/session/session.go 2015-02-09 10:47:29 +0000
@@ -74,8 +74,22 @@
74 Connected74 Connected
75 Started75 Started
76 Running76 Running
77 Unknown
77)78)
7879
80func (s ClientSessionState) String() string {
81 if s >= Unknown {
82 return fmt.Sprintf("??? (%d)", s)
83 }
84 return [Unknown]string{
85 "Error",
86 "Disconnected",
87 "Connected",
88 "Started",
89 "Running",
90 }[s]
91}
92
79type hostGetter interface {93type hostGetter interface {
80 Get() (*gethosts.Host, error)94 Get() (*gethosts.Host, error)
81}95}
@@ -131,6 +145,7 @@
131 proto protocol.Protocol145 proto protocol.Protocol
132 pingInterval time.Duration146 pingInterval time.Duration
133 retrier util.AutoRedialer147 retrier util.AutoRedialer
148 retrierLock sync.Mutex
134 cookie string149 cookie string
135 // status150 // status
136 stateP *uint32151 stateP *uint32
@@ -220,6 +235,7 @@
220}235}
221236
222func (sess *ClientSession) setState(state ClientSessionState) {237func (sess *ClientSession) setState(state ClientSessionState) {
238 sess.Log.Debugf("session.setState: %s -> %s", ClientSessionState(atomic.LoadUint32(sess.stateP)), state)
223 atomic.StoreUint32(sess.stateP, uint32(state))239 atomic.StoreUint32(sess.stateP, uint32(state))
224}240}
225241
@@ -348,6 +364,8 @@
348}364}
349365
350func (sess *ClientSession) stopRedial() {366func (sess *ClientSession) stopRedial() {
367 sess.retrierLock.Lock()
368 defer sess.retrierLock.Unlock()
351 if sess.retrier != nil {369 if sess.retrier != nil {
352 sess.retrier.Stop()370 sess.retrier.Stop()
353 sess.retrier = nil371 sess.retrier = nil
@@ -360,15 +378,31 @@
360 sess.setShouldDelay()378 sess.setShouldDelay()
361 }379 }
362 time.Sleep(sess.redialDelay(sess))380 time.Sleep(sess.redialDelay(sess))
381 sess.retrierLock.Lock()
382 defer sess.retrierLock.Unlock()
383 if sess.retrier != nil {
384 panic("session AutoRedial: unexpected non-nil retrier.")
385 }
363 sess.retrier = util.NewAutoRedialer(sess)386 sess.retrier = util.NewAutoRedialer(sess)
364 sess.lastAutoRedial = time.Now()387 sess.lastAutoRedial = time.Now()
365 go func() { doneCh <- sess.retrier.Redial() }()388 go func() {
389 sess.retrierLock.Lock()
390 retrier := sess.retrier
391 sess.retrierLock.Unlock()
392 if retrier == nil {
393 sess.Log.Debugf("session autoredialer skipping retry: retrier has been set to nil.")
394 return
395 }
396 sess.Log.Debugf("session autoredialier launching Redial goroutine")
397 doneCh <- retrier.Redial()
398 }()
366}399}
367400
368func (sess *ClientSession) Close() {401func (sess *ClientSession) Close() {
369 sess.stopRedial()402 sess.stopRedial()
370 sess.doClose()403 sess.doClose()
371}404}
405
372func (sess *ClientSession) doClose() {406func (sess *ClientSession) doClose() {
373 sess.connLock.Lock()407 sess.connLock.Lock()
374 defer sess.connLock.Unlock()408 defer sess.connLock.Unlock()
@@ -508,6 +542,7 @@
508 sess.proto.SetDeadline(time.Now().Add(deadAfter))542 sess.proto.SetDeadline(time.Now().Add(deadAfter))
509 err = sess.proto.ReadMessage(&recv)543 err = sess.proto.ReadMessage(&recv)
510 if err != nil {544 if err != nil {
545 sess.Log.Debugf("session aborting with error on read.")
511 sess.setState(Error)546 sess.setState(Error)
512 return err547 return err
513 }548 }
@@ -529,6 +564,7 @@
529 sess.Log.Errorf("server sent warning: %s", recv.Reason)564 sess.Log.Errorf("server sent warning: %s", recv.Reason)
530 }565 }
531 if err != nil {566 if err != nil {
567 sess.Log.Debugf("session aborting with error from handler.")
532 return err568 return err
533 }569 }
534 }570 }
@@ -591,7 +627,7 @@
591 }627 }
592 sess.proto = proto628 sess.proto = proto
593 sess.pingInterval = pingInterval629 sess.pingInterval = pingInterval
594 sess.Log.Debugf("Connected %v.", conn.RemoteAddr())630 sess.Log.Debugf("connected %v.", conn.RemoteAddr())
595 sess.started() // deals with choosing which host to retry with as well631 sess.started() // deals with choosing which host to retry with as well
596 return nil632 return nil
597}633}
598634
=== modified file 'client/session/session_test.go'
--- client/session/session_test.go 2014-11-25 17:36:27 +0000
+++ client/session/session_test.go 2015-02-09 10:47:29 +0000
@@ -162,6 +162,7 @@
162162
163func (*brokenSeenState) SetLevel(string, int64) error { return errors.New("broken.") }163func (*brokenSeenState) SetLevel(string, int64) error { return errors.New("broken.") }
164func (*brokenSeenState) GetAllLevels() (map[string]int64, error) { return nil, errors.New("broken.") }164func (*brokenSeenState) GetAllLevels() (map[string]int64, error) { return nil, errors.New("broken.") }
165func (*brokenSeenState) Close() {}
165func (*brokenSeenState) FilterBySeen([]protocol.Notification) ([]protocol.Notification, error) {166func (*brokenSeenState) FilterBySeen([]protocol.Notification) ([]protocol.Notification, error) {
166 return nil, errors.New("broken.")167 return nil, errors.New("broken.")
167}168}
168169
=== modified file 'debian/changelog'
--- debian/changelog 2014-12-11 16:56:31 +0000
+++ debian/changelog 2015-02-09 10:47:29 +0000
@@ -1,3 +1,43 @@
1ubuntu-push (0.67-0ubuntu1) UNRELEASED; urgency=medium
2
3 * Updated precommit script. [dev]
4
5 * Include code examples in docs (instead of repeating). [docs]
6
7 * Make tests more robust in the face of go 1.3 [client, server]
8
9 * Introduce StartClientAuthFlex for acceptance tests: Start a client
10 with auth, take a devId regexp, don't check any client event; support
11 connbroken in acceptanceclient. [server]
12
13 * Cleanup and improve logging, and make log messages more
14 consistent. [client]
15
16 * Partially work around bug lp:1390663 in a minimally intrusive way
17 (real fix will have to wait). [client]
18
19 * Add SIGQUIT handler to spit out stack dumps; more logging
20 tweaks. [client, server]
21
22 * Adds a couple of buttons to exercise more APIs, version bump to
23 0.44. [sample app]
24
25 * Add APIError to server/acceptance/kit that includes the body for
26 debugging. [server]
27
28 * Add DisableKeepAlives and MaxIdleConnsPerHost to the APIClient
29 SetupClient method. [server]
30
31 * Clean up goroutines in tests. [client]
32
33 * Add an explicit check and log message for nil error on webcheck's CopyN. [client]
34
35 * Log line nums, enabled when logLevel = debug. [client server]
36
37 * Workaround gc issue with 1.3 and 32 bits. Fixes FTBFS. [client]
38
39 -- John R. Lenton <john.lenton@canonical.com> Mon, 09 Feb 2015 10:19:59 +0000
40
1ubuntu-push (0.66+15.04.20141211-0ubuntu1) vivid; urgency=medium41ubuntu-push (0.66+15.04.20141211-0ubuntu1) vivid; urgency=medium
242
3 [ Roberto Alsina ]43 [ Roberto Alsina ]
444
=== modified file 'dependencies.tsv'
--- dependencies.tsv 2014-08-20 12:42:51 +0000
+++ dependencies.tsv 2015-02-09 10:47:29 +0000
@@ -1,5 +1,5 @@
1code.google.com/p/go-uuid hg 7dda39b2e7d5e265014674c5af696ba4186679e9 111code.google.com/p/go-uuid hg 7dda39b2e7d5e265014674c5af696ba4186679e9 11
2code.google.com/p/gosqlite hg 74691fb6f83716190870cde1b658538dd4b18eb0 152code.google.com/p/gosqlite hg 74691fb6f83716190870cde1b658538dd4b18eb0 15
3launchpad.net/go-dbus/v1 bzr james@jamesh.id.au-20140801110939-lzfql7fk76dt6ckd 1283launchpad.net/go-dbus/v1 bzr jlenton@gmail.com-20141023032446-s5icvsucwlv5o38a 129
4launchpad.net/go-xdg/v0 bzr john.lenton@canonical.com-20140208094800-gubd5md7cro3mtxa 104launchpad.net/go-xdg/v0 bzr john.lenton@canonical.com-20140208094800-gubd5md7cro3mtxa 10
5launchpad.net/gocheck bzr gustavo@niemeyer.net-20140225173054-xu9zlkf9kxhvow02 875launchpad.net/gocheck bzr gustavo@niemeyer.net-20140225173054-xu9zlkf9kxhvow02 87
66
=== modified file 'docs/example-client/main.qml'
--- docs/example-client/main.qml 2014-10-23 15:37:21 +0000
+++ docs/example-client/main.qml 2015-02-09 10:47:29 +0000
@@ -71,8 +71,12 @@
71 Component.onCompleted: {71 Component.onCompleted: {
72 notificationsChanged.connect(messageList.handle_notifications)72 notificationsChanged.connect(messageList.handle_notifications)
73 error.connect(messageList.handle_error)73 error.connect(messageList.handle_error)
74 onTokenChanged: {
75 console.log("foooooo")
76 }
74 }77 }
75 appId: "com.ubuntu.developer.ralsina.hello_hello"78 appId: "com.ubuntu.developer.ralsina.hello_hello"
79
76 }80 }
7781
78 TextField {82 TextField {
@@ -227,7 +231,7 @@
227 right: parent.right231 right: parent.right
228 bottom: parent.bottom232 bottom: parent.bottom
229 }233 }
230 height: item1.height * 7234 height: item1.height * 9
231 UbuntuShape {235 UbuntuShape {
232 anchors.fill: parent236 anchors.fill: parent
233 color: Theme.palette.normal.overlay237 color: Theme.palette.normal.overlay
@@ -285,6 +289,14 @@
285 value: 42289 value: 42
286 }290 }
287 }291 }
292 Button {
293 text: "Set Counter Via Plugin"
294 onClicked: { pushClient.count = counterSlider.value; }
295 }
296 Button {
297 text: "Clear Persistent Notifications"
298 onClicked: { pushClient.clearPersistent([]); }
299 }
288 }300 }
289 }301 }
290 }302 }
291303
=== modified file 'docs/example-client/manifest.json'
--- docs/example-client/manifest.json 2014-10-23 17:46:23 +0000
+++ docs/example-client/manifest.json 2015-02-09 10:47:29 +0000
@@ -1,7 +1,7 @@
1{1{
2 "architecture": "all",2 "architecture": "all",
3 "description": "Example app for Ubuntu push notifications.",3 "description": "Example app for Ubuntu push notifications.",
4 "framework": "ubuntu-sdk-14.10-dev2",4 "framework": "ubuntu-sdk-14.10",
5 "hooks": {5 "hooks": {
6 "hello": {6 "hello": {
7 "apparmor": "hello.json",7 "apparmor": "hello.json",
@@ -15,5 +15,5 @@
15 "maintainer": "Roberto Alsina <roberto.alsina@canonical.com>",15 "maintainer": "Roberto Alsina <roberto.alsina@canonical.com>",
16 "name": "com.ubuntu.developer.ralsina.hello",16 "name": "com.ubuntu.developer.ralsina.hello",
17 "title": "Hello",17 "title": "Hello",
18 "version": "0.4.3"18 "version": "0.4.4"
19}19}
2020
=== modified file 'identifier/identifier.go'
--- identifier/identifier.go 2014-08-04 20:40:50 +0000
+++ identifier/identifier.go 2015-02-09 10:47:29 +0000
@@ -48,7 +48,7 @@
48func New() (Id, error) {48func New() (Id, error) {
49 value, err := readMachineId()49 value, err := readMachineId()
50 if err != nil {50 if err != nil {
51 return &Identifier{value: ""}, fmt.Errorf("Failed to read the machine id: %s", err)51 return &Identifier{value: ""}, fmt.Errorf("failed to read the machine id: %s", err)
52 }52 }
53 return &Identifier{value: value}, nil53 return &Identifier{value: value}, nil
54}54}
5555
=== modified file 'identifier/identifier_test.go'
--- identifier/identifier_test.go 2014-08-12 00:32:32 +0000
+++ identifier/identifier_test.go 2015-02-09 10:47:29 +0000
@@ -48,7 +48,7 @@
48 machineIdPath = "/var/lib/dbus/no-such-file"48 machineIdPath = "/var/lib/dbus/no-such-file"
49 id, err := New()49 id, err := New()
50 c.Check(err, NotNil)50 c.Check(err, NotNil)
51 c.Check(err.Error(), Equals, "Failed to read the machine id: open /var/lib/dbus/no-such-file: no such file or directory")51 c.Check(err.Error(), Equals, "failed to read the machine id: open /var/lib/dbus/no-such-file: no such file or directory")
52 c.Check(id.String(), HasLen, 0)52 c.Check(id.String(), HasLen, 0)
53}53}
5454
5555
=== modified file 'launch_helper/helper_finder/helper_finder.go'
--- launch_helper/helper_finder/helper_finder.go 2014-07-29 15:36:00 +0000
+++ launch_helper/helper_finder/helper_finder.go 2015-02-09 10:47:29 +0000
@@ -72,7 +72,7 @@
72 fInfo, err := os.Stat(helpersDataPath)72 fInfo, err := os.Stat(helpersDataPath)
73 if err != nil {73 if err != nil {
74 // cache file is missing, go via the slow route74 // cache file is missing, go via the slow route
75 log.Infof("Cache file not found, falling back to .json file lookup")75 log.Infof("cache file not found, falling back to .json file lookup")
76 return helperFromHookFile(app)76 return helperFromHookFile(app)
77 }77 }
78 // get the lock as the map can be changed while we read78 // get the lock as the map can be changed while we read
7979
=== modified file 'launch_helper/helper_finder/helper_finder_test.go'
--- launch_helper/helper_finder/helper_finder_test.go 2014-07-29 15:36:00 +0000
+++ launch_helper/helper_finder/helper_finder_test.go 2015-02-09 10:47:29 +0000
@@ -139,7 +139,7 @@
139 hid, hex := Helper(app, s.log)139 hid, hex := Helper(app, s.log)
140 c.Check(hid, Equals, "com.example.test_test-helper_1")140 c.Check(hid, Equals, "com.example.test_test-helper_1")
141 c.Check(hex, Equals, filepath.Join(s.symlinkPath, "tsthlpr"))141 c.Check(hex, Equals, filepath.Join(s.symlinkPath, "tsthlpr"))
142 c.Check(s.log.Captured(), Matches, ".*Cache file not found, falling back to .json file lookup\n")142 c.Check(s.log.Captured(), Matches, ".*(?i)Cache file not found, falling back to .json file lookup\n")
143}143}
144144
145func (s *helperSuite) TestHelperFromHookBasic(c *C) {145func (s *helperSuite) TestHelperFromHookBasic(c *C) {
146146
=== modified file 'launch_helper/kindpool.go'
--- launch_helper/kindpool.go 2014-11-05 12:07:53 +0000
+++ launch_helper/kindpool.go 2015-02-09 10:47:29 +0000
@@ -296,7 +296,7 @@
296 if err != nil {296 if err != nil {
297 pool.log.Errorf("unable to read output from %v helper: %v", args.AppId, err)297 pool.log.Errorf("unable to read output from %v helper: %v", args.AppId, err)
298 } else {298 } else {
299 pool.log.Infof("%v helper output: %#v", args.AppId, payload)299 pool.log.Infof("%v helper output: %s", args.AppId, payload)
300 res := &HelperResult{Input: args.Input}300 res := &HelperResult{Input: args.Input}
301 err = json.Unmarshal(payload, &res.HelperOutput)301 err = json.Unmarshal(payload, &res.HelperOutput)
302 if err != nil {302 if err != nil {
303303
=== modified file 'launch_helper/legacy/legacy.go'
--- launch_helper/legacy/legacy.go 2014-11-05 12:07:53 +0000
+++ launch_helper/legacy/legacy.go 2015-02-09 10:47:29 +0000
@@ -78,7 +78,7 @@
78 p_err := cmd.Wait()78 p_err := cmd.Wait()
79 if p_err != nil {79 if p_err != nil {
80 // Helper failed or got killed, log output/errors80 // Helper failed or got killed, log output/errors
81 lhl.log.Errorf("Legacy helper failed: appId: %v, helper: %v, pid: %v, error: %v, stdout: %#v, stderr: %#v.",81 lhl.log.Errorf("legacy helper failed: appId: %v, helper: %v, pid: %v, error: %v, stdout: %#v, stderr: %#v.",
82 appId, progname, id, p_err, stdout.String(), stderr.String())82 appId, progname, id, p_err, stdout.String(), stderr.String())
83 }83 }
84 lhl.done(id)84 lhl.done(id)
8585
=== modified file 'launch_helper/legacy/legacy_test.go'
--- launch_helper/legacy/legacy_test.go 2014-08-21 18:03:49 +0000
+++ launch_helper/legacy/legacy_test.go 2015-02-09 10:47:29 +0000
@@ -104,7 +104,7 @@
104 c.Assert(err, IsNil)104 c.Assert(err, IsNil)
105105
106 takeNext(ch, c)106 takeNext(ch, c)
107 c.Check(ls.log.Captured(), Matches, "(?s).*Legacy helper failed.*")107 c.Check(ls.log.Captured(), Matches, "(?si).*Legacy helper failed.*")
108}108}
109109
110func (ls *legacySuite) TestHelperFailsLog(c *C) {110func (ls *legacySuite) TestHelperFailsLog(c *C) {
111111
=== modified file 'logger/logger.go'
--- logger/logger.go 2014-04-11 23:17:40 +0000
+++ logger/logger.go 2015-02-09 10:47:29 +0000
@@ -50,7 +50,8 @@
50}50}
5151
52const (52const (
53 lError = iota53 calldepthBase = 3
54 lError = iota
54 lInfo55 lInfo
55 lDebug56 lDebug
56)57)
@@ -81,8 +82,12 @@
81// level. The level can be, in order: "error", "info", "debug". It takes an82// level. The level can be, in order: "error", "info", "debug". It takes an
82// io.Writer.83// io.Writer.
83func NewSimpleLogger(w io.Writer, level string) Logger {84func NewSimpleLogger(w io.Writer, level string) Logger {
85 flags := log.Ldate | log.Ltime | log.Lmicroseconds
86 if levelToNLevel[level] >= lDebug {
87 flags = flags | log.Lshortfile
88 }
84 return NewSimpleLoggerFromMinimalLogger(89 return NewSimpleLoggerFromMinimalLogger(
85 log.New(w, "", log.Ldate|log.Ltime|log.Lmicroseconds),90 log.New(w, "", flags),
86 level,91 level,
87 )92 )
88}93}
@@ -92,13 +97,13 @@
92}97}
9398
94func (lg *simpleLogger) Errorf(format string, v ...interface{}) {99func (lg *simpleLogger) Errorf(format string, v ...interface{}) {
95 lg.outputFunc(2, fmt.Sprintf("ERROR "+format, v...))100 lg.outputFunc(calldepthBase, fmt.Sprintf("ERROR "+format, v...))
96}101}
97102
98var osExit = os.Exit // for testing103var osExit = os.Exit // for testing
99104
100func (lg *simpleLogger) Fatalf(format string, v ...interface{}) {105func (lg *simpleLogger) Fatalf(format string, v ...interface{}) {
101 lg.outputFunc(2, fmt.Sprintf("ERROR "+format, v...))106 lg.outputFunc(calldepthBase, fmt.Sprintf("ERROR "+format, v...))
102 osExit(1)107 osExit(1)
103}108}
104109
@@ -107,18 +112,18 @@
107 stack := make([]byte, 8*1024) // Stack writes less but doesn't fail112 stack := make([]byte, 8*1024) // Stack writes less but doesn't fail
108 stackWritten := runtime.Stack(stack, false)113 stackWritten := runtime.Stack(stack, false)
109 stack = stack[:stackWritten]114 stack = stack[:stackWritten]
110 lg.outputFunc(2, fmt.Sprintf("ERROR(PANIC) %s:\n%s", msg, stack))115 lg.outputFunc(calldepthBase, fmt.Sprintf("ERROR(PANIC) %s:\n%s", msg, stack))
111}116}
112117
113func (lg *simpleLogger) Infof(format string, v ...interface{}) {118func (lg *simpleLogger) Infof(format string, v ...interface{}) {
114 if lg.nlevel >= lInfo {119 if lg.nlevel >= lInfo {
115 lg.outputFunc(2, fmt.Sprintf("INFO "+format, v...))120 lg.outputFunc(calldepthBase, fmt.Sprintf("INFO "+format, v...))
116 }121 }
117}122}
118123
119func (lg *simpleLogger) Debugf(format string, v ...interface{}) {124func (lg *simpleLogger) Debugf(format string, v ...interface{}) {
120 if lg.nlevel >= lDebug {125 if lg.nlevel >= lDebug {
121 lg.outputFunc(2, fmt.Sprintf("DEBUG "+format, v...))126 lg.outputFunc(calldepthBase, fmt.Sprintf("DEBUG "+format, v...))
122 }127 }
123}128}
124129
125130
=== modified file 'logger/logger_test.go'
--- logger/logger_test.go 2014-04-11 19:05:35 +0000
+++ logger/logger_test.go 2015-02-09 10:47:29 +0000
@@ -163,3 +163,15 @@
163 checkError(`{"lvl": 1}`, "lvl:.*type string")163 checkError(`{"lvl": 1}`, "lvl:.*type string")
164 checkError(`{"lvl": "foo"}`, "lvl: not a log level: foo")164 checkError(`{"lvl": "foo"}`, "lvl: not a log level: foo")
165}165}
166
167func (s *loggerSuite) TestLogLineNo(c *C) {
168 buf := &bytes.Buffer{}
169 logger := NewSimpleLogger(buf, "debug")
170 logger.Output(1, "foobaz")
171 c.Check(buf.String(), Matches, ".* .* logger_test.go:[0-9]+: foobaz\n")
172
173 buf.Reset()
174 logger = NewSimpleLogger(buf, "error")
175 logger.Output(1, "foobaz")
176 c.Check(buf.String(), Matches, ".* .* foobaz\n")
177}
166178
=== modified file 'messaging/messaging.go'
--- messaging/messaging.go 2014-07-27 02:54:40 +0000
+++ messaging/messaging.go 2015-02-09 10:47:29 +0000
@@ -181,7 +181,7 @@
181 Action: action,181 Action: action,
182 })182 })
183 if err != nil {183 if err != nil {
184 mmu.Log.Errorf("Failed to build action: %s", action)184 mmu.Log.Errorf("failed to build action: %s", action)
185 return false185 return false
186 }186 }
187 actions[2*i] = string(act)187 actions[2*i] = string(act)
188188
=== modified file 'poller/poller.go'
--- poller/poller.go 2014-08-29 13:50:16 +0000
+++ poller/poller.go 2015-02-09 10:47:29 +0000
@@ -167,7 +167,7 @@
167 // the channel will produce a true for every167 // the channel will produce a true for every
168 // wakeup, not only the one we asked for168 // wakeup, not only the one we asked for
169 now := time.Now()169 now := time.Now()
170 p.log.Debugf("got woken up; time is %s", now)170 p.log.Debugf("got woken up; time is %s (𝛥: %s)", now, now.Sub(t))
171 if !now.Before(t) {171 if !now.Before(t) {
172 break172 break
173 }173 }
174174
=== modified file 'server/acceptance/acceptanceclient.go'
--- server/acceptance/acceptanceclient.go 2014-08-27 21:19:51 +0000
+++ server/acceptance/acceptanceclient.go 2015-02-09 10:47:29 +0000
@@ -176,6 +176,8 @@
176 events <- fmt.Sprintf("%sbroadcast chan:%v app:%v topLevel:%d payloads:%s", sess.Prefix, recv.ChanId, recv.AppId, recv.TopLevel, pack)176 events <- fmt.Sprintf("%sbroadcast chan:%v app:%v topLevel:%d payloads:%s", sess.Prefix, recv.ChanId, recv.AppId, recv.TopLevel, pack)
177 case "warn", "connwarn":177 case "warn", "connwarn":
178 events <- fmt.Sprintf("%sconnwarn %s", sess.Prefix, recv.Reason)178 events <- fmt.Sprintf("%sconnwarn %s", sess.Prefix, recv.Reason)
179 case "connbroken":
180 events <- fmt.Sprintf("%sconnbroken %s", sess.Prefix, recv.Reason)
179 case "setparams":181 case "setparams":
180 sess.SetCookie(recv.SetCookie)182 sess.SetCookie(recv.SetCookie)
181 if sess.ReportSetParams {183 if sess.ReportSetParams {
182184
=== modified file 'server/acceptance/kit/api.go'
--- server/acceptance/kit/api.go 2014-08-20 19:48:59 +0000
+++ server/acceptance/kit/api.go 2015-02-09 10:47:29 +0000
@@ -35,10 +35,21 @@
35 httpClient *http.Client35 httpClient *http.Client
36}36}
3737
38type APIError struct {
39 Msg string
40 Body []byte
41}
42
43func (e *APIError) Error() string {
44 return e.Msg
45}
46
38// SetupClient sets up the http client to make requests.47// SetupClient sets up the http client to make requests.
39func (api *APIClient) SetupClient(tlsConfig *tls.Config) {48func (api *APIClient) SetupClient(tlsConfig *tls.Config, disableKeepAlives bool, maxIdleConnsPerHost int) {
40 api.httpClient = &http.Client{49 api.httpClient = &http.Client{
41 Transport: &http.Transport{TLSClientConfig: tlsConfig},50 Transport: &http.Transport{TLSClientConfig: tlsConfig,
51 DisableKeepAlives: disableKeepAlives,
52 MaxIdleConnsPerHost: maxIdleConnsPerHost},
42 }53 }
43}54}
4455
@@ -73,7 +84,7 @@
73 var res map[string]interface{}84 var res map[string]interface{}
74 err = json.Unmarshal(body, &res)85 err = json.Unmarshal(body, &res)
75 if err != nil {86 if err != nil {
76 return nil, err87 return nil, &APIError{err.Error(), body}
77 }88 }
78 if ok, _ := res["ok"].(bool); !ok {89 if ok, _ := res["ok"].(bool); !ok {
79 return res, ErrNOk90 return res, ErrNOk
8091
=== modified file 'server/acceptance/suites/helpers.go'
--- server/acceptance/suites/helpers.go 2014-11-04 16:29:31 +0000
+++ server/acceptance/suites/helpers.go 2015-02-09 10:47:29 +0000
@@ -80,7 +80,7 @@
80 return cfgFpath80 return cfgFpath
81}81}
8282
83var rxLineInfo = regexp.MustCompile("^.*? ([[:alpha:]].*)\n")83var rxLineInfo = regexp.MustCompile("^.*?(?: .+\\.go:\\d+:)? ([[:alpha:]].*)\n")
8484
85// RunAndObserve runs cmdName and returns a channel that will receive85// RunAndObserve runs cmdName and returns a channel that will receive
86// cmdName stderr logging and a function to kill the process.86// cmdName stderr logging and a function to kill the process.
8787
=== modified file 'server/acceptance/suites/suite.go'
--- server/acceptance/suites/suite.go 2014-09-01 14:48:03 +0000
+++ server/acceptance/suites/suite.go 2015-02-09 10:47:29 +0000
@@ -21,7 +21,9 @@
21 "flag"21 "flag"
22 "fmt"22 "fmt"
23 "net"23 "net"
24 "net/http"
24 "os"25 "os"
26 "regexp"
25 "runtime"27 "runtime"
26 "time"28 "time"
2729
@@ -48,6 +50,13 @@
4850
49// Start a client with auth.51// Start a client with auth.
50func (h *ServerHandle) StartClientAuth(c *C, devId string, levels map[string]int64, auth string, cookie string) (events <-chan string, errorCh <-chan error, stop func()) {52func (h *ServerHandle) StartClientAuth(c *C, devId string, levels map[string]int64, auth string, cookie string) (events <-chan string, errorCh <-chan error, stop func()) {
53 cliEvents, errCh, stop := h.StartClientAuthFlex(c, devId, levels, auth, cookie, regexp.QuoteMeta(devId))
54 c.Assert(NextEvent(cliEvents, errCh), Matches, "connected .*")
55 return cliEvents, errCh, stop
56}
57
58// Start a client with auth, take a devId regexp, don't check any client event.
59func (h *ServerHandle) StartClientAuthFlex(c *C, devId string, levels map[string]int64, auth, cookie, devIdRegexp string) (events <-chan string, errorCh <-chan error, stop func()) {
51 errCh := make(chan error, 1)60 errCh := make(chan error, 1)
52 cliEvents := make(chan string, 10)61 cliEvents := make(chan string, 10)
53 sess := testClientSession(h.ServerAddr, devId, "m1", "img1", false)62 sess := testClientSession(h.ServerAddr, devId, "m1", "img1", false)
@@ -76,9 +85,8 @@
76 go func() {85 go func() {
77 errCh <- sess.Run(cliEvents)86 errCh <- sess.Run(cliEvents)
78 }()87 }()
79 c.Assert(NextEvent(cliEvents, errCh), Matches, "connected .*")
80 c.Assert(NextEvent(h.ServerEvents, nil), Matches, ".*session.* connected .*")88 c.Assert(NextEvent(h.ServerEvents, nil), Matches, ".*session.* connected .*")
81 c.Assert(NextEvent(h.ServerEvents, nil), Matches, ".*session.* registered "+devId)89 c.Assert(NextEvent(h.ServerEvents, nil), Matches, ".*session.* registered "+devIdRegexp)
82 return cliEvents, errCh, func() { clientShutdown <- true }90 return cliEvents, errCh, func() { clientShutdown <- true }
83}91}
8492
@@ -101,7 +109,7 @@
101 c.Assert(s.ServerHandle.ServerEvents, NotNil)109 c.Assert(s.ServerHandle.ServerEvents, NotNil)
102 c.Assert(s.ServerHandle.ServerAddr, Not(Equals), "")110 c.Assert(s.ServerHandle.ServerAddr, Not(Equals), "")
103 c.Assert(s.ServerAPIURL, Not(Equals), "")111 c.Assert(s.ServerAPIURL, Not(Equals), "")
104 s.SetupClient(nil)112 s.SetupClient(nil, false, http.DefaultMaxIdleConnsPerHost)
105}113}
106114
107func (s *AcceptanceSuite) TearDownTest(c *C) {115func (s *AcceptanceSuite) TearDownTest(c *C) {
108116
=== modified file 'testing/helpers.go'
--- testing/helpers.go 2014-07-11 19:42:57 +0000
+++ testing/helpers.go 2015-02-09 10:47:29 +0000
@@ -118,7 +118,7 @@
118118
119 idx := strings.LastIndex(dir, sep)119 idx := strings.LastIndex(dir, sep)
120 if idx == -1 {120 if idx == -1 {
121 panic(fmt.Errorf("Unable to find %s in %#v", sep, dir))121 panic(fmt.Errorf("unable to find %s in %#v", sep, dir))
122 }122 }
123 idx += len(sep)123 idx += len(sep)
124124
125125
=== modified file 'ubuntu-push-client.go'
--- ubuntu-push-client.go 2014-05-08 22:29:26 +0000
+++ ubuntu-push-client.go 2015-02-09 10:47:29 +0000
@@ -18,13 +18,31 @@
1818
19import (19import (
20 "log"20 "log"
21 "os"
22 "os/signal"
23 "runtime"
24 "syscall"
2125
22 "launchpad.net/go-xdg/v0"26 "launchpad.net/go-xdg/v0"
2327
24 "launchpad.net/ubuntu-push/client"28 "launchpad.net/ubuntu-push/client"
25)29)
2630
31func installSigQuitHandler() {
32 go func() {
33 sigs := make(chan os.Signal, 1)
34 signal.Notify(sigs, syscall.SIGQUIT)
35 buf := make([]byte, 1<<20)
36 for {
37 <-sigs
38 runtime.Stack(buf, true)
39 log.Printf("=== received SIGQUIT ===\n*** goroutine dump...\n%s\n*** end\n", buf)
40 }
41 }()
42}
43
27func main() {44func main() {
45 installSigQuitHandler()
28 cfgFname, err := xdg.Config.Find("ubuntu-push-client/config.json")46 cfgFname, err := xdg.Config.Find("ubuntu-push-client/config.json")
29 if err != nil {47 if err != nil {
30 log.Fatalf("unable to find a configuration file: %v", err)48 log.Fatalf("unable to find a configuration file: %v", err)
3149
=== modified file 'urldispatcher/curldispatcher/curldispatcher.go'
--- urldispatcher/curldispatcher/curldispatcher.go 2014-09-01 13:27:17 +0000
+++ urldispatcher/curldispatcher/curldispatcher.go 2015-02-09 10:47:29 +0000
@@ -79,7 +79,7 @@
79 C.dispatch_url(c_url, (C.gpointer)(&payload))79 C.dispatch_url(c_url, (C.gpointer)(&payload))
80 success := <-doneCh80 success := <-doneCh
81 if !success {81 if !success {
82 return fmt.Errorf("Failed to DispatchURL: %s for %s", url, appPackage)82 return fmt.Errorf("failed to DispatchURL: %s for %s", url, appPackage)
83 }83 }
84 return nil84 return nil
85}85}
8686
=== modified file 'urldispatcher/urldispatcher.go'
--- urldispatcher/urldispatcher.go 2014-09-01 13:27:17 +0000
+++ urldispatcher/urldispatcher.go 2015-02-09 10:47:29 +0000
@@ -44,7 +44,7 @@
44var cTestURL = curldispatcher.TestURL44var cTestURL = curldispatcher.TestURL
4545
46func (ud *urlDispatcher) DispatchURL(url string, app *click.AppId) error {46func (ud *urlDispatcher) DispatchURL(url string, app *click.AppId) error {
47 ud.log.Debugf("Dispatching %s", url)47 ud.log.Debugf("dispatching %s", url)
48 err := cDispatchURL(url, app.DispatchPackage())48 err := cDispatchURL(url, app.DispatchPackage())
49 if err != nil {49 if err != nil {
50 ud.log.Errorf("DispatchURL failed: %s", err)50 ud.log.Errorf("DispatchURL failed: %s", err)
@@ -62,7 +62,7 @@
62 }62 }
63 for _, appId := range appIds {63 for _, appId := range appIds {
64 if appId != app.Versioned() {64 if appId != app.Versioned() {
65 ud.log.Debugf("Notification skipped because of different appid for actions: %v - %s != %s", urls, appId, app.Versioned())65 ud.log.Debugf("notification skipped because of different appid for actions: %v - %s != %s", urls, appId, app.Versioned())
66 return false66 return false
67 }67 }
68 }68 }
6969
=== modified file 'urldispatcher/urldispatcher_test.go'
--- urldispatcher/urldispatcher_test.go 2014-08-21 17:45:01 +0000
+++ urldispatcher/urldispatcher_test.go 2015-02-09 10:47:29 +0000
@@ -106,7 +106,7 @@
106 appId := clickhelp.MustParseAppId("com.example.test_app_0.99")106 appId := clickhelp.MustParseAppId("com.example.test_app_0.99")
107 urls := []string{"potato://test-app"}107 urls := []string{"potato://test-app"}
108 c.Check(ud.TestURL(appId, urls), Equals, false)108 c.Check(ud.TestURL(appId, urls), Equals, false)
109 c.Check(s.log.Captured(), Matches, `(?sm).*Notification skipped because of different appid for actions: \[potato://test-app\] - com.example.test_test-app_0.1 != com.example.test_app_0.99`)109 c.Check(s.log.Captured(), Matches, `(?smi).*notification skipped because of different appid for actions: \[potato://test-app\] - com.example.test_test-app_0.1 != com.example.test_app_0.99`)
110}110}
111111
112func (s *UDSuite) TestTestURLOneWrongApp(c *C) {112func (s *UDSuite) TestTestURLOneWrongApp(c *C) {
@@ -117,7 +117,7 @@
117 appId := clickhelp.MustParseAppId("com.example.test_test-app_0")117 appId := clickhelp.MustParseAppId("com.example.test_test-app_0")
118 urls := []string{"potato://test-app", "potato_a://foo"}118 urls := []string{"potato://test-app", "potato_a://foo"}
119 c.Check(ud.TestURL(appId, urls), Equals, false)119 c.Check(ud.TestURL(appId, urls), Equals, false)
120 c.Check(s.log.Captured(), Matches, `(?sm).*Notification skipped because of different appid for actions: \[potato://test-app potato_a://foo\] - com.example.test_test-app1 != com.example.test_test-app.*`)120 c.Check(s.log.Captured(), Matches, `(?smi).*notification skipped because of different appid for actions: \[potato://test-app potato_a://foo\] - com.example.test_test-app1 != com.example.test_test-app.*`)
121}121}
122122
123func (s *UDSuite) TestTestURLInvalidURL(c *C) {123func (s *UDSuite) TestTestURLInvalidURL(c *C) {
124124
=== modified file 'util/redialer.go'
--- util/redialer.go 2014-03-20 12:15:47 +0000
+++ util/redialer.go 2015-02-09 10:47:29 +0000
@@ -65,30 +65,69 @@
65 Stop() // Stop shuts down the given AutoRedialer, if it is still retrying.65 Stop() // Stop shuts down the given AutoRedialer, if it is still retrying.
66}66}
6767
68type redialerState uint32
69
70const (
71 Unconfigured redialerState = iota
72 Redialing
73 Stopped
74)
75
76func (s *redialerState) String() string {
77 return [3]string{"Unconfigured", "Redialing", "Stopped"}[uint32(*s)]
78}
79
68type autoRedialer struct {80type autoRedialer struct {
69 stop chan bool81 stateLock sync.RWMutex
70 lock sync.RWMutex82 stateValue redialerState
71 dial func() error83 stopping chan struct{}
72 jitter func(time.Duration) time.Duration84 reallyStopped chan struct{}
85 dial func() error
86 jitter func(time.Duration) time.Duration
87}
88
89func (ar *autoRedialer) state() redialerState {
90 ar.stateLock.RLock()
91 defer ar.stateLock.RUnlock()
92 return ar.stateValue
93}
94
95func (ar *autoRedialer) setState(s redialerState) {
96 ar.stateLock.Lock()
97 defer ar.stateLock.Unlock()
98 ar.stateValue = s
99}
100
101func (ar *autoRedialer) setStateIfEqual(oldState, newState redialerState) bool {
102 ar.stateLock.Lock()
103 defer ar.stateLock.Unlock()
104 if ar.stateValue != oldState {
105 return false
106 }
107 ar.stateValue = newState
108 return true
109}
110
111func (ar *autoRedialer) setStateStopped() {
112 ar.stateLock.Lock()
113 defer ar.stateLock.Unlock()
114 switch ar.stateValue {
115 case Stopped:
116 return
117 case Unconfigured:
118 close(ar.reallyStopped)
119 }
120 ar.stateValue = Stopped
121 close(ar.stopping)
73}122}
74123
75func (ar *autoRedialer) Stop() {124func (ar *autoRedialer) Stop() {
76 if ar != nil {125 if ar != nil {
77 ar.lock.RLock()126 ar.setStateStopped()
78 defer ar.lock.RUnlock()127 <-ar.reallyStopped
79 if ar.stop != nil {
80 ar.stop <- true
81 }
82 }128 }
83}129}
84130
85func (ar *autoRedialer) shutdown() {
86 ar.lock.Lock()
87 defer ar.lock.Unlock()
88 close(ar.stop)
89 ar.stop = nil
90}
91
92// Redial keeps on calling Dial until it stops returning an error. It does131// Redial keeps on calling Dial until it stops returning an error. It does
93// exponential backoff, adding back the output of Jitter at each step.132// exponential backoff, adding back the output of Jitter at each step.
94func (ar *autoRedialer) Redial() uint32 {133func (ar *autoRedialer) Redial() uint32 {
@@ -96,20 +135,20 @@
96 // at least it's better than a segfault...135 // at least it's better than a segfault...
97 panic("you can't Redial a nil AutoRedialer")136 panic("you can't Redial a nil AutoRedialer")
98 }137 }
99 if ar.stop == nil {138 if !ar.setStateIfEqual(Unconfigured, Redialing) {
100 panic("this AutoRedialer has already been shut down")139 // XXX log this
140 return 0
101 }141 }
102 defer ar.shutdown()142 defer close(ar.reallyStopped)
103
104 ar.lock.RLock()
105 stop := ar.stop
106 ar.lock.RUnlock()
107143
108 var timeout time.Duration144 var timeout time.Duration
109 var dialAttempts uint32 = 0 // unsigned so it can wrap safely ...145 var dialAttempts uint32 = 0 // unsigned so it can wrap safely ...
110 timeouts := Timeouts()146 timeouts := Timeouts()
111 var numTimeouts uint32 = uint32(len(timeouts))147 var numTimeouts uint32 = uint32(len(timeouts))
112 for {148 for {
149 if ar.state() != Redialing {
150 return dialAttempts
151 }
113 if ar.dial() == nil {152 if ar.dial() == nil {
114 return dialAttempts + 1153 return dialAttempts + 1
115 }154 }
@@ -123,8 +162,7 @@
123 }162 }
124 dialAttempts++163 dialAttempts++
125 select {164 select {
126 case <-stop:165 case <-ar.stopping:
127 return dialAttempts
128 case <-time.After(timeout):166 case <-time.After(timeout):
129 }167 }
130 }168 }
@@ -133,7 +171,12 @@
133// Returns a stoppable AutoRedialer using the provided Dialer. If the Dialer171// Returns a stoppable AutoRedialer using the provided Dialer. If the Dialer
134// is also a Jitterer, the backoff will be jittered.172// is also a Jitterer, the backoff will be jittered.
135func NewAutoRedialer(dialer Dialer) AutoRedialer {173func NewAutoRedialer(dialer Dialer) AutoRedialer {
136 ar := &autoRedialer{stop: make(chan bool), dial: dialer.Dial}174 ar := &autoRedialer{
175 stateValue: Unconfigured,
176 dial: dialer.Dial,
177 reallyStopped: make(chan struct{}),
178 stopping: make(chan struct{}),
179 }
137 jitterer, ok := dialer.(Jitterer)180 jitterer, ok := dialer.(Jitterer)
138 if ok {181 if ok {
139 ar.jitter = jitterer.Jitter182 ar.jitter = jitterer.Jitter
140183
=== added file 'util/redialer_states.gv'
--- util/redialer_states.gv 1970-01-01 00:00:00 +0000
+++ util/redialer_states.gv 2015-02-09 10:47:29 +0000
@@ -0,0 +1,9 @@
1digraph "redialer" {
2 "Unconfigured" -> "Redialing" [ label="Redial" ]
3 "Unconfigured" -> "Stopped" [ label="Stop" ]
4
5 "Redialing" -> "Redialing" [ label="Redial" ]
6 "Redialing" -> "Stopped" [ label="Stop" ]
7
8 "Stopped" -> "Stopped" [ label="*" ]
9}
010
=== modified file 'util/redialer_test.go'
--- util/redialer_test.go 2014-02-05 13:02:47 +0000
+++ util/redialer_test.go 2015-02-09 10:47:29 +0000
@@ -48,10 +48,10 @@
48func (s *RedialerSuite) TestWorks(c *C) {48func (s *RedialerSuite) TestWorks(c *C) {
49 endp := testibus.NewTestingEndpoint(condition.Fail2Work(3), nil)49 endp := testibus.NewTestingEndpoint(condition.Fail2Work(3), nil)
50 ar := NewAutoRedialer(endp)50 ar := NewAutoRedialer(endp)
51 c.Check(ar.(*autoRedialer).stop, NotNil)51 // c.Check(ar.(*autoRedialer).stop, NotNil)
52 c.Check(ar.Redial(), Equals, uint32(4))52 c.Check(ar.Redial(), Equals, uint32(4))
53 // and on success, the stopper goes away53 // and on success, the stopper goes away
54 c.Check(ar.(*autoRedialer).stop, IsNil)54 // c.Check(ar.(*autoRedialer).stop, IsNil)
55}55}
5656
57func (s *RedialerSuite) TestRetryNil(c *C) {57func (s *RedialerSuite) TestRetryNil(c *C) {
@@ -63,7 +63,7 @@
63 endp := testibus.NewTestingEndpoint(condition.Work(true), nil)63 endp := testibus.NewTestingEndpoint(condition.Work(true), nil)
64 ar := NewAutoRedialer(endp)64 ar := NewAutoRedialer(endp)
65 c.Check(ar.Redial(), Equals, uint32(1))65 c.Check(ar.Redial(), Equals, uint32(1))
66 c.Check(ar.Redial, PanicMatches, ".*shut.?down.*")66 c.Check(ar.Redial(), Equals, uint32(0))
67}67}
6868
69type JitteringEndpoint struct {69type JitteringEndpoint struct {
@@ -103,13 +103,13 @@
103 go func() { countCh <- ar.Redial() }()103 go func() { countCh <- ar.Redial() }()
104 ar.Stop()104 ar.Stop()
105 select {105 select {
106 case n := <-countCh:106 case <-countCh:
107 c.Check(n, Equals, uint32(1))107 // pass
108 case <-time.After(20 * time.Millisecond):108 case <-time.After(20 * time.Millisecond):
109 c.Fatal("timed out waiting for redial")109 c.Fatal("timed out waiting for redial")
110 }110 }
111 // on Stop(), the stopper goes away too111 // on Stop(), the redialer is Stopped
112 c.Check(ar.(*autoRedialer).stop, IsNil)112 c.Check(ar.(*autoRedialer).state(), Equals, Stopped)
113 // and the next Stop() doesn't panic nor block113 // and the next Stop() doesn't panic nor block
114 ar.Stop()114 ar.Stop()
115}115}

Subscribers

People subscribed via source and target branches