All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.caucho.junit.RunnerBaratine Maven / Gradle / Ivy

There is a newer version: 1.0.1
Show newest version
/*
 * Copyright (c) 1998-2015 Caucho Technology -- all rights reserved
 *
 * This file is part of Baratine(TM)
 *
 * Each copy or derived work must preserve the copyright notice and this
 * notice unmodified.
 *
 * Baratine is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Baratine is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
 * of NON-INFRINGEMENT.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Baratine; if not, write to the
 *
 *   Free Software Foundation, Inc.
 *   59 Temple Place, Suite 330
 *   Boston, MA 02111-1307  USA
 *
 * @author Alex Rojkov
 */

package com.caucho.junit;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.inject.Inject;

import com.caucho.v5.amp.spi.ShutdownModeAmp;
import com.caucho.v5.inject.AnnotationLiteral;
import com.caucho.v5.io.Vfs;
import com.caucho.v5.loader.EnvironmentClassLoader;
import com.caucho.v5.subsystem.RootDirectorySystem;
import com.caucho.v5.subsystem.SystemManager;
import com.caucho.v5.util.L10N;
import com.caucho.v5.util.RandomUtil;
import com.caucho.v5.vfs.VfsOld;
import io.baratine.service.Api;
import io.baratine.service.Service;
import io.baratine.service.ServiceRef;
import io.baratine.service.Services;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkField;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.TestClass;

public class RunnerBaratine extends BlockJUnit4ClassRunner
{
  private static final Logger log
    = Logger.getLogger(RunnerBaratine.class.getName());

  private static final L10N L = new L10N(RunnerBaratine.class);

  public RunnerBaratine(Class cl) throws InitializationError
  {
    super(cl);
  }

  @Override
  protected Object createTest() throws Exception
  {
    Object test = super.createTest();

    initialize(test);

    return test;
  }

  private ServiceTest[] getServices()
  {
    TestClass test = getTestClass();

    ServiceTests config
      = test.getAnnotation(ServiceTests.class);

    if (config != null)
      return config.value();

    Annotation[] annotations = test.getAnnotations();

    List list = new ArrayList<>();

    for (Annotation annotation : annotations) {
      if (ServiceTest.class.isAssignableFrom(annotation.getClass()))
        list.add((ServiceTest) annotation);
    }

    return list.toArray(new ServiceTest[list.size()]);
  }

  private void initialize(Object test) throws IllegalAccessException
  {
    TestClass testClass = getTestClass();

    Services manager = Services.newManager().autoServices(true).start();

    Map descriptors = deployServices(manager);

    bindFields(test, testClass, manager, descriptors);
  }

  private void bindFields(Object test,
                          TestClass testClass,
                          Services manager,
                          Map descriptors)
    throws IllegalAccessException
  {
    List fields = testClass.getAnnotatedFields();

    for (FrameworkField field : fields) {
      Object inject;

      if (field.getAnnotation(Service.class) != null) {
        inject = findService(manager, descriptors, field);
      }
      else if (field.getAnnotation(Inject.class) != null) {
        inject = findInject(manager, field);
      }
      else {
        continue;
      }

      Field javaField = field.getField();

      javaField.setAccessible(true);

      javaField.set(test, inject);
    }
  }

  private Map deployServices(
    Services manager)
  {
    Map descriptors = new HashMap<>();

    for (ServiceTest service : getServices()) {
      Class serviceClass = service.value();

      ServiceDescriptor descriptor = ServiceDescriptor.of(serviceClass);

      ServiceRef ref = manager.newService(serviceClass).addressAuto().ref();

      descriptors.put(descriptor, ref);
    }

    return descriptors;
  }

  public Object findService(Services manager,
                            Map map,
                            FrameworkField field)
  {
    final Service binding = field.getAnnotation(Service.class);

    final Class type = field.getType();

    ServiceRef service = null;

    service = matchServiceByImpl(map, type);

    if (service == null)
      service = matchServiceByAddress(map, binding);

    if (service == null)
      service = matchServiceByApi(map, type);

    if (service == null)
      service = matchDefaultService(manager, binding);

    if (service == null)
      throw new IllegalStateException(L.l(
        "unable to bind field {0}, make sure corresponding service is deployed.",
        field.getField()));

    if (ServiceRef.class == type)
      return service;
    else
      return service.as(type);
  }

  private ServiceRef matchDefaultService(Services manager,
                                         Service binding)
  {
    String address = binding.value();

    if (address == null)
      return null;

    return manager.service(address);
  }

  private ServiceRef matchServiceByApi(Map map,
                                       Class type)
  {
    for (Map.Entry entry : map.entrySet()) {
      ServiceDescriptor descriptor = entry.getKey();
      Class api = descriptor.getApi();

      if (api != null && type.isAssignableFrom(descriptor.getApi())) {
        return entry.getValue();
      }
    }

    return null;
  }

  private ServiceRef matchServiceByAddress(Map map,
                                           Service binding)
  {
    for (Map.Entry entry : map.entrySet()) {
      ServiceDescriptor descriptor = entry.getKey();

      if (descriptor.getAddress().equals(binding.value())) {
        return entry.getValue();
      }
    }

    return null;
  }

