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.experimental.categories.Category; 026import org.junit.jupiter.api.Tag; 027import org.junit.runners.Suite; 028 029/** 030 * ClassFinder that is pre-configured with filters that will only allow test classes. The name is 031 * strange because a logical name would start with "Test" and be confusing. 032 */ 033public class ClassTestFinder extends ClassFinder { 034 035 public ClassTestFinder() { 036 super(new TestFileNameFilter(), new TestFileNameFilter(), new TestClassFilter()); 037 } 038 039 public ClassTestFinder(Class<?> category) { 040 super(new TestFileNameFilter(), new TestFileNameFilter(), new TestClassFilter(category)); 041 } 042 043 public static Class<?>[] getCategoryAnnotations(Class<?> c) { 044 Category category = c.getAnnotation(Category.class); 045 if (category != null) { 046 return category.value(); 047 } 048 return new Class<?>[0]; 049 } 050 051 public static String[] getTagAnnotations(Class<?> c) { 052 // TODO handle optional Tags annotation 053 Tag[] tags = c.getAnnotationsByType(Tag.class); 054 List<String> values = new ArrayList<>(); 055 for (Tag tag : tags) { 056 values.add(tag.value()); 057 } 058 return values.toArray(new String[values.size()]); 059 } 060 061 /** Filters both test classes and anything in the hadoop-compat modules */ 062 public static class TestFileNameFilter implements FileNameFilter, ResourcePathFilter { 063 private static final Pattern hadoopCompactRe = Pattern.compile("hbase-hadoop\\d?-compat"); 064 065 @Override 066 public boolean isCandidateFile(String fileName, String absFilePath) { 067 boolean isTestFile = fileName.startsWith("Test") || fileName.startsWith("IntegrationTest"); 068 return isTestFile && !hadoopCompactRe.matcher(absFilePath).find(); 069 } 070 071 @Override 072 public boolean isCandidatePath(String resourcePath, boolean isJar) { 073 return !hadoopCompactRe.matcher(resourcePath).find(); 074 } 075 } 076 077 /* 078 * A class is considered as a test class if: - it's not Abstract AND - one or more of its methods 079 * is annotated with org.junit.Test OR - the class is annotated with Suite.SuiteClasses 080 */ 081 public static class TestClassFilter implements ClassFilter { 082 private Class<?> categoryAnnotation = null; 083 084 public TestClassFilter(Class<?> categoryAnnotation) { 085 this.categoryAnnotation = categoryAnnotation; 086 } 087 088 public TestClassFilter() { 089 this(null); 090 } 091 092 @Override 093 public boolean isCandidateClass(Class<?> c) { 094 return isTestClass(c) && isCategorizedClass(c); 095 } 096 097 private boolean isTestClass(Class<?> c) { 098 if (Modifier.isAbstract(c.getModifiers())) { 099 return false; 100 } 101 102 if (c.getAnnotation(Suite.SuiteClasses.class) != null) { 103 return true; 104 } 105 106 for (Method met : c.getMethods()) { 107 if ( 108 met.getAnnotation(org.junit.Test.class) != null 109 || met.getAnnotation(org.junit.jupiter.api.Test.class) != null 110 ) { 111 return true; 112 } 113 } 114 115 return false; 116 } 117 118 private boolean isCategorizedClass(Class<?> c) { 119 if (this.categoryAnnotation == null) { 120 return true; 121 } 122 for (Class<?> cc : getCategoryAnnotations(c)) { 123 if (cc.equals(this.categoryAnnotation)) { 124 return true; 125 } 126 } 127 return false; 128 } 129 } 130}