mirror of
https://github.com/moby/moby.git
synced 2026-01-11 18:51:37 +00:00
Merge pull request #51685 from vvoland/sync-29.x
[docker-29.x] Move to `29.1`
This commit is contained in:
15
.github/actions/setup-tracing/action.yml
vendored
15
.github/actions/setup-tracing/action.yml
vendored
@@ -6,9 +6,18 @@ runs:
|
||||
steps:
|
||||
- run: |
|
||||
set -e
|
||||
# Jaeger is set up on Windows through an inline run step. If you update Jaeger here, don't forget to update
|
||||
# the version set in .github/workflows/.windows.yml.
|
||||
docker run -d --net=host --name jaeger -e COLLECTOR_OTLP_ENABLED=true jaegertracing/all-in-one:1.46
|
||||
# The OTEL Collector is set up on Windows through an inline run step. If
|
||||
# you update the collector here, don't forget to update the version set
|
||||
# in .github/workflows/.windows.yml.
|
||||
mkdir -p /tmp/reports
|
||||
chmod 777 /tmp/reports
|
||||
docker run -d --net=host --name otelcol \
|
||||
-v "$(pwd)/otelcol-ci-config.yml:/etc/otelcol-contrib/config.yaml" \
|
||||
-v "/tmp/reports:/data" \
|
||||
otel/opentelemetry-collector-contrib:0.140.0 \
|
||||
--config file:/etc/otelcol-contrib/config.yaml \
|
||||
--config "yaml:exporters::file::path: /data/otel-trace.jsonl"
|
||||
docker0_ip="$(ip -f inet addr show docker0 | grep -Po 'inet \K[\d.]+')"
|
||||
echo "OTEL_EXPORTER_OTLP_ENDPOINT=http://${docker0_ip}:4318" >> "${GITHUB_ENV}"
|
||||
echo "OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf" >> "${GITHUB_ENV}"
|
||||
shell: bash
|
||||
|
||||
2
.github/workflows/.dco.yml
vendored
2
.github/workflows/.dco.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
|
||||
10
.github/workflows/.test-unit.yml
vendored
10
.github/workflows/.test-unit.yml
vendored
@@ -16,7 +16,7 @@ on:
|
||||
workflow_call:
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.25.4"
|
||||
GO_VERSION: "1.25.5"
|
||||
GOTESTLIST_VERSION: v0.3.1
|
||||
TESTSTAT_VERSION: v0.1.25
|
||||
SETUP_BUILDX_VERSION: edge
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
@@ -87,7 +87,7 @@ jobs:
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: test-reports-unit--${{ matrix.mode }}
|
||||
path: /tmp/reports/*
|
||||
@@ -103,13 +103,13 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: false
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
pattern: test-reports-unit-*
|
||||
path: /tmp/reports
|
||||
|
||||
39
.github/workflows/.test.yml
vendored
39
.github/workflows/.test.yml
vendored
@@ -21,7 +21,7 @@ on:
|
||||
default: "graphdriver"
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.25.4"
|
||||
GO_VERSION: "1.25.5"
|
||||
GOTESTLIST_VERSION: v0.3.1
|
||||
TESTSTAT_VERSION: v0.1.25
|
||||
ITG_CLI_MATRIX_SIZE: 6
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
@@ -68,13 +68,12 @@ jobs:
|
||||
name: Prepare reports
|
||||
if: always()
|
||||
run: |
|
||||
docker stop otelcol
|
||||
mkdir -p bundles /tmp/reports
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \( -name '*-report.json' -o -name '*.log' -o -name '*.out' -o -name '*.prof' -o -name '*-report.xml' \) -print | xargs sudo tar -czf /tmp/reports.tar.gz
|
||||
tar -xzf /tmp/reports.tar.gz -C /tmp/reports
|
||||
sudo chown -R $(id -u):$(id -g) /tmp/reports
|
||||
tree -nh /tmp/reports
|
||||
|
||||
curl -sSLf localhost:16686/api/traces?service=integration-test-client > /tmp/reports/jaeger-trace.json
|
||||
-
|
||||
name: Test daemon logs
|
||||
if: always()
|
||||
@@ -83,7 +82,7 @@ jobs:
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: test-reports-docker-py-${{ inputs.storage }}
|
||||
path: /tmp/reports/*
|
||||
@@ -96,7 +95,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
@@ -170,7 +169,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
@@ -228,13 +227,13 @@ jobs:
|
||||
reportsPath="/tmp/reports/$reportsName"
|
||||
echo "TESTREPORTS_NAME=$reportsName" >> $GITHUB_ENV
|
||||
|
||||
docker stop otelcol
|
||||
mkdir -p bundles $reportsPath
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \( -name '*-report.json' -o -name '*.log' -o -name '*.out' -o -name '*.prof' -o -name '*-report.xml' \) -print | xargs sudo tar -czf /tmp/reports.tar.gz
|
||||
tar -xzf /tmp/reports.tar.gz -C $reportsPath
|
||||
mv /tmp/reports/otel-trace*.jsonl $reportsPath/
|
||||
sudo chown -R $(id -u):$(id -g) $reportsPath
|
||||
tree -nh $reportsPath
|
||||
|
||||
curl -sSLf localhost:16686/api/traces?service=integration-test-client > $reportsPath/jaeger-trace.json
|
||||
-
|
||||
name: Send to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
@@ -251,7 +250,7 @@ jobs:
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: test-reports-integration-${{ inputs.storage }}-${{ env.TESTREPORTS_NAME }}
|
||||
path: /tmp/reports/*
|
||||
@@ -267,13 +266,13 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: false
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
path: /tmp/reports
|
||||
pattern: test-reports-integration-${{ inputs.storage }}-*
|
||||
@@ -296,10 +295,10 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: false
|
||||
@@ -394,7 +393,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
@@ -443,14 +442,14 @@ jobs:
|
||||
reportsPath=/tmp/reports/$reportsName
|
||||
echo "TESTREPORTS_NAME=$reportsName" >> $GITHUB_ENV
|
||||
|
||||
docker stop otelcol
|
||||
mkdir -p bundles $reportsPath
|
||||
echo "${{ matrix.test }}" | tr -s '|' '\n' | tee -a "$reportsPath/tests.txt"
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \( -name '*-report.json' -o -name '*.log' -o -name '*.out' -o -name '*.prof' -o -name '*-report.xml' \) -print | xargs sudo tar -czf /tmp/reports.tar.gz
|
||||
tar -xzf /tmp/reports.tar.gz -C $reportsPath
|
||||
mv /tmp/reports/otel-trace*.jsonl $reportsPath/
|
||||
sudo chown -R $(id -u):$(id -g) $reportsPath
|
||||
tree -nh $reportsPath
|
||||
|
||||
curl -sSLf localhost:16686/api/traces?service=integration-test-client > $reportsPath/jaeger-trace.json
|
||||
-
|
||||
name: Send to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
@@ -467,7 +466,7 @@ jobs:
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: test-reports-integration-cli-${{ inputs.storage }}-${{ matrix.mode }}-${{ env.TESTREPORTS_NAME }}
|
||||
path: /tmp/reports/*
|
||||
@@ -483,13 +482,13 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: false
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
path: /tmp/reports
|
||||
pattern: test-reports-integration-cli-${{ inputs.storage }}-${{ matrix.mode }}-*
|
||||
|
||||
10
.github/workflows/.vm.yml
vendored
10
.github/workflows/.vm.yml
vendored
@@ -20,7 +20,7 @@ on:
|
||||
type: string
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.25.4"
|
||||
GO_VERSION: "1.25.5"
|
||||
TESTSTAT_VERSION: v0.1.25
|
||||
|
||||
jobs:
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Set up Lima
|
||||
uses: lima-vm/lima-actions/setup@03b96d61959e83b2c737e44162c3088e81de0886 # v1.0.1
|
||||
@@ -167,7 +167,7 @@ jobs:
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: test-reports-integration-${{ env.TESTREPORTS_NAME }}
|
||||
path: /tmp/reports/*
|
||||
@@ -183,7 +183,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: false
|
||||
@@ -192,7 +192,7 @@ jobs:
|
||||
run: echo "TESTREPORTS_NAME=$(basename ${{ inputs.template }})*" >> $GITHUB_ENV
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
path: /tmp/reports
|
||||
pattern: test-reports-integration-${{ env.TESTREPORTS_NAME }}
|
||||
|
||||
63
.github/workflows/.windows.yml
vendored
63
.github/workflows/.windows.yml
vendored
@@ -28,7 +28,7 @@ on:
|
||||
default: false
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.25.4"
|
||||
GO_VERSION: "1.25.5"
|
||||
GOTESTLIST_VERSION: v0.3.1
|
||||
TESTSTAT_VERSION: v0.1.25
|
||||
WINDOWS_BASE_IMAGE: mcr.microsoft.com/windows/servercore
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
path: ${{ env.GOPATH }}/src/github.com/docker/docker
|
||||
-
|
||||
@@ -98,7 +98,7 @@ jobs:
|
||||
docker cp "${{ env.TEST_CTN_NAME }}`:c`:\containerd\bin\containerd-shim-runhcs-v1.exe" ${{ env.BIN_OUT }}\
|
||||
-
|
||||
name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: build-${{ inputs.storage }}-${{ inputs.os }}
|
||||
path: ${{ env.BIN_OUT }}/*
|
||||
@@ -117,7 +117,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
path: ${{ env.GOPATH }}/src/github.com/docker/docker
|
||||
-
|
||||
@@ -166,7 +166,7 @@ jobs:
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: ${{ inputs.os }}-${{ inputs.storage }}-unit-reports
|
||||
path: ${{ env.GOPATH }}\src\github.com\docker\docker\bundles\*
|
||||
@@ -181,13 +181,13 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: false
|
||||
-
|
||||
name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: ${{ inputs.os }}-${{ inputs.storage }}-unit-reports
|
||||
path: /tmp/artifacts
|
||||
@@ -208,10 +208,10 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: false
|
||||
@@ -264,24 +264,27 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
path: ${{ env.GOPATH }}/src/github.com/docker/docker
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: false
|
||||
-
|
||||
name: Set up Jaeger
|
||||
name: Set up OpenTelemetry Collector
|
||||
run: |
|
||||
# Jaeger is set up on Linux through the setup-tracing action. If you update Jaeger here, don't forget to
|
||||
# The collectors is set up on Linux through the setup-tracing action. If you update the collector here, don't forget to
|
||||
# update the version set in .github/actions/setup-tracing/action.yml.
|
||||
Invoke-WebRequest -Uri "https://github.com/jaegertracing/jaeger/releases/download/v1.46.0/jaeger-1.46.0-windows-amd64.tar.gz" -OutFile ".\jaeger-1.46.0-windows-amd64.tar.gz"
|
||||
tar -zxvf ".\jaeger-1.46.0-windows-amd64.tar.gz"
|
||||
Start-Process '.\jaeger-1.46.0-windows-amd64\jaeger-all-in-one.exe'
|
||||
echo "OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
New-Item -ItemType Directory -Force -Path bundles -ErrorAction Continue
|
||||
Start-Process "msiexec" -ArgumentList "/i",
|
||||
"https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v0.140.0/otelcol_0.140.0_windows_x64.msi",
|
||||
"/qn", "/l*v", "$(Join-Path (Get-Location) "bundles/otelcol-install.log")",
|
||||
"COLLECTOR_SVC_ARGS=`"--config=`"`"file:$(Join-Path (Get-Location) "otelcol-ci-config.yml")`"`" --config=`"`"yaml:exporters::file::path: $(Join-Path (Get-Location) "bundles/otel-trace.jsonl")`"`"`"" `
|
||||
-NoNewWindow -Wait
|
||||
@("OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318", "OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf") | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
shell: pwsh
|
||||
-
|
||||
name: Env
|
||||
@@ -289,14 +292,14 @@ jobs:
|
||||
Get-ChildItem Env: | Out-String
|
||||
-
|
||||
name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: build-${{ inputs.storage }}-${{ inputs.os }}
|
||||
path: ${{ env.BIN_OUT }}
|
||||
-
|
||||
name: Init
|
||||
run: |
|
||||
New-Item -ItemType "directory" -Path "bundles"
|
||||
New-Item -ItemType "directory" -Path "bundles" -ErrorAction SilentlyContinue
|
||||
If ("${{ inputs.os }}" -eq "windows-2025") {
|
||||
echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2025 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
} ElseIf ("${{ inputs.os }}" -eq "windows-2022") {
|
||||
@@ -342,14 +345,14 @@ jobs:
|
||||
"--exec-root=$env:TEMP\moby-exec", `
|
||||
"--pidfile=$env:TEMP\docker.pid", `
|
||||
"--register-service"
|
||||
# Make the env-var visible to the service-managed dockerd, as there's no CLI flag for this option.
|
||||
$dockerEnviron = @("DOCKER_MIN_API_VERSION=1.24")
|
||||
$dockerEnviron += @(Get-Item Env:\OTEL_* | ForEach-Object { "$($_.Name)=$($_.Value)" })
|
||||
If ("${{ inputs.storage }}" -eq "graphdriver") {
|
||||
# Make the env-var visible to the service-managed dockerd, as there's no CLI flag for this option.
|
||||
& reg add "HKLM\SYSTEM\CurrentControlSet\Services\docker" /v Environment /t REG_MULTI_SZ /s '@' /d "DOCKER_MIN_API_VERSION=1.24@TEST_INTEGRATION_USE_GRAPHDRIVER=1"
|
||||
$dockerEnviron += @("TEST_INTEGRATION_USE_GRAPHDRIVER=1")
|
||||
echo "TEST_INTEGRATION_USE_GRAPHDRIVER=1" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
} Else {
|
||||
# Make the env-var visible to the service-managed dockerd, as there's no CLI flag for this option.
|
||||
& reg add "HKLM\SYSTEM\CurrentControlSet\Services\docker" /v Environment /t REG_MULTI_SZ /s '@' /d DOCKER_MIN_API_VERSION=1.24
|
||||
}
|
||||
New-ItemProperty -Name "Environment" -Path "HKLM:\SYSTEM\CurrentControlSet\Services\docker" -PropertyType MultiString -Value $dockerEnviron
|
||||
Write-Host "Starting service"
|
||||
Start-Service -Name docker
|
||||
Write-Host "Service started successfully!"
|
||||
@@ -459,16 +462,14 @@ jobs:
|
||||
ForEach-Object {"$($_.TimeCreated.ToUniversalTime().ToString("o")) [$($_.LevelDisplayName)] $($_.Message)"} |
|
||||
Tee-Object -file ".\bundles\daemon.log"
|
||||
-
|
||||
name: Download Jaeger traces
|
||||
name: Stop OpenTelemetry Collector
|
||||
if: always()
|
||||
run: |
|
||||
Invoke-WebRequest `
|
||||
-Uri "http://127.0.0.1:16686/api/traces?service=integration-test-client" `
|
||||
-OutFile ".\bundles\jaeger-trace.json"
|
||||
(Stop-Service -DisplayName "OpenTelemetry Collector" -PassThru).WaitForStatus('Stopped', (New-TimeSpan -Seconds 30))
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: ${{ inputs.os }}-${{ inputs.storage }}-integration-reports-${{ matrix.runtime }}-${{ env.TESTREPORTS_NAME }}
|
||||
path: ${{ env.GOPATH }}\src\github.com\docker\docker\bundles\*
|
||||
@@ -495,13 +496,13 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: false
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
path: /tmp/reports
|
||||
pattern: ${{ inputs.os }}-${{ inputs.storage }}-integration-reports-${{ matrix.runtime }}-*
|
||||
|
||||
21
.github/workflows/arm64.yml
vendored
21
.github/workflows/arm64.yml
vendored
@@ -23,7 +23,7 @@ on:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.25.4"
|
||||
GO_VERSION: "1.25.5"
|
||||
TESTSTAT_VERSION: v0.1.25
|
||||
DESTDIR: ./build
|
||||
SETUP_BUILDX_VERSION: edge
|
||||
@@ -101,7 +101,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
@@ -146,7 +146,7 @@ jobs:
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: test-reports-unit-arm64-graphdriver
|
||||
path: /tmp/reports/*
|
||||
@@ -162,13 +162,13 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: false
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
pattern: test-reports-unit-arm64-*
|
||||
path: /tmp/reports
|
||||
@@ -191,7 +191,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
@@ -226,13 +226,14 @@ jobs:
|
||||
name: Prepare reports
|
||||
if: always()
|
||||
run: |
|
||||
docker stop otelcol
|
||||
reportsPath="/tmp/reports/arm64-graphdriver"
|
||||
mkdir -p bundles $reportsPath
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \( -name '*-report.json' -o -name '*.log' -o -name '*.out' -o -name '*.prof' -o -name '*-report.xml' \) -print | xargs sudo tar -czf /tmp/reports.tar.gz
|
||||
tar -xzf /tmp/reports.tar.gz -C $reportsPath
|
||||
mv /tmp/reports/otel-trace*.jsonl $reportsPath/
|
||||
sudo chown -R $(id -u):$(id -g) $reportsPath
|
||||
tree -nh $reportsPath
|
||||
curl -sSLf localhost:16686/api/traces?service=integration-test-client > $reportsPath/jaeger-trace.json
|
||||
-
|
||||
name: Send to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
@@ -249,7 +250,7 @@ jobs:
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: test-reports-integration-arm64-graphdriver
|
||||
path: /tmp/reports/*
|
||||
@@ -265,13 +266,13 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: false
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
path: /tmp/reports
|
||||
pattern: test-reports-integration-arm64-*
|
||||
|
||||
14
.github/workflows/bin-image.yml
vendored
14
.github/workflows/bin-image.yml
vendored
@@ -49,7 +49,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Docker meta
|
||||
id: meta
|
||||
@@ -83,7 +83,7 @@ jobs:
|
||||
mv "${bakeFile#cwd://}" "/tmp/bake-meta.json"
|
||||
-
|
||||
name: Upload meta bake definition
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: bake-meta
|
||||
path: /tmp/bake-meta.json
|
||||
@@ -109,7 +109,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
@@ -119,7 +119,7 @@ jobs:
|
||||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||
-
|
||||
name: Download meta bake definition
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: bake-meta
|
||||
path: /tmp
|
||||
@@ -164,7 +164,7 @@ jobs:
|
||||
-
|
||||
name: Upload digest
|
||||
if: github.event_name != 'pull_request' && github.repository == 'moby/moby'
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: digests-${{ env.PLATFORM_PAIR }}
|
||||
path: /tmp/digests/*
|
||||
@@ -180,13 +180,13 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Download meta bake definition
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: bake-meta
|
||||
path: /tmp
|
||||
-
|
||||
name: Download digests
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
path: /tmp/digests
|
||||
pattern: digests-*
|
||||
|
||||
28
.github/workflows/buildkit.yml
vendored
28
.github/workflows/buildkit.yml
vendored
@@ -23,7 +23,7 @@ on:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.25.4"
|
||||
GO_VERSION: "1.25.5"
|
||||
DESTDIR: ./build
|
||||
SETUP_BUILDX_VERSION: edge
|
||||
SETUP_BUILDKIT_IMAGE: moby/buildkit:latest
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
targets: binary
|
||||
-
|
||||
name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: binary
|
||||
path: ${{ env.DESTDIR }}
|
||||
@@ -100,12 +100,12 @@ jobs:
|
||||
uses: crazy-max/ghaction-github-runtime@v3
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
path: moby
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: false
|
||||
@@ -116,7 +116,7 @@ jobs:
|
||||
working-directory: moby
|
||||
-
|
||||
name: Checkout BuildKit ${{ env.BUILDKIT_REF }}
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: ${{ env.BUILDKIT_REPO }}
|
||||
ref: ${{ env.BUILDKIT_REF }}
|
||||
@@ -133,7 +133,7 @@ jobs:
|
||||
buildkitd-flags: --debug
|
||||
-
|
||||
name: Download binary artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: binary
|
||||
path: ./buildkit/build/moby/
|
||||
@@ -184,7 +184,7 @@ jobs:
|
||||
working-directory: ${{ env.GOPATH }}/src/github.com/docker/docker
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
path: ${{ env.GOPATH }}/src/github.com/docker/docker
|
||||
|
||||
@@ -199,7 +199,7 @@ jobs:
|
||||
echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2022 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: false
|
||||
@@ -225,7 +225,7 @@ jobs:
|
||||
go install github.com/distribution/distribution/v3/cmd/registry@latest
|
||||
|
||||
- name: Checkout BuildKit
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: moby/buildkit
|
||||
ref: master
|
||||
@@ -248,7 +248,7 @@ jobs:
|
||||
cp ${{ env.GOPATH }}\bin\buildctl.exe ${{ env.BIN_OUT }}
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: build-windows
|
||||
path: ${{ env.BIN_OUT }}/*
|
||||
@@ -307,12 +307,12 @@ jobs:
|
||||
uses: crazy-max/ghaction-github-runtime@v3
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
path: moby
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: false
|
||||
@@ -324,14 +324,14 @@ jobs:
|
||||
working-directory: moby
|
||||
|
||||
- name: Checkout BuildKit ${{ env.BUILDKIT_REF }}
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: ${{ env.BUILDKIT_REPO }}
|
||||
ref: ${{ env.BUILDKIT_REF }}
|
||||
path: buildkit
|
||||
|
||||
- name: Download Moby artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: build-windows
|
||||
path: ${{ env.BIN_OUT }}
|
||||
|
||||
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -75,7 +75,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Create matrix
|
||||
id: platforms
|
||||
|
||||
6
.github/workflows/codeql.yml
vendored
6
.github/workflows/codeql.yml
vendored
@@ -34,7 +34,7 @@ on:
|
||||
- cron: '0 9 * * 4'
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.25.4"
|
||||
GO_VERSION: "1.25.5"
|
||||
|
||||
jobs:
|
||||
codeql:
|
||||
@@ -47,11 +47,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 2
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: false
|
||||
|
||||
34
.github/workflows/test.yml
vendored
34
.github/workflows/test.yml
vendored
@@ -23,7 +23,7 @@ on:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.25.4"
|
||||
GO_VERSION: "1.25.5"
|
||||
GIT_PAGER: "cat"
|
||||
PAGER: "cat"
|
||||
SETUP_BUILDX_VERSION: edge
|
||||
@@ -67,7 +67,14 @@ jobs:
|
||||
set: |
|
||||
*.cache-from=type=gha,scope=dev${{ matrix.mode }}
|
||||
*.cache-to=type=gha,scope=dev${{ matrix.mode }}
|
||||
*.output=type=cacheonly
|
||||
${{ matrix.mode == '' && '*.output=type=docker,dest=/tmp/dev-image.tar' || '*.output=type=cacheonly' }}
|
||||
-
|
||||
name: Cache dev image
|
||||
if: matrix.mode == ''
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
key: dev-image-${{ github.run_id }}
|
||||
path: /tmp/dev-image.tar
|
||||
|
||||
test:
|
||||
if: ${{ github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci/validate-only') }}
|
||||
@@ -103,7 +110,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Create matrix
|
||||
id: scripts
|
||||
@@ -122,13 +129,12 @@ jobs:
|
||||
- validate-prepare
|
||||
- build-dev
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
script: ${{ fromJson(needs.validate-prepare.outputs.matrix) }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
@@ -139,15 +145,19 @@ jobs:
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: ${{ env.SETUP_BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }}
|
||||
driver: docker
|
||||
buildkitd-flags: --debug
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v6
|
||||
name: Restore dev image
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
dev.cache-from=type=gha,scope=dev
|
||||
key: dev-image-${{ github.run_id }}
|
||||
path: /tmp/dev-image.tar
|
||||
fail-on-cache-miss: true
|
||||
-
|
||||
name: Load dev image
|
||||
run: |
|
||||
docker load -i /tmp/dev-image.tar
|
||||
-
|
||||
name: Validate
|
||||
run: |
|
||||
@@ -164,7 +174,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
-
|
||||
name: Create matrix
|
||||
id: platforms
|
||||
|
||||
@@ -3,7 +3,7 @@ version: "2"
|
||||
run:
|
||||
# prevent golangci-lint from deducting the go version to lint for through go.mod,
|
||||
# which causes it to fallback to go1.17 semantics.
|
||||
go: "1.25.4"
|
||||
go: "1.25.5"
|
||||
concurrency: 2
|
||||
# Only supported with go modules enabled (build flag -mod=vendor only valid when using modules)
|
||||
# modules-download-mode: vendor
|
||||
|
||||
10
Dockerfile
10
Dockerfile
@@ -1,6 +1,6 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
ARG GO_VERSION=1.25.4
|
||||
ARG GO_VERSION=1.25.5
|
||||
ARG BASE_DEBIAN_DISTRO="bookworm"
|
||||
ARG GOLANG_IMAGE="golang:${GO_VERSION}-${BASE_DEBIAN_DISTRO}"
|
||||
|
||||
@@ -13,7 +13,7 @@ ARG XX_VERSION=1.7.0
|
||||
ARG VPNKIT_VERSION=0.6.0
|
||||
|
||||
# DOCKERCLI_VERSION is the version of the CLI to install in the dev-container.
|
||||
ARG DOCKERCLI_VERSION=v28.5.0
|
||||
ARG DOCKERCLI_VERSION=v29.0.1
|
||||
ARG DOCKERCLI_REPOSITORY="https://github.com/docker/cli.git"
|
||||
|
||||
# cli version used for integration-cli tests
|
||||
@@ -21,7 +21,7 @@ ARG DOCKERCLI_INTEGRATION_REPOSITORY="https://github.com/docker/cli.git"
|
||||
ARG DOCKERCLI_INTEGRATION_VERSION=v25.0.5
|
||||
|
||||
# BUILDX_VERSION is the version of buildx to install in the dev container.
|
||||
ARG BUILDX_VERSION=0.29.1
|
||||
ARG BUILDX_VERSION=0.30.1
|
||||
|
||||
# COMPOSE_VERSION is the version of compose to install in the dev container.
|
||||
ARG COMPOSE_VERSION=v2.40.0
|
||||
@@ -163,7 +163,7 @@ RUN git init . && git remote add origin "https://github.com/containerd/container
|
||||
# integration tests. The distributed docker .deb and .rpm packages depend on a
|
||||
# separate (containerd.io) package, which may be a different version as is
|
||||
# specified here.
|
||||
ARG CONTAINERD_VERSION=v2.1.5
|
||||
ARG CONTAINERD_VERSION=v2.2.0
|
||||
RUN git fetch -q --depth 1 origin "${CONTAINERD_VERSION}" +refs/tags/*:refs/tags/* && git checkout -q FETCH_HEAD
|
||||
|
||||
FROM base AS containerd-build
|
||||
@@ -254,7 +254,7 @@ RUN git init . && git remote add origin "https://github.com/opencontainers/runc.
|
||||
# This version should usually match the version that is used by the containerd version
|
||||
# that is used. If you need to update runc, open a pull request in the containerd
|
||||
# project first, and update both after that is merged.
|
||||
ARG RUNC_VERSION=v1.3.3
|
||||
ARG RUNC_VERSION=v1.3.4
|
||||
RUN git fetch -q --depth 1 origin "${RUNC_VERSION}" +refs/tags/*:refs/tags/* && git checkout -q FETCH_HEAD
|
||||
|
||||
FROM base AS runc-build
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
# This represents the bare minimum required to build and test Docker.
|
||||
|
||||
ARG GO_VERSION=1.25.4
|
||||
ARG GO_VERSION=1.25.5
|
||||
|
||||
ARG BASE_DEBIAN_DISTRO="bookworm"
|
||||
ARG GOLANG_IMAGE="golang:${GO_VERSION}-${BASE_DEBIAN_DISTRO}"
|
||||
|
||||
@@ -161,7 +161,7 @@ FROM ${WINDOWS_BASE_IMAGE}:${WINDOWS_BASE_IMAGE_TAG}
|
||||
# Use PowerShell as the default shell
|
||||
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
|
||||
|
||||
ARG GO_VERSION=1.25.4
|
||||
ARG GO_VERSION=1.25.5
|
||||
|
||||
# GOTESTSUM_VERSION is the version of gotest.tools/gotestsum to install.
|
||||
ARG GOTESTSUM_VERSION=v1.13.0
|
||||
|
||||
@@ -23,19 +23,28 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
apiClient, err := client.New(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||
// Create a new client that handles common environment variables
|
||||
// for configuration (DOCKER_HOST, DOCKER_API_VERSION), and does
|
||||
// API-version negotiation to allow downgrading the API version
|
||||
// when connecting with an older daemon version.
|
||||
apiClient, err := client.New(client.FromEnv)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer apiClient.Close()
|
||||
|
||||
containers, err := apiClient.ContainerList(context.Background(), client.ContainerListOptions{All: true})
|
||||
// List all containers (both stopped and running).
|
||||
result, err := apiClient.ContainerList(context.Background(), client.ContainerListOptions{
|
||||
All: true,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, ctr := range containers {
|
||||
fmt.Printf("%s %s (status: %s)\n", ctr.ID, ctr.Image, ctr.Status)
|
||||
// Print each container's ID, status and the image it was created from.
|
||||
fmt.Printf("%s %-22s %s\n", "ID", "STATUS", "IMAGE")
|
||||
for _, ctr := range result.Items {
|
||||
fmt.Printf("%s %-22s %s\n", ctr.ID, ctr.Status, ctr.Image)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -8,10 +8,8 @@ https://docs.docker.com/reference/api/engine/
|
||||
|
||||
You use the library by constructing a client object using [New]
|
||||
and calling methods on it. The client can be configured from environment
|
||||
variables by passing the [FromEnv] option, and the [WithAPIVersionNegotiation]
|
||||
option to allow downgrading the API version used when connecting with an older
|
||||
daemon version. Other options cen be configured manually by passing any of
|
||||
the available [Opt] options.
|
||||
variables by passing the [FromEnv] option. Other options can be configured
|
||||
manually by passing any of the available [Opt] options.
|
||||
|
||||
For example, to list running containers (the equivalent of "docker ps"):
|
||||
|
||||
@@ -30,7 +28,7 @@ For example, to list running containers (the equivalent of "docker ps"):
|
||||
// for configuration (DOCKER_HOST, DOCKER_API_VERSION), and does
|
||||
// API-version negotiation to allow downgrading the API version
|
||||
// when connecting with an older daemon version.
|
||||
apiClient, err := client.New(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||
apiClient, err := client.New(client.FromEnv)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@@ -103,18 +101,16 @@ import (
|
||||
const DummyHost = "api.moby.localhost"
|
||||
|
||||
// MaxAPIVersion is the highest REST API version supported by the client.
|
||||
// If API-version negotiation is enabled (see [WithAPIVersionNegotiation],
|
||||
// [Client.NegotiateAPIVersion]), the client may downgrade its API version.
|
||||
// Similarly, the [WithVersion] and [WithVersionFromEnv] allow overriding
|
||||
// the version.
|
||||
// If API-version negotiation is enabled, the client may downgrade its API version.
|
||||
// Similarly, the [WithAPIVersion] and [WithAPIVersionFromEnv] options allow
|
||||
// overriding the version and disable API-version negotiation.
|
||||
//
|
||||
// This version may be lower than the version of the api library module used.
|
||||
const MaxAPIVersion = "1.52"
|
||||
|
||||
// fallbackAPIVersion is the version to fall back to if API-version negotiation
|
||||
// fails. API versions below this version are not supported by the client,
|
||||
// and not considered when negotiating.
|
||||
const fallbackAPIVersion = "1.44"
|
||||
// MinAPIVersion is the minimum API version supported by the client. API versions
|
||||
// below this version are not considered when performing API-version negotiation.
|
||||
const MinAPIVersion = "1.44"
|
||||
|
||||
// Ensure that Client always implements APIClient.
|
||||
var _ APIClient = &Client{}
|
||||
@@ -174,8 +170,13 @@ func NewClientWithOpts(ops ...Opt) (*Client, error) {
|
||||
// It takes an optional list of [Opt] functional arguments, which are applied in
|
||||
// the order they're provided, which allows modifying the defaults when creating
|
||||
// the client. For example, the following initializes a client that configures
|
||||
// itself with values from environment variables ([FromEnv]), and has automatic
|
||||
// API version negotiation enabled ([WithAPIVersionNegotiation]).
|
||||
// itself with values from environment variables ([FromEnv]).
|
||||
//
|
||||
// By default, the client automatically negotiates the API version to use when
|
||||
// making requests. API version negotiation is performed on the first request;
|
||||
// subsequent requests do not re-negotiate. Use [WithAPIVersion] or
|
||||
// [WithAPIVersionFromEnv] to configure the client with a fixed API version
|
||||
// and disable API version negotiation.
|
||||
//
|
||||
// cli, err := client.New(
|
||||
// client.FromEnv,
|
||||
@@ -213,6 +214,12 @@ func New(ops ...Opt) (*Client, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.envAPIVersion != "" {
|
||||
c.setAPIVersion(cfg.envAPIVersion)
|
||||
} else if cfg.manualAPIVersion != "" {
|
||||
c.setAPIVersion(cfg.manualAPIVersion)
|
||||
}
|
||||
|
||||
if tr, ok := c.client.Transport.(*http.Transport); ok {
|
||||
// Store the base transport before we wrap it in tracing libs below
|
||||
// This is used, as an example, to close idle connections when the client is closed
|
||||
@@ -278,7 +285,7 @@ func (cli *Client) Close() error {
|
||||
// be negotiated when making the actual requests, and for which cases
|
||||
// we cannot do the negotiation lazily.
|
||||
func (cli *Client) checkVersion(ctx context.Context) error {
|
||||
if cli.manualOverride || !cli.negotiateVersion || cli.negotiated.Load() {
|
||||
if cli.negotiated.Load() {
|
||||
return nil
|
||||
}
|
||||
_, err := cli.Ping(ctx, PingOptions{
|
||||
@@ -306,36 +313,47 @@ func (cli *Client) ClientVersion() string {
|
||||
}
|
||||
|
||||
// negotiateAPIVersion updates the version to match the API version from
|
||||
// the ping response. It falls back to the lowest version supported if the
|
||||
// API version is empty, or returns an error if the API version is lower than
|
||||
// the lowest supported API version, in which case the version is not modified.
|
||||
// the ping response.
|
||||
//
|
||||
// It returns an error if version is invalid, or lower than the minimum
|
||||
// supported API version in which case the client's API version is not
|
||||
// updated, and negotiation is not marked as completed.
|
||||
func (cli *Client) negotiateAPIVersion(pingVersion string) error {
|
||||
pingVersion = strings.TrimPrefix(pingVersion, "v")
|
||||
if pingVersion == "" {
|
||||
// TODO(thaJeztah): consider returning an error on empty value or not falling back; see https://github.com/moby/moby/pull/51119#discussion_r2413148487
|
||||
pingVersion = fallbackAPIVersion
|
||||
} else if versions.LessThan(pingVersion, fallbackAPIVersion) {
|
||||
return cerrdefs.ErrInvalidArgument.WithMessage(fmt.Sprintf("API version %s is not supported by this client: the minimum supported API version is %s", pingVersion, fallbackAPIVersion))
|
||||
var err error
|
||||
pingVersion, err = parseAPIVersion(pingVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if versions.LessThan(pingVersion, MinAPIVersion) {
|
||||
return cerrdefs.ErrInvalidArgument.WithMessage(fmt.Sprintf("API version %s is not supported by this client: the minimum supported API version is %s", pingVersion, MinAPIVersion))
|
||||
}
|
||||
|
||||
// if the client is not initialized with a version, start with the latest supported version
|
||||
if cli.version == "" {
|
||||
cli.version = MaxAPIVersion
|
||||
negotiatedVersion := cli.version
|
||||
if negotiatedVersion == "" {
|
||||
negotiatedVersion = MaxAPIVersion
|
||||
}
|
||||
|
||||
// if server version is lower than the client version, downgrade
|
||||
if versions.LessThan(pingVersion, cli.version) {
|
||||
cli.version = pingVersion
|
||||
if versions.LessThan(pingVersion, negotiatedVersion) {
|
||||
negotiatedVersion = pingVersion
|
||||
}
|
||||
|
||||
// Store the results, so that automatic API version negotiation (if enabled)
|
||||
// won't be performed on the next request.
|
||||
if cli.negotiateVersion {
|
||||
cli.negotiated.Store(true)
|
||||
}
|
||||
cli.setAPIVersion(negotiatedVersion)
|
||||
return nil
|
||||
}
|
||||
|
||||
// setAPIVersion sets the client's API version and marks API version negotiation
|
||||
// as completed, so that automatic API version negotiation (if enabled) won't
|
||||
// be performed on the next request.
|
||||
func (cli *Client) setAPIVersion(version string) {
|
||||
cli.version = version
|
||||
cli.negotiated.Store(true)
|
||||
}
|
||||
|
||||
// DaemonHost returns the host address used by the client
|
||||
func (cli *Client) DaemonHost() string {
|
||||
return cli.host
|
||||
|
||||
@@ -13,10 +13,11 @@ func ExampleNew() {
|
||||
// for configuration (DOCKER_HOST, DOCKER_API_VERSION), and does
|
||||
// API-version negotiation to allow downgrading the API version
|
||||
// when connecting with an older daemon version.
|
||||
apiClient, err := client.New(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||
apiClient, err := client.New(client.FromEnv)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer apiClient.Close()
|
||||
|
||||
// List all containers (both stopped and running).
|
||||
result, err := apiClient.ContainerList(context.Background(), client.ContainerListOptions{
|
||||
|
||||
@@ -5,9 +5,13 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/moby/moby/api/types/build"
|
||||
"github.com/moby/moby/api/types/common"
|
||||
"github.com/moby/moby/api/types/swarm"
|
||||
)
|
||||
|
||||
// defaultAPIPath is the API path prefix for the default API version used.
|
||||
@@ -40,20 +44,88 @@ func assertRequestWithQuery(req *http.Request, expMethod string, expectedPath st
|
||||
return nil
|
||||
}
|
||||
|
||||
// ensureBody makes sure the response has a Body, using [http.NoBody] if
|
||||
// none is present, and returns it as a testRoundTripper.
|
||||
// ensureBody makes sure the response has a Body (using [http.NoBody] if
|
||||
// none is present), and that the request is set on the response, then returns
|
||||
// it as a testRoundTripper.
|
||||
func ensureBody(f func(req *http.Request) (*http.Response, error)) testRoundTripper {
|
||||
return func(req *http.Request) (*http.Response, error) {
|
||||
resp, err := f(req)
|
||||
if resp != nil && resp.Body == nil {
|
||||
resp.Body = http.NoBody
|
||||
if resp != nil {
|
||||
if resp.Body == nil {
|
||||
resp.Body = http.NoBody
|
||||
}
|
||||
if resp.Request == nil {
|
||||
resp.Request = req
|
||||
}
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
}
|
||||
|
||||
// WithMockClient is a test helper that allows you to inject a mock client for testing.
|
||||
// makeTestRoundTripper makes sure the response has a Body, using [http.NoBody] if
|
||||
// none is present, and returns it as a testRoundTripper. If withDefaults is set,
|
||||
// it also mocks the "/_ping" endpoint and sets default headers as returned
|
||||
// by the daemon.
|
||||
func makeTestRoundTripper(f func(req *http.Request) (*http.Response, error)) testRoundTripper {
|
||||
return func(req *http.Request) (*http.Response, error) {
|
||||
if req.URL.Path == "/_ping" {
|
||||
return mockPingResponse(http.StatusOK, PingResult{
|
||||
APIVersion: MaxAPIVersion,
|
||||
OSType: runtime.GOOS,
|
||||
Experimental: true,
|
||||
BuilderVersion: build.BuilderBuildKit,
|
||||
SwarmStatus: &SwarmStatus{
|
||||
NodeState: swarm.LocalNodeStateActive,
|
||||
ControlAvailable: true,
|
||||
},
|
||||
})(req)
|
||||
}
|
||||
resp, err := f(req)
|
||||
if resp != nil {
|
||||
if resp.Body == nil {
|
||||
resp.Body = http.NoBody
|
||||
}
|
||||
if resp.Request == nil {
|
||||
resp.Request = req
|
||||
}
|
||||
}
|
||||
applyDefaultHeaders(resp)
|
||||
return resp, err
|
||||
}
|
||||
}
|
||||
|
||||
// applyDefaultHeaders mocks the headers set by the daemon's VersionMiddleware.
|
||||
func applyDefaultHeaders(resp *http.Response) {
|
||||
if resp == nil {
|
||||
return
|
||||
}
|
||||
if resp.Header == nil {
|
||||
resp.Header = make(http.Header)
|
||||
}
|
||||
if resp.Header.Get("Server") == "" {
|
||||
resp.Header.Set("Server", fmt.Sprintf("Docker/%s (%s)", "v99.99.99", runtime.GOOS))
|
||||
}
|
||||
if resp.Header.Get("Api-Version") == "" {
|
||||
resp.Header.Set("Api-Version", MaxAPIVersion)
|
||||
}
|
||||
if resp.Header.Get("Ostype") == "" {
|
||||
resp.Header.Set("Ostype", runtime.GOOS)
|
||||
}
|
||||
}
|
||||
|
||||
// WithMockClient is a test helper that allows you to inject a mock client for
|
||||
// testing. By default, it mocks the "/_ping" endpoint, so allow the client
|
||||
// to perform API-version negotiation. Other endpoints are handled by "doer".
|
||||
func WithMockClient(doer func(*http.Request) (*http.Response, error)) Opt {
|
||||
return WithHTTPClient(&http.Client{
|
||||
Transport: makeTestRoundTripper(doer),
|
||||
})
|
||||
}
|
||||
|
||||
// WithBaseMockClient is a test helper that allows you to inject a mock client
|
||||
// for testing. It is identical to [WithMockClient], but does not mock the "/_ping"
|
||||
// endpoint, and doesn't set the default headers.
|
||||
func WithBaseMockClient(doer func(*http.Request) (*http.Response, error)) Opt {
|
||||
return WithHTTPClient(&http.Client{
|
||||
Transport: ensureBody(doer),
|
||||
})
|
||||
@@ -78,21 +150,39 @@ func mockJSONResponse[T any](statusCode int, headers http.Header, resp T) func(r
|
||||
return mockResponse(statusCode, hdr, string(respBody))
|
||||
}
|
||||
|
||||
// mockPingResponse mocks the headers set for a "/_ping" response.
|
||||
func mockPingResponse(statusCode int, ping PingResult) func(req *http.Request) (*http.Response, error) {
|
||||
headers := http.Header{}
|
||||
if s := ping.SwarmStatus; s != nil {
|
||||
role := "worker"
|
||||
if s.ControlAvailable {
|
||||
role = "manager"
|
||||
}
|
||||
headers.Set("Swarm", fmt.Sprintf("%s/%s", string(swarm.LocalNodeStateActive), role))
|
||||
}
|
||||
headers.Set("Api-Version", ping.APIVersion)
|
||||
headers.Set("Ostype", ping.OSType)
|
||||
headers.Set("Docker-Experimental", strconv.FormatBool(ping.Experimental))
|
||||
headers.Set("Builder-Version", string(ping.BuilderVersion))
|
||||
|
||||
headers.Set("Content-Type", "text/plain; charset=utf-8")
|
||||
headers.Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||
headers.Set("Pragma", "no-cache")
|
||||
return mockResponse(statusCode, headers, "OK")
|
||||
}
|
||||
|
||||
func mockResponse(statusCode int, headers http.Header, respBody string) func(req *http.Request) (*http.Response, error) {
|
||||
if headers == nil {
|
||||
headers = make(http.Header)
|
||||
}
|
||||
var body io.ReadCloser
|
||||
if respBody == "" {
|
||||
body = http.NoBody
|
||||
} else {
|
||||
body = io.NopCloser(strings.NewReader(respBody))
|
||||
}
|
||||
return func(req *http.Request) (*http.Response, error) {
|
||||
var body io.ReadCloser
|
||||
if respBody == "" || req.Method == http.MethodHead {
|
||||
body = http.NoBody
|
||||
} else {
|
||||
body = io.NopCloser(strings.NewReader(respBody))
|
||||
}
|
||||
return &http.Response{
|
||||
Status: fmt.Sprintf("%d %s", statusCode, http.StatusText(statusCode)),
|
||||
StatusCode: statusCode,
|
||||
Header: headers,
|
||||
Header: headers.Clone(),
|
||||
Body: body,
|
||||
Request: req,
|
||||
}, nil
|
||||
|
||||
@@ -38,14 +38,22 @@ type clientConfig struct {
|
||||
userAgent *string
|
||||
// custom HTTP headers configured by users.
|
||||
customHTTPHeaders map[string]string
|
||||
// manualOverride is set to true when the version was set by users.
|
||||
manualOverride bool
|
||||
|
||||
// negotiateVersion indicates if the client should automatically negotiate
|
||||
// the API version to use when making requests. API version negotiation is
|
||||
// performed on the first request, after which negotiated is set to "true"
|
||||
// so that subsequent requests do not re-negotiate.
|
||||
negotiateVersion bool
|
||||
// manualAPIVersion contains the API version set by users. This field
|
||||
// will only be non-empty if a valid-formed version was set through
|
||||
// [WithAPIVersion].
|
||||
//
|
||||
// If both manualAPIVersion and envAPIVersion are set, manualAPIVersion
|
||||
// takes precedence. Either field disables API-version negotiation.
|
||||
manualAPIVersion string
|
||||
|
||||
// envAPIVersion contains the API version set by users. This field
|
||||
// will only be non-empty if a valid-formed version was set through
|
||||
// [WithAPIVersionFromEnv].
|
||||
//
|
||||
// If both manualAPIVersion and envAPIVersion are set, manualAPIVersion
|
||||
// takes precedence. Either field disables API-version negotiation.
|
||||
envAPIVersion string
|
||||
|
||||
// traceOpts is a list of options to configure the tracing span.
|
||||
traceOpts []otelhttp.Option
|
||||
@@ -56,7 +64,7 @@ type Opt func(*clientConfig) error
|
||||
|
||||
// FromEnv configures the client with values from environment variables. It
|
||||
// is the equivalent of using the [WithTLSClientConfigFromEnv], [WithHostFromEnv],
|
||||
// and [WithVersionFromEnv] options.
|
||||
// and [WithAPIVersionFromEnv] options.
|
||||
//
|
||||
// FromEnv uses the following environment variables:
|
||||
//
|
||||
@@ -71,7 +79,7 @@ func FromEnv(c *clientConfig) error {
|
||||
ops := []Opt{
|
||||
WithTLSClientConfigFromEnv(),
|
||||
WithHostFromEnv(),
|
||||
WithVersionFromEnv(),
|
||||
WithAPIVersionFromEnv(),
|
||||
}
|
||||
for _, op := range ops {
|
||||
if err := op(c); err != nil {
|
||||
@@ -241,18 +249,59 @@ func WithTLSClientConfigFromEnv() Opt {
|
||||
}
|
||||
}
|
||||
|
||||
// WithVersion overrides the client version with the specified one. If an empty
|
||||
// version is provided, the value is ignored to allow version negotiation
|
||||
// (see [WithAPIVersionNegotiation]).
|
||||
// WithAPIVersion overrides the client's API version with the specified one,
|
||||
// and disables API version negotiation. If an empty version is provided,
|
||||
// this option is ignored to allow version negotiation. The given version
|
||||
// should be formatted "<major>.<minor>" (for example, "1.52"). It returns
|
||||
// an error if the given value not in the correct format.
|
||||
//
|
||||
// WithVersion does not validate if the client supports the given version,
|
||||
// and callers should verify if the version is in the correct format and
|
||||
// lower than the maximum supported version as defined by [MaxAPIVersion].
|
||||
func WithVersion(version string) Opt {
|
||||
// WithAPIVersion does not validate if the client supports the given version,
|
||||
// and callers should verify if the version lower than the maximum supported
|
||||
// version as defined by [MaxAPIVersion].
|
||||
//
|
||||
// [WithAPIVersionFromEnv] takes precedence if [WithAPIVersion] and
|
||||
// [WithAPIVersionFromEnv] are both set.
|
||||
func WithAPIVersion(version string) Opt {
|
||||
return func(c *clientConfig) error {
|
||||
if v := strings.TrimPrefix(version, "v"); v != "" {
|
||||
c.version = v
|
||||
c.manualOverride = true
|
||||
version = strings.TrimSpace(version)
|
||||
if val := strings.TrimPrefix(version, "v"); val != "" {
|
||||
ver, err := parseAPIVersion(val)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid API version (%s): %w", version, err)
|
||||
}
|
||||
c.manualAPIVersion = ver
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithVersion overrides the client version with the specified one.
|
||||
//
|
||||
// Deprecated: use [WithAPIVersion] instead.
|
||||
func WithVersion(version string) Opt {
|
||||
return WithAPIVersion(version)
|
||||
}
|
||||
|
||||
// WithAPIVersionFromEnv overrides the client version with the version specified in
|
||||
// the DOCKER_API_VERSION ([EnvOverrideAPIVersion]) environment variable.
|
||||
// If DOCKER_API_VERSION is not set, or set to an empty value, the version
|
||||
// is not modified.
|
||||
//
|
||||
// WithAPIVersion does not validate if the client supports the given version,
|
||||
// and callers should verify if the version lower than the maximum supported
|
||||
// version as defined by [MaxAPIVersion].
|
||||
//
|
||||
// [WithAPIVersionFromEnv] takes precedence if [WithAPIVersion] and
|
||||
// [WithAPIVersionFromEnv] are both set.
|
||||
func WithAPIVersionFromEnv() Opt {
|
||||
return func(c *clientConfig) error {
|
||||
version := strings.TrimSpace(os.Getenv(EnvOverrideAPIVersion))
|
||||
if val := strings.TrimPrefix(version, "v"); val != "" {
|
||||
ver, err := parseAPIVersion(val)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid API version (%s): %w", version, err)
|
||||
}
|
||||
c.envAPIVersion = ver
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -260,25 +309,21 @@ func WithVersion(version string) Opt {
|
||||
|
||||
// WithVersionFromEnv overrides the client version with the version specified in
|
||||
// the DOCKER_API_VERSION ([EnvOverrideAPIVersion]) environment variable.
|
||||
// If DOCKER_API_VERSION is not set, or set to an empty value, the version
|
||||
// is not modified.
|
||||
//
|
||||
// WithVersion does not validate if the client supports the given version,
|
||||
// and callers should verify if the version is in the correct format and
|
||||
// lower than the maximum supported version as defined by [MaxAPIVersion].
|
||||
// Deprecated: use [WithAPIVersionFromEnv] instead.
|
||||
func WithVersionFromEnv() Opt {
|
||||
return func(c *clientConfig) error {
|
||||
return WithVersion(os.Getenv(EnvOverrideAPIVersion))(c)
|
||||
}
|
||||
return WithAPIVersionFromEnv()
|
||||
}
|
||||
|
||||
// WithAPIVersionNegotiation enables automatic API version negotiation for the client.
|
||||
// With this option enabled, the client automatically negotiates the API version
|
||||
// to use when making requests. API version negotiation is performed on the first
|
||||
// request; subsequent requests do not re-negotiate.
|
||||
//
|
||||
// Deprecated: API-version negotiation is now enabled by default. Use [WithAPIVersion]
|
||||
// or [WithAPIVersionFromEnv] to disable API version negotiation.
|
||||
func WithAPIVersionNegotiation() Opt {
|
||||
return func(c *clientConfig) error {
|
||||
c.negotiateVersion = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
369
client/client_options_test.go
Normal file
369
client/client_options_test.go
Normal file
@@ -0,0 +1,369 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestOptionWithHostFromEnv(t *testing.T) {
|
||||
c, err := New(WithHostFromEnv())
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, c.client != nil)
|
||||
assert.Check(t, is.Equal(c.basePath, ""))
|
||||
if runtime.GOOS == "windows" {
|
||||
assert.Check(t, is.Equal(c.host, "npipe:////./pipe/docker_engine"))
|
||||
assert.Check(t, is.Equal(c.proto, "npipe"))
|
||||
assert.Check(t, is.Equal(c.addr, "//./pipe/docker_engine"))
|
||||
} else {
|
||||
assert.Check(t, is.Equal(c.host, "unix:///var/run/docker.sock"))
|
||||
assert.Check(t, is.Equal(c.proto, "unix"))
|
||||
assert.Check(t, is.Equal(c.addr, "/var/run/docker.sock"))
|
||||
}
|
||||
|
||||
t.Setenv("DOCKER_HOST", "tcp://foo.example.com:2376/test/")
|
||||
|
||||
c, err = New(WithHostFromEnv())
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, c.client != nil)
|
||||
assert.Check(t, is.Equal(c.basePath, "/test/"))
|
||||
assert.Check(t, is.Equal(c.host, "tcp://foo.example.com:2376/test/"))
|
||||
assert.Check(t, is.Equal(c.proto, "tcp"))
|
||||
assert.Check(t, is.Equal(c.addr, "foo.example.com:2376"))
|
||||
}
|
||||
|
||||
func TestOptionWithTimeout(t *testing.T) {
|
||||
timeout := 10 * time.Second
|
||||
c, err := New(WithTimeout(timeout))
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, c.client != nil)
|
||||
assert.Check(t, is.Equal(c.client.Timeout, timeout))
|
||||
}
|
||||
|
||||
func TestOptionWithAPIVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
doc string
|
||||
version string
|
||||
expected string
|
||||
expError string
|
||||
}{
|
||||
{
|
||||
doc: "empty version",
|
||||
version: "",
|
||||
expected: MaxAPIVersion,
|
||||
},
|
||||
{
|
||||
doc: "custom lower version with whitespace, no v-prefix",
|
||||
version: " 1.50 ",
|
||||
expected: "1.50",
|
||||
},
|
||||
{
|
||||
// We currently allow downgrading the client to an unsupported lower version for testing.
|
||||
doc: "downgrade unsupported version, no v-prefix",
|
||||
version: "1.0",
|
||||
expected: "1.0",
|
||||
},
|
||||
{
|
||||
doc: "custom lower version, no v-prefix",
|
||||
version: "1.50",
|
||||
expected: "1.50",
|
||||
},
|
||||
{
|
||||
// We currently allow upgrading the client to an unsupported higher version for testing.
|
||||
doc: "upgrade version, no v-prefix",
|
||||
version: "9.99",
|
||||
expected: "9.99",
|
||||
},
|
||||
{
|
||||
doc: "empty version, with v-prefix",
|
||||
version: "v",
|
||||
expected: MaxAPIVersion,
|
||||
},
|
||||
{
|
||||
doc: "whitespace, with v-prefix",
|
||||
version: " v1.0 ",
|
||||
expected: "1.0",
|
||||
},
|
||||
{
|
||||
doc: "downgrade unsupported version, with v-prefix",
|
||||
version: "v1.0",
|
||||
expected: "1.0",
|
||||
},
|
||||
{
|
||||
doc: "custom lower version with whitespace and v-prefix",
|
||||
version: " v1.50 ",
|
||||
expected: "1.50",
|
||||
},
|
||||
{
|
||||
doc: "custom lower version, with v-prefix",
|
||||
version: "v1.50",
|
||||
expected: "1.50",
|
||||
},
|
||||
{
|
||||
doc: "upgrade version, with v-prefix",
|
||||
version: "v9.99",
|
||||
expected: "9.99",
|
||||
},
|
||||
{
|
||||
doc: "malformed version",
|
||||
version: "something-weird",
|
||||
expError: "invalid API version (something-weird): must be formatted <major>.<minor>",
|
||||
},
|
||||
{
|
||||
doc: "no minor",
|
||||
version: "1",
|
||||
expError: "invalid API version (1): must be formatted <major>.<minor>",
|
||||
},
|
||||
{
|
||||
doc: "too many digits",
|
||||
version: "1.2.3",
|
||||
expError: "invalid API version (1.2.3): invalid minor version: must be formatted <major>.<minor>",
|
||||
},
|
||||
{
|
||||
doc: "embedded whitespace",
|
||||
version: "v 1.0",
|
||||
expError: "invalid API version (v 1.0): invalid major version: must be formatted <major>.<minor>",
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.doc, func(t *testing.T) {
|
||||
client, err := New(WithAPIVersion(tc.version))
|
||||
if tc.expError != "" {
|
||||
assert.Check(t, is.ErrorContains(err, tc.expError))
|
||||
assert.Check(t, client == nil)
|
||||
} else {
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, client != nil)
|
||||
assert.Check(t, is.Equal(client.ClientVersion(), tc.expected))
|
||||
isNoOp := strings.TrimPrefix(strings.TrimSpace(tc.version), "v") == ""
|
||||
assert.Check(t, is.Equal(client.negotiated.Load(), !isNoOp))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOptionWithAPIVersionFromEnv(t *testing.T) {
|
||||
tests := []struct {
|
||||
doc string
|
||||
version string
|
||||
expected string
|
||||
expError string
|
||||
}{
|
||||
{
|
||||
doc: "empty version",
|
||||
version: "",
|
||||
expected: MaxAPIVersion,
|
||||
},
|
||||
{
|
||||
doc: "custom lower version with whitespace, no v-prefix",
|
||||
version: " 1.50 ",
|
||||
expected: "1.50",
|
||||
},
|
||||
{
|
||||
// We currently allow downgrading the client to an unsupported lower version for testing.
|
||||
doc: "downgrade unsupported version, no v-prefix",
|
||||
version: "1.0",
|
||||
expected: "1.0",
|
||||
},
|
||||
{
|
||||
doc: "custom lower version, no v-prefix",
|
||||
version: "1.50",
|
||||
expected: "1.50",
|
||||
},
|
||||
{
|
||||
// We currently allow upgrading the client to an unsupported higher version for testing.
|
||||
doc: "upgrade version, no v-prefix",
|
||||
version: "9.99",
|
||||
expected: "9.99",
|
||||
},
|
||||
{
|
||||
doc: "empty version, with v-prefix",
|
||||
version: "v",
|
||||
expected: MaxAPIVersion,
|
||||
},
|
||||
{
|
||||
doc: "whitespace, with v-prefix",
|
||||
version: " v1.0 ",
|
||||
expected: "1.0",
|
||||
},
|
||||
{
|
||||
doc: "downgrade unsupported version, with v-prefix",
|
||||
version: "v1.0",
|
||||
expected: "1.0",
|
||||
},
|
||||
{
|
||||
doc: "custom lower version with whitespace and v-prefix",
|
||||
version: " v1.50 ",
|
||||
expected: "1.50",
|
||||
},
|
||||
{
|
||||
doc: "custom lower version, with v-prefix",
|
||||
version: "v1.50",
|
||||
expected: "1.50",
|
||||
},
|
||||
{
|
||||
doc: "upgrade version, with v-prefix",
|
||||
version: "v9.99",
|
||||
expected: "9.99",
|
||||
},
|
||||
{
|
||||
doc: "malformed version",
|
||||
version: "something-weird",
|
||||
expError: "invalid API version (something-weird): must be formatted <major>.<minor>",
|
||||
},
|
||||
{
|
||||
doc: "no minor",
|
||||
version: "1",
|
||||
expError: "invalid API version (1): must be formatted <major>.<minor>",
|
||||
},
|
||||
{
|
||||
doc: "too many digits",
|
||||
version: "1.2.3",
|
||||
expError: "invalid API version (1.2.3): invalid minor version: must be formatted <major>.<minor>",
|
||||
},
|
||||
{
|
||||
doc: "embedded whitespace",
|
||||
version: "v 1.0",
|
||||
expError: "invalid API version (v 1.0): invalid major version: must be formatted <major>.<minor>",
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.doc, func(t *testing.T) {
|
||||
t.Setenv(EnvOverrideAPIVersion, tc.version)
|
||||
client, err := New(WithAPIVersionFromEnv())
|
||||
if tc.expError != "" {
|
||||
assert.Check(t, is.ErrorContains(err, tc.expError))
|
||||
assert.Check(t, client == nil)
|
||||
} else {
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, client != nil)
|
||||
assert.Check(t, is.Equal(client.ClientVersion(), tc.expected))
|
||||
isNoOp := strings.TrimPrefix(strings.TrimSpace(tc.version), "v") == ""
|
||||
assert.Check(t, is.Equal(client.negotiated.Load(), !isNoOp))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestOptionOverridePriority validates that overriding the API version through
|
||||
// [WithAPIVersionFromEnv] takes precedence over other manual options, regardless
|
||||
// the order in which they're passed.
|
||||
func TestOptionOverridePriority(t *testing.T) {
|
||||
t.Run("no env-var set", func(t *testing.T) {
|
||||
client, err := New(WithAPIVersionFromEnv(), WithAPIVersion("1.50"))
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(client.ClientVersion(), "1.50"))
|
||||
assert.Check(t, is.Equal(client.negotiated.Load(), true))
|
||||
})
|
||||
|
||||
const expected = "1.51"
|
||||
t.Setenv(EnvOverrideAPIVersion, expected)
|
||||
|
||||
t.Run("WithAPIVersionFromEnv first", func(t *testing.T) {
|
||||
client, err := New(WithAPIVersionFromEnv(), WithAPIVersion("1.50"))
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(client.ClientVersion(), expected))
|
||||
assert.Check(t, is.Equal(client.negotiated.Load(), true))
|
||||
})
|
||||
|
||||
t.Run("WithAPIVersionFromEnv last", func(t *testing.T) {
|
||||
client, err := New(WithAPIVersion("1.50"), WithAPIVersionFromEnv())
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(client.ClientVersion(), expected))
|
||||
assert.Check(t, is.Equal(client.negotiated.Load(), true))
|
||||
})
|
||||
|
||||
t.Run("FromEnv first", func(t *testing.T) {
|
||||
client, err := New(FromEnv, WithAPIVersion("1.50"))
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(client.ClientVersion(), expected))
|
||||
assert.Check(t, is.Equal(client.negotiated.Load(), true))
|
||||
})
|
||||
|
||||
t.Run("FromEnv last", func(t *testing.T) {
|
||||
client, err := New(WithAPIVersion("1.50"), FromEnv)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(client.ClientVersion(), expected))
|
||||
assert.Check(t, is.Equal(client.negotiated.Load(), true))
|
||||
})
|
||||
}
|
||||
|
||||
func TestWithUserAgent(t *testing.T) {
|
||||
const userAgent = "Magic-Client/v1.2.3"
|
||||
t.Run("user-agent", func(t *testing.T) {
|
||||
c, err := New(
|
||||
WithUserAgent(userAgent),
|
||||
WithMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
assert.Check(t, is.Equal(req.Header.Get("User-Agent"), userAgent))
|
||||
return &http.Response{StatusCode: http.StatusOK}, nil
|
||||
}),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
_, err = c.Ping(t.Context(), PingOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.NilError(t, c.Close())
|
||||
})
|
||||
t.Run("user-agent and custom headers", func(t *testing.T) {
|
||||
c, err := New(
|
||||
WithUserAgent(userAgent),
|
||||
WithHTTPHeaders(map[string]string{"User-Agent": "should-be-ignored/1.0.0", "Other-Header": "hello-world"}),
|
||||
WithMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
assert.Check(t, is.Equal(req.Header.Get("User-Agent"), userAgent))
|
||||
assert.Check(t, is.Equal(req.Header.Get("Other-Header"), "hello-world"))
|
||||
return &http.Response{StatusCode: http.StatusOK}, nil
|
||||
}),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
_, err = c.Ping(t.Context(), PingOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.NilError(t, c.Close())
|
||||
})
|
||||
t.Run("custom headers", func(t *testing.T) {
|
||||
c, err := New(
|
||||
WithHTTPHeaders(map[string]string{"User-Agent": "from-custom-headers/1.0.0", "Other-Header": "hello-world"}),
|
||||
WithMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
assert.Check(t, is.Equal(req.Header.Get("User-Agent"), "from-custom-headers/1.0.0"))
|
||||
assert.Check(t, is.Equal(req.Header.Get("Other-Header"), "hello-world"))
|
||||
return &http.Response{StatusCode: http.StatusOK}, nil
|
||||
}),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
_, err = c.Ping(t.Context(), PingOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.NilError(t, c.Close())
|
||||
})
|
||||
t.Run("no user-agent set", func(t *testing.T) {
|
||||
c, err := New(
|
||||
WithHTTPHeaders(map[string]string{"Other-Header": "hello-world"}),
|
||||
WithMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
assert.Check(t, is.Equal(req.Header.Get("User-Agent"), ""))
|
||||
assert.Check(t, is.Equal(req.Header.Get("Other-Header"), "hello-world"))
|
||||
return &http.Response{StatusCode: http.StatusOK}, nil
|
||||
}),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
_, err = c.Ping(t.Context(), PingOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.NilError(t, c.Close())
|
||||
})
|
||||
t.Run("reset custom user-agent", func(t *testing.T) {
|
||||
c, err := New(
|
||||
WithUserAgent(""),
|
||||
WithHTTPHeaders(map[string]string{"User-Agent": "from-custom-headers/1.0.0", "Other-Header": "hello-world"}),
|
||||
WithMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
assert.Check(t, is.Equal(req.Header.Get("User-Agent"), ""))
|
||||
assert.Check(t, is.Equal(req.Header.Get("Other-Header"), "hello-world"))
|
||||
return &http.Response{StatusCode: http.StatusOK}, nil
|
||||
}),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
_, err = c.Ping(t.Context(), PingOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.NilError(t, c.Close())
|
||||
})
|
||||
}
|
||||
@@ -175,7 +175,7 @@ func TestGetAPIPath(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
for _, tc := range tests {
|
||||
client, err := New(
|
||||
WithVersion(tc.version),
|
||||
WithAPIVersion(tc.version),
|
||||
WithHost("tcp://localhost:2375"),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
@@ -254,11 +254,10 @@ func TestNegotiateAPIVersionEmpty(t *testing.T) {
|
||||
|
||||
// if no version from server, expect the earliest
|
||||
// version before APIVersion was implemented
|
||||
const expected = fallbackAPIVersion
|
||||
const expected = MinAPIVersion
|
||||
|
||||
client, err := New(FromEnv,
|
||||
WithAPIVersionNegotiation(),
|
||||
WithMockClient(mockResponse(http.StatusOK, http.Header{"Api-Version": []string{expected}}, "OK")),
|
||||
WithBaseMockClient(mockPingResponse(http.StatusOK, PingResult{APIVersion: expected})),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
@@ -301,12 +300,10 @@ func TestNegotiateAPIVersion(t *testing.T) {
|
||||
expectedVersion: "1.51",
|
||||
},
|
||||
{
|
||||
// client should downgrade to the last version before version
|
||||
// negotiation was added (1.24) if the daemon does not report
|
||||
// a version.
|
||||
// client should not downgrade if the daemon didn't report a version.
|
||||
doc: "downgrade legacy",
|
||||
pingVersion: "",
|
||||
expectedVersion: fallbackAPIVersion,
|
||||
expectedVersion: MaxAPIVersion,
|
||||
},
|
||||
{
|
||||
// client should not downgrade to the version reported by the daemon
|
||||
@@ -314,7 +311,7 @@ func TestNegotiateAPIVersion(t *testing.T) {
|
||||
doc: "no downgrade old",
|
||||
pingVersion: "1.19",
|
||||
expectedVersion: MaxAPIVersion,
|
||||
expectedErr: "API version 1.19 is not supported by this client: the minimum supported API version is " + fallbackAPIVersion,
|
||||
expectedErr: "API version 1.19 is not supported by this client: the minimum supported API version is " + MinAPIVersion,
|
||||
},
|
||||
{
|
||||
// client should not upgrade to a newer version if a version was set,
|
||||
@@ -330,15 +327,14 @@ func TestNegotiateAPIVersion(t *testing.T) {
|
||||
t.Run(tc.doc, func(t *testing.T) {
|
||||
opts := []Opt{
|
||||
FromEnv,
|
||||
WithAPIVersionNegotiation(),
|
||||
WithMockClient(mockResponse(http.StatusOK, http.Header{"Api-Version": []string{tc.pingVersion}}, "OK")),
|
||||
WithBaseMockClient(mockPingResponse(http.StatusOK, PingResult{APIVersion: tc.pingVersion})),
|
||||
}
|
||||
|
||||
if tc.clientVersion != "" {
|
||||
// Note that this check is redundant, as WithVersion() considers
|
||||
// an empty version equivalent to "not setting a version", but
|
||||
// doing this just to be explicit we are using the default.
|
||||
opts = append(opts, WithVersion(tc.clientVersion))
|
||||
opts = append(opts, WithAPIVersion(tc.clientVersion))
|
||||
}
|
||||
client, err := New(opts...)
|
||||
assert.NilError(t, err)
|
||||
@@ -363,7 +359,7 @@ func TestNegotiateAPIVersionOverride(t *testing.T) {
|
||||
|
||||
client, err := New(
|
||||
FromEnv,
|
||||
WithMockClient(mockResponse(http.StatusOK, http.Header{"Api-Version": []string{"1.45"}}, "OK")),
|
||||
WithBaseMockClient(mockPingResponse(http.StatusOK, PingResult{APIVersion: "1.45"})),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
@@ -393,11 +389,9 @@ func TestNegotiateAPIVersionAutomatic(t *testing.T) {
|
||||
|
||||
ctx := t.Context()
|
||||
client, err := New(
|
||||
WithMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
hdr := http.Header{"Api-Version": []string{pingVersion}}
|
||||
return mockResponse(http.StatusOK, hdr, "OK")(req)
|
||||
WithBaseMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
return mockPingResponse(http.StatusOK, PingResult{APIVersion: pingVersion})(req)
|
||||
}),
|
||||
WithAPIVersionNegotiation(),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
@@ -422,8 +416,8 @@ func TestNegotiateAPIVersionAutomatic(t *testing.T) {
|
||||
// with an empty version string does still allow API-version negotiation
|
||||
func TestNegotiateAPIVersionWithEmptyVersion(t *testing.T) {
|
||||
client, err := New(
|
||||
WithVersion(""),
|
||||
WithMockClient(mockResponse(http.StatusOK, http.Header{"Api-Version": []string{"1.50"}}, "OK")),
|
||||
WithAPIVersion(""),
|
||||
WithBaseMockClient(mockPingResponse(http.StatusOK, PingResult{APIVersion: "1.50"})),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
@@ -437,94 +431,28 @@ func TestNegotiateAPIVersionWithEmptyVersion(t *testing.T) {
|
||||
// TestNegotiateAPIVersionWithFixedVersion asserts that initializing a client
|
||||
// with a fixed version disables API-version negotiation
|
||||
func TestNegotiateAPIVersionWithFixedVersion(t *testing.T) {
|
||||
const customVersion = "1.50"
|
||||
const (
|
||||
customVersion = "1.50"
|
||||
pingVersion = "1.49"
|
||||
)
|
||||
client, err := New(
|
||||
WithVersion(customVersion),
|
||||
WithMockClient(mockResponse(http.StatusOK, http.Header{"Api-Version": []string{"1.49"}}, "OK")),
|
||||
WithAPIVersion(customVersion),
|
||||
WithBaseMockClient(mockPingResponse(http.StatusOK, PingResult{APIVersion: pingVersion})),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.Ping(t.Context(), PingOptions{
|
||||
NegotiateAPIVersion: true,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(client.ClientVersion(), customVersion))
|
||||
|
||||
_, err = client.Ping(t.Context(), PingOptions{
|
||||
NegotiateAPIVersion: true,
|
||||
ForceNegotiate: true,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(client.ClientVersion(), customVersion))
|
||||
}
|
||||
|
||||
// TestCustomAPIVersion tests initializing the client with a custom
|
||||
// version.
|
||||
func TestCustomAPIVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
doc string
|
||||
version string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
doc: "empty version",
|
||||
version: "",
|
||||
expected: MaxAPIVersion,
|
||||
},
|
||||
{
|
||||
doc: "custom lower version, no v-prefix",
|
||||
version: "1.50",
|
||||
expected: "1.50",
|
||||
},
|
||||
{
|
||||
// We allow upgrading the client to an unsupported higher version for testing.
|
||||
doc: "upgrade version, no v-prefix",
|
||||
version: "9.99",
|
||||
expected: "9.99",
|
||||
},
|
||||
{
|
||||
// We currently ignore malformed versions.
|
||||
doc: "empty version, with v-prefix",
|
||||
version: "v",
|
||||
expected: MaxAPIVersion,
|
||||
},
|
||||
{
|
||||
doc: "custom lower version, with v-prefix",
|
||||
version: "v1.50",
|
||||
expected: "1.50",
|
||||
},
|
||||
{
|
||||
// We allow upgrading the client to an unsupported higher version for testing.
|
||||
doc: "upgrade version, with v-prefix",
|
||||
version: "v9.99",
|
||||
expected: "9.99",
|
||||
},
|
||||
{
|
||||
// We currently allow downgrading the client to an unsupported lower version for testing.
|
||||
doc: "downgrade unsupported version, no v-prefix",
|
||||
version: "1.0",
|
||||
expected: "1.0",
|
||||
},
|
||||
{
|
||||
// We currently allow downgrading the client to an unsupported lower version for testing.
|
||||
doc: "downgrade unsupported version, no v-prefix",
|
||||
version: "v1.0",
|
||||
expected: "1.0",
|
||||
},
|
||||
{
|
||||
// When manually setting a version, no validation happens.
|
||||
// so anything is accepted.
|
||||
doc: "malformed version",
|
||||
version: "something-weird",
|
||||
expected: "something-weird",
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.doc, func(t *testing.T) {
|
||||
client, err := New(WithVersion(tc.version))
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(client.ClientVersion(), tc.expected))
|
||||
|
||||
t.Setenv(EnvOverrideAPIVersion, tc.expected)
|
||||
client, err = New(WithVersionFromEnv())
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(client.ClientVersion(), tc.expected))
|
||||
})
|
||||
}
|
||||
assert.Check(t, is.Equal(client.ClientVersion(), pingVersion))
|
||||
}
|
||||
|
||||
func TestClientRedirect(t *testing.T) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -17,7 +16,7 @@ func TestConfigCreateError(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ConfigCreate(context.Background(), ConfigCreateOptions{Spec: swarm.ConfigSpec{}})
|
||||
_, err = client.ConfigCreate(t.Context(), ConfigCreateOptions{Spec: swarm.ConfigSpec{}})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -35,7 +34,7 @@ func TestConfigCreate(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
r, err := client.ConfigCreate(context.Background(), ConfigCreateOptions{Spec: swarm.ConfigSpec{}})
|
||||
r, err := client.ConfigCreate(t.Context(), ConfigCreateOptions{Spec: swarm.ConfigSpec{}})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(r.ID, "test_config"))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"testing"
|
||||
@@ -18,7 +17,7 @@ func TestConfigInspectNotFound(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ConfigInspect(context.Background(), "unknown", ConfigInspectOptions{})
|
||||
_, err = client.ConfigInspect(t.Context(), "unknown", ConfigInspectOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsNotFound))
|
||||
}
|
||||
|
||||
@@ -29,11 +28,11 @@ func TestConfigInspectWithEmptyID(t *testing.T) {
|
||||
}),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
_, err = client.ConfigInspect(context.Background(), "", ConfigInspectOptions{})
|
||||
_, err = client.ConfigInspect(t.Context(), "", ConfigInspectOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.ConfigInspect(context.Background(), " ", ConfigInspectOptions{})
|
||||
_, err = client.ConfigInspect(t.Context(), " ", ConfigInspectOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -44,7 +43,7 @@ func TestConfigInspectError(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ConfigInspect(context.Background(), "nothing", ConfigInspectOptions{})
|
||||
_, err = client.ConfigInspect(t.Context(), "nothing", ConfigInspectOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -54,7 +53,7 @@ func TestConfigInspectConfigNotFound(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ConfigInspect(context.Background(), "unknown", ConfigInspectOptions{})
|
||||
_, err = client.ConfigInspect(t.Context(), "unknown", ConfigInspectOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsNotFound))
|
||||
}
|
||||
|
||||
@@ -72,7 +71,7 @@ func TestConfigInspect(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
result, err := client.ConfigInspect(context.Background(), "config_id", ConfigInspectOptions{})
|
||||
result, err := client.ConfigInspect(t.Context(), "config_id", ConfigInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(result.Config.ID, "config_id"))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
@@ -18,7 +17,7 @@ func TestConfigListError(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ConfigList(context.Background(), ConfigListOptions{})
|
||||
_, err = client.ConfigList(t.Context(), ConfigListOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -67,7 +66,7 @@ func TestConfigList(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
result, err := client.ConfigList(context.Background(), listCase.options)
|
||||
result, err := client.ConfigList(t.Context(), listCase.options)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Len(result.Items, 2))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -16,14 +15,14 @@ func TestConfigRemoveError(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ConfigRemove(context.Background(), "config_id", ConfigRemoveOptions{})
|
||||
_, err = client.ConfigRemove(t.Context(), "config_id", ConfigRemoveOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
_, err = client.ConfigRemove(context.Background(), "", ConfigRemoveOptions{})
|
||||
_, err = client.ConfigRemove(t.Context(), "", ConfigRemoveOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.ConfigRemove(context.Background(), " ", ConfigRemoveOptions{})
|
||||
_, err = client.ConfigRemove(t.Context(), " ", ConfigRemoveOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -41,6 +40,6 @@ func TestConfigRemove(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ConfigRemove(context.Background(), "config_id", ConfigRemoveOptions{})
|
||||
_, err = client.ConfigRemove(t.Context(), "config_id", ConfigRemoveOptions{})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -16,14 +15,14 @@ func TestConfigUpdateError(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ConfigUpdate(context.Background(), "config_id", ConfigUpdateOptions{})
|
||||
_, err = client.ConfigUpdate(t.Context(), "config_id", ConfigUpdateOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
_, err = client.ConfigUpdate(context.Background(), "", ConfigUpdateOptions{})
|
||||
_, err = client.ConfigUpdate(t.Context(), "", ConfigUpdateOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.ConfigUpdate(context.Background(), " ", ConfigUpdateOptions{})
|
||||
_, err = client.ConfigUpdate(t.Context(), " ", ConfigUpdateOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -41,6 +40,6 @@ func TestConfigUpdate(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ConfigUpdate(context.Background(), "config_id", ConfigUpdateOptions{})
|
||||
_, err = client.ConfigUpdate(t.Context(), "config_id", ConfigUpdateOptions{})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
@@ -18,14 +17,14 @@ func TestContainerCommitError(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ContainerCommit(context.Background(), "nothing", ContainerCommitOptions{})
|
||||
_, err = client.ContainerCommit(t.Context(), "nothing", ContainerCommitOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
_, err = client.ContainerCommit(context.Background(), "", ContainerCommitOptions{})
|
||||
_, err = client.ContainerCommit(t.Context(), "", ContainerCommitOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.ContainerCommit(context.Background(), " ", ContainerCommitOptions{})
|
||||
_, err = client.ContainerCommit(t.Context(), " ", ContainerCommitOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -83,7 +82,7 @@ func TestContainerCommit(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
r, err := client.ContainerCommit(context.Background(), expectedContainerID, ContainerCommitOptions{
|
||||
r, err := client.ContainerCommit(t.Context(), expectedContainerID, ContainerCommitOptions{
|
||||
Reference: specifiedReference,
|
||||
Comment: expectedComment,
|
||||
Author: expectedAuthor,
|
||||
|
||||
@@ -2,7 +2,6 @@ package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
@@ -24,14 +23,14 @@ func TestContainerStatPathError(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ContainerStatPath(context.Background(), "container_id", ContainerStatPathOptions{Path: "path"})
|
||||
_, err = client.ContainerStatPath(t.Context(), "container_id", ContainerStatPathOptions{Path: "path"})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
_, err = client.ContainerStatPath(context.Background(), "", ContainerStatPathOptions{Path: "path"})
|
||||
_, err = client.ContainerStatPath(t.Context(), "", ContainerStatPathOptions{Path: "path"})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.ContainerStatPath(context.Background(), " ", ContainerStatPathOptions{Path: "path"})
|
||||
_, err = client.ContainerStatPath(t.Context(), " ", ContainerStatPathOptions{Path: "path"})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -42,7 +41,7 @@ func TestContainerStatPathNotFoundError(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ContainerStatPath(context.Background(), "container_id", ContainerStatPathOptions{Path: "path"})
|
||||
_, err = client.ContainerStatPath(t.Context(), "container_id", ContainerStatPathOptions{Path: "path"})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsNotFound))
|
||||
}
|
||||
|
||||
@@ -52,7 +51,7 @@ func TestContainerStatPathNoHeaderError(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ContainerStatPath(context.Background(), "container_id", ContainerStatPathOptions{Path: "path/to/file"})
|
||||
_, err = client.ContainerStatPath(t.Context(), "container_id", ContainerStatPathOptions{Path: "path/to/file"})
|
||||
assert.Check(t, err != nil, "expected an error, got nothing")
|
||||
}
|
||||
|
||||
@@ -86,7 +85,7 @@ func TestContainerStatPath(t *testing.T) {
|
||||
}),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
res, err := client.ContainerStatPath(context.Background(), "container_id", ContainerStatPathOptions{Path: expectedPath})
|
||||
res, err := client.ContainerStatPath(t.Context(), "container_id", ContainerStatPathOptions{Path: expectedPath})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(res.Stat.Name, "name"))
|
||||
assert.Check(t, is.Equal(res.Stat.Mode, os.FileMode(0o700)))
|
||||
@@ -98,20 +97,20 @@ func TestCopyToContainerError(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.CopyToContainer(context.Background(), "container_id", CopyToContainerOptions{
|
||||
_, err = client.CopyToContainer(t.Context(), "container_id", CopyToContainerOptions{
|
||||
DestinationPath: "path/to/file",
|
||||
Content: bytes.NewReader([]byte("")),
|
||||
})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
_, err = client.CopyToContainer(context.Background(), "", CopyToContainerOptions{
|
||||
_, err = client.CopyToContainer(t.Context(), "", CopyToContainerOptions{
|
||||
DestinationPath: "path/to/file",
|
||||
Content: bytes.NewReader([]byte("")),
|
||||
})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.CopyToContainer(context.Background(), " ", CopyToContainerOptions{
|
||||
_, err = client.CopyToContainer(t.Context(), " ", CopyToContainerOptions{
|
||||
DestinationPath: "path/to/file",
|
||||
Content: bytes.NewReader([]byte("")),
|
||||
})
|
||||
@@ -125,7 +124,7 @@ func TestCopyToContainerNotFoundError(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.CopyToContainer(context.Background(), "container_id", CopyToContainerOptions{
|
||||
_, err = client.CopyToContainer(t.Context(), "container_id", CopyToContainerOptions{
|
||||
DestinationPath: "path/to/file",
|
||||
Content: bytes.NewReader([]byte("")),
|
||||
})
|
||||
@@ -140,7 +139,7 @@ func TestCopyToContainerEmptyResponse(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.CopyToContainer(context.Background(), "container_id", CopyToContainerOptions{
|
||||
_, err = client.CopyToContainer(t.Context(), "container_id", CopyToContainerOptions{
|
||||
DestinationPath: "path/to/file",
|
||||
Content: bytes.NewReader([]byte("")),
|
||||
})
|
||||
@@ -183,7 +182,7 @@ func TestCopyToContainer(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.CopyToContainer(context.Background(), "container_id", CopyToContainerOptions{
|
||||
_, err = client.CopyToContainer(t.Context(), "container_id", CopyToContainerOptions{
|
||||
DestinationPath: expectedPath,
|
||||
Content: bytes.NewReader([]byte("content")),
|
||||
AllowOverwriteDirWithFile: false,
|
||||
@@ -197,14 +196,14 @@ func TestCopyFromContainerError(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.CopyFromContainer(context.Background(), "container_id", CopyFromContainerOptions{SourcePath: "path/to/file"})
|
||||
_, err = client.CopyFromContainer(t.Context(), "container_id", CopyFromContainerOptions{SourcePath: "path/to/file"})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
_, err = client.CopyFromContainer(context.Background(), "", CopyFromContainerOptions{SourcePath: "path/to/file"})
|
||||
_, err = client.CopyFromContainer(t.Context(), "", CopyFromContainerOptions{SourcePath: "path/to/file"})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.CopyFromContainer(context.Background(), " ", CopyFromContainerOptions{SourcePath: "path/to/file"})
|
||||
_, err = client.CopyFromContainer(t.Context(), " ", CopyFromContainerOptions{SourcePath: "path/to/file"})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -215,7 +214,7 @@ func TestCopyFromContainerNotFoundError(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.CopyFromContainer(context.Background(), "container_id", CopyFromContainerOptions{SourcePath: "path/to/file"})
|
||||
_, err = client.CopyFromContainer(t.Context(), "container_id", CopyFromContainerOptions{SourcePath: "path/to/file"})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsNotFound))
|
||||
}
|
||||
|
||||
@@ -240,7 +239,7 @@ func TestCopyFromContainerEmptyResponse(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.CopyFromContainer(context.Background(), "container_id", CopyFromContainerOptions{SourcePath: "path/to/file"})
|
||||
_, err = client.CopyFromContainer(t.Context(), "container_id", CopyFromContainerOptions{SourcePath: "path/to/file"})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
@@ -250,7 +249,7 @@ func TestCopyFromContainerNoHeaderError(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.CopyFromContainer(context.Background(), "container_id", CopyFromContainerOptions{SourcePath: "path/to/file"})
|
||||
_, err = client.CopyFromContainer(t.Context(), "container_id", CopyFromContainerOptions{SourcePath: "path/to/file"})
|
||||
assert.Check(t, err != nil, "expected an error, got nothing")
|
||||
}
|
||||
|
||||
@@ -285,7 +284,7 @@ func TestCopyFromContainer(t *testing.T) {
|
||||
}),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
res2, err := client.CopyFromContainer(context.Background(), "container_id", CopyFromContainerOptions{SourcePath: expectedPath})
|
||||
res2, err := client.CopyFromContainer(t.Context(), "container_id", CopyFromContainerOptions{SourcePath: expectedPath})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(res2.Stat.Name, "name"))
|
||||
assert.Check(t, is.Equal(res2.Stat.Mode, os.FileMode(0o700)))
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -20,11 +19,11 @@ func TestContainerCreateError(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ContainerCreate(context.Background(), ContainerCreateOptions{Config: nil, Name: "nothing"})
|
||||
_, err = client.ContainerCreate(t.Context(), ContainerCreateOptions{Config: nil, Name: "nothing"})
|
||||
assert.Error(t, err, "config.Image or Image is required")
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
|
||||
_, err = client.ContainerCreate(context.Background(), ContainerCreateOptions{Config: &container.Config{}, Name: "nothing"})
|
||||
_, err = client.ContainerCreate(t.Context(), ContainerCreateOptions{Config: &container.Config{}, Name: "nothing"})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
}
|
||||
|
||||
@@ -34,7 +33,7 @@ func TestContainerCreateImageNotFound(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ContainerCreate(context.Background(), ContainerCreateOptions{Config: &container.Config{Image: "unknown_image"}, Name: "unknown"})
|
||||
_, err = client.ContainerCreate(t.Context(), ContainerCreateOptions{Config: &container.Config{Image: "unknown_image"}, Name: "unknown"})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsNotFound))
|
||||
}
|
||||
|
||||
@@ -56,7 +55,7 @@ func TestContainerCreateWithName(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
r, err := client.ContainerCreate(context.Background(), ContainerCreateOptions{Config: &container.Config{Image: "test"}, Name: "container_name"})
|
||||
r, err := client.ContainerCreate(t.Context(), ContainerCreateOptions{Config: &container.Config{Image: "test"}, Name: "container_name"})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(r.ID, "container_id"))
|
||||
}
|
||||
@@ -78,7 +77,7 @@ func TestContainerCreateAutoRemove(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
resp, err := client.ContainerCreate(context.Background(), ContainerCreateOptions{Config: &container.Config{Image: "test"}, HostConfig: &container.HostConfig{AutoRemove: true}})
|
||||
resp, err := client.ContainerCreate(t.Context(), ContainerCreateOptions{Config: &container.Config{Image: "test"}, HostConfig: &container.HostConfig{AutoRemove: true}})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(resp.ID, "container_id"))
|
||||
}
|
||||
@@ -88,10 +87,10 @@ func TestContainerCreateAutoRemove(t *testing.T) {
|
||||
//
|
||||
// Regression test for https://github.com/docker/cli/issues/4890
|
||||
func TestContainerCreateConnectionError(t *testing.T) {
|
||||
client, err := New(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
|
||||
client, err := New(WithHost("tcp://no-such-host.invalid"))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ContainerCreate(context.Background(), ContainerCreateOptions{Config: &container.Config{Image: "test"}})
|
||||
_, err = client.ContainerCreate(t.Context(), ContainerCreateOptions{Config: &container.Config{Image: "test"}})
|
||||
assert.Check(t, is.ErrorType(err, IsErrConnectionFailed))
|
||||
}
|
||||
|
||||
@@ -133,6 +132,6 @@ func TestContainerCreateCapabilities(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ContainerCreate(context.Background(), ContainerCreateOptions{Config: &container.Config{Image: "test"}, HostConfig: &container.HostConfig{CapAdd: inputCaps, CapDrop: inputCaps}})
|
||||
_, err = client.ContainerCreate(t.Context(), ContainerCreateOptions{Config: &container.Config{Image: "test"}, HostConfig: &container.HostConfig{CapAdd: inputCaps, CapDrop: inputCaps}})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -17,14 +16,14 @@ func TestContainerDiffError(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ContainerDiff(context.Background(), "nothing", ContainerDiffOptions{})
|
||||
_, err = client.ContainerDiff(t.Context(), "nothing", ContainerDiffOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
_, err = client.ContainerDiff(context.Background(), "", ContainerDiffOptions{})
|
||||
_, err = client.ContainerDiff(t.Context(), "", ContainerDiffOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.ContainerDiff(context.Background(), " ", ContainerDiffOptions{})
|
||||
_, err = client.ContainerDiff(t.Context(), " ", ContainerDiffOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -57,7 +56,7 @@ func TestContainerDiff(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
result, err := client.ContainerDiff(context.Background(), "container_id", ContainerDiffOptions{})
|
||||
result, err := client.ContainerDiff(t.Context(), "container_id", ContainerDiffOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.DeepEqual(result.Changes, expected))
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ func TestExecCreateError(t *testing.T) {
|
||||
//
|
||||
// Regression test for https://github.com/docker/cli/issues/4890
|
||||
func TestExecCreateConnectionError(t *testing.T) {
|
||||
client, err := New(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
|
||||
client, err := New(WithHost("tcp://no-such-host.invalid"))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ExecCreate(t.Context(), "container_id", ExecCreateOptions{})
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
@@ -18,7 +17,7 @@ func TestContainerListError(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ContainerList(context.Background(), ContainerListOptions{})
|
||||
_, err = client.ContainerList(t.Context(), ContainerListOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -65,7 +64,7 @@ func TestContainerList(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
list, err := client.ContainerList(context.Background(), ContainerListOptions{
|
||||
list, err := client.ContainerList(t.Context(), ContainerListOptions{
|
||||
Size: true,
|
||||
All: true,
|
||||
Since: "container",
|
||||
|
||||
@@ -167,7 +167,7 @@ func TestContainerLogs(t *testing.T) {
|
||||
}
|
||||
|
||||
func ExampleClient_ContainerLogs_withTimeout() {
|
||||
client, err := New(FromEnv, WithAPIVersionNegotiation())
|
||||
client, err := New(FromEnv)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -15,7 +14,7 @@ func TestContainerPruneError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ContainerPrune(context.Background(), ContainerPruneOptions{})
|
||||
_, err = client.ContainerPrune(t.Context(), ContainerPruneOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -89,7 +88,7 @@ func TestContainerPrune(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
req, err := client.ContainerPrune(context.Background(), ContainerPruneOptions{Filters: listCase.filters})
|
||||
req, err := client.ContainerPrune(t.Context(), ContainerPruneOptions{Filters: listCase.filters})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Len(req.Report.ContainersDeleted, 2))
|
||||
assert.Check(t, is.Equal(uint64(9999), req.Report.SpaceReclaimed))
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
@@ -14,14 +13,14 @@ import (
|
||||
func TestContainerRenameError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.ContainerRename(context.Background(), "nothing", ContainerRenameOptions{NewName: "newNothing"})
|
||||
_, err = client.ContainerRename(t.Context(), "nothing", ContainerRenameOptions{NewName: "newNothing"})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
_, err = client.ContainerRename(context.Background(), "", ContainerRenameOptions{NewName: "newNothing"})
|
||||
_, err = client.ContainerRename(t.Context(), "", ContainerRenameOptions{NewName: "newNothing"})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.ContainerRename(context.Background(), " ", ContainerRenameOptions{NewName: "newNothing"})
|
||||
_, err = client.ContainerRename(t.Context(), " ", ContainerRenameOptions{NewName: "newNothing"})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -40,6 +39,6 @@ func TestContainerRename(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ContainerRename(context.Background(), "container_id", ContainerRenameOptions{NewName: "newName"})
|
||||
_, err = client.ContainerRename(t.Context(), "container_id", ContainerRenameOptions{NewName: "newName"})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ func TestContainerRestartError(t *testing.T) {
|
||||
//
|
||||
// Regression test for https://github.com/docker/cli/issues/4890
|
||||
func TestContainerRestartConnectionError(t *testing.T) {
|
||||
client, err := New(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
|
||||
client, err := New(WithHost("tcp://no-such-host.invalid"))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ContainerRestart(t.Context(), "nothing", ContainerRestartOptions{})
|
||||
|
||||
@@ -30,7 +30,7 @@ func TestContainerStopError(t *testing.T) {
|
||||
//
|
||||
// Regression test for https://github.com/docker/cli/issues/4890
|
||||
func TestContainerStopConnectionError(t *testing.T) {
|
||||
client, err := New(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
|
||||
client, err := New(WithHost("tcp://no-such-host.invalid"))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ContainerStop(t.Context(), "container_id", ContainerStopOptions{})
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
@@ -15,14 +14,14 @@ import (
|
||||
func TestContainerTopError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.ContainerTop(context.Background(), "nothing", ContainerTopOptions{})
|
||||
_, err = client.ContainerTop(t.Context(), "nothing", ContainerTopOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
_, err = client.ContainerTop(context.Background(), "", ContainerTopOptions{})
|
||||
_, err = client.ContainerTop(t.Context(), "", ContainerTopOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.ContainerTop(context.Background(), " ", ContainerTopOptions{})
|
||||
_, err = client.ContainerTop(t.Context(), " ", ContainerTopOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -54,7 +53,7 @@ func TestContainerTop(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
processList, err := client.ContainerTop(context.Background(), "container_id", ContainerTopOptions{
|
||||
processList, err := client.ContainerTop(t.Context(), "container_id", ContainerTopOptions{
|
||||
Arguments: []string{"arg1", "arg2"},
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -14,14 +13,14 @@ import (
|
||||
func TestContainerUpdateError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.ContainerUpdate(context.Background(), "nothing", ContainerUpdateOptions{})
|
||||
_, err = client.ContainerUpdate(t.Context(), "nothing", ContainerUpdateOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
_, err = client.ContainerUpdate(context.Background(), "", ContainerUpdateOptions{})
|
||||
_, err = client.ContainerUpdate(t.Context(), "", ContainerUpdateOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.ContainerUpdate(context.Background(), " ", ContainerUpdateOptions{})
|
||||
_, err = client.ContainerUpdate(t.Context(), " ", ContainerUpdateOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -37,7 +36,7 @@ func TestContainerUpdate(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ContainerUpdate(context.Background(), "container_id", ContainerUpdateOptions{
|
||||
_, err = client.ContainerUpdate(t.Context(), "container_id", ContainerUpdateOptions{
|
||||
Resources: &container.Resources{
|
||||
CPUPeriod: 1,
|
||||
},
|
||||
|
||||
@@ -19,9 +19,12 @@ import (
|
||||
)
|
||||
|
||||
func TestContainerWaitError(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
defer cancel()
|
||||
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
wait := client.ContainerWait(t.Context(), "nothing", ContainerWaitOptions{})
|
||||
wait := client.ContainerWait(ctx, "nothing", ContainerWaitOptions{})
|
||||
select {
|
||||
case result := <-wait.Result:
|
||||
t.Fatalf("expected to not get a wait result, got %d", result.StatusCode)
|
||||
@@ -35,10 +38,13 @@ func TestContainerWaitError(t *testing.T) {
|
||||
//
|
||||
// Regression test for https://github.com/docker/cli/issues/4890
|
||||
func TestContainerWaitConnectionError(t *testing.T) {
|
||||
client, err := New(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
defer cancel()
|
||||
|
||||
client, err := New(WithHost("tcp://no-such-host.invalid"))
|
||||
assert.NilError(t, err)
|
||||
|
||||
wait := client.ContainerWait(t.Context(), "nothing", ContainerWaitOptions{})
|
||||
wait := client.ContainerWait(ctx, "nothing", ContainerWaitOptions{})
|
||||
select {
|
||||
case result := <-wait.Result:
|
||||
t.Fatalf("expected to not get a wait result, got %d", result.StatusCode)
|
||||
@@ -48,6 +54,9 @@ func TestContainerWaitConnectionError(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestContainerWait(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
defer cancel()
|
||||
|
||||
const expectedURL = "/containers/container_id/wait"
|
||||
client, err := New(WithMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
if err := assertRequest(req, http.MethodPost, expectedURL); err != nil {
|
||||
@@ -59,7 +68,7 @@ func TestContainerWait(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
wait := client.ContainerWait(t.Context(), "container_id", ContainerWaitOptions{})
|
||||
wait := client.ContainerWait(ctx, "container_id", ContainerWaitOptions{})
|
||||
select {
|
||||
case err := <-wait.Error:
|
||||
assert.NilError(t, err)
|
||||
@@ -69,6 +78,9 @@ func TestContainerWait(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestContainerWaitProxyInterrupt(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
defer cancel()
|
||||
|
||||
const (
|
||||
expectedURL = "/containers/container_id/wait"
|
||||
expErr = "copying response body from Docker: unexpected EOF"
|
||||
@@ -82,16 +94,19 @@ func TestContainerWaitProxyInterrupt(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
wait := client.ContainerWait(t.Context(), "container_id", ContainerWaitOptions{})
|
||||
wait := client.ContainerWait(ctx, "container_id", ContainerWaitOptions{})
|
||||
select {
|
||||
case err := <-wait.Error:
|
||||
assert.Check(t, is.ErrorContains(err, expErr))
|
||||
case result := <-wait.Result:
|
||||
t.Fatalf("Unexpected result: %v", result)
|
||||
t.Errorf("Unexpected result: %v", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainerWaitProxyInterruptLong(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
defer cancel()
|
||||
|
||||
const expectedURL = "/containers/container_id/wait"
|
||||
msg := strings.Repeat("x", containerWaitErrorMsgLimit*5)
|
||||
client, err := New(WithMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
@@ -102,13 +117,13 @@ func TestContainerWaitProxyInterruptLong(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
wait := client.ContainerWait(t.Context(), "container_id", ContainerWaitOptions{})
|
||||
wait := client.ContainerWait(ctx, "container_id", ContainerWaitOptions{})
|
||||
select {
|
||||
case err := <-wait.Error:
|
||||
// LimitReader limiting isn't exact, because of how the Readers do chunking.
|
||||
assert.Check(t, len(err.Error()) <= containerWaitErrorMsgLimit*2, "Expected error to be limited around %d, actual length: %d", containerWaitErrorMsgLimit, len(err.Error()))
|
||||
case result := <-wait.Result:
|
||||
t.Fatalf("Unexpected result: %v", result)
|
||||
t.Errorf("Unexpected result: %v", result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +155,7 @@ func TestContainerWaitErrorHandling(t *testing.T) {
|
||||
assert.Check(t, is.Equal(err.Error(), test.exp.Error()))
|
||||
return
|
||||
case result := <-wait.Result:
|
||||
t.Fatalf("expected to not get a wait result, got %d", result.StatusCode)
|
||||
t.Errorf("expected to not get a wait result, got %d", result.StatusCode)
|
||||
return
|
||||
}
|
||||
// Unexpected - we should not reach this line
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"testing"
|
||||
@@ -16,6 +15,6 @@ func TestDistributionInspectWithEmptyID(t *testing.T) {
|
||||
return nil, errors.New("should not make request")
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.DistributionInspect(context.Background(), "", DistributionInspectOptions{})
|
||||
_, err = client.DistributionInspect(t.Context(), "", DistributionInspectOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsNotFound))
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ const (
|
||||
// be used to override the API version to use. Value must be
|
||||
// formatted as MAJOR.MINOR, for example, "1.19".
|
||||
//
|
||||
// This env-var is read by [FromEnv] and [WithVersionFromEnv] and when set to a
|
||||
// This env-var is read by [FromEnv] and [WithAPIVersionFromEnv] and when set to a
|
||||
// non-empty value, takes precedence over API version negotiation.
|
||||
//
|
||||
// This environment variable should be used for debugging purposes only, as
|
||||
|
||||
@@ -18,11 +18,24 @@ import (
|
||||
|
||||
func TestTLSCloseWriter(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
defer cancel()
|
||||
|
||||
var chErr chan error
|
||||
ts := &httptest.Server{Config: &http.Server{
|
||||
ReadHeaderTimeout: 5 * time.Minute, // "G112: Potential Slowloris Attack (gosec)"; not a real concern for our use, so setting a long timeout.
|
||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
if req.URL.Path == "/_ping" {
|
||||
resp, err := mockPingResponse(http.StatusOK, PingResult{APIVersion: MaxAPIVersion})(req)
|
||||
if err != nil {
|
||||
chErr <- fmt.Errorf("sending ping response: %w", err)
|
||||
return
|
||||
}
|
||||
_ = resp.Header.Write(w)
|
||||
w.WriteHeader(resp.StatusCode)
|
||||
return
|
||||
}
|
||||
|
||||
chErr = make(chan error, 1)
|
||||
defer close(chErr)
|
||||
|
||||
@@ -38,12 +51,16 @@ func TestTLSCloseWriter(t *testing.T) {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
defer func() { _ = conn.Close() }()
|
||||
|
||||
// Flush the options to make sure the client sets the raw mode
|
||||
_, _ = conn.Write([]byte{})
|
||||
|
||||
fmt.Fprint(conn, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\n")
|
||||
_, err = fmt.Fprint(conn, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\n")
|
||||
if err != nil {
|
||||
chErr <- fmt.Errorf("writing update response: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
buf := make([]byte, 5)
|
||||
_, err = conn.Read(buf)
|
||||
@@ -72,7 +89,7 @@ func TestTLSCloseWriter(t *testing.T) {
|
||||
assert.NilError(t, err)
|
||||
|
||||
ts.Listener = l
|
||||
defer l.Close()
|
||||
defer func() { _ = l.Close() }()
|
||||
|
||||
defer func() {
|
||||
if chErr != nil {
|
||||
@@ -86,10 +103,12 @@ func TestTLSCloseWriter(t *testing.T) {
|
||||
serverURL, err := url.Parse(ts.URL)
|
||||
assert.NilError(t, err)
|
||||
|
||||
client, err := New(WithHost("tcp://"+serverURL.Host), WithHTTPClient(ts.Client()))
|
||||
httpClient := ts.Client()
|
||||
defer httpClient.CloseIdleConnections()
|
||||
client, err := New(WithHost("tcp://"+serverURL.Host), WithHTTPClient(httpClient))
|
||||
assert.NilError(t, err)
|
||||
|
||||
resp, err := client.postHijacked(context.Background(), "/asdf", url.Values{}, nil, map[string][]string{"Content-Type": {"text/plain"}})
|
||||
resp, err := client.postHijacked(ctx, "/asdf", url.Values{}, nil, map[string][]string{"Content-Type": {"text/plain"}})
|
||||
assert.NilError(t, err)
|
||||
defer resp.Close()
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -18,7 +17,7 @@ import (
|
||||
func TestImageBuildError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.ImageBuild(context.Background(), nil, ImageBuildOptions{})
|
||||
_, err = client.ImageBuild(t.Context(), nil, ImageBuildOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -188,7 +187,7 @@ func TestImageBuild(t *testing.T) {
|
||||
return mockResponse(http.StatusOK, nil, "body")(req)
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
buildResponse, err := client.ImageBuild(context.Background(), nil, buildCase.buildOptions)
|
||||
buildResponse, err := client.ImageBuild(t.Context(), nil, buildCase.buildOptions)
|
||||
assert.NilError(t, err)
|
||||
response, err := io.ReadAll(buildResponse.Body)
|
||||
assert.NilError(t, err)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -15,7 +14,7 @@ import (
|
||||
func TestImageHistoryError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.ImageHistory(context.Background(), "nothing")
|
||||
_, err = client.ImageHistory(t.Context(), "nothing")
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -44,7 +43,7 @@ func TestImageHistory(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
imageHistories, err := client.ImageHistory(context.Background(), "image_id", ImageHistoryWithPlatform(ocispec.Platform{
|
||||
imageHistories, err := client.ImageHistory(t.Context(), "image_id", ImageHistoryWithPlatform(ocispec.Platform{
|
||||
Architecture: "arm64",
|
||||
OS: "linux",
|
||||
Variant: "v8",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -17,7 +16,7 @@ import (
|
||||
func TestImageImportError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.ImageImport(context.Background(), ImageImportSource{}, "image:tag", ImageImportOptions{})
|
||||
_, err = client.ImageImport(t.Context(), ImageImportSource{}, "image:tag", ImageImportOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -77,7 +76,7 @@ func TestImageImport(t *testing.T) {
|
||||
return mockResponse(http.StatusOK, nil, expectedOutput)(req)
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
result, err := client.ImageImport(context.Background(), ImageImportSource{
|
||||
result, err := client.ImageImport(t.Context(), ImageImportSource{
|
||||
Source: strings.NewReader("source"),
|
||||
SourceName: "image_source",
|
||||
}, "repository_name:imported", tc.options)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
@@ -18,7 +17,7 @@ func TestImageInspectError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ImageInspect(context.Background(), "nothing")
|
||||
_, err = client.ImageInspect(t.Context(), "nothing")
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -26,7 +25,7 @@ func TestImageInspectImageNotFound(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusNotFound, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ImageInspect(context.Background(), "unknown")
|
||||
_, err = client.ImageInspect(t.Context(), "unknown")
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsNotFound))
|
||||
}
|
||||
|
||||
@@ -35,7 +34,7 @@ func TestImageInspectWithEmptyID(t *testing.T) {
|
||||
return nil, errors.New("should not make request")
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.ImageInspect(context.Background(), "")
|
||||
_, err = client.ImageInspect(t.Context(), "")
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsNotFound))
|
||||
}
|
||||
|
||||
@@ -53,7 +52,7 @@ func TestImageInspect(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
imageInspect, err := client.ImageInspect(context.Background(), "image_id")
|
||||
imageInspect, err := client.ImageInspect(t.Context(), "image_id")
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(imageInspect.ID, "image_id"))
|
||||
assert.Check(t, is.DeepEqual(imageInspect.RepoTags, expectedTags))
|
||||
@@ -88,7 +87,7 @@ func TestImageInspectWithPlatform(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
imageInspect, err := client.ImageInspect(context.Background(), "image_id", ImageInspectWithPlatform(requestedPlatform))
|
||||
imageInspect, err := client.ImageInspect(t.Context(), "image_id", ImageInspectWithPlatform(requestedPlatform))
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(imageInspect.ID, "image_id"))
|
||||
assert.Check(t, is.Equal(imageInspect.Architecture, "arm64"))
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
cerrdefs "github.com/containerd/errdefs"
|
||||
@@ -17,7 +15,7 @@ func TestImageListError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ImageList(context.Background(), ImageListOptions{})
|
||||
_, err = client.ImageList(t.Context(), ImageListOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -26,21 +24,23 @@ func TestImageListError(t *testing.T) {
|
||||
//
|
||||
// Regression test for https://github.com/docker/cli/issues/4890
|
||||
func TestImageListConnectionError(t *testing.T) {
|
||||
client, err := New(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
|
||||
client, err := New(WithHost("tcp://no-such-host.invalid"))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ImageList(context.Background(), ImageListOptions{})
|
||||
_, err = client.ImageList(t.Context(), ImageListOptions{})
|
||||
assert.Check(t, is.ErrorType(err, IsErrConnectionFailed))
|
||||
}
|
||||
|
||||
func TestImageList(t *testing.T) {
|
||||
const expectedURL = "/images/json"
|
||||
|
||||
listCases := []struct {
|
||||
tests := []struct {
|
||||
doc string
|
||||
options ImageListOptions
|
||||
expectedQueryParams map[string]string
|
||||
}{
|
||||
{
|
||||
doc: "no options",
|
||||
options: ImageListOptions{},
|
||||
expectedQueryParams: map[string]string{
|
||||
"all": "",
|
||||
@@ -49,6 +49,7 @@ func TestImageList(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
doc: "label filters and dangling",
|
||||
options: ImageListOptions{
|
||||
Filters: make(Filters).
|
||||
Add("label", "label1").
|
||||
@@ -62,6 +63,7 @@ func TestImageList(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
doc: "label filters no dangling",
|
||||
options: ImageListOptions{
|
||||
Filters: make(Filters).Add("dangling", "false"),
|
||||
},
|
||||
@@ -71,59 +73,40 @@ func TestImageList(t *testing.T) {
|
||||
"filters": `{"dangling":{"false":true}}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
doc: "with shared size",
|
||||
options: ImageListOptions{
|
||||
SharedSize: true,
|
||||
},
|
||||
expectedQueryParams: map[string]string{
|
||||
"shared-size": "1",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, listCase := range listCases {
|
||||
client, err := New(WithMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
if err := assertRequest(req, http.MethodGet, expectedURL); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
query := req.URL.Query()
|
||||
for key, expected := range listCase.expectedQueryParams {
|
||||
actual := query.Get(key)
|
||||
if actual != expected {
|
||||
return nil, fmt.Errorf("%s not set in URL query properly. Expected '%s', got %s", key, expected, actual)
|
||||
}
|
||||
}
|
||||
return mockJSONResponse(http.StatusOK, nil, []image.Summary{
|
||||
{ID: "image_id2"},
|
||||
{ID: "image_id2"},
|
||||
})(req)
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
images, err := client.ImageList(context.Background(), listCase.options)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Len(images.Items, 2))
|
||||
}
|
||||
}
|
||||
|
||||
// Checks if shared-size query parameter is set/not being set correctly
|
||||
// for /images/json.
|
||||
func TestImageListWithSharedSize(t *testing.T) {
|
||||
t.Parallel()
|
||||
const sharedSize = "shared-size"
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
version string
|
||||
options ImageListOptions
|
||||
sharedSize string // expected value for the shared-size query param, or empty if it should not be set.
|
||||
}{
|
||||
{name: "unset, no options set"},
|
||||
{name: "set", options: ImageListOptions{SharedSize: true}, sharedSize: "1"},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
var query url.Values
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.doc, func(t *testing.T) {
|
||||
client, err := New(WithMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
query = req.URL.Query()
|
||||
return mockResponse(http.StatusOK, nil, "[]")(req)
|
||||
}), WithVersion(tc.version))
|
||||
if err := assertRequest(req, http.MethodGet, expectedURL); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
query := req.URL.Query()
|
||||
for key, expected := range tc.expectedQueryParams {
|
||||
actual := query.Get(key)
|
||||
if actual != expected {
|
||||
return nil, fmt.Errorf("%s not set in URL query properly. Expected '%s', got %s", key, expected, actual)
|
||||
}
|
||||
}
|
||||
return mockJSONResponse(http.StatusOK, nil, []image.Summary{
|
||||
{ID: "image_id2"},
|
||||
{ID: "image_id2"},
|
||||
})(req)
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.ImageList(context.Background(), tc.options)
|
||||
defer func() { _ = client.Close() }()
|
||||
|
||||
images, err := client.ImageList(t.Context(), tc.options)
|
||||
assert.NilError(t, err)
|
||||
expectedSet := tc.sharedSize != ""
|
||||
assert.Check(t, is.Equal(query.Has(sharedSize), expectedSet))
|
||||
assert.Check(t, is.Equal(query.Get(sharedSize), tc.sharedSize))
|
||||
assert.Check(t, is.Len(images.Items, 2))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -19,7 +18,7 @@ func TestImageLoadError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ImageLoad(context.Background(), nil, ImageLoadWithQuiet(true))
|
||||
_, err = client.ImageLoad(t.Context(), nil, ImageLoadWithQuiet(true))
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -81,7 +80,7 @@ func TestImageLoad(t *testing.T) {
|
||||
assert.NilError(t, err)
|
||||
|
||||
input := bytes.NewReader([]byte(expectedInput))
|
||||
imageLoadResponse, err := client.ImageLoad(context.Background(), input,
|
||||
imageLoadResponse, err := client.ImageLoad(t.Context(), input,
|
||||
ImageLoadWithQuiet(tc.quiet),
|
||||
ImageLoadWithPlatforms(tc.platforms...),
|
||||
)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -16,7 +15,7 @@ func TestImagePruneError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ImagePrune(context.Background(), ImagePruneOptions{})
|
||||
_, err = client.ImagePrune(t.Context(), ImagePruneOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -83,7 +82,7 @@ func TestImagePrune(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
res, err := client.ImagePrune(context.Background(), ImagePruneOptions{Filters: listCase.filters})
|
||||
res, err := client.ImagePrune(t.Context(), ImagePruneOptions{Filters: listCase.filters})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Len(res.Report.ImagesDeleted, 2))
|
||||
assert.Check(t, is.Equal(uint64(9999), res.Report.SpaceReclaimed))
|
||||
|
||||
@@ -23,28 +23,28 @@ func TestImagePullReferenceParseError(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
// An empty reference is an invalid reference
|
||||
_, err = client.ImagePull(context.Background(), "", ImagePullOptions{})
|
||||
_, err = client.ImagePull(t.Context(), "", ImagePullOptions{})
|
||||
assert.Check(t, is.ErrorContains(err, "invalid reference format"))
|
||||
}
|
||||
|
||||
func TestImagePullAnyError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.ImagePull(context.Background(), "myimage", ImagePullOptions{})
|
||||
_, err = client.ImagePull(t.Context(), "myimage", ImagePullOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
func TestImagePullStatusUnauthorizedError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusUnauthorized, "Unauthorized error")))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.ImagePull(context.Background(), "myimage", ImagePullOptions{})
|
||||
_, err = client.ImagePull(t.Context(), "myimage", ImagePullOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsUnauthorized))
|
||||
}
|
||||
|
||||
func TestImagePullWithUnauthorizedErrorAndPrivilegeFuncError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusUnauthorized, "Unauthorized error")))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.ImagePull(context.Background(), "myimage", ImagePullOptions{
|
||||
_, err = client.ImagePull(t.Context(), "myimage", ImagePullOptions{
|
||||
PrivilegeFunc: func(_ context.Context) (string, error) {
|
||||
return "", errors.New("error requesting privilege")
|
||||
},
|
||||
@@ -55,7 +55,7 @@ func TestImagePullWithUnauthorizedErrorAndPrivilegeFuncError(t *testing.T) {
|
||||
func TestImagePullWithUnauthorizedErrorAndAnotherUnauthorizedError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusUnauthorized, "Unauthorized error")))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.ImagePull(context.Background(), "myimage", ImagePullOptions{
|
||||
_, err = client.ImagePull(t.Context(), "myimage", ImagePullOptions{
|
||||
PrivilegeFunc: staticAuth("a-auth-header"),
|
||||
})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsUnauthorized))
|
||||
@@ -88,7 +88,7 @@ func TestImagePullWithPrivilegedFuncNoError(t *testing.T) {
|
||||
return mockResponse(http.StatusOK, nil, "hello world")(req)
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
resp, err := client.ImagePull(context.Background(), "myimage", ImagePullOptions{
|
||||
resp, err := client.ImagePull(t.Context(), "myimage", ImagePullOptions{
|
||||
RegistryAuth: invalidAuth,
|
||||
PrivilegeFunc: staticAuth(validAuth),
|
||||
})
|
||||
@@ -177,7 +177,7 @@ func TestImagePullWithoutErrors(t *testing.T) {
|
||||
return mockResponse(http.StatusOK, nil, expectedOutput)(req)
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
resp, err := client.ImagePull(context.Background(), pullCase.reference, ImagePullOptions{
|
||||
resp, err := client.ImagePull(t.Context(), pullCase.reference, ImagePullOptions{
|
||||
All: pullCase.all,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
@@ -20,24 +20,24 @@ func TestImagePushReferenceError(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
// An empty reference is an invalid reference
|
||||
_, err = client.ImagePush(context.Background(), "", ImagePushOptions{})
|
||||
_, err = client.ImagePush(t.Context(), "", ImagePushOptions{})
|
||||
assert.Check(t, is.ErrorContains(err, "invalid reference format"))
|
||||
// A canonical reference cannot be pushed
|
||||
_, err = client.ImagePush(context.Background(), "repo@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", ImagePushOptions{})
|
||||
_, err = client.ImagePush(t.Context(), "repo@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", ImagePushOptions{})
|
||||
assert.Check(t, is.Error(err, "cannot push a digest reference"))
|
||||
}
|
||||
|
||||
func TestImagePushAnyError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.ImagePush(context.Background(), "myimage", ImagePushOptions{})
|
||||
_, err = client.ImagePush(t.Context(), "myimage", ImagePushOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
func TestImagePushStatusUnauthorizedError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusUnauthorized, "Unauthorized error")))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.ImagePush(context.Background(), "myimage", ImagePushOptions{})
|
||||
_, err = client.ImagePush(t.Context(), "myimage", ImagePushOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsUnauthorized))
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ func TestImagePushWithUnauthorizedErrorAndPrivilegeFuncError(t *testing.T) {
|
||||
privilegeFunc := func(_ context.Context) (string, error) {
|
||||
return "", errors.New("error requesting privilege")
|
||||
}
|
||||
_, err = client.ImagePush(context.Background(), "myimage", ImagePushOptions{
|
||||
_, err = client.ImagePush(t.Context(), "myimage", ImagePushOptions{
|
||||
PrivilegeFunc: privilegeFunc,
|
||||
})
|
||||
assert.Check(t, is.Error(err, "error requesting privilege"))
|
||||
@@ -59,7 +59,7 @@ func TestImagePushWithUnauthorizedErrorAndAnotherUnauthorizedError(t *testing.T)
|
||||
privilegeFunc := func(_ context.Context) (string, error) {
|
||||
return "a-auth-header", nil
|
||||
}
|
||||
_, err = client.ImagePush(context.Background(), "myimage", ImagePushOptions{
|
||||
_, err = client.ImagePush(t.Context(), "myimage", ImagePushOptions{
|
||||
PrivilegeFunc: privilegeFunc,
|
||||
})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsUnauthorized))
|
||||
@@ -88,7 +88,7 @@ func TestImagePushWithPrivilegedFuncNoError(t *testing.T) {
|
||||
return mockResponse(http.StatusOK, nil, "hello world")(req)
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
resp, err := client.ImagePush(context.Background(), "myname/myimage:tag", ImagePushOptions{
|
||||
resp, err := client.ImagePush(t.Context(), "myname/myimage:tag", ImagePushOptions{
|
||||
RegistryAuth: invalidAuth,
|
||||
PrivilegeFunc: staticAuth(validAuth),
|
||||
})
|
||||
@@ -174,7 +174,7 @@ func TestImagePushWithoutErrors(t *testing.T) {
|
||||
return mockResponse(http.StatusOK, nil, expectedOutput)(req)
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
resp, err := client.ImagePush(context.Background(), tc.reference, ImagePushOptions{
|
||||
resp, err := client.ImagePush(t.Context(), tc.reference, ImagePushOptions{
|
||||
All: tc.all,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
@@ -17,7 +16,7 @@ func TestImageRemoveError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ImageRemove(context.Background(), "image_id", ImageRemoveOptions{})
|
||||
_, err = client.ImageRemove(t.Context(), "image_id", ImageRemoveOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -25,7 +24,7 @@ func TestImageRemoveImageNotFound(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusNotFound, "no such image: unknown")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ImageRemove(context.Background(), "unknown", ImageRemoveOptions{})
|
||||
_, err = client.ImageRemove(t.Context(), "unknown", ImageRemoveOptions{})
|
||||
assert.Check(t, is.ErrorContains(err, "no such image: unknown"))
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsNotFound))
|
||||
}
|
||||
@@ -91,7 +90,7 @@ func TestImageRemove(t *testing.T) {
|
||||
opts.Platforms = []ocispec.Platform{*removeCase.platform}
|
||||
}
|
||||
|
||||
res, err := client.ImageRemove(context.Background(), "image_id", opts)
|
||||
res, err := client.ImageRemove(t.Context(), "image_id", opts)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Len(res.Items, 2))
|
||||
}
|
||||
|
||||
@@ -16,14 +16,14 @@ import (
|
||||
func TestImageSearchAnyError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.ImageSearch(context.Background(), "some-image", ImageSearchOptions{})
|
||||
_, err = client.ImageSearch(t.Context(), "some-image", ImageSearchOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
func TestImageSearchStatusUnauthorizedError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusUnauthorized, "Unauthorized error")))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.ImageSearch(context.Background(), "some-image", ImageSearchOptions{})
|
||||
_, err = client.ImageSearch(t.Context(), "some-image", ImageSearchOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsUnauthorized))
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ func TestImageSearchWithUnauthorizedErrorAndPrivilegeFuncError(t *testing.T) {
|
||||
privilegeFunc := func(_ context.Context) (string, error) {
|
||||
return "", errors.New("Error requesting privilege")
|
||||
}
|
||||
_, err = client.ImageSearch(context.Background(), "some-image", ImageSearchOptions{
|
||||
_, err = client.ImageSearch(t.Context(), "some-image", ImageSearchOptions{
|
||||
PrivilegeFunc: privilegeFunc,
|
||||
})
|
||||
assert.Check(t, is.Error(err, "Error requesting privilege"))
|
||||
@@ -45,7 +45,7 @@ func TestImageSearchWithUnauthorizedErrorAndAnotherUnauthorizedError(t *testing.
|
||||
privilegeFunc := func(_ context.Context) (string, error) {
|
||||
return "a-auth-header", nil
|
||||
}
|
||||
_, err = client.ImageSearch(context.Background(), "some-image", ImageSearchOptions{
|
||||
_, err = client.ImageSearch(t.Context(), "some-image", ImageSearchOptions{
|
||||
PrivilegeFunc: privilegeFunc,
|
||||
})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsUnauthorized))
|
||||
@@ -77,7 +77,7 @@ func TestImageSearchWithPrivilegedFuncNoError(t *testing.T) {
|
||||
privilegeFunc := func(_ context.Context) (string, error) {
|
||||
return "IAmValid", nil
|
||||
}
|
||||
results, err := client.ImageSearch(context.Background(), "some-image", ImageSearchOptions{
|
||||
results, err := client.ImageSearch(t.Context(), "some-image", ImageSearchOptions{
|
||||
RegistryAuth: "NotValid",
|
||||
PrivilegeFunc: privilegeFunc,
|
||||
})
|
||||
@@ -107,7 +107,7 @@ func TestImageSearchWithoutErrors(t *testing.T) {
|
||||
})(req)
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
results, err := client.ImageSearch(context.Background(), "some-image", ImageSearchOptions{
|
||||
results, err := client.ImageSearch(t.Context(), "some-image", ImageSearchOptions{
|
||||
Filters: make(Filters).Add("is-automated", "true").Add("stars", "3"),
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
@@ -16,7 +15,7 @@ func TestImageTagError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ImageTag(context.Background(), ImageTagOptions{Source: "image_id", Target: "repo:tag"})
|
||||
_, err = client.ImageTag(t.Context(), ImageTagOptions{Source: "image_id", Target: "repo:tag"})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -26,13 +25,13 @@ func TestImageTagInvalidReference(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ImageTag(context.Background(), ImageTagOptions{Source: "image_id", Target: "aa/asdf$$^/aa"})
|
||||
_, err = client.ImageTag(t.Context(), ImageTagOptions{Source: "image_id", Target: "aa/asdf$$^/aa"})
|
||||
assert.Check(t, is.Error(err, `error parsing reference: "aa/asdf$$^/aa" is not a valid repository/tag: invalid reference format`))
|
||||
}
|
||||
|
||||
// Ensure we don't allow the use of invalid repository names or tags; these tag operations should fail.
|
||||
func TestImageTagInvalidSourceImageName(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "client should not have made an API call")))
|
||||
assert.NilError(t, err)
|
||||
@@ -89,7 +88,7 @@ func TestImageTagHexSource(t *testing.T) {
|
||||
client, err := New(WithMockClient(mockResponse(http.StatusOK, nil, "OK")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ImageTag(context.Background(), ImageTagOptions{Source: "0d409d33b27e47423b049f7f863faa08655a8c901749c2b25b93ca67d01a470d", Target: "repo:tag"})
|
||||
_, err = client.ImageTag(t.Context(), ImageTagOptions{Source: "0d409d33b27e47423b049f7f863faa08655a8c901749c2b25b93ca67d01a470d", Target: "repo:tag"})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
@@ -164,7 +163,7 @@ func TestImageTag(t *testing.T) {
|
||||
return mockResponse(http.StatusOK, nil, "")(req)
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.ImageTag(context.Background(), ImageTagOptions{Source: "image_id", Target: tagCase.reference})
|
||||
_, err = client.ImageTag(t.Context(), ImageTagOptions{Source: "image_id", Target: tagCase.reference})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
@@ -17,19 +16,19 @@ func TestNetworkConnectError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.NetworkConnect(context.Background(), "network_id", NetworkConnectOptions{
|
||||
_, err = client.NetworkConnect(t.Context(), "network_id", NetworkConnectOptions{
|
||||
Container: "container_id",
|
||||
})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
// Empty network ID or container ID
|
||||
_, err = client.NetworkConnect(context.Background(), "", NetworkConnectOptions{
|
||||
_, err = client.NetworkConnect(t.Context(), "", NetworkConnectOptions{
|
||||
Container: "container_id",
|
||||
})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.NetworkConnect(context.Background(), "network_id", NetworkConnectOptions{})
|
||||
_, err = client.NetworkConnect(t.Context(), "network_id", NetworkConnectOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -59,7 +58,7 @@ func TestNetworkConnectEmptyNilEndpointSettings(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.NetworkConnect(context.Background(), "network_id", NetworkConnectOptions{
|
||||
_, err = client.NetworkConnect(t.Context(), "network_id", NetworkConnectOptions{
|
||||
Container: "container_id",
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
@@ -94,7 +93,7 @@ func TestNetworkConnect(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.NetworkConnect(context.Background(), "network_id", NetworkConnectOptions{
|
||||
_, err = client.NetworkConnect(t.Context(), "network_id", NetworkConnectOptions{
|
||||
Container: "container_id",
|
||||
EndpointConfig: &network.EndpointSettings{
|
||||
NetworkID: "NetworkID",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -15,7 +14,7 @@ func TestNetworkCreateError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.NetworkCreate(context.Background(), "mynetwork", NetworkCreateOptions{})
|
||||
_, err = client.NetworkCreate(t.Context(), "mynetwork", NetworkCreateOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -24,10 +23,10 @@ func TestNetworkCreateError(t *testing.T) {
|
||||
//
|
||||
// Regression test for https://github.com/docker/cli/issues/4890
|
||||
func TestNetworkCreateConnectionError(t *testing.T) {
|
||||
client, err := New(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
|
||||
client, err := New(WithHost("tcp://no-such-host.invalid"))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.NetworkCreate(context.Background(), "mynetwork", NetworkCreateOptions{})
|
||||
_, err = client.NetworkCreate(t.Context(), "mynetwork", NetworkCreateOptions{})
|
||||
assert.Check(t, is.ErrorType(err, IsErrConnectionFailed))
|
||||
}
|
||||
|
||||
@@ -46,7 +45,7 @@ func TestNetworkCreate(t *testing.T) {
|
||||
assert.NilError(t, err)
|
||||
|
||||
enableIPv6 := true
|
||||
networkResponse, err := client.NetworkCreate(context.Background(), "mynetwork", NetworkCreateOptions{
|
||||
networkResponse, err := client.NetworkCreate(t.Context(), "mynetwork", NetworkCreateOptions{
|
||||
Driver: "mydriver",
|
||||
EnableIPv6: &enableIPv6,
|
||||
Internal: true,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
@@ -17,19 +16,19 @@ func TestNetworkDisconnectError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.NetworkDisconnect(context.Background(), "network_id", NetworkDisconnectOptions{
|
||||
_, err = client.NetworkDisconnect(t.Context(), "network_id", NetworkDisconnectOptions{
|
||||
Container: "container_id",
|
||||
})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
// Empty network ID or container ID
|
||||
_, err = client.NetworkDisconnect(context.Background(), "", NetworkDisconnectOptions{
|
||||
_, err = client.NetworkDisconnect(t.Context(), "", NetworkDisconnectOptions{
|
||||
Container: "container_id",
|
||||
})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.NetworkDisconnect(context.Background(), "network_id", NetworkDisconnectOptions{})
|
||||
_, err = client.NetworkDisconnect(t.Context(), "network_id", NetworkDisconnectOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -59,6 +58,6 @@ func TestNetworkDisconnect(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.NetworkDisconnect(context.Background(), "network_id", NetworkDisconnectOptions{Container: "container_id", Force: true})
|
||||
_, err = client.NetworkDisconnect(t.Context(), "network_id", NetworkDisconnectOptions{Container: "container_id", Force: true})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -52,39 +51,39 @@ func TestNetworkInspect(t *testing.T) {
|
||||
|
||||
t.Run("empty ID", func(t *testing.T) {
|
||||
// verify that the client does not create a request if the network-ID/name is empty.
|
||||
_, err := client.NetworkInspect(context.Background(), "", NetworkInspectOptions{})
|
||||
_, err := client.NetworkInspect(t.Context(), "", NetworkInspectOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.NetworkInspect(context.Background(), " ", NetworkInspectOptions{})
|
||||
_, err = client.NetworkInspect(t.Context(), " ", NetworkInspectOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
})
|
||||
t.Run("no options", func(t *testing.T) {
|
||||
r, err := client.NetworkInspect(context.Background(), "network_id", NetworkInspectOptions{})
|
||||
r, err := client.NetworkInspect(t.Context(), "network_id", NetworkInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(r.Network.Name, "mynetwork"))
|
||||
})
|
||||
t.Run("verbose", func(t *testing.T) {
|
||||
r, err := client.NetworkInspect(context.Background(), "network_id", NetworkInspectOptions{Verbose: true})
|
||||
r, err := client.NetworkInspect(t.Context(), "network_id", NetworkInspectOptions{Verbose: true})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(r.Network.Name, "mynetwork"))
|
||||
_, ok := r.Network.Services["web"]
|
||||
assert.Check(t, ok, "expected service `web` missing in the verbose output")
|
||||
})
|
||||
t.Run("global scope", func(t *testing.T) {
|
||||
_, err := client.NetworkInspect(context.Background(), "network_id", NetworkInspectOptions{Scope: "global"})
|
||||
_, err := client.NetworkInspect(t.Context(), "network_id", NetworkInspectOptions{Scope: "global"})
|
||||
assert.Check(t, is.ErrorContains(err, "Error: No such network: network_id"))
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsNotFound))
|
||||
})
|
||||
t.Run("unknown network", func(t *testing.T) {
|
||||
_, err := client.NetworkInspect(context.Background(), "unknown", NetworkInspectOptions{})
|
||||
_, err := client.NetworkInspect(t.Context(), "unknown", NetworkInspectOptions{})
|
||||
assert.Check(t, is.ErrorContains(err, "Error: No such network: unknown"))
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsNotFound))
|
||||
})
|
||||
t.Run("server error", func(t *testing.T) {
|
||||
// Just testing that an internal server error is converted correctly by the client
|
||||
_, err := client.NetworkInspect(context.Background(), "test-500-response", NetworkInspectOptions{})
|
||||
_, err := client.NetworkInspect(t.Context(), "test-500-response", NetworkInspectOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
@@ -16,7 +15,7 @@ func TestNetworkListError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.NetworkList(context.Background(), NetworkListOptions{})
|
||||
_, err = client.NetworkList(t.Context(), NetworkListOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -74,7 +73,7 @@ func TestNetworkList(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
res, err := client.NetworkList(context.Background(), listCase.options)
|
||||
res, err := client.NetworkList(t.Context(), listCase.options)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Len(res.Items, 1))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -17,7 +16,7 @@ func TestNetworkPruneError(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.NetworkPrune(context.Background(), NetworkPruneOptions{})
|
||||
_, err = client.NetworkPrune(t.Context(), NetworkPruneOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -82,7 +81,7 @@ func TestNetworkPrune(t *testing.T) {
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
res, err := client.NetworkPrune(context.Background(), NetworkPruneOptions{Filters: listCase.filters})
|
||||
res, err := client.NetworkPrune(t.Context(), NetworkPruneOptions{Filters: listCase.filters})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Len(res.Report.NetworksDeleted, 2))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -14,14 +13,14 @@ func TestNetworkRemoveError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.NetworkRemove(context.Background(), "network_id", NetworkRemoveOptions{})
|
||||
_, err = client.NetworkRemove(t.Context(), "network_id", NetworkRemoveOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
_, err = client.NetworkRemove(context.Background(), "", NetworkRemoveOptions{})
|
||||
_, err = client.NetworkRemove(t.Context(), "", NetworkRemoveOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.NetworkRemove(context.Background(), " ", NetworkRemoveOptions{})
|
||||
_, err = client.NetworkRemove(t.Context(), " ", NetworkRemoveOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -37,6 +36,6 @@ func TestNetworkRemove(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.NetworkRemove(context.Background(), "network_id", NetworkRemoveOptions{})
|
||||
_, err = client.NetworkRemove(t.Context(), "network_id", NetworkRemoveOptions{})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"testing"
|
||||
@@ -16,7 +15,7 @@ func TestNodeInspectError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.NodeInspect(context.Background(), "nothing", NodeInspectOptions{})
|
||||
_, err = client.NodeInspect(t.Context(), "nothing", NodeInspectOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -24,7 +23,7 @@ func TestNodeInspectNodeNotFound(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusNotFound, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.NodeInspect(context.Background(), "unknown", NodeInspectOptions{})
|
||||
_, err = client.NodeInspect(t.Context(), "unknown", NodeInspectOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsNotFound))
|
||||
}
|
||||
|
||||
@@ -33,11 +32,11 @@ func TestNodeInspectWithEmptyID(t *testing.T) {
|
||||
return nil, errors.New("should not make request")
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.NodeInspect(context.Background(), "", NodeInspectOptions{})
|
||||
_, err = client.NodeInspect(t.Context(), "", NodeInspectOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.NodeInspect(context.Background(), " ", NodeInspectOptions{})
|
||||
_, err = client.NodeInspect(t.Context(), " ", NodeInspectOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -54,7 +53,7 @@ func TestNodeInspect(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
result, err := client.NodeInspect(context.Background(), "node_id", NodeInspectOptions{})
|
||||
result, err := client.NodeInspect(t.Context(), "node_id", NodeInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(result.Node.ID, "node_id"))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
@@ -16,7 +15,7 @@ func TestNodeListError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.NodeList(context.Background(), NodeListOptions{})
|
||||
_, err = client.NodeList(t.Context(), NodeListOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -62,7 +61,7 @@ func TestNodeList(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
result, err := client.NodeList(context.Background(), listCase.options)
|
||||
result, err := client.NodeList(t.Context(), listCase.options)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Len(result.Items, 2))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
@@ -15,14 +14,14 @@ func TestNodeRemoveError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.NodeRemove(context.Background(), "node_id", NodeRemoveOptions{Force: false})
|
||||
_, err = client.NodeRemove(t.Context(), "node_id", NodeRemoveOptions{Force: false})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
_, err = client.NodeRemove(context.Background(), "", NodeRemoveOptions{Force: false})
|
||||
_, err = client.NodeRemove(t.Context(), "", NodeRemoveOptions{Force: false})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.NodeRemove(context.Background(), " ", NodeRemoveOptions{Force: false})
|
||||
_, err = client.NodeRemove(t.Context(), " ", NodeRemoveOptions{Force: false})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -57,7 +56,7 @@ func TestNodeRemove(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.NodeRemove(context.Background(), "node_id", NodeRemoveOptions{Force: removeCase.force})
|
||||
_, err = client.NodeRemove(t.Context(), "node_id", NodeRemoveOptions{Force: removeCase.force})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -15,20 +14,20 @@ func TestNodeUpdateError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.NodeUpdate(context.Background(), "node_id", NodeUpdateOptions{
|
||||
_, err = client.NodeUpdate(t.Context(), "node_id", NodeUpdateOptions{
|
||||
Version: swarm.Version{},
|
||||
Spec: swarm.NodeSpec{},
|
||||
})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
_, err = client.NodeUpdate(context.Background(), "", NodeUpdateOptions{
|
||||
_, err = client.NodeUpdate(t.Context(), "", NodeUpdateOptions{
|
||||
Version: swarm.Version{},
|
||||
Spec: swarm.NodeSpec{},
|
||||
})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.NodeUpdate(context.Background(), " ", NodeUpdateOptions{
|
||||
_, err = client.NodeUpdate(t.Context(), " ", NodeUpdateOptions{
|
||||
Version: swarm.Version{},
|
||||
Spec: swarm.NodeSpec{},
|
||||
})
|
||||
@@ -47,7 +46,7 @@ func TestNodeUpdate(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.NodeUpdate(context.Background(), "node_id", NodeUpdateOptions{
|
||||
_, err = client.NodeUpdate(t.Context(), "node_id", NodeUpdateOptions{
|
||||
Version: swarm.Version{},
|
||||
Spec: swarm.NodeSpec{},
|
||||
})
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestOptionWithHostFromEnv(t *testing.T) {
|
||||
c, err := New(WithHostFromEnv())
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, c.client != nil)
|
||||
assert.Check(t, is.Equal(c.basePath, ""))
|
||||
if runtime.GOOS == "windows" {
|
||||
assert.Check(t, is.Equal(c.host, "npipe:////./pipe/docker_engine"))
|
||||
assert.Check(t, is.Equal(c.proto, "npipe"))
|
||||
assert.Check(t, is.Equal(c.addr, "//./pipe/docker_engine"))
|
||||
} else {
|
||||
assert.Check(t, is.Equal(c.host, "unix:///var/run/docker.sock"))
|
||||
assert.Check(t, is.Equal(c.proto, "unix"))
|
||||
assert.Check(t, is.Equal(c.addr, "/var/run/docker.sock"))
|
||||
}
|
||||
|
||||
t.Setenv("DOCKER_HOST", "tcp://foo.example.com:2376/test/")
|
||||
|
||||
c, err = New(WithHostFromEnv())
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, c.client != nil)
|
||||
assert.Check(t, is.Equal(c.basePath, "/test/"))
|
||||
assert.Check(t, is.Equal(c.host, "tcp://foo.example.com:2376/test/"))
|
||||
assert.Check(t, is.Equal(c.proto, "tcp"))
|
||||
assert.Check(t, is.Equal(c.addr, "foo.example.com:2376"))
|
||||
}
|
||||
|
||||
func TestOptionWithTimeout(t *testing.T) {
|
||||
timeout := 10 * time.Second
|
||||
c, err := New(WithTimeout(timeout))
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, c.client != nil)
|
||||
assert.Check(t, is.Equal(c.client.Timeout, timeout))
|
||||
}
|
||||
|
||||
func TestOptionWithVersionFromEnv(t *testing.T) {
|
||||
c, err := New(WithVersionFromEnv())
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, c.client != nil)
|
||||
assert.Check(t, is.Equal(c.version, MaxAPIVersion))
|
||||
assert.Check(t, is.Equal(c.manualOverride, false))
|
||||
|
||||
t.Setenv("DOCKER_API_VERSION", "2.9999")
|
||||
|
||||
c, err = New(WithVersionFromEnv())
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, c.client != nil)
|
||||
assert.Check(t, is.Equal(c.version, "2.9999"))
|
||||
assert.Check(t, is.Equal(c.manualOverride, true))
|
||||
}
|
||||
|
||||
func TestWithUserAgent(t *testing.T) {
|
||||
const userAgent = "Magic-Client/v1.2.3"
|
||||
t.Run("user-agent", func(t *testing.T) {
|
||||
c, err := New(
|
||||
WithUserAgent(userAgent),
|
||||
WithMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
assert.Check(t, is.Equal(req.Header.Get("User-Agent"), userAgent))
|
||||
return &http.Response{StatusCode: http.StatusOK}, nil
|
||||
}),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
_, err = c.Ping(t.Context(), PingOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.NilError(t, c.Close())
|
||||
})
|
||||
t.Run("user-agent and custom headers", func(t *testing.T) {
|
||||
c, err := New(
|
||||
WithUserAgent(userAgent),
|
||||
WithHTTPHeaders(map[string]string{"User-Agent": "should-be-ignored/1.0.0", "Other-Header": "hello-world"}),
|
||||
WithMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
assert.Check(t, is.Equal(req.Header.Get("User-Agent"), userAgent))
|
||||
assert.Check(t, is.Equal(req.Header.Get("Other-Header"), "hello-world"))
|
||||
return &http.Response{StatusCode: http.StatusOK}, nil
|
||||
}),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
_, err = c.Ping(t.Context(), PingOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.NilError(t, c.Close())
|
||||
})
|
||||
t.Run("custom headers", func(t *testing.T) {
|
||||
c, err := New(
|
||||
WithHTTPHeaders(map[string]string{"User-Agent": "from-custom-headers/1.0.0", "Other-Header": "hello-world"}),
|
||||
WithMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
assert.Check(t, is.Equal(req.Header.Get("User-Agent"), "from-custom-headers/1.0.0"))
|
||||
assert.Check(t, is.Equal(req.Header.Get("Other-Header"), "hello-world"))
|
||||
return &http.Response{StatusCode: http.StatusOK}, nil
|
||||
}),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
_, err = c.Ping(t.Context(), PingOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.NilError(t, c.Close())
|
||||
})
|
||||
t.Run("no user-agent set", func(t *testing.T) {
|
||||
c, err := New(
|
||||
WithHTTPHeaders(map[string]string{"Other-Header": "hello-world"}),
|
||||
WithMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
assert.Check(t, is.Equal(req.Header.Get("User-Agent"), ""))
|
||||
assert.Check(t, is.Equal(req.Header.Get("Other-Header"), "hello-world"))
|
||||
return &http.Response{StatusCode: http.StatusOK}, nil
|
||||
}),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
_, err = c.Ping(t.Context(), PingOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.NilError(t, c.Close())
|
||||
})
|
||||
t.Run("reset custom user-agent", func(t *testing.T) {
|
||||
c, err := New(
|
||||
WithUserAgent(""),
|
||||
WithHTTPHeaders(map[string]string{"User-Agent": "from-custom-headers/1.0.0", "Other-Header": "hello-world"}),
|
||||
WithMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
assert.Check(t, is.Equal(req.Header.Get("User-Agent"), ""))
|
||||
assert.Check(t, is.Equal(req.Header.Get("Other-Header"), "hello-world"))
|
||||
return &http.Response{StatusCode: http.StatusOK}, nil
|
||||
}),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
_, err = c.Ping(t.Context(), PingOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.NilError(t, c.Close())
|
||||
})
|
||||
}
|
||||
@@ -20,7 +20,7 @@ type PingOptions struct {
|
||||
//
|
||||
// If a manual override is in place, either through the "DOCKER_API_VERSION"
|
||||
// ([EnvOverrideAPIVersion]) environment variable, or if the client is initialized
|
||||
// with a fixed version ([WithVersion]), no negotiation is performed.
|
||||
// with a fixed version ([WithAPIVersion]), no negotiation is performed.
|
||||
//
|
||||
// If the API server's ping response does not contain an API version, or if the
|
||||
// client did not get a successful ping response, it assumes it is connected with
|
||||
@@ -29,9 +29,8 @@ type PingOptions struct {
|
||||
NegotiateAPIVersion bool
|
||||
|
||||
// ForceNegotiate forces the client to re-negotiate the API version, even if
|
||||
// API-version negotiation already happened. This option cannot be
|
||||
// used if the client is configured with a fixed version using (using
|
||||
// [WithVersion] or [WithVersionFromEnv]).
|
||||
// API-version negotiation already happened or it the client is configured
|
||||
// with a fixed version (using [WithAPIVersion] or [WithAPIVersionFromEnv]).
|
||||
//
|
||||
// This option has no effect if NegotiateAPIVersion is not set.
|
||||
ForceNegotiate bool
|
||||
@@ -72,10 +71,12 @@ type SwarmStatus struct {
|
||||
// for other non-success status codes, failing to connect to the API, or failing
|
||||
// to parse the API response.
|
||||
func (cli *Client) Ping(ctx context.Context, options PingOptions) (PingResult, error) {
|
||||
if cli.manualOverride {
|
||||
if !options.NegotiateAPIVersion {
|
||||
// No API version negotiation needed; just return ping response.
|
||||
return cli.ping(ctx)
|
||||
}
|
||||
if !options.NegotiateAPIVersion && !cli.negotiateVersion {
|
||||
if cli.negotiated.Load() && !options.ForceNegotiate {
|
||||
// API version was already negotiated or manually set.
|
||||
return cli.ping(ctx)
|
||||
}
|
||||
|
||||
@@ -85,10 +86,19 @@ func (cli *Client) Ping(ctx context.Context, options PingOptions) (PingResult, e
|
||||
|
||||
ping, err := cli.ping(ctx)
|
||||
if err != nil {
|
||||
return cli.ping(ctx)
|
||||
return ping, err
|
||||
}
|
||||
|
||||
if cli.negotiated.Load() && !options.ForceNegotiate {
|
||||
// API version was already negotiated or manually set.
|
||||
//
|
||||
// We check cli.negotiated again under lock, to account for race
|
||||
// conditions with the check at the start of this function.
|
||||
return ping, nil
|
||||
}
|
||||
|
||||
if ping.APIVersion == "" {
|
||||
cli.setAPIVersion(MaxAPIVersion)
|
||||
return ping, nil
|
||||
}
|
||||
|
||||
@@ -112,10 +122,15 @@ func (cli *Client) ping(ctx context.Context) (PingResult, error) {
|
||||
// response-body to get error details from.
|
||||
return newPingResult(resp), nil
|
||||
}
|
||||
// close to allow reusing connection.
|
||||
ensureReaderClosed(resp)
|
||||
|
||||
// HEAD failed or returned a non-OK status; fallback to GET.
|
||||
req.Method = http.MethodGet
|
||||
resp, err = cli.doRequest(req)
|
||||
req2, err := cli.buildRequest(ctx, http.MethodGet, path.Join(cli.basePath, "/_ping"), nil, nil)
|
||||
if err != nil {
|
||||
return PingResult{}, err
|
||||
}
|
||||
resp, err = cli.doRequest(req2)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
// Failed to connect.
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
// panics.
|
||||
func TestPingFail(t *testing.T) {
|
||||
var withHeader bool
|
||||
client, err := New(WithMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
client, err := New(WithBaseMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
var hdr http.Header
|
||||
if withHeader {
|
||||
hdr = http.Header{}
|
||||
@@ -48,7 +48,7 @@ func TestPingFail(t *testing.T) {
|
||||
// TestPingWithError tests the case where there is a protocol error in the ping.
|
||||
// This test is mostly just testing that there are no panics in this code path.
|
||||
func TestPingWithError(t *testing.T) {
|
||||
client, err := New(WithMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
client, err := New(WithBaseMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
return nil, errors.New("some connection error")
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
@@ -64,7 +64,7 @@ func TestPingWithError(t *testing.T) {
|
||||
// TestPingSuccess tests that we are able to get the expected API headers/ping
|
||||
// details on success.
|
||||
func TestPingSuccess(t *testing.T) {
|
||||
client, err := New(WithMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
client, err := New(WithBaseMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
hdr := http.Header{}
|
||||
hdr.Set("Api-Version", "awesome")
|
||||
hdr.Set("Docker-Experimental", "true")
|
||||
@@ -76,6 +76,7 @@ func TestPingSuccess(t *testing.T) {
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(true, ping.Experimental))
|
||||
assert.Check(t, is.Equal("awesome", ping.APIVersion))
|
||||
assert.Check(t, is.Equal(MaxAPIVersion, client.version))
|
||||
assert.Check(t, is.Equal(SwarmStatus{NodeState: "active", ControlAvailable: true}, *ping.SwarmStatus))
|
||||
}
|
||||
|
||||
@@ -109,7 +110,7 @@ func TestPingHeadFallback(t *testing.T) {
|
||||
for _, tc := range tests {
|
||||
t.Run(http.StatusText(tc.status), func(t *testing.T) {
|
||||
var reqs []string
|
||||
client, err := New(WithMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
client, err := New(WithBaseMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
if !strings.HasPrefix(req.URL.Path, expectedPath) {
|
||||
return nil, fmt.Errorf("expected URL '%s', got '%s'", expectedPath, req.URL.Path)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -14,14 +13,14 @@ func TestPluginDisableError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.PluginDisable(context.Background(), "plugin_name", PluginDisableOptions{})
|
||||
_, err = client.PluginDisable(t.Context(), "plugin_name", PluginDisableOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
_, err = client.PluginDisable(context.Background(), "", PluginDisableOptions{})
|
||||
_, err = client.PluginDisable(t.Context(), "", PluginDisableOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.PluginDisable(context.Background(), " ", PluginDisableOptions{})
|
||||
_, err = client.PluginDisable(t.Context(), " ", PluginDisableOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -37,6 +36,6 @@ func TestPluginDisable(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.PluginDisable(context.Background(), "plugin_name", PluginDisableOptions{})
|
||||
_, err = client.PluginDisable(t.Context(), "plugin_name", PluginDisableOptions{})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -14,14 +13,14 @@ func TestPluginEnableError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.PluginEnable(context.Background(), "plugin_name", PluginEnableOptions{})
|
||||
_, err = client.PluginEnable(t.Context(), "plugin_name", PluginEnableOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
_, err = client.PluginEnable(context.Background(), "", PluginEnableOptions{})
|
||||
_, err = client.PluginEnable(t.Context(), "", PluginEnableOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.PluginEnable(context.Background(), " ", PluginEnableOptions{})
|
||||
_, err = client.PluginEnable(t.Context(), " ", PluginEnableOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -37,6 +36,6 @@ func TestPluginEnable(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.PluginEnable(context.Background(), "plugin_name", PluginEnableOptions{})
|
||||
_, err = client.PluginEnable(t.Context(), "plugin_name", PluginEnableOptions{})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
@@ -16,7 +15,7 @@ func TestPluginListError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.PluginList(context.Background(), PluginListOptions{})
|
||||
_, err = client.PluginList(t.Context(), PluginListOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -71,7 +70,7 @@ func TestPluginList(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
list, err := client.PluginList(context.Background(), PluginListOptions{
|
||||
list, err := client.PluginList(t.Context(), PluginListOptions{
|
||||
Filters: listCase.filters,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
@@ -16,14 +15,14 @@ func TestPluginPushError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.PluginPush(context.Background(), "plugin_name", PluginPushOptions{})
|
||||
_, err = client.PluginPush(t.Context(), "plugin_name", PluginPushOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
_, err = client.PluginPush(context.Background(), "", PluginPushOptions{})
|
||||
_, err = client.PluginPush(t.Context(), "", PluginPushOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.PluginPush(context.Background(), " ", PluginPushOptions{})
|
||||
_, err = client.PluginPush(t.Context(), " ", PluginPushOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -43,6 +42,6 @@ func TestPluginPush(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.PluginPush(context.Background(), "plugin_name", PluginPushOptions{RegistryAuth: "authtoken"})
|
||||
_, err = client.PluginPush(t.Context(), "plugin_name", PluginPushOptions{RegistryAuth: "authtoken"})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -14,14 +13,14 @@ func TestPluginRemoveError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.PluginRemove(context.Background(), "plugin_name", PluginRemoveOptions{})
|
||||
_, err = client.PluginRemove(t.Context(), "plugin_name", PluginRemoveOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
_, err = client.PluginRemove(context.Background(), "", PluginRemoveOptions{})
|
||||
_, err = client.PluginRemove(t.Context(), "", PluginRemoveOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.PluginRemove(context.Background(), " ", PluginRemoveOptions{})
|
||||
_, err = client.PluginRemove(t.Context(), " ", PluginRemoveOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -37,6 +36,6 @@ func TestPluginRemove(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.PluginRemove(context.Background(), "plugin_name", PluginRemoveOptions{})
|
||||
_, err = client.PluginRemove(t.Context(), "plugin_name", PluginRemoveOptions{})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -14,14 +13,14 @@ func TestPluginSetError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.PluginSet(context.Background(), "plugin_name", PluginSetOptions{})
|
||||
_, err = client.PluginSet(t.Context(), "plugin_name", PluginSetOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
_, err = client.PluginSet(context.Background(), "", PluginSetOptions{})
|
||||
_, err = client.PluginSet(t.Context(), "", PluginSetOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.PluginSet(context.Background(), " ", PluginSetOptions{})
|
||||
_, err = client.PluginSet(t.Context(), " ", PluginSetOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -37,6 +36,6 @@ func TestPluginSet(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.PluginSet(context.Background(), "plugin_name", PluginSetOptions{Args: []string{"arg1"}})
|
||||
_, err = client.PluginSet(t.Context(), "plugin_name", PluginSetOptions{Args: []string{"arg1"}})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
@@ -67,31 +67,22 @@ func (cli *Client) delete(ctx context.Context, path string, query url.Values, he
|
||||
// prepareJSONRequest encodes the given body to JSON and returns it as an [io.Reader], and sets the Content-Type
|
||||
// header. If body is nil, or a nil-interface, a "nil" body is returned without
|
||||
// error.
|
||||
//
|
||||
// TODO(thaJeztah): should this return an error if a different Content-Type is already set?
|
||||
// TODO(thaJeztah): is "nil" the appropriate approach for an empty body, or should we use [http.NoBody] (or similar)?
|
||||
func prepareJSONRequest(body any, headers http.Header) (io.Reader, http.Header, error) {
|
||||
if body == nil {
|
||||
return nil, headers, nil
|
||||
}
|
||||
// encoding/json encodes a nil pointer as the JSON document `null`,
|
||||
// irrespective of whether the type implements json.Marshaler or encoding.TextMarshaler.
|
||||
// That is almost certainly not what the caller intended as the request body.
|
||||
//
|
||||
// TODO(thaJeztah): consider moving this to jsonEncode, which would also allow returning an (empty) reader instead of nil.
|
||||
if reflect.TypeOf(body).Kind() == reflect.Ptr && reflect.ValueOf(body).IsNil() {
|
||||
return nil, headers, nil
|
||||
}
|
||||
|
||||
jsonBody, err := jsonEncode(body)
|
||||
if err != nil {
|
||||
return nil, headers, err
|
||||
}
|
||||
if jsonBody == nil || jsonBody == http.NoBody {
|
||||
// no content-type is set on empty requests.
|
||||
return jsonBody, headers, nil
|
||||
}
|
||||
|
||||
hdr := http.Header{}
|
||||
if headers != nil {
|
||||
hdr = headers.Clone()
|
||||
}
|
||||
|
||||
// TODO(thaJeztah): should this return an error if a different Content-Type is already set?
|
||||
hdr.Set("Content-Type", "application/json")
|
||||
return jsonBody, hdr, nil
|
||||
}
|
||||
@@ -110,9 +101,6 @@ func (cli *Client) buildRequest(ctx context.Context, method, path string, body i
|
||||
req.Host = DummyHost
|
||||
}
|
||||
|
||||
if body != nil && req.Header.Get("Content-Type") == "" {
|
||||
req.Header.Set("Content-Type", "text/plain")
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
@@ -248,7 +236,11 @@ func checkResponseErr(serverResp *http.Response) (retErr error) {
|
||||
if statusMsg == "" {
|
||||
statusMsg = http.StatusText(serverResp.StatusCode)
|
||||
}
|
||||
if serverResp.Body != nil {
|
||||
var reqMethod string
|
||||
if serverResp.Request != nil {
|
||||
reqMethod = serverResp.Request.Method
|
||||
}
|
||||
if serverResp.Body != nil && reqMethod != http.MethodHead {
|
||||
bodyMax := 1 * 1024 * 1024 // 1 MiB
|
||||
bodyR := &io.LimitedReader{
|
||||
R: serverResp.Body,
|
||||
@@ -333,25 +325,49 @@ func (cli *Client) addHeaders(req *http.Request, headers http.Header) *http.Requ
|
||||
}
|
||||
|
||||
func jsonEncode(data any) (io.Reader, error) {
|
||||
var params bytes.Buffer
|
||||
if data != nil {
|
||||
if err := json.NewEncoder(¶ms).Encode(data); err != nil {
|
||||
return nil, err
|
||||
switch x := data.(type) {
|
||||
case nil:
|
||||
return http.NoBody, nil
|
||||
case io.Reader:
|
||||
// http.NoBody or other readers
|
||||
return x, nil
|
||||
case json.RawMessage:
|
||||
if len(x) == 0 {
|
||||
return http.NoBody, nil
|
||||
}
|
||||
return bytes.NewReader(x), nil
|
||||
}
|
||||
return ¶ms, nil
|
||||
|
||||
// encoding/json encodes a nil pointer as the JSON document `null`,
|
||||
// irrespective of whether the type implements json.Marshaler or encoding.TextMarshaler.
|
||||
// That is almost certainly not what the caller intended as the request body.
|
||||
if v := reflect.ValueOf(data); v.Kind() == reflect.Ptr && v.IsNil() {
|
||||
return http.NoBody, nil
|
||||
}
|
||||
|
||||
b, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bytes.NewReader(b), nil
|
||||
}
|
||||
|
||||
func ensureReaderClosed(response *http.Response) {
|
||||
if response != nil && response.Body != nil {
|
||||
// Drain up to 512 bytes and close the body to let the Transport reuse the connection
|
||||
// see https://github.com/google/go-github/pull/317/files#r57536827
|
||||
//
|
||||
// TODO(thaJeztah): see if this optimization is still needed, or already implemented in stdlib,
|
||||
// and check if context-cancellation should handle this as well. If still needed, consider
|
||||
// wrapping response.Body, or returning a "closer()" from [Client.sendRequest] and related
|
||||
// methods.
|
||||
_, _ = io.CopyN(io.Discard, response.Body, 512)
|
||||
_ = response.Body.Close()
|
||||
if response == nil || response.Body == nil {
|
||||
return
|
||||
}
|
||||
if response.ContentLength == 0 || (response.Request != nil && response.Request.Method == http.MethodHead) {
|
||||
// No need to drain head requests or zero-length responses.
|
||||
_ = response.Body.Close()
|
||||
return
|
||||
}
|
||||
// Drain up to 512 bytes and close the body to let the Transport reuse the connection
|
||||
// see https://github.com/google/go-github/pull/317/files#r57536827
|
||||
//
|
||||
// TODO(thaJeztah): see if this optimization is still needed, or already implemented in stdlib,
|
||||
// and check if context-cancellation should handle this as well. If still needed, consider
|
||||
// wrapping response.Body, or returning a "closer()" from [Client.sendRequest] and related
|
||||
// methods.
|
||||
_, _ = io.CopyN(io.Discard, response.Body, 512)
|
||||
_ = response.Body.Close()
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"io"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -64,7 +63,7 @@ func TestSetHostHeader(t *testing.T) {
|
||||
}), WithHost(tc.host))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.sendRequest(context.Background(), http.MethodGet, testEndpoint, nil, nil, nil)
|
||||
_, err = client.sendRequest(t.Context(), http.MethodGet, testEndpoint, nil, nil, nil)
|
||||
assert.NilError(t, err)
|
||||
})
|
||||
}
|
||||
@@ -76,7 +75,7 @@ func TestSetHostHeader(t *testing.T) {
|
||||
func TestPlainTextError(t *testing.T) {
|
||||
client, err := New(WithMockClient(mockResponse(http.StatusInternalServerError, nil, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.ContainerList(context.Background(), ContainerListOptions{})
|
||||
_, err = client.ContainerList(t.Context(), ContainerListOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -195,11 +194,11 @@ func TestResponseErrors(t *testing.T) {
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.doc, func(t *testing.T) {
|
||||
client, err := New(WithMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
client, err := New(WithBaseMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
return mockResponse(http.StatusBadRequest, http.Header{"Content-Type": []string{tc.contentType}}, tc.response)(req)
|
||||
}))
|
||||
if tc.apiVersion != "" {
|
||||
client, err = New(WithHTTPClient(client.client), WithVersion(tc.apiVersion))
|
||||
client, err = New(WithHTTPClient(client.client), WithAPIVersion(tc.apiVersion))
|
||||
}
|
||||
assert.NilError(t, err)
|
||||
_, err = client.Ping(t.Context(), PingOptions{})
|
||||
@@ -211,7 +210,7 @@ func TestResponseErrors(t *testing.T) {
|
||||
|
||||
func TestInfiniteError(t *testing.T) {
|
||||
infinitR := rand.New(rand.NewSource(42))
|
||||
client, err := New(WithMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
client, err := New(WithBaseMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
resp := &http.Response{
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
Header: http.Header{},
|
||||
@@ -235,7 +234,7 @@ func TestCanceledContext(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
cancel()
|
||||
|
||||
_, err = client.sendRequest(ctx, http.MethodGet, testEndpoint, nil, nil, nil)
|
||||
@@ -251,7 +250,7 @@ func TestDeadlineExceededContext(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
ctx, cancel := context.WithDeadline(context.Background(), time.Now())
|
||||
ctx, cancel := context.WithDeadline(t.Context(), time.Now())
|
||||
defer cancel()
|
||||
|
||||
<-ctx.Done()
|
||||
@@ -266,26 +265,25 @@ func TestPrepareJSONRequest(t *testing.T) {
|
||||
body any
|
||||
headers http.Header
|
||||
expBody string
|
||||
expNilBody bool
|
||||
expHeaders http.Header
|
||||
}{
|
||||
{
|
||||
doc: "nil body",
|
||||
body: nil,
|
||||
headers: http.Header{"Something": []string{"something"}},
|
||||
expNilBody: true,
|
||||
doc: "nil body",
|
||||
body: nil,
|
||||
headers: http.Header{"Something": []string{"something"}},
|
||||
expBody: "",
|
||||
expHeaders: http.Header{
|
||||
// currently, no content-type is set on empty requests.
|
||||
// no content-type is set on empty requests.
|
||||
"Something": []string{"something"},
|
||||
},
|
||||
},
|
||||
{
|
||||
doc: "nil interface body",
|
||||
body: (*struct{})(nil),
|
||||
headers: http.Header{"Something": []string{"something"}},
|
||||
expNilBody: true,
|
||||
doc: "nil interface body",
|
||||
body: (*struct{})(nil),
|
||||
headers: http.Header{"Something": []string{"something"}},
|
||||
expBody: "",
|
||||
expHeaders: http.Header{
|
||||
// currently, no content-type is set on empty requests.
|
||||
// no content-type is set on empty requests.
|
||||
"Something": []string{"something"},
|
||||
},
|
||||
},
|
||||
@@ -308,12 +306,16 @@ func TestPrepareJSONRequest(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
doc: "empty body",
|
||||
body: http.NoBody,
|
||||
expBody: `{}`,
|
||||
expHeaders: http.Header{
|
||||
"Content-Type": []string{"application/json"},
|
||||
},
|
||||
doc: "empty json raw message",
|
||||
body: json.RawMessage(""),
|
||||
expBody: "",
|
||||
expHeaders: nil, // no content-type is set on empty requests.
|
||||
},
|
||||
{
|
||||
doc: "empty body",
|
||||
body: http.NoBody,
|
||||
expBody: "",
|
||||
expHeaders: nil, // no content-type is set on empty requests.
|
||||
},
|
||||
}
|
||||
|
||||
@@ -322,16 +324,9 @@ func TestPrepareJSONRequest(t *testing.T) {
|
||||
req, hdr, err := prepareJSONRequest(tc.body, tc.headers)
|
||||
assert.NilError(t, err)
|
||||
|
||||
var body string
|
||||
if tc.expNilBody {
|
||||
assert.Check(t, is.Nil(req))
|
||||
} else {
|
||||
assert.Assert(t, req != nil)
|
||||
|
||||
resp, err := io.ReadAll(req)
|
||||
assert.NilError(t, err)
|
||||
body = strings.TrimSpace(string(resp))
|
||||
}
|
||||
resp, err := io.ReadAll(req)
|
||||
assert.NilError(t, err)
|
||||
body := string(resp)
|
||||
|
||||
assert.Check(t, is.Equal(body, tc.expBody))
|
||||
assert.Check(t, is.DeepEqual(hdr, tc.expHeaders))
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -14,7 +13,7 @@ import (
|
||||
func TestSecretCreateError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.SecretCreate(context.Background(), SecretCreateOptions{})
|
||||
_, err = client.SecretCreate(t.Context(), SecretCreateOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -30,7 +29,7 @@ func TestSecretCreate(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
r, err := client.SecretCreate(context.Background(), SecretCreateOptions{})
|
||||
r, err := client.SecretCreate(t.Context(), SecretCreateOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(r.ID, "test_secret"))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"testing"
|
||||
@@ -16,7 +15,7 @@ func TestSecretInspectError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.SecretInspect(context.Background(), "nothing", SecretInspectOptions{})
|
||||
_, err = client.SecretInspect(t.Context(), "nothing", SecretInspectOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -24,7 +23,7 @@ func TestSecretInspectSecretNotFound(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusNotFound, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.SecretInspect(context.Background(), "unknown", SecretInspectOptions{})
|
||||
_, err = client.SecretInspect(t.Context(), "unknown", SecretInspectOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsNotFound))
|
||||
}
|
||||
|
||||
@@ -33,11 +32,11 @@ func TestSecretInspectWithEmptyID(t *testing.T) {
|
||||
return nil, errors.New("should not make request")
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.SecretInspect(context.Background(), "", SecretInspectOptions{})
|
||||
_, err = client.SecretInspect(t.Context(), "", SecretInspectOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.SecretInspect(context.Background(), " ", SecretInspectOptions{})
|
||||
_, err = client.SecretInspect(t.Context(), " ", SecretInspectOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -54,7 +53,7 @@ func TestSecretInspect(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
res, err := client.SecretInspect(context.Background(), "secret_id", SecretInspectOptions{})
|
||||
res, err := client.SecretInspect(t.Context(), "secret_id", SecretInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(res.Secret.ID, "secret_id"))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
@@ -16,7 +15,7 @@ func TestSecretListError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.SecretList(context.Background(), SecretListOptions{})
|
||||
_, err = client.SecretList(t.Context(), SecretListOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -62,7 +61,7 @@ func TestSecretList(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
res, err := client.SecretList(context.Background(), listCase.options)
|
||||
res, err := client.SecretList(t.Context(), listCase.options)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Len(res.Items, 2))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -14,14 +13,14 @@ func TestSecretRemoveError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.SecretRemove(context.Background(), "secret_id", SecretRemoveOptions{})
|
||||
_, err = client.SecretRemove(t.Context(), "secret_id", SecretRemoveOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
_, err = client.SecretRemove(context.Background(), "", SecretRemoveOptions{})
|
||||
_, err = client.SecretRemove(t.Context(), "", SecretRemoveOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.SecretRemove(context.Background(), " ", SecretRemoveOptions{})
|
||||
_, err = client.SecretRemove(t.Context(), " ", SecretRemoveOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -37,6 +36,6 @@ func TestSecretRemove(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.SecretRemove(context.Background(), "secret_id", SecretRemoveOptions{})
|
||||
_, err = client.SecretRemove(t.Context(), "secret_id", SecretRemoveOptions{})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -14,14 +13,14 @@ func TestSecretUpdateError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.SecretUpdate(context.Background(), "secret_id", SecretUpdateOptions{})
|
||||
_, err = client.SecretUpdate(t.Context(), "secret_id", SecretUpdateOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
_, err = client.SecretUpdate(context.Background(), "", SecretUpdateOptions{})
|
||||
_, err = client.SecretUpdate(t.Context(), "", SecretUpdateOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.SecretUpdate(context.Background(), " ", SecretUpdateOptions{})
|
||||
_, err = client.SecretUpdate(t.Context(), " ", SecretUpdateOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -37,6 +36,6 @@ func TestSecretUpdate(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.SecretUpdate(context.Background(), "secret_id", SecretUpdateOptions{})
|
||||
_, err = client.SecretUpdate(t.Context(), "secret_id", SecretUpdateOptions{})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
@@ -59,16 +59,18 @@ func (cli *Client) ServiceCreate(ctx context.Context, options ServiceCreateOptio
|
||||
options.Spec.TaskTemplate.ContainerSpec.Image = taggedImg
|
||||
}
|
||||
if options.QueryRegistry {
|
||||
resolveWarning := resolveContainerSpecImage(ctx, cli, &options.Spec.TaskTemplate, options.EncodedRegistryAuth)
|
||||
warnings = append(warnings, resolveWarning)
|
||||
if warning := resolveContainerSpecImage(ctx, cli, &options.Spec.TaskTemplate, options.EncodedRegistryAuth); warning != "" {
|
||||
warnings = append(warnings, warning)
|
||||
}
|
||||
}
|
||||
case options.Spec.TaskTemplate.PluginSpec != nil:
|
||||
if taggedImg := imageWithTagString(options.Spec.TaskTemplate.PluginSpec.Remote); taggedImg != "" {
|
||||
options.Spec.TaskTemplate.PluginSpec.Remote = taggedImg
|
||||
}
|
||||
if options.QueryRegistry {
|
||||
resolveWarning := resolvePluginSpecRemote(ctx, cli, &options.Spec.TaskTemplate, options.EncodedRegistryAuth)
|
||||
warnings = append(warnings, resolveWarning)
|
||||
if warning := resolvePluginSpecRemote(ctx, cli, &options.Spec.TaskTemplate, options.EncodedRegistryAuth); warning != "" {
|
||||
warnings = append(warnings, warning)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,35 +95,33 @@ func (cli *Client) ServiceCreate(ctx context.Context, options ServiceCreateOptio
|
||||
}
|
||||
|
||||
func resolveContainerSpecImage(ctx context.Context, cli DistributionAPIClient, taskSpec *swarm.TaskSpec, encodedAuth string) string {
|
||||
var warning string
|
||||
if img, imgPlatforms, err := imageDigestAndPlatforms(ctx, cli, taskSpec.ContainerSpec.Image, encodedAuth); err != nil {
|
||||
warning = digestWarning(taskSpec.ContainerSpec.Image)
|
||||
} else {
|
||||
taskSpec.ContainerSpec.Image = img
|
||||
if len(imgPlatforms) > 0 {
|
||||
if taskSpec.Placement == nil {
|
||||
taskSpec.Placement = &swarm.Placement{}
|
||||
}
|
||||
taskSpec.Placement.Platforms = imgPlatforms
|
||||
}
|
||||
img, imgPlatforms, err := imageDigestAndPlatforms(ctx, cli, taskSpec.ContainerSpec.Image, encodedAuth)
|
||||
if err != nil {
|
||||
return digestWarning(taskSpec.ContainerSpec.Image)
|
||||
}
|
||||
return warning
|
||||
taskSpec.ContainerSpec.Image = img
|
||||
if len(imgPlatforms) > 0 {
|
||||
if taskSpec.Placement == nil {
|
||||
taskSpec.Placement = &swarm.Placement{}
|
||||
}
|
||||
taskSpec.Placement.Platforms = imgPlatforms
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func resolvePluginSpecRemote(ctx context.Context, cli DistributionAPIClient, taskSpec *swarm.TaskSpec, encodedAuth string) string {
|
||||
var warning string
|
||||
if img, imgPlatforms, err := imageDigestAndPlatforms(ctx, cli, taskSpec.PluginSpec.Remote, encodedAuth); err != nil {
|
||||
warning = digestWarning(taskSpec.PluginSpec.Remote)
|
||||
} else {
|
||||
taskSpec.PluginSpec.Remote = img
|
||||
if len(imgPlatforms) > 0 {
|
||||
if taskSpec.Placement == nil {
|
||||
taskSpec.Placement = &swarm.Placement{}
|
||||
}
|
||||
taskSpec.Placement.Platforms = imgPlatforms
|
||||
}
|
||||
img, imgPlatforms, err := imageDigestAndPlatforms(ctx, cli, taskSpec.PluginSpec.Remote, encodedAuth)
|
||||
if err != nil {
|
||||
return digestWarning(taskSpec.PluginSpec.Remote)
|
||||
}
|
||||
return warning
|
||||
taskSpec.PluginSpec.Remote = img
|
||||
if len(imgPlatforms) > 0 {
|
||||
if taskSpec.Placement == nil {
|
||||
taskSpec.Placement = &swarm.Placement{}
|
||||
}
|
||||
taskSpec.Placement.Platforms = imgPlatforms
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func imageDigestAndPlatforms(ctx context.Context, cli DistributionAPIClient, image, encodedAuth string) (string, []swarm.Platform, error) {
|
||||
|
||||
@@ -29,7 +29,7 @@ func TestServiceCreateError(t *testing.T) {
|
||||
//
|
||||
// Regression test for https://github.com/docker/cli/issues/4890
|
||||
func TestServiceCreateConnectionError(t *testing.T) {
|
||||
client, err := New(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
|
||||
client, err := New(WithHost("tcp://no-such-host.invalid"))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ServiceCreate(t.Context(), ServiceCreateOptions{})
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"testing"
|
||||
@@ -16,7 +15,7 @@ func TestServiceInspectError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ServiceInspect(context.Background(), "nothing", ServiceInspectOptions{})
|
||||
_, err = client.ServiceInspect(t.Context(), "nothing", ServiceInspectOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -24,7 +23,7 @@ func TestServiceInspectServiceNotFound(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusNotFound, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ServiceInspect(context.Background(), "unknown", ServiceInspectOptions{})
|
||||
_, err = client.ServiceInspect(t.Context(), "unknown", ServiceInspectOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsNotFound))
|
||||
}
|
||||
|
||||
@@ -33,11 +32,11 @@ func TestServiceInspectWithEmptyID(t *testing.T) {
|
||||
return nil, errors.New("should not make request")
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.ServiceInspect(context.Background(), "", ServiceInspectOptions{})
|
||||
_, err = client.ServiceInspect(t.Context(), "", ServiceInspectOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.ServiceInspect(context.Background(), " ", ServiceInspectOptions{})
|
||||
_, err = client.ServiceInspect(t.Context(), " ", ServiceInspectOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -54,7 +53,7 @@ func TestServiceInspect(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
inspect, err := client.ServiceInspect(context.Background(), "service_id", ServiceInspectOptions{})
|
||||
inspect, err := client.ServiceInspect(t.Context(), "service_id", ServiceInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(inspect.Service.ID, "service_id"))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
@@ -16,7 +15,7 @@ func TestServiceListError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ServiceList(context.Background(), ServiceListOptions{})
|
||||
_, err = client.ServiceList(t.Context(), ServiceListOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -62,7 +61,7 @@ func TestServiceList(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
list, err := client.ServiceList(context.Background(), listCase.options)
|
||||
list, err := client.ServiceList(t.Context(), listCase.options)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Len(list.Items, 2))
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ func TestServiceLogs(t *testing.T) {
|
||||
}
|
||||
|
||||
func ExampleClient_ServiceLogs_withTimeout() {
|
||||
client, err := New(FromEnv, WithAPIVersionNegotiation())
|
||||
client, err := New(FromEnv)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -14,14 +13,14 @@ func TestServiceRemoveError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ServiceRemove(context.Background(), "service_id", ServiceRemoveOptions{})
|
||||
_, err = client.ServiceRemove(t.Context(), "service_id", ServiceRemoveOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
|
||||
_, err = client.ServiceRemove(context.Background(), "", ServiceRemoveOptions{})
|
||||
_, err = client.ServiceRemove(t.Context(), "", ServiceRemoveOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
|
||||
_, err = client.ServiceRemove(context.Background(), " ", ServiceRemoveOptions{})
|
||||
_, err = client.ServiceRemove(t.Context(), " ", ServiceRemoveOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
@@ -30,7 +29,7 @@ func TestServiceRemoveNotFoundError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusNotFound, "no such service: service_id")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ServiceRemove(context.Background(), "service_id", ServiceRemoveOptions{})
|
||||
_, err = client.ServiceRemove(t.Context(), "service_id", ServiceRemoveOptions{})
|
||||
assert.Check(t, is.ErrorContains(err, "no such service: service_id"))
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsNotFound))
|
||||
}
|
||||
@@ -46,6 +45,6 @@ func TestServiceRemove(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ServiceRemove(context.Background(), "service_id", ServiceRemoveOptions{})
|
||||
_, err = client.ServiceRemove(t.Context(), "service_id", ServiceRemoveOptions{})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
@@ -82,16 +82,18 @@ func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, options
|
||||
options.Spec.TaskTemplate.ContainerSpec.Image = taggedImg
|
||||
}
|
||||
if options.QueryRegistry {
|
||||
resolveWarning := resolveContainerSpecImage(ctx, cli, &options.Spec.TaskTemplate, options.EncodedRegistryAuth)
|
||||
warnings = append(warnings, resolveWarning)
|
||||
if warning := resolveContainerSpecImage(ctx, cli, &options.Spec.TaskTemplate, options.EncodedRegistryAuth); warning != "" {
|
||||
warnings = append(warnings, warning)
|
||||
}
|
||||
}
|
||||
case options.Spec.TaskTemplate.PluginSpec != nil:
|
||||
if taggedImg := imageWithTagString(options.Spec.TaskTemplate.PluginSpec.Remote); taggedImg != "" {
|
||||
options.Spec.TaskTemplate.PluginSpec.Remote = taggedImg
|
||||
}
|
||||
if options.QueryRegistry {
|
||||
resolveWarning := resolvePluginSpecRemote(ctx, cli, &options.Spec.TaskTemplate, options.EncodedRegistryAuth)
|
||||
warnings = append(warnings, resolveWarning)
|
||||
if warning := resolvePluginSpecRemote(ctx, cli, &options.Spec.TaskTemplate, options.EncodedRegistryAuth); warning != "" {
|
||||
warnings = append(warnings, warning)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ func TestServiceUpdateError(t *testing.T) {
|
||||
//
|
||||
// Regression test for https://github.com/docker/cli/issues/4890
|
||||
func TestServiceUpdateConnectionError(t *testing.T) {
|
||||
client, err := New(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
|
||||
client, err := New(WithHost("tcp://no-such-host.invalid"))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ServiceUpdate(t.Context(), "service_id", ServiceUpdateOptions{})
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -15,7 +14,7 @@ func TestSwarmGetUnlockKeyError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.SwarmGetUnlockKey(context.Background())
|
||||
_, err = client.SwarmGetUnlockKey(t.Context())
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -35,7 +34,7 @@ func TestSwarmGetUnlockKey(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
result, err := client.SwarmGetUnlockKey(context.Background())
|
||||
result, err := client.SwarmGetUnlockKey(t.Context())
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(unlockKey, result.Key))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -14,7 +13,7 @@ func TestSwarmInitError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.SwarmInit(context.Background(), SwarmInitOptions{})
|
||||
_, err = client.SwarmInit(t.Context(), SwarmInitOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -29,7 +28,7 @@ func TestSwarmInit(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
result, err := client.SwarmInit(context.Background(), SwarmInitOptions{
|
||||
result, err := client.SwarmInit(t.Context(), SwarmInitOptions{
|
||||
ListenAddr: "0.0.0.0:2377",
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -14,7 +13,7 @@ func TestSwarmJoinError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.SwarmJoin(context.Background(), SwarmJoinOptions{})
|
||||
_, err = client.SwarmJoin(t.Context(), SwarmJoinOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -29,7 +28,7 @@ func TestSwarmJoin(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.SwarmJoin(context.Background(), SwarmJoinOptions{
|
||||
_, err = client.SwarmJoin(t.Context(), SwarmJoinOptions{
|
||||
ListenAddr: "0.0.0.0:2377",
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
@@ -15,7 +14,7 @@ func TestSwarmLeaveError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.SwarmLeave(context.Background(), SwarmLeaveOptions{})
|
||||
_, err = client.SwarmLeave(t.Context(), SwarmLeaveOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -48,7 +47,7 @@ func TestSwarmLeave(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.SwarmLeave(context.Background(), SwarmLeaveOptions{Force: leaveCase.force})
|
||||
_, err = client.SwarmLeave(t.Context(), SwarmLeaveOptions{Force: leaveCase.force})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -14,7 +13,7 @@ func TestSwarmUnlockError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.SwarmUnlock(context.Background(), SwarmUnlockOptions{Key: "SWMKEY-1-y6guTZNTwpQeTL5RhUfOsdBdXoQjiB2GADHSRJvbXeU"})
|
||||
_, err = client.SwarmUnlock(t.Context(), SwarmUnlockOptions{Key: "SWMKEY-1-y6guTZNTwpQeTL5RhUfOsdBdXoQjiB2GADHSRJvbXeU"})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -29,6 +28,6 @@ func TestSwarmUnlock(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.SwarmUnlock(context.Background(), SwarmUnlockOptions{Key: "SWMKEY-1-y6guTZNTwpQeTL5RhUfOsdBdXoQjiB2GADHSRJvbXeU"})
|
||||
_, err = client.SwarmUnlock(t.Context(), SwarmUnlockOptions{Key: "SWMKEY-1-y6guTZNTwpQeTL5RhUfOsdBdXoQjiB2GADHSRJvbXeU"})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ func TestLegacyDiskUsage(t *testing.T) {
|
||||
const legacyVersion = "1.51"
|
||||
const expectedURL = "/system/df"
|
||||
client, err := New(
|
||||
WithVersion(legacyVersion),
|
||||
WithAPIVersion(legacyVersion),
|
||||
WithMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
if err := assertRequest(req, http.MethodGet, "/v"+legacyVersion+expectedURL); err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -2,7 +2,6 @@ package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -37,8 +36,8 @@ func TestEventsErrorInOptions(t *testing.T) {
|
||||
for _, tc := range errorCases {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
events := client.Events(context.Background(), tc.options)
|
||||
err = <-events.Err
|
||||
res := client.Events(t.Context(), tc.options)
|
||||
err = <-res.Err
|
||||
assert.Check(t, is.ErrorContains(err, tc.expectedError))
|
||||
}
|
||||
}
|
||||
@@ -46,8 +45,8 @@ func TestEventsErrorInOptions(t *testing.T) {
|
||||
func TestEventsErrorFromServer(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
events := client.Events(context.Background(), EventsListOptions{})
|
||||
err = <-events.Err
|
||||
res := client.Events(t.Context(), EventsListOptions{})
|
||||
err = <-res.Err
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
@@ -133,18 +132,18 @@ func TestEvents(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
events := client.Events(context.Background(), eventsCase.options)
|
||||
res := client.Events(t.Context(), eventsCase.options)
|
||||
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case err := <-events.Err:
|
||||
case err := <-res.Err:
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
break loop
|
||||
case e := <-events.Messages:
|
||||
case e := <-res.Messages:
|
||||
_, ok := eventsCase.expectedEvents[e.Actor.ID]
|
||||
assert.Check(t, ok, "event received not expected with action %s & id %s", e.Action, e.Actor.ID)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -14,14 +13,14 @@ import (
|
||||
func TestInfoServerError(t *testing.T) {
|
||||
client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.Info(context.Background(), InfoOptions{})
|
||||
_, err = client.Info(t.Context(), InfoOptions{})
|
||||
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
||||
}
|
||||
|
||||
func TestInfoInvalidResponseJSONError(t *testing.T) {
|
||||
client, err := New(WithMockClient(mockResponse(http.StatusOK, nil, "invalid json")))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.Info(context.Background(), InfoOptions{})
|
||||
_, err = client.Info(t.Context(), InfoOptions{})
|
||||
assert.Check(t, is.ErrorContains(err, "invalid character"))
|
||||
}
|
||||
|
||||
@@ -38,7 +37,7 @@ func TestInfo(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
result, err := client.Info(context.Background(), InfoOptions{})
|
||||
result, err := client.Info(t.Context(), InfoOptions{})
|
||||
assert.NilError(t, err)
|
||||
info := result.Info
|
||||
|
||||
@@ -69,7 +68,7 @@ func TestInfoWithDiscoveredDevices(t *testing.T) {
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
|
||||
result, err := client.Info(context.Background(), InfoOptions{})
|
||||
result, err := client.Info(t.Context(), InfoOptions{})
|
||||
assert.NilError(t, err)
|
||||
info := result.Info
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user