Merge lp:~mattyw/sharinfoo/tests-and-client-refactoring into lp:sharinfoo

Proposed by Matthew Williams
Status: Merged
Merged at revision: 11
Proposed branch: lp:~mattyw/sharinfoo/tests-and-client-refactoring
Merge into: lp:sharinfoo
Prerequisite: lp:~mattyw/sharinfoo/view-access-list
Diff against target: 613 lines (+350/-199)
6 files modified
Makefile (+8/-0)
client/client.go (+205/-0)
client/client_test.go (+45/-0)
cmd/shfoo/main.go (+20/-198)
server.go (+1/-1)
tests/client_test.py (+71/-0)
To merge this branch: bzr merge lp:~mattyw/sharinfoo/tests-and-client-refactoring
Reviewer Review Type Date Requested Status
Cloud Engineering: Green Squad Pending
Casey Marshall Pending
Review via email: mp+201170@code.launchpad.net

Commit message

Refactored the client to allow unit tests to be written.
Added a python test which tests the actual client binary.
Added a makefile to run the tests

Description of the change

Refactored the client to allow unit tests to be written.
Added a python test which tests the actual client binary.
Added a makefile to run the tests

After this change I can start refactoring the server without fearing breaking the client

To post a comment you must log in.
19. By Matthew Williams

