[U-Boot-Users] [RFC PATCH] Add u-boot command regression tests.

Jerry Van Baren
2007-11-24T01:03:38Z

This uses PyUnit and python-serial <http://pyserial.sourceforge.net/>
to do unit testing on u-boot commands.

Signed-off-by: Gerald Van Baren <vanbaren@cideas.com>
---

...and now, for something completely different.

The concept here is to use PyUnit testing in conjunction with python
serial I/O (theoretically, ethernet-based command I/O could be handled
too).

This is a concept probably sufficiently implemented for the "help"
command and a good start for the "fdt" command.

What does The List think?
* Useful to have regression tests for the u-boot commands?
* Implementation-wise, am I heading in the right direction?

Best regards,
gvb

u-unit/.gitignore | 2 +
u-unit/fdt.dts | 30 +++++++++
u-unit/fdt.py | 171 +++++++++++++++++++++++++++++++++++++++++++++++++++++
u-unit/help.py | 70 ++++++++++++++++++++++
u-unit/ubootio.py | 55 +++++++++++++++++
5 files changed, 328 insertions(+), 0 deletions(-)
create mode 100644 u-unit/.gitignore
create mode 100644 u-unit/fdt.dts
create mode 100755 u-unit/fdt.py
create mode 100755 u-unit/help.py
create mode 100755 u-unit/ubootio.py

