diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/env/fw_env.c | 127 | ||||
-rw-r--r-- | tools/env/fw_env.h | 24 | ||||
-rw-r--r-- | tools/env/fw_env_main.c | 249 | ||||
-rw-r--r-- | tools/palmtreo680/flash_u-boot.c | 2 | ||||
-rw-r--r-- | tools/patman/README | 2 | ||||
-rw-r--r-- | tools/tbot/README | 185 | ||||
-rw-r--r-- | tools/tbot/README-ToDo | 62 | ||||
-rw-r--r-- | tools/tbot/README.create_a_new_testcase | 117 | ||||
-rw-r--r-- | tools/tbot/README.install | 370 |
9 files changed, 967 insertions, 171 deletions
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c index 39f733376e..ee17a69016 100644 --- a/tools/env/fw_env.c +++ b/tools/env/fw_env.c @@ -34,8 +34,6 @@ #include "fw_env.h" -#include <aes.h> - #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) #define WHITESPACE(c) ((c == '\t') || (c == ' ')) @@ -105,9 +103,6 @@ static struct environment environment = { .flag_scheme = FLAG_NONE, }; -/* Is AES encryption used? */ -static int aes_flag; -static uint8_t aes_key[AES_KEY_LENGTH] = { 0 }; static int env_aes_cbc_crypt(char *data, const int enc); static int HaveRedundEnv = 0; @@ -125,7 +120,6 @@ static int parse_config (void); #if defined(CONFIG_FILE) static int get_config (char *); -static char *config_file = CONFIG_FILE; #endif static inline ulong getenvsize (void) { @@ -134,7 +128,7 @@ static inline ulong getenvsize (void) if (HaveRedundEnv) rc -= sizeof (char); - if (aes_flag) + if (common_args.aes_flag) rc &= ~(AES_KEY_LENGTH - 1); return rc; @@ -208,7 +202,7 @@ char *fw_getdefenv(char *name) return NULL; } -static int parse_aes_key(char *key) +int parse_aes_key(char *key, uint8_t *bin_key) { char tmp[5] = { '0', 'x', 0, 0, 0 }; unsigned long ul; @@ -230,11 +224,9 @@ static int parse_aes_key(char *key) "## Error: '-a' option requires valid AES key\n"); return -1; } - aes_key[i] = ul & 0xff; + bin_key[i] = ul & 0xff; key += 2; } - aes_flag = 1; - return 0; } @@ -245,39 +237,12 @@ static int parse_aes_key(char *key) int fw_printenv (int argc, char *argv[]) { char *env, *nxt; - int i, n_flag; - int rc = 0; - -#ifdef CONFIG_FILE - if (argc >= 2 && strcmp(argv[1], "-c") == 0) { - if (argc < 3) { - fprintf(stderr, - "## Error: '-c' option requires the config file to use\n"); - return -1; - } - config_file = argv[2]; - argv += 2; - argc -= 2; - } -#endif - - if (argc >= 2 && strcmp(argv[1], "-a") == 0) { - if (argc < 3) { - fprintf(stderr, - "## Error: '-a' option requires AES key\n"); - return -1; - } - rc = parse_aes_key(argv[2]); - if (rc) - return rc; - argv += 2; - argc -= 2; - } + int i, rc = 0; if (fw_env_open()) return -1; - if (argc == 1) { /* Print all env variables */ + if (argc == 0) { /* Print all env variables */ for (env = environment.data; *env; env = nxt + 1) { for (nxt = env; *nxt; ++nxt) { if (nxt >= &environment.data[ENV_SIZE]) { @@ -292,20 +257,13 @@ int fw_printenv (int argc, char *argv[]) return 0; } - if (strcmp (argv[1], "-n") == 0) { - n_flag = 1; - ++argv; - --argc; - if (argc != 2) { - fprintf (stderr, "## Error: " - "`-n' option requires exactly one argument\n"); - return -1; - } - } else { - n_flag = 0; + if (printenv_args.name_suppress && argc != 1) { + fprintf(stderr, + "## Error: `-n' option requires exactly one argument\n"); + return -1; } - for (i = 1; i < argc; ++i) { /* print single env variables */ + for (i = 0; i < argc; ++i) { /* print single env variables */ char *name = argv[i]; char *val = NULL; @@ -320,7 +278,7 @@ int fw_printenv (int argc, char *argv[]) } val = envmatch (name, env); if (val) { - if (!n_flag) { + if (!printenv_args.name_suppress) { fputs (name, stdout); putc ('=', stdout); } @@ -340,7 +298,7 @@ int fw_printenv (int argc, char *argv[]) int fw_env_close(void) { int ret; - if (aes_flag) { + if (common_args.aes_flag) { ret = env_aes_cbc_crypt(environment.data, 1); if (ret) { fprintf(stderr, @@ -496,43 +454,14 @@ int fw_env_write(char *name, char *value) */ int fw_setenv(int argc, char *argv[]) { - int i, rc; + int i; size_t len; - char *name; + char *name, **valv; char *value = NULL; + int valc; -#ifdef CONFIG_FILE - if (argc >= 2 && strcmp(argv[1], "-c") == 0) { - if (argc < 3) { - fprintf(stderr, - "## Error: '-c' option requires the config file to use\n"); - return -1; - } - config_file = argv[2]; - argv += 2; - argc -= 2; - } -#endif - - if (argc < 2) { - errno = EINVAL; - return -1; - } - - if (strcmp(argv[1], "-a") == 0) { - if (argc < 3) { - fprintf(stderr, - "## Error: '-a' option requires AES key\n"); - return -1; - } - rc = parse_aes_key(argv[2]); - if (rc) - return rc; - argv += 2; - argc -= 2; - } - - if (argc < 2) { + if (argc < 1) { + fprintf(stderr, "## Error: variable name missing\n"); errno = EINVAL; return -1; } @@ -542,14 +471,16 @@ int fw_setenv(int argc, char *argv[]) return -1; } - name = argv[1]; + name = argv[0]; + valv = argv + 1; + valc = argc - 1; - if (env_flags_validate_env_set_params(argc, argv) < 0) + if (env_flags_validate_env_set_params(name, valv, valc) < 0) return 1; len = 0; - for (i = 2; i < argc; ++i) { - char *val = argv[i]; + for (i = 0; i < valc; ++i) { + char *val = valv[i]; size_t val_len = strlen(val); if (value) @@ -1023,7 +954,7 @@ static int env_aes_cbc_crypt(char *payload, const int enc) uint32_t aes_blocks; /* First we expand the key. */ - aes_expand_key(aes_key, key_exp); + aes_expand_key(common_args.aes_key, key_exp); /* Calculate the number of AES blocks to encrypt. */ aes_blocks = DIV_ROUND_UP(len, AES_KEY_LENGTH); @@ -1251,7 +1182,7 @@ int fw_env_open(void) crc0 = crc32 (0, (uint8_t *) environment.data, ENV_SIZE); - if (aes_flag) { + if (common_args.aes_flag) { ret = env_aes_cbc_crypt(environment.data, 0); if (ret) return ret; @@ -1308,7 +1239,7 @@ int fw_env_open(void) crc1 = crc32 (0, (uint8_t *) redundant->data, ENV_SIZE); - if (aes_flag) { + if (common_args.aes_flag) { ret = env_aes_cbc_crypt(redundant->data, 0); if (ret) return ret; @@ -1392,9 +1323,9 @@ static int parse_config () #if defined(CONFIG_FILE) /* Fills in DEVNAME(), ENVSIZE(), DEVESIZE(). Or don't. */ - if (get_config (config_file)) { - fprintf (stderr, - "Cannot parse config file '%s': %s\n", config_file, strerror (errno)); + if (get_config(common_args.config_file)) { + fprintf(stderr, "Cannot parse config file '%s': %m\n", + common_args.config_file); return -1; } #else diff --git a/tools/env/fw_env.h b/tools/env/fw_env.h index 60c05177ff..57149e733b 100644 --- a/tools/env/fw_env.h +++ b/tools/env/fw_env.h @@ -5,6 +5,9 @@ * SPDX-License-Identifier: GPL-2.0+ */ +#include <aes.h> +#include <stdint.h> + /* Pull in the current config to define the default environment */ #include <linux/kconfig.h> @@ -54,6 +57,27 @@ "bootm" #endif +struct common_args { +#ifdef CONFIG_FILE + char *config_file; +#endif + uint8_t aes_key[AES_KEY_LENGTH]; + int aes_flag; /* Is AES encryption used? */ +}; +extern struct common_args common_args; + +struct printenv_args { + int name_suppress; +}; +extern struct printenv_args printenv_args; + +struct setenv_args { + char *script_file; +}; +extern struct setenv_args setenv_args; + +int parse_aes_key(char *key, uint8_t *bin_key); + extern int fw_printenv(int argc, char *argv[]); extern char *fw_getenv (char *name); extern int fw_setenv (int argc, char *argv[]); diff --git a/tools/env/fw_env_main.c b/tools/env/fw_env_main.c index 234c061544..4bd4216625 100644 --- a/tools/env/fw_env_main.c +++ b/tools/env/fw_env_main.c @@ -36,119 +36,226 @@ #include <unistd.h> #include "fw_env.h" -#define CMD_PRINTENV "fw_printenv" +#define CMD_PRINTENV "fw_printenv" #define CMD_SETENV "fw_setenv" +static int do_printenv; static struct option long_options[] = { - {"script", required_argument, NULL, 's'}, + {"aes", required_argument, NULL, 'a'}, + {"config", required_argument, NULL, 'c'}, {"help", no_argument, NULL, 'h'}, + {"script", required_argument, NULL, 's'}, + {"noheader", required_argument, NULL, 'n'}, {NULL, 0, NULL, 0} }; -void usage(void) +struct common_args common_args; +struct printenv_args printenv_args; +struct setenv_args setenv_args; + +void usage_printenv(void) { - fprintf(stderr, "fw_printenv/fw_setenv, " - "a command line interface to U-Boot environment\n\n" -#ifndef CONFIG_FILE - "usage:\tfw_printenv [-a key] [-n] [variable name]\n" - "\tfw_setenv [-a key] [variable name] [variable value]\n" -#else - "usage:\tfw_printenv [-c /my/fw_env.config] [-a key] [-n] [variable name]\n" - "\tfw_setenv [-c /my/fw_env.config] [-a key] [variable name] [variable value]\n" + fprintf(stderr, + "Usage: fw_printenv [OPTIONS]... [VARIABLE]...\n" + "Print variables from U-Boot environment\n" + "\n" + " -h, --help print this help.\n" +#ifdef CONFIG_ENV_AES + " -a, --aes aes key to access environment\n" +#endif +#ifdef CONFIG_FILE + " -c, --config configuration file, default:" CONFIG_FILE "\n" +#endif + " -n, --noheader do not repeat variable name in output\n" + "\n"); +} + +void usage_setenv(void) +{ + fprintf(stderr, + "Usage: fw_setenv [OPTIONS]... [VARIABLE]...\n" + "Modify variables in U-Boot environment\n" + "\n" + " -h, --help print this help.\n" +#ifdef CONFIG_ENV_AES + " -a, --aes aes key to access environment\n" +#endif +#ifdef CONFIG_FILE + " -c, --config configuration file, default:" CONFIG_FILE "\n" #endif - "\tfw_setenv -s [ file ]\n" - "\tfw_setenv -s - < [ file ]\n\n" - "The file passed as argument contains only pairs " - "name / value\n" - "Example:\n" - "# Any line starting with # is treated as comment\n" + " -s, --script batch mode to minimize writes\n" + "\n" + "Examples:\n" + " fw_setenv foo bar set variable foo equal bar\n" + " fw_setenv foo clear variable foo\n" + " fw_setenv --script file run batch script\n" "\n" - "\t netdev eth0\n" - "\t kernel_addr 400000\n" - "\t var1\n" - "\t var2 The quick brown fox jumps over the " - "lazy dog\n" + "Script Syntax:\n" + " key [space] value\n" + " lines starting with '#' are treated as commment\n" "\n" - "A variable without value will be dropped. It is possible\n" - "to put any number of spaces between the fields, but any\n" - "space inside the value is treated as part of the value " - "itself.\n\n" - ); + " A variable without value will be deleted. Any number of spaces are\n" + " allowed between key and value. Space inside of the value is treated\n" + " as part of the value itself.\n" + "\n" + "Script Example:\n" + " netdev eth0\n" + " kernel_addr 400000\n" + " foo empty empty empty empty empty empty\n" + " bar\n" + "\n"); } -int main(int argc, char *argv[]) +static void parse_common_args(int argc, char *argv[]) { - char *p; - char *cmdname = *argv; - char *script_file = NULL; int c; - const char *lockname = "/var/lock/" CMD_PRINTENV ".lock"; - int lockfd = -1; - int retval = EXIT_SUCCESS; - lockfd = open(lockname, O_WRONLY | O_CREAT | O_TRUNC, 0666); - if (-1 == lockfd) { - fprintf(stderr, "Error opening lock file %s\n", lockname); - return EXIT_FAILURE; - } +#ifdef CONFIG_FILE + common_args.config_file = CONFIG_FILE; +#endif - if (-1 == flock(lockfd, LOCK_EX)) { - fprintf(stderr, "Error locking file %s\n", lockname); - close(lockfd); - return EXIT_FAILURE; + while ((c = getopt_long(argc, argv, ":a:c:h", long_options, NULL)) != + EOF) { + switch (c) { + case 'a': + if (parse_aes_key(optarg, common_args.aes_key)) { + fprintf(stderr, "AES key parse error\n"); + exit(EXIT_FAILURE); + } + common_args.aes_flag = 1; + break; +#ifdef CONFIG_FILE + case 'c': + common_args.config_file = optarg; + break; +#endif + case 'h': + do_printenv ? usage_printenv() : usage_setenv(); + exit(EXIT_SUCCESS); + break; + default: + /* ignore unknown options */ + break; + } } - if ((p = strrchr (cmdname, '/')) != NULL) { - cmdname = p + 1; - } + /* Reset getopt for the next pass. */ + opterr = 1; + optind = 1; +} + +int parse_printenv_args(int argc, char *argv[]) +{ + int c; - while ((c = getopt_long (argc, argv, "a:c:ns:h", - long_options, NULL)) != EOF) { + parse_common_args(argc, argv); + + while ((c = getopt_long(argc, argv, "a:c:ns:h", long_options, NULL)) != + EOF) { switch (c) { - case 'a': - /* AES key, handled later */ + case 'n': + printenv_args.name_suppress = 1; break; + case 'a': case 'c': - /* handled later */ + case 'h': + /* ignore common options */ break; - case 'n': - /* handled in fw_printenv */ + default: /* '?' */ + usage_printenv(); + exit(EXIT_FAILURE); break; + } + } + return 0; +} + +int parse_setenv_args(int argc, char *argv[]) +{ + int c; + + parse_common_args(argc, argv); + + while ((c = getopt_long(argc, argv, "a:c:ns:h", long_options, NULL)) != + EOF) { + switch (c) { case 's': - script_file = optarg; + setenv_args.script_file = optarg; break; + case 'a': + case 'c': case 'h': - usage(); - goto exit; + /* ignore common options */ + break; default: /* '?' */ - fprintf(stderr, "Try `%s --help' for more information." - "\n", cmdname); - retval = EXIT_FAILURE; - goto exit; + usage_setenv(); + exit(EXIT_FAILURE); + break; } } + return 0; +} + +int main(int argc, char *argv[]) +{ + const char *lockname = "/var/lock/" CMD_PRINTENV ".lock"; + int lockfd = -1; + int retval = EXIT_SUCCESS; + char *_cmdname; + + _cmdname = *argv; + if (strrchr(_cmdname, '/') != NULL) + _cmdname = strrchr(_cmdname, '/') + 1; - if (strcmp(cmdname, CMD_PRINTENV) == 0) { + if (strcmp(_cmdname, CMD_PRINTENV) == 0) { + do_printenv = 1; + } else if (strcmp(_cmdname, CMD_SETENV) == 0) { + do_printenv = 0; + } else { + fprintf(stderr, + "Identity crisis - may be called as `%s' or as `%s' but not as `%s'\n", + CMD_PRINTENV, CMD_SETENV, _cmdname); + exit(EXIT_FAILURE); + } + + if (do_printenv) { + if (parse_printenv_args(argc, argv)) + exit(EXIT_FAILURE); + } else { + if (parse_setenv_args(argc, argv)) + exit(EXIT_FAILURE); + } + + /* shift parsed flags, jump to non-option arguments */ + argc -= optind; + argv += optind; + + lockfd = open(lockname, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (-1 == lockfd) { + fprintf(stderr, "Error opening lock file %s\n", lockname); + return EXIT_FAILURE; + } + + if (-1 == flock(lockfd, LOCK_EX)) { + fprintf(stderr, "Error locking file %s\n", lockname); + close(lockfd); + return EXIT_FAILURE; + } + + if (do_printenv) { if (fw_printenv(argc, argv) != 0) retval = EXIT_FAILURE; - } else if (strcmp(cmdname, CMD_SETENV) == 0) { - if (!script_file) { + } else { + if (!setenv_args.script_file) { if (fw_setenv(argc, argv) != 0) retval = EXIT_FAILURE; } else { - if (fw_parse_script(script_file) != 0) + if (fw_parse_script(setenv_args.script_file) != 0) retval = EXIT_FAILURE; } - } else { - fprintf(stderr, - "Identity crisis - may be called as `" CMD_PRINTENV - "' or as `" CMD_SETENV "' but not as `%s'\n", - cmdname); - retval = EXIT_FAILURE; } -exit: flock(lockfd, LOCK_UN); close(lockfd); return retval; diff --git a/tools/palmtreo680/flash_u-boot.c b/tools/palmtreo680/flash_u-boot.c index 3d8296fc6b..832d3fef7b 100644 --- a/tools/palmtreo680/flash_u-boot.c +++ b/tools/palmtreo680/flash_u-boot.c @@ -97,7 +97,7 @@ int main(int argc, char * const argv[]) return -errsv; } printf("The mtd partition contains %d blocks\n", devinfo.eb_cnt); - printf("U-boot will occupy %d blocks\n", num_blocks); + printf("U-Boot will occupy %d blocks\n", num_blocks); if (num_blocks > devinfo.eb_cnt) { fprintf(stderr, "Insufficient blocks on partition\n"); return -EINVAL; diff --git a/tools/patman/README b/tools/patman/README index 5bd74c4f83..e36857dede 100644 --- a/tools/patman/README +++ b/tools/patman/README @@ -138,7 +138,7 @@ is useful if your top commit is for setting up testing. How to install it ================= -The most up to date version of patman can be found in the U-boot sources. +The most up to date version of patman can be found in the U-Boot sources. However to use it on other projects it may be more convenient to install it as a standalone application. A distutils installer is included, this can be used to install patman: diff --git a/tools/tbot/README b/tools/tbot/README new file mode 100644 index 0000000000..a637a63d32 --- /dev/null +++ b/tools/tbot/README @@ -0,0 +1,185 @@ +# Copyright (c) 2016 DENX Software Engineering GmbH +# Heiko Schocher <hs@denx.de> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +What is tbot ? +============== + +tbot is a tool for executing testcases on boards. +Source code found on [1] +Based on DUTS [2] +written in python + +Basic Ideas of tbot +=================== +(see also the figure: +https://github.com/hsdenx/tbot/blob/master/doc/tbot_structure.png ) + +- Virtual laboratory (VL) + VL is the basic environment that groups: + - [a number of] boards - target devices on which tbot executes testcases. + - one Lab PC + +- Test case (TC): + A piece of python code, which uses the tbot class from [1]. + Tbot provides functions for sending shell commands and parsing the + shell commands output. + Tbot waits endless for a shell commands end (detected through reading + the consoles prompt). + A TC can also call other TC-es. + + remark: + Tbot not really waits endless, for a shell commands end, instead + tbot starts a watchdog in the background, and if it triggers, tbot + ends the TC as failed. In the tbot beginning there was a lot of + timeouts / retry cases, but it turned out, that waiting endless + is robust and easy ... + +- Host PC (where tbot runs, currently only linux host tested) + must not a powerful machine (For example [3], I use a + raspberry pi for running tbot and buildbot) + +- Lab PC: + - Host PC connects through ssh to the Lab PC + -> so it is possible to test boards, which + are not at the same place as the Host PC. + (Lab PC and Host PC can be the same of course) + -> maybe we can setup a Testsystem, which does nightly + U-Boot/Linux builds and test from current mainline U-Boot + on boards wherever they are accessible. + + - necessary tasks a Lab PC must deliver: + - connect to boards console through a shell command. + - power on/off boards through a shell command + - detect the current power state of a board through + a shell command + + - optional tasks: + - tftp server (for example loading images) + - nfs server (used as rootfs for linux kernels) + - Internet access for example for downloading + U-Boot source with git. + - toolchains installed for compiling source code + + -> a linux machine is preffered. + + - currently only Lab PC with an installed linux supported/tested. + +- Boards(s): + the boards on which shell commands are executed. + +- Board state: + equals to the software, the board is currently running. + + Currently tbot supports 2 board states: + - "u-boot", if the board is running U-Boot + - "linux", if the board is running a linux kernel + + It should be easy to add other board states to tbot, see + https://github.com/hsdenx/tbot/tree/master/src/lab_api/state_[u-boot/linux].py + + A board state is detected through analysing the boards + shell prompt. In linux, tbot sets a special tbot prompt, + in U-Boot the prompt is static, and configurable in tbot through + a board config file. + + A TC can say in which board state it want to send shell commands. + Tbot tries to detect the current board state, if board is not in + the requested board state, tbot tries to switch into the correct + state. If this fails, the TC fails. + + It is possible to switch in a single TC between board states. + +- tbot cmdline parameters: + +$ python2.7 src/common/tbot.py --help +Usage: tbot.py [options] + +Options: + -h, --help show this help message and exit + -c CFGFILE, --cfgfile=CFGFILE + the tbot common configfilename + -l LOGFILE, --logfile=LOGFILE + the tbot logfilename, if default, tbot creates a + defaultnamelogfile + -t TC, --testcase=TC the testcase which should be run + -v, --verbose be verbose, print all read/write to stdout + -w WORKDIR, --workdir=WORKDIR + set workdir, default os.getcwd() +$ + +tbot needs the following files for proper execution: + + - tbot board configuration file (option -c): + A board configuration file contains settings tbot needs to + connect to the Lab PC and board specific variable settings + for testcases. + + - name of the logfile tbot creates (option -l) + defaultname: 'log/' + now.strftime("%Y-%m-%d-%H-%M") + '.log' + + - tbots working directory (option -w) + + - the testcasename tbot executes (option -t) + +You are interested and want to use tbot? +If so, please read on the file: +tools/tbot/README.install + +If not read [3] ;-) + +Heiko Schocher <hs@denx.de> +v1 2016.01.22 + +-------------- +[1] https://github.com/hsdenx/tbot +[2] http://www.denx.de/wiki/DUTS/DUTSDocs +[3] automated Testsetup with buildbot and tbot doing cyclic tests + (buildbot used for starting tbot TC and web presentation of the + results, all testing done through tbot): + http://xeidos.ddns.net/buildbot/tgrid + Host PC in Letkes/hungary + VL in munich/germany + + Fancy things are done here, for example: + - http://xeidos.ddns.net/buildbot/builders/smartweb_dfu/builds/43/steps/shell/logs/tbotlog + (I try to cleanup the logfile soon, so it is not so filled with crap ;-) + A first step see here: + http://xeidos.ddns.net/buildbot/builders/smartweb_dfu/builds/45/steps/shell/logs/tbotlog + (same TC now with the new loglevel = 'CON' ... not yet perfect) + Executed steps: + - clone u-boot.git + - set toolchain + - get a list of patchwork patches from my U-Boots ToDo list + - download all of them, and check them with checkpatch + and apply them to u-boot.git + - compile U-Boot for the smartweb board + - install the resulting images on the smartweb board + - boot U-boot + - test DFU + - more TC should be added here for testing U-Boot + + - automatic "git bisect" + https://github.com/hsdenx/tbot/blob/master/src/tc/tc_board_git_bisect.py + http://xeidos.ddns.net/buildbot/builders/tqm5200s/builds/3/steps/shell/logs/tbotlog + + If a current U-Boot image not works on the tqm5200 board + this TC can be started. It starts a "git bisect" session, + and compiles for each step U-Boot, install it on the tqm5200 + board, and tests if U-Boot works ! + + At the end, it detects the commit, which breaks the board + + This TC is not dependend on U-Boot nor on a special board. It + needs only 3 variables: + tb.board_git_bisect_get_source_tc: TC which gets the source tree, in which + "git bisect" should be executed + tb.board_git_bisect_call_tc: TC which gets called every "git bisect" step, + which executes commands for detecting if current source code is OK or not. + This could be a TC which compiles U-Boot, install it on the board and + executes TC on the new booted U-Boot image. ! Board maybe gets borken, + as not all U-Boot images work, so you must have a TC which install U-Boot + image for example through a debugger. + tb.board_git_bisect_good_commit: last nown good commit id diff --git a/tools/tbot/README-ToDo b/tools/tbot/README-ToDo new file mode 100644 index 0000000000..daf1af1323 --- /dev/null +++ b/tools/tbot/README-ToDo @@ -0,0 +1,62 @@ +# Copyright (c) 2016 DENX Software Engineering GmbH +# Heiko Schocher <hs@denx.de> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +ToDo list for tbot +================== + +please look also into the tbot ToDo list. +https://github.com/hsdenx/tbot/blob/master/ToDo + +- cleanup tbot code: + - remove all retry / timeout pieces of code + - clean up tbot function names, as I am not good in + giving function a understandable name ;-) + - as I am not a python programmer, cleanup whole tbot code + +- introduce a "layering" like yocto do, so U-Boot TC can integrated + into U-Boot source code. + + Proposal: + introduce subdirs in "src/tc" + + lab: all lab specific stuff + lab/common: common lab stuff (for example ssh handling) + lab/ssh_std: ssh_std specific stuff + + u-boot: all u-boot tests + u-boot/common: common u-boot tc + u-boot/duts: DUTS tc + u-boot-dxr2: all u-boot dxr2 board specific tc + + board: board tc + board/common: common board tc + board/dxr2: all tc for dxr2 board + + linux: all linux tc + linux/common: common linux tc + linux/dxr2 + + - move U-Boot special TC to U-Boot source + -> need a mechanism in tbot, how it gets automatically for example + U-Boot TC from U-Boot source... + -> add a consistency checker + +- simplify tbot log output (seperate a lot of output which is currently + in INFO logging level, to another logging level) + started (new loglevel "CON", whih prints read/write from console only), see: + https://github.com/hsdenx/tbot/commit/b4ab2567ad8c19ad53f785203159d3c8465a21c6 + - make the timestamp configurable + +- Open more than 2 filehandles ? + Do we need for more complex TC more than 2 filehandles? + +- Find a way to document all TC and document all variables they use in an + automated way. + +- write a lot of more TC + +- get U-Boot configuration settings from current U-Boot code and use + them in U-Boot TC-es diff --git a/tools/tbot/README.create_a_new_testcase b/tools/tbot/README.create_a_new_testcase new file mode 100644 index 0000000000..fbf8ae8329 --- /dev/null +++ b/tools/tbot/README.create_a_new_testcase @@ -0,0 +1,117 @@ +# Copyright (c) 2016 DENX Software Engineering GmbH +# Heiko Schocher <hs@denx.de> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +write a new testcase +===================== + +A TC is written in python, so you can use python as usual. For accessing +the boards console, use functions from the tbotlib, therefore + +First import the tbotlib with the line: + + from tbotlib import tbot + +If your TC uses variables, please add a line which adds them to +the log file (for debugging purposes): + + logging.info("args: %s ...", tb.varname, ...) + +Say tbot, for which board state your TC is valid with: + + tb.set_board_state("u-boot") + +Then you are ready ... and you can use the tbotlib funtions +for writting/reading to the boards console. + +Big fat warning: + +A TC must worry about to end only if a board has finished the shell +command! + +Not following this rule, will end in unpredictable behaviour. + +(hopefully) useful tbotlib functions +==================================== +- set the board state, you want to test + tb.set_board_state(state) + states are: "u-boot" or "linux" + If tbot could not set the board state, tbot ends with failure. + +- write a command to the boards console: + tb.eof_write_con(command): + write the command to the boards console. If this + fails, tbot ends with failure + +- write a command to boards console and wait for prompt: + tb.eof_write_cmd(fd, command): + fd: filedescriptor which is used, use tb.channel_con for boards console + command: command which is written to fd + + Wait endless for board prompt + +- write a list of commands to boards console: + tb.eof_write_cmd_list(fd, cmdlist): + fd: filedescriptor which is used, use tb.channel_con for boards console + cmdlist: python list of commandstrings which is written to fd + +- wait for boards prompt: + tb.eof_read_end_state_con(retry): + retry: deprecated, not used anymore, cleanup needed here... + tbot waits endless for the boards prompt + +- write a command, wait for prompt and check, if a string is read + tb.write_cmd_check(fd, cmd, string): + fd: filedescriptor which is used, use tb.channel_con for boards console + cmd: command, which is send to fd + string: string which should be read from fd + + return value: + True, if string is read and tbot got back boards prompt + False, else + + tb.eof_write_cmd_check(fd, cmd, string): + same as tb.write_cmd_check(fd, cmd, string) except, that tbot + ends immediately with Failure, if string is not read. + +- read until prompt and search strings: + tb.readline_and_search_strings(fd, strings): + fd: filedescriptor which is used, use tb.channel_con for boards console + strings: python list of strings, which can be read + If one of this strings is read, this function return the index, which + string is read. This function shoud be called in a while loop, + until this function returns 'prompt' + +- read a line from filedescriptor: + not recommended to use, as the TC must check, if tprompt is read for every + readen line. Also TC must ensure, that it ends only, if prompt is read. + tb.read_line(fd, retry) + fd: filedescriptor which is used, use tb.channel_con for boards console + retry: retry of trying to reead a line + + return values: + True, if a line is read. Readen line in tb.buf[fd] + False, if something read, but not a complete line + None, if nothing is read + + check if string contains prompt with: + tb.is_end_fd(fd, string) + fd: filedescriptor which is used, use tb.channel_con for boards console + string: buffer, in which a prompt gets searched. + +- calling other TC: + eof_call_tc(name): + call another TC from "src/tc" + if the called TC fails with failure, tbot ends with failure + + call_tc(name): + call another TC from "src/tc" + if the TC which call_tc calls fails, call_tc() returns False, else True + +There are more functions, but for writting TC this should be enough. But +its software, so new useful functions can always pop up. + +Heiko Schocher <hs@denx.de> +v1 2016.01.23 diff --git a/tools/tbot/README.install b/tools/tbot/README.install new file mode 100644 index 0000000000..24c67bc661 --- /dev/null +++ b/tools/tbot/README.install @@ -0,0 +1,370 @@ +# Copyright (c) 2016 DENX Software Engineering GmbH +# Heiko Schocher <hs@denx.de> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +install tbot on your PC (linux only tested): +============================================ + +- get the source code: + +$ git clone https://github.com/hsdenx/tbot.git +[...] +$ + + cd into the tbot directory. + +- you need the for running tbot the python paramiko module, see: + http://www.paramiko.org/installing.html + + paramiko is used for handling ssh sessions, and open filedescriptors + on a ssh connection. Tbot open a ssh connection to a "lab PC" and + opens on that connection 2 filehandles, one for control functions + and one for the connection to the boards console. May it is worth + to think about to open more filehandles and use them in tbot, but + thats a point in the Todo list ... + + See [1] for more infos about tbot principles. + +- prepare a directory for storing the logfiles + and pass it with the commandline option "-l" + to tbot. Default is the directory "log" in the tbot + root (don;t forget to create it, if you want to use it) + +- If your VL is not yet in tbot source, integrate it + (This task has only to be done once for your VL): + + A VL has, as described in [2] "necessary tasks for a Lab PC" explained, + 3 tasks: + + a) power on/off the board + b) get power state of the board + c) connect to the boards console + + As tbot sends only shell commands (also to the Lab PC) + this tasks must be executable through shell commands on your + Lab PC: + + Task a) power on/off board: + default TC for this task is: + https://github.com/hsdenx/tbot/blob/master/src/tc/tc_lab_denx_power.py + + - now copy this file to for example + cp src/tc/tc_lab_denx_power.py src/tc/tc_lab_denx_power_XXX.py + (replace XXX to a proper value) + and adapt the "remote_power" command from the denx lab to your needs. + + As this TC powers on the board for all your boards in your VL, + you can differ between the boards through the tbot class + variable "tb.boardlabpowername" (which is in the default case the + same as "tb.boardname"), but you may need to name the power target + with an other name than boardname, so you can configure this case. + The power state "tb.power_state" which the TC has to set + is "on" for power on, or "off" for power off. + + If switching on the power is successful, call "tb.end_tc(True)" + else "tb.end_tc(False)" + + - set in your board config file: + self.tc_lab_denx_power_tc = 'tc_lab_denx_power_XXX.py' + + Task b) power on/off board: + default TC for this task is: + https://github.com/hsdenx/tbot/blob/master/src/tc/tc_lab_denx_get_power_state.py + + - now copy this file to for example + (replace XXX to a proper value) + cp src/tc/tc_lab_denx_get_power_state.py src/tc/tc_lab_denx_get_power_state_XXX.py + and adapt the commands to your needs. + + If the power of the board is on, call "tb.end_tc(True)" + else "tb.end_tc(False)" + + - set in your board config file: + self.tc_lab_denx_get_power_state_tc = 'tc_lab_denx_get_power_state_XXX.py' + + Task c) connect to the boards console: + default TC for this task is: + https://github.com/hsdenx/tbot/blob/master/src/tc/tc_lab_denx_connect_to_board.py + + - now copy this file to for example + (replace XXX to a proper value) + cp src/tc/tc_lab_denx_connect_to_board.py src/tc/tc_lab_denx_connect_to_board_XXX.py + and adapt the commands to your needs. + + As this TC powers on the board for all your boards in your VL, + you can differ between the boards through the tbot class + variable "tb.boardlabname" (which is in the default case the + same as "tb.boardname"), but you may need to name the power target + with an other name than boardname, so you can configure this case. + + If connect fails end this TC with "tb.end_tc(False)" + else call "tb.end_tc(True)" + + If you want to use kermit for connecting to the boards console, you + can use: + + https://github.com/hsdenx/tbot/blob/master/src/tc/tc_workfd_connect_with_kermit.py + + Example for such a board in the VL from denx: + self.tc_lab_denx_connect_to_board_tc = 'tc_workfd_connect_with_kermit.py' + https://github.com/hsdenx/tbot/blob/master/tbot_dxr2.cfg#L24 + + Hopefully this works for you too. + + - set in your board config file: + self.tc_lab_denx_connect_to_board_tc = 'tc_lab_denx_connect_to_board_XXX.py' + + remarks while writting this: + - Currently there is only the denx VL. Original idea was to include + other VL through a seperate class/file in + https://github.com/hsdenx/tbot/tree/master/src/lab_api + but it turned out, that if we say "ssh" is the standard way to connect + to a VL, we can integrate the VL specific tasks through testcases, see + above, so we should do: + - rename the "denx" API to a more general name. + This is a point on my ToDo list ... done, renamed to 'ssh_std' + + - the VL specific configuration may moved from the board config files + and should be collected in VL specific config files, which boards + config file simple include. + +- prepare password.py file: + This file contains all passwords tbot needs (for example for + linux login on the boards) + tbot searches this file in the tbot root directory. + It is a simple python file, for example: + + # passwords for the lab + if (board == 'lab'): + if (user == 'hs'): + password = 'passwordforuserhs' + if (user == 'root'): + password = 'passwordforrootuser' + # passwords for the boards + elif (board == 'mcx'): + if (user == 'root'): + password = 'passwordformcxrootfs' + else: + if (user == 'root'): + password = '' + + In the above example passwords for logging into the Lab PC tbot finds + through: + if (board == 'lab'): + user = 'name': + password = 'gnlmpf' # password 'gnlmpf' for login of user 'name' + +- prepare board config file + Each board which is found in the VL needs a tbot configuration file + pass the config file name with the option '-c' to tbot, tbot searches + in the root dir for them. + + board Example (dxr2 board): + https://github.com/hsdenx/tbot/blob/master/tbot_dxr2.cfg + + Necessary variables: + + line 3: boardname, here it is the "etamin" board + no default value, must be set. + line 4: boardlabname: name used for connecting to the board + may differ from tb.boardname, default tb.boardname + line 5: boardlabpowername: name used for power on/off + may differ from tb.boardname, default tb.boardname + line 6: tftpboardname: name used for tftp subdir (from where + U-Boot loads images for example). + may differ from tb.boardname, default tb.boardname + line 7: labprompt: linux prompt tbot sets + no defaultvalue, must be set (maybe we should introduce + "ttbott" as default ... + line 8: debug: If True, adds debug output on the tbot shell + line 9: debugstatus: enable status debug output on the shell + line 10: ip: Where tbot finds the Lab PC + line 11: user: As which user does tbot logs into the Lab PC + line 12: accept_all: passed to paramiko, accept all connections + line 13: keepalivetimout: passed to paramiko, timeout for sending + keepalive message. + line 14: channel_timeout: passed to paramiko + line 15: loglevel: tbots loglevel for adding entries into the logfile. + line 16: lap_api: used lap API (currently only 'ssh_std') + Should be declared as standard -> this line would be not needed + longer. + line 17: wdt_timeout: timeout in seconds for tbots watchdog. + Watchdog gets triggered if prompt get read. + line 20,21: include 'ssh_std' api + should be removed. + line 24: tc_lab_denx_connect_to_board_tc: Which TC is used for + connecting to the boards console the TC, here: + https://github.com/hsdenx/tbot/blob/master/src/tc/tc_workfd_connect_with_kermit.py + line 27: uboot_prompt: boards U-Boot prompt + line 28: linux_prompt: boards linux prompt + + Now comes a list of variables TC needs, this vary from which TC + you start on the board. + +Thats it ... you now can call tbot and hopefully, it works ;-) +Find an example log [3] for calling simple U-Boot TC for setting +an U-Boot Environmentvariable. + +If you have problems in setting tbot up, please contact me +(and may give me ssh access to your Lab PC ;-) + +If you have running your first TC [3], you may want to write now your own +TC (and hopefully share them), so continue with: +u-boot:tools/tbot/README.create_a_new_testcase + +Heiko Schocher <hs@denx.de> +v1 2016.01.22 + +-------------- + +[1] tbot Dokumentation: + [2] u-boot:/tools/tbot/README + https://github.com/hsdenx/tbot/blob/master/README.md + +[3] Example for a first U-Boot TC which should always work: + (with commandline option "-v" for verbose output): + +hs@localhost:tbot [master] $ python2.7 src/common/tbot.py -c tbot_dxr2.cfg -t tc_ub_setenv.py -v -l log/tbot.log +**** option cfg: tbot_dxr2.cfg log: log/tbot.log tc: tc_ub_setenv.py v 1 +('CUR WORK PATH: ', '/home/hs/data/Entwicklung/tbot') +('CFGFILE ', 'tbot_dxr2.cfg') +('LOGFILE ', '/home/hs/data/Entwicklung/tbot/log/tbot.log') +(<denx.tbot_lab_api object at 0x7f53ac1808d0>, <tbotlib.tbot object at 0x7f53a45fd410>, True) +(<denx.tbot_lab_api object at 0x7f53ac1808d0>, <tbotlib.tbot object at 0x7f53a45fd410>, True) +read 0: Last login: Fri Jan 22 12:20:12 2016 from 87.97.28.177 +read 0: +read 0: ************************************************************* +read 0: BDI2000 Assignment: (last updated: 2015-11-20 12:30 MET) +read 0: bdi1 => techem bdi2 => cetec_mx25 bdi3 => lpc3250 +read 0: bdi4 => - bdi5 => --Rev.B!-- bdi6 => tqm5200s +read 0: bdi7 => [stefano] bdi8 => smartweb bdi9 => sigmatek-nand +read 0: bdi10 => pcm052 bdi11 => socrates bdi12 => aristainetos +read 0: bdi13 => imx53 bdi14 => ib8315 bdi15 => cairo +read 0: bdi16 => g2c1 bdi17 => lwe090 bdi18 => symphony +read 0: bdi19 => dxr2 bdi20 => ima3-mx6 bdi21 => sama5d3 +read 0: bdi98 => - bdi99 => - bdi0 => - +read 0: Please power off unused systems when you leave! Thanks, wd. +read 0: ************************************************************* +read no ret 0: +pollux:~ hs $ +write 0: export PS1="\u@\h [\$(date +%k:%M:%S)] ttbott >" +read 0: export PS1="\u@\h [\$(date +%k:%M:%S)] ttbott >" +read 0: hs@pollux [12:21:00] ttbott > +read 1: Last login: Fri Jan 22 12:20:59 2016 from 87.97.28.177 +read 1: +read 1: ************************************************************* +read 1: BDI2000 Assignment: (last updated: 2015-11-20 12:30 MET) +read 1: bdi1 => techem bdi2 => cetec_mx25 bdi3 => lpc3250 +read 1: bdi4 => - bdi5 => --Rev.B!-- bdi6 => tqm5200s +read 1: bdi7 => [stefano] bdi8 => smartweb bdi9 => sigmatek-nand +read 1: bdi10 => pcm052 bdi11 => socrates bdi12 => aristainetos +read 1: bdi13 => imx53 bdi14 => ib8315 bdi15 => cairo +read 1: bdi16 => g2c1 bdi17 => lwe090 bdi18 => symphony +read 1: bdi19 => dxr2 bdi20 => ima3-mx6 bdi21 => sama5d3 +read 1: bdi98 => - bdi99 => - bdi0 => - +read 1: Please power off unused systems when you leave! Thanks, wd. +read 1: ************************************************************* +read no ret 1: +pollux:~ hs $ +write 1: export PS1="\u@\h [\$(date +%k:%M:%S)] ttbott >" +read 1: export PS1="\u@\h [\$(date +%k:%M:%S)] ttbott >" +read 1: hs@pollux [12:21:02] ttbott > +write 0: remote_power dxr2 -l +read 0: hs@pollux [12:21:00] ttbott >remote_power dxr2 -l +read 0: dxr2 ON +read 0: hs@pollux [12:21:02] ttbott > +read no ret 1: +hs@pollux [12:21:02] ttbott > +write 1: ssh hs@lena +read 1: ssh hs@lena +read no ret 1: +hs@lena's password: +read 1: +read 1: Last login: Fri Jan 22 12:20:17 2016 from 192.168.1.1 +read 1: +read no ret 1: +[hs@lena ~]$ +write 1: export PS1="\u@\h [\$(date +%k:%M:%S)] ttbott >" +read 1: export PS1="\u@\h [\$(date +%k:%M:%S)] ttbott >" +read 1: hs@lena [12:21:07] ttbott > +read no ret 1: +hs@lena [12:21:07] ttbott > +write 1: stty cols 200 +read 1: stty cols 200 +read 1: hs@lena [12:21:08] ttbott > +write 1: export TERM=vt200 +read 1: hs@lena [12:21:08] ttbott >export TERM=vt200 +read 1: hs@lena [12:21:08] ttbott > +write 1: echo $COLUMNS +read 1: hs@lena [12:21:08] ttbott >echo $COLUMNS +read 1: 200 +read 1: hs@lena [12:21:08] ttbott > +write 1: kermit +read 1: hs@lena [12:21:08] ttbott >kermit +read 1: C-Kermit 8.0.211, 10 Apr 2004, for Linux +read 1: +read 1: Copyright (C) 1985, 2004, +read 1: Trustees of Columbia University in the City of New York. +read 1: Type ? or HELP for help. +read 1: +read 1: (/home/hs/) C-Kermit> +read 1: +read no ret 1: (/home/hs/) C-Kermit> +write 1: set line /dev/ttyUSB0 +read 1: set line /dev/ttyUSB0 +read 1: +read 1: (/home/hs/) C-Kermit> +write 1: set speed 115200 +read 1: +read 1: (/home/hs/) C-Kermit>set speed 115200 +read 1: /dev/ttyUSB0, 115200 bps +read 1: +read 1: (/home/hs/) C-Kermit> +write 1: set flow-control none +read 1: +read 1: (/home/hs/) C-Kermit>set flow-control none +read 1: +read 1: (/home/hs/) C-Kermit> +write 1: set carrier-watch off +read 1: +read 1: (/home/hs/) C-Kermit>set carrier-watch off +read 1: +read 1: (/home/hs/) C-Kermit> +write 1: connect +read 1: +read 1: (/home/hs/) C-Kermit>connect +read 1: Connecting to /dev/ttyUSB0, speed 115200 +read 1: +read 1: Escape character: Ctrl-\ (ASCII 28, FS): enabled +read 1: +read 1: Type the escape character followed by C to get back, +read 1: +read 1: or followed by ? to see other options. +read 1: +read 1: ---------------------------------------------------- +read no ret 1: + +write no ret 1: + +read 1: +read 1: Heiko=Schocher +read no ret 1: +U-Boot# +write no ret 1: +write no ret 1: + +read 1: <INTERRUPT> +read 1: U-Boot# +write 1: setenv Heiko Schocher +read 1: U-Boot# setenv Heiko Schocher +read no ret 1: +U-Boot# +write 1: printenv Heiko +read 1: printenv Heiko +read 1: Heiko=Schocher +read no ret 1: +U-Boot# +End of TBOT: success +hs@localhost:tbot [master] $ |