@@ -2,74 +2,168 @@ package envbuilder_test
2
2
3
3
import (
4
4
"context"
5
+ "fmt"
5
6
"io"
6
7
"net/http/httptest"
8
+ "net/url"
7
9
"os"
10
+ "regexp"
8
11
"testing"
9
- "time"
10
12
11
13
"github.com/coder/envbuilder"
12
- "github.com/coder/envbuilder/gittest"
14
+ "github.com/coder/envbuilder/testutil/gittest"
15
+ "github.com/go-git/go-billy/v5"
13
16
"github.com/go-git/go-billy/v5/memfs"
14
- "github.com/go-git/go-git/v5"
15
- "github.com/go-git/go-git/v5/plumbing/object"
17
+ githttp "github.com/go-git/go-git/v5/plumbing/transport/http"
16
18
"github.com/stretchr/testify/require"
17
19
)
18
20
19
21
func TestCloneRepo (t * testing.T ) {
20
22
t .Parallel ()
21
23
22
- t .Run ("Clones" , func (t * testing.T ) {
23
- t .Parallel ()
24
+ for _ , tc := range []struct {
25
+ name string
26
+ srvUsername string
27
+ srvPassword string
28
+ username string
29
+ password string
30
+ mungeURL func (* string )
31
+ expectError string
32
+ expectClone bool
33
+ }{
34
+ {
35
+ name : "no auth" ,
36
+ expectClone : true ,
37
+ },
38
+ {
39
+ name : "auth" ,
40
+ srvUsername : "user" ,
41
+ srvPassword : "password" ,
42
+ username : "user" ,
43
+ password : "password" ,
44
+ expectClone : true ,
45
+ },
46
+ {
47
+ name : "auth but no creds" ,
48
+ srvUsername : "user" ,
49
+ srvPassword : "password" ,
50
+ expectClone : false ,
51
+ expectError : "authentication required" ,
52
+ },
53
+ {
54
+ name : "invalid auth" ,
55
+ srvUsername : "user" ,
56
+ srvPassword : "password" ,
57
+ username : "notuser" ,
58
+ password : "notpassword" ,
59
+ expectClone : false ,
60
+ expectError : "authentication required" ,
61
+ },
62
+ {
63
+ name : "tokenish username" ,
64
+ srvUsername : "tokentokentoken" ,
65
+ srvPassword : "" ,
66
+ username : "tokentokentoken" ,
67
+ password : "" ,
68
+ expectClone : true ,
69
+ },
70
+ } {
71
+ tc := tc
72
+ t .Run (tc .name , func (t * testing.T ) {
73
+ t .Parallel ()
24
74
25
- serverFS := memfs .New ()
26
- repo := gittest .NewRepo (t , serverFS )
27
- tree , err := repo .Worktree ()
28
- require .NoError (t , err )
75
+ // We do not overwrite a repo if one is already present.
76
+ t .Run ("AlreadyCloned" , func (t * testing.T ) {
77
+ srvFS := memfs .New ()
78
+ _ = gittest .NewRepo (t , srvFS , gittest .Commit (t , "README.md" , "Hello, world!" , "Wow!" ))
79
+ authMW := gittest .BasicAuthMW (tc .srvUsername , tc .srvPassword )
80
+ srv := httptest .NewServer (authMW (gittest .NewServer (srvFS )))
81
+ clientFS := memfs .New ()
82
+ // A repo already exists!
83
+ _ = gittest .NewRepo (t , clientFS )
84
+ cloned , err := envbuilder .CloneRepo (context .Background (), envbuilder.CloneRepoOptions {
85
+ Path : "/" ,
86
+ RepoURL : srv .URL ,
87
+ Storage : clientFS ,
88
+ })
89
+ require .NoError (t , err )
90
+ require .False (t , cloned )
91
+ })
29
92
30
- gittest .WriteFile (t , serverFS , "README.md" , "Hello, world!" )
31
- _ , err = tree .Add ("README.md" )
32
- require .NoError (t , err )
33
- commit , err := tree .Commit ("Wow!" , & git.CommitOptions {
34
- Author : & object.Signature {
35
- Name : "Example" ,
36
-
37
- When : time .Now (),
38
- },
39
- })
40
- require .NoError (t , err )
41
- _ , err = repo .CommitObject (commit )
42
- require .NoError (t , err )
93
+ // Basic Auth
94
+ t .Run ("BasicAuth" , func (t * testing.T ) {
95
+ t .Parallel ()
96
+ srvFS := memfs .New ()
97
+ _ = gittest .NewRepo (t , srvFS , gittest .Commit (t , "README.md" , "Hello, world!" , "Wow!" ))
98
+ authMW := gittest .BasicAuthMW (tc .srvUsername , tc .srvPassword )
99
+ srv := httptest .NewServer (authMW (gittest .NewServer (srvFS )))
100
+ clientFS := memfs .New ()
43
101
44
- srv := httptest .NewServer (gittest .NewServer (serverFS ))
102
+ cloned , err := envbuilder .CloneRepo (context .Background (), envbuilder.CloneRepoOptions {
103
+ Path : "/workspace" ,
104
+ RepoURL : srv .URL ,
105
+ Storage : clientFS ,
106
+ RepoAuth : & githttp.BasicAuth {
107
+ Username : tc .username ,
108
+ Password : tc .password ,
109
+ },
110
+ })
111
+ require .Equal (t , tc .expectClone , cloned )
112
+ if tc .expectError != "" {
113
+ require .ErrorContains (t , err , tc .expectError )
114
+ return
115
+ }
116
+ require .NoError (t , err )
117
+ require .True (t , cloned )
45
118
46
- clientFS := memfs .New ()
47
- cloned , err := envbuilder .CloneRepo (context .Background (), envbuilder.CloneRepoOptions {
48
- Path : "/workspace" ,
49
- RepoURL : srv .URL ,
50
- Storage : clientFS ,
51
- })
52
- require .NoError (t , err )
53
- require .True (t , cloned )
119
+ readme := mustRead (t , clientFS , "/workspace/README.md" )
120
+ require .Equal (t , "Hello, world!" , readme )
121
+ gitConfig := mustRead (t , clientFS , "/workspace/.git/config" )
122
+ // Ensure we do not modify the git URL that folks pass in.
123
+ require .Regexp (t , fmt .Sprintf (`(?m)^\s+url\s+=\s+%s\s*$` , regexp .QuoteMeta (srv .URL )), gitConfig )
124
+ })
125
+
126
+ // In-URL-style auth e.g. http://user:password@host:port
127
+ t .Run ("InURL" , func (t * testing.T ) {
128
+ t .Parallel ()
129
+ srvFS := memfs .New ()
130
+ _ = gittest .NewRepo (t , srvFS , gittest .Commit (t , "README.md" , "Hello, world!" , "Wow!" ))
131
+ authMW := gittest .BasicAuthMW (tc .srvUsername , tc .srvPassword )
132
+ srv := httptest .NewServer (authMW (gittest .NewServer (srvFS )))
54
133
55
- file , err := clientFS .OpenFile ("/workspace/README.md" , os .O_RDONLY , 0644 )
56
- require .NoError (t , err )
57
- defer file .Close ()
58
- content , err := io .ReadAll (file )
59
- require .NoError (t , err )
60
- require .Equal (t , "Hello, world!" , string (content ))
61
- })
134
+ authURL , err := url .Parse (srv .URL )
135
+ require .NoError (t , err )
136
+ authURL .User = url .UserPassword (tc .username , tc .password )
137
+ clientFS := memfs .New ()
62
138
63
- t .Run ("DoesntCloneIfRepoExists" , func (t * testing.T ) {
64
- t .Parallel ()
65
- clientFS := memfs .New ()
66
- gittest .NewRepo (t , clientFS )
67
- cloned , err := envbuilder .CloneRepo (context .Background (), envbuilder.CloneRepoOptions {
68
- Path : "/" ,
69
- RepoURL : "https://example.com" ,
70
- Storage : clientFS ,
139
+ cloned , err := envbuilder .CloneRepo (context .Background (), envbuilder.CloneRepoOptions {
140
+ Path : "/workspace" ,
141
+ RepoURL : authURL .String (),
142
+ Storage : clientFS ,
143
+ })
144
+ require .Equal (t , tc .expectClone , cloned )
145
+ if tc .expectError != "" {
146
+ require .ErrorContains (t , err , tc .expectError )
147
+ return
148
+ }
149
+ require .NoError (t , err )
150
+ require .True (t , cloned )
151
+
152
+ readme := mustRead (t , clientFS , "/workspace/README.md" )
153
+ require .Equal (t , "Hello, world!" , readme )
154
+ gitConfig := mustRead (t , clientFS , "/workspace/.git/config" )
155
+ // Ensure we do not modify the git URL that folks pass in.
156
+ require .Regexp (t , fmt .Sprintf (`(?m)^\s+url\s+=\s+%s\s*$` , regexp .QuoteMeta (authURL .String ())), gitConfig )
157
+ })
71
158
})
72
- require .NoError (t , err )
73
- require .False (t , cloned )
74
- })
159
+ }
160
+ }
161
+
162
+ func mustRead (t * testing.T , fs billy.Filesystem , path string ) string {
163
+ t .Helper ()
164
+ f , err := fs .OpenFile (path , os .O_RDONLY , 0644 )
165
+ require .NoError (t , err )
166
+ content , err := io .ReadAll (f )
167
+ require .NoError (t , err )
168
+ return string (content )
75
169
}
0 commit comments