2018-05-16 06:54:22 +00:00
|
|
|
#!/usr/bin/env python
|
2018-09-18 12:43:23 +00:00
|
|
|
from __future__ import print_function
|
2021-01-26 02:49:01 +00:00
|
|
|
|
2018-05-16 06:54:22 +00:00
|
|
|
import argparse
|
2019-09-10 07:58:52 +00:00
|
|
|
import json
|
|
|
|
import os
|
|
|
|
import re
|
2018-09-18 12:43:23 +00:00
|
|
|
import tempfile
|
2018-05-16 06:54:22 +00:00
|
|
|
|
|
|
|
import pexpect
|
|
|
|
|
2019-01-25 04:16:51 +00:00
|
|
|
# Each protocol version to be tested needs a 'testcases_vX.txt' file
|
|
|
|
PROTOCOL_VERSIONS = [1, 2]
|
2018-05-16 06:54:22 +00:00
|
|
|
|
2019-01-25 04:16:51 +00:00
|
|
|
|
|
|
|
def parse_testcases(version):
|
2021-01-26 02:49:01 +00:00
|
|
|
with open('testcases_v%d.txt' % version, 'r') as f:
|
2020-05-19 11:54:14 +00:00
|
|
|
cases = [line for line in f.readlines() if len(line.strip()) > 0]
|
2018-05-16 06:54:22 +00:00
|
|
|
# Each 3 lines in the file should be formatted as:
|
|
|
|
# * Description of the test change
|
|
|
|
# * JSON "changes" to send to the server
|
|
|
|
# * Result JSON to expect back from the server
|
|
|
|
if len(cases) % 3 != 0:
|
2021-01-26 02:49:01 +00:00
|
|
|
print('Warning: testcases.txt has wrong number of non-empty lines (%d). Should be 3 lines per test case, always.' % len(cases))
|
2018-05-16 06:54:22 +00:00
|
|
|
|
|
|
|
for i in range(0, len(cases), 3):
|
|
|
|
desc = cases[i]
|
2018-12-04 12:46:48 +00:00
|
|
|
send = cases[i + 1]
|
|
|
|
expect = cases[i + 2]
|
2021-01-26 02:49:01 +00:00
|
|
|
if not desc.startswith('* '):
|
2018-12-04 12:46:48 +00:00
|
|
|
raise RuntimeError("Unexpected description at line %d: '%s'" % (i + 1, desc))
|
2021-01-26 02:49:01 +00:00
|
|
|
if not send.startswith('> '):
|
2018-12-04 12:46:48 +00:00
|
|
|
raise RuntimeError("Unexpected send at line %d: '%s'" % (i + 2, send))
|
2021-01-26 02:49:01 +00:00
|
|
|
if not expect.startswith('< '):
|
2018-12-04 12:46:48 +00:00
|
|
|
raise RuntimeError("Unexpected expect at line %d: '%s'" % (i + 3, expect))
|
2018-05-16 06:54:22 +00:00
|
|
|
desc = desc[2:]
|
|
|
|
send = json.loads(send[2:])
|
|
|
|
expect = json.loads(expect[2:])
|
|
|
|
yield (desc, send, expect)
|
|
|
|
|
2018-12-04 12:46:48 +00:00
|
|
|
|
2018-05-16 06:54:22 +00:00
|
|
|
def main():
|
|
|
|
parser = argparse.ArgumentParser()
|
|
|
|
parser.add_argument('--logfile', type=argparse.FileType('w'), help='Optional session log of the interactions with confserver.py')
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
try:
|
2018-09-18 12:43:23 +00:00
|
|
|
# set up temporary file to use as sdkconfig copy
|
2021-01-26 02:49:01 +00:00
|
|
|
with tempfile.NamedTemporaryFile(mode='w', delete=False) as temp_sdkconfig:
|
2018-09-18 12:43:23 +00:00
|
|
|
temp_sdkconfig_path = os.path.join(tempfile.gettempdir(), temp_sdkconfig.name)
|
2021-01-26 02:49:01 +00:00
|
|
|
with open('sdkconfig') as orig:
|
2018-05-16 06:54:22 +00:00
|
|
|
temp_sdkconfig.write(orig.read())
|
|
|
|
|
2019-09-10 07:58:52 +00:00
|
|
|
with tempfile.NamedTemporaryFile(delete=False) as f:
|
|
|
|
temp_kconfigs_source_file = os.path.join(tempfile.gettempdir(), f.name)
|
|
|
|
|
|
|
|
with tempfile.NamedTemporaryFile(delete=False) as f:
|
|
|
|
temp_kconfig_projbuilds_source_file = os.path.join(tempfile.gettempdir(), f.name)
|
|
|
|
|
2019-12-12 15:02:36 +00:00
|
|
|
cmdline = '''../../confserver.py --env "COMPONENT_KCONFIGS_SOURCE_FILE=%s" \
|
|
|
|
--env "COMPONENT_KCONFIGS_PROJBUILD_SOURCE_FILE=%s" \
|
|
|
|
--env "COMPONENT_KCONFIGS=" \
|
|
|
|
--env "COMPONENT_KCONFIGS_PROJBUILD=" \
|
|
|
|
--kconfig Kconfig \
|
|
|
|
--config %s \
|
2019-09-10 07:58:52 +00:00
|
|
|
''' % (temp_kconfigs_source_file, temp_kconfig_projbuilds_source_file, temp_sdkconfig_path)
|
|
|
|
|
|
|
|
cmdline = re.sub(r' +', ' ', cmdline)
|
|
|
|
|
2019-10-21 11:44:19 +00:00
|
|
|
# prepare_kconfig_files.py doesn't have to be called because COMPONENT_KCONFIGS and
|
|
|
|
# COMPONENT_KCONFIGS_PROJBUILD are empty
|
|
|
|
|
2021-01-26 02:49:01 +00:00
|
|
|
print('Running: %s' % cmdline)
|
2019-06-13 03:05:14 +00:00
|
|
|
p = pexpect.spawn(cmdline, timeout=30, logfile=args.logfile, echo=False, use_poll=True, maxread=1)
|
2018-05-16 06:54:22 +00:00
|
|
|
|
2021-01-26 02:49:01 +00:00
|
|
|
p.expect('Server running.+\r\n')
|
2019-01-25 04:16:51 +00:00
|
|
|
initial = expect_json(p)
|
2021-01-26 02:49:01 +00:00
|
|
|
print('Initial: %s' % initial)
|
2019-01-25 04:16:51 +00:00
|
|
|
|
|
|
|
for version in PROTOCOL_VERSIONS:
|
|
|
|
test_protocol_version(p, version)
|
|
|
|
|
|
|
|
test_load_save(p, temp_sdkconfig_path)
|
|
|
|
|
2019-03-15 01:17:14 +00:00
|
|
|
test_invalid_json(p)
|
|
|
|
|
2021-01-26 02:49:01 +00:00
|
|
|
print('Done. All passed.')
|
2018-05-16 06:54:22 +00:00
|
|
|
|
|
|
|
finally:
|
|
|
|
try:
|
|
|
|
os.remove(temp_sdkconfig_path)
|
2019-09-10 07:58:52 +00:00
|
|
|
os.remove(temp_kconfigs_source_file)
|
|
|
|
os.remove(temp_kconfig_projbuilds_source_file)
|
2018-05-16 06:54:22 +00:00
|
|
|
except OSError:
|
|
|
|
pass
|
|
|
|
|
2018-12-04 12:46:48 +00:00
|
|
|
|
2019-01-25 04:16:51 +00:00
|
|
|
def expect_json(p):
|
|
|
|
# run p.expect() to expect a json object back, and return it as parsed JSON
|
2021-01-26 02:49:01 +00:00
|
|
|
p.expect('{.+}\r\n')
|
2019-01-25 04:16:51 +00:00
|
|
|
result = p.match.group(0).strip().decode()
|
2021-01-26 02:49:01 +00:00
|
|
|
print('Read raw data from server: %s' % result)
|
2019-01-25 04:16:51 +00:00
|
|
|
return json.loads(result)
|
|
|
|
|
|
|
|
|
|
|
|
def send_request(p, req):
|
|
|
|
req = json.dumps(req)
|
2021-01-26 02:49:01 +00:00
|
|
|
print('Sending: %s' % (req))
|
|
|
|
p.send('%s\n' % req)
|
2019-01-25 04:16:51 +00:00
|
|
|
readback = expect_json(p)
|
2021-01-26 02:49:01 +00:00
|
|
|
print('Read back: %s' % (json.dumps(readback)))
|
2019-01-25 04:16:51 +00:00
|
|
|
return readback
|
|
|
|
|
|
|
|
|
|
|
|
def test_protocol_version(p, version):
|
2021-01-26 02:49:01 +00:00
|
|
|
print('*****')
|
|
|
|
print('Testing version %d...' % version)
|
2019-01-25 04:16:51 +00:00
|
|
|
|
|
|
|
# reload the config from the sdkconfig file
|
2021-01-26 02:49:01 +00:00
|
|
|
req = {'version': version, 'load': None}
|
2019-01-25 04:16:51 +00:00
|
|
|
readback = send_request(p, req)
|
2021-01-26 02:49:01 +00:00
|
|
|
print('Reset response: %s' % (json.dumps(readback)))
|
2019-01-25 04:16:51 +00:00
|
|
|
|
|
|
|
# run through each test case
|
|
|
|
cases = parse_testcases(version)
|
|
|
|
for (desc, send, expected) in cases:
|
|
|
|
print(desc)
|
2021-01-26 02:49:01 +00:00
|
|
|
req = {'version': version, 'set': send}
|
2019-01-25 04:16:51 +00:00
|
|
|
readback = send_request(p, req)
|
2021-01-26 02:49:01 +00:00
|
|
|
if readback.get('version', None) != version:
|
2019-01-25 04:16:51 +00:00
|
|
|
raise RuntimeError('Expected {"version" : %d} in response' % version)
|
|
|
|
for expect_key in expected.keys():
|
|
|
|
read_vals = readback[expect_key]
|
|
|
|
exp_vals = expected[expect_key]
|
|
|
|
if read_vals != exp_vals:
|
|
|
|
expect_diff = dict((k,v) for (k,v) in exp_vals.items() if k not in read_vals or v != read_vals[k])
|
2021-01-26 02:49:01 +00:00
|
|
|
raise RuntimeError('Test failed! Was expecting %s: %s' % (expect_key, json.dumps(expect_diff)))
|
|
|
|
print('OK')
|
|
|
|
print('Version %d OK' % version)
|
2019-01-25 04:16:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_load_save(p, temp_sdkconfig_path):
|
2021-01-26 02:49:01 +00:00
|
|
|
print('Testing load/save...')
|
2019-01-25 04:16:51 +00:00
|
|
|
before = os.stat(temp_sdkconfig_path).st_mtime
|
2021-01-26 02:49:01 +00:00
|
|
|
save_result = send_request(p, {'version': 2, 'save': temp_sdkconfig_path})
|
|
|
|
print('Save result: %s' % (json.dumps(save_result)))
|
|
|
|
assert 'error' not in save_result
|
|
|
|
assert len(save_result['values']) == 0 # nothing changes when we save
|
|
|
|
assert len(save_result['ranges']) == 0
|
2019-01-25 04:16:51 +00:00
|
|
|
after = os.stat(temp_sdkconfig_path).st_mtime
|
|
|
|
assert after > before # something got written to disk
|
|
|
|
|
2019-03-14 06:47:08 +00:00
|
|
|
# Do a V2 load
|
2021-01-26 02:49:01 +00:00
|
|
|
load_result = send_request(p, {'version': 2, 'load': temp_sdkconfig_path})
|
|
|
|
print('V2 Load result: %s' % (json.dumps(load_result)))
|
|
|
|
assert 'error' not in load_result
|
|
|
|
assert len(load_result['values']) == 0 # in V2, loading same file should return no config items
|
|
|
|
assert len(load_result['ranges']) == 0
|
2019-03-14 06:47:08 +00:00
|
|
|
|
2019-01-25 04:16:51 +00:00
|
|
|
# Do a V1 load
|
2021-01-26 02:49:01 +00:00
|
|
|
load_result = send_request(p, {'version': 1, 'load': temp_sdkconfig_path})
|
|
|
|
print('V1 Load result: %s' % (json.dumps(load_result)))
|
|
|
|
assert 'error' not in load_result
|
|
|
|
assert len(load_result['values']) > 0 # in V1, loading same file should return all config items
|
|
|
|
assert len(load_result['ranges']) > 0
|
2019-01-25 04:16:51 +00:00
|
|
|
|
|
|
|
|
2019-03-15 01:17:14 +00:00
|
|
|
def test_invalid_json(p):
|
2021-01-26 02:49:01 +00:00
|
|
|
print('Testing invalid JSON formatting...')
|
2019-03-15 01:17:14 +00:00
|
|
|
|
|
|
|
bad_escaping = r'{ "version" : 2, "load" : "c:\some\path\not\escaped\as\json" }'
|
2021-01-26 02:49:01 +00:00
|
|
|
p.send('%s\n' % bad_escaping)
|
2019-03-15 01:17:14 +00:00
|
|
|
readback = expect_json(p)
|
|
|
|
print(readback)
|
2021-01-26 02:49:01 +00:00
|
|
|
assert 'json' in readback['error'][0].lower()
|
2019-03-15 01:17:14 +00:00
|
|
|
|
|
|
|
not_really_json = 'Hello world!!'
|
2021-01-26 02:49:01 +00:00
|
|
|
p.send('%s\n' % not_really_json)
|
2019-03-15 01:17:14 +00:00
|
|
|
readback = expect_json(p)
|
|
|
|
print(readback)
|
2021-01-26 02:49:01 +00:00
|
|
|
assert 'json' in readback['error'][0].lower()
|
2019-03-15 01:17:14 +00:00
|
|
|
|
|
|
|
|
2021-01-26 02:49:01 +00:00
|
|
|
if __name__ == '__main__':
|
2018-05-16 06:54:22 +00:00
|
|
|
main()
|