Skip to content

Commit 4e7c568

Browse files
committed
Adapt error handling, debug level and dav integration test setup
1 parent cc66878 commit 4e7c568

9 files changed

Lines changed: 176 additions & 180 deletions

File tree

.github/workflows/dav-integration.yml

Lines changed: 5 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,6 @@ jobs:
2121
name: DAV Integration Tests
2222
runs-on: ubuntu-latest
2323

24-
services:
25-
webdav:
26-
image: httpd:2.4
27-
ports:
28-
- 8443:443
29-
3024
steps:
3125
- name: Checkout code
3226
uses: actions/checkout@v6
@@ -39,93 +33,11 @@ jobs:
3933
- name: Install Ginkgo
4034
run: go install github.com/onsi/ginkgo/v2/ginkgo@latest
4135

42-
- name: Setup WebDAV Server Configuration
36+
- name: Build and start WebDAV server
4337
run: |
44-
# Create certificates
45-
mkdir -p /tmp/webdav-certs
46-
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
47-
-keyout /tmp/webdav-certs/server.key \
48-
-out /tmp/webdav-certs/server.crt \
49-
-subj "/C=US/ST=Test/L=Test/O=Test/CN=localhost" \
50-
-addext "subjectAltName=DNS:localhost,IP:127.0.0.1"
51-
52-
# Create WebDAV directory
53-
mkdir -p /tmp/webdav-data
54-
chmod 777 /tmp/webdav-data
55-
56-
# Create htpasswd file
57-
docker run --rm httpd:2.4 htpasswd -nb testuser testpass > /tmp/webdav.passwd
58-
59-
# Create Apache config with DAV
60-
cat > /tmp/httpd.conf << 'EOF'
61-
ServerRoot "/usr/local/apache2"
62-
Listen 443
63-
64-
LoadModule mpm_event_module modules/mod_mpm_event.so
65-
LoadModule authn_file_module modules/mod_authn_file.so
66-
LoadModule authn_core_module modules/mod_authn_core.so
67-
LoadModule authz_host_module modules/mod_authz_host.so
68-
LoadModule authz_user_module modules/mod_authz_user.so
69-
LoadModule authz_core_module modules/mod_authz_core.so
70-
LoadModule auth_basic_module modules/mod_auth_basic.so
71-
LoadModule dav_module modules/mod_dav.so
72-
LoadModule dav_fs_module modules/mod_dav_fs.so
73-
LoadModule setenvif_module modules/mod_setenvif.so
74-
LoadModule ssl_module modules/mod_ssl.so
75-
LoadModule unixd_module modules/mod_unixd.so
76-
LoadModule dir_module modules/mod_dir.so
77-
78-
User daemon
79-
Group daemon
80-
81-
DAVLockDB /usr/local/apache2/var/DavLock
82-
83-
<IfModule ssl_module>
84-
SSLRandomSeed startup builtin
85-
SSLRandomSeed connect builtin
86-
</IfModule>
87-
88-
<VirtualHost *:443>
89-
SSLEngine on
90-
SSLCertificateFile /usr/local/apache2/certs/server.crt
91-
SSLCertificateKeyFile /usr/local/apache2/certs/server.key
92-
93-
DocumentRoot "/usr/local/apache2/webdav"
94-
95-
<Directory "/usr/local/apache2/webdav">
96-
Dav On
97-
Options +Indexes
98-
AuthType Basic
99-
AuthName "WebDAV"
100-
AuthUserFile /usr/local/apache2/webdav.passwd
101-
Require valid-user
102-
103-
<LimitExcept GET OPTIONS>
104-
Require valid-user
105-
</LimitExcept>
106-
</Directory>
107-
</VirtualHost>
108-
EOF
109-
110-
# Get the service container ID
111-
CONTAINER_ID=$(docker ps --filter "ancestor=httpd:2.4" --format "{{.ID}}")
112-
echo "WebDAV container ID: $CONTAINER_ID"
113-
114-
# Create required directories in container first
115-
docker exec $CONTAINER_ID mkdir -p /usr/local/apache2/certs
116-
docker exec $CONTAINER_ID mkdir -p /usr/local/apache2/webdav
117-
docker exec $CONTAINER_ID mkdir -p /usr/local/apache2/var
118-
docker exec $CONTAINER_ID chmod 777 /usr/local/apache2/webdav
119-
docker exec $CONTAINER_ID chmod 777 /usr/local/apache2/var
120-
121-
# Copy files to container
122-
docker cp /tmp/httpd.conf $CONTAINER_ID:/usr/local/apache2/conf/httpd.conf
123-
docker cp /tmp/webdav.passwd $CONTAINER_ID:/usr/local/apache2/webdav.passwd
124-
docker cp /tmp/webdav-certs/server.crt $CONTAINER_ID:/usr/local/apache2/certs/server.crt
125-
docker cp /tmp/webdav-certs/server.key $CONTAINER_ID:/usr/local/apache2/certs/server.key
126-
127-
# Reload Apache
128-
docker exec $CONTAINER_ID apachectl graceful
38+
cd dav/integration/testdata
39+
docker build -t webdav-test .
40+
docker run -d --name webdav -p 8443:443 webdav-test
12941
13042
# Wait for Apache to be ready
13143
sleep 5
@@ -140,7 +52,7 @@ jobs:
14052
DAV_PASSWORD: "testpass"
14153
DAV_SECRET: "test-secret-key"
14254
run: |
143-
export DAV_CA_CERT="$(cat /tmp/webdav-certs/server.crt)"
55+
export DAV_CA_CERT="$(cat dav/integration/testdata/certs/server.crt)"
14456
cd dav
14557
ginkgo -v ./integration
14658

