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