@@ -17,10 +17,20 @@ import (
17
17
"gitlab.com/gitlab-org/gitlab-shell/v14/internal/gitlabnet/twofactorverify"
18
18
)
19
19
20
+ type blockingReader struct {}
21
+
22
+ func (* blockingReader ) Read ([]byte ) (int , error ) {
23
+ waitInfinitely := make (chan struct {})
24
+ <- waitInfinitely
25
+
26
+ return 0 , nil
27
+ }
28
+
20
29
func setup (t * testing.T ) []testserver.TestRequestHandler {
30
+ waitInfinitely := make (chan struct {})
21
31
requests := []testserver.TestRequestHandler {
22
32
{
23
- Path : "/api/v4/internal/two_factor_otp_check " ,
33
+ Path : "/api/v4/internal/two_factor_manual_otp_check " ,
24
34
Handler : func (w http.ResponseWriter , r * http.Request ) {
25
35
b , err := io .ReadAll (r .Body )
26
36
defer r .Body .Close ()
@@ -31,11 +41,13 @@ func setup(t *testing.T) []testserver.TestRequestHandler {
31
41
require .NoError (t , json .Unmarshal (b , & requestBody ))
32
42
33
43
switch requestBody .KeyId {
34
- case "1 " :
44
+ case "verify_via_otp" , "verify_via_otp_with_push_error " :
35
45
body := map [string ]interface {}{
36
46
"success" : true ,
37
47
}
38
48
json .NewEncoder (w ).Encode (body )
49
+ case "wait_infinitely" :
50
+ <- waitInfinitely
39
51
case "error" :
40
52
body := map [string ]interface {}{
41
53
"success" : false ,
@@ -47,15 +59,36 @@ func setup(t *testing.T) []testserver.TestRequestHandler {
47
59
}
48
60
},
49
61
},
62
+ {
63
+ Path : "/api/v4/internal/two_factor_push_otp_check" ,
64
+ Handler : func (w http.ResponseWriter , r * http.Request ) {
65
+ b , err := io .ReadAll (r .Body )
66
+ defer r .Body .Close ()
67
+
68
+ require .NoError (t , err )
69
+
70
+ var requestBody * twofactorverify.RequestBody
71
+ require .NoError (t , json .Unmarshal (b , & requestBody ))
72
+
73
+ switch requestBody .KeyId {
74
+ case "verify_via_push" :
75
+ body := map [string ]interface {}{
76
+ "success" : true ,
77
+ }
78
+ json .NewEncoder (w ).Encode (body )
79
+ case "verify_via_otp_with_push_error" :
80
+ w .WriteHeader (http .StatusInternalServerError )
81
+ default :
82
+ <- waitInfinitely
83
+ }
84
+ },
85
+ },
50
86
}
51
87
52
88
return requests
53
89
}
54
90
55
- const (
56
- question = "OTP: \n "
57
- errorHeader = "OTP validation failed.\n "
58
- )
91
+ const errorHeader = "OTP validation failed: "
59
92
60
93
func TestExecute (t * testing.T ) {
61
94
requests := setup (t )
@@ -65,46 +98,61 @@ func TestExecute(t *testing.T) {
65
98
testCases := []struct {
66
99
desc string
67
100
arguments * commandargs.Shell
68
- answer string
101
+ input io. Reader
69
102
expectedOutput string
70
103
}{
71
104
{
72
- desc : "With a known key id" ,
73
- arguments : & commandargs.Shell {GitlabKeyId : "1" },
74
- answer : "123456\n " ,
75
- expectedOutput : question +
76
- "OTP validation successful. Git operations are now allowed.\n " ,
105
+ desc : "Verify via OTP" ,
106
+ arguments : & commandargs.Shell {GitlabKeyId : "verify_via_otp" },
107
+ expectedOutput : "OTP validation successful. Git operations are now allowed.\n " ,
108
+ },
109
+ {
110
+ desc : "Verify via OTP" ,
111
+ arguments : & commandargs.Shell {GitlabKeyId : "verify_via_otp_with_push_error" },
112
+ expectedOutput : "OTP validation successful. Git operations are now allowed.\n " ,
113
+ },
114
+ {
115
+ desc : "Verify via push authentication" ,
116
+ arguments : & commandargs.Shell {GitlabKeyId : "verify_via_push" },
117
+ input : & blockingReader {},
118
+ expectedOutput : "OTP has been validated by Push Authentication. Git operations are now allowed.\n " ,
119
+ },
120
+ {
121
+ desc : "With an empty OTP" ,
122
+ arguments : & commandargs.Shell {GitlabKeyId : "verify_via_otp" },
123
+ input : bytes .NewBufferString ("\n " ),
124
+ expectedOutput : errorHeader + "OTP cannot be blank.\n " ,
77
125
},
78
126
{
79
127
desc : "With bad response" ,
80
128
arguments : & commandargs.Shell {GitlabKeyId : "-1" },
81
- answer : "123456\n " ,
82
- expectedOutput : question + errorHeader + "Parsing failed\n " ,
129
+ expectedOutput : errorHeader + "Parsing failed\n " ,
83
130
},
84
131
{
85
132
desc : "With API returns an error" ,
86
133
arguments : & commandargs.Shell {GitlabKeyId : "error" },
87
- answer : "yes\n " ,
88
- expectedOutput : question + errorHeader + "error message\n " ,
134
+ expectedOutput : errorHeader + "error message\n " ,
89
135
},
90
136
{
91
137
desc : "With API fails" ,
92
138
arguments : & commandargs.Shell {GitlabKeyId : "broken" },
93
- answer : "yes\n " ,
94
- expectedOutput : question + errorHeader + "Internal API error (500)\n " ,
139
+ expectedOutput : errorHeader + "Internal API error (500)\n " ,
95
140
},
96
141
{
97
142
desc : "With missing arguments" ,
98
143
arguments : & commandargs.Shell {},
99
- answer : "yes\n " ,
100
- expectedOutput : question + errorHeader + "who='' is invalid\n " ,
144
+ expectedOutput : errorHeader + "who='' is invalid\n " ,
101
145
},
102
146
}
103
147
104
148
for _ , tc := range testCases {
105
149
t .Run (tc .desc , func (t * testing.T ) {
106
150
output := & bytes.Buffer {}
107
- input := bytes .NewBufferString (tc .answer )
151
+
152
+ input := tc .input
153
+ if input == nil {
154
+ input = bytes .NewBufferString ("123456\n " )
155
+ }
108
156
109
157
cmd := & Command {
110
158
Config : & config.Config {GitlabUrl : url },
@@ -115,7 +163,29 @@ func TestExecute(t *testing.T) {
115
163
err := cmd .Execute (context .Background ())
116
164
117
165
require .NoError (t , err )
118
- require .Equal (t , tc .expectedOutput , output .String ())
166
+ require .Equal (t , prompt + " \n " + tc .expectedOutput , output .String ())
119
167
})
120
168
}
121
169
}
170
+
171
+ func TestCanceledContext (t * testing.T ) {
172
+ requests := setup (t )
173
+
174
+ output := & bytes.Buffer {}
175
+
176
+ url := testserver .StartSocketHttpServer (t , requests )
177
+ cmd := & Command {
178
+ Config : & config.Config {GitlabUrl : url },
179
+ Args : & commandargs.Shell {GitlabKeyId : "wait_infinitely" },
180
+ ReadWriter : & readwriter.ReadWriter {Out : output , In : & bytes.Buffer {}},
181
+ }
182
+
183
+ ctx , cancel := context .WithCancel (context .Background ())
184
+
185
+ errCh := make (chan error )
186
+ go func () { errCh <- cmd .Execute (ctx ) }()
187
+ cancel ()
188
+
189
+ require .NoError (t , <- errCh )
190
+ require .Equal (t , prompt + "\n " + errorHeader + "context canceled\n " , output .String ())
191
+ }
0 commit comments