name: Test Asterinas

on:
  pull_request:
  push:
    branches:
      - main
  # Schedule to run on every day at 22:00 UTC (06:00 Beijing Time)
  schedule:
    - cron: '0 22 * * *'

jobs:
  lint:
    if: github.event_name == 'push' || github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    timeout-minutes: 15
    container: asterinas/asterinas:0.14.0
    steps:
      - run: echo "Running in asterinas/asterinas:0.14.0"

      - uses: actions/checkout@v4
      
      - name: Check
        id: check
        run: make check

  compilation:
    if: github.event_name == 'push' || github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    timeout-minutes: 15
    container: asterinas/asterinas:0.14.0
    steps:
      - run: echo "Running in asterinas/asterinas:0.14.0"

      - uses: actions/checkout@v4

      # The compilation test builds the project with all features enabled.
      # In contrast, subsequent tests may choose to enable select features.
      - name: Compilation
        id: compilation
        run: make build FEATURES=all

  unit-test:
    if: github.event_name == 'push' || github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    timeout-minutes: 15
    container: 
      image: asterinas/asterinas:0.14.0
      options: --device=/dev/kvm --privileged
    steps:
      - run: echo "Running in asterinas/asterinas:0.14.0"

      - uses: actions/checkout@v4

      - name: Usermode Unit test
        id: usermode_unit_test
        run: make test

      - name: Ktest Unit Test
        id: ktest_unit_test
        run: make ktest NETDEV=tap

      # TODO: add component check.

  integration-test:
    if: github.event_name == 'push' || github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    timeout-minutes: 15
    container:
      image: asterinas/asterinas:0.14.0
      options: --device=/dev/kvm --privileged
    strategy:
      matrix:
        # The ids of each test
        test_id:
          - 'boot_test_mb'
          - 'boot_test_linux_legacy32'
          - 'syscall_test'
          - 'syscall_test_at_ext2_microvm'
          - 'syscall_test_at_ext2_iommu'
          - 'syscall_test_at_exfat_linux'
          - 'smp_syscall_test_mb2'
          - 'test_linux'
          - 'smp_test_mb2'
      fail-fast: false

    steps:
      - run: echo "Running in asterinas/asterinas:0.14.0"

      - uses: actions/checkout@v4

      - name: SMP Boot Test (Multiboot)
        id: boot_test_mb
        if: ${{ matrix.test_id == 'boot_test_mb' }}
        run: make run AUTO_TEST=boot ENABLE_KVM=1 BOOT_PROTOCOL=multiboot RELEASE=1 SMP=4 NETDEV=tap

      - name: SMP Boot Test (Linux Legacy 32-bit Boot Protocol)
        id: boot_test_linux_legacy32
        if: ${{ matrix.test_id == 'boot_test_linux_legacy32' }}
        run: make run AUTO_TEST=boot ENABLE_KVM=1 BOOT_PROTOCOL=linux-legacy32 RELEASE=1 SMP=4 NETDEV=tap

      - name: Syscall Test (Linux EFI Handover Boot Protocol) (Debug Build)
        id: syscall_test
        if: ${{ matrix.test_id == 'syscall_test' }}
        run: make run AUTO_TEST=syscall ENABLE_KVM=1 BOOT_PROTOCOL=linux-efi-handover64 RELEASE=0 NETDEV=tap

      - name: Syscall Test at Ext2 (MicroVM)
        id: syscall_test_at_ext2_microvm
        if: ${{ matrix.test_id == 'syscall_test_at_ext2_microvm' }}
        run: make run AUTO_TEST=syscall SYSCALL_TEST_DIR=/ext2 ENABLE_KVM=1 SCHEME=microvm RELEASE=1 NETDEV=tap

      - name: Syscall Test at Ext2 (IOMMU) (Debug Build)
        id: syscall_test_at_ext2_iommu
        if: ${{ matrix.test_id == 'syscall_test_at_ext2_iommu' }}
        run: make run AUTO_TEST=syscall SYSCALL_TEST_DIR=/ext2 ENABLE_KVM=1 SCHEME=iommu RELEASE=0 NETDEV=tap

      - name: Syscall Test at Exfat (Multiboot2) (without KVM enabled)
        id: syscall_test_at_exfat_linux
        if: ${{ matrix.test_id == 'syscall_test_at_exfat_linux' }}
        run: |
          make run AUTO_TEST=syscall \
            SYSCALL_TEST_DIR=/exfat EXTRA_BLOCKLISTS_DIRS=blocklists.exfat \
            ENABLE_KVM=0 BOOT_PROTOCOL=multiboot2 RELEASE=1 NETDEV=tap
      
      - name: SMP Syscall Test (Multiboot2)
        id: smp_syscall_test_mb2
        if: ${{ matrix.test_id == 'smp_syscall_test_mb2' }}
        run: make run AUTO_TEST=syscall ENABLE_KVM=1 BOOT_PROTOCOL=multiboot2 RELEASE=1 SMP=4 NETDEV=tap

      - name: General Test (Linux EFI Handover Boot Protocol)
        id: test_linux
        if: ${{ matrix.test_id == 'test_linux' }}
        run: make run AUTO_TEST=test ENABLE_KVM=1 BOOT_PROTOCOL=linux-efi-handover64 RELEASE=1 NETDEV=tap
      
      - name: SMP General Test (Multiboot2)
        id: smp_test_mb2
        if: ${{ matrix.test_id == 'smp_test_mb2' }}
        run: make run AUTO_TEST=test ENABLE_KVM=1 BOOT_PROTOCOL=multiboot2 RELEASE=1 SMP=4 NETDEV=tap

  integration-test-tdx:
    if: github.event_name == 'schedule'
    runs-on: self-hosted
    timeout-minutes: 30
    container:
      image: asterinas/asterinas:0.14.0-tdx
      options: --device=/dev/kvm --privileged
    env:
      # Need to set up proxy since the self-hosted CI server is located in China,
      # which has poor network connection to the official Rust crate repositories.
      RUSTUP_DIST_SERVER: https://mirrors.ustc.edu.cn/rust-static
      RUSTUP_UPDATE_ROOT: https://mirrors.ustc.edu.cn/rust-static/rustup
    steps:
      - run: echo "Running in asterinas/asterinas:0.14.0-tdx"
      - uses: actions/checkout@v4
      - name: Set up the environment
        run: |
          chmod +x test/benchmark/bench_linux_and_aster.sh
          # Set up git due to the network issue on the self-hosted runner
          git config --global --add safe.directory /__w/asterinas/asterinas
          git config --global http.sslVerify false
          git config --global http.version HTTP/1.1
      - name: TDX Boot Test
        uses: nick-invision/retry@v2
        id: tdx_boot_test
        with:
          timeout_minutes: 20
          max_attempts: 3
          command: make run AUTO_TEST=boot RELEASE=1 INTEL_TDX=1

      - name: TDX Syscall Test
        uses: nick-invision/retry@v2
        id: tdx_syscall_test
        with:
          timeout_minutes: 20
          max_attempts: 3
          command: make run AUTO_TEST=syscall RELEASE=1 INTEL_TDX=1

      - name: TDX Syscall Test at Exfat
        uses: nick-invision/retry@v2
        id: tdx_syscall_test_at_exfat
        with:
          timeout_minutes: 20
          max_attempts: 3
          command: make run AUTO_TEST=syscall SYSCALL_TEST_DIR=/exfat EXTRA_BLOCKLISTS_DIRS=blocklists.exfat RELEASE=1 INTEL_TDX=1

      - name: TDX General Test
        uses: nick-invision/retry@v2
        id: tdx_general_test
        with:
          timeout_minutes: 20
          max_attempts: 3
          command: make run AUTO_TEST=test RELEASE=1 INTEL_TDX=1

      - name: TDX SMP Boot Test
        uses: nick-invision/retry@v2
        id: tdx_smp_boot_test
        with:
          timeout_minutes: 20
          max_attempts: 3
          command: make run AUTO_TEST=boot INTEL_TDX=1 RELEASE=1 SMP=4 NETDEV=tap

      - name: TDX SMP General Test
        uses: nick-invision/retry@v2
        id: tdx_smp_general_test
        with:
          timeout_minutes: 20
          max_attempts: 3
          command: make run AUTO_TEST=test INTEL_TDX=1 RELEASE=1 SMP=4 NETDEV=tap

      - name: TDX SMP Syscall Test
        uses: nick-invision/retry@v2
        id: tdx_smp_syscall_test
        with:
          timeout_minutes: 20
          max_attempts: 3
          command: make run AUTO_TEST=syscall INTEL_TDX=1 RELEASE=1 SMP=4 NETDEV=tap
