content: // Licensed to the Apache Software Foundation (ASF) under one
  // or more contributor license agreements.  See the NOTICE file
  // distributed with this work for additional information
  // regarding copyright ownership.  The ASF licenses this file
  // to you under the Apache License, Version 2.0 (the
  // "License"); you may not use this file except in compliance
  // the License.  You may obtain a copy of the License at
  //
  // http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing,
  // software distributed under the License is distributed on an
  // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  // KIND, either express or implied.  See the License for the
  // specific language governing permissions and limitations
  // under the License.
  
  package org.apache.cloudstack.test.utils;
  
  import java.util.ArrayList;
  import java.util.List;
  
  import org.springframework.context.annotation.Bean;
  import org.springframework.context.annotation.ComponentScan;
  
  import com.cloud.utils.component.ComponentContext;
  import com.cloud.utils.component.ComponentInstantiationPostProcessor;
  import com.cloud.utils.component.ComponentMethodInterceptor;
  import com.cloud.utils.db.TransactionContextBuilder;
  import com.cloud.utils.exception.CloudRuntimeException;
  
  public class SpringUtils {
  
      /**
       * This method allows you to use @ComponentScan for your unit testing but
       * it limits the scope of the classes found to the class specified in
       * the @ComponentScan annotation.
       *
       * Without using this method, the default behavior of @ComponentScan is
       * to actually scan in the package of the class specified rather than
       * only the class. This can cause extra classes to be loaded which causes
       * the classes these extra classes depend on to be loaded. The end effect
       * is often most of the project gets loaded.
       *
       * In order to use this method properly, you must do the following: <li>
       *   - Specify @ComponentScan with basePackageClasses, includeFilters, and
       *     useDefaultFilters=true.  See the following example.
       *
       * <pre>
       *     @ComponentScan(basePackageClasses={AffinityGroupServiceImpl.class, EventUtils.class},
       *     includeFilters={@Filter(value=TestConfiguration.Library.class, type=FilterType.CUSTOM)},
       *     useDefaultFilters=false)
       * </pre>
       *
       *   - Create a Library class and use that to call this method.  See the
       *     following example.  The Library class you define here is the Library
       *     class being added in the filter above.
       *
       * <pre>
       * public static class Library implements TypeFilter {
       *      @Override
       *      public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException {
       *          ComponentScan cs = TestConfiguration.class.getAnnotation(ComponentScan.class);
       *          return SpringUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs);
       *      }
       * }
       * </pre>
       *
       * @param clazzName name of the class that should be included in the Spring components
       * @param cs ComponentScan annotation that was declared on the configuration
       *
       * @return
       */
      public static boolean includedInBasePackageClasses(String clazzName, ComponentScan cs) {
          Class<?> clazzToCheck;
          try {
              clazzToCheck = Class.forName(clazzName);
          } catch (ClassNotFoundException e) {
              throw new CloudRuntimeException("Unable to find " + clazzName);
          }
          Class<?>[] clazzes = cs.basePackageClasses();
          for (Class<?> clazz : clazzes) {
              if (clazzToCheck.isAssignableFrom(clazz)) {
                  return true;
              }
          }
          return false;
      }
  
      public static class CloudStackTestConfiguration {
  
          @Bean
          public ComponentContext componentContext() {
              return new ComponentContext();
          }
  
          @Bean
          public TransactionContextBuilder transactionContextBuilder() {
              return new TransactionContextBuilder();
          }
  
          @Bean
          public ComponentInstantiationPostProcessor instantiatePostProcessor() {
              ComponentInstantiationPostProcessor processor = new ComponentInstantiationPostProcessor();
  
              List<ComponentMethodInterceptor> interceptors = new ArrayList<ComponentMethodInterceptor>();
              interceptors.add(new TransactionContextBuilder());
              processor.setInterceptors(interceptors);
  
              return processor;
          }
  
      }
  }
  