diff --git a/u-unit/.gitignore b/u-unit/.gitignore
new file mode 100644
index 0000000..88e6bec
--- /dev/null
+++ b/u-unit/.gitignore
@@ -0,0 +1,2 @@
+*.pyc
+*.dtb
diff --git a/u-unit/fdt.dts b/u-unit/fdt.dts
new file mode 100644
index 0000000..66efcdd
--- /dev/null
+++ b/u-unit/fdt.dts
@@ -0,0 +1,30 @@
+/dts-v1/;
+
+/ {
+ compatible = "fdt";
+ prop-int = <0xdeadbeef>;
+ prop-str = "hello world";
+
+ subnode at 1 {
+ compatible = "subnode1";
+ prop-int = <0x01234567>;
+
+ subsubnode {
+ compatible = "subsubnode1", "subsubnode";
+ prop-int = <0x12345678>;
+ prop-empty;
+ };
+ };
+
+ subnode at 2 {
+ linux,phandle = <0x2000>;
+ prop-int = <0x23456789>;
+
+ subsubnode at 0 {
+ linux,phandle = <0x2001>;
+ compatible = "subsubnode2", "subsubnode";
+ prop-empty;
+ prop-int = <0x3456789a>;
+ };
+ };
+};
diff --git a/u-unit/fdt.py b/u-unit/fdt.py
new file mode 100755
index 0000000..53c1117
--- /dev/null
+++ b/u-unit/fdt.py
@@ -0,0 +1,171 @@
+#!/usr/bin/python
+#
+# Test suite for the fdt u-boot command
+#
+
+import unittest
+import re
+import ubootio
+
+class FdtTestCase(unittest.TestCase):
+ """
+ Run regression tests the "fdt" command and subcommands
+
+ This requires a test fdt blob to be loaded.
+
+ Subcommands to be tested...
+help fdt
+fdt addr <addr> [<length>] - Set the fdt location to <addr>
+fdt boardsetup - Do board-specific set up
+fdt move <fdt> <newaddr> <length> - Copy the fdt to <addr>
+fdt print <path> [<prop>] - Recursive print starting at <path>
+fdt list <path> [<prop>] - Print one level starting at <path>
+fdt set <path> <prop> [<val>] - Set <property> [to <val>]
+fdt mknode <path> <node> - Create a new node after <path>
+fdt rm <path> [<prop>] - Delete the node or <property>
+fdt chosen - Add/update the /chosen branch in the tree
+fdt env - Add/replace the /u-boot-env branch in the tree
+fdt bd_t - Add/replace the /bd_t branch in the tree
+ """
+
+ #
+ # Configuration
+ #
+ scratchram = "0x400000"
+ serverip = "192.168.47.8"
+ ipaddr = "192.168.47.214"
+
+
+ def setUp(self):
+ """fdt test case setup."""
+
+ # Configuration
+ self.fdt_setup = "\
+set serverip " + self.serverip + " ; \
+set ipaddr " + self.ipaddr + " ; \
+tftp " + self.scratchram + " fdt.dtb ; \
+fdt address " + self.scratchram + "\n"
+
+ self.fdt_dts = """\
+/ {
+ compatible = "fdt";
+ prop-int = <0xdeadbeef>;
+ prop-str = "hello world";
+ subnode at 1 {
+ compatible = "subnode1";
+ prop-int = <0x01234567>;
+ subsubnode {
+ compatible = "subsubnode1", "subsubnode";
+ prop-int = <0x12345678>;
+ prop-empty;
+ };
+ };
+ subnode at 2 {
+ linux,phandle = <0x00002000>;
+ prop-int = <0x23456789>;
+ subsubnode at 0 {
+ linux,phandle = <0x00002001>;
+ compatible = "subsubnode2", "subsubnode";
+ prop-empty;
+ prop-int = <0x3456789a>;
+ };
+ };
+};"""
+ self.fdt_subnode2_dts = """\
+subnode at 2 {
+ linux,phandle = <0x00002000>;
+ prop-int = <0x23456789>;
+ subsubnode at 0 {
+ linux,phandle = <0x00002001>;
+ compatible = "subsubnode2", "subsubnode";
+ prop-empty;
+ prop-int = <0x3456789a>;
+ };
+};"""
+ self.fdt_list_dts = """\
+/ {
+ compatible = "fdt";
+ prop-int = <0xdeadbeef>;
+ prop-str = "hello world";
+ subnode at 1 {
+ };
+ subnode at 2 {
+ };
+};"""
+
+ self.re_dts = re.compile(self.fdt_dts)
+ self.re_subnode2_dts = re.compile(self.fdt_subnode2_dts)
+ self.re_list_dts = re.compile(self.fdt_list_dts)
+
+ self.IO = ubootio.uBootIO()
+
+ self.IO.sendcmd(self.fdt_setup);
+ n = self.IO.waitresponse()
+ if (n <= 0):
+ print "FAIL: Timeout"
+ raise AssertionError
+ s = self.IO.getresponse(n)
+
+ # Verify that the dtb was loaded.
+ if (not re.search("Bytes transferred =", s)):
+ print "FAIL: could not load the test dtb.\n", s
+ raise AssertionError
+
+ def tearDown(self):
+ pass
+
+ def testPrintRoot(self):
+ """
+ Print starting@the root node.
+ """
+ self.IO.sendcmd("fdt print /\n");
+ n = self.IO.waitresponse()
+ assert n > 0, "Timeout"
+
+ s = self.IO.getresponse(n)
+ assert self.re_dts.search(s), \
+ "fdt print did not match.\nIS:\n" + s + \
+ "SHOULD BE:\n" + fdt_dts
+
+ def testPrintUnspecified(self):
+ """
+ Print with no node specified, defaults to the root node.
+ """
+ self.IO.sendcmd("fdt print\n");
+ n = self.IO.waitresponse()
+ assert n > 0, "Timeout"
+
+ s = self.IO.getresponse(n)
+ assert self.re_dts.search(s), \
+ "fdt print did not match.\nIS:\n" + s + \
+ "SHOULD BE:\n" + fdt_dts
+
+ def testPrintSubnode(self):
+ """
+ Print a subnode.
+ """
+ self.IO.sendcmd("fdt p /subnode at 2\n");
+ n = self.IO.waitresponse()
+ assert n > 0, "Timeout"
+
+ s = self.IO.getresponse(n)
+ assert self.re_subnode2_dts.search(s), \
+ "fdt print did not match.\nIS:\n" + s + \
+ "SHOULD BE:\n" + fdt_subnode2_dts
+
+ def testListRoot(self):
+ """
+ List starting at the root node.
+ """
+ self.IO.sendcmd("fdt list\n");
+ n = self.IO.waitresponse()
+ assert n > 0, "Timeout"
+
+ s = self.IO.getresponse(n)
+ assert self.re_list_dts.search(s), \
+ "fdt list did not match.\nIS:\n" + s + \
+ "SHOULD BE:\n" + fdt_list_dts
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/u-unit/help.py b/u-unit/help.py
new file mode 100755
index 0000000..dbd0e0e
--- /dev/null
+++ b/u-unit/help.py
@@ -0,0 +1,70 @@
+#!/usr/bin/python
+#
+# Test suite for the fdt u-boot command
+#
+
+import unittest
+import re
+import ubootio
+
+class HelpTestCase(unittest.TestCase):
+ """ Run regression tests the "help" command """
+
+
+ def setUp(self):
+ """help test case setup."""
+
+ self.IO = ubootio.uBootIO()
+
+
+ def testHelp(self):
+ """
+ Run regression tests the "help" command
+
+ This runs the "help" command and verifies that it returns
+ information on a subset of the commands.
+ """
+
+ # These commands should be on all configurations
+ tests = [ \
+ "askenv", \
+ "base", \
+ "boot", \
+ "cp", \
+ "crc32", \
+ "echo", \
+ "erase", \
+ "exit", \
+ "go", \
+ "help", \
+ "icrc32", \
+ "md", \
+ "mm", \
+ "mw", \
+ "nm", \
+ "printenv", \
+ "protect", \
+ "reset", \
+ "run", \
+ "saveenv", \
+ "setenv", \
+ "sleep", \
+ "test", \
+ "version", \
+ "=>" ]
+
+ self.IO.sendcmd("help\n")
+ n = self.IO.waitresponse()
+ if (n <= 0):
+ print "FAIL: Timeout"
+ testpassed = False
+ else:
+ s = self.IO.getresponse(n)
+ for test in tests:
+ if (not re.search(test, s)):
+ print "FAIL: ", test, " not found in\n", s
+ testpassed = False
+
+if __name__ == "__main__":
+ unittest.main()
+
diff --git a/u-unit/ubootio.py b/u-unit/ubootio.py
new file mode 100755
index 0000000..3dad300
--- /dev/null
+++ b/u-unit/ubootio.py
@@ -0,0 +1,55 @@
+#!/usr/bin/python
+#
+# I/O for the u-boot command regression tests
+#
+
+import serial
+import time
+import re
+
+
+class uBootIO:
+ #
+ # Configuration
+ #
+ chantimeout = 0.5
+
+ def __init__(self):
+ self.chan = serial.Serial(0, 115200, timeout=5.0, rtscts=0, \
+ parity=serial.PARITY_NONE)
+
+
+ def waitresponse(self):
+ """
+ Waits for a response from the target.
+
+ Returns the number of characters waiting to be received.
+ """
+
+ n = -1
+ time.sleep(self.chantimeout)
+ while (self.chan.inWaiting() > n):
+ time.sleep(self.chantimeout)
+ n = self.chan.inWaiting()
+ if (n <= 0):
+ print "FAIL: Timeout"
+ return n
+
+ def getresponse(self, n):
+ """
+ Returns the response from the target.
+
+ Post-processes the response for line ends (changes to newlines).
+ """
+
+ canonical = re.compile("[\r\n]+")
+
+ s = self.chan.read(n)
+ return canonical.sub("\n", s)
+
+ def sendcmd(self, s):
+ """
+ Send a command string to the target.
+ """
+
+ self.chan.write(s)
--
1.5.3.4