Merge lp:~pedronis/ubuntu-push/unicast-preps into lp:ubuntu-push
- unicast-preps
- Merge into trunk
Proposed by
Samuele Pedroni
Status: | Superseded |
---|---|
Proposed branch: | lp:~pedronis/ubuntu-push/unicast-preps |
Merge into: | lp:ubuntu-push |
Diff against target: |
3632 lines (+1467/-388) 49 files modified
Makefile (+3/-0) README (+12/-2) bus/connectivity/connectivity.go (+8/-7) bus/connectivity/connectivity_test.go (+77/-3) client/client.go (+8/-9) client/client_test.go (+15/-1) client/gethosts/gethost.go (+7/-5) client/gethosts/gethost_test.go (+6/-2) client/session/session.go (+86/-16) client/session/session_test.go (+232/-16) config/config.go (+130/-21) config/config_test.go (+105/-0) debian/changelog (+6/-0) debian/control (+4/-0) debian/rules (+4/-1) dependencies.tsv (+2/-0) logger/logger.go (+27/-0) logger/logger_test.go (+25/-0) protocol/messages.go (+45/-0) protocol/messages_test.go (+18/-2) protocol/state-diag-client.gv (+4/-1) protocol/state-diag-client.svg (+77/-49) protocol/state-diag-session.gv (+10/-0) protocol/state-diag-session.svg (+132/-74) server/acceptance/acceptanceclient.go (+5/-0) server/acceptance/cmd/acceptanceclient.go (+7/-2) server/acceptance/suites/broadcast.go (+6/-2) server/acceptance/suites/suite.go (+9/-0) server/api/handlers_test.go (+3/-2) server/broker/broker.go (+1/-1) server/broker/exchanges.go (+31/-35) server/broker/exchanges_test.go (+29/-25) server/broker/exchg_impl_test.go (+19/-17) server/broker/simple/simple.go (+10/-10) server/broker/simple/simple_test.go (+5/-4) server/broker/testsuite/suite.go (+36/-33) server/session/session.go (+23/-11) server/session/session_test.go (+43/-14) server/session/tracker.go (+12/-5) server/session/tracker_test.go (+4/-4) server/store/inmemory.go (+8/-6) server/store/inmemory_test.go (+6/-3) server/store/store.go (+3/-1) testing/helpers.go (+11/-0) ubuntu-push-client.go (+29/-0) util/auth.go (+36/-0) util/auth_test.go (+53/-0) whoopsie/identifier/identifier.go (+20/-4) whoopsie/identifier/identifier_test.go (+15/-0) |
To merge this branch: | bzr merge lp:~pedronis/ubuntu-push/unicast-preps |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Push Hackers | Pending | ||
Review via email: mp+217654@code.launchpad.net |
Commit message
reorganize things such that GetChannelSnapshot returns a bunch of Notification (with optional AppId, MsgId) so that it can be used together with the underlying store to store unicast notification user/device channels
Description of the change
reorganize things such that GetChannelSnapshot returns a bunch of Notification (with optional AppId, MsgId) so that it can be used together with the underlying store to store unicast notification user/device channels
To post a comment you must log in.
Unmerged revisions
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'Makefile' | |||
2 | --- Makefile 2014-03-31 17:58:54 +0000 | |||
3 | +++ Makefile 2014-04-29 18:02:00 +0000 | |||
4 | @@ -11,10 +11,13 @@ | |||
5 | 11 | GODEPS += launchpad.net/go-dbus/v1 | 11 | GODEPS += launchpad.net/go-dbus/v1 |
6 | 12 | GODEPS += launchpad.net/go-xdg/v0 | 12 | GODEPS += launchpad.net/go-xdg/v0 |
7 | 13 | GODEPS += code.google.com/p/gosqlite/sqlite3 | 13 | GODEPS += code.google.com/p/gosqlite/sqlite3 |
8 | 14 | GODEPS += gopkg.in/qml.v0 | ||
9 | 15 | GODEPS += gopkg.in/niemeyer/uoneauth.v1 | ||
10 | 14 | 16 | ||
11 | 15 | TOTEST = $(shell env GOPATH=$(GOPATH) go list $(PROJECT)/...|grep -v acceptance|grep -v http13client ) | 17 | TOTEST = $(shell env GOPATH=$(GOPATH) go list $(PROJECT)/...|grep -v acceptance|grep -v http13client ) |
12 | 16 | 18 | ||
13 | 17 | bootstrap: | 19 | bootstrap: |
14 | 20 | $(RM) -r $(GOPATH)/pkg | ||
15 | 18 | mkdir -p $(GOPATH)/bin | 21 | mkdir -p $(GOPATH)/bin |
16 | 19 | mkdir -p $(GOPATH)/pkg | 22 | mkdir -p $(GOPATH)/pkg |
17 | 20 | go get -u launchpad.net/godeps | 23 | go get -u launchpad.net/godeps |
18 | 21 | 24 | ||
19 | === modified file 'README' | |||
20 | --- README 2014-03-31 17:58:54 +0000 | |||
21 | +++ README 2014-04-29 18:02:00 +0000 | |||
22 | @@ -6,11 +6,21 @@ | |||
23 | 6 | The code expects to be checked out as launchpad.net/ubuntu-push in a Go | 6 | The code expects to be checked out as launchpad.net/ubuntu-push in a Go |
24 | 7 | workspace, see "go help gopath". | 7 | workspace, see "go help gopath". |
25 | 8 | 8 | ||
27 | 9 | To setup Go dependencies, install libsqlite3-dev and run: | 9 | To setup Go dependencies, install the following dependencies: |
28 | 10 | |||
29 | 11 | build-essential | ||
30 | 12 | libsqlite3-dev | ||
31 | 13 | qtbase5-private-dev | ||
32 | 14 | qtdeclarative5-dev | ||
33 | 15 | libqt5opengl5-dev | ||
34 | 16 | libubuntuoneauth-2.0-dev | ||
35 | 17 | |||
36 | 18 | and run: | ||
37 | 10 | 19 | ||
38 | 11 | make bootstrap | 20 | make bootstrap |
39 | 12 | 21 | ||
41 | 13 | To run tests, install libgcrypt11-dev and libwhoopsie-dev and run: | 22 | To run tests, install libglib2.0-dev, libgcrypt11-dev, libwhoopsie-dev, |
42 | 23 | and run: | ||
43 | 14 | 24 | ||
44 | 15 | make check | 25 | make check |
45 | 16 | 26 | ||
46 | 17 | 27 | ||
47 | === modified file 'bus/connectivity/connectivity.go' | |||
48 | --- bus/connectivity/connectivity.go 2014-04-04 11:08:28 +0000 | |||
49 | +++ bus/connectivity/connectivity.go 2014-04-29 18:02:00 +0000 | |||
50 | @@ -72,19 +72,20 @@ | |||
51 | 72 | cs.connAttempts += ar.Redial() | 72 | cs.connAttempts += ar.Redial() |
52 | 73 | nm := networkmanager.New(cs.endp, cs.log) | 73 | nm := networkmanager.New(cs.endp, cs.log) |
53 | 74 | 74 | ||
54 | 75 | // set up the watch | ||
55 | 76 | stateCh, err = nm.WatchState() | ||
56 | 77 | if err != nil { | ||
57 | 78 | cs.log.Debugf("failed to set up the state watch: %s", err) | ||
58 | 79 | goto Continue | ||
59 | 80 | } | ||
60 | 81 | |||
61 | 75 | // Get the current state. | 82 | // Get the current state. |
62 | 76 | initial = nm.GetState() | 83 | initial = nm.GetState() |
63 | 77 | if initial == networkmanager.Unknown { | 84 | if initial == networkmanager.Unknown { |
64 | 78 | cs.log.Debugf("Failed to get state.") | 85 | cs.log.Debugf("Failed to get state.") |
65 | 79 | goto Continue | 86 | goto Continue |
66 | 80 | } | 87 | } |
74 | 81 | 88 | cs.log.Debugf("got initial state of %s", initial) | |
68 | 82 | // set up the watch | ||
69 | 83 | stateCh, err = nm.WatchState() | ||
70 | 84 | if err != nil { | ||
71 | 85 | cs.log.Debugf("failed to set up the state watch: %s", err) | ||
72 | 86 | goto Continue | ||
73 | 87 | } | ||
75 | 88 | 89 | ||
76 | 89 | primary = nm.GetPrimaryConnection() | 90 | primary = nm.GetPrimaryConnection() |
77 | 90 | cs.log.Debugf("primary connection starts as %#v", primary) | 91 | cs.log.Debugf("primary connection starts as %#v", primary) |
78 | 91 | 92 | ||
79 | === modified file 'bus/connectivity/connectivity_test.go' | |||
80 | --- bus/connectivity/connectivity_test.go 2014-04-04 12:01:42 +0000 | |||
81 | +++ bus/connectivity/connectivity_test.go 2014-04-29 18:02:00 +0000 | |||
82 | @@ -17,8 +17,15 @@ | |||
83 | 17 | package connectivity | 17 | package connectivity |
84 | 18 | 18 | ||
85 | 19 | import ( | 19 | import ( |
86 | 20 | "net/http/httptest" | ||
87 | 21 | "sync" | ||
88 | 22 | "testing" | ||
89 | 23 | "time" | ||
90 | 24 | |||
91 | 20 | "launchpad.net/go-dbus/v1" | 25 | "launchpad.net/go-dbus/v1" |
92 | 21 | . "launchpad.net/gocheck" | 26 | . "launchpad.net/gocheck" |
93 | 27 | |||
94 | 28 | "launchpad.net/ubuntu-push/bus" | ||
95 | 22 | "launchpad.net/ubuntu-push/bus/networkmanager" | 29 | "launchpad.net/ubuntu-push/bus/networkmanager" |
96 | 23 | testingbus "launchpad.net/ubuntu-push/bus/testing" | 30 | testingbus "launchpad.net/ubuntu-push/bus/testing" |
97 | 24 | "launchpad.net/ubuntu-push/config" | 31 | "launchpad.net/ubuntu-push/config" |
98 | @@ -26,9 +33,6 @@ | |||
99 | 26 | helpers "launchpad.net/ubuntu-push/testing" | 33 | helpers "launchpad.net/ubuntu-push/testing" |
100 | 27 | "launchpad.net/ubuntu-push/testing/condition" | 34 | "launchpad.net/ubuntu-push/testing/condition" |
101 | 28 | "launchpad.net/ubuntu-push/util" | 35 | "launchpad.net/ubuntu-push/util" |
102 | 29 | "net/http/httptest" | ||
103 | 30 | "testing" | ||
104 | 31 | "time" | ||
105 | 32 | ) | 36 | ) |
106 | 33 | 37 | ||
107 | 34 | // hook up gocheck | 38 | // hook up gocheck |
108 | @@ -115,6 +119,76 @@ | |||
109 | 115 | c.Check(<-cs.networkStateCh, Equals, networkmanager.ConnectedGlobal) | 119 | c.Check(<-cs.networkStateCh, Equals, networkmanager.ConnectedGlobal) |
110 | 116 | } | 120 | } |
111 | 117 | 121 | ||
112 | 122 | // a racyEndpoint is an endpoint that behaves differently depending on | ||
113 | 123 | // how much time passes between getting the state and setting up the | ||
114 | 124 | // watch | ||
115 | 125 | type racyEndpoint struct { | ||
116 | 126 | stateGot bool | ||
117 | 127 | maxTime time.Time | ||
118 | 128 | delta time.Duration | ||
119 | 129 | lock sync.RWMutex | ||
120 | 130 | } | ||
121 | 131 | |||
122 | 132 | func (rep *racyEndpoint) GetProperty(prop string) (interface{}, error) { | ||
123 | 133 | switch prop { | ||
124 | 134 | case "state": | ||
125 | 135 | rep.lock.Lock() | ||
126 | 136 | defer rep.lock.Unlock() | ||
127 | 137 | rep.stateGot = true | ||
128 | 138 | rep.maxTime = time.Now().Add(rep.delta) | ||
129 | 139 | return uint32(networkmanager.Connecting), nil | ||
130 | 140 | case "PrimaryConnection": | ||
131 | 141 | return dbus.ObjectPath("/something"), nil | ||
132 | 142 | default: | ||
133 | 143 | return nil, nil | ||
134 | 144 | } | ||
135 | 145 | } | ||
136 | 146 | |||
137 | 147 | func (rep *racyEndpoint) WatchSignal(member string, f func(...interface{}), d func()) error { | ||
138 | 148 | if member == "StateChanged" { | ||
139 | 149 | // we count never having gotten the state as happening "after" now. | ||
140 | 150 | rep.lock.RLock() | ||
141 | 151 | defer rep.lock.RUnlock() | ||
142 | 152 | ok := !rep.stateGot || time.Now().Before(rep.maxTime) | ||
143 | 153 | go func() { | ||
144 | 154 | if ok { | ||
145 | 155 | f(uint32(networkmanager.ConnectedGlobal)) | ||
146 | 156 | } | ||
147 | 157 | d() | ||
148 | 158 | }() | ||
149 | 159 | } | ||
150 | 160 | return nil | ||
151 | 161 | } | ||
152 | 162 | |||
153 | 163 | func (*racyEndpoint) Close() {} | ||
154 | 164 | func (*racyEndpoint) Dial() error { return nil } | ||
155 | 165 | func (*racyEndpoint) String() string { return "racyEndpoint" } | ||
156 | 166 | func (*racyEndpoint) Call(string, []interface{}, ...interface{}) error { return nil } | ||
157 | 167 | |||
158 | 168 | var _ bus.Endpoint = (*racyEndpoint)(nil) | ||
159 | 169 | |||
160 | 170 | // takeNext takes a value from given channel with a 1s timeout | ||
161 | 171 | func takeNext(ch <-chan networkmanager.State) networkmanager.State { | ||
162 | 172 | select { | ||
163 | 173 | case <-time.After(time.Second): | ||
164 | 174 | panic("channel stuck: too long waiting") | ||
165 | 175 | case v := <-ch: | ||
166 | 176 | return v | ||
167 | 177 | } | ||
168 | 178 | } | ||
169 | 179 | |||
170 | 180 | // test that if the nm state goes from connecting to connected very | ||
171 | 181 | // shortly after calling GetState, we don't lose the event. | ||
172 | 182 | func (s *ConnSuite) TestStartAvoidsRace(c *C) { | ||
173 | 183 | for delta := time.Second; delta > 1; delta /= 2 { | ||
174 | 184 | rep := &racyEndpoint{delta: delta} | ||
175 | 185 | cs := connectedState{config: ConnectivityConfig{}, log: s.log, endp: rep} | ||
176 | 186 | f := Commentf("when delta=%s", delta) | ||
177 | 187 | c.Assert(cs.start(), Equals, networkmanager.Connecting, f) | ||
178 | 188 | c.Assert(takeNext(cs.networkStateCh), Equals, networkmanager.ConnectedGlobal, f) | ||
179 | 189 | } | ||
180 | 190 | } | ||
181 | 191 | |||
182 | 118 | /* | 192 | /* |
183 | 119 | tests for connectedStateStep() | 193 | tests for connectedStateStep() |
184 | 120 | */ | 194 | */ |
185 | 121 | 195 | ||
186 | === modified file 'client/client.go' | |||
187 | --- client/client.go 2014-04-11 16:37:48 +0000 | |||
188 | +++ client/client.go 2014-04-29 18:02:00 +0000 | |||
189 | @@ -26,6 +26,7 @@ | |||
190 | 26 | "os" | 26 | "os" |
191 | 27 | "strings" | 27 | "strings" |
192 | 28 | 28 | ||
193 | 29 | "gopkg.in/qml.v0" | ||
194 | 29 | "launchpad.net/go-dbus/v1" | 30 | "launchpad.net/go-dbus/v1" |
195 | 30 | 31 | ||
196 | 31 | "launchpad.net/ubuntu-push/bus" | 32 | "launchpad.net/ubuntu-push/bus" |
197 | @@ -57,7 +58,7 @@ | |||
198 | 57 | // The PEM-encoded server certificate | 58 | // The PEM-encoded server certificate |
199 | 58 | CertPEMFile string `json:"cert_pem_file"` | 59 | CertPEMFile string `json:"cert_pem_file"` |
200 | 59 | // The logging level (one of "debug", "info", "error") | 60 | // The logging level (one of "debug", "info", "error") |
202 | 60 | LogLevel string `json:"log_level"` | 61 | LogLevel logger.ConfigLogLevel `json:"log_level"` |
203 | 61 | } | 62 | } |
204 | 62 | 63 | ||
205 | 63 | // PushClient is the Ubuntu Push Notifications client-side daemon. | 64 | // PushClient is the Ubuntu Push Notifications client-side daemon. |
206 | @@ -95,13 +96,13 @@ | |||
207 | 95 | 96 | ||
208 | 96 | // configure loads its configuration, and sets it up. | 97 | // configure loads its configuration, and sets it up. |
209 | 97 | func (client *PushClient) configure() error { | 98 | func (client *PushClient) configure() error { |
211 | 98 | f, err := os.Open(client.configPath) | 99 | _, err := os.Stat(client.configPath) |
212 | 99 | if err != nil { | 100 | if err != nil { |
214 | 100 | return fmt.Errorf("opening config: %v", err) | 101 | return fmt.Errorf("config: %v", err) |
215 | 101 | } | 102 | } |
217 | 102 | err = config.ReadConfig(f, &client.config) | 103 | err = config.ReadFiles(&client.config, client.configPath, "<flags>") |
218 | 103 | if err != nil { | 104 | if err != nil { |
220 | 104 | return fmt.Errorf("reading config: %v", err) | 105 | return fmt.Errorf("config: %v", err) |
221 | 105 | } | 106 | } |
222 | 106 | // ignore spaces | 107 | // ignore spaces |
223 | 107 | client.config.Addr = strings.Replace(client.config.Addr, " ", "", -1) | 108 | client.config.Addr = strings.Replace(client.config.Addr, " ", "", -1) |
224 | @@ -110,7 +111,8 @@ | |||
225 | 110 | } | 111 | } |
226 | 111 | 112 | ||
227 | 112 | // later, we'll be specifying more logging options in the config file | 113 | // later, we'll be specifying more logging options in the config file |
229 | 113 | client.log = logger.NewSimpleLogger(os.Stderr, client.config.LogLevel) | 114 | client.log = logger.NewSimpleLogger(os.Stderr, client.config.LogLevel.Level()) |
230 | 115 | qml.SetLogger(client.log) | ||
231 | 114 | 116 | ||
232 | 115 | // overridden for testing | 117 | // overridden for testing |
233 | 116 | client.idder = identifier.New() | 118 | client.idder = identifier.New() |
234 | @@ -285,9 +287,6 @@ | |||
235 | 285 | h := map[string]*dbus.Variant{"x-canonical-switch-to-application": &dbus.Variant{true}} | 287 | h := map[string]*dbus.Variant{"x-canonical-switch-to-application": &dbus.Variant{true}} |
236 | 286 | nots := notifications.Raw(client.notificationsEndp, client.log) | 288 | nots := notifications.Raw(client.notificationsEndp, client.log) |
237 | 287 | body := "Tap to open the system updater." | 289 | body := "Tap to open the system updater." |
238 | 288 | if msg != nil { | ||
239 | 289 | body = fmt.Sprintf("[%d] %s", msg.TopLevel, body) | ||
240 | 290 | } | ||
241 | 291 | not_id, err := nots.Notify( | 290 | not_id, err := nots.Notify( |
242 | 292 | "ubuntu-push-client", // app name | 291 | "ubuntu-push-client", // app name |
243 | 293 | uint32(0), // id | 292 | uint32(0), // id |
244 | 294 | 293 | ||
245 | === modified file 'client/client_test.go' | |||
246 | --- client/client_test.go 2014-04-11 16:21:45 +0000 | |||
247 | +++ client/client_test.go 2014-04-29 18:02:00 +0000 | |||
248 | @@ -19,10 +19,12 @@ | |||
249 | 19 | import ( | 19 | import ( |
250 | 20 | "encoding/json" | 20 | "encoding/json" |
251 | 21 | "errors" | 21 | "errors" |
252 | 22 | "flag" | ||
253 | 22 | "fmt" | 23 | "fmt" |
254 | 23 | "io/ioutil" | 24 | "io/ioutil" |
255 | 24 | "net/http" | 25 | "net/http" |
256 | 25 | "net/http/httptest" | 26 | "net/http/httptest" |
257 | 27 | "os" | ||
258 | 26 | "path/filepath" | 28 | "path/filepath" |
259 | 27 | "reflect" | 29 | "reflect" |
260 | 28 | "testing" | 30 | "testing" |
261 | @@ -37,6 +39,7 @@ | |||
262 | 37 | testibus "launchpad.net/ubuntu-push/bus/testing" | 39 | testibus "launchpad.net/ubuntu-push/bus/testing" |
263 | 38 | "launchpad.net/ubuntu-push/client/session" | 40 | "launchpad.net/ubuntu-push/client/session" |
264 | 39 | "launchpad.net/ubuntu-push/client/session/levelmap" | 41 | "launchpad.net/ubuntu-push/client/session/levelmap" |
265 | 42 | "launchpad.net/ubuntu-push/config" | ||
266 | 40 | helpers "launchpad.net/ubuntu-push/testing" | 43 | helpers "launchpad.net/ubuntu-push/testing" |
267 | 41 | "launchpad.net/ubuntu-push/testing/condition" | 44 | "launchpad.net/ubuntu-push/testing/condition" |
268 | 42 | "launchpad.net/ubuntu-push/util" | 45 | "launchpad.net/ubuntu-push/util" |
269 | @@ -79,6 +82,7 @@ | |||
270 | 79 | } | 82 | } |
271 | 80 | 83 | ||
272 | 81 | func (cs *clientSuite) SetUpSuite(c *C) { | 84 | func (cs *clientSuite) SetUpSuite(c *C) { |
273 | 85 | config.IgnoreParsedFlags = true // because configure() uses <flags> | ||
274 | 82 | cs.timeouts = util.SwapTimeouts([]time.Duration{0}) | 86 | cs.timeouts = util.SwapTimeouts([]time.Duration{0}) |
275 | 83 | cs.leveldbPath = "" | 87 | cs.leveldbPath = "" |
276 | 84 | } | 88 | } |
277 | @@ -142,6 +146,16 @@ | |||
278 | 142 | c.Check(cli.config.ExchangeTimeout.TimeDuration(), Equals, time.Duration(10*time.Millisecond)) | 146 | c.Check(cli.config.ExchangeTimeout.TimeDuration(), Equals, time.Duration(10*time.Millisecond)) |
279 | 143 | } | 147 | } |
280 | 144 | 148 | ||
281 | 149 | func (cs *clientSuite) TestConfigureWorksWithFlags(c *C) { | ||
282 | 150 | flag.CommandLine = flag.NewFlagSet("client", flag.ContinueOnError) | ||
283 | 151 | os.Args = []string{"client", "-addr", "foo:7777"} | ||
284 | 152 | cli := NewPushClient(cs.configPath, cs.leveldbPath) | ||
285 | 153 | err := cli.configure() | ||
286 | 154 | c.Assert(err, IsNil) | ||
287 | 155 | c.Assert(cli.config, NotNil) | ||
288 | 156 | c.Check(cli.config.Addr, Equals, "foo:7777") | ||
289 | 157 | } | ||
290 | 158 | |||
291 | 145 | func (cs *clientSuite) TestConfigureSetsUpLog(c *C) { | 159 | func (cs *clientSuite) TestConfigureSetsUpLog(c *C) { |
292 | 146 | cli := NewPushClient(cs.configPath, cs.leveldbPath) | 160 | cli := NewPushClient(cs.configPath, cs.leveldbPath) |
293 | 147 | c.Check(cli.log, IsNil) | 161 | c.Check(cli.log, IsNil) |
294 | @@ -163,7 +177,7 @@ | |||
295 | 163 | c.Check(cli.idder, IsNil) | 177 | c.Check(cli.idder, IsNil) |
296 | 164 | err := cli.configure() | 178 | err := cli.configure() |
297 | 165 | c.Assert(err, IsNil) | 179 | c.Assert(err, IsNil) |
299 | 166 | c.Assert(cli.idder, DeepEquals, identifier.New()) | 180 | c.Assert(cli.idder, FitsTypeOf, identifier.New()) |
300 | 167 | } | 181 | } |
301 | 168 | 182 | ||
302 | 169 | func (cs *clientSuite) TestConfigureSetsUpEndpoints(c *C) { | 183 | func (cs *clientSuite) TestConfigureSetsUpEndpoints(c *C) { |
303 | 170 | 184 | ||
304 | === modified file 'client/gethosts/gethost.go' | |||
305 | --- client/gethosts/gethost.go 2014-03-24 15:32:29 +0000 | |||
306 | +++ client/gethosts/gethost.go 2014-04-29 18:02:00 +0000 | |||
307 | @@ -49,8 +49,10 @@ | |||
308 | 49 | } | 49 | } |
309 | 50 | } | 50 | } |
310 | 51 | 51 | ||
313 | 52 | type expected struct { | 52 | // Host contains the domain and hosts returned by the remote endpoint |
314 | 53 | Hosts []string | 53 | type Host struct { |
315 | 54 | Domain string | ||
316 | 55 | Hosts []string | ||
317 | 54 | } | 56 | } |
318 | 55 | 57 | ||
319 | 56 | var ( | 58 | var ( |
320 | @@ -60,7 +62,7 @@ | |||
321 | 60 | ) | 62 | ) |
322 | 61 | 63 | ||
323 | 62 | // Get gets a list of hosts consulting the endpoint. | 64 | // Get gets a list of hosts consulting the endpoint. |
325 | 63 | func (gh *GetHost) Get() ([]string, error) { | 65 | func (gh *GetHost) Get() (*Host, error) { |
326 | 64 | resp, err := gh.cli.Get(gh.endpointUrl + "?h=" + gh.hash) | 66 | resp, err := gh.cli.Get(gh.endpointUrl + "?h=" + gh.hash) |
327 | 65 | if err != nil { | 67 | if err != nil { |
328 | 66 | return nil, err | 68 | return nil, err |
329 | @@ -80,7 +82,7 @@ | |||
330 | 80 | if err != nil { | 82 | if err != nil { |
331 | 81 | return nil, err | 83 | return nil, err |
332 | 82 | } | 84 | } |
334 | 83 | var parsed expected | 85 | var parsed Host |
335 | 84 | err = json.Unmarshal(body, &parsed) | 86 | err = json.Unmarshal(body, &parsed) |
336 | 85 | if err != nil { | 87 | if err != nil { |
337 | 86 | return nil, ErrTemporary | 88 | return nil, ErrTemporary |
338 | @@ -88,5 +90,5 @@ | |||
339 | 88 | if len(parsed.Hosts) == 0 { | 90 | if len(parsed.Hosts) == 0 { |
340 | 89 | return nil, ErrTemporary | 91 | return nil, ErrTemporary |
341 | 90 | } | 92 | } |
343 | 91 | return parsed.Hosts, nil | 93 | return &parsed, nil |
344 | 92 | } | 94 | } |
345 | 93 | 95 | ||
346 | === modified file 'client/gethosts/gethost_test.go' | |||
347 | --- client/gethosts/gethost_test.go 2014-03-31 14:31:07 +0000 | |||
348 | +++ client/gethosts/gethost_test.go 2014-04-29 18:02:00 +0000 | |||
349 | @@ -45,7 +45,8 @@ | |||
350 | 45 | ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | 45 | ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
351 | 46 | x := r.FormValue("h") | 46 | x := r.FormValue("h") |
352 | 47 | b, err := json.Marshal(map[string]interface{}{ | 47 | b, err := json.Marshal(map[string]interface{}{ |
354 | 48 | "hosts": []string{"http://" + x}, | 48 | "domain": "example.com", |
355 | 49 | "hosts": []string{"http://" + x}, | ||
356 | 49 | }) | 50 | }) |
357 | 50 | if err != nil { | 51 | if err != nil { |
358 | 51 | panic(err) | 52 | panic(err) |
359 | @@ -57,7 +58,8 @@ | |||
360 | 57 | gh := New("foobar", ts.URL, 1*time.Second) | 58 | gh := New("foobar", ts.URL, 1*time.Second) |
361 | 58 | res, err := gh.Get() | 59 | res, err := gh.Get() |
362 | 59 | c.Assert(err, IsNil) | 60 | c.Assert(err, IsNil) |
364 | 60 | c.Check(res, DeepEquals, []string{"http://c1130408a700afe0"}) | 61 | c.Check(*res, DeepEquals, |
365 | 62 | Host{Domain: "example.com", Hosts: []string{"http://c1130408a700afe0"}}) | ||
366 | 61 | } | 63 | } |
367 | 62 | 64 | ||
368 | 63 | func (s *getHostsSuite) TestGetTimeout(c *C) { | 65 | func (s *getHostsSuite) TestGetTimeout(c *C) { |
369 | @@ -97,4 +99,6 @@ | |||
370 | 97 | 99 | ||
371 | 98 | scenario(http.StatusOK, "{", ErrTemporary) | 100 | scenario(http.StatusOK, "{", ErrTemporary) |
372 | 99 | scenario(http.StatusOK, "{}", ErrTemporary) | 101 | scenario(http.StatusOK, "{}", ErrTemporary) |
373 | 102 | scenario(http.StatusOK, `{"domain": "example.com"}`, ErrTemporary) | ||
374 | 103 | scenario(http.StatusOK, `{"hosts": ["one"]}`, nil) | ||
375 | 100 | } | 104 | } |
376 | 101 | 105 | ||
377 | === modified file 'client/session/session.go' | |||
378 | --- client/session/session.go 2014-04-04 13:55:00 +0000 | |||
379 | +++ client/session/session.go 2014-04-29 18:02:00 +0000 | |||
380 | @@ -38,7 +38,11 @@ | |||
381 | 38 | "launchpad.net/ubuntu-push/util" | 38 | "launchpad.net/ubuntu-push/util" |
382 | 39 | ) | 39 | ) |
383 | 40 | 40 | ||
385 | 41 | var wireVersionBytes = []byte{protocol.ProtocolWireVersion} | 41 | var ( |
386 | 42 | wireVersionBytes = []byte{protocol.ProtocolWireVersion} | ||
387 | 43 | getAuthorization = util.GetAuthorization | ||
388 | 44 | shouldGetAuth = false | ||
389 | 45 | ) | ||
390 | 42 | 46 | ||
391 | 43 | type Notification struct { | 47 | type Notification struct { |
392 | 44 | TopLevel int64 | 48 | TopLevel int64 |
393 | @@ -73,7 +77,7 @@ | |||
394 | 73 | ) | 77 | ) |
395 | 74 | 78 | ||
396 | 75 | type hostGetter interface { | 79 | type hostGetter interface { |
398 | 76 | Get() ([]string, error) | 80 | Get() (*gethosts.Host, error) |
399 | 77 | } | 81 | } |
400 | 78 | 82 | ||
401 | 79 | // ClientSessionConfig groups the client session configuration. | 83 | // ClientSessionConfig groups the client session configuration. |
402 | @@ -115,6 +119,28 @@ | |||
403 | 115 | stateP *uint32 | 119 | stateP *uint32 |
404 | 116 | ErrCh chan error | 120 | ErrCh chan error |
405 | 117 | MsgCh chan *Notification | 121 | MsgCh chan *Notification |
406 | 122 | // authorization | ||
407 | 123 | auth string | ||
408 | 124 | // autoredial knobs | ||
409 | 125 | shouldDelayP *uint32 | ||
410 | 126 | lastAutoRedial time.Time | ||
411 | 127 | redialDelay func(*ClientSession) time.Duration | ||
412 | 128 | redialJitter func(time.Duration) time.Duration | ||
413 | 129 | redialDelays []time.Duration | ||
414 | 130 | redialDelaysIdx int | ||
415 | 131 | } | ||
416 | 132 | |||
417 | 133 | func redialDelay(sess *ClientSession) time.Duration { | ||
418 | 134 | if sess.ShouldDelay() { | ||
419 | 135 | t := sess.redialDelays[sess.redialDelaysIdx] | ||
420 | 136 | if len(sess.redialDelays) > sess.redialDelaysIdx+1 { | ||
421 | 137 | sess.redialDelaysIdx++ | ||
422 | 138 | } | ||
423 | 139 | return t + sess.redialJitter(t) | ||
424 | 140 | } else { | ||
425 | 141 | sess.redialDelaysIdx = 0 | ||
426 | 142 | return 0 | ||
427 | 143 | } | ||
428 | 118 | } | 144 | } |
429 | 119 | 145 | ||
430 | 120 | func NewSession(serverAddrSpec string, conf ClientSessionConfig, | 146 | func NewSession(serverAddrSpec string, conf ClientSessionConfig, |
431 | @@ -131,6 +157,7 @@ | |||
432 | 131 | if hostsEndpoint != "" { | 157 | if hostsEndpoint != "" { |
433 | 132 | getHost = gethosts.New(deviceId, hostsEndpoint, conf.ExchangeTimeout) | 158 | getHost = gethosts.New(deviceId, hostsEndpoint, conf.ExchangeTimeout) |
434 | 133 | } | 159 | } |
435 | 160 | var shouldDelay uint32 = 0 | ||
436 | 134 | sess := &ClientSession{ | 161 | sess := &ClientSession{ |
437 | 135 | ClientSessionConfig: conf, | 162 | ClientSessionConfig: conf, |
438 | 136 | getHost: getHost, | 163 | getHost: getHost, |
439 | @@ -139,10 +166,14 @@ | |||
440 | 139 | Log: log, | 166 | Log: log, |
441 | 140 | Protocolator: protocol.NewProtocol0, | 167 | Protocolator: protocol.NewProtocol0, |
442 | 141 | Levels: levels, | 168 | Levels: levels, |
444 | 142 | TLS: &tls.Config{InsecureSkipVerify: true}, // XXX | 169 | TLS: &tls.Config{}, |
445 | 143 | stateP: &state, | 170 | stateP: &state, |
446 | 144 | timeSince: time.Since, | 171 | timeSince: time.Since, |
447 | 172 | shouldDelayP: &shouldDelay, | ||
448 | 173 | redialDelay: redialDelay, | ||
449 | 174 | redialDelays: util.Timeouts(), | ||
450 | 145 | } | 175 | } |
451 | 176 | sess.redialJitter = sess.Jitter | ||
452 | 146 | if sess.PEM != nil { | 177 | if sess.PEM != nil { |
453 | 147 | cp := x509.NewCertPool() | 178 | cp := x509.NewCertPool() |
454 | 148 | ok := cp.AppendCertsFromPEM(sess.PEM) | 179 | ok := cp.AppendCertsFromPEM(sess.PEM) |
455 | @@ -154,6 +185,18 @@ | |||
456 | 154 | return sess, nil | 185 | return sess, nil |
457 | 155 | } | 186 | } |
458 | 156 | 187 | ||
459 | 188 | func (sess *ClientSession) ShouldDelay() bool { | ||
460 | 189 | return atomic.LoadUint32(sess.shouldDelayP) != 0 | ||
461 | 190 | } | ||
462 | 191 | |||
463 | 192 | func (sess *ClientSession) setShouldDelay() { | ||
464 | 193 | atomic.StoreUint32(sess.shouldDelayP, uint32(1)) | ||
465 | 194 | } | ||
466 | 195 | |||
467 | 196 | func (sess *ClientSession) clearShouldDelay() { | ||
468 | 197 | atomic.StoreUint32(sess.shouldDelayP, uint32(0)) | ||
469 | 198 | } | ||
470 | 199 | |||
471 | 157 | func (sess *ClientSession) State() ClientSessionState { | 200 | func (sess *ClientSession) State() ClientSessionState { |
472 | 158 | return ClientSessionState(atomic.LoadUint32(sess.stateP)) | 201 | return ClientSessionState(atomic.LoadUint32(sess.stateP)) |
473 | 159 | } | 202 | } |
474 | @@ -180,20 +223,38 @@ | |||
475 | 180 | if sess.deliveryHosts != nil && sess.timeSince(sess.deliveryHostsTimestamp) < sess.HostsCachingExpiryTime { | 223 | if sess.deliveryHosts != nil && sess.timeSince(sess.deliveryHostsTimestamp) < sess.HostsCachingExpiryTime { |
476 | 181 | return nil | 224 | return nil |
477 | 182 | } | 225 | } |
479 | 183 | hosts, err := sess.getHost.Get() | 226 | host, err := sess.getHost.Get() |
480 | 184 | if err != nil { | 227 | if err != nil { |
481 | 185 | sess.Log.Errorf("getHosts: %v", err) | 228 | sess.Log.Errorf("getHosts: %v", err) |
482 | 186 | sess.setState(Error) | 229 | sess.setState(Error) |
483 | 187 | return err | 230 | return err |
484 | 188 | } | 231 | } |
485 | 189 | sess.deliveryHostsTimestamp = time.Now() | 232 | sess.deliveryHostsTimestamp = time.Now() |
487 | 190 | sess.deliveryHosts = hosts | 233 | sess.deliveryHosts = host.Hosts |
488 | 234 | if sess.TLS != nil { | ||
489 | 235 | sess.TLS.ServerName = host.Domain | ||
490 | 236 | } | ||
491 | 191 | } else { | 237 | } else { |
492 | 192 | sess.deliveryHosts = sess.fallbackHosts | 238 | sess.deliveryHosts = sess.fallbackHosts |
493 | 193 | } | 239 | } |
494 | 194 | return nil | 240 | return nil |
495 | 195 | } | 241 | } |
496 | 196 | 242 | ||
497 | 243 | // checkAuthorization checks the authorization within the phone | ||
498 | 244 | func (sess *ClientSession) checkAuthorization() error { | ||
499 | 245 | // grab the authorization string from the accounts | ||
500 | 246 | // TODO: remove this condition when we have a way to deal with failing authorizations | ||
501 | 247 | if shouldGetAuth { | ||
502 | 248 | auth, err := getAuthorization() | ||
503 | 249 | if err != nil { | ||
504 | 250 | // For now we just log the error, as we don't want to block unauthorized users | ||
505 | 251 | sess.Log.Errorf("unable to get the authorization token from the account: %v", err) | ||
506 | 252 | } | ||
507 | 253 | sess.auth = auth | ||
508 | 254 | } | ||
509 | 255 | return nil | ||
510 | 256 | } | ||
511 | 257 | |||
512 | 197 | func (sess *ClientSession) resetHosts() { | 258 | func (sess *ClientSession) resetHosts() { |
513 | 198 | sess.deliveryHosts = nil | 259 | sess.deliveryHosts = nil |
514 | 199 | } | 260 | } |
515 | @@ -234,6 +295,7 @@ | |||
516 | 234 | // connect to a server using the configuration in the ClientSession | 295 | // connect to a server using the configuration in the ClientSession |
517 | 235 | // and set up the connection. | 296 | // and set up the connection. |
518 | 236 | func (sess *ClientSession) connect() error { | 297 | func (sess *ClientSession) connect() error { |
519 | 298 | sess.setShouldDelay() | ||
520 | 237 | sess.startConnectionAttempt() | 299 | sess.startConnectionAttempt() |
521 | 238 | var err error | 300 | var err error |
522 | 239 | var conn net.Conn | 301 | var conn net.Conn |
523 | @@ -263,7 +325,12 @@ | |||
524 | 263 | 325 | ||
525 | 264 | func (sess *ClientSession) AutoRedial(doneCh chan uint32) { | 326 | func (sess *ClientSession) AutoRedial(doneCh chan uint32) { |
526 | 265 | sess.stopRedial() | 327 | sess.stopRedial() |
527 | 328 | if time.Since(sess.lastAutoRedial) < 2*time.Second { | ||
528 | 329 | sess.setShouldDelay() | ||
529 | 330 | } | ||
530 | 331 | time.Sleep(sess.redialDelay(sess)) | ||
531 | 266 | sess.retrier = util.NewAutoRedialer(sess) | 332 | sess.retrier = util.NewAutoRedialer(sess) |
532 | 333 | sess.lastAutoRedial = time.Now() | ||
533 | 267 | go func() { doneCh <- sess.retrier.Redial() }() | 334 | go func() { doneCh <- sess.retrier.Redial() }() |
534 | 268 | } | 335 | } |
535 | 269 | 336 | ||
536 | @@ -289,6 +356,7 @@ | |||
537 | 289 | err := sess.proto.WriteMessage(protocol.PingPongMsg{Type: "pong"}) | 356 | err := sess.proto.WriteMessage(protocol.PingPongMsg{Type: "pong"}) |
538 | 290 | if err == nil { | 357 | if err == nil { |
539 | 291 | sess.Log.Debugf("ping.") | 358 | sess.Log.Debugf("ping.") |
540 | 359 | sess.clearShouldDelay() | ||
541 | 292 | } else { | 360 | } else { |
542 | 293 | sess.setState(Error) | 361 | sess.setState(Error) |
543 | 294 | sess.Log.Errorf("unable to pong: %s", err) | 362 | sess.Log.Errorf("unable to pong: %s", err) |
544 | @@ -330,6 +398,7 @@ | |||
545 | 330 | sess.Log.Errorf("unable to ack broadcast: %s", err) | 398 | sess.Log.Errorf("unable to ack broadcast: %s", err) |
546 | 331 | return err | 399 | return err |
547 | 332 | } | 400 | } |
548 | 401 | sess.clearShouldDelay() | ||
549 | 333 | sess.Log.Debugf("broadcast chan:%v app:%v topLevel:%d payloads:%s", | 402 | sess.Log.Debugf("broadcast chan:%v app:%v topLevel:%d payloads:%s", |
550 | 334 | bcast.ChanId, bcast.AppId, bcast.TopLevel, bcast.Payloads) | 403 | bcast.ChanId, bcast.AppId, bcast.TopLevel, bcast.Payloads) |
551 | 335 | if bcast.ChanId == protocol.SystemChannelId { | 404 | if bcast.ChanId == protocol.SystemChannelId { |
552 | @@ -409,10 +478,9 @@ | |||
553 | 409 | return err | 478 | return err |
554 | 410 | } | 479 | } |
555 | 411 | err = proto.WriteMessage(protocol.ConnectMsg{ | 480 | err = proto.WriteMessage(protocol.ConnectMsg{ |
560 | 412 | Type: "connect", | 481 | Type: "connect", |
561 | 413 | DeviceId: sess.DeviceId, | 482 | DeviceId: sess.DeviceId, |
562 | 414 | // xxx get the SSO Authorization string from the phone | 483 | Authorization: sess.auth, |
559 | 415 | Authorization: "", | ||
563 | 416 | Levels: levels, | 484 | Levels: levels, |
564 | 417 | Info: sess.Info, | 485 | Info: sess.Info, |
565 | 418 | }) | 486 | }) |
566 | @@ -447,13 +515,15 @@ | |||
567 | 447 | 515 | ||
568 | 448 | // run calls connect, and if it works it calls start, and if it works | 516 | // run calls connect, and if it works it calls start, and if it works |
569 | 449 | // it runs loop in a goroutine, and ships its return value over ErrCh. | 517 | // it runs loop in a goroutine, and ships its return value over ErrCh. |
571 | 450 | func (sess *ClientSession) run(closer func(), hostGetter, connecter, starter, looper func() error) error { | 518 | func (sess *ClientSession) run(closer func(), authChecker, hostGetter, connecter, starter, looper func() error) error { |
572 | 451 | closer() | 519 | closer() |
578 | 452 | err := hostGetter() | 520 | if err := authChecker(); err != nil { |
579 | 453 | if err != nil { | 521 | return err |
580 | 454 | return err | 522 | } |
581 | 455 | } | 523 | if err := hostGetter(); err != nil { |
582 | 456 | err = connecter() | 524 | return err |
583 | 525 | } | ||
584 | 526 | err := connecter() | ||
585 | 457 | if err == nil { | 527 | if err == nil { |
586 | 458 | err = starter() | 528 | err = starter() |
587 | 459 | if err == nil { | 529 | if err == nil { |
588 | @@ -483,7 +553,7 @@ | |||
589 | 483 | // keep on trying. | 553 | // keep on trying. |
590 | 484 | panic("can't Dial() without a protocol constructor.") | 554 | panic("can't Dial() without a protocol constructor.") |
591 | 485 | } | 555 | } |
593 | 486 | return sess.run(sess.doClose, sess.getHosts, sess.connect, sess.start, sess.loop) | 556 | return sess.run(sess.doClose, sess.checkAuthorization, sess.getHosts, sess.connect, sess.start, sess.loop) |
594 | 487 | } | 557 | } |
595 | 488 | 558 | ||
596 | 489 | func init() { | 559 | func init() { |
597 | 490 | 560 | ||
598 | === modified file 'client/session/session_test.go' | |||
599 | --- client/session/session_test.go 2014-04-04 13:55:00 +0000 | |||
600 | +++ client/session/session_test.go 2014-04-29 18:02:00 +0000 | |||
601 | @@ -32,12 +32,12 @@ | |||
602 | 32 | 32 | ||
603 | 33 | . "launchpad.net/gocheck" | 33 | . "launchpad.net/gocheck" |
604 | 34 | 34 | ||
605 | 35 | "launchpad.net/ubuntu-push/client/gethosts" | ||
606 | 35 | "launchpad.net/ubuntu-push/client/session/levelmap" | 36 | "launchpad.net/ubuntu-push/client/session/levelmap" |
607 | 36 | //"launchpad.net/ubuntu-push/client/gethosts" | ||
608 | 37 | "launchpad.net/ubuntu-push/logger" | ||
609 | 38 | "launchpad.net/ubuntu-push/protocol" | 37 | "launchpad.net/ubuntu-push/protocol" |
610 | 39 | helpers "launchpad.net/ubuntu-push/testing" | 38 | helpers "launchpad.net/ubuntu-push/testing" |
611 | 40 | "launchpad.net/ubuntu-push/testing/condition" | 39 | "launchpad.net/ubuntu-push/testing/condition" |
612 | 40 | "launchpad.net/ubuntu-push/util" | ||
613 | 41 | ) | 41 | ) |
614 | 42 | 42 | ||
615 | 43 | func TestSession(t *testing.T) { TestingT(t) } | 43 | func TestSession(t *testing.T) { TestingT(t) } |
616 | @@ -165,14 +165,26 @@ | |||
617 | 165 | ///// | 165 | ///// |
618 | 166 | 166 | ||
619 | 167 | type clientSessionSuite struct { | 167 | type clientSessionSuite struct { |
621 | 168 | log logger.Logger | 168 | log *helpers.TestLogger |
622 | 169 | lvls func() (levelmap.LevelMap, error) | 169 | lvls func() (levelmap.LevelMap, error) |
623 | 170 | } | 170 | } |
624 | 171 | 171 | ||
625 | 172 | func (cs *clientSessionSuite) SetUpSuite(c *C) { | ||
626 | 173 | getAuthorization = func() (string, error) { | ||
627 | 174 | return "some auth", nil | ||
628 | 175 | } | ||
629 | 176 | shouldGetAuth = true | ||
630 | 177 | } | ||
631 | 178 | |||
632 | 172 | func (cs *clientSessionSuite) SetUpTest(c *C) { | 179 | func (cs *clientSessionSuite) SetUpTest(c *C) { |
633 | 173 | cs.log = helpers.NewTestLogger(c, "debug") | 180 | cs.log = helpers.NewTestLogger(c, "debug") |
634 | 174 | } | 181 | } |
635 | 175 | 182 | ||
636 | 183 | func (cs *clientSessionSuite) TearDownSuite(c *C) { | ||
637 | 184 | getAuthorization = util.GetAuthorization | ||
638 | 185 | shouldGetAuth = false | ||
639 | 186 | } | ||
640 | 187 | |||
641 | 176 | // in-memory level map testing | 188 | // in-memory level map testing |
642 | 177 | var _ = Suite(&clientSessionSuite{lvls: levelmap.NewLevelMap}) | 189 | var _ = Suite(&clientSessionSuite{lvls: levelmap.NewLevelMap}) |
643 | 178 | 190 | ||
644 | @@ -182,6 +194,7 @@ | |||
645 | 182 | var _ = Suite(&clientSqlevelsSessionSuite{}) | 194 | var _ = Suite(&clientSqlevelsSessionSuite{}) |
646 | 183 | 195 | ||
647 | 184 | func (cs *clientSqlevelsSessionSuite) SetUpSuite(c *C) { | 196 | func (cs *clientSqlevelsSessionSuite) SetUpSuite(c *C) { |
648 | 197 | cs.clientSessionSuite.SetUpSuite(c) | ||
649 | 185 | cs.lvls = func() (levelmap.LevelMap, error) { return levelmap.NewSqliteLevelMap(":memory:") } | 198 | cs.lvls = func() (levelmap.LevelMap, error) { return levelmap.NewSqliteLevelMap(":memory:") } |
650 | 186 | } | 199 | } |
651 | 187 | 200 | ||
652 | @@ -214,6 +227,10 @@ | |||
653 | 214 | c.Check(sess, NotNil) | 227 | c.Check(sess, NotNil) |
654 | 215 | c.Check(err, IsNil) | 228 | c.Check(err, IsNil) |
655 | 216 | c.Check(sess.fallbackHosts, DeepEquals, []string{"foo:443"}) | 229 | c.Check(sess.fallbackHosts, DeepEquals, []string{"foo:443"}) |
656 | 230 | // the session is happy and redial delayer is default | ||
657 | 231 | c.Check(sess.ShouldDelay(), Equals, false) | ||
658 | 232 | c.Check(fmt.Sprintf("%#v", sess.redialDelay), Equals, fmt.Sprintf("%#v", redialDelay)) | ||
659 | 233 | c.Check(sess.redialDelays, DeepEquals, util.Timeouts()) | ||
660 | 217 | // but no root CAs set | 234 | // but no root CAs set |
661 | 218 | c.Check(sess.TLS.RootCAs, IsNil) | 235 | c.Check(sess.TLS.RootCAs, IsNil) |
662 | 219 | c.Check(sess.State(), Equals, Disconnected) | 236 | c.Check(sess.State(), Equals, Disconnected) |
663 | @@ -264,16 +281,17 @@ | |||
664 | 264 | } | 281 | } |
665 | 265 | 282 | ||
666 | 266 | type testHostGetter struct { | 283 | type testHostGetter struct { |
669 | 267 | hosts []string | 284 | domain string |
670 | 268 | err error | 285 | hosts []string |
671 | 286 | err error | ||
672 | 269 | } | 287 | } |
673 | 270 | 288 | ||
676 | 271 | func (thg *testHostGetter) Get() ([]string, error) { | 289 | func (thg *testHostGetter) Get() (*gethosts.Host, error) { |
677 | 272 | return thg.hosts, thg.err | 290 | return &gethosts.Host{thg.domain, thg.hosts}, thg.err |
678 | 273 | } | 291 | } |
679 | 274 | 292 | ||
680 | 275 | func (cs *clientSessionSuite) TestGetHostsRemote(c *C) { | 293 | func (cs *clientSessionSuite) TestGetHostsRemote(c *C) { |
682 | 276 | hostGetter := &testHostGetter{[]string{"foo:443", "bar:443"}, nil} | 294 | hostGetter := &testHostGetter{"example.com", []string{"foo:443", "bar:443"}, nil} |
683 | 277 | sess := &ClientSession{getHost: hostGetter, timeSince: time.Since} | 295 | sess := &ClientSession{getHost: hostGetter, timeSince: time.Since} |
684 | 278 | err := sess.getHosts() | 296 | err := sess.getHosts() |
685 | 279 | c.Assert(err, IsNil) | 297 | c.Assert(err, IsNil) |
686 | @@ -284,7 +302,7 @@ | |||
687 | 284 | sess, err := NewSession("", dummyConf, "", cs.lvls, cs.log) | 302 | sess, err := NewSession("", dummyConf, "", cs.lvls, cs.log) |
688 | 285 | c.Assert(err, IsNil) | 303 | c.Assert(err, IsNil) |
689 | 286 | hostsErr := errors.New("failed") | 304 | hostsErr := errors.New("failed") |
691 | 287 | hostGetter := &testHostGetter{nil, hostsErr} | 305 | hostGetter := &testHostGetter{"", nil, hostsErr} |
692 | 288 | sess.getHost = hostGetter | 306 | sess.getHost = hostGetter |
693 | 289 | err = sess.getHosts() | 307 | err = sess.getHosts() |
694 | 290 | c.Assert(err, Equals, hostsErr) | 308 | c.Assert(err, Equals, hostsErr) |
695 | @@ -293,7 +311,7 @@ | |||
696 | 293 | } | 311 | } |
697 | 294 | 312 | ||
698 | 295 | func (cs *clientSessionSuite) TestGetHostsRemoteCaching(c *C) { | 313 | func (cs *clientSessionSuite) TestGetHostsRemoteCaching(c *C) { |
700 | 296 | hostGetter := &testHostGetter{[]string{"foo:443", "bar:443"}, nil} | 314 | hostGetter := &testHostGetter{"example.com", []string{"foo:443", "bar:443"}, nil} |
701 | 297 | sess := &ClientSession{ | 315 | sess := &ClientSession{ |
702 | 298 | getHost: hostGetter, | 316 | getHost: hostGetter, |
703 | 299 | ClientSessionConfig: ClientSessionConfig{ | 317 | ClientSessionConfig: ClientSessionConfig{ |
704 | @@ -318,7 +336,7 @@ | |||
705 | 318 | } | 336 | } |
706 | 319 | 337 | ||
707 | 320 | func (cs *clientSessionSuite) TestGetHostsRemoteCachingReset(c *C) { | 338 | func (cs *clientSessionSuite) TestGetHostsRemoteCachingReset(c *C) { |
709 | 321 | hostGetter := &testHostGetter{[]string{"foo:443", "bar:443"}, nil} | 339 | hostGetter := &testHostGetter{"example.com", []string{"foo:443", "bar:443"}, nil} |
710 | 322 | sess := &ClientSession{ | 340 | sess := &ClientSession{ |
711 | 323 | getHost: hostGetter, | 341 | getHost: hostGetter, |
712 | 324 | ClientSessionConfig: ClientSessionConfig{ | 342 | ClientSessionConfig: ClientSessionConfig{ |
713 | @@ -341,6 +359,18 @@ | |||
714 | 341 | } | 359 | } |
715 | 342 | 360 | ||
716 | 343 | /**************************************************************** | 361 | /**************************************************************** |
717 | 362 | checkAuthorization() tests | ||
718 | 363 | ****************************************************************/ | ||
719 | 364 | |||
720 | 365 | func (cs *clientSessionSuite) TestChecksAuthorizationFromServer(c *C) { | ||
721 | 366 | sess := &ClientSession{} | ||
722 | 367 | c.Assert(sess.auth, Equals, "") | ||
723 | 368 | err := sess.checkAuthorization() | ||
724 | 369 | c.Assert(err, IsNil) | ||
725 | 370 | c.Check(sess.auth, Equals, "some auth") | ||
726 | 371 | } | ||
727 | 372 | |||
728 | 373 | /**************************************************************** | ||
729 | 344 | startConnectionAttempt()/nextHostToTry()/started tests | 374 | startConnectionAttempt()/nextHostToTry()/started tests |
730 | 345 | ****************************************************************/ | 375 | ****************************************************************/ |
731 | 346 | 376 | ||
732 | @@ -427,7 +457,9 @@ | |||
733 | 427 | sess, err := NewSession("", dummyConf, "wah", cs.lvls, cs.log) | 457 | sess, err := NewSession("", dummyConf, "wah", cs.lvls, cs.log) |
734 | 428 | c.Assert(err, IsNil) | 458 | c.Assert(err, IsNil) |
735 | 429 | sess.deliveryHosts = []string{"nowhere"} | 459 | sess.deliveryHosts = []string{"nowhere"} |
736 | 460 | sess.clearShouldDelay() | ||
737 | 430 | err = sess.connect() | 461 | err = sess.connect() |
738 | 462 | c.Check(sess.ShouldDelay(), Equals, true) | ||
739 | 431 | c.Check(err, ErrorMatches, ".*connect.*address.*") | 463 | c.Check(err, ErrorMatches, ".*connect.*address.*") |
740 | 432 | c.Check(sess.State(), Equals, Error) | 464 | c.Check(sess.State(), Equals, Error) |
741 | 433 | } | 465 | } |
742 | @@ -439,7 +471,9 @@ | |||
743 | 439 | sess, err := NewSession("", dummyConf, "wah", cs.lvls, cs.log) | 471 | sess, err := NewSession("", dummyConf, "wah", cs.lvls, cs.log) |
744 | 440 | c.Assert(err, IsNil) | 472 | c.Assert(err, IsNil) |
745 | 441 | sess.deliveryHosts = []string{srv.Addr().String()} | 473 | sess.deliveryHosts = []string{srv.Addr().String()} |
746 | 474 | sess.clearShouldDelay() | ||
747 | 442 | err = sess.connect() | 475 | err = sess.connect() |
748 | 476 | c.Check(sess.ShouldDelay(), Equals, true) | ||
749 | 443 | c.Check(err, IsNil) | 477 | c.Check(err, IsNil) |
750 | 444 | c.Check(sess.Connection, NotNil) | 478 | c.Check(sess.Connection, NotNil) |
751 | 445 | c.Check(sess.State(), Equals, Connected) | 479 | c.Check(sess.State(), Equals, Connected) |
752 | @@ -452,7 +486,9 @@ | |||
753 | 452 | sess, err := NewSession("", dummyConf, "wah", cs.lvls, cs.log) | 486 | sess, err := NewSession("", dummyConf, "wah", cs.lvls, cs.log) |
754 | 453 | c.Assert(err, IsNil) | 487 | c.Assert(err, IsNil) |
755 | 454 | sess.deliveryHosts = []string{"nowhere", srv.Addr().String()} | 488 | sess.deliveryHosts = []string{"nowhere", srv.Addr().String()} |
756 | 489 | sess.clearShouldDelay() | ||
757 | 455 | err = sess.connect() | 490 | err = sess.connect() |
758 | 491 | c.Check(sess.ShouldDelay(), Equals, true) | ||
759 | 456 | c.Check(err, IsNil) | 492 | c.Check(err, IsNil) |
760 | 457 | c.Check(sess.Connection, NotNil) | 493 | c.Check(sess.Connection, NotNil) |
761 | 458 | c.Check(sess.State(), Equals, Connected) | 494 | c.Check(sess.State(), Equals, Connected) |
762 | @@ -466,7 +502,9 @@ | |||
763 | 466 | srv.Close() | 502 | srv.Close() |
764 | 467 | c.Assert(err, IsNil) | 503 | c.Assert(err, IsNil) |
765 | 468 | sess.deliveryHosts = []string{srv.Addr().String()} | 504 | sess.deliveryHosts = []string{srv.Addr().String()} |
766 | 505 | sess.clearShouldDelay() | ||
767 | 469 | err = sess.connect() | 506 | err = sess.connect() |
768 | 507 | c.Check(sess.ShouldDelay(), Equals, true) | ||
769 | 470 | c.Check(err, ErrorMatches, ".*connection refused") | 508 | c.Check(err, ErrorMatches, ".*connection refused") |
770 | 471 | c.Check(sess.State(), Equals, Error) | 509 | c.Check(sess.State(), Equals, Error) |
771 | 472 | } | 510 | } |
772 | @@ -548,6 +586,27 @@ | |||
773 | 548 | c.Check(<-ch, Not(Equals), 0) | 586 | c.Check(<-ch, Not(Equals), 0) |
774 | 549 | } | 587 | } |
775 | 550 | 588 | ||
776 | 589 | func (cs *clientSessionSuite) TestAutoRedialCallsRedialDelay(c *C) { | ||
777 | 590 | sess, err := NewSession("", dummyConf, "wah", cs.lvls, cs.log) | ||
778 | 591 | c.Assert(err, IsNil) | ||
779 | 592 | flag := false | ||
780 | 593 | sess.redialDelay = func(sess *ClientSession) time.Duration { flag = true; return 0 } | ||
781 | 594 | sess.AutoRedial(nil) | ||
782 | 595 | c.Check(flag, Equals, true) | ||
783 | 596 | } | ||
784 | 597 | |||
785 | 598 | func (cs *clientSessionSuite) TestAutoRedialSetsRedialDelayIfTooQuick(c *C) { | ||
786 | 599 | sess, err := NewSession("", dummyConf, "wah", cs.lvls, cs.log) | ||
787 | 600 | c.Assert(err, IsNil) | ||
788 | 601 | sess.redialDelay = func(sess *ClientSession) time.Duration { return 0 } | ||
789 | 602 | sess.AutoRedial(nil) | ||
790 | 603 | c.Check(sess.ShouldDelay(), Equals, false) | ||
791 | 604 | sess.stopRedial() | ||
792 | 605 | sess.clearShouldDelay() | ||
793 | 606 | sess.AutoRedial(nil) | ||
794 | 607 | c.Check(sess.ShouldDelay(), Equals, true) | ||
795 | 608 | } | ||
796 | 609 | |||
797 | 551 | /**************************************************************** | 610 | /**************************************************************** |
798 | 552 | handlePing() tests | 611 | handlePing() tests |
799 | 553 | ****************************************************************/ | 612 | ****************************************************************/ |
800 | @@ -594,6 +653,24 @@ | |||
801 | 594 | c.Check(s.sess.State(), Equals, Error) | 653 | c.Check(s.sess.State(), Equals, Error) |
802 | 595 | } | 654 | } |
803 | 596 | 655 | ||
804 | 656 | func (s *msgSuite) TestHandlePingClearsDelay(c *C) { | ||
805 | 657 | s.sess.setShouldDelay() | ||
806 | 658 | s.upCh <- nil // no error | ||
807 | 659 | c.Check(s.sess.handlePing(), IsNil) | ||
808 | 660 | c.Assert(len(s.downCh), Equals, 1) | ||
809 | 661 | c.Check(<-s.downCh, Equals, protocol.PingPongMsg{Type: "pong"}) | ||
810 | 662 | c.Check(s.sess.ShouldDelay(), Equals, false) | ||
811 | 663 | } | ||
812 | 664 | |||
813 | 665 | func (s *msgSuite) TestHandlePingDoesNotClearsDelayOnError(c *C) { | ||
814 | 666 | s.sess.setShouldDelay() | ||
815 | 667 | s.upCh <- errors.New("Pong") | ||
816 | 668 | c.Check(s.sess.handlePing(), NotNil) | ||
817 | 669 | c.Assert(len(s.downCh), Equals, 1) | ||
818 | 670 | c.Check(<-s.downCh, Equals, protocol.PingPongMsg{Type: "pong"}) | ||
819 | 671 | c.Check(s.sess.ShouldDelay(), Equals, true) | ||
820 | 672 | } | ||
821 | 673 | |||
822 | 597 | /**************************************************************** | 674 | /**************************************************************** |
823 | 598 | handleBroadcast() tests | 675 | handleBroadcast() tests |
824 | 599 | ****************************************************************/ | 676 | ****************************************************************/ |
825 | @@ -687,6 +764,32 @@ | |||
826 | 687 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"nak"}) | 764 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"nak"}) |
827 | 688 | } | 765 | } |
828 | 689 | 766 | ||
829 | 767 | func (s *msgSuite) TestHandleBroadcastClearsDelay(c *C) { | ||
830 | 768 | s.sess.setShouldDelay() | ||
831 | 769 | |||
832 | 770 | msg := serverMsg{"broadcast", protocol.BroadcastMsg{}, | ||
833 | 771 | protocol.NotificationsMsg{}, protocol.ConnBrokenMsg{}} | ||
834 | 772 | go func() { s.errCh <- s.sess.handleBroadcast(&msg) }() | ||
835 | 773 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) | ||
836 | 774 | s.upCh <- nil // ack ok | ||
837 | 775 | c.Check(<-s.errCh, IsNil) | ||
838 | 776 | |||
839 | 777 | c.Check(s.sess.ShouldDelay(), Equals, false) | ||
840 | 778 | } | ||
841 | 779 | |||
842 | 780 | func (s *msgSuite) TestHandleBroadcastDoesNotClearDelayOnError(c *C) { | ||
843 | 781 | s.sess.setShouldDelay() | ||
844 | 782 | |||
845 | 783 | msg := serverMsg{"broadcast", protocol.BroadcastMsg{}, | ||
846 | 784 | protocol.NotificationsMsg{}, protocol.ConnBrokenMsg{}} | ||
847 | 785 | go func() { s.errCh <- s.sess.handleBroadcast(&msg) }() | ||
848 | 786 | c.Check(takeNext(s.downCh), Equals, protocol.AckMsg{"ack"}) | ||
849 | 787 | s.upCh <- errors.New("bcast") | ||
850 | 788 | c.Check(<-s.errCh, NotNil) | ||
851 | 789 | |||
852 | 790 | c.Check(s.sess.ShouldDelay(), Equals, true) | ||
853 | 791 | } | ||
854 | 792 | |||
855 | 690 | /**************************************************************** | 793 | /**************************************************************** |
856 | 691 | handleConnBroken() tests | 794 | handleConnBroken() tests |
857 | 692 | ****************************************************************/ | 795 | ****************************************************************/ |
858 | @@ -852,9 +955,10 @@ | |||
859 | 852 | 955 | ||
860 | 853 | c.Check(takeNext(downCh), Equals, "deadline 0") | 956 | c.Check(takeNext(downCh), Equals, "deadline 0") |
861 | 854 | c.Check(takeNext(downCh), DeepEquals, protocol.ConnectMsg{ | 957 | c.Check(takeNext(downCh), DeepEquals, protocol.ConnectMsg{ |
865 | 855 | Type: "connect", | 958 | Type: "connect", |
866 | 856 | DeviceId: sess.DeviceId, | 959 | DeviceId: sess.DeviceId, |
867 | 857 | Levels: map[string]int64{}, | 960 | Levels: map[string]int64{}, |
868 | 961 | Authorization: "", | ||
869 | 858 | }) | 962 | }) |
870 | 859 | upCh <- errors.New("Overflow error in /dev/null") | 963 | upCh <- errors.New("Overflow error in /dev/null") |
871 | 860 | err = <-errCh | 964 | err = <-errCh |
872 | @@ -959,6 +1063,7 @@ | |||
873 | 959 | msg, ok := takeNext(downCh).(protocol.ConnectMsg) | 1063 | msg, ok := takeNext(downCh).(protocol.ConnectMsg) |
874 | 960 | c.Check(ok, Equals, true) | 1064 | c.Check(ok, Equals, true) |
875 | 961 | c.Check(msg.DeviceId, Equals, "wah") | 1065 | c.Check(msg.DeviceId, Equals, "wah") |
876 | 1066 | c.Check(msg.Authorization, Equals, "") | ||
877 | 962 | c.Check(msg.Info, DeepEquals, info) | 1067 | c.Check(msg.Info, DeepEquals, info) |
878 | 963 | upCh <- nil // no error | 1068 | upCh <- nil // no error |
879 | 964 | upCh <- protocol.ConnAckMsg{ | 1069 | upCh <- protocol.ConnAckMsg{ |
880 | @@ -975,6 +1080,22 @@ | |||
881 | 975 | run() tests | 1080 | run() tests |
882 | 976 | ****************************************************************/ | 1081 | ****************************************************************/ |
883 | 977 | 1082 | ||
884 | 1083 | func (cs *clientSessionSuite) TestRunBailsIfAuthCheckFails(c *C) { | ||
885 | 1084 | sess, err := NewSession("", dummyConf, "wah", cs.lvls, cs.log) | ||
886 | 1085 | c.Assert(err, IsNil) | ||
887 | 1086 | failure := errors.New("TestRunBailsIfAuthCheckFails") | ||
888 | 1087 | has_closed := false | ||
889 | 1088 | err = sess.run( | ||
890 | 1089 | func() { has_closed = true }, | ||
891 | 1090 | func() error { return failure }, | ||
892 | 1091 | nil, | ||
893 | 1092 | nil, | ||
894 | 1093 | nil, | ||
895 | 1094 | nil) | ||
896 | 1095 | c.Check(err, Equals, failure) | ||
897 | 1096 | c.Check(has_closed, Equals, true) | ||
898 | 1097 | } | ||
899 | 1098 | |||
900 | 978 | func (cs *clientSessionSuite) TestRunBailsIfHostGetterFails(c *C) { | 1099 | func (cs *clientSessionSuite) TestRunBailsIfHostGetterFails(c *C) { |
901 | 979 | sess, err := NewSession("", dummyConf, "wah", cs.lvls, cs.log) | 1100 | sess, err := NewSession("", dummyConf, "wah", cs.lvls, cs.log) |
902 | 980 | c.Assert(err, IsNil) | 1101 | c.Assert(err, IsNil) |
903 | @@ -982,6 +1103,7 @@ | |||
904 | 982 | has_closed := false | 1103 | has_closed := false |
905 | 983 | err = sess.run( | 1104 | err = sess.run( |
906 | 984 | func() { has_closed = true }, | 1105 | func() { has_closed = true }, |
907 | 1106 | func() error { return nil }, | ||
908 | 985 | func() error { return failure }, | 1107 | func() error { return failure }, |
909 | 986 | nil, | 1108 | nil, |
910 | 987 | nil, | 1109 | nil, |
911 | @@ -997,6 +1119,7 @@ | |||
912 | 997 | err = sess.run( | 1119 | err = sess.run( |
913 | 998 | func() {}, | 1120 | func() {}, |
914 | 999 | func() error { return nil }, | 1121 | func() error { return nil }, |
915 | 1122 | func() error { return nil }, | ||
916 | 1000 | func() error { return failure }, | 1123 | func() error { return failure }, |
917 | 1001 | nil, | 1124 | nil, |
918 | 1002 | nil) | 1125 | nil) |
919 | @@ -1011,6 +1134,7 @@ | |||
920 | 1011 | func() {}, | 1134 | func() {}, |
921 | 1012 | func() error { return nil }, | 1135 | func() error { return nil }, |
922 | 1013 | func() error { return nil }, | 1136 | func() error { return nil }, |
923 | 1137 | func() error { return nil }, | ||
924 | 1014 | func() error { return failure }, | 1138 | func() error { return failure }, |
925 | 1015 | nil) | 1139 | nil) |
926 | 1016 | c.Check(err, Equals, failure) | 1140 | c.Check(err, Equals, failure) |
927 | @@ -1030,6 +1154,7 @@ | |||
928 | 1030 | func() error { return nil }, | 1154 | func() error { return nil }, |
929 | 1031 | func() error { return nil }, | 1155 | func() error { return nil }, |
930 | 1032 | func() error { return nil }, | 1156 | func() error { return nil }, |
931 | 1157 | func() error { return nil }, | ||
932 | 1033 | func() error { sess.MsgCh <- notf; return <-failureCh }) | 1158 | func() error { sess.MsgCh <- notf; return <-failureCh }) |
933 | 1034 | c.Check(err, Equals, nil) | 1159 | c.Check(err, Equals, nil) |
934 | 1035 | // if run doesn't error it sets up the channels | 1160 | // if run doesn't error it sets up the channels |
935 | @@ -1087,9 +1212,64 @@ | |||
936 | 1087 | 1212 | ||
937 | 1088 | var ( | 1213 | var ( |
938 | 1089 | dialTestTimeout = 100 * time.Millisecond | 1214 | dialTestTimeout = 100 * time.Millisecond |
940 | 1090 | dialTestConf = ClientSessionConfig{ExchangeTimeout: dialTestTimeout} | 1215 | dialTestConf = ClientSessionConfig{ |
941 | 1216 | ExchangeTimeout: dialTestTimeout, | ||
942 | 1217 | PEM: helpers.TestCertPEMBlock, | ||
943 | 1218 | } | ||
944 | 1091 | ) | 1219 | ) |
945 | 1092 | 1220 | ||
946 | 1221 | func (cs *clientSessionSuite) TestDialBadServerName(c *C) { | ||
947 | 1222 | // a borked server name | ||
948 | 1223 | cert, err := tls.X509KeyPair(helpers.TestCertPEMBlock, helpers.TestKeyPEMBlock) | ||
949 | 1224 | c.Assert(err, IsNil) | ||
950 | 1225 | tlsCfg := &tls.Config{ | ||
951 | 1226 | Certificates: []tls.Certificate{cert}, | ||
952 | 1227 | SessionTicketsDisabled: true, | ||
953 | 1228 | } | ||
954 | 1229 | |||
955 | 1230 | lst, err := tls.Listen("tcp", "localhost:0", tlsCfg) | ||
956 | 1231 | c.Assert(err, IsNil) | ||
957 | 1232 | // advertise | ||
958 | 1233 | ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
959 | 1234 | b, err := json.Marshal(map[string]interface{}{ | ||
960 | 1235 | "domain": "xyzzy", // <-- *** THIS *** is the bit that'll break it | ||
961 | 1236 | "hosts": []string{"nowhere", lst.Addr().String()}, | ||
962 | 1237 | }) | ||
963 | 1238 | if err != nil { | ||
964 | 1239 | panic(err) | ||
965 | 1240 | } | ||
966 | 1241 | w.Header().Set("Content-Type", "application/json") | ||
967 | 1242 | w.Write(b) | ||
968 | 1243 | })) | ||
969 | 1244 | defer ts.Close() | ||
970 | 1245 | |||
971 | 1246 | sess, err := NewSession(ts.URL, dialTestConf, "wah", cs.lvls, cs.log) | ||
972 | 1247 | c.Assert(err, IsNil) | ||
973 | 1248 | tconn := &testConn{} | ||
974 | 1249 | sess.Connection = tconn | ||
975 | 1250 | |||
976 | 1251 | upCh := make(chan interface{}, 5) | ||
977 | 1252 | downCh := make(chan interface{}, 5) | ||
978 | 1253 | errCh := make(chan error, 1) | ||
979 | 1254 | proto := &testProtocol{up: upCh, down: downCh} | ||
980 | 1255 | sess.Protocolator = func(net.Conn) protocol.Protocol { return proto } | ||
981 | 1256 | |||
982 | 1257 | go func() { | ||
983 | 1258 | errCh <- sess.Dial() | ||
984 | 1259 | }() | ||
985 | 1260 | |||
986 | 1261 | srv, err := lst.Accept() | ||
987 | 1262 | c.Assert(err, IsNil) | ||
988 | 1263 | |||
989 | 1264 | // connect done | ||
990 | 1265 | |||
991 | 1266 | _, err = protocol.ReadWireFormatVersion(srv, dialTestTimeout) | ||
992 | 1267 | c.Check(err, NotNil) | ||
993 | 1268 | |||
994 | 1269 | c.Check(<-errCh, NotNil) | ||
995 | 1270 | c.Check(sess.State(), Equals, Error) | ||
996 | 1271 | } | ||
997 | 1272 | |||
998 | 1093 | func (cs *clientSessionSuite) TestDialWorks(c *C) { | 1273 | func (cs *clientSessionSuite) TestDialWorks(c *C) { |
999 | 1094 | // happy path thoughts | 1274 | // happy path thoughts |
1000 | 1095 | cert, err := tls.X509KeyPair(helpers.TestCertPEMBlock, helpers.TestKeyPEMBlock) | 1275 | cert, err := tls.X509KeyPair(helpers.TestCertPEMBlock, helpers.TestKeyPEMBlock) |
1001 | @@ -1104,7 +1284,8 @@ | |||
1002 | 1104 | // advertise | 1284 | // advertise |
1003 | 1105 | ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | 1285 | ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
1004 | 1106 | b, err := json.Marshal(map[string]interface{}{ | 1286 | b, err := json.Marshal(map[string]interface{}{ |
1006 | 1107 | "hosts": []string{"nowhere", lst.Addr().String()}, | 1287 | "domain": "localhost", |
1007 | 1288 | "hosts": []string{"nowhere", lst.Addr().String()}, | ||
1008 | 1108 | }) | 1289 | }) |
1009 | 1109 | if err != nil { | 1290 | if err != nil { |
1010 | 1110 | panic(err) | 1291 | panic(err) |
1011 | @@ -1223,3 +1404,38 @@ | |||
1012 | 1223 | c.Assert(err, IsNil) | 1404 | c.Assert(err, IsNil) |
1013 | 1224 | // connect done | 1405 | // connect done |
1014 | 1225 | } | 1406 | } |
1015 | 1407 | |||
1016 | 1408 | /**************************************************************** | ||
1017 | 1409 | redialDelay() tests | ||
1018 | 1410 | ****************************************************************/ | ||
1019 | 1411 | |||
1020 | 1412 | func (cs *clientSessionSuite) TestShouldDelay(c *C) { | ||
1021 | 1413 | sess, err := NewSession("foo:443", dummyConf, "", cs.lvls, cs.log) | ||
1022 | 1414 | c.Assert(err, IsNil) | ||
1023 | 1415 | c.Check(sess.ShouldDelay(), Equals, false) | ||
1024 | 1416 | sess.setShouldDelay() | ||
1025 | 1417 | c.Check(sess.ShouldDelay(), Equals, true) | ||
1026 | 1418 | sess.clearShouldDelay() | ||
1027 | 1419 | c.Check(sess.ShouldDelay(), Equals, false) | ||
1028 | 1420 | } | ||
1029 | 1421 | |||
1030 | 1422 | func (cs *clientSessionSuite) TestRedialDelay(c *C) { | ||
1031 | 1423 | sess, err := NewSession("foo:443", dummyConf, "", cs.lvls, cs.log) | ||
1032 | 1424 | c.Assert(err, IsNil) | ||
1033 | 1425 | sess.redialDelays = []time.Duration{17, 42} | ||
1034 | 1426 | n := 0 | ||
1035 | 1427 | sess.redialJitter = func(time.Duration) time.Duration { n++; return 0 } | ||
1036 | 1428 | // we get increasing delays while we're unhappy | ||
1037 | 1429 | sess.setShouldDelay() | ||
1038 | 1430 | c.Check(redialDelay(sess), Equals, time.Duration(17)) | ||
1039 | 1431 | c.Check(redialDelay(sess), Equals, time.Duration(42)) | ||
1040 | 1432 | c.Check(redialDelay(sess), Equals, time.Duration(42)) | ||
1041 | 1433 | // once we're happy, delays drop to 0 | ||
1042 | 1434 | sess.clearShouldDelay() | ||
1043 | 1435 | c.Check(redialDelay(sess), Equals, time.Duration(0)) | ||
1044 | 1436 | // and start again from the top if we become unhappy again | ||
1045 | 1437 | sess.setShouldDelay() | ||
1046 | 1438 | c.Check(redialDelay(sess), Equals, time.Duration(17)) | ||
1047 | 1439 | // and redialJitter got called every time shouldDelay was true | ||
1048 | 1440 | c.Check(n, Equals, 4) | ||
1049 | 1441 | } | ||
1050 | 1226 | 1442 | ||
1051 | === modified file 'config/config.go' | |||
1052 | --- config/config.go 2014-03-25 18:49:18 +0000 | |||
1053 | +++ config/config.go 2014-04-29 18:02:00 +0000 | |||
1054 | @@ -20,6 +20,7 @@ | |||
1055 | 20 | import ( | 20 | import ( |
1056 | 21 | "encoding/json" | 21 | "encoding/json" |
1057 | 22 | "errors" | 22 | "errors" |
1058 | 23 | "flag" | ||
1059 | 23 | "fmt" | 24 | "fmt" |
1060 | 24 | "io" | 25 | "io" |
1061 | 25 | "io/ioutil" | 26 | "io/ioutil" |
1062 | @@ -27,6 +28,7 @@ | |||
1063 | 27 | "os" | 28 | "os" |
1064 | 28 | "path/filepath" | 29 | "path/filepath" |
1065 | 29 | "reflect" | 30 | "reflect" |
1066 | 31 | "strconv" | ||
1067 | 30 | "strings" | 32 | "strings" |
1068 | 31 | "time" | 33 | "time" |
1069 | 32 | ) | 34 | ) |
1070 | @@ -118,6 +120,22 @@ | |||
1071 | 118 | return fillDestConfig(destValue, p1) | 120 | return fillDestConfig(destValue, p1) |
1072 | 119 | } | 121 | } |
1073 | 120 | 122 | ||
1074 | 123 | // FromString are config holders that can be set by parsing a string. | ||
1075 | 124 | type FromString interface { | ||
1076 | 125 | SetFromString(enc string) error | ||
1077 | 126 | } | ||
1078 | 127 | |||
1079 | 128 | // UnmarshalJSONViaString helps unmarshalling from JSON for FromString | ||
1080 | 129 | // supporting config holders. | ||
1081 | 130 | func UnmarshalJSONViaString(dest FromString, b []byte) error { | ||
1082 | 131 | var enc string | ||
1083 | 132 | err := json.Unmarshal(b, &enc) | ||
1084 | 133 | if err != nil { | ||
1085 | 134 | return err | ||
1086 | 135 | } | ||
1087 | 136 | return dest.SetFromString(enc) | ||
1088 | 137 | } | ||
1089 | 138 | |||
1090 | 121 | // ConfigTimeDuration can hold a time.Duration in a configuration struct, | 139 | // ConfigTimeDuration can hold a time.Duration in a configuration struct, |
1091 | 122 | // that is parsed from a string as supported by time.ParseDuration. | 140 | // that is parsed from a string as supported by time.ParseDuration. |
1092 | 123 | type ConfigTimeDuration struct { | 141 | type ConfigTimeDuration struct { |
1093 | @@ -125,13 +143,11 @@ | |||
1094 | 125 | } | 143 | } |
1095 | 126 | 144 | ||
1096 | 127 | func (ctd *ConfigTimeDuration) UnmarshalJSON(b []byte) error { | 145 | func (ctd *ConfigTimeDuration) UnmarshalJSON(b []byte) error { |
1104 | 128 | var enc string | 146 | return UnmarshalJSONViaString(ctd, b) |
1105 | 129 | var v time.Duration | 147 | } |
1106 | 130 | err := json.Unmarshal(b, &enc) | 148 | |
1107 | 131 | if err != nil { | 149 | func (ctd *ConfigTimeDuration) SetFromString(enc string) error { |
1108 | 132 | return err | 150 | v, err := time.ParseDuration(enc) |
1102 | 133 | } | ||
1103 | 134 | v, err = time.ParseDuration(enc) | ||
1109 | 135 | if err != nil { | 151 | if err != nil { |
1110 | 136 | return err | 152 | return err |
1111 | 137 | } | 153 | } |
1112 | @@ -148,12 +164,11 @@ | |||
1113 | 148 | type ConfigHostPort string | 164 | type ConfigHostPort string |
1114 | 149 | 165 | ||
1115 | 150 | func (chp *ConfigHostPort) UnmarshalJSON(b []byte) error { | 166 | func (chp *ConfigHostPort) UnmarshalJSON(b []byte) error { |
1122 | 151 | var enc string | 167 | return UnmarshalJSONViaString(chp, b) |
1123 | 152 | err := json.Unmarshal(b, &enc) | 168 | } |
1124 | 153 | if err != nil { | 169 | |
1125 | 154 | return err | 170 | func (chp *ConfigHostPort) SetFromString(enc string) error { |
1126 | 155 | } | 171 | _, _, err := net.SplitHostPort(enc) |
1121 | 156 | _, _, err = net.SplitHostPort(enc) | ||
1127 | 157 | if err != nil { | 172 | if err != nil { |
1128 | 158 | return err | 173 | return err |
1129 | 159 | } | 174 | } |
1130 | @@ -198,23 +213,117 @@ | |||
1131 | 198 | return ioutil.ReadFile(p) | 213 | return ioutil.ReadFile(p) |
1132 | 199 | } | 214 | } |
1133 | 200 | 215 | ||
1135 | 201 | // ReadFiles reads configuration from a set of files. Uses ReadConfig internally. | 216 | // used to implement getting config values with flag.Parse() |
1136 | 217 | type val struct { | ||
1137 | 218 | destField destField | ||
1138 | 219 | accu map[string]json.RawMessage | ||
1139 | 220 | } | ||
1140 | 221 | |||
1141 | 222 | func (v *val) String() string { // used to show default | ||
1142 | 223 | return string(v.accu[v.destField.configName()]) | ||
1143 | 224 | } | ||
1144 | 225 | |||
1145 | 226 | func (v *val) IsBoolFlag() bool { | ||
1146 | 227 | return v.destField.fld.Type.Kind() == reflect.Bool | ||
1147 | 228 | } | ||
1148 | 229 | |||
1149 | 230 | func (v *val) marshalAsNeeded(s string) (json.RawMessage, error) { | ||
1150 | 231 | var toMarshal interface{} | ||
1151 | 232 | switch v.destField.dest.(type) { | ||
1152 | 233 | case *string, FromString: | ||
1153 | 234 | toMarshal = s | ||
1154 | 235 | case *bool: | ||
1155 | 236 | bit, err := strconv.ParseBool(s) | ||
1156 | 237 | if err != nil { | ||
1157 | 238 | return nil, err | ||
1158 | 239 | } | ||
1159 | 240 | toMarshal = bit | ||
1160 | 241 | default: | ||
1161 | 242 | return json.RawMessage(s), nil | ||
1162 | 243 | } | ||
1163 | 244 | return json.Marshal(toMarshal) | ||
1164 | 245 | } | ||
1165 | 246 | |||
1166 | 247 | func (v *val) Set(s string) error { | ||
1167 | 248 | marshalled, err := v.marshalAsNeeded(s) | ||
1168 | 249 | if err != nil { | ||
1169 | 250 | return err | ||
1170 | 251 | } | ||
1171 | 252 | v.accu[v.destField.configName()] = marshalled | ||
1172 | 253 | return nil | ||
1173 | 254 | } | ||
1174 | 255 | |||
1175 | 256 | func readOneConfig(accu map[string]json.RawMessage, cfgPath string) error { | ||
1176 | 257 | r, err := os.Open(cfgPath) | ||
1177 | 258 | if err != nil { | ||
1178 | 259 | return err | ||
1179 | 260 | } | ||
1180 | 261 | defer r.Close() | ||
1181 | 262 | err = json.NewDecoder(r).Decode(&accu) | ||
1182 | 263 | if err != nil { | ||
1183 | 264 | return err | ||
1184 | 265 | } | ||
1185 | 266 | return nil | ||
1186 | 267 | } | ||
1187 | 268 | |||
1188 | 269 | // used to implement -cfg@= | ||
1189 | 270 | type readConfigAtVal struct { | ||
1190 | 271 | accu map[string]json.RawMessage | ||
1191 | 272 | } | ||
1192 | 273 | |||
1193 | 274 | func (v *readConfigAtVal) String() string { | ||
1194 | 275 | return "<config.json>" | ||
1195 | 276 | } | ||
1196 | 277 | |||
1197 | 278 | func (v *readConfigAtVal) Set(path string) error { | ||
1198 | 279 | return readOneConfig(v.accu, path) | ||
1199 | 280 | } | ||
1200 | 281 | |||
1201 | 282 | // readUsingFlags gets config values from command line flags. | ||
1202 | 283 | func readUsingFlags(accu map[string]json.RawMessage, destValue reflect.Value) error { | ||
1203 | 284 | if flag.Parsed() { | ||
1204 | 285 | if IgnoreParsedFlags { | ||
1205 | 286 | return nil | ||
1206 | 287 | } | ||
1207 | 288 | return fmt.Errorf("too late, flags already parsed") | ||
1208 | 289 | } | ||
1209 | 290 | destStruct := destValue.Elem() | ||
1210 | 291 | for destField := range traverseStruct(destStruct) { | ||
1211 | 292 | help := destField.fld.Tag.Get("help") | ||
1212 | 293 | flag.Var(&val{destField, accu}, destField.configName(), help) | ||
1213 | 294 | } | ||
1214 | 295 | flag.Var(&readConfigAtVal{accu}, "cfg@", "get config values from file") | ||
1215 | 296 | flag.Parse() | ||
1216 | 297 | return nil | ||
1217 | 298 | } | ||
1218 | 299 | |||
1219 | 300 | // IgnoreParsedFlags will just have ReadFiles ignore <flags> if the | ||
1220 | 301 | // command line was already parsed. | ||
1221 | 302 | var IgnoreParsedFlags = false | ||
1222 | 303 | |||
1223 | 304 | // ReadFiles reads configuration from a set of files. The string | ||
1224 | 305 | // "<flags>" can be used as a pseudo file-path, it will consider | ||
1225 | 306 | // command line flags, invoking flag.Parse(). Among those the flag | ||
1226 | 307 | // -cfg@=FILE can be used to get further config values from FILE. | ||
1227 | 202 | func ReadFiles(destConfig interface{}, cfgFpaths ...string) error { | 308 | func ReadFiles(destConfig interface{}, cfgFpaths ...string) error { |
1228 | 203 | destValue, err := checkDestConfig("destConfig", destConfig) | 309 | destValue, err := checkDestConfig("destConfig", destConfig) |
1229 | 204 | if err != nil { | 310 | if err != nil { |
1230 | 205 | return err | 311 | return err |
1231 | 206 | } | 312 | } |
1232 | 207 | // do the parsing in two phases for better error handling | 313 | // do the parsing in two phases for better error handling |
1234 | 208 | var p1 map[string]json.RawMessage | 314 | p1 := make(map[string]json.RawMessage) |
1235 | 209 | readOne := false | 315 | readOne := false |
1236 | 210 | for _, cfgPath := range cfgFpaths { | 316 | for _, cfgPath := range cfgFpaths { |
1237 | 317 | if cfgPath == "<flags>" { | ||
1238 | 318 | err := readUsingFlags(p1, destValue) | ||
1239 | 319 | if err != nil { | ||
1240 | 320 | return err | ||
1241 | 321 | } | ||
1242 | 322 | readOne = true | ||
1243 | 323 | continue | ||
1244 | 324 | } | ||
1245 | 211 | if _, err := os.Stat(cfgPath); err == nil { | 325 | if _, err := os.Stat(cfgPath); err == nil { |
1252 | 212 | r, err := os.Open(cfgPath) | 326 | err := readOneConfig(p1, cfgPath) |
1247 | 213 | if err != nil { | ||
1248 | 214 | return err | ||
1249 | 215 | } | ||
1250 | 216 | defer r.Close() | ||
1251 | 217 | err = json.NewDecoder(r).Decode(&p1) | ||
1253 | 218 | if err != nil { | 327 | if err != nil { |
1254 | 219 | return err | 328 | return err |
1255 | 220 | } | 329 | } |
1256 | 221 | 330 | ||
1257 | === modified file 'config/config_test.go' | |||
1258 | --- config/config_test.go 2014-03-25 18:49:18 +0000 | |||
1259 | +++ config/config_test.go 2014-04-29 18:02:00 +0000 | |||
1260 | @@ -18,6 +18,9 @@ | |||
1261 | 18 | 18 | ||
1262 | 19 | import ( | 19 | import ( |
1263 | 20 | "bytes" | 20 | "bytes" |
1264 | 21 | "encoding/json" | ||
1265 | 22 | "flag" | ||
1266 | 23 | "fmt" | ||
1267 | 21 | "io/ioutil" | 24 | "io/ioutil" |
1268 | 22 | "os" | 25 | "os" |
1269 | 23 | "path/filepath" | 26 | "path/filepath" |
1270 | @@ -230,3 +233,105 @@ | |||
1271 | 230 | c.Check(res, DeepEquals, []string{"b", "c_list", "d"}) | 233 | c.Check(res, DeepEquals, []string{"b", "c_list", "d"}) |
1272 | 231 | 234 | ||
1273 | 232 | } | 235 | } |
1274 | 236 | |||
1275 | 237 | type testConfig3 struct { | ||
1276 | 238 | A bool | ||
1277 | 239 | B string | ||
1278 | 240 | C []string `json:"c_list"` | ||
1279 | 241 | D ConfigTimeDuration `help:"duration"` | ||
1280 | 242 | E ConfigHostPort | ||
1281 | 243 | F string | ||
1282 | 244 | } | ||
1283 | 245 | |||
1284 | 246 | type configFlagsSuite struct{} | ||
1285 | 247 | |||
1286 | 248 | var _ = Suite(&configFlagsSuite{}) | ||
1287 | 249 | |||
1288 | 250 | func (s *configFlagsSuite) SetUpTest(c *C) { | ||
1289 | 251 | flag.CommandLine = flag.NewFlagSet("cmd", flag.PanicOnError) | ||
1290 | 252 | // supress outputs | ||
1291 | 253 | flag.Usage = func() { flag.PrintDefaults() } | ||
1292 | 254 | flag.CommandLine.SetOutput(ioutil.Discard) | ||
1293 | 255 | } | ||
1294 | 256 | |||
1295 | 257 | func (s *configFlagsSuite) TestReadUsingFlags(c *C) { | ||
1296 | 258 | os.Args = []string{"cmd", "-a=1", "-b=foo", "-c_list", `["x","y"]`, "-d", "10s", "-e=localhost:80"} | ||
1297 | 259 | var cfg testConfig3 | ||
1298 | 260 | p := make(map[string]json.RawMessage) | ||
1299 | 261 | err := readUsingFlags(p, reflect.ValueOf(&cfg)) | ||
1300 | 262 | c.Assert(err, IsNil) | ||
1301 | 263 | c.Check(p, DeepEquals, map[string]json.RawMessage{ | ||
1302 | 264 | "a": json.RawMessage("true"), | ||
1303 | 265 | "b": json.RawMessage(`"foo"`), | ||
1304 | 266 | "c_list": json.RawMessage(`["x","y"]`), | ||
1305 | 267 | "d": json.RawMessage(`"10s"`), | ||
1306 | 268 | "e": json.RawMessage(`"localhost:80"`), | ||
1307 | 269 | }) | ||
1308 | 270 | } | ||
1309 | 271 | |||
1310 | 272 | func (s *configFlagsSuite) TestReadUsingFlagsBoolError(c *C) { | ||
1311 | 273 | os.Args = []string{"cmd", "-a=zoo"} | ||
1312 | 274 | var cfg testConfig3 | ||
1313 | 275 | p := make(map[string]json.RawMessage) | ||
1314 | 276 | c.Check(func() { readUsingFlags(p, reflect.ValueOf(&cfg)) }, PanicMatches, ".*invalid boolean.*-a.*") | ||
1315 | 277 | } | ||
1316 | 278 | |||
1317 | 279 | func (s *configFlagsSuite) TestReadFilesAndFlags(c *C) { | ||
1318 | 280 | // test <flags> pseudo file | ||
1319 | 281 | os.Args = []string{"cmd", "-b=x"} | ||
1320 | 282 | tmpDir := c.MkDir() | ||
1321 | 283 | cfgPath := filepath.Join(tmpDir, "cfg.json") | ||
1322 | 284 | err := ioutil.WriteFile(cfgPath, []byte(`{"a": 42, "c_list": ["y", "z"]}`), os.ModePerm) | ||
1323 | 285 | c.Assert(err, IsNil) | ||
1324 | 286 | var cfg testConfig1 | ||
1325 | 287 | err = ReadFiles(&cfg, cfgPath, "<flags>") | ||
1326 | 288 | c.Assert(err, IsNil) | ||
1327 | 289 | c.Check(cfg.A, Equals, 42) | ||
1328 | 290 | c.Check(cfg.B, Equals, "x") | ||
1329 | 291 | c.Check(cfg.C, DeepEquals, []string{"y", "z"}) | ||
1330 | 292 | } | ||
1331 | 293 | |||
1332 | 294 | func (s *configFlagsSuite) TestReadFilesAndFlagsConfigAtSupport(c *C) { | ||
1333 | 295 | // test <flags> pseudo file | ||
1334 | 296 | tmpDir := c.MkDir() | ||
1335 | 297 | cfgPath := filepath.Join(tmpDir, "cfg.json") | ||
1336 | 298 | os.Args = []string{"cmd", "-a=42", fmt.Sprintf("-cfg@=%s", cfgPath)} | ||
1337 | 299 | err := ioutil.WriteFile(cfgPath, []byte(`{"b": "x", "c_list": ["y", "z"]}`), os.ModePerm) | ||
1338 | 300 | c.Assert(err, IsNil) | ||
1339 | 301 | var cfg testConfig1 | ||
1340 | 302 | err = ReadFiles(&cfg, "<flags>") | ||
1341 | 303 | c.Assert(err, IsNil) | ||
1342 | 304 | c.Check(cfg.A, Equals, 42) | ||
1343 | 305 | c.Check(cfg.B, Equals, "x") | ||
1344 | 306 | c.Check(cfg.C, DeepEquals, []string{"y", "z"}) | ||
1345 | 307 | } | ||
1346 | 308 | |||
1347 | 309 | func (s *configFlagsSuite) TestReadUsingFlagsHelp(c *C) { | ||
1348 | 310 | os.Args = []string{"cmd", "-h"} | ||
1349 | 311 | buf := bytes.NewBufferString("") | ||
1350 | 312 | flag.CommandLine.Init("cmd", flag.ContinueOnError) | ||
1351 | 313 | flag.CommandLine.SetOutput(buf) | ||
1352 | 314 | var cfg testConfig3 | ||
1353 | 315 | p := map[string]json.RawMessage{ | ||
1354 | 316 | "d": json.RawMessage(`"2s"`), | ||
1355 | 317 | } | ||
1356 | 318 | readUsingFlags(p, reflect.ValueOf(&cfg)) | ||
1357 | 319 | c.Check(buf.String(), Matches, `(?s).*-cfg@=<config.json>: get config values from file\n.*-d="2s": duration.*`) | ||
1358 | 320 | } | ||
1359 | 321 | |||
1360 | 322 | func (s *configFlagsSuite) TestReadUsingFlagsAlreadyParsed(c *C) { | ||
1361 | 323 | os.Args = []string{"cmd"} | ||
1362 | 324 | flag.Parse() | ||
1363 | 325 | var cfg struct{} | ||
1364 | 326 | p := make(map[string]json.RawMessage) | ||
1365 | 327 | err := readUsingFlags(p, reflect.ValueOf(&cfg)) | ||
1366 | 328 | c.Assert(err, ErrorMatches, "too late, flags already parsed") | ||
1367 | 329 | err = ReadFiles(&cfg, "<flags>") | ||
1368 | 330 | c.Assert(err, ErrorMatches, "too late, flags already parsed") | ||
1369 | 331 | IgnoreParsedFlags = true | ||
1370 | 332 | defer func() { | ||
1371 | 333 | IgnoreParsedFlags = false | ||
1372 | 334 | }() | ||
1373 | 335 | err = ReadFiles(&cfg, "<flags>") | ||
1374 | 336 | c.Assert(err, IsNil) | ||
1375 | 337 | } | ||
1376 | 233 | 338 | ||
1377 | === modified file 'debian/changelog' | |||
1378 | --- debian/changelog 2014-04-11 18:31:57 +0000 | |||
1379 | +++ debian/changelog 2014-04-29 18:02:00 +0000 | |||
1380 | @@ -1,3 +1,9 @@ | |||
1381 | 1 | ubuntu-push (0.21-0.ubuntu1) UNRELEASED; urgency=medium | ||
1382 | 2 | |||
1383 | 3 | * New upstream release: first auth bits, and Qt dependency. | ||
1384 | 4 | |||
1385 | 5 | -- John Lenton <john.lenton@canonical.com> Tue, 15 Apr 2014 14:04:35 +0100 | ||
1386 | 6 | |||
1387 | 1 | ubuntu-push (0.2+14.04.20140411-0ubuntu1) trusty; urgency=medium | 7 | ubuntu-push (0.2+14.04.20140411-0ubuntu1) trusty; urgency=medium |
1388 | 2 | 8 | ||
1389 | 3 | [ John Lenton ] | 9 | [ John Lenton ] |
1390 | 4 | 10 | ||
1391 | === modified file 'debian/control' | |||
1392 | --- debian/control 2014-03-25 16:26:20 +0000 | |||
1393 | +++ debian/control 2014-04-29 18:02:00 +0000 | |||
1394 | @@ -14,6 +14,10 @@ | |||
1395 | 14 | libgcrypt11-dev, | 14 | libgcrypt11-dev, |
1396 | 15 | libglib2.0-dev (>= 2.31.6), | 15 | libglib2.0-dev (>= 2.31.6), |
1397 | 16 | libwhoopsie-dev, | 16 | libwhoopsie-dev, |
1398 | 17 | qtbase5-private-dev, | ||
1399 | 18 | qtdeclarative5-dev, | ||
1400 | 19 | libqt5opengl5-dev, | ||
1401 | 20 | libubuntuoneauth-2.0-dev, | ||
1402 | 17 | Standards-Version: 3.9.5 | 21 | Standards-Version: 3.9.5 |
1403 | 18 | Homepage: http://launchpad.net/ubuntu-push | 22 | Homepage: http://launchpad.net/ubuntu-push |
1404 | 19 | Vcs-Bzr: lp:ubuntu-push | 23 | Vcs-Bzr: lp:ubuntu-push |
1405 | 20 | 24 | ||
1406 | === modified file 'debian/rules' | |||
1407 | --- debian/rules 2014-03-24 12:22:55 +0000 | |||
1408 | +++ debian/rules 2014-04-29 18:02:00 +0000 | |||
1409 | @@ -2,9 +2,12 @@ | |||
1410 | 2 | # -*- makefile -*- | 2 | # -*- makefile -*- |
1411 | 3 | 3 | ||
1412 | 4 | export DH_GOPKG := launchpad.net/ubuntu-push | 4 | export DH_GOPKG := launchpad.net/ubuntu-push |
1413 | 5 | export DEB_BUILD_OPTIONS := nostrip | ||
1414 | 6 | export UBUNTU_PUSH_TEST_RESOURCES_ROOT := $(CURDIR) | 5 | export UBUNTU_PUSH_TEST_RESOURCES_ROOT := $(CURDIR) |
1415 | 7 | 6 | ||
1416 | 7 | override_dh_auto_build: | ||
1417 | 8 | cd $$( find ./ -type d -regex '\./[^/]*/src/launchpad.net' -printf "%h\n" | head -n1) && tar xvzf ../../externals.tgz | ||
1418 | 9 | dh_auto_build --buildsystem=golang | ||
1419 | 10 | |||
1420 | 8 | override_dh_install: | 11 | override_dh_install: |
1421 | 9 | dh_install -Xusr/bin/cmd -Xusr/bin/dev --fail-missing | 12 | dh_install -Xusr/bin/cmd -Xusr/bin/dev --fail-missing |
1422 | 10 | 13 | ||
1423 | 11 | 14 | ||
1424 | === modified file 'dependencies.tsv' | |||
1425 | --- dependencies.tsv 2014-03-12 13:23:26 +0000 | |||
1426 | +++ dependencies.tsv 2014-04-29 18:02:00 +0000 | |||
1427 | @@ -2,3 +2,5 @@ | |||
1428 | 2 | launchpad.net/go-dbus/v1 bzr james@jamesh.id.au-20140206110213-pbzcr6ucaz3rqmnw 125 | 2 | launchpad.net/go-dbus/v1 bzr james@jamesh.id.au-20140206110213-pbzcr6ucaz3rqmnw 125 |
1429 | 3 | launchpad.net/go-xdg/v0 bzr john.lenton@canonical.com-20140208094800-gubd5md7cro3mtxa 10 | 3 | launchpad.net/go-xdg/v0 bzr john.lenton@canonical.com-20140208094800-gubd5md7cro3mtxa 10 |
1430 | 4 | launchpad.net/gocheck bzr gustavo@niemeyer.net-20140127131816-zshobk1qqme626xw 86 | 4 | launchpad.net/gocheck bzr gustavo@niemeyer.net-20140127131816-zshobk1qqme626xw 86 |
1431 | 5 | gopkg.in/qml.v0 git master 8adbc8c2bf2da9f609df366683ad0f47a89c3d49 | ||
1432 | 6 | gopkg.in/niemeyer/uoneauth.v1 git v1 0758ba882a143ad2862dbcac85a7ca145750b640 | ||
1433 | 5 | 7 | ||
1434 | === added file 'externals.tgz' | |||
1435 | 6 | Binary files externals.tgz 1970-01-01 00:00:00 +0000 and externals.tgz 2014-04-29 18:02:00 +0000 differ | 8 | Binary files externals.tgz 1970-01-01 00:00:00 +0000 and externals.tgz 2014-04-29 18:02:00 +0000 differ |
1436 | === modified file 'logger/logger.go' | |||
1437 | --- logger/logger.go 2014-02-24 10:27:38 +0000 | |||
1438 | +++ logger/logger.go 2014-04-29 18:02:00 +0000 | |||
1439 | @@ -23,6 +23,8 @@ | |||
1440 | 23 | "log" | 23 | "log" |
1441 | 24 | "os" | 24 | "os" |
1442 | 25 | "runtime" | 25 | "runtime" |
1443 | 26 | |||
1444 | 27 | "launchpad.net/ubuntu-push/config" | ||
1445 | 26 | ) | 28 | ) |
1446 | 27 | 29 | ||
1447 | 28 | // Logger is a simple logger interface with logging at levels. | 30 | // Logger is a simple logger interface with logging at levels. |
1448 | @@ -119,3 +121,28 @@ | |||
1449 | 119 | lg.outputFunc(2, fmt.Sprintf("DEBUG "+format, v...)) | 121 | lg.outputFunc(2, fmt.Sprintf("DEBUG "+format, v...)) |
1450 | 120 | } | 122 | } |
1451 | 121 | } | 123 | } |
1452 | 124 | |||
1453 | 125 | // config bits | ||
1454 | 126 | |||
1455 | 127 | // ConfigLogLevel can hold a log level in a configuration struct. | ||
1456 | 128 | type ConfigLogLevel string | ||
1457 | 129 | |||
1458 | 130 | func (cll *ConfigLogLevel) ConfigFromJSONString() {} | ||
1459 | 131 | |||
1460 | 132 | func (cll *ConfigLogLevel) UnmarshalJSON(b []byte) error { | ||
1461 | 133 | return config.UnmarshalJSONViaString(cll, b) | ||
1462 | 134 | } | ||
1463 | 135 | |||
1464 | 136 | func (cll *ConfigLogLevel) SetFromString(enc string) error { | ||
1465 | 137 | _, ok := levelToNLevel[enc] | ||
1466 | 138 | if !ok { | ||
1467 | 139 | return fmt.Errorf("not a log level: %s", enc) | ||
1468 | 140 | } | ||
1469 | 141 | *cll = ConfigLogLevel(enc) | ||
1470 | 142 | return nil | ||
1471 | 143 | } | ||
1472 | 144 | |||
1473 | 145 | // Level returns the log level string held in cll. | ||
1474 | 146 | func (cll ConfigLogLevel) Level() string { | ||
1475 | 147 | return string(cll) | ||
1476 | 148 | } | ||
1477 | 122 | 149 | ||
1478 | === modified file 'logger/logger_test.go' | |||
1479 | --- logger/logger_test.go 2014-02-10 22:51:43 +0000 | |||
1480 | +++ logger/logger_test.go 2014-04-29 18:02:00 +0000 | |||
1481 | @@ -25,6 +25,8 @@ | |||
1482 | 25 | "testing" | 25 | "testing" |
1483 | 26 | 26 | ||
1484 | 27 | . "launchpad.net/gocheck" | 27 | . "launchpad.net/gocheck" |
1485 | 28 | |||
1486 | 29 | "launchpad.net/ubuntu-push/config" | ||
1487 | 28 | ) | 30 | ) |
1488 | 29 | 31 | ||
1489 | 30 | func TestLogger(t *testing.T) { TestingT(t) } | 32 | func TestLogger(t *testing.T) { TestingT(t) } |
1490 | @@ -138,3 +140,26 @@ | |||
1491 | 138 | logger.Output(1, "foobaz") | 140 | logger.Output(1, "foobaz") |
1492 | 139 | c.Check(buf.String(), Matches, "logger_test.go:[0-9]+: foobar\nlogger_test.go:[0-9]+: foobaz\n") | 141 | c.Check(buf.String(), Matches, "logger_test.go:[0-9]+: foobar\nlogger_test.go:[0-9]+: foobaz\n") |
1493 | 140 | } | 142 | } |
1494 | 143 | |||
1495 | 144 | type testLogLevelConfig struct { | ||
1496 | 145 | Lvl ConfigLogLevel | ||
1497 | 146 | } | ||
1498 | 147 | |||
1499 | 148 | func (s *loggerSuite) TestReadConfigLogLevel(c *C) { | ||
1500 | 149 | buf := bytes.NewBufferString(`{"lvl": "debug"}`) | ||
1501 | 150 | var cfg testLogLevelConfig | ||
1502 | 151 | err := config.ReadConfig(buf, &cfg) | ||
1503 | 152 | c.Assert(err, IsNil) | ||
1504 | 153 | c.Check(cfg.Lvl.Level(), Equals, "debug") | ||
1505 | 154 | } | ||
1506 | 155 | |||
1507 | 156 | func (s *loggerSuite) TestReadConfigLogLevelErrors(c *C) { | ||
1508 | 157 | var cfg testLogLevelConfig | ||
1509 | 158 | checkError := func(jsonCfg string, expectedError string) { | ||
1510 | 159 | buf := bytes.NewBufferString(jsonCfg) | ||
1511 | 160 | err := config.ReadConfig(buf, &cfg) | ||
1512 | 161 | c.Check(err, ErrorMatches, expectedError) | ||
1513 | 162 | } | ||
1514 | 163 | checkError(`{"lvl": 1}`, "lvl:.*type string") | ||
1515 | 164 | checkError(`{"lvl": "foo"}`, "lvl: not a log level: foo") | ||
1516 | 165 | } | ||
1517 | 141 | 166 | ||
1518 | === modified file 'protocol/messages.go' | |||
1519 | --- protocol/messages.go 2014-04-04 13:54:45 +0000 | |||
1520 | +++ protocol/messages.go 2014-04-29 18:02:00 +0000 | |||
1521 | @@ -54,6 +54,14 @@ | |||
1522 | 54 | Split() (done bool) | 54 | Split() (done bool) |
1523 | 55 | } | 55 | } |
1524 | 56 | 56 | ||
1525 | 57 | // OnewayMsg are messages that are not to be followed by a response, | ||
1526 | 58 | // after sending them the session either aborts or continues. | ||
1527 | 59 | type OnewayMsg interface { | ||
1528 | 60 | SplittableMsg | ||
1529 | 61 | // continue session after the message? | ||
1530 | 62 | OnewayContinue() bool | ||
1531 | 63 | } | ||
1532 | 64 | |||
1533 | 57 | // CONNBROKEN message, server side is breaking the connection for reason. | 65 | // CONNBROKEN message, server side is breaking the connection for reason. |
1534 | 58 | type ConnBrokenMsg struct { | 66 | type ConnBrokenMsg struct { |
1535 | 59 | Type string `json:"T"` | 67 | Type string `json:"T"` |
1536 | @@ -65,11 +73,35 @@ | |||
1537 | 65 | return true | 73 | return true |
1538 | 66 | } | 74 | } |
1539 | 67 | 75 | ||
1540 | 76 | func (m *ConnBrokenMsg) OnewayContinue() bool { | ||
1541 | 77 | return false | ||
1542 | 78 | } | ||
1543 | 79 | |||
1544 | 68 | // CONNBROKEN reasons | 80 | // CONNBROKEN reasons |
1545 | 69 | const ( | 81 | const ( |
1546 | 70 | BrokenHostMismatch = "host-mismatch" | 82 | BrokenHostMismatch = "host-mismatch" |
1547 | 71 | ) | 83 | ) |
1548 | 72 | 84 | ||
1549 | 85 | // CONNWARN message, server side is warning about partial functionality | ||
1550 | 86 | // because reason. | ||
1551 | 87 | type ConnWarnMsg struct { | ||
1552 | 88 | Type string `json:"T"` | ||
1553 | 89 | // reason | ||
1554 | 90 | Reason string | ||
1555 | 91 | } | ||
1556 | 92 | |||
1557 | 93 | func (m *ConnWarnMsg) Split() bool { | ||
1558 | 94 | return true | ||
1559 | 95 | } | ||
1560 | 96 | func (m *ConnWarnMsg) OnewayContinue() bool { | ||
1561 | 97 | return true | ||
1562 | 98 | } | ||
1563 | 99 | |||
1564 | 100 | // CONNWARN reasons | ||
1565 | 101 | const ( | ||
1566 | 102 | WarnUnauthorized = "unauthorized" | ||
1567 | 103 | ) | ||
1568 | 104 | |||
1569 | 73 | // PING/PONG messages | 105 | // PING/PONG messages |
1570 | 74 | type PingPongMsg struct { | 106 | type PingPongMsg struct { |
1571 | 75 | Type string `json:"T"` | 107 | Type string `json:"T"` |
1572 | @@ -130,6 +162,19 @@ | |||
1573 | 130 | Payload json.RawMessage `json:"P"` | 162 | Payload json.RawMessage `json:"P"` |
1574 | 131 | } | 163 | } |
1575 | 132 | 164 | ||
1576 | 165 | // ExtractPayloads gets only the payloads out of a slice of notications. | ||
1577 | 166 | func ExtractPayloads(notifications []Notification) []json.RawMessage { | ||
1578 | 167 | n := len(notifications) | ||
1579 | 168 | if n == 0 { | ||
1580 | 169 | return nil | ||
1581 | 170 | } | ||
1582 | 171 | payloads := make([]json.RawMessage, n) | ||
1583 | 172 | for i := 0; i < n; i++ { | ||
1584 | 173 | payloads[i] = notifications[i].Payload | ||
1585 | 174 | } | ||
1586 | 175 | return payloads | ||
1587 | 176 | } | ||
1588 | 177 | |||
1589 | 133 | // ACKnowledgement message | 178 | // ACKnowledgement message |
1590 | 134 | type AckMsg struct { | 179 | type AckMsg struct { |
1591 | 135 | Type string `json:"T"` | 180 | Type string `json:"T"` |
1592 | 136 | 181 | ||
1593 | === modified file 'protocol/messages_test.go' | |||
1594 | --- protocol/messages_test.go 2014-04-04 13:19:10 +0000 | |||
1595 | +++ protocol/messages_test.go 2014-04-29 18:02:00 +0000 | |||
1596 | @@ -104,6 +104,22 @@ | |||
1597 | 104 | c.Check(b.splitting, Equals, 0) | 104 | c.Check(b.splitting, Equals, 0) |
1598 | 105 | } | 105 | } |
1599 | 106 | 106 | ||
1602 | 107 | func (s *messagesSuite) TestSplitConnBrokenMsg(c *C) { | 107 | func (s *messagesSuite) TestConnBrokenMsg(c *C) { |
1603 | 108 | c.Check((&ConnBrokenMsg{}).Split(), Equals, true) | 108 | m := &ConnBrokenMsg{} |
1604 | 109 | c.Check(m.Split(), Equals, true) | ||
1605 | 110 | c.Check(m.OnewayContinue(), Equals, false) | ||
1606 | 111 | } | ||
1607 | 112 | |||
1608 | 113 | func (s *messagesSuite) TestConnWarnMsg(c *C) { | ||
1609 | 114 | m := &ConnWarnMsg{} | ||
1610 | 115 | c.Check(m.Split(), Equals, true) | ||
1611 | 116 | c.Check(m.OnewayContinue(), Equals, true) | ||
1612 | 117 | } | ||
1613 | 118 | |||
1614 | 119 | func (s *messagesSuite) TestExtractPayloads(c *C) { | ||
1615 | 120 | c.Check(ExtractPayloads(nil), IsNil) | ||
1616 | 121 | p1 := json.RawMessage(`{"a":1}`) | ||
1617 | 122 | p2 := json.RawMessage(`{"b":2}`) | ||
1618 | 123 | ns := []Notification{Notification{Payload: p1}, Notification{Payload: p2}} | ||
1619 | 124 | c.Check(ExtractPayloads(ns), DeepEquals, []json.RawMessage{p1, p2}) | ||
1620 | 109 | } | 125 | } |
1621 | 110 | 126 | ||
1622 | === modified file 'protocol/state-diag-client.gv' | |||
1623 | --- protocol/state-diag-client.gv 2014-01-16 20:07:13 +0000 | |||
1624 | +++ protocol/state-diag-client.gv 2014-04-29 18:02:00 +0000 | |||
1625 | @@ -2,7 +2,7 @@ | |||
1626 | 2 | label = "State diagram for client"; | 2 | label = "State diagram for client"; |
1627 | 3 | size="12,6"; | 3 | size="12,6"; |
1628 | 4 | rankdir=LR; | 4 | rankdir=LR; |
1630 | 5 | node [shape = doublecircle]; pingTimeout; | 5 | node [shape = doublecircle]; pingTimeout; connBroken; |
1631 | 6 | node [shape = circle]; | 6 | node [shape = circle]; |
1632 | 7 | start1 -> start2 [ label = "Write wire version" ]; | 7 | start1 -> start2 [ label = "Write wire version" ]; |
1633 | 8 | start2 -> start3 [ label = "Write CONNECT" ]; | 8 | start2 -> start3 [ label = "Write CONNECT" ]; |
1634 | @@ -13,4 +13,7 @@ | |||
1635 | 13 | broadcast -> loop [label = "Write ACK"]; | 13 | broadcast -> loop [label = "Write ACK"]; |
1636 | 14 | loop -> pingTimeout [ | 14 | loop -> pingTimeout [ |
1637 | 15 | label = "Elapsed ping interval + exchange interval"]; | 15 | label = "Elapsed ping interval + exchange interval"]; |
1638 | 16 | loop -> connBroken [label = "Read CONNBROKEN"]; | ||
1639 | 17 | loop -> warn [label = "Read CONNWARN"]; | ||
1640 | 18 | warn -> loop; | ||
1641 | 16 | } | 19 | } |
1642 | 17 | 20 | ||
1643 | === modified file 'protocol/state-diag-client.svg' | |||
1644 | --- protocol/state-diag-client.svg 2014-01-16 19:37:57 +0000 | |||
1645 | +++ protocol/state-diag-client.svg 2014-04-29 18:02:00 +0000 | |||
1646 | @@ -4,95 +4,123 @@ | |||
1647 | 4 | <!-- Generated by graphviz version 2.26.3 (20100126.1600) | 4 | <!-- Generated by graphviz version 2.26.3 (20100126.1600) |
1648 | 5 | --> | 5 | --> |
1649 | 6 | <!-- Title: state_diagram_client Pages: 1 --> | 6 | <!-- Title: state_diagram_client Pages: 1 --> |
1653 | 7 | <svg width="864pt" height="279pt" | 7 | <svg width="822pt" height="432pt" |
1654 | 8 | viewBox="0.00 0.00 864.00 278.89" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> | 8 | viewBox="0.00 0.00 822.36 432.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> |
1655 | 9 | <g id="graph1" class="graph" transform="scale(0.683544 0.683544) rotate(0) translate(4 404)"> | 9 | <g id="graph1" class="graph" transform="scale(0.650602 0.650602) rotate(0) translate(4 660)"> |
1656 | 10 | <title>state_diagram_client</title> | 10 | <title>state_diagram_client</title> |
1658 | 11 | <polygon fill="white" stroke="white" points="-4,5 -4,-404 1261,-404 1261,5 -4,5"/> | 11 | <polygon fill="white" stroke="white" points="-4,5 -4,-660 1261,-660 1261,5 -4,5"/> |
1659 | 12 | <text text-anchor="middle" x="628" y="-9.4" font-family="Times Roman,serif" font-size="14.00">State diagram for client</text> | 12 | <text text-anchor="middle" x="628" y="-9.4" font-family="Times Roman,serif" font-size="14.00">State diagram for client</text> |
1660 | 13 | <!-- pingTimeout --> | 13 | <!-- pingTimeout --> |
1661 | 14 | <g id="node1" class="node"><title>pingTimeout</title> | 14 | <g id="node1" class="node"><title>pingTimeout</title> |
1665 | 15 | <ellipse fill="none" stroke="black" cx="1180" cy="-324" rx="72.1249" ry="72.1249"/> | 15 | <ellipse fill="none" stroke="black" cx="1180" cy="-580" rx="72.1249" ry="72.1249"/> |
1666 | 16 | <ellipse fill="none" stroke="black" cx="1180" cy="-324" rx="76.1249" ry="76.1249"/> | 16 | <ellipse fill="none" stroke="black" cx="1180" cy="-580" rx="76.1249" ry="76.1249"/> |
1667 | 17 | <text text-anchor="middle" x="1180" y="-320.4" font-family="Times Roman,serif" font-size="14.00">pingTimeout</text> | 17 | <text text-anchor="middle" x="1180" y="-576.4" font-family="Times Roman,serif" font-size="14.00">pingTimeout</text> |
1668 | 18 | </g> | ||
1669 | 19 | <!-- connBroken --> | ||
1670 | 20 | <g id="node2" class="node"><title>connBroken</title> | ||
1671 | 21 | <ellipse fill="none" stroke="black" cx="1180" cy="-413" rx="68.8251" ry="69.2965"/> | ||
1672 | 22 | <ellipse fill="none" stroke="black" cx="1180" cy="-413" rx="72.7978" ry="73.2965"/> | ||
1673 | 23 | <text text-anchor="middle" x="1180" y="-409.4" font-family="Times Roman,serif" font-size="14.00">connBroken</text> | ||
1674 | 18 | </g> | 24 | </g> |
1675 | 19 | <!-- start1 --> | 25 | <!-- start1 --> |
1679 | 20 | <g id="node2" class="node"><title>start1</title> | 26 | <g id="node3" class="node"><title>start1</title> |
1680 | 21 | <ellipse fill="none" stroke="black" cx="42" cy="-166" rx="41.2167" ry="41.7193"/> | 27 | <ellipse fill="none" stroke="black" cx="42" cy="-231" rx="41.2167" ry="41.7193"/> |
1681 | 22 | <text text-anchor="middle" x="42" y="-162.4" font-family="Times Roman,serif" font-size="14.00">start1</text> | 28 | <text text-anchor="middle" x="42" y="-227.4" font-family="Times Roman,serif" font-size="14.00">start1</text> |
1682 | 23 | </g> | 29 | </g> |
1683 | 24 | <!-- start2 --> | 30 | <!-- start2 --> |
1687 | 25 | <g id="node4" class="node"><title>start2</title> | 31 | <g id="node5" class="node"><title>start2</title> |
1688 | 26 | <ellipse fill="none" stroke="black" cx="292" cy="-166" rx="41.2167" ry="41.7193"/> | 32 | <ellipse fill="none" stroke="black" cx="292" cy="-231" rx="41.2167" ry="41.7193"/> |
1689 | 27 | <text text-anchor="middle" x="292" y="-162.4" font-family="Times Roman,serif" font-size="14.00">start2</text> | 33 | <text text-anchor="middle" x="292" y="-227.4" font-family="Times Roman,serif" font-size="14.00">start2</text> |
1690 | 28 | </g> | 34 | </g> |
1691 | 29 | <!-- start1->start2 --> | 35 | <!-- start1->start2 --> |
1692 | 30 | <g id="edge2" class="edge"><title>start1->start2</title> | 36 | <g id="edge2" class="edge"><title>start1->start2</title> |
1696 | 31 | <path fill="none" stroke="black" d="M83.5631,-166C126.547,-166 193.757,-166 240.181,-166"/> | 37 | <path fill="none" stroke="black" d="M83.5631,-231C126.547,-231 193.757,-231 240.181,-231"/> |
1697 | 32 | <polygon fill="black" stroke="black" points="240.338,-169.5 250.338,-166 240.338,-162.5 240.338,-169.5"/> | 38 | <polygon fill="black" stroke="black" points="240.338,-234.5 250.338,-231 240.338,-227.5 240.338,-234.5"/> |
1698 | 33 | <text text-anchor="middle" x="167" y="-171.4" font-family="Times Roman,serif" font-size="14.00">Write wire version</text> | 39 | <text text-anchor="middle" x="167" y="-236.4" font-family="Times Roman,serif" font-size="14.00">Write wire version</text> |
1699 | 34 | </g> | 40 | </g> |
1700 | 35 | <!-- start3 --> | 41 | <!-- start3 --> |
1704 | 36 | <g id="node6" class="node"><title>start3</title> | 42 | <g id="node7" class="node"><title>start3</title> |
1705 | 37 | <ellipse fill="none" stroke="black" cx="526" cy="-166" rx="41.2167" ry="41.7193"/> | 43 | <ellipse fill="none" stroke="black" cx="526" cy="-231" rx="41.2167" ry="41.7193"/> |
1706 | 38 | <text text-anchor="middle" x="526" y="-162.4" font-family="Times Roman,serif" font-size="14.00">start3</text> | 44 | <text text-anchor="middle" x="526" y="-227.4" font-family="Times Roman,serif" font-size="14.00">start3</text> |
1707 | 39 | </g> | 45 | </g> |
1708 | 40 | <!-- start2->start3 --> | 46 | <!-- start2->start3 --> |
1709 | 41 | <g id="edge4" class="edge"><title>start2->start3</title> | 47 | <g id="edge4" class="edge"><title>start2->start3</title> |
1713 | 42 | <path fill="none" stroke="black" d="M333.565,-166C372.875,-166 431.992,-166 474.321,-166"/> | 48 | <path fill="none" stroke="black" d="M333.565,-231C372.875,-231 431.992,-231 474.321,-231"/> |
1714 | 43 | <polygon fill="black" stroke="black" points="474.429,-169.5 484.429,-166 474.429,-162.5 474.429,-169.5"/> | 49 | <polygon fill="black" stroke="black" points="474.429,-234.5 484.429,-231 474.429,-227.5 474.429,-234.5"/> |
1715 | 44 | <text text-anchor="middle" x="409" y="-171.4" font-family="Times Roman,serif" font-size="14.00">Write CONNECT</text> | 50 | <text text-anchor="middle" x="409" y="-236.4" font-family="Times Roman,serif" font-size="14.00">Write CONNECT</text> |
1716 | 45 | </g> | 51 | </g> |
1717 | 46 | <!-- loop --> | 52 | <!-- loop --> |
1721 | 47 | <g id="node8" class="node"><title>loop</title> | 53 | <g id="node9" class="node"><title>loop</title> |
1722 | 48 | <ellipse fill="none" stroke="black" cx="746" cy="-166" rx="31.8198" ry="31.8198"/> | 54 | <ellipse fill="none" stroke="black" cx="746" cy="-231" rx="31.8198" ry="31.8198"/> |
1723 | 49 | <text text-anchor="middle" x="746" y="-162.4" font-family="Times Roman,serif" font-size="14.00">loop</text> | 55 | <text text-anchor="middle" x="746" y="-227.4" font-family="Times Roman,serif" font-size="14.00">loop</text> |
1724 | 50 | </g> | 56 | </g> |
1725 | 51 | <!-- start3->loop --> | 57 | <!-- start3->loop --> |
1726 | 52 | <g id="edge6" class="edge"><title>start3->loop</title> | 58 | <g id="edge6" class="edge"><title>start3->loop</title> |
1730 | 53 | <path fill="none" stroke="black" d="M567.639,-166C606.633,-166 664.616,-166 703.793,-166"/> | 59 | <path fill="none" stroke="black" d="M567.639,-231C606.633,-231 664.616,-231 703.793,-231"/> |
1731 | 54 | <polygon fill="black" stroke="black" points="703.818,-169.5 713.818,-166 703.818,-162.5 703.818,-169.5"/> | 60 | <polygon fill="black" stroke="black" points="703.818,-234.5 713.818,-231 703.818,-227.5 703.818,-234.5"/> |
1732 | 55 | <text text-anchor="middle" x="641" y="-171.4" font-family="Times Roman,serif" font-size="14.00">Read CONNACK</text> | 61 | <text text-anchor="middle" x="641" y="-236.4" font-family="Times Roman,serif" font-size="14.00">Read CONNACK</text> |
1733 | 56 | </g> | 62 | </g> |
1734 | 57 | <!-- loop->pingTimeout --> | 63 | <!-- loop->pingTimeout --> |
1735 | 58 | <g id="edge16" class="edge"><title>loop->pingTimeout</title> | 64 | <g id="edge16" class="edge"><title>loop->pingTimeout</title> |
1739 | 59 | <path fill="none" stroke="black" d="M763.666,-192.937C772.211,-204.042 783.361,-216.128 796,-224 888.06,-281.339 1012.12,-305.973 1094,-316.443"/> | 65 | <path fill="none" stroke="black" d="M750.211,-262.971C757.458,-313.528 773.689,-408.79 796,-434 872.806,-520.784 1006.81,-556.22 1094.46,-570.528"/> |
1740 | 60 | <polygon fill="black" stroke="black" points="1093.67,-319.928 1104.02,-317.68 1094.53,-312.981 1093.67,-319.928"/> | 66 | <polygon fill="black" stroke="black" points="1093.96,-573.992 1104.39,-572.09 1095.05,-567.078 1093.96,-573.992"/> |
1741 | 61 | <text text-anchor="middle" x="941" y="-319.4" font-family="Times Roman,serif" font-size="14.00">Elapsed ping interval + exchange interval</text> | 67 | <text text-anchor="middle" x="941" y="-572.4" font-family="Times Roman,serif" font-size="14.00">Elapsed ping interval + exchange interval</text> |
1742 | 68 | </g> | ||
1743 | 69 | <!-- loop->connBroken --> | ||
1744 | 70 | <g id="edge18" class="edge"><title>loop->connBroken</title> | ||
1745 | 71 | <path fill="none" stroke="black" d="M755.1,-261.824C762.755,-282.438 775.756,-308.526 796,-324 883.382,-390.791 1012.39,-408.797 1096.33,-412.948"/> | ||
1746 | 72 | <polygon fill="black" stroke="black" points="1096.19,-416.445 1106.33,-413.388 1096.5,-409.452 1096.19,-416.445"/> | ||
1747 | 73 | <text text-anchor="middle" x="941" y="-417.4" font-family="Times Roman,serif" font-size="14.00">Read CONNBROKEN</text> | ||
1748 | 62 | </g> | 74 | </g> |
1749 | 63 | <!-- pong --> | 75 | <!-- pong --> |
1753 | 64 | <g id="node10" class="node"><title>pong</title> | 76 | <g id="node11" class="node"><title>pong</title> |
1754 | 65 | <ellipse fill="none" stroke="black" cx="1180" cy="-195" rx="34.8574" ry="35.3553"/> | 77 | <ellipse fill="none" stroke="black" cx="1180" cy="-287" rx="34.8574" ry="35.3553"/> |
1755 | 66 | <text text-anchor="middle" x="1180" y="-191.4" font-family="Times Roman,serif" font-size="14.00">pong</text> | 78 | <text text-anchor="middle" x="1180" y="-283.4" font-family="Times Roman,serif" font-size="14.00">pong</text> |
1756 | 67 | </g> | 79 | </g> |
1757 | 68 | <!-- loop->pong --> | 80 | <!-- loop->pong --> |
1758 | 69 | <g id="edge8" class="edge"><title>loop->pong</title> | 81 | <g id="edge8" class="edge"><title>loop->pong</title> |
1762 | 70 | <path fill="none" stroke="black" d="M775.392,-179.044C782.046,-181.465 789.167,-183.653 796,-185 916.362,-208.722 1062.02,-203.515 1134.48,-198.706"/> | 82 | <path fill="none" stroke="black" d="M768.467,-253.959C776.476,-260.698 786.005,-267.259 796,-271 911.696,-314.31 1060.9,-303.343 1134.62,-293.955"/> |
1763 | 71 | <polygon fill="black" stroke="black" points="1134.89,-202.186 1144.62,-198.003 1134.4,-195.203 1134.89,-202.186"/> | 83 | <polygon fill="black" stroke="black" points="1135.49,-297.371 1144.94,-292.588 1134.57,-290.432 1135.49,-297.371"/> |
1764 | 72 | <text text-anchor="middle" x="941" y="-207.4" font-family="Times Roman,serif" font-size="14.00">Read PING</text> | 84 | <text text-anchor="middle" x="941" y="-307.4" font-family="Times Roman,serif" font-size="14.00">Read PING</text> |
1765 | 73 | </g> | 85 | </g> |
1766 | 74 | <!-- broadcast --> | 86 | <!-- broadcast --> |
1770 | 75 | <g id="node12" class="node"><title>broadcast</title> | 87 | <g id="node13" class="node"><title>broadcast</title> |
1771 | 76 | <ellipse fill="none" stroke="black" cx="1180" cy="-84" rx="58.1882" ry="58.6899"/> | 88 | <ellipse fill="none" stroke="black" cx="1180" cy="-176" rx="58.1882" ry="58.6899"/> |
1772 | 77 | <text text-anchor="middle" x="1180" y="-80.4" font-family="Times Roman,serif" font-size="14.00">broadcast</text> | 89 | <text text-anchor="middle" x="1180" y="-172.4" font-family="Times Roman,serif" font-size="14.00">broadcast</text> |
1773 | 78 | </g> | 90 | </g> |
1774 | 79 | <!-- loop->broadcast --> | 91 | <!-- loop->broadcast --> |
1775 | 80 | <g id="edge10" class="edge"><title>loop->broadcast</title> | 92 | <g id="edge10" class="edge"><title>loop->broadcast</title> |
1779 | 81 | <path fill="none" stroke="black" d="M770.52,-145.1C778.217,-139.607 787.053,-134.301 796,-131 917.482,-86.1746 957.924,-122.075 1086,-103 1094.61,-101.717 1103.63,-100.165 1112.53,-98.5074"/> | 93 | <path fill="none" stroke="black" d="M775.45,-218.228C782.1,-215.791 789.205,-213.528 796,-212 922.145,-183.64 957.464,-202.973 1086,-189 1094.36,-188.091 1103.12,-187.028 1111.79,-185.909"/> |
1780 | 82 | <polygon fill="black" stroke="black" points="1113.34,-101.917 1122.5,-96.5998 1112.02,-95.0419 1113.34,-101.917"/> | 94 | <polygon fill="black" stroke="black" points="1112.44,-189.353 1121.9,-184.574 1111.53,-182.413 1112.44,-189.353"/> |
1781 | 83 | <text text-anchor="middle" x="941" y="-136.4" font-family="Times Roman,serif" font-size="14.00">Read BROADCAST</text> | 95 | <text text-anchor="middle" x="941" y="-217.4" font-family="Times Roman,serif" font-size="14.00">Read BROADCAST</text> |
1782 | 96 | </g> | ||
1783 | 97 | <!-- warn --> | ||
1784 | 98 | <g id="node19" class="node"><title>warn</title> | ||
1785 | 99 | <ellipse fill="none" stroke="black" cx="1180" cy="-63" rx="36.7696" ry="36.7696"/> | ||
1786 | 100 | <text text-anchor="middle" x="1180" y="-59.4" font-family="Times Roman,serif" font-size="14.00">warn</text> | ||
1787 | 101 | </g> | ||
1788 | 102 | <!-- loop->warn --> | ||
1789 | 103 | <g id="edge20" class="edge"><title>loop->warn</title> | ||
1790 | 104 | <path fill="none" stroke="black" d="M753.357,-199.767C760.401,-177.027 773.396,-147.441 796,-131 901.425,-54.3166 958.242,-112.935 1086,-87 1101.84,-83.7841 1119.02,-79.6061 1134.3,-75.6396"/> | ||
1791 | 105 | <polygon fill="black" stroke="black" points="1135.26,-79.0068 1144.04,-73.0757 1133.48,-72.2376 1135.26,-79.0068"/> | ||
1792 | 106 | <text text-anchor="middle" x="941" y="-136.4" font-family="Times Roman,serif" font-size="14.00">Read CONNWARN</text> | ||
1793 | 84 | </g> | 107 | </g> |
1794 | 85 | <!-- pong->loop --> | 108 | <!-- pong->loop --> |
1795 | 86 | <g id="edge12" class="edge"><title>pong->loop</title> | 109 | <g id="edge12" class="edge"><title>pong->loop</title> |
1799 | 87 | <path fill="none" stroke="black" d="M1147.19,-180.867C1129.44,-173.986 1106.92,-166.463 1086,-163 980.081,-145.465 853.051,-154.36 788.368,-160.981"/> | 110 | <path fill="none" stroke="black" d="M1148.22,-271.079C1130.39,-262.942 1107.48,-253.77 1086,-249 1030.54,-236.684 866.695,-232.715 788.482,-231.502"/> |
1800 | 88 | <polygon fill="black" stroke="black" points="787.736,-157.528 778.16,-162.06 788.472,-164.489 787.736,-157.528"/> | 111 | <polygon fill="black" stroke="black" points="788.085,-227.996 778.035,-231.348 787.982,-234.995 788.085,-227.996"/> |
1801 | 89 | <text text-anchor="middle" x="941" y="-168.4" font-family="Times Roman,serif" font-size="14.00">Write PONG</text> | 112 | <text text-anchor="middle" x="941" y="-254.4" font-family="Times Roman,serif" font-size="14.00">Write PONG</text> |
1802 | 90 | </g> | 113 | </g> |
1803 | 91 | <!-- broadcast->loop --> | 114 | <!-- broadcast->loop --> |
1804 | 92 | <g id="edge14" class="edge"><title>broadcast->loop</title> | 115 | <g id="edge14" class="edge"><title>broadcast->loop</title> |
1808 | 93 | <path fill="none" stroke="black" d="M1123.8,-67.0114C1044.83,-46.6166 899.156,-22.0001 796,-81 778.946,-90.7538 767.135,-108.842 759.293,-125.833"/> | 116 | <path fill="none" stroke="black" d="M1121.7,-168.205C1028.72,-156.837 851.665,-139.849 796,-167 784,-172.853 774.037,-183.132 766.245,-193.762"/> |
1809 | 94 | <polygon fill="black" stroke="black" points="756.044,-124.528 755.336,-135.099 762.482,-127.277 756.044,-124.528"/> | 117 | <polygon fill="black" stroke="black" points="763.182,-192.043 760.465,-202.284 768.975,-195.973 763.182,-192.043"/> |
1810 | 95 | <text text-anchor="middle" x="941" y="-86.4" font-family="Times Roman,serif" font-size="14.00">Write ACK</text> | 118 | <text text-anchor="middle" x="941" y="-172.4" font-family="Times Roman,serif" font-size="14.00">Write ACK</text> |
1811 | 119 | </g> | ||
1812 | 120 | <!-- warn->loop --> | ||
1813 | 121 | <g id="edge22" class="edge"><title>warn->loop</title> | ||
1814 | 122 | <path fill="none" stroke="black" d="M1144.07,-53.3553C1070.4,-35.8873 900.397,-7.71825 796,-87 779.313,-99.6722 764.14,-151.763 754.991,-189.659"/> | ||
1815 | 123 | <polygon fill="black" stroke="black" points="751.574,-188.904 752.686,-199.44 758.387,-190.51 751.574,-188.904"/> | ||
1816 | 96 | </g> | 124 | </g> |
1817 | 97 | </g> | 125 | </g> |
1818 | 98 | </svg> | 126 | </svg> |
1819 | 99 | 127 | ||
1820 | === modified file 'protocol/state-diag-session.gv' | |||
1821 | --- protocol/state-diag-session.gv 2014-01-16 20:07:13 +0000 | |||
1822 | +++ protocol/state-diag-session.gv 2014-04-29 18:02:00 +0000 | |||
1823 | @@ -2,6 +2,7 @@ | |||
1824 | 2 | label = "State diagram for session"; | 2 | label = "State diagram for session"; |
1825 | 3 | size="12,6"; | 3 | size="12,6"; |
1826 | 4 | rankdir=LR; | 4 | rankdir=LR; |
1827 | 5 | node [shape = doublecircle]; stop; | ||
1828 | 5 | node [shape = circle]; | 6 | node [shape = circle]; |
1829 | 6 | start1 -> start2 [ label = "Read wire version" ]; | 7 | start1 -> start2 [ label = "Read wire version" ]; |
1830 | 7 | start2 -> start3 [ label = "Read CONNECT" ]; | 8 | start2 -> start3 [ label = "Read CONNECT" ]; |
1831 | @@ -17,4 +18,13 @@ | |||
1832 | 17 | split_broadcast -> split_ack_wait [label = "Write split BROADCAST"]; | 18 | split_broadcast -> split_ack_wait [label = "Write split BROADCAST"]; |
1833 | 18 | split_ack_wait -> split_broadcast [label = "Read ACK"]; | 19 | split_ack_wait -> split_broadcast [label = "Read ACK"]; |
1834 | 19 | split_broadcast -> loop [label = "All split msgs written"]; | 20 | split_broadcast -> loop [label = "All split msgs written"]; |
1835 | 21 | // other | ||
1836 | 22 | loop -> conn_broken [label = "Receive connbroken request"]; | ||
1837 | 23 | loop -> conn_warn [label = "Receive connwarn request"]; | ||
1838 | 24 | conn_broken -> stop [label = "Write CONNBROKEN"]; | ||
1839 | 25 | conn_warn -> loop [label = "Write CONNWARN"]; | ||
1840 | 26 | // timeouts | ||
1841 | 27 | ack_wait -> stop [label = "Elapsed exhange timeout"]; | ||
1842 | 28 | split_ack_wait -> stop [label = "Elapsed exhange timeout"]; | ||
1843 | 29 | pong_wait -> stop [label = "Elapsed exhange timeout"]; | ||
1844 | 20 | } | 30 | } |
1845 | 21 | 31 | ||
1846 | === modified file 'protocol/state-diag-session.svg' | |||
1847 | --- protocol/state-diag-session.svg 2014-01-16 19:37:57 +0000 | |||
1848 | +++ protocol/state-diag-session.svg 2014-04-29 18:02:00 +0000 | |||
1849 | @@ -4,139 +4,197 @@ | |||
1850 | 4 | <!-- Generated by graphviz version 2.26.3 (20100126.1600) | 4 | <!-- Generated by graphviz version 2.26.3 (20100126.1600) |
1851 | 5 | --> | 5 | --> |
1852 | 6 | <!-- Title: state_diagram_session Pages: 1 --> | 6 | <!-- Title: state_diagram_session Pages: 1 --> |
1856 | 7 | <svg width="864pt" height="208pt" | 7 | <svg width="864pt" height="266pt" |
1857 | 8 | viewBox="0.00 0.00 864.00 207.94" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> | 8 | viewBox="0.00 0.00 864.00 265.73" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> |
1858 | 9 | <g id="graph1" class="graph" transform="scale(0.435923 0.435923) rotate(0) translate(4 473)"> | 9 | <g id="graph1" class="graph" transform="scale(0.367035 0.367035) rotate(0) translate(4 720)"> |
1859 | 10 | <title>state_diagram_session</title> | 10 | <title>state_diagram_session</title> |
1862 | 11 | <polygon fill="white" stroke="white" points="-4,5 -4,-473 1979,-473 1979,5 -4,5"/> | 11 | <polygon fill="white" stroke="white" points="-4,5 -4,-720 2351,-720 2351,5 -4,5"/> |
1863 | 12 | <text text-anchor="middle" x="987" y="-9.4" font-family="Times Roman,serif" font-size="14.00">State diagram for session</text> | 12 | <text text-anchor="middle" x="1173" y="-9.4" font-family="Times Roman,serif" font-size="14.00">State diagram for session</text> |
1864 | 13 | <!-- stop --> | ||
1865 | 14 | <g id="node1" class="node"><title>stop</title> | ||
1866 | 15 | <ellipse fill="none" stroke="black" cx="2309" cy="-335" rx="32.0813" ry="32.5269"/> | ||
1867 | 16 | <ellipse fill="none" stroke="black" cx="2309" cy="-335" rx="36.0265" ry="36.5269"/> | ||
1868 | 17 | <text text-anchor="middle" x="2309" y="-331.4" font-family="Times Roman,serif" font-size="14.00">stop</text> | ||
1869 | 18 | </g> | ||
1870 | 13 | <!-- start1 --> | 19 | <!-- start1 --> |
1874 | 14 | <g id="node1" class="node"><title>start1</title> | 20 | <g id="node2" class="node"><title>start1</title> |
1875 | 15 | <ellipse fill="none" stroke="black" cx="42" cy="-294" rx="41.2167" ry="41.7193"/> | 21 | <ellipse fill="none" stroke="black" cx="42" cy="-395" rx="41.2167" ry="41.7193"/> |
1876 | 16 | <text text-anchor="middle" x="42" y="-290.4" font-family="Times Roman,serif" font-size="14.00">start1</text> | 22 | <text text-anchor="middle" x="42" y="-391.4" font-family="Times Roman,serif" font-size="14.00">start1</text> |
1877 | 17 | </g> | 23 | </g> |
1878 | 18 | <!-- start2 --> | 24 | <!-- start2 --> |
1882 | 19 | <g id="node3" class="node"><title>start2</title> | 25 | <g id="node4" class="node"><title>start2</title> |
1883 | 20 | <ellipse fill="none" stroke="black" cx="286" cy="-294" rx="41.2167" ry="41.7193"/> | 26 | <ellipse fill="none" stroke="black" cx="286" cy="-395" rx="41.2167" ry="41.7193"/> |
1884 | 21 | <text text-anchor="middle" x="286" y="-290.4" font-family="Times Roman,serif" font-size="14.00">start2</text> | 27 | <text text-anchor="middle" x="286" y="-391.4" font-family="Times Roman,serif" font-size="14.00">start2</text> |
1885 | 22 | </g> | 28 | </g> |
1886 | 23 | <!-- start1->start2 --> | 29 | <!-- start1->start2 --> |
1887 | 24 | <g id="edge2" class="edge"><title>start1->start2</title> | 30 | <g id="edge2" class="edge"><title>start1->start2</title> |
1891 | 25 | <path fill="none" stroke="black" d="M83.6679,-294C125.213,-294 189.13,-294 233.981,-294"/> | 31 | <path fill="none" stroke="black" d="M83.6679,-395C125.213,-395 189.13,-395 233.981,-395"/> |
1892 | 26 | <polygon fill="black" stroke="black" points="234.096,-297.5 244.096,-294 234.096,-290.5 234.096,-297.5"/> | 32 | <polygon fill="black" stroke="black" points="234.096,-398.5 244.096,-395 234.096,-391.5 234.096,-398.5"/> |
1893 | 27 | <text text-anchor="middle" x="164" y="-299.4" font-family="Times Roman,serif" font-size="14.00">Read wire version</text> | 33 | <text text-anchor="middle" x="164" y="-400.4" font-family="Times Roman,serif" font-size="14.00">Read wire version</text> |
1894 | 28 | </g> | 34 | </g> |
1895 | 29 | <!-- start3 --> | 35 | <!-- start3 --> |
1899 | 30 | <g id="node5" class="node"><title>start3</title> | 36 | <g id="node6" class="node"><title>start3</title> |
1900 | 31 | <ellipse fill="none" stroke="black" cx="516" cy="-294" rx="41.2167" ry="41.7193"/> | 37 | <ellipse fill="none" stroke="black" cx="537" cy="-395" rx="41.2167" ry="41.7193"/> |
1901 | 32 | <text text-anchor="middle" x="516" y="-290.4" font-family="Times Roman,serif" font-size="14.00">start3</text> | 38 | <text text-anchor="middle" x="537" y="-391.4" font-family="Times Roman,serif" font-size="14.00">start3</text> |
1902 | 33 | </g> | 39 | </g> |
1903 | 34 | <!-- start2->start3 --> | 40 | <!-- start2->start3 --> |
1904 | 35 | <g id="edge4" class="edge"><title>start2->start3</title> | 41 | <g id="edge4" class="edge"><title>start2->start3</title> |
1908 | 36 | <path fill="none" stroke="black" d="M327.651,-294C365.959,-294 422.903,-294 464.145,-294"/> | 42 | <path fill="none" stroke="black" d="M327.729,-395C370.886,-395 438.364,-395 484.973,-395"/> |
1909 | 37 | <polygon fill="black" stroke="black" points="464.271,-297.5 474.271,-294 464.271,-290.5 464.271,-297.5"/> | 43 | <polygon fill="black" stroke="black" points="485.171,-398.5 495.171,-395 485.171,-391.5 485.171,-398.5"/> |
1910 | 38 | <text text-anchor="middle" x="401" y="-299.4" font-family="Times Roman,serif" font-size="14.00">Read CONNECT</text> | 44 | <text text-anchor="middle" x="401" y="-400.4" font-family="Times Roman,serif" font-size="14.00">Read CONNECT</text> |
1911 | 39 | </g> | 45 | </g> |
1912 | 40 | <!-- loop --> | 46 | <!-- loop --> |
1916 | 41 | <g id="node7" class="node"><title>loop</title> | 47 | <g id="node8" class="node"><title>loop</title> |
1917 | 42 | <ellipse fill="none" stroke="black" cx="740" cy="-294" rx="31.8198" ry="31.8198"/> | 48 | <ellipse fill="none" stroke="black" cx="790" cy="-395" rx="31.8198" ry="31.8198"/> |
1918 | 43 | <text text-anchor="middle" x="740" y="-290.4" font-family="Times Roman,serif" font-size="14.00">loop</text> | 49 | <text text-anchor="middle" x="790" y="-391.4" font-family="Times Roman,serif" font-size="14.00">loop</text> |
1919 | 44 | </g> | 50 | </g> |
1920 | 45 | <!-- start3->loop --> | 51 | <!-- start3->loop --> |
1921 | 46 | <g id="edge6" class="edge"><title>start3->loop</title> | 52 | <g id="edge6" class="edge"><title>start3->loop</title> |
1925 | 47 | <path fill="none" stroke="black" d="M557.608,-294C597.53,-294 657.517,-294 697.677,-294"/> | 53 | <path fill="none" stroke="black" d="M578.778,-395C625.49,-395 700.728,-395 747.665,-395"/> |
1926 | 48 | <polygon fill="black" stroke="black" points="697.687,-297.5 707.687,-294 697.687,-290.5 697.687,-297.5"/> | 54 | <polygon fill="black" stroke="black" points="747.805,-398.5 757.805,-395 747.805,-391.5 747.805,-398.5"/> |
1927 | 49 | <text text-anchor="middle" x="633" y="-299.4" font-family="Times Roman,serif" font-size="14.00">Write CONNACK</text> | 55 | <text text-anchor="middle" x="675" y="-400.4" font-family="Times Roman,serif" font-size="14.00">Write CONNACK</text> |
1928 | 50 | </g> | 56 | </g> |
1929 | 51 | <!-- ping --> | 57 | <!-- ping --> |
1933 | 52 | <g id="node9" class="node"><title>ping</title> | 58 | <g id="node10" class="node"><title>ping</title> |
1934 | 53 | <ellipse fill="none" stroke="black" cx="1063" cy="-416" rx="32.0265" ry="32.5269"/> | 59 | <ellipse fill="none" stroke="black" cx="1135" cy="-593" rx="32.0265" ry="32.5269"/> |
1935 | 54 | <text text-anchor="middle" x="1063" y="-412.4" font-family="Times Roman,serif" font-size="14.00">ping</text> | 60 | <text text-anchor="middle" x="1135" y="-589.4" font-family="Times Roman,serif" font-size="14.00">ping</text> |
1936 | 55 | </g> | 61 | </g> |
1937 | 56 | <!-- loop->ping --> | 62 | <!-- loop->ping --> |
1938 | 57 | <g id="edge8" class="edge"><title>loop->ping</title> | 63 | <g id="edge8" class="edge"><title>loop->ping</title> |
1942 | 58 | <path fill="none" stroke="black" d="M754.564,-322.853C763.046,-336.78 775.035,-352.491 790,-362 861.597,-407.491 963.396,-415.983 1020.29,-416.829"/> | 64 | <path fill="none" stroke="black" d="M800.39,-425.317C809.609,-448.006 825.187,-478.237 848,-497 920.691,-556.785 1032.18,-579.907 1092.58,-588.403"/> |
1943 | 59 | <polygon fill="black" stroke="black" points="1020.35,-420.33 1030.38,-416.906 1020.4,-413.33 1020.35,-420.33"/> | 65 | <polygon fill="black" stroke="black" points="1092.15,-591.877 1102.53,-589.734 1093.08,-584.939 1092.15,-591.877"/> |
1944 | 60 | <text text-anchor="middle" x="881" y="-418.4" font-family="Times Roman,serif" font-size="14.00">Elapsed ping interval</text> | 66 | <text text-anchor="middle" x="946" y="-583.4" font-family="Times Roman,serif" font-size="14.00">Elapsed ping interval</text> |
1945 | 61 | </g> | 67 | </g> |
1946 | 62 | <!-- broadcast --> | 68 | <!-- broadcast --> |
1950 | 63 | <g id="node11" class="node"><title>broadcast</title> | 69 | <g id="node12" class="node"><title>broadcast</title> |
1951 | 64 | <ellipse fill="none" stroke="black" cx="1063" cy="-200" rx="58.1882" ry="58.6899"/> | 70 | <ellipse fill="none" stroke="black" cx="1135" cy="-281" rx="58.1882" ry="58.6899"/> |
1952 | 65 | <text text-anchor="middle" x="1063" y="-196.4" font-family="Times Roman,serif" font-size="14.00">broadcast</text> | 71 | <text text-anchor="middle" x="1135" y="-277.4" font-family="Times Roman,serif" font-size="14.00">broadcast</text> |
1953 | 66 | </g> | 72 | </g> |
1954 | 67 | <!-- loop->broadcast --> | 73 | <!-- loop->broadcast --> |
1955 | 68 | <g id="edge10" class="edge"><title>loop->broadcast</title> | 74 | <g id="edge10" class="edge"><title>loop->broadcast</title> |
1959 | 69 | <path fill="none" stroke="black" d="M766.046,-274.934C773.498,-270.155 781.824,-265.421 790,-262 856.828,-234.035 938.382,-217.617 994.86,-208.779"/> | 75 | <path fill="none" stroke="black" d="M811.332,-370.953C821.492,-360.892 834.388,-349.946 848,-343 917.32,-307.628 1006.03,-292.395 1066.35,-285.86"/> |
1960 | 70 | <polygon fill="black" stroke="black" points="995.396,-212.238 1004.75,-207.269 994.34,-205.318 995.396,-212.238"/> | 76 | <polygon fill="black" stroke="black" points="1066.94,-289.319 1076.53,-284.811 1066.22,-282.355 1066.94,-289.319"/> |
1961 | 71 | <text text-anchor="middle" x="881" y="-267.4" font-family="Times Roman,serif" font-size="14.00">Receive broadcast request</text> | 77 | <text text-anchor="middle" x="946" y="-348.4" font-family="Times Roman,serif" font-size="14.00">Receive broadcast request</text> |
1962 | 78 | </g> | ||
1963 | 79 | <!-- conn_broken --> | ||
1964 | 80 | <g id="node26" class="node"><title>conn_broken</title> | ||
1965 | 81 | <ellipse fill="none" stroke="black" cx="1361" cy="-99" rx="73.0388" ry="73.5391"/> | ||
1966 | 82 | <text text-anchor="middle" x="1361" y="-95.4" font-family="Times Roman,serif" font-size="14.00">conn_broken</text> | ||
1967 | 83 | </g> | ||
1968 | 84 | <!-- loop->conn_broken --> | ||
1969 | 85 | <g id="edge28" class="edge"><title>loop->conn_broken</title> | ||
1970 | 86 | <path fill="none" stroke="black" d="M793.216,-363.054C799.833,-304.219 817.014,-182.243 848,-155 967.196,-50.2026 1167.08,-63.6291 1278.91,-81.8408"/> | ||
1971 | 87 | <polygon fill="black" stroke="black" points="1278.34,-85.2954 1288.79,-83.4998 1279.5,-78.392 1278.34,-85.2954"/> | ||
1972 | 88 | <text text-anchor="middle" x="946" y="-160.4" font-family="Times Roman,serif" font-size="14.00">Receive connbroken request</text> | ||
1973 | 89 | </g> | ||
1974 | 90 | <!-- conn_warn --> | ||
1975 | 91 | <g id="node28" class="node"><title>conn_warn</title> | ||
1976 | 92 | <ellipse fill="none" stroke="black" cx="1135" cy="-477" rx="65.7609" ry="65.7609"/> | ||
1977 | 93 | <text text-anchor="middle" x="1135" y="-473.4" font-family="Times Roman,serif" font-size="14.00">conn_warn</text> | ||
1978 | 94 | </g> | ||
1979 | 95 | <!-- loop->conn_warn --> | ||
1980 | 96 | <g id="edge30" class="edge"><title>loop->conn_warn</title> | ||
1981 | 97 | <path fill="none" stroke="black" d="M814.092,-416.512C823.957,-424.185 835.89,-432.126 848,-437 915.942,-464.343 999.421,-473.523 1058.8,-476.355"/> | ||
1982 | 98 | <polygon fill="black" stroke="black" points="1058.71,-479.855 1068.85,-476.786 1059.01,-472.861 1058.71,-479.855"/> | ||
1983 | 99 | <text text-anchor="middle" x="946" y="-480.4" font-family="Times Roman,serif" font-size="14.00">Receive connwarn request</text> | ||
1984 | 72 | </g> | 100 | </g> |
1985 | 73 | <!-- pong_wait --> | 101 | <!-- pong_wait --> |
1989 | 74 | <g id="node13" class="node"><title>pong_wait</title> | 102 | <g id="node14" class="node"><title>pong_wait</title> |
1990 | 75 | <ellipse fill="none" stroke="black" cx="1526" cy="-406" rx="62.9325" ry="62.9325"/> | 103 | <ellipse fill="none" stroke="black" cx="537" cy="-653" rx="62.9325" ry="62.9325"/> |
1991 | 76 | <text text-anchor="middle" x="1526" y="-402.4" font-family="Times Roman,serif" font-size="14.00">pong_wait</text> | 104 | <text text-anchor="middle" x="537" y="-649.4" font-family="Times Roman,serif" font-size="14.00">pong_wait</text> |
1992 | 77 | </g> | 105 | </g> |
1993 | 78 | <!-- ping->pong_wait --> | 106 | <!-- ping->pong_wait --> |
1994 | 79 | <g id="edge12" class="edge"><title>ping->pong_wait</title> | 107 | <g id="edge12" class="edge"><title>ping->pong_wait</title> |
1998 | 80 | <path fill="none" stroke="black" d="M1095.56,-415.297C1169.19,-413.707 1350.04,-409.8 1452.36,-407.591"/> | 108 | <path fill="none" stroke="black" d="M1103.4,-600.831C1035.81,-617.134 871.913,-654.261 732,-667 681.542,-671.594 668.481,-671.33 618,-667 615.134,-666.754 612.217,-666.46 609.275,-666.127"/> |
1999 | 81 | <polygon fill="black" stroke="black" points="1452.69,-411.084 1462.61,-407.369 1452.54,-404.086 1452.69,-411.084"/> | 109 | <polygon fill="black" stroke="black" points="609.573,-662.637 599.214,-664.858 608.697,-669.582 609.573,-662.637"/> |
2000 | 82 | <text text-anchor="middle" x="1289" y="-418.4" font-family="Times Roman,serif" font-size="14.00">Write PING</text> | 110 | <text text-anchor="middle" x="790" y="-670.4" font-family="Times Roman,serif" font-size="14.00">Write PING</text> |
2001 | 83 | </g> | 111 | </g> |
2002 | 84 | <!-- ack_wait --> | 112 | <!-- ack_wait --> |
2006 | 85 | <g id="node15" class="node"><title>ack_wait</title> | 113 | <g id="node16" class="node"><title>ack_wait</title> |
2007 | 86 | <ellipse fill="none" stroke="black" cx="1526" cy="-269" rx="55.1543" ry="55.1543"/> | 114 | <ellipse fill="none" stroke="black" cx="1598" cy="-373" rx="55.1543" ry="55.1543"/> |
2008 | 87 | <text text-anchor="middle" x="1526" y="-265.4" font-family="Times Roman,serif" font-size="14.00">ack_wait</text> | 115 | <text text-anchor="middle" x="1598" y="-369.4" font-family="Times Roman,serif" font-size="14.00">ack_wait</text> |
2009 | 88 | </g> | 116 | </g> |
2010 | 89 | <!-- broadcast->ack_wait --> | 117 | <!-- broadcast->ack_wait --> |
2011 | 90 | <g id="edge14" class="edge"><title>broadcast->ack_wait</title> | 118 | <g id="edge14" class="edge"><title>broadcast->ack_wait</title> |
2015 | 91 | <path fill="none" stroke="black" d="M1121.17,-208.669C1207.93,-221.599 1370.7,-245.856 1461.17,-259.339"/> | 119 | <path fill="none" stroke="black" d="M1193.25,-288.88C1264.95,-299.067 1390.23,-318.45 1496,-343 1508.9,-345.993 1522.57,-349.664 1535.58,-353.397"/> |
2016 | 92 | <polygon fill="black" stroke="black" points="1460.9,-262.837 1471.3,-260.849 1461.93,-255.913 1460.9,-262.837"/> | 120 | <polygon fill="black" stroke="black" points="1534.79,-356.813 1545.37,-356.254 1536.75,-350.093 1534.79,-356.813"/> |
2017 | 93 | <text text-anchor="middle" x="1289" y="-257.4" font-family="Times Roman,serif" font-size="14.00">Write BROADCAST [fits one wire msg]</text> | 121 | <text text-anchor="middle" x="1361" y="-348.4" font-family="Times Roman,serif" font-size="14.00">Write BROADCAST [fits one wire msg]</text> |
2018 | 94 | </g> | 122 | </g> |
2019 | 95 | <!-- split_broadcast --> | 123 | <!-- split_broadcast --> |
2023 | 96 | <g id="node17" class="node"><title>split_broadcast</title> | 124 | <g id="node18" class="node"><title>split_broadcast</title> |
2024 | 97 | <ellipse fill="none" stroke="black" cx="1526" cy="-110" rx="84.1457" ry="84.1457"/> | 125 | <ellipse fill="none" stroke="black" cx="1598" cy="-216" rx="84.1457" ry="84.1457"/> |
2025 | 98 | <text text-anchor="middle" x="1526" y="-106.4" font-family="Times Roman,serif" font-size="14.00">split_broadcast</text> | 126 | <text text-anchor="middle" x="1598" y="-212.4" font-family="Times Roman,serif" font-size="14.00">split_broadcast</text> |
2026 | 99 | </g> | 127 | </g> |
2027 | 100 | <!-- broadcast->split_broadcast --> | 128 | <!-- broadcast->split_broadcast --> |
2028 | 101 | <g id="edge16" class="edge"><title>broadcast->split_broadcast</title> | 129 | <g id="edge16" class="edge"><title>broadcast->split_broadcast</title> |
2032 | 102 | <path fill="none" stroke="black" d="M1120.7,-188.783C1199.06,-173.553 1340.01,-146.154 1433.29,-128.021"/> | 130 | <path fill="none" stroke="black" d="M1193.17,-272.834C1271.44,-261.846 1411.56,-242.174 1504.66,-229.104"/> |
2033 | 103 | <polygon fill="black" stroke="black" points="1434.15,-131.421 1443.29,-126.077 1432.81,-124.549 1434.15,-131.421"/> | 131 | <polygon fill="black" stroke="black" points="1505.23,-232.558 1514.65,-227.702 1504.26,-225.626 1505.23,-232.558"/> |
2034 | 104 | <text text-anchor="middle" x="1289" y="-185.4" font-family="Times Roman,serif" font-size="14.00">BROADCAST does not fit one wire msg</text> | 132 | <text text-anchor="middle" x="1361" y="-272.4" font-family="Times Roman,serif" font-size="14.00">BROADCAST does not fit one wire msg</text> |
2035 | 133 | </g> | ||
2036 | 134 | <!-- pong_wait->stop --> | ||
2037 | 135 | <g id="edge40" class="edge"><title>pong_wait->stop</title> | ||
2038 | 136 | <path fill="none" stroke="black" d="M600.164,-653C651.344,-653 725.322,-653 790,-653 790,-653 790,-653 1972,-653 2131.11,-653 2245.53,-463.168 2289.33,-376.844"/> | ||
2039 | 137 | <polygon fill="black" stroke="black" points="2292.5,-378.343 2293.84,-367.834 2286.24,-375.212 2292.5,-378.343"/> | ||
2040 | 138 | <text text-anchor="middle" x="1361" y="-658.4" font-family="Times Roman,serif" font-size="14.00">Elapsed exhange timeout</text> | ||
2041 | 105 | </g> | 139 | </g> |
2042 | 106 | <!-- pong_wait->loop --> | 140 | <!-- pong_wait->loop --> |
2043 | 107 | <g id="edge18" class="edge"><title>pong_wait->loop</title> | 141 | <g id="edge18" class="edge"><title>pong_wait->loop</title> |
2047 | 108 | <path fill="none" stroke="black" d="M1463.29,-398.59C1336,-383.27 1038.34,-346.004 790,-304 787.177,-303.523 784.269,-303.006 781.343,-302.468"/> | 142 | <path fill="none" stroke="black" d="M581.359,-607.765C632.774,-555.333 716.085,-470.376 760.273,-425.314"/> |
2048 | 109 | <polygon fill="black" stroke="black" points="781.898,-299.011 771.42,-300.582 780.59,-305.888 781.898,-299.011"/> | 143 | <polygon fill="black" stroke="black" points="762.774,-427.763 767.277,-418.172 757.776,-422.862 762.774,-427.763"/> |
2049 | 110 | <text text-anchor="middle" x="1063" y="-359.4" font-family="Times Roman,serif" font-size="14.00">Read PONG</text> | 144 | <text text-anchor="middle" x="675" y="-574.4" font-family="Times Roman,serif" font-size="14.00">Read PONG</text> |
2050 | 145 | </g> | ||
2051 | 146 | <!-- ack_wait->stop --> | ||
2052 | 147 | <g id="edge36" class="edge"><title>ack_wait->stop</title> | ||
2053 | 148 | <path fill="none" stroke="black" d="M1653.02,-372.757C1765.96,-371.776 2032.03,-366.986 2254,-344 2256.89,-343.701 2259.85,-343.348 2262.84,-342.959"/> | ||
2054 | 149 | <polygon fill="black" stroke="black" points="2263.58,-346.389 2272.99,-341.517 2262.59,-339.459 2263.58,-346.389"/> | ||
2055 | 150 | <text text-anchor="middle" x="1972" y="-373.4" font-family="Times Roman,serif" font-size="14.00">Elapsed exhange timeout</text> | ||
2056 | 111 | </g> | 151 | </g> |
2057 | 112 | <!-- ack_wait->loop --> | 152 | <!-- ack_wait->loop --> |
2058 | 113 | <g id="edge20" class="edge"><title>ack_wait->loop</title> | 153 | <g id="edge20" class="edge"><title>ack_wait->loop</title> |
2062 | 114 | <path fill="none" stroke="black" d="M1470.96,-271.898C1455.75,-272.644 1439.24,-273.404 1424,-274 1181.02,-283.507 889.323,-290.597 782.144,-293.057"/> | 154 | <path fill="none" stroke="black" d="M1542.83,-374.081C1445.66,-375.995 1237.64,-380.146 1062,-384 966.886,-386.087 942.947,-382.989 848,-389 842.829,-389.327 837.406,-389.764 832.04,-390.252"/> |
2063 | 115 | <polygon fill="black" stroke="black" points="781.977,-289.56 772.059,-293.288 782.136,-296.558 781.977,-289.56"/> | 155 | <polygon fill="black" stroke="black" points="831.485,-386.79 821.871,-391.242 832.163,-393.757 831.485,-386.79"/> |
2064 | 116 | <text text-anchor="middle" x="1063" y="-292.4" font-family="Times Roman,serif" font-size="14.00">Read ACK</text> | 156 | <text text-anchor="middle" x="1135" y="-389.4" font-family="Times Roman,serif" font-size="14.00">Read ACK</text> |
2065 | 117 | </g> | 157 | </g> |
2066 | 118 | <!-- split_broadcast->loop --> | 158 | <!-- split_broadcast->loop --> |
2067 | 119 | <g id="edge26" class="edge"><title>split_broadcast->loop</title> | 159 | <g id="edge26" class="edge"><title>split_broadcast->loop</title> |
2071 | 120 | <path fill="none" stroke="black" d="M1442.56,-99.9981C1336.06,-89.6718 1146.8,-79.5577 990,-115 894.383,-136.612 862.41,-141.921 790,-208 775.817,-220.943 764.522,-238.865 756.283,-254.999"/> | 160 | <path fill="none" stroke="black" d="M1515.33,-201.109C1409.22,-184.681 1219.98,-164.458 1062,-196 960.985,-216.168 924.079,-215.554 848,-285 827.351,-303.849 812.751,-331.776 803.364,-354.774"/> |
2072 | 121 | <polygon fill="black" stroke="black" points="753.014,-253.718 751.785,-264.241 759.308,-256.781 753.014,-253.718"/> | 161 | <polygon fill="black" stroke="black" points="800.027,-353.699 799.658,-364.287 806.549,-356.24 800.027,-353.699"/> |
2073 | 122 | <text text-anchor="middle" x="1063" y="-120.4" font-family="Times Roman,serif" font-size="14.00">All split msgs written</text> | 162 | <text text-anchor="middle" x="1135" y="-201.4" font-family="Times Roman,serif" font-size="14.00">All split msgs written</text> |
2074 | 123 | </g> | 163 | </g> |
2075 | 124 | <!-- split_ack_wait --> | 164 | <!-- split_ack_wait --> |
2079 | 125 | <g id="node21" class="node"><title>split_ack_wait</title> | 165 | <g id="node22" class="node"><title>split_ack_wait</title> |
2080 | 126 | <ellipse fill="none" stroke="black" cx="1893" cy="-110" rx="80.1095" ry="80.6102"/> | 166 | <ellipse fill="none" stroke="black" cx="1972" cy="-257" rx="80.1095" ry="80.6102"/> |
2081 | 127 | <text text-anchor="middle" x="1893" y="-106.4" font-family="Times Roman,serif" font-size="14.00">split_ack_wait</text> | 167 | <text text-anchor="middle" x="1972" y="-253.4" font-family="Times Roman,serif" font-size="14.00">split_ack_wait</text> |
2082 | 128 | </g> | 168 | </g> |
2083 | 129 | <!-- split_broadcast->split_ack_wait --> | 169 | <!-- split_broadcast->split_ack_wait --> |
2084 | 130 | <g id="edge22" class="edge"><title>split_broadcast->split_ack_wait</title> | 170 | <g id="edge22" class="edge"><title>split_broadcast->split_ack_wait</title> |
2088 | 131 | <path fill="none" stroke="black" d="M1610.2,-110C1667.61,-110 1743.59,-110 1802.33,-110"/> | 171 | <path fill="none" stroke="black" d="M1680.55,-232.126C1687.12,-233.18 1693.66,-234.156 1700,-235 1760.22,-243.022 1828.36,-248.528 1881.38,-252.025"/> |
2089 | 132 | <polygon fill="black" stroke="black" points="1802.35,-113.5 1812.35,-110 1802.34,-106.5 1802.35,-113.5"/> | 172 | <polygon fill="black" stroke="black" points="1881.23,-255.523 1891.43,-252.676 1881.68,-248.537 1881.23,-255.523"/> |
2090 | 133 | <text text-anchor="middle" x="1711" y="-115.4" font-family="Times Roman,serif" font-size="14.00">Write split BROADCAST</text> | 173 | <text text-anchor="middle" x="1783" y="-256.4" font-family="Times Roman,serif" font-size="14.00">Write split BROADCAST</text> |
2091 | 174 | </g> | ||
2092 | 175 | <!-- split_ack_wait->stop --> | ||
2093 | 176 | <g id="edge38" class="edge"><title>split_ack_wait->stop</title> | ||
2094 | 177 | <path fill="none" stroke="black" d="M2050.59,-275.189C2116.55,-290.456 2208.51,-311.74 2263.08,-324.372"/> | ||
2095 | 178 | <polygon fill="black" stroke="black" points="2262.62,-327.857 2273.15,-326.702 2264.2,-321.037 2262.62,-327.857"/> | ||
2096 | 179 | <text text-anchor="middle" x="2166" y="-327.4" font-family="Times Roman,serif" font-size="14.00">Elapsed exhange timeout</text> | ||
2097 | 134 | </g> | 180 | </g> |
2098 | 135 | <!-- split_ack_wait->split_broadcast --> | 181 | <!-- split_ack_wait->split_broadcast --> |
2099 | 136 | <g id="edge24" class="edge"><title>split_ack_wait->split_broadcast</title> | 182 | <g id="edge24" class="edge"><title>split_ack_wait->split_broadcast</title> |
2103 | 137 | <path fill="none" stroke="black" d="M1814.64,-90.9448C1807.69,-89.7544 1800.74,-88.7397 1794,-88 1720.66,-79.9496 1701.36,-80.1783 1628,-88 1624.71,-88.3505 1621.38,-88.7628 1618.01,-89.2264"/> | 183 | <path fill="none" stroke="black" d="M1899.33,-222.493C1888.37,-218.573 1877.04,-215.2 1866,-213 1808.89,-201.617 1743.56,-202.081 1691.71,-205.529"/> |
2104 | 138 | <polygon fill="black" stroke="black" points="1617.23,-85.8043 1607.87,-90.7602 1618.28,-92.7256 1617.23,-85.8043"/> | 184 | <polygon fill="black" stroke="black" points="1691.25,-202.053 1681.52,-206.256 1691.74,-209.035 1691.25,-202.053"/> |
2105 | 139 | <text text-anchor="middle" x="1711" y="-93.4" font-family="Times Roman,serif" font-size="14.00">Read ACK</text> | 185 | <text text-anchor="middle" x="1783" y="-218.4" font-family="Times Roman,serif" font-size="14.00">Read ACK</text> |
2106 | 186 | </g> | ||
2107 | 187 | <!-- conn_broken->stop --> | ||
2108 | 188 | <g id="edge32" class="edge"><title>conn_broken->stop</title> | ||
2109 | 189 | <path fill="none" stroke="black" d="M1434.61,-95.8477C1564.45,-92.5456 1841.16,-95.6985 2060,-168 2154.32,-199.163 2175.34,-218.326 2254,-279 2262.17,-285.305 2270.33,-292.782 2277.75,-300.185"/> | ||
2110 | 190 | <polygon fill="black" stroke="black" points="2275.42,-302.808 2284.91,-307.517 2280.43,-297.917 2275.42,-302.808"/> | ||
2111 | 191 | <text text-anchor="middle" x="1783" y="-127.4" font-family="Times Roman,serif" font-size="14.00">Write CONNBROKEN</text> | ||
2112 | 192 | </g> | ||
2113 | 193 | <!-- conn_warn->loop --> | ||
2114 | 194 | <g id="edge34" class="edge"><title>conn_warn->loop</title> | ||
2115 | 195 | <path fill="none" stroke="black" d="M1083.63,-435.301C1071.29,-427.246 1057.71,-419.822 1044,-415 972.758,-389.933 883.562,-389.406 832.05,-391.836"/> | ||
2116 | 196 | <polygon fill="black" stroke="black" points="831.758,-388.346 821.959,-392.373 832.131,-395.337 831.758,-388.346"/> | ||
2117 | 197 | <text text-anchor="middle" x="946" y="-420.4" font-family="Times Roman,serif" font-size="14.00">Write CONNWARN</text> | ||
2118 | 140 | </g> | 198 | </g> |
2119 | 141 | </g> | 199 | </g> |
2120 | 142 | </svg> | 200 | </svg> |
2121 | 143 | 201 | ||
2122 | === modified file 'server/acceptance/acceptanceclient.go' | |||
2123 | --- server/acceptance/acceptanceclient.go 2014-04-09 19:30:53 +0000 | |||
2124 | +++ server/acceptance/acceptanceclient.go 2014-04-29 18:02:00 +0000 | |||
2125 | @@ -44,6 +44,7 @@ | |||
2126 | 44 | Levels map[string]int64 | 44 | Levels map[string]int64 |
2127 | 45 | Insecure bool // don't verify certs | 45 | Insecure bool // don't verify certs |
2128 | 46 | Prefix string // prefix for events | 46 | Prefix string // prefix for events |
2129 | 47 | Auth string | ||
2130 | 47 | // connection | 48 | // connection |
2131 | 48 | Connection net.Conn | 49 | Connection net.Conn |
2132 | 49 | } | 50 | } |
2133 | @@ -73,6 +74,7 @@ | |||
2134 | 73 | Type string `json:"T"` | 74 | Type string `json:"T"` |
2135 | 74 | protocol.BroadcastMsg | 75 | protocol.BroadcastMsg |
2136 | 75 | protocol.NotificationsMsg | 76 | protocol.NotificationsMsg |
2137 | 77 | protocol.ConnWarnMsg | ||
2138 | 76 | } | 78 | } |
2139 | 77 | 79 | ||
2140 | 78 | // Run the session with the server, emits a stream of events. | 80 | // Run the session with the server, emits a stream of events. |
2141 | @@ -93,6 +95,7 @@ | |||
2142 | 93 | "device": sess.Model, | 95 | "device": sess.Model, |
2143 | 94 | "channel": sess.ImageChannel, | 96 | "channel": sess.ImageChannel, |
2144 | 95 | }, | 97 | }, |
2145 | 98 | Authorization: sess.Auth, | ||
2146 | 96 | }) | 99 | }) |
2147 | 97 | if err != nil { | 100 | if err != nil { |
2148 | 98 | return err | 101 | return err |
2149 | @@ -136,6 +139,8 @@ | |||
2150 | 136 | return err | 139 | return err |
2151 | 137 | } | 140 | } |
2152 | 138 | events <- fmt.Sprintf("%sbroadcast chan:%v app:%v topLevel:%d payloads:%s", sess.Prefix, recv.ChanId, recv.AppId, recv.TopLevel, pack) | 141 | events <- fmt.Sprintf("%sbroadcast chan:%v app:%v topLevel:%d payloads:%s", sess.Prefix, recv.ChanId, recv.AppId, recv.TopLevel, pack) |
2153 | 142 | case "warn": | ||
2154 | 143 | events <- fmt.Sprintf("%swarn %s", sess.Prefix, recv.Reason) | ||
2155 | 139 | } | 144 | } |
2156 | 140 | } | 145 | } |
2157 | 141 | return nil | 146 | return nil |
2158 | 142 | 147 | ||
2159 | === modified file 'server/acceptance/cmd/acceptanceclient.go' | |||
2160 | --- server/acceptance/cmd/acceptanceclient.go 2014-04-10 13:52:31 +0000 | |||
2161 | +++ server/acceptance/cmd/acceptanceclient.go 2014-04-29 18:02:00 +0000 | |||
2162 | @@ -48,13 +48,18 @@ | |||
2163 | 48 | fmt.Fprintf(os.Stderr, "Usage: acceptancclient [options] <config.json> <device id>\n") | 48 | fmt.Fprintf(os.Stderr, "Usage: acceptancclient [options] <config.json> <device id>\n") |
2164 | 49 | flag.PrintDefaults() | 49 | flag.PrintDefaults() |
2165 | 50 | } | 50 | } |
2166 | 51 | missingArg := func(what string) { | ||
2167 | 52 | fmt.Fprintf(os.Stderr, "missing %s\n", what) | ||
2168 | 53 | flag.Usage() | ||
2169 | 54 | os.Exit(2) | ||
2170 | 55 | } | ||
2171 | 51 | flag.Parse() | 56 | flag.Parse() |
2172 | 52 | narg := flag.NArg() | 57 | narg := flag.NArg() |
2173 | 53 | switch { | 58 | switch { |
2174 | 54 | case narg < 1: | 59 | case narg < 1: |
2176 | 55 | log.Fatal("missing config file") | 60 | missingArg("config file") |
2177 | 56 | case narg < 2: | 61 | case narg < 2: |
2179 | 57 | log.Fatal("missing device-id") | 62 | missingArg("device-id") |
2180 | 58 | } | 63 | } |
2181 | 59 | configFName := flag.Arg(0) | 64 | configFName := flag.Arg(0) |
2182 | 60 | f, err := os.Open(configFName) | 65 | f, err := os.Open(configFName) |
2183 | 61 | 66 | ||
2184 | === modified file 'server/acceptance/suites/broadcast.go' | |||
2185 | --- server/acceptance/suites/broadcast.go 2014-04-07 19:39:19 +0000 | |||
2186 | +++ server/acceptance/suites/broadcast.go 2014-04-29 18:02:00 +0000 | |||
2187 | @@ -265,7 +265,11 @@ | |||
2188 | 265 | 265 | ||
2189 | 266 | func (s *BroadcastAcceptanceSuite) TestGetHosts(c *C) { | 266 | func (s *BroadcastAcceptanceSuite) TestGetHosts(c *C) { |
2190 | 267 | gh := gethosts.New("", s.ServerAPIURL+"/delivery-hosts", 2*time.Second) | 267 | gh := gethosts.New("", s.ServerAPIURL+"/delivery-hosts", 2*time.Second) |
2192 | 268 | hosts, err := gh.Get() | 268 | host, err := gh.Get() |
2193 | 269 | c.Assert(err, IsNil) | 269 | c.Assert(err, IsNil) |
2195 | 270 | c.Check(hosts, DeepEquals, []string{s.ServerAddr}) | 270 | expected := &gethosts.Host{ |
2196 | 271 | Domain: "localhost", | ||
2197 | 272 | Hosts: []string{s.ServerAddr}, | ||
2198 | 273 | } | ||
2199 | 274 | c.Check(host, DeepEquals, expected) | ||
2200 | 271 | } | 275 | } |
2201 | 272 | 276 | ||
2202 | === modified file 'server/acceptance/suites/suite.go' | |||
2203 | --- server/acceptance/suites/suite.go 2014-04-03 16:47:47 +0000 | |||
2204 | +++ server/acceptance/suites/suite.go 2014-04-29 18:02:00 +0000 | |||
2205 | @@ -44,10 +44,19 @@ | |||
2206 | 44 | 44 | ||
2207 | 45 | // Start a client. | 45 | // Start a client. |
2208 | 46 | func (h *ServerHandle) StartClient(c *C, devId string, levels map[string]int64) (events <-chan string, errorCh <-chan error, stop func()) { | 46 | func (h *ServerHandle) StartClient(c *C, devId string, levels map[string]int64) (events <-chan string, errorCh <-chan error, stop func()) { |
2209 | 47 | return h.StartClientAuth(c, devId, levels, "") | ||
2210 | 48 | } | ||
2211 | 49 | |||
2212 | 50 | // Start a client with auth. | ||
2213 | 51 | func (h *ServerHandle) StartClientAuth(c *C, devId string, levels map[string]int64, auth string) (events <-chan string, errorCh <-chan error, stop func()) { | ||
2214 | 47 | errCh := make(chan error, 1) | 52 | errCh := make(chan error, 1) |
2215 | 48 | cliEvents := make(chan string, 10) | 53 | cliEvents := make(chan string, 10) |
2216 | 49 | sess := testClientSession(h.ServerAddr, devId, "m1", "img1", false) | 54 | sess := testClientSession(h.ServerAddr, devId, "m1", "img1", false) |
2217 | 50 | sess.Levels = levels | 55 | sess.Levels = levels |
2218 | 56 | sess.Auth = auth | ||
2219 | 57 | if auth != "" { | ||
2220 | 58 | sess.ExchangeTimeout = 5 * time.Second | ||
2221 | 59 | } | ||
2222 | 51 | err := sess.Dial() | 60 | err := sess.Dial() |
2223 | 52 | c.Assert(err, IsNil) | 61 | c.Assert(err, IsNil) |
2224 | 53 | clientShutdown := make(chan bool, 1) // abused as an atomic flag | 62 | clientShutdown := make(chan bool, 1) // abused as an atomic flag |
2225 | 54 | 63 | ||
2226 | === modified file 'server/api/handlers_test.go' | |||
2227 | --- server/api/handlers_test.go 2014-02-21 11:32:38 +0000 | |||
2228 | +++ server/api/handlers_test.go 2014-04-29 18:02:00 +0000 | |||
2229 | @@ -30,6 +30,7 @@ | |||
2230 | 30 | 30 | ||
2231 | 31 | . "launchpad.net/gocheck" | 31 | . "launchpad.net/gocheck" |
2232 | 32 | 32 | ||
2233 | 33 | "launchpad.net/ubuntu-push/protocol" | ||
2234 | 33 | "launchpad.net/ubuntu-push/server/store" | 34 | "launchpad.net/ubuntu-push/server/store" |
2235 | 34 | helpers "launchpad.net/ubuntu-push/testing" | 35 | helpers "launchpad.net/ubuntu-push/testing" |
2236 | 35 | ) | 36 | ) |
2237 | @@ -142,11 +143,11 @@ | |||
2238 | 142 | } | 143 | } |
2239 | 143 | 144 | ||
2240 | 144 | func (cbsend *checkBrokerSending) Broadcast(chanId store.InternalChannelId) { | 145 | func (cbsend *checkBrokerSending) Broadcast(chanId store.InternalChannelId) { |
2242 | 145 | top, payloads, err := cbsend.store.GetChannelSnapshot(chanId) | 146 | top, notifications, err := cbsend.store.GetChannelSnapshot(chanId) |
2243 | 146 | cbsend.err = err | 147 | cbsend.err = err |
2244 | 147 | cbsend.chanId = chanId | 148 | cbsend.chanId = chanId |
2245 | 148 | cbsend.top = top | 149 | cbsend.top = top |
2247 | 149 | cbsend.payloads = payloads | 150 | cbsend.payloads = protocol.ExtractPayloads(notifications) |
2248 | 150 | } | 151 | } |
2249 | 151 | 152 | ||
2250 | 152 | func (s *handlersSuite) TestDoBroadcast(c *C) { | 153 | func (s *handlersSuite) TestDoBroadcast(c *C) { |
2251 | 153 | 154 | ||
2252 | === modified file 'server/broker/broker.go' | |||
2253 | --- server/broker/broker.go 2014-04-04 09:58:34 +0000 | |||
2254 | +++ server/broker/broker.go 2014-04-29 18:02:00 +0000 | |||
2255 | @@ -30,7 +30,7 @@ | |||
2256 | 30 | // through them. | 30 | // through them. |
2257 | 31 | type Broker interface { | 31 | type Broker interface { |
2258 | 32 | // Register the session. | 32 | // Register the session. |
2260 | 33 | Register(*protocol.ConnectMsg) (BrokerSession, error) | 33 | Register(connMsg *protocol.ConnectMsg, sessionId string) (BrokerSession, error) |
2261 | 34 | // Unregister the session. | 34 | // Unregister the session. |
2262 | 35 | Unregister(BrokerSession) | 35 | Unregister(BrokerSession) |
2263 | 36 | } | 36 | } |
2264 | 37 | 37 | ||
2265 | === modified file 'server/broker/exchanges.go' | |||
2266 | --- server/broker/exchanges.go 2014-04-04 13:19:10 +0000 | |||
2267 | +++ server/broker/exchanges.go 2014-04-29 18:02:00 +0000 | |||
2268 | @@ -28,18 +28,17 @@ | |||
2269 | 28 | 28 | ||
2270 | 29 | // Scratch area for exchanges, sessions should hold one of these. | 29 | // Scratch area for exchanges, sessions should hold one of these. |
2271 | 30 | type ExchangesScratchArea struct { | 30 | type ExchangesScratchArea struct { |
2275 | 31 | broadcastMsg protocol.BroadcastMsg | 31 | broadcastMsg protocol.BroadcastMsg |
2276 | 32 | ackMsg protocol.AckMsg | 32 | ackMsg protocol.AckMsg |
2274 | 33 | connBrokenMsg protocol.ConnBrokenMsg | ||
2277 | 34 | } | 33 | } |
2278 | 35 | 34 | ||
2279 | 36 | // BroadcastExchange leads a session through delivering a BROADCAST. | 35 | // BroadcastExchange leads a session through delivering a BROADCAST. |
2280 | 37 | // For simplicity it is fully public. | 36 | // For simplicity it is fully public. |
2281 | 38 | type BroadcastExchange struct { | 37 | type BroadcastExchange struct { |
2286 | 39 | ChanId store.InternalChannelId | 38 | ChanId store.InternalChannelId |
2287 | 40 | TopLevel int64 | 39 | TopLevel int64 |
2288 | 41 | NotificationPayloads []json.RawMessage | 40 | Notifications []protocol.Notification |
2289 | 42 | Decoded []map[string]interface{} | 41 | Decoded []map[string]interface{} |
2290 | 43 | } | 42 | } |
2291 | 44 | 43 | ||
2292 | 45 | // check interface already here | 44 | // check interface already here |
2293 | @@ -47,18 +46,18 @@ | |||
2294 | 47 | 46 | ||
2295 | 48 | // Init ensures the BroadcastExchange is fully initialized for the sessions. | 47 | // Init ensures the BroadcastExchange is fully initialized for the sessions. |
2296 | 49 | func (sbe *BroadcastExchange) Init() { | 48 | func (sbe *BroadcastExchange) Init() { |
2298 | 50 | decoded := make([]map[string]interface{}, len(sbe.NotificationPayloads)) | 49 | decoded := make([]map[string]interface{}, len(sbe.Notifications)) |
2299 | 51 | sbe.Decoded = decoded | 50 | sbe.Decoded = decoded |
2302 | 52 | for i, p := range sbe.NotificationPayloads { | 51 | for i, notif := range sbe.Notifications { |
2303 | 53 | err := json.Unmarshal(p, &decoded[i]) | 52 | err := json.Unmarshal(notif.Payload, &decoded[i]) |
2304 | 54 | if err != nil { | 53 | if err != nil { |
2305 | 55 | decoded[i] = nil | 54 | decoded[i] = nil |
2306 | 56 | } | 55 | } |
2307 | 57 | } | 56 | } |
2308 | 58 | } | 57 | } |
2309 | 59 | 58 | ||
2312 | 60 | func filterByLevel(clientLevel, topLevel int64, payloads []json.RawMessage) []json.RawMessage { | 59 | func filterByLevel(clientLevel, topLevel int64, notifs []protocol.Notification) []protocol.Notification { |
2313 | 61 | c := int64(len(payloads)) | 60 | c := int64(len(notifs)) |
2314 | 62 | if c == 0 { | 61 | if c == 0 { |
2315 | 63 | return nil | 62 | return nil |
2316 | 64 | } | 63 | } |
2317 | @@ -67,32 +66,32 @@ | |||
2318 | 67 | delta = 1 | 66 | delta = 1 |
2319 | 68 | } | 67 | } |
2320 | 69 | if delta < c { | 68 | if delta < c { |
2322 | 70 | return payloads[c-delta:] | 69 | return notifs[c-delta:] |
2323 | 71 | } else { | 70 | } else { |
2325 | 72 | return payloads | 71 | return notifs |
2326 | 73 | } | 72 | } |
2327 | 74 | } | 73 | } |
2328 | 75 | 74 | ||
2332 | 76 | func channelFilter(tag string, chanId store.InternalChannelId, payloads []json.RawMessage, decoded []map[string]interface{}) []json.RawMessage { | 75 | func channelFilter(tag string, chanId store.InternalChannelId, notifs []protocol.Notification, decoded []map[string]interface{}) []json.RawMessage { |
2333 | 77 | if len(payloads) != 0 && chanId == store.SystemInternalChannelId { | 76 | if len(notifs) != 0 && chanId == store.SystemInternalChannelId { |
2334 | 78 | decoded := decoded[len(decoded)-len(payloads):] | 77 | decoded := decoded[len(decoded)-len(notifs):] |
2335 | 79 | filtered := make([]json.RawMessage, 0) | 78 | filtered := make([]json.RawMessage, 0) |
2336 | 80 | for i, decoded1 := range decoded { | 79 | for i, decoded1 := range decoded { |
2337 | 81 | if _, ok := decoded1[tag]; ok { | 80 | if _, ok := decoded1[tag]; ok { |
2339 | 82 | filtered = append(filtered, payloads[i]) | 81 | filtered = append(filtered, notifs[i].Payload) |
2340 | 83 | } | 82 | } |
2341 | 84 | } | 83 | } |
2343 | 85 | payloads = filtered | 84 | return filtered |
2344 | 86 | } | 85 | } |
2346 | 87 | return payloads | 86 | return protocol.ExtractPayloads(notifs) |
2347 | 88 | } | 87 | } |
2348 | 89 | 88 | ||
2349 | 90 | // Prepare session for a BROADCAST. | 89 | // Prepare session for a BROADCAST. |
2350 | 91 | func (sbe *BroadcastExchange) Prepare(sess BrokerSession) (outMessage protocol.SplittableMsg, inMessage interface{}, err error) { | 90 | func (sbe *BroadcastExchange) Prepare(sess BrokerSession) (outMessage protocol.SplittableMsg, inMessage interface{}, err error) { |
2351 | 92 | clientLevel := sess.Levels()[sbe.ChanId] | 91 | clientLevel := sess.Levels()[sbe.ChanId] |
2353 | 93 | payloads := filterByLevel(clientLevel, sbe.TopLevel, sbe.NotificationPayloads) | 92 | notifs := filterByLevel(clientLevel, sbe.TopLevel, sbe.Notifications) |
2354 | 94 | tag := fmt.Sprintf("%s/%s", sess.DeviceImageChannel(), sess.DeviceImageModel()) | 93 | tag := fmt.Sprintf("%s/%s", sess.DeviceImageChannel(), sess.DeviceImageModel()) |
2356 | 95 | payloads = channelFilter(tag, sbe.ChanId, payloads, sbe.Decoded) | 94 | payloads := channelFilter(tag, sbe.ChanId, notifs, sbe.Decoded) |
2357 | 96 | if len(payloads) == 0 && sbe.TopLevel >= clientLevel { | 95 | if len(payloads) == 0 && sbe.TopLevel >= clientLevel { |
2358 | 97 | // empty and don't need to force resync => do nothing | 96 | // empty and don't need to force resync => do nothing |
2359 | 98 | return nil, nil, ErrNop | 97 | return nil, nil, ErrNop |
2360 | @@ -119,23 +118,20 @@ | |||
2361 | 119 | return nil | 118 | return nil |
2362 | 120 | } | 119 | } |
2363 | 121 | 120 | ||
2367 | 122 | // ConnBrokenExchange breaks a session giving a reason. | 121 | // ConnMetaExchange allows to send a CONNBROKEN or CONNWARN message. |
2368 | 123 | type ConnBrokenExchange struct { | 122 | type ConnMetaExchange struct { |
2369 | 124 | Reason string | 123 | Msg protocol.OnewayMsg |
2370 | 125 | } | 124 | } |
2371 | 126 | 125 | ||
2372 | 127 | // check interface already here | 126 | // check interface already here |
2374 | 128 | var _ Exchange = (*ConnBrokenExchange)(nil) | 127 | var _ Exchange = (*ConnMetaExchange)(nil) |
2375 | 129 | 128 | ||
2382 | 130 | // Prepare session for a CONNBROKEN. | 129 | // Prepare session for a CONNBROKEN/WARN. |
2383 | 131 | func (cbe *ConnBrokenExchange) Prepare(sess BrokerSession) (outMessage protocol.SplittableMsg, inMessage interface{}, err error) { | 130 | func (cbe *ConnMetaExchange) Prepare(sess BrokerSession) (outMessage protocol.SplittableMsg, inMessage interface{}, err error) { |
2384 | 132 | scratchArea := sess.ExchangeScratchArea() | 131 | return cbe.Msg, nil, nil |
2379 | 133 | scratchArea.connBrokenMsg.Type = "connbroken" | ||
2380 | 134 | scratchArea.connBrokenMsg.Reason = cbe.Reason | ||
2381 | 135 | return &scratchArea.connBrokenMsg, nil, nil | ||
2385 | 136 | } | 132 | } |
2386 | 137 | 133 | ||
2390 | 138 | // CONNBROKEN isn't acked | 134 | // CONNBROKEN/WARN aren't acked. |
2391 | 139 | func (cbe *ConnBrokenExchange) Acked(sess BrokerSession, done bool) error { | 135 | func (cbe *ConnMetaExchange) Acked(sess BrokerSession, done bool) error { |
2392 | 140 | panic("Acked should not get invoked on ConnBrokenExchange") | 136 | panic("Acked should not get invoked on ConnMetaExchange") |
2393 | 141 | } | 137 | } |
2394 | 142 | 138 | ||
2395 | === modified file 'server/broker/exchanges_test.go' | |||
2396 | --- server/broker/exchanges_test.go 2014-04-04 13:19:10 +0000 | |||
2397 | +++ server/broker/exchanges_test.go 2014-04-29 18:02:00 +0000 | |||
2398 | @@ -24,9 +24,11 @@ | |||
2399 | 24 | 24 | ||
2400 | 25 | . "launchpad.net/gocheck" | 25 | . "launchpad.net/gocheck" |
2401 | 26 | 26 | ||
2402 | 27 | "launchpad.net/ubuntu-push/protocol" | ||
2403 | 27 | "launchpad.net/ubuntu-push/server/broker" | 28 | "launchpad.net/ubuntu-push/server/broker" |
2404 | 28 | "launchpad.net/ubuntu-push/server/broker/testing" | 29 | "launchpad.net/ubuntu-push/server/broker/testing" |
2405 | 29 | "launchpad.net/ubuntu-push/server/store" | 30 | "launchpad.net/ubuntu-push/server/store" |
2406 | 31 | help "launchpad.net/ubuntu-push/testing" | ||
2407 | 30 | ) | 32 | ) |
2408 | 31 | 33 | ||
2409 | 32 | func TestBroker(t *stdtesting.T) { TestingT(t) } | 34 | func TestBroker(t *stdtesting.T) { TestingT(t) } |
2410 | @@ -39,11 +41,11 @@ | |||
2411 | 39 | exchg := &broker.BroadcastExchange{ | 41 | exchg := &broker.BroadcastExchange{ |
2412 | 40 | ChanId: store.SystemInternalChannelId, | 42 | ChanId: store.SystemInternalChannelId, |
2413 | 41 | TopLevel: 3, | 43 | TopLevel: 3, |
2415 | 42 | NotificationPayloads: []json.RawMessage{ | 44 | Notifications: help.Ns( |
2416 | 43 | json.RawMessage(`{"a":"x"}`), | 45 | json.RawMessage(`{"a":"x"}`), |
2417 | 44 | json.RawMessage(`[]`), | 46 | json.RawMessage(`[]`), |
2418 | 45 | json.RawMessage(`{"a":"y"}`), | 47 | json.RawMessage(`{"a":"y"}`), |
2420 | 46 | }, | 48 | ), |
2421 | 47 | } | 49 | } |
2422 | 48 | exchg.Init() | 50 | exchg.Init() |
2423 | 49 | c.Check(exchg.Decoded, DeepEquals, []map[string]interface{}{ | 51 | c.Check(exchg.Decoded, DeepEquals, []map[string]interface{}{ |
2424 | @@ -62,10 +64,10 @@ | |||
2425 | 62 | exchg := &broker.BroadcastExchange{ | 64 | exchg := &broker.BroadcastExchange{ |
2426 | 63 | ChanId: store.SystemInternalChannelId, | 65 | ChanId: store.SystemInternalChannelId, |
2427 | 64 | TopLevel: 3, | 66 | TopLevel: 3, |
2429 | 65 | NotificationPayloads: []json.RawMessage{ | 67 | Notifications: help.Ns( |
2430 | 66 | json.RawMessage(`{"img1/m1":100}`), | 68 | json.RawMessage(`{"img1/m1":100}`), |
2431 | 67 | json.RawMessage(`{"img2/m2":200}`), | 69 | json.RawMessage(`{"img2/m2":200}`), |
2433 | 68 | }, | 70 | ), |
2434 | 69 | } | 71 | } |
2435 | 70 | exchg.Init() | 72 | exchg.Init() |
2436 | 71 | outMsg, inMsg, err := exchg.Prepare(sess) | 73 | outMsg, inMsg, err := exchg.Prepare(sess) |
2437 | @@ -88,9 +90,9 @@ | |||
2438 | 88 | ImageChannel: "img1", | 90 | ImageChannel: "img1", |
2439 | 89 | } | 91 | } |
2440 | 90 | exchg := &broker.BroadcastExchange{ | 92 | exchg := &broker.BroadcastExchange{ |
2444 | 91 | ChanId: store.SystemInternalChannelId, | 93 | ChanId: store.SystemInternalChannelId, |
2445 | 92 | TopLevel: 3, | 94 | TopLevel: 3, |
2446 | 93 | NotificationPayloads: []json.RawMessage{}, | 95 | Notifications: []protocol.Notification{}, |
2447 | 94 | } | 96 | } |
2448 | 95 | exchg.Init() | 97 | exchg.Init() |
2449 | 96 | outMsg, inMsg, err := exchg.Prepare(sess) | 98 | outMsg, inMsg, err := exchg.Prepare(sess) |
2450 | @@ -108,9 +110,9 @@ | |||
2451 | 108 | ImageChannel: "img1", | 110 | ImageChannel: "img1", |
2452 | 109 | } | 111 | } |
2453 | 110 | exchg := &broker.BroadcastExchange{ | 112 | exchg := &broker.BroadcastExchange{ |
2457 | 111 | ChanId: store.SystemInternalChannelId, | 113 | ChanId: store.SystemInternalChannelId, |
2458 | 112 | TopLevel: 3, | 114 | TopLevel: 3, |
2459 | 113 | NotificationPayloads: []json.RawMessage{}, | 115 | Notifications: []protocol.Notification{}, |
2460 | 114 | } | 116 | } |
2461 | 115 | exchg.Init() | 117 | exchg.Init() |
2462 | 116 | outMsg, inMsg, err := exchg.Prepare(sess) | 118 | outMsg, inMsg, err := exchg.Prepare(sess) |
2463 | @@ -133,9 +135,9 @@ | |||
2464 | 133 | 135 | ||
2465 | 134 | topLevel := int64(len(needsSplitting)) | 136 | topLevel := int64(len(needsSplitting)) |
2466 | 135 | exchg := &broker.BroadcastExchange{ | 137 | exchg := &broker.BroadcastExchange{ |
2470 | 136 | ChanId: store.SystemInternalChannelId, | 138 | ChanId: store.SystemInternalChannelId, |
2471 | 137 | TopLevel: topLevel, | 139 | TopLevel: topLevel, |
2472 | 138 | NotificationPayloads: needsSplitting, | 140 | Notifications: help.Ns(needsSplitting...), |
2473 | 139 | } | 141 | } |
2474 | 140 | exchg.Init() | 142 | exchg.Init() |
2475 | 141 | outMsg, _, err := exchg.Prepare(sess) | 143 | outMsg, _, err := exchg.Prepare(sess) |
2476 | @@ -152,10 +154,10 @@ | |||
2477 | 152 | exchg = &broker.BroadcastExchange{ | 154 | exchg = &broker.BroadcastExchange{ |
2478 | 153 | ChanId: store.SystemInternalChannelId, | 155 | ChanId: store.SystemInternalChannelId, |
2479 | 154 | TopLevel: topLevel + 2, | 156 | TopLevel: topLevel + 2, |
2481 | 155 | NotificationPayloads: []json.RawMessage{ | 157 | Notifications: help.Ns( |
2482 | 156 | json.RawMessage(`{"img1/m1":"x"}`), | 158 | json.RawMessage(`{"img1/m1":"x"}`), |
2483 | 157 | json.RawMessage(`{"img1/m1":"y"}`), | 159 | json.RawMessage(`{"img1/m1":"y"}`), |
2485 | 158 | }, | 160 | ), |
2486 | 159 | } | 161 | } |
2487 | 160 | exchg.Init() | 162 | exchg.Init() |
2488 | 161 | outMsg, _, err = exchg.Prepare(sess) | 163 | outMsg, _, err = exchg.Prepare(sess) |
2489 | @@ -173,9 +175,9 @@ | |||
2490 | 173 | exchg := &broker.BroadcastExchange{ | 175 | exchg := &broker.BroadcastExchange{ |
2491 | 174 | ChanId: store.SystemInternalChannelId, | 176 | ChanId: store.SystemInternalChannelId, |
2492 | 175 | TopLevel: 3, | 177 | TopLevel: 3, |
2494 | 176 | NotificationPayloads: []json.RawMessage{ | 178 | Notifications: help.Ns( |
2495 | 177 | json.RawMessage(`{"img2/m1":1}`), | 179 | json.RawMessage(`{"img2/m1":1}`), |
2497 | 178 | }, | 180 | ), |
2498 | 179 | } | 181 | } |
2499 | 180 | exchg.Init() | 182 | exchg.Init() |
2500 | 181 | outMsg, inMsg, err := exchg.Prepare(sess) | 183 | outMsg, inMsg, err := exchg.Prepare(sess) |
2501 | @@ -202,10 +204,10 @@ | |||
2502 | 202 | exchg := &broker.BroadcastExchange{ | 204 | exchg := &broker.BroadcastExchange{ |
2503 | 203 | ChanId: store.SystemInternalChannelId, | 205 | ChanId: store.SystemInternalChannelId, |
2504 | 204 | TopLevel: 3, | 206 | TopLevel: 3, |
2506 | 205 | NotificationPayloads: []json.RawMessage{ | 207 | Notifications: help.Ns( |
2507 | 206 | json.RawMessage(`{"img1/m1":100}`), | 208 | json.RawMessage(`{"img1/m1":100}`), |
2508 | 207 | json.RawMessage(`{"img1/m1":101}`), | 209 | json.RawMessage(`{"img1/m1":101}`), |
2510 | 208 | }, | 210 | ), |
2511 | 209 | } | 211 | } |
2512 | 210 | exchg.Init() | 212 | exchg.Init() |
2513 | 211 | outMsg, inMsg, err := exchg.Prepare(sess) | 213 | outMsg, inMsg, err := exchg.Prepare(sess) |
2514 | @@ -229,11 +231,11 @@ | |||
2515 | 229 | exchg := &broker.BroadcastExchange{ | 231 | exchg := &broker.BroadcastExchange{ |
2516 | 230 | ChanId: store.SystemInternalChannelId, | 232 | ChanId: store.SystemInternalChannelId, |
2517 | 231 | TopLevel: 5, | 233 | TopLevel: 5, |
2519 | 232 | NotificationPayloads: []json.RawMessage{ | 234 | Notifications: help.Ns( |
2520 | 233 | json.RawMessage(`{"img1/m1":100}`), | 235 | json.RawMessage(`{"img1/m1":100}`), |
2521 | 234 | json.RawMessage(`{"img2/m2":200}`), | 236 | json.RawMessage(`{"img2/m2":200}`), |
2522 | 235 | json.RawMessage(`{"img1/m1":101}`), | 237 | json.RawMessage(`{"img1/m1":101}`), |
2524 | 236 | }, | 238 | ), |
2525 | 237 | } | 239 | } |
2526 | 238 | exchg.Init() | 240 | exchg.Init() |
2527 | 239 | outMsg, inMsg, err := exchg.Prepare(sess) | 241 | outMsg, inMsg, err := exchg.Prepare(sess) |
2528 | @@ -249,16 +251,18 @@ | |||
2529 | 249 | c.Check(sess.LevelsMap[store.SystemInternalChannelId], Equals, int64(5)) | 251 | c.Check(sess.LevelsMap[store.SystemInternalChannelId], Equals, int64(5)) |
2530 | 250 | } | 252 | } |
2531 | 251 | 253 | ||
2533 | 252 | func (s *exchangesSuite) TestConnBrokenExchange(c *C) { | 254 | func (s *exchangesSuite) TestConnMetaExchange(c *C) { |
2534 | 253 | sess := &testing.TestBrokerSession{} | 255 | sess := &testing.TestBrokerSession{} |
2536 | 254 | cbe := &broker.ConnBrokenExchange{"REASON"} | 256 | var msg protocol.OnewayMsg = &protocol.ConnWarnMsg{"connwarn", "REASON"} |
2537 | 257 | cbe := &broker.ConnMetaExchange{msg} | ||
2538 | 255 | outMsg, inMsg, err := cbe.Prepare(sess) | 258 | outMsg, inMsg, err := cbe.Prepare(sess) |
2539 | 256 | c.Assert(err, IsNil) | 259 | c.Assert(err, IsNil) |
2540 | 260 | c.Check(msg, Equals, outMsg) | ||
2541 | 257 | c.Check(inMsg, IsNil) // no answer is expected | 261 | c.Check(inMsg, IsNil) // no answer is expected |
2542 | 258 | // check | 262 | // check |
2543 | 259 | marshalled, err := json.Marshal(outMsg) | 263 | marshalled, err := json.Marshal(outMsg) |
2544 | 260 | c.Assert(err, IsNil) | 264 | c.Assert(err, IsNil) |
2546 | 261 | c.Check(string(marshalled), Equals, `{"T":"connbroken","Reason":"REASON"}`) | 265 | c.Check(string(marshalled), Equals, `{"T":"connwarn","Reason":"REASON"}`) |
2547 | 262 | 266 | ||
2549 | 263 | c.Check(func() { cbe.Acked(nil, true) }, PanicMatches, "Acked should not get invoked on ConnBrokenExchange") | 267 | c.Check(func() { cbe.Acked(nil, true) }, PanicMatches, "Acked should not get invoked on ConnMetaExchange") |
2550 | 264 | } | 268 | } |
2551 | 265 | 269 | ||
2552 | === modified file 'server/broker/exchg_impl_test.go' | |||
2553 | --- server/broker/exchg_impl_test.go 2014-04-03 16:00:53 +0000 | |||
2554 | +++ server/broker/exchg_impl_test.go 2014-04-29 18:02:00 +0000 | |||
2555 | @@ -22,6 +22,7 @@ | |||
2556 | 22 | . "launchpad.net/gocheck" | 22 | . "launchpad.net/gocheck" |
2557 | 23 | 23 | ||
2558 | 24 | "launchpad.net/ubuntu-push/server/store" | 24 | "launchpad.net/ubuntu-push/server/store" |
2559 | 25 | help "launchpad.net/ubuntu-push/testing" | ||
2560 | 25 | ) | 26 | ) |
2561 | 26 | 27 | ||
2562 | 27 | type exchangesImplSuite struct{} | 28 | type exchangesImplSuite struct{} |
2563 | @@ -29,27 +30,27 @@ | |||
2564 | 29 | var _ = Suite(&exchangesImplSuite{}) | 30 | var _ = Suite(&exchangesImplSuite{}) |
2565 | 30 | 31 | ||
2566 | 31 | func (s *exchangesImplSuite) TestFilterByLevel(c *C) { | 32 | func (s *exchangesImplSuite) TestFilterByLevel(c *C) { |
2568 | 32 | payloads := []json.RawMessage{ | 33 | notifs := help.Ns( |
2569 | 33 | json.RawMessage(`{"a": 3}`), | 34 | json.RawMessage(`{"a": 3}`), |
2570 | 34 | json.RawMessage(`{"a": 4}`), | 35 | json.RawMessage(`{"a": 4}`), |
2571 | 35 | json.RawMessage(`{"a": 5}`), | 36 | json.RawMessage(`{"a": 5}`), |
2574 | 36 | } | 37 | ) |
2575 | 37 | res := filterByLevel(5, 5, payloads) | 38 | res := filterByLevel(5, 5, notifs) |
2576 | 38 | c.Check(len(res), Equals, 0) | 39 | c.Check(len(res), Equals, 0) |
2578 | 39 | res = filterByLevel(4, 5, payloads) | 40 | res = filterByLevel(4, 5, notifs) |
2579 | 40 | c.Check(len(res), Equals, 1) | 41 | c.Check(len(res), Equals, 1) |
2582 | 41 | c.Check(res[0], DeepEquals, json.RawMessage(`{"a": 5}`)) | 42 | c.Check(res[0].Payload, DeepEquals, json.RawMessage(`{"a": 5}`)) |
2583 | 42 | res = filterByLevel(3, 5, payloads) | 43 | res = filterByLevel(3, 5, notifs) |
2584 | 43 | c.Check(len(res), Equals, 2) | 44 | c.Check(len(res), Equals, 2) |
2587 | 44 | c.Check(res[0], DeepEquals, json.RawMessage(`{"a": 4}`)) | 45 | c.Check(res[0].Payload, DeepEquals, json.RawMessage(`{"a": 4}`)) |
2588 | 45 | res = filterByLevel(2, 5, payloads) | 46 | res = filterByLevel(2, 5, notifs) |
2589 | 46 | c.Check(len(res), Equals, 3) | 47 | c.Check(len(res), Equals, 3) |
2591 | 47 | res = filterByLevel(1, 5, payloads) | 48 | res = filterByLevel(1, 5, notifs) |
2592 | 48 | c.Check(len(res), Equals, 3) | 49 | c.Check(len(res), Equals, 3) |
2593 | 49 | // too ahead, pick only last | 50 | // too ahead, pick only last |
2595 | 50 | res = filterByLevel(10, 5, payloads) | 51 | res = filterByLevel(10, 5, notifs) |
2596 | 51 | c.Check(len(res), Equals, 1) | 52 | c.Check(len(res), Equals, 1) |
2598 | 52 | c.Check(res[0], DeepEquals, json.RawMessage(`{"a": 5}`)) | 53 | c.Check(res[0].Payload, DeepEquals, json.RawMessage(`{"a": 5}`)) |
2599 | 53 | } | 54 | } |
2600 | 54 | 55 | ||
2601 | 55 | func (s *exchangesImplSuite) TestFilterByLevelEmpty(c *C) { | 56 | func (s *exchangesImplSuite) TestFilterByLevelEmpty(c *C) { |
2602 | @@ -71,18 +72,19 @@ | |||
2603 | 71 | err := json.Unmarshal(p, &decoded[i]) | 72 | err := json.Unmarshal(p, &decoded[i]) |
2604 | 72 | c.Assert(err, IsNil) | 73 | c.Assert(err, IsNil) |
2605 | 73 | } | 74 | } |
2606 | 75 | notifs := help.Ns(payloads...) | ||
2607 | 74 | 76 | ||
2608 | 75 | other := store.InternalChannelId("1") | 77 | other := store.InternalChannelId("1") |
2609 | 76 | 78 | ||
2610 | 77 | c.Check(channelFilter("", store.SystemInternalChannelId, nil, nil), IsNil) | 79 | c.Check(channelFilter("", store.SystemInternalChannelId, nil, nil), IsNil) |
2612 | 78 | c.Check(channelFilter("", other, payloads[1:], decoded), DeepEquals, payloads[1:]) | 80 | c.Check(channelFilter("", other, notifs[1:], decoded), DeepEquals, payloads[1:]) |
2613 | 79 | 81 | ||
2614 | 80 | // use tag when channel is the sytem channel | 82 | // use tag when channel is the sytem channel |
2615 | 81 | 83 | ||
2621 | 82 | c.Check(channelFilter("c/z", store.SystemInternalChannelId, payloads, decoded), HasLen, 0) | 84 | c.Check(channelFilter("c/z", store.SystemInternalChannelId, notifs, decoded), HasLen, 0) |
2622 | 83 | 85 | ||
2623 | 84 | c.Check(channelFilter("a/x", store.SystemInternalChannelId, payloads, decoded), DeepEquals, []json.RawMessage{payloads[0], payloads[3]}) | 86 | c.Check(channelFilter("a/x", store.SystemInternalChannelId, notifs, decoded), DeepEquals, []json.RawMessage{payloads[0], payloads[3]}) |
2624 | 85 | 87 | ||
2625 | 86 | c.Check(channelFilter("a/x", store.SystemInternalChannelId, payloads[1:], decoded), DeepEquals, []json.RawMessage{payloads[3]}) | 88 | c.Check(channelFilter("a/x", store.SystemInternalChannelId, notifs[1:], decoded), DeepEquals, []json.RawMessage{payloads[3]}) |
2626 | 87 | 89 | ||
2627 | 88 | } | 90 | } |
2628 | 89 | 91 | ||
2629 | === modified file 'server/broker/simple/simple.go' | |||
2630 | --- server/broker/simple/simple.go 2014-04-11 08:47:18 +0000 | |||
2631 | +++ server/broker/simple/simple.go 2014-04-29 18:02:00 +0000 | |||
2632 | @@ -144,7 +144,7 @@ | |||
2633 | 144 | // find relevant channels, for now only system | 144 | // find relevant channels, for now only system |
2634 | 145 | channels := []store.InternalChannelId{store.SystemInternalChannelId} | 145 | channels := []store.InternalChannelId{store.SystemInternalChannelId} |
2635 | 146 | for _, chanId := range channels { | 146 | for _, chanId := range channels { |
2637 | 147 | topLevel, payloads, err := b.sto.GetChannelSnapshot(chanId) | 147 | topLevel, notifications, err := b.sto.GetChannelSnapshot(chanId) |
2638 | 148 | if err != nil { | 148 | if err != nil { |
2639 | 149 | // next broadcast will try again | 149 | // next broadcast will try again |
2640 | 150 | b.logger.Errorf("unsuccessful feed pending, get channel snapshot for %v: %v", chanId, err) | 150 | b.logger.Errorf("unsuccessful feed pending, get channel snapshot for %v: %v", chanId, err) |
2641 | @@ -153,9 +153,9 @@ | |||
2642 | 153 | clientLevel := sess.levels[chanId] | 153 | clientLevel := sess.levels[chanId] |
2643 | 154 | if clientLevel != topLevel { | 154 | if clientLevel != topLevel { |
2644 | 155 | broadcastExchg := &broker.BroadcastExchange{ | 155 | broadcastExchg := &broker.BroadcastExchange{ |
2648 | 156 | ChanId: chanId, | 156 | ChanId: chanId, |
2649 | 157 | TopLevel: topLevel, | 157 | TopLevel: topLevel, |
2650 | 158 | NotificationPayloads: payloads, | 158 | Notifications: notifications, |
2651 | 159 | } | 159 | } |
2652 | 160 | broadcastExchg.Init() | 160 | broadcastExchg.Init() |
2653 | 161 | sess.exchanges <- broadcastExchg | 161 | sess.exchanges <- broadcastExchg |
2654 | @@ -166,7 +166,7 @@ | |||
2655 | 166 | 166 | ||
2656 | 167 | // Register registers a session with the broker. It feeds the session | 167 | // Register registers a session with the broker. It feeds the session |
2657 | 168 | // pending notifications as well. | 168 | // pending notifications as well. |
2659 | 169 | func (b *SimpleBroker) Register(connect *protocol.ConnectMsg) (broker.BrokerSession, error) { | 169 | func (b *SimpleBroker) Register(connect *protocol.ConnectMsg, sessionId string) (broker.BrokerSession, error) { |
2660 | 170 | // xxx sanity check DeviceId | 170 | // xxx sanity check DeviceId |
2661 | 171 | model, err := broker.GetInfoString(connect, "device", "?") | 171 | model, err := broker.GetInfoString(connect, "device", "?") |
2662 | 172 | if err != nil { | 172 | if err != nil { |
2663 | @@ -224,7 +224,7 @@ | |||
2664 | 224 | } else { // register | 224 | } else { // register |
2665 | 225 | prev := b.registry[sess.deviceId] | 225 | prev := b.registry[sess.deviceId] |
2666 | 226 | if prev != nil { // kick it | 226 | if prev != nil { // kick it |
2668 | 227 | close(prev.exchanges) | 227 | prev.exchanges <- nil |
2669 | 228 | } | 228 | } |
2670 | 229 | b.registry[sess.deviceId] = sess | 229 | b.registry[sess.deviceId] = sess |
2671 | 230 | sess.registered = true | 230 | sess.registered = true |
2672 | @@ -233,16 +233,16 @@ | |||
2673 | 233 | case delivery := <-b.deliveryCh: | 233 | case delivery := <-b.deliveryCh: |
2674 | 234 | switch delivery.kind { | 234 | switch delivery.kind { |
2675 | 235 | case broadcastDelivery: | 235 | case broadcastDelivery: |
2677 | 236 | topLevel, payloads, err := b.sto.GetChannelSnapshot(delivery.chanId) | 236 | topLevel, notifications, err := b.sto.GetChannelSnapshot(delivery.chanId) |
2678 | 237 | if err != nil { | 237 | if err != nil { |
2679 | 238 | // next broadcast will try again | 238 | // next broadcast will try again |
2680 | 239 | b.logger.Errorf("unsuccessful broadcast, get channel snapshot for %v: %v", delivery.chanId, err) | 239 | b.logger.Errorf("unsuccessful broadcast, get channel snapshot for %v: %v", delivery.chanId, err) |
2681 | 240 | continue Loop | 240 | continue Loop |
2682 | 241 | } | 241 | } |
2683 | 242 | broadcastExchg := &broker.BroadcastExchange{ | 242 | broadcastExchg := &broker.BroadcastExchange{ |
2687 | 243 | ChanId: delivery.chanId, | 243 | ChanId: delivery.chanId, |
2688 | 244 | TopLevel: topLevel, | 244 | TopLevel: topLevel, |
2689 | 245 | NotificationPayloads: payloads, | 245 | Notifications: notifications, |
2690 | 246 | } | 246 | } |
2691 | 247 | broadcastExchg.Init() | 247 | broadcastExchg.Init() |
2692 | 248 | for _, sess := range b.registry { | 248 | for _, sess := range b.registry { |
2693 | 249 | 249 | ||
2694 | === modified file 'server/broker/simple/simple_test.go' | |||
2695 | --- server/broker/simple/simple_test.go 2014-04-03 16:00:53 +0000 | |||
2696 | +++ server/broker/simple/simple_test.go 2014-04-29 18:02:00 +0000 | |||
2697 | @@ -26,6 +26,7 @@ | |||
2698 | 26 | "launchpad.net/ubuntu-push/server/broker" | 26 | "launchpad.net/ubuntu-push/server/broker" |
2699 | 27 | "launchpad.net/ubuntu-push/server/broker/testing" | 27 | "launchpad.net/ubuntu-push/server/broker/testing" |
2700 | 28 | "launchpad.net/ubuntu-push/server/store" | 28 | "launchpad.net/ubuntu-push/server/store" |
2701 | 29 | help "launchpad.net/ubuntu-push/testing" | ||
2702 | 29 | ) | 30 | ) |
2703 | 30 | 31 | ||
2704 | 31 | func TestSimple(t *stdtesting.T) { TestingT(t) } | 32 | func TestSimple(t *stdtesting.T) { TestingT(t) } |
2705 | @@ -58,10 +59,10 @@ | |||
2706 | 58 | c.Assert(len(sess.exchanges), Equals, 1) | 59 | c.Assert(len(sess.exchanges), Equals, 1) |
2707 | 59 | exchg1 := <-sess.exchanges | 60 | exchg1 := <-sess.exchanges |
2708 | 60 | c.Check(exchg1, DeepEquals, &broker.BroadcastExchange{ | 61 | c.Check(exchg1, DeepEquals, &broker.BroadcastExchange{ |
2713 | 61 | ChanId: store.SystemInternalChannelId, | 62 | ChanId: store.SystemInternalChannelId, |
2714 | 62 | TopLevel: 1, | 63 | TopLevel: 1, |
2715 | 63 | NotificationPayloads: []json.RawMessage{notification1}, | 64 | Notifications: help.Ns(notification1), |
2716 | 64 | Decoded: []map[string]interface{}{decoded1}, | 65 | Decoded: []map[string]interface{}{decoded1}, |
2717 | 65 | }) | 66 | }) |
2718 | 66 | } | 67 | } |
2719 | 67 | 68 | ||
2720 | 68 | 69 | ||
2721 | === modified file 'server/broker/testsuite/suite.go' | |||
2722 | --- server/broker/testsuite/suite.go 2014-04-11 08:47:18 +0000 | |||
2723 | +++ server/broker/testsuite/suite.go 2014-04-29 18:02:00 +0000 | |||
2724 | @@ -30,7 +30,7 @@ | |||
2725 | 30 | "launchpad.net/ubuntu-push/server/broker" | 30 | "launchpad.net/ubuntu-push/server/broker" |
2726 | 31 | "launchpad.net/ubuntu-push/server/broker/testing" | 31 | "launchpad.net/ubuntu-push/server/broker/testing" |
2727 | 32 | "launchpad.net/ubuntu-push/server/store" | 32 | "launchpad.net/ubuntu-push/server/store" |
2729 | 33 | helpers "launchpad.net/ubuntu-push/testing" | 33 | help "launchpad.net/ubuntu-push/testing" |
2730 | 34 | ) | 34 | ) |
2731 | 35 | 35 | ||
2732 | 36 | // The expected interface for tested brokers. | 36 | // The expected interface for tested brokers. |
2733 | @@ -51,11 +51,11 @@ | |||
2734 | 51 | // Let us get to a broker.BroadcastExchange from an Exchange. | 51 | // Let us get to a broker.BroadcastExchange from an Exchange. |
2735 | 52 | RevealBroadcastExchange func(broker.Exchange) *broker.BroadcastExchange | 52 | RevealBroadcastExchange func(broker.Exchange) *broker.BroadcastExchange |
2736 | 53 | // private | 53 | // private |
2738 | 54 | testlog *helpers.TestLogger | 54 | testlog *help.TestLogger |
2739 | 55 | } | 55 | } |
2740 | 56 | 56 | ||
2741 | 57 | func (s *CommonBrokerSuite) SetUpTest(c *C) { | 57 | func (s *CommonBrokerSuite) SetUpTest(c *C) { |
2743 | 58 | s.testlog = helpers.NewTestLogger(c, "error") | 58 | s.testlog = help.NewTestLogger(c, "error") |
2744 | 59 | } | 59 | } |
2745 | 60 | 60 | ||
2746 | 61 | var testBrokerConfig = &testing.TestBrokerConfig{10, 5} | 61 | var testBrokerConfig = &testing.TestBrokerConfig{10, 5} |
2747 | @@ -89,7 +89,7 @@ | |||
2748 | 89 | "device": "model", | 89 | "device": "model", |
2749 | 90 | "channel": "daily", | 90 | "channel": "daily", |
2750 | 91 | }, | 91 | }, |
2752 | 92 | }) | 92 | }, "s1") |
2753 | 93 | c.Assert(err, IsNil) | 93 | c.Assert(err, IsNil) |
2754 | 94 | c.Assert(s.RevealSession(b, "dev-1"), Equals, sess) | 94 | c.Assert(s.RevealSession(b, "dev-1"), Equals, sess) |
2755 | 95 | c.Assert(sess.DeviceIdentifier(), Equals, "dev-1") | 95 | c.Assert(sess.DeviceIdentifier(), Equals, "dev-1") |
2756 | @@ -101,7 +101,7 @@ | |||
2757 | 101 | })) | 101 | })) |
2758 | 102 | b.Unregister(sess) | 102 | b.Unregister(sess) |
2759 | 103 | // just to make sure the unregister was processed | 103 | // just to make sure the unregister was processed |
2761 | 104 | _, err = b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: ""}) | 104 | _, err = b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: ""}, "s2") |
2762 | 105 | c.Assert(err, IsNil) | 105 | c.Assert(err, IsNil) |
2763 | 106 | c.Check(s.RevealSession(b, "dev-1"), IsNil) | 106 | c.Check(s.RevealSession(b, "dev-1"), IsNil) |
2764 | 107 | } | 107 | } |
2765 | @@ -111,7 +111,7 @@ | |||
2766 | 111 | b := s.MakeBroker(sto, testBrokerConfig, nil) | 111 | b := s.MakeBroker(sto, testBrokerConfig, nil) |
2767 | 112 | b.Start() | 112 | b.Start() |
2768 | 113 | defer b.Stop() | 113 | defer b.Stop() |
2770 | 114 | _, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev-1", Levels: map[string]int64{"z": 5}}) | 114 | _, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev-1", Levels: map[string]int64{"z": 5}}, "s1") |
2771 | 115 | c.Check(err, FitsTypeOf, &broker.ErrAbort{}) | 115 | c.Check(err, FitsTypeOf, &broker.ErrAbort{}) |
2772 | 116 | } | 116 | } |
2773 | 117 | 117 | ||
2774 | @@ -123,11 +123,11 @@ | |||
2775 | 123 | info := map[string]interface{}{ | 123 | info := map[string]interface{}{ |
2776 | 124 | "device": -1, | 124 | "device": -1, |
2777 | 125 | } | 125 | } |
2779 | 126 | _, err := b.Register(&protocol.ConnectMsg{Type: "connect", Info: info}) | 126 | _, err := b.Register(&protocol.ConnectMsg{Type: "connect", Info: info}, "s1") |
2780 | 127 | c.Check(err, Equals, broker.ErrUnexpectedValue) | 127 | c.Check(err, Equals, broker.ErrUnexpectedValue) |
2781 | 128 | info["device"] = "m" | 128 | info["device"] = "m" |
2782 | 129 | info["channel"] = -1 | 129 | info["channel"] = -1 |
2784 | 130 | _, err = b.Register(&protocol.ConnectMsg{Type: "connect", Info: info}) | 130 | _, err = b.Register(&protocol.ConnectMsg{Type: "connect", Info: info}, "s2") |
2785 | 131 | c.Check(err, Equals, broker.ErrUnexpectedValue) | 131 | c.Check(err, Equals, broker.ErrUnexpectedValue) |
2786 | 132 | } | 132 | } |
2787 | 133 | 133 | ||
2788 | @@ -139,7 +139,7 @@ | |||
2789 | 139 | b := s.MakeBroker(sto, testBrokerConfig, nil) | 139 | b := s.MakeBroker(sto, testBrokerConfig, nil) |
2790 | 140 | b.Start() | 140 | b.Start() |
2791 | 141 | defer b.Stop() | 141 | defer b.Stop() |
2793 | 142 | sess, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev-1"}) | 142 | sess, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev-1"}, "s1") |
2794 | 143 | c.Assert(err, IsNil) | 143 | c.Assert(err, IsNil) |
2795 | 144 | c.Check(len(sess.SessionChannel()), Equals, 1) | 144 | c.Check(len(sess.SessionChannel()), Equals, 1) |
2796 | 145 | } | 145 | } |
2797 | @@ -149,7 +149,7 @@ | |||
2798 | 149 | b := s.MakeBroker(sto, testBrokerConfig, s.testlog) | 149 | b := s.MakeBroker(sto, testBrokerConfig, s.testlog) |
2799 | 150 | b.Start() | 150 | b.Start() |
2800 | 151 | defer b.Stop() | 151 | defer b.Stop() |
2802 | 152 | _, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev-1"}) | 152 | _, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev-1"}, "s1") |
2803 | 153 | c.Assert(err, IsNil) | 153 | c.Assert(err, IsNil) |
2804 | 154 | // but | 154 | // but |
2805 | 155 | c.Check(s.testlog.Captured(), Matches, "ERROR unsuccessful feed pending, get channel snapshot for 0: get channel snapshot fail\n") | 155 | c.Check(s.testlog.Captured(), Matches, "ERROR unsuccessful feed pending, get channel snapshot for 0: get channel snapshot fail\n") |
2806 | @@ -160,22 +160,25 @@ | |||
2807 | 160 | b := s.MakeBroker(sto, testBrokerConfig, nil) | 160 | b := s.MakeBroker(sto, testBrokerConfig, nil) |
2808 | 161 | b.Start() | 161 | b.Start() |
2809 | 162 | defer b.Stop() | 162 | defer b.Stop() |
2816 | 163 | sess1, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev-1"}) | 163 | sess1, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev-1"}, "s1") |
2817 | 164 | c.Assert(err, IsNil) | 164 | c.Assert(err, IsNil) |
2818 | 165 | sess2, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev-1"}) | 165 | sess2, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev-1"}, "s2") |
2819 | 166 | c.Assert(err, IsNil) | 166 | c.Assert(err, IsNil) |
2820 | 167 | checkAndFalse := false | 167 | // previous session got signaled by sending nil on its channel |
2821 | 168 | // previous session got signaled by closing its channel | 168 | var sentinel broker.Exchange |
2822 | 169 | got := false | ||
2823 | 169 | select { | 170 | select { |
2827 | 170 | case _, ok := <-sess1.SessionChannel(): | 171 | case sentinel = <-sess1.SessionChannel(): |
2828 | 171 | checkAndFalse = ok == false | 172 | got = true |
2829 | 172 | default: | 173 | case <-time.After(5 * time.Second): |
2830 | 174 | c.Fatal("taking too long to get sentinel") | ||
2831 | 173 | } | 175 | } |
2833 | 174 | c.Check(checkAndFalse, Equals, true) | 176 | c.Check(got, Equals, true) |
2834 | 177 | c.Check(sentinel, IsNil) | ||
2835 | 175 | c.Assert(s.RevealSession(b, "dev-1"), Equals, sess2) | 178 | c.Assert(s.RevealSession(b, "dev-1"), Equals, sess2) |
2836 | 176 | b.Unregister(sess1) | 179 | b.Unregister(sess1) |
2837 | 177 | // just to make sure the unregister was processed | 180 | // just to make sure the unregister was processed |
2839 | 178 | _, err = b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: ""}) | 181 | _, err = b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: ""}, "s3") |
2840 | 179 | c.Assert(err, IsNil) | 182 | c.Assert(err, IsNil) |
2841 | 180 | c.Check(s.RevealSession(b, "dev-1"), Equals, sess2) | 183 | c.Check(s.RevealSession(b, "dev-1"), Equals, sess2) |
2842 | 181 | } | 184 | } |
2843 | @@ -187,9 +190,9 @@ | |||
2844 | 187 | b := s.MakeBroker(sto, testBrokerConfig, nil) | 190 | b := s.MakeBroker(sto, testBrokerConfig, nil) |
2845 | 188 | b.Start() | 191 | b.Start() |
2846 | 189 | defer b.Stop() | 192 | defer b.Stop() |
2848 | 190 | sess1, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev-1"}) | 193 | sess1, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev-1"}, "s1") |
2849 | 191 | c.Assert(err, IsNil) | 194 | c.Assert(err, IsNil) |
2851 | 192 | sess2, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev-2"}) | 195 | sess2, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev-2"}, "s2") |
2852 | 193 | c.Assert(err, IsNil) | 196 | c.Assert(err, IsNil) |
2853 | 194 | // add notification to channel *after* the registrations | 197 | // add notification to channel *after* the registrations |
2854 | 195 | muchLater := time.Now().Add(10 * time.Minute) | 198 | muchLater := time.Now().Add(10 * time.Minute) |
2855 | @@ -200,10 +203,10 @@ | |||
2856 | 200 | c.Fatal("taking too long to get broadcast exchange") | 203 | c.Fatal("taking too long to get broadcast exchange") |
2857 | 201 | case exchg1 := <-sess1.SessionChannel(): | 204 | case exchg1 := <-sess1.SessionChannel(): |
2858 | 202 | c.Check(s.RevealBroadcastExchange(exchg1), DeepEquals, &broker.BroadcastExchange{ | 205 | c.Check(s.RevealBroadcastExchange(exchg1), DeepEquals, &broker.BroadcastExchange{ |
2863 | 203 | ChanId: store.SystemInternalChannelId, | 206 | ChanId: store.SystemInternalChannelId, |
2864 | 204 | TopLevel: 1, | 207 | TopLevel: 1, |
2865 | 205 | NotificationPayloads: []json.RawMessage{notification1}, | 208 | Notifications: help.Ns(notification1), |
2866 | 206 | Decoded: []map[string]interface{}{decoded1}, | 209 | Decoded: []map[string]interface{}{decoded1}, |
2867 | 207 | }) | 210 | }) |
2868 | 208 | } | 211 | } |
2869 | 209 | select { | 212 | select { |
2870 | @@ -211,10 +214,10 @@ | |||
2871 | 211 | c.Fatal("taking too long to get broadcast exchange") | 214 | c.Fatal("taking too long to get broadcast exchange") |
2872 | 212 | case exchg2 := <-sess2.SessionChannel(): | 215 | case exchg2 := <-sess2.SessionChannel(): |
2873 | 213 | c.Check(s.RevealBroadcastExchange(exchg2), DeepEquals, &broker.BroadcastExchange{ | 216 | c.Check(s.RevealBroadcastExchange(exchg2), DeepEquals, &broker.BroadcastExchange{ |
2878 | 214 | ChanId: store.SystemInternalChannelId, | 217 | ChanId: store.SystemInternalChannelId, |
2879 | 215 | TopLevel: 1, | 218 | TopLevel: 1, |
2880 | 216 | NotificationPayloads: []json.RawMessage{notification1}, | 219 | Notifications: help.Ns(notification1), |
2881 | 217 | Decoded: []map[string]interface{}{decoded1}, | 220 | Decoded: []map[string]interface{}{decoded1}, |
2882 | 218 | }) | 221 | }) |
2883 | 219 | } | 222 | } |
2884 | 220 | } | 223 | } |
2885 | @@ -224,7 +227,7 @@ | |||
2886 | 224 | countdownToFail int | 227 | countdownToFail int |
2887 | 225 | } | 228 | } |
2888 | 226 | 229 | ||
2890 | 227 | func (sto *testFailingStore) GetChannelSnapshot(chanId store.InternalChannelId) (int64, []json.RawMessage, error) { | 230 | func (sto *testFailingStore) GetChannelSnapshot(chanId store.InternalChannelId) (int64, []protocol.Notification, error) { |
2891 | 228 | if sto.countdownToFail == 0 { | 231 | if sto.countdownToFail == 0 { |
2892 | 229 | return 0, nil, errors.New("get channel snapshot fail") | 232 | return 0, nil, errors.New("get channel snapshot fail") |
2893 | 230 | } | 233 | } |
2894 | @@ -241,7 +244,7 @@ | |||
2895 | 241 | b := s.MakeBroker(sto, testBrokerConfig, s.testlog) | 244 | b := s.MakeBroker(sto, testBrokerConfig, s.testlog) |
2896 | 242 | b.Start() | 245 | b.Start() |
2897 | 243 | defer b.Stop() | 246 | defer b.Stop() |
2899 | 244 | _, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev-1"}) | 247 | _, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev-1"}, "s1") |
2900 | 245 | c.Assert(err, IsNil) | 248 | c.Assert(err, IsNil) |
2901 | 246 | b.Broadcast(store.SystemInternalChannelId) | 249 | b.Broadcast(store.SystemInternalChannelId) |
2902 | 247 | select { | 250 | select { |
2903 | 248 | 251 | ||
2904 | === modified file 'server/session/session.go' | |||
2905 | --- server/session/session.go 2014-04-11 08:47:18 +0000 | |||
2906 | +++ server/session/session.go 2014-04-29 18:02:00 +0000 | |||
2907 | @@ -18,6 +18,7 @@ | |||
2908 | 18 | package session | 18 | package session |
2909 | 19 | 19 | ||
2910 | 20 | import ( | 20 | import ( |
2911 | 21 | "errors" | ||
2912 | 21 | "net" | 22 | "net" |
2913 | 22 | "time" | 23 | "time" |
2914 | 23 | 24 | ||
2915 | @@ -35,7 +36,7 @@ | |||
2916 | 35 | } | 36 | } |
2917 | 36 | 37 | ||
2918 | 37 | // sessionStart manages the start of the protocol session. | 38 | // sessionStart manages the start of the protocol session. |
2920 | 38 | func sessionStart(proto protocol.Protocol, brkr broker.Broker, cfg SessionConfig) (broker.BrokerSession, error) { | 39 | func sessionStart(proto protocol.Protocol, brkr broker.Broker, cfg SessionConfig, sessionId string) (broker.BrokerSession, error) { |
2921 | 39 | var connMsg protocol.ConnectMsg | 40 | var connMsg protocol.ConnectMsg |
2922 | 40 | proto.SetDeadline(time.Now().Add(cfg.ExchangeTimeout())) | 41 | proto.SetDeadline(time.Now().Add(cfg.ExchangeTimeout())) |
2923 | 41 | err := proto.ReadMessage(&connMsg) | 42 | err := proto.ReadMessage(&connMsg) |
2924 | @@ -52,9 +53,11 @@ | |||
2925 | 52 | if err != nil { | 53 | if err != nil { |
2926 | 53 | return nil, err | 54 | return nil, err |
2927 | 54 | } | 55 | } |
2929 | 55 | return brkr.Register(&connMsg) | 56 | return brkr.Register(&connMsg, sessionId) |
2930 | 56 | } | 57 | } |
2931 | 57 | 58 | ||
2932 | 59 | var errOneway = errors.New("oneway") | ||
2933 | 60 | |||
2934 | 58 | // exchange writes outMsg message, reads answer in inMsg | 61 | // exchange writes outMsg message, reads answer in inMsg |
2935 | 59 | func exchange(proto protocol.Protocol, outMsg, inMsg interface{}, exchangeTimeout time.Duration) error { | 62 | func exchange(proto protocol.Protocol, outMsg, inMsg interface{}, exchangeTimeout time.Duration) error { |
2936 | 60 | proto.SetDeadline(time.Now().Add(exchangeTimeout)) | 63 | proto.SetDeadline(time.Now().Add(exchangeTimeout)) |
2937 | @@ -62,7 +65,10 @@ | |||
2938 | 62 | if err != nil { | 65 | if err != nil { |
2939 | 63 | return err | 66 | return err |
2940 | 64 | } | 67 | } |
2942 | 65 | if inMsg == nil { // no answer expected, breaking connection | 68 | if inMsg == nil { // no answer expected |
2943 | 69 | if outMsg.(protocol.OnewayMsg).OnewayContinue() { | ||
2944 | 70 | return errOneway | ||
2945 | 71 | } | ||
2946 | 66 | return &broker.ErrAbort{"session broken for reason"} | 72 | return &broker.ErrAbort{"session broken for reason"} |
2947 | 67 | } | 73 | } |
2948 | 68 | err = proto.ReadMessage(inMsg) | 74 | err = proto.ReadMessage(inMsg) |
2949 | @@ -78,6 +84,10 @@ | |||
2950 | 78 | exchangeTimeout := cfg.ExchangeTimeout() | 84 | exchangeTimeout := cfg.ExchangeTimeout() |
2951 | 79 | pingTimer := time.NewTimer(pingInterval) | 85 | pingTimer := time.NewTimer(pingInterval) |
2952 | 80 | intervalStart := time.Now() | 86 | intervalStart := time.Now() |
2953 | 87 | pingTimerReset := func() { | ||
2954 | 88 | pingTimer.Reset(pingInterval) | ||
2955 | 89 | intervalStart = time.Now() | ||
2956 | 90 | } | ||
2957 | 81 | ch := sess.SessionChannel() | 91 | ch := sess.SessionChannel() |
2958 | 82 | Loop: | 92 | Loop: |
2959 | 83 | for { | 93 | for { |
2960 | @@ -93,16 +103,15 @@ | |||
2961 | 93 | if pongMsg.Type != "pong" { | 103 | if pongMsg.Type != "pong" { |
2962 | 94 | return &broker.ErrAbort{"expected PONG message"} | 104 | return &broker.ErrAbort{"expected PONG message"} |
2963 | 95 | } | 105 | } |
2966 | 96 | pingTimer.Reset(pingInterval) | 106 | pingTimerReset() |
2967 | 97 | case exchg, ok := <-ch: | 107 | case exchg := <-ch: |
2968 | 98 | pingTimer.Stop() | 108 | pingTimer.Stop() |
2970 | 99 | if !ok { | 109 | if exchg == nil { |
2971 | 100 | return &broker.ErrAbort{"terminated"} | 110 | return &broker.ErrAbort{"terminated"} |
2972 | 101 | } | 111 | } |
2973 | 102 | outMsg, inMsg, err := exchg.Prepare(sess) | 112 | outMsg, inMsg, err := exchg.Prepare(sess) |
2974 | 103 | if err == broker.ErrNop { // nothing to do | 113 | if err == broker.ErrNop { // nothing to do |
2977 | 104 | pingTimer.Reset(pingInterval) | 114 | pingTimerReset() |
2976 | 105 | intervalStart = time.Now() | ||
2978 | 106 | continue Loop | 115 | continue Loop |
2979 | 107 | } | 116 | } |
2980 | 108 | if err != nil { | 117 | if err != nil { |
2981 | @@ -111,12 +120,15 @@ | |||
2982 | 111 | for { | 120 | for { |
2983 | 112 | done := outMsg.Split() | 121 | done := outMsg.Split() |
2984 | 113 | err = exchange(proto, outMsg, inMsg, exchangeTimeout) | 122 | err = exchange(proto, outMsg, inMsg, exchangeTimeout) |
2985 | 123 | if err == errOneway { | ||
2986 | 124 | pingTimerReset() | ||
2987 | 125 | continue Loop | ||
2988 | 126 | } | ||
2989 | 114 | if err != nil { | 127 | if err != nil { |
2990 | 115 | return err | 128 | return err |
2991 | 116 | } | 129 | } |
2992 | 117 | if done { | 130 | if done { |
2995 | 118 | pingTimer.Reset(pingInterval) | 131 | pingTimerReset() |
2994 | 119 | intervalStart = time.Now() | ||
2996 | 120 | } | 132 | } |
2997 | 121 | err = exchg.Acked(sess, done) | 133 | err = exchg.Acked(sess, done) |
2998 | 122 | if err != nil { | 134 | if err != nil { |
2999 | @@ -142,7 +154,7 @@ | |||
3000 | 142 | return track.End(&broker.ErrAbort{"unexpected wire format version"}) | 154 | return track.End(&broker.ErrAbort{"unexpected wire format version"}) |
3001 | 143 | } | 155 | } |
3002 | 144 | proto := protocol.NewProtocol0(conn) | 156 | proto := protocol.NewProtocol0(conn) |
3004 | 145 | sess, err := sessionStart(proto, brkr, cfg) | 157 | sess, err := sessionStart(proto, brkr, cfg, track.SessionId()) |
3005 | 146 | if err != nil { | 158 | if err != nil { |
3006 | 147 | return track.End(err) | 159 | return track.End(err) |
3007 | 148 | } | 160 | } |
3008 | 149 | 161 | ||
3009 | === modified file 'server/session/session_test.go' | |||
3010 | --- server/session/session_test.go 2014-04-11 08:47:18 +0000 | |||
3011 | +++ server/session/session_test.go 2014-04-29 18:02:00 +0000 | |||
3012 | @@ -130,8 +130,8 @@ | |||
3013 | 130 | return &testBroker{registration: make(chan interface{}, 2)} | 130 | return &testBroker{registration: make(chan interface{}, 2)} |
3014 | 131 | } | 131 | } |
3015 | 132 | 132 | ||
3018 | 133 | func (tb *testBroker) Register(connect *protocol.ConnectMsg) (broker.BrokerSession, error) { | 133 | func (tb *testBroker) Register(connect *protocol.ConnectMsg, sessionId string) (broker.BrokerSession, error) { |
3019 | 134 | tb.registration <- "register " + connect.DeviceId | 134 | tb.registration <- fmt.Sprintf("register %s %s", connect.DeviceId, sessionId) |
3020 | 135 | return &testing.TestBrokerSession{DeviceId: connect.DeviceId}, tb.err | 135 | return &testing.TestBrokerSession{DeviceId: connect.DeviceId}, tb.err |
3021 | 136 | } | 136 | } |
3022 | 137 | 137 | ||
3023 | @@ -148,7 +148,7 @@ | |||
3024 | 148 | brkr := newTestBroker() | 148 | brkr := newTestBroker() |
3025 | 149 | go func() { | 149 | go func() { |
3026 | 150 | var err error | 150 | var err error |
3028 | 151 | sess, err = sessionStart(tp, brkr, cfg10msPingInterval5msExchangeTout) | 151 | sess, err = sessionStart(tp, brkr, cfg10msPingInterval5msExchangeTout, "s1") |
3029 | 152 | errCh <- err | 152 | errCh <- err |
3030 | 153 | }() | 153 | }() |
3031 | 154 | c.Check(takeNext(down), Equals, "deadline 5ms") | 154 | c.Check(takeNext(down), Equals, "deadline 5ms") |
3032 | @@ -160,7 +160,7 @@ | |||
3033 | 160 | up <- nil // no write error | 160 | up <- nil // no write error |
3034 | 161 | err := <-errCh | 161 | err := <-errCh |
3035 | 162 | c.Check(err, IsNil) | 162 | c.Check(err, IsNil) |
3037 | 163 | c.Check(takeNext(brkr.registration), Equals, "register dev-1") | 163 | c.Check(takeNext(brkr.registration), Equals, "register dev-1 s1") |
3038 | 164 | c.Check(sess.DeviceIdentifier(), Equals, "dev-1") | 164 | c.Check(sess.DeviceIdentifier(), Equals, "dev-1") |
3039 | 165 | } | 165 | } |
3040 | 166 | 166 | ||
3041 | @@ -175,7 +175,7 @@ | |||
3042 | 175 | brkr.err = errRegister | 175 | brkr.err = errRegister |
3043 | 176 | go func() { | 176 | go func() { |
3044 | 177 | var err error | 177 | var err error |
3046 | 178 | sess, err = sessionStart(tp, brkr, cfg10msPingInterval5msExchangeTout) | 178 | sess, err = sessionStart(tp, brkr, cfg10msPingInterval5msExchangeTout, "s2") |
3047 | 179 | errCh <- err | 179 | errCh <- err |
3048 | 180 | }() | 180 | }() |
3049 | 181 | up <- protocol.ConnectMsg{Type: "connect", ClientVer: "1", DeviceId: "dev-1"} | 181 | up <- protocol.ConnectMsg{Type: "connect", ClientVer: "1", DeviceId: "dev-1"} |
3050 | @@ -190,7 +190,7 @@ | |||
3051 | 190 | down := make(chan interface{}, 5) | 190 | down := make(chan interface{}, 5) |
3052 | 191 | tp := &testProtocol{up, down} | 191 | tp := &testProtocol{up, down} |
3053 | 192 | up <- io.ErrUnexpectedEOF | 192 | up <- io.ErrUnexpectedEOF |
3055 | 193 | _, err := sessionStart(tp, nil, cfg10msPingInterval5msExchangeTout) | 193 | _, err := sessionStart(tp, nil, cfg10msPingInterval5msExchangeTout, "s3") |
3056 | 194 | c.Check(err, Equals, io.ErrUnexpectedEOF) | 194 | c.Check(err, Equals, io.ErrUnexpectedEOF) |
3057 | 195 | } | 195 | } |
3058 | 196 | 196 | ||
3059 | @@ -200,7 +200,7 @@ | |||
3060 | 200 | tp := &testProtocol{up, down} | 200 | tp := &testProtocol{up, down} |
3061 | 201 | up <- protocol.ConnectMsg{Type: "connect"} | 201 | up <- protocol.ConnectMsg{Type: "connect"} |
3062 | 202 | up <- io.ErrUnexpectedEOF | 202 | up <- io.ErrUnexpectedEOF |
3064 | 203 | _, err := sessionStart(tp, nil, cfg10msPingInterval5msExchangeTout) | 203 | _, err := sessionStart(tp, nil, cfg10msPingInterval5msExchangeTout, "s4") |
3065 | 204 | c.Check(err, Equals, io.ErrUnexpectedEOF) | 204 | c.Check(err, Equals, io.ErrUnexpectedEOF) |
3066 | 205 | // sanity | 205 | // sanity |
3067 | 206 | c.Check(takeNext(down), Matches, "deadline.*") | 206 | c.Check(takeNext(down), Matches, "deadline.*") |
3068 | @@ -212,7 +212,7 @@ | |||
3069 | 212 | down := make(chan interface{}, 5) | 212 | down := make(chan interface{}, 5) |
3070 | 213 | tp := &testProtocol{up, down} | 213 | tp := &testProtocol{up, down} |
3071 | 214 | up <- protocol.ConnectMsg{Type: "what"} | 214 | up <- protocol.ConnectMsg{Type: "what"} |
3073 | 215 | _, err := sessionStart(tp, nil, cfg10msPingInterval5msExchangeTout) | 215 | _, err := sessionStart(tp, nil, cfg10msPingInterval5msExchangeTout, "s5") |
3074 | 216 | c.Check(err, DeepEquals, &broker.ErrAbort{"expected CONNECT message"}) | 216 | c.Check(err, DeepEquals, &broker.ErrAbort{"expected CONNECT message"}) |
3075 | 217 | } | 217 | } |
3076 | 218 | 218 | ||
3077 | @@ -222,14 +222,14 @@ | |||
3078 | 222 | } | 222 | } |
3079 | 223 | 223 | ||
3080 | 224 | func (s *sessionSuite) TestSessionLoop(c *C) { | 224 | func (s *sessionSuite) TestSessionLoop(c *C) { |
3082 | 225 | nopTrack := NewTracker(s.testlog) | 225 | track := &testTracker{NewTracker(s.testlog), make(chan interface{}, 2)} |
3083 | 226 | errCh := make(chan error, 1) | 226 | errCh := make(chan error, 1) |
3084 | 227 | up := make(chan interface{}, 5) | 227 | up := make(chan interface{}, 5) |
3085 | 228 | down := make(chan interface{}, 5) | 228 | down := make(chan interface{}, 5) |
3086 | 229 | tp := &testProtocol{up, down} | 229 | tp := &testProtocol{up, down} |
3087 | 230 | sess := &testing.TestBrokerSession{} | 230 | sess := &testing.TestBrokerSession{} |
3088 | 231 | go func() { | 231 | go func() { |
3090 | 232 | errCh <- sessionLoop(tp, sess, cfg5msPingInterval2msExchangeTout, nopTrack) | 232 | errCh <- sessionLoop(tp, sess, cfg5msPingInterval2msExchangeTout, track) |
3091 | 233 | }() | 233 | }() |
3092 | 234 | c.Check(takeNext(down), Equals, "deadline 2ms") | 234 | c.Check(takeNext(down), Equals, "deadline 2ms") |
3093 | 235 | c.Check(takeNext(down), DeepEquals, protocol.PingPongMsg{Type: "ping"}) | 235 | c.Check(takeNext(down), DeepEquals, protocol.PingPongMsg{Type: "ping"}) |
3094 | @@ -241,6 +241,9 @@ | |||
3095 | 241 | up <- io.ErrUnexpectedEOF | 241 | up <- io.ErrUnexpectedEOF |
3096 | 242 | err := <-errCh | 242 | err := <-errCh |
3097 | 243 | c.Check(err, Equals, io.ErrUnexpectedEOF) | 243 | c.Check(err, Equals, io.ErrUnexpectedEOF) |
3098 | 244 | c.Check(track.interval, HasLen, 2) | ||
3099 | 245 | c.Check((<-track.interval).(time.Duration) <= 8*time.Millisecond, Equals, true) | ||
3100 | 246 | c.Check((<-track.interval).(time.Duration) <= 8*time.Millisecond, Equals, true) | ||
3101 | 244 | } | 247 | } |
3102 | 245 | 248 | ||
3103 | 246 | func (s *sessionSuite) TestSessionLoopWriteError(c *C) { | 249 | func (s *sessionSuite) TestSessionLoopWriteError(c *C) { |
3104 | @@ -357,7 +360,7 @@ | |||
3105 | 357 | go func() { | 360 | go func() { |
3106 | 358 | errCh <- sessionLoop(tp, sess, cfg5msPingInterval2msExchangeTout, nopTrack) | 361 | errCh <- sessionLoop(tp, sess, cfg5msPingInterval2msExchangeTout, nopTrack) |
3107 | 359 | }() | 362 | }() |
3109 | 360 | close(exchanges) | 363 | exchanges <- nil |
3110 | 361 | err := <-errCh | 364 | err := <-errCh |
3111 | 362 | c.Check(err, DeepEquals, &broker.ErrAbort{"terminated"}) | 365 | c.Check(err, DeepEquals, &broker.ErrAbort{"terminated"}) |
3112 | 363 | } | 366 | } |
3113 | @@ -477,18 +480,44 @@ | |||
3114 | 477 | down := make(chan interface{}, 5) | 480 | down := make(chan interface{}, 5) |
3115 | 478 | tp := &testProtocol{up, down} | 481 | tp := &testProtocol{up, down} |
3116 | 479 | exchanges := make(chan broker.Exchange, 1) | 482 | exchanges := make(chan broker.Exchange, 1) |
3118 | 480 | exchanges <- &broker.ConnBrokenExchange{"REASON"} | 483 | msg := &protocol.ConnBrokenMsg{"connbroken", "BREASON"} |
3119 | 484 | exchanges <- &broker.ConnMetaExchange{msg} | ||
3120 | 481 | sess := &testing.TestBrokerSession{Exchanges: exchanges} | 485 | sess := &testing.TestBrokerSession{Exchanges: exchanges} |
3121 | 482 | go func() { | 486 | go func() { |
3122 | 483 | errCh <- sessionLoop(tp, sess, cfg5msPingInterval2msExchangeTout, nopTrack) | 487 | errCh <- sessionLoop(tp, sess, cfg5msPingInterval2msExchangeTout, nopTrack) |
3123 | 484 | }() | 488 | }() |
3124 | 485 | c.Check(takeNext(down), Equals, "deadline 2ms") | 489 | c.Check(takeNext(down), Equals, "deadline 2ms") |
3126 | 486 | c.Check(takeNext(down), DeepEquals, protocol.ConnBrokenMsg{"connbroken", "REASON"}) | 490 | c.Check(takeNext(down), DeepEquals, protocol.ConnBrokenMsg{"connbroken", "BREASON"}) |
3127 | 487 | up <- nil // no write error | 491 | up <- nil // no write error |
3128 | 488 | err := <-errCh | 492 | err := <-errCh |
3129 | 489 | c.Check(err, DeepEquals, &broker.ErrAbort{"session broken for reason"}) | 493 | c.Check(err, DeepEquals, &broker.ErrAbort{"session broken for reason"}) |
3130 | 490 | } | 494 | } |
3131 | 491 | 495 | ||
3132 | 496 | func (s *sessionSuite) TestSessionLoopConnWarnExchange(c *C) { | ||
3133 | 497 | nopTrack := NewTracker(s.testlog) | ||
3134 | 498 | errCh := make(chan error, 1) | ||
3135 | 499 | up := make(chan interface{}, 5) | ||
3136 | 500 | down := make(chan interface{}, 5) | ||
3137 | 501 | tp := &testProtocol{up, down} | ||
3138 | 502 | exchanges := make(chan broker.Exchange, 1) | ||
3139 | 503 | msg := &protocol.ConnWarnMsg{"connwarn", "WREASON"} | ||
3140 | 504 | exchanges <- &broker.ConnMetaExchange{msg} | ||
3141 | 505 | sess := &testing.TestBrokerSession{Exchanges: exchanges} | ||
3142 | 506 | go func() { | ||
3143 | 507 | errCh <- sessionLoop(tp, sess, cfg5msPingInterval2msExchangeTout, nopTrack) | ||
3144 | 508 | }() | ||
3145 | 509 | c.Check(takeNext(down), Equals, "deadline 2ms") | ||
3146 | 510 | c.Check(takeNext(down), DeepEquals, protocol.ConnWarnMsg{"connwarn", "WREASON"}) | ||
3147 | 511 | up <- nil // no write error | ||
3148 | 512 | // session continues | ||
3149 | 513 | c.Check(takeNext(down), Equals, "deadline 2ms") | ||
3150 | 514 | c.Check(takeNext(down), DeepEquals, protocol.PingPongMsg{Type: "ping"}) | ||
3151 | 515 | up <- nil // no write error | ||
3152 | 516 | up <- io.EOF | ||
3153 | 517 | err := <-errCh | ||
3154 | 518 | c.Check(err, Equals, io.EOF) | ||
3155 | 519 | } | ||
3156 | 520 | |||
3157 | 492 | type testTracker struct { | 521 | type testTracker struct { |
3158 | 493 | SessionTracker | 522 | SessionTracker |
3159 | 494 | interval chan interface{} | 523 | interval chan interface{} |
3160 | @@ -593,7 +622,7 @@ | |||
3161 | 593 | msg, err = downStream.ReadBytes(byte('}')) | 622 | msg, err = downStream.ReadBytes(byte('}')) |
3162 | 594 | c.Check(err, IsNil) | 623 | c.Check(err, IsNil) |
3163 | 595 | c.Check(msg, DeepEquals, []byte("\x00\x0c{\"T\":\"ping\"}")) | 624 | c.Check(msg, DeepEquals, []byte("\x00\x0c{\"T\":\"ping\"}")) |
3165 | 596 | c.Check(takeNext(brkr.registration), Equals, "register DEV") | 625 | c.Check(takeNext(brkr.registration), Equals, "register DEV "+track.SessionId()) |
3166 | 597 | c.Check(len(brkr.registration), Equals, 0) // not yet unregistered | 626 | c.Check(len(brkr.registration), Equals, 0) // not yet unregistered |
3167 | 598 | cli.Close() | 627 | cli.Close() |
3168 | 599 | err = <-errCh | 628 | err = <-errCh |
3169 | 600 | 629 | ||
3170 | === modified file 'server/session/tracker.go' | |||
3171 | --- server/session/tracker.go 2014-02-10 23:19:08 +0000 | |||
3172 | +++ server/session/tracker.go 2014-04-29 18:02:00 +0000 | |||
3173 | @@ -17,6 +17,7 @@ | |||
3174 | 17 | package session | 17 | package session |
3175 | 18 | 18 | ||
3176 | 19 | import ( | 19 | import ( |
3177 | 20 | "fmt" | ||
3178 | 20 | "net" | 21 | "net" |
3179 | 21 | "time" | 22 | "time" |
3180 | 22 | 23 | ||
3181 | @@ -29,6 +30,8 @@ | |||
3182 | 29 | logger.Logger | 30 | logger.Logger |
3183 | 30 | // Session got started. | 31 | // Session got started. |
3184 | 31 | Start(WithRemoteAddr) | 32 | Start(WithRemoteAddr) |
3185 | 33 | // SessionId | ||
3186 | 34 | SessionId() string | ||
3187 | 32 | // Session got registered with broker as sess BrokerSession. | 35 | // Session got registered with broker as sess BrokerSession. |
3188 | 33 | Registered(sess broker.BrokerSession) | 36 | Registered(sess broker.BrokerSession) |
3189 | 34 | // Report effective elapsed ping interval. | 37 | // Report effective elapsed ping interval. |
3190 | @@ -47,7 +50,7 @@ | |||
3191 | 47 | // Tracker implements SessionTracker simply. | 50 | // Tracker implements SessionTracker simply. |
3192 | 48 | type tracker struct { | 51 | type tracker struct { |
3193 | 49 | logger.Logger | 52 | logger.Logger |
3195 | 50 | sessionId int64 // xxx use timeuuid later | 53 | sessionId string |
3196 | 51 | } | 54 | } |
3197 | 52 | 55 | ||
3198 | 53 | func NewTracker(logger logger.Logger) SessionTracker { | 56 | func NewTracker(logger logger.Logger) SessionTracker { |
3199 | @@ -55,18 +58,22 @@ | |||
3200 | 55 | } | 58 | } |
3201 | 56 | 59 | ||
3202 | 57 | func (trk *tracker) Start(conn WithRemoteAddr) { | 60 | func (trk *tracker) Start(conn WithRemoteAddr) { |
3205 | 58 | trk.sessionId = time.Now().UnixNano() - sessionsEpoch | 61 | trk.sessionId = fmt.Sprintf("%x", time.Now().UnixNano()-sessionsEpoch) |
3206 | 59 | trk.Debugf("session(%x) connected %v", trk.sessionId, conn.RemoteAddr()) | 62 | trk.Debugf("session(%s) connected %v", trk.sessionId, conn.RemoteAddr()) |
3207 | 63 | } | ||
3208 | 64 | |||
3209 | 65 | func (trk *tracker) SessionId() string { | ||
3210 | 66 | return trk.sessionId | ||
3211 | 60 | } | 67 | } |
3212 | 61 | 68 | ||
3213 | 62 | func (trk *tracker) Registered(sess broker.BrokerSession) { | 69 | func (trk *tracker) Registered(sess broker.BrokerSession) { |
3215 | 63 | trk.Infof("session(%x) registered %v", trk.sessionId, sess.DeviceIdentifier()) | 70 | trk.Infof("session(%s) registered %v", trk.sessionId, sess.DeviceIdentifier()) |
3216 | 64 | } | 71 | } |
3217 | 65 | 72 | ||
3218 | 66 | func (trk *tracker) EffectivePingInterval(time.Duration) { | 73 | func (trk *tracker) EffectivePingInterval(time.Duration) { |
3219 | 67 | } | 74 | } |
3220 | 68 | 75 | ||
3221 | 69 | func (trk *tracker) End(err error) error { | 76 | func (trk *tracker) End(err error) error { |
3223 | 70 | trk.Debugf("session(%x) ended with: %v", trk.sessionId, err) | 77 | trk.Debugf("session(%s) ended with: %v", trk.sessionId, err) |
3224 | 71 | return err | 78 | return err |
3225 | 72 | } | 79 | } |
3226 | 73 | 80 | ||
3227 | === modified file 'server/session/tracker_test.go' | |||
3228 | --- server/session/tracker_test.go 2014-02-10 23:19:08 +0000 | |||
3229 | +++ server/session/tracker_test.go 2014-04-29 18:02:00 +0000 | |||
3230 | @@ -46,8 +46,8 @@ | |||
3231 | 46 | func (s *trackerSuite) TestSessionTrackStart(c *C) { | 46 | func (s *trackerSuite) TestSessionTrackStart(c *C) { |
3232 | 47 | track := NewTracker(s.testlog) | 47 | track := NewTracker(s.testlog) |
3233 | 48 | track.Start(&testRemoteAddrable{}) | 48 | track.Start(&testRemoteAddrable{}) |
3236 | 49 | c.Check(track.(*tracker).sessionId, Not(Equals), 0) | 49 | c.Check(track.SessionId(), Not(Equals), "") |
3237 | 50 | regExpected := fmt.Sprintf(`DEBUG session\(%x\) connected 127\.0\.0\.1:9999\n`, track.(*tracker).sessionId) | 50 | regExpected := fmt.Sprintf(`DEBUG session\(%s\) connected 127\.0\.0\.1:9999\n`, track.SessionId()) |
3238 | 51 | c.Check(s.testlog.Captured(), Matches, regExpected) | 51 | c.Check(s.testlog.Captured(), Matches, regExpected) |
3239 | 52 | } | 52 | } |
3240 | 53 | 53 | ||
3241 | @@ -55,7 +55,7 @@ | |||
3242 | 55 | track := NewTracker(s.testlog) | 55 | track := NewTracker(s.testlog) |
3243 | 56 | track.Start(&testRemoteAddrable{}) | 56 | track.Start(&testRemoteAddrable{}) |
3244 | 57 | track.Registered(&testing.TestBrokerSession{DeviceId: "DEV-ID"}) | 57 | track.Registered(&testing.TestBrokerSession{DeviceId: "DEV-ID"}) |
3246 | 58 | regExpected := fmt.Sprintf(`.*connected.*\nINFO session\(%x\) registered DEV-ID\n`, track.(*tracker).sessionId) | 58 | regExpected := fmt.Sprintf(`.*connected.*\nINFO session\(%s\) registered DEV-ID\n`, track.SessionId()) |
3247 | 59 | c.Check(s.testlog.Captured(), Matches, regExpected) | 59 | c.Check(s.testlog.Captured(), Matches, regExpected) |
3248 | 60 | } | 60 | } |
3249 | 61 | 61 | ||
3250 | @@ -63,6 +63,6 @@ | |||
3251 | 63 | track := NewTracker(s.testlog) | 63 | track := NewTracker(s.testlog) |
3252 | 64 | track.Start(&testRemoteAddrable{}) | 64 | track.Start(&testRemoteAddrable{}) |
3253 | 65 | track.End(&broker.ErrAbort{}) | 65 | track.End(&broker.ErrAbort{}) |
3255 | 66 | regExpected := fmt.Sprintf(`.*connected.*\nDEBUG session\(%x\) ended with: session aborted \(\)\n`, track.(*tracker).sessionId) | 66 | regExpected := fmt.Sprintf(`.*connected.*\nDEBUG session\(%s\) ended with: session aborted \(\)\n`, track.SessionId()) |
3256 | 67 | c.Check(s.testlog.Captured(), Matches, regExpected) | 67 | c.Check(s.testlog.Captured(), Matches, regExpected) |
3257 | 68 | } | 68 | } |
3258 | 69 | 69 | ||
3259 | === modified file 'server/store/inmemory.go' | |||
3260 | --- server/store/inmemory.go 2014-02-18 14:19:05 +0000 | |||
3261 | +++ server/store/inmemory.go 2014-04-29 18:02:00 +0000 | |||
3262 | @@ -20,11 +20,13 @@ | |||
3263 | 20 | "encoding/json" | 20 | "encoding/json" |
3264 | 21 | "sync" | 21 | "sync" |
3265 | 22 | "time" | 22 | "time" |
3266 | 23 | |||
3267 | 24 | "launchpad.net/ubuntu-push/protocol" | ||
3268 | 23 | ) | 25 | ) |
3269 | 24 | 26 | ||
3270 | 25 | // one stored notification | 27 | // one stored notification |
3271 | 26 | type notification struct { | 28 | type notification struct { |
3273 | 27 | payload json.RawMessage | 29 | protocol.Notification |
3274 | 28 | expiration time.Time | 30 | expiration time.Time |
3275 | 29 | } | 31 | } |
3276 | 30 | 32 | ||
3277 | @@ -63,14 +65,14 @@ | |||
3278 | 63 | } | 65 | } |
3279 | 64 | prev.topLevel++ | 66 | prev.topLevel++ |
3280 | 65 | prev.notifications = append(prev.notifications, notification{ | 67 | prev.notifications = append(prev.notifications, notification{ |
3283 | 66 | payload: notificationPayload, | 68 | Notification: protocol.Notification{Payload: notificationPayload}, |
3284 | 67 | expiration: expiration, | 69 | expiration: expiration, |
3285 | 68 | }) | 70 | }) |
3286 | 69 | sto.store[chanId] = prev | 71 | sto.store[chanId] = prev |
3287 | 70 | return nil | 72 | return nil |
3288 | 71 | } | 73 | } |
3289 | 72 | 74 | ||
3291 | 73 | func (sto *InMemoryPendingStore) GetChannelSnapshot(chanId InternalChannelId) (int64, []json.RawMessage, error) { | 75 | func (sto *InMemoryPendingStore) GetChannelSnapshot(chanId InternalChannelId) (int64, []protocol.Notification, error) { |
3292 | 74 | sto.lock.Lock() | 76 | sto.lock.Lock() |
3293 | 75 | defer sto.lock.Unlock() | 77 | defer sto.lock.Unlock() |
3294 | 76 | channel, ok := sto.store[chanId] | 78 | channel, ok := sto.store[chanId] |
3295 | @@ -79,13 +81,13 @@ | |||
3296 | 79 | } | 81 | } |
3297 | 80 | topLevel := channel.topLevel | 82 | topLevel := channel.topLevel |
3298 | 81 | n := len(channel.notifications) | 83 | n := len(channel.notifications) |
3300 | 82 | res := make([]json.RawMessage, 0, n) | 84 | res := make([]protocol.Notification, 0, n) |
3301 | 83 | now := time.Now() | 85 | now := time.Now() |
3302 | 84 | for _, notification := range channel.notifications { | 86 | for _, notification := range channel.notifications { |
3303 | 85 | if notification.expiration.Before(now) { | 87 | if notification.expiration.Before(now) { |
3304 | 86 | continue | 88 | continue |
3305 | 87 | } | 89 | } |
3307 | 88 | res = append(res, notification.payload) | 90 | res = append(res, notification.Notification) |
3308 | 89 | } | 91 | } |
3309 | 90 | return topLevel, res, nil | 92 | return topLevel, res, nil |
3310 | 91 | } | 93 | } |
3311 | 92 | 94 | ||
3312 | === modified file 'server/store/inmemory_test.go' | |||
3313 | --- server/store/inmemory_test.go 2014-02-14 12:38:38 +0000 | |||
3314 | +++ server/store/inmemory_test.go 2014-04-29 18:02:00 +0000 | |||
3315 | @@ -21,6 +21,9 @@ | |||
3316 | 21 | "time" | 21 | "time" |
3317 | 22 | 22 | ||
3318 | 23 | . "launchpad.net/gocheck" | 23 | . "launchpad.net/gocheck" |
3319 | 24 | |||
3320 | 25 | "launchpad.net/ubuntu-push/protocol" | ||
3321 | 26 | help "launchpad.net/ubuntu-push/testing" | ||
3322 | 24 | ) | 27 | ) |
3323 | 25 | 28 | ||
3324 | 26 | type inMemorySuite struct{} | 29 | type inMemorySuite struct{} |
3325 | @@ -45,7 +48,7 @@ | |||
3326 | 45 | top, res, err := sto.GetChannelSnapshot(SystemInternalChannelId) | 48 | top, res, err := sto.GetChannelSnapshot(SystemInternalChannelId) |
3327 | 46 | c.Assert(err, IsNil) | 49 | c.Assert(err, IsNil) |
3328 | 47 | c.Check(top, Equals, int64(0)) | 50 | c.Check(top, Equals, int64(0)) |
3330 | 48 | c.Check(res, DeepEquals, []json.RawMessage(nil)) | 51 | c.Check(res, DeepEquals, []protocol.Notification(nil)) |
3331 | 49 | } | 52 | } |
3332 | 50 | 53 | ||
3333 | 51 | func (s *inMemorySuite) TestAppendToChannelAndGetChannelSnapshot(c *C) { | 54 | func (s *inMemorySuite) TestAppendToChannelAndGetChannelSnapshot(c *C) { |
3334 | @@ -61,7 +64,7 @@ | |||
3335 | 61 | top, res, err := sto.GetChannelSnapshot(SystemInternalChannelId) | 64 | top, res, err := sto.GetChannelSnapshot(SystemInternalChannelId) |
3336 | 62 | c.Assert(err, IsNil) | 65 | c.Assert(err, IsNil) |
3337 | 63 | c.Check(top, Equals, int64(2)) | 66 | c.Check(top, Equals, int64(2)) |
3339 | 64 | c.Check(res, DeepEquals, []json.RawMessage{notification1, notification2}) | 67 | c.Check(res, DeepEquals, help.Ns(notification1, notification2)) |
3340 | 65 | } | 68 | } |
3341 | 66 | 69 | ||
3342 | 67 | func (s *inMemorySuite) TestAppendToChannelAndGetChannelSnapshotWithExpiration(c *C) { | 70 | func (s *inMemorySuite) TestAppendToChannelAndGetChannelSnapshotWithExpiration(c *C) { |
3343 | @@ -81,5 +84,5 @@ | |||
3344 | 81 | top, res, err := sto.GetChannelSnapshot(SystemInternalChannelId) | 84 | top, res, err := sto.GetChannelSnapshot(SystemInternalChannelId) |
3345 | 82 | c.Assert(err, IsNil) | 85 | c.Assert(err, IsNil) |
3346 | 83 | c.Check(top, Equals, int64(2)) | 86 | c.Check(top, Equals, int64(2)) |
3348 | 84 | c.Check(res, DeepEquals, []json.RawMessage{notification1}) | 87 | c.Check(res, DeepEquals, help.Ns(notification1)) |
3349 | 85 | } | 88 | } |
3350 | 86 | 89 | ||
3351 | === modified file 'server/store/store.go' | |||
3352 | --- server/store/store.go 2014-02-18 13:43:07 +0000 | |||
3353 | +++ server/store/store.go 2014-04-29 18:02:00 +0000 | |||
3354 | @@ -22,6 +22,8 @@ | |||
3355 | 22 | "encoding/json" | 22 | "encoding/json" |
3356 | 23 | "errors" | 23 | "errors" |
3357 | 24 | "time" | 24 | "time" |
3358 | 25 | |||
3359 | 26 | "launchpad.net/ubuntu-push/protocol" | ||
3360 | 25 | ) | 27 | ) |
3361 | 26 | 28 | ||
3362 | 27 | type InternalChannelId string | 29 | type InternalChannelId string |
3363 | @@ -70,7 +72,7 @@ | |||
3364 | 70 | AppendToChannel(chanId InternalChannelId, notification json.RawMessage, expiration time.Time) error | 72 | AppendToChannel(chanId InternalChannelId, notification json.RawMessage, expiration time.Time) error |
3365 | 71 | // GetChannelSnapshot gets all the current notifications and | 73 | // GetChannelSnapshot gets all the current notifications and |
3366 | 72 | // current top level in the channel. | 74 | // current top level in the channel. |
3368 | 73 | GetChannelSnapshot(chanId InternalChannelId) (topLevel int64, payloads []json.RawMessage, err error) | 75 | GetChannelSnapshot(chanId InternalChannelId) (topLevel int64, notifications []protocol.Notification, err error) |
3369 | 74 | // Close is to be called when done with the store. | 76 | // Close is to be called when done with the store. |
3370 | 75 | Close() | 77 | Close() |
3371 | 76 | } | 78 | } |
3372 | 77 | 79 | ||
3373 | === modified file 'testing/helpers.go' | |||
3374 | --- testing/helpers.go 2014-02-21 16:04:44 +0000 | |||
3375 | +++ testing/helpers.go 2014-04-29 18:02:00 +0000 | |||
3376 | @@ -18,6 +18,7 @@ | |||
3377 | 18 | package testing | 18 | package testing |
3378 | 19 | 19 | ||
3379 | 20 | import ( | 20 | import ( |
3380 | 21 | "encoding/json" | ||
3381 | 21 | "fmt" | 22 | "fmt" |
3382 | 22 | "os" | 23 | "os" |
3383 | 23 | "path/filepath" | 24 | "path/filepath" |
3384 | @@ -26,6 +27,7 @@ | |||
3385 | 26 | "sync" | 27 | "sync" |
3386 | 27 | 28 | ||
3387 | 28 | "launchpad.net/ubuntu-push/logger" | 29 | "launchpad.net/ubuntu-push/logger" |
3388 | 30 | "launchpad.net/ubuntu-push/protocol" | ||
3389 | 29 | ) | 31 | ) |
3390 | 30 | 32 | ||
3391 | 31 | type captureHelper struct { | 33 | type captureHelper struct { |
3392 | @@ -122,3 +124,12 @@ | |||
3393 | 122 | } | 124 | } |
3394 | 123 | return filepath.Join(dir, relativePath) | 125 | return filepath.Join(dir, relativePath) |
3395 | 124 | } | 126 | } |
3396 | 127 | |||
3397 | 128 | // Ns makes a []Notification from just payloads. | ||
3398 | 129 | func Ns(payloads ...json.RawMessage) []protocol.Notification { | ||
3399 | 130 | res := make([]protocol.Notification, len(payloads)) | ||
3400 | 131 | for i := 0; i < len(payloads); i++ { | ||
3401 | 132 | res[i].Payload = payloads[i] | ||
3402 | 133 | } | ||
3403 | 134 | return res | ||
3404 | 135 | } | ||
3405 | 125 | 136 | ||
3406 | === modified file 'ubuntu-push-client.go' | |||
3407 | --- ubuntu-push-client.go 2014-03-12 13:25:20 +0000 | |||
3408 | +++ ubuntu-push-client.go 2014-04-29 18:02:00 +0000 | |||
3409 | @@ -19,12 +19,38 @@ | |||
3410 | 19 | import ( | 19 | import ( |
3411 | 20 | "log" | 20 | "log" |
3412 | 21 | 21 | ||
3413 | 22 | "gopkg.in/qml.v0" | ||
3414 | 23 | "launchpad.net/go-dbus/v1" | ||
3415 | 22 | "launchpad.net/go-xdg/v0" | 24 | "launchpad.net/go-xdg/v0" |
3416 | 23 | 25 | ||
3417 | 24 | "launchpad.net/ubuntu-push/client" | 26 | "launchpad.net/ubuntu-push/client" |
3418 | 25 | ) | 27 | ) |
3419 | 26 | 28 | ||
3420 | 29 | const NAME = "com.ubuntu.PushNotifications" | ||
3421 | 30 | |||
3422 | 31 | // grabName grabs ownership of the dbus name, and bails the client as | ||
3423 | 32 | // soon as somebody else grabs it. | ||
3424 | 33 | func grabName() { | ||
3425 | 34 | conn, err := dbus.Connect(dbus.SessionBus) | ||
3426 | 35 | if err != nil { | ||
3427 | 36 | log.Fatalf("bus: %v", err) | ||
3428 | 37 | } | ||
3429 | 38 | |||
3430 | 39 | flags := dbus.NameFlagAllowReplacement | dbus.NameFlagReplaceExisting | ||
3431 | 40 | n := conn.RequestName(NAME, flags) | ||
3432 | 41 | go func() { | ||
3433 | 42 | for err := range n.C { | ||
3434 | 43 | if err != nil { | ||
3435 | 44 | log.Fatalf("FATAL: name channel got: %v", err) | ||
3436 | 45 | } | ||
3437 | 46 | } | ||
3438 | 47 | }() | ||
3439 | 48 | } | ||
3440 | 49 | |||
3441 | 27 | func main() { | 50 | func main() { |
3442 | 51 | // XXX: this is a quick hack to ensure unicity | ||
3443 | 52 | grabName() | ||
3444 | 53 | |||
3445 | 28 | cfgFname, err := xdg.Config.Find("ubuntu-push-client/config.json") | 54 | cfgFname, err := xdg.Config.Find("ubuntu-push-client/config.json") |
3446 | 29 | if err != nil { | 55 | if err != nil { |
3447 | 30 | log.Fatalf("unable to find a configuration file: %v", err) | 56 | log.Fatalf("unable to find a configuration file: %v", err) |
3448 | @@ -33,6 +59,9 @@ | |||
3449 | 33 | if err != nil { | 59 | if err != nil { |
3450 | 34 | log.Fatalf("unable to open the levels database: %v", err) | 60 | log.Fatalf("unable to open the levels database: %v", err) |
3451 | 35 | } | 61 | } |
3452 | 62 | |||
3453 | 63 | qml.Init(nil) | ||
3454 | 64 | |||
3455 | 36 | cli := client.NewPushClient(cfgFname, lvlFname) | 65 | cli := client.NewPushClient(cfgFname, lvlFname) |
3456 | 37 | err = cli.Start() | 66 | err = cli.Start() |
3457 | 38 | if err != nil { | 67 | if err != nil { |
3458 | 39 | 68 | ||
3459 | === added file 'util/auth.go' | |||
3460 | --- util/auth.go 1970-01-01 00:00:00 +0000 | |||
3461 | +++ util/auth.go 2014-04-29 18:02:00 +0000 | |||
3462 | @@ -0,0 +1,36 @@ | |||
3463 | 1 | /* | ||
3464 | 2 | Copyright 2013-2014 Canonical Ltd. | ||
3465 | 3 | |||
3466 | 4 | This program is free software: you can redistribute it and/or modify it | ||
3467 | 5 | under the terms of the GNU General Public License version 3, as published | ||
3468 | 6 | by the Free Software Foundation. | ||
3469 | 7 | |||
3470 | 8 | This program is distributed in the hope that it will be useful, but | ||
3471 | 9 | WITHOUT ANY WARRANTY; without even the implied warranties of | ||
3472 | 10 | MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
3473 | 11 | PURPOSE. See the GNU General Public License for more details. | ||
3474 | 12 | |||
3475 | 13 | You should have received a copy of the GNU General Public License along | ||
3476 | 14 | with this program. If not, see <http://www.gnu.org/licenses/>. | ||
3477 | 15 | */ | ||
3478 | 16 | |||
3479 | 17 | package util | ||
3480 | 18 | |||
3481 | 19 | import ( | ||
3482 | 20 | "gopkg.in/niemeyer/uoneauth.v1" | ||
3483 | 21 | "gopkg.in/qml.v0" | ||
3484 | 22 | ) | ||
3485 | 23 | |||
3486 | 24 | func GetAuthorization() (string, error) { | ||
3487 | 25 | engine := qml.NewEngine() | ||
3488 | 26 | defer engine.Destroy() | ||
3489 | 27 | authService := uoneauth.NewService(engine) | ||
3490 | 28 | var auth string | ||
3491 | 29 | token, err := authService.Token() | ||
3492 | 30 | if err != nil { | ||
3493 | 31 | return "", err | ||
3494 | 32 | } else { | ||
3495 | 33 | auth = token.HeaderSignature("POST", "https://push.ubuntu.com") | ||
3496 | 34 | } | ||
3497 | 35 | return auth, nil | ||
3498 | 36 | } | ||
3499 | 0 | 37 | ||
3500 | === added file 'util/auth_test.go' | |||
3501 | --- util/auth_test.go 1970-01-01 00:00:00 +0000 | |||
3502 | +++ util/auth_test.go 2014-04-29 18:02:00 +0000 | |||
3503 | @@ -0,0 +1,53 @@ | |||
3504 | 1 | /* | ||
3505 | 2 | Copyright 2013-2014 Canonical Ltd. | ||
3506 | 3 | |||
3507 | 4 | This program is free software: you can redistribute it and/or modify it | ||
3508 | 5 | under the terms of the GNU General Public License version 3, as published | ||
3509 | 6 | by the Free Software Foundation. | ||
3510 | 7 | |||
3511 | 8 | This program is distributed in the hope that it will be useful, but | ||
3512 | 9 | WITHOUT ANY WARRANTY; without even the implied warranties of | ||
3513 | 10 | MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
3514 | 11 | PURPOSE. See the GNU General Public License for more details. | ||
3515 | 12 | |||
3516 | 13 | You should have received a copy of the GNU General Public License along | ||
3517 | 14 | with this program. If not, see <http://www.gnu.org/licenses/>. | ||
3518 | 15 | */ | ||
3519 | 16 | |||
3520 | 17 | package util | ||
3521 | 18 | |||
3522 | 19 | import ( | ||
3523 | 20 | "os" | ||
3524 | 21 | |||
3525 | 22 | "gopkg.in/qml.v0" | ||
3526 | 23 | |||
3527 | 24 | . "launchpad.net/gocheck" | ||
3528 | 25 | ) | ||
3529 | 26 | |||
3530 | 27 | type authSuite struct{} | ||
3531 | 28 | |||
3532 | 29 | var _ = Suite(&authSuite{}) | ||
3533 | 30 | |||
3534 | 31 | func (s *authSuite) SetUpSuite(c *C) { | ||
3535 | 32 | if os.Getenv("PUSH_AUTH_TEST") == "1" { | ||
3536 | 33 | qml.Init(nil) | ||
3537 | 34 | } | ||
3538 | 35 | } | ||
3539 | 36 | |||
3540 | 37 | func (s *authSuite) SetUpTest(c *C) { | ||
3541 | 38 | qml.SetLogger(c) | ||
3542 | 39 | } | ||
3543 | 40 | |||
3544 | 41 | func (s *authSuite) TestGetAuth(c *C) { | ||
3545 | 42 | /* | ||
3546 | 43 | * This test is only useful when the PUSH_AUTH_TEST environment | ||
3547 | 44 | * variable is set to "1" - in which case the runner should have | ||
3548 | 45 | * a Ubuntu One account setup via system-settings. | ||
3549 | 46 | */ | ||
3550 | 47 | if os.Getenv("PUSH_AUTH_TEST") != "1" { | ||
3551 | 48 | c.Skip("PUSH_AUTH_TEST not set to '1'") | ||
3552 | 49 | } | ||
3553 | 50 | auth, err := GetAuthorization() | ||
3554 | 51 | c.Assert(err, IsNil) | ||
3555 | 52 | c.Assert(auth, Matches, "OAuth .*oauth_consumer_key=.*") | ||
3556 | 53 | } | ||
3557 | 0 | 54 | ||
3558 | === modified file 'whoopsie/identifier/identifier.go' | |||
3559 | --- whoopsie/identifier/identifier.go 2014-02-21 16:17:28 +0000 | |||
3560 | +++ whoopsie/identifier/identifier.go 2014-04-29 18:02:00 +0000 | |||
3561 | @@ -27,6 +27,7 @@ | |||
3562 | 27 | import "C" | 27 | import "C" |
3563 | 28 | import "unsafe" | 28 | import "unsafe" |
3564 | 29 | import "errors" | 29 | import "errors" |
3565 | 30 | import "time" | ||
3566 | 30 | 31 | ||
3567 | 31 | // an Id knows how to generate itself, and how to stringify itself. | 32 | // an Id knows how to generate itself, and how to stringify itself. |
3568 | 32 | type Id interface { | 33 | type Id interface { |
3569 | @@ -36,12 +37,17 @@ | |||
3570 | 36 | 37 | ||
3571 | 37 | // Identifier is the default Id implementation. | 38 | // Identifier is the default Id implementation. |
3572 | 38 | type Identifier struct { | 39 | type Identifier struct { |
3574 | 39 | value string | 40 | value string |
3575 | 41 | generator func(**C.char, **C.GError) | ||
3576 | 42 | } | ||
3577 | 43 | |||
3578 | 44 | func generator(csp **C.char, errp **C.GError) { | ||
3579 | 45 | C.whoopsie_identifier_generate(csp, errp) | ||
3580 | 40 | } | 46 | } |
3581 | 41 | 47 | ||
3582 | 42 | // New creates an Identifier, but does not call Generate() on it. | 48 | // New creates an Identifier, but does not call Generate() on it. |
3583 | 43 | func New() Id { | 49 | func New() Id { |
3585 | 44 | return &Identifier{} | 50 | return &Identifier{generator: generator} |
3586 | 45 | } | 51 | } |
3587 | 46 | 52 | ||
3588 | 47 | // Generate makes the Identifier create the identifier itself. | 53 | // Generate makes the Identifier create the identifier itself. |
3589 | @@ -49,8 +55,18 @@ | |||
3590 | 49 | var gerr *C.GError | 55 | var gerr *C.GError |
3591 | 50 | var cs *C.char | 56 | var cs *C.char |
3592 | 51 | defer C.g_free((C.gpointer)(unsafe.Pointer(cs))) | 57 | defer C.g_free((C.gpointer)(unsafe.Pointer(cs))) |
3595 | 52 | C.whoopsie_identifier_generate(&cs, &gerr) | 58 | |
3596 | 53 | 59 | for i := 0; i < 200; i++ { | |
3597 | 60 | id.generator(&cs, &gerr) | ||
3598 | 61 | |||
3599 | 62 | if cs != nil || gerr != nil { | ||
3600 | 63 | goto SuccessMaybe | ||
3601 | 64 | } | ||
3602 | 65 | time.Sleep(600 * time.Millisecond) | ||
3603 | 66 | } | ||
3604 | 67 | return errors.New("whoopsie_identifier_generate still bad after 2m; giving up") | ||
3605 | 68 | |||
3606 | 69 | SuccessMaybe: | ||
3607 | 54 | if gerr != nil { | 70 | if gerr != nil { |
3608 | 55 | return errors.New(C.GoString((*C.char)(gerr.message))) | 71 | return errors.New(C.GoString((*C.char)(gerr.message))) |
3609 | 56 | } else { | 72 | } else { |
3610 | 57 | 73 | ||
3611 | === modified file 'whoopsie/identifier/identifier_test.go' | |||
3612 | --- whoopsie/identifier/identifier_test.go 2014-01-15 15:51:50 +0000 | |||
3613 | +++ whoopsie/identifier/identifier_test.go 2014-04-29 18:02:00 +0000 | |||
3614 | @@ -41,3 +41,18 @@ | |||
3615 | 41 | func (s *IdentifierSuite) TestIdentifierInterface(c *C) { | 41 | func (s *IdentifierSuite) TestIdentifierInterface(c *C) { |
3616 | 42 | _ = []Id{New()} | 42 | _ = []Id{New()} |
3617 | 43 | } | 43 | } |
3618 | 44 | |||
3619 | 45 | // TestFailure checks that Identifier survives whoopsie shenanigans | ||
3620 | 46 | func (s *IdentifierSuite) TestIdentifierSurvivesShenanigans(c *C) { | ||
3621 | 47 | count := 0 | ||
3622 | 48 | // using _Ctype* as a workaround for gocheck also having a C | ||
3623 | 49 | gen := func(csp **_Ctype_char, errp **_Ctype_GError) { | ||
3624 | 50 | count++ | ||
3625 | 51 | if count > 3 { | ||
3626 | 52 | generator(csp, errp) | ||
3627 | 53 | } | ||
3628 | 54 | } | ||
3629 | 55 | id := &Identifier{generator: gen} | ||
3630 | 56 | id.Generate() | ||
3631 | 57 | c.Check(id.String(), HasLen, 128) | ||
3632 | 58 | } |