dav/README.md

Lines changed: 8 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -112,45 +112,16 @@ go test ./dav/client/...
112112

113113
### Integration Tests
114114

115-
The DAV implementation includes Go-based integration tests that run against a real WebDAV server.
115+
The DAV implementation includes Go-based integration tests that run against a real WebDAV server. These tests require a WebDAV server to be available and the following environment variables to be set:
116116

117-
**Prerequisites:**
118-
- Running WebDAV server (can be set up with Docker - see below)
119-
- Environment variables configured
117+
- `DAV_ENDPOINT` - WebDAV server URL
118+
- `DAV_USER` - Username for authentication
119+
- `DAV_PASSWORD` - Password for authentication
120+
- `DAV_CA_CERT` - CA certificate (optional, for HTTPS with custom CA)
121+
- `DAV_SECRET` - Secret for signed URLs (optional, for signed URL tests)
120122

121-
**Setup WebDAV server with Docker:**
122-
```bash
123-
cd dav
124-
./setup-webdav-test.sh # Sets up Apache WebDAV with HTTPS
125-
```
126-
127-
**Run integration tests:**
128-
```bash
129-
# Set environment variables (from the dav/ directory after running setup)
130-
export DAV_ENDPOINT="https://localhost:8443"
131-
export DAV_USER="testuser"
132-
export DAV_PASSWORD="testpass"
133-
export DAV_CA_CERT="$(cat webdav-test/certs/ca.pem)"
134-
export DAV_SECRET="test-secret-key" # Optional, for signed URL tests
135-
136-
# Run integration tests
137-
ginkgo -v ./integration
138-
139-
# Or using go test
140-
go test -v ./integration/...
141-
```
142-
143-
These tests cover all operations: PUT, GET, DELETE, DELETE-RECURSIVE, EXISTS, LIST, COPY, PROPERTIES, and ENSURE-STORAGE-EXISTS.
123+
If these environment variables are not set, the integration tests will be skipped.
144124

145125
### End-to-End Tests
146126

147-
The DAV implementation also includes shell-based end-to-end tests using the compiled storage-cli binary.
148-
149-
**Quick start:**
150-
```bash
151-
cd dav
152-
./setup-webdav-test.sh # Sets up Apache WebDAV with HTTPS
153-
./test-storage-cli.sh # Runs complete test suite
154-
```
155-
156-
**For detailed testing instructions, see [TESTING.md](TESTING.md).**
127+
The `dav/` directory includes shell-based end-to-end tests that test the compiled storage-cli binary against a WebDAV server. See [TESTING.md](TESTING.md) for local setup instructions.

