summary: Verify kernel modules components work as expected
details: |
  Install a kernel-modules component and verify that the shipped
  kernel module is installed.

systems: [-ubuntu-1*, -ubuntu-20*, -ubuntu-22*]
environment:
  # Test both encrypted and unencrypted cases
  NESTED_ENABLE_TPM/encrypted: true
  NESTED_ENABLE_SECURE_BOOT/encrypted: true

  # unencrypted case
  NESTED_ENABLE_TPM/plain: false
  NESTED_ENABLE_SECURE_BOOT/plain: false

  NESTED_BUILD_SNAPD_FROM_CURRENT: true

prepare: |
  # Modify kernel and create a component
  "$TESTSTOOLS"/build_kernel_with_comps.sh mac80211_hwsim wifi-comp

  cp pc-kernel.snap "$(tests.nested get extra-snaps-path)"
  tests.nested build-image core
  tests.nested create-vm core

execute: |
  # Compare times to check that drivers tree was created on
  # installation, not on seeding
  # shellcheck disable=SC2016
  tree_birth=$(remote.exec 'date -d"$(stat --printf="%w\n" /var/lib/snapd/kernel/pc-kernel)" +%s')
  reboot_time=$(remote.exec 'last reboot --time-format full | sed -n "s/wtmp begins //p"')
  reboot_time=$(date -d"$reboot_time" +%s)
  test "$reboot_time" -gt "$tree_birth"

  # Loading the module fails
  not remote.exec modprobe mac80211_hwsim

  # install the component
  comp_file=pc-kernel+wifi-comp.comp
  remote.push "$comp_file"
  remote.exec sudo snap install --dangerous "$comp_file"

  # check that the component is in place
  kern_ver=$(remote.exec uname -r)
  comp_install_dir=/var/lib/snapd/kernel/pc-kernel/x1/lib/modules/"$kern_ver"/updates/wifi-comp
  comp_dir=/snap/pc-kernel/components/mnt/wifi-comp/x1/modules/"$kern_ver"
  test "$(remote.exec readlink -f "$comp_install_dir")" = "$comp_dir"

  # check that module can be loaded/unloaded
  remote.exec sudo modprobe mac80211_hwsim
  remote.exec ip link show wlan0
  remote.exec sudo rmmod mac80211_hwsim
  not remote.exec ip link show wlan0

  # remove the component
  remote.exec sudo snap remove pc-kernel+wifi-comp
  not remote.exec grep mac80211_hwsim /lib/modules/*/modules.dep
  not remote.exec sudo modprobe mac80211_hwsim

  # Rule to force module loading on system start (we randomly choose
  # the rtc device add event for this)
  rule='ACTION==\"add\", SUBSYSTEM==\"rtc\", KERNEL==\"rtc*\", RUN{builtin}+=\"kmod load mac80211_hwsim\"\n'
  remote.exec "sudo sh -c 'printf \"$rule\" > /etc/udev/rules.d/70-load-wifi.rules'"

  # Install jointly kernel with component
  remote.push pc-kernel.snap
  boot_id=$(tests.nested boot-id)
  remote_chg_id=$(remote.exec sudo snap install --no-wait --dangerous pc-kernel.snap "$comp_file")
  tests.nested wait-for reboot "$boot_id"
  remote.exec sudo snap watch "$remote_chg_id"
  remote.exec "snap change $remote_chg_id" | NOMATCH Error
  # Check that the module has been loaded by the udev rule
  remote.exec ip link show wlan0

  # Install again, but force a failure to check revert
  boot_id=$(tests.nested boot-id)
  remote.exec sudo systemd-inhibit bash <<\EOF &
  count=0
  while ! [ -e /run/mnt/ubuntu-boot/EFI/ubuntu/try-kernel.efi ]; do
    if [ "$((count++))" -gt 300 ]; then
      exit 1
    fi
    sleep 1
  done
  rm /run/mnt/ubuntu-boot/EFI/ubuntu/try-kernel.efi
  EOF
  kernel_remover="${!}"
  remote_chg_id=$(remote.exec sudo snap install --no-wait --dangerous pc-kernel.snap "$comp_file")
  wait "${kernel_remover}"
  tests.nested wait-for reboot "$boot_id"
  # Note that snap watch will end with error
  not remote.exec sudo snap watch "$remote_chg_id"
  remote.exec "snap change $remote_chg_id | MATCH Error"
  # Module is still loaded
  remote.exec ip link show wlan0
