Skip to content

Commit 79534fd

Browse files
tests: add tests for go/vt/hook (#15015)
Signed-off-by: Manik Rana <manikrana54@gmail.com> Signed-off-by: Manik Rana <Manikrana54@gmail.com> Co-authored-by: Florent Poinsard <35779988+frouioui@users.noreply.github.com>
1 parent 2d2c68e commit 79534fd

File tree

1 file changed

+255
-0
lines changed

1 file changed

+255
-0
lines changed

go/vt/hook/hook_test.go

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,29 @@
1+
/*
2+
Copyright 2024 The Vitess Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
117
package hook
218

319
import (
420
"context"
21+
"io"
522
"os"
623
"os/exec"
724
"path"
25+
"strings"
26+
"sync"
827
"testing"
928
"time"
1029

@@ -22,6 +41,11 @@ func TestExecuteContext(t *testing.T) {
2241
require.NoError(t, err)
2342

2443
sleepHookPath := path.Join(vtroot, "vthook", "sleep")
44+
45+
if _, err := os.Lstat(sleepHookPath); err == nil {
46+
require.NoError(t, os.Remove(sleepHookPath))
47+
}
48+
2549
require.NoError(t, os.Symlink(sleep, sleepHookPath))
2650
defer func() {
2751
require.NoError(t, os.Remove(sleepHookPath))
@@ -38,3 +62,234 @@ func TestExecuteContext(t *testing.T) {
3862
hr = h.Execute()
3963
assert.Equal(t, HOOK_SUCCESS, hr.ExitStatus)
4064
}
65+
66+
func TestExecuteOptional(t *testing.T) {
67+
vtroot, err := vtenv.VtRoot()
68+
require.NoError(t, err)
69+
70+
echo, err := exec.LookPath("echo")
71+
require.NoError(t, err)
72+
73+
echoHookPath := path.Join(vtroot, "vthook", "echo")
74+
75+
if _, err := os.Lstat(echoHookPath); err == nil {
76+
require.NoError(t, os.Remove(echoHookPath))
77+
}
78+
79+
require.NoError(t, os.Symlink(echo, echoHookPath))
80+
defer func() {
81+
require.NoError(t, os.Remove(echoHookPath))
82+
}()
83+
tt := []struct {
84+
name string
85+
hookName string
86+
parameters []string
87+
expectedError string
88+
}{
89+
{
90+
name: "HookSuccess",
91+
hookName: "echo",
92+
parameters: []string{"test"},
93+
},
94+
{
95+
name: "HookDoesNotExist",
96+
hookName: "nonexistent-hook",
97+
parameters: []string{"test"},
98+
},
99+
}
100+
101+
for _, tc := range tt {
102+
t.Run(tc.name, func(t *testing.T) {
103+
h := NewHook(tc.hookName, tc.parameters)
104+
err := h.ExecuteOptional()
105+
if tc.expectedError == "" {
106+
assert.NoError(t, err)
107+
} else {
108+
assert.Error(t, err)
109+
assert.ErrorContains(t, err, tc.expectedError)
110+
}
111+
})
112+
}
113+
}
114+
115+
func TestNewHook(t *testing.T) {
116+
h := NewHook("test-hook", []string{"arg1", "arg2"})
117+
assert.Equal(t, "test-hook", h.Name)
118+
assert.Equal(t, []string{"arg1", "arg2"}, h.Parameters)
119+
}
120+
121+
func TestNewSimpleHook(t *testing.T) {
122+
h := NewSimpleHook("simple-hook")
123+
assert.Equal(t, "simple-hook", h.Name)
124+
assert.Empty(t, h.Parameters)
125+
}
126+
127+
func TestNewHookWithEnv(t *testing.T) {
128+
h := NewHookWithEnv("env-hook", []string{"arg1", "arg2"}, map[string]string{"KEY": "VALUE"})
129+
assert.Equal(t, "env-hook", h.Name)
130+
assert.Equal(t, []string{"arg1", "arg2"}, h.Parameters)
131+
assert.Equal(t, map[string]string{"KEY": "VALUE"}, h.ExtraEnv)
132+
}
133+
134+
func TestString(t *testing.T) {
135+
tt := []struct {
136+
name string
137+
input HookResult
138+
expected string
139+
}{
140+
{
141+
name: "HOOK_SUCCESS",
142+
input: HookResult{ExitStatus: HOOK_SUCCESS, Stdout: "output"},
143+
expected: "result: HOOK_SUCCESS\nstdout:\noutput",
144+
},
145+
{
146+
name: "HOOK_DOES_NOT_EXIST",
147+
input: HookResult{ExitStatus: HOOK_DOES_NOT_EXIST},
148+
expected: "result: HOOK_DOES_NOT_EXIST",
149+
},
150+
{
151+
name: "HOOK_STAT_FAILED",
152+
input: HookResult{ExitStatus: HOOK_STAT_FAILED},
153+
expected: "result: HOOK_STAT_FAILED",
154+
},
155+
{
156+
name: "HOOK_CANNOT_GET_EXIT_STATUS",
157+
input: HookResult{ExitStatus: HOOK_CANNOT_GET_EXIT_STATUS},
158+
expected: "result: HOOK_CANNOT_GET_EXIT_STATUS",
159+
},
160+
{
161+
name: "HOOK_INVALID_NAME",
162+
input: HookResult{ExitStatus: HOOK_INVALID_NAME},
163+
expected: "result: HOOK_INVALID_NAME",
164+
},
165+
{
166+
name: "HOOK_VTROOT_ERROR",
167+
input: HookResult{ExitStatus: HOOK_VTROOT_ERROR},
168+
expected: "result: HOOK_VTROOT_ERROR",
169+
},
170+
{
171+
name: "case default",
172+
input: HookResult{ExitStatus: 42},
173+
expected: "result: exit(42)",
174+
},
175+
{
176+
name: "WithStderr",
177+
input: HookResult{ExitStatus: HOOK_SUCCESS, Stderr: "error"},
178+
expected: "result: HOOK_SUCCESS\nstderr:\nerror",
179+
},
180+
{
181+
name: "WithStderr",
182+
input: HookResult{ExitStatus: HOOK_SUCCESS, Stderr: "error"},
183+
expected: "result: HOOK_SUCCESS\nstderr:\nerror",
184+
},
185+
{
186+
name: "WithStdoutAndStderr",
187+
input: HookResult{ExitStatus: HOOK_SUCCESS, Stdout: "output", Stderr: "error"},
188+
expected: "result: HOOK_SUCCESS\nstdout:\noutput\nstderr:\nerror",
189+
},
190+
}
191+
192+
for _, tc := range tt {
193+
t.Run(tc.name, func(t *testing.T) {
194+
result := tc.input.String()
195+
assert.Equal(t, tc.expected, result)
196+
})
197+
}
198+
}
199+
200+
func TestExecuteAsReadPipe(t *testing.T) {
201+
vtroot, err := vtenv.VtRoot()
202+
require.NoError(t, err)
203+
204+
cat, err := exec.LookPath("cat")
205+
require.NoError(t, err)
206+
207+
catHookPath := path.Join(vtroot, "vthook", "cat")
208+
209+
if _, err := os.Lstat(catHookPath); err == nil {
210+
require.NoError(t, os.Remove(catHookPath))
211+
}
212+
213+
require.NoError(t, os.Symlink(cat, catHookPath))
214+
defer func() {
215+
require.NoError(t, os.Remove(catHookPath))
216+
}()
217+
218+
h := NewHook("cat", nil)
219+
reader, waitFunc, status, err := h.ExecuteAsReadPipe(strings.NewReader("Hello, World!\n"))
220+
require.NoError(t, err)
221+
defer reader.(io.Closer).Close()
222+
223+
output, err := io.ReadAll(reader)
224+
require.NoError(t, err)
225+
assert.Equal(t, "Hello, World!\n", string(output))
226+
227+
stderr, waitErr := waitFunc()
228+
assert.Empty(t, stderr)
229+
assert.NoError(t, waitErr)
230+
assert.Equal(t, HOOK_SUCCESS, status)
231+
}
232+
233+
func TestExecuteAsReadPipeErrorFindingHook(t *testing.T) {
234+
h := NewHook("nonexistent-hook", nil)
235+
reader, waitFunc, status, err := h.ExecuteAsReadPipe(strings.NewReader("Hello, World!\n"))
236+
require.Error(t, err)
237+
assert.Nil(t, reader)
238+
assert.Nil(t, waitFunc)
239+
assert.Equal(t, HOOK_DOES_NOT_EXIST, status)
240+
}
241+
242+
func TestExecuteAsWritePipe(t *testing.T) {
243+
var writer strings.Builder
244+
var writerMutex sync.Mutex
245+
246+
vtroot, err := vtenv.VtRoot()
247+
require.NoError(t, err)
248+
249+
echo, err := exec.LookPath("echo")
250+
require.NoError(t, err)
251+
252+
echoHookPath := path.Join(vtroot, "vthook", "echo")
253+
254+
if _, err := os.Lstat(echoHookPath); err == nil {
255+
require.NoError(t, os.Remove(echoHookPath))
256+
}
257+
258+
require.NoError(t, os.Symlink(echo, echoHookPath))
259+
defer func() {
260+
require.NoError(t, os.Remove(echoHookPath))
261+
}()
262+
263+
h := NewHook("echo", nil)
264+
265+
writerMutex.Lock()
266+
var writerTemp strings.Builder
267+
_, waitFunc, status, err := h.ExecuteAsWritePipe(&writerTemp)
268+
writerMutex.Unlock()
269+
270+
require.NoError(t, err)
271+
defer func() {
272+
writerMutex.Lock()
273+
writer.Reset()
274+
writerMutex.Unlock()
275+
}()
276+
277+
writerMutex.Lock()
278+
_, err = writer.Write([]byte("Hello, World!\n"))
279+
writerMutex.Unlock()
280+
require.NoError(t, err)
281+
282+
stderr, waitErr := waitFunc()
283+
assert.Empty(t, stderr)
284+
assert.NoError(t, waitErr)
285+
assert.Equal(t, HOOK_SUCCESS, status)
286+
}
287+
288+
func TestExecuteAsWritePipeErrorFindingHook(t *testing.T) {
289+
h := NewHook("nonexistent-hook", nil)
290+
var writer strings.Builder
291+
writerPtr := &writer
292+
_, _, status, err := h.ExecuteAsWritePipe(writerPtr)
293+
assert.Error(t, err)
294+
assert.Equal(t, HOOK_DOES_NOT_EXIST, status)
295+
}

0 commit comments

Comments
 (0)