Merge lp:~pedronis/ubuntu-push/acceptance-flex-1 into lp:ubuntu-push

Proposed by Samuele Pedroni
Status: Merged
Approved by: Samuele Pedroni
Approved revision: 68
Merged at revision: 64
Proposed branch: lp:~pedronis/ubuntu-push/acceptance-flex-1
Merge into: lp:ubuntu-push
Diff against target: 501 lines (+203/-143)
2 files modified
server/acceptance/acceptance_helpers.go (+156/-0)
server/acceptance/acceptance_test.go (+47/-143)
To merge this branch: bzr merge lp:~pedronis/ubuntu-push/acceptance-flex-1
Reviewer Review Type Date Requested Status
John Lenton (community) Approve
Review via email: mp+205846@code.launchpad.net

Commit message

starting splitting out helpers in the acceptance tests

Description of the change

in preparation of restructuring acceptance tests as reusable suites: starting splitting out helpers

To post a comment you must log in.
Revision history for this message
John Lenton (chipaca) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'server/acceptance/acceptance_helpers.go'
2--- server/acceptance/acceptance_helpers.go 1970-01-01 00:00:00 +0000
3+++ server/acceptance/acceptance_helpers.go 2014-02-11 20:38:55 +0000
4@@ -0,0 +1,156 @@
5+/*
6+ Copyright 2013-2014 Canonical Ltd.
7+
8+ This program is free software: you can redistribute it and/or modify it
9+ under the terms of the GNU General Public License version 3, as published
10+ by the Free Software Foundation.
11+
12+ This program is distributed in the hope that it will be useful, but
13+ WITHOUT ANY WARRANTY; without even the implied warranties of
14+ MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
15+ PURPOSE. See the GNU General Public License for more details.
16+
17+ You should have received a copy of the GNU General Public License along
18+ with this program. If not, see <http://www.gnu.org/licenses/>.
19+*/
20+
21+package acceptance
22+
23+import (
24+ "bufio"
25+ "encoding/json"
26+ "fmt"
27+ "io/ioutil"
28+ "os"
29+ "os/exec"
30+ "path/filepath"
31+ "regexp"
32+ "strings"
33+ "time"
34+
35+ . "launchpad.net/gocheck"
36+
37+ helpers "launchpad.net/ubuntu-push/testing"
38+)
39+
40+// FillConfig fills cfg from values.
41+func FillConfig(cfg, values map[string]interface{}) {
42+ for k, v := range values {
43+ cfg[k] = v
44+ }
45+}
46+
47+// FillServerConfig fills cfg with default server values and "addr": addr.
48+func FillServerConfig(cfg map[string]interface{}, addr string) {
49+ FillConfig(cfg, map[string]interface{}{
50+ "exchange_timeout": "0.1s",
51+ "ping_interval": "0.5s",
52+ "session_queue_size": 10,
53+ "broker_queue_size": 100,
54+ "addr": addr,
55+ "key_pem_file": helpers.SourceRelative("config/testing.key"),
56+ "cert_pem_file": helpers.SourceRelative("config/testing.cert"),
57+ })
58+}
59+
60+// FillHttpServerConfig fills cfg with default http server values and
61+// "http_addr": httpAddr.
62+func FillHTTPServerConfig(cfg map[string]interface{}, httpAddr string) {
63+ FillConfig(cfg, map[string]interface{}{
64+ "http_addr": httpAddr,
65+ "http_read_timeout": "1s",
66+ "http_write_timeout": "1s",
67+ })
68+}
69+
70+// WriteConfig writes out a config and returns the written filepath.
71+func WriteConfig(c *C, dir, filename string, cfg map[string]interface{}) string {
72+ cfgFpath := filepath.Join(dir, filename)
73+ cfgJson, err := json.Marshal(cfg)
74+ if err != nil {
75+ c.Fatal(err)
76+ }
77+ err = ioutil.WriteFile(cfgFpath, cfgJson, os.ModePerm)
78+ if err != nil {
79+ c.Fatal(err)
80+ }
81+ return cfgFpath
82+}
83+
84+var rxLineInfo = regexp.MustCompile("^.*? ([[:alpha:]].*)\n")
85+
86+// RunAndObserve runs cmdName and returns a channel that will receive
87+// cmdName stderr logging and a function to kill the process.
88+func RunAndObserve(c *C, cmdName string, arg ...string) (<-chan string, func()) {
89+ cmd := exec.Command(cmdName, arg...)
90+ stderr, err := cmd.StderrPipe()
91+ if err != nil {
92+ c.Fatal(err)
93+ }
94+ err = cmd.Start()
95+ if err != nil {
96+ c.Fatal(err)
97+ }
98+ bufErr := bufio.NewReaderSize(stderr, 5000)
99+ getLineInfo := func() (string, error) {
100+ for {
101+ line, err := bufErr.ReadString('\n')
102+ if err != nil {
103+ return "", err
104+ }
105+ extracted := rxLineInfo.FindStringSubmatch(line)
106+ if extracted == nil {
107+ return "", fmt.Errorf("unexpected line: %#v", line)
108+ }
109+ info := extracted[1]
110+ return info, nil
111+ }
112+ }
113+ logs := make(chan string, 10)
114+ go func() {
115+ for {
116+ info, err := getLineInfo()
117+ if err != nil {
118+ logs <- fmt.Sprintf("%s capture: %v", cmdName, err)
119+ close(logs)
120+ return
121+ }
122+ logs <- info
123+ }
124+ }()
125+ return logs, func() { cmd.Process.Kill() }
126+}
127+
128+const (
129+ DevListeningOnPat = "INFO listening for devices on "
130+ HTTPListeningOnPat = "INFO listening for http on "
131+ debugPrefix = "DEBUG "
132+)
133+
134+// ExtractListeningAddr goes over logs ignoring DEBUG lines
135+// until a line starting with pat and returns the rest of that line.
136+func ExtractListeningAddr(c *C, logs <-chan string, pat string) string {
137+ for line := range logs {
138+ if strings.HasPrefix(line, debugPrefix) {
139+ continue
140+ }
141+ if !strings.HasPrefix(line, pat) {
142+ c.Fatalf("matching %v: %v", pat, line)
143+ }
144+ return line[len(pat):]
145+ }
146+ panic(fmt.Errorf("logs closed unexpectedly marching %v", pat))
147+}
148+
149+// NextEvent receives an event from given string channel with a 5s timeout,
150+// or from a channel for errors.
151+func NextEvent(events <-chan string, errCh <-chan error) string {
152+ select {
153+ case <-time.After(5 * time.Second):
154+ panic("too long stuck waiting for next event")
155+ case err := <-errCh:
156+ return err.Error() // will fail comparison typically
157+ case evStr := <-events:
158+ return evStr
159+ }
160+}
161
162=== modified file 'server/acceptance/acceptance_test.go'
163--- server/acceptance/acceptance_test.go 2014-02-10 23:50:29 +0000
164+++ server/acceptance/acceptance_test.go 2014-02-11 20:38:55 +0000
165@@ -17,7 +17,6 @@
166 package acceptance
167
168 import (
169- "bufio"
170 "bytes"
171 "encoding/json"
172 "flag"
173@@ -25,10 +24,6 @@
174 "io/ioutil"
175 "net"
176 "net/http"
177- "os"
178- "os/exec"
179- "path/filepath"
180- "regexp"
181 "runtime"
182 "strings"
183 "testing"
184@@ -44,7 +39,7 @@
185 func TestAcceptance(t *testing.T) { TestingT(t) }
186
187 type acceptanceSuite struct {
188- server *exec.Cmd
189+ serverKill func()
190 serverAddr string
191 serverURL string
192 serverEvents <-chan string
193@@ -57,18 +52,9 @@
194 var serverAuxCfg = flag.String("auxcfg", "", "auxiliary config for the server")
195
196 func testServerConfig(addr, httpAddr string) map[string]interface{} {
197- cfg := map[string]interface{}{
198- "exchange_timeout": "0.1s",
199- "ping_interval": "0.5s",
200- "session_queue_size": 10,
201- "broker_queue_size": 100,
202- "addr": addr,
203- "key_pem_file": helpers.SourceRelative("config/testing.key"),
204- "cert_pem_file": helpers.SourceRelative("config/testing.cert"),
205- "http_addr": httpAddr,
206- "http_read_timeout": "1s",
207- "http_write_timeout": "1s",
208- }
209+ cfg := make(map[string]interface{})
210+ FillServerConfig(cfg, addr)
211+ FillHTTPServerConfig(cfg, httpAddr)
212 return cfg
213 }
214
215@@ -86,109 +72,27 @@
216 }
217 }
218
219-const (
220- devListeningOnPat = "INFO listening for devices on "
221- httpListeningOnPat = "INFO listening for http on "
222- debugPrefix = "DEBUG "
223-)
224-
225-var rxLineInfo = regexp.MustCompile("^.*? ([[:alpha:]].*)\n")
226-
227-func extractListeningAddr(c *C, pat, line string) string {
228- if !strings.HasPrefix(line, pat) {
229- c.Fatalf("server: %v", line)
230- }
231- return line[len(pat):]
232-}
233-
234 // start a new server for each test
235 func (s *acceptanceSuite) SetUpTest(c *C) {
236 if *serverCmd == "" {
237 c.Skip("executable server not specified")
238 }
239 tmpDir := c.MkDir()
240- cfgFilename := filepath.Join(tmpDir, "config.json")
241- cfgJson, err := json.Marshal(testServerConfig("127.0.0.1:0", "127.0.0.1:0"))
242- if err != nil {
243- c.Fatal(err)
244- }
245- err = ioutil.WriteFile(cfgFilename, cfgJson, os.ModePerm)
246- if err != nil {
247- c.Fatal(err)
248- }
249+ cfg := testServerConfig("127.0.0.1:0", "127.0.0.1:0")
250+ cfgFilename := WriteConfig(c, tmpDir, "config.json", cfg)
251 cfgs := append(strings.Fields(*serverAuxCfg), cfgFilename)
252- server := exec.Command(*serverCmd, cfgs...)
253- stderr, err := server.StderrPipe()
254- if err != nil {
255- c.Fatal(err)
256- }
257- err = server.Start()
258- if err != nil {
259- c.Fatal(err)
260- }
261- bufErr := bufio.NewReaderSize(stderr, 5000)
262- getLineInfo := func(ignoreDebug bool) (string, error) {
263- for {
264- line, err := bufErr.ReadString('\n')
265- if err != nil {
266- return "", err
267- }
268- extracted := rxLineInfo.FindStringSubmatch(line)
269- if extracted == nil {
270- return "", fmt.Errorf("unexpected server line: %#v", line)
271- }
272- info := extracted[1]
273- if ignoreDebug && strings.HasPrefix(info, debugPrefix) {
274- // don't report DEBUG lines
275- continue
276- }
277- return info, nil
278- }
279- }
280- infoHTTP, err := getLineInfo(true)
281- if err != nil {
282- c.Fatal(err)
283- }
284- serverHTTPAddr := extractListeningAddr(c, httpListeningOnPat, infoHTTP)
285+ serverEvents, killServer := RunAndObserve(c, *serverCmd, cfgs...)
286+ s.serverKill = killServer
287+ serverHTTPAddr := ExtractListeningAddr(c, serverEvents, HTTPListeningOnPat)
288 s.serverURL = fmt.Sprintf("http://%s", serverHTTPAddr)
289- info, err := getLineInfo(true)
290- if err != nil {
291- c.Fatal(err)
292- }
293- s.serverAddr = extractListeningAddr(c, devListeningOnPat, info)
294- s.server = server
295- serverEvents := make(chan string, 5)
296+ s.serverAddr = ExtractListeningAddr(c, serverEvents, DevListeningOnPat)
297 s.serverEvents = serverEvents
298- go func() {
299- for {
300- info, err := getLineInfo(false)
301- if err != nil {
302- serverEvents <- fmt.Sprintf("ERROR: %v", err)
303- close(serverEvents)
304- return
305- }
306- serverEvents <- info
307- }
308- }()
309 s.httpClient = &http.Client{}
310 }
311
312 func (s *acceptanceSuite) TearDownTest(c *C) {
313- if s.server != nil {
314- s.server.Process.Kill()
315- s.server = nil
316- }
317-}
318-
319-// nextEvent receives an event from given channel with a 5s timeout
320-func nextEvent(events <-chan string, errCh <-chan error) string {
321- select {
322- case <-time.After(5 * time.Second):
323- panic("too long stuck waiting for next event")
324- case err := <-errCh:
325- return err.Error() // will fail comparison typically
326- case evStr := <-events:
327- return evStr
328+ if s.serverKill != nil {
329+ s.serverKill()
330 }
331 }
332
333@@ -256,19 +160,19 @@
334 go func() {
335 errCh <- sess.Run(events)
336 }()
337- connectCli := nextEvent(events, errCh)
338- connectSrv := nextEvent(s.serverEvents, nil)
339- registeredSrv := nextEvent(s.serverEvents, nil)
340+ connectCli := NextEvent(events, errCh)
341+ connectSrv := NextEvent(s.serverEvents, nil)
342+ registeredSrv := NextEvent(s.serverEvents, nil)
343 tconnect := time.Now()
344 c.Assert(connectSrv, Matches, ".*session.* connected .*")
345 c.Assert(registeredSrv, Matches, ".*session.* registered DEVA")
346 c.Assert(strings.HasSuffix(connectSrv, connectCli), Equals, true)
347- c.Assert(nextEvent(events, errCh), Equals, "Ping")
348+ c.Assert(NextEvent(events, errCh), Equals, "Ping")
349 elapsedOfPing := float64(time.Since(tconnect)) / float64(500*time.Millisecond)
350 c.Check(elapsedOfPing >= 1.0, Equals, true)
351 c.Check(elapsedOfPing < 1.05, Equals, true)
352- c.Assert(nextEvent(events, errCh), Equals, "Ping")
353- c.Assert(nextEvent(s.serverEvents, nil), Matches, ".*session.* ended with: EOF")
354+ c.Assert(NextEvent(events, errCh), Equals, "Ping")
355+ c.Assert(NextEvent(s.serverEvents, nil), Matches, ".*session.* ended with: EOF")
356 c.Check(len(errCh), Equals, 0)
357 }
358
359@@ -291,11 +195,11 @@
360 go func() {
361 errCh <- sess.Run(events)
362 }()
363- c.Assert(nextEvent(events, errCh), Matches, "connected .*")
364- c.Assert(nextEvent(s.serverEvents, nil), Matches, ".*session.* connected .*")
365- c.Assert(nextEvent(s.serverEvents, nil), Matches, ".*session.* registered .*")
366- c.Assert(nextEvent(events, errCh), Equals, "Ping")
367- c.Assert(nextEvent(s.serverEvents, nil), Matches, `.* ended with:.*timeout`)
368+ c.Assert(NextEvent(events, errCh), Matches, "connected .*")
369+ c.Assert(NextEvent(s.serverEvents, nil), Matches, ".*session.* connected .*")
370+ c.Assert(NextEvent(s.serverEvents, nil), Matches, ".*session.* registered .*")
371+ c.Assert(NextEvent(events, errCh), Equals, "Ping")
372+ c.Assert(NextEvent(s.serverEvents, nil), Matches, `.* ended with:.*timeout`)
373 c.Check(len(errCh), Equals, 0)
374 }
375
376@@ -335,9 +239,9 @@
377 go func() {
378 errCh <- sess.Run(events)
379 }()
380- c.Assert(nextEvent(events, errCh), Matches, "connected .*")
381- c.Assert(nextEvent(s.serverEvents, nil), Matches, ".*session.* connected .*")
382- c.Assert(nextEvent(s.serverEvents, nil), Matches, ".*session.* registered "+devId)
383+ c.Assert(NextEvent(events, errCh), Matches, "connected .*")
384+ c.Assert(NextEvent(s.serverEvents, nil), Matches, ".*session.* connected .*")
385+ c.Assert(NextEvent(s.serverEvents, nil), Matches, ".*session.* registered "+devId)
386 return events, errCh
387 }
388
389@@ -359,9 +263,9 @@
390 })
391 c.Assert(err, IsNil)
392 c.Assert(got, Matches, ".*ok.*")
393- c.Check(nextEvent(events, errCh), Equals, `broadcast chan:0 app: topLevel:1 payloads:[{"n":42}]`)
394+ c.Check(NextEvent(events, errCh), Equals, `broadcast chan:0 app: topLevel:1 payloads:[{"n":42}]`)
395 clientShutdown <- true
396- c.Assert(nextEvent(s.serverEvents, nil), Matches, `.* ended with:.*EOF`)
397+ c.Assert(NextEvent(s.serverEvents, nil), Matches, `.* ended with:.*EOF`)
398 c.Check(len(errCh), Equals, 0)
399 }
400
401@@ -386,9 +290,9 @@
402 }
403 events, errCh := s.startClient(c, "DEVB", intercept, nil)
404 // gettting pending on connect
405- c.Check(nextEvent(events, errCh), Equals, `broadcast chan:0 app: topLevel:1 payloads:[{"b":1}]`)
406+ c.Check(NextEvent(events, errCh), Equals, `broadcast chan:0 app: topLevel:1 payloads:[{"b":1}]`)
407 clientShutdown <- true
408- c.Assert(nextEvent(s.serverEvents, nil), Matches, `.* ended with:.*EOF`)
409+ c.Assert(NextEvent(s.serverEvents, nil), Matches, `.* ended with:.*EOF`)
410 c.Check(len(errCh), Equals, 0)
411 }
412
413@@ -416,10 +320,10 @@
414 }
415 events, errCh := s.startClient(c, "DEVC", intercept, nil)
416 // gettting pending on connect
417- c.Check(nextEvent(events, errCh), Matches, `broadcast chan:0 app: topLevel:30 payloads:\[{"b":0,.*`)
418- c.Check(nextEvent(events, errCh), Matches, `broadcast chan:0 app: topLevel:32 payloads:\[.*`)
419+ c.Check(NextEvent(events, errCh), Matches, `broadcast chan:0 app: topLevel:30 payloads:\[{"b":0,.*`)
420+ c.Check(NextEvent(events, errCh), Matches, `broadcast chan:0 app: topLevel:32 payloads:\[.*`)
421 clientShutdown <- true
422- c.Assert(nextEvent(s.serverEvents, nil), Matches, `.* ended with:.*EOF`)
423+ c.Assert(NextEvent(s.serverEvents, nil), Matches, `.* ended with:.*EOF`)
424 c.Check(len(errCh), Equals, 0)
425 }
426
427@@ -445,11 +349,11 @@
428 })
429 c.Assert(err, IsNil)
430 c.Assert(got, Matches, ".*ok.*")
431- c.Check(nextEvent(events1, errCh1), Equals, `broadcast chan:0 app: topLevel:1 payloads:[{"n":42}]`)
432- c.Check(nextEvent(events2, errCh2), Equals, `broadcast chan:0 app: topLevel:1 payloads:[{"n":42}]`)
433+ c.Check(NextEvent(events1, errCh1), Equals, `broadcast chan:0 app: topLevel:1 payloads:[{"n":42}]`)
434+ c.Check(NextEvent(events2, errCh2), Equals, `broadcast chan:0 app: topLevel:1 payloads:[{"n":42}]`)
435 clientShutdown <- true
436- c.Assert(nextEvent(s.serverEvents, nil), Matches, `.* ended with:.*EOF`)
437- c.Assert(nextEvent(s.serverEvents, nil), Matches, `.* ended with:.*EOF`)
438+ c.Assert(NextEvent(s.serverEvents, nil), Matches, `.* ended with:.*EOF`)
439+ c.Assert(NextEvent(s.serverEvents, nil), Matches, `.* ended with:.*EOF`)
440 c.Check(len(errCh1), Equals, 0)
441 c.Check(len(errCh2), Equals, 0)
442 }
443@@ -472,9 +376,9 @@
444 })
445 c.Assert(err, IsNil)
446 c.Assert(got, Matches, ".*ok.*")
447- c.Check(nextEvent(events, errCh), Equals, `broadcast chan:0 app: topLevel:1 payloads:[{"b":1}]`)
448+ c.Check(NextEvent(events, errCh), Equals, `broadcast chan:0 app: topLevel:1 payloads:[{"b":1}]`)
449 clientShutdown <- true
450- c.Assert(nextEvent(s.serverEvents, nil), Matches, `.* ended with:.*EOF`)
451+ c.Assert(NextEvent(s.serverEvents, nil), Matches, `.* ended with:.*EOF`)
452 c.Check(len(errCh), Equals, 0)
453 // another broadcast
454 got, err = s.postRequest("/broadcast", &api.Broadcast{
455@@ -489,9 +393,9 @@
456 events, errCh = s.startClient(c, "DEVD", intercept, map[string]int64{
457 protocol.SystemChannelId: 1,
458 })
459- c.Check(nextEvent(events, errCh), Equals, `broadcast chan:0 app: topLevel:2 payloads:[{"b":2}]`)
460+ c.Check(NextEvent(events, errCh), Equals, `broadcast chan:0 app: topLevel:2 payloads:[{"b":2}]`)
461 clientShutdown <- true
462- c.Assert(nextEvent(s.serverEvents, nil), Matches, `.* ended with:.*EOF`)
463+ c.Assert(NextEvent(s.serverEvents, nil), Matches, `.* ended with:.*EOF`)
464 c.Check(len(errCh), Equals, 0)
465 }
466
467@@ -525,9 +429,9 @@
468 protocol.SystemChannelId: 10,
469 })
470 // gettting last one pending on connect
471- c.Check(nextEvent(events, errCh), Equals, `broadcast chan:0 app: topLevel:2 payloads:[{"b":2}]`)
472+ c.Check(NextEvent(events, errCh), Equals, `broadcast chan:0 app: topLevel:2 payloads:[{"b":2}]`)
473 clientShutdown <- true
474- c.Assert(nextEvent(s.serverEvents, nil), Matches, `.* ended with:.*EOF`)
475+ c.Assert(NextEvent(s.serverEvents, nil), Matches, `.* ended with:.*EOF`)
476 c.Check(len(errCh), Equals, 0)
477 }
478
479@@ -546,9 +450,9 @@
480 protocol.SystemChannelId: 10,
481 })
482 // gettting empty pending on connect
483- c.Check(nextEvent(events, errCh), Equals, `broadcast chan:0 app: topLevel:0 payloads:null`)
484+ c.Check(NextEvent(events, errCh), Equals, `broadcast chan:0 app: topLevel:0 payloads:null`)
485 clientShutdown <- true
486- c.Assert(nextEvent(s.serverEvents, nil), Matches, `.* ended with:.*EOF`)
487+ c.Assert(NextEvent(s.serverEvents, nil), Matches, `.* ended with:.*EOF`)
488 c.Check(len(errCh), Equals, 0)
489 }
490
491@@ -582,8 +486,8 @@
492 protocol.SystemChannelId: -10,
493 })
494 // gettting pending on connect
495- c.Check(nextEvent(events, errCh), Equals, `broadcast chan:0 app: topLevel:2 payloads:[{"b":1},{"b":2}]`)
496+ c.Check(NextEvent(events, errCh), Equals, `broadcast chan:0 app: topLevel:2 payloads:[{"b":1},{"b":2}]`)
497 clientShutdown <- true
498- c.Assert(nextEvent(s.serverEvents, nil), Matches, `.* ended with:.*EOF`)
499+ c.Assert(NextEvent(s.serverEvents, nil), Matches, `.* ended with:.*EOF`)
500 c.Check(len(errCh), Equals, 0)
501 }

Subscribers

People subscribed via source and target branches