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

Jerry Van Baren gvb.uboot at gmail.com
Sat Nov 24 02:03:38 CET 2007


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 at 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 at 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





More information about the U-Boot mailing list