Merge lp:~pedronis/ubuntu-push/fixes-to-wily into lp:ubuntu-push
- fixes-to-wily
- Merge into trunk
Proposed by
Samuele Pedroni
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Samuele Pedroni | ||||
Approved revision: | 150 | ||||
Merged at revision: | 149 | ||||
Proposed branch: | lp:~pedronis/ubuntu-push/fixes-to-wily | ||||
Merge into: | lp:ubuntu-push | ||||
Diff against target: |
705 lines (+257/-136) 9 files modified
client/service/postal.go (+0/-2) messaging/cmessaging/cmessaging.go (+0/-1) messaging/messaging.go (+32/-49) messaging/messaging_test.go (+102/-50) server/acceptance/acceptanceclient.go (+6/-1) server/acceptance/cmd/acceptanceclient.go (+1/-1) server/acceptance/kit/api.go (+41/-7) server/acceptance/kit/cliloop.go (+73/-23) ubuntu-push-client.go (+2/-2) |
||||
To merge this branch: | bzr merge lp:~pedronis/ubuntu-push/fixes-to-wily | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Samuele Pedroni | Approve | ||
Review via email: mp+268067@code.launchpad.net |
Commit message
* address lp:1451510 aggressively finding gone notifications in Tags()
* truncate runtime.Stack result to size, otherwise we log \x00s or old stuff
Description of the change
bring in recent fixes, mainly addressing lp:1451510
To post a comment you must log in.
Revision history for this message
Samuele Pedroni (pedronis) : | # |
review:
Approve
- 150. By Samuele Pedroni
-
revert rules
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'client/service/postal.go' | |||
2 | --- client/service/postal.go 2015-03-05 14:09:54 +0000 | |||
3 | +++ client/service/postal.go 2015-08-14 14:03:06 +0000 | |||
4 | @@ -53,7 +53,6 @@ | |||
5 | 53 | Presenter | 53 | Presenter |
6 | 54 | GetCh() chan *reply.MMActionReply | 54 | GetCh() chan *reply.MMActionReply |
7 | 55 | RemoveNotification(string, bool) | 55 | RemoveNotification(string, bool) |
8 | 56 | StartCleanupLoop() | ||
9 | 57 | Tags(*click.AppId) []string | 56 | Tags(*click.AppId) []string |
10 | 58 | Clear(*click.AppId, ...string) int | 57 | Clear(*click.AppId, ...string) int |
11 | 59 | } | 58 | } |
12 | @@ -187,7 +186,6 @@ | |||
13 | 187 | 186 | ||
14 | 188 | go svc.consumeHelperResults(svc.HelperPool.Start()) | 187 | go svc.consumeHelperResults(svc.HelperPool.Start()) |
15 | 189 | go svc.handleActions(actionsCh, svc.messagingMenu.GetCh()) | 188 | go svc.handleActions(actionsCh, svc.messagingMenu.GetCh()) |
16 | 190 | svc.messagingMenu.StartCleanupLoop() | ||
17 | 191 | return nil | 189 | return nil |
18 | 192 | } | 190 | } |
19 | 193 | 191 | ||
20 | 194 | 192 | ||
21 | === modified file 'messaging/cmessaging/cmessaging.go' | |||
22 | --- messaging/cmessaging/cmessaging.go 2014-08-07 10:20:35 +0000 | |||
23 | +++ messaging/cmessaging/cmessaging.go 2015-08-14 14:03:06 +0000 | |||
24 | @@ -44,7 +44,6 @@ | |||
25 | 44 | Actions []string | 44 | Actions []string |
26 | 45 | App *click.AppId | 45 | App *click.AppId |
27 | 46 | Tag string | 46 | Tag string |
28 | 47 | Gone bool | ||
29 | 48 | } | 47 | } |
30 | 49 | 48 | ||
31 | 50 | func gchar(s string) *C.gchar { | 49 | func gchar(s string) *C.gchar { |
32 | 51 | 50 | ||
33 | === modified file 'messaging/messaging.go' | |||
34 | --- messaging/messaging.go 2015-01-22 09:52:07 +0000 | |||
35 | +++ messaging/messaging.go 2015-08-14 14:03:06 +0000 | |||
36 | @@ -31,23 +31,19 @@ | |||
37 | 31 | "launchpad.net/ubuntu-push/messaging/reply" | 31 | "launchpad.net/ubuntu-push/messaging/reply" |
38 | 32 | ) | 32 | ) |
39 | 33 | 33 | ||
40 | 34 | var cleanupLoopDuration = 5 * time.Minute | ||
41 | 35 | |||
42 | 36 | type MessagingMenu struct { | 34 | type MessagingMenu struct { |
50 | 37 | Log logger.Logger | 35 | Log logger.Logger |
51 | 38 | Ch chan *reply.MMActionReply | 36 | Ch chan *reply.MMActionReply |
52 | 39 | notifications map[string]*cmessaging.Payload // keep a ref to the Payload used in the MMU callback | 37 | notifications map[string]*cmessaging.Payload // keep a ref to the Payload used in the MMU callback |
53 | 40 | lock sync.RWMutex | 38 | lock sync.RWMutex |
54 | 41 | stopCleanupLoopCh chan bool | 39 | lastCleanupTime time.Time |
48 | 42 | ticker *time.Ticker | ||
49 | 43 | tickerCh <-chan time.Time | ||
55 | 44 | } | 40 | } |
56 | 45 | 41 | ||
57 | 42 | type cleanUp func() | ||
58 | 43 | |||
59 | 46 | // New returns a new MessagingMenu | 44 | // New returns a new MessagingMenu |
60 | 47 | func New(log logger.Logger) *MessagingMenu { | 45 | func New(log logger.Logger) *MessagingMenu { |
64 | 48 | ticker := time.NewTicker(cleanupLoopDuration) | 46 | return &MessagingMenu{Log: log, Ch: make(chan *reply.MMActionReply), notifications: make(map[string]*cmessaging.Payload)} |
62 | 49 | stopCh := make(chan bool) | ||
63 | 50 | return &MessagingMenu{Log: log, Ch: make(chan *reply.MMActionReply), notifications: make(map[string]*cmessaging.Payload), ticker: ticker, tickerCh: ticker.C, stopCleanupLoopCh: stopCh} | ||
65 | 51 | } | 47 | } |
66 | 52 | 48 | ||
67 | 53 | var cAddNotification = cmessaging.AddNotification | 49 | var cAddNotification = cmessaging.AddNotification |
68 | @@ -59,12 +55,23 @@ | |||
69 | 59 | return mmu.Ch | 55 | return mmu.Ch |
70 | 60 | } | 56 | } |
71 | 61 | 57 | ||
73 | 62 | func (mmu *MessagingMenu) addNotification(app *click.AppId, notificationId string, tag string, card *launch_helper.Card, actions []string) { | 58 | func (mmu *MessagingMenu) addNotification(app *click.AppId, notificationId string, tag string, card *launch_helper.Card, actions []string, testingCleanUpFunction cleanUp) { |
74 | 63 | mmu.lock.Lock() | 59 | mmu.lock.Lock() |
75 | 64 | defer mmu.lock.Unlock() | 60 | defer mmu.lock.Unlock() |
76 | 65 | payload := &cmessaging.Payload{Ch: mmu.Ch, Actions: actions, App: app, Tag: tag} | 61 | payload := &cmessaging.Payload{Ch: mmu.Ch, Actions: actions, App: app, Tag: tag} |
77 | 66 | mmu.notifications[notificationId] = payload | 62 | mmu.notifications[notificationId] = payload |
78 | 67 | cAddNotification(app.DesktopId(), notificationId, card, payload) | 63 | cAddNotification(app.DesktopId(), notificationId, card, payload) |
79 | 64 | |||
80 | 65 | // Clean up our internal notifications store if it holds more than 20 messages (and apparently nobody ever calls Tags()) | ||
81 | 66 | if len(mmu.notifications) > 20 && time.Since(mmu.lastCleanupTime).Minutes() > 10 { | ||
82 | 67 | mmu.lastCleanupTime = time.Now() | ||
83 | 68 | if testingCleanUpFunction == nil { | ||
84 | 69 | go mmu.cleanUpNotifications() | ||
85 | 70 | } else { | ||
86 | 71 | testingCleanUpFunction() // Has to implement the asynchronous part itself | ||
87 | 72 | } | ||
88 | 73 | |||
89 | 74 | } | ||
90 | 68 | } | 75 | } |
91 | 69 | 76 | ||
92 | 70 | func (mmu *MessagingMenu) RemoveNotification(notificationId string, fromUI bool) { | 77 | func (mmu *MessagingMenu) RemoveNotification(notificationId string, fromUI bool) { |
93 | @@ -77,53 +84,28 @@ | |||
94 | 77 | } | 84 | } |
95 | 78 | } | 85 | } |
96 | 79 | 86 | ||
97 | 80 | // cleanupNotifications remove notifications that were cleared from the messaging menu | ||
98 | 81 | func (mmu *MessagingMenu) cleanUpNotifications() { | 87 | func (mmu *MessagingMenu) cleanUpNotifications() { |
99 | 82 | mmu.lock.Lock() | 88 | mmu.lock.Lock() |
100 | 83 | defer mmu.lock.Unlock() | 89 | defer mmu.lock.Unlock() |
101 | 90 | mmu.doCleanUpNotifications() | ||
102 | 91 | } | ||
103 | 92 | |||
104 | 93 | // doCleanupNotifications removes notifications that were cleared from the messaging menu | ||
105 | 94 | func (mmu *MessagingMenu) doCleanUpNotifications() { | ||
106 | 84 | for nid, payload := range mmu.notifications { | 95 | for nid, payload := range mmu.notifications { |
109 | 85 | if payload.Gone { | 96 | if !cNotificationExists(payload.App.DesktopId(), nid) { |
108 | 86 | // sweep | ||
110 | 87 | delete(mmu.notifications, nid) | 97 | delete(mmu.notifications, nid) |
111 | 88 | // don't check the mmu for this nid | ||
112 | 89 | continue | ||
113 | 90 | } | ||
114 | 91 | exists := cNotificationExists(payload.App.DesktopId(), nid) | ||
115 | 92 | if !exists { | ||
116 | 93 | // mark | ||
117 | 94 | payload.Gone = true | ||
118 | 95 | } | 98 | } |
119 | 96 | } | 99 | } |
120 | 97 | } | 100 | } |
121 | 98 | 101 | ||
122 | 99 | func (mmu *MessagingMenu) StartCleanupLoop() { | ||
123 | 100 | mmu.doStartCleanupLoop(mmu.cleanUpNotifications) | ||
124 | 101 | } | ||
125 | 102 | |||
126 | 103 | func (mmu *MessagingMenu) doStartCleanupLoop(cleanupFunc func()) { | ||
127 | 104 | go func() { | ||
128 | 105 | for { | ||
129 | 106 | select { | ||
130 | 107 | case <-mmu.tickerCh: | ||
131 | 108 | cleanupFunc() | ||
132 | 109 | case <-mmu.stopCleanupLoopCh: | ||
133 | 110 | mmu.ticker.Stop() | ||
134 | 111 | mmu.Log.Debugf("CleanupLoop stopped.") | ||
135 | 112 | return | ||
136 | 113 | } | ||
137 | 114 | } | ||
138 | 115 | }() | ||
139 | 116 | } | ||
140 | 117 | |||
141 | 118 | func (mmu *MessagingMenu) StopCleanupLoop() { | ||
142 | 119 | mmu.stopCleanupLoopCh <- true | ||
143 | 120 | } | ||
144 | 121 | |||
145 | 122 | func (mmu *MessagingMenu) Tags(app *click.AppId) []string { | 102 | func (mmu *MessagingMenu) Tags(app *click.AppId) []string { |
146 | 123 | orig := app.Original() | 103 | orig := app.Original() |
147 | 124 | tags := []string(nil) | 104 | tags := []string(nil) |
150 | 125 | mmu.lock.RLock() | 105 | mmu.lock.Lock() |
151 | 126 | defer mmu.lock.RUnlock() | 106 | defer mmu.lock.Unlock() |
152 | 107 | mmu.lastCleanupTime = time.Now() | ||
153 | 108 | mmu.doCleanUpNotifications() | ||
154 | 127 | for _, payload := range mmu.notifications { | 109 | for _, payload := range mmu.notifications { |
155 | 128 | if payload.App.Original() == orig { | 110 | if payload.App.Original() == orig { |
156 | 129 | tags = append(tags, payload.Tag) | 111 | tags = append(tags, payload.Tag) |
157 | @@ -156,6 +138,7 @@ | |||
158 | 156 | for _, nid := range nids { | 138 | for _, nid := range nids { |
159 | 157 | mmu.RemoveNotification(nid, true) | 139 | mmu.RemoveNotification(nid, true) |
160 | 158 | } | 140 | } |
161 | 141 | mmu.cleanUpNotifications() | ||
162 | 159 | 142 | ||
163 | 160 | return len(nids) | 143 | return len(nids) |
164 | 161 | } | 144 | } |
165 | @@ -190,7 +173,7 @@ | |||
166 | 190 | 173 | ||
167 | 191 | mmu.Log.Debugf("[%s] creating notification centre entry for %s (summary: %s)", nid, app.Base(), card.Summary) | 174 | mmu.Log.Debugf("[%s] creating notification centre entry for %s (summary: %s)", nid, app.Base(), card.Summary) |
168 | 192 | 175 | ||
170 | 193 | mmu.addNotification(app, nid, notification.Tag, card, actions) | 176 | mmu.addNotification(app, nid, notification.Tag, card, actions, nil) |
171 | 194 | 177 | ||
172 | 195 | return true | 178 | return true |
173 | 196 | } | 179 | } |
174 | 197 | 180 | ||
175 | === modified file 'messaging/messaging_test.go' | |||
176 | --- messaging/messaging_test.go 2014-11-25 18:33:24 +0000 | |||
177 | +++ messaging/messaging_test.go 2015-08-14 14:03:06 +0000 | |||
178 | @@ -18,6 +18,8 @@ | |||
179 | 18 | 18 | ||
180 | 19 | import ( | 19 | import ( |
181 | 20 | "sort" | 20 | "sort" |
182 | 21 | "strconv" | ||
183 | 22 | "sync" | ||
184 | 21 | "time" | 23 | "time" |
185 | 22 | 24 | ||
186 | 23 | . "launchpad.net/gocheck" | 25 | . "launchpad.net/gocheck" |
187 | @@ -48,8 +50,6 @@ | |||
188 | 48 | cRemoveNotification = func(a, n string) { | 50 | cRemoveNotification = func(a, n string) { |
189 | 49 | ms.log.Debugf("REMOVE: app: %s, not: %s", a, n) | 51 | ms.log.Debugf("REMOVE: app: %s, not: %s", a, n) |
190 | 50 | } | 52 | } |
191 | 51 | // just in case | ||
192 | 52 | cNotificationExists = nil | ||
193 | 53 | } | 53 | } |
194 | 54 | 54 | ||
195 | 55 | func (ms *MessagingSuite) TearDownSuite(c *C) { | 55 | func (ms *MessagingSuite) TearDownSuite(c *C) { |
196 | @@ -61,6 +61,8 @@ | |||
197 | 61 | func (ms *MessagingSuite) SetUpTest(c *C) { | 61 | func (ms *MessagingSuite) SetUpTest(c *C) { |
198 | 62 | ms.log = helpers.NewTestLogger(c, "debug") | 62 | ms.log = helpers.NewTestLogger(c, "debug") |
199 | 63 | ms.app = clickhelp.MustParseAppId("com.example.test_test_0") | 63 | ms.app = clickhelp.MustParseAppId("com.example.test_test_0") |
200 | 64 | // just in case | ||
201 | 65 | cNotificationExists = nil | ||
202 | 64 | } | 66 | } |
203 | 65 | 67 | ||
204 | 66 | func (ms *MessagingSuite) TestPresentPresents(c *C) { | 68 | func (ms *MessagingSuite) TestPresentPresents(c *C) { |
205 | @@ -135,11 +137,23 @@ | |||
206 | 135 | return &launch_helper.Notification{Card: &card, Tag: s} | 137 | return &launch_helper.Notification{Card: &card, Tag: s} |
207 | 136 | } | 138 | } |
208 | 137 | 139 | ||
209 | 140 | existsCount := 0 | ||
210 | 141 | // patch cNotificationExists to return true | ||
211 | 142 | cNotificationExists = func(did string, nid string) bool { | ||
212 | 143 | existsCount++ | ||
213 | 144 | return true | ||
214 | 145 | } | ||
215 | 146 | |||
216 | 138 | c.Check(mmu.Tags(ms.app), IsNil) | 147 | c.Check(mmu.Tags(ms.app), IsNil) |
217 | 139 | c.Assert(mmu.Present(ms.app, "notif1", f("one")), Equals, true) | 148 | c.Assert(mmu.Present(ms.app, "notif1", f("one")), Equals, true) |
218 | 140 | ms.checkTags(c, mmu.Tags(ms.app), []string{"one"}) | 149 | ms.checkTags(c, mmu.Tags(ms.app), []string{"one"}) |
219 | 150 | c.Check(existsCount, Equals, 1) | ||
220 | 151 | existsCount = 0 | ||
221 | 152 | |||
222 | 141 | c.Assert(mmu.Present(ms.app, "notif2", f("")), Equals, true) | 153 | c.Assert(mmu.Present(ms.app, "notif2", f("")), Equals, true) |
223 | 142 | ms.checkTags(c, mmu.Tags(ms.app), []string{"one", ""}) | 154 | ms.checkTags(c, mmu.Tags(ms.app), []string{"one", ""}) |
224 | 155 | c.Check(existsCount, Equals, 2) | ||
225 | 156 | |||
226 | 143 | // and an empty notification doesn't count | 157 | // and an empty notification doesn't count |
227 | 144 | c.Assert(mmu.Present(ms.app, "notif3", &launch_helper.Notification{Tag: "X"}), Equals, false) | 158 | c.Assert(mmu.Present(ms.app, "notif3", &launch_helper.Notification{Tag: "X"}), Equals, false) |
228 | 145 | ms.checkTags(c, mmu.Tags(ms.app), []string{"one", ""}) | 159 | ms.checkTags(c, mmu.Tags(ms.app), []string{"one", ""}) |
229 | @@ -172,6 +186,12 @@ | |||
230 | 172 | c.Assert(f(app3, "notif6", "one", true), Equals, true) | 186 | c.Assert(f(app3, "notif6", "one", true), Equals, true) |
231 | 173 | c.Assert(f(app3, "notif7", "", true), Equals, true) | 187 | c.Assert(f(app3, "notif7", "", true), Equals, true) |
232 | 174 | 188 | ||
233 | 189 | // patch cNotificationExists to return true in order to make sure that messages | ||
234 | 190 | // do not get deleted by the doCleanUpTags() call in the Tags() function | ||
235 | 191 | cNotificationExists = func(did string, nid string) bool { | ||
236 | 192 | return true | ||
237 | 193 | } | ||
238 | 194 | |||
239 | 175 | // that is: | 195 | // that is: |
240 | 176 | // app 1: "one", "two", ""; | 196 | // app 1: "one", "two", ""; |
241 | 177 | // app 2: "one", "two"; | 197 | // app 2: "one", "two"; |
242 | @@ -223,7 +243,7 @@ | |||
243 | 223 | mmu := New(ms.log) | 243 | mmu := New(ms.log) |
244 | 224 | card := launch_helper.Card{Summary: "ehlo", Persist: true, Actions: []string{"action-1"}} | 244 | card := launch_helper.Card{Summary: "ehlo", Persist: true, Actions: []string{"action-1"}} |
245 | 225 | actions := []string{"{\"app\":\"com.example.test_test_0\",\"act\":\"action-1\",\"nid\":\"notif-id\"}", "action-1"} | 245 | actions := []string{"{\"app\":\"com.example.test_test_0\",\"act\":\"action-1\",\"nid\":\"notif-id\"}", "action-1"} |
247 | 226 | mmu.addNotification(ms.app, "notif-id", "a-tag", &card, actions) | 246 | mmu.addNotification(ms.app, "notif-id", "a-tag", &card, actions, nil) |
248 | 227 | 247 | ||
249 | 228 | // check it's there | 248 | // check it's there |
250 | 229 | payload, ok := mmu.notifications["notif-id"] | 249 | payload, ok := mmu.notifications["notif-id"] |
251 | @@ -242,7 +262,7 @@ | |||
252 | 242 | mmu := New(ms.log) | 262 | mmu := New(ms.log) |
253 | 243 | card := launch_helper.Card{Summary: "ehlo", Persist: true, Actions: []string{"action-1"}} | 263 | card := launch_helper.Card{Summary: "ehlo", Persist: true, Actions: []string{"action-1"}} |
254 | 244 | actions := []string{"{\"app\":\"com.example.test_test_0\",\"act\":\"action-1\",\"nid\":\"notif-id\"}", "action-1"} | 264 | actions := []string{"{\"app\":\"com.example.test_test_0\",\"act\":\"action-1\",\"nid\":\"notif-id\"}", "action-1"} |
256 | 245 | mmu.addNotification(ms.app, "notif-id", "a-tag", &card, actions) | 265 | mmu.addNotification(ms.app, "notif-id", "a-tag", &card, actions, nil) |
257 | 246 | 266 | ||
258 | 247 | // check it's there | 267 | // check it's there |
259 | 248 | _, ok := mmu.notifications["notif-id"] | 268 | _, ok := mmu.notifications["notif-id"] |
260 | @@ -261,13 +281,13 @@ | |||
261 | 261 | mmu := New(ms.log) | 281 | mmu := New(ms.log) |
262 | 262 | card := launch_helper.Card{Summary: "ehlo", Persist: true, Actions: []string{"action-1"}} | 282 | card := launch_helper.Card{Summary: "ehlo", Persist: true, Actions: []string{"action-1"}} |
263 | 263 | actions := []string{"{\"app\":\"com.example.test_test_0\",\"act\":\"action-1\",\"nid\":\"notif-id\"}", "action-1"} | 283 | actions := []string{"{\"app\":\"com.example.test_test_0\",\"act\":\"action-1\",\"nid\":\"notif-id\"}", "action-1"} |
265 | 264 | mmu.addNotification(ms.app, "notif-id", "", &card, actions) | 284 | mmu.addNotification(ms.app, "notif-id", "", &card, actions, nil) |
266 | 265 | 285 | ||
267 | 266 | // check it's there | 286 | // check it's there |
268 | 267 | _, ok := mmu.notifications["notif-id"] | 287 | _, ok := mmu.notifications["notif-id"] |
269 | 268 | c.Check(ok, Equals, true) | 288 | c.Check(ok, Equals, true) |
270 | 269 | 289 | ||
272 | 270 | // patch cnotificationexists to return true | 290 | // patch cNotificationExists to return true |
273 | 271 | cNotificationExists = func(did string, nid string) bool { | 291 | cNotificationExists = func(did string, nid string) bool { |
274 | 272 | return true | 292 | return true |
275 | 273 | } | 293 | } |
276 | @@ -276,62 +296,94 @@ | |||
277 | 276 | // check it's still there | 296 | // check it's still there |
278 | 277 | _, ok = mmu.notifications["notif-id"] | 297 | _, ok = mmu.notifications["notif-id"] |
279 | 278 | c.Check(ok, Equals, true) | 298 | c.Check(ok, Equals, true) |
281 | 279 | // patch cnotificationexists to return false | 299 | |
282 | 300 | // patch cNotificationExists to return false | ||
283 | 280 | cNotificationExists = func(did string, nid string) bool { | 301 | cNotificationExists = func(did string, nid string) bool { |
284 | 281 | return false | 302 | return false |
285 | 282 | } | 303 | } |
292 | 283 | // mark the notification | 304 | // remove the notification |
287 | 284 | mmu.cleanUpNotifications() | ||
288 | 285 | // check it's gone | ||
289 | 286 | _, ok = mmu.notifications["notif-id"] | ||
290 | 287 | c.Check(ok, Equals, true) | ||
291 | 288 | // sweep the notification | ||
293 | 289 | mmu.cleanUpNotifications() | 305 | mmu.cleanUpNotifications() |
294 | 290 | // check it's gone | 306 | // check it's gone |
295 | 291 | _, ok = mmu.notifications["notif-id"] | 307 | _, ok = mmu.notifications["notif-id"] |
296 | 292 | c.Check(ok, Equals, false) | 308 | c.Check(ok, Equals, false) |
297 | 293 | } | 309 | } |
298 | 294 | 310 | ||
327 | 295 | func (ms *MessagingSuite) TestCleanupLoop(c *C) { | 311 | func (ms *MessagingSuite) TestCleanupInAddNotification(c *C) { |
328 | 296 | mmu := New(ms.log) | 312 | mmu := New(ms.log) |
329 | 297 | tickerCh := make(chan time.Time) | 313 | |
330 | 298 | mmu.tickerCh = tickerCh | 314 | var wg sync.WaitGroup |
331 | 299 | cleanupCh := make(chan bool) | 315 | |
332 | 300 | cleanupFunc := func() { | 316 | var cleanUpAsynchronously = func() { |
333 | 301 | cleanupCh <- true | 317 | wg.Add(1) |
334 | 302 | } | 318 | go func() { |
335 | 303 | // start the cleanup loop | 319 | defer wg.Done() |
336 | 304 | mmu.doStartCleanupLoop(cleanupFunc) | 320 | mmu.cleanUpNotifications() |
337 | 305 | // mark | 321 | }() |
338 | 306 | tickerCh <- time.Now() | 322 | } |
339 | 307 | // check it was called | 323 | |
340 | 308 | <-cleanupCh | 324 | showNotification := func(number int) { |
341 | 309 | // stop the loop and check that it's actually stopped. | 325 | action := "action-" + strconv.Itoa(number) |
342 | 310 | mmu.StopCleanupLoop() | 326 | notificationId := "notif-id-" + strconv.Itoa(number) |
343 | 311 | c.Check(ms.log.Captured(), Matches, "(?s).*DEBUG CleanupLoop stopped.*") | 327 | card := launch_helper.Card{Summary: "ehlo", Persist: true, Actions: []string{action}} |
344 | 312 | } | 328 | actions := []string{"{\"app\":\"com.example.test_test_0\",\"act\":\"" + action + "\",\"nid\":\"" + notificationId + "\"}", action} |
345 | 313 | 329 | mmu.addNotification(ms.app, notificationId, "", &card, actions, cleanUpAsynchronously) | |
346 | 314 | func (ms *MessagingSuite) TestStartCleanupLoop(c *C) { | 330 | } |
347 | 315 | mmu := New(ms.log) | 331 | |
348 | 316 | tickerCh := make(chan time.Time) | 332 | // Add 20 notifications |
349 | 317 | mmu.tickerCh = tickerCh | 333 | for i := 0; i < 20; i++ { |
350 | 318 | card := launch_helper.Card{Summary: "ehlo", Persist: true, Actions: []string{"action-1"}} | 334 | showNotification(i) |
351 | 319 | actions := []string{"{\"app\":\"com.example.test_test_0\",\"act\":\"action-1\",\"nid\":\"notif-id\"}", "action-1"} | 335 | } |
352 | 320 | mmu.addNotification(ms.app, "notif-id", "", &card, actions) | 336 | |
353 | 321 | // patch cnotificationexists to return true and signal when it's called | 337 | // wait for the cleanup goroutine in addNotification to finish in case it gets called (which it shouldn't!) |
354 | 322 | notifExistsCh := make(chan bool) | 338 | wg.Wait() |
355 | 339 | |||
356 | 340 | // check that we have got 20 notifications | ||
357 | 341 | c.Check(mmu.notifications, HasLen, 20) | ||
358 | 342 | |||
359 | 343 | // patch cNotificationExists to return true | ||
360 | 323 | cNotificationExists = func(did string, nid string) bool { | 344 | cNotificationExists = func(did string, nid string) bool { |
361 | 324 | notifExistsCh <- true | ||
362 | 325 | return true | 345 | return true |
363 | 326 | } | 346 | } |
372 | 327 | // statr the cleanup loop | 347 | |
373 | 328 | mmu.StartCleanupLoop() | 348 | // adding another notification should not remove the current ones |
374 | 329 | // mark | 349 | showNotification(21) |
375 | 330 | tickerCh <- time.Now() | 350 | |
376 | 331 | // check it's there, and marked | 351 | // wait for the cleanup goroutine in addNotification to finish in case it gets called (which it shouldn't!) |
377 | 332 | <-notifExistsCh | 352 | wg.Wait() |
378 | 333 | // stop the loop | 353 | |
379 | 334 | mmu.StopCleanupLoop() | 354 | // check we that have 21 notifications now |
380 | 355 | c.Check(mmu.notifications, HasLen, 21) | ||
381 | 356 | |||
382 | 357 | // patch cNotificationExists to return false for all but the next one we are going to add | ||
383 | 358 | cNotificationExists = func(did string, nid string) bool { | ||
384 | 359 | return nid == "notif-id-22" | ||
385 | 360 | } | ||
386 | 361 | |||
387 | 362 | // adding another notification should not remove the current ones as mmu.lastCleanupTime is too recent | ||
388 | 363 | showNotification(22) | ||
389 | 364 | |||
390 | 365 | // wait for the cleanup goroutine in addNotification to finish in case it gets called (which it shouldn't!) | ||
391 | 366 | wg.Wait() | ||
392 | 367 | |||
393 | 368 | // check we that have got 22 notifications now | ||
394 | 369 | c.Check(mmu.notifications, HasLen, 22) | ||
395 | 370 | |||
396 | 371 | // set back the lastCleanupTime to 11 minutes ago | ||
397 | 372 | mmu.lastCleanupTime = mmu.lastCleanupTime.Add(-11 * time.Minute) | ||
398 | 373 | |||
399 | 374 | // patch cNotificationExists to return false for all but the next one we are going to add | ||
400 | 375 | cNotificationExists = func(did string, nid string) bool { | ||
401 | 376 | return nid == "notif-id-23" | ||
402 | 377 | } | ||
403 | 378 | |||
404 | 379 | // adding another notification should remove all previous ones now | ||
405 | 380 | showNotification(23) | ||
406 | 381 | |||
407 | 382 | // wait for the cleanup goroutine in addNotification to finish | ||
408 | 383 | wg.Wait() | ||
409 | 384 | |||
410 | 385 | // check that all notifications except the last one have been removed | ||
411 | 386 | c.Check(mmu.notifications, HasLen, 1) | ||
412 | 335 | } | 387 | } |
413 | 336 | 388 | ||
414 | 337 | func (ms *MessagingSuite) TestGetCh(c *C) { | 389 | func (ms *MessagingSuite) TestGetCh(c *C) { |
415 | 338 | 390 | ||
416 | === modified file 'server/acceptance/acceptanceclient.go' | |||
417 | --- server/acceptance/acceptanceclient.go 2015-04-16 12:16:51 +0000 | |||
418 | +++ server/acceptance/acceptanceclient.go 2015-08-14 14:03:06 +0000 | |||
419 | @@ -49,6 +49,8 @@ | |||
420 | 49 | cookie string | 49 | cookie string |
421 | 50 | cookieLock sync.RWMutex | 50 | cookieLock sync.RWMutex |
422 | 51 | ReportSetParams bool | 51 | ReportSetParams bool |
423 | 52 | DontClose bool | ||
424 | 53 | SlowStart time.Duration | ||
425 | 52 | // connection | 54 | // connection |
426 | 53 | Connection net.Conn | 55 | Connection net.Conn |
427 | 54 | } | 56 | } |
428 | @@ -101,7 +103,10 @@ | |||
429 | 101 | // Run the session with the server, emits a stream of events. | 103 | // Run the session with the server, emits a stream of events. |
430 | 102 | func (sess *ClientSession) Run(events chan<- string) error { | 104 | func (sess *ClientSession) Run(events chan<- string) error { |
431 | 103 | conn := sess.Connection | 105 | conn := sess.Connection |
433 | 104 | defer conn.Close() | 106 | if !sess.DontClose { |
434 | 107 | defer conn.Close() | ||
435 | 108 | } | ||
436 | 109 | time.Sleep(sess.SlowStart) | ||
437 | 105 | conn.SetDeadline(time.Now().Add(sess.ExchangeTimeout)) | 110 | conn.SetDeadline(time.Now().Add(sess.ExchangeTimeout)) |
438 | 106 | _, err := conn.Write(wireVersionBytes) | 111 | _, err := conn.Write(wireVersionBytes) |
439 | 107 | if err != nil { | 112 | if err != nil { |
440 | 108 | 113 | ||
441 | === modified file 'server/acceptance/cmd/acceptanceclient.go' | |||
442 | --- server/acceptance/cmd/acceptanceclient.go 2014-08-20 19:48:59 +0000 | |||
443 | +++ server/acceptance/cmd/acceptanceclient.go 2015-08-14 14:03:06 +0000 | |||
444 | @@ -36,7 +36,7 @@ | |||
445 | 36 | kit.Defaults["auth_helper"] = "" | 36 | kit.Defaults["auth_helper"] = "" |
446 | 37 | kit.Defaults["wait_for"] = "" | 37 | kit.Defaults["wait_for"] = "" |
447 | 38 | cfg := &configuration{} | 38 | cfg := &configuration{} |
449 | 39 | kit.CliLoop(cfg, &cfg.Configuration, func(session *acceptance.ClientSession, cfgDir string) { | 39 | kit.CliLoop(cfg, &cfg.Configuration, func(session *acceptance.ClientSession, apiCli *kit.APIClient, cfgDir string) { |
450 | 40 | log.Printf("with: %#v", session) | 40 | log.Printf("with: %#v", session) |
451 | 41 | }, func(url string) string { | 41 | }, func(url string) string { |
452 | 42 | if cfg.AuthHelper == "" { | 42 | if cfg.AuthHelper == "" { |
453 | 43 | 43 | ||
454 | === modified file 'server/acceptance/kit/api.go' | |||
455 | --- server/acceptance/kit/api.go 2015-04-16 12:16:51 +0000 | |||
456 | +++ server/acceptance/kit/api.go 2015-08-14 14:03:06 +0000 | |||
457 | @@ -23,8 +23,10 @@ | |||
458 | 23 | "crypto/tls" | 23 | "crypto/tls" |
459 | 24 | "encoding/json" | 24 | "encoding/json" |
460 | 25 | "errors" | 25 | "errors" |
461 | 26 | "io" | ||
462 | 26 | "io/ioutil" | 27 | "io/ioutil" |
463 | 27 | "net/http" | 28 | "net/http" |
464 | 29 | "net/url" | ||
465 | 28 | ) | 30 | ) |
466 | 29 | 31 | ||
467 | 30 | // APIClient helps making api requests. | 32 | // APIClient helps making api requests. |
468 | @@ -56,6 +58,20 @@ | |||
469 | 56 | 58 | ||
470 | 57 | var ErrNOk = errors.New("not ok") | 59 | var ErrNOk = errors.New("not ok") |
471 | 58 | 60 | ||
472 | 61 | func readBody(respBody io.ReadCloser) (map[string]interface{}, error) { | ||
473 | 62 | defer respBody.Close() | ||
474 | 63 | body, err := ioutil.ReadAll(respBody) | ||
475 | 64 | if err != nil { | ||
476 | 65 | return nil, err | ||
477 | 66 | } | ||
478 | 67 | var res map[string]interface{} | ||
479 | 68 | err = json.Unmarshal(body, &res) | ||
480 | 69 | if err != nil { | ||
481 | 70 | return nil, &APIError{err.Error(), body} | ||
482 | 71 | } | ||
483 | 72 | return res, nil | ||
484 | 73 | } | ||
485 | 74 | |||
486 | 59 | // Post a API request. | 75 | // Post a API request. |
487 | 60 | func (api *APIClient) PostRequest(path string, message interface{}) (map[string]interface{}, error) { | 76 | func (api *APIClient) PostRequest(path string, message interface{}) (map[string]interface{}, error) { |
488 | 61 | packedMessage, err := json.Marshal(message) | 77 | packedMessage, err := json.Marshal(message) |
489 | @@ -77,18 +93,36 @@ | |||
490 | 77 | if err != nil { | 93 | if err != nil { |
491 | 78 | return nil, err | 94 | return nil, err |
492 | 79 | } | 95 | } |
495 | 80 | defer resp.Body.Close() | 96 | res, err := readBody(resp.Body) |
494 | 81 | body, err := ioutil.ReadAll(resp.Body) | ||
496 | 82 | if err != nil { | 97 | if err != nil { |
497 | 83 | return nil, err | 98 | return nil, err |
498 | 84 | } | 99 | } |
504 | 85 | var res map[string]interface{} | 100 | |
500 | 86 | err = json.Unmarshal(body, &res) | ||
501 | 87 | if err != nil { | ||
502 | 88 | return nil, &APIError{err.Error(), body} | ||
503 | 89 | } | ||
505 | 90 | if ok, _ := res["ok"].(bool); !ok { | 101 | if ok, _ := res["ok"].(bool); !ok { |
506 | 91 | return res, ErrNOk | 102 | return res, ErrNOk |
507 | 92 | } | 103 | } |
508 | 93 | return res, nil | 104 | return res, nil |
509 | 94 | } | 105 | } |
510 | 106 | |||
511 | 107 | // Get resource from API endpoint. | ||
512 | 108 | func (api *APIClient) GetRequest(path string, params map[string]string) (map[string]interface{}, error) { | ||
513 | 109 | apiURL := api.ServerAPIURL + path | ||
514 | 110 | if len(params) != 0 { | ||
515 | 111 | vals := url.Values{} | ||
516 | 112 | for k, v := range params { | ||
517 | 113 | vals.Set(k, v) | ||
518 | 114 | } | ||
519 | 115 | apiURL += "?" + vals.Encode() | ||
520 | 116 | } | ||
521 | 117 | request, _ := http.NewRequest("GET", apiURL, nil) | ||
522 | 118 | |||
523 | 119 | resp, err := api.httpClient.Do(request) | ||
524 | 120 | if err != nil { | ||
525 | 121 | return nil, err | ||
526 | 122 | } | ||
527 | 123 | res, err := readBody(resp.Body) | ||
528 | 124 | if err != nil { | ||
529 | 125 | return nil, err | ||
530 | 126 | } | ||
531 | 127 | return res, nil | ||
532 | 128 | } | ||
533 | 95 | 129 | ||
534 | === modified file 'server/acceptance/kit/cliloop.go' | |||
535 | --- server/acceptance/kit/cliloop.go 2015-04-15 15:35:12 +0000 | |||
536 | +++ server/acceptance/kit/cliloop.go 2015-08-14 14:03:06 +0000 | |||
537 | @@ -17,6 +17,7 @@ | |||
538 | 17 | package kit | 17 | package kit |
539 | 18 | 18 | ||
540 | 19 | import ( | 19 | import ( |
541 | 20 | "crypto/tls" | ||
542 | 20 | "flag" | 21 | "flag" |
543 | 21 | "fmt" | 22 | "fmt" |
544 | 22 | "log" | 23 | "log" |
545 | @@ -26,6 +27,8 @@ | |||
546 | 26 | "strings" | 27 | "strings" |
547 | 27 | "time" | 28 | "time" |
548 | 28 | 29 | ||
549 | 30 | "launchpad.net/ubuntu-push/external/murmur3" | ||
550 | 31 | |||
551 | 29 | "launchpad.net/ubuntu-push/config" | 32 | "launchpad.net/ubuntu-push/config" |
552 | 30 | "launchpad.net/ubuntu-push/server/acceptance" | 33 | "launchpad.net/ubuntu-push/server/acceptance" |
553 | 31 | ) | 34 | ) |
554 | @@ -34,11 +37,15 @@ | |||
555 | 34 | // session configuration | 37 | // session configuration |
556 | 35 | ExchangeTimeout config.ConfigTimeDuration `json:"exchange_timeout"` | 38 | ExchangeTimeout config.ConfigTimeDuration `json:"exchange_timeout"` |
557 | 36 | // server connection config | 39 | // server connection config |
559 | 37 | Target string `json:"target"` | 40 | Target string `json:"target" help:"production|staging - picks defaults"` |
560 | 38 | Addr config.ConfigHostPort `json:"addr"` | 41 | Addr config.ConfigHostPort `json:"addr"` |
561 | 42 | Vnode string `json:"vnode" help:"vnode postfix to make up a targeting device-id"` | ||
562 | 39 | CertPEMFile string `json:"cert_pem_file"` | 43 | CertPEMFile string `json:"cert_pem_file"` |
563 | 40 | Insecure bool `json:"insecure" help:"disable checking of server certificate and hostname"` | 44 | Insecure bool `json:"insecure" help:"disable checking of server certificate and hostname"` |
564 | 41 | Domain string `json:"domain" help:"domain for tls connect"` | 45 | Domain string `json:"domain" help:"domain for tls connect"` |
565 | 46 | // api config | ||
566 | 47 | APIURL string `json:"api" help:"api url"` | ||
567 | 48 | APICertPEMFile string `json:"api_cert_pem_file"` | ||
568 | 42 | // run timeout | 49 | // run timeout |
569 | 43 | RunTimeout config.ConfigTimeDuration `json:"run_timeout"` | 50 | RunTimeout config.ConfigTimeDuration `json:"run_timeout"` |
570 | 44 | // flags | 51 | // flags |
571 | @@ -66,22 +73,25 @@ | |||
572 | 66 | var ( | 73 | var ( |
573 | 67 | Name = "acceptanceclient" | 74 | Name = "acceptanceclient" |
574 | 68 | Defaults = map[string]interface{}{ | 75 | Defaults = map[string]interface{}{ |
586 | 69 | "target": "", | 76 | "target": "", |
587 | 70 | "addr": ":0", | 77 | "addr": ":0", |
588 | 71 | "exchange_timeout": "5s", | 78 | "vnode": "", |
589 | 72 | "cert_pem_file": "", | 79 | "exchange_timeout": "5s", |
590 | 73 | "insecure": false, | 80 | "cert_pem_file": "", |
591 | 74 | "domain": "", | 81 | "insecure": false, |
592 | 75 | "run_timeout": "0s", | 82 | "domain": "", |
593 | 76 | "reportPings": true, | 83 | "run_timeout": "0s", |
594 | 77 | "model": "?", | 84 | "reportPings": true, |
595 | 78 | "imageChannel": "?", | 85 | "model": "?", |
596 | 79 | "buildNumber": -1, | 86 | "imageChannel": "?", |
597 | 87 | "buildNumber": -1, | ||
598 | 88 | "api": "", | ||
599 | 89 | "api_cert_pem_file": "", | ||
600 | 80 | } | 90 | } |
601 | 81 | ) | 91 | ) |
602 | 82 | 92 | ||
603 | 83 | // CliLoop parses command line arguments and runs a client loop. | 93 | // CliLoop parses command line arguments and runs a client loop. |
605 | 84 | func CliLoop(totalCfg interface{}, cfg *Configuration, onSetup func(sess *acceptance.ClientSession, cfgDir string), auth func(string) string, waitFor func() string, onConnect func()) { | 94 | func CliLoop(totalCfg interface{}, cfg *Configuration, onSetup func(sess *acceptance.ClientSession, apiCli *APIClient, cfgDir string), auth func(string) string, waitFor func() string, onConnect func()) { |
606 | 85 | flag.Usage = func() { | 95 | flag.Usage = func() { |
607 | 86 | fmt.Fprintf(os.Stderr, "Usage: %s [options] <device id>\n", Name) | 96 | fmt.Fprintf(os.Stderr, "Usage: %s [options] <device id>\n", Name) |
608 | 87 | flag.PrintDefaults() | 97 | flag.PrintDefaults() |
609 | @@ -95,31 +105,71 @@ | |||
610 | 95 | if err != nil { | 105 | if err != nil { |
611 | 96 | log.Fatalf("reading config: %v", err) | 106 | log.Fatalf("reading config: %v", err) |
612 | 97 | } | 107 | } |
617 | 98 | narg := flag.NArg() | 108 | deviceId := "" |
618 | 99 | switch { | 109 | if cfg.Vnode != "" { |
619 | 100 | case narg < 1: | 110 | if cfg.Addr == ":0" { |
620 | 101 | missingArg("device-id") | 111 | log.Fatalf("-vnode needs -addr specified") |
621 | 112 | } | ||
622 | 113 | deviceId = cfg.Addr.HostPort() + "|" + cfg.Vnode | ||
623 | 114 | log.Printf("using device-id: %q", deviceId) | ||
624 | 115 | } else { | ||
625 | 116 | narg := flag.NArg() | ||
626 | 117 | switch { | ||
627 | 118 | case narg < 1: | ||
628 | 119 | missingArg("device-id") | ||
629 | 120 | } | ||
630 | 121 | deviceId = flag.Arg(0) | ||
631 | 122 | } | ||
632 | 123 | cfgDir := filepath.Dir(flag.Lookup("cfg@").Value.String()) | ||
633 | 124 | // setup api | ||
634 | 125 | apiCli := &APIClient{} | ||
635 | 126 | var apiTLSConfig *tls.Config | ||
636 | 127 | if cfg.APICertPEMFile != "" || cfg.Insecure { | ||
637 | 128 | var err error | ||
638 | 129 | apiTLSConfig, err = MakeTLSConfig("", cfg.Insecure, | ||
639 | 130 | cfg.APICertPEMFile, cfgDir) | ||
640 | 131 | if err != nil { | ||
641 | 132 | log.Fatalf("api tls config: %v", err) | ||
642 | 133 | } | ||
643 | 134 | } | ||
644 | 135 | apiCli.SetupClient(apiTLSConfig, true, 1) | ||
645 | 136 | if cfg.APIURL == "" { | ||
646 | 137 | apiCli.ServerAPIURL = cfg.PickByTarget("api", | ||
647 | 138 | "https://push.ubuntu.com", | ||
648 | 139 | "https://push.staging.ubuntu.com") | ||
649 | 140 | } else { | ||
650 | 141 | apiCli.ServerAPIURL = cfg.APIURL | ||
651 | 102 | } | 142 | } |
652 | 103 | addr := "" | 143 | addr := "" |
653 | 144 | domain := "" | ||
654 | 104 | if cfg.Addr == ":0" { | 145 | if cfg.Addr == ":0" { |
657 | 105 | addr = cfg.PickByTarget("addr", "push-delivery.ubuntu.com:443", | 146 | hash := murmur3.Sum64([]byte(deviceId)) |
658 | 106 | "push-delivery.staging.ubuntu.com:443") | 147 | hosts, err := apiCli.GetRequest("/delivery-hosts", |
659 | 148 | map[string]string{ | ||
660 | 149 | "h": fmt.Sprintf("%x", hash), | ||
661 | 150 | }) | ||
662 | 151 | if err != nil { | ||
663 | 152 | log.Fatalf("querying hosts: %v", err) | ||
664 | 153 | } | ||
665 | 154 | addr = hosts["hosts"].([]interface{})[0].(string) | ||
666 | 155 | domain = hosts["domain"].(string) | ||
667 | 156 | log.Printf("using: %s %s", addr, domain) | ||
668 | 107 | } else { | 157 | } else { |
669 | 108 | addr = cfg.Addr.HostPort() | 158 | addr = cfg.Addr.HostPort() |
670 | 159 | domain = cfg.Domain | ||
671 | 109 | } | 160 | } |
672 | 110 | session := &acceptance.ClientSession{ | 161 | session := &acceptance.ClientSession{ |
673 | 111 | ExchangeTimeout: cfg.ExchangeTimeout.TimeDuration(), | 162 | ExchangeTimeout: cfg.ExchangeTimeout.TimeDuration(), |
674 | 112 | ServerAddr: addr, | 163 | ServerAddr: addr, |
676 | 113 | DeviceId: flag.Arg(0), | 164 | DeviceId: deviceId, |
677 | 114 | // flags | 165 | // flags |
678 | 115 | Model: cfg.DeviceModel, | 166 | Model: cfg.DeviceModel, |
679 | 116 | ImageChannel: cfg.ImageChannel, | 167 | ImageChannel: cfg.ImageChannel, |
680 | 117 | BuildNumber: cfg.BuildNumber, | 168 | BuildNumber: cfg.BuildNumber, |
681 | 118 | ReportPings: cfg.ReportPings, | 169 | ReportPings: cfg.ReportPings, |
682 | 119 | } | 170 | } |
686 | 120 | cfgDir := filepath.Dir(flag.Lookup("cfg@").Value.String()) | 171 | onSetup(session, apiCli, cfgDir) |
687 | 121 | onSetup(session, cfgDir) | 172 | session.TLSConfig, err = MakeTLSConfig(domain, cfg.Insecure, cfg.CertPEMFile, cfgDir) |
685 | 122 | session.TLSConfig, err = MakeTLSConfig(cfg.Domain, cfg.Insecure, cfg.CertPEMFile, cfgDir) | ||
688 | 123 | if err != nil { | 173 | if err != nil { |
689 | 124 | log.Fatalf("tls config: %v", err) | 174 | log.Fatalf("tls config: %v", err) |
690 | 125 | } | 175 | } |
691 | 126 | 176 | ||
692 | === modified file 'ubuntu-push-client.go' | |||
693 | --- ubuntu-push-client.go 2015-01-21 21:31:39 +0000 | |||
694 | +++ ubuntu-push-client.go 2015-08-14 14:03:06 +0000 | |||
695 | @@ -35,8 +35,8 @@ | |||
696 | 35 | buf := make([]byte, 1<<20) | 35 | buf := make([]byte, 1<<20) |
697 | 36 | for { | 36 | for { |
698 | 37 | <-sigs | 37 | <-sigs |
701 | 38 | runtime.Stack(buf, true) | 38 | sz := runtime.Stack(buf, true) |
702 | 39 | log.Printf("=== received SIGQUIT ===\n*** goroutine dump...\n%s\n*** end\n", buf) | 39 | log.Printf("=== received SIGQUIT ===\n*** goroutine dump...\n%s\n*** end", buf[:sz]) |
703 | 40 | } | 40 | } |
704 | 41 | }() | 41 | }() |
705 | 42 | } | 42 | } |