# # Common test library # # # sanity checks # acctest_boardsetup() { test_begin checking "for boardsetup file" test -f "${PTXDIST_BOARDSETUP}" result fatal test_end } # # test if we have a ptxconfig file in the project # acctest_ptxconfig() { test_begin checking "if ptxconfig exists" test -e "${PTXDIST_WORKSPACE}/selected_ptxconfig" result test_end } # # do we have network access to the target? # acctest_ping() { test_begin checking "response to icmp ping requests" ping -q -n -c1 ${PTXCONF_BOARDSETUP_TARGETIP} result test_end } # # Check if the target listens on a specific port # Note: Runs on the host # # $1 name or ip address # $2 check for port # function acctest_open_port() { test_begin checking "if port '$2' at '$1' waits for connections" nc -z $1 $2 result test_end } # # check for required PTXdist version # # $1 Version to check for # acctest_ptxdist() { test_begin checking "ptxdist version" test "${PTXDIST_VERSION_FULL}" = "$1" result test_end } # # $1 Partition string to test for # acctest_flash_partition() { test_begin local mtdX=$1 local X=${mtdX/"mtd"} checking "${mtdX} layout" remote_compare "grep \"^${mtdX}\" /proc/mtd" "${mtdX}: ${mtd_line[$X]}" result test_end } # # check memory # acctest_memory() { test_begin local memory=$(echo $(remote 'grep "^MemTotal" /proc/meminfo') | sed -e "s/^MemTotal: *//g") checking "memory: $memory" test "${memory: -2}" = "kB" result test_end } # # Check for CPU's FPU feature (or not) # imx_fpu_test() { local fpu="" test_begin if [ $1 = true ]; then checking "FPU support" else checking "No FPU support" fi fpu=$(echo $(remote 'grep "^Features" /proc/cpuinfo | grep vfp')) if [ $1 = true ]; then if [ -z "$fpu" ]; then result_fail else result_ok fi else if [ -z "$fpu" ]; then result_ok else result_fail fi fi test_end } # # check if root filesystem is jffs2 # acctest_rootfs_jffs2() { test_begin checking "if root filesystem is jffs2 and rw" remote_compare 'mount | grep "/dev/root" | cut -f5 -d" "' 'jffs2' result test_end } # # check if root filesystem is ext2 # acctest_rootfs_ext2() { test_begin checking "if root filesystem is ext2 and rw" remote_compare 'mount | grep "/dev/root" | cut -f5 -d" "' 'ext2' result test_end } # # check if root filesystem is ubifs # acctest_rootfs_ubifs() { test_begin checking "if root filesystem is ubifs and rw" remote_compare 'mount | grep "ubi0:root" | cut -f5 -d" "' 'ubifs' result test_end } # # check if vital files are present # # $1 file to check for # acctest_files() { test_begin checking "if file $1 exists" remote_file "$1" exists result test_end } # # check if a file is not present # # $1 file to check for # acctest_no_files() { test_begin checking "if file $1 not exists" remote_file "$1" exists local exitstatus=$? test ${exitstatus} -eq 1 result test_end } # # check if a link is not present # # $1 file to check for # acctest_no_link() { test_begin checking "if link $1 not exists" echo "remote \"test -h $1\"" >> "$LOGFILE" remote "test -h \"$1\"" 2>> "$LOGFILE" local exitstatus=$? test ${exitstatus} -eq 1 result test_end } # # check if vital processes are running, uhh sleeping # acctest_process() { test_begin checking "if process $1 is active" remote_assure_process "$1" result test_end } # # check for vital devices nodes # acctest_devicenode() { local DEV_TYPE=${2:-character} test_begin checking "if device $1 exists" remote_file "$1" $DEV_TYPE result test_end } # # check for network interface(s) in sysfs # acctest_network_device() { test_begin checking "if network interface $1 exists" remote_file "/sys/class/net/$1" exists result test_end } # # check for specific bus(ses) in sysfs # acctest_bus() { test_begin checking "if bus $1 exists" remote_file "/sys/bus/$1" exists result test_end } # # check for specific class(ses) in sysfs # acctest_class() { test_begin checking "if class $1 exists" remote_file "/sys/class/$1" exists result test_end } # # check that unwanted devices do not exist # acctest_nodevice() { test_begin checking "that device $1 does not exist" remote_file "$1" exists local exitstatus=$? test ${exitstatus} -eq 1 result test_end } # # is an executable binary available # acctest_command_executable() { test_begin checking "if command $1 is executable" remote_file "$1" executable result test_end } # # kernel module present? # acctest_module() { test_begin checking "if module $1 appears in lsmod" remote_assure_module "$1" result test_end } # # check that "Kernel announces correct kernel release number" # # $1 kernel release string # acctest_kernel_release() { test_begin checking "kernel release number" remote_compare 'uname -r' "$1" result test_end } # # check that the platform announces the correct name [EDITME] # # $0 platform name # acctest_platform_name() { test_begin checking "platform name" test "${PTXCONF_PLATFORM}" = "$1" result test_end } # # check that the platform announces the correct release number # # $1 Release number string # acctest_platform_release() { test_begin checking "platform release number" test "${PTXCONF_PLATFORM_VERSION}" = "$1" result test_end } # # check network services (multiple test) # # $1 title # $2 port number # $3 string to check # $4 penetration counter # acctest_network_services() { checking "$1" for i in $(seq $4) do local nmap=$(nmap ${PTXCONF_BOARDSETUP_TARGETIP}) done test "$(echo "$nmap" | grep "^$2/" | sed 's/ */ /g')" = "$3" result } # # check network reliability # # $1 repeats # acctest_network_reliability() { # test_begin in for loop checking "for netcat on target" remote_file "/bin/netcat" executable result fatal local repeats=$1 local ddoptions="bs=10M count=1" local randomdata=$(mktemp) || exit 1 dd if=/dev/urandom of=$randomdata $ddoptions 2> /dev/null local correctmd5=($(md5sum $randomdata)) for i in `seq 1 $repeats`; do test_begin checking "network reliability, pass $i of $repeats" remote "(dd if=/dev/stdout $ddoptions 2>/dev/null | netcat -l -p 12222 > /dev/stdin &)"& sleep 1 local receivedmd5=($(netcat -q 3 ${PTXCONF_BOARDSETUP_TARGETIP} 12222 < $randomdata | md5sum)) test ${receivedmd5[0]} = ${correctmd5[0]} result test_end done rm -f $randomdata } # # check network throughput with iperf # # $1 durations # $2 how many kbits/s do we expect for a PASS # acctest_network_throughput() { checking "for iperf on target" remote_file "/usr/bin/iperf" executable result fatal checking "for running iperf server on this machine" curl -s -m 1 "telnet://${PTXCONF_BOARDSETUP_SERVERIP}:5001" if [ $? = 28 ] # iperf is running on this machine then result local duration=$1 local threshold=$2 checking "network throughput averaged over $duration seconds" local ret=$(remote "iperf -c ${PTXCONF_BOARDSETUP_SERVERIP} -d -t $duration -f k") local upstream_id=$(echo "$ret" | grep ".* connected with .* 5001$" | sed 's/^\[\(.*\)\].*/\1/') local downstream_id=$(echo "$ret" | grep "port 5001 connected with" | sed 's/^\[\(.*\)\].*/\1/') local upstreamkbits=$(echo "$ret" | grep "^\[$upstream_id\] " | sed 's/ */ /g' | cut -f7 -d" ") local upstreamkbits=$(echo "$upstreamkbits/1" | bc) # cut away decimal places local downstreamkbits=$(echo "$ret" | grep "^\[$downstream_id\] " | sed 's/ */ /g' | cut -f7 -d" ") local downstreamkbits=$(echo "$downstreamkbits/1" | bc) # cut away decimal places write_to_log "Upstream (DUT to server): $upstreamkbits kbits/s" write_to_log "Downstream (server to DUT): $downstreamkbits kbits/s" test $upstreamkbits -ge $threshold -a $downstreamkbits -ge $threshold result else write_to_log "There is no iperf server running on this machine at ${PTXCONF_BOARDSETUP_SERVERIP}!" false result fi } # # check for a running busybox multi-call binary # acctest_busybox() { test_begin checking "for busybox" ret=$(remote 'busybox | head -n1') test "${ret:0:7}" = "BusyBox" result test_end } # # check fb display resolution # # $1 width # $2 height # acctest_display_resolution() { test_begin local expected_resolution="$1 $2" checking "frame buffer display resolution" local ret=$(remote 'busybox | head -n1') # remote_compare "/usr/sbin/fbset | awk \"NR == 2 {print \\\$2, \\\$3}\"" "${expected_resolution}" remote_compare "/usr/sbin/fbset | grep geometry | awk \"{print \\\$2, \\\$3}\"" "${expected_resolution}" result test_end } # # check eeprom read and write capability # # $1 path to the entry # $2 size # acctest_eeprom_rw() { local zeromd5[1024]="0f343b0931126a20f133d67c2b018a3b" local zeromd5[2048]="c99a74c555371a433d121f551d6c6398" local zeromd5[4096]="620f0b67a91f7f74151bc5be745b7110" local zeromd5[8192]="0829f71740aab1ab98b33eae21dee122" local zeromd5[16384]="ce338fe6899778aacfc28414f2d9498b" local zeromd5[32768]="bb7df04e1b0a2570657527a7e108ae23" test_begin local eeprom_rw_startingtime=$(date +%s) local path="$1" local size=$2 # The first 2KiB are used by uboot environment, we don't want to overwrite it, # hence we only test the upper 2KiB checking "eeprom read/write with random data" remote "dd if=/dev/urandom bs=${size} count=1 2>/dev/null > /tmp/random.dat" local correctmd5=($(remote "md5sum /tmp/random.dat")) remote "dd if=/tmp/random.dat of=${path} bs=${size} seek=1 2>/dev/null" remote "dd if=${path} of=/tmp/eeprom.dat bs=${size} skip=1 2>/dev/null" local readmd5=($(remote "md5sum /tmp/eeprom.dat")) test ${readmd5[0]} = ${correctmd5[0]} result checking "eeprom read/write with zeros" remote "dd if=/dev/zero of=${path} bs=${size} count=1 seek=1 2>/dev/null" remote "dd if=${path} of=/tmp/eeprom.dat bs=${size} skip=1 2>/dev/null" local readzeromd5=($(remote "md5sum /tmp/eeprom.dat")) local eeprom_rw_endingtime=$(date +%s) test ${readzeromd5[0]} = ${zeromd5[${size}]} result test_end # Now check if it took way too long to test the EEPROM. # This happens for example when single-byte writing is being used # instead of page-writing test_begin local timediff=$(($eeprom_rw_endingtime-$eeprom_rw_startingtime)) checking "if test duration (= $timediff s) was below limit" test ${timediff} -le 20 result test_end } # # check if hardware clock is accepting and reproducing date/time # acctest_hwclock() { test_begin local first=$(remote "date -u +%s") local present_time=$(remote "date -u +%m%d%H%M%Y.%S") # store present system time in hardware remote "/sbin/hwclock --systohc" checking "y2k capability of system clock" # set a completely different date in system clock (and test y2k en route) remote "date -u -s 200101010000.00" local y2k=$(remote "date -u +%s") test $(($y2k-978307200)) -le 2 result checking "functionality of hardware clock" # restore the present time from hardware to system remote "/sbin/hwclock --hctosys" local second=$(remote "date -u +%s") test $(($second-$first)) -le 2 result test_end } # # compare the two realtime clocks # acctest_realtime_clock() { test_begin local endingtimethere=$(remote 'date +%s') local endingtimehere=$(date +%s) local elapsedtimethere=$(($endingtimethere-$startingtimethere)) local elapsedtimehere=$(($endingtimehere-$startingtimehere)) checking "realtime clock retardation over a period of $elapsedtimehere seconds" test \( $(($elapsedtimehere-$elapsedtimethere)) -le 2 \) -a \( $(($elapsedtimethere-$elapsedtimehere)) -le 2 \) result test_end } # # CAN tests # Note: Don't use unfinished yet # acctest_can() { local canhost="himalia" local canhostport="can1" local cantargetport="can0" checking "for existing $cantargetport device on target" remote_file "/dev/$cantargetport" exists result fatal checking "for candump on target" remote "which candump" result fatal checking "for canconfig on target" remote "which canconfig" result fatal for baudrate in 125 250 500 1000 # for baudrate in 10 20 50 100 125 250 500 800 1000 do # CAN receive (host_cansend -> target_candump) checking "CAN reception at $baudrate kbit/s" remote 'rm -f cantest.log' remote "canconfig $cantargetport baudrate $baudrate" remote "candump -d -o cantest.log $cantargetport" ssh -q $canhost "sudo ifconfig $canhostport down" ssh -q $canhost "sudo canconfig $canhostport bitrate ${baudrate}000" ssh -q $canhost "sudo ifconfig $canhostport up" ssh -q $canhost "cansend $canhostport 0x43 0x41 0x4e 0x2d 0x54 0x45 0x53 0x54" remote 'kill -SIGINT $(pidof candump)' remote 'grep "<0x001> \[8\] 43 41 4e 2d 54 45 53 54" cantest.log' local grepretval=$? remote 'rm -f cantest.log' test $grepretval = 0 result # CAN transmit (host_cansend -> target_cansend -> host_candump) checking "CAN transmission at $baudrate kbit/s" local candumpdata=$(ssh -q $canhost mktemp) ssh -q $canhost "sudo ifconfig $canhostport down" ssh -q $canhost "sudo canconfig $canhostport bitrate ${baudrate}000" ssh -q $canhost "sudo ifconfig $canhostport up" ssh -q $canhost "candump -d -o $candumpdata $canhostport" remote "canconfig $cantargetport baudrate $baudrate" local ret=$(remote 'cansend can0 0x43 0x41 0x4e 0x2d 0x54 0x45 0x53 0x54 2>&1') local cansendretval=$? if echo "$ret" | grep "write: No buffer space available" then write_to_log "write: No buffer space available" false result else ssh -q $canhost 'kill -SIGINT $(pidof candump)' ssh -q $canhost "grep \"<0x001> \[8\] 43 41 4e 2d 54 45 53 54\" $candumpdata" local grepretval=$? ssh -q $canhost "rm -f $candumpdata" test $cansendretval = 0 -a $grepretval = 0 result fi # bulk cansend checking "CAN queue filling at $baudrate kbit/s, 15000 frames" ret=$(remote "cansend $cantargetport 0x43 0x41 0x4e 0x2d 0x54 0x45 0x53 0x54 --loop 15000 2>&1") cansendretval=$? if echo "$ret" | grep "write: No buffer space available" then write_to_log "write: No buffer space available" false result else test $cansendretval = 0 result fi done } # # Realtime test cyclictest # acctest_cyclictest() { test_begin local threshold=100 # [EDITME], how many microseconds we allow for a PASS checking "realtime performance with cyclictest (average < $threshold us)" local ret=$(remote "cyclictest -n -p80 -t1 -i1000 -q -l10000") local min=$(echo "${ret}" | sed "s/.*Min: *\([^ ]*\) .*/\1/") local avg=$(echo "${ret}" | sed "s/.*Avg: *\([^ ]*\) .*/\1/") local max=$(echo "${ret}" | sed "s/.*Max: *\([^ ]*\)/\1/") # FIXME: We are using the *average* value as criterion while still not RT-PREEMPT. test $avg -le $threshold result test_end } # # Check if a filesystem is supported by the running kernel # acctest_filesystem_support() { test_begin checking "if filesystem '$1' is available" remote "grep $1 /proc/filesystems" result test_end } # # Check if a specific filesystem is NOT supported by the running kernel # acctest_filesystem_not_supported() { test_begin checking "if filesystem '$1' is disabled" remote "grep $1 /proc/filesystems" local exitstatus=$? test ${exitstatus} -eq 1 result test_end } # # Check if a specific filesystem type is mounted at a specific location # acctest_filesystem_mounted() { test_begin checking "if '$2' is mounted at '$1'" remote "mount | grep $1 | grep $2" result test_end } # # Check if a specific filesystem type is NOT mounted # acctest_filesystem_not_mounted() { test_begin checking "if '$1' is NOT mounted" remote "mount | grep $1" local exitstatus=$? test ${exitstatus} -eq 1 result test_end } # # Check if the USB is working # acctest_usb_working() { test_begin checking "if the USB is working" remote "/usr/bin/lsusb -vv" result test_end } # # Check a file content # acctest_file_content() { acctest_files "$1" test_begin checking "if '$1' contains '$2'" local string=$(remote "cat $1") test "$string" = "$2" result test_end } # # Check for a valid MAC address # acctest_valid_mac() { test_begin checking "if '$1' has a valid MAC address" local string=$(remote "cat /sys/class/net/$1/address") if [ -z $string ]; then result_fail test_end return 1 fi shift until [ -z "$1" ]; do if [ "$string" = "$1" ]; then result_ok test_end return fi shift done result_fail test_end } # # check for RSH server running on target and its usability # acctest_rsh_available() { acctest_open_port ${PTXCONF_BOARDSETUP_TARGETIP} 514 local rsh_avail=$? if [ $rsh_avail -ne 0 ]; then echo >&2 echo "RSH port 514 isn\'t open though, exiting." >&2 exit 1 fi if ! remote_compare 'echo RSH RESPONSE TEST' 'RSH RESPONSE TEST' then echo >&2 echo "RSH is selected as connection method. Port 514 seems to be open," >&2 echo "but the RSH server does not respond as expected. Exiting." >&2 exit 1 fi } # # Do some tests on some kind of blockdevice # acctest_filesystem() { local TESTFILE=/bin/busybox local TESTFILE_BASE=$(basename ${TESTFILE}) local NAME=$1 local DEVICE=$2 local PARTITION=$3 local FS=$4 local FS_MKFS=$5 local SFDISK_OPTS=$6 test_begin checking "for ${NAME} as device ${DEVICE}" remote "grep '${DEVICE}\$' /proc/partitions" result [ $? != 0 ] && return 1 checking "for ${FS} support in the kernel" remote "grep ${FS} /proc/filesystems" result [ $? != 0 ] && return 1 if [ -n "${SFDISK_OPTS}" ]; then checking "if we can create a ${FS} partition" remote "echo ${SFDISK_OPTS} | /sbin/sfdisk /dev/${DEVICE} 2>&1" result fi if [ -n "${FS_MKFS}" ]; then checking "if we can create a ${FS} filesystem" remote "${FS_MKFS} /dev/${PARTITION} 2>&1" result fi checking "if we can mount a ${FS} filesystem" remote "mount -t ${FS} /dev/${PARTITION} /mnt 2>&1" result checking "write() on ${FS}" remote "cp ${TESTFILE} /mnt" result checking "read() on ${FS}" remote "cmp /mnt/${TESTFILE_BASE} ${TESTFILE}" result checking "unlink() on ${FS}" remote "rm /mnt/${TESTFILE_BASE}" result checking "if we can unmount a ${FS} filesystem" remote 'umount /mnt 2>&1' result test_end } # # Do some tests on some kind of flash device # acctest_flashfilesystem() { local TESTFILE=/bin/busybox local TESTFILE_BASE=$(basename ${TESTFILE}) local ERASE_CMD=${5:-flash_eraseall} acctest_devicenode "/dev/$2" acctest_devicenode "/dev/$3" block acctest_filesystem_support "$4" checking "if we can erase $1 flash partition $2" remote "$ERASE_CMD /dev/$2 2>&1" result || return 1 checking "if we can mount a $4 filesystem" remote "mount -t $4 /dev/$3 /mnt 2>&1" result checking "write() on $4" remote "cp ${TESTFILE} /mnt" result checking "read() on $4" remote "cmp /mnt/${TESTFILE_BASE} ${TESTFILE}" result checking "unlink() on $4" remote "rm /mnt/${TESTFILE_BASE}" result checking "if we can unmount a $4 filesystem" remote 'umount /mnt 2>&1' result test_end } # # On ARM we must monitoring /proc/cpu/alignment # If there are other values than 0, our kernel has problems with incorrect # alignment. # function acctest_alignment { local alignment="" local ar="" test_begin checking "if we can get content of /proc/cpu/alignment" alignment=$(remote "cat /proc/cpu/alignment") if [ -z "$alignment" ]; then result_fail test_end return 1 fi result_ok ar=( ${alignment} ) checking "if user alignment counter is zero" if [ ${ar[1]} -ne 0 ]; then result_fail else result_ok fi checking "if system alignment counter is zero" if [ ${ar[3]} -ne 0 ]; then result_fail else result_ok fi checking "if skipped alignment is zero" if [ ${ar[5]} -ne 0 ]; then result_fail else result_ok fi checking "if half alignment is zero" if [ ${ar[7]} -ne 0 ]; then result_fail else result_ok fi checking "if word alignment is zero" if [ ${ar[9]} -ne 0 ]; then result_fail else result_ok fi checking "if dword alignment is zero" if [ ${ar[11]} -ne 0 ]; then result_fail else result_ok fi checking "if multi alignment is zero" if [ ${ar[13]} -ne 0 ]; then result_fail else result_ok fi checking "if user faults is at least at 'fixup+warn'" if [ ${ar[16]} -ge 3 ]; then result_ok else result_fail fi test_end } # # Measure target's time # $1 period to measure (in seconds) # # This function is an exception. Its not a 'step', its a full # 'test' due to the very special handling we need to get the 'time' # command to provide the correct data we need. # function acctest_compare_time { ( local timeret=$(mktemp -q -u -p /tmp $timeret_XXXXXXXXX) local ignore="" local result="" test_begin checking "for time anomalies ($1 seconds)" # change the time format for easier result parsing TIMEFORMAT=$'%3R %3U %3S' # FIXME here comes the qouting hell ignore=$( { time rsh -n -l root ${PTXCONF_BOARDSETUP_TARGETIP} "sleep $1"; } 2> $timeret ) if [ $? -ne 0 ]; then echo "Something went wrong when rsh was running" cat "$timeret" rm -f "$timeret" result_fail test_end return 1 fi # the local time will measure the time the rsh command runs. # we will get something like that: # 10.01 0.00 0.01 # we are interested in the first value local ar=( $(cat $timeret) ) if [ -z "${ar[0]}" ]; then echo "acctest_compare_time: Can't extract time" cat "$timeret" rm -f "$timeret" result_fail test_end return 1 fi # OK when the difference is less than 0.5s result=$(echo "(${ar[0]}-${1}) < .5" | bc -l) if [ $result -eq 1 ]; then result_ok else result_fail fi rm -f "$timeret" test_end ) } USER_OUTPUT_PREFIX="${BLUE}* " USER_OUTPUT_POSTFIX="${NC}" message_to_user() { echo -e "${USER_OUTPUT_PREFIX}" >&2 while [ $# != 0 ]; do echo -e "${USER_OUTPUT_PREFIX}$1" >&2 shift done echo -e "${USER_OUTPUT_PREFIX}${USER_OUTPUT_POSTFIX}" >&2 } line_from_user() { echo -ne "${USER_OUTPUT_PREFIX}" >&2 read -p "$1 " >&2 echo -e "${USER_OUTPUT_POSTFIX}" >&2 }