name: hostap and wpa-supplicant Tests

on:
  workflow_call:

jobs:
  build_wolfssl:
    strategy:
      matrix:
        include:
          - build_id: hostap-build1
            wolf_extra_config: --disable-tls13
          - build_id: hostap-build2
            wolf_extra_config: --enable-brainpool --enable-wpas-dpp
    name: Build wolfSSL
    # Just to keep it the same as the testing target
    runs-on: ubuntu-20.04
    # This should be a safe limit for the tests to run.
    timeout-minutes: 4
    steps:
        # No way to view the full strategy in the browser (really weird)
      - name: Print strategy
        run: |
          cat <<EOF
          ${{ toJSON(matrix) }}
          EOF

      - if: ${{ runner.debug }}
        name: Enable wolfSSL debug logging
        run: |
          echo "wolf_debug_flags=--enable-debug" >> $GITHUB_ENV

      - name: Build wolfSSL
        uses: wolfSSL/actions-build-autotools-project@v1
        with:
          path: wolfssl
          configure: >-
            --enable-wpas CFLAGS=-DWOLFSSL_STATIC_RSA
            ${{ env.wolf_debug_flags }} ${{ matrix.wolf_extra_config }}
          install: true

      - name: Upload built lib
        uses: actions/upload-artifact@v3
        with:
          name: ${{ matrix.build_id }}
          path: build-dir
          retention-days: 1

  # Build wpa_supplicant with wolfSSL and hostapd with OpenSSL and interop.
  hostap_test:
    strategy:
      fail-fast: false
      matrix:
        # should hostapd be compiled with wolfssl
        hostapd: [true, false]
        # should wpa_supplicant be compiled with wolfssl
        wpa_supplicant: [true, false]
        # Fix the versions of hostap and osp to not break testing when a new
        # patch is added in to osp. hostap_cherry_pick is used to apply the
        # commit that updates the certificates used for testing. Tests are read
        # from the corresponding configs/hostap_ref/tests file.
        config: [
          {
            hostap_ref: hostap_2_10,
            hostap_cherry_pick: 5679ec5c3dda25a0547a5f66407fd9b0b55fd04a,
            remove_teap: true,
            # TLS 1.3 does not work for this version
            build_id: hostap-build1,
          },
          # Test the dpp patch
          {
            hostap_ref: b607d2723e927a3446d89aed813f1aa6068186bb,
            hostap_cherry_pick: 5679ec5c3dda25a0547a5f66407fd9b0b55fd04a,
            osp_ref: ad5b52a49b3cc2a5bfb47ccc1d6a5137132e9446,
            build_id: hostap-build2
          },
        ]
        # parallelize the tests to be able to run all tests within 10 minutes
        # Update the <total server> in the ./run-tests.py step when changing.
        server: [1, 2, 3, 4, 5]
        exclude:
          # don't test openssl on both sides
          - hostapd: false
            wpa_supplicant: false
          # no hostapd support for dpp yet
          - hostapd: true
            config: {
              hostap_ref: b607d2723e927a3446d89aed813f1aa6068186bb,
              osp_ref: ad5b52a49b3cc2a5bfb47ccc1d6a5137132e9446,
              build_id: hostap-build2
            }
    name: hwsim test
    # For openssl 1.1
    runs-on: ubuntu-20.04
    # This should be a safe limit for the tests to run.
    timeout-minutes: 12
    needs: build_wolfssl
    steps:
        # No way to view the full strategy in the browser (really weird)
      - name: Print strategy
        run: |
          cat <<EOF
          ${{ toJSON(matrix) }}
          EOF

      - name: Print computed job run ID
        run: |
          SHA_SUM=$(sha256sum << 'END_OF_HEREDOC' | cut -d " " -f 1
          ${{ toJSON(github) }}
          END_OF_HEREDOC
          )
          echo "our_job_run_id=$SHA_SUM" >> $GITHUB_ENV
          echo Our job run ID is $SHA_SUM

      - name: Checkout wolfSSL
        uses: actions/checkout@v3
        with:
          path: wolfssl

      - name: Install dependencies
        run: |
          # Don't prompt for anything
          export DEBIAN_FRONTEND=noninteractive
          sudo apt-get update
          # hostap dependencies
          sudo apt-get install -y libpcap0.8 libpcap-dev curl libcurl4-openssl-dev \
            libnl-3-dev binutils-dev libssl-dev libiberty-dev libnl-genl-3-dev \
            libnl-route-3-dev libdbus-1-dev linux-modules-extra-`uname -r` \
            bridge-utils
          sudo pip3 install pycryptodome

      - name: Enable mac80211
        run: |
          sudo modprobe mac80211
          lsmod | grep mac80211

      - if: ${{ runner.debug }}
        name: Enable hostap debug logging
        run: |
          echo "hostap_debug_flags=-d" >> $GITHUB_ENV

      - name: Download lib
        uses: actions/download-artifact@v3
        with:
          name: ${{ matrix.config.build_id }}
          path: build-dir

      - name: Setup d-bus
        working-directory: wolfssl/.github/workflows/hostap-files
        run: |
          sudo cp dbus-wpa_supplicant.conf /usr/share/dbus-1/system.d/wpa_supplicant.conf
          sudo service dbus reload

        # This is super hack-ish :P
        # If you are trying to reproduce this on a more generic system, you can
        # just run `sudo apt install linux-modules-extra-$(uname -r)` and
        # this should have the module in the package. No need to compile it.
      - name: Compile and install mac80211_hwsim
        working-directory: wolfssl/.github/workflows/hostap-files
        run: |
          # The tag will be the first two numbers of from uname -r
          LINUX_TAG=$(uname -r | grep -oP '^\d+\.\d+')
          # Download the correct version of the driver
          wget https://raw.githubusercontent.com/torvalds/linux/v$LINUX_TAG/drivers/net/wireless/mac80211_hwsim.c
          wget https://raw.githubusercontent.com/torvalds/linux/v$LINUX_TAG/drivers/net/wireless/mac80211_hwsim.h
          make
          sudo make install
          sudo modprobe mac80211_hwsim
          lsmod | grep mac80211_hwsim
          sudo rmmod mac80211_hwsim

      - name: Checkout hostap
        uses: actions/checkout@v3
        with:
          repository: julek-wolfssl/hostap-mirror 
          path: hostap
          ref: ${{ matrix.config.hostap_ref }}
          # necessary for cherry pick step
          fetch-depth: 0

      - if: ${{ matrix.config.hostap_cherry_pick }}
        name: Cherry pick certificate update
        working-directory: hostap
        run: git cherry-pick -n -X theirs ${{ matrix.config.hostap_cherry_pick }}

      - if: ${{ matrix.config.osp_ref }}
        name: Checkout OSP
        uses: actions/checkout@v3
        with:
          repository: wolfssl/osp
          path: osp
          ref: ${{ matrix.config.osp_ref }}

      - if: ${{ matrix.config.osp_ref }}
        name: Apply patch files
        working-directory: hostap
        run: |
          for f in $GITHUB_WORKSPACE/osp/hostap-patches/pending/*
          do
            patch -p1 < $f
          done

      - if: ${{ matrix.hostapd }}
        name: Setup hostapd config file 
        run: |
          cp wolfssl/.github/workflows/hostap-files/configs/${{ matrix.config.hostap_ref }}/hostapd.config \
             hostap/hostapd/.config
          cat <<EOF >> hostap/hostapd/.config
            CFLAGS += -I$GITHUB_WORKSPACE/build-dir/include -Wl,-rpath=$GITHUB_WORKSPACE/build-dir/lib
            LIBS += -L$GITHUB_WORKSPACE/build-dir/lib -Wl,-rpath=$GITHUB_WORKSPACE/build-dir/lib
          EOF

      - if: ${{ matrix.wpa_supplicant }}
        name: Setup wpa_supplicant config file 
        run: |
          cp wolfssl/.github/workflows/hostap-files/configs/${{ matrix.config.hostap_ref }}/wpa_supplicant.config \
             hostap/wpa_supplicant/.config
          cat <<EOF >> hostap/wpa_supplicant/.config
            CFLAGS += -I$GITHUB_WORKSPACE/build-dir/include -Wl,-rpath=$GITHUB_WORKSPACE/build-dir/lib
            LIBS += -L$GITHUB_WORKSPACE/build-dir/lib -Wl,-rpath=$GITHUB_WORKSPACE/build-dir/lib
          EOF

      - name: Build hostap
        working-directory: hostap/tests/hwsim/
        run: ./build.sh

      - if: ${{ matrix.hostapd }}
        name: Confirm hostapd linking with wolfSSL
        run: ldd hostap/hostapd/hostapd | grep wolfssl

      - if: ${{ matrix.wpa_supplicant }}
        name: Confirm wpa_supplicant linking with wolfSSL
        run: ldd hostap/wpa_supplicant/wpa_supplicant | grep wolfssl

      - if: ${{ matrix.config.remove_teap }}
        name: Remove EAP-TEAP from test configuration
        working-directory: hostap/tests/hwsim/auth_serv
        run: |
          sed -e 's/"erp-teap@example.com"\tTEAP//' -i eap_user.conf
          sed -e 's/"erp-teap@example.com"\tMSCHAPV2\t"password"\t\[2\]//' -i eap_user.conf
          sed -e 's/"TEAP"\t\tTEAP//' -i eap_user.conf
          sed -e 's/TEAP,//' -i eap_user.conf

      - name: Run tests
        id: testing
        working-directory: hostap/tests/hwsim/
        run: |
          # Run tests in increments of 50 to cut down on the uploaded log size.
          while mapfile -t -n 50 ary && ((${#ary[@]})); do
            TESTS=$(printf '%s\n' "${ary[@]}" | tr '\n' ' ')
            # Retry up to three times
            for i in {1..3}; do
              HWSIM_RES=0 # Not set when command succeeds
              # Logs can grow quickly especially in debug mode
              sudo rm -rf logs
              sudo ./start.sh
              sudo ./run-tests.py ${{ env.hostap_debug_flags }} --split ${{ matrix.server }}/5 $TESTS || HWSIM_RES=$?
              sudo ./stop.sh
              if [ "$HWSIM_RES" -eq "0" ]; then
                break
              fi
            done
            echo "test ran $i times"
            if [ "$HWSIM_RES" -ne "0" ]; then
              exit $HWSIM_RES
            fi
          done < $GITHUB_WORKSPACE/wolfssl/.github/workflows/hostap-files/configs/${{ matrix.config.hostap_ref }}/tests

      - name: Change failure log permissions
        if: ${{ failure() && steps.testing.outcome == 'failure' }}
        working-directory: hostap/tests/hwsim/
        run: |
          sudo chown -R $USER:$USER logs
          zip -9 -r logs.zip logs/current

      - name: Upload failure logs
        if: ${{ failure() && steps.testing.outcome == 'failure' }}
        uses: actions/upload-artifact@v3
        with:
          name: hostap-logs-${{ env.our_job_run_id }}
          path: hostap/tests/hwsim/logs.zip
          retention-days: 5

