Merge lp:~chipaca/ubuntu-push/actual-client-v0 into lp:ubuntu-push
- actual-client-v0
- Merge into trunk
Proposed by
John Lenton
Status: | Rejected |
---|---|
Rejected by: | John Lenton |
Proposed branch: | lp:~chipaca/ubuntu-push/actual-client-v0 |
Merge into: | lp:ubuntu-push |
Prerequisite: | lp:~chipaca/ubuntu-push/client-v0 |
Diff against target: |
528 lines (+199/-43) 7 files modified
bus/connectivity/connectivity.go (+7/-7) bus/connectivity/connectivity_test.go (+6/-6) client.json (+9/-0) client/client.go (+141/-0) client/session/session.go (+2/-2) client/session/session_test.go (+22/-22) util/redialer.go (+12/-6) |
To merge this branch: | bzr merge lp:~chipaca/ubuntu-push/actual-client-v0 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Push Hackers | Pending | ||
Review via email:
|
Commit message
v0 of the actual client. Not covered by tests yet.
Description of the change
v0 of the actual client. Not covered by tests yet.
To post a comment you must log in.
- 28. By John Lenton
-
moved client config to etc
- 29. By John Lenton
-
merged pipeline; conflict in the redialer fixed
- 30. By John Lenton
-
merged trunk, resolved conflict in redialer
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Samuele Pedroni (pedronis) wrote : | # |
Unmerged revisions
- 30. By John Lenton
-
merged trunk, resolved conflict in redialer
- 29. By John Lenton
-
merged pipeline; conflict in the redialer fixed
- 28. By John Lenton
-
moved client config to etc
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'bus/connectivity/connectivity.go' | |||
2 | --- bus/connectivity/connectivity.go 2014-01-23 14:33:08 +0000 | |||
3 | +++ bus/connectivity/connectivity.go 2014-01-27 18:11:05 +0000 | |||
4 | @@ -34,21 +34,21 @@ | |||
5 | 34 | 34 | ||
6 | 35 | // the configuration for ConnectedState, with the idea that you'd populate it | 35 | // the configuration for ConnectedState, with the idea that you'd populate it |
7 | 36 | // from a config file. | 36 | // from a config file. |
9 | 37 | type Config struct { | 37 | type ConnectivityConfig struct { |
10 | 38 | // how long to wait after a state change to make sure it's "stable" | 38 | // how long to wait after a state change to make sure it's "stable" |
11 | 39 | // before acting on it | 39 | // before acting on it |
13 | 40 | StabilizingTimeout config.ConfigTimeDuration | 40 | StabilizingTimeout config.ConfigTimeDuration `json:"stabilizing_timeout"` |
14 | 41 | // How long to wait between online connectivity checks. | 41 | // How long to wait between online connectivity checks. |
16 | 42 | RecheckTimeout config.ConfigTimeDuration | 42 | RecheckTimeout config.ConfigTimeDuration `json:"recheck_timeout"` |
17 | 43 | // The URL against which to do the connectivity check. | 43 | // The URL against which to do the connectivity check. |
19 | 44 | ConnectivityCheckURL string | 44 | ConnectivityCheckURL string `json:"connectivity_check_url"` |
20 | 45 | // The expected MD5 of the content at the ConnectivityCheckURL | 45 | // The expected MD5 of the content at the ConnectivityCheckURL |
22 | 46 | ConnectivityCheckMD5 string | 46 | ConnectivityCheckMD5 string `json:"connectivity_check_md5"` |
23 | 47 | } | 47 | } |
24 | 48 | 48 | ||
25 | 49 | type connectedState struct { | 49 | type connectedState struct { |
26 | 50 | networkStateCh <-chan networkmanager.State | 50 | networkStateCh <-chan networkmanager.State |
28 | 51 | config Config | 51 | config ConnectivityConfig |
29 | 52 | log logger.Logger | 52 | log logger.Logger |
30 | 53 | endp bus.Endpoint | 53 | endp bus.Endpoint |
31 | 54 | connAttempts uint32 | 54 | connAttempts uint32 |
32 | @@ -140,7 +140,7 @@ | |||
33 | 140 | // | 140 | // |
34 | 141 | // The endpoint need not be dialed; connectivity will Dial() and Close() | 141 | // The endpoint need not be dialed; connectivity will Dial() and Close() |
35 | 142 | // it as it sees fit. | 142 | // it as it sees fit. |
37 | 143 | func ConnectedState(endp bus.Endpoint, config Config, log logger.Logger, out chan<- bool) { | 143 | func ConnectedState(endp bus.Endpoint, config ConnectivityConfig, log logger.Logger, out chan<- bool) { |
38 | 144 | wg := NewWebchecker(config.ConnectivityCheckURL, config.ConnectivityCheckMD5, log) | 144 | wg := NewWebchecker(config.ConnectivityCheckURL, config.ConnectivityCheckMD5, log) |
39 | 145 | cs := &connectedState{ | 145 | cs := &connectedState{ |
40 | 146 | config: config, | 146 | config: config, |
41 | 147 | 147 | ||
42 | === modified file 'bus/connectivity/connectivity_test.go' | |||
43 | --- bus/connectivity/connectivity_test.go 2014-01-24 14:12:22 +0000 | |||
44 | +++ bus/connectivity/connectivity_test.go 2014-01-27 18:11:05 +0000 | |||
45 | @@ -58,7 +58,7 @@ | |||
46 | 58 | // when given a working config and bus, Start() will work | 58 | // when given a working config and bus, Start() will work |
47 | 59 | func (s *ConnSuite) TestStartWorks(c *C) { | 59 | func (s *ConnSuite) TestStartWorks(c *C) { |
48 | 60 | endp := testingbus.NewTestingEndpoint(condition.Work(true), condition.Work(true), uint32(networkmanager.Connecting)) | 60 | endp := testingbus.NewTestingEndpoint(condition.Work(true), condition.Work(true), uint32(networkmanager.Connecting)) |
50 | 61 | cs := connectedState{config: Config{}, log: nullog, endp: endp} | 61 | cs := connectedState{config: ConnectivityConfig{}, log: nullog, endp: endp} |
51 | 62 | 62 | ||
52 | 63 | c.Check(cs.start(), Equals, networkmanager.Connecting) | 63 | c.Check(cs.start(), Equals, networkmanager.Connecting) |
53 | 64 | } | 64 | } |
54 | @@ -66,7 +66,7 @@ | |||
55 | 66 | // if the bus fails a couple of times, we're still OK | 66 | // if the bus fails a couple of times, we're still OK |
56 | 67 | func (s *ConnSuite) TestStartRetriesConnect(c *C) { | 67 | func (s *ConnSuite) TestStartRetriesConnect(c *C) { |
57 | 68 | endp := testingbus.NewTestingEndpoint(condition.Fail2Work(2), condition.Work(true), uint32(networkmanager.Connecting)) | 68 | endp := testingbus.NewTestingEndpoint(condition.Fail2Work(2), condition.Work(true), uint32(networkmanager.Connecting)) |
59 | 69 | cs := connectedState{config: Config{}, log: nullog, endp: endp} | 69 | cs := connectedState{config: ConnectivityConfig{}, log: nullog, endp: endp} |
60 | 70 | 70 | ||
61 | 71 | c.Check(cs.start(), Equals, networkmanager.Connecting) | 71 | c.Check(cs.start(), Equals, networkmanager.Connecting) |
62 | 72 | c.Check(cs.connAttempts, Equals, uint32(3)) // 1 more than the Fail2Work | 72 | c.Check(cs.connAttempts, Equals, uint32(3)) // 1 more than the Fail2Work |
63 | @@ -75,7 +75,7 @@ | |||
64 | 75 | // when the calls to NetworkManager fail for a bit, we're still OK | 75 | // when the calls to NetworkManager fail for a bit, we're still OK |
65 | 76 | func (s *ConnSuite) TestStartRetriesCall(c *C) { | 76 | func (s *ConnSuite) TestStartRetriesCall(c *C) { |
66 | 77 | endp := testingbus.NewTestingEndpoint(condition.Work(true), condition.Fail2Work(5), uint32(networkmanager.Connecting)) | 77 | endp := testingbus.NewTestingEndpoint(condition.Work(true), condition.Fail2Work(5), uint32(networkmanager.Connecting)) |
68 | 78 | cs := connectedState{config: Config{}, log: nullog, endp: endp} | 78 | cs := connectedState{config: ConnectivityConfig{}, log: nullog, endp: endp} |
69 | 79 | 79 | ||
70 | 80 | c.Check(cs.start(), Equals, networkmanager.Connecting) | 80 | c.Check(cs.start(), Equals, networkmanager.Connecting) |
71 | 81 | 81 | ||
72 | @@ -93,7 +93,7 @@ | |||
73 | 93 | endp := testingbus.NewTestingEndpoint(condition.Work(true), nmcond, | 93 | endp := testingbus.NewTestingEndpoint(condition.Work(true), nmcond, |
74 | 94 | uint32(networkmanager.Connecting), | 94 | uint32(networkmanager.Connecting), |
75 | 95 | uint32(networkmanager.ConnectedGlobal)) | 95 | uint32(networkmanager.ConnectedGlobal)) |
77 | 96 | cs := connectedState{config: Config{}, log: nullog, endp: endp} | 96 | cs := connectedState{config: ConnectivityConfig{}, log: nullog, endp: endp} |
78 | 97 | 97 | ||
79 | 98 | c.Check(cs.start(), Equals, networkmanager.Connecting) | 98 | c.Check(cs.start(), Equals, networkmanager.Connecting) |
80 | 99 | c.Check(cs.connAttempts, Equals, uint32(2)) | 99 | c.Check(cs.connAttempts, Equals, uint32(2)) |
81 | @@ -109,7 +109,7 @@ | |||
82 | 109 | var webget_p condition.Interface = condition.Work(true) | 109 | var webget_p condition.Interface = condition.Work(true) |
83 | 110 | recheck_timeout := 50 * time.Millisecond | 110 | recheck_timeout := 50 * time.Millisecond |
84 | 111 | 111 | ||
86 | 112 | cfg := Config{ | 112 | cfg := ConnectivityConfig{ |
87 | 113 | RecheckTimeout: config.ConfigTimeDuration{recheck_timeout}, | 113 | RecheckTimeout: config.ConfigTimeDuration{recheck_timeout}, |
88 | 114 | } | 114 | } |
89 | 115 | ch := make(chan networkmanager.State, 10) | 115 | ch := make(chan networkmanager.State, 10) |
90 | @@ -184,7 +184,7 @@ | |||
91 | 184 | ts := httptest.NewServer(mkHandler(staticText)) | 184 | ts := httptest.NewServer(mkHandler(staticText)) |
92 | 185 | defer ts.Close() | 185 | defer ts.Close() |
93 | 186 | 186 | ||
95 | 187 | cfg := Config{ | 187 | cfg := ConnectivityConfig{ |
96 | 188 | ConnectivityCheckURL: ts.URL, | 188 | ConnectivityCheckURL: ts.URL, |
97 | 189 | ConnectivityCheckMD5: staticHash, | 189 | ConnectivityCheckMD5: staticHash, |
98 | 190 | RecheckTimeout: config.ConfigTimeDuration{time.Second}, | 190 | RecheckTimeout: config.ConfigTimeDuration{time.Second}, |
99 | 191 | 191 | ||
100 | === added file 'client.json' | |||
101 | --- client.json 1970-01-01 00:00:00 +0000 | |||
102 | +++ client.json 2014-01-27 18:11:05 +0000 | |||
103 | @@ -0,0 +1,9 @@ | |||
104 | 1 | { | ||
105 | 2 | "exchange_timeout": "30s", | ||
106 | 3 | "addr": ":9090", | ||
107 | 4 | "cert_pem_file": "server/acceptance/config/testing.cert", | ||
108 | 5 | "stabilizing_timeout": "2s", | ||
109 | 6 | "recheck_timeout": "10m", | ||
110 | 7 | "connectivity_check_url": "http://start.ubuntu.com/connectivity-check.html", | ||
111 | 8 | "connectivity_check_md5": "4589f42e1546aa47ca181e5d949d310b" | ||
112 | 9 | } | ||
113 | 0 | 10 | ||
114 | === added file 'client/client.go' | |||
115 | --- client/client.go 1970-01-01 00:00:00 +0000 | |||
116 | +++ client/client.go 2014-01-27 18:11:05 +0000 | |||
117 | @@ -0,0 +1,141 @@ | |||
118 | 1 | package main | ||
119 | 2 | |||
120 | 3 | import ( | ||
121 | 4 | "launchpad.net/go-dbus/v1" | ||
122 | 5 | "launchpad.net/ubuntu-push/bus" | ||
123 | 6 | "launchpad.net/ubuntu-push/bus/connectivity" | ||
124 | 7 | "launchpad.net/ubuntu-push/bus/networkmanager" | ||
125 | 8 | "launchpad.net/ubuntu-push/bus/notifications" | ||
126 | 9 | "launchpad.net/ubuntu-push/bus/urldispatcher" | ||
127 | 10 | "launchpad.net/ubuntu-push/client/session" | ||
128 | 11 | "launchpad.net/ubuntu-push/config" | ||
129 | 12 | "launchpad.net/ubuntu-push/logger" | ||
130 | 13 | "launchpad.net/ubuntu-push/util" | ||
131 | 14 | "launchpad.net/ubuntu-push/whoopsie/identifier" | ||
132 | 15 | "os" | ||
133 | 16 | ) | ||
134 | 17 | |||
135 | 18 | type configuration struct { | ||
136 | 19 | connectivity.ConnectivityConfig | ||
137 | 20 | session.ClientConfig | ||
138 | 21 | } | ||
139 | 22 | |||
140 | 23 | const ( | ||
141 | 24 | configFName string = "/etc/ubuntu-push/client.json" | ||
142 | 25 | ) | ||
143 | 26 | |||
144 | 27 | func notify_update(nots *notifications.RawNotifications, log logger.Logger) { | ||
145 | 28 | action_id := "my_action_id" | ||
146 | 29 | a := []string{action_id, "Go get it!"} // action value not visible on the phone | ||
147 | 30 | h := map[string]*dbus.Variant{"x-canonical-switch-to-application": &dbus.Variant{true}} | ||
148 | 31 | not_id, err := nots.Notify( | ||
149 | 32 | "ubuntu-push-client", // app name | ||
150 | 33 | uint32(0), // id | ||
151 | 34 | "update_manager_icon", // icon | ||
152 | 35 | "There's an updated system image!", // summary | ||
153 | 36 | "You've got to get it! Now! Run!", // body | ||
154 | 37 | a, // actions | ||
155 | 38 | h, // hints | ||
156 | 39 | int32(10*1000), // timeout | ||
157 | 40 | ) | ||
158 | 41 | if err != nil { | ||
159 | 42 | log.Fatalf("%s", err) | ||
160 | 43 | } | ||
161 | 44 | log.Debugf("Got notification id %d\n", not_id) | ||
162 | 45 | } | ||
163 | 46 | |||
164 | 47 | func main() { | ||
165 | 48 | log := logger.NewSimpleLogger(os.Stderr, "debug") | ||
166 | 49 | f, err := os.Open(configFName) | ||
167 | 50 | if err != nil { | ||
168 | 51 | log.Fatalf("reading config: %v", err) | ||
169 | 52 | } | ||
170 | 53 | cfg := &configuration{} | ||
171 | 54 | err = config.ReadConfig(f, cfg) | ||
172 | 55 | if err != nil { | ||
173 | 56 | log.Fatalf("reading config: %v", err) | ||
174 | 57 | } | ||
175 | 58 | whopId := identifier.New() | ||
176 | 59 | err = whopId.Generate() | ||
177 | 60 | if err != nil { | ||
178 | 61 | log.Fatalf("Generating device id: %v", err) | ||
179 | 62 | } | ||
180 | 63 | deviceId := whopId.String() | ||
181 | 64 | log.Debugf("Connecting as device id %s", deviceId) | ||
182 | 65 | session, err := session.NewSession(cfg.ClientConfig, log, deviceId) | ||
183 | 66 | if err != nil { | ||
184 | 67 | log.Fatalf("%s", err) | ||
185 | 68 | } | ||
186 | 69 | // ^^ up to this line, things that never change | ||
187 | 70 | var is_connected, ok bool | ||
188 | 71 | // vv from this line, things that never stay the same | ||
189 | 72 | for { | ||
190 | 73 | log.Debugf("Here we go!") | ||
191 | 74 | is_connected = false | ||
192 | 75 | connCh := make(chan bool) | ||
193 | 76 | iniCh := make(chan uint32) | ||
194 | 77 | |||
195 | 78 | notEndp := bus.SessionBus.Endpoint(notifications.BusAddress, log) | ||
196 | 79 | urlEndp := bus.SessionBus.Endpoint(urldispatcher.BusAddress, log) | ||
197 | 80 | |||
198 | 81 | go func() { iniCh <- util.AutoRetry(session.Reset) }() | ||
199 | 82 | go func() { iniCh <- util.AutoRedial(notEndp) }() | ||
200 | 83 | go func() { iniCh <- util.AutoRedial(urlEndp) }() | ||
201 | 84 | go connectivity.ConnectedState(bus.SystemBus.Endpoint(networkmanager.BusAddress, log), cfg.ConnectivityConfig, log, connCh) | ||
202 | 85 | |||
203 | 86 | <-iniCh | ||
204 | 87 | <-iniCh | ||
205 | 88 | <-iniCh | ||
206 | 89 | nots := notifications.Raw(notEndp, log) | ||
207 | 90 | urld := urldispatcher.New(urlEndp, log) | ||
208 | 91 | |||
209 | 92 | actnCh, err := nots.WatchActions() | ||
210 | 93 | if err != nil { | ||
211 | 94 | log.Errorf("%s", err) | ||
212 | 95 | continue | ||
213 | 96 | } | ||
214 | 97 | |||
215 | 98 | InnerLoop: | ||
216 | 99 | for { | ||
217 | 100 | select { | ||
218 | 101 | case is_connected, ok = <-connCh: | ||
219 | 102 | // handle connectivty changes | ||
220 | 103 | // disconnect session if offline, reconnect if online | ||
221 | 104 | if !ok { | ||
222 | 105 | log.Errorf("connectivity checker crashed? restarting everything") | ||
223 | 106 | break InnerLoop | ||
224 | 107 | } | ||
225 | 108 | // fallthrough | ||
226 | 109 | // oh, silly ol' go doesn't like that. | ||
227 | 110 | if is_connected { | ||
228 | 111 | err = session.Reset() | ||
229 | 112 | if err != nil { | ||
230 | 113 | break InnerLoop | ||
231 | 114 | } | ||
232 | 115 | } | ||
233 | 116 | case <-session.ErrCh: | ||
234 | 117 | // handle session errors | ||
235 | 118 | // restart if online, otherwise ignore | ||
236 | 119 | if is_connected { | ||
237 | 120 | err = session.Reset() | ||
238 | 121 | if err != nil { | ||
239 | 122 | break InnerLoop | ||
240 | 123 | } | ||
241 | 124 | } | ||
242 | 125 | case <-session.MsgCh: | ||
243 | 126 | // handle push notifications | ||
244 | 127 | // pop up client notification | ||
245 | 128 | // what to do does not depend on the rest | ||
246 | 129 | // (... for now) | ||
247 | 130 | log.Debugf("got a notification! let's pop it up.") | ||
248 | 131 | notify_update(nots, log) | ||
249 | 132 | case <-actnCh: | ||
250 | 133 | // handle action clicks | ||
251 | 134 | // launch system updates | ||
252 | 135 | // what to do does not depend on the rest | ||
253 | 136 | // (... for now) | ||
254 | 137 | urld.DispatchURL("settings:///system/system-update") | ||
255 | 138 | } | ||
256 | 139 | } | ||
257 | 140 | } | ||
258 | 141 | } | ||
259 | 0 | 142 | ||
260 | === modified file 'client/session/session.go' | |||
261 | --- client/session/session.go 2014-01-27 18:11:05 +0000 | |||
262 | +++ client/session/session.go 2014-01-27 18:11:05 +0000 | |||
263 | @@ -50,7 +50,7 @@ | |||
264 | 50 | 50 | ||
265 | 51 | var _ LevelMap = &mapLevelMap{} | 51 | var _ LevelMap = &mapLevelMap{} |
266 | 52 | 52 | ||
268 | 53 | type Config struct { | 53 | type ClientConfig struct { |
269 | 54 | // session configuration | 54 | // session configuration |
270 | 55 | ExchangeTimeout config.ConfigTimeDuration `json:"exchange_timeout"` | 55 | ExchangeTimeout config.ConfigTimeDuration `json:"exchange_timeout"` |
271 | 56 | // server connection config | 56 | // server connection config |
272 | @@ -75,7 +75,7 @@ | |||
273 | 75 | MsgCh chan *Notification | 75 | MsgCh chan *Notification |
274 | 76 | } | 76 | } |
275 | 77 | 77 | ||
277 | 78 | func NewSession(config Config, log logger.Logger, deviceId string) (*ClientSession, error) { | 78 | func NewSession(config ClientConfig, log logger.Logger, deviceId string) (*ClientSession, error) { |
278 | 79 | sess := &ClientSession{ | 79 | sess := &ClientSession{ |
279 | 80 | ExchangeTimeout: config.ExchangeTimeout.TimeDuration(), | 80 | ExchangeTimeout: config.ExchangeTimeout.TimeDuration(), |
280 | 81 | ServerAddr: config.Addr.HostPort(), | 81 | ServerAddr: config.Addr.HostPort(), |
281 | 82 | 82 | ||
282 | === modified file 'client/session/session_test.go' | |||
283 | --- client/session/session_test.go 2014-01-27 18:11:05 +0000 | |||
284 | +++ client/session/session_test.go 2014-01-27 18:11:05 +0000 | |||
285 | @@ -49,7 +49,7 @@ | |||
286 | 49 | ****************************************************************/ | 49 | ****************************************************************/ |
287 | 50 | 50 | ||
288 | 51 | func (cs *clientSessionSuite) TestNewSessionPlainWorks(c *C) { | 51 | func (cs *clientSessionSuite) TestNewSessionPlainWorks(c *C) { |
290 | 52 | cfg := Config{} | 52 | cfg := ClientConfig{} |
291 | 53 | sess, err := NewSession(cfg, nullog, "wah") | 53 | sess, err := NewSession(cfg, nullog, "wah") |
292 | 54 | c.Check(sess, NotNil) | 54 | c.Check(sess, NotNil) |
293 | 55 | c.Check(err, IsNil) | 55 | c.Check(err, IsNil) |
294 | @@ -58,7 +58,7 @@ | |||
295 | 58 | var certfile string = helpers.SourceRelative("../../server/acceptance/config/testing.cert") | 58 | var certfile string = helpers.SourceRelative("../../server/acceptance/config/testing.cert") |
296 | 59 | 59 | ||
297 | 60 | func (cs *clientSessionSuite) TestNewSessionPEMWorks(c *C) { | 60 | func (cs *clientSessionSuite) TestNewSessionPEMWorks(c *C) { |
299 | 61 | cfg := Config{CertPEMFile: certfile} | 61 | cfg := ClientConfig{CertPEMFile: certfile} |
300 | 62 | sess, err := NewSession(cfg, nullog, "wah") | 62 | sess, err := NewSession(cfg, nullog, "wah") |
301 | 63 | c.Check(sess, NotNil) | 63 | c.Check(sess, NotNil) |
302 | 64 | c.Assert(err, IsNil) | 64 | c.Assert(err, IsNil) |
303 | @@ -66,14 +66,14 @@ | |||
304 | 66 | } | 66 | } |
305 | 67 | 67 | ||
306 | 68 | func (cs *clientSessionSuite) TestNewSessionBadPEMFilePathFails(c *C) { | 68 | func (cs *clientSessionSuite) TestNewSessionBadPEMFilePathFails(c *C) { |
308 | 69 | cfg := Config{CertPEMFile: "/no/such/path"} | 69 | cfg := ClientConfig{CertPEMFile: "/no/such/path"} |
309 | 70 | sess, err := NewSession(cfg, nullog, "wah") | 70 | sess, err := NewSession(cfg, nullog, "wah") |
310 | 71 | c.Check(sess, IsNil) | 71 | c.Check(sess, IsNil) |
311 | 72 | c.Check(err, NotNil) | 72 | c.Check(err, NotNil) |
312 | 73 | } | 73 | } |
313 | 74 | 74 | ||
314 | 75 | func (cs *clientSessionSuite) TestNewSessionBadPEMFileContentFails(c *C) { | 75 | func (cs *clientSessionSuite) TestNewSessionBadPEMFileContentFails(c *C) { |
316 | 76 | cfg := Config{CertPEMFile: "/etc/passwd"} | 76 | cfg := ClientConfig{CertPEMFile: "/etc/passwd"} |
317 | 77 | sess, err := NewSession(cfg, nullog, "wah") | 77 | sess, err := NewSession(cfg, nullog, "wah") |
318 | 78 | c.Check(sess, IsNil) | 78 | c.Check(sess, IsNil) |
319 | 79 | c.Check(err, NotNil) | 79 | c.Check(err, NotNil) |
320 | @@ -214,7 +214,7 @@ | |||
321 | 214 | ****************************************************************/ | 214 | ****************************************************************/ |
322 | 215 | 215 | ||
323 | 216 | func (cs *clientSessionSuite) TestRunFailsIfNilConnection(c *C) { | 216 | func (cs *clientSessionSuite) TestRunFailsIfNilConnection(c *C) { |
325 | 217 | sess, err := NewSession(Config{}, debuglog, "wah") | 217 | sess, err := NewSession(ClientConfig{}, debuglog, "wah") |
326 | 218 | c.Assert(err, IsNil) | 218 | c.Assert(err, IsNil) |
327 | 219 | // not connected! | 219 | // not connected! |
328 | 220 | err = sess.run() | 220 | err = sess.run() |
329 | @@ -223,7 +223,7 @@ | |||
330 | 223 | } | 223 | } |
331 | 224 | 224 | ||
332 | 225 | func (cs *clientSessionSuite) TestRunFailsIfNilProtocolator(c *C) { | 225 | func (cs *clientSessionSuite) TestRunFailsIfNilProtocolator(c *C) { |
334 | 226 | sess, err := NewSession(Config{}, debuglog, "wah") | 226 | sess, err := NewSession(ClientConfig{}, debuglog, "wah") |
335 | 227 | c.Assert(err, IsNil) | 227 | c.Assert(err, IsNil) |
336 | 228 | sess.Connection = &testConn{Name: testname()} // ok, have a constructor | 228 | sess.Connection = &testConn{Name: testname()} // ok, have a constructor |
337 | 229 | sess.Protocolator = nil // but no protocol, seeficare. | 229 | sess.Protocolator = nil // but no protocol, seeficare. |
338 | @@ -233,7 +233,7 @@ | |||
339 | 233 | } | 233 | } |
340 | 234 | 234 | ||
341 | 235 | func (cs *clientSessionSuite) TestRunFailsIfSetDeadlineFails(c *C) { | 235 | func (cs *clientSessionSuite) TestRunFailsIfSetDeadlineFails(c *C) { |
343 | 236 | sess, err := NewSession(Config{}, debuglog, "wah") | 236 | sess, err := NewSession(ClientConfig{}, debuglog, "wah") |
344 | 237 | c.Assert(err, IsNil) | 237 | c.Assert(err, IsNil) |
345 | 238 | sess.Connection = &testConn{Name: testname(), | 238 | sess.Connection = &testConn{Name: testname(), |
346 | 239 | DeadlineCondition: condition.Work(false)} // setdeadline will fail | 239 | DeadlineCondition: condition.Work(false)} // setdeadline will fail |
347 | @@ -243,7 +243,7 @@ | |||
348 | 243 | } | 243 | } |
349 | 244 | 244 | ||
350 | 245 | func (cs *clientSessionSuite) TestRunFailsIfWriteFails(c *C) { | 245 | func (cs *clientSessionSuite) TestRunFailsIfWriteFails(c *C) { |
352 | 246 | sess, err := NewSession(Config{}, debuglog, "wah") | 246 | sess, err := NewSession(ClientConfig{}, debuglog, "wah") |
353 | 247 | c.Assert(err, IsNil) | 247 | c.Assert(err, IsNil) |
354 | 248 | sess.Connection = &testConn{Name: testname(), | 248 | sess.Connection = &testConn{Name: testname(), |
355 | 249 | WriteCondition: condition.Work(false)} // write will fail | 249 | WriteCondition: condition.Work(false)} // write will fail |
356 | @@ -253,7 +253,7 @@ | |||
357 | 253 | } | 253 | } |
358 | 254 | 254 | ||
359 | 255 | func (cs *clientSessionSuite) TestRunConnectMessageFails(c *C) { | 255 | func (cs *clientSessionSuite) TestRunConnectMessageFails(c *C) { |
361 | 256 | sess, err := NewSession(Config{}, debuglog, "wah") | 256 | sess, err := NewSession(ClientConfig{}, debuglog, "wah") |
362 | 257 | c.Assert(err, IsNil) | 257 | c.Assert(err, IsNil) |
363 | 258 | sess.Connection = &testConn{Name: testname()} | 258 | sess.Connection = &testConn{Name: testname()} |
364 | 259 | errCh := make(chan error, 1) | 259 | errCh := make(chan error, 1) |
365 | @@ -278,7 +278,7 @@ | |||
366 | 278 | } | 278 | } |
367 | 279 | 279 | ||
368 | 280 | func (cs *clientSessionSuite) TestRunConnackReadError(c *C) { | 280 | func (cs *clientSessionSuite) TestRunConnackReadError(c *C) { |
370 | 281 | sess, err := NewSession(Config{}, debuglog, "wah") | 281 | sess, err := NewSession(ClientConfig{}, debuglog, "wah") |
371 | 282 | c.Assert(err, IsNil) | 282 | c.Assert(err, IsNil) |
372 | 283 | sess.Connection = &testConn{Name: testname()} | 283 | sess.Connection = &testConn{Name: testname()} |
373 | 284 | errCh := make(chan error, 1) | 284 | errCh := make(chan error, 1) |
374 | @@ -300,7 +300,7 @@ | |||
375 | 300 | } | 300 | } |
376 | 301 | 301 | ||
377 | 302 | func (cs *clientSessionSuite) TestRunBadConnack(c *C) { | 302 | func (cs *clientSessionSuite) TestRunBadConnack(c *C) { |
379 | 303 | sess, err := NewSession(Config{}, debuglog, "wah") | 303 | sess, err := NewSession(ClientConfig{}, debuglog, "wah") |
380 | 304 | c.Assert(err, IsNil) | 304 | c.Assert(err, IsNil) |
381 | 305 | sess.Connection = &testConn{Name: testname()} | 305 | sess.Connection = &testConn{Name: testname()} |
382 | 306 | errCh := make(chan error, 1) | 306 | errCh := make(chan error, 1) |
383 | @@ -322,7 +322,7 @@ | |||
384 | 322 | } | 322 | } |
385 | 323 | 323 | ||
386 | 324 | func (cs *clientSessionSuite) TestRunMainloopReadError(c *C) { | 324 | func (cs *clientSessionSuite) TestRunMainloopReadError(c *C) { |
388 | 325 | sess, err := NewSession(Config{}, debuglog, "wah") | 325 | sess, err := NewSession(ClientConfig{}, debuglog, "wah") |
389 | 326 | c.Assert(err, IsNil) | 326 | c.Assert(err, IsNil) |
390 | 327 | sess.Connection = &testConn{Name: testname()} | 327 | sess.Connection = &testConn{Name: testname()} |
391 | 328 | errCh := make(chan error, 1) | 328 | errCh := make(chan error, 1) |
392 | @@ -349,7 +349,7 @@ | |||
393 | 349 | } | 349 | } |
394 | 350 | 350 | ||
395 | 351 | func (cs *clientSessionSuite) TestRunPongWriteError(c *C) { | 351 | func (cs *clientSessionSuite) TestRunPongWriteError(c *C) { |
397 | 352 | sess, err := NewSession(Config{}, debuglog, "wah") | 352 | sess, err := NewSession(ClientConfig{}, debuglog, "wah") |
398 | 353 | c.Assert(err, IsNil) | 353 | c.Assert(err, IsNil) |
399 | 354 | sess.Connection = &testConn{Name: testname()} | 354 | sess.Connection = &testConn{Name: testname()} |
400 | 355 | errCh := make(chan error, 1) | 355 | errCh := make(chan error, 1) |
401 | @@ -378,7 +378,7 @@ | |||
402 | 378 | } | 378 | } |
403 | 379 | 379 | ||
404 | 380 | func (cs *clientSessionSuite) TestRunPingPong(c *C) { | 380 | func (cs *clientSessionSuite) TestRunPingPong(c *C) { |
406 | 381 | sess, err := NewSession(Config{}, debuglog, "wah") | 381 | sess, err := NewSession(ClientConfig{}, debuglog, "wah") |
407 | 382 | c.Assert(err, IsNil) | 382 | c.Assert(err, IsNil) |
408 | 383 | sess.Connection = &testConn{Name: testname()} | 383 | sess.Connection = &testConn{Name: testname()} |
409 | 384 | errCh := make(chan error, 1) | 384 | errCh := make(chan error, 1) |
410 | @@ -406,7 +406,7 @@ | |||
411 | 406 | } | 406 | } |
412 | 407 | 407 | ||
413 | 408 | func (cs *clientSessionSuite) TestRunBadAckWrite(c *C) { | 408 | func (cs *clientSessionSuite) TestRunBadAckWrite(c *C) { |
415 | 409 | sess, err := NewSession(Config{}, debuglog, "wah") | 409 | sess, err := NewSession(ClientConfig{}, debuglog, "wah") |
416 | 410 | c.Assert(err, IsNil) | 410 | c.Assert(err, IsNil) |
417 | 411 | sess.Connection = &testConn{Name: testname()} | 411 | sess.Connection = &testConn{Name: testname()} |
418 | 412 | errCh := make(chan error, 1) | 412 | errCh := make(chan error, 1) |
419 | @@ -444,7 +444,7 @@ | |||
420 | 444 | } | 444 | } |
421 | 445 | 445 | ||
422 | 446 | func (cs *clientSessionSuite) TestRunBroadcastWrongChannel(c *C) { | 446 | func (cs *clientSessionSuite) TestRunBroadcastWrongChannel(c *C) { |
424 | 447 | sess, err := NewSession(Config{}, debuglog, "wah") | 447 | sess, err := NewSession(ClientConfig{}, debuglog, "wah") |
425 | 448 | c.Assert(err, IsNil) | 448 | c.Assert(err, IsNil) |
426 | 449 | sess.Connection = &testConn{Name: testname()} | 449 | sess.Connection = &testConn{Name: testname()} |
427 | 450 | errCh := make(chan error, 1) | 450 | errCh := make(chan error, 1) |
428 | @@ -482,7 +482,7 @@ | |||
429 | 482 | } | 482 | } |
430 | 483 | 483 | ||
431 | 484 | func (cs *clientSessionSuite) TestRunBroadcastRightChannel(c *C) { | 484 | func (cs *clientSessionSuite) TestRunBroadcastRightChannel(c *C) { |
433 | 485 | sess, err := NewSession(Config{}, debuglog, "wah") | 485 | sess, err := NewSession(ClientConfig{}, debuglog, "wah") |
434 | 486 | c.Assert(err, IsNil) | 486 | c.Assert(err, IsNil) |
435 | 487 | sess.Connection = &testConn{Name: testname()} | 487 | sess.Connection = &testConn{Name: testname()} |
436 | 488 | sess.ErrCh = make(chan error, 1) | 488 | sess.ErrCh = make(chan error, 1) |
437 | @@ -528,7 +528,7 @@ | |||
438 | 528 | */ | 528 | */ |
439 | 529 | 529 | ||
440 | 530 | func (cs *clientSessionSuite) TestDialFailsWithNoAddress(c *C) { | 530 | func (cs *clientSessionSuite) TestDialFailsWithNoAddress(c *C) { |
442 | 531 | sess, err := NewSession(Config{}, debuglog, "wah") | 531 | sess, err := NewSession(ClientConfig{}, debuglog, "wah") |
443 | 532 | c.Assert(err, IsNil) | 532 | c.Assert(err, IsNil) |
444 | 533 | err = sess.Dial() | 533 | err = sess.Dial() |
445 | 534 | c.Assert(err, NotNil) | 534 | c.Assert(err, NotNil) |
446 | @@ -539,7 +539,7 @@ | |||
447 | 539 | lp, err := net.Listen("tcp", ":0") | 539 | lp, err := net.Listen("tcp", ":0") |
448 | 540 | c.Assert(err, IsNil) | 540 | c.Assert(err, IsNil) |
449 | 541 | defer lp.Close() | 541 | defer lp.Close() |
451 | 542 | sess, err := NewSession(Config{}, debuglog, "wah") | 542 | sess, err := NewSession(ClientConfig{}, debuglog, "wah") |
452 | 543 | c.Assert(err, IsNil) | 543 | c.Assert(err, IsNil) |
453 | 544 | sess.ServerAddr = lp.Addr().String() | 544 | sess.ServerAddr = lp.Addr().String() |
454 | 545 | err = sess.Dial() | 545 | err = sess.Dial() |
455 | @@ -548,7 +548,7 @@ | |||
456 | 548 | } | 548 | } |
457 | 549 | 549 | ||
458 | 550 | func (cs *clientSessionSuite) TestResetFailsWithoutProtocolator(c *C) { | 550 | func (cs *clientSessionSuite) TestResetFailsWithoutProtocolator(c *C) { |
460 | 551 | sess, _ := NewSession(Config{}, debuglog, "wah") | 551 | sess, _ := NewSession(ClientConfig{}, debuglog, "wah") |
461 | 552 | sess.Protocolator = nil | 552 | sess.Protocolator = nil |
462 | 553 | err := sess.Reset() | 553 | err := sess.Reset() |
463 | 554 | c.Assert(err, NotNil) | 554 | c.Assert(err, NotNil) |
464 | @@ -556,7 +556,7 @@ | |||
465 | 556 | } | 556 | } |
466 | 557 | 557 | ||
467 | 558 | func (cs *clientSessionSuite) TestResetFailsWithNoAddress(c *C) { | 558 | func (cs *clientSessionSuite) TestResetFailsWithNoAddress(c *C) { |
469 | 559 | sess, err := NewSession(Config{}, debuglog, "wah") | 559 | sess, err := NewSession(ClientConfig{}, debuglog, "wah") |
470 | 560 | c.Assert(err, IsNil) | 560 | c.Assert(err, IsNil) |
471 | 561 | err = sess.Reset() | 561 | err = sess.Reset() |
472 | 562 | c.Assert(err, NotNil) | 562 | c.Assert(err, NotNil) |
473 | @@ -571,7 +571,7 @@ | |||
474 | 571 | c.Assert(err, IsNil) | 571 | c.Assert(err, IsNil) |
475 | 572 | defer lp.Close() | 572 | defer lp.Close() |
476 | 573 | 573 | ||
478 | 574 | sess, err := NewSession(Config{}, debuglog, "wah") | 574 | sess, err := NewSession(ClientConfig{}, debuglog, "wah") |
479 | 575 | c.Assert(err, IsNil) | 575 | c.Assert(err, IsNil) |
480 | 576 | sess.ServerAddr = lp.Addr().String() | 576 | sess.ServerAddr = lp.Addr().String() |
481 | 577 | sess.Connection = &testConn{Name: testname()} | 577 | sess.Connection = &testConn{Name: testname()} |
482 | 578 | 578 | ||
483 | === modified file 'util/redialer.go' | |||
484 | --- util/redialer.go 2014-01-27 13:02:26 +0000 | |||
485 | +++ util/redialer.go 2014-01-27 18:11:05 +0000 | |||
486 | @@ -49,15 +49,14 @@ | |||
487 | 49 | return time.Duration(rand.Int63n(2*n+1) - n) | 49 | return time.Duration(rand.Int63n(2*n+1) - n) |
488 | 50 | } | 50 | } |
489 | 51 | 51 | ||
494 | 52 | // AutoRedialer takes a Dialer and retries its Dial() method until it | 52 | // AutoRetry keeps on calling f() until it stops returning an error. |
495 | 53 | // stops returning an error. It does exponential (optionally | 53 | // It does exponential backoff, adding jitter at each step back. |
496 | 54 | // jitter'ed) backoff. | 54 | func AutoRetry(f func() error, jitter func(time.Duration) time.Duration) uint32 { |
493 | 55 | func AutoRedial(dialer Dialer) uint32 { | ||
497 | 56 | var timeout time.Duration | 55 | var timeout time.Duration |
498 | 57 | var dialAttempts uint32 = 0 // unsigned so it can wrap safely ... | 56 | var dialAttempts uint32 = 0 // unsigned so it can wrap safely ... |
499 | 58 | var numTimeouts uint32 = uint32(len(Timeouts)) | 57 | var numTimeouts uint32 = uint32(len(Timeouts)) |
500 | 59 | for { | 58 | for { |
502 | 60 | if dialer.Dial() == nil { | 59 | if f() == nil { |
503 | 61 | return dialAttempts + 1 | 60 | return dialAttempts + 1 |
504 | 62 | } | 61 | } |
505 | 63 | if dialAttempts < numTimeouts { | 62 | if dialAttempts < numTimeouts { |
506 | @@ -65,7 +64,7 @@ | |||
507 | 65 | } else { | 64 | } else { |
508 | 66 | timeout = Timeouts[numTimeouts-1] | 65 | timeout = Timeouts[numTimeouts-1] |
509 | 67 | } | 66 | } |
511 | 68 | timeout += dialer.Jitter(timeout) | 67 | timeout += jitter(timeout) |
512 | 69 | dialAttempts++ | 68 | dialAttempts++ |
513 | 70 | select { | 69 | select { |
514 | 71 | case <-quitRedialing: | 70 | case <-quitRedialing: |
515 | @@ -75,6 +74,13 @@ | |||
516 | 75 | } | 74 | } |
517 | 76 | } | 75 | } |
518 | 77 | 76 | ||
519 | 77 | // AutoRedialer takes a Dialer and retries its Dial() method until it | ||
520 | 78 | // stops returning an error. It does exponential (optionally | ||
521 | 79 | // jitter'ed) backoff. | ||
522 | 80 | func AutoRedial(dialer Dialer) uint32 { | ||
523 | 81 | return AutoRetry(dialer.Dial, dialer.Jitter) | ||
524 | 82 | } | ||
525 | 83 | |||
526 | 78 | func init() { | 84 | func init() { |
527 | 79 | ps := []int{1, 2, 5, 11, 19, 37, 67, 113, 191} // 3 pₙ₊₁ ≥ 5 pₙ | 85 | ps := []int{1, 2, 5, 11, 19, 37, 67, 113, 191} // 3 pₙ₊₁ ≥ 5 pₙ |
528 | 80 | Timeouts = make([]time.Duration, len(ps)) | 86 | Timeouts = make([]time.Duration, len(ps)) |
I think main is testable if it gets split in some parts