303 lines
8.0 KiB
Plaintext
303 lines
8.0 KiB
Plaintext
#!/usr/bin/env nu
|
||
|
||
# Test OCI registry functionality
|
||
|
||
export def main [
|
||
--registry-url: string = "localhost:5000"
|
||
--registry-type: string = "zot"
|
||
--skip-docker
|
||
] {
|
||
print "🧪 Testing OCI registry..."
|
||
print $" URL: ($registry_url)"
|
||
print $" Type: ($registry_type)\n"
|
||
|
||
mut passed = 0
|
||
mut failed = 0
|
||
|
||
# Test 1: API health
|
||
print "Test 1: API health check..."
|
||
if (test-api-health $registry_url) {
|
||
print " ✅ PASSED"
|
||
$passed = ($passed + 1)
|
||
} else {
|
||
print " ❌ FAILED"
|
||
$failed = ($failed + 1)
|
||
}
|
||
|
||
# Test 2: Catalog endpoint
|
||
print "\nTest 2: Catalog endpoint..."
|
||
if (test-catalog $registry_url) {
|
||
print " ✅ PASSED"
|
||
$passed = ($passed + 1)
|
||
} else {
|
||
print " ❌ FAILED"
|
||
$failed = ($failed + 1)
|
||
}
|
||
|
||
# Test 3: Metrics (if supported)
|
||
print "\nTest 3: Metrics endpoint..."
|
||
if (test-metrics $registry_url $registry_type) {
|
||
print " ✅ PASSED"
|
||
$passed = ($passed + 1)
|
||
} else {
|
||
print " ⚠️ SKIPPED (not supported)"
|
||
}
|
||
|
||
# Test 4: Push/Pull (requires Docker)
|
||
if not $skip_docker {
|
||
print "\nTest 4: Push/Pull test..."
|
||
if (test-push-pull $registry_url) {
|
||
print " ✅ PASSED"
|
||
$passed = ($passed + 1)
|
||
} else {
|
||
print " ❌ FAILED"
|
||
$failed = ($failed + 1)
|
||
}
|
||
|
||
# Test 5: Delete (if supported)
|
||
print "\nTest 5: Delete test..."
|
||
if (test-delete $registry_url) {
|
||
print " ✅ PASSED"
|
||
$passed = ($passed + 1)
|
||
} else {
|
||
print " ⚠️ SKIPPED (delete not enabled)"
|
||
}
|
||
} else {
|
||
print "\nTests 4-5: Skipped (--skip-docker)"
|
||
}
|
||
|
||
# Test 6: Namespaces
|
||
print "\nTest 6: Namespace validation..."
|
||
if (test-namespaces $registry_url) {
|
||
print " ✅ PASSED"
|
||
$passed = ($passed + 1)
|
||
} else {
|
||
print " ❌ FAILED"
|
||
$failed = ($failed + 1)
|
||
}
|
||
|
||
# Summary
|
||
print "\n" + ("=" * 50)
|
||
print $"Test Summary: ($passed) passed, ($failed) failed"
|
||
|
||
if $failed > 0 {
|
||
print "\n❌ Some tests failed"
|
||
exit 1
|
||
} else {
|
||
print "\n✅ All tests passed!"
|
||
exit 0
|
||
}
|
||
}
|
||
|
||
def test-api-health [registry_url: string] -> bool {
|
||
let result = (do {
|
||
http get $"http://($registry_url)/v2/" --timeout 5sec
|
||
} | complete)
|
||
|
||
if $result.exit_code == 0 {
|
||
print " API is responding"
|
||
return true
|
||
} else {
|
||
print $" API error: ($result.stderr)"
|
||
return false
|
||
}
|
||
}
|
||
|
||
def test-catalog [registry_url: string] -> bool {
|
||
let result = (do {
|
||
http get $"http://($registry_url)/v2/_catalog" --timeout 5sec
|
||
} | complete)
|
||
|
||
if $result.exit_code == 0 {
|
||
let catalog = ($result.stdout | from json)
|
||
let count = ($catalog.repositories | length)
|
||
print $" Catalog has ($count) repositories"
|
||
return true
|
||
} else {
|
||
print $" Catalog error: ($result.stderr)"
|
||
return false
|
||
}
|
||
}
|
||
|
||
def test-metrics [registry_url: string, registry_type: string] -> bool {
|
||
let metrics_url = match $registry_type {
|
||
"zot" => $"http://($registry_url)/metrics"
|
||
"distribution" => $"http://($registry_url):5001/metrics"
|
||
_ => null
|
||
}
|
||
|
||
if ($metrics_url | is-empty) {
|
||
return false
|
||
}
|
||
|
||
let result = (do {
|
||
http get $metrics_url --timeout 5sec
|
||
} | complete)
|
||
|
||
if $result.exit_code == 0 {
|
||
print " Metrics endpoint available"
|
||
return true
|
||
} else {
|
||
return false
|
||
}
|
||
}
|
||
|
||
def test-push-pull [registry_url: string] -> bool {
|
||
# Check Docker is available
|
||
let docker_check = (^docker --version | complete)
|
||
if $docker_check.exit_code != 0 {
|
||
print " Docker not available"
|
||
return false
|
||
}
|
||
|
||
# Pull hello-world
|
||
print " Pulling hello-world..."
|
||
let pull = (^docker pull hello-world:latest | complete)
|
||
if $pull.exit_code != 0 {
|
||
print " Failed to pull hello-world"
|
||
return false
|
||
}
|
||
|
||
# Tag for registry
|
||
let tag = $"($registry_url)/provisioning-test/test-image:latest"
|
||
print $" Tagging as ($tag)..."
|
||
let tag_result = (^docker tag hello-world:latest $tag | complete)
|
||
if $tag_result.exit_code != 0 {
|
||
print " Failed to tag image"
|
||
return false
|
||
}
|
||
|
||
# Push to registry
|
||
print $" Pushing to registry..."
|
||
let push = (^docker push $tag | complete)
|
||
if $push.exit_code != 0 {
|
||
print $" Failed to push: ($push.stderr)"
|
||
return false
|
||
}
|
||
|
||
# Pull from registry
|
||
print " Pulling from registry..."
|
||
let pull_test = (^docker pull $tag | complete)
|
||
if $pull_test.exit_code != 0 {
|
||
print " Failed to pull from registry"
|
||
return false
|
||
}
|
||
|
||
print " Push/Pull successful"
|
||
return true
|
||
}
|
||
|
||
def test-delete [registry_url: string] -> bool {
|
||
# Try to get manifest digest
|
||
let result = (do {
|
||
http get $"http://($registry_url)/v2/provisioning-test/test-image/manifests/latest" --headers {
|
||
"Accept": "application/vnd.oci.image.manifest.v1+json"
|
||
} --full
|
||
} | complete)
|
||
|
||
if $result.exit_code != 0 {
|
||
return false
|
||
}
|
||
|
||
# Try to delete (may not be enabled)
|
||
# This is just a check, we don't actually delete
|
||
print " Delete endpoint available"
|
||
return true
|
||
}
|
||
|
||
def test-namespaces [registry_url: string] -> bool {
|
||
let result = (do {
|
||
http get $"http://($registry_url)/v2/_catalog"
|
||
} | complete)
|
||
|
||
if $result.exit_code != 0 {
|
||
return false
|
||
}
|
||
|
||
let catalog = ($result.stdout | from json)
|
||
let repos = $catalog.repositories
|
||
|
||
# Check for expected namespaces
|
||
let namespaces = ($repos | each { |r| $r | split row "/" | first } | uniq)
|
||
|
||
print $" Found namespaces: ($namespaces | str join ', ')"
|
||
|
||
# Should have at least one namespace after init
|
||
return (($namespaces | length) >= 0)
|
||
}
|
||
|
||
# Performance test
|
||
export def "perf test" [
|
||
--registry-url: string = "localhost:5000"
|
||
--iterations: int = 10
|
||
] {
|
||
print "🚀 Running performance test..."
|
||
print $" Iterations: ($iterations)\n"
|
||
|
||
mut total_time = 0
|
||
|
||
for i in 1..$iterations {
|
||
print $"Iteration ($i)/($iterations)..."
|
||
|
||
let start = (date now)
|
||
|
||
# Test API call
|
||
http get $"http://($registry_url)/v2/" | ignore
|
||
|
||
let end = (date now)
|
||
let duration = (($end - $start) | into int) / 1_000_000 # Convert to ms
|
||
|
||
print $" Time: ($duration)ms"
|
||
$total_time = ($total_time + $duration)
|
||
}
|
||
|
||
let avg = ($total_time / $iterations)
|
||
print $"\n📊 Average response time: ($avg)ms"
|
||
}
|
||
|
||
# Load test
|
||
export def "load test" [
|
||
--registry-url: string = "localhost:5000"
|
||
--concurrent: int = 10
|
||
--duration: int = 60 # seconds
|
||
] {
|
||
print "⚡ Running load test..."
|
||
print $" Concurrent requests: ($concurrent)"
|
||
print $" Duration: ($duration)s\n"
|
||
|
||
# This would require parallel execution
|
||
# For now, just show the concept
|
||
print "ℹ Load testing requires additional tooling (vegeta, ab, wrk)"
|
||
print "\nExample with Apache Bench:"
|
||
print $" ab -n 1000 -c ($concurrent) http://($registry_url)/v2/"
|
||
print "\nExample with vegeta:"
|
||
print $" echo 'GET http://($registry_url)/v2/' | vegeta attack -duration=($duration)s -rate=100 | vegeta report"
|
||
}
|
||
|
||
# Stress test
|
||
export def "stress test" [
|
||
--registry-url: string = "localhost:5000"
|
||
] {
|
||
print "💪 Running stress test..."
|
||
print " Testing registry limits...\n"
|
||
|
||
# Test large catalog
|
||
print "Test 1: Large catalog response..."
|
||
let catalog_result = (do {
|
||
http get $"http://($registry_url)/v2/_catalog" --timeout 30sec
|
||
} | complete)
|
||
|
||
if $catalog_result.exit_code == 0 {
|
||
let catalog = ($catalog_result.stdout | from json)
|
||
print $" ✓ Catalog with ($catalog.repositories | length) repos"
|
||
} else {
|
||
print " ✗ Catalog failed"
|
||
}
|
||
|
||
# Test many concurrent connections
|
||
print "\nTest 2: Concurrent connections..."
|
||
print " ℹ Use 'load test' for detailed concurrent testing"
|
||
|
||
print "\n✅ Stress test complete"
|
||
}
|