194 lines
8.2 KiB
PHP
194 lines
8.2 KiB
PHP
<?php
|
|
|
|
test('parses simple volume mappings', function () {
|
|
// Simple named volume
|
|
$result = parseDockerVolumeString('gitea:/data');
|
|
expect($result['source']->value())->toBe('gitea');
|
|
expect($result['target']->value())->toBe('/data');
|
|
expect($result['mode'])->toBeNull();
|
|
|
|
// Simple bind mount
|
|
$result = parseDockerVolumeString('./data:/app/data');
|
|
expect($result['source']->value())->toBe('./data');
|
|
expect($result['target']->value())->toBe('/app/data');
|
|
expect($result['mode'])->toBeNull();
|
|
|
|
// Absolute path bind mount
|
|
$result = parseDockerVolumeString('/var/lib/data:/data');
|
|
expect($result['source']->value())->toBe('/var/lib/data');
|
|
expect($result['target']->value())->toBe('/data');
|
|
expect($result['mode'])->toBeNull();
|
|
});
|
|
|
|
test('parses volumes with read-only mode', function () {
|
|
// Named volume with ro mode
|
|
$result = parseDockerVolumeString('gitea-localtime:/etc/localtime:ro');
|
|
expect($result['source']->value())->toBe('gitea-localtime');
|
|
expect($result['target']->value())->toBe('/etc/localtime');
|
|
expect($result['mode']->value())->toBe('ro');
|
|
|
|
// Bind mount with ro mode
|
|
$result = parseDockerVolumeString('/etc/localtime:/etc/localtime:ro');
|
|
expect($result['source']->value())->toBe('/etc/localtime');
|
|
expect($result['target']->value())->toBe('/etc/localtime');
|
|
expect($result['mode']->value())->toBe('ro');
|
|
});
|
|
|
|
test('parses volumes with other modes', function () {
|
|
// Read-write mode
|
|
$result = parseDockerVolumeString('data:/var/data:rw');
|
|
expect($result['source']->value())->toBe('data');
|
|
expect($result['target']->value())->toBe('/var/data');
|
|
expect($result['mode']->value())->toBe('rw');
|
|
|
|
// Z mode (SELinux)
|
|
$result = parseDockerVolumeString('config:/etc/config:z');
|
|
expect($result['source']->value())->toBe('config');
|
|
expect($result['target']->value())->toBe('/etc/config');
|
|
expect($result['mode']->value())->toBe('z');
|
|
|
|
// Cached mode (macOS)
|
|
$result = parseDockerVolumeString('./src:/app/src:cached');
|
|
expect($result['source']->value())->toBe('./src');
|
|
expect($result['target']->value())->toBe('/app/src');
|
|
expect($result['mode']->value())->toBe('cached');
|
|
|
|
// Delegated mode (macOS)
|
|
$result = parseDockerVolumeString('./node_modules:/app/node_modules:delegated');
|
|
expect($result['source']->value())->toBe('./node_modules');
|
|
expect($result['target']->value())->toBe('/app/node_modules');
|
|
expect($result['mode']->value())->toBe('delegated');
|
|
});
|
|
|
|
test('parses volumes with environment variables', function () {
|
|
// Variable with default value
|
|
$result = parseDockerVolumeString('${VOLUME_DB_PATH:-db}:/data/db');
|
|
expect($result['source']->value())->toBe('db');
|
|
expect($result['target']->value())->toBe('/data/db');
|
|
expect($result['mode'])->toBeNull();
|
|
|
|
// Variable without default value
|
|
$result = parseDockerVolumeString('${VOLUME_PATH}:/data');
|
|
expect($result['source']->value())->toBe('${VOLUME_PATH}');
|
|
expect($result['target']->value())->toBe('/data');
|
|
expect($result['mode'])->toBeNull();
|
|
|
|
// Variable with empty default - keeps variable reference for env resolution
|
|
$result = parseDockerVolumeString('${VOLUME_PATH:-}:/data');
|
|
expect($result['source']->value())->toBe('${VOLUME_PATH}');
|
|
expect($result['target']->value())->toBe('/data');
|
|
expect($result['mode'])->toBeNull();
|
|
|
|
// Variable with mode
|
|
$result = parseDockerVolumeString('${DATA_PATH:-./data}:/app/data:ro');
|
|
expect($result['source']->value())->toBe('./data');
|
|
expect($result['target']->value())->toBe('/app/data');
|
|
expect($result['mode']->value())->toBe('ro');
|
|
});
|
|
|
|
test('parses Windows paths', function () {
|
|
// Windows absolute path
|
|
$result = parseDockerVolumeString('C:/Users/data:/data');
|
|
expect($result['source']->value())->toBe('C:/Users/data');
|
|
expect($result['target']->value())->toBe('/data');
|
|
expect($result['mode'])->toBeNull();
|
|
|
|
// Windows path with mode
|
|
$result = parseDockerVolumeString('D:/projects/app:/app:rw');
|
|
expect($result['source']->value())->toBe('D:/projects/app');
|
|
expect($result['target']->value())->toBe('/app');
|
|
expect($result['mode']->value())->toBe('rw');
|
|
|
|
// Windows path with spaces (should be quoted in real use)
|
|
$result = parseDockerVolumeString('C:/Program Files/data:/data');
|
|
expect($result['source']->value())->toBe('C:/Program Files/data');
|
|
expect($result['target']->value())->toBe('/data');
|
|
expect($result['mode'])->toBeNull();
|
|
});
|
|
|
|
test('parses edge cases', function () {
|
|
// Volume name only (unusual but valid)
|
|
$result = parseDockerVolumeString('myvolume');
|
|
expect($result['source']->value())->toBe('myvolume');
|
|
expect($result['target']->value())->toBe('myvolume');
|
|
expect($result['mode'])->toBeNull();
|
|
|
|
// Path with colon in target (not a mode)
|
|
$result = parseDockerVolumeString('source:/path:8080');
|
|
expect($result['source']->value())->toBe('source');
|
|
expect($result['target']->value())->toBe('/path:8080');
|
|
expect($result['mode'])->toBeNull();
|
|
|
|
// Multiple colons in path (not Windows)
|
|
$result = parseDockerVolumeString('data:/var/lib/docker:data:backup');
|
|
expect($result['source']->value())->toBe('data');
|
|
expect($result['target']->value())->toBe('/var/lib/docker:data:backup');
|
|
expect($result['mode'])->toBeNull();
|
|
});
|
|
|
|
test('parses tmpfs and other special cases', function () {
|
|
// Docker socket binding
|
|
$result = parseDockerVolumeString('/var/run/docker.sock:/var/run/docker.sock');
|
|
expect($result['source']->value())->toBe('/var/run/docker.sock');
|
|
expect($result['target']->value())->toBe('/var/run/docker.sock');
|
|
expect($result['mode'])->toBeNull();
|
|
|
|
// Docker socket with mode
|
|
$result = parseDockerVolumeString('/var/run/docker.sock:/var/run/docker.sock:ro');
|
|
expect($result['source']->value())->toBe('/var/run/docker.sock');
|
|
expect($result['target']->value())->toBe('/var/run/docker.sock');
|
|
expect($result['mode']->value())->toBe('ro');
|
|
|
|
// Tmp mount
|
|
$result = parseDockerVolumeString('/tmp:/tmp');
|
|
expect($result['source']->value())->toBe('/tmp');
|
|
expect($result['target']->value())->toBe('/tmp');
|
|
expect($result['mode'])->toBeNull();
|
|
});
|
|
|
|
test('handles whitespace correctly', function () {
|
|
// Leading/trailing whitespace
|
|
$result = parseDockerVolumeString(' data:/app/data ');
|
|
expect($result['source']->value())->toBe('data');
|
|
expect($result['target']->value())->toBe('/app/data');
|
|
expect($result['mode'])->toBeNull();
|
|
|
|
// Whitespace with mode
|
|
$result = parseDockerVolumeString(' ./config:/etc/config:ro ');
|
|
expect($result['source']->value())->toBe('./config');
|
|
expect($result['target']->value())->toBe('/etc/config');
|
|
expect($result['mode']->value())->toBe('ro');
|
|
});
|
|
|
|
test('parses all valid Docker volume modes', function () {
|
|
$validModes = ['ro', 'rw', 'z', 'Z', 'rslave', 'rprivate', 'rshared',
|
|
'slave', 'private', 'shared', 'cached', 'delegated', 'consistent'];
|
|
|
|
foreach ($validModes as $mode) {
|
|
$result = parseDockerVolumeString("volume:/data:$mode");
|
|
expect($result['source']->value())->toBe('volume');
|
|
expect($result['target']->value())->toBe('/data');
|
|
expect($result['mode']->value())->toBe($mode);
|
|
}
|
|
});
|
|
|
|
test('parses complex real-world examples', function () {
|
|
// MongoDB volume with environment variable
|
|
$result = parseDockerVolumeString('${VOLUME_DB_PATH:-./data/db}:/data/db');
|
|
expect($result['source']->value())->toBe('./data/db');
|
|
expect($result['target']->value())->toBe('/data/db');
|
|
expect($result['mode'])->toBeNull();
|
|
|
|
// Config file mount with read-only
|
|
$result = parseDockerVolumeString('/home/user/app/config.yml:/app/config.yml:ro');
|
|
expect($result['source']->value())->toBe('/home/user/app/config.yml');
|
|
expect($result['target']->value())->toBe('/app/config.yml');
|
|
expect($result['mode']->value())->toBe('ro');
|
|
|
|
// Named volume with hyphens and underscores
|
|
$result = parseDockerVolumeString('my-app_data_v2:/var/lib/app-data');
|
|
expect($result['source']->value())->toBe('my-app_data_v2');
|
|
expect($result['target']->value())->toBe('/var/lib/app-data');
|
|
expect($result['mode'])->toBeNull();
|
|
});
|