Merge lp:~chipaca/ubuntu-push/auto-to-trunk into lp:ubuntu-push

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
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.
Revision history for this message
John Lenton (chipaca) wrote :

Quick approve because it's merge-only.

review: Approve

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 }

Subscribers

People subscribed via source and target branches