1diff --git a/go.mod b/go.mod
2index 1d85ed2..dbd8c5a 100644
3--- a/go.mod
4+++ b/go.mod
5@@ -83,6 +83,7 @@ require (
6 filippo.io/edwards25519 v1.1.0 // indirect
7 git.sr.ht/~rockorager/vaxis v0.10.3 // indirect
8 github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect
9+ github.com/DavidGamba/go-getoptions v0.29.0 // indirect
10 github.com/Masterminds/goutils v1.1.1 // indirect
11 github.com/Masterminds/semver/v3 v3.2.0 // indirect
12 github.com/Masterminds/sprig/v3 v3.2.3 // indirect
13@@ -198,6 +199,7 @@ require (
14 github.com/google/cel-go v0.20.1 // indirect
15 github.com/google/flatbuffers v23.1.21+incompatible // indirect
16 github.com/google/pprof v0.0.0-20240711041743-f6c9dda6c6da // indirect
17+ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
18 github.com/gorilla/css v1.0.1 // indirect
19 github.com/hashicorp/errwrap v1.1.0 // indirect
20 github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
21diff --git a/go.sum b/go.sum
22index 29703c1..eadbfe8 100644
23--- a/go.sum
24+++ b/go.sum
25@@ -23,6 +23,8 @@ github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOv
26 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
27 github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
28 github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
29+github.com/DavidGamba/go-getoptions v0.29.0 h1:cU8MjOyfAyPZke4hrgEuiGBJHS9PFYPAHve2fhDhdDk=
30+github.com/DavidGamba/go-getoptions v0.29.0/go.mod h1:zE97E3PR9P3BI/HKyNYgdMlYxodcuiC6W68KIgeYT84=
31 github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
32 github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
33 github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
34@@ -441,6 +443,8 @@ github.com/google/pprof v0.0.0-20240711041743-f6c9dda6c6da/go.mod h1:K1liHPHnj73
35 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
36 github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM=
37 github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA=
38+github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
39+github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
40 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
41 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
42 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
43diff --git a/pgs/ssh_test.go b/pgs/ssh_test.go
44index 62bdeb4..5591e41 100644
45--- a/pgs/ssh_test.go
46+++ b/pgs/ssh_test.go
47@@ -132,6 +132,7 @@ func TestSshServerRsync(t *testing.T) {
48 if err != nil {
49 panic(err)
50 }
51+ defer os.RemoveAll(name)
52
53 // remove the temporary directory at the end of the program
54 // defer os.RemoveAll(name)
55@@ -184,10 +185,9 @@ func TestSshServerRsync(t *testing.T) {
56
57 // copy files
58 cmd := exec.Command("rsync", "-rv", "-e", eCmd, name+"/", "localhost:/test")
59- fmt.Println(cmd.Args)
60 result, err := cmd.CombinedOutput()
61 if err != nil {
62- fmt.Println(string(result), err)
63+ cfg.Logger.Error("cannot upload", "err", err, "result", string(result))
64 t.Error(err)
65 return
66 }
67@@ -205,6 +205,55 @@ func TestSshServerRsync(t *testing.T) {
68 return
69 }
70
71+ dlName, err := os.MkdirTemp("", "rsync-download")
72+ if err != nil {
73+ panic(err)
74+ }
75+ defer os.RemoveAll(dlName)
76+
77+ // download files
78+ downloadCmd := exec.Command("rsync", "-rv", "-e", eCmd, "localhost:/test/", dlName+"/")
79+ result, err = downloadCmd.CombinedOutput()
80+ if err != nil {
81+ cfg.Logger.Error("cannot download files", "err", err, "result", string(result))
82+ t.Error(err)
83+ return
84+ }
85+
86+ // check contents
87+ idx, err := os.ReadFile(filepath.Join(dlName, "index.html"))
88+ if err != nil {
89+ cfg.Logger.Error("cannot open file", "file", "index.html", "err", err)
90+ t.Error(err)
91+ return
92+ }
93+ if string(idx) != index {
94+ t.Error("downloaded index.html file does not match original")
95+ return
96+ }
97+
98+ abt, err := os.ReadFile(filepath.Join(dlName, "about.html"))
99+ if err != nil {
100+ cfg.Logger.Error("cannot open file", "file", "about.html", "err", err)
101+ t.Error(err)
102+ return
103+ }
104+ if string(abt) != about {
105+ t.Error("downloaded about.html file does not match original")
106+ return
107+ }
108+
109+ cnt, err := os.ReadFile(filepath.Join(dlName, "contact.html"))
110+ if err != nil {
111+ cfg.Logger.Error("cannot open file", "file", "contact.html", "err", err)
112+ t.Error(err)
113+ return
114+ }
115+ if string(cnt) != contact {
116+ t.Error("downloaded contact.html file does not match original")
117+ return
118+ }
119+
120 // remove about file
121 os.Remove(aboutFile)
122
123@@ -212,7 +261,7 @@ func TestSshServerRsync(t *testing.T) {
124 delCmd := exec.Command("rsync", "-rv", "--delete", "-e", eCmd, name+"/", "localhost:/test")
125 result, err = delCmd.CombinedOutput()
126 if err != nil {
127- fmt.Println(string(result), err)
128+ cfg.Logger.Error("cannot upload with delete", "err", err, "result", string(result))
129 t.Error(err)
130 return
131 }