  private ServiceRef matchServiceByImpl(Map map,
                                        Class type)
  {
    for (Map.Entry entry : map.entrySet()) {
      ServiceDescriptor descriptor = entry.getKey();

      if (descriptor.getServiceClass().equals(type)) {
        return entry.getValue();
      }
    }

    return null;
  }

  private Object findInject(Services manager, FrameworkField field)
  {
    final Class type = field.getType();

    Object inject = null;

    if (type == Services.class) {
      inject = manager;
    }

    if (inject == null)
      throw new IllegalStateException(L.l("unable to bind field {0}",
                                          field.getField()));

    return inject;
  }

  static class ServiceDescriptor
  {
    private Class _api;
    private Class _serviceClass;
    private Service _service;

    private ServiceDescriptor(final Class serviceClass)
    {
      Objects.requireNonNull(serviceClass);

      _serviceClass = serviceClass;
      _service = (Service) serviceClass.getAnnotation(Service.class);

      Objects.requireNonNull(_service,
                             L.l("{0} must declare @Service annotation",
                                 _serviceClass));

      if (serviceClass.isInterface()) {
        _api = serviceClass;
      }
      else {
        _api = getApi(serviceClass);
      }
    }

    private Class getApi(Class serviceClass)
    {
      Api api;
      Class t = serviceClass;

      do {
        api = (Api) t.getAnnotation(Api.class);
      } while (api == null
               && (t = serviceClass.getSuperclass()) != Object.class);

      return api == null ? null : api.value();
    }

    public String getAddress()
    {
      final String address;

      if (_service.value() != null) {
        address = _service.value();
      }
      else {
        String name = _serviceClass.getSimpleName();
        if (name.endsWith("Impl"))
          name = name.substring(0, name.length() - 4);

        address = '/' + name;
      }

      return address;
    }

    public static ServiceDescriptor of(Class t)
    {
      return new ServiceDescriptor(t);
    }

    @Override
    public boolean equals(Object o)
    {
      if (this == o) return true;
      if (o == null || getClass() != o.getClass()) return false;

      ServiceDescriptor that = (ServiceDescriptor) o;

      return _serviceClass.equals(that._serviceClass);
    }

    @Override
    public int hashCode()
    {
      return _serviceClass.hashCode();
    }

    public Class getServiceClass()
    {
      return _serviceClass;
    }

    public Class getApi()
    {
      return _api;
    }
  }

  @Override
  protected void runChild(FrameworkMethod method, RunNotifier notifier)
  {
    Thread thread = Thread.currentThread();

    ClassLoader oldLoader = thread.getContextClassLoader();

    EnvironmentClassLoader envLoader
      = EnvironmentClassLoader.create(oldLoader, "test-loader");

    String baratineRoot = getWorkDir();
    System.setProperty("baratine.root", baratineRoot);

    RootDirectorySystem rootDir = null;

    SystemManager manager = null;

    try {
      thread.setContextClassLoader(envLoader);

      long startTime = getStartTime();

      if (startTime != -1) {
        TestTime.setTime(startTime);

        RandomUtil.setTestSeed(startTime);
      }

      Logger.getLogger("").setLevel(Level.INFO);
      Logger.getLogger("javax.management").setLevel(Level.INFO);

      try {
        VfsOld.lookup(baratineRoot).removeAll();
      } catch (Exception e) {
      }

      manager = new SystemManager("test-manager");

      rootDir = RootDirectorySystem.createAndAddSystem(Vfs.path(baratineRoot));

      rootDir.start();

      super.runChild(method, notifier);
    } catch (Throwable t) {
      t.printStackTrace();
    } finally {
      Logger.getLogger("").setLevel(Level.INFO);

      try {
        rootDir.stop(ShutdownModeAmp.GRACEFUL);
      } catch (Throwable t) {
        t.printStackTrace();
      }

      try {
        envLoader.close();
      } catch (Throwable t) {
        t.printStackTrace();
      }

      try {
        manager.close();
      } catch (Throwable t) {
        t.printStackTrace();
      }

      thread.setContextClassLoader(oldLoader);
    }
  }

  private ConfigurationBaratine getConfiguration()
  {
    ConfigurationBaratine config
      = getTestClass().getAnnotation(ConfigurationBaratine.class);

    if (config == null)
      config = ConfigurationBaratineDefault.INSTNANCE;

    return config;
  }

  private String getWorkDir()
  {
    final ConfigurationBaratine config = getConfiguration();

    String workDir = config.workDir();

    if (workDir.charAt(0) == '{') {
      workDir = eval(workDir);
    }

    return workDir;
  }

  private long getStartTime()
  {
    final ConfigurationBaratine config = getConfiguration();

    return config.testTime();
  }

  private String eval(String expr)
  {
    if (expr.charAt(0) != '{' || expr.charAt(expr.length() - 1) != '}')
      throw new IllegalArgumentException(L.l(
        "property {0} does not match expected format of {property}",
        expr));

    return System.getProperty(expr.substring(1, expr.length() - 1));
  }
}

class ConfigurationBaratineDefault
  extends AnnotationLiteral
  implements ConfigurationBaratine
{
  public static final long TEST_TIME = 894621091000L;

  static final ConfigurationBaratine INSTNANCE
    = new ConfigurationBaratineDefault();

  private ConfigurationBaratineDefault()
  {
  }

  @Override
  public String workDir()
  {
    return "{java.io.tmpdir}";
  }

  @Override
  public long testTime()
  {
    return TEST_TIME;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy