001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase; 019 020import java.lang.reflect.Method; 021import java.lang.reflect.Modifier; 022import java.util.ArrayList; 023import java.util.List; 024import java.util.regex.Pattern; 025import org.junit.jupiter.api.Tag; 026 027/** 028 * ClassFinder that is pre-configured with filters that will only allow test classes. The name is 029 * strange because a logical name would start with "Test" and be confusing. 030 */ 031public class ClassTestFinder extends ClassFinder { 032 033 public ClassTestFinder() { 034 super(new TestFileNameFilter(), new TestFileNameFilter(), new TestClassFilter()); 035 } 036 037 public ClassTestFinder(Class<?> tag) { 038 super(new TestFileNameFilter(), new TestFileNameFilter(), new TestClassFilter(tag)); 039 } 040 041 public static Class<?>[] getTagAnnotations(Class<?> c) { 042 // TODO handle optional Tags annotation 043 Tag[] tags = c.getAnnotationsByType(Tag.class); 044 List<Class<?>> values = new ArrayList<>(); 045 if (tags != null) { 046 for (Tag tag : tags) { 047 try { 048 values.add(Class.forName(tag.value())); 049 } catch (ClassNotFoundException e) { 050 throw new RuntimeException(e); 051 } 052 } 053 } 054 return values.toArray(new Class<?>[values.size()]); 055 } 056 057 /** Filters both test classes and anything in the hadoop-compat modules */ 058 public static class TestFileNameFilter implements FileNameFilter, ResourcePathFilter { 059 private static final Pattern hadoopCompactRe = Pattern.compile("hbase-hadoop\\d?-compat"); 060 061 @Override 062 public boolean isCandidateFile(String fileName, String absFilePath) { 063 boolean isTestFile = fileName.startsWith("Test") || fileName.startsWith("IntegrationTest"); 064 return isTestFile && !hadoopCompactRe.matcher(absFilePath).find(); 065 } 066 067 @Override 068 public boolean isCandidatePath(String resourcePath, boolean isJar) { 069 return !hadoopCompactRe.matcher(resourcePath).find(); 070 } 071 } 072 073 /* 074 * A class is considered as a test class if: - it's not Abstract AND - one or more of its methods 075 * is annotated with org.junit.Test OR - the class is annotated with Suite.SuiteClasses 076 */ 077 public static class TestClassFilter implements ClassFilter { 078 private Class<?> tagAnnotation = null; 079 080 public TestClassFilter(Class<?> categoryAnnotation) { 081 this.tagAnnotation = categoryAnnotation; 082 } 083 084 public TestClassFilter() { 085 this(null); 086 } 087 088 @Override 089 public boolean isCandidateClass(Class<?> c) { 090 return isTestClass(c) && isTagedClass(c); 091 } 092 093 private boolean isTestClass(Class<?> c) { 094 if (Modifier.isAbstract(c.getModifiers())) { 095 return false; 096 } 097 098 for (Method met : c.getMethods()) { 099 if (met.getAnnotation(org.junit.jupiter.api.Test.class) != null) { 100 return true; 101 } 102 } 103 104 return false; 105 } 106 107 private boolean isTagedClass(Class<?> c) { 108 if (this.tagAnnotation == null) { 109 return true; 110 } 111 for (Class<?> cc : getTagAnnotations(c)) { 112 if (cc.equals(this.tagAnnotation)) { 113 return true; 114 } 115 } 116 return false; 117 } 118 } 119}