Merge lp:~chipaca/ubuntu-push/elements-of-client-session-toponomy into lp:ubuntu-push
- elements-of-client-session-toponomy
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | John Lenton |
Approved revision: | 52 |
Merged at revision: | 40 |
Proposed branch: | lp:~chipaca/ubuntu-push/elements-of-client-session-toponomy |
Merge into: | lp:ubuntu-push |
Prerequisite: | lp:~chipaca/ubuntu-push/introduction-to-quantum-client-sessions |
Diff against target: |
286 lines (+209/-10) 2 files modified
client/session/session.go (+43/-1) client/session/session_test.go (+166/-9) |
To merge this branch: | bzr merge lp:~chipaca/ubuntu-push/elements-of-client-session-toponomy |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Samuele Pedroni | Approve | ||
Review via email: mp+204129@code.launchpad.net |
Commit message
Starting to take shape.
Description of the change
Client session, volume 5: elements of client session toponomy.
- 41. By John Lenton
-
Merged introduction-
to-quantum- client- sessions into elements- of-client- session- toponomy. - 42. By John Lenton
-
Merged introduction-
to-quantum- client- sessions into elements- of-client- session- toponomy. - 43. By John Lenton
-
Merged introduction-
to-quantum- client- sessions into elements- of-client- session- toponomy. - 44. By John Lenton
-
Merged introduction-
to-quantum- client- sessions into elements- of-client- session- toponomy. - 45. By John Lenton
-
Merged introduction-
to-quantum- client- sessions into elements- of-client- session- toponomy. - 46. By John Lenton
-
Merged introduction-
to-quantum- client- sessions into elements- of-client- session- toponomy. - 47. By John Lenton
-
Merged introduction-
to-quantum- client- sessions into elements- of-client- session- toponomy. - 48. By John Lenton
-
brought back testConn.
SetDeadline; added a proto.SetDeadline before sending the connect msg; fixed the tests appropriately; added a check on the type of the Connn^Cssages in TestStart*. - 49. By John Lenton
-
Merged introduction-
to-quantum- client- sessions into elements- of-client- session- toponomy. - 50. By John Lenton
-
Merged introduction-
to-quantum- client- sessions into elements- of-client- session- toponomy.
Samuele Pedroni (pedronis) wrote : | # |
- 51. By John Lenton
-
sanity check to connack; used ErrorMatches in tests
Samuele Pedroni (pedronis) wrote : | # |
there are still some:
client/
client/
client/
client/
client/
- 52. By John Lenton
-
more ErrorMatches
Preview Diff
1 | === modified file 'client/session/session.go' | |||
2 | --- client/session/session.go 2014-01-31 17:40:56 +0000 | |||
3 | +++ client/session/session.go 2014-01-31 19:56:23 +0000 | |||
4 | @@ -22,6 +22,7 @@ | |||
5 | 22 | "crypto/tls" | 22 | "crypto/tls" |
6 | 23 | "crypto/x509" | 23 | "crypto/x509" |
7 | 24 | "errors" | 24 | "errors" |
8 | 25 | "fmt" | ||
9 | 25 | "launchpad.net/ubuntu-push/client/session/levelmap" | 26 | "launchpad.net/ubuntu-push/client/session/levelmap" |
10 | 26 | "launchpad.net/ubuntu-push/logger" | 27 | "launchpad.net/ubuntu-push/logger" |
11 | 27 | "launchpad.net/ubuntu-push/protocol" | 28 | "launchpad.net/ubuntu-push/protocol" |
12 | @@ -138,7 +139,7 @@ | |||
13 | 138 | sess.Levels.Set(bcast.ChanId, bcast.TopLevel) | 139 | sess.Levels.Set(bcast.ChanId, bcast.TopLevel) |
14 | 139 | sess.MsgCh <- &Notification{} | 140 | sess.MsgCh <- &Notification{} |
15 | 140 | } else { | 141 | } else { |
17 | 141 | sess.Log.Debugf("what is this weird channel, %s?", bcast.ChanId) | 142 | sess.Log.Debugf("what is this weird channel, %#v?", bcast.ChanId) |
18 | 142 | } | 143 | } |
19 | 143 | return nil | 144 | return nil |
20 | 144 | } | 145 | } |
21 | @@ -165,3 +166,44 @@ | |||
22 | 165 | } | 166 | } |
23 | 166 | } | 167 | } |
24 | 167 | } | 168 | } |
25 | 169 | |||
26 | 170 | // Call this when you've connected and are ready to start running. | ||
27 | 171 | func (sess *ClientSession) start() error { | ||
28 | 172 | conn := sess.Connection | ||
29 | 173 | err := conn.SetDeadline(time.Now().Add(sess.ExchangeTimeout)) | ||
30 | 174 | if err != nil { | ||
31 | 175 | return err | ||
32 | 176 | } | ||
33 | 177 | _, err = conn.Write(wireVersionBytes) | ||
34 | 178 | // The Writer docs: Write must return a non-nil error if it returns | ||
35 | 179 | // n < len(p). So, no need to check number of bytes written, hooray. | ||
36 | 180 | if err != nil { | ||
37 | 181 | return err | ||
38 | 182 | } | ||
39 | 183 | proto := sess.Protocolator(conn) | ||
40 | 184 | proto.SetDeadline(time.Now().Add(sess.ExchangeTimeout)) | ||
41 | 185 | err = proto.WriteMessage(protocol.ConnectMsg{ | ||
42 | 186 | Type: "connect", | ||
43 | 187 | DeviceId: sess.DeviceId, | ||
44 | 188 | Levels: sess.Levels.GetAll(), | ||
45 | 189 | }) | ||
46 | 190 | if err != nil { | ||
47 | 191 | return err | ||
48 | 192 | } | ||
49 | 193 | var connAck protocol.ConnAckMsg | ||
50 | 194 | err = proto.ReadMessage(&connAck) | ||
51 | 195 | if err != nil { | ||
52 | 196 | return err | ||
53 | 197 | } | ||
54 | 198 | if connAck.Type != "connack" { | ||
55 | 199 | return fmt.Errorf("expecting CONNACK, got %#v", connAck.Type) | ||
56 | 200 | } | ||
57 | 201 | pingInterval, err := time.ParseDuration(connAck.Params.PingInterval) | ||
58 | 202 | if err != nil { | ||
59 | 203 | return err | ||
60 | 204 | } | ||
61 | 205 | sess.proto = proto | ||
62 | 206 | sess.pingInterval = pingInterval | ||
63 | 207 | sess.Log.Debugf("Connected %v.", conn.LocalAddr()) | ||
64 | 208 | return nil | ||
65 | 209 | } | ||
66 | 168 | 210 | ||
67 | === modified file 'client/session/session_test.go' | |||
68 | --- client/session/session_test.go 2014-01-31 17:40:56 +0000 | |||
69 | +++ client/session/session_test.go 2014-01-31 19:56:23 +0000 | |||
70 | @@ -20,6 +20,7 @@ | |||
71 | 20 | "encoding/json" | 20 | "encoding/json" |
72 | 21 | "errors" | 21 | "errors" |
73 | 22 | "fmt" | 22 | "fmt" |
74 | 23 | "io" | ||
75 | 23 | "io/ioutil" | 24 | "io/ioutil" |
76 | 24 | . "launchpad.net/gocheck" | 25 | . "launchpad.net/gocheck" |
77 | 25 | "launchpad.net/ubuntu-push/logger" | 26 | "launchpad.net/ubuntu-push/logger" |
78 | @@ -73,11 +74,29 @@ | |||
79 | 73 | } | 74 | } |
80 | 74 | } | 75 | } |
81 | 75 | 76 | ||
83 | 76 | func (tc *testConn) SetDeadline(t time.Time) error { panic("SetDeadline not implemented.") } | 77 | func (tc *testConn) SetDeadline(t time.Time) error { |
84 | 78 | tc.Deadlines = append(tc.Deadlines, t.Sub(time.Now())) | ||
85 | 79 | if tc.DeadlineCondition == nil || tc.DeadlineCondition.OK() { | ||
86 | 80 | return nil | ||
87 | 81 | } else { | ||
88 | 82 | return errors.New("deadliner on fire") | ||
89 | 83 | } | ||
90 | 84 | } | ||
91 | 85 | |||
92 | 77 | func (tc *testConn) SetReadDeadline(t time.Time) error { panic("SetReadDeadline not implemented.") } | 86 | func (tc *testConn) SetReadDeadline(t time.Time) error { panic("SetReadDeadline not implemented.") } |
93 | 78 | func (tc *testConn) SetWriteDeadline(t time.Time) error { panic("SetWriteDeadline not implemented.") } | 87 | func (tc *testConn) SetWriteDeadline(t time.Time) error { panic("SetWriteDeadline not implemented.") } |
94 | 79 | func (tc *testConn) Read(buf []byte) (n int, err error) { panic("Read not implemented.") } | 88 | func (tc *testConn) Read(buf []byte) (n int, err error) { panic("Read not implemented.") } |
96 | 80 | func (tc *testConn) Write(buf []byte) (int, error) { panic("Write not implemented.") } | 89 | |
97 | 90 | func (tc *testConn) Write(buf []byte) (int, error) { | ||
98 | 91 | store := make([]byte, len(buf)) | ||
99 | 92 | copy(store, buf) | ||
100 | 93 | tc.Writes = append(tc.Writes, store) | ||
101 | 94 | if tc.WriteCondition == nil || tc.WriteCondition.OK() { | ||
102 | 95 | return len(store), nil | ||
103 | 96 | } else { | ||
104 | 97 | return -1, errors.New("writer on fire") | ||
105 | 98 | } | ||
106 | 99 | } | ||
107 | 81 | 100 | ||
108 | 82 | // test protocol (from session_test) | 101 | // test protocol (from session_test) |
109 | 83 | 102 | ||
110 | @@ -174,8 +193,7 @@ | |||
111 | 174 | sess, err := NewSession("", nil, 0, "wah", debuglog) | 193 | sess, err := NewSession("", nil, 0, "wah", debuglog) |
112 | 175 | c.Assert(err, IsNil) | 194 | c.Assert(err, IsNil) |
113 | 176 | err = sess.Dial() | 195 | err = sess.Dial() |
116 | 177 | c.Assert(err, NotNil) | 196 | c.Check(err, ErrorMatches, ".*dial.*address.*") |
115 | 178 | c.Check(err.Error(), Matches, ".*dial.*address.*") | ||
117 | 179 | } | 197 | } |
118 | 180 | 198 | ||
119 | 181 | func (cs *clientSessionSuite) TestDialConnects(c *C) { | 199 | func (cs *clientSessionSuite) TestDialConnects(c *C) { |
120 | @@ -196,9 +214,7 @@ | |||
121 | 196 | srv.Close() | 214 | srv.Close() |
122 | 197 | c.Assert(err, IsNil) | 215 | c.Assert(err, IsNil) |
123 | 198 | err = sess.Dial() | 216 | err = sess.Dial() |
127 | 199 | c.Check(sess.Connection, IsNil) | 217 | c.Check(err, ErrorMatches, ".*connection refused") |
125 | 200 | c.Assert(err, NotNil) | ||
126 | 201 | c.Check(err.Error(), Matches, ".*connection refused") | ||
128 | 202 | } | 218 | } |
129 | 203 | 219 | ||
130 | 204 | /**************************************************************** | 220 | /**************************************************************** |
131 | @@ -376,8 +392,7 @@ | |||
132 | 376 | func (s *runSuite) TestRunReadError(c *C) { | 392 | func (s *runSuite) TestRunReadError(c *C) { |
133 | 377 | s.upCh <- errors.New("Read") | 393 | s.upCh <- errors.New("Read") |
134 | 378 | err := <-s.errCh | 394 | err := <-s.errCh |
137 | 379 | c.Assert(err, NotNil) | 395 | c.Check(err, ErrorMatches, "Read") |
136 | 380 | c.Check(err.Error(), Equals, "Read") | ||
138 | 381 | } | 396 | } |
139 | 382 | 397 | ||
140 | 383 | func (s *runSuite) TestRunPing(c *C) { | 398 | func (s *runSuite) TestRunPing(c *C) { |
141 | @@ -416,3 +431,145 @@ | |||
142 | 416 | s.upCh <- failure | 431 | s.upCh <- failure |
143 | 417 | c.Check(<-s.errCh, Equals, failure) | 432 | c.Check(<-s.errCh, Equals, failure) |
144 | 418 | } | 433 | } |
145 | 434 | |||
146 | 435 | /**************************************************************** | ||
147 | 436 | start() tests | ||
148 | 437 | ****************************************************************/ | ||
149 | 438 | func (cs *clientSessionSuite) TestStartFailsIfSetDeadlineFails(c *C) { | ||
150 | 439 | sess, err := NewSession("", nil, 0, "wah", debuglog) | ||
151 | 440 | c.Assert(err, IsNil) | ||
152 | 441 | sess.Connection = &testConn{Name: "TestStartFailsIfSetDeadlineFails", | ||
153 | 442 | DeadlineCondition: condition.Work(false)} // setdeadline will fail | ||
154 | 443 | err = sess.start() | ||
155 | 444 | c.Check(err, ErrorMatches, ".*deadline.*") | ||
156 | 445 | } | ||
157 | 446 | |||
158 | 447 | func (cs *clientSessionSuite) TestStartFailsIfWriteFails(c *C) { | ||
159 | 448 | sess, err := NewSession("", nil, 0, "wah", debuglog) | ||
160 | 449 | c.Assert(err, IsNil) | ||
161 | 450 | sess.Connection = &testConn{Name: "TestStartFailsIfWriteFails", | ||
162 | 451 | WriteCondition: condition.Work(false)} // write will fail | ||
163 | 452 | err = sess.start() | ||
164 | 453 | c.Check(err, ErrorMatches, ".*write.*") | ||
165 | 454 | } | ||
166 | 455 | |||
167 | 456 | func (cs *clientSessionSuite) TestStartConnectMessageFails(c *C) { | ||
168 | 457 | sess, err := NewSession("", nil, 0, "wah", debuglog) | ||
169 | 458 | c.Assert(err, IsNil) | ||
170 | 459 | sess.Connection = &testConn{Name: "TestStartConnectMessageFails"} | ||
171 | 460 | errCh := make(chan error, 1) | ||
172 | 461 | upCh := make(chan interface{}, 5) | ||
173 | 462 | downCh := make(chan interface{}, 5) | ||
174 | 463 | proto := &testProtocol{up: upCh, down: downCh} | ||
175 | 464 | sess.Protocolator = func(_ net.Conn) protocol.Protocol { return proto } | ||
176 | 465 | |||
177 | 466 | go func() { | ||
178 | 467 | errCh <- sess.start() | ||
179 | 468 | }() | ||
180 | 469 | |||
181 | 470 | c.Check(takeNext(downCh), Equals, "deadline 0") | ||
182 | 471 | c.Check(takeNext(downCh), DeepEquals, protocol.ConnectMsg{ | ||
183 | 472 | Type: "connect", | ||
184 | 473 | DeviceId: sess.DeviceId, | ||
185 | 474 | Levels: map[string]int64{}, | ||
186 | 475 | }) | ||
187 | 476 | upCh <- errors.New("Overflow error in /dev/null") | ||
188 | 477 | err = <-errCh | ||
189 | 478 | c.Check(err, ErrorMatches, "Overflow.*null") | ||
190 | 479 | } | ||
191 | 480 | |||
192 | 481 | func (cs *clientSessionSuite) TestStartConnackReadError(c *C) { | ||
193 | 482 | sess, err := NewSession("", nil, 0, "wah", debuglog) | ||
194 | 483 | c.Assert(err, IsNil) | ||
195 | 484 | sess.Connection = &testConn{Name: "TestStartConnackReadError"} | ||
196 | 485 | errCh := make(chan error, 1) | ||
197 | 486 | upCh := make(chan interface{}, 5) | ||
198 | 487 | downCh := make(chan interface{}, 5) | ||
199 | 488 | proto := &testProtocol{up: upCh, down: downCh} | ||
200 | 489 | sess.Protocolator = func(_ net.Conn) protocol.Protocol { return proto } | ||
201 | 490 | |||
202 | 491 | go func() { | ||
203 | 492 | errCh <- sess.start() | ||
204 | 493 | }() | ||
205 | 494 | |||
206 | 495 | c.Check(takeNext(downCh), Equals, "deadline 0") | ||
207 | 496 | _, ok := takeNext(downCh).(protocol.ConnectMsg) | ||
208 | 497 | c.Check(ok, Equals, true) | ||
209 | 498 | upCh <- nil // no error | ||
210 | 499 | upCh <- io.EOF | ||
211 | 500 | err = <-errCh | ||
212 | 501 | c.Check(err, ErrorMatches, ".*EOF.*") | ||
213 | 502 | } | ||
214 | 503 | |||
215 | 504 | func (cs *clientSessionSuite) TestStartBadConnack(c *C) { | ||
216 | 505 | sess, err := NewSession("", nil, 0, "wah", debuglog) | ||
217 | 506 | c.Assert(err, IsNil) | ||
218 | 507 | sess.Connection = &testConn{Name: "TestStartBadConnack"} | ||
219 | 508 | errCh := make(chan error, 1) | ||
220 | 509 | upCh := make(chan interface{}, 5) | ||
221 | 510 | downCh := make(chan interface{}, 5) | ||
222 | 511 | proto := &testProtocol{up: upCh, down: downCh} | ||
223 | 512 | sess.Protocolator = func(_ net.Conn) protocol.Protocol { return proto } | ||
224 | 513 | |||
225 | 514 | go func() { | ||
226 | 515 | errCh <- sess.start() | ||
227 | 516 | }() | ||
228 | 517 | |||
229 | 518 | c.Check(takeNext(downCh), Equals, "deadline 0") | ||
230 | 519 | _, ok := takeNext(downCh).(protocol.ConnectMsg) | ||
231 | 520 | c.Check(ok, Equals, true) | ||
232 | 521 | upCh <- nil // no error | ||
233 | 522 | upCh <- protocol.ConnAckMsg{Type: "connack"} | ||
234 | 523 | err = <-errCh | ||
235 | 524 | c.Check(err, ErrorMatches, ".*invalid.*") | ||
236 | 525 | } | ||
237 | 526 | |||
238 | 527 | func (cs *clientSessionSuite) TestStartNotConnack(c *C) { | ||
239 | 528 | sess, err := NewSession("", nil, 0, "wah", debuglog) | ||
240 | 529 | c.Assert(err, IsNil) | ||
241 | 530 | sess.Connection = &testConn{Name: "TestStartBadConnack"} | ||
242 | 531 | errCh := make(chan error, 1) | ||
243 | 532 | upCh := make(chan interface{}, 5) | ||
244 | 533 | downCh := make(chan interface{}, 5) | ||
245 | 534 | proto := &testProtocol{up: upCh, down: downCh} | ||
246 | 535 | sess.Protocolator = func(_ net.Conn) protocol.Protocol { return proto } | ||
247 | 536 | |||
248 | 537 | go func() { | ||
249 | 538 | errCh <- sess.start() | ||
250 | 539 | }() | ||
251 | 540 | |||
252 | 541 | c.Check(takeNext(downCh), Equals, "deadline 0") | ||
253 | 542 | _, ok := takeNext(downCh).(protocol.ConnectMsg) | ||
254 | 543 | c.Check(ok, Equals, true) | ||
255 | 544 | upCh <- nil // no error | ||
256 | 545 | upCh <- protocol.ConnAckMsg{Type: "connnak"} | ||
257 | 546 | err = <-errCh | ||
258 | 547 | c.Check(err, ErrorMatches, ".*CONNACK.*") | ||
259 | 548 | } | ||
260 | 549 | |||
261 | 550 | func (cs *clientSessionSuite) TestStartWorks(c *C) { | ||
262 | 551 | sess, err := NewSession("", nil, 0, "wah", debuglog) | ||
263 | 552 | c.Assert(err, IsNil) | ||
264 | 553 | sess.Connection = &testConn{Name: "TestStartWorks"} | ||
265 | 554 | errCh := make(chan error, 1) | ||
266 | 555 | upCh := make(chan interface{}, 5) | ||
267 | 556 | downCh := make(chan interface{}, 5) | ||
268 | 557 | proto := &testProtocol{up: upCh, down: downCh} | ||
269 | 558 | sess.Protocolator = func(_ net.Conn) protocol.Protocol { return proto } | ||
270 | 559 | |||
271 | 560 | go func() { | ||
272 | 561 | errCh <- sess.start() | ||
273 | 562 | }() | ||
274 | 563 | |||
275 | 564 | c.Check(takeNext(downCh), Equals, "deadline 0") | ||
276 | 565 | _, ok := takeNext(downCh).(protocol.ConnectMsg) | ||
277 | 566 | c.Check(ok, Equals, true) | ||
278 | 567 | upCh <- nil // no error | ||
279 | 568 | upCh <- protocol.ConnAckMsg{ | ||
280 | 569 | Type: "connack", | ||
281 | 570 | Params: protocol.ConnAckParams{(10 * time.Millisecond).String()}, | ||
282 | 571 | } | ||
283 | 572 | // start is now done. | ||
284 | 573 | err = <-errCh | ||
285 | 574 | c.Assert(err, IsNil) | ||
286 | 575 | } |
42 + err = proto.ReadMessa ge(&connAck)
around here there should be a sanity check that connAck.Type is "connack"
114 + c.Check( err.Error( ), Matches, ".*deadline.*")
gocheck has c.Check(err, ErrorMatches, ...)
I just noticed that upCh downCh are still from the point of view of the server, I suppose we need to live with that if we want to share later unless we can invent neutral names