run_darwin_framework_ota_test.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. #! /usr/bin/env -S python3 -B
  2. import io
  3. import json
  4. import logging
  5. import time
  6. from subprocess import PIPE
  7. import click
  8. from chiptest.accessories import AppsRegister
  9. from chiptest.runner import Runner
  10. from chiptest.test_definition import App, ExecutionCapture
  11. from yaml.paths_finder import PathsFinder
  12. TEST_NODE_ID = '0x12344321'
  13. TEST_VID = '0xFFF1'
  14. TEST_PID = '0x8001'
  15. class DarwinToolRunner:
  16. def __init__(self, runner, command):
  17. self.process = None
  18. self.outpipe = None
  19. self.runner = runner
  20. self.lastLogIndex = 0
  21. self.command = command
  22. self.stdin = None
  23. def start(self):
  24. self.process, self.outpipe, errpipe = self.runner.RunSubprocess(self.command,
  25. name='DARWIN-TOOL',
  26. wait=False,
  27. stdin=PIPE)
  28. self.stdin = io.TextIOWrapper(self.process.stdin, line_buffering=True)
  29. def stop(self):
  30. if self.process:
  31. self.process.kill()
  32. def waitForMessage(self, message):
  33. logging.debug('Waiting for %s' % message)
  34. start_time = time.monotonic()
  35. ready, self.lastLogIndex = self.outpipe.CapturedLogContains(
  36. message, self.lastLogIndex)
  37. while not ready:
  38. if self.process.poll() is not None:
  39. died_str = ('Process died while waiting for %s, returncode %d' %
  40. (message, self.process.returncode))
  41. logging.error(died_str)
  42. raise Exception(died_str)
  43. if time.monotonic() - start_time > 10:
  44. raise Exception('Timeout while waiting for %s' % message)
  45. time.sleep(0.1)
  46. ready, self.lastLogIndex = self.outpipe.CapturedLogContains(
  47. message, self.lastLogIndex)
  48. logging.debug('Success waiting for: %s' % message)
  49. class InteractiveDarwinTool(DarwinToolRunner):
  50. def __init__(self, runner, binary_path):
  51. self.prompt = "WAITING FOR COMMANDS NOW"
  52. super().__init__(runner, [binary_path, "interactive", "start", "--additional-prompt", self.prompt])
  53. def waitForPrompt(self):
  54. self.waitForMessage(self.prompt)
  55. def sendCommand(self, command):
  56. logging.debug('Sending command %s' % command)
  57. print(command, file=self.stdin)
  58. self.waitForPrompt()
  59. @click.group(chain=True)
  60. @click.pass_context
  61. def main(context):
  62. pass
  63. @main.command(
  64. 'run', help='Execute the test')
  65. @click.option(
  66. '--darwin-framework-tool',
  67. help="what darwin-framework-tool to use")
  68. @click.option(
  69. '--ota-requestor-app',
  70. help='what ota requestor app to use')
  71. @click.option(
  72. '--ota-data-file',
  73. required=True,
  74. help='The file to use to store our OTA data. This file does not need to exist.')
  75. @click.option(
  76. '--ota-image-file',
  77. required=True,
  78. help='The file to use to store the OTA image we plan to send. This file does not need to exist.')
  79. @click.option(
  80. '--ota-destination-file',
  81. required=True,
  82. help='The destination file to use for the requestor\'s download. This file does not need to exist.')
  83. @click.option(
  84. '--ota-candidate-file',
  85. required=True,
  86. help='The file to use for our OTA candidate JSON. This file does not need to exist.')
  87. @click.pass_context
  88. def cmd_run(context, darwin_framework_tool, ota_requestor_app, ota_data_file, ota_image_file, ota_destination_file, ota_candidate_file):
  89. paths_finder = PathsFinder()
  90. if darwin_framework_tool is None:
  91. darwin_framework_tool = paths_finder.get('darwin-framework-tool')
  92. if ota_requestor_app is None:
  93. ota_requestor_app = paths_finder.get('chip-ota-requestor-app')
  94. runner = Runner()
  95. runner.capture_delegate = ExecutionCapture()
  96. apps_register = AppsRegister()
  97. apps_register.init()
  98. darwin_tool = None
  99. try:
  100. apps_register.createOtaImage(ota_image_file, ota_data_file, "This is some test OTA data", vid=TEST_VID, pid=TEST_PID)
  101. json_data = {
  102. "deviceSoftwareVersionModel": [{
  103. "vendorId": int(TEST_VID, 16),
  104. "productId": int(TEST_PID, 16),
  105. "softwareVersion": 2,
  106. "softwareVersionString": "2.0",
  107. "cDVersionNumber": 18,
  108. "softwareVersionValid": True,
  109. "minApplicableSoftwareVersion": 0,
  110. "maxApplicableSoftwareVersion": 100,
  111. "otaURL": ota_image_file
  112. }]
  113. }
  114. with open(ota_candidate_file, "w") as f:
  115. json.dump(json_data, f)
  116. requestor_app = App(runner, [ota_requestor_app, '--otaDownloadPath', ota_destination_file])
  117. apps_register.add('default', requestor_app)
  118. requestor_app.start()
  119. pairing_cmd = [darwin_framework_tool, 'pairing', 'code', TEST_NODE_ID, requestor_app.setupCode]
  120. runner.RunSubprocess(pairing_cmd, name='PAIR', dependencies=[apps_register])
  121. # pairing get-commissioner-node-id does not seem to work right in interactive mode for some reason
  122. darwin_tool = DarwinToolRunner(runner, [darwin_framework_tool, 'pairing', 'get-commissioner-node-id'])
  123. darwin_tool.start()
  124. darwin_tool.waitForMessage(": Commissioner Node Id")
  125. nodeIdLine = darwin_tool.outpipe.FindLastMatchingLine('.*: Commissioner Node Id (0x[0-9A-F]+)')
  126. if not nodeIdLine:
  127. raise Exception("Unable to find commissioner node id")
  128. commissionerNodeId = nodeIdLine.group(1)
  129. darwin_tool.stop()
  130. darwin_tool = InteractiveDarwinTool(runner, darwin_framework_tool)
  131. darwin_tool.start()
  132. darwin_tool.waitForPrompt()
  133. darwin_tool.sendCommand("otasoftwareupdateapp candidate-file-path %s" % ota_candidate_file)
  134. darwin_tool.sendCommand("otasoftwareupdateapp set-reply-params --status 0")
  135. darwin_tool.sendCommand("otasoftwareupdaterequestor announce-otaprovider %s 0 0 0 %s 0" %
  136. (commissionerNodeId, TEST_NODE_ID))
  137. # Now wait for the OTA download to finish.
  138. requestor_app.waitForMessage("OTA image downloaded to %s" % ota_destination_file)
  139. # Make sure the right thing was downloaded.
  140. apps_register.compareFiles(ota_data_file, ota_destination_file)
  141. except Exception:
  142. logging.error("!!!!!!!!!!!!!!!!!!!! ERROR !!!!!!!!!!!!!!!!!!!!!!")
  143. runner.capture_delegate.LogContents()
  144. raise
  145. finally:
  146. if darwin_tool is not None:
  147. darwin_tool.stop()
  148. apps_register.killAll()
  149. apps_register.factoryResetAll()
  150. apps_register.removeAll()
  151. apps_register.uninit()
  152. if __name__ == '__main__':
  153. main(auto_envvar_prefix='CHIP')