name: EasyTier Test

on:
  push:
    branches: [ "develop", "main" ]
  pull_request:
    branches: [ "develop", "main" ]

concurrency:
  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

env:
  CARGO_TERM_COLOR: always
#  RUSTC_WRAPPER: "sccache"
#  SCCACHE_GHA_ENABLED: "true"

defaults:
  run:
    # necessary for windows
    shell: bash

jobs:
  pre_job:
    # continue-on-error: true # Uncomment once integration is finished
    runs-on: ubuntu-latest
    # Map a step output to a job output
    outputs:
      should_skip: ${{ steps.skip_check.outputs.should_skip }}
    steps:
      - id: skip_check
        uses: fkirc/skip-duplicate-actions@v5
        with:
          # All of these options are optional, so you can remove them if you are happy with the defaults
          concurrent_skipping: 'never'
          skip_after_successful_duplicate: 'true'
          paths: '["Cargo.toml", "Cargo.lock", "easytier/**", ".github/workflows/test.yml", ".github/workflows/install_gui_dep.sh", ".github/workflows/install_rust.sh"]'

  check:
    name: Run linters & check
    runs-on: ubuntu-latest
    needs: pre_job
    if: needs.pre_job.outputs.should_skip != 'true'
    steps:
      - uses: actions/checkout@v5

      - name: Prepare build environment
        uses: ./.github/actions/prepare-build
        with:
          gui: true
          web: true
          token: ${{ secrets.GITHUB_TOKEN }}

      - uses: Swatinem/rust-cache@v2

      - name: Install rustfmt and clippy
        run: |
          rustup component add rustfmt
          rustup component add clippy

      - uses: taiki-e/install-action@cargo-hack

      - name: Check Cargo.lock is up to date
        run: |
          if ! cargo metadata --format-version 1 --locked --no-deps > /dev/null; then
            echo "::error::Cargo.lock is out of date. Run cargo generate-lockfile or cargo build locally, then commit Cargo.lock."
            exit 1
          fi

      - name: Check formatting
        run: cargo fmt --all -- --check

      - name: Check Clippy
        run: cargo clippy --all-targets --features full --all -- -D warnings

      - name: Check features
        if: ${{ !cancelled() }}
        run: cargo hack check --package easytier --each-feature --exclude-features macos-ne --verbose

  pre-test:
    name: Build test
    runs-on: ubuntu-latest
    needs: pre_job
    if: needs.pre_job.outputs.should_skip != 'true'
    steps:
      - uses: actions/checkout@v5

      - name: Prepare build environment
        uses: ./.github/actions/prepare-build
        with:
          gui: true
          web: true
          token: ${{ secrets.GITHUB_TOKEN }}

      - uses: Swatinem/rust-cache@v2

      - uses: taiki-e/install-action@nextest

      - name: Archive test
        run: cargo nextest archive --archive-file tests.tar.zst --package easytier --features full

      - uses: actions/upload-artifact@v5
        with:
          name: tests
          path: tests.tar.zst
          retention-days: 1

  test_matrix:
    name: Test (${{ matrix.name }})
    runs-on: ubuntu-latest
    needs: [ pre_job, pre-test ]
    if: needs.pre_job.outputs.should_skip != 'true'
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: "easytier"
            opts: "-E 'not test(tests::three_node)' --test-threads 1 --no-fail-fast"

          - name: "three_node"
            opts: "-E 'test(tests::three_node) and not test(subnet_proxy_three_node_test)' --test-threads 1 --no-fail-fast"

          - name: "three_node::subnet_proxy_three_node_test"
            opts: "-E 'test(subnet_proxy_three_node_test)' --test-threads 1 --no-fail-fast"
    steps:
      - uses: actions/checkout@v5

      - name: Setup tools for test
        run: sudo apt install bridge-utils

      - name: Setup system for test
        run: |
          sudo modprobe br_netfilter
          sudo sysctl net.bridge.bridge-nf-call-iptables=0
          sudo sysctl net.bridge.bridge-nf-call-ip6tables=0
          sudo sysctl net.ipv6.conf.lo.disable_ipv6=0
          sudo ip addr add 2001:db8::2/64 dev lo

      - uses: taiki-e/install-action@nextest

      - name: Download tests
        uses: actions/download-artifact@v4
        with:
          name: tests

      - name: Run tests
        run: |
          sudo prlimit --pid $$ --nofile=1048576:1048576
          sudo -E env "PATH=$PATH" cargo nextest run --archive-file tests.tar.zst ${{ matrix.opts }}

  test:
    runs-on: ubuntu-latest
    needs: [ pre_job, check, test_matrix ]
    if: needs.pre_job.result == 'success' && needs.pre_job.outputs.should_skip != 'true' && !cancelled()
    steps:
      - name: Mark result as failed
        if: contains(needs.*.result, 'failure')
        run: exit 1
