Skip to content

Commit

Permalink
allow reading test environment from python mocks
Browse files Browse the repository at this point in the history
This allows requesting environment variable values set in the C++ test
code, from python mock code. Use case is cross-checking test
results against values expected by the host side part of the test.
  • Loading branch information
igrr committed Apr 11, 2018
1 parent 8bd26f2 commit 1acaa8b
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 7 deletions.
2 changes: 1 addition & 1 deletion tests/device/libraries/BSTest/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ $(PYTHON_ENV_DIR):
. $(PYTHON_ENV_DIR)/bin/activate && pip install -r requirements.txt

test: $(TEST_EXECUTABLE) $(PYTHON_ENV_DIR)
. $(PYTHON_ENV_DIR)/bin/activate && python runner.py -e $(TEST_EXECUTABLE)
. $(PYTHON_ENV_DIR)/bin/activate && python runner.py -e $(TEST_EXECUTABLE) -m test/test.py

$(TEST_EXECUTABLE): test/test.cpp
g++ -std=c++11 -Isrc -o $@ test/test.cpp
Expand Down
16 changes: 16 additions & 0 deletions tests/device/libraries/BSTest/mock_decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,19 @@ def func_wrapper():
func_env['teardown'] = func_wrapper
return func_wrapper
return decorator

def setenv(test_env, key, value):
if 'env' not in test_env:
test_env['env'] = []
test_env['env'] += [(key, value)]

def request_env(test_env, key):
return test_env['request_env'](key)

def get_all_envs(test_name):
global env
if test_name not in env:
return None
if 'env' not in env[test_name]:
return None
return env[test_name]['env']
32 changes: 27 additions & 5 deletions tests/device/libraries/BSTest/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,19 +93,27 @@ def run_tests(self):
self.sp.logfile = test_output
print('running test "{}"'.format(name))
if should_update_env:
res = self.update_env()
res = self.update_env(self.env_vars)
if res != BSTestRunner.SUCCESS:
print('failed to set environment variables')
break;
should_update_env = False
if name in self.mocks:
debug_print('setting up mocks')
self.mocks[name]['request_env'] = self.request_env
self.mocks[name]['setup']()
extra_env = mock_decorators.get_all_envs(name)
if extra_env is not None:
self.update_env(extra_env)
t_start = time.time()
result = self.run_test(index)
if name in self.mocks:
debug_print('tearing down mocks')
self.mocks[name]['teardown']()
try:
self.mocks[name]['teardown']()
except AssertionError:
debug_print('teardown assert failure')
result = BSTestRunner.FAIL
t_stop = time.time()
self.sp.logfile = None
test_case.elapsed_sec = t_stop - t_start
Expand Down Expand Up @@ -167,12 +175,12 @@ def run_test(self, index):
if timeout <= 0:
return BSTestRunner.TIMEOUT

def update_env(self):
for env_kv in self.env_vars:
def update_env(self, env_to_set):
for env_kv in env_to_set:
self.sp.sendline('setenv "{}" "{}"'.format(env_kv[0], env_kv[1]))
timeout = 10
while timeout > 0:
res = self.sp.expect(['>>>>>bs_test_setenv ok', EOF, TIMEOUT])
res = self.sp.expect(['>>>>>bs_test_setenv', EOF, TIMEOUT])
if res == 0:
break
time.sleep(0.1)
Expand All @@ -183,6 +191,20 @@ def update_env(self):
return BSTestRunner.TIMEOUT
return BSTestRunner.SUCCESS

def request_env(self, key):
self.sp.sendline('getenv "{}"'.format(key))
timeout = 10
while timeout > 0:
res = self.sp.expect([r'>>>>>bs_test_getenv value=\"(.+)\"', EOF, TIMEOUT])
if res == 0:
break
time.sleep(0.1)
timeout -= 0.1
if res != 0:
return None
return self.sp.match.group(1)


ser = None

def spawn_port(port_name, baudrate=115200):
Expand Down
18 changes: 17 additions & 1 deletion tests/device/libraries/BSTest/src/BSProtocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,14 @@ void output_menu_end(IO& io)
template<typename IO>
void output_setenv_result(IO& io, const char* key, const char* value)
{
io.printf(BS_LINE_PREFIX "setenv ok key='%s' value='%s'\n", key, value);
io.printf(BS_LINE_PREFIX "setenv key=\"%s\" value=\"%s\"\n", key, value);
}

template<typename IO>
void output_getenv_result(IO& io, const char* key, const char* value)
{
(void) key;
io.printf(BS_LINE_PREFIX "getenv value=\"%s\"\n", value);
}

template<typename IO>
Expand All @@ -72,6 +79,15 @@ bool input_handle(IO& io, char* line_buf, size_t line_buf_size, int& test_num)
test_num = -1;
return false; /* we didn't get the test number yet, so return false */
}
if (strcmp(argv[0], "getenv") == 0) {
if (argc != 2) {
return false;
}
const char* value = getenv(argv[1]);
output_getenv_result(io, argv[1], (value != NULL) ? value : "");
return false;
}
/* not one of the commands, try to parse as test number */
char* endptr;
test_num = (int) strtol(argv[0], &endptr, 10);
if (endptr != argv[0] + strlen(argv[0])) {
Expand Down
9 changes: 9 additions & 0 deletions tests/device/libraries/BSTest/test/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,12 @@ TEST_CASE("this test also runs successfully", "[bluesmoke]")
{

}

TEST_CASE("environment variables can be set and read from python", "[bluesmoke]")
{
const char* res = getenv("VAR_FROM_PYTHON");
REQUIRE(res != NULL);
CHECK(strcmp(res, "42") == 0);
setenv("VAR_FROM_TEST", "24", 1);
}

11 changes: 11 additions & 0 deletions tests/device/libraries/BSTest/test/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from mock_decorators import setup, teardown, setenv, request_env

@setup('environment variables can be set and read from python')
def setup_envtest(e):
setenv(e, 'VAR_FROM_PYTHON', '42')


@teardown('environment variables can be set and read from python')
def teardown_envtest(e):
env_value = request_env(e, 'VAR_FROM_TEST')
assert(env_value == '24')

0 comments on commit 1acaa8b

Please sign in to comment.