Merge lp:~chipaca/ubuntu-push/release-0.67 into lp:ubuntu-push
- release-0.67
- Merge into trunk
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 |
Related bugs: |
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/
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/
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]
- 141. By John Lenton
-
changelog polish.
Preview Diff
1 | === modified file 'bus/connectivity/connectivity.go' | |||
2 | --- bus/connectivity/connectivity.go 2014-07-04 19:12:38 +0000 | |||
3 | +++ bus/connectivity/connectivity.go 2015-02-09 10:47:29 +0000 | |||
4 | @@ -82,7 +82,7 @@ | |||
5 | 82 | // Get the current state. | 82 | // Get the current state. |
6 | 83 | initial = nm.GetState() | 83 | initial = nm.GetState() |
7 | 84 | if initial == networkmanager.Unknown { | 84 | if initial == networkmanager.Unknown { |
9 | 85 | cs.log.Debugf("Failed to get state.") | 85 | cs.log.Debugf("failed to get state.") |
10 | 86 | goto Continue | 86 | goto Continue |
11 | 87 | } | 87 | } |
12 | 88 | cs.log.Debugf("got initial state of %s", initial) | 88 | cs.log.Debugf("got initial state of %s", initial) |
13 | @@ -120,40 +120,51 @@ | |||
14 | 120 | case <-cs.networkConCh: | 120 | case <-cs.networkConCh: |
15 | 121 | cs.webgetCh = nil | 121 | cs.webgetCh = nil |
16 | 122 | cs.timer.Reset(stabilizingTimeout) | 122 | cs.timer.Reset(stabilizingTimeout) |
17 | 123 | log.Debugf("PrimaryConnection changed. Assuming disconnect.") | ||
18 | 124 | if cs.lastSent == true { | 123 | if cs.lastSent == true { |
19 | 124 | log.Debugf("connectivity: PrimaryConnection changed. lastSent: %v, sending 'disconnected'.", cs.lastSent) | ||
20 | 125 | cs.lastSent = false | 125 | cs.lastSent = false |
21 | 126 | break Loop | 126 | break Loop |
22 | 127 | } else { | ||
23 | 128 | log.Debugf("connectivity: PrimaryConnection changed. lastSent: %v, Ignoring.", cs.lastSent) | ||
24 | 127 | } | 129 | } |
25 | 128 | 130 | ||
26 | 129 | case v, ok := <-cs.networkStateCh: | 131 | case v, ok := <-cs.networkStateCh: |
27 | 132 | // Handle only disconnecting here, connecting handled under the timer below | ||
28 | 130 | if !ok { | 133 | if !ok { |
29 | 131 | // tear it all down and start over | 134 | // tear it all down and start over |
30 | 132 | return false, errors.New("got not-OK from StateChanged watch") | 135 | return false, errors.New("got not-OK from StateChanged watch") |
31 | 133 | } | 136 | } |
32 | 134 | cs.webgetCh = nil | 137 | cs.webgetCh = nil |
33 | 138 | lastState := cs.currentState | ||
34 | 135 | cs.currentState = v | 139 | cs.currentState = v |
41 | 136 | cs.timer.Reset(stabilizingTimeout) | 140 | // ignore Connecting (followed immediately by "Connected Global") and repeats |
42 | 137 | log.Debugf("State changed to %s. Assuming disconnect.", v) | 141 | if v != networkmanager.Connecting && lastState != v { |
43 | 138 | if cs.lastSent == true { | 142 | cs.timer.Reset(stabilizingTimeout) |
44 | 139 | log.Infof("Sending 'disconnected'.") | 143 | log.Debugf("state changed to %s. Assuming disconnect.", v) |
45 | 140 | cs.lastSent = false | 144 | if cs.lastSent == true { |
46 | 141 | break Loop | 145 | log.Debugf("connectivity: %s -> %s. lastSent: %v, sending 'disconnected'", lastState, v, cs.lastSent) |
47 | 146 | cs.lastSent = false | ||
48 | 147 | break Loop | ||
49 | 148 | } else { | ||
50 | 149 | log.Debugf("connectivity: %s -> %s. lastSent: %v, Ignoring.", lastState, v, cs.lastSent) | ||
51 | 150 | } | ||
52 | 151 | } else { | ||
53 | 152 | log.Debugf("connectivity: %s -> %s. lastSent: %v, Ignoring.", lastState, v, cs.lastSent) | ||
54 | 142 | } | 153 | } |
55 | 143 | 154 | ||
56 | 144 | case <-cs.timer.C: | 155 | case <-cs.timer.C: |
57 | 145 | if cs.currentState == networkmanager.ConnectedGlobal { | 156 | if cs.currentState == networkmanager.ConnectedGlobal { |
59 | 146 | log.Debugf("May be connected; checking...") | 157 | log.Debugf("connectivity: timer signal, state: ConnectedGlobal, checking...") |
60 | 147 | cs.webgetCh = make(chan bool) | 158 | cs.webgetCh = make(chan bool) |
61 | 148 | go cs.webget(cs.webgetCh) | 159 | go cs.webget(cs.webgetCh) |
62 | 149 | } | 160 | } |
63 | 150 | 161 | ||
64 | 151 | case connected := <-cs.webgetCh: | 162 | case connected := <-cs.webgetCh: |
65 | 152 | cs.timer.Reset(recheckTimeout) | 163 | cs.timer.Reset(recheckTimeout) |
67 | 153 | log.Debugf("Connection check says: %t", connected) | 164 | log.Debugf("connectivity: connection check says: %t", connected) |
68 | 154 | cs.webgetCh = nil | 165 | cs.webgetCh = nil |
69 | 155 | if connected && cs.lastSent == false { | 166 | if connected && cs.lastSent == false { |
71 | 156 | log.Infof("Sending 'connected'.") | 167 | log.Debugf("connectivity: connection check ok, lastSent: %v, sending 'connected'.", cs.lastSent) |
72 | 157 | cs.lastSent = true | 168 | cs.lastSent = true |
73 | 158 | break Loop | 169 | break Loop |
74 | 159 | } | 170 | } |
75 | @@ -178,7 +189,7 @@ | |||
76 | 178 | } | 189 | } |
77 | 179 | 190 | ||
78 | 180 | Start: | 191 | Start: |
80 | 181 | log.Infof("Sending initial 'disconnected'.") | 192 | log.Debugf("sending initial 'disconnected'.") |
81 | 182 | out <- false | 193 | out <- false |
82 | 183 | cs.lastSent = false | 194 | cs.lastSent = false |
83 | 184 | cs.currentState = cs.start() | 195 | cs.currentState = cs.start() |
84 | 185 | 196 | ||
85 | === modified file 'bus/connectivity/connectivity_test.go' | |||
86 | --- bus/connectivity/connectivity_test.go 2014-07-04 23:00:42 +0000 | |||
87 | +++ bus/connectivity/connectivity_test.go 2015-02-09 10:47:29 +0000 | |||
88 | @@ -217,20 +217,22 @@ | |||
89 | 217 | f, e := cs.connectedStateStep() | 217 | f, e := cs.connectedStateStep() |
90 | 218 | c.Check(e, IsNil) | 218 | c.Check(e, IsNil) |
91 | 219 | c.Check(f, Equals, true) | 219 | c.Check(f, Equals, true) |
99 | 220 | ch <- networkmanager.ConnectedGlobal // a ConnectedGlobal when connected signals trouble | 220 | ch <- networkmanager.Disconnected |
100 | 221 | f, e = cs.connectedStateStep() | 221 | ch <- networkmanager.ConnectedGlobal |
101 | 222 | c.Check(e, IsNil) | 222 | f, e = cs.connectedStateStep() |
102 | 223 | c.Check(f, Equals, false) // so we assume a disconnect happened | 223 | c.Check(e, IsNil) |
103 | 224 | f, e = cs.connectedStateStep() | 224 | c.Check(f, Equals, false) |
104 | 225 | c.Check(e, IsNil) | 225 | f, e = cs.connectedStateStep() |
105 | 226 | c.Check(f, Equals, true) // and if the web check works, go back to connected | 226 | c.Check(e, IsNil) |
106 | 227 | c.Check(f, Equals, true) | ||
107 | 227 | 228 | ||
108 | 228 | // same scenario, but with failing web check | 229 | // same scenario, but with failing web check |
109 | 229 | webget_p = condition.Fail2Work(1) | 230 | webget_p = condition.Fail2Work(1) |
110 | 231 | ch <- networkmanager.Disconnected | ||
111 | 230 | ch <- networkmanager.ConnectedGlobal | 232 | ch <- networkmanager.ConnectedGlobal |
112 | 231 | f, e = cs.connectedStateStep() | 233 | f, e = cs.connectedStateStep() |
113 | 232 | c.Check(e, IsNil) | 234 | c.Check(e, IsNil) |
115 | 233 | c.Check(f, Equals, false) // first false is from assuming a Connected signals trouble | 235 | c.Check(f, Equals, false) // first false is from the Disconnected |
116 | 234 | 236 | ||
117 | 235 | // the next call to Step will time out | 237 | // the next call to Step will time out |
118 | 236 | _ch := make(chan bool, 1) | 238 | _ch := make(chan bool, 1) |
119 | @@ -284,7 +286,6 @@ | |||
120 | 284 | 286 | ||
121 | 285 | endp := testingbus.NewTestingEndpoint(condition.Work(true), condition.Work(true), | 287 | endp := testingbus.NewTestingEndpoint(condition.Work(true), condition.Work(true), |
122 | 286 | uint32(networkmanager.ConnectedGlobal), | 288 | uint32(networkmanager.ConnectedGlobal), |
123 | 287 | uint32(networkmanager.ConnectedGlobal), | ||
124 | 288 | uint32(networkmanager.Disconnected), | 289 | uint32(networkmanager.Disconnected), |
125 | 289 | ) | 290 | ) |
126 | 290 | 291 | ||
127 | @@ -303,8 +304,6 @@ | |||
128 | 303 | }{ | 304 | }{ |
129 | 304 | {false, "first state is always false", 0}, | 305 | {false, "first state is always false", 0}, |
130 | 305 | {true, "then it should be true as per ConnectedGlobal above", 0}, | 306 | {true, "then it should be true as per ConnectedGlobal above", 0}, |
131 | 306 | {false, "then, false (upon receiving the next ConnectedGlobal)", 2}, | ||
132 | 307 | {true, "then it should be true (webcheck passed)", 0}, | ||
133 | 308 | {false, "then it should be false (Disconnected)", 2}, | 307 | {false, "then it should be false (Disconnected)", 2}, |
134 | 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}, |
135 | 310 | } | 309 | } |
136 | 311 | 310 | ||
137 | === modified file 'bus/connectivity/webchecker.go' | |||
138 | --- bus/connectivity/webchecker.go 2014-03-20 12:24:33 +0000 | |||
139 | +++ bus/connectivity/webchecker.go 2015-02-09 10:47:29 +0000 | |||
140 | @@ -64,7 +64,7 @@ | |||
141 | 64 | func (wb *webchecker) Webcheck(ch chan<- bool) { | 64 | func (wb *webchecker) Webcheck(ch chan<- bool) { |
142 | 65 | response, err := wb.cli.Get(wb.url) | 65 | response, err := wb.cli.Get(wb.url) |
143 | 66 | if err != nil { | 66 | if err != nil { |
145 | 67 | wb.log.Errorf("While GETting %s: %v", wb.url, err) | 67 | wb.log.Errorf("while GETting %s: %v", wb.url, err) |
146 | 68 | ch <- false | 68 | ch <- false |
147 | 69 | return | 69 | return |
148 | 70 | } | 70 | } |
149 | @@ -72,17 +72,20 @@ | |||
150 | 72 | hash := md5.New() | 72 | hash := md5.New() |
151 | 73 | _, err = io.CopyN(hash, response.Body, 1024) | 73 | _, err = io.CopyN(hash, response.Body, 1024) |
152 | 74 | if err != io.EOF { | 74 | if err != io.EOF { |
155 | 75 | wb.log.Errorf("Reading %s, expecting EOF, got: %v", | 75 | if err == nil { |
156 | 76 | wb.url, err) | 76 | wb.log.Errorf("reading %s, but response body is larger than 1k.", wb.url) |
157 | 77 | } else { | ||
158 | 78 | wb.log.Errorf("reading %s, expecting EOF, got: %v", wb.url, err) | ||
159 | 79 | } | ||
160 | 77 | ch <- false | 80 | ch <- false |
161 | 78 | return | 81 | return |
162 | 79 | } | 82 | } |
163 | 80 | sum := fmt.Sprintf("%x", hash.Sum(nil)) | 83 | sum := fmt.Sprintf("%x", hash.Sum(nil)) |
164 | 81 | if sum == wb.target { | 84 | if sum == wb.target { |
166 | 82 | wb.log.Infof("Connectivity check passed.") | 85 | wb.log.Infof("connectivity check passed.") |
167 | 83 | ch <- true | 86 | ch <- true |
168 | 84 | } else { | 87 | } else { |
170 | 85 | wb.log.Infof("Connectivity check failed: content mismatch.") | 88 | wb.log.Infof("connectivity check failed: content mismatch.") |
171 | 86 | ch <- false | 89 | ch <- false |
172 | 87 | } | 90 | } |
173 | 88 | } | 91 | } |
174 | 89 | 92 | ||
175 | === modified file 'bus/connectivity/webchecker_test.go' | |||
176 | --- bus/connectivity/webchecker_test.go 2014-03-20 12:24:33 +0000 | |||
177 | +++ bus/connectivity/webchecker_test.go 2015-02-09 10:47:29 +0000 | |||
178 | @@ -18,7 +18,6 @@ | |||
179 | 18 | 18 | ||
180 | 19 | import ( | 19 | import ( |
181 | 20 | . "launchpad.net/gocheck" | 20 | . "launchpad.net/gocheck" |
182 | 21 | "launchpad.net/ubuntu-push/logger" | ||
183 | 22 | helpers "launchpad.net/ubuntu-push/testing" | 21 | helpers "launchpad.net/ubuntu-push/testing" |
184 | 23 | "launchpad.net/ubuntu-push/util" | 22 | "launchpad.net/ubuntu-push/util" |
185 | 24 | "net/http" | 23 | "net/http" |
186 | @@ -28,7 +27,7 @@ | |||
187 | 28 | 27 | ||
188 | 29 | type WebcheckerSuite struct { | 28 | type WebcheckerSuite struct { |
189 | 30 | timeouts []time.Duration | 29 | timeouts []time.Duration |
191 | 31 | log logger.Logger | 30 | log *helpers.TestLogger |
192 | 32 | } | 31 | } |
193 | 33 | 32 | ||
194 | 34 | var _ = Suite(&WebcheckerSuite{}) | 33 | var _ = Suite(&WebcheckerSuite{}) |
195 | @@ -104,6 +103,7 @@ | |||
196 | 104 | ch := make(chan bool, 1) | 103 | ch := make(chan bool, 1) |
197 | 105 | ck.Webcheck(ch) | 104 | ck.Webcheck(ch) |
198 | 106 | c.Check(<-ch, Equals, false) | 105 | c.Check(<-ch, Equals, false) |
199 | 106 | c.Check(s.log.Captured(), Matches, "(?ism).*content mismatch.*") | ||
200 | 107 | } | 107 | } |
201 | 108 | 108 | ||
202 | 109 | // Webchecker sends false if the download is too big | 109 | // Webchecker sends false if the download is too big |
203 | @@ -115,6 +115,7 @@ | |||
204 | 115 | ch := make(chan bool, 1) | 115 | ch := make(chan bool, 1) |
205 | 116 | ck.Webcheck(ch) | 116 | ck.Webcheck(ch) |
206 | 117 | c.Check(<-ch, Equals, false) | 117 | c.Check(<-ch, Equals, false) |
207 | 118 | c.Check(s.log.Captured(), Matches, "(?ism).*larger than 1k.*") | ||
208 | 118 | } | 119 | } |
209 | 119 | 120 | ||
210 | 120 | // Webchecker sends false if the request timeouts | 121 | // Webchecker sends false if the request timeouts |
211 | 121 | 122 | ||
212 | === modified file 'bus/endpoint.go' | |||
213 | --- bus/endpoint.go 2014-09-08 15:48:00 +0000 | |||
214 | +++ bus/endpoint.go 2015-02-09 10:47:29 +0000 | |||
215 | @@ -84,7 +84,7 @@ | |||
216 | 84 | name := endp.addr.Name | 84 | name := endp.addr.Name |
217 | 85 | hasOwner, err := d.NameHasOwner(name) | 85 | hasOwner, err := d.NameHasOwner(name) |
218 | 86 | if err != nil { | 86 | if err != nil { |
220 | 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) |
221 | 88 | bus.Close() | 88 | bus.Close() |
222 | 89 | return err | 89 | return err |
223 | 90 | } | 90 | } |
224 | @@ -110,7 +110,7 @@ | |||
225 | 110 | return errors.New(msg) | 110 | return errors.New(msg) |
226 | 111 | } | 111 | } |
227 | 112 | } | 112 | } |
229 | 113 | endp.log.Infof("%#v dialed in.", name) | 113 | endp.log.Debugf("%#v dialed in.", name) |
230 | 114 | endp.bus = bus | 114 | endp.bus = bus |
231 | 115 | endp.proxy = bus.Object(name, dbus.ObjectPath(endp.addr.Path)) | 115 | endp.proxy = bus.Object(name, dbus.ObjectPath(endp.addr.Path)) |
232 | 116 | return nil | 116 | return nil |
233 | @@ -126,7 +126,7 @@ | |||
234 | 126 | func (endp *endpoint) WatchSignal(member string, f func(...interface{}), d func()) error { | 126 | func (endp *endpoint) WatchSignal(member string, f func(...interface{}), d func()) error { |
235 | 127 | watch, err := endp.proxy.WatchSignal(endp.addr.Interface, member) | 127 | watch, err := endp.proxy.WatchSignal(endp.addr.Interface, member) |
236 | 128 | if err != nil { | 128 | if err != nil { |
238 | 129 | endp.log.Debugf("Failed to set up the watch: %s", err) | 129 | endp.log.Debugf("failed to set up the watch: %s", err) |
239 | 130 | return err | 130 | return err |
240 | 131 | } | 131 | } |
241 | 132 | 132 | ||
242 | @@ -167,15 +167,15 @@ | |||
243 | 167 | variantvs := endp.unpackOneMsg(msg, property) | 167 | variantvs := endp.unpackOneMsg(msg, property) |
244 | 168 | switch len(variantvs) { | 168 | switch len(variantvs) { |
245 | 169 | default: | 169 | default: |
247 | 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)) |
248 | 171 | case 0: | 171 | case 0: |
250 | 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)) |
251 | 173 | case 1: | 173 | case 1: |
252 | 174 | // carry on | 174 | // carry on |
253 | 175 | } | 175 | } |
254 | 176 | variant, ok := variantvs[0].(*dbus.Variant) | 176 | variant, ok := variantvs[0].(*dbus.Variant) |
255 | 177 | if !ok { | 177 | if !ok { |
257 | 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") |
258 | 179 | } | 179 | } |
259 | 180 | return variant.Value, nil | 180 | return variant.Value, nil |
260 | 181 | } | 181 | } |
261 | @@ -324,6 +324,6 @@ | |||
262 | 324 | } | 324 | } |
263 | 325 | f(endp.unpackOneMsg(msg, member)...) | 325 | f(endp.unpackOneMsg(msg, member)...) |
264 | 326 | } | 326 | } |
266 | 327 | endp.log.Errorf("Got not-OK from %s watch", member) | 327 | endp.log.Errorf("got not-OK from %s watch", member) |
267 | 328 | d() | 328 | d() |
268 | 329 | } | 329 | } |
269 | 330 | 330 | ||
270 | === modified file 'bus/networkmanager/networkmanager.go' | |||
271 | --- bus/networkmanager/networkmanager.go 2014-04-04 12:01:42 +0000 | |||
272 | +++ bus/networkmanager/networkmanager.go 2015-02-09 10:47:29 +0000 | |||
273 | @@ -71,14 +71,14 @@ | |||
274 | 71 | func (nm *networkManager) GetState() State { | 71 | func (nm *networkManager) GetState() State { |
275 | 72 | s, err := nm.bus.GetProperty("state") | 72 | s, err := nm.bus.GetProperty("state") |
276 | 73 | if err != nil { | 73 | if err != nil { |
279 | 74 | nm.log.Errorf("Failed gettting current state: %s", err) | 74 | nm.log.Errorf("failed gettting current state: %s", err) |
280 | 75 | nm.log.Debugf("Defaulting state to Unknown") | 75 | nm.log.Debugf("defaulting state to Unknown") |
281 | 76 | return Unknown | 76 | return Unknown |
282 | 77 | } | 77 | } |
283 | 78 | 78 | ||
284 | 79 | v, ok := s.(uint32) | 79 | v, ok := s.(uint32) |
285 | 80 | if !ok { | 80 | if !ok { |
287 | 81 | nm.log.Errorf("Got weird state: %#v", s) | 81 | nm.log.Errorf("got weird state: %#v", s) |
288 | 82 | return Unknown | 82 | return Unknown |
289 | 83 | } | 83 | } |
290 | 84 | 84 | ||
291 | @@ -110,8 +110,8 @@ | |||
292 | 110 | func (nm *networkManager) GetPrimaryConnection() string { | 110 | func (nm *networkManager) GetPrimaryConnection() string { |
293 | 111 | s, err := nm.bus.GetProperty("PrimaryConnection") | 111 | s, err := nm.bus.GetProperty("PrimaryConnection") |
294 | 112 | if err != nil { | 112 | if err != nil { |
297 | 113 | nm.log.Errorf("Failed gettting current primary connection: %s", err) | 113 | nm.log.Errorf("failed gettting current primary connection: %s", err) |
298 | 114 | nm.log.Debugf("Defaulting primary connection to empty") | 114 | nm.log.Debugf("defaulting primary connection to empty") |
299 | 115 | return "" | 115 | return "" |
300 | 116 | } | 116 | } |
301 | 117 | 117 | ||
302 | @@ -146,7 +146,7 @@ | |||
303 | 146 | ch <- string(con) | 146 | ch <- string(con) |
304 | 147 | }, func() { close(ch) }) | 147 | }, func() { close(ch) }) |
305 | 148 | if err != nil { | 148 | if err != nil { |
307 | 149 | nm.log.Debugf("Failed to set up the watch: %s", err) | 149 | nm.log.Debugf("failed to set up the watch: %s", err) |
308 | 150 | return nil, err | 150 | return nil, err |
309 | 151 | } | 151 | } |
310 | 152 | 152 | ||
311 | 153 | 153 | ||
312 | === modified file 'bus/notifications/raw.go' | |||
313 | --- bus/notifications/raw.go 2014-08-15 10:33:04 +0000 | |||
314 | +++ bus/notifications/raw.go 2015-02-09 10:47:29 +0000 | |||
315 | @@ -119,7 +119,7 @@ | |||
316 | 119 | ch <- action | 119 | ch <- action |
317 | 120 | }, func() { close(ch) }) | 120 | }, func() { close(ch) }) |
318 | 121 | if err != nil { | 121 | if err != nil { |
320 | 122 | raw.log.Debugf("Failed to set up the watch: %s", err) | 122 | raw.log.Debugf("failed to set up the watch: %s", err) |
321 | 123 | return nil, err | 123 | return nil, err |
322 | 124 | } | 124 | } |
323 | 125 | return ch, nil | 125 | return ch, nil |
324 | 126 | 126 | ||
325 | === modified file 'bus/systemimage/systemimage.go' | |||
326 | --- bus/systemimage/systemimage.go 2014-04-02 08:46:48 +0000 | |||
327 | +++ bus/systemimage/systemimage.go 2015-02-09 10:47:29 +0000 | |||
328 | @@ -57,7 +57,7 @@ | |||
329 | 57 | var _ SystemImage = &systemImage{} // ensures it conforms | 57 | var _ SystemImage = &systemImage{} // ensures it conforms |
330 | 58 | 58 | ||
331 | 59 | func (si *systemImage) Info() (*InfoResult, error) { | 59 | func (si *systemImage) Info() (*InfoResult, error) { |
333 | 60 | si.log.Debugf("Invoking Info") | 60 | si.log.Debugf("invoking Info") |
334 | 61 | res := &InfoResult{} | 61 | res := &InfoResult{} |
335 | 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) |
336 | 63 | if err != nil { | 63 | if err != nil { |
337 | 64 | 64 | ||
338 | === modified file 'bus/testing/testing_endpoint.go' | |||
339 | --- bus/testing/testing_endpoint.go 2014-07-04 23:00:42 +0000 | |||
340 | +++ bus/testing/testing_endpoint.go 2015-02-09 10:47:29 +0000 | |||
341 | @@ -89,7 +89,11 @@ | |||
342 | 89 | ticker := tc.watchTicker | 89 | ticker := tc.watchTicker |
343 | 90 | tc.watchLck.RUnlock() | 90 | tc.watchLck.RUnlock() |
344 | 91 | if ticker != nil { | 91 | if ticker != nil { |
346 | 92 | <-ticker | 92 | _, ok := <-ticker |
347 | 93 | if !ok { | ||
348 | 94 | // bail out | ||
349 | 95 | return | ||
350 | 96 | } | ||
351 | 93 | } else { | 97 | } else { |
352 | 94 | time.Sleep(10 * time.Millisecond) | 98 | time.Sleep(10 * time.Millisecond) |
353 | 95 | } | 99 | } |
354 | 96 | 100 | ||
355 | === modified file 'click/cclick/cclick.go' | |||
356 | --- click/cclick/cclick.go 2014-07-07 22:04:30 +0000 | |||
357 | +++ click/cclick/cclick.go 2015-02-09 10:47:29 +0000 | |||
358 | @@ -51,6 +51,7 @@ | |||
359 | 51 | } | 51 | } |
360 | 52 | ccu.cref = cref | 52 | ccu.cref = cref |
361 | 53 | runtime.SetFinalizer(holder, func(interface{}) { | 53 | runtime.SetFinalizer(holder, func(interface{}) { |
362 | 54 | ccu.cref = nil // 1.3 gc gets confused otherwise | ||
363 | 54 | C.g_object_unref((C.gpointer)(cref)) | 55 | C.g_object_unref((C.gpointer)(cref)) |
364 | 55 | }) | 56 | }) |
365 | 56 | return nil | 57 | return nil |
366 | 57 | 58 | ||
367 | === modified file 'client/client.go' | |||
368 | --- client/client.go 2014-11-03 13:36:00 +0000 | |||
369 | +++ client/client.go 2015-02-09 10:47:29 +0000 | |||
370 | @@ -376,15 +376,15 @@ | |||
371 | 376 | 376 | ||
372 | 377 | // handleConnState deals with connectivity events | 377 | // handleConnState deals with connectivity events |
373 | 378 | func (client *PushClient) handleConnState(hasConnectivity bool) { | 378 | func (client *PushClient) handleConnState(hasConnectivity bool) { |
374 | 379 | client.log.Debugf("handleConnState: %v", hasConnectivity) | ||
375 | 379 | if client.hasConnectivity == hasConnectivity { | 380 | if client.hasConnectivity == hasConnectivity { |
376 | 380 | // nothing to do! | 381 | // nothing to do! |
377 | 381 | return | 382 | return |
378 | 382 | } | 383 | } |
379 | 383 | client.hasConnectivity = hasConnectivity | 384 | client.hasConnectivity = hasConnectivity |
380 | 385 | client.session.Close() | ||
381 | 384 | if hasConnectivity { | 386 | if hasConnectivity { |
382 | 385 | client.session.AutoRedial(client.sessionConnectedCh) | 387 | client.session.AutoRedial(client.sessionConnectedCh) |
383 | 386 | } else { | ||
384 | 387 | client.session.Close() | ||
385 | 388 | } | 388 | } |
386 | 389 | } | 389 | } |
387 | 390 | 390 | ||
388 | @@ -490,7 +490,7 @@ | |||
389 | 490 | case err := <-client.session.ErrCh: | 490 | case err := <-client.session.ErrCh: |
390 | 491 | errhandler(err) | 491 | errhandler(err) |
391 | 492 | case count := <-client.sessionConnectedCh: | 492 | case count := <-client.sessionConnectedCh: |
393 | 493 | client.log.Debugf("Session connected after %d attempts", count) | 493 | client.log.Debugf("session connected after %d attempts", count) |
394 | 494 | case app := <-client.unregisterCh: | 494 | case app := <-client.unregisterCh: |
395 | 495 | unregisterhandler(app) | 495 | unregisterhandler(app) |
396 | 496 | } | 496 | } |
397 | 497 | 497 | ||
398 | === modified file 'client/client_test.go' | |||
399 | --- client/client_test.go 2014-09-05 10:47:29 +0000 | |||
400 | +++ client/client_test.go 2015-02-09 10:47:29 +0000 | |||
401 | @@ -27,6 +27,7 @@ | |||
402 | 27 | "os" | 27 | "os" |
403 | 28 | "path/filepath" | 28 | "path/filepath" |
404 | 29 | "reflect" | 29 | "reflect" |
405 | 30 | //"runtime" | ||
406 | 30 | "testing" | 31 | "testing" |
407 | 31 | "time" | 32 | "time" |
408 | 32 | 33 | ||
409 | @@ -203,6 +204,15 @@ | |||
410 | 203 | cs.writeTestConfig(nil) | 204 | cs.writeTestConfig(nil) |
411 | 204 | } | 205 | } |
412 | 205 | 206 | ||
413 | 207 | func (cs *clientSuite) TearDownTest(c *C) { | ||
414 | 208 | //fmt.Println("GOROUTINE# ", runtime.NumGoroutine()) | ||
415 | 209 | /* | ||
416 | 210 | var x [16*1024]byte | ||
417 | 211 | sz := runtime.Stack(x[:], true) | ||
418 | 212 | fmt.Println(string(x[:sz])) | ||
419 | 213 | */ | ||
420 | 214 | } | ||
421 | 215 | |||
422 | 206 | type sqlientSuite struct{ clientSuite } | 216 | type sqlientSuite struct{ clientSuite } |
423 | 207 | 217 | ||
424 | 208 | func (s *sqlientSuite) SetUpSuite(c *C) { | 218 | func (s *sqlientSuite) SetUpSuite(c *C) { |
425 | @@ -651,7 +661,9 @@ | |||
426 | 651 | ) | 661 | ) |
427 | 652 | siCond := condition.Fail2Work(2) | 662 | siCond := condition.Fail2Work(2) |
428 | 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{}}) |
430 | 654 | testibus.SetWatchTicker(cEndp, make(chan bool)) | 664 | tickerCh := make(chan bool) |
431 | 665 | testibus.SetWatchTicker(cEndp, tickerCh) | ||
432 | 666 | defer close(tickerCh) | ||
433 | 655 | // ok, create the thing | 667 | // ok, create the thing |
434 | 656 | cli := NewPushClient(cs.configPath, cs.leveldbPath) | 668 | cli := NewPushClient(cs.configPath, cs.leveldbPath) |
435 | 657 | cli.log = cs.log | 669 | cli.log = cs.log |
436 | @@ -700,6 +712,7 @@ | |||
437 | 700 | c.Assert(cli.initSessionAndPoller(), IsNil) | 712 | c.Assert(cli.initSessionAndPoller(), IsNil) |
438 | 701 | cs.log.ResetCapture() | 713 | cs.log.ResetCapture() |
439 | 702 | cli.hasConnectivity = true | 714 | cli.hasConnectivity = true |
440 | 715 | defer cli.session.Close() | ||
441 | 703 | cli.handleErr(errors.New("bananas")) | 716 | cli.handleErr(errors.New("bananas")) |
442 | 704 | c.Check(cs.log.Captured(), Matches, ".*session exited.*bananas\n") | 717 | c.Check(cs.log.Captured(), Matches, ".*session exited.*bananas\n") |
443 | 705 | } | 718 | } |
444 | @@ -712,6 +725,7 @@ | |||
445 | 712 | cli := NewPushClient(cs.configPath, "") | 725 | cli := NewPushClient(cs.configPath, "") |
446 | 713 | ln, err := cli.seenStateFactory() | 726 | ln, err := cli.seenStateFactory() |
447 | 714 | c.Assert(err, IsNil) | 727 | c.Assert(err, IsNil) |
448 | 728 | defer ln.Close() | ||
449 | 715 | c.Check(fmt.Sprintf("%T", ln), Equals, "*seenstate.memSeenState") | 729 | c.Check(fmt.Sprintf("%T", ln), Equals, "*seenstate.memSeenState") |
450 | 716 | } | 730 | } |
451 | 717 | 731 | ||
452 | @@ -719,6 +733,7 @@ | |||
453 | 719 | cli := NewPushClient(cs.configPath, ":memory:") | 733 | cli := NewPushClient(cs.configPath, ":memory:") |
454 | 720 | ln, err := cli.seenStateFactory() | 734 | ln, err := cli.seenStateFactory() |
455 | 721 | c.Assert(err, IsNil) | 735 | c.Assert(err, IsNil) |
456 | 736 | defer ln.Close() | ||
457 | 722 | c.Check(fmt.Sprintf("%T", ln), Equals, "*seenstate.sqliteSeenState") | 737 | c.Check(fmt.Sprintf("%T", ln), Equals, "*seenstate.sqliteSeenState") |
458 | 723 | } | 738 | } |
459 | 724 | 739 | ||
460 | @@ -733,6 +748,7 @@ | |||
461 | 733 | c.Assert(cli.initSessionAndPoller(), IsNil) | 748 | c.Assert(cli.initSessionAndPoller(), IsNil) |
462 | 734 | 749 | ||
463 | 735 | c.Assert(cli.hasConnectivity, Equals, false) | 750 | c.Assert(cli.hasConnectivity, Equals, false) |
464 | 751 | defer cli.session.Close() | ||
465 | 736 | cli.handleConnState(true) | 752 | cli.handleConnState(true) |
466 | 737 | c.Check(cli.hasConnectivity, Equals, true) | 753 | c.Check(cli.hasConnectivity, Equals, true) |
467 | 738 | c.Assert(cli.session, NotNil) | 754 | c.Assert(cli.session, NotNil) |
468 | @@ -1135,7 +1151,7 @@ | |||
469 | 1135 | // sessionConnectedCh to nothing in particular, but it'll help sync this test | 1151 | // sessionConnectedCh to nothing in particular, but it'll help sync this test |
470 | 1136 | cli.sessionConnectedCh <- 42 | 1152 | cli.sessionConnectedCh <- 42 |
471 | 1137 | tick() | 1153 | tick() |
473 | 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$") |
474 | 1139 | 1155 | ||
475 | 1140 | // loop() should have connected: | 1156 | // loop() should have connected: |
476 | 1141 | // * connCh to the connectivity checker | 1157 | // * connCh to the connectivity checker |
477 | 1142 | 1158 | ||
478 | === modified file 'client/service/postal.go' | |||
479 | --- client/service/postal.go 2014-11-03 13:36:00 +0000 | |||
480 | +++ client/service/postal.go 2015-02-09 10:47:29 +0000 | |||
481 | @@ -244,7 +244,6 @@ | |||
482 | 244 | for _, endp := range endps { | 244 | for _, endp := range endps { |
483 | 245 | go func(name string, endp bus.Endpoint) { | 245 | go func(name string, endp bus.Endpoint) { |
484 | 246 | util.NewAutoRedialer(endp).Redial() | 246 | util.NewAutoRedialer(endp).Redial() |
485 | 247 | svc.Log.Debugf("%s dialed in", name) | ||
486 | 248 | wg.Done() | 247 | wg.Done() |
487 | 249 | }(endp.name, endp.endp) | 248 | }(endp.name, endp.endp) |
488 | 250 | } | 249 | } |
489 | 251 | 250 | ||
490 | === modified file 'client/service/service.go' | |||
491 | --- client/service/service.go 2014-11-19 13:58:12 +0000 | |||
492 | +++ client/service/service.go 2015-02-09 10:47:29 +0000 | |||
493 | @@ -149,14 +149,14 @@ | |||
494 | 149 | // errors below here Can't Happen (tm). | 149 | // errors below here Can't Happen (tm). |
495 | 150 | body, err := ioutil.ReadAll(resp.Body) | 150 | body, err := ioutil.ReadAll(resp.Body) |
496 | 151 | if err != nil { | 151 | if err != nil { |
498 | 152 | svc.Log.Errorf("Reading response body: %v", err) | 152 | svc.Log.Errorf("during ReadAll() of response body: %v", err) |
499 | 153 | return nil, err | 153 | return nil, err |
500 | 154 | } | 154 | } |
501 | 155 | 155 | ||
502 | 156 | var reply registrationReply | 156 | var reply registrationReply |
503 | 157 | err = json.Unmarshal(body, &reply) | 157 | err = json.Unmarshal(body, &reply) |
504 | 158 | if err != nil { | 158 | if err != nil { |
506 | 159 | svc.Log.Errorf("Unmarshalling response body: %v", err) | 159 | svc.Log.Errorf("during Unmarshal of response body: %v", err) |
507 | 160 | return nil, fmt.Errorf("unable to unmarshal register response: %v", err) | 160 | return nil, fmt.Errorf("unable to unmarshal register response: %v", err) |
508 | 161 | } | 161 | } |
509 | 162 | 162 | ||
510 | @@ -181,7 +181,7 @@ | |||
511 | 181 | } | 181 | } |
512 | 182 | 182 | ||
513 | 183 | if !reply.Ok || reply.Token == "" { | 183 | if !reply.Ok || reply.Token == "" { |
515 | 184 | svc.Log.Errorf("Unexpected response: %#v", reply) | 184 | svc.Log.Errorf("unexpected response: %#v", reply) |
516 | 185 | return nil, ErrBadToken | 185 | return nil, ErrBadToken |
517 | 186 | } | 186 | } |
518 | 187 | 187 | ||
519 | 188 | 188 | ||
520 | === modified file 'client/session/seenstate/seenstate.go' | |||
521 | --- client/session/seenstate/seenstate.go 2014-05-14 17:42:24 +0000 | |||
522 | +++ client/session/seenstate/seenstate.go 2015-02-09 10:47:29 +0000 | |||
523 | @@ -28,8 +28,10 @@ | |||
524 | 28 | // GetAll() returns a "simple" map of the current levels. | 28 | // GetAll() returns a "simple" map of the current levels. |
525 | 29 | GetAllLevels() (map[string]int64, error) | 29 | GetAllLevels() (map[string]int64, error) |
526 | 30 | // FilterBySeen filters notifications already seen, keep track | 30 | // FilterBySeen filters notifications already seen, keep track |
528 | 31 | // of them as well | 31 | // of them as well. |
529 | 32 | FilterBySeen([]protocol.Notification) ([]protocol.Notification, error) | 32 | FilterBySeen([]protocol.Notification) ([]protocol.Notification, error) |
530 | 33 | // Close closes state. | ||
531 | 34 | Close() | ||
532 | 33 | } | 35 | } |
533 | 34 | 36 | ||
534 | 35 | type memSeenState struct { | 37 | type memSeenState struct { |
535 | @@ -58,6 +60,9 @@ | |||
536 | 58 | return acc, nil | 60 | return acc, nil |
537 | 59 | } | 61 | } |
538 | 60 | 62 | ||
539 | 63 | func (m *memSeenState) Close() { | ||
540 | 64 | } | ||
541 | 65 | |||
542 | 61 | var _ SeenState = (*memSeenState)(nil) | 66 | var _ SeenState = (*memSeenState)(nil) |
543 | 62 | 67 | ||
544 | 63 | // NewSeenState returns an implementation of SeenState that is memory-based and | 68 | // NewSeenState returns an implementation of SeenState that is memory-based and |
545 | 64 | 69 | ||
546 | === modified file 'client/session/seenstate/sqlseenstate.go' | |||
547 | --- client/session/seenstate/sqlseenstate.go 2014-05-14 17:42:24 +0000 | |||
548 | +++ client/session/seenstate/sqlseenstate.go 2015-02-09 10:47:29 +0000 | |||
549 | @@ -48,6 +48,11 @@ | |||
550 | 48 | return &sqliteSeenState{db}, nil | 48 | return &sqliteSeenState{db}, nil |
551 | 49 | } | 49 | } |
552 | 50 | 50 | ||
553 | 51 | // Closes closes the underlying db. | ||
554 | 52 | func (ps *sqliteSeenState) Close() { | ||
555 | 53 | ps.db.Close() | ||
556 | 54 | } | ||
557 | 55 | |||
558 | 51 | func (ps *sqliteSeenState) SetLevel(level string, top int64) error { | 56 | func (ps *sqliteSeenState) SetLevel(level string, top int64) error { |
559 | 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) |
560 | 53 | if err != nil { | 58 | if err != nil { |
561 | 54 | 59 | ||
562 | === modified file 'client/session/seenstate/sqlseenstate_test.go' | |||
563 | --- client/session/seenstate/sqlseenstate_test.go 2014-05-14 17:42:24 +0000 | |||
564 | +++ client/session/seenstate/sqlseenstate_test.go 2015-02-09 10:47:29 +0000 | |||
565 | @@ -112,6 +112,15 @@ | |||
566 | 112 | c.Check(err, ErrorMatches, "cannot insert .*") | 112 | c.Check(err, ErrorMatches, "cannot insert .*") |
567 | 113 | } | 113 | } |
568 | 114 | 114 | ||
569 | 115 | func (s *sqlsSuite) TestClose(c *C) { | ||
570 | 116 | dir := c.MkDir() | ||
571 | 117 | filename := dir + "test.db" | ||
572 | 118 | sqls, err := NewSqliteSeenState(filename) | ||
573 | 119 | c.Check(err, IsNil) | ||
574 | 120 | c.Assert(sqls, NotNil) | ||
575 | 121 | sqls.Close() | ||
576 | 122 | } | ||
577 | 123 | |||
578 | 115 | func (s *sqlsSuite) TestDropPrevThan(c *C) { | 124 | func (s *sqlsSuite) TestDropPrevThan(c *C) { |
579 | 116 | dir := c.MkDir() | 125 | dir := c.MkDir() |
580 | 117 | filename := dir + "test.db" | 126 | filename := dir + "test.db" |
581 | 118 | 127 | ||
582 | === modified file 'client/session/session.go' | |||
583 | --- client/session/session.go 2014-11-19 13:58:12 +0000 | |||
584 | +++ client/session/session.go 2015-02-09 10:47:29 +0000 | |||
585 | @@ -74,8 +74,22 @@ | |||
586 | 74 | Connected | 74 | Connected |
587 | 75 | Started | 75 | Started |
588 | 76 | Running | 76 | Running |
589 | 77 | Unknown | ||
590 | 77 | ) | 78 | ) |
591 | 78 | 79 | ||
592 | 80 | func (s ClientSessionState) String() string { | ||
593 | 81 | if s >= Unknown { | ||
594 | 82 | return fmt.Sprintf("??? (%d)", s) | ||
595 | 83 | } | ||
596 | 84 | return [Unknown]string{ | ||
597 | 85 | "Error", | ||
598 | 86 | "Disconnected", | ||
599 | 87 | "Connected", | ||
600 | 88 | "Started", | ||
601 | 89 | "Running", | ||
602 | 90 | }[s] | ||
603 | 91 | } | ||
604 | 92 | |||
605 | 79 | type hostGetter interface { | 93 | type hostGetter interface { |
606 | 80 | Get() (*gethosts.Host, error) | 94 | Get() (*gethosts.Host, error) |
607 | 81 | } | 95 | } |
608 | @@ -131,6 +145,7 @@ | |||
609 | 131 | proto protocol.Protocol | 145 | proto protocol.Protocol |
610 | 132 | pingInterval time.Duration | 146 | pingInterval time.Duration |
611 | 133 | retrier util.AutoRedialer | 147 | retrier util.AutoRedialer |
612 | 148 | retrierLock sync.Mutex | ||
613 | 134 | cookie string | 149 | cookie string |
614 | 135 | // status | 150 | // status |
615 | 136 | stateP *uint32 | 151 | stateP *uint32 |
616 | @@ -220,6 +235,7 @@ | |||
617 | 220 | } | 235 | } |
618 | 221 | 236 | ||
619 | 222 | func (sess *ClientSession) setState(state ClientSessionState) { | 237 | func (sess *ClientSession) setState(state ClientSessionState) { |
620 | 238 | sess.Log.Debugf("session.setState: %s -> %s", ClientSessionState(atomic.LoadUint32(sess.stateP)), state) | ||
621 | 223 | atomic.StoreUint32(sess.stateP, uint32(state)) | 239 | atomic.StoreUint32(sess.stateP, uint32(state)) |
622 | 224 | } | 240 | } |
623 | 225 | 241 | ||
624 | @@ -348,6 +364,8 @@ | |||
625 | 348 | } | 364 | } |
626 | 349 | 365 | ||
627 | 350 | func (sess *ClientSession) stopRedial() { | 366 | func (sess *ClientSession) stopRedial() { |
628 | 367 | sess.retrierLock.Lock() | ||
629 | 368 | defer sess.retrierLock.Unlock() | ||
630 | 351 | if sess.retrier != nil { | 369 | if sess.retrier != nil { |
631 | 352 | sess.retrier.Stop() | 370 | sess.retrier.Stop() |
632 | 353 | sess.retrier = nil | 371 | sess.retrier = nil |
633 | @@ -360,15 +378,31 @@ | |||
634 | 360 | sess.setShouldDelay() | 378 | sess.setShouldDelay() |
635 | 361 | } | 379 | } |
636 | 362 | time.Sleep(sess.redialDelay(sess)) | 380 | time.Sleep(sess.redialDelay(sess)) |
637 | 381 | sess.retrierLock.Lock() | ||
638 | 382 | defer sess.retrierLock.Unlock() | ||
639 | 383 | if sess.retrier != nil { | ||
640 | 384 | panic("session AutoRedial: unexpected non-nil retrier.") | ||
641 | 385 | } | ||
642 | 363 | sess.retrier = util.NewAutoRedialer(sess) | 386 | sess.retrier = util.NewAutoRedialer(sess) |
643 | 364 | sess.lastAutoRedial = time.Now() | 387 | sess.lastAutoRedial = time.Now() |
645 | 365 | go func() { doneCh <- sess.retrier.Redial() }() | 388 | go func() { |
646 | 389 | sess.retrierLock.Lock() | ||
647 | 390 | retrier := sess.retrier | ||
648 | 391 | sess.retrierLock.Unlock() | ||
649 | 392 | if retrier == nil { | ||
650 | 393 | sess.Log.Debugf("session autoredialer skipping retry: retrier has been set to nil.") | ||
651 | 394 | return | ||
652 | 395 | } | ||
653 | 396 | sess.Log.Debugf("session autoredialier launching Redial goroutine") | ||
654 | 397 | doneCh <- retrier.Redial() | ||
655 | 398 | }() | ||
656 | 366 | } | 399 | } |
657 | 367 | 400 | ||
658 | 368 | func (sess *ClientSession) Close() { | 401 | func (sess *ClientSession) Close() { |
659 | 369 | sess.stopRedial() | 402 | sess.stopRedial() |
660 | 370 | sess.doClose() | 403 | sess.doClose() |
661 | 371 | } | 404 | } |
662 | 405 | |||
663 | 372 | func (sess *ClientSession) doClose() { | 406 | func (sess *ClientSession) doClose() { |
664 | 373 | sess.connLock.Lock() | 407 | sess.connLock.Lock() |
665 | 374 | defer sess.connLock.Unlock() | 408 | defer sess.connLock.Unlock() |
666 | @@ -508,6 +542,7 @@ | |||
667 | 508 | sess.proto.SetDeadline(time.Now().Add(deadAfter)) | 542 | sess.proto.SetDeadline(time.Now().Add(deadAfter)) |
668 | 509 | err = sess.proto.ReadMessage(&recv) | 543 | err = sess.proto.ReadMessage(&recv) |
669 | 510 | if err != nil { | 544 | if err != nil { |
670 | 545 | sess.Log.Debugf("session aborting with error on read.") | ||
671 | 511 | sess.setState(Error) | 546 | sess.setState(Error) |
672 | 512 | return err | 547 | return err |
673 | 513 | } | 548 | } |
674 | @@ -529,6 +564,7 @@ | |||
675 | 529 | sess.Log.Errorf("server sent warning: %s", recv.Reason) | 564 | sess.Log.Errorf("server sent warning: %s", recv.Reason) |
676 | 530 | } | 565 | } |
677 | 531 | if err != nil { | 566 | if err != nil { |
678 | 567 | sess.Log.Debugf("session aborting with error from handler.") | ||
679 | 532 | return err | 568 | return err |
680 | 533 | } | 569 | } |
681 | 534 | } | 570 | } |
682 | @@ -591,7 +627,7 @@ | |||
683 | 591 | } | 627 | } |
684 | 592 | sess.proto = proto | 628 | sess.proto = proto |
685 | 593 | sess.pingInterval = pingInterval | 629 | sess.pingInterval = pingInterval |
687 | 594 | sess.Log.Debugf("Connected %v.", conn.RemoteAddr()) | 630 | sess.Log.Debugf("connected %v.", conn.RemoteAddr()) |
688 | 595 | sess.started() // deals with choosing which host to retry with as well | 631 | sess.started() // deals with choosing which host to retry with as well |
689 | 596 | return nil | 632 | return nil |
690 | 597 | } | 633 | } |
691 | 598 | 634 | ||
692 | === modified file 'client/session/session_test.go' | |||
693 | --- client/session/session_test.go 2014-11-25 17:36:27 +0000 | |||
694 | +++ client/session/session_test.go 2015-02-09 10:47:29 +0000 | |||
695 | @@ -162,6 +162,7 @@ | |||
696 | 162 | 162 | ||
697 | 163 | func (*brokenSeenState) SetLevel(string, int64) error { return errors.New("broken.") } | 163 | func (*brokenSeenState) SetLevel(string, int64) error { return errors.New("broken.") } |
698 | 164 | func (*brokenSeenState) GetAllLevels() (map[string]int64, error) { return nil, errors.New("broken.") } | 164 | func (*brokenSeenState) GetAllLevels() (map[string]int64, error) { return nil, errors.New("broken.") } |
699 | 165 | func (*brokenSeenState) Close() {} | ||
700 | 165 | func (*brokenSeenState) FilterBySeen([]protocol.Notification) ([]protocol.Notification, error) { | 166 | func (*brokenSeenState) FilterBySeen([]protocol.Notification) ([]protocol.Notification, error) { |
701 | 166 | return nil, errors.New("broken.") | 167 | return nil, errors.New("broken.") |
702 | 167 | } | 168 | } |
703 | 168 | 169 | ||
704 | === modified file 'debian/changelog' | |||
705 | --- debian/changelog 2014-12-11 16:56:31 +0000 | |||
706 | +++ debian/changelog 2015-02-09 10:47:29 +0000 | |||
707 | @@ -1,3 +1,43 @@ | |||
708 | 1 | ubuntu-push (0.67-0ubuntu1) UNRELEASED; urgency=medium | ||
709 | 2 | |||
710 | 3 | * Updated precommit script. [dev] | ||
711 | 4 | |||
712 | 5 | * Include code examples in docs (instead of repeating). [docs] | ||
713 | 6 | |||
714 | 7 | * Make tests more robust in the face of go 1.3 [client, server] | ||
715 | 8 | |||
716 | 9 | * Introduce StartClientAuthFlex for acceptance tests: Start a client | ||
717 | 10 | with auth, take a devId regexp, don't check any client event; support | ||
718 | 11 | connbroken in acceptanceclient. [server] | ||
719 | 12 | |||
720 | 13 | * Cleanup and improve logging, and make log messages more | ||
721 | 14 | consistent. [client] | ||
722 | 15 | |||
723 | 16 | * Partially work around bug lp:1390663 in a minimally intrusive way | ||
724 | 17 | (real fix will have to wait). [client] | ||
725 | 18 | |||
726 | 19 | * Add SIGQUIT handler to spit out stack dumps; more logging | ||
727 | 20 | tweaks. [client, server] | ||
728 | 21 | |||
729 | 22 | * Adds a couple of buttons to exercise more APIs, version bump to | ||
730 | 23 | 0.44. [sample app] | ||
731 | 24 | |||
732 | 25 | * Add APIError to server/acceptance/kit that includes the body for | ||
733 | 26 | debugging. [server] | ||
734 | 27 | |||
735 | 28 | * Add DisableKeepAlives and MaxIdleConnsPerHost to the APIClient | ||
736 | 29 | SetupClient method. [server] | ||
737 | 30 | |||
738 | 31 | * Clean up goroutines in tests. [client] | ||
739 | 32 | |||
740 | 33 | * Add an explicit check and log message for nil error on webcheck's CopyN. [client] | ||
741 | 34 | |||
742 | 35 | * Log line nums, enabled when logLevel = debug. [client server] | ||
743 | 36 | |||
744 | 37 | * Workaround gc issue with 1.3 and 32 bits. Fixes FTBFS. [client] | ||
745 | 38 | |||
746 | 39 | -- John R. Lenton <john.lenton@canonical.com> Mon, 09 Feb 2015 10:19:59 +0000 | ||
747 | 40 | |||
748 | 1 | ubuntu-push (0.66+15.04.20141211-0ubuntu1) vivid; urgency=medium | 41 | ubuntu-push (0.66+15.04.20141211-0ubuntu1) vivid; urgency=medium |
749 | 2 | 42 | ||
750 | 3 | [ Roberto Alsina ] | 43 | [ Roberto Alsina ] |
751 | 4 | 44 | ||
752 | === modified file 'dependencies.tsv' | |||
753 | --- dependencies.tsv 2014-08-20 12:42:51 +0000 | |||
754 | +++ dependencies.tsv 2015-02-09 10:47:29 +0000 | |||
755 | @@ -1,5 +1,5 @@ | |||
756 | 1 | code.google.com/p/go-uuid hg 7dda39b2e7d5e265014674c5af696ba4186679e9 11 | 1 | code.google.com/p/go-uuid hg 7dda39b2e7d5e265014674c5af696ba4186679e9 11 |
757 | 2 | code.google.com/p/gosqlite hg 74691fb6f83716190870cde1b658538dd4b18eb0 15 | 2 | code.google.com/p/gosqlite hg 74691fb6f83716190870cde1b658538dd4b18eb0 15 |
759 | 3 | launchpad.net/go-dbus/v1 bzr james@jamesh.id.au-20140801110939-lzfql7fk76dt6ckd 128 | 3 | launchpad.net/go-dbus/v1 bzr jlenton@gmail.com-20141023032446-s5icvsucwlv5o38a 129 |
760 | 4 | launchpad.net/go-xdg/v0 bzr john.lenton@canonical.com-20140208094800-gubd5md7cro3mtxa 10 | 4 | launchpad.net/go-xdg/v0 bzr john.lenton@canonical.com-20140208094800-gubd5md7cro3mtxa 10 |
761 | 5 | launchpad.net/gocheck bzr gustavo@niemeyer.net-20140225173054-xu9zlkf9kxhvow02 87 | 5 | launchpad.net/gocheck bzr gustavo@niemeyer.net-20140225173054-xu9zlkf9kxhvow02 87 |
762 | 6 | 6 | ||
763 | === modified file 'docs/example-client/main.qml' | |||
764 | --- docs/example-client/main.qml 2014-10-23 15:37:21 +0000 | |||
765 | +++ docs/example-client/main.qml 2015-02-09 10:47:29 +0000 | |||
766 | @@ -71,8 +71,12 @@ | |||
767 | 71 | Component.onCompleted: { | 71 | Component.onCompleted: { |
768 | 72 | notificationsChanged.connect(messageList.handle_notifications) | 72 | notificationsChanged.connect(messageList.handle_notifications) |
769 | 73 | error.connect(messageList.handle_error) | 73 | error.connect(messageList.handle_error) |
770 | 74 | onTokenChanged: { | ||
771 | 75 | console.log("foooooo") | ||
772 | 76 | } | ||
773 | 74 | } | 77 | } |
774 | 75 | appId: "com.ubuntu.developer.ralsina.hello_hello" | 78 | appId: "com.ubuntu.developer.ralsina.hello_hello" |
775 | 79 | |||
776 | 76 | } | 80 | } |
777 | 77 | 81 | ||
778 | 78 | TextField { | 82 | TextField { |
779 | @@ -227,7 +231,7 @@ | |||
780 | 227 | right: parent.right | 231 | right: parent.right |
781 | 228 | bottom: parent.bottom | 232 | bottom: parent.bottom |
782 | 229 | } | 233 | } |
784 | 230 | height: item1.height * 7 | 234 | height: item1.height * 9 |
785 | 231 | UbuntuShape { | 235 | UbuntuShape { |
786 | 232 | anchors.fill: parent | 236 | anchors.fill: parent |
787 | 233 | color: Theme.palette.normal.overlay | 237 | color: Theme.palette.normal.overlay |
788 | @@ -285,6 +289,14 @@ | |||
789 | 285 | value: 42 | 289 | value: 42 |
790 | 286 | } | 290 | } |
791 | 287 | } | 291 | } |
792 | 292 | Button { | ||
793 | 293 | text: "Set Counter Via Plugin" | ||
794 | 294 | onClicked: { pushClient.count = counterSlider.value; } | ||
795 | 295 | } | ||
796 | 296 | Button { | ||
797 | 297 | text: "Clear Persistent Notifications" | ||
798 | 298 | onClicked: { pushClient.clearPersistent([]); } | ||
799 | 299 | } | ||
800 | 288 | } | 300 | } |
801 | 289 | } | 301 | } |
802 | 290 | } | 302 | } |
803 | 291 | 303 | ||
804 | === modified file 'docs/example-client/manifest.json' | |||
805 | --- docs/example-client/manifest.json 2014-10-23 17:46:23 +0000 | |||
806 | +++ docs/example-client/manifest.json 2015-02-09 10:47:29 +0000 | |||
807 | @@ -1,7 +1,7 @@ | |||
808 | 1 | { | 1 | { |
809 | 2 | "architecture": "all", | 2 | "architecture": "all", |
810 | 3 | "description": "Example app for Ubuntu push notifications.", | 3 | "description": "Example app for Ubuntu push notifications.", |
812 | 4 | "framework": "ubuntu-sdk-14.10-dev2", | 4 | "framework": "ubuntu-sdk-14.10", |
813 | 5 | "hooks": { | 5 | "hooks": { |
814 | 6 | "hello": { | 6 | "hello": { |
815 | 7 | "apparmor": "hello.json", | 7 | "apparmor": "hello.json", |
816 | @@ -15,5 +15,5 @@ | |||
817 | 15 | "maintainer": "Roberto Alsina <roberto.alsina@canonical.com>", | 15 | "maintainer": "Roberto Alsina <roberto.alsina@canonical.com>", |
818 | 16 | "name": "com.ubuntu.developer.ralsina.hello", | 16 | "name": "com.ubuntu.developer.ralsina.hello", |
819 | 17 | "title": "Hello", | 17 | "title": "Hello", |
821 | 18 | "version": "0.4.3" | 18 | "version": "0.4.4" |
822 | 19 | } | 19 | } |
823 | 20 | 20 | ||
824 | === modified file 'identifier/identifier.go' | |||
825 | --- identifier/identifier.go 2014-08-04 20:40:50 +0000 | |||
826 | +++ identifier/identifier.go 2015-02-09 10:47:29 +0000 | |||
827 | @@ -48,7 +48,7 @@ | |||
828 | 48 | func New() (Id, error) { | 48 | func New() (Id, error) { |
829 | 49 | value, err := readMachineId() | 49 | value, err := readMachineId() |
830 | 50 | if err != nil { | 50 | if err != nil { |
832 | 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) |
833 | 52 | } | 52 | } |
834 | 53 | return &Identifier{value: value}, nil | 53 | return &Identifier{value: value}, nil |
835 | 54 | } | 54 | } |
836 | 55 | 55 | ||
837 | === modified file 'identifier/identifier_test.go' | |||
838 | --- identifier/identifier_test.go 2014-08-12 00:32:32 +0000 | |||
839 | +++ identifier/identifier_test.go 2015-02-09 10:47:29 +0000 | |||
840 | @@ -48,7 +48,7 @@ | |||
841 | 48 | machineIdPath = "/var/lib/dbus/no-such-file" | 48 | machineIdPath = "/var/lib/dbus/no-such-file" |
842 | 49 | id, err := New() | 49 | id, err := New() |
843 | 50 | c.Check(err, NotNil) | 50 | c.Check(err, NotNil) |
845 | 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") |
846 | 52 | c.Check(id.String(), HasLen, 0) | 52 | c.Check(id.String(), HasLen, 0) |
847 | 53 | } | 53 | } |
848 | 54 | 54 | ||
849 | 55 | 55 | ||
850 | === modified file 'launch_helper/helper_finder/helper_finder.go' | |||
851 | --- launch_helper/helper_finder/helper_finder.go 2014-07-29 15:36:00 +0000 | |||
852 | +++ launch_helper/helper_finder/helper_finder.go 2015-02-09 10:47:29 +0000 | |||
853 | @@ -72,7 +72,7 @@ | |||
854 | 72 | fInfo, err := os.Stat(helpersDataPath) | 72 | fInfo, err := os.Stat(helpersDataPath) |
855 | 73 | if err != nil { | 73 | if err != nil { |
856 | 74 | // cache file is missing, go via the slow route | 74 | // cache file is missing, go via the slow route |
858 | 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") |
859 | 76 | return helperFromHookFile(app) | 76 | return helperFromHookFile(app) |
860 | 77 | } | 77 | } |
861 | 78 | // get the lock as the map can be changed while we read | 78 | // get the lock as the map can be changed while we read |
862 | 79 | 79 | ||
863 | === modified file 'launch_helper/helper_finder/helper_finder_test.go' | |||
864 | --- launch_helper/helper_finder/helper_finder_test.go 2014-07-29 15:36:00 +0000 | |||
865 | +++ launch_helper/helper_finder/helper_finder_test.go 2015-02-09 10:47:29 +0000 | |||
866 | @@ -139,7 +139,7 @@ | |||
867 | 139 | hid, hex := Helper(app, s.log) | 139 | hid, hex := Helper(app, s.log) |
868 | 140 | c.Check(hid, Equals, "com.example.test_test-helper_1") | 140 | c.Check(hid, Equals, "com.example.test_test-helper_1") |
869 | 141 | c.Check(hex, Equals, filepath.Join(s.symlinkPath, "tsthlpr")) | 141 | c.Check(hex, Equals, filepath.Join(s.symlinkPath, "tsthlpr")) |
871 | 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") |
872 | 143 | } | 143 | } |
873 | 144 | 144 | ||
874 | 145 | func (s *helperSuite) TestHelperFromHookBasic(c *C) { | 145 | func (s *helperSuite) TestHelperFromHookBasic(c *C) { |
875 | 146 | 146 | ||
876 | === modified file 'launch_helper/kindpool.go' | |||
877 | --- launch_helper/kindpool.go 2014-11-05 12:07:53 +0000 | |||
878 | +++ launch_helper/kindpool.go 2015-02-09 10:47:29 +0000 | |||
879 | @@ -296,7 +296,7 @@ | |||
880 | 296 | if err != nil { | 296 | if err != nil { |
881 | 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) |
882 | 298 | } else { | 298 | } else { |
884 | 299 | pool.log.Infof("%v helper output: %#v", args.AppId, payload) | 299 | pool.log.Infof("%v helper output: %s", args.AppId, payload) |
885 | 300 | res := &HelperResult{Input: args.Input} | 300 | res := &HelperResult{Input: args.Input} |
886 | 301 | err = json.Unmarshal(payload, &res.HelperOutput) | 301 | err = json.Unmarshal(payload, &res.HelperOutput) |
887 | 302 | if err != nil { | 302 | if err != nil { |
888 | 303 | 303 | ||
889 | === modified file 'launch_helper/legacy/legacy.go' | |||
890 | --- launch_helper/legacy/legacy.go 2014-11-05 12:07:53 +0000 | |||
891 | +++ launch_helper/legacy/legacy.go 2015-02-09 10:47:29 +0000 | |||
892 | @@ -78,7 +78,7 @@ | |||
893 | 78 | p_err := cmd.Wait() | 78 | p_err := cmd.Wait() |
894 | 79 | if p_err != nil { | 79 | if p_err != nil { |
895 | 80 | // Helper failed or got killed, log output/errors | 80 | // Helper failed or got killed, log output/errors |
897 | 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.", |
898 | 82 | appId, progname, id, p_err, stdout.String(), stderr.String()) | 82 | appId, progname, id, p_err, stdout.String(), stderr.String()) |
899 | 83 | } | 83 | } |
900 | 84 | lhl.done(id) | 84 | lhl.done(id) |
901 | 85 | 85 | ||
902 | === modified file 'launch_helper/legacy/legacy_test.go' | |||
903 | --- launch_helper/legacy/legacy_test.go 2014-08-21 18:03:49 +0000 | |||
904 | +++ launch_helper/legacy/legacy_test.go 2015-02-09 10:47:29 +0000 | |||
905 | @@ -104,7 +104,7 @@ | |||
906 | 104 | c.Assert(err, IsNil) | 104 | c.Assert(err, IsNil) |
907 | 105 | 105 | ||
908 | 106 | takeNext(ch, c) | 106 | takeNext(ch, c) |
910 | 107 | c.Check(ls.log.Captured(), Matches, "(?s).*Legacy helper failed.*") | 107 | c.Check(ls.log.Captured(), Matches, "(?si).*Legacy helper failed.*") |
911 | 108 | } | 108 | } |
912 | 109 | 109 | ||
913 | 110 | func (ls *legacySuite) TestHelperFailsLog(c *C) { | 110 | func (ls *legacySuite) TestHelperFailsLog(c *C) { |
914 | 111 | 111 | ||
915 | === modified file 'logger/logger.go' | |||
916 | --- logger/logger.go 2014-04-11 23:17:40 +0000 | |||
917 | +++ logger/logger.go 2015-02-09 10:47:29 +0000 | |||
918 | @@ -50,7 +50,8 @@ | |||
919 | 50 | } | 50 | } |
920 | 51 | 51 | ||
921 | 52 | const ( | 52 | const ( |
923 | 53 | lError = iota | 53 | calldepthBase = 3 |
924 | 54 | lError = iota | ||
925 | 54 | lInfo | 55 | lInfo |
926 | 55 | lDebug | 56 | lDebug |
927 | 56 | ) | 57 | ) |
928 | @@ -81,8 +82,12 @@ | |||
929 | 81 | // level. The level can be, in order: "error", "info", "debug". It takes an | 82 | // level. The level can be, in order: "error", "info", "debug". It takes an |
930 | 82 | // io.Writer. | 83 | // io.Writer. |
931 | 83 | func NewSimpleLogger(w io.Writer, level string) Logger { | 84 | func NewSimpleLogger(w io.Writer, level string) Logger { |
932 | 85 | flags := log.Ldate | log.Ltime | log.Lmicroseconds | ||
933 | 86 | if levelToNLevel[level] >= lDebug { | ||
934 | 87 | flags = flags | log.Lshortfile | ||
935 | 88 | } | ||
936 | 84 | return NewSimpleLoggerFromMinimalLogger( | 89 | return NewSimpleLoggerFromMinimalLogger( |
938 | 85 | log.New(w, "", log.Ldate|log.Ltime|log.Lmicroseconds), | 90 | log.New(w, "", flags), |
939 | 86 | level, | 91 | level, |
940 | 87 | ) | 92 | ) |
941 | 88 | } | 93 | } |
942 | @@ -92,13 +97,13 @@ | |||
943 | 92 | } | 97 | } |
944 | 93 | 98 | ||
945 | 94 | func (lg *simpleLogger) Errorf(format string, v ...interface{}) { | 99 | func (lg *simpleLogger) Errorf(format string, v ...interface{}) { |
947 | 95 | lg.outputFunc(2, fmt.Sprintf("ERROR "+format, v...)) | 100 | lg.outputFunc(calldepthBase, fmt.Sprintf("ERROR "+format, v...)) |
948 | 96 | } | 101 | } |
949 | 97 | 102 | ||
950 | 98 | var osExit = os.Exit // for testing | 103 | var osExit = os.Exit // for testing |
951 | 99 | 104 | ||
952 | 100 | func (lg *simpleLogger) Fatalf(format string, v ...interface{}) { | 105 | func (lg *simpleLogger) Fatalf(format string, v ...interface{}) { |
954 | 101 | lg.outputFunc(2, fmt.Sprintf("ERROR "+format, v...)) | 106 | lg.outputFunc(calldepthBase, fmt.Sprintf("ERROR "+format, v...)) |
955 | 102 | osExit(1) | 107 | osExit(1) |
956 | 103 | } | 108 | } |
957 | 104 | 109 | ||
958 | @@ -107,18 +112,18 @@ | |||
959 | 107 | stack := make([]byte, 8*1024) // Stack writes less but doesn't fail | 112 | stack := make([]byte, 8*1024) // Stack writes less but doesn't fail |
960 | 108 | stackWritten := runtime.Stack(stack, false) | 113 | stackWritten := runtime.Stack(stack, false) |
961 | 109 | stack = stack[:stackWritten] | 114 | stack = stack[:stackWritten] |
963 | 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)) |
964 | 111 | } | 116 | } |
965 | 112 | 117 | ||
966 | 113 | func (lg *simpleLogger) Infof(format string, v ...interface{}) { | 118 | func (lg *simpleLogger) Infof(format string, v ...interface{}) { |
967 | 114 | if lg.nlevel >= lInfo { | 119 | if lg.nlevel >= lInfo { |
969 | 115 | lg.outputFunc(2, fmt.Sprintf("INFO "+format, v...)) | 120 | lg.outputFunc(calldepthBase, fmt.Sprintf("INFO "+format, v...)) |
970 | 116 | } | 121 | } |
971 | 117 | } | 122 | } |
972 | 118 | 123 | ||
973 | 119 | func (lg *simpleLogger) Debugf(format string, v ...interface{}) { | 124 | func (lg *simpleLogger) Debugf(format string, v ...interface{}) { |
974 | 120 | if lg.nlevel >= lDebug { | 125 | if lg.nlevel >= lDebug { |
976 | 121 | lg.outputFunc(2, fmt.Sprintf("DEBUG "+format, v...)) | 126 | lg.outputFunc(calldepthBase, fmt.Sprintf("DEBUG "+format, v...)) |
977 | 122 | } | 127 | } |
978 | 123 | } | 128 | } |
979 | 124 | 129 | ||
980 | 125 | 130 | ||
981 | === modified file 'logger/logger_test.go' | |||
982 | --- logger/logger_test.go 2014-04-11 19:05:35 +0000 | |||
983 | +++ logger/logger_test.go 2015-02-09 10:47:29 +0000 | |||
984 | @@ -163,3 +163,15 @@ | |||
985 | 163 | checkError(`{"lvl": 1}`, "lvl:.*type string") | 163 | checkError(`{"lvl": 1}`, "lvl:.*type string") |
986 | 164 | checkError(`{"lvl": "foo"}`, "lvl: not a log level: foo") | 164 | checkError(`{"lvl": "foo"}`, "lvl: not a log level: foo") |
987 | 165 | } | 165 | } |
988 | 166 | |||
989 | 167 | func (s *loggerSuite) TestLogLineNo(c *C) { | ||
990 | 168 | buf := &bytes.Buffer{} | ||
991 | 169 | logger := NewSimpleLogger(buf, "debug") | ||
992 | 170 | logger.Output(1, "foobaz") | ||
993 | 171 | c.Check(buf.String(), Matches, ".* .* logger_test.go:[0-9]+: foobaz\n") | ||
994 | 172 | |||
995 | 173 | buf.Reset() | ||
996 | 174 | logger = NewSimpleLogger(buf, "error") | ||
997 | 175 | logger.Output(1, "foobaz") | ||
998 | 176 | c.Check(buf.String(), Matches, ".* .* foobaz\n") | ||
999 | 177 | } | ||
1000 | 166 | 178 | ||
1001 | === modified file 'messaging/messaging.go' | |||
1002 | --- messaging/messaging.go 2014-07-27 02:54:40 +0000 | |||
1003 | +++ messaging/messaging.go 2015-02-09 10:47:29 +0000 | |||
1004 | @@ -181,7 +181,7 @@ | |||
1005 | 181 | Action: action, | 181 | Action: action, |
1006 | 182 | }) | 182 | }) |
1007 | 183 | if err != nil { | 183 | if err != nil { |
1009 | 184 | mmu.Log.Errorf("Failed to build action: %s", action) | 184 | mmu.Log.Errorf("failed to build action: %s", action) |
1010 | 185 | return false | 185 | return false |
1011 | 186 | } | 186 | } |
1012 | 187 | actions[2*i] = string(act) | 187 | actions[2*i] = string(act) |
1013 | 188 | 188 | ||
1014 | === modified file 'poller/poller.go' | |||
1015 | --- poller/poller.go 2014-08-29 13:50:16 +0000 | |||
1016 | +++ poller/poller.go 2015-02-09 10:47:29 +0000 | |||
1017 | @@ -167,7 +167,7 @@ | |||
1018 | 167 | // the channel will produce a true for every | 167 | // the channel will produce a true for every |
1019 | 168 | // wakeup, not only the one we asked for | 168 | // wakeup, not only the one we asked for |
1020 | 169 | now := time.Now() | 169 | now := time.Now() |
1022 | 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)) |
1023 | 171 | if !now.Before(t) { | 171 | if !now.Before(t) { |
1024 | 172 | break | 172 | break |
1025 | 173 | } | 173 | } |
1026 | 174 | 174 | ||
1027 | === modified file 'server/acceptance/acceptanceclient.go' | |||
1028 | --- server/acceptance/acceptanceclient.go 2014-08-27 21:19:51 +0000 | |||
1029 | +++ server/acceptance/acceptanceclient.go 2015-02-09 10:47:29 +0000 | |||
1030 | @@ -176,6 +176,8 @@ | |||
1031 | 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) |
1032 | 177 | case "warn", "connwarn": | 177 | case "warn", "connwarn": |
1033 | 178 | events <- fmt.Sprintf("%sconnwarn %s", sess.Prefix, recv.Reason) | 178 | events <- fmt.Sprintf("%sconnwarn %s", sess.Prefix, recv.Reason) |
1034 | 179 | case "connbroken": | ||
1035 | 180 | events <- fmt.Sprintf("%sconnbroken %s", sess.Prefix, recv.Reason) | ||
1036 | 179 | case "setparams": | 181 | case "setparams": |
1037 | 180 | sess.SetCookie(recv.SetCookie) | 182 | sess.SetCookie(recv.SetCookie) |
1038 | 181 | if sess.ReportSetParams { | 183 | if sess.ReportSetParams { |
1039 | 182 | 184 | ||
1040 | === modified file 'server/acceptance/kit/api.go' | |||
1041 | --- server/acceptance/kit/api.go 2014-08-20 19:48:59 +0000 | |||
1042 | +++ server/acceptance/kit/api.go 2015-02-09 10:47:29 +0000 | |||
1043 | @@ -35,10 +35,21 @@ | |||
1044 | 35 | httpClient *http.Client | 35 | httpClient *http.Client |
1045 | 36 | } | 36 | } |
1046 | 37 | 37 | ||
1047 | 38 | type APIError struct { | ||
1048 | 39 | Msg string | ||
1049 | 40 | Body []byte | ||
1050 | 41 | } | ||
1051 | 42 | |||
1052 | 43 | func (e *APIError) Error() string { | ||
1053 | 44 | return e.Msg | ||
1054 | 45 | } | ||
1055 | 46 | |||
1056 | 38 | // SetupClient sets up the http client to make requests. | 47 | // SetupClient sets up the http client to make requests. |
1058 | 39 | func (api *APIClient) SetupClient(tlsConfig *tls.Config) { | 48 | func (api *APIClient) SetupClient(tlsConfig *tls.Config, disableKeepAlives bool, maxIdleConnsPerHost int) { |
1059 | 40 | api.httpClient = &http.Client{ | 49 | api.httpClient = &http.Client{ |
1061 | 41 | Transport: &http.Transport{TLSClientConfig: tlsConfig}, | 50 | Transport: &http.Transport{TLSClientConfig: tlsConfig, |
1062 | 51 | DisableKeepAlives: disableKeepAlives, | ||
1063 | 52 | MaxIdleConnsPerHost: maxIdleConnsPerHost}, | ||
1064 | 42 | } | 53 | } |
1065 | 43 | } | 54 | } |
1066 | 44 | 55 | ||
1067 | @@ -73,7 +84,7 @@ | |||
1068 | 73 | var res map[string]interface{} | 84 | var res map[string]interface{} |
1069 | 74 | err = json.Unmarshal(body, &res) | 85 | err = json.Unmarshal(body, &res) |
1070 | 75 | if err != nil { | 86 | if err != nil { |
1072 | 76 | return nil, err | 87 | return nil, &APIError{err.Error(), body} |
1073 | 77 | } | 88 | } |
1074 | 78 | if ok, _ := res["ok"].(bool); !ok { | 89 | if ok, _ := res["ok"].(bool); !ok { |
1075 | 79 | return res, ErrNOk | 90 | return res, ErrNOk |
1076 | 80 | 91 | ||
1077 | === modified file 'server/acceptance/suites/helpers.go' | |||
1078 | --- server/acceptance/suites/helpers.go 2014-11-04 16:29:31 +0000 | |||
1079 | +++ server/acceptance/suites/helpers.go 2015-02-09 10:47:29 +0000 | |||
1080 | @@ -80,7 +80,7 @@ | |||
1081 | 80 | return cfgFpath | 80 | return cfgFpath |
1082 | 81 | } | 81 | } |
1083 | 82 | 82 | ||
1085 | 83 | var rxLineInfo = regexp.MustCompile("^.*? ([[:alpha:]].*)\n") | 83 | var rxLineInfo = regexp.MustCompile("^.*?(?: .+\\.go:\\d+:)? ([[:alpha:]].*)\n") |
1086 | 84 | 84 | ||
1087 | 85 | // RunAndObserve runs cmdName and returns a channel that will receive | 85 | // RunAndObserve runs cmdName and returns a channel that will receive |
1088 | 86 | // cmdName stderr logging and a function to kill the process. | 86 | // cmdName stderr logging and a function to kill the process. |
1089 | 87 | 87 | ||
1090 | === modified file 'server/acceptance/suites/suite.go' | |||
1091 | --- server/acceptance/suites/suite.go 2014-09-01 14:48:03 +0000 | |||
1092 | +++ server/acceptance/suites/suite.go 2015-02-09 10:47:29 +0000 | |||
1093 | @@ -21,7 +21,9 @@ | |||
1094 | 21 | "flag" | 21 | "flag" |
1095 | 22 | "fmt" | 22 | "fmt" |
1096 | 23 | "net" | 23 | "net" |
1097 | 24 | "net/http" | ||
1098 | 24 | "os" | 25 | "os" |
1099 | 26 | "regexp" | ||
1100 | 25 | "runtime" | 27 | "runtime" |
1101 | 26 | "time" | 28 | "time" |
1102 | 27 | 29 | ||
1103 | @@ -48,6 +50,13 @@ | |||
1104 | 48 | 50 | ||
1105 | 49 | // Start a client with auth. | 51 | // Start a client with auth. |
1106 | 50 | func (h *ServerHandle) StartClientAuth(c *C, devId string, levels map[string]int64, auth string, cookie string) (events <-chan string, errorCh <-chan error, stop func()) { | 52 | func (h *ServerHandle) StartClientAuth(c *C, devId string, levels map[string]int64, auth string, cookie string) (events <-chan string, errorCh <-chan error, stop func()) { |
1107 | 53 | cliEvents, errCh, stop := h.StartClientAuthFlex(c, devId, levels, auth, cookie, regexp.QuoteMeta(devId)) | ||
1108 | 54 | c.Assert(NextEvent(cliEvents, errCh), Matches, "connected .*") | ||
1109 | 55 | return cliEvents, errCh, stop | ||
1110 | 56 | } | ||
1111 | 57 | |||
1112 | 58 | // Start a client with auth, take a devId regexp, don't check any client event. | ||
1113 | 59 | func (h *ServerHandle) StartClientAuthFlex(c *C, devId string, levels map[string]int64, auth, cookie, devIdRegexp string) (events <-chan string, errorCh <-chan error, stop func()) { | ||
1114 | 51 | errCh := make(chan error, 1) | 60 | errCh := make(chan error, 1) |
1115 | 52 | cliEvents := make(chan string, 10) | 61 | cliEvents := make(chan string, 10) |
1116 | 53 | sess := testClientSession(h.ServerAddr, devId, "m1", "img1", false) | 62 | sess := testClientSession(h.ServerAddr, devId, "m1", "img1", false) |
1117 | @@ -76,9 +85,8 @@ | |||
1118 | 76 | go func() { | 85 | go func() { |
1119 | 77 | errCh <- sess.Run(cliEvents) | 86 | errCh <- sess.Run(cliEvents) |
1120 | 78 | }() | 87 | }() |
1121 | 79 | c.Assert(NextEvent(cliEvents, errCh), Matches, "connected .*") | ||
1122 | 80 | c.Assert(NextEvent(h.ServerEvents, nil), Matches, ".*session.* connected .*") | 88 | c.Assert(NextEvent(h.ServerEvents, nil), Matches, ".*session.* connected .*") |
1124 | 81 | c.Assert(NextEvent(h.ServerEvents, nil), Matches, ".*session.* registered "+devId) | 89 | c.Assert(NextEvent(h.ServerEvents, nil), Matches, ".*session.* registered "+devIdRegexp) |
1125 | 82 | return cliEvents, errCh, func() { clientShutdown <- true } | 90 | return cliEvents, errCh, func() { clientShutdown <- true } |
1126 | 83 | } | 91 | } |
1127 | 84 | 92 | ||
1128 | @@ -101,7 +109,7 @@ | |||
1129 | 101 | c.Assert(s.ServerHandle.ServerEvents, NotNil) | 109 | c.Assert(s.ServerHandle.ServerEvents, NotNil) |
1130 | 102 | c.Assert(s.ServerHandle.ServerAddr, Not(Equals), "") | 110 | c.Assert(s.ServerHandle.ServerAddr, Not(Equals), "") |
1131 | 103 | c.Assert(s.ServerAPIURL, Not(Equals), "") | 111 | c.Assert(s.ServerAPIURL, Not(Equals), "") |
1133 | 104 | s.SetupClient(nil) | 112 | s.SetupClient(nil, false, http.DefaultMaxIdleConnsPerHost) |
1134 | 105 | } | 113 | } |
1135 | 106 | 114 | ||
1136 | 107 | func (s *AcceptanceSuite) TearDownTest(c *C) { | 115 | func (s *AcceptanceSuite) TearDownTest(c *C) { |
1137 | 108 | 116 | ||
1138 | === modified file 'testing/helpers.go' | |||
1139 | --- testing/helpers.go 2014-07-11 19:42:57 +0000 | |||
1140 | +++ testing/helpers.go 2015-02-09 10:47:29 +0000 | |||
1141 | @@ -118,7 +118,7 @@ | |||
1142 | 118 | 118 | ||
1143 | 119 | idx := strings.LastIndex(dir, sep) | 119 | idx := strings.LastIndex(dir, sep) |
1144 | 120 | if idx == -1 { | 120 | if idx == -1 { |
1146 | 121 | panic(fmt.Errorf("Unable to find %s in %#v", sep, dir)) | 121 | panic(fmt.Errorf("unable to find %s in %#v", sep, dir)) |
1147 | 122 | } | 122 | } |
1148 | 123 | idx += len(sep) | 123 | idx += len(sep) |
1149 | 124 | 124 | ||
1150 | 125 | 125 | ||
1151 | === modified file 'ubuntu-push-client.go' | |||
1152 | --- ubuntu-push-client.go 2014-05-08 22:29:26 +0000 | |||
1153 | +++ ubuntu-push-client.go 2015-02-09 10:47:29 +0000 | |||
1154 | @@ -18,13 +18,31 @@ | |||
1155 | 18 | 18 | ||
1156 | 19 | import ( | 19 | import ( |
1157 | 20 | "log" | 20 | "log" |
1158 | 21 | "os" | ||
1159 | 22 | "os/signal" | ||
1160 | 23 | "runtime" | ||
1161 | 24 | "syscall" | ||
1162 | 21 | 25 | ||
1163 | 22 | "launchpad.net/go-xdg/v0" | 26 | "launchpad.net/go-xdg/v0" |
1164 | 23 | 27 | ||
1165 | 24 | "launchpad.net/ubuntu-push/client" | 28 | "launchpad.net/ubuntu-push/client" |
1166 | 25 | ) | 29 | ) |
1167 | 26 | 30 | ||
1168 | 31 | func installSigQuitHandler() { | ||
1169 | 32 | go func() { | ||
1170 | 33 | sigs := make(chan os.Signal, 1) | ||
1171 | 34 | signal.Notify(sigs, syscall.SIGQUIT) | ||
1172 | 35 | buf := make([]byte, 1<<20) | ||
1173 | 36 | for { | ||
1174 | 37 | <-sigs | ||
1175 | 38 | runtime.Stack(buf, true) | ||
1176 | 39 | log.Printf("=== received SIGQUIT ===\n*** goroutine dump...\n%s\n*** end\n", buf) | ||
1177 | 40 | } | ||
1178 | 41 | }() | ||
1179 | 42 | } | ||
1180 | 43 | |||
1181 | 27 | func main() { | 44 | func main() { |
1182 | 45 | installSigQuitHandler() | ||
1183 | 28 | cfgFname, err := xdg.Config.Find("ubuntu-push-client/config.json") | 46 | cfgFname, err := xdg.Config.Find("ubuntu-push-client/config.json") |
1184 | 29 | if err != nil { | 47 | if err != nil { |
1185 | 30 | log.Fatalf("unable to find a configuration file: %v", err) | 48 | log.Fatalf("unable to find a configuration file: %v", err) |
1186 | 31 | 49 | ||
1187 | === modified file 'urldispatcher/curldispatcher/curldispatcher.go' | |||
1188 | --- urldispatcher/curldispatcher/curldispatcher.go 2014-09-01 13:27:17 +0000 | |||
1189 | +++ urldispatcher/curldispatcher/curldispatcher.go 2015-02-09 10:47:29 +0000 | |||
1190 | @@ -79,7 +79,7 @@ | |||
1191 | 79 | C.dispatch_url(c_url, (C.gpointer)(&payload)) | 79 | C.dispatch_url(c_url, (C.gpointer)(&payload)) |
1192 | 80 | success := <-doneCh | 80 | success := <-doneCh |
1193 | 81 | if !success { | 81 | if !success { |
1195 | 82 | return fmt.Errorf("Failed to DispatchURL: %s for %s", url, appPackage) | 82 | return fmt.Errorf("failed to DispatchURL: %s for %s", url, appPackage) |
1196 | 83 | } | 83 | } |
1197 | 84 | return nil | 84 | return nil |
1198 | 85 | } | 85 | } |
1199 | 86 | 86 | ||
1200 | === modified file 'urldispatcher/urldispatcher.go' | |||
1201 | --- urldispatcher/urldispatcher.go 2014-09-01 13:27:17 +0000 | |||
1202 | +++ urldispatcher/urldispatcher.go 2015-02-09 10:47:29 +0000 | |||
1203 | @@ -44,7 +44,7 @@ | |||
1204 | 44 | var cTestURL = curldispatcher.TestURL | 44 | var cTestURL = curldispatcher.TestURL |
1205 | 45 | 45 | ||
1206 | 46 | func (ud *urlDispatcher) DispatchURL(url string, app *click.AppId) error { | 46 | func (ud *urlDispatcher) DispatchURL(url string, app *click.AppId) error { |
1208 | 47 | ud.log.Debugf("Dispatching %s", url) | 47 | ud.log.Debugf("dispatching %s", url) |
1209 | 48 | err := cDispatchURL(url, app.DispatchPackage()) | 48 | err := cDispatchURL(url, app.DispatchPackage()) |
1210 | 49 | if err != nil { | 49 | if err != nil { |
1211 | 50 | ud.log.Errorf("DispatchURL failed: %s", err) | 50 | ud.log.Errorf("DispatchURL failed: %s", err) |
1212 | @@ -62,7 +62,7 @@ | |||
1213 | 62 | } | 62 | } |
1214 | 63 | for _, appId := range appIds { | 63 | for _, appId := range appIds { |
1215 | 64 | if appId != app.Versioned() { | 64 | if appId != app.Versioned() { |
1217 | 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()) |
1218 | 66 | return false | 66 | return false |
1219 | 67 | } | 67 | } |
1220 | 68 | } | 68 | } |
1221 | 69 | 69 | ||
1222 | === modified file 'urldispatcher/urldispatcher_test.go' | |||
1223 | --- urldispatcher/urldispatcher_test.go 2014-08-21 17:45:01 +0000 | |||
1224 | +++ urldispatcher/urldispatcher_test.go 2015-02-09 10:47:29 +0000 | |||
1225 | @@ -106,7 +106,7 @@ | |||
1226 | 106 | appId := clickhelp.MustParseAppId("com.example.test_app_0.99") | 106 | appId := clickhelp.MustParseAppId("com.example.test_app_0.99") |
1227 | 107 | urls := []string{"potato://test-app"} | 107 | urls := []string{"potato://test-app"} |
1228 | 108 | c.Check(ud.TestURL(appId, urls), Equals, false) | 108 | c.Check(ud.TestURL(appId, urls), Equals, false) |
1230 | 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`) |
1231 | 110 | } | 110 | } |
1232 | 111 | 111 | ||
1233 | 112 | func (s *UDSuite) TestTestURLOneWrongApp(c *C) { | 112 | func (s *UDSuite) TestTestURLOneWrongApp(c *C) { |
1234 | @@ -117,7 +117,7 @@ | |||
1235 | 117 | appId := clickhelp.MustParseAppId("com.example.test_test-app_0") | 117 | appId := clickhelp.MustParseAppId("com.example.test_test-app_0") |
1236 | 118 | urls := []string{"potato://test-app", "potato_a://foo"} | 118 | urls := []string{"potato://test-app", "potato_a://foo"} |
1237 | 119 | c.Check(ud.TestURL(appId, urls), Equals, false) | 119 | c.Check(ud.TestURL(appId, urls), Equals, false) |
1239 | 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.*`) |
1240 | 121 | } | 121 | } |
1241 | 122 | 122 | ||
1242 | 123 | func (s *UDSuite) TestTestURLInvalidURL(c *C) { | 123 | func (s *UDSuite) TestTestURLInvalidURL(c *C) { |
1243 | 124 | 124 | ||
1244 | === modified file 'util/redialer.go' | |||
1245 | --- util/redialer.go 2014-03-20 12:15:47 +0000 | |||
1246 | +++ util/redialer.go 2015-02-09 10:47:29 +0000 | |||
1247 | @@ -65,30 +65,69 @@ | |||
1248 | 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. |
1249 | 66 | } | 66 | } |
1250 | 67 | 67 | ||
1251 | 68 | type redialerState uint32 | ||
1252 | 69 | |||
1253 | 70 | const ( | ||
1254 | 71 | Unconfigured redialerState = iota | ||
1255 | 72 | Redialing | ||
1256 | 73 | Stopped | ||
1257 | 74 | ) | ||
1258 | 75 | |||
1259 | 76 | func (s *redialerState) String() string { | ||
1260 | 77 | return [3]string{"Unconfigured", "Redialing", "Stopped"}[uint32(*s)] | ||
1261 | 78 | } | ||
1262 | 79 | |||
1263 | 68 | type autoRedialer struct { | 80 | type autoRedialer struct { |
1268 | 69 | stop chan bool | 81 | stateLock sync.RWMutex |
1269 | 70 | lock sync.RWMutex | 82 | stateValue redialerState |
1270 | 71 | dial func() error | 83 | stopping chan struct{} |
1271 | 72 | jitter func(time.Duration) time.Duration | 84 | reallyStopped chan struct{} |
1272 | 85 | dial func() error | ||
1273 | 86 | jitter func(time.Duration) time.Duration | ||
1274 | 87 | } | ||
1275 | 88 | |||
1276 | 89 | func (ar *autoRedialer) state() redialerState { | ||
1277 | 90 | ar.stateLock.RLock() | ||
1278 | 91 | defer ar.stateLock.RUnlock() | ||
1279 | 92 | return ar.stateValue | ||
1280 | 93 | } | ||
1281 | 94 | |||
1282 | 95 | func (ar *autoRedialer) setState(s redialerState) { | ||
1283 | 96 | ar.stateLock.Lock() | ||
1284 | 97 | defer ar.stateLock.Unlock() | ||
1285 | 98 | ar.stateValue = s | ||
1286 | 99 | } | ||
1287 | 100 | |||
1288 | 101 | func (ar *autoRedialer) setStateIfEqual(oldState, newState redialerState) bool { | ||
1289 | 102 | ar.stateLock.Lock() | ||
1290 | 103 | defer ar.stateLock.Unlock() | ||
1291 | 104 | if ar.stateValue != oldState { | ||
1292 | 105 | return false | ||
1293 | 106 | } | ||
1294 | 107 | ar.stateValue = newState | ||
1295 | 108 | return true | ||
1296 | 109 | } | ||
1297 | 110 | |||
1298 | 111 | func (ar *autoRedialer) setStateStopped() { | ||
1299 | 112 | ar.stateLock.Lock() | ||
1300 | 113 | defer ar.stateLock.Unlock() | ||
1301 | 114 | switch ar.stateValue { | ||
1302 | 115 | case Stopped: | ||
1303 | 116 | return | ||
1304 | 117 | case Unconfigured: | ||
1305 | 118 | close(ar.reallyStopped) | ||
1306 | 119 | } | ||
1307 | 120 | ar.stateValue = Stopped | ||
1308 | 121 | close(ar.stopping) | ||
1309 | 73 | } | 122 | } |
1310 | 74 | 123 | ||
1311 | 75 | func (ar *autoRedialer) Stop() { | 124 | func (ar *autoRedialer) Stop() { |
1312 | 76 | if ar != nil { | 125 | if ar != nil { |
1318 | 77 | ar.lock.RLock() | 126 | ar.setStateStopped() |
1319 | 78 | defer ar.lock.RUnlock() | 127 | <-ar.reallyStopped |
1315 | 79 | if ar.stop != nil { | ||
1316 | 80 | ar.stop <- true | ||
1317 | 81 | } | ||
1320 | 82 | } | 128 | } |
1321 | 83 | } | 129 | } |
1322 | 84 | 130 | ||
1323 | 85 | func (ar *autoRedialer) shutdown() { | ||
1324 | 86 | ar.lock.Lock() | ||
1325 | 87 | defer ar.lock.Unlock() | ||
1326 | 88 | close(ar.stop) | ||
1327 | 89 | ar.stop = nil | ||
1328 | 90 | } | ||
1329 | 91 | |||
1330 | 92 | // Redial keeps on calling Dial until it stops returning an error. It does | 131 | // Redial keeps on calling Dial until it stops returning an error. It does |
1331 | 93 | // exponential backoff, adding back the output of Jitter at each step. | 132 | // exponential backoff, adding back the output of Jitter at each step. |
1332 | 94 | func (ar *autoRedialer) Redial() uint32 { | 133 | func (ar *autoRedialer) Redial() uint32 { |
1333 | @@ -96,20 +135,20 @@ | |||
1334 | 96 | // at least it's better than a segfault... | 135 | // at least it's better than a segfault... |
1335 | 97 | panic("you can't Redial a nil AutoRedialer") | 136 | panic("you can't Redial a nil AutoRedialer") |
1336 | 98 | } | 137 | } |
1339 | 99 | if ar.stop == nil { | 138 | if !ar.setStateIfEqual(Unconfigured, Redialing) { |
1340 | 100 | panic("this AutoRedialer has already been shut down") | 139 | // XXX log this |
1341 | 140 | return 0 | ||
1342 | 101 | } | 141 | } |
1348 | 102 | defer ar.shutdown() | 142 | defer close(ar.reallyStopped) |
1344 | 103 | |||
1345 | 104 | ar.lock.RLock() | ||
1346 | 105 | stop := ar.stop | ||
1347 | 106 | ar.lock.RUnlock() | ||
1349 | 107 | 143 | ||
1350 | 108 | var timeout time.Duration | 144 | var timeout time.Duration |
1351 | 109 | var dialAttempts uint32 = 0 // unsigned so it can wrap safely ... | 145 | var dialAttempts uint32 = 0 // unsigned so it can wrap safely ... |
1352 | 110 | timeouts := Timeouts() | 146 | timeouts := Timeouts() |
1353 | 111 | var numTimeouts uint32 = uint32(len(timeouts)) | 147 | var numTimeouts uint32 = uint32(len(timeouts)) |
1354 | 112 | for { | 148 | for { |
1355 | 149 | if ar.state() != Redialing { | ||
1356 | 150 | return dialAttempts | ||
1357 | 151 | } | ||
1358 | 113 | if ar.dial() == nil { | 152 | if ar.dial() == nil { |
1359 | 114 | return dialAttempts + 1 | 153 | return dialAttempts + 1 |
1360 | 115 | } | 154 | } |
1361 | @@ -123,8 +162,7 @@ | |||
1362 | 123 | } | 162 | } |
1363 | 124 | dialAttempts++ | 163 | dialAttempts++ |
1364 | 125 | select { | 164 | select { |
1367 | 126 | case <-stop: | 165 | case <-ar.stopping: |
1366 | 127 | return dialAttempts | ||
1368 | 128 | case <-time.After(timeout): | 166 | case <-time.After(timeout): |
1369 | 129 | } | 167 | } |
1370 | 130 | } | 168 | } |
1371 | @@ -133,7 +171,12 @@ | |||
1372 | 133 | // Returns a stoppable AutoRedialer using the provided Dialer. If the Dialer | 171 | // Returns a stoppable AutoRedialer using the provided Dialer. If the Dialer |
1373 | 134 | // is also a Jitterer, the backoff will be jittered. | 172 | // is also a Jitterer, the backoff will be jittered. |
1374 | 135 | func NewAutoRedialer(dialer Dialer) AutoRedialer { | 173 | func NewAutoRedialer(dialer Dialer) AutoRedialer { |
1376 | 136 | ar := &autoRedialer{stop: make(chan bool), dial: dialer.Dial} | 174 | ar := &autoRedialer{ |
1377 | 175 | stateValue: Unconfigured, | ||
1378 | 176 | dial: dialer.Dial, | ||
1379 | 177 | reallyStopped: make(chan struct{}), | ||
1380 | 178 | stopping: make(chan struct{}), | ||
1381 | 179 | } | ||
1382 | 137 | jitterer, ok := dialer.(Jitterer) | 180 | jitterer, ok := dialer.(Jitterer) |
1383 | 138 | if ok { | 181 | if ok { |
1384 | 139 | ar.jitter = jitterer.Jitter | 182 | ar.jitter = jitterer.Jitter |
1385 | 140 | 183 | ||
1386 | === added file 'util/redialer_states.gv' | |||
1387 | --- util/redialer_states.gv 1970-01-01 00:00:00 +0000 | |||
1388 | +++ util/redialer_states.gv 2015-02-09 10:47:29 +0000 | |||
1389 | @@ -0,0 +1,9 @@ | |||
1390 | 1 | digraph "redialer" { | ||
1391 | 2 | "Unconfigured" -> "Redialing" [ label="Redial" ] | ||
1392 | 3 | "Unconfigured" -> "Stopped" [ label="Stop" ] | ||
1393 | 4 | |||
1394 | 5 | "Redialing" -> "Redialing" [ label="Redial" ] | ||
1395 | 6 | "Redialing" -> "Stopped" [ label="Stop" ] | ||
1396 | 7 | |||
1397 | 8 | "Stopped" -> "Stopped" [ label="*" ] | ||
1398 | 9 | } | ||
1399 | 0 | 10 | ||
1400 | === modified file 'util/redialer_test.go' | |||
1401 | --- util/redialer_test.go 2014-02-05 13:02:47 +0000 | |||
1402 | +++ util/redialer_test.go 2015-02-09 10:47:29 +0000 | |||
1403 | @@ -48,10 +48,10 @@ | |||
1404 | 48 | func (s *RedialerSuite) TestWorks(c *C) { | 48 | func (s *RedialerSuite) TestWorks(c *C) { |
1405 | 49 | endp := testibus.NewTestingEndpoint(condition.Fail2Work(3), nil) | 49 | endp := testibus.NewTestingEndpoint(condition.Fail2Work(3), nil) |
1406 | 50 | ar := NewAutoRedialer(endp) | 50 | ar := NewAutoRedialer(endp) |
1408 | 51 | c.Check(ar.(*autoRedialer).stop, NotNil) | 51 | // c.Check(ar.(*autoRedialer).stop, NotNil) |
1409 | 52 | c.Check(ar.Redial(), Equals, uint32(4)) | 52 | c.Check(ar.Redial(), Equals, uint32(4)) |
1410 | 53 | // and on success, the stopper goes away | 53 | // and on success, the stopper goes away |
1412 | 54 | c.Check(ar.(*autoRedialer).stop, IsNil) | 54 | // c.Check(ar.(*autoRedialer).stop, IsNil) |
1413 | 55 | } | 55 | } |
1414 | 56 | 56 | ||
1415 | 57 | func (s *RedialerSuite) TestRetryNil(c *C) { | 57 | func (s *RedialerSuite) TestRetryNil(c *C) { |
1416 | @@ -63,7 +63,7 @@ | |||
1417 | 63 | endp := testibus.NewTestingEndpoint(condition.Work(true), nil) | 63 | endp := testibus.NewTestingEndpoint(condition.Work(true), nil) |
1418 | 64 | ar := NewAutoRedialer(endp) | 64 | ar := NewAutoRedialer(endp) |
1419 | 65 | c.Check(ar.Redial(), Equals, uint32(1)) | 65 | c.Check(ar.Redial(), Equals, uint32(1)) |
1421 | 66 | c.Check(ar.Redial, PanicMatches, ".*shut.?down.*") | 66 | c.Check(ar.Redial(), Equals, uint32(0)) |
1422 | 67 | } | 67 | } |
1423 | 68 | 68 | ||
1424 | 69 | type JitteringEndpoint struct { | 69 | type JitteringEndpoint struct { |
1425 | @@ -103,13 +103,13 @@ | |||
1426 | 103 | go func() { countCh <- ar.Redial() }() | 103 | go func() { countCh <- ar.Redial() }() |
1427 | 104 | ar.Stop() | 104 | ar.Stop() |
1428 | 105 | select { | 105 | select { |
1431 | 106 | case n := <-countCh: | 106 | case <-countCh: |
1432 | 107 | c.Check(n, Equals, uint32(1)) | 107 | // pass |
1433 | 108 | case <-time.After(20 * time.Millisecond): | 108 | case <-time.After(20 * time.Millisecond): |
1434 | 109 | c.Fatal("timed out waiting for redial") | 109 | c.Fatal("timed out waiting for redial") |
1435 | 110 | } | 110 | } |
1438 | 111 | // on Stop(), the stopper goes away too | 111 | // on Stop(), the redialer is Stopped |
1439 | 112 | c.Check(ar.(*autoRedialer).stop, IsNil) | 112 | c.Check(ar.(*autoRedialer).state(), Equals, Stopped) |
1440 | 113 | // and the next Stop() doesn't panic nor block | 113 | // and the next Stop() doesn't panic nor block |
1441 | 114 | ar.Stop() | 114 | ar.Stop() |
1442 | 115 | } | 115 | } |
Individual branches have been approved sepparately.