# Copyright 2024 RustFS Team # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. name: Windows Filesystem Tests on: push: branches: [ main ] paths: - "crates/ecstore/src/disk/**" - "crates/ecstore/src/layout/**" - "crates/ecstore/src/store/init_format.rs" - "crates/ecstore/src/set_disk/ops/locking.rs" - "crates/ecstore/src/object_api/write_commit_context.rs" - "crates/ecstore/src/bucket/utils.rs" - "crates/ecstore/Cargo.toml" - "crates/storage-api/src/bucket.rs" - "crates/storage-api/Cargo.toml" - "crates/utils/src/dunce.rs" - "crates/utils/src/os/**" - "crates/utils/Cargo.toml" - "crates/utils/src/path.rs" - "rustfs/build.rs" - "rustfs/Cargo.toml" - "rustfs/src/main.rs" - "rustfs/src/server/runtime.rs" - "rustfs/src/startup_*.rs" - "Cargo.toml" - "Cargo.lock" - ".github/actions/setup/**" - ".github/workflows/windows-filesystem.yml" pull_request: branches: [ main ] paths: - "crates/ecstore/src/disk/**" - "crates/ecstore/src/layout/**" - "crates/ecstore/src/store/init_format.rs" - "crates/ecstore/src/set_disk/ops/locking.rs" - "crates/ecstore/src/object_api/write_commit_context.rs" - "crates/ecstore/src/bucket/utils.rs" - "crates/ecstore/Cargo.toml" - "crates/storage-api/src/bucket.rs" - "crates/storage-api/Cargo.toml" - "crates/utils/src/dunce.rs" - "crates/utils/src/os/**" - "crates/utils/Cargo.toml" - "crates/utils/src/path.rs" - "rustfs/build.rs" - "rustfs/Cargo.toml" - "rustfs/src/main.rs" - "rustfs/src/server/runtime.rs" - "rustfs/src/startup_*.rs" - "Cargo.toml" - "Cargo.lock" - ".github/actions/setup/**" - ".github/workflows/windows-filesystem.yml" workflow_dispatch: permissions: contents: read concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true env: CARGO_TERM_COLOR: always FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" RUST_BACKTRACE: 1 jobs: rename-safety: name: Rename Safety runs-on: windows-latest timeout-minutes: 60 steps: - name: Checkout repository uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v7 with: persist-credentials: false - name: Setup Rust environment uses: ./.github/actions/setup with: rust-version: stable cache-shared-key: build-x86_64-pc-windows-msvc cache-save-if: 'false' install-build-packaging-tools: 'false' install-test-tools: 'false' - name: Check production Windows dependencies shell: pwsh run: cargo check -p rustfs-ecstore --lib - name: Test guarded rename publication shell: pwsh run: cargo test -p rustfs-ecstore --lib rename_all_ -- --nocapture - name: Test Windows path conversion shell: pwsh run: "cargo test -p rustfs-utils --no-default-features --features path --lib dunce:: -- --nocapture" - name: Test Windows volume and disk-space probes shell: pwsh run: | # Map a drive letter to the temp drive's administrative share so the # remote-volume probe also covers mapped network drives. $drive = (Split-Path -Qualifier ([System.IO.Path]::GetTempPath())).TrimEnd(':') net use R: "\\localhost\$drive`$" /persistent:no if ($LASTEXITCODE -eq 0) { $env:RUSTFS_TEST_WINDOWS_MAPPED_DRIVE = 'R:' } else { Write-Output "::warning::could not map R: to \\localhost\$drive`$; mapped-drive test will skip" } cargo test -p rustfs-utils --features os --lib os:: -- --nocapture $status = $LASTEXITCODE if ($env:RUSTFS_TEST_WINDOWS_MAPPED_DRIVE) { net use R: /delete /y | Out-Null } exit $status - name: Test Windows handle guards shell: pwsh run: cargo test -p rustfs-ecstore --lib windows_ -- --nocapture - name: Test endpoint path parsing shell: pwsh run: "cargo test -p rustfs-ecstore --lib layout::endpoint:: -- --nocapture" - name: Test startup temporary-directory cleanup shell: pwsh run: cargo test -p rustfs-ecstore --lib cleanup_tmp_on_startup_ -- --nocapture - name: Test object key Windows admission shell: pwsh run: "cargo test -p rustfs-ecstore --lib bucket::utils:: -- --nocapture" - name: Test artifact prefix Windows file-name rules shell: pwsh run: | $testName = 'bucket::tests::artifact_prefix_preserves_host_file_name_rules' cargo test --locked -p rustfs-storage-api --lib $testName -- --exact --nocapture --color never 2>&1 | Tee-Object -Variable testOutput if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } if (($testOutput -join "`n") -notmatch 'test result: ok\. 1 passed; 0 failed; 0 ignored;') { throw 'Expected exactly one passing artifact prefix test on Windows' } - name: Test Windows file-name rules shell: pwsh run: "cargo test -p rustfs-utils --no-default-features --features path --lib dunce:: -- --nocapture" - name: Test fresh format publication shell: pwsh run: cargo test -p rustfs-ecstore --lib fresh_format_load_initializes_all_disks -- --nocapture # The native Windows main thread only gets the 1 MiB PE stack reserve, while # Linux and macOS hand out 8 MiB. Startup runs the whole root future on the # thread that calls `block_on`, so a debug server once overflowed before it # listened on Windows only. Start a real server to keep that covered. startup-smoke: name: Startup Smoke runs-on: windows-latest timeout-minutes: 90 steps: - name: Checkout repository uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v7 with: persist-credentials: false - name: Setup Rust environment uses: ./.github/actions/setup with: rust-version: stable cache-shared-key: build-x86_64-pc-windows-msvc cache-save-if: 'false' install-build-packaging-tools: 'false' install-test-tools: 'false' - name: Build debug server binary shell: pwsh run: cargo build --locked -p rustfs --bin rustfs - name: Print version shell: pwsh run: | & .\target\debug\rustfs.exe --version if ($LASTEXITCODE -ne 0) { throw "rustfs --version exited with $LASTEXITCODE" } - name: Start server and wait for readiness shell: pwsh env: RUSTFS_ACCESS_KEY: rustfsadmin RUSTFS_SECRET_KEY: rustfsadmin run: | $volume = Join-Path $env:RUNNER_TEMP 'rustfs-startup-smoke' $stdout = Join-Path $env:RUNNER_TEMP 'rustfs-startup-smoke.out.log' $stderr = Join-Path $env:RUNNER_TEMP 'rustfs-startup-smoke.err.log' New-Item -ItemType Directory -Force -Path $volume | Out-Null $server = Start-Process -FilePath .\target\debug\rustfs.exe ` -ArgumentList @('--address', '127.0.0.1:9000', "`"$volume`"") ` -RedirectStandardOutput $stdout -RedirectStandardError $stderr ` -NoNewWindow -PassThru # Cache the process handle now; otherwise ExitCode reads back empty. $null = $server.Handle $ready = $false try { for ($i = 0; $i -lt 180; $i++) { if ($server.HasExited) { break } try { $response = Invoke-WebRequest -Uri 'http://127.0.0.1:9000/health/ready' -UseBasicParsing -NoProxy -TimeoutSec 2 if ($response.StatusCode -eq 200) { $ready = $true; break } } catch {} Start-Sleep -Seconds 1 } } finally { if (-not $server.HasExited) { Stop-Process -Id $server.Id -Force } $server.WaitForExit() Write-Host '--- server stdout (tail) ---' Get-Content $stdout -Tail 100 -ErrorAction SilentlyContinue Write-Host '--- server stderr (tail) ---' Get-Content $stderr -Tail 100 -ErrorAction SilentlyContinue } if (-not $ready) { throw ("rustfs did not report ready on /health/ready (exit code: {0})" -f $server.ExitCode) }