* [PATCH 0/2] RFC: A common test container
@ 2012-10-23 8:03 steffen.schwigon
2012-10-23 8:03 ` [PATCH 1/2] bash-test-utils: support writing functional tests steffen.schwigon
2012-10-23 8:03 ` [PATCH 2/2] A common test subdirectory steffen.schwigon
0 siblings, 2 replies; 3+ messages in thread
From: steffen.schwigon @ 2012-10-23 8:03 UTC (permalink / raw)
To: linux-kernel
Cc: ss5, srostedt, Dariusz.Filipski, yoshitake.kobayashi, sassmann,
andre.przywara, frank.arnold, conny.seidel, csd,
Steffen Schwigon
From: Steffen Schwigon <steffen.schwigon@amd.com>
OVERVIEW
--------
ABSTRACT: This patch set introduces a mature test library and t/ as a
subdirectory for placing tests that can be run via the existing Linux
tool 'prove' (available in most major Linux distributions). I already
presented and discussed the approach with several people at LinuxCon
Europe 2011 as part of my talk "Linux and virtualization testing".
Tests in t/ are assumed to produce TAP, the "Test Anything Protocol"
(see http://testanything.org) which is well established in many test
communities. The advantage for Linux is that it is easy to generate
which makes it suitable for restricted environments like OS testing.
To write such tests for Linux a library with special utilities is
provided: 'bash-test-utils'.
It provides utility functions to write tests in baremetal and Xen/KVM
contexts (host and guest support) and was polished to work with i686,
x86_64, and ARM under lots of major Linux distributions (Debian,
Ubuntu, RHEL, SLES, Slackware, Fedora, openSUSE). We actively use this
library in all the above contexts for about 2 years.
Other TAP libraries (without special Linux support) are available for
many programming languages.
The autotest project already provides TAP support.
PURPOSE
-------
Provide a container subdir where to place functional tests that are
*in sync* with Linux' git history.
Such tests are usually "unit tests" for features and can also be used
for bisecting regressions of those feature, e.g., by executing 'prove'
with 'ktest' (already part of Linux).
It is possible to organize such tests in a subdir hierarchy (though
not contained with this patch) where separate functional areas as well
as Linux contributors and vendors can be organized without conflicts
and executed separately, for example:
t/
t/bare/arch/x86
t/bare/arch/arm
t/virt/kvm/
t/virt/xen/
t/vendors/fedora/
t/vendors/companyx/
Separate testprojects like autotest can be kept in sync with the Linux
kernel via git submodules under t/ and called via frontend wrapper
scripts to trigger TAP output.
SYNOPSIS
--------
Testscripts are by convention named "*.t" to be chosen automatically
by 'prove' if executing directories and to differentiate between tests
and other utilities. The subdirectory t/ is also a default convention
used by 'prove'.
Tests can be executed like this:
$ prove -v t/example/basic.t
$ prove -v t/example/
$ prove -r t/
QUESTIONS
---------
Q: Why not submit it to one of the Linux test projects, like LTP or
autotest?
A: External test projects are not in sync with the Linux kernel. They
regularly do not fit older or newer kernels.
Having a test container (subdir t/ with the TAP convention) in
Linux itself allows
- contributors, vendors, and companies to place a functional test
nearby the functionality it belongs to.
- integrate and sync with existing test projects, e.g., via git
submodules or wrapper scripts.
Q: Why TAP? Why not XUNIT or other test protocols?
A: There are not that many test protocols. TAP is well established,
easy, language and platform independent, and already supported in
every Linux system out-of-the-box. It looks like this:
1..4
ok - feature a
not ok - feature b
# diagnostic lines with details
ok - feature c # SKIP not done for this architecture
not ok - feature d # TODO yet to be implemented
This can be produced even with the most minimal tools like printf
from a test inside a strange subsystem, though for practically all
major programming languages libraries exist. And for evaluating
tests the tool 'prove' already exists in your Linux system.
The syntax is easy, yet allows expressing complex test results if
needed. Besides the #TODO/#SKIP semantics it also allows to embed
structured data, eg. for benchmark results.
Q: Do we need more framework overhead to execute the tests?
A: Not in the Linux kernel. There are enough tools to execute them:
- prove ... to run functional tests
- ktest ... to compile a kernel and boot a machine
Everything is in place, we just need the common container, per
convention.
Steffen Schwigon (2):
bash-test-utils: support writing functional tests
A common test subdirectory
t/examples/basic.t | 49 ++
tools/testing/tap/bash-test-utils | 1508 +++++++++++++++++++++++++++++++++
tools/testing/tap/bash-test-utils.txt | 320 +++++++
3 files changed, 1877 insertions(+)
create mode 100755 t/examples/basic.t
create mode 100755 tools/testing/tap/bash-test-utils
create mode 100644 tools/testing/tap/bash-test-utils.txt
--
1.7.10.4
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 1/2] bash-test-utils: support writing functional tests
2012-10-23 8:03 [PATCH 0/2] RFC: A common test container steffen.schwigon
@ 2012-10-23 8:03 ` steffen.schwigon
2012-10-23 8:03 ` [PATCH 2/2] A common test subdirectory steffen.schwigon
1 sibling, 0 replies; 3+ messages in thread
From: steffen.schwigon @ 2012-10-23 8:03 UTC (permalink / raw)
To: linux-kernel
Cc: ss5, srostedt, Dariusz.Filipski, yoshitake.kobayashi, sassmann,
andre.przywara, frank.arnold, conny.seidel, csd,
Steffen Schwigon
From: Steffen Schwigon <steffen.schwigon@amd.com>
It provides utility functions and facilities to write tests in
baremetal and Xen/KVM contexts (host and guest support) and was
polished to work with i686, x86_64, and ARM under lots of major
Linux distributions (Debian, Ubuntu, RHEL, SLES, Slackware,
Fedora, openSUSE).
It can be run as normal bash script or indirectly via the "prove"
command, a standard Linux tool to run test scripts.
Synopsis:
$ cd /usr/src/linux
$ cat t/my-feature-test.t
#! /bin/bash
. tools/testing/tap/bash-test-utils
test_feature_foo
ok $? "feature foo"
done_testing
$ prove -v t/my-feature-test.t
Signed-off-by: Steffen Schwigon <steffen.schwigon@amd.com>
Signed-off-by: Andre Przywara <andre.przywara@amd.com>
Signed-off-by: Frank Arnold <frank.arnold@amd.com>
Signed-off-by: Conny Seidel <conny.seidel@amd.com>
Signed-off-by: Christian Daudt <csd@broadcom.com>
---
tools/testing/tap/bash-test-utils | 1508 +++++++++++++++++++++++++++++++++
tools/testing/tap/bash-test-utils.txt | 320 +++++++
2 files changed, 1828 insertions(+)
create mode 100755 tools/testing/tap/bash-test-utils
create mode 100644 tools/testing/tap/bash-test-utils.txt
diff --git a/tools/testing/tap/bash-test-utils b/tools/testing/tap/bash-test-utils
new file mode 100755
index 0000000..68661dd
--- /dev/null
+++ b/tools/testing/tap/bash-test-utils
@@ -0,0 +1,1508 @@
+#! /bin/bash
+
+# bash-test-utils -- an include file to support writing test scripts.
+#
+# --------------------------------------------------------------------
+#
+# It provides utility functions and facilities to write tests in
+# baremetal and Xen/KVM contexts (host and guest support) and was
+# polished to work with i686, x86_64, and ARM under lots of major
+# Linux distributions (Debian, Ubuntu, RHEL, SLES, Slackware,
+# Fedora, openSUSE).
+#
+# It can be run as normal bash script or indirectly via the "prove"
+# command, a standard Linux tool to run test scripts.
+#
+# Synopsis:
+#
+# $ cd /usr/src/linux
+#
+# $ cat > t/my-feature-test.t
+# #! /bin/bash
+# . tools/testing/tap/bash-test-utils
+# test_feature_foo
+# ok $? "feature foo worked"
+# done_testing
+#
+# $ prove -v t/my-feature-test.t
+#
+# --------------------------------------------------------------------
+#
+# Copyright (c) 2009-2012, Advanced Micro Devices, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+
+# ==================== Utility functions =============================
+
+# constants
+_SUCCESS=0
+_FAILURE=1
+
+# gets vendor "AMD" or "Intel" from /proc/cpuinfo
+get_vendor () {
+ vendor=$(echo $(grep vendor_id /proc/cpuinfo |head -1|cut -d: -f2|sed -e "s/Genuine\|Authentic//"))
+ echo $vendor
+}
+
+# checks for vendor "Intel" in /proc/cpuinfo
+vendor_intel () {
+ grep -Eq 'vendor_id.*:.*Intel' /proc/cpuinfo
+}
+
+# checks for vendor "AMD" in /proc/cpuinfo
+vendor_amd () {
+ grep -Eq 'vendor_id.*:.*AMD' /proc/cpuinfo
+}
+
+# stops testscript if not matching required cpu vendor
+require_vendor_intel () {
+ if vendor_intel
+ then
+ if [ "x1" = "x$REQUIRES_GENERATE_TAP" ] ; then ok 0 "require_vendor_intel" ; fi
+ return $_SUCCESS
+ else
+ explanation="${1:-vendor does not match Intel}"
+ autoreport_skip_all "$explanation"
+ fi
+}
+
+# stops testscript if not matching required cpu vendor
+require_vendor_amd () {
+ if vendor_amd
+ then
+ if [ "x1" = "x$REQUIRES_GENERATE_TAP" ] ; then ok 0 "require_vendor_amd" ; fi
+ return $_SUCCESS
+ else
+ explanation="${1:-vendor does not match AMD}"
+ autoreport_skip_all "$explanation"
+ fi
+}
+
+# Checks for ARM cpu
+arm_cpu () {
+ grep -Eqi 'Processor.*:.*ARM' /proc/cpuinfo
+}
+
+# outputs cpu stepping from /proc/cpuinfo
+get_cpu_stepping () {
+ echo $(echo $(grep "^stepping" /proc/cpuinfo |head -1|cut -d: -f2))
+}
+# outputs cpu model from /proc/cpuinfo
+get_cpu_model () {
+ echo $(echo $(grep "^model[^ ]" /proc/cpuinfo |head -1|cut -d: -f2))
+}
+
+# outputs cpu model from /proc/cpuinfo
+get_cpu_model_hex () {
+ echo "0x"$(get_hex_from_int $(get_cpu_model))
+}
+
+# checks cpu model from /proc/cpuinfo against a minimum model
+cpu_model_min () {
+ min=${1:-0}
+ mod=$(get_cpu_model)
+ [ $(($mod)) -ge $(($min)) ]
+}
+
+# checks cpu model from /proc/cpuinfo against a maximum model
+cpu_model_max () {
+ max=${1:-0x999}
+ mod=$(get_cpu_model)
+ [ $(($mod)) -le $(($max)) ]
+}
+
+# outputs cpu family from /proc/cpuinfo
+# since all testsuites using hex values, return value in hex format
+get_cpu_family () {
+ echo $(echo $(grep "^cpu family" /proc/cpuinfo |head -1|cut -d: -f2))
+}
+
+get_cpu_family_hex () {
+ echo "0x"$(get_hex_from_int $(get_cpu_family))
+}
+
+# checks cpu family from /proc/cpuinfo against a minimum family
+cpu_family_min () {
+ min=${1:-0}
+ fam=$(get_cpu_family)
+ [ $(($fam)) -ge $(($min)) ]
+}
+
+# checks cpu family from /proc/cpuinfo against a maximum family
+cpu_family_max () {
+ max=${1:-0x999}
+ fam=$(get_cpu_family)
+ [ $(($fam)) -le $(($max)) ]
+}
+
+is_amd_family_range () {
+ min="${1:-0}"
+ max="${2:-$min}"
+ if vendor_amd && cpu_family_min "$min" && cpu_family_max "$max" ; then
+ return $_SUCCESS
+ else
+ return $_FAILURE
+ fi
+}
+
+# stops testscript if not matching required cpu family from
+# /proc/cpuinfo of a minimum/maximum range
+require_amd_family_range () {
+ min="${1:-0}"
+ max="${2:-$min}"
+ if is_amd_family_range "$min" "$max" ; then
+ if [ "x1" = "x$REQUIRES_GENERATE_TAP" ] ; then ok 0 "require_amd_family_range $min $max" ; fi
+ return $_SUCCESS
+ else
+ vendor=$(get_vendor);
+ fam=$(printf "0x%x" $(get_cpu_family));
+ explanation="${3:-Family $vendor/$fam does not match AMD/$min..$max}"
+ autoreport_skip_all "$explanation"
+ fi
+}
+
+# Checks all nodes for NB devices with one of the supplied PCI device ids
+# Note: Call it separately for different PCI device functions
+has_amd_nb_function_id () {
+ devids=${@:-"0xffffffff"}
+
+ for devid in $devids; do
+ devid=$(printf '0x%x' $devid)
+ nbdevs="/sys/bus/pci/devices/0000:00:1[89abcdef].*"
+
+ [ $(ls $nbdevs 2>/dev/null | wc -l) -gt 0 ] || continue
+
+ f0devs="/sys/bus/pci/devices/0000:00:1[89abcdef].0/vendor"
+ northbridges=$(ls $f0devs 2>/dev/null | wc -l)
+
+ devices=0
+ for nbdev in $nbdevs; do
+ vendor=$(cat $nbdev/vendor 2>/dev/null)
+ if [ "$vendor" != "0x1022" ]; then
+ return $_FAILURE
+ fi
+
+ device=$(cat $nbdev/device 2>/dev/null)
+ if [ "$device" = "$devid" ]; then
+ let devices++
+ fi
+ done
+
+ if [ $devices -gt 0 -a $devices -eq $northbridges ]; then
+ return $_SUCCESS
+ fi
+ done
+
+ return $_FAILURE
+}
+
+# Stops if no NB devices with one of supplied PCI device ids exist on all nodes
+# Note: Call it separately for different PCI device functions
+require_amd_nb_function_id () {
+ devids=${@:-"0xffffffff"}
+ if has_amd_nb_function_id "$devids"; then
+ if [ "x1" = "x$REQUIRES_GENERATE_TAP" ] ; then ok $_SUCCESS "require_amd_nb_function_id" ; fi
+ else
+ autoreport_skip_all "No supported AMD northbridge function devices"
+ fi
+}
+
+get_number_cpus () {
+ (getconf _NPROCESSORS_ONLN || grep -ci "^bogomips" /proc/cpuinfo || echo -1) 2>/dev/null
+}
+
+# check sysfs whether cpu has L3 cache
+has_l3cache () {
+ if [ -d /sys/devices/system/cpu/cpu0/cache/index3 ] ; then
+ return $_SUCCESS
+ else
+ return $_FAILURE
+ fi
+}
+
+# stops testscript if cpu does not have L3 cache
+require_l3cache () {
+ explanation="${1:-No L3 cache}"
+ if has_l3cache ; then
+ if [ "x1" = "x$REQUIRES_GENERATE_TAP" ] ; then ok $_SUCCESS "require_l3cache" ; fi
+ return $_SUCCESS
+ else
+ autoreport_skip_all "$explanation"
+ fi
+}
+
+# check x86_64
+is_x86_64 () {
+ if uname -m | grep -q x86_64 ; then
+ return $_SUCCESS
+ else
+ return $_FAILURE
+ fi
+}
+
+# stops testscript if is not x86_64
+require_x86_64 () {
+ explanation="${1:-No x86_64}"
+ if is_x86_64 ; then
+ if [ "x1" = "x$REQUIRES_GENERATE_TAP" ] ; then ok $_SUCCESS "require_x86_64" ; fi
+ return $_SUCCESS
+ else
+ autoreport_skip_all "$explanation"
+ fi
+}
+
+# scan all PCI devices for one with XenSource's PCI-ID
+has_xen_pci_device() {
+ # try lspci (not in PATH if not root)
+ _ta_xen_LSPCI=$(which lspci 2> /dev/null) || _ta_xen_LSPCI=/sbin/lspci
+ if [ -x "$_ta_xen_LSPCI" ]
+ then
+ $_ta_xen_LSPCI -n | grep -q " 5853:"
+ return $?
+ else
+ # directly query sysfs and check for XenSource's PCI-ID
+ if [ -r /sys/bus/pci/devices/0000:00:00.0/vendor ] ; then
+ cat /sys/bus/pci/devices/*/vendor | grep -q 0x5853
+ return $?
+ else
+ return $_FAILURE
+ fi
+ fi
+}
+
+# checks the PCI hostbridge's vendor and optionally device ID
+# usage: check_hostbridge 0x1022 (for checking for AMD northbridge)
+# check_hostbridge 0x8086 0x1237 (for QEMU host bridge)
+check_hostbridge() (
+ LSPCI=$(which lspci 2> /dev/null) || LSPCI=/sbin/lspci
+ if [ -x "$LSPCI" ]
+ then
+ lspciout=$($LSPCI -s 0:0.0 -n | cut -d: -f3- | tr -d \ )
+ vendor="0x$(echo $lspciout | cut -d: -f1)"
+ device="0x$(echo $lspciout | cut -d: -f2)"
+ else
+ vendor=$(cat /sys/bus/pci/devices/0000:00:00.0/vendor)
+ device=$(cat /sys/bus/pci/devices/0000:00:00.0/device)
+ fi
+ [ "$vendor" = "$1" ] || return $_FAILURE
+ [ -z "$2" ] && return $_SUCCESS
+ [ "$device" = "$2" ]
+ return $?
+)
+
+# checks whether the Xen hypervisor is running
+# this returns 0 if we are a Dom0 or PV DomU or HVM DomU
+is_running_under_xen_hv () {
+ if [ -r /sys/hypervisor/type ] ; then
+ [ $(cat /sys/hypervisor/type) = "xen" ]
+ return $?
+ fi
+
+ [ -r /proc/xen/capabilities ] && return $_SUCCESS
+
+ # Linux denies registering XenFS if not running under Xen
+ if has_kernel_config CONFIG_XENFS ; then
+ grep -q xenfs /proc/filesystems
+ return $?
+ fi
+
+ # TODO: do older kernels support this? At least RHEL5 does
+ has_cpufeature hypervisor || return $_FAILURE
+
+ _ta_e820prov=$(dmesg | sed -e 's/^\[.*\] *//' | grep -A1 "^BIOS-provided physical RAM map:" | tail -1 | cut -d: -f1)
+ [ -n "$_ta_820prov" ] && [ "$_ta_e820prov" = "Xen" ] && return $_SUCCESS
+
+ dmesg | grep -q "Booting paravirtualized kernel on Xen" && return $_SUCCESS
+
+ return $_FAILURE
+}
+
+# check if we are in a Xen host
+# it is a bit tricky to differentiate Dom0 and (PV-)DomU
+is_running_in_xen_dom0 () {
+
+ # this is a definite way to check for Dom0, but not always available, since
+ # XENFS could not be mounted
+ if [ -r /proc/xen/capabilities ] ; then
+ grep -q control_d /proc/xen/capabilities
+ return $?
+ fi
+
+ # this should sort out most of the other possibilities
+ is_running_under_xen_hv || return $_FAILURE
+
+ # we need to sort out only Dom0 vs. DomU from now on
+
+ # an ATI or AMD northbridge means Dom0
+ if check_hostbridge 0x1002 || check_hostbridge 0x1022 ; then
+ return $_SUCCESS
+ fi
+
+ # a QEMU northbridge cannot be Dom0
+ check_hostbridge 0x8086 0x1237 && return $_FAILURE
+
+ # out of clues, but we are probably not Dom0 at this point anymore
+ return $_FAILURE
+}
+
+# check if we are in a KVM host
+is_running_in_kvm_host () {
+ [ -e /dev/kvm ]
+}
+
+# check if we have KVM guests running
+has_kvm_guests () {
+ counter=$(lsmod |grep '^kvm_'|awk '{print $3}')
+ if [ $counter -gt 0 ] ; then
+ return $_SUCCESS
+ else
+ return $_FAILURE
+ fi
+}
+
+get_xen_tool() {
+ which xl 2> /dev/null || which xm 2> /dev/null
+}
+
+get_number_xen_guests() {
+ XL=$(get_xen_tool) || return $_FAILURE
+ res=$($XL list | wc -l)
+ if [ -n "$res" -a "$res" -ge 2 ] ; then
+ echo "$((res-2))"
+ return $_SUCCESS
+ else
+ echo "0"
+ return $_FAILURE
+ fi
+}
+
+# check if we are in a Xen guest
+# Note:
+# In Xen the dom0 reports the same 'hypervisor' flag and CPUID entry
+# as in domU therefore the CPUID check is not enough, but dmidecode
+# and lspci show different devices inside a domU.
+is_running_in_xen_guest () {
+
+ is_running_under_xen_hv || return $_FAILURE
+
+ has_xen_pci_device && return $_SUCCESS
+
+ check_hostbridge 0x8086 0x1237 && return $_SUCCESS
+
+ # try dmidecode
+ if dmidecode > /dev/null 2>&1 ; then
+ _dmi_chassis=$(dmidecode -s chassis-manufacturer)
+ # dmidecode does not output anything in PV Xen
+ if [ -n "$_dmi_chassis" ] ; then
+ echo "$_dmi_chassis" | grep -q Xen
+ return $?
+ fi
+ fi
+
+ # last resort: check for Xen Dom0
+ is_running_in_xen_dom0 && return $_FAILURE
+
+ # there are no PCI device by default in PV guests
+ _nr_pci_devices=$(ls /sys/bus/pci/devices | wc -l)
+ [ "$_nr_pci_devices" -eq 0 ] && return $_SUCCESS
+
+ # no more clues at this point, assume we are some kind of DomU
+ return $_SUCCESS
+}
+
+# check if we are in a KVM guest
+# Note:
+# In KVM the hypervisor CPUID check is relieable and we can first
+# narrow it against being not a Xen guest. After that the devices
+# are less significant in KVM so here we then check for the CPUID.
+is_running_in_kvm_guest () {
+
+ is_running_in_xen_guest && return $_FAILURE
+ has_cpufeature hypervisor || return $_FAILURE
+
+ # try to load the cpuid module if not already done
+ [ -c /dev/cpu/0/cpuid ] || modprobe cpuid > /dev/null 2>&1
+
+ if [ -c /dev/cpu/0/cpuid ] ; then
+ virtvendor=$(dd if=/dev/cpu/0/cpuid bs=16 skip=67108864 count=1 2> /dev/null)
+ [ "$virtvendor" = "KVMKVMKVM" ]
+ return $?
+ fi
+ return 1
+}
+
+# check if we are in a virtualized guest (Xen or KVM)
+is_running_in_virtualized_guest () {
+ is_running_in_xen_guest || is_running_in_kvm_guest
+ return $?
+}
+
+# stops testscript if we aren't a Xen guest
+require_running_in_xen_guest () {
+ explanation="${1:-Needs to run in Xen guest}"
+ if is_running_in_xen_guest ; then
+ if [ "x1" = "x$REQUIRES_GENERATE_TAP" ] ; then ok $_SUCCESS "require_running_in_xen_guest" ; fi
+ return $_SUCCESS
+ else
+ autoreport_skip_all "$explanation"
+ fi
+}
+
+# stops testscript if we aren't a Xen dom0
+require_running_in_xen_dom0 () {
+ explanation="${1:-Needs to run in Xen dom0}"
+ if is_running_in_xen_dom0 ; then
+ if [ "x1" = "x$REQUIRES_GENERATE_TAP" ] ; then ok $_SUCCESS "require_running_in_xen_dom0" ; fi
+ return $_SUCCESS
+ else
+ autoreport_skip_all "$explanation"
+ fi
+}
+
+# stops testscript if we aren't a KVM guest
+require_running_in_kvm_guest () {
+ explanation="${1:-Needs to run in KVM guest}"
+ if is_running_in_kvm_guest ; then
+ if [ "x1" = "x$REQUIRES_GENERATE_TAP" ] ; then ok $_SUCCESS "require_running_in_kvm_guest" ; fi
+ return $_SUCCESS
+ else
+ autoreport_skip_all "$explanation"
+ fi
+}
+
+# stops testscript if we aren't a KVM host
+require_running_in_kvm_host () {
+ explanation="${1:-Needs to run in KVM host}"
+ if is_running_in_kvm_host ; then
+ if [ "x1" = "x$REQUIRES_GENERATE_TAP" ] ; then ok $_SUCCESS "require_running_in_kvm_host" ; fi
+ return $_SUCCESS
+ else
+ autoreport_skip_all "$explanation"
+ fi
+}
+
+# stops testscript if we aren't a virtualized guest
+require_running_in_virtualized_guest () {
+ explanation="${1:-Needs to run in virtualized guest}"
+ if is_running_in_virtualized_guest ; then
+ if [ "x1" = "x$REQUIRES_GENERATE_TAP" ] ; then ok $_SUCCESS "require_running_in_virtualized_guest" ; fi
+ return $_SUCCESS
+ else
+ autoreport_skip_all "$explanation"
+ fi
+}
+
+# checks for a feature flag in /proc/cpuinfo
+has_cpufeature () {
+ _ta_feature="${1:-UNKNOWNFEATURE}"
+ if cat /proc/cpuinfo | grep -E '^flags\W*:' | head -1 | sed -e 's/^flags\W*://' | grep -q "\<${_ta_feature}\>" 2>&1 ; then
+ return $_SUCCESS
+ else
+ return $_FAILURE
+ fi
+}
+
+# stops testscript if a feature flag is not found in /proc/cpuinfo
+require_cpufeature () {
+ _ta2_feature="${1:-UNKNOWNFEATURE}"
+ explanation="${2:-Missing cpufeature $_ta2_feature}"
+ if has_cpufeature "$_ta2_feature" ; then
+ if [ "x1" = "x$REQUIRES_GENERATE_TAP" ] ; then ok $_SUCCESS "require_cpufeature $_ta2_feature" ; fi
+ return $_SUCCESS
+ else
+ autoreport_skip_all "$explanation"
+ fi
+}
+
+# checks for a config in /proc/config.gz or /boot/config/$(uname -r)
+has_kernel_config () {
+ _ta3_feature="${1:-UNKNOWNFEATURE}"
+ CONFIG=$(get_first_file "/proc/config.gz" "/boot/config-$(uname -r)")
+ if [ -z "$CONFIG" ] ; then
+ return $_FAILURE
+ fi
+ if echo $CONFIG | grep -q '\.gz' ; then
+ gzip -cd "$CONFIG" | grep -q "^${_ta3_feature}=."
+ else
+ grep -q "^${_ta3_feature}=." "$CONFIG"
+ fi
+}
+
+# stops testscript if a feature flag is not found in /proc/cpuinfo
+require_kernel_config () {
+ _ta4_feature="${1:-UNKNOWNFEATURE}"
+ explanation="${2:-Missing kernel config $_ta4_feature}"
+ if has_kernel_config "$_ta4_feature" ; then
+ if [ "x1" = "x$REQUIRES_GENERATE_TAP" ] ; then ok $_SUCCESS "require_kernel_config $_ta4_feature" ; fi
+ return $_SUCCESS
+ else
+ autoreport_skip_all "$explanation"
+ fi
+}
+
+# Enable CPU frequency scaling and set sane defaults
+# - Makes sure the appropriate cpufreq driver is loaded
+# - Enables ondemand governor on all cores
+# - Sets the boost state, on=1 (default), off=0
+enable_cpufreq () {
+ booststate="$1"
+ [ "$booststate" != "0" ] && booststate=1
+
+ # Load cpufreq driver module
+ for module in acpi-cpufreq powernow-k8; do
+ [ -d /sys/devices/system/cpu/cpu0/cpufreq ] && break
+ modprobe $module 2>/dev/null
+ done
+ if [ ! -d /sys/devices/system/cpu/cpu0/cpufreq ]; then
+ echo "failed to load cpufreq driver"
+ return $_FAILURE
+ fi
+
+ # Load ondemand governor module and set ondemand governor
+ if ! grep -q ondemand /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors; then
+ modprobe cpufreq-ondemand 2>/dev/null
+ fi
+ for cpu in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do
+ echo ondemand > $cpu 2>/dev/null
+ if [ "$(cat $cpu)" != "ondemand" ]; then
+ echo "failed to set ondemand governor"
+ return $_FAILURE
+ fi
+ done
+
+ # Set requested boost state
+ if ! has_cpufeature cpb; then
+ return $_SUCCESS
+ elif [ -f /sys/devices/system/cpu/cpufreq/boost ]; then
+ interfaces="/sys/devices/system/cpu/cpufreq/boost"
+ elif [ $(ls /sys/devices/system/cpu/cpu*/cpufreq/cpb 2>/dev/null | wc -l) -gt 0 ]; then
+ interfaces="/sys/devices/system/cpu/cpu*/cpufreq/cpb"
+ elif grep -q " show_cpb\| show_global_boost" /proc/kallsyms; then
+ echo "failed to find sysfs boost state interface"
+ return $_FAILURE
+ elif [ $booststate -eq 0 ]; then
+ echo "cpufreq driver doesn't provide sysfs boost state interface"
+ return $_FAILURE
+ else
+ return $_SUCCESS
+ fi
+ for interface in $interfaces; do
+ echo $booststate > $interface 2>/dev/null
+ if [ "$(cat $interface)" != "$booststate" ]; then
+ echo "failed to set requested boost state"
+ return $_FAILURE
+ fi
+ done
+
+ return $_SUCCESS
+}
+
+require_cpufreq_enabled () {
+ explanation="${1:-CPUFreq not available}"
+ reason=$(enable_cpufreq 1)
+ if [ $? -eq $_SUCCESS ] ; then
+ if [ "x1" = "x$REQUIRES_GENERATE_TAP" ] ; then ok $_SUCCESS "require_cpufreq_enabled" ; fi
+ return $_SUCCESS
+ else
+ autoreport_skip_all "$explanation ($reason)"
+ fi
+}
+
+require_cpb_disabled () {
+ explanation="${1:-Failed to disable Core Boosting}"
+ reason=$(enable_cpufreq 0)
+ if [ $? -eq $_SUCCESS ] ; then
+ if [ "x1" = "x$REQUIRES_GENERATE_TAP" ] ; then ok $_SUCCESS "require_cpufreq_enabled" ; fi
+ return $_SUCCESS
+ else
+ autoreport_skip_all "$explanation ($reason)"
+ fi
+}
+
+request_cpufreq_enabled () {
+ todo="# TODO $(enable_cpufreq 1)" && todo=""
+ ok $? "request_cpufreq_enabled $todo"
+ [ -n "$todo" ] && return $_FAILURE
+ return $_SUCCESS
+}
+
+request_cpb_disabled () {
+ todo="# TODO $(enable_cpufreq 0)" && todo=""
+ ok $? "request_cpb_disabled $todo"
+ [ -n "$todo" ] && return $_FAILURE
+ return $_SUCCESS
+}
+
+# disables core performance boosting for reproducable and well scaling
+# benchmarks. Tries hard to learn the actual state and to really disable
+# it. Diagnostic messages will be print to stdout, the return value
+# describes the success: 0=CPB is disabled, 1=CPB is (probably) still enabled.
+# possible usage (failed disabling is non-fatal, but report it):
+# todostem="# TODO "
+# expl=$(disable_cpb) && todostem=""
+# ok $? "disable CPB $todostem$expl"
+# or a fatal version ending the script:
+# expl=$(disable_cpb)
+# require_ok $? "disable CPB"
+# or: just try to disable it, but don't care if we fail
+# disable_cpb > /dev/null
+disable_cpb() {
+ # check whether the CPB sysfs knob is there
+ if [ ! -r /sys/devices/system/cpu/cpu0/cpufreq/cpb ] ; then
+ is_running_in_virtualized_guest && _cpbhint=" (running virtualized)"
+ # if the CPU does not support boosting, we dont care
+ if ! has_cpufeature cpb ; then
+ echo "# CPU has no CPB support$_cpbhint"
+ return 0
+ fi
+ # is the powernow_k8 driver loaded?
+ if ! grep -q " powernowk8_init" /proc/kallsyms; then
+ # if not, try to load it
+ if ! _modprobe_res=$(modprobe powernow_k8 2>&1) ; then
+ echo "# modprobe powernow_k8: $_modprobe_res"
+ return 1
+ fi
+ fi
+ # does this version of powernow_k8 support CPB?
+ if ! grep -q " show_cpb" /proc/kallsyms ; then
+ echo "# powernow_k8 loaded, but no CPB support"
+ return 1
+ fi
+ fi
+ # now check for the sysfs knob again (we may have loaded the driver)
+ if [ ! -r /sys/devices/system/cpu/cpu0/cpufreq/cpb ] ; then
+ echo "# no sysfs knob for disabling CPB, probably still active"
+ return 1
+ fi
+
+ # if the knob is there and it reads 0, everything is fine
+ if [ $(cat /sys/devices/system/cpu/cpu0/cpufreq/cpb) = "0" ] ; then
+ echo "# CPB already disabled"
+ return 0
+ fi
+ # try to disable CPB on all cores and count the number of failures
+ failures=0
+ for cpb in /sys/devices/system/cpu/cpu*/cpufreq/cpb; do
+ echo 0 2> /dev/null > $cpb || let failures++
+ done
+ # no failures means everything is fine
+ if [ "$failures" = 0 ] ; then
+ echo "# CPB successfully disabled"
+ return 0
+ fi
+ # don't give up so quickly, try to explore dmesg for the right message
+ if $(dmesg | grep -q "Core Boosting .*abled") ; then
+ # there was at least one messages, check the last one
+ if dmesg | grep -q "Core Boosting .*abled" | tail -1 | grep -q "Core Boosting disabled" ; then
+ # the last message says its disabled, believe this
+ echo "# CPB disabling failed, but probably disabled before"
+ return 0
+ else
+ # the last message says its enabled, we failed eventually
+ echo "# CPB disabling failed (no permissions), CPB active"
+ return 1
+ fi
+ fi
+ # we have no real clue at this point, but assume the worst
+ echo "# CPB disabling failed, probably still active"
+ return 1
+}
+
+# checks whether the cpbdisable file exists in sysfs
+has_cpbdisable () {
+ # This file's existence is not the best check.
+ # It also exists on non-cpb systems.
+ if [ -e /sys/devices/system/cpu/cpu0/cpufreq/cpb ] ; then
+ return $_SUCCESS
+ else
+ return $_FAILURE
+ fi
+}
+
+# stops testscript if the cpbdisable file does not exist in sysfs
+require_cpbdisable () {
+ explanation="${1:-No CPB disable}"
+ if has_cpbdisable ; then
+ if [ "x1" = "x$REQUIRES_GENERATE_TAP" ] ; then ok $_SUCCESS "require_cpbdisable" ; fi
+ return $_SUCCESS
+ else
+ autoreport_skip_all "$explanation"
+ fi
+}
+
+# checks whether the module is ther
+has_module () {
+ module="${1:-UNKNOWNMODULE}"
+ if lsmod | grep -q "^$module\b" ; then
+ return $_SUCCESS
+ else
+ return $_FAILURE
+ fi
+}
+
+# stops testscript if the cpbdisable file does not exist in sysfs
+require_module () {
+ module="${1:-UNKNOWNMODULE}"
+ explanation="${2:-No module $module disable}"
+ if has_module "$module"; then
+ if [ "x1" = "x$REQUIRES_GENERATE_TAP" ] ; then ok $_SUCCESS "require_module" ; fi
+ return $_SUCCESS
+ else
+ autoreport_skip_all "$explanation"
+ fi
+}
+
+# checks whether the program is available
+has_program () {
+ program="${1:-UNKNOWNPROGRAM}"
+ if which "$program" > /dev/null 2>&1 ; then
+ return $_SUCCESS
+ else
+ return $_FAILURE
+ fi
+}
+
+# stops testscript if program not available
+require_program () {
+ program="${1:-UNKNOWNPROGRAM}"
+ explanation="${2:-Missing program $program}"
+ if has_program "$program" ; then
+ return $_SUCCESS
+ else
+ autoreport_skip_all "$explanation"
+ fi
+}
+
+# checks whether the file is available
+has_file () {
+ file="${1:-UNKNOWNFILE}"
+ explanation="${2:-Missing file $file}"
+ if [ -e "$file" ] ; then
+ return $_SUCCESS
+ else
+ return $_FAILURE
+ fi
+}
+
+# stops testscript if file not available
+require_file () {
+ file="${1:-UNKNOWNFILE}"
+ explanation="${2:-Missing file $file}"
+ if has_file "$file" ; then
+ if [ "x1" = "x$REQUIRES_GENERATE_TAP" ] ; then ok $_SUCCESS "require_file $file" ; fi
+ return $_SUCCESS
+ else
+ autoreport_skip_all "$explanation"
+ fi
+}
+
+# checks whether the script's criticality is in allowed range
+has_crit_level () {
+ _ta_crit_level="${1:-5}"
+ _ta_crit_level_allowed="${CRITICALITY:-0}"
+ if [ $_ta_crit_level -le $_ta_crit_level_allowed ] ; then
+ return $_SUCCESS;
+ else
+ return $_FAILURE
+ fi
+}
+
+# stops testscript if script's criticality is not in allowed range
+require_crit_level () {
+ _ta_crit_level="${1:-5}"
+ _ta_crit_level_allowed="${CRITICALITY:-0}"
+ explanation="${2:-Too high criticality level: $_ta_crit_level (CRITICALITY=$_ta_crit_level_allowed)}"
+
+ if has_crit_level $_ta_crit_level ; then
+ if [ "x1" = "x$REQUIRES_GENERATE_TAP" ] ; then ok $_SUCCESS "criticality level $_ta_crit_level (CRITICALITY=$_ta_crit_level_allowed)" ; fi
+ return $_SUCCESS
+ else
+ autoreport_skip_all "$explanation"
+ fi
+}
+
+require_root () {
+ explanation="${1:-Need to run as root}"
+ ID=$(id|cut -d" " -f1|cut -d= -f2|cut -d\( -f1)
+ if [ "x$ID" == "x0" ] ; then
+ if [ "x1" = "x$REQUIRES_GENERATE_TAP" ] ; then ok $_SUCCESS "require_root" ; fi
+ return $_SUCCESS
+ else
+ autoreport_skip_all "$explanation"
+ fi
+}
+
+get_first_file () {
+ for i in $(seq 1 $#) ; do
+ file=${!i}
+ if [ -r "$file" ] ; then
+ echo "$file"
+ return
+ fi
+ done
+}
+
+# checks whether MSRs could be read from userspace
+# will try to load the appropriate kernel module if not already done
+# will return an error if the file is not readable (not root)
+has_msr_access() (
+ cpu=${1:-0}
+ if [ ! -e /dev/cpu/$cpu/msr ] ; then
+ has_program modprobe || return 1
+ modprobe msr || return 1
+ fi
+ [ -r /dev/cpu/$cpu/msr ]
+)
+
+# reads a MSR via the /dev/cpu/<n>/msr device
+# expects the MSR number (in hex) as the first parameter and optionally the
+# CPU number from which to read as the second argument (defaults to 0)
+# outputs a 16 char hex value (lower case letters) to stdout
+# returns 0 on success, 1 for an invalid MSR and 2 for permission issues
+read_msr() (
+ cpu=${2:-0}
+ if has_program rdmsr ; then
+ rdmsr -x -0 -p $cpu "$1" 2> /dev/null
+ return $?
+ fi
+ [ -r /dev/cpu/$cpu/msr ] || return 2
+
+ perl -e 'my $msr;sysseek(STDIN,hex($ARGV[0]),0);sysread(STDIN,$msr,8) or exit(1);my @words=unpack("LL",$msr);printf("%08x%08x\n",$words[1],$words[0]);' $1 < /dev/cpu/$cpu/msr
+)
+
+# writes a MSR via the /dev/cpu/<n>/msr device
+# expects the MSR number (in hex) as the first parameter, the value (in hex)
+# is the second one. Optionally the CPU number to use for the write can be
+# given as the third argument (defaults to 0)
+# returns 0 on success, 1 for an invalid MSR and 2 for permission issues
+write_msr() (
+ [ $# -lt 2 ] && return 3
+ cpu=${3:-0}
+ if has_program wrmsr ; then
+ wrmsr -p $cpu "$1" "$2" 2> /dev/null
+ return $?
+ fi
+ [ -w /dev/cpu/$cpu/msr ] || return 2
+ low=$(printf "0x%x" $(($2 & (2**32 - 1))))
+ high=$(printf "0x%x" $((($2 >> 32) & (2**32 - 1))))
+ perl -e 'my $value=pack("LL",hex($ARGV[1]),hex($ARGV[2]));sysseek(STDOUT,hex($ARGV[0]),0);syswrite(STDOUT,$value,8) or exit(1);' $1 $low $high > /dev/cpu/$cpu/msr
+)
+
+# Reads an entire cpuid register
+# Usage: get_cpuid_register <leafnr_in_hex> e[abcd]x
+# Example: get_cpuid_register 0x80000001 ecx
+# Outputs the decimal register value to stdout
+# Returns 0 for success, 1 for invalid cpuid leaf, 2 for permission
+get_cpuid_register() {
+ [ $# -lt 2 ] && return 3
+ cpu=${3:-0}
+
+ # try to load the cpuid module if not already done
+ [ -c /dev/cpu/$cpu/cpuid ] || modprobe cpuid > /dev/null 2>&1
+ [ -r /dev/cpu/$cpu/cpuid ] || return 2
+
+ perl -e 'my $leaf;sysseek(STDIN, hex($ARGV[0]),0);sysread(STDIN,$leaf,16) or exit(1);my @regs=unpack("LLLL",$leaf);printf("%u\n",$regs[ord(substr($ARGV[1],1,1))-ord("a")]);' $1 $2 < /dev/cpu/$cpu/cpuid
+}
+
+# Reads a cpuid register and filters a certain bit
+# Usage: get_cpuid_bit <leafnr_in_hex> e[abcd]x <bitnr>
+# Example: get_cpuid_bit 0x80000001 ecx 2
+# Outputs either 0 or 1 to stdout
+# Returns 0 for success, 1 for invalid cpuid leaf, 2 for permission
+get_cpuid_bit() {
+ [ $# -lt 3 ] && return 3
+ cpu=${4:-0}
+ reg=$(get_cpuid_register $1 $2 $4) || return $?
+
+ echo $(($reg >> $3 & 1))
+}
+
+# Get a space separated list of CPUs from a sysfs cpumap file
+# Example:
+# get_cpus_from_cpumap /sys/devices/system/node/node0/cpumap
+# 0 1 2 3
+# Notes:
+# Result may be an empty string
+# Result may be -1 in case of parsing errors
+get_cpus_from_cpumap () {
+ cpumap="${1}"
+ cpus=""
+ wordcnt=$(cat $cpumap | sed -e 's/,/ /g' | wc -w)
+
+ if [ $wordcnt -eq 0 ]; then
+ echo -1
+ return
+ fi
+
+ for i in $(seq $wordcnt -1 1); do
+ offset=$(($wordcnt - $i))
+ word=$((0x$(cat $cpumap | cut -d , -f $i)))
+ if [ $? -ne 0 ]; then cpus=-1; break; fi
+ for j in $(seq 0 31); do
+ if [ $(($word >> $j & 1 )) -eq 1 ]; then
+ cpus="$cpus $((32 * $offset + $j))"
+ fi
+ done
+ done
+
+ echo $cpus
+}
+
+# Get a space separated list of CPUs from a sysfs cpulist file
+# Example:
+# get_cpus_from_cpulist /sys/devices/system/cpu/online
+# 0 1 2 3
+# Notes:
+# Result may be an empty string
+# Result may be -1 in case of parsing errors
+get_cpus_from_cpulist () {
+ cpulist="${1}"
+ cpus=""
+ ranges=$(cat $cpulist | sed -e 's/,/ /g')
+
+ if [ -z "$ranges" ]; then
+ echo -1
+ return
+ fi
+
+ for range in $ranges; do
+ if echo $range | grep -q '^[0-9]\+-[0-9]\+$'; then
+ min=$(echo $range | sed 's/-[0-9]\+$//')
+ max=$(echo $range | sed 's/^[0-9]\+-//')
+ if [ $min -ge $max ]; then cpus=-1; break; fi
+ for cpu in $(seq $min $max); do cpus="$cpus $cpu"; done
+ elif echo $range | grep -q '^[0-9]\+$'; then
+ cpus="$cpus $range"
+ else
+ cpus=-1; break
+ fi
+ done
+
+ echo $cpus
+}
+
+autoreport_skip_all () {
+ explanation="${1:-'no explanation'}"
+ SKIPALL="1..0 # skip $explanation"
+ autoreport_start
+ exit 0
+}
+
+# ==================== TAP utils ====================
+
+get_tap_counter () {
+ echo ${#TAP[@]}
+}
+
+get_tapdata_counter () {
+ echo ${#TAPDATA[@]}
+}
+
+append_tap () {
+ tapline="${1:-'not ok - unknown TAP line in utility function append_tap'}"
+ TAP=( "${TAP[@]}" "$tapline" )
+}
+
+append_tapdata () {
+ tapline="${1:-'not ok - unknown TAP line in utility function append_tapdata'}"
+ TAPDATA=( "${TAPDATA[@]}" "$tapline" )
+}
+
+append_comment () {
+ tapline="# ${@:-''}"
+ TAP=( "${TAP[@]}" "$tapline" )
+ COMMENTCOUNTER=$((COMMENTCOUNTER + 1))
+}
+
+diag () {
+ append_comment "${@}"
+}
+
+is () {
+ A="${1:-}"
+ B="${2:-}"
+ msg="${3:-unknown}"
+
+ if [ "x$A" != "x$B" ] ; then
+ append_tap "not ok - $msg"
+ append_comment "Failed test '$msg'"
+ append_comment "got: '$A'"
+ append_comment "expected: '$B'"
+ else
+ append_tap "ok - $msg"
+ fi
+}
+
+isnt () {
+ A="${1:-}"
+ B="${2:-}"
+ msg="${3:-unknown}"
+
+ if [ "x$A" = "x$B" ] ; then
+ append_tap "not ok - $msg"
+ append_comment "Failed test '$msg'"
+ append_comment "got: '$A'"
+ append_comment "expected: anything else"
+ else
+ append_tap "ok - $msg"
+ fi
+}
+
+require_ok () {
+ success="${1:-0}"
+ msg="${2:-unknown}"
+ if [ "$success" != "0" ] ; then
+ NOT="not "
+ else
+ NOT=""
+ fi
+ append_tap "${NOT}ok - $msg"
+
+ if [ "$success" = "0" ] ; then
+ return
+ fi
+
+ # similar to SKIPALL but report what we have so far
+ if [[ -n $EXIT_ON_SKIPALL ]]; then
+ exit 254
+ else
+ autoreport_start
+ exit 0
+ fi
+}
+
+ok () {
+ success="${1:-0}"
+ msg="${2:-unknown}"
+ if [ "$success" != "0" ] ; then
+ NOT="not "
+ else
+ NOT=""
+ fi
+ append_tap "${NOT}ok - $msg"
+ return $success
+}
+
+negate_ok () {
+ success="${1:-0}"
+ msg="${2:-unknown}"
+ if [ "$success" == "0" ] ; then
+ NOT="not "
+ else
+ NOT=""
+ fi
+ append_tap "${NOT}ok - $msg"
+ return $success
+}
+
+get_hex_from_int() { # returns lower case
+ printf "%x\n" "$1"
+}
+
+lower_case () {
+ string="${1:-}"
+ echo $(echo "$string" | tr '[A-Z]' '[a-z]')
+}
+
+get_random_number () {
+ range_max="${1:-32768}"
+ number=$RANDOM
+ let "number %= $range_max"
+ echo "$number"
+}
+
+get_kernel_release_1 () {
+ uname -r | cut -d. -f1
+}
+
+get_kernel_release_2 () {
+ uname -r | cut -d. -f2
+}
+
+get_kernel_release_3 () {
+ uname -r | cut -d. -f3 | sed -s 's/^\([0-9]*\).*$/\1/'
+}
+
+get_kernel_release () {
+ echo $(uname -r | cut -d. -f1-2).$(get_kernel_release_3)
+}
+
+normalize_version_number () {
+ A="${1:-0}"
+ # triplets x.y.z are converted to x + y/thousands + z/millions
+ # easier, but requires awk:
+ # awk -F. '{printf ("%d.%03d%03d\n",$1,$2,$3);}'
+ # we have to do a trick do avoid octal interpretation due to leading
+ # zeros, we use $((10#<number>)), which overrides with a base of 10
+ if echo $A | grep -q '\.' ; then
+ printf "%d.%03d%03d\n" $((10#$(echo "$A" | cut -d. -f1))) $((10#$(echo "$A" | cut -d. -f2))) $((10#$(echo "$A" | cut -d. -f3)))
+ else
+ echo "$A.000000"
+ fi
+}
+
+version_number_compare () {
+ A="${1:-0}"
+ COMPARATOR="${2:-'-eq'}"
+ B="${3:-0}"
+
+ An=$(normalize_version_number $A | tr -d .)
+ Bn=$(normalize_version_number $B | tr -d .)
+
+ test "$An" $COMPARATOR "$Bn"
+}
+
+version_number_gt () {
+ A="${1:-0}"
+ B="${2:-0}"
+ return $(version_number_compare "$A" -gt "$B")
+}
+
+version_number_ge () {
+ A="${1:-0}"
+ B="${2:-0}"
+ return $(version_number_compare "$A" -ge "$B")
+}
+
+version_number_lt () {
+ A="${1:-0}"
+ B="${2:-0}"
+ return $(version_number_compare "$A" -lt "$B")
+}
+
+version_number_le () {
+ A="${1:-0}"
+ B="${2:-0}"
+ return $(version_number_compare "$A" -le "$B")
+}
+
+has_kernel_release_min () {
+ _ta_autoreport_v="${1:-0}"
+ version_number_compare $(get_kernel_release) -gt $_ta_autoreport_v
+}
+
+require_kernel_release_min () {
+ release_req="${1:-}"
+ explanation="${2:-Linux Kernel must be newer than ${release_req}}"
+ if has_kernel_release_min "$release_req"; then
+ if [ "x1" = "x$REQUIRES_GENERATE_TAP" ] ; then ok $_SUCCESS "require_kernel_release_min $release_req" ; fi
+ return $_SUCCESS
+ else
+ autoreport_skip_all "$explanation"
+ fi
+}
+
+prepare_information() {
+
+ # ===== control variables defaults ==================
+
+ # by default require_* functions generate TAP ok lines
+ REQUIRES_GENERATE_TAP=${REQUIRES_GENERATE_TAP:-1}
+
+ # ===== kernel details ==================
+
+ kernelrelease=$(uname -r)
+
+ # ===== suite name ==================
+
+ myname=$(echo $(basename -- $0 | sed -e 's/\.\w*$//i'))
+
+ SUITE=${myname:-bash-test-utils}
+ VERSION=1.000
+
+ # ===== other meta info ==================
+
+ suite_name=${SUITENAME:-$(echo $SUITE)}
+ suite_version=${SUITEVERSION:-$VERSION}
+ hostname=${HOSTNAME:-$(hostname)}
+ hostname=$(echo $hostname | cut -d. -f1)
+
+ if [ -e /etc/issue.net ]
+ then
+ osname=${OSNAME:-$(cat /etc/issue.net | head -1)}
+ else
+ osname=${OSNAME:-$(uname -o)}
+ fi
+
+ changeset=${CHANGESET:-$(cat /proc/version | head -1)}
+ kernelflags=$(cat /proc/cmdline)
+ uname=$(uname -a)
+ ram=$(free -m | grep -i mem: | awk '{print $2}'MB)
+ starttime_test_program=${starttime_test_program:-$(date --rfc-2822)} # first occurrence
+ starttime_test_program_epoch=${starttime_test_program_epoch:-$(date +"%s")}
+ endtime_test_program=$(date --rfc-2822) # last occurrence
+ endtime_test_program_epoch=$(date +"%s")
+ bogomips=$(echo $(cat /proc/cpuinfo | grep -i bogomips | head -1 | cut -d: -f2))
+ cpuinfo=$(
+ if arm_cpu
+ then
+ cpu=$(grep 'Processor' < /proc/cpuinfo | cut -d: -f2- |head -1 | cut -d" " -f2);
+ else
+ cpu=$(grep 'model name' < /proc/cpuinfo | cut -d: -f2- | head -1 | sed -e "s/^ *//");
+ fi
+ echo "$(get_number_cpus) cores [$cpu]";
+ )
+ # TODO: bogomips from /proc/cpuinfo
+
+ if [ -e "/boot/config-$kernelrelease" ]
+ then
+ BOOTCONFIG="/boot/config-$kernelrelease"
+ else
+ BOOTCONFIG=
+ fi
+ PROCCONFIG="/proc/config.gz"
+
+} # prepare_information()
+
+ltu_suite_meta() {
+ if [[ -n $VERBOSE ]]; then
+ echo "# Test-section: $suite_name";
+ echo "# Test-suite-version: $suite_version";
+ fi
+ echo "# Test-suite-name: $suite_name";
+ echo "# Test-machine-name: $hostname";
+}
+
+ltu_base_os_description () {
+ if [ -r /etc/lsb-release ] ; then
+ . /etc/lsb-release
+ BASE_OS_DESCRIPTION="$DISTRIB_DESCRIPTION"
+ else
+ RELEASE_FILES="/etc/slackware-version /etc/gentoo-release /etc/SuSE-release /etc/issue /etc/issue.net /etc/motd"
+ for i in $RELEASE_FILES ; do if [ -r $i ] ; then RELEASE_FILE=$i ; break ; fi; done
+ BASE_OS_DESCRIPTION=$(cat $RELEASE_FILE | perl -ne 'print if /\w/' | head -1)
+ fi
+ echo $BASE_OS_DESCRIPTION
+}
+
+# we could as well use uname -r here, but lets explicitly ask Xen
+# first what it thinks the Dom0 kernel version is
+ltu_xen_dom0_kernel () {
+ XL=$(get_xen_tool)
+ if [ "$?" -eq 0 ] ; then
+ $XL info 2> /dev/null | grep '^release.*:' | cut -d: -f2 || uname -r
+ else
+ uname -r
+ fi
+}
+
+ltu_xen_changeset () {
+ if [ -r /sys/hypervisor/properties/changeset ] ; then
+ cat /sys/hypervisor/properties/changeset | sed -e 's/^.* \([^ ]*\)/\1/'
+ else
+ XL=$(get_xen_tool) || return $_FAILURE
+ echo $($XL info|grep '^xen_changeset.*:'|sed -e 's/^.* \([^ ]*\)/\1/')
+ fi
+}
+
+ltu_xen_version () {
+ if [ -r /sys/hypervisor/version/major ] ; then
+ _VPATH="/sys/hypervisor/version"
+ echo "$(cat $_VPATH/major).$(cat $_VPATH/minor)$(cat $_VPATH/extra)"
+ else
+ XL=$(get_xen_tool) || return $_FAILURE
+ XEN_VERSION_MAJOR=$(echo $($XL info|grep '^xen_major.*:'|cut -d: -f2))
+ XEN_VERSION_MINOR=$(echo $($XL info|grep '^xen_minor.*:'|cut -d: -f2))
+ XEN_VERSION_EXTRA=$(echo $($XL info|grep '^xen_extra.*:'|cut -d: -f2))
+ XEN_VERSION=""
+ if [ -n "$XEN_VERSION_MAJOR" ] ; then
+ XEN_VERSION="$XEN_VERSION_MAJOR.$XEN_VERSION_MINOR$XEN_VERSION_EXTRA"
+ fi
+ echo $XEN_VERSION
+ fi
+}
+
+ltu_xen_meta () {
+ echo "# Test-xen-dom0-kernel: $(ltu_xen_dom0_kernel)"
+ echo "# Test-xen-version: $(ltu_xen_version)"
+ echo "# Test-xen-changeset: $(ltu_xen_changeset)"
+ echo "# Test-xen-base-os-description: $(ltu_base_os_description)"
+}
+
+ltu_kvm_meta () {
+ echo "# Test-kvm-version: $(uname -r)"
+ echo "# Test-kvm-base-os-description: $(ltu_base_os_description)"
+}
+
+ltu_section_meta() {
+ if [ ! "x1" = "x$DONTREPEATMETA" ] ; then
+ echo "# Test-uname: $uname"
+ echo "# Test-osname: $osname"
+ echo "# Test-kernel: $kernelrelease"
+ echo "# Test-changeset: $changeset"
+ echo "# Test-flags: $kernelflags"
+ echo "# Test-cpuinfo: $cpuinfo"
+ echo "# Test-ram: $ram"
+ echo "# Test-starttime-test-program: $starttime_test_program"
+ echo "# Test-endtime-test-program: $endtime_test_program"
+ if is_running_in_xen_dom0 ; then
+ ltu_xen_meta
+ fi
+ if is_running_in_kvm_host ; then
+ ltu_kvm_meta
+ fi
+ fi
+
+ if [ -n "$SECTION" ] ; then
+ echo "# Test-section: $SECTION"
+ fi
+}
+
+ltu_help () {
+ echo "bash-test-utils"
+ echo ""
+ echo "This is the 'bash-test-utils' bash utility -- a bash include file"
+ echo "to turn your bash script into a test suite that can optionally be"
+ echo "used with the 'prove' command, a standard tool to run test scripts."
+ echo ""
+ echo "Use in your script:"
+ echo " . ./bash-test-utils"
+ echo " # ... your testing here, eg.:"
+ echo " grep -q foobar /proc/cpuinfo"
+ echo ' ok $? "found foobar in cpuinfo"'
+ echo " done_testing"
+ echo ""
+ echo "Run:"
+ echo " prove ./examples/utils-example-01.t"
+ echo " prove -v ./examples/utils-example-01.t # verbose"
+ echo " prove ./examples/ # whole subdir"
+ echo ""
+}
+
+ltu_version () {
+ echo "$VERSION"
+}
+
+# ===== param evaluation ==============================
+
+prepare_start () {
+ prepare_information
+ # other context sensitive initialization (eg. default, destructive, ...)
+}
+
+prepare_plan() {
+ # count of our own tests
+ COUNT=${#TAP[@]}
+ PLAN=$(($MYPLAN + $COUNT - $COMMENTCOUNTER))
+}
+
+# ===== main =========================================
+
+autoreport_main() {
+
+ COMMENTCOUNTER=${COMMENTCOUNTER:-0}
+
+ if [ -n "$SKIPALL" ] ; then
+ echo "$SKIPALL"
+ ltu_suite_meta
+ if [[ -n $VERBOSE ]]; then
+ ltu_section_meta
+ fi
+ return
+ fi
+
+ # ==================== prepare plan
+
+ # count of tests until "END of own tests"
+ MYPLAN=2
+ prepare_plan
+ echo "TAP Version 13"
+ echo "1..$PLAN"
+
+ # ==================== meta info ====================
+ ltu_suite_meta
+ if [[ -n $VERBOSE ]]; then
+ ltu_section_meta
+ fi
+
+ # =============== own headers (later entries win) ===============
+ HEADERSCOUNT=${#HEADERS[@]}
+ for l in $(seq 0 $(($HEADERSCOUNT - 1))) ; do
+ echo ${HEADERS[l]}
+ done
+
+ # ,==================== BEGIN of own tests ====================
+ # |
+ #
+ echo "ok - autoreport"
+ #
+ # |
+ # `==================== END of own tests ====================
+
+ # ==================== remaining TAP ====================
+ for l in $(seq 0 $(($COUNT - 1))) ; do
+ echo ${TAP[l]}
+ done
+
+ # ==================== additional TAP/YAML data ====================
+ echo "ok - tapdata"
+ echo " ---"
+ echo " tapdata: 1"
+ if [ -n "$starttime_test_program_epoch" ] && [ -n "$endtime_test_program_epoch" ] ; then
+ echo " starttime: $starttime_test_program_epoch"
+ echo " endtime: $endtime_test_program_epoch"
+ echo " runtime: $((endtime_test_program_epoch-starttime_test_program_epoch))"
+ fi
+ TAPDATACOUNT=${#TAPDATA[@]}
+ if [ "$TAPDATACOUNT" -gt 0 ] ; then
+ for l in $(seq 0 $(($TAPDATACOUNT - 1))) ; do
+ echo " ${TAPDATA[l]}"
+ done
+ fi
+ echo " ..."
+
+ # ==================== remaining output ====================
+ OUTPUTCOUNT=${#OUTPUT[@]}
+ for l in $(seq 0 $(($OUTPUTCOUNT - 1))) ; do
+ echo ${OUTPUT[l]}
+ done
+
+ # ==================== files ====================
+ for f in $(seq 0 $(($FILECOUNT - 1))) ; do
+ echo "# File upload: '${FILES[f]}'"
+ done
+
+ if set | grep -q '^main_after_hook \(\)' ; then
+ main_after_hook
+ fi
+}
+
+# ===== main =========================================
+
+autoreport_start () {
+
+ prepare_start "${@}"
+ autoreport_main
+}
+
+done_testing () {
+ autoreport_start "${@}"
+}
+
+# =====================================================
+
+function recover_kill {
+ ok 1 'GOT KILLED EXTERNALLY'
+ done_testing
+ exit
+}
+
+trap "recover_kill" SIGTERM SIGHUP SIGINT SIGKILL
+
+# =====================================================
+
+[ "$1" == "--help" ] && ltu_help && exit $_SUCCESS
+[ "$1" == "--version" ] && ltu_version && exit $_SUCCESS
+
+# =====================================================
+
+prepare_information
diff --git a/tools/testing/tap/bash-test-utils.txt b/tools/testing/tap/bash-test-utils.txt
new file mode 100644
index 0000000..b0596db
--- /dev/null
+++ b/tools/testing/tap/bash-test-utils.txt
@@ -0,0 +1,320 @@
+bash-test-utils -- support writing functional tests
+
+ABOUT
+=====
+
+It provides utility functions and facilities to write tests in
+baremetal and Xen/KVM contexts (host and guest support) and was
+polished to work with i686, x86_64, and ARM under lots of major Linux
+distributions (Debian, Ubuntu, RHEL, SLES, Slackware, Fedora,
+openSUSE).
+
+It can be run as normal bash script or indirectly via the "prove"
+command, a standard Linux tool to run test scripts.
+
+
+SYNOPSIS
+========
+
+A test script
+-------------
+
+ #! /bin/bash
+ . ./bash-test-utils
+ # your_feature_test here
+ done_testing
+
+This imports utility functions to be used by your script, then you
+write your tests, and at the end it calls the actual printing of test
+results.
+
+
+Run it via 'prove' (a standard test utility)
+--------------------------------------------
+
+ $ prove ./trivial-example-1.sh
+ ./trivial-example-1.sh .. ok
+ All tests successful.
+ Files=1, Tests=5, 20 wallclock secs
+ Result: PASS
+
+The tool "prove" is a standard tool available in every Linux
+distribution. It runs the script and prints success statistics. See
+"man prove" for more options.
+
+
+UTILITY FUNCTIONS
+=================
+
+Import utility functions at the beginning of the script via
+
+ . tools/testing/tap/bash-test-utils
+
+Then you have several functions available.
+
+Expressing test results
+-----------------------
+
+* ok ARG1 "some description"
+
+ Evaluates the first argument with Shell boolean semantics (0 is
+ true) and appends a corresponding TAP line. See also "require_ok"
+ below.
+
+* negate_ok ARG1 "some description"
+
+ Evaluates the first argument with Shell inverse boolean semantics (0
+ is false) and appends a corresponding TAP line.
+
+* append_tap "ok - some description"
+
+ Appends a complete TAP line where you have taken care for the
+ "ok"/"not ok" at the beginning.
+
+* append_comment "foo bar baz"
+
+ Appends a complete comment line starting with "#". It appears
+ directly after the last added TAP line so it can be used for
+ diagnostics.
+
+* append_tapdata "key: value"
+
+ Appends a key:value line at the final tapdata YAML block. The key
+ must start with letter and consist of only alphanum an underscore.
+
+
+require_* functions
+-------------------
+
+ All require_* functions check for something and gracefully exit the
+ script if the requirement is not fulfilled. Use this to allow the
+ script to run everywhere without polluting results with false
+ negatives.
+
+* require_ok ARG1 "some description"
+
+ Evaluates the first argument with Shell boolean semantics (0 is
+ true) and appends a corresponding TAP line. If it reports "not ok"
+ the script gracefully exits.
+
+* require_amd_family_range [ MIN [ MAX ] ]
+
+ Ensures vendor is AMD and cpu family from /proc/cpuinfo is in a
+ minimum/maximum range. If you don't specify MIN it defaults to 0. If
+ you don't specify MAX it defaults to MIN.
+
+* require_cpufeature "foo"
+
+ Verifies that the string "foo" occurs in /proc/cpuinfo flags section.
+
+* require_kernel_config "CONFIG_FOO"
+
+ Verify that regex "^CONFIG_FOO=." occurs in /proc/config.gz or
+ /boot/config/$ (uname -r).
+
+* require_program "foo"
+
+ Verify that the program "foo" is available. Use it to declare
+ external programs you call, like "awk", "bc", "perl", etc.
+
+* require_l3cache
+
+ Verify that L3 cache is available (checked in
+ /sys/devices/system/cpu/cpu0/ cache/index3).
+
+* require_root
+
+ Verify that the user executing the script is root (UID 0).
+
+* require_crit_level N
+
+ Verify that the criticality level N of the script is allowed to be
+ run, which is controlled by environment variable CRITICALITY. See
+ "has_crit_level" for meaning of criticality levels.
+
+* require_cpb_disabled
+
+ Enables cpufreq and disables boosting. In case of errors the calling
+ test is skipped.
+
+* require_cpufreq_enabled
+
+ Enables cpufreq and also core boosting. In case of errors the
+ calling test is skipped.
+
+* require_kernel_release_min
+
+ Verify that the current LK release is at least the required version
+ number.
+
+* require_running_in_xen_guest
+
+ Verify if we are in a Xen guest.
+
+* require_running_in_kvm_guest
+
+ Verify if we are in a KVM guest.
+
+* require_running_in_virtualized_guest
+
+ Verify if we are in a virtualized guest (Xen or KVM).
+
+
+request_* functions
+-------------------
+
+All request_* functions try to enable something and if that fails mark it as
+#TODO but continue the test. It's kind of an "uncritical require_*".
+
+* request_cpb_disabled
+
+ Enables cpufreq and disables boosting. The result will be reported
+ and returned. Errors are marked as TODO.
+
+* request_cpufreq_enabled
+
+ Enables cpufreq and also core boosting. The result will be reported
+ and returned. Errors are marked as TODO.
+
+
+Misc auxiliary functions
+------------------------
+
+These are really just utilities to help you but they don't influence the
+behaviour like the require_* functions do.
+
+* has_l3cache
+
+ Returns 0 (shell TRUE) if L3 cache is available (checked in
+ /sys/devices/ system/cpu/cpu0/cache/index3).
+
+* has_cpufeature "foo"
+
+ Returns 0 (shell TRUE) if string "foo" occurs in /proc/cpuinfo flags
+ section.
+
+* has_kernel_release_min
+
+ Returns 0 (shell TRUE) if the current LK release is at least the
+ required version number.
+
+* has_kernel_config "CONFIG_FOO"
+
+ Returns 0 (shell TRUE) if regex "^CONFIG_FOO=." occurs in
+ /proc/config.gz or / boot/config/$(uname -r).
+
+* has_program "foo"
+
+ Return 0 (shell TRUE) if the program "foo" is available.
+
+* has_crit_level N
+
+ Checks whether the criticality level N of the script is allowed to
+ be run, which is controlled by environment variable CRITICALITY. The
+ criticality levels are defined as this:
+
+ * 0: not critical
+ * 1: read sysfs/debugfs/proc files
+ * 2: read HW (MSRs/Northbridge)
+ * 3: write sysfs/debugfs/proc files
+ * 4: write HW (MSRs/Northbridge) or potentially crash the machine
+
+* get_vendor
+
+ Prints vendor "AMD" or "Intel" from /proc/cpuinfo.
+
+* vendor_intel
+
+ Returns 0 (shell TRUE) if vendor is Intel.
+
+* vendor_amd
+
+ Returns 0 (shell TRUE) if vendor is AMD.
+
+* get_random_number [ MAX ]
+
+ Prints a random integer between 0 and MAX (default 32768).
+
+* get_cpu_family
+
+ Print cpu family from /proc/cpuinfo.
+
+* get_cpu_family_hex
+
+ Print cpu family from /proc/cpuinfo in hex syntax (0x...).
+
+* cpu_family_min [ MINFAMILY ]
+
+ Returns 0 (shell TRUE) if cpu family from /proc/cpuinfo is greater
+ or equal to MINFAMILY. Defaults to 0.
+
+* cpu_family_max [ MAXFAMILY ]
+
+ Returns 0 (shell TRUE) if cpu family from /proc/cpuinfo is less or
+ equal to MAXFAMILY. Defaults to 999.
+
+* get_first_file [ LIST OF FILENAMES ]
+
+ Goes through all specified filenames and prints the first one that
+ exists and is readable.
+
+* is_element_in_list WORD "SPACE SEPARATED LIST OF WORDS"
+
+ Returns 0 (shell TRUE) if WORD appears in "SPACE SEPARATED LIST OF
+ WORDS". Remember the usual shell quoting rules.
+
+* get_kernel_release
+
+ Prints the kernel version number from uname -r.
+
+* is_running_in_xen_guest
+
+ Check if we are in a Xen guest.
+
+* is_running_in_kvm_guest
+
+ Check if we are in a KVM guest.
+
+* is_running_in_virtualized_guest
+
+ Check if we are in a virtualized guest (Xen or KVM).
+
+
+INFLUENCING BEHAVIOUR
+=====================
+
+Environment Variables
+---------------------
+
+These variables are expected to be set inside the script to declare
+meta information or influence behaviour:
+
+* TAP[*] - Array of TAP lines
+* TAPDATA[*] - Array of YAML lines that contain data in TAP
+* OUTPUT[*] - Array of additional output lines
+* SUITENAME - alternative suite name instead of $0
+* SUITEVERSION - alternative suite version
+* KEYWORDS - space separated keywords to influence suite
+ name
+* OSNAME - alternative OS description
+* CHANGESET - alternative changeset
+* HOSTNAME - alternative hostname
+* TICKETURL - relevant URL in used ticket system
+ (Bugzilla)
+* WIKIURL - relevant URL in used wiki
+* PLANNINGID - relevant task planning id
+ (MS Project, TaskJuggler, etc.)
+* REQUIRES_GENERATE_TAP - if "1" then require_* functions generate
+ additional "ok" line on success
+
+
+External environment variables
+------------------------------
+
+These variables are expected to be set from outside of the script to
+influence behaviour:
+
+* EXIT_ON_SKIPALL - if "1" then on skip_all we immediately exit
+ with exitcode 254.
+* CRITICALITY - Sets the allowed maximal criticality level.
+ Scripts with higher level call skip_all().
--
1.7.10.4
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 2/2] A common test subdirectory
2012-10-23 8:03 [PATCH 0/2] RFC: A common test container steffen.schwigon
2012-10-23 8:03 ` [PATCH 1/2] bash-test-utils: support writing functional tests steffen.schwigon
@ 2012-10-23 8:03 ` steffen.schwigon
1 sibling, 0 replies; 3+ messages in thread
From: steffen.schwigon @ 2012-10-23 8:03 UTC (permalink / raw)
To: linux-kernel
Cc: ss5, srostedt, Dariusz.Filipski, yoshitake.kobayashi, sassmann,
andre.przywara, frank.arnold, conny.seidel, csd,
Steffen Schwigon
From: Steffen Schwigon <steffen.schwigon@amd.com>
This commit introduces t/ as a subdirectory for placing
tests that can be run via the existing Linux tool
'prove' (available in all major Linux distributions).
Tests in there are assumed to produce TAP, the "Test
Anything Protocol" (see http://testanything.org).
A library with special utilities to write TAP tests for
Linux (inclusive KVM and Xen support) is provided in the
previous commit ('bash-test-utils'). TAP libraries are
available for many programming languages. The autotest
project already provides TAP support.
Signed-off-by: Steffen Schwigon <steffen.schwigon@amd.com>
---
t/examples/basic.t | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
create mode 100755 t/examples/basic.t
diff --git a/t/examples/basic.t b/t/examples/basic.t
new file mode 100755
index 0000000..d776108
--- /dev/null
+++ b/t/examples/basic.t
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+############################################################
+#
+# t/examples/basic.t
+#
+# An example test script for bash-test-utils
+#
+# Run it with:
+#
+# $ cd $LINUX_SRC_DIR
+# $ prove -v t/examples/basic.t
+#
+############################################################
+
+. ./tools/testing/tap/bash-test-utils
+
+uname -a | grep -q Linux # example for ok exit code
+ok $? "we run on Linux"
+
+# require_* functions gracefully exit if requirements not met
+require_cpufeature "msr"
+require_cpufeature "fpu"
+
+# store success in variables and make complex tests
+if grep -q sse2 /proc/cpuinfo ; then
+ success=0
+else
+ success=1
+fi
+
+# ok() evaluates arg 1 with exit code shell boolean semantics
+# and creates TAP
+ok $success "SSE2 in cpuinfo"
+
+# negate_ok() reverses the success semantics of ok()
+grep -q impossible-value /proc/cpuinfo
+negate_ok $? "no impossible-value in cpuinfo"
+
+# mark tests with "# TODO" at end of description
+# for test driven development
+grep -q not-yet-implemented-detail /proc/cpuinfo
+ok $? "example that fails expectedly # TODO some todo explanation"
+
+# append key:value lines to track values
+bogomips=$(grep -i bogomips /proc/cpuinfo | head -1 | cut -d: -f2)
+append_tapdata "bogomips: $(echo $bogomips)"
+
+done_testing
--
1.7.10.4
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2012-10-23 8:06 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-10-23 8:03 [PATCH 0/2] RFC: A common test container steffen.schwigon
2012-10-23 8:03 ` [PATCH 1/2] bash-test-utils: support writing functional tests steffen.schwigon
2012-10-23 8:03 ` [PATCH 2/2] A common test subdirectory steffen.schwigon
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®