test.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. #!/usr/bin/env python3
  2. # Copyright (c) 2021 Project CHIP Authors
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. import difflib
  16. import os
  17. import subprocess
  18. import sys
  19. import unittest
  20. from typing import List
  21. SCRIPT_ROOT = os.path.dirname(__file__)
  22. def build_expected_output(source: str, root: str, out: str) -> List[str]:
  23. with open(os.path.join(SCRIPT_ROOT, source), 'rt') as f:
  24. for line in f.readlines():
  25. yield line.replace("{root}", root).replace("{out}", out)
  26. def build_actual_output(root: str, out: str, args: List[str]) -> List[str]:
  27. # Fake out that we have a project root
  28. binary = os.path.join(SCRIPT_ROOT, 'build_examples.py')
  29. runenv = {}
  30. runenv.update(os.environ)
  31. runenv.update({
  32. 'PW_PROJECT_ROOT': root,
  33. 'ANDROID_NDK_HOME': 'TEST_ANDROID_NDK_HOME',
  34. 'ANDROID_HOME': 'TEST_ANDROID_HOME',
  35. 'TIZEN_SDK_ROOT': 'TEST_TIZEN_SDK_ROOT',
  36. 'TIZEN_SDK_SYSROOT': 'TEST_TIZEN_SDK_SYSROOT',
  37. 'TELINK_ZEPHYR_SDK_DIR': 'TELINK_ZEPHYR_SDK_DIR',
  38. 'SYSROOT_AARCH64': 'SYSROOT_AARCH64',
  39. 'NXP_K32W0_SDK_ROOT': 'TEST_NXP_K32W0_SDK_ROOT',
  40. 'IMX_SDK_ROOT': 'IMX_SDK_ROOT',
  41. 'TI_SYSCONFIG_ROOT': 'TEST_TI_SYSCONFIG_ROOT',
  42. 'JAVA_PATH': 'TEST_JAVA_PATH',
  43. })
  44. retval = subprocess.run([
  45. binary,
  46. '--log-level', 'FATAL',
  47. '--dry-run',
  48. '--repo', root,
  49. '--out-prefix', out,
  50. ] + args, stdout=subprocess.PIPE, check=True, encoding='UTF-8', env=runenv)
  51. result = [line + '\n' for line in retval.stdout.split('\n')]
  52. # ensure a single terminating newline: easier to edit since autoformat
  53. # often strips ending double newlines on text files
  54. while result[-1] == '\n':
  55. result = result[:-1]
  56. return result
  57. class TestBuilder(unittest.TestCase):
  58. def assertCommandOutput(self, expected_file: str, args: List[str]):
  59. ROOT = '/TEST/BUILD/ROOT'
  60. OUT = '/OUTPUT/DIR'
  61. expected = [line for line in build_expected_output(expected_file, ROOT, OUT)]
  62. actual = [line for line in build_actual_output(ROOT, OUT, args)]
  63. diffs = [line for line in difflib.unified_diff(expected, actual)]
  64. if diffs:
  65. reference = os.path.basename(expected_file) + '.actual'
  66. with open(reference, 'wt') as fo:
  67. for line in build_actual_output(ROOT, OUT, args):
  68. fo.write(line.replace(ROOT, '{root}').replace(OUT, '{out}'))
  69. msg = "DIFFERENCE between expected and generated output in %s\n" % expected_file
  70. msg += "Expected file can be found in %s" % reference
  71. for line in diffs:
  72. msg += ("\n " + line.replace(ROOT,
  73. '{root}').replace(OUT, '{out}').strip())
  74. self.fail(msg)
  75. @unittest.skipUnless(sys.platform == 'linux', 'Build on linux test')
  76. @unittest.skipUnless(os.uname().machine == 'x86_64', 'Validation x64 and crosscompile, requires linux x64')
  77. def test_linux64_targets(self):
  78. self.assertCommandOutput(
  79. os.path.join('testdata', 'all_targets_linux_x64.txt'),
  80. 'targets'.split(' ')
  81. )
  82. def test_general_dry_runs(self):
  83. # A sampling of targets and variants to validate that
  84. # build options do not change too much
  85. TARGETS = [
  86. 'esp32-devkitc-light-rpc',
  87. 'esp32-m5stack-all-clusters-minimal-rpc-ipv6only',
  88. 'android-arm64-chip-tool',
  89. 'nrf-nrf52840dk-pump',
  90. 'efr32-brd4161a-light-rpc-no-version',
  91. 'openiotsdk-lock-mbedtls',
  92. 'openiotsdk-shell-mbedtls'
  93. ]
  94. for target in TARGETS:
  95. expected = os.path.join('testdata', f'dry_run_{target}.txt')
  96. self.assertCommandOutput(expected, f'--target {target} --dry-run build'.split(' '))
  97. @unittest.skipUnless(sys.platform == 'linux', 'Build on linux test')
  98. @unittest.skipUnless(os.uname().machine == 'x86_64', 'Validation x64 and crosscompile, requires linux x64')
  99. def test_linux_dry_runs(self):
  100. TARGETS = [
  101. 'linux-arm64-chip-tool-ipv6only-clang',
  102. 'linux-arm64-ota-requestor-nodeps-ipv6only',
  103. 'linux-x64-all-clusters-coverage',
  104. ]
  105. for target in TARGETS:
  106. expected = os.path.join('testdata', f'dry_run_{target}.txt')
  107. self.assertCommandOutput(expected, f'--target {target} --dry-run build'.split(' '))
  108. if __name__ == '__main__':
  109. unittest.main()