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, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.directory.server.core.integ; 020 021import java.lang.reflect.AnnotatedElement; 022import java.lang.reflect.Field; 023import java.lang.reflect.Method; 024import java.util.UUID; 025 026import org.apache.directory.api.util.FileUtils; 027import org.apache.directory.server.annotations.CreateLdapServer; 028import org.apache.directory.server.core.annotations.CreateDS; 029import org.apache.directory.server.core.api.DirectoryService; 030import org.apache.directory.server.core.api.changelog.Tag; 031import org.apache.directory.server.core.factory.DSAnnotationProcessor; 032import org.apache.directory.server.core.factory.DefaultDirectoryServiceFactory; 033import org.apache.directory.server.core.factory.DirectoryServiceFactory; 034import org.apache.directory.server.factory.ServerAnnotationProcessor; 035import org.apache.directory.server.ldap.LdapServer; 036import org.junit.jupiter.api.Disabled; 037import org.junit.jupiter.api.extension.AfterAllCallback; 038import org.junit.jupiter.api.extension.AfterEachCallback; 039import org.junit.jupiter.api.extension.BeforeAllCallback; 040import org.junit.jupiter.api.extension.BeforeEachCallback; 041import org.junit.jupiter.api.extension.ExtensionContext; 042import org.slf4j.Logger; 043import org.slf4j.LoggerFactory; 044 045public class CreateDSTestExtension implements BeforeEachCallback, AfterEachCallback, BeforeAllCallback, AfterAllCallback 046{ 047 private static final Logger LOG = LoggerFactory.getLogger( CreateDSTestExtension.class ); 048 049 private static final String CLASS_DS = "classDirectoryService"; 050 private static final String METHOD_DS = "methodDirectoryService"; 051 052 private void setDirectoryService( ExtensionContext context, String fieldName, DirectoryService directoryService ) 053 throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException 054 { 055 Class<?> testClass = context.getTestClass().get(); 056 Field field = testClass.getField( fieldName ); 057 field.set( null, directoryService ); 058 } 059 060 061 private DirectoryService getDirectoryService( ExtensionContext context, String fieldName ) 062 throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException 063 { 064 Class<?> testClass = context.getTestClass().get(); 065 Field directoryServiceField = testClass.getField( fieldName ); 066 067 if ( directoryServiceField != null ) 068 { 069 return ( DirectoryService ) directoryServiceField.get( testClass ); 070 } 071 else 072 { 073 return null; 074 } 075 } 076 077 078 /** 079 * In the BeforeALl method, we will create a DirectoryService instance that will be used by all 080 * the tests for this class. This DirectoryService will be destroyed in the AfterAll callback. 081 * 082 * Either we create it from the given description, or we create a default one 083 * 084 * In any case, we will inject the instance in the test class. 085 */ 086 @Override 087 public void beforeAll( ExtensionContext context ) throws Exception 088 { 089 // Don't run the test if the @Disabled annotation is used 090 if ( context.getTestClass().get().getAnnotation( Disabled.class ) != null ) 091 { 092 return; 093 } 094 095 AnnotatedElement classAnnotation = context.getTestClass().get(); 096 097 // Check if we have a CreateS annotation. If not, we will create the DirectoryService instance 098 CreateDS createDs = classAnnotation.getAnnotation( CreateDS.class ); 099 DirectoryService directoryService; 100 101 if ( createDs == null ) 102 { 103 // No description: create a default DS 104 DirectoryServiceFactory dsf = DefaultDirectoryServiceFactory.class.newInstance(); 105 106 directoryService = dsf.getDirectoryService(); 107 108 // enable CL explicitly cause we are not using DSAnnotationProcessor 109 directoryService.getChangeLog().setEnabled( true ); 110 111 dsf.init( "default" + UUID.randomUUID().toString() ); 112 113 if ( directoryService != null ) 114 { 115 Tag tag = directoryService.getChangeLog().tag(); 116 DSAnnotationProcessor.applyLdifs( classAnnotation, classAnnotation.getClass().getName(), directoryService ); 117 LOG.debug( "Tagged change log: {}", tag ); 118 } 119 else 120 { 121 LOG.trace( "no @CreateDS and no outer @CreateDS on: {}", classAnnotation.getClass().getName() ); 122 } 123 } 124 else 125 { 126 // We have a description, use it 127 LOG.trace( "Creating directory service" ); 128 directoryService = DSAnnotationProcessor.getDirectoryService( createDs ); 129 DSAnnotationProcessor.applyLdifs( classAnnotation, classAnnotation.getClass().getName(), directoryService ); 130 } 131 132 // Check if we have a LdapServer annotation 133 CreateLdapServer createLapServer = classAnnotation.getAnnotation( CreateLdapServer.class ); 134 135 if ( createLapServer == null ) 136 { 137 System.out.println( "" ); 138 } 139 else 140 { 141 LdapServer classLdapServer = ServerAnnotationProcessor.createLdapServer( createLapServer, directoryService ); 142 } 143 144 145 // The created DS is now stored in the test class 146 setDirectoryService( context, CLASS_DS, directoryService ); 147 } 148 149 150 /** 151 * We have to shutown the global DS now 152 */ 153 @Override 154 public void afterAll( ExtensionContext context ) throws Exception 155 { 156 LOG.trace( "Shutting down global directory service" ); 157 Class<?> testClass = context.getTestClass().get(); 158 Field directoryServiceField = testClass.getField( CLASS_DS ); 159 DirectoryService directoryService = ( DirectoryService ) directoryServiceField.get( testClass ); 160 Method shutdownMethod = directoryService.getClass().getDeclaredMethod( "shutdown", new Class[]{} ); 161 shutdownMethod.invoke( directoryService ); 162 163 FileUtils.deleteDirectory( directoryService.getInstanceLayout().getInstanceDirectory() ); 164 } 165 166 167 /** 168 * Here, we will create a local directoryService if needed, and only if needed 169 */ 170 @Override 171 public void beforeEach( ExtensionContext context ) throws Exception 172 { 173 // Don't run the test if the @Disabled annotation is used 174 if ( context.getTestMethod().get().getAnnotation( Disabled.class ) != null ) 175 { 176 return; 177 } 178 179 AnnotatedElement methodAnnotation = context.getTestMethod().get(); 180 AnnotatedElement classAnnotation = context.getTestClass().get(); 181 DirectoryService directoryService; 182 183 CreateDS createDs = methodAnnotation.getAnnotation( CreateDS.class ); 184 185 if ( createDs != null ) 186 { 187 LOG.trace( "Creating directory service" ); 188 directoryService = DSAnnotationProcessor.getDirectoryService( createDs ); 189 DSAnnotationProcessor.applyLdifs( classAnnotation, classAnnotation.getClass().getName(), directoryService ); 190 DSAnnotationProcessor.applyLdifs( methodAnnotation, methodAnnotation.getClass().getName(), directoryService ); 191 192 setDirectoryService( context, METHOD_DS, directoryService ); 193 } 194 else 195 { 196 // We don't have a local DS, so use the global one 197 directoryService = getDirectoryService( context, CLASS_DS ); 198 199 DSAnnotationProcessor.applyLdifs( methodAnnotation, methodAnnotation.getClass().getName(), directoryService ); 200 } 201 } 202 203 204 @Override 205 public void afterEach( ExtensionContext context ) throws Exception 206 { 207 LOG.trace( "Shutting down directory service" ); 208 Class<?> testClass = context.getTestClass().get(); 209 Field directoryServiceField = testClass.getField( METHOD_DS ); 210 DirectoryService directoryService = ( DirectoryService ) directoryServiceField.get( testClass ); 211 212 if ( directoryService != null ) 213 { 214 Method shutdownMethod = directoryService.getClass().getDeclaredMethod( "shutdown", new Class[]{} ); 215 shutdownMethod.invoke( directoryService ); 216 FileUtils.deleteDirectory( directoryService.getInstanceLayout().getInstanceDirectory() ); 217 218 setDirectoryService( context, METHOD_DS, null ); 219 } 220 } 221}