def _find_classes_by_annotated_methods(annotations, suite): """ Scan distributions from binary suite dependencies for classes contain at least one method with an annotation from 'annotations' and return a dictionary from fully qualified class names to the distribution containing the class. """ binarySuiteDists = [d for d in mx.dependencies(opt_limit_to_suite=True) if d.isJARDistribution() and isinstance(d.suite, mx.BinarySuite) and (not suite or suite == d.suite)] if len(binarySuiteDists) != 0: # Ensure Java support class is built mx.build(['--dependencies', 'com.oracle.mxtool.junit']) # Create map from jar file to the binary suite distribution defining it jars = {d.classpath_repr() : d for d in binarySuiteDists} cp = mx.classpath(['com.oracle.mxtool.junit'] + [d.name for d in binarySuiteDists]) out = mx.OutputCapture() mx.run_java(['-cp', cp] + ['com.oracle.mxtool.junit.FindClassesByAnnotatedMethods'] + annotations + jars.keys(), out=out) candidates = {} for line in out.data.strip().split('\n'): name, jar = line.split(' ') # Record class name to the binary suite distribution containing it candidates[name] = jars[jar] return candidates return {}
def _find_classes_by_annotated_methods(annotations, suite): """ Scan distributions from binary suite dependencies for classes contain at least one method with an annotation from 'annotations' and return a dictionary from fully qualified class names to the distribution containing the class. """ binarySuiteDists = [ d for d in mx.dependencies(opt_limit_to_suite=True) if d.isJARDistribution() and isinstance(d.suite, mx.BinarySuite) and ( not suite or suite == d.suite) ] if len(binarySuiteDists) != 0: # Ensure Java support class is built mx.build(['--dependencies', 'com.oracle.mxtool.junit']) # Create map from jar file to the binary suite distribution defining it jars = {d.classpath_repr(): d for d in binarySuiteDists} cp = mx.classpath(['com.oracle.mxtool.junit'] + [d.name for d in binarySuiteDists]) out = mx.OutputCapture() mx.run_java(['-cp', cp] + ['com.oracle.mxtool.junit.FindClassesByAnnotatedMethods'] + annotations + jars.keys(), out=out) candidates = {} for line in out.data.strip().split('\n'): name, jar = line.split(' ') # Record class name to the binary suite distribution containing it candidates[name] = jars[jar] return candidates return {}
def mx_post_parse_cmd_line(opts): def _uses_truffle_dsl_processor(dist): for dep in dist.deps: if dep.name.startswith('TRUFFLE_DSL_PROCESSOR'): return True truffle_dsl_processors = set() def visit(dep, edge): if dep is not dist and dep.isJavaProject(): for ap in dep.annotation_processors(): if ap.name.startswith('TRUFFLE_DSL_PROCESSOR'): truffle_dsl_processors.add(ap) dist.walk_deps(visit=visit) return len(truffle_dsl_processors) != 0 for d in mx.dependencies(): if d.isJARDistribution(): if _uses_truffle_dsl_processor(d): d.set_archiveparticipant(TruffleArchiveParticipant())
def find_test_candidates(annotations, suite, jdk, buildCacheDir='unittest'): """ Finds all classes containing methods annotated with one of the supplied annotations. To speed up subsequent invocations, the results are cached in the `buildCacheDir`. :param list annotations: a list of annotations to recognize test methods, e.g. ['@Test', '@Parameters'] :param suite: the mx suite in which to look for test classes. If no suite is given, the primary suite is used. :param JDKConfig jdk: the JDK for which the list of classes must be found :param str buildCacheDir: a path relative to the mx suite output root that is used to store the cache files. :return: a dictionary associating each found test class with the distribution it occurs in. """ assert not isabs(buildCacheDir), "buildCacheDir must be a relative path" compat_suite = suite if suite else mx.primary_suite() if suite != mx._mx_suite and compat_suite.getMxCompatibility( ).useDistsForUnittest(): jar_distributions = [ d for d in mx.sorted_dists() if d.isJARDistribution() and exists(d.classpath_repr( resolve=False)) and (not suite or d.suite == suite) ] # find a corresponding distribution for each test candidates = _find_classes_by_annotated_methods( annotations, jar_distributions, buildCacheDir, jdk) else: binary_deps = [ d for d in mx.dependencies(opt_limit_to_suite=True) if d.isJARDistribution() and isinstance(d.suite, mx.BinarySuite) and (not suite or suite == d.suite) ] candidates = _find_classes_by_annotated_methods( annotations, binary_deps, buildCacheDir, jdk) for p in mx.projects(opt_limit_to_suite=True): if not p.isJavaProject(): continue if suite and not p.suite == suite: continue if jdk.javaCompliance < p.javaCompliance: continue for c in _find_classes_with_annotations(p, None, annotations): candidates[c] = p return candidates
def suite_classpath(): """Get the classpath containing only the current suite's dependencies, removing Graal projects (if any) from it""" dependencies = mx.dependencies(True) dependencies = itertools.ifilter(lambda d: not d.isNativeProject(), dependencies) dependencies = itertools.ifilter(lambda d: not d.isPackedResourceLibrary(), dependencies) dependencies = [d.name for d in dependencies] cp = mx.classpath(dependencies) cp_list = cp.split(os.pathsep) sanitized_list = [] for entry in cp_list: include = True if entry.find("com.oracle.graal") >= 0 or entry.find( "com.oracle.truffle") >= 0 or entry.find("graal/dists") >= 0: include = False if include: sanitized_list.append(entry) result = os.pathsep.join(sanitized_list) return result
def _run_tests(args, harness, vmLauncher, annotations, testfile, blacklist, whitelist, regex, suite): vmArgs, tests = mx.extract_VM_args(args) for t in tests: if t.startswith('-'): mx.abort('VM option ' + t + ' must precede ' + tests[0]) # this is what should be used compat_suite = suite if suite else mx.primary_suite() if suite != mx._mx_suite and compat_suite.getMxCompatibility( ).useDistsForUnittest(): jar_distributions = [ d for d in mx.sorted_dists() if d.isJARDistribution() and exists(d.classpath_repr( resolve=False)) and (not suite or d.suite == suite) ] # find a corresponding distribution for each test candidates = _find_classes_by_annotated_methods( annotations, jar_distributions, vmLauncher.jdk()) else: binary_deps = [ d for d in mx.dependencies(opt_limit_to_suite=True) if d.isJARDistribution() and isinstance(d.suite, mx.BinarySuite) and (not suite or suite == d.suite) ] candidates = _find_classes_by_annotated_methods( annotations, binary_deps, vmLauncher.jdk()) for p in mx.projects(opt_limit_to_suite=True): if not p.isJavaProject(): continue if suite and not p.suite == suite: continue if vmLauncher.jdk().javaCompliance < p.javaCompliance: continue for c in _find_classes_with_annotations(p, None, annotations): candidates[c] = p classes = [] if len(tests) == 0: classes = candidates.keys() depsContainingTests = set(candidates.values()) else: depsContainingTests = set() found = False if len(tests) == 1 and '#' in tests[0]: words = tests[0].split('#') if len(words) != 2: mx.abort("Method specification is class#method: " + tests[0]) t, method = words for c, p in candidates.iteritems(): # prefer exact matches first if t == c: found = True classes.append(c) depsContainingTests.add(p) if not found: for c, p in candidates.iteritems(): if t in c: found = True classes.append(c) depsContainingTests.add(p) if not found: mx.warn('no tests matched by substring: ' + t + ' (did you forget to run "mx build"?)') elif len(classes) != 1: mx.abort('More than one test matches substring {0} {1}'.format( t, classes)) classes = [c + "#" + method for c in classes] else: for t in tests: if '#' in t: mx.abort( 'Method specifications can only be used in a single test: ' + t) for c, p in candidates.iteritems(): if t in c: found = True classes.append(c) depsContainingTests.add(p) if not found: mx.warn('no tests matched by substring: ' + t + ' (did you forget to run "mx build"?)') if blacklist: classes = [ c for c in classes if not any((glob.match(c) for glob in blacklist)) ] if whitelist: classes = [ c for c in classes if any((glob.match(c) for glob in whitelist)) ] if regex: classes = [c for c in classes if re.search(regex, c)] if len(classes) != 0: f_testfile = open(testfile, 'w') for c in classes: f_testfile.write(c + '\n') f_testfile.close() harness(depsContainingTests, vmLauncher, vmArgs)
def _unittest_config_participant(config): vmArgs, mainClass, mainClassArgs = config cpIndex, cp = mx.find_classpath_arg(vmArgs) if cp: cp = _uniqify(cp.split(os.pathsep)) if isJDK8: # Remove entries from class path that are in Graal or on the boot class path redundantClasspathEntries = set() for dist in [entry.dist() for entry in _jvmci_classpath]: redundantClasspathEntries.update((d.output_dir() for d in dist.archived_deps() if d.isJavaProject())) redundantClasspathEntries.add(dist.path) cp = os.pathsep.join([e for e in cp if e not in redundantClasspathEntries]) vmArgs[cpIndex] = cp else: deployedModules = [] redundantClasspathEntries = set() for dist in [entry.dist() for entry in _jvmci_classpath] + _bootclasspath_appends: deployedModule = as_java_module(dist, jdk) deployedModules.append(deployedModule) redundantClasspathEntries.update(mx.classpath(dist, preferProjects=False, jdk=jdk).split(os.pathsep)) redundantClasspathEntries.update(mx.classpath(dist, preferProjects=True, jdk=jdk).split(os.pathsep)) if hasattr(dist, 'overlaps'): for o in dist.overlaps: path = mx.distribution(o).classpath_repr() if path: redundantClasspathEntries.add(path) # Remove entries from the class path that are in the deployed modules cp = [classpathEntry for classpathEntry in cp if classpathEntry not in redundantClasspathEntries] vmArgs[cpIndex] = os.pathsep.join(cp) # Junit libraries are made into automatic modules so that they are visible to tests # patched into modules. These automatic modules must be declared to be read by # Graal which means they must also be made root modules (i.e., ``--add-modules``) # since ``--add-reads`` can only be applied to root modules. junitCp = [e.classpath_repr() for e in mx.classpath_entries(['JUNIT'])] junitModules = [_automatic_module_name(e) for e in junitCp] vmArgs.append('--module-path=' + os.pathsep.join(junitCp)) vmArgs.append('--add-modules=' + ','.join(junitModules + [m.name for m in deployedModules])) for deployedModule in deployedModules: vmArgs.append('--add-reads=' + deployedModule.name + '=' + ','.join(junitModules)) # Explicitly export concealed JVMCI packages required by Graal. Even though # normally exported via jdk.vm.ci.services.Services.exportJVMCITo(), the # Junit harness wants to access JVMCI classes (e.g., when loading classes # to find test methods) without going through that entry point. addedExports = {} for deployedModule in deployedModules: for concealingModule, packages in deployedModule.concealedRequires.iteritems(): if concealingModule == 'jdk.vm.ci': for package in packages: addedExports.setdefault(concealingModule + '/' + package, set()).add(deployedModule.name) pathToDep = {p.output_dir() if p.isJavaProject() else p.path: p for p in mx.dependencies() if p.isJavaProject() or p.isJARDistribution()} for classpathEntry in cp: # Export concealed packages used by the class path entry _add_exports_for_concealed_packages(classpathEntry, pathToDep, addedExports, 'ALL-UNNAMED', deployedModules) for deployedModule in deployedModules: assert deployedModule.dist.path != classpathEntry, deployedModule.dist.path + ' should no longer be on the class path' # Ensure the class path entry does not define packages already defined by the module. # Packages definitions cannot be split between modules. classpathEntryPackages = frozenset(_defined_packages(classpathEntry)) intersection = classpathEntryPackages.intersection(deployedModule.packages) if intersection: mx.abort(classpathEntry + ' cannot extend package(s) defined in the module ' + deployedModule.name + ': ' + ', '.join(intersection)) vmArgs.extend(['--add-exports=' + export + '=' + ','.join(sorted(targets)) for export, targets in addedExports.iteritems()]) if isJDK8: # Run the VM in a mode where application/test classes can # access JVMCI loaded classes. vmArgs.append('-XX:-UseJVMCIClassLoader') return (vmArgs, mainClass, mainClassArgs)
def _run_tests(args, harness, vmLauncher, annotations, testfile, blacklist, whitelist, regex, suite): vmArgs, tests = mx.extract_VM_args(args) for t in tests: if t.startswith('-'): mx.abort('VM option ' + t + ' must precede ' + tests[0]) # this is what should be used compat_suite = suite if suite else mx.primary_suite() if suite != mx._mx_suite and compat_suite.getMxCompatibility().useDistsForUnittest(): jar_distributions = [d for d in mx.sorted_dists() if d.isJARDistribution() and (not suite or d.suite == suite)] # find a corresponding distribution for each test candidates = _find_classes_by_annotated_methods(annotations, jar_distributions, vmLauncher.jdk()) else: binary_deps = [d for d in mx.dependencies(opt_limit_to_suite=True) if d.isJARDistribution() and isinstance(d.suite, mx.BinarySuite) and (not suite or suite == d.suite)] candidates = _find_classes_by_annotated_methods(annotations, binary_deps, vmLauncher.jdk()) for p in mx.projects(opt_limit_to_suite=True): if not p.isJavaProject(): continue if suite and not p.suite == suite: continue if vmLauncher.jdk().javaCompliance < p.javaCompliance: continue for c in _find_classes_with_annotations(p, None, annotations): candidates[c] = p classes = [] if len(tests) == 0: classes = candidates.keys() depsContainingTests = set(candidates.values()) else: depsContainingTests = set() found = False if len(tests) == 1 and '#' in tests[0]: words = tests[0].split('#') if len(words) != 2: mx.abort("Method specification is class#method: " + tests[0]) t, method = words for c, p in candidates.iteritems(): # prefer exact matches first if t == c: found = True classes.append(c) depsContainingTests.add(p) if not found: for c, p in candidates.iteritems(): if t in c: found = True classes.append(c) depsContainingTests.add(p) if not found: mx.log('warning: no tests matched by substring: ' + t) elif len(classes) != 1: mx.abort('More than one test matches substring {0} {1}'.format(t, classes)) classes = [c + "#" + method for c in classes] else: for t in tests: if '#' in t: mx.abort('Method specifications can only be used in a single test: ' + t) for c, p in candidates.iteritems(): if t in c: found = True classes.append(c) depsContainingTests.add(p) if not found: mx.log('warning: no tests matched by substring: ' + t) if blacklist: classes = [c for c in classes if not any((glob.match(c) for glob in blacklist))] if whitelist: classes = [c for c in classes if any((glob.match(c) for glob in whitelist))] if regex: classes = [c for c in classes if re.search(regex, c)] if len(classes) != 0: f_testfile = open(testfile, 'w') for c in classes: f_testfile.write(c + '\n') f_testfile.close() harness(depsContainingTests, vmLauncher, vmArgs)
def _unittest_config_participant(config): vmArgs, mainClass, mainClassArgs = config cpIndex, cp = mx.find_classpath_arg(vmArgs) if cp: cp = _uniqify(cp.split(os.pathsep)) if isJDK8: # Remove entries from class path that are in Graal or on the boot class path redundantClasspathEntries = set() for dist in [entry.dist() for entry in _jvmci_classpath]: redundantClasspathEntries.update( (d.output_dir() for d in dist.archived_deps() if d.isJavaProject())) redundantClasspathEntries.add(dist.path) cp = os.pathsep.join( [e for e in cp if e not in redundantClasspathEntries]) vmArgs[cpIndex] = cp else: deployedModules = [] redundantClasspathEntries = set() for dist in [entry.dist() for entry in _jvmci_classpath ] + _bootclasspath_appends: deployedModule = as_java_module(dist, jdk) deployedModules.append(deployedModule) redundantClasspathEntries.update( mx.classpath(dist, preferProjects=False, jdk=jdk).split(os.pathsep)) redundantClasspathEntries.update( mx.classpath(dist, preferProjects=True, jdk=jdk).split(os.pathsep)) if hasattr(dist, 'overlaps'): for o in dist.overlaps: path = mx.distribution(o).classpath_repr() if path: redundantClasspathEntries.add(path) # Remove entries from the class path that are in the deployed modules cp = [ classpathEntry for classpathEntry in cp if classpathEntry not in redundantClasspathEntries ] vmArgs[cpIndex] = os.pathsep.join(cp) # Junit libraries are made into automatic modules so that they are visible to tests # patched into modules. These automatic modules must be declared to be read by # Graal which means they must also be made root modules (i.e., ``--add-modules``) # since ``--add-reads`` can only be applied to root modules. junitCp = [ e.classpath_repr() for e in mx.classpath_entries(['JUNIT']) ] junitModules = [_automatic_module_name(e) for e in junitCp] vmArgs.append('--module-path=' + os.pathsep.join(junitCp)) vmArgs.append('--add-modules=' + ','.join(junitModules + [m.name for m in deployedModules])) for deployedModule in deployedModules: vmArgs.append('--add-reads=' + deployedModule.name + '=' + ','.join(junitModules)) # Explicitly export concealed JVMCI packages required by Graal. Even though # normally exported via jdk.vm.ci.services.Services.exportJVMCITo(), the # Junit harness wants to access JVMCI classes (e.g., when loading classes # to find test methods) without going through that entry point. addedExports = {} for deployedModule in deployedModules: for concealingModule, packages in deployedModule.concealedRequires.iteritems( ): if concealingModule == 'jdk.vm.ci': for package in packages: addedExports.setdefault( concealingModule + '/' + package, set()).add(deployedModule.name) pathToDep = { p.output_dir() if p.isJavaProject() else p.path: p for p in mx.dependencies() if p.isJavaProject() or p.isJARDistribution() } for classpathEntry in cp: # Export concealed packages used by the class path entry _add_exports_for_concealed_packages(classpathEntry, pathToDep, addedExports, 'ALL-UNNAMED', deployedModules) for deployedModule in deployedModules: assert deployedModule.dist.path != classpathEntry, deployedModule.dist.path + ' should no longer be on the class path' # Ensure the class path entry does not define packages already defined by the module. # Packages definitions cannot be split between modules. classpathEntryPackages = frozenset( _defined_packages(classpathEntry)) intersection = classpathEntryPackages.intersection( deployedModule.packages) if intersection: mx.abort( classpathEntry + ' cannot extend package(s) defined in the module ' + deployedModule.name + ': ' + ', '.join(intersection)) vmArgs.extend([ '--add-exports=' + export + '=' + ','.join(sorted(targets)) for export, targets in addedExports.iteritems() ]) if isJDK8: # Run the VM in a mode where application/test classes can # access JVMCI loaded classes. vmArgs.append('-XX:-UseJVMCIClassLoader') return (vmArgs, mainClass, mainClassArgs)