Skip to content

Commit 8bd26f2

Browse files
committed
add support for environment variables in device tests
Previously device tests included information such as access point SSID/password at compile time. This made it difficult to compile test binaries once and then send them to multiple test runners for execution. This change adds a command to the test library to set environment variable on the target device: “setenv key value”. C library setenv/getenv facility is used to store variables. Test runner, tests, and makefile are updated to use this functionality.
1 parent 2315ac2 commit 8bd26f2

File tree

21 files changed

+306
-78
lines changed

21 files changed

+306
-78
lines changed

tests/device/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
.hardware
33
test_report.xml
44
test_report.html
5+
test_env.cfg

tests/device/Makefile

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,10 @@ BS_DIR ?= libraries/BSTest
1212
DEBUG_LEVEL ?= DebugLevel=None____
1313
FQBN ?= esp8266com:esp8266:generic:CpuFrequency=80,FlashFreq=40,FlashMode=dio,UploadSpeed=115200,FlashSize=4M1M,LwIPVariant=v2mss536,ResetMethod=none,Debug=Serial,$(DEBUG_LEVEL)
1414
BUILD_TOOL := $(ARDUINO_IDE_PATH)/arduino-builder
15-
TEST_CONFIG := libraries/test_config/test_config.h
15+
TEST_CONFIG := test_env.cfg
1616
TEST_REPORT_XML := test_report.xml
1717
TEST_REPORT_HTML := test_report.html
1818

19-
ifeq ("$(UPLOAD_PORT)","")
20-
$(error "Failed to detect upload port, please export UPLOAD_PORT manually")
21-
endif
22-
23-
ifeq ("$(ARDUINO_IDE_PATH)","")
24-
$(error "Please export ARDUINO_IDE_PATH")
25-
endif
2619

2720
ifneq ("$(V)","1")
2821
SILENT = @
@@ -35,16 +28,17 @@ endif
3528

3629
all: count tests test_report
3730

38-
count:
39-
@echo Running $(words $(TEST_LIST)) tests
31+
$(TEST_LIST): | virtualenv $(TEST_CONFIG) $(BUILD_DIR) $(HARDWARE_DIR)
4032

41-
tests: $(BUILD_DIR) $(HARDWARE_DIR) virtualenv $(TEST_CONFIG) $(TEST_LIST)
33+
tests: $(TEST_LIST)
4234

4335
$(TEST_LIST): LOCAL_BUILD_DIR=$(BUILD_DIR)/$(notdir $@)
4436

4537
$(TEST_LIST):
38+
@echo Running $(words $(TEST_LIST)) tests
4639
$(SILENT)mkdir -p $(LOCAL_BUILD_DIR)
4740
ifneq ("$(NO_BUILD)","1")
41+
@test -n "$(ARDUINO_IDE_PATH)" || (echo "Please export ARDUINO_IDE_PATH" && exit 1)
4842
@echo Compiling $(notdir $@)
4943
$(SILENT)$(BUILD_TOOL) -compile -logger=human \
5044
-libraries "$(PWD)/libraries" \
@@ -59,6 +53,7 @@ ifneq ("$(NO_BUILD)","1")
5953
$@
6054
endif
6155
ifneq ("$(NO_UPLOAD)","1")
56+
@test -n "$(UPLOAD_PORT)" || (echo "Failed to detect upload port, please export UPLOAD_PORT manually" && exit 1)
6257
@echo Uploading binary
6358
$(SILENT)$(ESPTOOL) $(UPLOAD_VERBOSE_FLAG) \
6459
-cp $(UPLOAD_PORT) \
@@ -67,6 +62,7 @@ ifneq ("$(NO_UPLOAD)","1")
6762
-cf $(LOCAL_BUILD_DIR)/$(notdir $@).bin
6863
endif
6964
ifneq ("$(NO_RUN)","1")
65+
@test -n "$(UPLOAD_PORT)" || (echo "Failed to detect upload port, please export UPLOAD_PORT manually" && exit 1)
7066
@echo Running tests
7167
$(SILENT)$(ESPTOOL) $(UPLOAD_VERBOSE_FLAG) -cp $(UPLOAD_PORT) -cd $(UPLOAD_BOARD) -cr
7268
@source $(BS_DIR)/virtualenv/bin/activate && \
@@ -75,6 +71,7 @@ ifneq ("$(NO_RUN)","1")
7571
-p $(UPLOAD_PORT) \
7672
-n $(basename $(notdir $@)) \
7773
-o $(LOCAL_BUILD_DIR)/test_result.xml \
74+
--env-file $(TEST_CONFIG) \
7875
`test -f $(addsuffix .py, $(basename $@)) && echo "-m $(addsuffix .py, $(basename $@))" || echo ""`
7976
endif
8077

