blob: eb5c9645094151ff5dfcdbb9a96324fddb9a353f [file] [log] [blame]
Philip Zeyliger254c49f2025-07-17 17:26:24 -07001package dockerimg
2
3import (
4 "os"
5 "os/exec"
6 "path/filepath"
7 "testing"
8)
9
10func TestSetupHooksDir(t *testing.T) {
11 // Create a temporary git repository
12 tmpDir, err := os.MkdirTemp("", "test-git-repo-*")
13 if err != nil {
14 t.Fatalf("failed to create temp dir: %v", err)
15 }
16 defer os.RemoveAll(tmpDir)
17
18 // Test setupHooksDir function
19 hooksDir, err := setupHooksDir(tmpDir)
20 if err != nil {
21 t.Fatalf("setupHooksDir failed: %v", err)
22 }
23 defer os.RemoveAll(hooksDir)
24
25 // Verify hooks directory was created
26 if _, err := os.Stat(hooksDir); os.IsNotExist(err) {
27 t.Errorf("hooks directory was not created: %s", hooksDir)
28 }
29
30 // Verify pre-receive hook was created
31 preReceiveHook := filepath.Join(hooksDir, "pre-receive")
32 if _, err := os.Stat(preReceiveHook); os.IsNotExist(err) {
33 t.Errorf("pre-receive hook was not created: %s", preReceiveHook)
34 }
35
36 // Verify pre-receive hook is executable
37 info, err := os.Stat(preReceiveHook)
38 if err != nil {
39 t.Errorf("failed to stat pre-receive hook: %v", err)
40 }
41 if info.Mode()&0o111 == 0 {
42 t.Errorf("pre-receive hook is not executable")
43 }
44
45 // Verify pre-receive hook contains expected content
46 content, err := os.ReadFile(preReceiveHook)
47 if err != nil {
48 t.Errorf("failed to read pre-receive hook: %v", err)
49 }
50
51 // Check for key elements in the script
52 contentStr := string(content)
53 if !containsAll(contentStr, []string{
Euan Kempaabca2e2025-07-21 05:44:44 +000054 "#!/usr/bin/env bash",
Philip Zeyliger254c49f2025-07-17 17:26:24 -070055 "refs/remotes/origin/",
56 "git push origin",
57 "Force pushes are not allowed",
58 "git merge-base --is-ancestor",
59 }) {
60 t.Errorf("pre-receive hook missing expected content")
61 }
62}
63
64// Helper function to check if a string contains all substrings
65func containsAll(str string, substrings []string) bool {
66 for _, substr := range substrings {
67 if !contains(str, substr) {
68 return false
69 }
70 }
71 return true
72}
73
74// Helper function to check if a string contains a substring
75func contains(str, substr string) bool {
76 return len(str) >= len(substr) && findIndex(str, substr) >= 0
77}
78
79// Helper function to find index of substring (simple implementation)
80func findIndex(str, substr string) int {
81 for i := 0; i <= len(str)-len(substr); i++ {
82 if str[i:i+len(substr)] == substr {
83 return i
84 }
85 }
86 return -1
87}
88
89func TestPreReceiveHookScript(t *testing.T) {
90 // Create a temporary git repository
91 tmpDir, err := os.MkdirTemp("", "test-git-repo-*")
92 if err != nil {
93 t.Fatalf("failed to create temp dir: %v", err)
94 }
95 defer os.RemoveAll(tmpDir)
96
97 // Set up hooks directory
98 hooksDir, err := setupHooksDir(tmpDir)
99 if err != nil {
100 t.Fatalf("setupHooksDir failed: %v", err)
101 }
102 defer os.RemoveAll(hooksDir)
103
104 // Read the pre-receive hook script
105 preReceiveHook := filepath.Join(hooksDir, "pre-receive")
106 script, err := os.ReadFile(preReceiveHook)
107 if err != nil {
108 t.Fatalf("failed to read pre-receive hook: %v", err)
109 }
110
111 // Verify the script contains the expected bash shebang
112 scriptContent := string(script)
Euan Kempaabca2e2025-07-21 05:44:44 +0000113 if !contains(scriptContent, "#!/usr/bin/env bash") {
Philip Zeyliger254c49f2025-07-17 17:26:24 -0700114 t.Errorf("pre-receive hook missing bash shebang")
115 }
116
117 // Verify the script contains logic to handle refs/remotes/origin/Y
118 if !contains(scriptContent, "refs/remotes/origin/(.+)") {
119 t.Errorf("pre-receive hook missing refs/remotes/origin pattern matching")
120 }
121
122 // Verify the script contains force-push protection
123 if !contains(scriptContent, "git merge-base --is-ancestor") {
124 t.Errorf("pre-receive hook missing force-push protection")
125 }
126
127 // Verify the script contains git push origin command
128 if !contains(scriptContent, "git push origin") {
129 t.Errorf("pre-receive hook missing git push origin command")
130 }
131
132 // Verify the script exits with proper error codes
133 if !contains(scriptContent, "exit 1") {
134 t.Errorf("pre-receive hook missing error exit code")
135 }
136
137 if !contains(scriptContent, "exit 0") {
138 t.Errorf("pre-receive hook missing success exit code")
139 }
140}
141
142func TestGitHTTPHooksConfiguration(t *testing.T) {
143 // Create a temporary git repository
144 tmpDir, err := os.MkdirTemp("", "test-git-repo-*")
145 if err != nil {
146 t.Fatalf("failed to create temp dir: %v", err)
147 }
148 defer os.RemoveAll(tmpDir)
149
150 // Initialize git repository
151 if err := runGitCommand(tmpDir, "init"); err != nil {
152 t.Fatalf("failed to init git repo: %v", err)
153 }
154
155 // Set up hooks directory
156 hooksDir, err := setupHooksDir(tmpDir)
157 if err != nil {
158 t.Fatalf("setupHooksDir failed: %v", err)
159 }
160 defer os.RemoveAll(hooksDir)
161
162 // Create gitHTTP instance
163 gitHTTP := &gitHTTP{
164 gitRepoRoot: tmpDir,
165 hooksDir: hooksDir,
166 pass: []byte("test-pass"),
167 browserC: make(chan bool, 1),
168 }
169
170 // Test that the gitHTTP struct has the hooks directory set
171 if gitHTTP.hooksDir == "" {
172 t.Errorf("gitHTTP hooksDir is empty")
173 }
174
175 if gitHTTP.hooksDir != hooksDir {
176 t.Errorf("gitHTTP hooksDir mismatch: expected %s, got %s", hooksDir, gitHTTP.hooksDir)
177 }
178
179 // Verify that the hooks directory exists and contains the pre-receive hook
180 preReceiveHook := filepath.Join(hooksDir, "pre-receive")
181 if _, err := os.Stat(preReceiveHook); os.IsNotExist(err) {
182 t.Errorf("pre-receive hook missing: %s", preReceiveHook)
183 }
184}
185
186// Helper function to run git commands
187func runGitCommand(dir string, args ...string) error {
188 cmd := exec.Command("git", args...)
189 cmd.Dir = dir
190 return cmd.Run()
191}
192
193func TestPreReceiveHookExecution(t *testing.T) {
194 // Create a temporary git repository
195 tmpDir, err := os.MkdirTemp("", "test-git-repo-*")
196 if err != nil {
197 t.Fatalf("failed to create temp dir: %v", err)
198 }
199 defer os.RemoveAll(tmpDir)
200
201 // Initialize git repository
202 if err := runGitCommand(tmpDir, "init"); err != nil {
203 t.Fatalf("failed to init git repo: %v", err)
204 }
205
206 // Set up hooks directory
207 hooksDir, err := setupHooksDir(tmpDir)
208 if err != nil {
209 t.Fatalf("setupHooksDir failed: %v", err)
210 }
211 defer os.RemoveAll(hooksDir)
212
213 // Test the hook script syntax by running bash -n on it
214 preReceiveHook := filepath.Join(hooksDir, "pre-receive")
215 cmd := exec.Command("bash", "-n", preReceiveHook)
216 if err := cmd.Run(); err != nil {
217 t.Errorf("pre-receive hook has syntax errors: %v", err)
218 }
219
220 // Test that the hook script is executable
221 info, err := os.Stat(preReceiveHook)
222 if err != nil {
223 t.Fatalf("failed to stat pre-receive hook: %v", err)
224 }
225
226 mode := info.Mode()
227 if mode&0o111 == 0 {
228 t.Errorf("pre-receive hook is not executable: mode = %v", mode)
229 }
230}