Merge lp:~chipaca/ubuntu-push/auto-to-trunk into lp:ubuntu-push
- auto-to-trunk
- Merge into trunk
Proposed by
John Lenton
Status: | Merged |
---|---|
Approved by: | John Lenton |
Approved revision: | 139 |
Merged at revision: | 138 |
Proposed branch: | lp:~chipaca/ubuntu-push/auto-to-trunk |
Merge into: | lp:ubuntu-push |
Diff against target: |
956 lines (+262/-135) 20 files modified
.precommit (+21/-19) PACKAGE_DEPS (+1/-0) client/service/service.go (+2/-0) client/service/service_test.go (+28/-5) client/session/session.go (+3/-3) client/session/session_test.go (+5/-5) debian/changelog (+28/-0) debian/config.json (+1/-1) docs/_common.txt (+58/-45) docs/example-client/main.qml (+34/-17) docs/example-client/manifest.json (+1/-1) docs/lowlevel.txt (+2/-0) launch_helper/kindpool.go (+3/-2) launch_helper/legacy/legacy.go (+3/-4) messaging/messaging_test.go (+14/-7) server/acceptance/suites/helpers.go (+7/-6) server/api/handlers.go (+15/-1) server/api/handlers_test.go (+22/-6) server/broker/testsuite/suite.go (+11/-11) server/listener/listener_test.go (+3/-2) |
To merge this branch: | bzr merge lp:~chipaca/ubuntu-push/auto-to-trunk |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
John Lenton (community) | Approve | ||
Review via email: mp+244315@code.launchpad.net |
Commit message
Merge automatic to trunk.
Description of the change
Merge automatic to trunk.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '.precommit' |
2 | --- .precommit 2014-01-23 10:03:39 +0000 |
3 | +++ .precommit 2014-12-11 16:51:57 +0000 |
4 | @@ -5,25 +5,27 @@ |
5 | # And put this here-document in ~/.bazaar/plugins/precommit_script.py: |
6 | <<EOF |
7 | import os |
8 | -import subprocess |
9 | -from bzrlib.mutabletree import MutableTree |
10 | -from bzrlib import errors |
11 | - |
12 | -def start_commit_hook(*_): |
13 | - """This hook will execute '.precommit' script from root path of the bazaar |
14 | - branch. Commit will be canceled if precommit fails.""" |
15 | - |
16 | - # this hook only makes sense if a precommit file exist. |
17 | - if not os.path.exists(".precommit"): |
18 | - return |
19 | - try: |
20 | - subprocess.check_call(os.path.abspath(".precommit")) |
21 | - # if precommit fails (process return not zero) cancel commit. |
22 | - except subprocess.CalledProcessError: |
23 | - raise errors.BzrError("pre commit check failed.") |
24 | - |
25 | -MutableTree.hooks.install_named_hook('start_commit', start_commit_hook, |
26 | - 'Run "precommit" script on start_commit') |
27 | + |
28 | +if not os.getenv("SKIP_COMMIT_HOOK"): |
29 | + import subprocess |
30 | + from bzrlib.mutabletree import MutableTree |
31 | + from bzrlib import errors |
32 | + |
33 | + def start_commit_hook(*_): |
34 | + """This hook will execute '.precommit' script from root path of the bazaar |
35 | + branch. Commit will be canceled if precommit fails.""" |
36 | + |
37 | + # this hook only makes sense if a precommit file exist. |
38 | + if not os.path.exists(".precommit"): |
39 | + return |
40 | + try: |
41 | + subprocess.check_call(os.path.abspath(".precommit")) |
42 | + # if precommit fails (process return not zero) cancel commit. |
43 | + except subprocess.CalledProcessError: |
44 | + raise errors.BzrError("pre commit check failed (set SKIP_COMMIT_HOOK to skip).") |
45 | + |
46 | + MutableTree.hooks.install_named_hook('start_commit', start_commit_hook, |
47 | + 'Run "precommit" script on start_commit') |
48 | EOF |
49 | |
50 | make check-format # or whatever |
51 | |
52 | === modified file 'PACKAGE_DEPS' |
53 | --- PACKAGE_DEPS 2014-09-05 10:48:36 +0000 |
54 | +++ PACKAGE_DEPS 2014-12-11 16:51:57 +0000 |
55 | @@ -12,3 +12,4 @@ |
56 | libclick-0.4-dev |
57 | liburl-dispatcher1-dev |
58 | libaccounts-glib-dev |
59 | +system-image-dbus |
60 | |
61 | === modified file 'client/service/service.go' |
62 | --- client/service/service.go 2014-11-03 13:36:00 +0000 |
63 | +++ client/service/service.go 2014-12-11 16:51:57 +0000 |
64 | @@ -140,6 +140,8 @@ |
65 | case resp.StatusCode >= http.StatusInternalServerError: |
66 | // XXX retry on 503 |
67 | return nil, ErrBadServer |
68 | + case resp.StatusCode == http.StatusUnauthorized: |
69 | + return nil, ErrBadAuth |
70 | default: |
71 | return nil, ErrBadRequest |
72 | } |
73 | |
74 | === modified file 'client/service/service_test.go' |
75 | --- client/service/service_test.go 2014-08-06 09:01:59 +0000 |
76 | +++ client/service/service_test.go 2014-12-11 16:51:57 +0000 |
77 | @@ -19,6 +19,7 @@ |
78 | import ( |
79 | "encoding/json" |
80 | "fmt" |
81 | + "io" |
82 | "net/http" |
83 | "net/http/httptest" |
84 | "os" |
85 | @@ -179,7 +180,8 @@ |
86 | func (ss *serviceSuite) TestRegistrationWorks(c *C) { |
87 | ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
88 | buf := make([]byte, 256) |
89 | - n, e := r.Body.Read(buf) |
90 | + n := r.ContentLength |
91 | + _, e := io.ReadFull(r.Body, buf[:n]) |
92 | c.Assert(e, IsNil) |
93 | req := registrationRequest{} |
94 | c.Assert(json.Unmarshal(buf[:n], &req), IsNil) |
95 | @@ -240,6 +242,23 @@ |
96 | c.Check(err, ErrorMatches, "unable to request registration: .*") |
97 | } |
98 | |
99 | +func (ss *serviceSuite) TestManageRegFailsOn401(c *C) { |
100 | + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
101 | + http.Error(w, "Unauthorized", 401) |
102 | + })) |
103 | + defer ts.Close() |
104 | + setup := &PushServiceSetup{ |
105 | + DeviceId: "fake-device-id", |
106 | + RegURL: helpers.ParseURL(ts.URL), |
107 | + AuthGetter: func(string) string { return "tok" }, |
108 | + } |
109 | + svc := NewPushService(setup, ss.log) |
110 | + svc.Bus = ss.bus |
111 | + reg, err := svc.register(aPackageOnBus, []interface{}{anAppId}, nil) |
112 | + c.Check(err, Equals, ErrBadAuth) |
113 | + c.Check(reg, IsNil) |
114 | +} |
115 | + |
116 | func (ss *serviceSuite) TestManageRegFailsOn40x(c *C) { |
117 | ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
118 | http.Error(w, "I'm a teapot", 418) |
119 | @@ -277,7 +296,8 @@ |
120 | func (ss *serviceSuite) TestManageRegFailsOnBadJSON(c *C) { |
121 | ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
122 | buf := make([]byte, 256) |
123 | - n, e := r.Body.Read(buf) |
124 | + n := r.ContentLength |
125 | + _, e := io.ReadFull(r.Body, buf[:n]) |
126 | c.Assert(e, IsNil) |
127 | req := registrationRequest{} |
128 | c.Assert(json.Unmarshal(buf[:n], &req), IsNil) |
129 | @@ -303,7 +323,8 @@ |
130 | func (ss *serviceSuite) TestManageRegFailsOnBadJSONDocument(c *C) { |
131 | ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
132 | buf := make([]byte, 256) |
133 | - n, e := r.Body.Read(buf) |
134 | + n := r.ContentLength |
135 | + _, e := io.ReadFull(r.Body, buf[:n]) |
136 | c.Assert(e, IsNil) |
137 | req := registrationRequest{} |
138 | c.Assert(json.Unmarshal(buf[:n], &req), IsNil) |
139 | @@ -329,7 +350,8 @@ |
140 | func (ss *serviceSuite) TestDBusUnregisterWorks(c *C) { |
141 | ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
142 | buf := make([]byte, 256) |
143 | - n, e := r.Body.Read(buf) |
144 | + n := r.ContentLength |
145 | + _, e := io.ReadFull(r.Body, buf[:n]) |
146 | c.Assert(e, IsNil) |
147 | req := registrationRequest{} |
148 | c.Assert(json.Unmarshal(buf[:n], &req), IsNil) |
149 | @@ -356,7 +378,8 @@ |
150 | invoked := make(chan bool, 1) |
151 | ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
152 | buf := make([]byte, 256) |
153 | - n, e := r.Body.Read(buf) |
154 | + n := r.ContentLength |
155 | + _, e := io.ReadFull(r.Body, buf[:n]) |
156 | c.Assert(e, IsNil) |
157 | req := registrationRequest{} |
158 | c.Assert(json.Unmarshal(buf[:n], &req), IsNil) |
159 | |
160 | === modified file 'client/session/session.go' |
161 | --- client/session/session.go 2014-11-03 13:36:00 +0000 |
162 | +++ client/session/session.go 2014-12-11 16:51:57 +0000 |
163 | @@ -430,7 +430,7 @@ |
164 | return err |
165 | } |
166 | sess.clearShouldDelay() |
167 | - sess.Log.Debugf("broadcast chan:%v app:%v topLevel:%d payloads:%s", |
168 | + sess.Log.Infof("broadcast chan:%v app:%v topLevel:%d payloads:%s", |
169 | bcast.ChanId, bcast.AppId, bcast.TopLevel, bcast.Payloads) |
170 | if bcast.ChanId == protocol.SystemChannelId { |
171 | // the system channel id, the only one we care about for now |
172 | @@ -438,7 +438,7 @@ |
173 | sess.BroadcastCh <- sess.decodeBroadcast(bcast) |
174 | sess.Log.Debugf("sent bcast over") |
175 | } else { |
176 | - sess.Log.Debugf("what is this weird channel, %#v?", bcast.ChanId) |
177 | + sess.Log.Errorf("what is this weird channel, %#v?", bcast.ChanId) |
178 | } |
179 | return nil |
180 | } |
181 | @@ -468,7 +468,7 @@ |
182 | if to == nil { |
183 | continue |
184 | } |
185 | - sess.Log.Debugf("unicast app:%v msg:%s payload:%s", |
186 | + sess.Log.Infof("unicast app:%v msg:%s payload:%s", |
187 | notif.AppId, notif.MsgId, notif.Payload) |
188 | sess.Log.Debugf("sending ucast over") |
189 | sess.NotificationsCh <- AddressedNotification{to, notif} |
190 | |
191 | === modified file 'client/session/session_test.go' |
192 | --- client/session/session_test.go 2014-11-03 13:36:00 +0000 |
193 | +++ client/session/session_test.go 2014-12-11 16:51:57 +0000 |
194 | @@ -1480,7 +1480,7 @@ |
195 | } |
196 | |
197 | var ( |
198 | - dialTestTimeout = 100 * time.Millisecond |
199 | + dialTestTimeout = 300 * time.Millisecond |
200 | dialTestConf = ClientSessionConfig{ |
201 | ExchangeTimeout: dialTestTimeout, |
202 | PEM: helpers.TestCertPEMBlock, |
203 | @@ -1584,7 +1584,7 @@ |
204 | |
205 | // 2. "connect" (but on the fake protcol above! woo) |
206 | |
207 | - c.Check(takeNext(downCh), Equals, "deadline 100ms") |
208 | + c.Check(takeNext(downCh), Equals, fmt.Sprintf("deadline %v", dialTestTimeout)) |
209 | _, ok := takeNext(downCh).(protocol.ConnectMsg) |
210 | c.Check(ok, Equals, true) |
211 | upCh <- nil // no error |
212 | @@ -1597,7 +1597,7 @@ |
213 | // 3. "loop" |
214 | |
215 | // ping works, |
216 | - c.Check(takeNext(downCh), Equals, "deadline 110ms") |
217 | + c.Check(takeNext(downCh), Equals, fmt.Sprintf("deadline %v", dialTestTimeout+10*time.Millisecond)) |
218 | upCh <- protocol.PingPongMsg{Type: "ping"} |
219 | c.Check(takeNext(downCh), Equals, protocol.PingPongMsg{Type: "pong"}) |
220 | upCh <- nil |
221 | @@ -1613,7 +1613,7 @@ |
222 | TopLevel: 2, |
223 | Payloads: []json.RawMessage{json.RawMessage(`{"b":1}`)}, |
224 | } |
225 | - c.Check(takeNext(downCh), Equals, "deadline 110ms") |
226 | + c.Check(takeNext(downCh), Equals, fmt.Sprintf("deadline %v", dialTestTimeout+10*time.Millisecond)) |
227 | upCh <- b |
228 | c.Check(takeNext(downCh), Equals, protocol.AckMsg{"ack"}) |
229 | upCh <- nil |
230 | @@ -1625,7 +1625,7 @@ |
231 | c.Check(levels, DeepEquals, map[string]int64{"0": 2}) |
232 | |
233 | // and ping still work even after that. |
234 | - c.Check(takeNext(downCh), Equals, "deadline 110ms") |
235 | + c.Check(takeNext(downCh), Equals, fmt.Sprintf("deadline %v", dialTestTimeout+10*time.Millisecond)) |
236 | upCh <- protocol.PingPongMsg{Type: "ping"} |
237 | c.Check(takeNext(downCh), Equals, protocol.PingPongMsg{Type: "pong"}) |
238 | failure := errors.New("pongs") |
239 | |
240 | === modified file 'debian/changelog' |
241 | --- debian/changelog 2014-11-03 13:36:12 +0000 |
242 | +++ debian/changelog 2014-12-11 16:51:57 +0000 |
243 | @@ -1,3 +1,31 @@ |
244 | +ubuntu-push (0.66-0ubuntu1) UNRELEASED; urgency=medium |
245 | + |
246 | + [ Roberto Alsina ] |
247 | + * Change the example app to use declared states. |
248 | + * Add section describing limitations of the server API. |
249 | + |
250 | + [ Bret Barker ] |
251 | + * Fixes to PACKAGE_DEPS for client tests. |
252 | + |
253 | + [ Guillermo Gonzalez ] |
254 | + * Add 2 new errors for the server: ErrMissingUserId and |
255 | + ErrWrongRequestMethodGET. |
256 | + * When The server reply 401 on /register, make the DBus call to Register |
257 | + return ErrBadAuth instead of ErrBadRequest. |
258 | + * Add support to media-type in the Content-Type check at server/api |
259 | + handlers. |
260 | + |
261 | + [ Samuele Pedroni ] |
262 | + * Server-side logging improvements. |
263 | + * Make tests more robust in the face of 1.3. |
264 | + |
265 | + [ John R. Lenton ] |
266 | + * Client-side logging improvements (including: loglevel defaults to info). |
267 | + * Updated precommit script. |
268 | + * Include code examples in docs (instead of repeating). |
269 | + |
270 | + -- John R. Lenton <john.lenton@canonical.com> Thu, 11 Dec 2014 16:44:11 +0000 |
271 | + |
272 | ubuntu-push (0.65+15.04.20141103-0ubuntu1) vivid; urgency=medium |
273 | |
274 | [ John R. Lenton ] |
275 | |
276 | === modified file 'debian/config.json' |
277 | --- debian/config.json 2014-08-21 10:47:12 +0000 |
278 | +++ debian/config.json 2014-12-11 16:51:57 +0000 |
279 | @@ -12,7 +12,7 @@ |
280 | "recheck_timeout": "10m", |
281 | "connectivity_check_url": "http://start.ubuntu.com/connectivity-check.html", |
282 | "connectivity_check_md5": "4589f42e1546aa47ca181e5d949d310b", |
283 | - "log_level": "debug", |
284 | + "log_level": "info", |
285 | "fallback_vibration": {"pattern": [100, 100], "repeat": 2}, |
286 | "fallback_sound": "sounds/ubuntu/notifications/Slick.ogg", |
287 | "poll_interval": "5m", |
288 | |
289 | === modified file 'docs/_common.txt' |
290 | --- docs/_common.txt 2014-10-09 16:06:52 +0000 |
291 | +++ docs/_common.txt 2014-12-11 16:51:57 +0000 |
292 | @@ -7,47 +7,22 @@ |
293 | The helper receives two arguments ``infile`` and ``outfile``. The message is delivered via ``infile`` and the transformed |
294 | version is placed in ``outfile``. |
295 | |
296 | -This is the simplest possible useful helper, which simply passes the message through unchanged:: |
297 | - |
298 | - #!/usr/bin/python3 |
299 | - |
300 | - import sys |
301 | - f1, f2 = sys.argv[1:3] |
302 | - open(f2, "w").write(open(f1).read()) |
303 | - |
304 | -Helpers need to be added to the click package manifest:: |
305 | - |
306 | - { |
307 | - "name": "com.ubuntu.developer.ralsina.hello", |
308 | - "description": "description of hello", |
309 | - "framework": "ubuntu-sdk-14.10-qml-dev2", |
310 | - "architecture": "all", |
311 | - "title": "hello", |
312 | - "hooks": { |
313 | - "hello": { |
314 | - "apparmor": "hello.json", |
315 | - "desktop": "hello.desktop" |
316 | - }, |
317 | - "helloHelper": { |
318 | - "apparmor": "helloHelper-apparmor.json", |
319 | - "push-helper": "helloHelper.json" |
320 | - } |
321 | - }, |
322 | - "version": "0.2", |
323 | - "maintainer": "Roberto Alsina <roberto.alsina@canonical.com>" |
324 | - } |
325 | +This is the simplest possible useful helper, which simply passes the message through unchanged: |
326 | + |
327 | +.. include:: example-client/helloHelper |
328 | + :literal: |
329 | + |
330 | +Helpers need to be added to the click package manifest: |
331 | + |
332 | +.. include:: example-client/manifest.json |
333 | + :literal: |
334 | |
335 | Here, we created a helloHelper entry in hooks that has an apparmor profile and an additional JSON file for the push-helper hook. |
336 | |
337 | -helloHelper-apparmor.json must contain **only** the push-notification-client policy group and the ubuntu-push-helper template:: |
338 | +helloHelper-apparmor.json must contain **only** the push-notification-client policy group and the ubuntu-push-helper template: |
339 | |
340 | - { |
341 | - "template": "ubuntu-push-helper", |
342 | - "policy_groups": [ |
343 | - "push-notification-client" |
344 | - ], |
345 | - "policy_version": 1.2 |
346 | - } |
347 | +.. include:: example-client/helloHelper-apparmor.json |
348 | + :literal: |
349 | |
350 | And helloHelper.json must have at least a exec key with the path to the helper executable relative to the json, and optionally |
351 | an app_id key containing the short id of one of the apps in the package (in the format packagename_appname without a version). |
352 | @@ -139,15 +114,10 @@ |
353 | Security |
354 | ~~~~~~~~ |
355 | |
356 | -To use the push API, applications need to request permission in their security profile, using something like this:: |
357 | +To use the push API, applications need to request permission in their security profile, using something like this: |
358 | |
359 | - { |
360 | - "policy_groups": [ |
361 | - "networking", |
362 | - "push-notification-client" |
363 | - ], |
364 | - "policy_version": 1.2 |
365 | - } |
366 | +.. include:: example-client/hello.json |
367 | + :literal: |
368 | |
369 | |
370 | Ubuntu Push Server API |
371 | @@ -185,3 +155,46 @@ |
372 | :clear_pending: Discards all previous pending notifications. Usually in response to getting a "too-many-pending" error. |
373 | :replace_tag: If there's a pending notification with the same tag, delete it before queuing this new one. |
374 | :data: A JSON object. |
375 | + |
376 | +Limitations of the Server API |
377 | +----------------------------- |
378 | + |
379 | +The push notification infrastructure is meant to help ensuring timely |
380 | +delivery of application notifications if the device is online or |
381 | +timely informing the device user about application notifications that |
382 | +were pending when the device comes back online. This in the face of |
383 | +applications not being allowed to be running all the time, and |
384 | +avoiding the resource cost of many applications all polling different services |
385 | +frequently. |
386 | + |
387 | +The push notification infrastructure is architected to guarantee at |
388 | +least best-effort with respect to these goals and beyond it, on the |
389 | +other end applications should not expect to be able to use and only |
390 | +rely on the push notification infrastructure to store application |
391 | +messages if they want ensure all their notification or messages are |
392 | +delivered, the infrastructure is not intended to be the only long term |
393 | +"inbox" storage for an application. |
394 | + |
395 | +To preserve overall throughput the infrastructure imposes some limits |
396 | +on applications: |
397 | + |
398 | + * message data payload is limited to 2K |
399 | + |
400 | + * when inserted all messages need to specify an expiration date after |
401 | + which they can be dropped and not delivered |
402 | + |
403 | + * an application is limited in the number of messages per token |
404 | + (application/user/device combination) that can be undelivered/pending at the |
405 | + same time (100 currently) |
406 | + |
407 | +replace_tag can be used to implement notifications for which the newest |
408 | +one replace the previous one if pending. |
409 | + |
410 | +clear_pending can be used to be deal with a pending message limit |
411 | +reached, possibly substituting the current undelivered messages with a |
412 | +more generic one. |
413 | + |
414 | +Applications using the push notification HTTP API should be robust |
415 | +against receiving 503 errors, retrying after waiting with increasing |
416 | +back-off. Later rate limits (signaled with the 429 status) may also come |
417 | +into play. |
418 | |
419 | === modified file 'docs/example-client/main.qml' |
420 | --- docs/example-client/main.qml 2014-09-10 14:38:40 +0000 |
421 | +++ docs/example-client/main.qml 2014-12-11 16:51:57 +0000 |
422 | @@ -26,9 +26,42 @@ |
423 | property alias nickEnabled: nickEdit.enabled |
424 | } |
425 | |
426 | + states: [ |
427 | + State { |
428 | + name: "no-push-token" |
429 | + when: (pushClient.token == "") |
430 | + PropertyChanges { target: nickEdit; readOnly: true} |
431 | + PropertyChanges { target: nickEdit; focus: true} |
432 | + PropertyChanges { target: messageEdit; enabled: false} |
433 | + PropertyChanges { target: loginButton; enabled: false} |
434 | + PropertyChanges { target: loginButton; text: "Login"} |
435 | + }, |
436 | + State { |
437 | + name: "push-token-not-registered" |
438 | + when: ((pushClient.token != "") && (chatClient.registered == false)) |
439 | + PropertyChanges { target: nickEdit; readOnly: false} |
440 | + PropertyChanges { target: nickEdit; text: ""} |
441 | + PropertyChanges { target: nickEdit; focus: true} |
442 | + PropertyChanges { target: messageEdit; enabled: false} |
443 | + PropertyChanges { target: loginButton; enabled: true} |
444 | + PropertyChanges { target: loginButton; text: "Login"} |
445 | + }, |
446 | + State { |
447 | + name: "registered" |
448 | + when: ((pushClient.token != "") && (chatClient.registered == true)) |
449 | + PropertyChanges { target: nickEdit; readOnly: true} |
450 | + PropertyChanges { target: nickEdit; text: "Your nick is " + chatClient.nick} |
451 | + PropertyChanges { target: messageEdit; focus: true} |
452 | + PropertyChanges { target: messageEdit; enabled: true} |
453 | + PropertyChanges { target: loginButton; enabled: true} |
454 | + PropertyChanges { target: loginButton; text: "Logout"} |
455 | + } |
456 | + ] |
457 | + |
458 | + state: "no-push-token" |
459 | + |
460 | ChatClient { |
461 | id: chatClient |
462 | - onRegisteredChanged: {nickEdit.registered()} |
463 | onError: {messageList.handle_error(msg)} |
464 | token: pushClient.token |
465 | } |
466 | @@ -44,7 +77,6 @@ |
467 | |
468 | TextField { |
469 | id: nickEdit |
470 | - focus: true |
471 | placeholderText: "Your nickname" |
472 | inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText | Qt.ImhPreferLowercase |
473 | anchors.left: parent.left |
474 | @@ -53,31 +85,17 @@ |
475 | anchors.leftMargin: units.gu(.5) |
476 | anchors.rightMargin: units.gu(1) |
477 | anchors.topMargin: units.gu(.5) |
478 | - function registered() { |
479 | - readOnly = true |
480 | - text = "Your nick is " + chatClient.nick |
481 | - messageEdit.focus = true |
482 | - messageEdit.enabled = true |
483 | - loginButton.text = "Logout" |
484 | - } |
485 | onAccepted: { loginButton.clicked() } |
486 | } |
487 | |
488 | Button { |
489 | id: loginButton |
490 | - text: chatClient.rgistered? "Logout": "Login" |
491 | anchors.top: nickEdit.top |
492 | anchors.right: parent.right |
493 | anchors.rightMargin: units.gu(.5) |
494 | onClicked: { |
495 | if (chatClient.nick) { // logout |
496 | chatClient.nick = "" |
497 | - text = "Login" |
498 | - nickEdit.enabled = true |
499 | - nickEdit.readOnly = false |
500 | - nickEdit.text = "" |
501 | - nickEdit.focus = true |
502 | - messageEdit.enabled = false |
503 | } else { // login |
504 | chatClient.nick = nickEdit.text |
505 | } |
506 | @@ -94,7 +112,6 @@ |
507 | anchors.rightMargin: units.gu(.5) |
508 | anchors.leftMargin: units.gu(.5) |
509 | placeholderText: "Your message" |
510 | - enabled: false |
511 | onAccepted: { |
512 | console.log("sending " + text) |
513 | var idx = text.indexOf(":") |
514 | |
515 | === modified file 'docs/example-client/manifest.json' |
516 | --- docs/example-client/manifest.json 2014-09-10 14:38:31 +0000 |
517 | +++ docs/example-client/manifest.json 2014-12-11 16:51:57 +0000 |
518 | @@ -15,5 +15,5 @@ |
519 | "maintainer": "Roberto Alsina <roberto.alsina@canonical.com>", |
520 | "name": "com.ubuntu.developer.ralsina.hello", |
521 | "title": "Hello", |
522 | - "version": "0.4.2" |
523 | + "version": "0.4.3" |
524 | } |
525 | |
526 | === modified file 'docs/lowlevel.txt' |
527 | --- docs/lowlevel.txt 2014-10-15 16:34:25 +0000 |
528 | +++ docs/lowlevel.txt 2014-12-11 16:51:57 +0000 |
529 | @@ -57,6 +57,8 @@ |
530 | The Register method takes as argument the APP_ID (in the example, com.ubuntu.music_music) and returns a token identifying the user |
531 | and device. For this to succeed the user **must** have an Ubuntu One account configured in the device. |
532 | |
533 | +In the case the Register method returns a "bad auth" error, the application should inform the user to generate new Ubuntu One tokens. |
534 | + |
535 | The APP_ID is as described in the `ApplicationId documentation <https://wiki.ubuntu.com/AppStore/Interfaces/ApplicationId>`__ |
536 | except that the version is treated as optional. Therefore both ``com.ubuntu.music_music`` and ``com.ubuntu.music_music_1.3.496`` |
537 | are valid. Keep in mind that while both versioned and unversioned APP_IDs are valid, they are still different and will affect |
538 | |
539 | === modified file 'launch_helper/kindpool.go' |
540 | --- launch_helper/kindpool.go 2014-08-20 12:42:51 +0000 |
541 | +++ launch_helper/kindpool.go 2014-12-11 16:51:57 +0000 |
542 | @@ -294,12 +294,13 @@ |
543 | } |
544 | payload, err := ioutil.ReadFile(args.FileOut) |
545 | if err != nil { |
546 | - pool.log.Errorf("unable to read output from helper: %v", err) |
547 | + pool.log.Errorf("unable to read output from %v helper: %v", args.AppId, err) |
548 | } else { |
549 | + pool.log.Infof("%v helper output: %#v", args.AppId, payload) |
550 | res := &HelperResult{Input: args.Input} |
551 | err = json.Unmarshal(payload, &res.HelperOutput) |
552 | if err != nil { |
553 | - pool.log.Debugf("failed to parse HelperOutput from helper output: %v", err) |
554 | + pool.log.Errorf("failed to parse HelperOutput from %v helper output: %v", args.AppId, err) |
555 | } else { |
556 | pool.chOut <- res |
557 | } |
558 | |
559 | === modified file 'launch_helper/legacy/legacy.go' |
560 | --- launch_helper/legacy/legacy.go 2014-08-21 18:03:49 +0000 |
561 | +++ launch_helper/legacy/legacy.go 2014-12-11 16:51:57 +0000 |
562 | @@ -55,7 +55,7 @@ |
563 | err error |
564 | } |
565 | |
566 | -func (lhl *legacyHelperLauncher) Launch(_, progname, f1, f2 string) (string, error) { |
567 | +func (lhl *legacyHelperLauncher) Launch(appId, progname, f1, f2 string) (string, error) { |
568 | comm := make(chan msg) |
569 | |
570 | go func() { |
571 | @@ -78,9 +78,8 @@ |
572 | p_err := cmd.Wait() |
573 | if p_err != nil { |
574 | // Helper failed or got killed, log output/errors |
575 | - lhl.log.Errorf("Legacy helper failed: %v", p_err) |
576 | - lhl.log.Errorf("Legacy helper failed. Stdout: %s", stdout) |
577 | - lhl.log.Errorf("Legacy helper failed. Stderr: %s", stderr) |
578 | + lhl.log.Errorf("Legacy helper failed: appId: %v, helper: %v, pid: %v, error: %v, stdout: %#v, stderr: %#v.", |
579 | + appId, progname, id, p_err, stdout.String(), stderr.String()) |
580 | } |
581 | lhl.done(id) |
582 | }() |
583 | |
584 | === modified file 'messaging/messaging_test.go' |
585 | --- messaging/messaging_test.go 2014-07-27 02:54:40 +0000 |
586 | +++ messaging/messaging_test.go 2014-12-11 16:51:57 +0000 |
587 | @@ -17,6 +17,7 @@ |
588 | package messaging |
589 | |
590 | import ( |
591 | + "sort" |
592 | "time" |
593 | |
594 | . "launchpad.net/gocheck" |
595 | @@ -121,6 +122,12 @@ |
596 | c.Check(payload.Actions[1], Equals, "action-1") |
597 | } |
598 | |
599 | +func (msg *MessagingSuite) checkTags(c *C, got, expected []string) { |
600 | + sort.Strings(got) |
601 | + sort.Strings(expected) |
602 | + c.Check(got, DeepEquals, expected) |
603 | +} |
604 | + |
605 | func (ms *MessagingSuite) TestTagsListsTags(c *C) { |
606 | mmu := New(ms.log) |
607 | f := func(s string) *launch_helper.Notification { |
608 | @@ -130,15 +137,15 @@ |
609 | |
610 | c.Check(mmu.Tags(ms.app), IsNil) |
611 | c.Assert(mmu.Present(ms.app, "notif1", f("one")), Equals, true) |
612 | - c.Check(mmu.Tags(ms.app), DeepEquals, []string{"one"}) |
613 | + ms.checkTags(c, mmu.Tags(ms.app), []string{"one"}) |
614 | c.Assert(mmu.Present(ms.app, "notif2", f("")), Equals, true) |
615 | - c.Check(mmu.Tags(ms.app), DeepEquals, []string{"one", ""}) |
616 | + ms.checkTags(c, mmu.Tags(ms.app), []string{"one", ""}) |
617 | // and an empty notification doesn't count |
618 | c.Assert(mmu.Present(ms.app, "notif3", &launch_helper.Notification{Tag: "X"}), Equals, false) |
619 | - c.Check(mmu.Tags(ms.app), DeepEquals, []string{"one", ""}) |
620 | + ms.checkTags(c, mmu.Tags(ms.app), []string{"one", ""}) |
621 | // and they go away if we remove one |
622 | mmu.RemoveNotification("notif1", false) |
623 | - c.Check(mmu.Tags(ms.app), DeepEquals, []string{""}) |
624 | + ms.checkTags(c, mmu.Tags(ms.app), []string{""}) |
625 | mmu.RemoveNotification("notif2", false) |
626 | c.Check(mmu.Tags(ms.app), IsNil) |
627 | } |
628 | @@ -169,9 +176,9 @@ |
629 | // app 1: "one", "two", ""; |
630 | // app 2: "one", "two"; |
631 | // app 3: "one", "" |
632 | - c.Assert(mm.Tags(app1), DeepEquals, []string{"one", "two", ""}) |
633 | - c.Assert(mm.Tags(app2), DeepEquals, []string{"one", "two"}) |
634 | - c.Assert(mm.Tags(app3), DeepEquals, []string{"one", ""}) |
635 | + ms.checkTags(c, mm.Tags(app1), []string{"one", "two", ""}) |
636 | + ms.checkTags(c, mm.Tags(app2), []string{"one", "two"}) |
637 | + ms.checkTags(c, mm.Tags(app3), []string{"one", ""}) |
638 | |
639 | // clearing a non-existent tag does nothing |
640 | c.Check(mm.Clear(app1, "foo"), Equals, 0) |
641 | |
642 | === modified file 'server/acceptance/suites/helpers.go' |
643 | --- server/acceptance/suites/helpers.go 2014-07-08 15:08:52 +0000 |
644 | +++ server/acceptance/suites/helpers.go 2014-12-11 16:51:57 +0000 |
645 | @@ -127,6 +127,11 @@ |
646 | c.Log(info) |
647 | continue |
648 | } |
649 | + if strings.HasPrefix(info, "DEBUG ") && !strings.HasPrefix(info, "DEBUG session(") { |
650 | + // skip non session DEBUG logs |
651 | + c.Log(info) |
652 | + continue |
653 | + } |
654 | logs <- info |
655 | } |
656 | }() |
657 | @@ -136,16 +141,12 @@ |
658 | const ( |
659 | DevListeningOnPat = "INFO listening for devices on " |
660 | HTTPListeningOnPat = "INFO listening for http on " |
661 | - debugPrefix = "DEBUG " |
662 | ) |
663 | |
664 | -// ExtractListeningAddr goes over logs ignoring DEBUG lines |
665 | -// until a line starting with pat and returns the rest of that line. |
666 | +// ExtractListeningAddr goes over logs until a line starting with pat |
667 | +// and returns the rest of that line. |
668 | func ExtractListeningAddr(c *C, logs <-chan string, pat string) string { |
669 | for line := range logs { |
670 | - if strings.HasPrefix(line, debugPrefix) { |
671 | - continue |
672 | - } |
673 | if !strings.HasPrefix(line, pat) { |
674 | c.Fatalf("matching %v: %v", pat, line) |
675 | } |
676 | |
677 | === modified file 'server/api/handlers.go' |
678 | --- server/api/handlers.go 2014-07-14 15:23:17 +0000 |
679 | +++ server/api/handlers.go 2014-12-11 16:51:57 +0000 |
680 | @@ -23,6 +23,7 @@ |
681 | "encoding/json" |
682 | "fmt" |
683 | "io" |
684 | + "mime" |
685 | "net/http" |
686 | "time" |
687 | |
688 | @@ -98,6 +99,12 @@ |
689 | "Wrong request method, should be POST", |
690 | nil, |
691 | } |
692 | + ErrWrongRequestMethodGET = &APIError{ |
693 | + http.StatusMethodNotAllowed, |
694 | + invalidRequest, |
695 | + "Wrong request method, should be GET", |
696 | + nil, |
697 | + } |
698 | ErrMalformedJSONObject = &APIError{ |
699 | http.StatusBadRequest, |
700 | invalidRequest, |
701 | @@ -268,7 +275,8 @@ |
702 | if err := checkContentLength(request, maxBodySize); err != nil { |
703 | return err |
704 | } |
705 | - if request.Header.Get("Content-Type") != JSONMediaType { |
706 | + mediaType, _, err := mime.ParseMediaType(request.Header.Get("Content-Type")) |
707 | + if err != nil || mediaType != JSONMediaType { |
708 | return ErrWrongContentType |
709 | } |
710 | return nil |
711 | @@ -452,14 +460,17 @@ |
712 | if err != nil { |
713 | switch err { |
714 | case store.ErrUnknownToken: |
715 | + ctx.logger.Debugf("notify: %v %v unknown", ucast.AppId, ucast.Token) |
716 | return nil, ErrUnknownToken |
717 | case store.ErrUnauthorized: |
718 | + ctx.logger.Debugf("notify: %v %v unauthorized", ucast.AppId, ucast.Token) |
719 | return nil, ErrUnauthorized |
720 | default: |
721 | ctx.logger.Errorf("could not resolve token: %v", err) |
722 | return nil, ErrCouldNotResolveToken |
723 | } |
724 | } |
725 | + ctx.logger.Debugf("notify: %v %v -> %v", ucast.AppId, ucast.Token, chanId) |
726 | |
727 | _, notifs, meta, err := sto.GetChannelUnfiltered(chanId) |
728 | if err != nil { |
729 | @@ -491,6 +502,7 @@ |
730 | if ucast.ClearPending { |
731 | scrubCriteria = []string{ucast.AppId} |
732 | } else if forApp >= ctx.storage.GetMaxNotificationsPerApplication() { |
733 | + ctx.logger.Debugf("notify: %v %v too many pending", ucast.AppId, chanId) |
734 | return nil, apiErrorWithExtra(ErrTooManyPendingNotifications, |
735 | &last.Payload) |
736 | } else if replaceable > 0 { |
737 | @@ -518,6 +530,8 @@ |
738 | } |
739 | |
740 | ctx.broker.Unicast(chanId) |
741 | + |
742 | + ctx.logger.Debugf("notify: ok %v %v id:%v clear:%v replace:%v expired:%v", ucast.AppId, chanId, msgId, ucast.ClearPending, replaceable, expired) |
743 | return nil, nil |
744 | } |
745 | |
746 | |
747 | === modified file 'server/api/handlers_test.go' |
748 | --- server/api/handlers_test.go 2014-07-15 15:03:49 +0000 |
749 | +++ server/api/handlers_test.go 2014-12-11 16:51:57 +0000 |
750 | @@ -362,7 +362,7 @@ |
751 | } |
752 | sto := store.NewInMemoryPendingStore() |
753 | bsend := &checkBrokerSending{store: sto} |
754 | - ctx := &context{testStoreAccess(nil), bsend, nil} |
755 | + ctx := &context{testStoreAccess(nil), bsend, s.testlog} |
756 | payload := json.RawMessage(`{"a": 1}`) |
757 | res, apiErr := doUnicast(ctx, sto, &Unicast{ |
758 | UserId: "user1", |
759 | @@ -487,7 +487,7 @@ |
760 | sto.AppendToUnicastChannel(chanId, "app1", n, "m4", expire) |
761 | |
762 | bsend := &checkBrokerSending{store: sto} |
763 | - ctx := &context{testStoreAccess(nil), bsend, nil} |
764 | + ctx := &context{testStoreAccess(nil), bsend, s.testlog} |
765 | payload := json.RawMessage(`{"a": 1}`) |
766 | res, apiErr := doUnicast(ctx, sto, &Unicast{ |
767 | UserId: "user1", |
768 | @@ -528,7 +528,7 @@ |
769 | sto.AppendToUnicastChannel(chanId, "app1", n, "m1", expire) |
770 | |
771 | bsend := &checkBrokerSending{store: sto} |
772 | - ctx := &context{testStoreAccess(nil), bsend, nil} |
773 | + ctx := &context{testStoreAccess(nil), bsend, s.testlog} |
774 | payload := json.RawMessage(`{"a": 1}`) |
775 | res, apiErr := doUnicast(ctx, sto, &Unicast{ |
776 | UserId: "user1", |
777 | @@ -634,7 +634,7 @@ |
778 | sto.AppendToUnicastChannel(chanId, "app1", n, "m4", expire) |
779 | |
780 | bsend := &checkBrokerSending{store: sto} |
781 | - ctx := &context{testStoreAccess(nil), bsend, nil} |
782 | + ctx := &context{testStoreAccess(nil), bsend, s.testlog} |
783 | payload := json.RawMessage(`{"a": 1}`) |
784 | res, apiErr := doUnicast(ctx, sto, &Unicast{ |
785 | UserId: "user1", |
786 | @@ -933,6 +933,22 @@ |
787 | checkError(c, response, ErrWrongContentType) |
788 | } |
789 | |
790 | +func (s *handlersSuite) TestContentTypeWithCharset(c *C) { |
791 | + testServer := httptest.NewServer(&JSONPostHandler{}) |
792 | + defer testServer.Close() |
793 | + |
794 | + dataString := `{"foo":"bar"}` |
795 | + |
796 | + request := newPostRequest("/", &Broadcast{ |
797 | + Channel: "some-channel", |
798 | + ExpireOn: future, |
799 | + Data: json.RawMessage([]byte(dataString)), |
800 | + }, testServer) |
801 | + request.Header.Set("Content-Type", "application/json; charset=UTF-8") |
802 | + result := checkRequestAsPost(request, 1024) |
803 | + c.Assert(result, IsNil) |
804 | +} |
805 | + |
806 | func (s *handlersSuite) TestCannotBroadcastNonPostMessages(c *C) { |
807 | testServer := httptest.NewServer(&JSONPostHandler{}) |
808 | defer testServer.Close() |
809 | @@ -965,7 +981,7 @@ |
810 | return sto, nil |
811 | }) |
812 | bsend := testBrokerSending{make(chan store.InternalChannelId, 1)} |
813 | - testServer := httptest.NewServer(MakeHandlersMux(storage, bsend, nil)) |
814 | + testServer := httptest.NewServer(MakeHandlersMux(storage, bsend, s.testlog)) |
815 | defer testServer.Close() |
816 | |
817 | payload := json.RawMessage(`{"foo":"bar"}`) |
818 | @@ -1049,7 +1065,7 @@ |
819 | return sto, nil |
820 | }) |
821 | bsend := testBrokerSending{make(chan store.InternalChannelId, 1)} |
822 | - testServer := httptest.NewServer(MakeHandlersMux(storage, bsend, nil)) |
823 | + testServer := httptest.NewServer(MakeHandlersMux(storage, bsend, s.testlog)) |
824 | defer testServer.Close() |
825 | |
826 | request := newPostRequest("/register", &Registration{ |
827 | |
828 | === modified file 'server/broker/testsuite/suite.go' |
829 | --- server/broker/testsuite/suite.go 2014-09-25 11:16:38 +0000 |
830 | +++ server/broker/testsuite/suite.go 2014-12-11 16:51:57 +0000 |
831 | @@ -66,12 +66,12 @@ |
832 | |
833 | func (s *CommonBrokerSuite) TestSanity(c *C) { |
834 | sto := store.NewInMemoryPendingStore() |
835 | - b := s.MakeBroker(sto, testBrokerConfig, nil) |
836 | + b := s.MakeBroker(sto, testBrokerConfig, s.testlog) |
837 | c.Check(s.RevealSession(b, "FOO"), IsNil) |
838 | } |
839 | |
840 | func (s *CommonBrokerSuite) TestStartStop(c *C) { |
841 | - b := s.MakeBroker(nil, testBrokerConfig, nil) |
842 | + b := s.MakeBroker(nil, testBrokerConfig, s.testlog) |
843 | b.Start() |
844 | c.Check(b.Running(), Equals, true) |
845 | b.Start() |
846 | @@ -82,7 +82,7 @@ |
847 | |
848 | func (s *CommonBrokerSuite) TestRegistration(c *C) { |
849 | sto := store.NewInMemoryPendingStore() |
850 | - b := s.MakeBroker(sto, testBrokerConfig, nil) |
851 | + b := s.MakeBroker(sto, testBrokerConfig, s.testlog) |
852 | b.Start() |
853 | defer b.Stop() |
854 | sess, err := b.Register(&protocol.ConnectMsg{ |
855 | @@ -112,7 +112,7 @@ |
856 | |
857 | func (s *CommonBrokerSuite) TestRegistrationBrokenLevels(c *C) { |
858 | sto := store.NewInMemoryPendingStore() |
859 | - b := s.MakeBroker(sto, testBrokerConfig, nil) |
860 | + b := s.MakeBroker(sto, testBrokerConfig, s.testlog) |
861 | b.Start() |
862 | defer b.Stop() |
863 | _, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev-1", Levels: map[string]int64{"z": 5}}, s.MakeTracker("s1")) |
864 | @@ -121,7 +121,7 @@ |
865 | |
866 | func (s *CommonBrokerSuite) TestRegistrationInfoErrors(c *C) { |
867 | sto := store.NewInMemoryPendingStore() |
868 | - b := s.MakeBroker(sto, testBrokerConfig, nil) |
869 | + b := s.MakeBroker(sto, testBrokerConfig, s.testlog) |
870 | b.Start() |
871 | defer b.Stop() |
872 | info := map[string]interface{}{ |
873 | @@ -140,7 +140,7 @@ |
874 | notification1 := json.RawMessage(`{"m": "M"}`) |
875 | muchLater := time.Now().Add(10 * time.Minute) |
876 | sto.AppendToChannel(store.SystemInternalChannelId, notification1, muchLater) |
877 | - b := s.MakeBroker(sto, testBrokerConfig, nil) |
878 | + b := s.MakeBroker(sto, testBrokerConfig, s.testlog) |
879 | b.Start() |
880 | defer b.Stop() |
881 | sess, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev-1"}, s.MakeTracker("s1")) |
882 | @@ -166,7 +166,7 @@ |
883 | |
884 | func (s *CommonBrokerSuite) TestRegistrationLastWins(c *C) { |
885 | sto := store.NewInMemoryPendingStore() |
886 | - b := s.MakeBroker(sto, testBrokerConfig, nil) |
887 | + b := s.MakeBroker(sto, testBrokerConfig, s.testlog) |
888 | b.Start() |
889 | defer b.Stop() |
890 | sess1, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev-1"}, s.MakeTracker("s1")) |
891 | @@ -197,7 +197,7 @@ |
892 | sto := store.NewInMemoryPendingStore() |
893 | notification1 := json.RawMessage(`{"m": "M"}`) |
894 | decoded1 := map[string]interface{}{"m": "M"} |
895 | - b := s.MakeBroker(sto, testBrokerConfig, nil) |
896 | + b := s.MakeBroker(sto, testBrokerConfig, s.testlog) |
897 | b.Start() |
898 | defer b.Stop() |
899 | sess1, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev-1"}, s.MakeTracker("s1")) |
900 | @@ -278,7 +278,7 @@ |
901 | notification2 := json.RawMessage(`{"m": "M2"}`) |
902 | chanId1 := store.UnicastInternalChannelId("dev1", "dev1") |
903 | chanId2 := store.UnicastInternalChannelId("dev2", "dev2") |
904 | - b := s.MakeBroker(sto, testBrokerConfig, nil) |
905 | + b := s.MakeBroker(sto, testBrokerConfig, s.testlog) |
906 | b.Start() |
907 | defer b.Stop() |
908 | sess1, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev1"}, s.MakeTracker("s1")) |
909 | @@ -312,7 +312,7 @@ |
910 | sto := store.NewInMemoryPendingStore() |
911 | notification1 := json.RawMessage(`{"m": "M1"}`) |
912 | chanId1 := store.UnicastInternalChannelId("dev3", "dev3") |
913 | - b := s.MakeBroker(sto, testBrokerConfig, nil) |
914 | + b := s.MakeBroker(sto, testBrokerConfig, s.testlog) |
915 | b.Start() |
916 | defer b.Stop() |
917 | sess1, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev3"}, s.MakeTracker("s1")) |
918 | @@ -354,7 +354,7 @@ |
919 | |
920 | func (s *CommonBrokerSuite) TestSessionFeed(c *C) { |
921 | sto := store.NewInMemoryPendingStore() |
922 | - b := s.MakeBroker(sto, testBrokerConfig, nil) |
923 | + b := s.MakeBroker(sto, testBrokerConfig, s.testlog) |
924 | b.Start() |
925 | defer b.Stop() |
926 | sess1, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev3"}, s.MakeTracker("s1")) |
927 | |
928 | === modified file 'server/listener/listener_test.go' |
929 | --- server/listener/listener_test.go 2014-09-25 11:20:00 +0000 |
930 | +++ server/listener/listener_test.go 2014-12-11 16:51:57 +0000 |
931 | @@ -18,6 +18,7 @@ |
932 | |
933 | import ( |
934 | "crypto/tls" |
935 | + "io" |
936 | "net" |
937 | "os/exec" |
938 | "regexp" |
939 | @@ -112,7 +113,7 @@ |
940 | conn.SetDeadline(time.Now().Add(10 * time.Second)) |
941 | var buf [1]byte |
942 | for { |
943 | - _, err := conn.Read(buf[:]) |
944 | + _, err := io.ReadFull(conn, buf[:]) |
945 | if err != nil { |
946 | return err |
947 | } |
948 | @@ -137,7 +138,7 @@ |
949 | |
950 | func testReadByte(c *C, conn net.Conn, expected uint32) { |
951 | var buf [1]byte |
952 | - _, err := conn.Read(buf[:]) |
953 | + _, err := io.ReadFull(conn, buf[:]) |
954 | c.Check(err, IsNil) |
955 | c.Check(buf[0], Equals, byte(expected)) |
956 | } |
Quick approve because it's merge-only.