make the python file cleaner

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'Makefile'
2--- Makefile 1970-01-01 00:00:00 +0000
3+++ Makefile 2014-01-10 12:43:25 +0000
4@@ -0,0 +1,8 @@
5+check: install
6+ shfood &
7+ go test ./...
8+ python ./tests/client_test.py
9+ killall shfood
10+
11+install:
12+ go install ./...
13
14=== added directory 'client'
15=== added file 'client/client.go'
16--- client/client.go 1970-01-01 00:00:00 +0000
17+++ client/client.go 2014-01-10 12:43:25 +0000
18@@ -0,0 +1,205 @@
19+package client
20+
21+import (
22+ "bytes"
23+ "fmt"
24+ "io"
25+ "io/ioutil"
26+ "net/http"
27+ "net/url"
28+ "os"
29+ "path"
30+ "strings"
31+
32+ "code.google.com/p/gopass"
33+ "launchpad.net/usso"
34+)
35+
36+type ClosingBuffer struct {
37+ *bytes.Buffer
38+}
39+
40+func (cb *ClosingBuffer) Close() error {
41+ return nil
42+}
43+
44+func Login(user string) error {
45+ ssoData, err := SSOLogin(user)
46+ if err != nil {
47+ return err
48+ }
49+ f, err := os.Create(path.Join(os.Getenv("HOME"), ".shfoo_auth"))
50+ if err != nil {
51+ return err
52+ }
53+ defer f.Close()
54+ _, err = fmt.Fprintf(f, "ConsumerKey=%s, ConsumerSecret=%s, "+
55+ "TokenKey=%s, TokenName=%s, TokenSecret=%s",
56+ ssoData.ConsumerKey, ssoData.ConsumerSecret, ssoData.TokenKey,
57+ ssoData.TokenName, ssoData.TokenSecret)
58+ return err
59+}
60+
61+// Perform a Ubuntu SSO login with the provided email
62+func SSOLogin(email string) (*usso.SSOData, error) {
63+ pass, err := gopass.GetPass("Password: ")
64+ if err != nil {
65+ return nil, err
66+ }
67+
68+ ssoData, err := usso.ProductionUbuntuSSOServer.GetToken(email, pass, "sharinfoo")
69+ if err != nil {
70+ return nil, err
71+ }
72+
73+ return ssoData, nil
74+}
75+
76+func loadAuth() (string, error) {
77+ f, err := os.Open(path.Join(os.Getenv("HOME"), ".shfoo_auth"))
78+ if err != nil {
79+ return "", err
80+ }
81+ buf, err := ioutil.ReadAll(f)
82+ if err != nil {
83+ return "", err
84+ }
85+ return string(buf), nil
86+}
87+
88+func Delete(addr, path string) error {
89+ authString, err := loadAuth()
90+ if err != nil {
91+ return err
92+ }
93+ u := url.URL{
94+ Scheme: "http",
95+ Host: addr,
96+ Path: path,
97+ }
98+ req, err := http.NewRequest("DELETE", u.String(), nil)
99+ if err != nil {
100+ return err
101+ }
102+ req.Header.Add("Authorization", authString)
103+ resp, err := http.DefaultClient.Do(req)
104+ if err != nil {
105+ return err
106+ }
107+ if resp.StatusCode != 200 {
108+ return fmt.Errorf(resp.Status)
109+ }
110+ _, err = io.Copy(os.Stdout, resp.Body)
111+ return err
112+}
113+
114+func Put(addr, path string, data []byte) error {
115+ authString, err := loadAuth()
116+ if err != nil {
117+ return err
118+ }
119+ u := url.URL{
120+ Scheme: "http",
121+ Host: addr,
122+ Path: path,
123+ }
124+ req, err := http.NewRequest("PUT", u.String(), nil)
125+ if err != nil {
126+ return err
127+ }
128+ req.Header.Add("Authorization", authString)
129+ req.Body = &ClosingBuffer{bytes.NewBuffer(data)}
130+ resp, err := http.DefaultClient.Do(req)
131+ if err != nil {
132+ return err
133+ }
134+ if resp.StatusCode != 200 {
135+ return fmt.Errorf(resp.Status)
136+ }
137+ _, err = io.Copy(os.Stdout, resp.Body)
138+ return err
139+}
140+
141+func Get(addr, path string) ([]byte, error) {
142+ authString, err := loadAuth()
143+ if err != nil {
144+ return nil, err
145+ }
146+ u := url.URL{
147+ Scheme: "http",
148+ Host: addr,
149+ Path: path,
150+ }
151+ req, err := http.NewRequest("GET", u.String(), nil)
152+ if err != nil {
153+ return nil, err
154+ }
155+ req.Header.Add("Authorization", authString)
156+ resp, err := http.DefaultClient.Do(req)
157+ if err != nil {
158+ return nil, err
159+ }
160+ if resp.StatusCode != 200 {
161+ return nil, fmt.Errorf(resp.Status)
162+ }
163+ return ioutil.ReadAll(resp.Body)
164+}
165+
166+func Access(addr, path string) ([]byte, error) {
167+ authString, err := loadAuth()
168+ if err != nil {
169+ return nil, err
170+ }
171+ query := url.Values{}
172+ query.Add("meta", "1")
173+
174+ u := url.URL{
175+ Scheme: "http",
176+ Host: addr,
177+ Path: path,
178+ RawQuery: query.Encode(),
179+ }
180+ req, err := http.NewRequest("GET", u.String(), nil)
181+ if err != nil {
182+ return nil, err
183+ }
184+ req.Header.Add("Authorization", authString)
185+ resp, err := http.DefaultClient.Do(req)
186+ if err != nil {
187+ return nil, err
188+ }
189+ if resp.StatusCode != 200 {
190+ return nil, fmt.Errorf(resp.Status)
191+ }
192+ return ioutil.ReadAll(resp.Body)
193+}
194+
195+func Share(addr, path, with string) error {
196+ authString, err := loadAuth()
197+ if err != nil {
198+ return err
199+ }
200+ u := url.URL{
201+ Scheme: "http",
202+ Host: addr,
203+ Path: path,
204+ }
205+ req, err := http.NewRequest("PUT", u.String(), strings.NewReader(url.Values{
206+ "meta": []string{"1"},
207+ "reader": []string{with}}.Encode()))
208+ if err != nil {
209+ return err
210+ }
211+ req.Header.Add("Authorization", authString)
212+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
213+ resp, err := http.DefaultClient.Do(req)
214+ if err != nil {
215+ return err
216+ }
217+ if resp.StatusCode != 200 {
218+ return fmt.Errorf(resp.Status)
219+ }
220+ _, err = io.Copy(os.Stdout, resp.Body)
221+ return err
222+ panic("no impl")
223+}
224
225=== added file 'client/client_test.go'
226--- client/client_test.go 1970-01-01 00:00:00 +0000
227+++ client/client_test.go 2014-01-10 12:43:25 +0000
228@@ -0,0 +1,45 @@
229+package client
230+
231+import (
232+ "encoding/json"
233+ . "launchpad.net/gocheck"
234+ "testing"
235+)
236+
237+func Test(t *testing.T) { TestingT(t) }
238+
239+var addr = "localhost:8080"
240+
241+type ClientSuite struct{}
242+
243+var _ = Suite(&ClientSuite{})
244+
245+func (s *ClientSuite) TestPutGet(c *C) {
246+ data := []byte("hello there")
247+ path := "/test-data"
248+ err := Put(addr, path, data)
249+ c.Assert(err, IsNil)
250+ result, err := Get(addr, path)
251+ c.Assert(err, IsNil)
252+ c.Assert(result, DeepEquals, data)
253+ err = Delete(addr, path)
254+ c.Assert(err, IsNil)
255+}
256+
257+func (s *ClientSuite) TestShareAndAccess(c *C) {
258+ output := []map[string]bool{}
259+ shareWith := "foo@foobar.com"
260+ data := []byte("hello there")
261+ path := "/test-share"
262+ err := Put(addr, path, data)
263+ c.Assert(err, IsNil)
264+ err = Share(addr, path, shareWith)
265+ c.Assert(err, IsNil)
266+ owners, err := Access(addr, path)
267+ err = json.Unmarshal(owners, &output)
268+ c.Assert(err, IsNil)
269+ c.Assert(output[1], DeepEquals, map[string]bool{shareWith: true})
270+
271+ err = Delete(addr, path)
272+ c.Assert(err, IsNil)
273+}
274
275=== modified file 'cmd/shfoo/main.go'
276--- cmd/shfoo/main.go 2014-01-10 12:43:25 +0000
277+++ cmd/shfoo/main.go 2014-01-10 12:43:25 +0000
278@@ -19,17 +19,11 @@
279 import (
280 "flag"
281 "fmt"
282- "io"
283 "io/ioutil"
284 "log"
285- "net/http"
286- "net/url"
287 "os"
288- "path"
289- "strings"
290
291- "code.google.com/p/gopass"
292- "launchpad.net/usso"
293+ "launchpad.net/sharinfoo/client"
294 )
295
296 var login *string = flag.String("login", "", "Login user account")
297@@ -45,207 +39,35 @@
298 log.Println(err)
299 }
300
301-// Perform a Ubuntu SSO login with the provided email
302-func SSOLogin(email string) (*usso.SSOData, error) {
303- pass, err := gopass.GetPass("Password: ")
304- if err != nil {
305- return nil, err
306- }
307-
308- ssoData, err := usso.ProductionUbuntuSSOServer.GetToken(email, pass, "sharinfoo")
309- if err != nil {
310- return nil, err
311- }
312-
313- return ssoData, nil
314-}
315-
316-func Login() error {
317- ssoData, err := SSOLogin(*login)
318- if err != nil {
319- return err
320- }
321- f, err := os.Create(path.Join(os.Getenv("HOME"), ".shfoo_auth"))
322- if err != nil {
323- return err
324- }
325- defer f.Close()
326- _, err = fmt.Fprintf(f, "ConsumerKey=%s, ConsumerSecret=%s, "+
327- "TokenKey=%s, TokenName=%s, TokenSecret=%s",
328- ssoData.ConsumerKey, ssoData.ConsumerSecret, ssoData.TokenKey,
329- ssoData.TokenName, ssoData.TokenSecret)
330- return err
331-}
332-
333-func loadAuth() (string, error) {
334- f, err := os.Open(path.Join(os.Getenv("HOME"), ".shfoo_auth"))
335- if err != nil {
336- return "", err
337- }
338- buf, err := ioutil.ReadAll(f)
339- if err != nil {
340- return "", err
341- }
342- return string(buf), nil
343-}
344-
345-func Delete() error {
346- authString, err := loadAuth()
347- if err != nil {
348- return err
349- }
350- u := url.URL{
351- Scheme: "http",
352- Host: *addr,
353- Path: *del,
354- }
355- req, err := http.NewRequest("DELETE", u.String(), nil)
356- if err != nil {
357- return err
358- }
359- req.Header.Add("Authorization", authString)
360- resp, err := http.DefaultClient.Do(req)
361- if err != nil {
362- return err
363- }
364- if resp.StatusCode != 200 {
365- return fmt.Errorf(resp.Status)
366- }
367- _, err = io.Copy(os.Stdout, resp.Body)
368- return err
369-}
370-
371-func Put() error {
372- authString, err := loadAuth()
373- if err != nil {
374- return err
375- }
376- u := url.URL{
377- Scheme: "http",
378- Host: *addr,
379- Path: *put,
380- }
381- req, err := http.NewRequest("PUT", u.String(), nil)
382- if err != nil {
383- return err
384- }
385- req.Header.Add("Authorization", authString)
386- req.Body = os.Stdin
387- resp, err := http.DefaultClient.Do(req)
388- if err != nil {
389- return err
390- }
391- if resp.StatusCode != 200 {
392- return fmt.Errorf(resp.Status)
393- }
394- _, err = io.Copy(os.Stdout, resp.Body)
395- return err
396-}
397-
398-func Get() error {
399- authString, err := loadAuth()
400- if err != nil {
401- return err
402- }
403- u := url.URL{
404- Scheme: "http",
405- Host: *addr,
406- Path: *get,
407- }
408- req, err := http.NewRequest("GET", u.String(), nil)
409- if err != nil {
410- return err
411- }
412- req.Header.Add("Authorization", authString)
413- resp, err := http.DefaultClient.Do(req)
414- if err != nil {
415- return err
416- }
417- if resp.StatusCode != 200 {
418- return fmt.Errorf(resp.Status)
419- }
420- _, err = io.Copy(os.Stdout, resp.Body)
421- return err
422-}
423-
424-func Access() error {
425- authString, err := loadAuth()
426- if err != nil {
427- return err
428- }
429- query := url.Values{}
430- query.Add("meta", "1")
431-
432- u := url.URL{
433- Scheme: "http",
434- Host: *addr,
435- Path: *access,
436- RawQuery: query.Encode(),
437- }
438- req, err := http.NewRequest("GET", u.String(), nil)
439- if err != nil {
440- return err
441- }
442- req.Header.Add("Authorization", authString)
443- resp, err := http.DefaultClient.Do(req)
444- if err != nil {
445- return err
446- }
447- if resp.StatusCode != 200 {
448- return fmt.Errorf(resp.Status)
449- }
450- _, err = io.Copy(os.Stdout, resp.Body)
451- fmt.Printf("\n")
452- return err
453- panic("no impl")
454-}
455-
456-func Share() error {
457- authString, err := loadAuth()
458- if err != nil {
459- return err
460- }
461- u := url.URL{
462- Scheme: "http",
463- Host: *addr,
464- Path: *share,
465- }
466- req, err := http.NewRequest("PUT", u.String(), strings.NewReader(url.Values{
467- "meta": []string{"1"},
468- "reader": []string{*with}}.Encode()))
469- if err != nil {
470- return err
471- }
472- req.Header.Add("Authorization", authString)
473- req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
474- resp, err := http.DefaultClient.Do(req)
475- if err != nil {
476- return err
477- }
478- if resp.StatusCode != 200 {
479- return fmt.Errorf(resp.Status)
480- }
481- _, err = io.Copy(os.Stdout, resp.Body)
482- return err
483- panic("no impl")
484-}
485-
486 func main() {
487 flag.Parse()
488 var err error
489 switch {
490 case *login != "":
491- err = Login()
492+ err = client.Login(*login)
493 case *del != "":
494- err = Delete()
495+ err = client.Delete(*addr, *del)
496 case *put != "":
497- err = Put()
498+ data, err := ioutil.ReadAll(os.Stdin)
499+ if err != nil {
500+ log.Fatal(err)
501+ }
502+ err = client.Put(*addr, *put, data)
503 case *get != "":
504- err = Get()
505+ output, err := client.Get(*addr, *get)
506+ if err != nil {
507+ die(err)
508+ }
509+ os.Stdout.Write(output)
510 case *share != "" && *with != "":
511- err = Share()
512+ err = client.Share(*addr, *share, *with)
513 case *access != "":
514- err = Access()
515+ output, err := client.Access(*addr, *access)
516+ if err != nil {
517+ die(err)
518+ }
519+ os.Stdout.Write(output)
520+ fmt.Println("")
521 default:
522 err = fmt.Errorf("No action specified")
523 }
524
525=== modified file 'server.go'
526--- server.go 2014-01-10 12:43:25 +0000
527+++ server.go 2014-01-10 12:43:25 +0000
528@@ -59,7 +59,7 @@
529 return
530 }
531 req.ParseForm()
532- if req.Form.Get("meta") == "1" || query["meta"][0] == "1" {
533+ if req.Form.Get("meta") == "1" || len(query) == 1 && query["meta"][0] == "1" {
534 fs.handleMetadata(w, req)
535 } else {
536 fs.handleContent(w, req)
537
538=== added directory 'tests'
539=== added file 'tests/client_test.py'
540--- tests/client_test.py 1970-01-01 00:00:00 +0000
541+++ tests/client_test.py 2014-01-10 12:43:25 +0000
542@@ -0,0 +1,71 @@
543+import subprocess
544+import os
545+import os.path
546+import sys
547+import json
548+import unittest
549+
550+sample_data = "sample.txt"
551+test_data = "test.txt"
552+temporary_files = [sample_data, test_data]
553+
554+
555+def put_command(src_file, dst_path):
556+ out = subprocess.Popen(["cat", src_file], stdout=subprocess.PIPE)
557+ return subprocess.check_call(["shfoo", "-put", "/%s" % dst_path],
558+ stdin=out.stdout)
559+
560+
561+def get_command(dst_file, src_path):
562+ get = subprocess.Popen(["shfoo", "-get", "/%s" % src_path],
563+ stdout=subprocess.PIPE)
564+ with open(dst_file, "w") as f:
565+ for line in get.stdout:
566+ f.write(line)
567+
568+
569+def share_command(path, share):
570+ subprocess.check_call(["shfoo", "-share", "/%s" % path, "-with", share])
571+
572+
573+def delete_command(path):
574+ subprocess.check_call(["shfoo", "-delete", "/%s" % path])
575+
576+
577+def access_command(path):
578+ out = subprocess.Popen(["shfoo", "-access", "/%s" % path],
579+ stdout=subprocess.PIPE)
580+ return json.loads(out.stdout.read())
581+
582+
583+def delete_temp_files():
584+ for f in temporary_files:
585+ if os.path.exists(f):
586+ os.remove(f)
587+
588+
589+class ClientTest(unittest.TestCase):
590+
591+ def setUp(self):
592+ print "puttting test file"
593+ with open(sample_data, "w") as srcFile:
594+ srcFile.write("Line one\nLine two\n")
595+ put_command(sample_data, test_data)
596+
597+ def tearDown(self):
598+ delete_temp_files()
599+ print "deleting test file"
600+ delete_command(test_data)
601+
602+ def test_put_and_get(self):
603+ get_command(test_data, test_data)
604+ print "comparing"
605+ self.assertEquals(open(test_data).read(), open(sample_data).read())
606+
607+ def test_share_and_acess(self):
608+ share_command(test_data, "test123@a.com")
609+ out = access_command(test_data)
610+ self.assertEquals(out[1]["test123@a.com"], True)
611+
612+if __name__ == '__main__':
613+ unittest.main()

Subscribers

People subscribed via source and target branches