Browse code

add test for filesync path filtering and testutil helper

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>

Tonis Tiigi authored on 2017/06/28 14:42:28
Showing 3 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,71 @@
0
+package filesync
1
+
2
+import (
3
+	"context"
4
+	"io/ioutil"
5
+	"path/filepath"
6
+	"testing"
7
+
8
+	"github.com/docker/docker/client/session"
9
+	"github.com/docker/docker/client/session/testutil"
10
+	"github.com/stretchr/testify/assert"
11
+	"github.com/stretchr/testify/require"
12
+	"golang.org/x/sync/errgroup"
13
+)
14
+
15
+func TestFileSyncIncludePatterns(t *testing.T) {
16
+	tmpDir, err := ioutil.TempDir("", "fsynctest")
17
+	require.NoError(t, err)
18
+
19
+	destDir, err := ioutil.TempDir("", "fsynctest")
20
+	require.NoError(t, err)
21
+
22
+	err = ioutil.WriteFile(filepath.Join(tmpDir, "foo"), []byte("content1"), 0600)
23
+	require.NoError(t, err)
24
+
25
+	err = ioutil.WriteFile(filepath.Join(tmpDir, "bar"), []byte("content2"), 0600)
26
+	require.NoError(t, err)
27
+
28
+	s, err := session.NewSession("foo", "bar")
29
+	require.NoError(t, err)
30
+
31
+	m, err := session.NewManager()
32
+	require.NoError(t, err)
33
+
34
+	fs := NewFSSyncProvider(tmpDir, nil)
35
+	s.Allow(fs)
36
+
37
+	dialer := session.Dialer(testutil.TestStream(testutil.Handler(m.HandleConn)))
38
+
39
+	g, ctx := errgroup.WithContext(context.Background())
40
+
41
+	g.Go(func() error {
42
+		return s.Run(ctx, dialer)
43
+	})
44
+
45
+	g.Go(func() (reterr error) {
46
+		c, err := m.Get(ctx, s.UUID())
47
+		if err != nil {
48
+			return err
49
+		}
50
+		if err := FSSync(ctx, c, FSSendRequestOpt{
51
+			DestDir:         destDir,
52
+			IncludePatterns: []string{"ba*"},
53
+		}); err != nil {
54
+			return err
55
+		}
56
+
57
+		_, err = ioutil.ReadFile(filepath.Join(destDir, "foo"))
58
+		assert.Error(t, err)
59
+
60
+		dt, err := ioutil.ReadFile(filepath.Join(destDir, "bar"))
61
+		if err != nil {
62
+			return err
63
+		}
64
+		assert.Equal(t, "content2", string(dt))
65
+		return s.Close()
66
+	})
67
+
68
+	err = g.Wait()
69
+	require.NoError(t, err)
70
+}
... ...
@@ -1,6 +1,7 @@
1 1
 package session
2 2
 
3 3
 import (
4
+	"net"
4 5
 	"net/http"
5 6
 	"strings"
6 7
 	"sync"
... ...
@@ -49,8 +50,6 @@ func (sm *Manager) HandleHTTPRequest(ctx context.Context, w http.ResponseWriter,
49 49
 	}
50 50
 
51 51
 	uuid := r.Header.Get(headerSessionUUID)
52
-	name := r.Header.Get(headerSessionName)
53
-	sharedKey := r.Header.Get(headerSessionSharedKey)
54 52
 
55 53
 	proto := r.Header.Get("Upgrade")
56 54
 
... ...
@@ -89,9 +88,25 @@ func (sm *Manager) HandleHTTPRequest(ctx context.Context, w http.ResponseWriter,
89 89
 	conn.Write([]byte{})
90 90
 	resp.Write(conn)
91 91
 
92
+	return sm.handleConn(ctx, conn, r.Header)
93
+}
94
+
95
+// HandleConn handles an incoming raw connection
96
+func (sm *Manager) HandleConn(ctx context.Context, conn net.Conn, opts map[string][]string) error {
97
+	sm.mu.Lock()
98
+	return sm.handleConn(ctx, conn, opts)
99
+}
100
+
101
+// caller needs to take lock, this function will release it
102
+func (sm *Manager) handleConn(ctx context.Context, conn net.Conn, opts map[string][]string) error {
92 103
 	ctx, cancel := context.WithCancel(ctx)
93 104
 	defer cancel()
94 105
 
106
+	h := http.Header(opts)
107
+	uuid := h.Get(headerSessionUUID)
108
+	name := h.Get(headerSessionName)
109
+	sharedKey := h.Get(headerSessionSharedKey)
110
+
95 111
 	ctx, cc, err := grpcClientConn(ctx, conn)
96 112
 	if err != nil {
97 113
 		sm.mu.Unlock()
... ...
@@ -111,7 +126,7 @@ func (sm *Manager) HandleHTTPRequest(ctx context.Context, w http.ResponseWriter,
111 111
 		supported: make(map[string]struct{}),
112 112
 	}
113 113
 
114
-	for _, m := range r.Header[headerSessionMethod] {
114
+	for _, m := range opts[headerSessionMethod] {
115 115
 		c.supported[strings.ToLower(m)] = struct{}{}
116 116
 	}
117 117
 	sm.sessions[uuid] = c
118 118
new file mode 100644
... ...
@@ -0,0 +1,70 @@
0
+package testutil
1
+
2
+import (
3
+	"io"
4
+	"net"
5
+	"time"
6
+
7
+	"github.com/Sirupsen/logrus"
8
+	"golang.org/x/net/context"
9
+)
10
+
11
+// Handler is function called to handle incoming connection
12
+type Handler func(ctx context.Context, conn net.Conn, meta map[string][]string) error
13
+
14
+// Dialer is a function for dialing an outgoing connection
15
+type Dialer func(ctx context.Context, proto string, meta map[string][]string) (net.Conn, error)
16
+
17
+// TestStream creates an in memory session dialer for a handler function
18
+func TestStream(handler Handler) Dialer {
19
+	s1, s2 := sockPair()
20
+	return func(ctx context.Context, proto string, meta map[string][]string) (net.Conn, error) {
21
+		go func() {
22
+			err := handler(context.TODO(), s1, meta)
23
+			if err != nil {
24
+				logrus.Error(err)
25
+			}
26
+			s1.Close()
27
+		}()
28
+		return s2, nil
29
+	}
30
+}
31
+
32
+func sockPair() (*sock, *sock) {
33
+	pr1, pw1 := io.Pipe()
34
+	pr2, pw2 := io.Pipe()
35
+	return &sock{pw1, pr2, pw1}, &sock{pw2, pr1, pw2}
36
+}
37
+
38
+type sock struct {
39
+	io.Writer
40
+	io.Reader
41
+	io.Closer
42
+}
43
+
44
+func (s *sock) LocalAddr() net.Addr {
45
+	return dummyAddr{}
46
+}
47
+func (s *sock) RemoteAddr() net.Addr {
48
+	return dummyAddr{}
49
+}
50
+func (s *sock) SetDeadline(t time.Time) error {
51
+	return nil
52
+}
53
+func (s *sock) SetReadDeadline(t time.Time) error {
54
+	return nil
55
+}
56
+func (s *sock) SetWriteDeadline(t time.Time) error {
57
+	return nil
58
+}
59
+
60
+type dummyAddr struct {
61
+}
62
+
63
+func (d dummyAddr) Network() string {
64
+	return "tcp"
65
+}
66
+
67
+func (d dummyAddr) String() string {
68
+	return "localhost"
69
+}