dav/client/client.go

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import (
55
"io"
66
"log/slog"
77
"os"
8+
"strings"
89
"time"
910

10-
bosherr "github.com/cloudfoundry/bosh-utils/errors"
1111
"github.com/cloudfoundry/bosh-utils/httpclient"
1212
boshlog "github.com/cloudfoundry/bosh-utils/logger"
1313

@@ -26,7 +26,7 @@ func New(config davconf.Config) (*DavBlobstore, error) {
2626
var httpClientBase httpclient.Client
2727
var certPool, err = getCertPool(config)
2828
if err != nil {
29-
return nil, bosherr.WrapErrorf(err, "Failed to create certificate pool")
29+
return nil, fmt.Errorf("failed to create certificate pool: %w", err)
3030
}
3131

3232
httpClientBase = httpclient.CreateDefaultClient(certPool)
@@ -53,7 +53,7 @@ func New(config davconf.Config) (*DavBlobstore, error) {
5353

5454
// Put uploads a file to the WebDAV server
5555
func (d *DavBlobstore) Put(sourceFilePath string, dest string) error {
56-
slog.Debug("Uploading file to WebDAV", "source", sourceFilePath, "dest", dest)
56+
slog.Info("Uploading file to WebDAV", "source", sourceFilePath, "dest", dest)
5757

5858
source, err := os.Open(sourceFilePath)
5959
if err != nil {
@@ -71,13 +71,13 @@ func (d *DavBlobstore) Put(sourceFilePath string, dest string) error {
7171
return fmt.Errorf("upload failure: %w", err)
7272
}
7373

74-
slog.Debug("Successfully uploaded file", "dest", dest)
74+
slog.Info("Successfully uploaded file", "dest", dest)
7575
return nil
7676
}
7777

7878
// Get downloads a file from the WebDAV server
7979
func (d *DavBlobstore) Get(source string, dest string) error {
80-
slog.Debug("Downloading file from WebDAV", "source", source, "dest", dest)
80+
slog.Info("Downloading file from WebDAV", "source", source, "dest", dest)
8181

8282
destFile, err := os.Create(dest)
8383
if err != nil {
@@ -96,48 +96,48 @@ func (d *DavBlobstore) Get(source string, dest string) error {
9696
return fmt.Errorf("failed to write to destination file: %w", err)
9797
}
9898

99-
slog.Debug("Successfully downloaded file", "dest", dest)
99+
slog.Info("Successfully downloaded file", "dest", dest)
100100
return nil
101101
}
102102

103103
// Delete removes a file from the WebDAV server
104104
func (d *DavBlobstore) Delete(dest string) error {
105-
slog.Debug("Deleting file from WebDAV", "dest", dest)
105+
slog.Info("Deleting file from WebDAV", "dest", dest)
106106
return d.storageClient.Delete(dest)
107107
}
108108

109109
// DeleteRecursive deletes all files matching a prefix
110110
func (d *DavBlobstore) DeleteRecursive(prefix string) error {
111-
slog.Debug("Deleting files recursively from WebDAV", "prefix", prefix)
111+
slog.Info("Deleting files recursively from WebDAV", "prefix", prefix)
112112

113113
// List all blobs with the prefix
114114
blobs, err := d.storageClient.List(prefix)
115115
if err != nil {
116116
return fmt.Errorf("failed to list blobs with prefix '%s': %w", prefix, err)
117117
}
118118

119-
slog.Debug("Found blobs to delete", "count", len(blobs), "prefix", prefix)
119+
slog.Info("Found blobs to delete", "count", len(blobs), "prefix", prefix)
120120

121121
// Delete each blob
122122
for _, blob := range blobs {
123123
if err := d.storageClient.Delete(blob); err != nil {
124124
return fmt.Errorf("failed to delete blob '%s': %w", blob, err)
125125
}
126-
slog.Debug("Deleted blob", "blob", blob)
126+
slog.Info("Deleted blob", "blob", blob)
127127
}
128128

129-
slog.Debug("Successfully deleted all blobs", "prefix", prefix)
129+
slog.Info("Successfully deleted all blobs", "prefix", prefix)
130130
return nil
131131
}
132132

133133
// Exists checks if a file exists on the WebDAV server
134134
func (d *DavBlobstore) Exists(dest string) (bool, error) {
135-
slog.Debug("Checking if file exists on WebDAV", "dest", dest)
135+
slog.Info("Checking if file exists on WebDAV", "dest", dest)
136136

137137
err := d.storageClient.Exists(dest)
138138
if err != nil {
139139
// Check if it's a "not found" error
140-
if bosherr.WrapError(err, "").Error() == fmt.Sprintf("%s not found", dest) {
140+
if strings.Contains(err.Error(), "not found") {
141141
return false, nil
142142
}
143143
return false, err
@@ -148,7 +148,7 @@ func (d *DavBlobstore) Exists(dest string) (bool, error) {
148148

149149
// Sign generates a pre-signed URL for the blob
150150
func (d *DavBlobstore) Sign(dest string, action string, expiration time.Duration) (string, error) {
151-
slog.Debug("Signing URL for WebDAV", "dest", dest, "action", action, "expiration", expiration)
151+
slog.Info("Signing URL for WebDAV", "dest", dest, "action", action, "expiration", expiration)
152152

153153
signedURL, err := d.storageClient.Sign(dest, action, expiration)
154154
if err != nil {
@@ -160,38 +160,38 @@ func (d *DavBlobstore) Sign(dest string, action string, expiration time.Duration
160160

161161
// List returns a list of blob paths that match the given prefix
162162
func (d *DavBlobstore) List(prefix string) ([]string, error) {
163-
slog.Debug("Listing files on WebDAV", "prefix", prefix)
163+
slog.Info("Listing files on WebDAV", "prefix", prefix)
164164

165165
blobs, err := d.storageClient.List(prefix)
166166
if err != nil {
167167
return nil, fmt.Errorf("failed to list blobs: %w", err)
168168
}
169169

170-
slog.Debug("Found blobs", "count", len(blobs), "prefix", prefix)
170+
slog.Info("Found blobs", "count", len(blobs), "prefix", prefix)
171171
return blobs, nil
172172
}
173173

174174
// Copy copies a blob from source to destination
175175
func (d *DavBlobstore) Copy(srcBlob string, dstBlob string) error {
176-
slog.Debug("Copying blob on WebDAV", "source", srcBlob, "dest", dstBlob)
176+
slog.Info("Copying blob on WebDAV", "source", srcBlob, "dest", dstBlob)
177177

178178
err := d.storageClient.Copy(srcBlob, dstBlob)
179179
if err != nil {
180180
return fmt.Errorf("copy failure: %w", err)
181181
}
182182

183-
slog.Debug("Successfully copied blob", "source", srcBlob, "dest", dstBlob)
183+
slog.Info("Successfully copied blob", "source", srcBlob, "dest", dstBlob)
184184
return nil
185185
}
186186

187187
// Properties retrieves metadata for a blob
188188
func (d *DavBlobstore) Properties(dest string) error {
189-
slog.Debug("Getting properties for blob on WebDAV", "dest", dest)
189+
slog.Info("Getting properties for blob on WebDAV", "dest", dest)
190190
return d.storageClient.Properties(dest)
191191
}
192192

193193
// EnsureStorageExists ensures the WebDAV directory structure exists
194194
func (d *DavBlobstore) EnsureStorageExists() error {
195-
slog.Debug("Ensuring WebDAV storage exists")
195+
slog.Info("Ensuring WebDAV storage exists")
196196
return d.storageClient.EnsureStorageExists()
197197
}

0 commit comments

Comments
 (0)