diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index dbf3440..741e135 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -67,4 +67,6 @@ jobs:
         with:
           tool: bpf-linker,cargo-generate
 
+      - run: sudo apt update
+      - run: sudo apt install expect
       - run: ./test.sh ${{ github.workspace }} ${{ matrix.program }}
diff --git a/test.sh b/test.sh
index 43984bd..0d39c59 100755
--- a/test.sh
+++ b/test.sh
@@ -1,20 +1,13 @@
-#!/bin/bash
+#!/usr/bin/env bash
 
-set -ex
+set -eux
 
 TEMPLATE_DIR=$1
 if [ -z "${TEMPLATE_DIR}" ]; then echo "template dir required"; exit 1; fi
 PROG_TYPE=$2
 if [ -z "${PROG_TYPE}" ]; then echo "program type required"; exit 1; fi
+CRATE_NAME=aya-test-crate
 
-TMP_DIR=$(mktemp -d)
-clean_up() {
-    # shellcheck disable=SC2317
-    rm -rf "${TMP_DIR}"
-}
-trap clean_up EXIT
-
-pushd "${TMP_DIR}"
 case "${PROG_TYPE}" in
     "cgroup_sockopt")
 	    ADDITIONAL_ARGS=(-d sockopt_target=getsockopt)
@@ -26,7 +19,7 @@ case "${PROG_TYPE}" in
         ADDITIONAL_ARGS=(-d fn_name=try_to_wake_up)
         ;;
     "kprobe"|"kretprobe")
-        ADDITIONAL_ARGS=(-d kprobe=test)
+        ADDITIONAL_ARGS=(-d kprobe=do_unlinkat)
         ;;
     "lsm")
         ADDITIONAL_ARGS=(-d lsm_hook=file_open)
@@ -44,21 +37,52 @@ case "${PROG_TYPE}" in
 	    ADDITIONAL_ARGS=(-d tracepoint_category=net -d tracepoint_name=net_dev_queue)
         ;;
     "uprobe"|"uretprobe")
-        ADDITIONAL_ARGS=(-d uprobe_target=testlib -d uprobe_fn_name=testfn)
+        ADDITIONAL_ARGS=(-d uprobe_target=/proc/self/exe -d uprobe_fn_name=main)
         ;;
     *)
         ADDITIONAL_ARGS=()
 esac
 
-cargo generate --path "${TEMPLATE_DIR}" -n test -d program_type="${PROG_TYPE}" "${ADDITIONAL_ARGS[@]}"
-pushd test
+TMP_DIR=$(mktemp -d)
+clean_up() {
+    # shellcheck disable=SC2317
+    rm -rf "${TMP_DIR}"
+}
+trap clean_up EXIT
+
+pushd "${TMP_DIR}"
+cargo generate --path "${TEMPLATE_DIR}" -n "${CRATE_NAME}" -d program_type="${PROG_TYPE}" "${ADDITIONAL_ARGS[@]}"
+pushd "${CRATE_NAME}"
+
 cargo +nightly fmt --all -- --check
-cargo build --package test
-cargo build --package test --release
-# We cannot run clippy over the whole workspace at once due to feature unification. Since both test
-# and test-ebpf depend on test-common and test activates test-common's aya dependency, we end up
-# trying to compile the panic handler twice: once from the bpf program, and again from std via aya.
-cargo clippy --exclude test-ebpf --all-targets --workspace -- --deny warnings
-cargo clippy --package test-ebpf --all-targets -- --deny warnings
-popd
-exit 0
+cargo build --package "${CRATE_NAME}"
+cargo build --package "${CRATE_NAME}" --release
+# We cannot run clippy over the whole workspace at once due to feature unification. Since both
+# ${CRATE_NAME} and ${CRATE_NAME}-ebpf depend on ${CRATE_NAME}-common and ${CRATE_NAME} activates
+# ${CRATE_NAME}-common's aya dependency, we end up trying to compile the panic handler twice: once
+# from the bpf program, and again from std via aya.
+cargo clippy --exclude "${CRATE_NAME}-ebpf" --all-targets --workspace -- --deny warnings
+cargo clippy --package "${CRATE_NAME}-ebpf" --all-targets -- --deny warnings
+
+expect << EOF
+  set timeout 30        ;# Increase timeout if necessary
+  spawn cargo xtask run
+  expect {
+    -re "Waiting for Ctrl-C.*" {
+      send -- \003      ;# Send Ctrl-C
+    }
+    timeout {
+      puts "Error: Timed out waiting for 'Waiting for Ctrl-C...'"
+      exit 1
+    }
+    eof {
+      puts "Error: Process exited prematurely"
+      exit 1
+    }
+  }
+
+  expect {
+    -re "Exiting.*" { }
+    eof { }
+  }
+EOF
diff --git a/{{project-name}}-ebpf/src/main.rs b/{{project-name}}-ebpf/src/main.rs
index 63be060..64cfb70 100644
--- a/{{project-name}}-ebpf/src/main.rs
+++ b/{{project-name}}-ebpf/src/main.rs
@@ -14,7 +14,7 @@ pub fn {{crate_name}}(ctx: ProbeContext) -> u32 {
 }
 
 fn try_{{crate_name}}(ctx: ProbeContext) -> Result<u32, u32> {
-    info!(&ctx, "function {{kprobe}} called");
+    info!(&ctx, "kprobe called");
     Ok(0)
 }
 {%- when "kretprobe" %}
@@ -30,7 +30,7 @@ pub fn {{crate_name}}(ctx: RetProbeContext) -> u32 {
 }
 
 fn try_{{crate_name}}(ctx: RetProbeContext) -> Result<u32, u32> {
-    info!(&ctx, "function {{kprobe}} called");
+    info!(&ctx, "kretprobe called");
     Ok(0)
 }
 {%- when "fentry" %}
diff --git a/{{project-name}}/src/main.rs b/{{project-name}}/src/main.rs
index ea7baa8..e429865 100644
--- a/{{project-name}}/src/main.rs
+++ b/{{project-name}}/src/main.rs
@@ -61,7 +61,7 @@ struct Opt {
     #[clap(short, long, default_value = "eth0")]
     iface: String,
 {%- when "sock_ops", "cgroup_skb", "cgroup_sysctl", "cgroup_sockopt" %}
-    #[clap(short, long, default_value = "/sys/fs/cgroup/unified")]
+    #[clap(short, long, default_value = "/sys/fs/cgroup")]
     cgroup_path: std::path::PathBuf,
 {%- when "uprobe", "uretprobe" %}
     #[clap(short, long)]