GitRoot
Craft your forge, Build your project, Grow your community freely
1// SPDX-FileCopyrightText: 2025 Romain Maneschi <romain@gitroot.dev>
2//
3// SPDX-License-Identifier: MIT
4
5package test
6
7import (
8 "bytes"
9 "errors"
10 "io/fs"
11 "os"
12 "path/filepath"
13 "testing"
14
15 "gitroot.dev/libs/golang/plugin/model"
16)
17
18var ErrTryOther = errors.New("Not for me")
19
20type fakeServer struct {
21 t *testing.T
22 dirGit string
23 fsGit model.FsBase
24 grfsGit *model.GrFs
25 dirWeb string
26 fsWeb model.FsBase
27 grfsWeb *model.GrFs
28 dirCache string
29 fsCache model.FsBase
30 grfsCache *model.GrFs
31 override Override
32 NbCall nbCall
33}
34
35type Override struct {
36 PluginOption func(opts ...model.PluginOptionWith)
37 ForgeConf func() (model.ForgeConf, error)
38 Worktree func() *model.GrFs
39 Webcontent func() *model.GrFs
40 Cache func() *model.GrFs
41 CopyFile func(fromFs model.FsBase, fromPath string, toFs model.FsBase, toPath string) error
42 DeleteFile func(fromFs model.FsBase, filename string) error
43 MoveFile func(fromFs model.FsBase, fromPath string, toFs model.FsBase, toPath string) error
44 ReplaceContent func(fromFs model.FsBase, filepath string, oldContent string, content string) error
45 WriteContent func(fromFs model.FsBase, filepath string, content string) error
46 CommitAllIfNeeded func(message string)
47 DiffWithParent func(hash string, oldFilepath string, newFilepath string) (string, error)
48 Merge func(from string, to string)
49 Commits func(from string, to string) ([]model.Commit, error)
50 Exec func(exec model.Exec) (model.ExecStatus, error)
51 Report func(level model.ReportLevel, content []string) error
52 CanCallFunc func(plugin string, name string, args map[string]string) bool
53 ExportFunc func(name string, callback func(args map[string]string) (map[string]string, error))
54 CallFunc func(plugin string, name string, args map[string]string) (map[string]string, error)
55 HttpClient func(header map[string][]string) model.HttpClient
56 DoRequest func(request model.HttpRequest) (model.HttpResponse, error)
57}
58
59type nbCall struct {
60 PluginOption int
61 ForgeConf int
62 Worktree int
63 Webcontent int
64 Cache int
65 CopyFile int
66 DeleteFile int
67 MoveFile int
68 ReplaceContent int
69 WriteContent int
70 CommitAllIfNeeded int
71 DiffWithParent int
72 Log int
73 LogError int
74 Merge int
75 Commits int
76 Exec int
77 Report int
78 CanCallFunc int
79 ExportFunc int
80 CallFunc int
81 HttpClient int
82 DoRequest int
83}
84
85func NewFakeServer(t *testing.T) *fakeServer {
86 dirGit, _ := os.MkdirTemp("", "gitrootPluginTestGit*")
87 dirWeb, _ := os.MkdirTemp("", "gitrootPluginTestWeb*")
88 dirCache, _ := os.MkdirTemp("", "gitrootPluginTestCache*")
89 s := &fakeServer{
90 t: t,
91 dirGit: dirGit,
92 fsGit: model.FsBase(dirGit),
93 grfsGit: nil,
94 dirWeb: dirWeb,
95 fsWeb: model.FsBase(dirWeb),
96 grfsWeb: nil,
97 dirCache: dirCache,
98 fsCache: model.FsBase(dirCache),
99 grfsCache: nil,
100 override: Override{},
101 NbCall: nbCall{},
102 }
103 s.grfsGit = model.NewGrFs(s.fsGit, s)
104 s.grfsWeb = model.NewGrFs(s.fsWeb, s)
105 s.grfsCache = model.NewGrFs(s.fsCache, s)
106 return s
107}
108
109func NewFakeServerWithOverride(t *testing.T, o Override) *fakeServer {
110 return NewFakeServer(t).SetOverride(o)
111}
112
113func (s *fakeServer) SetOverride(o Override) *fakeServer {
114 s.override = o
115 return s
116}
117
118// To check that interface is always respected
119func (s *fakeServer) AsServer() model.Server {
120 return s
121}
122
123func (s *fakeServer) PluginOption(opts ...model.PluginOptionWith) {
124 s.NbCall.PluginOption++
125 if s.override.PluginOption != nil {
126 s.override.PluginOption(opts...)
127 }
128}
129
130func (s *fakeServer) ForgeConf() (model.ForgeConf, error) {
131 s.NbCall.ForgeConf++
132 if s.override.ForgeConf != nil {
133 return s.override.ForgeConf()
134 }
135 return model.ForgeConf{
136 Domain: "test",
137 ExternalSshAddr: "ssh://127.0.0.1:4545/",
138 ExternalHttpAddr: "http://127.0.0.1:4546/",
139 RootRepositoryName: "root",
140 }, nil
141}
142
143func (s *fakeServer) Worktree() *model.GrFs {
144 s.NbCall.Worktree++
145 if s.override.Worktree != nil {
146 return s.override.Worktree()
147 }
148 return s.grfsGit
149}
150
151func (s *fakeServer) Webcontent() *model.GrFs {
152 s.NbCall.Webcontent++
153 if s.override.Webcontent != nil {
154 return s.override.Webcontent()
155 }
156 return s.grfsWeb
157}
158
159func (s *fakeServer) Cache() *model.GrFs {
160 s.NbCall.Cache++
161 if s.override.Cache != nil {
162 return s.override.Cache()
163 }
164 return s.grfsCache
165}
166
167// CopyFile implements [model.ServerNeeded].
168func (s *fakeServer) CopyFile(fromFs model.FsBase, fromPath string, toFs model.FsBase, toPath string) error {
169 s.NbCall.CopyFile++
170 if s.override.CopyFile != nil {
171 if err := s.override.CopyFile(fromFs, fromPath, toFs, toPath); err == nil || !errors.Is(err, ErrTryOther) {
172 return err
173 }
174 }
175 realPath := ""
176 switch fromFs {
177 case s.fsGit:
178 realPath = filepath.Join(s.dirGit, fromPath)
179 case s.fsWeb:
180 realPath = filepath.Join(s.dirWeb, fromPath)
181 case s.fsCache:
182 realPath = filepath.Join(s.dirCache, fromPath)
183 default:
184 return errors.New("unknown fsbase")
185 }
186 content, err := os.ReadFile(realPath)
187 if err != nil {
188 return err
189 }
190 return s.WriteContent(toFs, toPath, string(content))
191}
192
193// DeleteFile implements [model.ServerNeeded].
194func (s *fakeServer) DeleteFile(fromFs model.FsBase, filename string) error {
195 s.NbCall.DeleteFile++
196 if s.override.DeleteFile != nil {
197 if err := s.override.DeleteFile(fromFs, filename); err == nil || !errors.Is(err, ErrTryOther) {
198 return err
199 }
200 }
201 realPath := ""
202 switch fromFs {
203 case s.fsGit:
204 realPath = filepath.Join(s.dirGit, filename)
205 case s.fsWeb:
206 realPath = filepath.Join(s.dirWeb, filename)
207 case s.fsCache:
208 realPath = filepath.Join(s.dirCache, filename)
209 default:
210 return errors.New("unknown fsbase")
211 }
212 return os.Remove(realPath)
213}
214
215// MoveFile implements [model.ServerNeeded].
216func (s *fakeServer) MoveFile(fromFs model.FsBase, fromPath string, toFs model.FsBase, toPath string) error {
217 s.NbCall.MoveFile++
218 if s.override.MoveFile != nil {
219 if err := s.override.MoveFile(fromFs, fromPath, toFs, toPath); err == nil || !errors.Is(err, ErrTryOther) {
220 return err
221 }
222 }
223 if err := s.CopyFile(fromFs, fromPath, toFs, toPath); err != nil {
224 return err
225 }
226 return s.DeleteFile(fromFs, fromPath)
227}
228
229// ReplaceContent implements [model.ServerNeeded].
230func (s *fakeServer) ReplaceContent(fromFs model.FsBase, path string, oldContent string, content string) error {
231 s.NbCall.ReplaceContent++
232 if s.override.ReplaceContent != nil {
233 if err := s.override.ReplaceContent(fromFs, path, oldContent, content); err == nil || !errors.Is(err, ErrTryOther) {
234 return err
235 }
236 }
237 realPath := ""
238 switch fromFs {
239 case s.fsGit:
240 realPath = filepath.Join(s.dirGit, path)
241 case s.fsWeb:
242 realPath = filepath.Join(s.dirWeb, path)
243 case s.fsCache:
244 realPath = filepath.Join(s.dirCache, path)
245 default:
246 return errors.New("unknown fsbase")
247 }
248 realContent, err := os.ReadFile(realPath)
249 if err != nil {
250 return err
251 }
252 return os.WriteFile(realPath, bytes.Replace(realContent, []byte(oldContent), []byte(content), 1), 0666)
253
254}
255
256// WriteContent implements [model.ServerNeeded].
257func (s *fakeServer) WriteContent(fromFs model.FsBase, path string, content string) error {
258 s.NbCall.WriteContent++
259 if s.override.WriteContent != nil {
260 if err := s.override.WriteContent(fromFs, path, content); err == nil || !errors.Is(err, ErrTryOther) {
261 return err
262 }
263 }
264 switch fromFs {
265 case s.fsGit:
266 os.MkdirAll(s.dirGit+"/"+filepath.Dir(path), fs.ModePerm)
267 return os.WriteFile(s.dirGit+"/"+path, []byte(content), fs.ModePerm)
268 case s.fsWeb:
269 os.MkdirAll(s.dirWeb+"/"+filepath.Dir(path), fs.ModePerm)
270 return os.WriteFile(s.dirWeb+"/"+path, []byte(content), fs.ModePerm)
271 case s.fsCache:
272 os.MkdirAll(s.dirCache+"/"+filepath.Dir(path), fs.ModePerm)
273 return os.WriteFile(s.dirCache+"/"+path, []byte(content), fs.ModePerm)
274 }
275 return errors.New("unknown fsbase")
276}
277
278func (s *fakeServer) CommitAllIfNeeded(message string) {
279 s.NbCall.CommitAllIfNeeded++
280 if s.override.CommitAllIfNeeded != nil {
281 s.override.CommitAllIfNeeded(message)
282 }
283}
284
285func (s *fakeServer) DiffWithParent(hash string, oldFilepath string, newFilepath string) (string, error) {
286 s.NbCall.DiffWithParent++
287 if s.override.DiffWithParent != nil {
288 return s.override.DiffWithParent(hash, oldFilepath, newFilepath)
289 }
290 return "", nil
291}
292
293func (s *fakeServer) Log(message string) {
294 s.NbCall.Log++
295}
296
297func (s *fakeServer) LogError(message string, err error) {
298 s.NbCall.LogError++
299}
300
301func (s *fakeServer) Merge(from string, to string) {
302 s.NbCall.Merge++
303 if s.override.Merge != nil {
304 s.override.Merge(from, to)
305 }
306}
307
308func (s *fakeServer) Commits(from string, to string) ([]model.Commit, error) {
309 s.NbCall.Commits++
310 if s.override.Commits != nil {
311 return s.override.Commits(from, to)
312 }
313 return []model.Commit{}, nil
314}
315
316func (s *fakeServer) Exec(exec model.Exec) (model.ExecStatus, error) {
317 s.NbCall.Exec++
318 if s.override.Exec != nil {
319 return s.override.Exec(exec)
320 }
321 return model.ExecStatus{}, nil
322}
323
324func (s *fakeServer) Report(level model.ReportLevel, content []string) error {
325 s.NbCall.Report++
326 if s.override.Report != nil {
327 return s.override.Report(level, content)
328 }
329 return nil
330}
331
332func (s *fakeServer) ExportFunc(name string, callback func(args map[string]string) (map[string]string, error)) {
333 s.NbCall.ExportFunc++
334 if s.override.ExportFunc != nil {
335 s.override.ExportFunc(name, callback)
336 }
337}
338
339func (s *fakeServer) CanCallFunc(plugin string, name string, args map[string]string) bool {
340 s.NbCall.CanCallFunc++
341 if s.override.CanCallFunc != nil {
342 return s.override.CanCallFunc(plugin, name, args)
343 }
344 return false
345}
346
347func (s *fakeServer) CallFunc(plugin string, name string, args map[string]string) (map[string]string, error) {
348 s.NbCall.CallFunc++
349 if s.override.CallFunc != nil {
350 return s.override.CallFunc(plugin, name, args)
351 }
352 return map[string]string{}, nil
353}
354
355func (s *fakeServer) HttpClient(header map[string][]string) model.HttpClient {
356 s.NbCall.HttpClient++
357 if s.override.HttpClient != nil {
358 return s.override.HttpClient(header)
359 }
360 return model.NewHttpClient(s, header)
361}
362
363func (s *fakeServer) DoRequest(request model.HttpRequest) (model.HttpResponse, error) {
364 s.NbCall.DoRequest++
365 if s.override.DoRequest != nil {
366 return s.override.DoRequest(request)
367 }
368 return model.HttpResponse{
369 StatusCode: 200,
370 Body: "Hello from fakeServer",
371 }, nil
372}