From e443655e7febaf2b5a47336a7d98c380c8febabd Mon Sep 17 00:00:00 2001
From: sheinz <shein@bk.ru>
Date: Tue, 1 Nov 2016 00:02:35 +0200
Subject: [PATCH] Travis running tests on remote servers.

Extend test_runner.py to flash using esptool.py
---
 common.mk                       | 14 +++++--
 tests/README.md                 |  6 +++
 tests/test_runner.py            | 42 +++++++++++++++++--
 utils/travis_tests/run_tests.sh | 74 ++++++++++++++++++++++++++++++---
 4 files changed, 123 insertions(+), 13 deletions(-)

diff --git a/common.mk b/common.mk
index 4f26cb5..ae65f6d 100644
--- a/common.mk
+++ b/common.mk
@@ -136,7 +136,7 @@ $$($(1)_OBJ_DIR)%.o: $$($(1)_REAL_ROOT)%.S $$($(1)_MAKEFILE) $(wildcard $(ROOT)*
 
 $(1)_AR_IN_FILES = $$($(1)_OBJ_FILES)
 
-# the component is shown to depend on both obj and source files so we get 
+# the component is shown to depend on both obj and source files so we get
 # a meaningful error message for missing explicitly named source files
 ifeq ($(INCLUDE_SRC_INTO_AR),1)
    $(1)_SRC_IN_AR_FILES = $$($(1)_SRC_FILES)
@@ -215,9 +215,14 @@ $(FW_FILE): $(PROGRAM_OUT) $(FIRMWARE_DIR)
 	$(vecho) "FW $@"
 	$(Q) $(ESPTOOL) elf2image --version=2 $(ESPTOOL_ARGS) $< -o $(FW_FILE)
 
+ESPTOOL_FLASH_CMD ?= -p $(ESPPORT) --baud $(ESPBAUD) write_flash $(ESPTOOL_ARGS) \
+	0x0 $(RBOOT_BIN) 0x1000 $(RBOOT_CONF) 0x2000 $(FW_FILE) $(SPIFFS_ESPTOOL_ARGS)
+
 flash: all
-	$(ESPTOOL) -p $(ESPPORT) --baud $(ESPBAUD) write_flash $(ESPTOOL_ARGS) \
-		0x0 $(RBOOT_BIN) 0x1000 $(RBOOT_CONF) 0x2000 $(FW_FILE) $(SPIFFS_ESPTOOL_ARGS)
+	$(Q) $(ESPTOOL) $(ESPTOOL_FLASH_CMD)
+
+print_flash_cmd:
+	$(Q) echo "$(ESPTOOL_FLASH_CMD)"
 
 erase_flash:
 	$(ESPTOOL) -p $(ESPPORT) --baud $(ESPBAUD) erase_flash
@@ -262,6 +267,9 @@ help:
 	@echo "test"
 	@echo "'flash', then start a GNU Screen session on the same serial port to see serial output."
 	@echo ""
+	@echo "print_flash_cmd"
+	@echo "Just print command line arguments for flashing with esptool.py"
+	@echo ""
 	@echo "size"
 	@echo "Build, then print a summary of built firmware size."
 	@echo ""
diff --git a/tests/README.md b/tests/README.md
index 90b08a8..a147049 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -39,6 +39,12 @@ If not specified device `/dev/ttyUSB1` is used.
 
 `--no-flash` or `-n` - Do not flash the test firmware before running tests.
 
+`--flash` or `-f` - Flash device directly with esptool instead of using
+`make flash` command. Can be used to flash binaries without esp-open-rtos
+environment.
+
+`--flash-cmd` or `-c` - Flash command for esptool. Used together with `--flash`.
+
 `--list` or `-l` - Display list of the available test cases on the device.
 
 ### Example
diff --git a/tests/test_runner.py b/tests/test_runner.py
index 347fd9b..7f7a440 100755
--- a/tests/test_runner.py
+++ b/tests/test_runner.py
@@ -44,9 +44,9 @@ def main():
     verbose = args.verbose
 
     if not args.no_flash:
-        flash_image(args.aport)
+        flash(args.aport, args)
         if args.type != 'solo':
-            flash_image(args.bport)
+            flash(args.bport, args)
 
     env = TestEnvironment(args.aport, TestEnvironment.A)
     env_b = None
@@ -279,11 +279,34 @@ def get_testdir():
     Return the 'tests' directory in the source tree
     (assuming the test_runner.py script is in that directory.
     """
-    res = os.path.dirname(__name__)
+    res = os.path.dirname(__file__)
     return "." if res == "" else res
 
 
-def flash_image(serial_port):
+def flash(serial_port, args):
+    if args.flash:
+        esptool_flash(serial_port, args.flash_cmd)
+    else:
+        make_flash(serial_port)
+
+
+def esptool_flash(serial_port, params):
+    env = dict(os.environ)
+    verbose_print("Flashing test image to %s..." % serial_port)
+    try:
+        stdout = sys.stdout if verbose else None
+        cmd = ["esptool.py", "-p", serial_port]
+        cmd.extend(params.split(' '))
+        cmd = [x for x in cmd if x]  # remove empty elements
+        subprocess.check_call(cmd, cwd=get_testdir(), stdout=stdout,
+                              stderr=subprocess.STDOUT, env=env)
+    except subprocess.CalledProcessError as e:
+        raise TestRunnerError("'esptool.py flash serial=%s' failed with exit code %d" %
+                              (serial_port, e.returncode))
+    verbose_print("Flashing successful.")
+
+
+def make_flash(serial_port):
     # Bit hacky: rather than calling esptool directly,
     # just use the Makefile flash target with the correct ESPPORT argument
     env = dict(os.environ)
@@ -329,6 +352,17 @@ def parse_args():
         action='store_true',
         default=False)
 
+    parser.add_argument(
+        '--flash', '-f',
+        help='Flash device directly with esptool',
+        action='store_true',
+        default=False)
+
+    parser.add_argument(
+        '--flash-cmd', '-c',
+        help='Flash command for esptool',
+        default='write_flash 0x2000 ./firmware/tests.bin')
+
     parser.add_argument(
         '--verbose', '-v',
         help='Verbose test runner debugging output',
diff --git a/utils/travis_tests/run_tests.sh b/utils/travis_tests/run_tests.sh
index 31b98cb..e33ab72 100755
--- a/utils/travis_tests/run_tests.sh
+++ b/utils/travis_tests/run_tests.sh
@@ -1,13 +1,58 @@
 #!/bin/bash
+#
+# This script builds tests, deploys them on one of the available test
+# servers and runs them.
+#
 
-TEST_SERVERS[0]="IP=195.138.84.66;User=pi;Type=dual"
-# TEST_SERVERS[1]="IP=195.138.84.55;Type=solo"
+# Test servers configuration
+TEST_SERVERS[0]="IP=195.138.84.66;User=pi;Type=solo"
+TEST_SERVERS[1]="IP=195.138.84.66;User=pi;Type=dual"
 
+FLASH_CMD=
+
+# Function doesn't accept any arguments. It build the tests,
+# packages the binaries into the archive and populates FLASH_CMD variable.
 function build {
     echo "Building tests"
     make -C ./tests clean
     make -C ./tests -j8
-    tar -czf /tmp/tests.tar.gz ./tests ./common.mk ./parameters.mk
+    FLASH_CMD=$(make -C ./tests print_flash_cmd)
+
+    # Now we need to pack all files that are included in the flash cmd
+    # so they can be transfered to the remote server and run there
+    # Also we need to prepare flash command:
+    #  - remove firmware files path
+    #  - remove serial port parameter
+    mkdir -p /tmp/firmware
+    rm -rf /tmp/firmware/*
+    params=($FLASH_CMD)
+    pushd ./tests
+    for param in "${params[@]}"
+    do
+        if [ -f ${param} ]
+        then
+            file_name=${param##*/}
+            cp ${param} /tmp/firmware/
+            FLASH_CMD=${FLASH_CMD/${param}/${file_name}}
+        fi
+
+        # Removing port parameter from the cmd string
+        if [[ "$param" == "-p" || "$param" == "--port" ]]
+        then
+            FLASH_CMD=${FLASH_CMD/${param}/}
+            next_port=true
+        else
+            # Removing port value from the cmd string
+            if [ "$next_port" ]
+            then
+                FLASH_CMD=${FLASH_CMD/${param} /}
+                unset next_port
+            fi
+        fi
+    done
+    cp test_runner.py /tmp/firmware/
+    tar -czf /tmp/tests.tar.gz -C /tmp/firmware .
+    popd
 }
 
 # $1 - Server IP
@@ -24,19 +69,36 @@ function deploy {
 # $2 - Login user name
 # $3 - Type "solo" or "dual"
 function run_tests {
-    echo "Running tests, server IP=${1}, type=${2}"
+    echo "Running tests, server IP=${1}, type=${3}"
+    echo "Flash cmd: ${FLASH_CMD}"
+    # Run test runner on the remote server
+    # ssh ${2}@${1} "source /home/pi/.profile; cd /tmp/eor_test/; ./test_runner.py --type ${3} -f -c \"${FLASH_CMD}\""
+    ssh ${2}@${1} "source /home/pi/.profile; /tmp/eor_test/test_runner.py --type ${3} -f -c \"${FLASH_CMD}\""
 }
 
+# First step is to build a firmware
 build
 
+failed=0
+
 for server in "${TEST_SERVERS[@]}"
 do
     params=(${server//;/ })
     ip=${params[0]#IP=}
     user=${params[1]#User=}
     type=${params[2]#Type=}
-    
+
     deploy ${ip} ${user}
-    run_tests ${ip} ${user} ${type}
+    if [ "$?" -eq "0" ]
+    then
+        run_tests ${ip} ${user} ${type}
+        if [ "$?" -ne "0" ]
+        then
+            failed=$((failed+1))
+        fi
+    else
+        echo "Server ${ip} is not available"
+    fi
 done
 
+exit $failed