Merge lp:~chipaca/ubuntu-push/no-more-session-autoredial into lp:ubuntu-push/automatic
- no-more-session-autoredial
- Merge into automatic
Proposed by
John Lenton
Status: | Merged |
---|---|
Approved by: | John Lenton |
Approved revision: | 381 |
Merged at revision: | 375 |
Proposed branch: | lp:~chipaca/ubuntu-push/no-more-session-autoredial |
Merge into: | lp:ubuntu-push/automatic |
Prerequisite: | lp:~chipaca/ubuntu-push/session-state-lock |
Diff against target: |
1169 lines (+401/-196) 4 files modified
client/client.go (+4/-26) client/client_test.go (+30/-109) client/session/session.go (+106/-7) client/session/session_test.go (+261/-54) |
To merge this branch: | bzr merge lp:~chipaca/ubuntu-push/no-more-session-autoredial |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Samuele Pedroni | Approve | ||
Review via email: mp+252612@code.launchpad.net |
Commit message
Remove AutoRedial from ClientSession's interface.
Description of the change
To post a comment you must log in.
- 378. By John Lenton
-
removed spurious test
- 379. By John Lenton
-
merged from lp
Revision history for this message
Samuele Pedroni (pedronis) wrote : | # |
Revision history for this message
John Lenton (chipaca) wrote : | # |
Agreed on both points, fixing.
- 380. By John Lenton
-
call close from stopCh handler; set state to shutdown before closing stopCh.
- 381. By John Lenton
-
repeat myself inside the stopCh handler, because it's not *exactly* doClose what I want, and there isn't yet a clear way of generalizing that function without making a mess down-pipe.
Revision history for this message
Samuele Pedroni (pedronis) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'client/client.go' | |||
2 | --- client/client.go 2015-03-03 10:46:04 +0000 | |||
3 | +++ client/client.go 2015-03-17 16:47:16 +0000 | |||
4 | @@ -115,7 +115,6 @@ | |||
5 | 115 | systemImageEndp bus.Endpoint | 115 | systemImageEndp bus.Endpoint |
6 | 116 | systemImageInfo *systemimage.InfoResult | 116 | systemImageInfo *systemimage.InfoResult |
7 | 117 | connCh chan bool | 117 | connCh chan bool |
8 | 118 | hasConnectivity bool | ||
9 | 119 | session session.ClientSession | 118 | session session.ClientSession |
10 | 120 | sessionConnectedCh chan uint32 | 119 | sessionConnectedCh chan uint32 |
11 | 121 | pushService PushService | 120 | pushService PushService |
12 | @@ -126,7 +125,6 @@ | |||
13 | 126 | poller poller.Poller | 125 | poller poller.Poller |
14 | 127 | accountsCh <-chan accounts.Changed | 126 | accountsCh <-chan accounts.Changed |
15 | 128 | // session-side channels | 127 | // session-side channels |
16 | 129 | errCh chan error | ||
17 | 130 | broadcastCh chan *session.BroadcastNotification | 128 | broadcastCh chan *session.BroadcastNotification |
18 | 131 | notificationsCh chan session.AddressedNotification | 129 | notificationsCh chan session.AddressedNotification |
19 | 132 | } | 130 | } |
20 | @@ -137,7 +135,6 @@ | |||
21 | 137 | return &PushClient{ | 135 | return &PushClient{ |
22 | 138 | configPath: configPath, | 136 | configPath: configPath, |
23 | 139 | leveldbPath: leveldbPath, | 137 | leveldbPath: leveldbPath, |
24 | 140 | errCh: make(chan error), | ||
25 | 141 | broadcastCh: make(chan *session.BroadcastNotification), | 138 | broadcastCh: make(chan *session.BroadcastNotification), |
26 | 142 | notificationsCh: make(chan session.AddressedNotification), | 139 | notificationsCh: make(chan session.AddressedNotification), |
27 | 143 | } | 140 | } |
28 | @@ -212,7 +209,6 @@ | |||
29 | 212 | AuthGetter: client.getAuthorization, | 209 | AuthGetter: client.getAuthorization, |
30 | 213 | AuthURL: client.config.SessionURL, | 210 | AuthURL: client.config.SessionURL, |
31 | 214 | AddresseeChecker: client, | 211 | AddresseeChecker: client, |
32 | 215 | ErrCh: client.errCh, | ||
33 | 216 | BroadcastCh: client.broadcastCh, | 212 | BroadcastCh: client.broadcastCh, |
34 | 217 | NotificationsCh: client.notificationsCh, | 213 | NotificationsCh: client.notificationsCh, |
35 | 218 | } | 214 | } |
36 | @@ -317,6 +313,7 @@ | |||
37 | 317 | return err | 313 | return err |
38 | 318 | } | 314 | } |
39 | 319 | client.session = sess | 315 | client.session = sess |
40 | 316 | sess.KeepConnection() | ||
41 | 320 | client.poller = poller.New(client.derivePollerSetup()) | 317 | client.poller = poller.New(client.derivePollerSetup()) |
42 | 321 | return nil | 318 | return nil |
43 | 322 | } | 319 | } |
44 | @@ -388,24 +385,8 @@ | |||
45 | 388 | // handleConnState deals with connectivity events | 385 | // handleConnState deals with connectivity events |
46 | 389 | func (client *PushClient) handleConnState(hasConnectivity bool) { | 386 | func (client *PushClient) handleConnState(hasConnectivity bool) { |
47 | 390 | client.log.Debugf("handleConnState: %v", hasConnectivity) | 387 | client.log.Debugf("handleConnState: %v", hasConnectivity) |
66 | 391 | if client.hasConnectivity == hasConnectivity { | 388 | client.session.HasConnectivity(hasConnectivity) |
67 | 392 | // nothing to do! | 389 | client.log.Debugf("handled.") |
50 | 393 | return | ||
51 | 394 | } | ||
52 | 395 | client.hasConnectivity = hasConnectivity | ||
53 | 396 | client.session.Close() | ||
54 | 397 | if hasConnectivity { | ||
55 | 398 | client.session.AutoRedial(client.sessionConnectedCh) | ||
56 | 399 | } | ||
57 | 400 | } | ||
58 | 401 | |||
59 | 402 | // handleErr deals with the session erroring out of its loop | ||
60 | 403 | func (client *PushClient) handleErr(err error) { | ||
61 | 404 | // if we're not connected, we don't really care | ||
62 | 405 | client.log.Errorf("session exited: %s", err) | ||
63 | 406 | if client.hasConnectivity { | ||
64 | 407 | client.session.AutoRedial(client.sessionConnectedCh) | ||
65 | 408 | } | ||
68 | 409 | } | 390 | } |
69 | 410 | 391 | ||
70 | 411 | // filterBroadcastNotification finds out if the notification is about an actual | 392 | // filterBroadcastNotification finds out if the notification is about an actual |
71 | @@ -487,7 +468,7 @@ | |||
72 | 487 | } | 468 | } |
73 | 488 | 469 | ||
74 | 489 | // doLoop connects events with their handlers | 470 | // doLoop connects events with their handlers |
76 | 490 | func (client *PushClient) doLoop(connhandler func(bool), bcasthandler func(*session.BroadcastNotification) error, ucasthandler func(session.AddressedNotification) error, errhandler func(error), unregisterhandler func(*click.AppId), accountshandler func()) { | 471 | func (client *PushClient) doLoop(connhandler func(bool), bcasthandler func(*session.BroadcastNotification) error, ucasthandler func(session.AddressedNotification) error, unregisterhandler func(*click.AppId), accountshandler func()) { |
77 | 491 | for { | 472 | for { |
78 | 492 | select { | 473 | select { |
79 | 493 | case <-client.accountsCh: | 474 | case <-client.accountsCh: |
80 | @@ -498,8 +479,6 @@ | |||
81 | 498 | bcasthandler(bcast) | 479 | bcasthandler(bcast) |
82 | 499 | case aucast := <-client.notificationsCh: | 480 | case aucast := <-client.notificationsCh: |
83 | 500 | ucasthandler(aucast) | 481 | ucasthandler(aucast) |
84 | 501 | case err := <-client.errCh: | ||
85 | 502 | errhandler(err) | ||
86 | 503 | case count := <-client.sessionConnectedCh: | 482 | case count := <-client.sessionConnectedCh: |
87 | 504 | client.log.Debugf("session connected after %d attempts", count) | 483 | client.log.Debugf("session connected after %d attempts", count) |
88 | 505 | case app := <-client.unregisterCh: | 484 | case app := <-client.unregisterCh: |
89 | @@ -524,7 +503,6 @@ | |||
90 | 524 | client.doLoop(client.handleConnState, | 503 | client.doLoop(client.handleConnState, |
91 | 525 | client.handleBroadcastNotification, | 504 | client.handleBroadcastNotification, |
92 | 526 | client.handleUnicastNotification, | 505 | client.handleUnicastNotification, |
93 | 527 | client.handleErr, | ||
94 | 528 | client.handleUnregister, | 506 | client.handleUnregister, |
95 | 529 | client.handleAccountsChange, | 507 | client.handleAccountsChange, |
96 | 530 | ) | 508 | ) |
97 | 531 | 509 | ||
98 | === modified file 'client/client_test.go' | |||
99 | --- client/client_test.go 2015-03-03 10:46:04 +0000 | |||
100 | +++ client/client_test.go 2015-03-17 16:47:16 +0000 | |||
101 | @@ -43,7 +43,6 @@ | |||
102 | 43 | clickhelp "launchpad.net/ubuntu-push/click/testing" | 43 | clickhelp "launchpad.net/ubuntu-push/click/testing" |
103 | 44 | "launchpad.net/ubuntu-push/client/service" | 44 | "launchpad.net/ubuntu-push/client/service" |
104 | 45 | "launchpad.net/ubuntu-push/client/session" | 45 | "launchpad.net/ubuntu-push/client/session" |
105 | 46 | "launchpad.net/ubuntu-push/client/session/seenstate" | ||
106 | 47 | "launchpad.net/ubuntu-push/config" | 46 | "launchpad.net/ubuntu-push/config" |
107 | 48 | "launchpad.net/ubuntu-push/identifier" | 47 | "launchpad.net/ubuntu-push/identifier" |
108 | 49 | idtesting "launchpad.net/ubuntu-push/identifier/testing" | 48 | idtesting "launchpad.net/ubuntu-push/identifier/testing" |
109 | @@ -427,7 +426,6 @@ | |||
110 | 427 | AuthGetter: func(string) string { return "" }, | 426 | AuthGetter: func(string) string { return "" }, |
111 | 428 | AuthURL: "xyzzy://", | 427 | AuthURL: "xyzzy://", |
112 | 429 | AddresseeChecker: cli, | 428 | AddresseeChecker: cli, |
113 | 430 | ErrCh: make(chan error), | ||
114 | 431 | BroadcastCh: make(chan *session.BroadcastNotification), | 429 | BroadcastCh: make(chan *session.BroadcastNotification), |
115 | 432 | NotificationsCh: make(chan session.AddressedNotification), | 430 | NotificationsCh: make(chan session.AddressedNotification), |
116 | 433 | } | 431 | } |
117 | @@ -444,10 +442,8 @@ | |||
118 | 444 | // compare authGetter by string | 442 | // compare authGetter by string |
119 | 445 | c.Check(fmt.Sprintf("%#v", conf.AuthGetter), Equals, fmt.Sprintf("%#v", cli.getAuthorization)) | 443 | c.Check(fmt.Sprintf("%#v", conf.AuthGetter), Equals, fmt.Sprintf("%#v", cli.getAuthorization)) |
120 | 446 | // channels are ok as long as non-nil | 444 | // channels are ok as long as non-nil |
121 | 447 | conf.ErrCh = nil | ||
122 | 448 | conf.BroadcastCh = nil | 445 | conf.BroadcastCh = nil |
123 | 449 | conf.NotificationsCh = nil | 446 | conf.NotificationsCh = nil |
124 | 450 | expected.ErrCh = nil | ||
125 | 451 | expected.BroadcastCh = nil | 447 | expected.BroadcastCh = nil |
126 | 452 | expected.NotificationsCh = nil | 448 | expected.NotificationsCh = nil |
127 | 453 | // and set it to nil | 449 | // and set it to nil |
128 | @@ -534,9 +530,11 @@ | |||
129 | 534 | type derivePollerSession struct{} | 530 | type derivePollerSession struct{} |
130 | 535 | 531 | ||
131 | 536 | func (s *derivePollerSession) Close() {} | 532 | func (s *derivePollerSession) Close() {} |
132 | 537 | func (s *derivePollerSession) AutoRedial(ch chan uint32) {} | ||
133 | 538 | func (s *derivePollerSession) ClearCookie() {} | 533 | func (s *derivePollerSession) ClearCookie() {} |
134 | 539 | func (s *derivePollerSession) State() session.ClientSessionState { return session.Unknown } | 534 | func (s *derivePollerSession) State() session.ClientSessionState { return session.Unknown } |
135 | 535 | func (s *derivePollerSession) HasConnectivity(bool) error { return nil } | ||
136 | 536 | func (s *derivePollerSession) KeepConnection() error { return nil } | ||
137 | 537 | func (s *derivePollerSession) StopKeepConnection() {} | ||
138 | 540 | 538 | ||
139 | 541 | func (cs *clientSuite) TestDerivePollerSetup(c *C) { | 539 | func (cs *clientSuite) TestDerivePollerSetup(c *C) { |
140 | 542 | cs.writeTestConfig(map[string]interface{}{}) | 540 | cs.writeTestConfig(map[string]interface{}{}) |
141 | @@ -722,22 +720,6 @@ | |||
142 | 722 | } | 720 | } |
143 | 723 | 721 | ||
144 | 724 | /***************************************************************** | 722 | /***************************************************************** |
145 | 725 | handleErr tests | ||
146 | 726 | ******************************************************************/ | ||
147 | 727 | |||
148 | 728 | func (cs *clientSuite) TestHandleErr(c *C) { | ||
149 | 729 | cli := NewPushClient(cs.configPath, cs.leveldbPath) | ||
150 | 730 | cli.log = cs.log | ||
151 | 731 | cli.systemImageInfo = siInfoRes | ||
152 | 732 | c.Assert(cli.initSessionAndPoller(), IsNil) | ||
153 | 733 | cs.log.ResetCapture() | ||
154 | 734 | cli.hasConnectivity = true | ||
155 | 735 | defer cli.session.Close() | ||
156 | 736 | cli.handleErr(errors.New("bananas")) | ||
157 | 737 | c.Check(cs.log.Captured(), Matches, ".*session exited.*bananas\n") | ||
158 | 738 | } | ||
159 | 739 | |||
160 | 740 | /***************************************************************** | ||
161 | 741 | seenStateFactory tests | 723 | seenStateFactory tests |
162 | 742 | ******************************************************************/ | 724 | ******************************************************************/ |
163 | 743 | 725 | ||
164 | @@ -758,66 +740,6 @@ | |||
165 | 758 | } | 740 | } |
166 | 759 | 741 | ||
167 | 760 | /***************************************************************** | 742 | /***************************************************************** |
168 | 761 | handleConnState tests | ||
169 | 762 | ******************************************************************/ | ||
170 | 763 | |||
171 | 764 | type handleConnStateSession struct { | ||
172 | 765 | connected bool | ||
173 | 766 | } | ||
174 | 767 | |||
175 | 768 | func (s *handleConnStateSession) AutoRedial(ch chan uint32) { s.connected = true } | ||
176 | 769 | func (s *handleConnStateSession) Close() { s.connected = false } | ||
177 | 770 | func (s *handleConnStateSession) ClearCookie() {} | ||
178 | 771 | func (s *handleConnStateSession) State() session.ClientSessionState { return session.Unknown } | ||
179 | 772 | |||
180 | 773 | func (cs *clientSuite) TestHandleConnStateD2C(c *C) { | ||
181 | 774 | cli := NewPushClient(cs.configPath, cs.leveldbPath) | ||
182 | 775 | cli.log = cs.log | ||
183 | 776 | sess := &handleConnStateSession{connected: false} | ||
184 | 777 | cli.session = sess | ||
185 | 778 | |||
186 | 779 | c.Assert(cli.hasConnectivity, Equals, false) | ||
187 | 780 | cli.handleConnState(true) | ||
188 | 781 | c.Check(cli.hasConnectivity, Equals, true) | ||
189 | 782 | c.Check(sess.connected, Equals, true) | ||
190 | 783 | } | ||
191 | 784 | |||
192 | 785 | func (cs *clientSuite) TestHandleConnStateSame(c *C) { | ||
193 | 786 | cli := NewPushClient(cs.configPath, cs.leveldbPath) | ||
194 | 787 | cli.log = cs.log | ||
195 | 788 | // here we want to check that we don't do anything | ||
196 | 789 | c.Assert(cli.session, IsNil) | ||
197 | 790 | c.Assert(cli.hasConnectivity, Equals, false) | ||
198 | 791 | cli.handleConnState(false) | ||
199 | 792 | c.Check(cli.session, IsNil) | ||
200 | 793 | |||
201 | 794 | cli.hasConnectivity = true | ||
202 | 795 | cli.handleConnState(true) | ||
203 | 796 | c.Check(cli.session, IsNil) | ||
204 | 797 | } | ||
205 | 798 | |||
206 | 799 | func (cs *clientSuite) TestHandleConnStateC2D(c *C) { | ||
207 | 800 | cli := NewPushClient(cs.configPath, cs.leveldbPath) | ||
208 | 801 | cli.log = cs.log | ||
209 | 802 | sess := &handleConnStateSession{connected: true} | ||
210 | 803 | cli.session = sess | ||
211 | 804 | cli.hasConnectivity = true | ||
212 | 805 | |||
213 | 806 | cli.handleConnState(false) | ||
214 | 807 | c.Check(sess.connected, Equals, false) | ||
215 | 808 | } | ||
216 | 809 | |||
217 | 810 | func (cs *clientSuite) TestHandleConnStateC2DPending(c *C) { | ||
218 | 811 | cli := NewPushClient(cs.configPath, cs.leveldbPath) | ||
219 | 812 | cli.log = cs.log | ||
220 | 813 | cli.session, _ = session.NewSession(cli.config.Addr, cli.deriveSessionConfig(nil), cli.deviceId, seenstate.NewSeenState, cs.log) | ||
221 | 814 | cli.hasConnectivity = true | ||
222 | 815 | |||
223 | 816 | cli.handleConnState(false) | ||
224 | 817 | c.Check(cli.session.State(), Equals, session.Disconnected) | ||
225 | 818 | } | ||
226 | 819 | |||
227 | 820 | /***************************************************************** | ||
228 | 821 | filterBroadcastNotification tests | 743 | filterBroadcastNotification tests |
229 | 822 | ******************************************************************/ | 744 | ******************************************************************/ |
230 | 823 | 745 | ||
231 | @@ -1035,7 +957,6 @@ | |||
232 | 1035 | var nopConn = func(bool) {} | 957 | var nopConn = func(bool) {} |
233 | 1036 | var nopBcast = func(*session.BroadcastNotification) error { return nil } | 958 | var nopBcast = func(*session.BroadcastNotification) error { return nil } |
234 | 1037 | var nopUcast = func(session.AddressedNotification) error { return nil } | 959 | var nopUcast = func(session.AddressedNotification) error { return nil } |
235 | 1038 | var nopError = func(error) {} | ||
236 | 1039 | var nopUnregister = func(*click.AppId) {} | 960 | var nopUnregister = func(*click.AppId) {} |
237 | 1040 | var nopAcct = func() {} | 961 | var nopAcct = func() {} |
238 | 1041 | 962 | ||
239 | @@ -1048,7 +969,7 @@ | |||
240 | 1048 | c.Assert(cli.initSessionAndPoller(), IsNil) | 969 | c.Assert(cli.initSessionAndPoller(), IsNil) |
241 | 1049 | 970 | ||
242 | 1050 | ch := make(chan bool, 1) | 971 | ch := make(chan bool, 1) |
244 | 1051 | go cli.doLoop(func(bool) { ch <- true }, nopBcast, nopUcast, nopError, nopUnregister, nopAcct) | 972 | go cli.doLoop(func(bool) { ch <- true }, nopBcast, nopUcast, nopUnregister, nopAcct) |
245 | 1052 | c.Check(takeNextBool(ch), Equals, true) | 973 | c.Check(takeNextBool(ch), Equals, true) |
246 | 1053 | } | 974 | } |
247 | 1054 | 975 | ||
248 | @@ -1061,7 +982,7 @@ | |||
249 | 1061 | cli.broadcastCh <- &session.BroadcastNotification{} | 982 | cli.broadcastCh <- &session.BroadcastNotification{} |
250 | 1062 | 983 | ||
251 | 1063 | ch := make(chan bool, 1) | 984 | ch := make(chan bool, 1) |
253 | 1064 | go cli.doLoop(nopConn, func(_ *session.BroadcastNotification) error { ch <- true; return nil }, nopUcast, nopError, nopUnregister, nopAcct) | 985 | go cli.doLoop(nopConn, func(_ *session.BroadcastNotification) error { ch <- true; return nil }, nopUcast, nopUnregister, nopAcct) |
254 | 1065 | c.Check(takeNextBool(ch), Equals, true) | 986 | c.Check(takeNextBool(ch), Equals, true) |
255 | 1066 | } | 987 | } |
256 | 1067 | 988 | ||
257 | @@ -1074,20 +995,7 @@ | |||
258 | 1074 | cli.notificationsCh <- session.AddressedNotification{} | 995 | cli.notificationsCh <- session.AddressedNotification{} |
259 | 1075 | 996 | ||
260 | 1076 | ch := make(chan bool, 1) | 997 | ch := make(chan bool, 1) |
275 | 1077 | go cli.doLoop(nopConn, nopBcast, func(session.AddressedNotification) error { ch <- true; return nil }, nopError, nopUnregister, nopAcct) | 998 | go cli.doLoop(nopConn, nopBcast, func(session.AddressedNotification) error { ch <- true; return nil }, nopUnregister, nopAcct) |
262 | 1078 | c.Check(takeNextBool(ch), Equals, true) | ||
263 | 1079 | } | ||
264 | 1080 | |||
265 | 1081 | func (cs *clientSuite) TestDoLoopErr(c *C) { | ||
266 | 1082 | cli := NewPushClient(cs.configPath, cs.leveldbPath) | ||
267 | 1083 | cli.log = cs.log | ||
268 | 1084 | cli.systemImageInfo = siInfoRes | ||
269 | 1085 | c.Assert(cli.initSessionAndPoller(), IsNil) | ||
270 | 1086 | cli.errCh = make(chan error, 1) | ||
271 | 1087 | cli.errCh <- nil | ||
272 | 1088 | |||
273 | 1089 | ch := make(chan bool, 1) | ||
274 | 1090 | go cli.doLoop(nopConn, nopBcast, nopUcast, func(error) { ch <- true }, nopUnregister, nopAcct) | ||
276 | 1091 | c.Check(takeNextBool(ch), Equals, true) | 999 | c.Check(takeNextBool(ch), Equals, true) |
277 | 1092 | } | 1000 | } |
278 | 1093 | 1001 | ||
279 | @@ -1100,7 +1008,7 @@ | |||
280 | 1100 | cli.unregisterCh <- app1 | 1008 | cli.unregisterCh <- app1 |
281 | 1101 | 1009 | ||
282 | 1102 | ch := make(chan bool, 1) | 1010 | ch := make(chan bool, 1) |
284 | 1103 | go cli.doLoop(nopConn, nopBcast, nopUcast, nopError, func(app *click.AppId) { c.Check(app.Original(), Equals, appId1); ch <- true }, nopAcct) | 1011 | go cli.doLoop(nopConn, nopBcast, nopUcast, func(app *click.AppId) { c.Check(app.Original(), Equals, appId1); ch <- true }, nopAcct) |
285 | 1104 | c.Check(takeNextBool(ch), Equals, true) | 1012 | c.Check(takeNextBool(ch), Equals, true) |
286 | 1105 | } | 1013 | } |
287 | 1106 | 1014 | ||
288 | @@ -1114,7 +1022,7 @@ | |||
289 | 1114 | cli.accountsCh = acctCh | 1022 | cli.accountsCh = acctCh |
290 | 1115 | 1023 | ||
291 | 1116 | ch := make(chan bool, 1) | 1024 | ch := make(chan bool, 1) |
293 | 1117 | go cli.doLoop(nopConn, nopBcast, nopUcast, nopError, nopUnregister, func() { ch <- true }) | 1025 | go cli.doLoop(nopConn, nopBcast, nopUcast, nopUnregister, func() { ch <- true }) |
294 | 1118 | c.Check(takeNextBool(ch), Equals, true) | 1026 | c.Check(takeNextBool(ch), Equals, true) |
295 | 1119 | } | 1027 | } |
296 | 1120 | 1028 | ||
297 | @@ -1149,6 +1057,21 @@ | |||
298 | 1149 | Loop() tests | 1057 | Loop() tests |
299 | 1150 | ******************************************************************/ | 1058 | ******************************************************************/ |
300 | 1151 | 1059 | ||
301 | 1060 | type loopSession struct{ hasConn bool } | ||
302 | 1061 | |||
303 | 1062 | func (s *loopSession) Close() {} | ||
304 | 1063 | func (s *loopSession) ClearCookie() {} | ||
305 | 1064 | func (s *loopSession) State() session.ClientSessionState { | ||
306 | 1065 | if s.hasConn { | ||
307 | 1066 | return session.Connected | ||
308 | 1067 | } else { | ||
309 | 1068 | return session.Disconnected | ||
310 | 1069 | } | ||
311 | 1070 | } | ||
312 | 1071 | func (s *loopSession) HasConnectivity(hasConn bool) error { s.hasConn = hasConn; return nil } | ||
313 | 1072 | func (s *loopSession) KeepConnection() error { return nil } | ||
314 | 1073 | func (s *loopSession) StopKeepConnection() {} | ||
315 | 1074 | |||
316 | 1152 | func (cs *clientSuite) TestLoop(c *C) { | 1075 | func (cs *clientSuite) TestLoop(c *C) { |
317 | 1153 | cli := NewPushClient(cs.configPath, cs.leveldbPath) | 1076 | cli := NewPushClient(cs.configPath, cs.leveldbPath) |
318 | 1154 | cli.connCh = make(chan bool) | 1077 | cli.connCh = make(chan bool) |
319 | @@ -1164,7 +1087,6 @@ | |||
320 | 1164 | c.Assert(cli.initSessionAndPoller(), IsNil) | 1087 | c.Assert(cli.initSessionAndPoller(), IsNil) |
321 | 1165 | 1088 | ||
322 | 1166 | cli.broadcastCh = make(chan *session.BroadcastNotification) | 1089 | cli.broadcastCh = make(chan *session.BroadcastNotification) |
323 | 1167 | cli.errCh = make(chan error) | ||
324 | 1168 | 1090 | ||
325 | 1169 | // we use tick() to make sure things have been through the | 1091 | // we use tick() to make sure things have been through the |
326 | 1170 | // event loop at least once before looking at things; | 1092 | // event loop at least once before looking at things; |
327 | @@ -1179,26 +1101,25 @@ | |||
328 | 1179 | tick() | 1101 | tick() |
329 | 1180 | c.Check(cs.log.Captured(), Matches, "(?msi).*Session connected after 42 attempts$") | 1102 | c.Check(cs.log.Captured(), Matches, "(?msi).*Session connected after 42 attempts$") |
330 | 1181 | 1103 | ||
331 | 1104 | c.Assert(cli.session, NotNil) | ||
332 | 1105 | cli.session.StopKeepConnection() | ||
333 | 1106 | cli.session = &loopSession{} | ||
334 | 1107 | |||
335 | 1182 | // loop() should have connected: | 1108 | // loop() should have connected: |
336 | 1183 | // * connCh to the connectivity checker | 1109 | // * connCh to the connectivity checker |
338 | 1184 | c.Check(cli.hasConnectivity, Equals, false) | 1110 | c.Check(cli.session.State(), Equals, session.Disconnected) |
339 | 1185 | cli.connCh <- true | 1111 | cli.connCh <- true |
340 | 1186 | tick() | 1112 | tick() |
342 | 1187 | c.Check(cli.hasConnectivity, Equals, true) | 1113 | c.Check(cli.session.State(), Equals, session.Connected) |
343 | 1188 | cli.connCh <- false | 1114 | cli.connCh <- false |
344 | 1189 | tick() | 1115 | tick() |
346 | 1190 | c.Check(cli.hasConnectivity, Equals, false) | 1116 | c.Check(cli.session.State(), Equals, session.Disconnected) |
347 | 1191 | 1117 | ||
348 | 1192 | // * session.BroadcastCh to the notifications handler | 1118 | // * session.BroadcastCh to the notifications handler |
349 | 1193 | c.Check(d.bcastCount, Equals, 0) | 1119 | c.Check(d.bcastCount, Equals, 0) |
350 | 1194 | cli.broadcastCh <- positiveBroadcastNotification | 1120 | cli.broadcastCh <- positiveBroadcastNotification |
351 | 1195 | tick() | 1121 | tick() |
352 | 1196 | c.Check(d.bcastCount, Equals, 1) | 1122 | c.Check(d.bcastCount, Equals, 1) |
353 | 1197 | |||
354 | 1198 | // * session.ErrCh to the error handler | ||
355 | 1199 | cli.errCh <- nil | ||
356 | 1200 | tick() | ||
357 | 1201 | c.Check(cs.log.Captured(), Matches, "(?ms).*session exited.*") | ||
358 | 1202 | } | 1123 | } |
359 | 1203 | 1124 | ||
360 | 1204 | /***************************************************************** | 1125 | /***************************************************************** |
361 | 1205 | 1126 | ||
362 | === modified file 'client/session/session.go' | |||
363 | --- client/session/session.go 2015-03-12 12:05:40 +0000 | |||
364 | +++ client/session/session.go 2015-03-17 16:47:16 +0000 | |||
365 | @@ -70,10 +70,12 @@ | |||
366 | 70 | 70 | ||
367 | 71 | const ( | 71 | const ( |
368 | 72 | Error ClientSessionState = iota | 72 | Error ClientSessionState = iota |
369 | 73 | Pristine | ||
370 | 73 | Disconnected | 74 | Disconnected |
371 | 74 | Connected | 75 | Connected |
372 | 75 | Started | 76 | Started |
373 | 76 | Running | 77 | Running |
374 | 78 | Shutdown | ||
375 | 77 | Unknown | 79 | Unknown |
376 | 78 | ) | 80 | ) |
377 | 79 | 81 | ||
378 | @@ -83,10 +85,12 @@ | |||
379 | 83 | } | 85 | } |
380 | 84 | return [Unknown]string{ | 86 | return [Unknown]string{ |
381 | 85 | "Error", | 87 | "Error", |
382 | 88 | "Pristine", | ||
383 | 86 | "Disconnected", | 89 | "Disconnected", |
384 | 87 | "Connected", | 90 | "Connected", |
385 | 88 | "Started", | 91 | "Started", |
386 | 89 | "Running", | 92 | "Running", |
387 | 93 | "Shutdown", | ||
388 | 90 | }[s] | 94 | }[s] |
389 | 91 | } | 95 | } |
390 | 92 | 96 | ||
391 | @@ -118,7 +122,6 @@ | |||
392 | 118 | AuthGetter func(string) string | 122 | AuthGetter func(string) string |
393 | 119 | AuthURL string | 123 | AuthURL string |
394 | 120 | AddresseeChecker AddresseeChecking | 124 | AddresseeChecker AddresseeChecking |
395 | 121 | ErrCh chan error | ||
396 | 122 | BroadcastCh chan *BroadcastNotification | 125 | BroadcastCh chan *BroadcastNotification |
397 | 123 | NotificationsCh chan AddressedNotification | 126 | NotificationsCh chan AddressedNotification |
398 | 124 | } | 127 | } |
399 | @@ -126,9 +129,11 @@ | |||
400 | 126 | // ClientSession holds a client<->server session and its configuration. | 129 | // ClientSession holds a client<->server session and its configuration. |
401 | 127 | type ClientSession interface { | 130 | type ClientSession interface { |
402 | 128 | Close() | 131 | Close() |
403 | 129 | AutoRedial(doneCh chan uint32) | ||
404 | 130 | ClearCookie() | 132 | ClearCookie() |
405 | 131 | State() ClientSessionState | 133 | State() ClientSessionState |
406 | 134 | HasConnectivity(bool) error | ||
407 | 135 | KeepConnection() error | ||
408 | 136 | StopKeepConnection() | ||
409 | 132 | } | 137 | } |
410 | 133 | 138 | ||
411 | 134 | type clientSession struct { | 139 | type clientSession struct { |
412 | @@ -169,6 +174,20 @@ | |||
413 | 169 | redialJitter func(time.Duration) time.Duration | 174 | redialJitter func(time.Duration) time.Duration |
414 | 170 | redialDelays []time.Duration | 175 | redialDelays []time.Duration |
415 | 171 | redialDelaysIdx int | 176 | redialDelaysIdx int |
416 | 177 | // connection events come in over here | ||
417 | 178 | connCh chan bool | ||
418 | 179 | // last seen connection event is here | ||
419 | 180 | lastConn bool | ||
420 | 181 | // connection events are handled by this | ||
421 | 182 | connHandler func(bool) | ||
422 | 183 | // autoredial goes over here (xxx spurious goroutine involved) | ||
423 | 184 | doneCh chan uint32 | ||
424 | 185 | // main loop errors out through here (possibly another spurious goroutine) | ||
425 | 186 | errCh chan error | ||
426 | 187 | // main loop errors are handled by this | ||
427 | 188 | errHandler func(error) | ||
428 | 189 | // look, a stopper! | ||
429 | 190 | stopCh chan struct{} | ||
430 | 172 | } | 191 | } |
431 | 173 | 192 | ||
432 | 174 | func redialDelay(sess *clientSession) time.Duration { | 193 | func redialDelay(sess *clientSession) time.Duration { |
433 | @@ -207,10 +226,10 @@ | |||
434 | 207 | Protocolator: protocol.NewProtocol0, | 226 | Protocolator: protocol.NewProtocol0, |
435 | 208 | SeenState: seenState, | 227 | SeenState: seenState, |
436 | 209 | TLS: &tls.Config{}, | 228 | TLS: &tls.Config{}, |
438 | 210 | state: Disconnected, | 229 | state: Pristine, |
439 | 211 | timeSince: time.Since, | 230 | timeSince: time.Since, |
440 | 212 | shouldDelayP: &shouldDelay, | 231 | shouldDelayP: &shouldDelay, |
442 | 213 | redialDelay: redialDelay, | 232 | redialDelay: redialDelay, // NOTE there are tests that use calling sess.redialDelay as an indication of calling autoRedial! |
443 | 214 | redialDelays: util.Timeouts(), | 233 | redialDelays: util.Timeouts(), |
444 | 215 | } | 234 | } |
445 | 216 | sess.redialJitter = sess.Jitter | 235 | sess.redialJitter = sess.Jitter |
446 | @@ -222,6 +241,15 @@ | |||
447 | 222 | } | 241 | } |
448 | 223 | sess.TLS.RootCAs = cp | 242 | sess.TLS.RootCAs = cp |
449 | 224 | } | 243 | } |
450 | 244 | sess.doneCh = make(chan uint32, 1) | ||
451 | 245 | sess.stopCh = make(chan struct{}) | ||
452 | 246 | sess.connCh = make(chan bool, 1) | ||
453 | 247 | sess.errCh = make(chan error, 1) | ||
454 | 248 | |||
455 | 249 | // to be overridden by tests | ||
456 | 250 | sess.connHandler = sess.handleConn | ||
457 | 251 | sess.errHandler = sess.handleErr | ||
458 | 252 | |||
459 | 225 | return sess, nil | 253 | return sess, nil |
460 | 226 | } | 254 | } |
461 | 227 | 255 | ||
462 | @@ -383,7 +411,7 @@ | |||
463 | 383 | } | 411 | } |
464 | 384 | } | 412 | } |
465 | 385 | 413 | ||
467 | 386 | func (sess *clientSession) AutoRedial(doneCh chan uint32) { | 414 | func (sess *clientSession) autoRedial() { |
468 | 387 | sess.stopRedial() | 415 | sess.stopRedial() |
469 | 388 | if time.Since(sess.lastAutoRedial) < 2*time.Second { | 416 | if time.Since(sess.lastAutoRedial) < 2*time.Second { |
470 | 389 | sess.setShouldDelay() | 417 | sess.setShouldDelay() |
471 | @@ -405,7 +433,7 @@ | |||
472 | 405 | return | 433 | return |
473 | 406 | } | 434 | } |
474 | 407 | sess.Log.Debugf("session autoredialier launching Redial goroutine") | 435 | sess.Log.Debugf("session autoredialier launching Redial goroutine") |
476 | 408 | doneCh <- retrier.Redial() | 436 | sess.doneCh <- retrier.Redial() |
477 | 409 | }() | 437 | }() |
478 | 410 | } | 438 | } |
479 | 411 | 439 | ||
480 | @@ -657,7 +685,7 @@ | |||
481 | 657 | if err == nil { | 685 | if err == nil { |
482 | 658 | err = starter() | 686 | err = starter() |
483 | 659 | if err == nil { | 687 | if err == nil { |
485 | 660 | go func() { sess.ErrCh <- looper() }() | 688 | go func() { sess.errCh <- looper() }() |
486 | 661 | } | 689 | } |
487 | 662 | } | 690 | } |
488 | 663 | return err | 691 | return err |
489 | @@ -684,6 +712,77 @@ | |||
490 | 684 | return sess.run(sess.doClose, sess.addAuthorization, sess.getHosts, sess.connect, sess.start, sess.loop) | 712 | return sess.run(sess.doClose, sess.addAuthorization, sess.getHosts, sess.connect, sess.start, sess.loop) |
491 | 685 | } | 713 | } |
492 | 686 | 714 | ||
493 | 715 | func (sess *clientSession) doKeepConnection() { | ||
494 | 716 | Loop: | ||
495 | 717 | for { | ||
496 | 718 | select { | ||
497 | 719 | case hasConn := <-sess.connCh: | ||
498 | 720 | sess.connHandler(hasConn) | ||
499 | 721 | case <-sess.stopCh: | ||
500 | 722 | sess.Log.Infof("session shutting down.") | ||
501 | 723 | sess.connLock.Lock() | ||
502 | 724 | defer sess.connLock.Unlock() | ||
503 | 725 | sess.stopRedial() | ||
504 | 726 | if sess.Connection != nil { | ||
505 | 727 | sess.Connection.Close() | ||
506 | 728 | sess.Connection = nil | ||
507 | 729 | } | ||
508 | 730 | break Loop | ||
509 | 731 | case n := <-sess.doneCh: | ||
510 | 732 | sess.Log.Debugf("connected after %d attempts.", n) | ||
511 | 733 | case err := <-sess.errCh: | ||
512 | 734 | sess.errHandler(err) | ||
513 | 735 | } | ||
514 | 736 | } | ||
515 | 737 | } | ||
516 | 738 | |||
517 | 739 | func (sess *clientSession) handleConn(hasConn bool) { | ||
518 | 740 | sess.lastConn = hasConn | ||
519 | 741 | |||
520 | 742 | // Note this does not depend on the current state! That's because Dial | ||
521 | 743 | // starts with doClose, which gets you to Disconnected even if you're | ||
522 | 744 | // connected, and you can call Close when Disconnected without it | ||
523 | 745 | // losing its stuff. | ||
524 | 746 | if hasConn { | ||
525 | 747 | sess.autoRedial() | ||
526 | 748 | } else { | ||
527 | 749 | sess.Close() | ||
528 | 750 | } | ||
529 | 751 | } | ||
530 | 752 | |||
531 | 753 | func (sess *clientSession) handleErr(err error) { | ||
532 | 754 | sess.Log.Errorf("session error'ed out with %v", err) | ||
533 | 755 | sess.stateLock.Lock() | ||
534 | 756 | if sess.state == Disconnected && sess.lastConn { | ||
535 | 757 | sess.autoRedial() | ||
536 | 758 | } | ||
537 | 759 | sess.stateLock.Unlock() | ||
538 | 760 | } | ||
539 | 761 | |||
540 | 762 | func (sess *clientSession) KeepConnection() error { | ||
541 | 763 | sess.stateLock.Lock() | ||
542 | 764 | defer sess.stateLock.Unlock() | ||
543 | 765 | if sess.state != Pristine { | ||
544 | 766 | return errors.New("don't call KeepConnection() on a non-pristine session.") | ||
545 | 767 | } | ||
546 | 768 | sess.state = Disconnected | ||
547 | 769 | |||
548 | 770 | go sess.doKeepConnection() | ||
549 | 771 | |||
550 | 772 | return nil | ||
551 | 773 | } | ||
552 | 774 | |||
553 | 775 | func (sess *clientSession) StopKeepConnection() { | ||
554 | 776 | sess.setState(Shutdown) | ||
555 | 777 | close(sess.stopCh) | ||
556 | 778 | } | ||
557 | 779 | |||
558 | 780 | func (sess *clientSession) HasConnectivity(hasConn bool) error { | ||
559 | 781 | sess.connCh <- hasConn | ||
560 | 782 | // XXX throw errors if called from weird state? | ||
561 | 783 | return nil | ||
562 | 784 | } | ||
563 | 785 | |||
564 | 687 | func init() { | 786 | func init() { |
565 | 688 | rand.Seed(time.Now().Unix()) // good enough for us (we're not using it for crypto) | 787 | rand.Seed(time.Now().Unix()) // good enough for us (we're not using it for crypto) |
566 | 689 | } | 788 | } |
567 | 690 | 789 | ||
568 | === modified file 'client/session/session_test.go' | |||
569 | --- client/session/session_test.go 2015-02-13 11:20:41 +0000 | |||
570 | +++ client/session/session_test.go 2015-03-17 16:47:16 +0000 | |||
571 | @@ -190,6 +190,24 @@ | |||
572 | 190 | cs.lvls = func() (seenstate.SeenState, error) { return seenstate.NewSqliteSeenState(":memory:") } | 190 | cs.lvls = func() (seenstate.SeenState, error) { return seenstate.NewSqliteSeenState(":memory:") } |
573 | 191 | } | 191 | } |
574 | 192 | 192 | ||
575 | 193 | func (cs *clientSessionSuite) TestStateString(c *C) { | ||
576 | 194 | for _, i := range []struct { | ||
577 | 195 | v ClientSessionState | ||
578 | 196 | s string | ||
579 | 197 | }{ | ||
580 | 198 | {Error, "Error"}, | ||
581 | 199 | {Pristine, "Pristine"}, | ||
582 | 200 | {Disconnected, "Disconnected"}, | ||
583 | 201 | {Connected, "Connected"}, | ||
584 | 202 | {Started, "Started"}, | ||
585 | 203 | {Running, "Running"}, | ||
586 | 204 | {Shutdown, "Shutdown"}, | ||
587 | 205 | {Unknown, fmt.Sprintf("??? (%d)", Unknown)}, | ||
588 | 206 | } { | ||
589 | 207 | c.Check(i.v.String(), Equals, i.s) | ||
590 | 208 | } | ||
591 | 209 | } | ||
592 | 210 | |||
593 | 193 | /**************************************************************** | 211 | /**************************************************************** |
594 | 194 | parseServerAddrSpec() tests | 212 | parseServerAddrSpec() tests |
595 | 195 | ****************************************************************/ | 213 | ****************************************************************/ |
596 | @@ -214,7 +232,6 @@ | |||
597 | 214 | 232 | ||
598 | 215 | func dummyConf() ClientSessionConfig { | 233 | func dummyConf() ClientSessionConfig { |
599 | 216 | return ClientSessionConfig{ | 234 | return ClientSessionConfig{ |
600 | 217 | ErrCh: make(chan error, 1), | ||
601 | 218 | BroadcastCh: make(chan *BroadcastNotification, 5), | 235 | BroadcastCh: make(chan *BroadcastNotification, 5), |
602 | 219 | NotificationsCh: make(chan AddressedNotification, 5), | 236 | NotificationsCh: make(chan AddressedNotification, 5), |
603 | 220 | } | 237 | } |
604 | @@ -231,7 +248,9 @@ | |||
605 | 231 | c.Check(sess.redialDelays, DeepEquals, util.Timeouts()) | 248 | c.Check(sess.redialDelays, DeepEquals, util.Timeouts()) |
606 | 232 | // but no root CAs set | 249 | // but no root CAs set |
607 | 233 | c.Check(sess.TLS.RootCAs, IsNil) | 250 | c.Check(sess.TLS.RootCAs, IsNil) |
609 | 234 | c.Check(sess.State(), Equals, Disconnected) | 251 | c.Check(sess.State(), Equals, Pristine) |
610 | 252 | c.Check(sess.stopCh, NotNil) | ||
611 | 253 | c.Check(sess.connCh, NotNil) | ||
612 | 235 | } | 254 | } |
613 | 236 | 255 | ||
614 | 237 | func (cs *clientSessionSuite) TestNewSessionHostEndpointWorks(c *C) { | 256 | func (cs *clientSessionSuite) TestNewSessionHostEndpointWorks(c *C) { |
615 | @@ -569,9 +588,9 @@ | |||
616 | 569 | c.Check(ar.stopped, Equals, true) | 588 | c.Check(ar.stopped, Equals, true) |
617 | 570 | } | 589 | } |
618 | 571 | 590 | ||
622 | 572 | /**************************************************************** | 591 | // /**************************************************************** |
623 | 573 | AutoRedial() tests | 592 | // AutoRedial() tests |
624 | 574 | ****************************************************************/ | 593 | // ****************************************************************/ |
625 | 575 | 594 | ||
626 | 576 | func (cs *clientSessionSuite) TestAutoRedialWorks(c *C) { | 595 | func (cs *clientSessionSuite) TestAutoRedialWorks(c *C) { |
627 | 577 | // checks that AutoRedial sets up a retrier and tries redialing it | 596 | // checks that AutoRedial sets up a retrier and tries redialing it |
628 | @@ -580,7 +599,8 @@ | |||
629 | 580 | ar := new(derp) | 599 | ar := new(derp) |
630 | 581 | sess.retrier = ar | 600 | sess.retrier = ar |
631 | 582 | c.Check(ar.stopped, Equals, false) | 601 | c.Check(ar.stopped, Equals, false) |
633 | 583 | sess.AutoRedial(nil) | 602 | sess.autoRedial() |
634 | 603 | defer sess.stopRedial() | ||
635 | 584 | c.Check(ar.stopped, Equals, true) | 604 | c.Check(ar.stopped, Equals, true) |
636 | 585 | } | 605 | } |
637 | 586 | 606 | ||
638 | @@ -588,20 +608,21 @@ | |||
639 | 588 | // checks that AutoRedial stops the previous retrier | 608 | // checks that AutoRedial stops the previous retrier |
640 | 589 | sess, err := NewSession("", dummyConf(), "wah", cs.lvls, cs.log) | 609 | sess, err := NewSession("", dummyConf(), "wah", cs.lvls, cs.log) |
641 | 590 | c.Assert(err, IsNil) | 610 | c.Assert(err, IsNil) |
643 | 591 | ch := make(chan uint32) | 611 | sess.doneCh = make(chan uint32) |
644 | 592 | c.Check(sess.retrier, IsNil) | 612 | c.Check(sess.retrier, IsNil) |
646 | 593 | sess.AutoRedial(ch) | 613 | sess.autoRedial() |
647 | 594 | c.Assert(sess.retrier, NotNil) | 614 | c.Assert(sess.retrier, NotNil) |
648 | 595 | sess.retrier.Stop() | 615 | sess.retrier.Stop() |
650 | 596 | c.Check(<-ch, Not(Equals), 0) | 616 | c.Check(<-sess.doneCh, Not(Equals), 0) |
651 | 597 | } | 617 | } |
652 | 598 | 618 | ||
653 | 599 | func (cs *clientSessionSuite) TestAutoRedialCallsRedialDelay(c *C) { | 619 | func (cs *clientSessionSuite) TestAutoRedialCallsRedialDelay(c *C) { |
654 | 620 | // NOTE there are tests that use calling redialDelay as an indication of calling autoRedial! | ||
655 | 600 | sess, err := NewSession("", dummyConf(), "wah", cs.lvls, cs.log) | 621 | sess, err := NewSession("", dummyConf(), "wah", cs.lvls, cs.log) |
656 | 601 | c.Assert(err, IsNil) | 622 | c.Assert(err, IsNil) |
657 | 602 | flag := false | 623 | flag := false |
658 | 603 | sess.redialDelay = func(sess *clientSession) time.Duration { flag = true; return 0 } | 624 | sess.redialDelay = func(sess *clientSession) time.Duration { flag = true; return 0 } |
660 | 604 | sess.AutoRedial(nil) | 625 | sess.autoRedial() |
661 | 605 | c.Check(flag, Equals, true) | 626 | c.Check(flag, Equals, true) |
662 | 606 | } | 627 | } |
663 | 607 | 628 | ||
664 | @@ -609,11 +630,11 @@ | |||
665 | 609 | sess, err := NewSession("", dummyConf(), "wah", cs.lvls, cs.log) | 630 | sess, err := NewSession("", dummyConf(), "wah", cs.lvls, cs.log) |
666 | 610 | c.Assert(err, IsNil) | 631 | c.Assert(err, IsNil) |
667 | 611 | sess.redialDelay = func(sess *clientSession) time.Duration { return 0 } | 632 | sess.redialDelay = func(sess *clientSession) time.Duration { return 0 } |
669 | 612 | sess.AutoRedial(nil) | 633 | sess.autoRedial() |
670 | 613 | c.Check(sess.ShouldDelay(), Equals, false) | 634 | c.Check(sess.ShouldDelay(), Equals, false) |
671 | 614 | sess.stopRedial() | 635 | sess.stopRedial() |
672 | 615 | sess.clearShouldDelay() | 636 | sess.clearShouldDelay() |
674 | 616 | sess.AutoRedial(nil) | 637 | sess.autoRedial() |
675 | 617 | c.Check(sess.ShouldDelay(), Equals, true) | 638 | c.Check(sess.ShouldDelay(), Equals, true) |
676 | 618 | } | 639 | } |
677 | 619 | 640 | ||
678 | @@ -625,7 +646,6 @@ | |||
679 | 625 | sess *clientSession | 646 | sess *clientSession |
680 | 626 | upCh chan interface{} | 647 | upCh chan interface{} |
681 | 627 | downCh chan interface{} | 648 | downCh chan interface{} |
682 | 628 | errCh chan error | ||
683 | 629 | } | 649 | } |
684 | 630 | 650 | ||
685 | 631 | var _ = Suite(&msgSuite{}) | 651 | var _ = Suite(&msgSuite{}) |
686 | @@ -637,7 +657,6 @@ | |||
687 | 637 | s.sess, err = NewSession("", conf, "wah", seenstate.NewSeenState, helpers.NewTestLogger(c, "debug")) | 657 | s.sess, err = NewSession("", conf, "wah", seenstate.NewSeenState, helpers.NewTestLogger(c, "debug")) |
688 | 638 | c.Assert(err, IsNil) | 658 | c.Assert(err, IsNil) |
689 | 639 | s.sess.Connection = &testConn{Name: "TestHandle*"} | 659 | s.sess.Connection = &testConn{Name: "TestHandle*"} |
690 | 640 | s.errCh = conf.ErrCh | ||
691 | 641 | s.upCh = make(chan interface{}, 5) | 660 | s.upCh = make(chan interface{}, 5) |
692 | 642 | s.downCh = make(chan interface{}, 5) | 661 | s.downCh = make(chan interface{}, 5) |
693 | 643 | s.sess.proto = &testProtocol{up: s.upCh, down: s.downCh} | 662 | s.sess.proto = &testProtocol{up: s.upCh, down: s.downCh} |
694 | @@ -696,10 +715,10 @@ | |||
695 | 696 | json.RawMessage(`{"img1/m1":[102,"tubular"]}`), | 715 | json.RawMessage(`{"img1/m1":[102,"tubular"]}`), |
696 | 697 | }, | 716 | }, |
697 | 698 | } | 717 | } |
699 | 699 | go func() { s.errCh <- s.sess.handleBroadcast(msg) }() | 718 | go func() { s.sess.errCh <- s.sess.handleBroadcast(msg) }() |
700 | 700 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) | 719 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) |
701 | 701 | s.upCh <- nil // ack ok | 720 | s.upCh <- nil // ack ok |
703 | 702 | c.Check(<-s.errCh, Equals, nil) | 721 | c.Check(<-s.sess.errCh, Equals, nil) |
704 | 703 | c.Assert(len(s.sess.BroadcastCh), Equals, 1) | 722 | c.Assert(len(s.sess.BroadcastCh), Equals, 1) |
705 | 704 | c.Check(<-s.sess.BroadcastCh, DeepEquals, &BroadcastNotification{ | 723 | c.Check(<-s.sess.BroadcastCh, DeepEquals, &BroadcastNotification{ |
706 | 705 | TopLevel: 2, | 724 | TopLevel: 2, |
707 | @@ -728,11 +747,11 @@ | |||
708 | 728 | TopLevel: 2, | 747 | TopLevel: 2, |
709 | 729 | Payloads: []json.RawMessage{json.RawMessage(`{"b":1}`)}, | 748 | Payloads: []json.RawMessage{json.RawMessage(`{"b":1}`)}, |
710 | 730 | } | 749 | } |
712 | 731 | go func() { s.errCh <- s.sess.handleBroadcast(msg) }() | 750 | go func() { s.sess.errCh <- s.sess.handleBroadcast(msg) }() |
713 | 732 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) | 751 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) |
714 | 733 | failure := errors.New("ACK ACK ACK") | 752 | failure := errors.New("ACK ACK ACK") |
715 | 734 | s.upCh <- failure | 753 | s.upCh <- failure |
717 | 735 | c.Assert(<-s.errCh, Equals, failure) | 754 | c.Assert(<-s.sess.errCh, Equals, failure) |
718 | 736 | c.Check(s.sess.State(), Equals, Error) | 755 | c.Check(s.sess.State(), Equals, Error) |
719 | 737 | } | 756 | } |
720 | 738 | 757 | ||
721 | @@ -746,10 +765,10 @@ | |||
722 | 746 | TopLevel: 2, | 765 | TopLevel: 2, |
723 | 747 | Payloads: []json.RawMessage{json.RawMessage(`{"b":1}`)}, | 766 | Payloads: []json.RawMessage{json.RawMessage(`{"b":1}`)}, |
724 | 748 | } | 767 | } |
726 | 749 | go func() { s.errCh <- s.sess.handleBroadcast(msg) }() | 768 | go func() { s.sess.errCh <- s.sess.handleBroadcast(msg) }() |
727 | 750 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) | 769 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) |
728 | 751 | s.upCh <- nil // ack ok | 770 | s.upCh <- nil // ack ok |
730 | 752 | c.Check(<-s.errCh, IsNil) | 771 | c.Check(<-s.sess.errCh, IsNil) |
731 | 753 | c.Check(len(s.sess.BroadcastCh), Equals, 0) | 772 | c.Check(len(s.sess.BroadcastCh), Equals, 0) |
732 | 754 | } | 773 | } |
733 | 755 | 774 | ||
734 | @@ -764,10 +783,10 @@ | |||
735 | 764 | TopLevel: 2, | 783 | TopLevel: 2, |
736 | 765 | Payloads: []json.RawMessage{json.RawMessage(`{"b":1}`)}, | 784 | Payloads: []json.RawMessage{json.RawMessage(`{"b":1}`)}, |
737 | 766 | } | 785 | } |
739 | 767 | go func() { s.errCh <- s.sess.handleBroadcast(msg) }() | 786 | go func() { s.sess.errCh <- s.sess.handleBroadcast(msg) }() |
740 | 768 | s.upCh <- nil // ack ok | 787 | s.upCh <- nil // ack ok |
741 | 769 | // start returns with error | 788 | // start returns with error |
743 | 770 | c.Check(<-s.errCh, Not(Equals), nil) | 789 | c.Check(<-s.sess.errCh, Not(Equals), nil) |
744 | 771 | c.Check(s.sess.State(), Equals, Error) | 790 | c.Check(s.sess.State(), Equals, Error) |
745 | 772 | // no message sent out | 791 | // no message sent out |
746 | 773 | c.Check(len(s.sess.BroadcastCh), Equals, 0) | 792 | c.Check(len(s.sess.BroadcastCh), Equals, 0) |
747 | @@ -780,10 +799,10 @@ | |||
748 | 780 | s.sess.setShouldDelay() | 799 | s.sess.setShouldDelay() |
749 | 781 | 800 | ||
750 | 782 | msg := &serverMsg{Type: "broadcast"} | 801 | msg := &serverMsg{Type: "broadcast"} |
752 | 783 | go func() { s.errCh <- s.sess.handleBroadcast(msg) }() | 802 | go func() { s.sess.errCh <- s.sess.handleBroadcast(msg) }() |
753 | 784 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) | 803 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) |
754 | 785 | s.upCh <- nil // ack ok | 804 | s.upCh <- nil // ack ok |
756 | 786 | c.Check(<-s.errCh, IsNil) | 805 | c.Check(<-s.sess.errCh, IsNil) |
757 | 787 | 806 | ||
758 | 788 | c.Check(s.sess.ShouldDelay(), Equals, false) | 807 | c.Check(s.sess.ShouldDelay(), Equals, false) |
759 | 789 | } | 808 | } |
760 | @@ -792,10 +811,10 @@ | |||
761 | 792 | s.sess.setShouldDelay() | 811 | s.sess.setShouldDelay() |
762 | 793 | 812 | ||
763 | 794 | msg := &serverMsg{Type: "broadcast"} | 813 | msg := &serverMsg{Type: "broadcast"} |
765 | 795 | go func() { s.errCh <- s.sess.handleBroadcast(msg) }() | 814 | go func() { s.sess.errCh <- s.sess.handleBroadcast(msg) }() |
766 | 796 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) | 815 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) |
767 | 797 | s.upCh <- errors.New("bcast") | 816 | s.upCh <- errors.New("bcast") |
769 | 798 | c.Check(<-s.errCh, NotNil) | 817 | c.Check(<-s.sess.errCh, NotNil) |
770 | 799 | 818 | ||
771 | 800 | c.Check(s.sess.ShouldDelay(), Equals, true) | 819 | c.Check(s.sess.ShouldDelay(), Equals, true) |
772 | 801 | } | 820 | } |
773 | @@ -845,10 +864,10 @@ | |||
774 | 845 | msg.NotificationsMsg = protocol.NotificationsMsg{ | 864 | msg.NotificationsMsg = protocol.NotificationsMsg{ |
775 | 846 | Notifications: []protocol.Notification{n1, n2}, | 865 | Notifications: []protocol.Notification{n1, n2}, |
776 | 847 | } | 866 | } |
778 | 848 | go func() { s.errCh <- s.sess.handleNotifications(msg) }() | 867 | go func() { s.sess.errCh <- s.sess.handleNotifications(msg) }() |
779 | 849 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) | 868 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) |
780 | 850 | s.upCh <- nil // ack ok | 869 | s.upCh <- nil // ack ok |
782 | 851 | c.Check(<-s.errCh, Equals, nil) | 870 | c.Check(<-s.sess.errCh, Equals, nil) |
783 | 852 | c.Check(s.sess.ShouldDelay(), Equals, false) | 871 | c.Check(s.sess.ShouldDelay(), Equals, false) |
784 | 853 | c.Assert(s.sess.NotificationsCh, HasLen, 2) | 872 | c.Assert(s.sess.NotificationsCh, HasLen, 2) |
785 | 854 | app1, err := click.ParseAppId("com.example.app1_app1") | 873 | app1, err := click.ParseAppId("com.example.app1_app1") |
786 | @@ -891,10 +910,10 @@ | |||
787 | 891 | msg.NotificationsMsg = protocol.NotificationsMsg{ | 910 | msg.NotificationsMsg = protocol.NotificationsMsg{ |
788 | 892 | Notifications: []protocol.Notification{n1, n2}, | 911 | Notifications: []protocol.Notification{n1, n2}, |
789 | 893 | } | 912 | } |
791 | 894 | go func() { s.errCh <- s.sess.handleNotifications(msg) }() | 913 | go func() { s.sess.errCh <- s.sess.handleNotifications(msg) }() |
792 | 895 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) | 914 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) |
793 | 896 | s.upCh <- nil // ack ok | 915 | s.upCh <- nil // ack ok |
795 | 897 | c.Check(<-s.errCh, Equals, nil) | 916 | c.Check(<-s.sess.errCh, Equals, nil) |
796 | 898 | c.Check(s.sess.ShouldDelay(), Equals, false) | 917 | c.Check(s.sess.ShouldDelay(), Equals, false) |
797 | 899 | c.Assert(s.sess.NotificationsCh, HasLen, 1) | 918 | c.Assert(s.sess.NotificationsCh, HasLen, 1) |
798 | 900 | app2, err := click.ParseAppId("com.example.app2_app2") | 919 | app2, err := click.ParseAppId("com.example.app2_app2") |
799 | @@ -926,10 +945,10 @@ | |||
800 | 926 | msg.NotificationsMsg = protocol.NotificationsMsg{ | 945 | msg.NotificationsMsg = protocol.NotificationsMsg{ |
801 | 927 | Notifications: []protocol.Notification{n1, n2}, | 946 | Notifications: []protocol.Notification{n1, n2}, |
802 | 928 | } | 947 | } |
804 | 929 | go func() { s.errCh <- s.sess.handleNotifications(msg) }() | 948 | go func() { s.sess.errCh <- s.sess.handleNotifications(msg) }() |
805 | 930 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) | 949 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) |
806 | 931 | s.upCh <- nil // ack ok | 950 | s.upCh <- nil // ack ok |
808 | 932 | c.Check(<-s.errCh, Equals, nil) | 951 | c.Check(<-s.sess.errCh, Equals, nil) |
809 | 933 | c.Assert(s.sess.NotificationsCh, HasLen, 2) | 952 | c.Assert(s.sess.NotificationsCh, HasLen, 2) |
810 | 934 | app1, err := click.ParseAppId("com.example.app1_app1") | 953 | app1, err := click.ParseAppId("com.example.app1_app1") |
811 | 935 | c.Assert(err, IsNil) | 954 | c.Assert(err, IsNil) |
812 | @@ -946,10 +965,10 @@ | |||
813 | 946 | c.Check(ac.ops, HasLen, 3) | 965 | c.Check(ac.ops, HasLen, 3) |
814 | 947 | 966 | ||
815 | 948 | // second time they get ignored | 967 | // second time they get ignored |
817 | 949 | go func() { s.errCh <- s.sess.handleNotifications(msg) }() | 968 | go func() { s.sess.errCh <- s.sess.handleNotifications(msg) }() |
818 | 950 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) | 969 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) |
819 | 951 | s.upCh <- nil // ack ok | 970 | s.upCh <- nil // ack ok |
821 | 952 | c.Check(<-s.errCh, Equals, nil) | 971 | c.Check(<-s.sess.errCh, Equals, nil) |
822 | 953 | c.Assert(s.sess.NotificationsCh, HasLen, 0) | 972 | c.Assert(s.sess.NotificationsCh, HasLen, 0) |
823 | 954 | c.Check(ac.ops, HasLen, 4) | 973 | c.Check(ac.ops, HasLen, 4) |
824 | 955 | } | 974 | } |
825 | @@ -966,11 +985,11 @@ | |||
826 | 966 | msg.NotificationsMsg = protocol.NotificationsMsg{ | 985 | msg.NotificationsMsg = protocol.NotificationsMsg{ |
827 | 967 | Notifications: []protocol.Notification{n1}, | 986 | Notifications: []protocol.Notification{n1}, |
828 | 968 | } | 987 | } |
830 | 969 | go func() { s.errCh <- s.sess.handleNotifications(msg) }() | 988 | go func() { s.sess.errCh <- s.sess.handleNotifications(msg) }() |
831 | 970 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) | 989 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) |
832 | 971 | failure := errors.New("ACK ACK ACK") | 990 | failure := errors.New("ACK ACK ACK") |
833 | 972 | s.upCh <- failure | 991 | s.upCh <- failure |
835 | 973 | c.Assert(<-s.errCh, Equals, failure) | 992 | c.Assert(<-s.sess.errCh, Equals, failure) |
836 | 974 | c.Check(s.sess.State(), Equals, Error) | 993 | c.Check(s.sess.State(), Equals, Error) |
837 | 975 | // didn't get to clear | 994 | // didn't get to clear |
838 | 976 | c.Check(s.sess.ShouldDelay(), Equals, true) | 995 | c.Check(s.sess.ShouldDelay(), Equals, true) |
839 | @@ -989,10 +1008,10 @@ | |||
840 | 989 | msg.NotificationsMsg = protocol.NotificationsMsg{ | 1008 | msg.NotificationsMsg = protocol.NotificationsMsg{ |
841 | 990 | Notifications: []protocol.Notification{n1}, | 1009 | Notifications: []protocol.Notification{n1}, |
842 | 991 | } | 1010 | } |
844 | 992 | go func() { s.errCh <- s.sess.handleNotifications(msg) }() | 1011 | go func() { s.sess.errCh <- s.sess.handleNotifications(msg) }() |
845 | 993 | s.upCh <- nil // ack ok | 1012 | s.upCh <- nil // ack ok |
846 | 994 | // start returns with error | 1013 | // start returns with error |
848 | 995 | c.Check(<-s.errCh, Not(Equals), nil) | 1014 | c.Check(<-s.sess.errCh, Not(Equals), nil) |
849 | 996 | c.Check(s.sess.State(), Equals, Error) | 1015 | c.Check(s.sess.State(), Equals, Error) |
850 | 997 | // no message sent out | 1016 | // no message sent out |
851 | 998 | c.Check(len(s.sess.NotificationsCh), Equals, 0) | 1017 | c.Check(len(s.sess.NotificationsCh), Equals, 0) |
852 | @@ -1013,8 +1032,8 @@ | |||
853 | 1013 | msg.ConnBrokenMsg = protocol.ConnBrokenMsg{ | 1032 | msg.ConnBrokenMsg = protocol.ConnBrokenMsg{ |
854 | 1014 | Reason: "REASON", | 1033 | Reason: "REASON", |
855 | 1015 | } | 1034 | } |
858 | 1016 | go func() { s.errCh <- s.sess.handleConnBroken(msg) }() | 1035 | go func() { s.sess.errCh <- s.sess.handleConnBroken(msg) }() |
859 | 1017 | c.Check(<-s.errCh, ErrorMatches, "server broke connection: REASON") | 1036 | c.Check(<-s.sess.errCh, ErrorMatches, "server broke connection: REASON") |
860 | 1018 | c.Check(s.sess.State(), Equals, Error) | 1037 | c.Check(s.sess.State(), Equals, Error) |
861 | 1019 | } | 1038 | } |
862 | 1020 | 1039 | ||
863 | @@ -1025,8 +1044,8 @@ | |||
864 | 1025 | Reason: protocol.BrokenHostMismatch, | 1044 | Reason: protocol.BrokenHostMismatch, |
865 | 1026 | } | 1045 | } |
866 | 1027 | s.sess.deliveryHosts = []string{"foo:443", "bar:443"} | 1046 | s.sess.deliveryHosts = []string{"foo:443", "bar:443"} |
869 | 1028 | go func() { s.errCh <- s.sess.handleConnBroken(msg) }() | 1047 | go func() { s.sess.errCh <- s.sess.handleConnBroken(msg) }() |
870 | 1029 | c.Check(<-s.errCh, ErrorMatches, "server broke connection: host-mismatch") | 1048 | c.Check(<-s.sess.errCh, ErrorMatches, "server broke connection: host-mismatch") |
871 | 1030 | c.Check(s.sess.State(), Equals, Error) | 1049 | c.Check(s.sess.State(), Equals, Error) |
872 | 1031 | // hosts were reset | 1050 | // hosts were reset |
873 | 1032 | c.Check(s.sess.deliveryHosts, IsNil) | 1051 | c.Check(s.sess.deliveryHosts, IsNil) |
874 | @@ -1044,14 +1063,14 @@ | |||
875 | 1044 | (*msgSuite)(s).SetUpTest(c) | 1063 | (*msgSuite)(s).SetUpTest(c) |
876 | 1045 | s.sess.Connection.(*testConn).Name = "TestLoop*" | 1064 | s.sess.Connection.(*testConn).Name = "TestLoop*" |
877 | 1046 | go func() { | 1065 | go func() { |
879 | 1047 | s.errCh <- s.sess.loop() | 1066 | s.sess.errCh <- s.sess.loop() |
880 | 1048 | }() | 1067 | }() |
881 | 1049 | } | 1068 | } |
882 | 1050 | 1069 | ||
883 | 1051 | func (s *loopSuite) TestLoopReadError(c *C) { | 1070 | func (s *loopSuite) TestLoopReadError(c *C) { |
884 | 1052 | c.Check(s.sess.State(), Equals, Running) | 1071 | c.Check(s.sess.State(), Equals, Running) |
885 | 1053 | s.upCh <- errors.New("Read") | 1072 | s.upCh <- errors.New("Read") |
887 | 1054 | err := <-s.errCh | 1073 | err := <-s.sess.errCh |
888 | 1055 | c.Check(err, ErrorMatches, "Read") | 1074 | c.Check(err, ErrorMatches, "Read") |
889 | 1056 | c.Check(s.sess.State(), Equals, Error) | 1075 | c.Check(s.sess.State(), Equals, Error) |
890 | 1057 | } | 1076 | } |
891 | @@ -1063,7 +1082,7 @@ | |||
892 | 1063 | c.Check(takeNext(s.downCh), Equals, protocol.PingPongMsg{Type: "pong"}) | 1082 | c.Check(takeNext(s.downCh), Equals, protocol.PingPongMsg{Type: "pong"}) |
893 | 1064 | failure := errors.New("pong") | 1083 | failure := errors.New("pong") |
894 | 1065 | s.upCh <- failure | 1084 | s.upCh <- failure |
896 | 1066 | c.Check(<-s.errCh, Equals, failure) | 1085 | c.Check(<-s.sess.errCh, Equals, failure) |
897 | 1067 | } | 1086 | } |
898 | 1068 | 1087 | ||
899 | 1069 | func (s *loopSuite) TestLoopLoopsDaLoop(c *C) { | 1088 | func (s *loopSuite) TestLoopLoopsDaLoop(c *C) { |
900 | @@ -1076,7 +1095,7 @@ | |||
901 | 1076 | } | 1095 | } |
902 | 1077 | failure := errors.New("pong") | 1096 | failure := errors.New("pong") |
903 | 1078 | s.upCh <- failure | 1097 | s.upCh <- failure |
905 | 1079 | c.Check(<-s.errCh, Equals, failure) | 1098 | c.Check(<-s.sess.errCh, Equals, failure) |
906 | 1080 | } | 1099 | } |
907 | 1081 | 1100 | ||
908 | 1082 | func (s *loopSuite) TestLoopBroadcast(c *C) { | 1101 | func (s *loopSuite) TestLoopBroadcast(c *C) { |
909 | @@ -1093,7 +1112,7 @@ | |||
910 | 1093 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) | 1112 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) |
911 | 1094 | failure := errors.New("ack") | 1113 | failure := errors.New("ack") |
912 | 1095 | s.upCh <- failure | 1114 | s.upCh <- failure |
914 | 1096 | c.Check(<-s.errCh, Equals, failure) | 1115 | c.Check(<-s.sess.errCh, Equals, failure) |
915 | 1097 | } | 1116 | } |
916 | 1098 | 1117 | ||
917 | 1099 | func (s *loopSuite) TestLoopNotifications(c *C) { | 1118 | func (s *loopSuite) TestLoopNotifications(c *C) { |
918 | @@ -1113,7 +1132,7 @@ | |||
919 | 1113 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) | 1132 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) |
920 | 1114 | failure := errors.New("ack") | 1133 | failure := errors.New("ack") |
921 | 1115 | s.upCh <- failure | 1134 | s.upCh <- failure |
923 | 1116 | c.Check(<-s.errCh, Equals, failure) | 1135 | c.Check(<-s.sess.errCh, Equals, failure) |
924 | 1117 | } | 1136 | } |
925 | 1118 | 1137 | ||
926 | 1119 | func (s *loopSuite) TestLoopSetParams(c *C) { | 1138 | func (s *loopSuite) TestLoopSetParams(c *C) { |
927 | @@ -1126,7 +1145,7 @@ | |||
928 | 1126 | s.upCh <- setParams | 1145 | s.upCh <- setParams |
929 | 1127 | failure := errors.New("fail") | 1146 | failure := errors.New("fail") |
930 | 1128 | s.upCh <- failure | 1147 | s.upCh <- failure |
932 | 1129 | c.Assert(<-s.errCh, Equals, failure) | 1148 | c.Assert(<-s.sess.errCh, Equals, failure) |
933 | 1130 | c.Check(s.sess.getCookie(), Equals, "COOKIE") | 1149 | c.Check(s.sess.getCookie(), Equals, "COOKIE") |
934 | 1131 | } | 1150 | } |
935 | 1132 | 1151 | ||
936 | @@ -1138,7 +1157,7 @@ | |||
937 | 1138 | } | 1157 | } |
938 | 1139 | c.Check(takeNext(s.downCh), Equals, "deadline 1ms") | 1158 | c.Check(takeNext(s.downCh), Equals, "deadline 1ms") |
939 | 1140 | s.upCh <- broken | 1159 | s.upCh <- broken |
941 | 1141 | c.Check(<-s.errCh, NotNil) | 1160 | c.Check(<-s.sess.errCh, NotNil) |
942 | 1142 | } | 1161 | } |
943 | 1143 | 1162 | ||
944 | 1144 | func (s *loopSuite) TestLoopConnWarn(c *C) { | 1163 | func (s *loopSuite) TestLoopConnWarn(c *C) { |
945 | @@ -1159,7 +1178,7 @@ | |||
946 | 1159 | s.upCh <- warn | 1178 | s.upCh <- warn |
947 | 1160 | s.upCh <- connwarn | 1179 | s.upCh <- connwarn |
948 | 1161 | s.upCh <- failure | 1180 | s.upCh <- failure |
950 | 1162 | c.Check(<-s.errCh, Equals, failure) | 1181 | c.Check(<-s.sess.errCh, Equals, failure) |
951 | 1163 | c.Check(log.Captured(), | 1182 | c.Check(log.Captured(), |
952 | 1164 | Matches, `(?ms).* warning: XXX$.*`) | 1183 | Matches, `(?ms).* warning: XXX$.*`) |
953 | 1165 | c.Check(log.Captured(), | 1184 | c.Check(log.Captured(), |
954 | @@ -1426,12 +1445,12 @@ | |||
955 | 1426 | func() error { sess.BroadcastCh <- notf; return <-failureCh }) | 1445 | func() error { sess.BroadcastCh <- notf; return <-failureCh }) |
956 | 1427 | c.Check(err, Equals, nil) | 1446 | c.Check(err, Equals, nil) |
957 | 1428 | // if run doesn't error it sets up the channels | 1447 | // if run doesn't error it sets up the channels |
959 | 1429 | c.Assert(sess.ErrCh, NotNil) | 1448 | c.Assert(sess.errCh, NotNil) |
960 | 1430 | c.Assert(sess.BroadcastCh, NotNil) | 1449 | c.Assert(sess.BroadcastCh, NotNil) |
961 | 1431 | c.Check(<-sess.BroadcastCh, Equals, notf) | 1450 | c.Check(<-sess.BroadcastCh, Equals, notf) |
962 | 1432 | failure := errors.New("TestRunRunsEvenIfLoopFails") | 1451 | failure := errors.New("TestRunRunsEvenIfLoopFails") |
963 | 1433 | failureCh <- failure | 1452 | failureCh <- failure |
965 | 1434 | c.Check(<-sess.ErrCh, Equals, failure) | 1453 | c.Check(<-sess.errCh, Equals, failure) |
966 | 1435 | // so now you know it was running in a goroutine :) | 1454 | // so now you know it was running in a goroutine :) |
967 | 1436 | } | 1455 | } |
968 | 1437 | 1456 | ||
969 | @@ -1632,7 +1651,7 @@ | |||
970 | 1632 | c.Check(takeNext(downCh), Equals, protocol.PingPongMsg{Type: "pong"}) | 1651 | c.Check(takeNext(downCh), Equals, protocol.PingPongMsg{Type: "pong"}) |
971 | 1633 | failure := errors.New("pongs") | 1652 | failure := errors.New("pongs") |
972 | 1634 | upCh <- failure | 1653 | upCh <- failure |
974 | 1635 | c.Check(<-sess.ErrCh, Equals, failure) | 1654 | c.Check(<-sess.errCh, Equals, failure) |
975 | 1636 | } | 1655 | } |
976 | 1637 | 1656 | ||
977 | 1638 | func (cs *clientSessionSuite) TestDialWorksDirect(c *C) { | 1657 | func (cs *clientSessionSuite) TestDialWorksDirect(c *C) { |
978 | @@ -1703,3 +1722,191 @@ | |||
979 | 1703 | sess.ClearCookie() | 1722 | sess.ClearCookie() |
980 | 1704 | c.Check(sess.getCookie(), Equals, "") | 1723 | c.Check(sess.getCookie(), Equals, "") |
981 | 1705 | } | 1724 | } |
982 | 1725 | |||
983 | 1726 | /**************************************************************** | ||
984 | 1727 | KeepConnection() (and related) tests | ||
985 | 1728 | ****************************************************************/ | ||
986 | 1729 | |||
987 | 1730 | func (cs *clientSessionSuite) TestKeepConnectionDoesNothingIfNotConnected(c *C) { | ||
988 | 1731 | // how do you test "does nothing?" | ||
989 | 1732 | sess, err := NewSession("foo:443", dummyConf(), "", cs.lvls, cs.log) | ||
990 | 1733 | c.Assert(err, IsNil) | ||
991 | 1734 | c.Assert(sess, NotNil) | ||
992 | 1735 | c.Assert(sess.State(), Equals, Pristine) | ||
993 | 1736 | c.Assert(sess.KeepConnection(), IsNil) | ||
994 | 1737 | // stopCh is meant to be used just for closing it, but abusing | ||
995 | 1738 | // it for testing seems the right thing to do: this ensures | ||
996 | 1739 | // the thing is ticking along before we check the state of | ||
997 | 1740 | // stuff. | ||
998 | 1741 | sess.stopCh <- struct{}{} | ||
999 | 1742 | c.Check(sess.State(), Equals, Disconnected) | ||
1000 | 1743 | } | ||
1001 | 1744 | |||
1002 | 1745 | func (cs *clientSessionSuite) TestYouCantCallKeepConnectionTwice(c *C) { | ||
1003 | 1746 | sess, err := NewSession("foo:443", dummyConf(), "", cs.lvls, cs.log) | ||
1004 | 1747 | c.Assert(err, IsNil) | ||
1005 | 1748 | c.Assert(sess, NotNil) | ||
1006 | 1749 | c.Assert(sess.State(), Equals, Pristine) | ||
1007 | 1750 | c.Assert(sess.KeepConnection(), IsNil) | ||
1008 | 1751 | defer sess.StopKeepConnection() | ||
1009 | 1752 | c.Check(sess.KeepConnection(), NotNil) | ||
1010 | 1753 | } | ||
1011 | 1754 | |||
1012 | 1755 | func (cs *clientSessionSuite) TestStopKeepConnectionShutsdown(c *C) { | ||
1013 | 1756 | sess, err := NewSession("foo:443", dummyConf(), "", cs.lvls, cs.log) | ||
1014 | 1757 | c.Assert(err, IsNil) | ||
1015 | 1758 | c.Assert(sess, NotNil) | ||
1016 | 1759 | sess.StopKeepConnection() | ||
1017 | 1760 | c.Check(sess.State(), Equals, Shutdown) | ||
1018 | 1761 | } | ||
1019 | 1762 | |||
1020 | 1763 | func (cs *clientSessionSuite) TestHasConnectivityTriggersConnectivityHandler(c *C) { | ||
1021 | 1764 | sess, err := NewSession("foo:443", dummyConf(), "", cs.lvls, cs.log) | ||
1022 | 1765 | c.Assert(err, IsNil) | ||
1023 | 1766 | c.Assert(sess, NotNil) | ||
1024 | 1767 | testCh := make(chan bool) | ||
1025 | 1768 | sess.connHandler = func(p bool) { testCh <- p } | ||
1026 | 1769 | go sess.doKeepConnection() | ||
1027 | 1770 | defer sess.StopKeepConnection() | ||
1028 | 1771 | sess.HasConnectivity(true) | ||
1029 | 1772 | c.Check(<-testCh, Equals, true) | ||
1030 | 1773 | sess.HasConnectivity(false) | ||
1031 | 1774 | c.Check(<-testCh, Equals, false) | ||
1032 | 1775 | } | ||
1033 | 1776 | |||
1034 | 1777 | func (cs *clientSessionSuite) TestDoneChIsEmptiedAndLogged(c *C) { | ||
1035 | 1778 | sess, err := NewSession("", dummyConf(), "wah", cs.lvls, cs.log) | ||
1036 | 1779 | c.Assert(err, IsNil) | ||
1037 | 1780 | sess.doneCh = make(chan uint32) // unbuffered | ||
1038 | 1781 | |||
1039 | 1782 | sess.KeepConnection() | ||
1040 | 1783 | defer sess.StopKeepConnection() | ||
1041 | 1784 | |||
1042 | 1785 | sess.doneCh <- 23 | ||
1043 | 1786 | |||
1044 | 1787 | c.Check(cs.log.Captured(), | ||
1045 | 1788 | Matches, `(?ms).* connected after 23 attempts\.`) | ||
1046 | 1789 | } | ||
1047 | 1790 | |||
1048 | 1791 | func (cs *clientSessionSuite) TestErrChIsEmptiedAndLoggedAndAutoRedial(c *C) { | ||
1049 | 1792 | sess, err := NewSession("", dummyConf(), "wah", cs.lvls, cs.log) | ||
1050 | 1793 | c.Assert(err, IsNil) | ||
1051 | 1794 | ch := make(chan struct{}, 1) | ||
1052 | 1795 | sess.errCh = make(chan error) // unbuffered | ||
1053 | 1796 | sess.redialDelay = func(sess *clientSession) time.Duration { ch <- struct{}{}; return 0 } | ||
1054 | 1797 | sess.lastConn = true // -> autoRedial, if the session is in Disconnected | ||
1055 | 1798 | |||
1056 | 1799 | sess.KeepConnection() | ||
1057 | 1800 | defer sess.StopKeepConnection() | ||
1058 | 1801 | |||
1059 | 1802 | sess.errCh <- errors.New("potato") | ||
1060 | 1803 | c.Assert(sess.State(), Equals, Disconnected) | ||
1061 | 1804 | select { | ||
1062 | 1805 | case <-ch: | ||
1063 | 1806 | // all ok | ||
1064 | 1807 | case <-time.After(100 * time.Millisecond): | ||
1065 | 1808 | c.Fatalf("redialDelay not called (-> autoRedial not called)?") | ||
1066 | 1809 | } | ||
1067 | 1810 | |||
1068 | 1811 | c.Check(cs.log.Captured(), | ||
1069 | 1812 | Matches, `(?ms).* session error.*potato`) | ||
1070 | 1813 | } | ||
1071 | 1814 | |||
1072 | 1815 | func (cs *clientSessionSuite) TestErrChIsEmptiedAndLoggedNoAutoRedial(c *C) { | ||
1073 | 1816 | sess, err := NewSession("", dummyConf(), "wah", cs.lvls, cs.log) | ||
1074 | 1817 | c.Assert(err, IsNil) | ||
1075 | 1818 | ch := make(chan struct{}, 1) | ||
1076 | 1819 | sess.errCh = make(chan error) // unbuffered | ||
1077 | 1820 | sess.redialDelay = func(sess *clientSession) time.Duration { ch <- struct{}{}; return 0 } | ||
1078 | 1821 | sess.connHandler = func(bool) {} | ||
1079 | 1822 | sess.lastConn = false // so, no autoredial | ||
1080 | 1823 | |||
1081 | 1824 | sess.KeepConnection() | ||
1082 | 1825 | defer sess.StopKeepConnection() | ||
1083 | 1826 | |||
1084 | 1827 | sess.errCh <- errors.New("potato") | ||
1085 | 1828 | c.Assert(sess.State(), Equals, Disconnected) | ||
1086 | 1829 | select { | ||
1087 | 1830 | case <-ch: | ||
1088 | 1831 | c.Fatalf("redialDelay called (-> autoRedial called) when disconnected?") | ||
1089 | 1832 | case <-time.After(100 * time.Millisecond): | ||
1090 | 1833 | // all ok | ||
1091 | 1834 | } | ||
1092 | 1835 | |||
1093 | 1836 | c.Check(cs.log.Captured(), | ||
1094 | 1837 | Matches, `(?ms).* session error.*potato`) | ||
1095 | 1838 | } | ||
1096 | 1839 | |||
1097 | 1840 | func (cs *clientSessionSuite) TestHandleConnConnFromConnected(c *C) { | ||
1098 | 1841 | sess, err := NewSession("", dummyConf(), "wah", cs.lvls, cs.log) | ||
1099 | 1842 | c.Assert(err, IsNil) | ||
1100 | 1843 | ch := make(chan struct{}, 1) | ||
1101 | 1844 | sess.redialDelay = func(sess *clientSession) time.Duration { ch <- struct{}{}; return 0 } | ||
1102 | 1845 | sess.state = Connected | ||
1103 | 1846 | sess.lastConn = true | ||
1104 | 1847 | sess.handleConn(true) | ||
1105 | 1848 | c.Check(sess.lastConn, Equals, true) | ||
1106 | 1849 | |||
1107 | 1850 | select { | ||
1108 | 1851 | case <-ch: | ||
1109 | 1852 | // all ok | ||
1110 | 1853 | case <-time.After(100 * time.Millisecond): | ||
1111 | 1854 | c.Fatalf("redialDelay not called (-> autoRedial not called)?") | ||
1112 | 1855 | } | ||
1113 | 1856 | } | ||
1114 | 1857 | |||
1115 | 1858 | func (cs *clientSessionSuite) TestHandleConnConnFromDisconnected(c *C) { | ||
1116 | 1859 | sess, err := NewSession("", dummyConf(), "wah", cs.lvls, cs.log) | ||
1117 | 1860 | c.Assert(err, IsNil) | ||
1118 | 1861 | ch := make(chan struct{}, 1) | ||
1119 | 1862 | sess.redialDelay = func(sess *clientSession) time.Duration { ch <- struct{}{}; return 0 } | ||
1120 | 1863 | sess.state = Disconnected | ||
1121 | 1864 | sess.lastConn = false | ||
1122 | 1865 | sess.handleConn(true) | ||
1123 | 1866 | c.Check(sess.lastConn, Equals, true) | ||
1124 | 1867 | |||
1125 | 1868 | select { | ||
1126 | 1869 | case <-ch: | ||
1127 | 1870 | // all ok | ||
1128 | 1871 | case <-time.After(100 * time.Millisecond): | ||
1129 | 1872 | c.Fatalf("redialDelay not called (-> autoRedial not called)?") | ||
1130 | 1873 | } | ||
1131 | 1874 | } | ||
1132 | 1875 | |||
1133 | 1876 | func (cs *clientSessionSuite) TestHandleConnNotConnFromDisconnected(c *C) { | ||
1134 | 1877 | sess, err := NewSession("", dummyConf(), "wah", cs.lvls, cs.log) | ||
1135 | 1878 | c.Assert(err, IsNil) | ||
1136 | 1879 | ch := make(chan struct{}, 1) | ||
1137 | 1880 | sess.redialDelay = func(sess *clientSession) time.Duration { ch <- struct{}{}; return 0 } | ||
1138 | 1881 | sess.state = Disconnected | ||
1139 | 1882 | sess.lastConn = false | ||
1140 | 1883 | sess.handleConn(false) | ||
1141 | 1884 | c.Check(sess.lastConn, Equals, false) | ||
1142 | 1885 | |||
1143 | 1886 | select { | ||
1144 | 1887 | case <-ch: | ||
1145 | 1888 | c.Fatalf("redialDelay called (-> autoRedial called)?") | ||
1146 | 1889 | case <-time.After(100 * time.Millisecond): | ||
1147 | 1890 | // all ok | ||
1148 | 1891 | } | ||
1149 | 1892 | c.Check(cs.log.Captured(), Matches, `(?ms).*-> Disconnected`) | ||
1150 | 1893 | } | ||
1151 | 1894 | |||
1152 | 1895 | func (cs *clientSessionSuite) TestHandleConnNotConnFromConnected(c *C) { | ||
1153 | 1896 | sess, err := NewSession("", dummyConf(), "wah", cs.lvls, cs.log) | ||
1154 | 1897 | c.Assert(err, IsNil) | ||
1155 | 1898 | ch := make(chan struct{}, 1) | ||
1156 | 1899 | sess.redialDelay = func(sess *clientSession) time.Duration { ch <- struct{}{}; return 0 } | ||
1157 | 1900 | sess.state = Connected | ||
1158 | 1901 | sess.lastConn = true | ||
1159 | 1902 | sess.handleConn(false) | ||
1160 | 1903 | c.Check(sess.lastConn, Equals, false) | ||
1161 | 1904 | |||
1162 | 1905 | select { | ||
1163 | 1906 | case <-ch: | ||
1164 | 1907 | c.Fatalf("redialDelay called (-> autoRedial called)?") | ||
1165 | 1908 | case <-time.After(100 * time.Millisecond): | ||
1166 | 1909 | // all ok | ||
1167 | 1910 | } | ||
1168 | 1911 | c.Check(cs.log.Captured(), Matches, `(?ms).*-> Disconnected`) | ||
1169 | 1912 | } |
see comments