@@ -95,7 +92,7 @@ $(HARDWARE_DIR):
9592
cd $(HARDWARE_DIR)/esp8266com && ln -s $(realpath $(ESP8266_CORE_PATH)) esp8266
9693

9794
virtualenv:
98-
make -C $(BS_DIR) virtualenv
95+
@make -C $(BS_DIR) virtualenv
9996

10097
clean:
10198
rm -rf $(BUILD_DIR)
@@ -104,9 +101,9 @@ clean:
104101

105102
$(TEST_CONFIG):
106103
@echo "****** "
107-
@echo "****** libraries/test_config/test_config.h does not exist"
108-
@echo "****** Create one from libraries/test_config/test_config.h.template"
104+
@echo "****** $(TEST_CONFIG) does not exist"
105+
@echo "****** Create one from $(TEST_CONFIG).template"
109106
@echo "****** "
110-
false
107+
@false
111108

112-
.PHONY: tests all count virtualenv test_report $(BUILD_DIR) $(TEST_LIST)
109+
.PHONY: tests all count virtualenv test_report $(TEST_LIST)

tests/device/libraries/BSTest/runner.py

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
import serial
1010
import subprocess
1111
import imp
12+
try:
13+
from configparser import ConfigParser
14+
except:
15+
from ConfigParser import ConfigParser
16+
import itertools
1217
from urlparse import urlparse
1318
from junit_xml import TestSuite, TestCase
1419
try:
@@ -34,12 +39,13 @@ class BSTestRunner(object):
3439
CRASH = 3
3540
BEGINTIMEOUT = 4
3641

37-
def __init__(self, spawn_obj, name, mocks):
42+
def __init__(self, spawn_obj, name, mocks, env_vars):
3843
self.sp = spawn_obj
3944
self.tests = []
4045
self.reset_timeout = 2
4146
self.name = name
4247
self.mocks = mocks
48+
self.env_vars = env_vars
4349

4450
def get_test_list(self):
4551
self.sp.sendline('-1')
@@ -73,6 +79,7 @@ def get_test_list(self):
7379

7480
def run_tests(self):
7581
test_cases = []
82+
should_update_env = True
7683
for test in self.tests:
7784
desc = test['desc']
7885
name = test['name']
@@ -84,13 +91,20 @@ def run_tests(self):
8491
else:
8592
test_output = StringIO()
8693
self.sp.logfile = test_output
94+
print('running test "{}"'.format(name))
95+
if should_update_env:
96+
res = self.update_env()
97+
if res != BSTestRunner.SUCCESS:
98+
print('failed to set environment variables')
99+
break;
100+
should_update_env = False
87101
if name in self.mocks:
88-
print('setting up mocks')
102+
debug_print('setting up mocks')
89103
self.mocks[name]['setup']()
90104
t_start = time.time()
91105
result = self.run_test(index)
92106
if name in self.mocks:
93-
print('tearing down mocks')
107+
debug_print('tearing down mocks')
94108
self.mocks[name]['teardown']()
95109
t_stop = time.time()
96110
self.sp.logfile = None
@@ -103,6 +117,7 @@ def run_tests(self):
103117
else:
104118
print('test "{}" failed'.format(name))
105119
test_case.add_failure_info('Test failed', output=test_output.getvalue())
120+
should_update_env = True
106121
test_output.close()
107122
test_cases += [test_case];
108123
return TestSuite(self.name, test_cases)
@@ -152,6 +167,22 @@ def run_test(self, index):
152167
if timeout <= 0:
153168
return BSTestRunner.TIMEOUT
154169

