def calculate_section_sizes(builddir): ''' Return the sizes of the main sections. ''' section_sizes = {'bss': 0, 'text': 0, 'data': 0, 'rodata': 0} mapfile = utils.join(builddir, 'linker.map') libdir = utils.join(builddir, 'libs') if not (utils.exists(mapfile) and utils.exists(libdir)): return section_sizes # Get the names of the object files that the static # libraries (libjerry-core.a, ...) have. objlist = read_objects_from_libs(libdir, _LIBLIST) raw_data = lumpy.load_map_data(mapfile) sections = lumpy.parse_to_sections(raw_data) # Extract .rodata section from the .text section. lumpy.hoist_section(sections, '.text', '.rodata') for section in sections: section_name = section['name'][1:] # Skip sections that are not relevant. if section_name not in section_sizes.keys(): continue for entry in section['contents']: if any(obj in entry['path'] for obj in objlist): section_sizes[section_name] += entry['size'] return section_sizes
def run(self): ''' Main method to run IoT.js or JerryScript tests. ''' if self.env.options.no_test: return reporter.report_configuration(self.env) for testset, tests in read_testsets(self.env).items(): self.run_testset(testset, tests) if self.env.options.coverage: device = self.env.options.device app_name = self.env.options.app if device in ['artik053', 'artik530', 'rpi2' ] and app_name == 'iotjs': iotjs = self.env.modules.iotjs commit_info = utils.last_commit_info(iotjs['src']) result_name = 'cov-%s-%s.json' % (commit_info['commit'], commit_info['date']) result_dir = utils.join(paths.RESULT_PATH, '%s/%s/' % (app_name, device)) result_path = utils.join(result_dir, result_name) self.coverage_info = testrunner_utils.parse_coverage_info( self.env, result_path) reporter.report_coverage(self.coverage_info) reporter.report_final(self.results)
def _build_iotjs(self, profile, extra_flags): ''' Build IoT.js for Tizen target. ''' iotjs = self.env['modules']['iotjs'] profiles = { 'minimal': 'profiles/minimal.profile', 'target': 'test/profiles/tizen.profile' } build_flags = [ '--clean', '--no-parallel-build', '--no-init-submodule', '--target-arch=noarch', '--target-os=tizen', '--target-board=rpi3', '--profile=%s' % profiles[profile], '--buildtype=%s' % self.env['info']['buildtype'] ] + extra_flags iotjs_build_options = ' '.join(build_flags) # Note: these values should be defined for GBS, because # it will compile the IoT.js itself. utils.define_environment('IOTJS_BUILD_OPTION', iotjs_build_options) args = ['--clean'] if self.env['info']['buildtype'] == 'debug': args.append('--debug') utils.execute(iotjs['src'], 'config/tizen/gbsbuild.sh', args) tizen_build_dir = utils.join(paths.GBS_IOTJS_PATH, 'build') iotjs_build_dir = utils.join(iotjs['src'], 'build') # Copy the GBS created binaries to the iotjs build folder. # Note: GBS compiles iotjs in the GBS folder. utils.copy(tizen_build_dir, iotjs_build_dir)
def _copy_build_files(self, target_module, builddir): ''' Copy the created binaries, libs, linker map to the build folder. ''' application = self.env['modules']['app'] linker_map = utils.join(builddir, 'linker.map') lib_folder = utils.join(builddir, 'libs') utils.copy(application['paths']['libdir'], lib_folder) utils.copy(target_module['paths']['linker-map'], linker_map) utils.copy(target_module['paths']['image'], builddir)
def create_result(self): ''' Create a final JSON result file from the build and test information. ''' result = {'bin': {}, 'date': {}, 'tests': {}, 'submodules': {}} labels = { 'profiles/minimal-profile-build': 'minimal-profile', 'profiles/target-es5.1-profile-build': 'target-es5_1-profile', 'profiles/target-es2015subset-profile-build': 'target-es2015subset-profile' } for job_id, build_path in self.results.iteritems(): # Append the binary information. if 'test-build' in job_id: filename = utils.join(build_path, 'testresults.json') # Do not save the testresults if there is no available data. if not utils.exists(filename): continue result.update(utils.read_json_file(filename)) else: filename = utils.join(build_path, 'build.json') # Do not save build info if there is no available data. if not utils.exists(filename): continue bin_data = utils.read_json_file(filename) # Translate job_id to database schema name. label = labels[job_id] result['bin'][label] = bin_data['bin'] result['submodules'] = bin_data['submodules'] result['date'] = bin_data['last-commit-date'] filepath = utils.join(paths.RESULT_PATH, self.options.app, self.options.device) filename = utils.join(filepath, utils.current_date() + '.json') # Save the content info a result file. utils.write_json_file(filename, result) console.log() console.log('The results are written into:', console.TERMINAL_BLUE) console.log(' {json_file}'.format(json_file=filename)) console.log() return result
def read_test_files(env): ''' Read all the tests from the given folder and create a dictionary similar to the IoT.js testsets.json file. ''' testsets = {} # Read all the tests from the application. app = env.modules.app testpath = app.paths.tests for root, _, files in os.walk(testpath): # The name of the testset is always the folder name. testset = utils.relpath(root, utils.abspath(utils.join(testpath, '..'))) # Create a new testset entry if it doesn't exist. if testset not in testsets: testsets[testset] = [] for filename in files: test = {'name': filename} if 'fail' in testset: test['expected-failure'] = True testsets[testset].append(test) return testsets
def parse_coverage_info(env, coverage_output): ''' Parse and create coverage information ''' coverage_info = {} iotjs = env.modules.iotjs js_folder = iotjs.paths['js-sources'] # Store line information from the JS sources. for js_file in os.listdir(js_folder): filename, _ = os.path.splitext(js_file) coverage_info[filename] = {} coverage_info[filename]['lines'] = [] coverage_info[filename]['coverage'] = [0, 0] js_file_path = utils.join(js_folder, js_file) with open(js_file_path, "r") as js_source: lines = js_source.readlines() for line in lines: # '0' indicates that the line has not been reached yet. coverage_info[filename]['lines'].append([line, '0']) with open(coverage_output, 'r') as cov_p: raw_data = json.load(cov_p) ignore_list = ['run_pass', 'run_fail', 'node', 'tools'] for js_name in raw_data: # Skip empty key value. if not js_name: continue # Ignore test and tool files. if any(ignored_name in js_name for ignored_name in ignore_list): continue filename, _ = os.path.splitext(js_name) if filename not in coverage_info: continue # Iterate reached js files. for line_number, line_value in raw_data[js_name].iteritems(): if line_value: # Increase covered lines. coverage_info[filename]['coverage'][0] += 1 # '2' indicates that the line has been covered. coverage_info[filename]['lines'][int(line_number) - 1][1] = '2' else: # '1' indicates that the line has not been covered. coverage_info[filename]['lines'][int(line_number) - 1][1] = '1' coverage_info[filename]['coverage'][1] += 1 return coverage_info
def create_build_info(env): ''' Write binary size and commit information into a file. ''' app_name = env['info']['app'] build_path = env['paths']['build'] # Binary size information. minimal_builddir = env['paths']['build-minimal'] target_builddir = env['paths']['build-target'] bin_sizes = { 'minimal-profile': calculate_section_sizes(minimal_builddir), 'target-profile': calculate_section_sizes(target_builddir) } # Git commit information from the projects. submodules = {} for name, module in env['modules'].iteritems(): # Don't duplicate the application information. if name == 'app': continue submodules[name] = utils.last_commit_info(module['src']) # Merge the collected values into a result object. build_info = { 'build-date': utils.current_date('%Y-%m-%dT%H.%M.%SZ'), 'last-commit-date': submodules[app_name]['date'], 'bin': bin_sizes, 'submodules': submodules } utils.write_json_file(utils.join(build_path, 'build.json'), build_info)
def save(self): ''' Save the current testresults into JSON format. ''' if self.env['info']['no_test']: return build_file = self.env['paths']['build-json'] build_info = utils.read_json_file(build_file) # Add the build information. test_info = { 'date': build_info['last-commit-date'], 'bin': build_info['bin'], 'submodules': build_info['submodules'] } # Specify a date named results file. result_dir = self.env['paths']['result'] filename = utils.join(result_dir, build_info['build-date']) if self.env['info']['coverage']: # Add the coverage information. test_info['coverage_info'] = self.coverage_info filename += '_coverage' else: # Add the test results. test_info['tests'] = self.results # Save the results into the date named file. utils.write_json_file(filename + '.json', test_info) # Publish the results if necessary. testrunner_utils.upload_data_to_firebase(self.env, test_info)
def read_testsets(env): ''' Read all the tests into dictionary. ''' testset = utils.join(env.modules.app.paths.tests, 'testsets.json') if utils.exists(testset): return utils.read_json_file(testset) return testrunner_utils.read_test_files(env)
def initialize(self): ''' Flash the device. ''' if self.env['info']['no_flash']: return target_app = self.env['modules']['app'] build_path = self.env['paths']['build'] test_src = target_app['paths']['tests'] test_dst = utils.join(build_path, 'tests') # 1. Copy all the necessary files. # Copy applicaiton RPM package file. rpm_package_path = self.env['paths']['tizen-rpm-package'] utils.copy(rpm_package_path, build_path) # Copy all the tests into the build folder. utils.copy(test_src, test_dst) utils.copy(paths.FREYA_TESTER, build_path) if not self.env['info']['no_memstat']: utils.copy(paths.FREYA_CONFIG, build_path) # Resolve the iotjs-dirname macro in the Freya configuration file. basename = utils.basename(paths.GBS_IOTJS_PATH) sed_flags = [ '-i', 's/%%{iotjs-dirname}/%s/g' % basename, 'iotjs-freya.config' ] utils.execute(build_path, 'sed', sed_flags) # 2. Deploy the build folder to the device. self.login() self.channel.exec_command('mount -o remount,rw /') shell_flags = 'ssh -p %s' % self.port rsync_flags = [ '--rsh', shell_flags, '--recursive', '--compress', '--delete' ] # Note: slash character is required after the path. # In this case `rsync` copies the whole folder, not # the subcontents to the destination. src = self.env['paths']['build'] + '/' dst = '%s@%s:%s' % (self.user, self.ip, self.workdir) utils.execute('.', 'rsync', rsync_flags + [src, dst]) # 3. Install rpm package template = 'rpm -ivh --force --nodeps %s/%s-1.0.0-0.armv7l.rpm' self.channel.exec_command(template % (self.workdir, self.app)) self.logout()
def _build_freya(self): ''' Cross-compile Valgrind and its Freya tool. ''' build_dir = utils.join(self.env['paths']['build'], 'valgrind_freya') valgrind_files = [ 'vg-in-place', 'coregrind/valgrind', '.in_place/freya-arm-linux', '.in_place/vgpreload_core-arm-linux.so', '.in_place/vgpreload_freya-arm-linux.so' ] # Check if a Freya build already exists, if yes, skip the build. if utils.exist_files(build_dir, valgrind_files): return freya = self.env['modules']['freya'] utils.define_environment('LD', 'arm-linux-gnueabihf-ld') utils.define_environment('AR', 'arm-linux-gnueabihf-ar') utils.define_environment('CC', 'arm-linux-gnueabihf-gcc') utils.define_environment('CPP', 'arm-linux-gnueabihf-cpp') utils.define_environment('CXX', 'arm-linux-gnueabihf-g++') configure_options = ['--host=armv7-linux-gnueabihf'] utils.execute(freya['src'], './autogen.sh') utils.execute(freya['src'], './configure', configure_options) utils.execute(freya['src'], 'make', ['clean']) utils.execute(freya['src'], 'make', ['TOOLS=freya']) utils.unset_environment('LD') utils.unset_environment('AR') utils.unset_environment('CC') utils.unset_environment('CPP') utils.unset_environment('CXX') # Copy necessary files into the output directory. for valgrind_file in valgrind_files: src = utils.join(freya['src'], valgrind_file) dst = utils.join(build_dir, valgrind_file) utils.copy(src, dst)
def run_coverage_script(env): ''' Start the client script. ''' # Add latency because the start up of the debug server needs time. time.sleep(2) address = env.options.debugger iotjs = env.modules.iotjs coverage_client = iotjs.paths['coverage-client'] device = env.options.device app_name = env.options.app commit_info = utils.last_commit_info(iotjs['src']) result_name = 'cov-%s-%s.json' % (commit_info['commit'], commit_info['date']) result_dir = utils.join(paths.RESULT_PATH, '%s/%s/' % (app_name, device)) result_path = utils.join(result_dir, result_name) utils.mkdir(result_dir) utils.execute(paths.PROJECT_ROOT, 'python', [coverage_client, '--coverage-output', result_path, address])
def _read_skiplist(self): ''' Read the local skiplists. ''' skiplists = { 'iotjs': 'iotjs-skiplist.json', 'jerryscript': 'jerryscript-skiplist.json' } skipfile = utils.join(paths.TESTRUNNER_PATH, skiplists[self.app]) skiplist = utils.read_json_file(skipfile) return skiplist[self.device_type]
def run_coverage_script(env): ''' Start the client script. ''' # Add latency because the start up of the debug server needs time. time.sleep(2) address = env['info']['coverage'] iotjs = env['modules']['iotjs'] coverage_client = iotjs['paths']['coverage-client'] device = env['info']['device'] app_name = env['info']['app'] commit_info = utils.last_commit_info(iotjs['src']) result_name = 'cov-%s-%s.json' % (commit_info['commit'], commit_info['date']) result_dir = utils.join(paths.RESULT_PATH, '%s/%s/' % (app_name, device)) result_path = utils.join(result_dir, result_name) utils.mkdir(result_dir) utils.execute(paths.PROJECT_ROOT, coverage_client, ['--non-interactive', '--coverage-output=%s' % result_path, address])
def create_testing_environment(user_options, job_options): ''' Load the resource infromation that all modules define. ''' resources = encode_as_objdict(utils.read_json_file(paths.RESOURCES_JSON)) # Merge the two options. # Modify the user options with the options for the current job. options = namespace_as_dict(user_options) options.update(job_options) # Create an object from the dictionary. options = encode_as_objdict(options) # Get the dependencies of the current device. deps = resources.targets[options.device] # Update the deps list with user selected project. deps.insert(0, options.app) # Get the required module information. Drop all the # modules that are not required by the target. modules = encode_as_objdict( {name: resources.modules[name] for name in deps}) # Update the path of the target application if custom # iotjs or jerryscript is used. if options.app_path: modules[options.app].src = options.app_path if options.testsuite: modules[options.app].paths.tests = options.testsuite # Add an 'app' named module that is just a reference # to the user defined target application. modules.app = modules[options.app] modules.app.name = options.app # Set the current build directory to the paths. resources.paths.builddir = utils.join(resources.paths.build, options.id) # Modify the no-build options according to the no-profile-build option. no_profile_build = options.no_profile_build and 'profile' in options.id options.no_build = options.no_build or no_profile_build environment = encode_as_objdict({ 'options': options, 'modules': modules, 'paths': resources.paths }) # Resolve the symbolic values in the resources.json file. return encode_as_objdict(symbol_resolver.resolve(environment, environment))
def _read_test_descriptor(self): ''' Read the local skiplists. ''' descriptors = { 'iotjs': 'iotjs-test-descriptor.json', 'jerryscript': 'jerryscript-test-descriptor.json' } descriptor_file = utils.join(paths.SKIPLIST_PATH, descriptors[self.app]) descriptor_info = utils.read_json_file(descriptor_file) return descriptor_info[self.device_type]
def generate_romfs(src, dst): ''' Create a romfs_img from the source directory that is converted to a header (byte array) file. Finally, add a `const` modifier to the byte array to be the data in the Read Only Memory. ''' romfs_img = utils.join(os.curdir, 'romfs_img') utils.execute(os.curdir, 'genromfs', ['-f', romfs_img, '-d', src]) utils.execute(os.curdir, 'xxd', ['-i', 'romfs_img', dst]) utils.execute(os.curdir, 'sed', ['-i', 's/unsigned/const\ unsigned/g', dst]) os.remove(romfs_img)
def genromfs(**params): ''' Create a romfs_img from the source directory that is converted to a header (byte array) file. Finally, add a `const` modifier to the byte array to be the data in the Read Only Memory. ''' src = params['args'][0] dst = params['args'][1] romfs_img = utils.join(params['cwd'], 'romfs_img') utils.execute(params['cwd'], 'genromfs', ['-f', romfs_img, '-d', src]) utils.execute(params['cwd'], 'xxd', ['-i', 'romfs_img', dst]) utils.execute(params['cwd'], 'sed', ['-i', 's/unsigned/const\ unsigned/g', dst]) utils.remove_file(romfs_img)
def read_modules(self): ''' Collect buildable modules and their build instructions. ''' modules = {} for name in self.env.modules: filename = utils.join(paths.BUILDER_MODULES_PATH, '%s.build.config' % name) # Skip modules that don't have configuration file (e.g. nuttx-apps). if not utils.exists(filename): continue build_info = utils.read_config_file(filename, self.env) # Check if the project is alredy built. if self.should_build(build_info): modules[name] = build_info[self.device] return modules
def initialize(self): ''' Flash the device. ''' if self.env['info']['no_flash']: return # 1. Copy all the necessary files. target_app = self.env['modules']['app'] build_path = self.env['paths']['build'] test_src = target_app['paths']['tests'] test_dst = utils.join(build_path, 'tests') # Copy all the tests into the build folder. utils.copy(test_src, test_dst) utils.copy(paths.FREYA_TESTER, build_path) if not self.env['info']['no_memstat']: # Copy Freya memory measurement files. utils.copy(paths.FREYA_CONFIG, build_path) # Resolve the iotjs-dirname macro in the Freya configuration file. basename = utils.basename(target_app['src']) sed_flags = [ '-i', 's/%%{iotjs-dirname}/%s/g' % basename, 'iotjs-freya.config' ] utils.execute(build_path, 'sed', sed_flags) # 2. Deploy the build folder to the device. shell_flags = 'ssh -p %s' % self.port rsync_flags = [ '--rsh', shell_flags, '--recursive', '--compress', '--delete' ] # Note: slash character is required after the path. # In this case `rsync` copies the whole folder, not # the subcontents to the destination. src = self.env['paths']['build'] + '/' dst = '%s@%s:%s' % (self.user, self.ip, self.workdir) utils.execute('.', 'rsync', rsync_flags + [src, dst])
def save(self): ''' Save the current testresults into JSON format. ''' if self.env.options.no_test: return results = {} # Specify a date named results file. filename = utils.join(self.env.paths.builddir, 'testresults.json') if self.env.options.coverage: results['coverage_info'] = self.coverage_info filename += '_coverage' else: results['tests'] = self.results # Save the results into the date named file. utils.write_json_file(filename, results)
def create_build_info(env): ''' Write binary size and commit information into a file. ''' submodules = {} for name, module in env.modules.iteritems(): # Don't duplicate the application information. if name == 'app': continue submodules[name] = utils.last_commit_info(module['src']) # Merge the collected values into a result object. build_info = { 'build-date': utils.current_date('%Y-%m-%dT%H.%M.%SZ'), 'last-commit-date': submodules[env.options.app]['date'], 'bin': calculate_section_sizes(env.paths.builddir), 'submodules': submodules } utils.write_json_file(utils.join(env.paths.builddir, 'build.json'), build_info)