From mboxrd@z Thu Jan 1 00:00:00 1970 From: Jerry Van Baren Date: Fri, 23 Nov 2007 20:03:38 -0500 Subject: [U-Boot-Users] [RFC PATCH] Add u-boot command regression tests. Message-ID: <20071124010338.GA27628@cideas.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de This uses PyUnit and python-serial to do unit testing on u-boot commands. Signed-off-by: Gerald Van Baren --- ...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 [] - Set the fdt location to +fdt boardsetup - Do board-specific set up +fdt move - Copy the fdt to +fdt print [] - Recursive print starting at +fdt list [] - Print one level starting at +fdt set [] - Set [to ] +fdt mknode - Create a new node after +fdt rm [] - Delete the node or +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