170+
def update_env(self):
171+
for env_kv in self.env_vars:
172+
self.sp.sendline('setenv "{}" "{}"'.format(env_kv[0], env_kv[1]))
173+
timeout = 10
174+
while timeout > 0:
175+
res = self.sp.expect(['>>>>>bs_test_setenv ok', EOF, TIMEOUT])
176+
if res == 0:
177+
break
178+
time.sleep(0.1)
179+
timeout -= 0.1
180+
if res == 0:
181+
continue
182+
else:
183+
return BSTestRunner.TIMEOUT
184+
return BSTestRunner.SUCCESS
185+
155186
ser = None
156187

157188
def spawn_port(port_name, baudrate=115200):
@@ -162,8 +193,8 @@ def spawn_port(port_name, baudrate=115200):
162193
def spawn_exec(name):
163194
return pexpect.spawn(name, timeout=0)
164195

165-
def run_tests(spawn, name, mocks):
166-
tw = BSTestRunner(spawn, name, mocks)
196+
def run_tests(spawn, name, mocks, env_vars):
197+
tw = BSTestRunner(spawn, name, mocks, env_vars)
167198
tw.get_test_list()
168199
return tw.run_tests()
169200

@@ -175,6 +206,7 @@ def parse_args():
175206
parser.add_argument('-n', '--name', help='Test run name')
176207
parser.add_argument('-o', '--output', help='Output JUnit format test report')
177208
parser.add_argument('-m', '--mock', help='Set python script to use for mocking purposes')
209+
parser.add_argument('--env-file', help='File containing a list of environment variables to set', type=argparse.FileType('r'))
178210
return parser.parse_args()
179211

180212
def main():
@@ -194,12 +226,19 @@ def main():
194226
if spawn_func is None:
195227
debug_print("Please specify port or executable", file=sys.stderr)
196228
return 1
229+
env_vars = []
230+
if args.env_file is not None:
231+
cfg = ConfigParser()
232+
cfg.optionxform = str
233+
with args.env_file as fp:
234+
cfg.readfp(fp)
235+
env_vars = cfg.items('global')
197236
mocks = {}
198237
if args.mock is not None:
199238
mocks_mod = imp.load_source('mocks', args.mock)
200239
mocks = mock_decorators.env
201240
with spawn_func(spawn_arg) as sp:
202-
ts = run_tests(sp, name, mocks)
241+
ts = run_tests(sp, name, mocks, env_vars)
203242
if args.output:
204243
with open(args.output, "w") as f:
205244
TestSuite.to_file(f, [ts])

tests/device/libraries/BSTest/src/BSArduino.h

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,27 @@ class ArduinoIOHelper
3535
return len;
3636
}
3737

38-
bool read_int(int& result)
38+
size_t read_line(char* dest, size_t dest_size)
3939
{
40-
// TODO: fix this for 0 value
41-
result = m_stream.parseInt();
42-
return result != 0;
40+
size_t len = 0;
41+
// Can't use Stream::readBytesUntil here because it can't tell the
42+
// difference between timing out and receiving the terminator.
43+
while (len < dest_size - 1) {
44+
int c = m_stream.read();
45+
if (c < 0) {
46+
delay(1);
47+
continue;
48+
}
49+
if (c == '\r') {
50+
continue;
51+
}
52+
if (c == '\n') {
53+
dest[len] = 0;
54+
break;
55+
}
56+
dest[len++] = c;
57+
}
58+
return len;
4359
}
4460

4561
protected:

0 commit comments

Comments
 (0)