diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml deleted file mode 100644 index c4475268e..000000000 --- a/.github/workflows/bench.yml +++ /dev/null @@ -1,164 +0,0 @@ -name: Benchmark - -# We use environments to require approval to run benchmarks on PRs, but not on pushes to `main` -# (which have been approved already since PRs are required for `main`). -on: - workflow_call: - inputs: - environment: - type: string - publish: - type: boolean - default: false - ref: - required: true - type: string - -env: - RUST_BACKTRACE: 1 - CARGO_TERM_COLOR: always - S3_BUCKET_NAME: ${{ vars.S3_BENCH_BUCKET_NAME }} - S3_BUCKET_TEST_PREFIX: ${{ vars.S3_BUCKET_BENCH_PREFIX || 'mountpoint-benchmark/' }} - S3_BUCKET_BENCH_FILE: ${{ vars.BENCH_FILE_NAME || 'bench100GB.bin' }} - S3_BUCKET_SMALL_BENCH_FILE: ${{ vars.SMALL_BENCH_FILE_NAME || 'bench5MB.bin' }} - S3_REGION: ${{ vars.S3_BENCH_REGION }} - -jobs: - bench: - name: Benchmark (Throughput) - runs-on: [self-hosted, linux, x64, nvme-high-performance] - - environment: ${{ inputs.environment }} - - steps: - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - role-to-assume: ${{ vars.ACTIONS_BENCH_IAM_ROLE }} - aws-region: ${{ vars.S3_BENCH_REGION }} - role-duration-seconds: 21600 - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: ${{ inputs.ref }} - submodules: true - persist-credentials: false - - name: Install operating system dependencies - uses: ./.github/actions/install-dependencies - with: - fuseVersion: 2 - libunwind: true - fio: true - - name: Set up stable Rust - uses: dtolnay/rust-toolchain@stable - - name: Build - run: cargo build --release - - name: Run Benchmark - run: mountpoint-s3/scripts/fs_bench.sh - - name: Check benchmark results - uses: benchmark-action/github-action-benchmark@v1 - with: - tool: 'customBiggerIsBetter' - output-file-path: results/output.json - alert-threshold: "200%" - fail-on-alert: true - # GitHub API token to make a commit comment - github-token: ${{ secrets.GITHUB_TOKEN }} - # Store the results and deploy GitHub pages automatically if the results are from main branch - auto-push: ${{ inputs.publish }} - comment-on-alert: true - max-items-in-chart: 20 - - latency-bench: - name: Benchmark (Latency) - runs-on: [self-hosted, linux, x64, nvme-high-performance] - - environment: ${{ inputs.environment }} - - steps: - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - role-to-assume: ${{ vars.ACTIONS_BENCH_IAM_ROLE }} - aws-region: ${{ vars.S3_BENCH_REGION }} - role-duration-seconds: 21600 - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: ${{ inputs.ref }} - submodules: true - persist-credentials: false - - name: Install operating system dependencies - uses: ./.github/actions/install-dependencies - with: - fuseVersion: 2 - libunwind: true - fio: true - - name: Set up stable Rust - uses: dtolnay/rust-toolchain@stable - - name: Build - run: cargo build --release - - name: Run Benchmark - run: mountpoint-s3/scripts/fs_latency_bench.sh - - name: Check benchmark results - uses: benchmark-action/github-action-benchmark@v1 - with: - tool: 'customSmallerIsBetter' - output-file-path: results/output.json - benchmark-data-dir-path: dev/latency_bench - alert-threshold: "200%" - fail-on-alert: true - # GitHub API token to make a commit comment - github-token: ${{ secrets.GITHUB_TOKEN }} - # Store the results and deploy GitHub pages automatically if the results are from main branch - auto-push: ${{ inputs.publish }} - comment-on-alert: true - max-items-in-chart: 20 - - cache-bench: - name: Benchmark (Cache) - runs-on: [self-hosted, linux, x64, nvme-high-performance] - - environment: ${{ inputs.environment }} - - steps: - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - role-to-assume: ${{ vars.ACTIONS_BENCH_IAM_ROLE }} - aws-region: ${{ vars.S3_BENCH_REGION }} - role-duration-seconds: 21600 - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: ${{ inputs.ref }} - submodules: true - persist-credentials: false - - name: Install operating system dependencies - uses: ./.github/actions/install-dependencies - with: - fuseVersion: 2 - libunwind: true - fio: true - - name: Set up stable Rust - uses: dtolnay/rust-toolchain@stable - - name: Build - run: cargo build --release - - name: Run Benchmark - env: - S3_MOUNT_LOCAL_STORAGE: yes - run: mountpoint-s3/scripts/fs_cache_bench.sh - - name: Check benchmark results - uses: benchmark-action/github-action-benchmark@v1 - with: - tool: 'customBiggerIsBetter' - output-file-path: results/output.json - benchmark-data-dir-path: dev/cache_bench - alert-threshold: "200%" - fail-on-alert: true - # GitHub API token to make a commit comment - github-token: ${{ secrets.GITHUB_TOKEN }} - # Store the results and deploy GitHub pages automatically if the results are from main branch - auto-push: ${{ inputs.publish }} - comment-on-alert: true - max-items-in-chart: 20 diff --git a/.github/workflows/bench_main.yml b/.github/workflows/bench_main.yml deleted file mode 100644 index 4c2702949..000000000 --- a/.github/workflows/bench_main.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Benchmarks - -on: - push: - branches: [ "main", "wf-changes/**" ] - -permissions: - id-token: write - contents: write - -jobs: - integration: - name: Benchmarks - uses: ./.github/workflows/bench.yml - with: - ref: ${{ github.event.after }} - publish: ${{ github.event.ref == 'refs/heads/main' }} - s3express-integration: - name: Benchmarks (s3express) - uses: ./.github/workflows/bench_s3express.yml - with: - ref: ${{ github.event.after }} - publish: ${{ github.event.ref == 'refs/heads/main' }} diff --git a/.github/workflows/bench_pr.yml b/.github/workflows/bench_pr.yml deleted file mode 100644 index de9d47ec6..000000000 --- a/.github/workflows/bench_pr.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Benchmarks (PR) - -on: - pull_request_target: - branches: [ "main" ] - types: [ labeled, opened, reopened, synchronize ] - -permissions: - id-token: write - contents: read - -jobs: - integration: - name: Benchmarks - uses: ./.github/workflows/bench.yml - if: ${{ contains(github.event.pull_request.labels.*.name, 'performance') }} - with: - environment: PR benchmarks - ref: ${{ github.event.pull_request.head.sha }} - s3express-integration: - name: Benchmarks (s3express) - uses: ./.github/workflows/bench_s3express.yml - if: ${{ contains(github.event.pull_request.labels.*.name, 'performance') }} - with: - environment: PR benchmarks - ref: ${{ github.event.pull_request.head.sha }} diff --git a/.github/workflows/bench_s3express.yml b/.github/workflows/bench_s3express.yml deleted file mode 100644 index 3457ce08c..000000000 --- a/.github/workflows/bench_s3express.yml +++ /dev/null @@ -1,117 +0,0 @@ -name: Benchmark (s3-express one zone) - -# We use environments to require approval to run benchmarks on PRs, but not on pushes to `main` -# (which have been approved already since PRs are required for `main`). -on: - workflow_call: - inputs: - environment: - type: string - publish: - type: boolean - default: false - ref: - required: true - type: string - -env: - RUST_BACKTRACE: 1 - CARGO_TERM_COLOR: always - S3_BUCKET_NAME: ${{ vars.S3_EXPRESS_ONE_ZONE_BENCH_BUCKET_NAME }} - S3_BUCKET_TEST_PREFIX: ${{ vars.S3_BUCKET_BENCH_PREFIX || 'mountpoint-benchmark/' }} - S3_BUCKET_BENCH_FILE: ${{ vars.BENCH_FILE_NAME || 'bench100GB.bin' }} - S3_BUCKET_SMALL_BENCH_FILE: ${{ vars.SMALL_BENCH_FILE_NAME || 'bench5MB.bin' }} - S3_REGION: ${{ vars.S3_BENCH_REGION }} - -jobs: - bench: - name: Benchmark (Throughput) - runs-on: [self-hosted, linux, x64, nvme-high-performance] - - environment: ${{ inputs.environment }} - - steps: - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - role-to-assume: ${{ vars.ACTIONS_BENCH_IAM_ROLE }} - aws-region: ${{ vars.S3_BENCH_REGION }} - role-duration-seconds: 21600 - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: ${{ inputs.ref }} - submodules: true - persist-credentials: false - - name: Install operating system dependencies - uses: ./.github/actions/install-dependencies - with: - fuseVersion: 2 - libunwind: true - fio: true - - name: Set up stable Rust - uses: dtolnay/rust-toolchain@stable - - name: Build - run: cargo build --release - - name: Run Benchmark - run: mountpoint-s3/scripts/fs_bench.sh - - name: Check benchmark results - uses: benchmark-action/github-action-benchmark@v1 - with: - tool: 'customBiggerIsBetter' - output-file-path: results/output.json - benchmark-data-dir-path: dev/s3-express/bench - alert-threshold: "200%" - fail-on-alert: true - # GitHub API token to make a commit comment - github-token: ${{ secrets.GITHUB_TOKEN }} - # Store the results and deploy GitHub pages automatically if the results are from main branch - auto-push: ${{ inputs.publish }} - comment-on-alert: true - max-items-in-chart: 20 - - latency-bench: - name: Benchmark (Latency) - runs-on: [self-hosted, linux, x64, nvme-high-performance] - - environment: ${{ inputs.environment }} - - steps: - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - role-to-assume: ${{ vars.ACTIONS_BENCH_IAM_ROLE }} - aws-region: ${{ vars.S3_BENCH_REGION }} - role-duration-seconds: 21600 - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: ${{ inputs.ref }} - submodules: true - persist-credentials: false - - name: Install operating system dependencies - uses: ./.github/actions/install-dependencies - with: - fuseVersion: 2 - libunwind: true - fio: true - - name: Set up stable Rust - uses: dtolnay/rust-toolchain@stable - - name: Build - run: cargo build --release - - name: Run Benchmark - run: mountpoint-s3/scripts/fs_latency_bench.sh - - name: Check benchmark results - uses: benchmark-action/github-action-benchmark@v1 - with: - tool: 'customSmallerIsBetter' - output-file-path: results/output.json - benchmark-data-dir-path: dev/s3-express/latency_bench - alert-threshold: "200%" - fail-on-alert: true - # GitHub API token to make a commit comment - github-token: ${{ secrets.GITHUB_TOKEN }} - # Store the results and deploy GitHub pages automatically if the results are from main branch - auto-push: ${{ inputs.publish }} - comment-on-alert: true - max-items-in-chart: 20 diff --git a/.github/workflows/crates.yml b/.github/workflows/crates.yml deleted file mode 100644 index 18c3e9fa2..000000000 --- a/.github/workflows/crates.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Crate checks - -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - merge_group: - types: [ "checks_requested" ] - -jobs: - verify-crate: - name: Verify crate - runs-on: ubuntu-22.04 - - strategy: - matrix: - crate: - - mountpoint-s3-crt-sys - - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - submodules: true - - name: Set up stable Rust - uses: dtolnay/rust-toolchain@stable - - name: Package ${{ matrix.crate }} crate - # `--no-verify` avoids building using crates.io dependencies, which for local packages may not be updated yet - run: cargo package -p ${{ matrix.crate }} --no-verify - - name: Verify compressed crate size is smaller than crates.io limit - run: | - ls -alh target/package/*.crate - test `cat target/package/*.crate | wc -c` -le 10485760 diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml deleted file mode 100644 index 51a2089dd..000000000 --- a/.github/workflows/integration.yml +++ /dev/null @@ -1,174 +0,0 @@ -name: Integration tests - -# We use environments to require approval to run integration tests on PRs, but not on pushes to -# `main` (which have been approved already since PRs are required for `main`). -on: - workflow_call: - inputs: - environment: - type: string - ref: - required: true - type: string - -env: - RUST_BACKTRACE: 1 - CARGO_TERM_COLOR: always - CARGO_INCREMENTAL: 0 - S3_BUCKET_NAME: ${{ vars.S3_BUCKET_NAME }} - S3_EXPRESS_ONE_ZONE_BUCKET_NAME: ${{ vars.S3_EXPRESS_ONE_ZONE_BUCKET_NAME }} - S3_REGION: ${{ vars.S3_REGION }} - S3_BUCKET_TEST_PREFIX: ${{ vars.S3_BUCKET_TEST_PREFIX || 'github-actions-tmp/' }}run-${{ github.run_id }}/attempt-${{ github.run_attempt }}/ - # A bucket our IAM role has no access to, but is in the right region, for permissions tests - S3_FORBIDDEN_BUCKET_NAME: ${{ vars.S3_FORBIDDEN_BUCKET_NAME }} - # An IAM role that tests can assume when they want to create session policies - S3_SUBSESSION_IAM_ROLE: ${{ vars.S3_SUBSESSION_IAM_ROLE }} - # Different Access Points Aliases and ARNs - S3_ACCESS_POINT_ALIAS: ${{ vars.S3_ACCESS_POINT_ALIAS }} - S3_ACCESS_POINT_ARN: ${{ vars.S3_ACCESS_POINT_ARN }} - S3_OLAP_ALIAS: ${{ vars.S3_OLAP_ALIAS }} - S3_OLAP_ARN: ${{ vars.S3_OLAP_ARN }} - S3_MRAP_ARN: ${{ vars.S3_MRAP_ARN }} - KMS_TEST_KEY_ID: ${{ vars.KMS_TEST_KEY_ID }} - RUST_FEATURES: fuse_tests,s3_tests,fips_tests,event_log - -permissions: - id-token: write - contents: read - -jobs: - test: - name: Tests (${{ matrix.runner.name }}, FUSE ${{ matrix.fuseVersion }}) - runs-on: ${{ matrix.runner.tags }} - - environment: ${{ inputs.environment }} - - strategy: - fail-fast: false - matrix: - fuseVersion: [2, 3] - runner: - - name: Ubuntu x86 - tags: [ubuntu-22.04] # GitHub-hosted - - name: Amazon Linux arm - tags: [self-hosted, linux, arm64] - exclude: - # fuse3 is not available on Amazon Linux 2 - - runner: - name: Amazon Linux arm - tags: [self-hosted, linux, arm64] - fuseVersion: 3 - - steps: - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - role-to-assume: ${{ vars.ACTIONS_IAM_ROLE }} - aws-region: ${{ vars.S3_REGION }} - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: ${{ inputs.ref }} - submodules: true - persist-credentials: false - - name: Set up stable Rust - uses: dtolnay/rust-toolchain@stable - - name: Install operating system dependencies - uses: ./.github/actions/install-dependencies - with: - fuseVersion: ${{ matrix.fuseVersion }} - - name: Build tests - run: cargo test --features $RUST_FEATURES --no-run - - name: Run tests - run: cargo test --features $RUST_FEATURES - - name: Save dump files - if: ${{ failure() && matrix.runner.name == 'Amazon Linux arm' }} - run: ./.github/actions/scripts/save-coredump.sh - - s3express-test: - name: S3 Express One Zone tests (${{ matrix.runner.name }}, FUSE ${{ matrix.fuseVersion }}) - runs-on: ${{ matrix.runner.tags }} - - environment: ${{ inputs.environment }} - - strategy: - fail-fast: false - matrix: - fuseVersion: [2, 3] - runner: - - name: Ubuntu x86 - tags: [ubuntu-22.04] # GitHub-hosted - - name: Amazon Linux arm - tags: [self-hosted, linux, arm64] - exclude: - # fuse3 is not available on Amazon Linux 2 - - runner: - name: Amazon Linux arm - tags: [self-hosted, linux, arm64] - fuseVersion: 3 - - steps: - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - role-to-assume: ${{ vars.ACTIONS_IAM_ROLE }} - aws-region: ${{ vars.S3_REGION }} - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: ${{ inputs.ref }} - submodules: true - persist-credentials: false - - name: Set up stable Rust - uses: dtolnay/rust-toolchain@stable - - name: Install operating system dependencies - uses: ./.github/actions/install-dependencies - with: - fuseVersion: ${{ matrix.fuseVersion }} - - name: Build tests - run: cargo test --features '${{ env.RUST_FEATURES }},s3express_tests' --no-run - - name: Run tests - run: cargo test --features '${{ env.RUST_FEATURES }},s3express_tests' - - name: Save dump files - if: ${{ failure() && matrix.runner.name == 'Amazon Linux arm' }} - run: ./.github/actions/scripts/save-coredump.sh - - asan: - name: Address sanitizer - runs-on: [self-hosted, linux, arm64] - - environment: ${{ inputs.environment }} - - env: - # We're using ASan to test our CRT bindings, so focus only on S3, not on FUSE - RUST_FEATURES: s3_tests,fips_tests - - timeout-minutes: 30 - - steps: - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - role-to-assume: ${{ vars.ACTIONS_IAM_ROLE }} - aws-region: ${{ vars.S3_REGION }} - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: ${{ inputs.ref }} - submodules: true - - name: Set up stable Rust - uses: dtolnay/rust-toolchain@stable - with: - components: rust-src - - name: Install operating system dependencies - uses: ./.github/actions/install-dependencies - with: - fuseVersion: 3 - llvm: true - - name: Validate ASan is working - run: make test-asan-working - - name: Run tests - run: make test-asan - - name: Save dump files - if: ${{ failure() }} - run: ./.github/actions/scripts/save-coredump.sh diff --git a/.github/workflows/integration_main.yml b/.github/workflows/integration_main.yml deleted file mode 100644 index abd6862b6..000000000 --- a/.github/workflows/integration_main.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Integration tests - -on: - push: - branches: [ "main", "wf-changes/**" ] - merge_group: - types: [ "checks_requested" ] - schedule: - - cron: "45 6 * * *" # Daily at 06:45 UTC - workflow_dispatch: - inputs: - ref: - description: "Git reference or commit hash to run the workflow against." - required: false - type: string - -permissions: - id-token: write - contents: read - -jobs: - integration: - if: github.event_name != 'schedule' || github.repository == 'awslabs/mountpoint-s3' - name: Integration - uses: ./.github/workflows/integration.yml - with: - ref: ${{ github.sha }} diff --git a/.github/workflows/integration_pr.yml b/.github/workflows/integration_pr.yml deleted file mode 100644 index 868dec2fe..000000000 --- a/.github/workflows/integration_pr.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Integration tests (PR) - -on: - pull_request_target: - branches: [ "main" ] - -permissions: - id-token: write - contents: read - -jobs: - integration: - name: Integration - uses: ./.github/workflows/integration.yml - with: - environment: PR integration tests - ref: ${{ github.event.pull_request.head.sha }} diff --git a/.github/workflows/merge_queue_dco_mock.yml b/.github/workflows/merge_queue_dco_mock.yml deleted file mode 100644 index 71618b81e..000000000 --- a/.github/workflows/merge_queue_dco_mock.yml +++ /dev/null @@ -1,15 +0,0 @@ ---- -# Workflow that always succeeds with name "DCO". -# This is temporarily needed to ensure we can keep DCO requirement on PRs and allow merge queue to succeed. -# It can be removed once DCO runs against `merge_group` events. See: https://github.com/dcoapp/app/issues/199 -name: DCO -"on": - merge_group: - -jobs: - DCO: - runs-on: ubuntu-latest - if: ${{ github.actor != 'dependabot[bot]' }} - steps: - - run: echo "This workflow always succeeds to unlock GitHub's Merge Queue." - - run: echo "DCO should already be completed during PR workflows." diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml deleted file mode 100644 index 1670e61ae..000000000 --- a/.github/workflows/package.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Packaging - -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - merge_group: - types: [ "checks_requested" ] - -jobs: - packages: - name: Package ${{ matrix.runner.name }} - runs-on: ${{ matrix.runner.tags }} - - strategy: - matrix: - runner: - - name: x86_64 - tags: [ubuntu-22.04] # GitHub-hosted - - name: aarch64 - tags: [self-hosted, linux, arm64] - - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - submodules: true - - name: Install operating system dependencies - uses: ./.github/actions/install-dependencies - with: - fuseVersion: 2 - - name: Build Docker image - uses: docker/build-push-action@v6 - with: - tags: mountpoint-builder - context: ./package - # https://github.com/docker/buildx/issues/379 - ulimit: nofile=100000 - - name: Package an unofficial release - run: docker run --mount type=bind,source=$(pwd),target=/mountpoint mountpoint-builder - - name: Check release binary - run: mkdir ./pkg-out && tar -xzf ./out/mount-s3*.tar.gz -C ./pkg-out && ./pkg-out/bin/mount-s3 --version - - name: Upload unofficial packages - uses: actions/upload-artifact@v4 - with: - name: packages-${{ matrix.runner.name }} - path: ./out/* - retention-days: 3 - if-no-files-found: error diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 90eb66d4c..000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Release - -on: - push: - tags: - - mountpoint-s3-[0-9]+.* - -permissions: - contents: write - - -jobs: - create-github-release: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: taiki-e/create-gh-release-action@v1 - with: - title: "mountpoint-s3 v$version" - # Strip this prefix off the tag to discover the version number - prefix: mountpoint-s3 - draft: true - changelog: mountpoint-s3/CHANGELOG.md - # TODO: make this mandatory once we have the format nailed down - allow-missing-changelog: true - branch: main - token: ${{ secrets.GITHUB_TOKEN }} diff --git a/mountpoint-s3/src/inode.rs b/mountpoint-s3/src/inode.rs index 8be944604..d908f7d0b 100644 --- a/mountpoint-s3/src/inode.rs +++ b/mountpoint-s3/src/inode.rs @@ -269,8 +269,13 @@ impl Superblock { logging::record_name(inode.name()); let mut sync = inode.get_mut_inode_state()?; + // If the inode is remote, we would typically throw an error here, but instead we + // silently fail and return the current stat. This allows programs like `wget` to + // continue working. if sync.write_status == WriteStatus::Remote { - return Err(InodeError::SetAttrNotPermittedOnRemoteInode(inode.err())); + let stat = sync.stat.clone(); + drop(sync); + return Ok(LookedUp { inode, stat }); } let validity = match inode.kind() { @@ -2887,11 +2892,11 @@ mod tests { // Invoke [finish_writing] to make the file remote writehandle.finish().unwrap(); - // Should get an error back when calling setattr + // Should not get an error back when calling setattr now that we've patched the code to allow this. let result = superblock .setattr(&client, new_inode.inode.ino(), Some(atime), Some(mtime)) .await; - assert!(matches!(result, Err(InodeError::SetAttrNotPermittedOnRemoteInode(_)))); + assert!(matches!(result, Ok(_))); } #[tokio::test]