Author: kmalhi
Date: Fri Jul  2 00:58:50 2010
New Revision: 959824

URL: http://svn.apache.org/viewvc?rev=959824&view=rev
Log:
A custom JUnit Runner to run tests involving OpenEjb validation. 

Added:
    
openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/rules/InvokeMethod.java
    
openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/rules/Keys.java
    
openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/rules/ValidationRunner.java

Added: 
openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/rules/InvokeMethod.java
URL: 
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/rules/InvokeMethod.java?rev=959824&view=auto
==============================================================================
--- 
openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/rules/InvokeMethod.java
 (added)
+++ 
openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/rules/InvokeMethod.java
 Fri Jul  2 00:58:50 2010
@@ -0,0 +1,106 @@
+package org.apache.openejb.config.rules;
+
+import static 
org.apache.openejb.config.rules.ValidationAssertions.assertFailures;
+import static org.junit.Assert.fail;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.ResourceBundle;
+import java.util.Set;
+
+import org.apache.openejb.assembler.classic.Assembler;
+import org.apache.openejb.assembler.classic.SecurityServiceInfo;
+import org.apache.openejb.assembler.classic.TransactionServiceInfo;
+import org.apache.openejb.config.ConfigurationFactory;
+import org.apache.openejb.config.ValidationFailedException;
+import org.apache.openejb.jee.EjbJar;
+import org.apache.openejb.util.Join;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.Statement;
+/**
+ * This Statement is the one which runs the test.
+ *
+ */
+public class InvokeMethod extends Statement {
+  private ConfigurationFactory config;
+  private Assembler assembler;
+  // The test method
+  private final FrameworkMethod testMethod;
+  // The TestCase instance
+  private Object target;
+  // These are all the keys defined in 
org.apache.openejb.config.rules.Messages.properties
+  private static Set<String> allKeys;
+  static {
+    ResourceBundle bundle = 
ResourceBundle.getBundle("org.apache.openejb.config.rules.Messages");
+    allKeys = bundle.keySet();
+  }
+
+  public InvokeMethod(FrameworkMethod testMethod, Object target) {
+    this.testMethod = testMethod;
+    this.target = target;
+  }
+
+  @Override
+  public void evaluate() throws Throwable {
+    List<String> expectedKeys = validateKeys();
+    setUp();
+    Object obj = testMethod.invokeExplosively(target);
+    if (obj instanceof EjbJar) {
+      EjbJar ejbJar = (EjbJar) obj;
+      try {
+        assembler.createApplication(config.configureApplication(ejbJar));
+        fail("A ValidationFailedException should have been thrown");
+      } catch (ValidationFailedException vfe) {
+        assertFailures(expectedKeys, vfe);
+      }
+    }
+    tearDown();
+  }
+
+  private void setUp() throws Exception {
+    config = new ConfigurationFactory();
+    assembler = new Assembler();
+    
assembler.createTransactionManager(config.configureService(TransactionServiceInfo.class));
+    
assembler.createSecurityService(config.configureService(SecurityServiceInfo.class));
+  }
+
+  private void tearDown() {
+  }
+
+  /**
+   * Tests to see if the keys specified in the @Keys annotation are also 
available in the org.apache.openejb.config.rules.Messages.properties file. If 
there are any invalid keys,
+   * then it throws an exception and causes the test to error out. If all the 
keys are valid, then it writes those keys to a file. This list of keys can then 
be compared with all
+   * the Keys in org.apache.openejb.config.rules.Messages.properties and one 
can then find out the "test coverage" of the keys i.e. this tool can be used to 
find keys for which
+   * tests have not yet been written
+   * 
+   * @return
+   * @throws Exception
+   */
+  private List<String> validateKeys() throws Exception {
+    Keys annotation = testMethod.getAnnotation(Keys.class);
+    String[] keys = annotation.value();
+    ArrayList<String> wrongKeys = new ArrayList<String>();
+    for (String key : keys) {
+      if (allKeys.contains("1." + key)) {
+        continue;
+      } else {
+        wrongKeys.add(key);
+      }
+    }
+    if (wrongKeys.isEmpty()) {
+      return Arrays.asList(keys);
+    } else {
+      String commaDelimitedKeys = Join.join(",", wrongKeys);
+      throw new Exception("The following keys listed in the @Keys annotation 
on the method " + testMethod.getName() + "() of " + 
testMethod.getMethod().getDeclaringClass()
+          + " are invalid : " + commaDelimitedKeys + " . Only keys listed in 
org.apache.openejb.config.rules.Messages.properties are allowed to be used in 
this annotation. ");
+    }
+  }
+}

Added: 
openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/rules/Keys.java
URL: 
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/rules/Keys.java?rev=959824&view=auto
==============================================================================
--- 
openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/rules/Keys.java
 (added)
+++ 
openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/rules/Keys.java
 Fri Jul  2 00:58:50 2010
@@ -0,0 +1,14 @@
+package org.apache.openejb.config.rules;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+/**
+ * Used to specify the keys being tested.
+ */
+...@target(ElementType.METHOD)
+...@retention(RetentionPolicy.RUNTIME)
+public @interface Keys {
+  String[] value();
+}

Added: 
openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/rules/ValidationRunner.java
URL: 
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/rules/ValidationRunner.java?rev=959824&view=auto
==============================================================================
--- 
openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/rules/ValidationRunner.java
 (added)
+++ 
openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/rules/ValidationRunner.java
 Fri Jul  2 00:58:50 2010
@@ -0,0 +1,71 @@
+package org.apache.openejb.config.rules;
+
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.internal.runners.model.ReflectiveCallable;
+import org.junit.internal.runners.statements.Fail;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.Statement;
+
+/**
+ * This class is created specifically to write tests which test OpenEjb 
validation code. Specifically, it is used to check the usage of keys defined in
+ * org.apache.openejb.config.rules.Messages.properties. To use this runner, 
simply annotate your test case with @RunWith(ValidationRunner.class). Here are 
some things to keep in
+ * mind when writing tests: 1. A test method needs to be annotated with 
org.apache.openejb.config.rules.Keys instead of the org.junit.Test 2. Any usage 
of the @Test annotation will
+ * be ignored 3. If the @Keys and @Test annotation are used together on a test 
method, then the TestCase will error out 4. Every test method should create a 
EjbJar and return it
+ * from the method. It should list the keys being tested in the @Keys 
annotation 5. The runner will invoke the test method and use the Assembler and 
ConfigurationFactory to create
+ * the application 6. This will kick off validation and this Runner will catch 
ValidationFailureException and make sure that all the keys specified in the 
@Keys annotation show up
+ * in the ValidationFailureException 7. If the keys listed in the @Keys 
annotation match the keys found in the ValidationFailureException, the test 
passes, else the test fails. 8.
+ * This Runner also validates that the keys specified in the @Keys annotation 
are also available in the org.apache.openejb.config.rules.Messages.properties 
file. If the key is not
+ * found, then the Runner throws and exception resulting in your test case not 
being allowed to run.
+ */
+public class ValidationRunner extends BlockJUnit4ClassRunner {
+  public ValidationRunner(Class<?> klass) throws InitializationError {
+    super(klass);
+  }
+
+  /**
+   * Flags an error if you have annotated a test with both @Test and @Keys. 
Any method annotated with @Test will be ignored anyways.
+   */
+  @Override
+  protected void collectInitializationErrors(List<Throwable> errors) {
+    super.collectInitializationErrors(errors);
+    List<FrameworkMethod> methodsAnnotatedWithKeys = 
getTestClass().getAnnotatedMethods(Keys.class);
+    for (FrameworkMethod frameworkMethod : methodsAnnotatedWithKeys) {
+      if (frameworkMethod.getAnnotation(Test.class) != null) {
+        String gripe = "The method " + frameworkMethod.getName() + "() can 
only be annotated with @Keys";
+        errors.add(new Exception(gripe));
+      }
+    }
+  }
+
+  @Override
+  protected Statement methodBlock(FrameworkMethod method) {
+    Object test;
+    try {
+      test = new ReflectiveCallable() {
+        @Override
+        protected Object runReflectiveCall() throws Throwable {
+          return createTest();
+        }
+      }.run();
+    } catch (Throwable e) {
+      return new Fail(e);
+    }
+    Statement statement = new InvokeMethod(method, test);
+    statement = withBefores(method, test, statement);
+    statement = withAfters(method, test, statement);
+    return statement;
+  }
+
+  /**
+   * By default JUnit includes all methods annotated with @Test. This method 
only allows methods annotated with @Keys to be included in the list of methods 
to be run in a TestCase.
+   * Any @Test methods will be ignored
+   */
+  @Override
+  protected List<FrameworkMethod> computeTestMethods() {
+    return getTestClass().getAnnotatedMethods(Keys.class);
+  }
+}


Reply via email to