1#!/usr/bin/env python 2# 3# SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD 4# SPDX-License-Identifier: Apache-2.0 5 6import json 7import os 8import shutil 9import sys 10import tempfile 11import unittest 12 13try: 14 from contextlib import redirect_stdout 15except ImportError: 16 import contextlib 17 18 @contextlib.contextmanager # type: ignore 19 def redirect_stdout(target): 20 original = sys.stdout 21 sys.stdout = target 22 yield 23 sys.stdout = original 24 25try: 26 from cStringIO import StringIO 27except ImportError: 28 from io import StringIO 29 30# Need to do this before importing idf_tools.py 31os.environ['IDF_MAINTAINER'] = '1' 32 33try: 34 import idf_tools 35except ImportError: 36 sys.path.append('..') 37 import idf_tools 38 39ESP32ULP = 'esp32ulp-elf' 40ESP32ULP_ARCHIVE = 'binutils-esp32ulp' 41ESP32S2ULP = 'esp32s2ulp-elf' 42ESP32S2ULP_ARCHIVE = 'binutils-esp32s2ulp' 43OPENOCD = 'openocd-esp32' 44RISCV_ELF = 'riscv32-esp-elf' 45XTENSA_ESP32_ELF = 'xtensa-esp32-elf' 46XTENSA_ESP32S2_ELF = 'xtensa-esp32s2-elf' 47XTENSA_ESP32S3_ELF = 'xtensa-esp32s3-elf' 48 49 50def get_version_dict(): 51 ''' 52 Return a dictionary with tool name to tool version mapping. 53 54 It works with tools.json directly and not through idf_tools.py in order to bypass the script under test. This is 55 a little hacky but thanks to this, versions are not required to be updated here every time a tool is updated. 56 ''' 57 with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'tools.json')) as f: 58 tools_obj = json.loads(f.read()) 59 60 return dict((tool['name'], tool['versions'][0]['name']) for tool in tools_obj['tools']) 61 62 63version_dict = get_version_dict() 64 65ESP32ULP_VERSION = version_dict[ESP32ULP] 66ESP32S2ULP_VERSION = version_dict[ESP32S2ULP] 67OPENOCD_VERSION = version_dict[OPENOCD] 68RISCV_ELF_VERSION = version_dict[RISCV_ELF] 69XTENSA_ESP32_ELF_VERSION = version_dict[XTENSA_ESP32_ELF] 70XTENSA_ESP32S2_ELF_VERSION = version_dict[XTENSA_ESP32S2_ELF] 71XTENSA_ESP32S3_ELF_VERSION = version_dict[XTENSA_ESP32S3_ELF] 72 73 74class TestUsage(unittest.TestCase): 75 76 @classmethod 77 def setUpClass(cls): 78 old_tools_dir = os.environ.get('IDF_TOOLS_PATH') or os.path.expanduser(idf_tools.IDF_TOOLS_PATH_DEFAULT) 79 80 mirror_prefix_map = None 81 if os.path.exists(old_tools_dir): 82 mirror_prefix_map = 'https://dl.espressif.com/dl/toolchains/preview,file://' + os.path.join(old_tools_dir, 83 'dist') 84 mirror_prefix_map += ';https://dl.espressif.com/dl,file://' + os.path.join(old_tools_dir, 'dist') 85 mirror_prefix_map += ';https://github.com/espressif/.*/releases/download/.*/,file://' + os.path.join( 86 old_tools_dir, 'dist', '') 87 if mirror_prefix_map: 88 print('Using IDF_MIRROR_PREFIX_MAP={}'.format(mirror_prefix_map)) 89 os.environ['IDF_MIRROR_PREFIX_MAP'] = mirror_prefix_map 90 91 cls.temp_tools_dir = tempfile.mkdtemp(prefix='idf_tools_tmp') 92 93 print('Using IDF_TOOLS_PATH={}'.format(cls.temp_tools_dir)) 94 os.environ['IDF_TOOLS_PATH'] = cls.temp_tools_dir 95 96 @classmethod 97 def tearDownClass(cls): 98 shutil.rmtree(cls.temp_tools_dir) 99 100 def tearDown(self): 101 if os.path.isdir(os.path.join(self.temp_tools_dir, 'dist')): 102 shutil.rmtree(os.path.join(self.temp_tools_dir, 'dist')) 103 104 if os.path.isdir(os.path.join(self.temp_tools_dir, 'tools')): 105 shutil.rmtree(os.path.join(self.temp_tools_dir, 'tools')) 106 107 if os.path.isfile(os.path.join(self.temp_tools_dir, 'idf-env.json')): 108 os.remove(os.path.join(self.temp_tools_dir, 'idf-env.json')) 109 110 def assert_tool_installed(self, output, tool, tool_version, tool_archive_name=None): 111 if tool_archive_name is None: 112 tool_archive_name = tool 113 self.assertIn('Installing %s@' % tool + tool_version, output) 114 self.assertIn('Downloading %s' % tool_archive_name, output) 115 116 def assert_tool_not_installed(self, output, tool, tool_version, tool_archive_name=None): 117 if tool_archive_name is None: 118 tool_archive_name = tool 119 self.assertNotIn('Installing %s@' % tool + tool_version, output) 120 self.assertNotIn('Downloading %s' % tool_archive_name, output) 121 122 def run_idf_tools_with_action(self, action): 123 output_stream = StringIO() 124 with redirect_stdout(output_stream): 125 idf_tools.main(['--non-interactive'] + action) 126 output = output_stream.getvalue() 127 return output 128 129 def test_usage_basic(self): 130 output = self.run_idf_tools_with_action(['list']) 131 self.assertIn('* %s:' % ESP32ULP, output) 132 self.assertIn('- %s (recommended)' % ESP32ULP_VERSION, output) 133 self.assertIn('* %s:' % ESP32S2ULP, output) 134 self.assertIn('- %s (recommended)' % ESP32S2ULP_VERSION, output) 135 self.assertIn('* %s:' % OPENOCD, output) 136 self.assertIn('- %s (recommended)' % OPENOCD_VERSION, output) 137 self.assertIn('* %s:' % RISCV_ELF, output) 138 self.assertIn('- %s (recommended)' % RISCV_ELF_VERSION, output) 139 self.assertIn('* %s:' % XTENSA_ESP32_ELF, output) 140 self.assertIn('- %s (recommended)' % XTENSA_ESP32_ELF_VERSION, output) 141 self.assertIn('* %s:' % XTENSA_ESP32S2_ELF, output) 142 self.assertIn('- %s (recommended)' % XTENSA_ESP32S2_ELF_VERSION, output) 143 self.assertIn('* %s:' % XTENSA_ESP32S3_ELF, output) 144 self.assertIn('- %s (recommended)' % XTENSA_ESP32S3_ELF_VERSION, output) 145 146 required_tools_installed = 7 147 output = self.run_idf_tools_with_action(['install']) 148 self.assert_tool_installed(output, OPENOCD, OPENOCD_VERSION) 149 self.assert_tool_installed(output, RISCV_ELF, RISCV_ELF_VERSION) 150 self.assert_tool_installed(output, XTENSA_ESP32_ELF, XTENSA_ESP32_ELF_VERSION) 151 self.assert_tool_installed(output, XTENSA_ESP32S2_ELF, XTENSA_ESP32S2_ELF_VERSION) 152 self.assert_tool_installed(output, XTENSA_ESP32S3_ELF, XTENSA_ESP32S3_ELF_VERSION) 153 self.assert_tool_installed(output, ESP32ULP, ESP32ULP_VERSION, ESP32ULP_ARCHIVE) 154 self.assert_tool_installed(output, ESP32S2ULP, ESP32S2ULP_VERSION, ESP32S2ULP_ARCHIVE) 155 self.assertIn('to ' + os.path.join(self.temp_tools_dir, 'dist'), output) 156 self.assertEqual(required_tools_installed, output.count('Done')) 157 158 output = self.run_idf_tools_with_action(['check']) 159 self.assertIn('version installed in tools directory: ' + ESP32ULP_VERSION, output) 160 self.assertIn('version installed in tools directory: ' + ESP32S2ULP_VERSION, output) 161 self.assertIn('version installed in tools directory: ' + OPENOCD_VERSION, output) 162 self.assertIn('version installed in tools directory: ' + RISCV_ELF_VERSION, output) 163 self.assertIn('version installed in tools directory: ' + XTENSA_ESP32_ELF_VERSION, output) 164 self.assertIn('version installed in tools directory: ' + XTENSA_ESP32S2_ELF_VERSION, output) 165 self.assertIn('version installed in tools directory: ' + XTENSA_ESP32S3_ELF_VERSION, output) 166 167 output = self.run_idf_tools_with_action(['export']) 168 self.assertIn('%s/tools/esp32ulp-elf/%s/esp32ulp-elf-binutils/bin' % 169 (self.temp_tools_dir, ESP32ULP_VERSION), output) 170 self.assertIn('%s/tools/xtensa-esp32-elf/%s/xtensa-esp32-elf/bin' % 171 (self.temp_tools_dir, XTENSA_ESP32_ELF_VERSION), output) 172 self.assertIn('%s/tools/openocd-esp32/%s/openocd-esp32/bin' % 173 (self.temp_tools_dir, OPENOCD_VERSION), output) 174 self.assertIn('%s/tools/riscv32-esp-elf/%s/riscv32-esp-elf/bin' % 175 (self.temp_tools_dir, RISCV_ELF_VERSION), output) 176 self.assertIn('%s/tools/esp32s2ulp-elf/%s/esp32s2ulp-elf-binutils/bin' % 177 (self.temp_tools_dir, ESP32S2ULP_VERSION), output) 178 self.assertIn('%s/tools/xtensa-esp32s2-elf/%s/xtensa-esp32s2-elf/bin' % 179 (self.temp_tools_dir, XTENSA_ESP32S2_ELF_VERSION), output) 180 self.assertIn('%s/tools/xtensa-esp32s3-elf/%s/xtensa-esp32s3-elf/bin' % 181 (self.temp_tools_dir, XTENSA_ESP32S3_ELF_VERSION), output) 182 183 def test_tools_for_esp32(self): 184 required_tools_installed = 3 185 output = self.run_idf_tools_with_action(['install', '--targets=esp32']) 186 self.assert_tool_installed(output, XTENSA_ESP32_ELF, XTENSA_ESP32_ELF_VERSION) 187 self.assert_tool_installed(output, OPENOCD, OPENOCD_VERSION) 188 self.assert_tool_installed(output, ESP32ULP, ESP32ULP_VERSION, ESP32ULP_ARCHIVE) 189 self.assert_tool_not_installed(output, RISCV_ELF, RISCV_ELF_VERSION) 190 self.assert_tool_not_installed(output, XTENSA_ESP32S2_ELF, XTENSA_ESP32S2_ELF_VERSION) 191 self.assert_tool_not_installed(output, XTENSA_ESP32S3_ELF, XTENSA_ESP32S3_ELF_VERSION) 192 self.assert_tool_not_installed(output, ESP32S2ULP, ESP32S2ULP_VERSION, ESP32S2ULP_ARCHIVE) 193 self.assertIn('to ' + os.path.join(self.temp_tools_dir, 'dist'), output) 194 self.assertEqual(required_tools_installed, output.count('Done')) 195 196 output = self.run_idf_tools_with_action(['check']) 197 self.assertIn('version installed in tools directory: ' + ESP32ULP_VERSION, output) 198 self.assertIn('version installed in tools directory: ' + XTENSA_ESP32_ELF_VERSION, output) 199 self.assertIn('version installed in tools directory: ' + OPENOCD_VERSION, output) 200 201 output = self.run_idf_tools_with_action(['export']) 202 self.assertIn('%s/tools/esp32ulp-elf/%s/esp32ulp-elf-binutils/bin' % 203 (self.temp_tools_dir, ESP32ULP_VERSION), output) 204 self.assertIn('%s/tools/xtensa-esp32-elf/%s/xtensa-esp32-elf/bin' % 205 (self.temp_tools_dir, XTENSA_ESP32_ELF_VERSION), output) 206 self.assertIn('%s/tools/openocd-esp32/%s/openocd-esp32/bin' % 207 (self.temp_tools_dir, OPENOCD_VERSION), output) 208 self.assertNotIn('%s/tools/riscv32-esp-elf/%s/riscv32-esp-elf/bin' % 209 (self.temp_tools_dir, RISCV_ELF_VERSION), output) 210 self.assertNotIn('%s/tools/esp32s2ulp-elf/%s/esp32s2ulp-elf-binutils/bin' % 211 (self.temp_tools_dir, ESP32S2ULP_VERSION), output) 212 self.assertNotIn('%s/tools/xtensa-esp32s2-elf/%s/xtensa-esp32s2-elf/bin' % 213 (self.temp_tools_dir, XTENSA_ESP32S2_ELF_VERSION), output) 214 self.assertNotIn('%s/tools/xtensa-esp32s3-elf/%s/xtensa-esp32s3-elf/bin' % 215 (self.temp_tools_dir, XTENSA_ESP32S3_ELF_VERSION), output) 216 217 def test_tools_for_esp32c3(self): 218 required_tools_installed = 2 219 output = self.run_idf_tools_with_action(['install', '--targets=esp32c3']) 220 self.assert_tool_installed(output, OPENOCD, OPENOCD_VERSION) 221 self.assert_tool_installed(output, RISCV_ELF, RISCV_ELF_VERSION) 222 self.assert_tool_not_installed(output, XTENSA_ESP32_ELF, XTENSA_ESP32_ELF_VERSION) 223 self.assert_tool_not_installed(output, XTENSA_ESP32S2_ELF, XTENSA_ESP32S2_ELF_VERSION) 224 self.assert_tool_not_installed(output, XTENSA_ESP32S3_ELF, XTENSA_ESP32S3_ELF_VERSION) 225 self.assert_tool_not_installed(output, ESP32ULP, ESP32ULP_VERSION, ESP32ULP_ARCHIVE) 226 self.assert_tool_not_installed(output, ESP32S2ULP, ESP32S2ULP_VERSION, ESP32S2ULP_ARCHIVE) 227 self.assertIn('to ' + os.path.join(self.temp_tools_dir, 'dist'), output) 228 self.assertEqual(required_tools_installed, output.count('Done')) 229 230 output = self.run_idf_tools_with_action(['check']) 231 self.assertIn('version installed in tools directory: ' + OPENOCD_VERSION, output) 232 self.assertIn('version installed in tools directory: ' + RISCV_ELF_VERSION, output) 233 234 output = self.run_idf_tools_with_action(['export']) 235 self.assertIn('%s/tools/openocd-esp32/%s/openocd-esp32/bin' % 236 (self.temp_tools_dir, OPENOCD_VERSION), output) 237 self.assertIn('%s/tools/riscv32-esp-elf/%s/riscv32-esp-elf/bin' % 238 (self.temp_tools_dir, RISCV_ELF_VERSION), output) 239 self.assertNotIn('%s/tools/esp32ulp-elf/%s/esp32ulp-elf-binutils/bin' % 240 (self.temp_tools_dir, ESP32ULP_VERSION), output) 241 self.assertNotIn('%s/tools/xtensa-esp32-elf/%s/xtensa-esp32-elf/bin' % 242 (self.temp_tools_dir, XTENSA_ESP32_ELF_VERSION), output) 243 self.assertNotIn('%s/tools/esp32s2ulp-elf/%s/esp32s2ulp-elf-binutils/bin' % 244 (self.temp_tools_dir, ESP32S2ULP_VERSION), output) 245 self.assertNotIn('%s/tools/xtensa-esp32s2-elf/%s/xtensa-esp32s2-elf/bin' % 246 (self.temp_tools_dir, XTENSA_ESP32S2_ELF_VERSION), output) 247 self.assertNotIn('%s/tools/xtensa-esp32s3-elf/%s/xtensa-esp32s3-elf/bin' % 248 (self.temp_tools_dir, XTENSA_ESP32S3_ELF_VERSION), output) 249 250 def test_tools_for_esp32s2(self): 251 required_tools_installed = 4 252 output = self.run_idf_tools_with_action(['install', '--targets=esp32s2']) 253 self.assert_tool_installed(output, XTENSA_ESP32S2_ELF, XTENSA_ESP32S2_ELF_VERSION) 254 self.assert_tool_installed(output, OPENOCD, OPENOCD_VERSION) 255 self.assert_tool_installed(output, RISCV_ELF, RISCV_ELF_VERSION) 256 self.assert_tool_not_installed(output, XTENSA_ESP32_ELF, XTENSA_ESP32_ELF_VERSION) 257 self.assert_tool_not_installed(output, XTENSA_ESP32S3_ELF, XTENSA_ESP32S3_ELF_VERSION) 258 self.assert_tool_not_installed(output, ESP32ULP, ESP32ULP_VERSION, ESP32ULP_ARCHIVE) 259 self.assert_tool_installed(output, ESP32S2ULP, ESP32S2ULP_VERSION, ESP32S2ULP_ARCHIVE) 260 self.assertIn('to ' + os.path.join(self.temp_tools_dir, 'dist'), output) 261 self.assertEqual(required_tools_installed, output.count('Done')) 262 263 output = self.run_idf_tools_with_action(['check']) 264 self.assertIn('version installed in tools directory: ' + ESP32S2ULP_VERSION, output) 265 self.assertIn('version installed in tools directory: ' + OPENOCD_VERSION, output) 266 self.assertIn('version installed in tools directory: ' + XTENSA_ESP32S2_ELF_VERSION, output) 267 268 output = self.run_idf_tools_with_action(['export']) 269 self.assertIn('%s/tools/esp32s2ulp-elf/%s/esp32s2ulp-elf-binutils/bin' % 270 (self.temp_tools_dir, ESP32S2ULP_VERSION), output) 271 self.assertIn('%s/tools/xtensa-esp32s2-elf/%s/xtensa-esp32s2-elf/bin' % 272 (self.temp_tools_dir, XTENSA_ESP32S2_ELF_VERSION), output) 273 self.assertIn('%s/tools/openocd-esp32/%s/openocd-esp32/bin' % 274 (self.temp_tools_dir, OPENOCD_VERSION), output) 275 self.assertNotIn('%s/tools/esp32ulp-elf/%s/esp32ulp-elf-binutils/bin' % 276 (self.temp_tools_dir, ESP32ULP_VERSION), output) 277 self.assertNotIn('%s/tools/xtensa-esp32-elf/%s/xtensa-esp32-elf/bin' % 278 (self.temp_tools_dir, XTENSA_ESP32_ELF_VERSION), output) 279 self.assertIn('%s/tools/riscv32-esp-elf/%s/riscv32-esp-elf/bin' % 280 (self.temp_tools_dir, RISCV_ELF_VERSION), output) 281 self.assertNotIn('%s/tools/xtensa-esp32s3-elf/%s/xtensa-esp32s3-elf/bin' % 282 (self.temp_tools_dir, XTENSA_ESP32S3_ELF_VERSION), output) 283 284 def test_tools_for_esp32s3(self): 285 required_tools_installed = 4 286 output = self.run_idf_tools_with_action(['install', '--targets=esp32s3']) 287 self.assert_tool_installed(output, XTENSA_ESP32S3_ELF, XTENSA_ESP32S3_ELF_VERSION) 288 self.assert_tool_installed(output, OPENOCD, OPENOCD_VERSION) 289 self.assert_tool_installed(output, RISCV_ELF, RISCV_ELF_VERSION) 290 self.assert_tool_not_installed(output, XTENSA_ESP32_ELF, XTENSA_ESP32_ELF_VERSION) 291 self.assert_tool_not_installed(output, XTENSA_ESP32S2_ELF, XTENSA_ESP32S2_ELF_VERSION) 292 self.assert_tool_not_installed(output, ESP32ULP, ESP32ULP_VERSION, ESP32ULP_ARCHIVE) 293 self.assert_tool_installed(output, ESP32S2ULP, ESP32S2ULP_VERSION, ESP32S2ULP_ARCHIVE) 294 self.assertIn('to ' + os.path.join(self.temp_tools_dir, 'dist'), output) 295 self.assertEqual(required_tools_installed, output.count('Done')) 296 297 output = self.run_idf_tools_with_action(['check']) 298 self.assertIn('version installed in tools directory: ' + OPENOCD_VERSION, output) 299 self.assertIn('version installed in tools directory: ' + XTENSA_ESP32S3_ELF_VERSION, output) 300 301 output = self.run_idf_tools_with_action(['export']) 302 self.assertIn('%s/tools/openocd-esp32/%s/openocd-esp32/bin' % 303 (self.temp_tools_dir, OPENOCD_VERSION), output) 304 self.assertIn('%s/tools/xtensa-esp32s3-elf/%s/xtensa-esp32s3-elf/bin' % 305 (self.temp_tools_dir, XTENSA_ESP32S3_ELF_VERSION), output) 306 self.assertNotIn('%s/tools/esp32ulp-elf/%s/esp32ulp-elf-binutils/bin' % 307 (self.temp_tools_dir, ESP32ULP_VERSION), output) 308 self.assertNotIn('%s/tools/xtensa-esp32-elf/%s/xtensa-esp32-elf/bin' % 309 (self.temp_tools_dir, XTENSA_ESP32_ELF_VERSION), output) 310 self.assertIn('%s/tools/riscv32-esp-elf/%s/riscv32-esp-elf/bin' % 311 (self.temp_tools_dir, RISCV_ELF_VERSION), output) 312 self.assertIn('%s/tools/esp32s2ulp-elf/%s/esp32s2ulp-elf-binutils/bin' % 313 (self.temp_tools_dir, ESP32S2ULP_VERSION), output) 314 self.assertNotIn('%s/tools/xtensa-esp32s2-elf/%s/xtensa-esp32s2-elf/bin' % 315 (self.temp_tools_dir, XTENSA_ESP32S2_ELF_VERSION), output) 316 317 318class TestMaintainer(unittest.TestCase): 319 320 def test_validation(self): 321 idf_tools.main(['validate']) 322 323 def test_json_rewrite(self): 324 idf_tools.main(['rewrite']) 325 idf_path = os.getenv('IDF_PATH') 326 if not idf_path: 327 self.fail('IDF_PATH needs to be set to run this test') 328 with open(os.path.join(idf_path, 'tools/tools.json'), 'r') as f: 329 json_old = f.read() 330 with open(os.path.join(idf_path, 'tools/tools.new.json'), 'r') as f: 331 json_new = f.read() 332 self.assertEqual(json_old, json_new, "Please check 'tools/tools.new.json' to find a cause!") 333 334 335if __name__ == '__main__': 336 unittest.main() 337