test_confserver.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. #!/usr/bin/env python
  2. from __future__ import print_function
  3. import os
  4. import json
  5. import argparse
  6. import tempfile
  7. import pexpect
  8. # Each protocol version to be tested needs a 'testcases_vX.txt' file
  9. PROTOCOL_VERSIONS = [1, 2]
  10. def parse_testcases(version):
  11. with open("testcases_v%d.txt" % version, "r") as f:
  12. cases = [line for line in f.readlines() if len(line.strip()) > 0]
  13. # Each 3 lines in the file should be formatted as:
  14. # * Description of the test change
  15. # * JSON "changes" to send to the server
  16. # * Result JSON to expect back from the server
  17. if len(cases) % 3 != 0:
  18. print("Warning: testcases.txt has wrong number of non-empty lines (%d). Should be 3 lines per test case, always." % len(cases))
  19. for i in range(0, len(cases), 3):
  20. desc = cases[i]
  21. send = cases[i + 1]
  22. expect = cases[i + 2]
  23. if not desc.startswith("* "):
  24. raise RuntimeError("Unexpected description at line %d: '%s'" % (i + 1, desc))
  25. if not send.startswith("> "):
  26. raise RuntimeError("Unexpected send at line %d: '%s'" % (i + 2, send))
  27. if not expect.startswith("< "):
  28. raise RuntimeError("Unexpected expect at line %d: '%s'" % (i + 3, expect))
  29. desc = desc[2:]
  30. send = json.loads(send[2:])
  31. expect = json.loads(expect[2:])
  32. yield (desc, send, expect)
  33. def main():
  34. parser = argparse.ArgumentParser()
  35. parser.add_argument('--logfile', type=argparse.FileType('w'), help='Optional session log of the interactions with confserver.py')
  36. args = parser.parse_args()
  37. try:
  38. # set up temporary file to use as sdkconfig copy
  39. with tempfile.NamedTemporaryFile(mode="w", delete=False) as temp_sdkconfig:
  40. temp_sdkconfig_path = os.path.join(tempfile.gettempdir(), temp_sdkconfig.name)
  41. with open("sdkconfig") as orig:
  42. temp_sdkconfig.write(orig.read())
  43. cmdline = "../confserver.py --kconfig Kconfig --config %s" % temp_sdkconfig_path
  44. print("Running: %s" % cmdline)
  45. p = pexpect.spawn(cmdline, timeout=30, logfile=args.logfile, echo=False, use_poll=True, maxread=1)
  46. p.expect("Server running.+\r\n")
  47. initial = expect_json(p)
  48. print("Initial: %s" % initial)
  49. for version in PROTOCOL_VERSIONS:
  50. test_protocol_version(p, version)
  51. test_load_save(p, temp_sdkconfig_path)
  52. test_invalid_json(p)
  53. print("Done. All passed.")
  54. finally:
  55. try:
  56. os.remove(temp_sdkconfig_path)
  57. except OSError:
  58. pass
  59. def expect_json(p):
  60. # run p.expect() to expect a json object back, and return it as parsed JSON
  61. p.expect("{.+}\r\n")
  62. result = p.match.group(0).strip().decode()
  63. print("Read raw data from server: %s" % result)
  64. return json.loads(result)
  65. def send_request(p, req):
  66. req = json.dumps(req)
  67. print("Sending: %s" % (req))
  68. p.send("%s\n" % req)
  69. readback = expect_json(p)
  70. print("Read back: %s" % (json.dumps(readback)))
  71. return readback
  72. def test_protocol_version(p, version):
  73. print("*****")
  74. print("Testing version %d..." % version)
  75. # reload the config from the sdkconfig file
  76. req = {"version": version, "load": None}
  77. readback = send_request(p, req)
  78. print("Reset response: %s" % (json.dumps(readback)))
  79. # run through each test case
  80. cases = parse_testcases(version)
  81. for (desc, send, expected) in cases:
  82. print(desc)
  83. req = {"version": version, "set": send}
  84. readback = send_request(p, req)
  85. if readback.get("version", None) != version:
  86. raise RuntimeError('Expected {"version" : %d} in response' % version)
  87. for expect_key in expected.keys():
  88. read_vals = readback[expect_key]
  89. exp_vals = expected[expect_key]
  90. if read_vals != exp_vals:
  91. expect_diff = dict((k,v) for (k,v) in exp_vals.items() if k not in read_vals or v != read_vals[k])
  92. raise RuntimeError("Test failed! Was expecting %s: %s" % (expect_key, json.dumps(expect_diff)))
  93. print("OK")
  94. print("Version %d OK" % version)
  95. def test_load_save(p, temp_sdkconfig_path):
  96. print("Testing load/save...")
  97. before = os.stat(temp_sdkconfig_path).st_mtime
  98. save_result = send_request(p, {"version": 2, "save": temp_sdkconfig_path})
  99. print("Save result: %s" % (json.dumps(save_result)))
  100. assert "error" not in save_result
  101. assert len(save_result["values"]) == 0 # nothing changes when we save
  102. assert len(save_result["ranges"]) == 0
  103. after = os.stat(temp_sdkconfig_path).st_mtime
  104. assert after > before # something got written to disk
  105. # Do a V2 load
  106. load_result = send_request(p, {"version": 2, "load": temp_sdkconfig_path})
  107. print("V2 Load result: %s" % (json.dumps(load_result)))
  108. assert "error" not in load_result
  109. assert len(load_result["values"]) == 0 # in V2, loading same file should return no config items
  110. assert len(load_result["ranges"]) == 0
  111. # Do a V1 load
  112. load_result = send_request(p, {"version": 1, "load": temp_sdkconfig_path})
  113. print("V1 Load result: %s" % (json.dumps(load_result)))
  114. assert "error" not in load_result
  115. assert len(load_result["values"]) > 0 # in V1, loading same file should return all config items
  116. assert len(load_result["ranges"]) > 0
  117. def test_invalid_json(p):
  118. print("Testing invalid JSON formatting...")
  119. bad_escaping = r'{ "version" : 2, "load" : "c:\some\path\not\escaped\as\json" }'
  120. p.send("%s\n" % bad_escaping)
  121. readback = expect_json(p)
  122. print(readback)
  123. assert "json" in readback["error"][0].lower()
  124. not_really_json = 'Hello world!!'
  125. p.send("%s\n" % not_really_json)
  126. readback = expect_json(p)
  127. print(readback)
  128. assert "json" in readback["error"][0].lower()
  129. if __name__ == "__main__":
  130. main()